From 999d4d533fa247db063590241dab4e95182cf12f Mon Sep 17 00:00:00 2001 From: snow flurry Date: Fri, 1 Mar 2024 19:51:05 -0800 Subject: [PATCH] Import from curl-8.6.0.zip Upstream: https://github.com/curl/curl/releases/tag/curl-8_6_0 --- CHANGES | 10696 ++++ CMake/CMakeConfigurableFile.in | 24 + CMake/CurlSymbolHiding.cmake | 84 + CMake/CurlTests.c | 430 + CMake/FindBearSSL.cmake | 32 + CMake/FindBrotli.cmake | 43 + CMake/FindCARES.cmake | 47 + CMake/FindGSS.cmake | 312 + CMake/FindLibPSL.cmake | 45 + CMake/FindLibSSH2.cmake | 45 + CMake/FindMSH3.cmake | 70 + CMake/FindMbedTLS.cmake | 36 + CMake/FindNGHTTP2.cmake | 41 + CMake/FindNGHTTP3.cmake | 78 + CMake/FindNGTCP2.cmake | 117 + CMake/FindQUICHE.cmake | 70 + CMake/FindWolfSSL.cmake | 36 + CMake/FindZstd.cmake | 78 + CMake/Macros.cmake | 109 + CMake/OtherTests.cmake | 184 + CMake/PickyWarnings.cmake | 232 + CMake/Platforms/WindowsCache.cmake | 188 + CMake/Utilities.cmake | 35 + CMake/cmake_uninstall.cmake.in | 49 + CMake/curl-config.cmake.in | 40 + CMakeLists.txt | 1754 + COPYING | 22 + MacOSX-Framework | 160 + Makefile | 71 + Makefile.am | 535 + Makefile.in | 2085 + README | 55 + RELEASE-NOTES | 365 + acinclude.m4 | 1663 + aclocal.m4 | 1252 + buildconf | 8 + buildconf.bat | 319 + compile | 348 + config.guess | 1754 + config.sub | 1890 + configure | 48774 ++++++++++++++++ configure.ac | 4971 ++ curl-config.in | 196 + depcomp | 791 + docs/ALTSVC.md | 44 + docs/BINDINGS.md | 138 + docs/BUFREF.md | 81 + docs/BUG-BOUNTY.md | 78 + docs/BUGS.md | 265 + docs/CHECKSRC.md | 184 + docs/CIPHERS.md | 427 + docs/CLIENT-WRITERS.md | 104 + docs/CMakeLists.txt | 30 + docs/CODE_OF_CONDUCT.md | 32 + docs/CODE_REVIEW.md | 168 + docs/CODE_STYLE.md | 310 + docs/CONNECTION-FILTERS.md | 242 + docs/CONTRIBUTE.md | 316 + docs/CURL-DISABLE.md | 168 + docs/CURLDOWN.md | 125 + docs/DEPRECATE.md | 52 + docs/DYNBUF.md | 128 + docs/EARLY-RELEASE.md | 67 + docs/EXPERIMENTAL.md | 24 + docs/FAQ | 1561 + docs/FEATURES.md | 219 + docs/GOVERNANCE.md | 182 + docs/HELP-US.md | 89 + docs/HISTORY.md | 437 + docs/HSTS.md | 42 + docs/HTTP-COOKIES.md | 166 + docs/HTTP2.md | 102 + docs/HTTP3.md | 415 + docs/HYPER.md | 73 + docs/INSTALL | 9 + docs/INSTALL-CMAKE.md | 133 + docs/INSTALL.md | 576 + docs/INTERNALS.md | 56 + docs/KNOWN_BUGS | 610 + docs/MAIL-ETIQUETTE | 285 + docs/MQTT.md | 27 + docs/Makefile.am | 128 + docs/Makefile.in | 951 + docs/NEW-PROTOCOL.md | 110 + docs/PARALLEL-TRANSFERS.md | 50 + docs/README.md | 12 + docs/RELEASE-PROCEDURE.md | 117 + docs/ROADMAP.md | 24 + docs/RUSTLS.md | 26 + docs/SECURITY-ADVISORY.md | 129 + docs/SSL-PROBLEMS.md | 97 + docs/SSLCERTS.md | 155 + docs/THANKS | 3083 + docs/TODO | 1408 + docs/TheArtOfHttpScripting.md | 709 + docs/URL-SYNTAX.md | 391 + docs/VERSIONS.md | 57 + docs/VULN-DISCLOSURE-POLICY.md | 293 + docs/WEBSOCKET.md | 135 + docs/cmdline-opts/CMakeLists.txt | 37 + docs/cmdline-opts/MANPAGE.md | 110 + docs/cmdline-opts/Makefile.am | 44 + docs/cmdline-opts/Makefile.in | 916 + docs/cmdline-opts/Makefile.inc | 305 + docs/cmdline-opts/_AUTHORS.md | 5 + docs/cmdline-opts/_BUGS.md | 5 + docs/cmdline-opts/_DESCRIPTION.md | 11 + docs/cmdline-opts/_ENVIRONMENT.md | 114 + docs/cmdline-opts/_EXITCODES.md | 201 + docs/cmdline-opts/_FILES.md | 6 + docs/cmdline-opts/_GLOBBING.md | 40 + docs/cmdline-opts/_NAME.md | 4 + docs/cmdline-opts/_OPTIONS.md | 26 + docs/cmdline-opts/_OUTPUT.md | 11 + docs/cmdline-opts/_PROGRESS.md | 25 + docs/cmdline-opts/_PROTOCOLS.md | 51 + docs/cmdline-opts/_PROXYPREFIX.md | 22 + docs/cmdline-opts/_SEEALSO.md | 5 + docs/cmdline-opts/_SYNOPSIS.md | 5 + docs/cmdline-opts/_URL.md | 28 + docs/cmdline-opts/_VARIABLES.md | 44 + docs/cmdline-opts/_VERSION.md | 15 + docs/cmdline-opts/_WWW.md | 4 + docs/cmdline-opts/abstract-unix-socket.md | 21 + docs/cmdline-opts/alt-svc.md | 28 + docs/cmdline-opts/anyauth.md | 30 + docs/cmdline-opts/append.md | 23 + docs/cmdline-opts/aws-sigv4.md | 30 + docs/cmdline-opts/basic.md | 23 + docs/cmdline-opts/ca-native.md | 28 + docs/cmdline-opts/cacert.md | 42 + docs/cmdline-opts/capath.md | 28 + docs/cmdline-opts/cert-status.md | 25 + docs/cmdline-opts/cert-type.md | 26 + docs/cmdline-opts/cert.md | 56 + docs/cmdline-opts/ciphers.md | 24 + docs/cmdline-opts/compressed-ssh.md | 19 + docs/cmdline-opts/compressed.md | 27 + docs/cmdline-opts/config.md | 83 + docs/cmdline-opts/connect-timeout.md | 28 + docs/cmdline-opts/connect-to.md | 30 + docs/cmdline-opts/continue-at.md | 26 + docs/cmdline-opts/cookie-jar.md | 37 + docs/cmdline-opts/cookie.md | 58 + docs/cmdline-opts/create-dirs.md | 26 + docs/cmdline-opts/create-file-mode.md | 23 + docs/cmdline-opts/crlf.md | 21 + docs/cmdline-opts/crlfile.md | 21 + docs/cmdline-opts/curves.md | 28 + docs/cmdline-opts/data-ascii.md | 21 + docs/cmdline-opts/data-binary.md | 31 + docs/cmdline-opts/data-raw.md | 21 + docs/cmdline-opts/data-urlencode.md | 51 + docs/cmdline-opts/data.md | 49 + docs/cmdline-opts/delegation.md | 31 + docs/cmdline-opts/digest.md | 23 + docs/cmdline-opts/disable-eprt.md | 32 + docs/cmdline-opts/disable-epsv.md | 30 + docs/cmdline-opts/disable.md | 23 + docs/cmdline-opts/disallow-username-in-url.md | 18 + docs/cmdline-opts/dns-interface.md | 23 + docs/cmdline-opts/dns-ipv4-addr.md | 23 + docs/cmdline-opts/dns-ipv6-addr.md | 23 + docs/cmdline-opts/dns-servers.md | 24 + docs/cmdline-opts/doh-cert-status.md | 17 + docs/cmdline-opts/doh-insecure.md | 17 + docs/cmdline-opts/doh-url.md | 27 + docs/cmdline-opts/dump-header.md | 27 + docs/cmdline-opts/egd-file.md | 23 + docs/cmdline-opts/engine.md | 22 + docs/cmdline-opts/etag-compare.md | 30 + docs/cmdline-opts/etag-save.md | 22 + docs/cmdline-opts/expect100-timeout.md | 25 + docs/cmdline-opts/fail-early.md | 32 + docs/cmdline-opts/fail-with-body.md | 27 + docs/cmdline-opts/fail.md | 29 + docs/cmdline-opts/false-start.md | 24 + docs/cmdline-opts/form-escape.md | 19 + docs/cmdline-opts/form-string.md | 23 + docs/cmdline-opts/form.md | 142 + docs/cmdline-opts/ftp-account.md | 20 + docs/cmdline-opts/ftp-alternative-to-user.md | 23 + docs/cmdline-opts/ftp-create-dirs.md | 20 + docs/cmdline-opts/ftp-method.md | 36 + docs/cmdline-opts/ftp-pasv.md | 26 + docs/cmdline-opts/ftp-port.md | 51 + docs/cmdline-opts/ftp-pret.md | 21 + docs/cmdline-opts/ftp-skip-pasv-ip.md | 24 + docs/cmdline-opts/ftp-ssl-ccc-mode.md | 22 + docs/cmdline-opts/ftp-ssl-ccc.md | 22 + docs/cmdline-opts/ftp-ssl-control.md | 20 + docs/cmdline-opts/gen.pl | 965 + docs/cmdline-opts/get.md | 28 + docs/cmdline-opts/globoff.md | 22 + .../cmdline-opts/happy-eyeballs-timeout-ms.md | 28 + docs/cmdline-opts/haproxy-clientip.md | 33 + docs/cmdline-opts/haproxy-protocol.md | 23 + docs/cmdline-opts/head.md | 23 + docs/cmdline-opts/header.md | 64 + docs/cmdline-opts/help.md | 27 + docs/cmdline-opts/hostpubmd5.md | 21 + docs/cmdline-opts/hostpubsha256.md | 23 + docs/cmdline-opts/hsts.md | 32 + docs/cmdline-opts/http0.9.md | 27 + docs/cmdline-opts/http1.0.md | 23 + docs/cmdline-opts/http1.1.md | 21 + docs/cmdline-opts/http2-prior-knowledge.md | 25 + docs/cmdline-opts/http2.md | 33 + docs/cmdline-opts/http3-only.md | 32 + docs/cmdline-opts/http3.md | 33 + docs/cmdline-opts/ignore-content-length.md | 25 + docs/cmdline-opts/include.md | 26 + docs/cmdline-opts/insecure.md | 41 + docs/cmdline-opts/interface.md | 25 + docs/cmdline-opts/ipfs-gateway.md | 39 + docs/cmdline-opts/ipv4.md | 24 + docs/cmdline-opts/ipv6.md | 24 + docs/cmdline-opts/json.md | 42 + docs/cmdline-opts/junk-session-cookies.md | 22 + docs/cmdline-opts/keepalive-time.md | 28 + docs/cmdline-opts/key-type.md | 20 + docs/cmdline-opts/key.md | 34 + docs/cmdline-opts/krb.md | 23 + docs/cmdline-opts/libcurl.md | 21 + docs/cmdline-opts/limit-rate.md | 37 + docs/cmdline-opts/list-only.md | 43 + docs/cmdline-opts/local-port.md | 21 + docs/cmdline-opts/location-trusted.md | 21 + docs/cmdline-opts/location.md | 40 + docs/cmdline-opts/login-options.md | 32 + docs/cmdline-opts/mail-auth.md | 21 + docs/cmdline-opts/mail-from.md | 20 + docs/cmdline-opts/mail-rcpt-allowfails.md | 28 + docs/cmdline-opts/mail-rcpt.md | 28 + docs/cmdline-opts/mainpage.idx | 43 + docs/cmdline-opts/manual.md | 20 + docs/cmdline-opts/max-filesize.md | 32 + docs/cmdline-opts/max-redirs.md | 21 + docs/cmdline-opts/max-time.md | 30 + docs/cmdline-opts/metalink.md | 18 + docs/cmdline-opts/negotiate.md | 28 + docs/cmdline-opts/netrc-file.md | 25 + docs/cmdline-opts/netrc-optional.md | 19 + docs/cmdline-opts/netrc.md | 38 + docs/cmdline-opts/next.md | 34 + docs/cmdline-opts/no-alpn.md | 26 + docs/cmdline-opts/no-buffer.md | 24 + docs/cmdline-opts/no-clobber.md | 26 + docs/cmdline-opts/no-keepalive.md | 21 + docs/cmdline-opts/no-npn.md | 26 + docs/cmdline-opts/no-progress-meter.md | 22 + docs/cmdline-opts/no-sessionid.md | 25 + docs/cmdline-opts/noproxy.md | 33 + docs/cmdline-opts/ntlm-wb.md | 20 + docs/cmdline-opts/ntlm.md | 28 + docs/cmdline-opts/oauth2-bearer.md | 25 + docs/cmdline-opts/output-dir.md | 26 + docs/cmdline-opts/output.md | 57 + docs/cmdline-opts/parallel-immediate.md | 22 + docs/cmdline-opts/parallel-max.md | 24 + docs/cmdline-opts/parallel.md | 21 + docs/cmdline-opts/pass.md | 20 + docs/cmdline-opts/path-as-is.md | 19 + docs/cmdline-opts/pinnedpubkey.md | 44 + docs/cmdline-opts/post301.md | 24 + docs/cmdline-opts/post302.md | 24 + docs/cmdline-opts/post303.md | 23 + docs/cmdline-opts/preproxy.md | 33 + docs/cmdline-opts/progress-bar.md | 26 + docs/cmdline-opts/proto-default.md | 27 + docs/cmdline-opts/proto-redir.md | 28 + docs/cmdline-opts/proto.md | 48 + docs/cmdline-opts/proxy-anyauth.md | 20 + docs/cmdline-opts/proxy-basic.md | 21 + docs/cmdline-opts/proxy-ca-native.md | 28 + docs/cmdline-opts/proxy-cacert.md | 21 + docs/cmdline-opts/proxy-capath.md | 20 + docs/cmdline-opts/proxy-cert-type.md | 18 + docs/cmdline-opts/proxy-cert.md | 18 + docs/cmdline-opts/proxy-ciphers.md | 26 + docs/cmdline-opts/proxy-crlfile.md | 19 + docs/cmdline-opts/proxy-digest.md | 20 + docs/cmdline-opts/proxy-header.md | 38 + docs/cmdline-opts/proxy-http2.md | 24 + docs/cmdline-opts/proxy-insecure.md | 18 + docs/cmdline-opts/proxy-key-type.md | 19 + docs/cmdline-opts/proxy-key.md | 19 + docs/cmdline-opts/proxy-negotiate.md | 20 + docs/cmdline-opts/proxy-ntlm.md | 19 + docs/cmdline-opts/proxy-pass.md | 19 + docs/cmdline-opts/proxy-pinnedpubkey.md | 29 + docs/cmdline-opts/proxy-service-name.md | 19 + docs/cmdline-opts/proxy-ssl-allow-beast.md | 18 + .../proxy-ssl-auto-client-cert.md | 18 + docs/cmdline-opts/proxy-tls13-ciphers.md | 29 + docs/cmdline-opts/proxy-tlsauthtype.md | 19 + docs/cmdline-opts/proxy-tlspassword.md | 19 + docs/cmdline-opts/proxy-tlsuser.md | 19 + docs/cmdline-opts/proxy-tlsv1.md | 17 + docs/cmdline-opts/proxy-user.md | 29 + docs/cmdline-opts/proxy.md | 58 + docs/cmdline-opts/proxy1.0.md | 25 + docs/cmdline-opts/proxytunnel.md | 24 + docs/cmdline-opts/pubkey.md | 25 + docs/cmdline-opts/quote.md | 90 + docs/cmdline-opts/random-file.md | 22 + docs/cmdline-opts/range.md | 57 + docs/cmdline-opts/rate.md | 42 + docs/cmdline-opts/raw.md | 19 + docs/cmdline-opts/referer.md | 27 + docs/cmdline-opts/remote-header-name.md | 40 + docs/cmdline-opts/remote-name-all.md | 20 + docs/cmdline-opts/remote-name.md | 36 + docs/cmdline-opts/remote-time.md | 21 + docs/cmdline-opts/remove-on-error.md | 21 + docs/cmdline-opts/request-target.md | 25 + docs/cmdline-opts/request.md | 57 + docs/cmdline-opts/resolve.md | 46 + docs/cmdline-opts/retry-all-errors.md | 40 + docs/cmdline-opts/retry-connrefused.md | 19 + docs/cmdline-opts/retry-delay.md | 21 + docs/cmdline-opts/retry-max-time.md | 23 + docs/cmdline-opts/retry.md | 31 + docs/cmdline-opts/sasl-authzid.md | 25 + docs/cmdline-opts/sasl-ir.md | 17 + docs/cmdline-opts/service-name.md | 19 + docs/cmdline-opts/show-error.md | 19 + docs/cmdline-opts/silent.md | 25 + docs/cmdline-opts/socks4.md | 36 + docs/cmdline-opts/socks4a.md | 35 + docs/cmdline-opts/socks5-basic.md | 19 + docs/cmdline-opts/socks5-gssapi-nec.md | 20 + docs/cmdline-opts/socks5-gssapi-service.md | 19 + docs/cmdline-opts/socks5-gssapi.md | 20 + docs/cmdline-opts/socks5-hostname.md | 34 + docs/cmdline-opts/socks5.md | 36 + docs/cmdline-opts/speed-limit.md | 23 + docs/cmdline-opts/speed-time.md | 25 + docs/cmdline-opts/ssl-allow-beast.md | 25 + docs/cmdline-opts/ssl-auto-client-cert.md | 21 + docs/cmdline-opts/ssl-no-revoke.md | 20 + docs/cmdline-opts/ssl-reqd.md | 30 + docs/cmdline-opts/ssl-revoke-best-effort.md | 21 + docs/cmdline-opts/ssl.md | 34 + docs/cmdline-opts/sslv2.md | 24 + docs/cmdline-opts/sslv3.md | 24 + docs/cmdline-opts/stderr.md | 21 + docs/cmdline-opts/styled-output.md | 23 + docs/cmdline-opts/suppress-connect-headers.md | 22 + docs/cmdline-opts/tcp-fastopen.md | 19 + docs/cmdline-opts/tcp-nodelay.md | 21 + docs/cmdline-opts/telnet-option.md | 28 + docs/cmdline-opts/tftp-blksize.md | 21 + docs/cmdline-opts/tftp-no-options.md | 22 + docs/cmdline-opts/time-cond.md | 34 + docs/cmdline-opts/tls-max.md | 44 + docs/cmdline-opts/tls13-ciphers.md | 29 + docs/cmdline-opts/tlsauthtype.md | 23 + docs/cmdline-opts/tlspassword.md | 22 + docs/cmdline-opts/tlsuser.md | 22 + docs/cmdline-opts/tlsv1.0.md | 22 + docs/cmdline-opts/tlsv1.1.md | 23 + docs/cmdline-opts/tlsv1.2.md | 23 + docs/cmdline-opts/tlsv1.3.md | 25 + docs/cmdline-opts/tlsv1.md | 24 + docs/cmdline-opts/tr-encoding.md | 19 + docs/cmdline-opts/trace-ascii.md | 31 + docs/cmdline-opts/trace-config.md | 28 + docs/cmdline-opts/trace-ids.md | 19 + docs/cmdline-opts/trace-time.md | 19 + docs/cmdline-opts/trace.md | 30 + docs/cmdline-opts/unix-socket.md | 19 + docs/cmdline-opts/upload-file.md | 52 + docs/cmdline-opts/url-query.md | 32 + docs/cmdline-opts/url.md | 33 + docs/cmdline-opts/use-ascii.md | 22 + docs/cmdline-opts/user-agent.md | 27 + docs/cmdline-opts/user.md | 51 + docs/cmdline-opts/variable.md | 58 + docs/cmdline-opts/verbose.md | 37 + docs/cmdline-opts/version.md | 120 + docs/cmdline-opts/write-out.md | 296 + docs/cmdline-opts/xattr.md | 23 + docs/curl-config.1 | 164 + docs/curl-config.md | 124 + docs/examples/.checksrc | 3 + docs/examples/10-at-a-time.c | 156 + docs/examples/Makefile.am | 73 + docs/examples/Makefile.example | 55 + docs/examples/Makefile.in | 2501 + docs/examples/Makefile.inc | 159 + docs/examples/Makefile.mk | 52 + docs/examples/README.md | 41 + docs/examples/address-scope.c | 62 + docs/examples/altsvc.c | 58 + docs/examples/anyauthput.c | 155 + docs/examples/cacertinmem.c | 183 + docs/examples/certinfo.c | 87 + docs/examples/chkspeed.c | 224 + docs/examples/connect-to.c | 70 + docs/examples/cookie_interface.c | 142 + docs/examples/crawler.c | 237 + docs/examples/debug.c | 155 + docs/examples/default-scheme.c | 57 + docs/examples/ephiperfifo.c | 547 + docs/examples/evhiperfifo.c | 450 + docs/examples/externalsocket.c | 173 + docs/examples/fileupload.c | 89 + docs/examples/ftp-wildcard.c | 152 + docs/examples/ftpget.c | 94 + docs/examples/ftpgetinfo.c | 93 + docs/examples/ftpgetresp.c | 79 + docs/examples/ftpsget.c | 101 + docs/examples/ftpupload.c | 142 + docs/examples/ftpuploadfrommem.c | 126 + docs/examples/ftpuploadresume.c | 167 + docs/examples/getinfo.c | 54 + docs/examples/getinmemory.c | 118 + docs/examples/getredirect.c | 72 + docs/examples/getreferrer.c | 59 + docs/examples/ghiper.c | 438 + docs/examples/headerapi.c | 81 + docs/examples/hiperfifo.c | 464 + docs/examples/href_extractor.c | 88 + docs/examples/hsts-preload.c | 118 + docs/examples/htmltidy.c | 130 + docs/examples/htmltitle.cpp | 296 + docs/examples/http-options.c | 59 + docs/examples/http-post.c | 61 + docs/examples/http2-download.c | 234 + docs/examples/http2-pushinmemory.c | 190 + docs/examples/http2-serverpush.c | 276 + docs/examples/http2-upload.c | 303 + docs/examples/http3-present.c | 49 + docs/examples/http3.c | 55 + docs/examples/httpcustomheader.c | 72 + docs/examples/httpput-postfields.c | 105 + docs/examples/httpput.c | 123 + docs/examples/https.c | 83 + docs/examples/imap-append.c | 130 + docs/examples/imap-authzid.c | 73 + docs/examples/imap-copy.c | 73 + docs/examples/imap-create.c | 69 + docs/examples/imap-delete.c | 69 + docs/examples/imap-examine.c | 69 + docs/examples/imap-fetch.c | 67 + docs/examples/imap-list.c | 68 + docs/examples/imap-lsub.c | 70 + docs/examples/imap-multi.c | 83 + docs/examples/imap-noop.c | 69 + docs/examples/imap-search.c | 73 + docs/examples/imap-ssl.c | 94 + docs/examples/imap-store.c | 84 + docs/examples/imap-tls.c | 94 + docs/examples/interface.c | 52 + docs/examples/ipv6.c | 48 + docs/examples/keepalive.c | 55 + docs/examples/localport.c | 53 + docs/examples/maxconnects.c | 66 + docs/examples/multi-app.c | 118 + docs/examples/multi-debugcallback.c | 165 + docs/examples/multi-double.c | 97 + docs/examples/multi-event.c | 242 + docs/examples/multi-formadd.c | 115 + docs/examples/multi-legacy.c | 179 + docs/examples/multi-post.c | 105 + docs/examples/multi-single.c | 84 + docs/examples/multi-uv.c | 237 + docs/examples/multithread.c | 96 + docs/examples/netrc.c | 49 + docs/examples/parseurl.c | 80 + docs/examples/persistent.c | 70 + docs/examples/pop3-authzid.c | 72 + docs/examples/pop3-dele.c | 72 + docs/examples/pop3-list.c | 66 + docs/examples/pop3-multi.c | 84 + docs/examples/pop3-noop.c | 72 + docs/examples/pop3-retr.c | 66 + docs/examples/pop3-ssl.c | 93 + docs/examples/pop3-stat.c | 72 + docs/examples/pop3-tls.c | 93 + docs/examples/pop3-top.c | 69 + docs/examples/pop3-uidl.c | 69 + docs/examples/post-callback.c | 156 + docs/examples/postinmemory.c | 114 + docs/examples/postit2-formadd.c | 112 + docs/examples/postit2.c | 104 + docs/examples/progressfunc.c | 97 + docs/examples/protofeats.c | 52 + docs/examples/range.c | 45 + docs/examples/resolve.c | 58 + docs/examples/rtsp-options.c | 55 + docs/examples/sendrecv.c | 173 + docs/examples/sepheaders.c | 96 + docs/examples/sessioninfo.c | 112 + docs/examples/sftpget.c | 112 + docs/examples/sftpuploadresume.c | 137 + docs/examples/shared-connection-cache.c | 87 + docs/examples/simple.c | 53 + docs/examples/simplepost.c | 59 + docs/examples/simplessl.c | 143 + docs/examples/smooth-gtk-thread.c | 218 + docs/examples/smtp-authzid.c | 162 + docs/examples/smtp-expn.c | 81 + docs/examples/smtp-mail.c | 150 + docs/examples/smtp-mime.c | 168 + docs/examples/smtp-multi.c | 153 + docs/examples/smtp-ssl.c | 170 + docs/examples/smtp-tls.c | 173 + docs/examples/smtp-vrfy.c | 81 + docs/examples/sslbackend.c | 79 + docs/examples/synctime.c | 377 + docs/examples/threaded-ssl.c | 168 + docs/examples/unixsocket.c | 67 + docs/examples/url2file.c | 88 + docs/examples/urlapi.c | 77 + docs/examples/usercertinmem.c | 228 + docs/examples/version-check.pl | 105 + docs/examples/websocket-cb.c | 68 + docs/examples/websocket.c | 131 + docs/examples/xmlstream.c | 168 + docs/libcurl/ABI.md | 68 + docs/libcurl/CMakeLists.txt | 69 + docs/libcurl/Makefile.am | 54 + docs/libcurl/Makefile.in | 1026 + docs/libcurl/Makefile.inc | 124 + docs/libcurl/curl_easy_cleanup.md | 76 + docs/libcurl/curl_easy_duphandle.md | 72 + docs/libcurl/curl_easy_escape.md | 75 + docs/libcurl/curl_easy_getinfo.md | 483 + docs/libcurl/curl_easy_header.md | 160 + docs/libcurl/curl_easy_init.md | 73 + docs/libcurl/curl_easy_nextheader.md | 100 + docs/libcurl/curl_easy_option_by_id.md | 54 + docs/libcurl/curl_easy_option_by_name.md | 53 + docs/libcurl/curl_easy_option_next.md | 89 + docs/libcurl/curl_easy_pause.md | 140 + docs/libcurl/curl_easy_perform.md | 83 + docs/libcurl/curl_easy_recv.md | 103 + docs/libcurl/curl_easy_reset.md | 56 + docs/libcurl/curl_easy_send.md | 95 + docs/libcurl/curl_easy_setopt.md | 1381 + docs/libcurl/curl_easy_strerror.md | 59 + docs/libcurl/curl_easy_unescape.md | 73 + docs/libcurl/curl_easy_upkeep.md | 77 + docs/libcurl/curl_escape.md | 58 + docs/libcurl/curl_formadd.md | 313 + docs/libcurl/curl_formfree.md | 76 + docs/libcurl/curl_formget.md | 72 + docs/libcurl/curl_free.md | 52 + docs/libcurl/curl_getdate.md | 128 + docs/libcurl/curl_getenv.md | 57 + docs/libcurl/curl_global_cleanup.md | 74 + docs/libcurl/curl_global_init.md | 131 + docs/libcurl/curl_global_init_mem.md | 95 + docs/libcurl/curl_global_sslset.md | 138 + docs/libcurl/curl_global_trace.md | 124 + docs/libcurl/curl_mime_addpart.md | 70 + docs/libcurl/curl_mime_data.md | 76 + docs/libcurl/curl_mime_data_cb.md | 168 + docs/libcurl/curl_mime_encoder.md | 100 + docs/libcurl/curl_mime_filedata.md | 88 + docs/libcurl/curl_mime_filename.md | 79 + docs/libcurl/curl_mime_free.md | 65 + docs/libcurl/curl_mime_headers.md | 78 + docs/libcurl/curl_mime_init.md | 72 + docs/libcurl/curl_mime_name.md | 67 + docs/libcurl/curl_mime_subparts.md | 83 + docs/libcurl/curl_mime_type.md | 86 + docs/libcurl/curl_mprintf.md | 288 + docs/libcurl/curl_multi_add_handle.md | 88 + docs/libcurl/curl_multi_assign.md | 81 + docs/libcurl/curl_multi_cleanup.md | 65 + docs/libcurl/curl_multi_fdset.md | 119 + docs/libcurl/curl_multi_get_handles.md | 77 + docs/libcurl/curl_multi_info_read.md | 102 + docs/libcurl/curl_multi_init.md | 57 + docs/libcurl/curl_multi_perform.md | 107 + docs/libcurl/curl_multi_poll.md | 128 + docs/libcurl/curl_multi_remove_handle.md | 73 + docs/libcurl/curl_multi_setopt.md | 125 + docs/libcurl/curl_multi_socket.md | 95 + docs/libcurl/curl_multi_socket_action.md | 120 + docs/libcurl/curl_multi_socket_all.md | 95 + docs/libcurl/curl_multi_strerror.md | 51 + docs/libcurl/curl_multi_timeout.md | 89 + docs/libcurl/curl_multi_wait.md | 121 + docs/libcurl/curl_multi_wakeup.md | 91 + docs/libcurl/curl_pushheader_byname.md | 82 + docs/libcurl/curl_pushheader_bynum.md | 69 + docs/libcurl/curl_share_cleanup.md | 54 + docs/libcurl/curl_share_init.md | 56 + docs/libcurl/curl_share_setopt.md | 71 + docs/libcurl/curl_share_strerror.md | 50 + docs/libcurl/curl_slist_append.md | 75 + docs/libcurl/curl_slist_free_all.md | 58 + docs/libcurl/curl_strequal.md | 57 + docs/libcurl/curl_strnequal.md | 57 + docs/libcurl/curl_unescape.md | 65 + docs/libcurl/curl_url.md | 64 + docs/libcurl/curl_url_cleanup.md | 51 + docs/libcurl/curl_url_dup.md | 56 + docs/libcurl/curl_url_get.md | 210 + docs/libcurl/curl_url_set.md | 247 + docs/libcurl/curl_url_strerror.md | 53 + docs/libcurl/curl_version.md | 46 + docs/libcurl/curl_version_info.md | 381 + docs/libcurl/curl_ws_meta.md | 143 + docs/libcurl/curl_ws_recv.md | 73 + docs/libcurl/curl_ws_send.md | 120 + docs/libcurl/libcurl-easy.md | 52 + docs/libcurl/libcurl-env-dbg.md | 118 + docs/libcurl/libcurl-env.md | 99 + docs/libcurl/libcurl-errors.md | 757 + docs/libcurl/libcurl-multi.md | 178 + docs/libcurl/libcurl-security.md | 487 + docs/libcurl/libcurl-share.md | 62 + docs/libcurl/libcurl-symbols.md | 3405 ++ docs/libcurl/libcurl-thread.md | 99 + docs/libcurl/libcurl-tutorial.md | 1451 + docs/libcurl/libcurl-url.md | 162 + docs/libcurl/libcurl-ws.md | 123 + docs/libcurl/libcurl.m4 | 274 + docs/libcurl/libcurl.md | 247 + docs/libcurl/mksymbolsmanpage.pl | 311 + docs/libcurl/opts/CMakeLists.txt | 34 + docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md | 77 + docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md | 71 + .../opts/CURLINFO_APPCONNECT_TIME_T.md | 73 + docs/libcurl/opts/CURLINFO_CAINFO.md | 66 + docs/libcurl/opts/CURLINFO_CAPATH.md | 66 + docs/libcurl/opts/CURLINFO_CERTINFO.md | 101 + docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md | 80 + docs/libcurl/opts/CURLINFO_CONNECT_TIME.md | 67 + docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md | 70 + docs/libcurl/opts/CURLINFO_CONN_ID.md | 70 + .../opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md | 70 + .../CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md | 67 + .../opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md | 69 + .../opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md | 66 + docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md | 75 + docs/libcurl/opts/CURLINFO_COOKIELIST.md | 82 + .../libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md | 72 + docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md | 68 + docs/libcurl/opts/CURLINFO_FILETIME.md | 76 + docs/libcurl/opts/CURLINFO_FILETIME_T.md | 78 + docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md | 70 + docs/libcurl/opts/CURLINFO_HEADER_SIZE.md | 65 + docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md | 77 + .../libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md | 65 + docs/libcurl/opts/CURLINFO_HTTP_VERSION.md | 61 + docs/libcurl/opts/CURLINFO_LASTSOCKET.md | 77 + docs/libcurl/opts/CURLINFO_LOCAL_IP.md | 72 + docs/libcurl/opts/CURLINFO_LOCAL_PORT.md | 68 + docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md | 68 + .../opts/CURLINFO_NAMELOOKUP_TIME_T.md | 69 + docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md | 65 + docs/libcurl/opts/CURLINFO_OS_ERRNO.md | 62 + .../libcurl/opts/CURLINFO_PRETRANSFER_TIME.md | 73 + .../opts/CURLINFO_PRETRANSFER_TIME_T.md | 75 + docs/libcurl/opts/CURLINFO_PRIMARY_IP.md | 73 + docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md | 67 + docs/libcurl/opts/CURLINFO_PRIVATE.md | 68 + docs/libcurl/opts/CURLINFO_PROTOCOL.md | 73 + docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md | 78 + docs/libcurl/opts/CURLINFO_PROXY_ERROR.md | 105 + .../opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md | 64 + docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md | 70 + docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md | 62 + docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md | 70 + docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md | 72 + docs/libcurl/opts/CURLINFO_REDIRECT_URL.md | 69 + docs/libcurl/opts/CURLINFO_REFERER.md | 67 + docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md | 63 + docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md | 65 + docs/libcurl/opts/CURLINFO_RETRY_AFTER.md | 71 + .../libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md | 61 + docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md | 61 + .../libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md | 65 + docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md | 66 + docs/libcurl/opts/CURLINFO_SCHEME.md | 68 + docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md | 73 + docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md | 70 + docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md | 69 + docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md | 66 + docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md | 67 + .../libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md | 65 + docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md | 65 + docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md | 63 + docs/libcurl/opts/CURLINFO_SSL_ENGINES.md | 65 + .../libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md | 65 + .../opts/CURLINFO_STARTTRANSFER_TIME.md | 71 + .../opts/CURLINFO_STARTTRANSFER_TIME_T.md | 73 + docs/libcurl/opts/CURLINFO_TLS_SESSION.md | 75 + docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md | 174 + docs/libcurl/opts/CURLINFO_TOTAL_TIME.md | 69 + docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md | 71 + docs/libcurl/opts/CURLINFO_XFER_ID.md | 70 + .../CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md | 61 + .../CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md | 60 + docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md | 69 + .../opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md | 59 + .../opts/CURLMOPT_MAX_HOST_CONNECTIONS.md | 72 + .../opts/CURLMOPT_MAX_PIPELINE_LENGTH.md | 64 + .../opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md | 70 + docs/libcurl/opts/CURLMOPT_PIPELINING.md | 77 + .../opts/CURLMOPT_PIPELINING_SERVER_BL.md | 68 + .../opts/CURLMOPT_PIPELINING_SITE_BL.md | 66 + docs/libcurl/opts/CURLMOPT_PUSHDATA.md | 87 + docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md | 148 + docs/libcurl/opts/CURLMOPT_SOCKETDATA.md | 82 + docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md | 135 + docs/libcurl/opts/CURLMOPT_TIMERDATA.md | 75 + docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md | 103 + .../opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md | 71 + docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md | 61 + docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md | 110 + docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md | 63 + docs/libcurl/opts/CURLOPT_ALTSVC.md | 111 + docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md | 97 + docs/libcurl/opts/CURLOPT_APPEND.md | 61 + docs/libcurl/opts/CURLOPT_AUTOREFERER.md | 77 + docs/libcurl/opts/CURLOPT_AWS_SIGV4.md | 118 + docs/libcurl/opts/CURLOPT_BUFFERSIZE.md | 79 + docs/libcurl/opts/CURLOPT_CAINFO.md | 87 + docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md | 84 + docs/libcurl/opts/CURLOPT_CAPATH.md | 79 + docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md | 82 + docs/libcurl/opts/CURLOPT_CERTINFO.md | 90 + .../opts/CURLOPT_CHUNK_BGN_FUNCTION.md | 152 + docs/libcurl/opts/CURLOPT_CHUNK_DATA.md | 102 + .../opts/CURLOPT_CHUNK_END_FUNCTION.md | 82 + docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md | 75 + .../opts/CURLOPT_CLOSESOCKETFUNCTION.md | 86 + docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md | 89 + .../libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md | 64 + docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md | 83 + docs/libcurl/opts/CURLOPT_CONNECT_TO.md | 114 + .../CURLOPT_CONV_FROM_NETWORK_FUNCTION.md | 114 + .../opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md | 107 + .../opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md | 110 + docs/libcurl/opts/CURLOPT_COOKIE.md | 97 + docs/libcurl/opts/CURLOPT_COOKIEFILE.md | 103 + docs/libcurl/opts/CURLOPT_COOKIEJAR.md | 86 + docs/libcurl/opts/CURLOPT_COOKIELIST.md | 136 + docs/libcurl/opts/CURLOPT_COOKIESESSION.md | 75 + docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md | 78 + docs/libcurl/opts/CURLOPT_CRLF.md | 62 + docs/libcurl/opts/CURLOPT_CRLFILE.md | 82 + docs/libcurl/opts/CURLOPT_CURLU.md | 79 + docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md | 130 + docs/libcurl/opts/CURLOPT_DEBUGDATA.md | 86 + docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md | 216 + docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md | 89 + docs/libcurl/opts/CURLOPT_DIRLISTONLY.md | 80 + .../opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md | 68 + .../libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md | 90 + docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md | 69 + docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md | 70 + docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md | 70 + docs/libcurl/opts/CURLOPT_DNS_SERVERS.md | 76 + .../opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md | 75 + .../opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md | 68 + .../opts/CURLOPT_DOH_SSL_VERIFYHOST.md | 90 + .../opts/CURLOPT_DOH_SSL_VERIFYPEER.md | 102 + .../opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md | 76 + docs/libcurl/opts/CURLOPT_DOH_URL.md | 96 + docs/libcurl/opts/CURLOPT_EGDSOCKET.md | 67 + docs/libcurl/opts/CURLOPT_ERRORBUFFER.md | 101 + .../opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md | 64 + docs/libcurl/opts/CURLOPT_FAILONERROR.md | 74 + docs/libcurl/opts/CURLOPT_FILETIME.md | 72 + docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md | 80 + docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md | 88 + docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md | 93 + docs/libcurl/opts/CURLOPT_FORBID_REUSE.md | 69 + docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md | 68 + docs/libcurl/opts/CURLOPT_FTPPORT.md | 99 + docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md | 76 + docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md | 67 + .../opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md | 70 + .../opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md | 88 + docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md | 86 + docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md | 72 + docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md | 78 + docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md | 73 + docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md | 73 + docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md | 66 + .../libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md | 65 + .../opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md | 71 + docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md | 64 + .../libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md | 63 + docs/libcurl/opts/CURLOPT_HEADER.md | 76 + docs/libcurl/opts/CURLOPT_HEADERDATA.md | 89 + docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md | 132 + docs/libcurl/opts/CURLOPT_HEADEROPT.md | 81 + docs/libcurl/opts/CURLOPT_HSTS.md | 83 + docs/libcurl/opts/CURLOPT_HSTSREADDATA.md | 72 + docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md | 106 + docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md | 72 + .../libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md | 110 + docs/libcurl/opts/CURLOPT_HSTS_CTRL.md | 78 + docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md | 64 + docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md | 75 + docs/libcurl/opts/CURLOPT_HTTPAUTH.md | 163 + docs/libcurl/opts/CURLOPT_HTTPGET.md | 71 + docs/libcurl/opts/CURLOPT_HTTPHEADER.md | 181 + docs/libcurl/opts/CURLOPT_HTTPPOST.md | 100 + docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md | 75 + .../opts/CURLOPT_HTTP_CONTENT_DECODING.md | 62 + .../opts/CURLOPT_HTTP_TRANSFER_DECODING.md | 61 + docs/libcurl/opts/CURLOPT_HTTP_VERSION.md | 119 + .../opts/CURLOPT_IGNORE_CONTENT_LENGTH.md | 73 + docs/libcurl/opts/CURLOPT_INFILESIZE.md | 85 + docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md | 81 + docs/libcurl/opts/CURLOPT_INTERFACE.md | 83 + docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md | 72 + .../opts/CURLOPT_INTERLEAVEFUNCTION.md | 102 + docs/libcurl/opts/CURLOPT_IOCTLDATA.md | 72 + docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md | 103 + docs/libcurl/opts/CURLOPT_IPRESOLVE.md | 83 + docs/libcurl/opts/CURLOPT_ISSUERCERT.md | 77 + docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md | 92 + .../opts/CURLOPT_KEEP_SENDING_ON_ERROR.md | 68 + docs/libcurl/opts/CURLOPT_KEYPASSWD.md | 68 + docs/libcurl/opts/CURLOPT_KRBLEVEL.md | 66 + docs/libcurl/opts/CURLOPT_LOCALPORT.md | 64 + docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md | 67 + docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md | 76 + docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md | 70 + docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md | 67 + docs/libcurl/opts/CURLOPT_MAIL_AUTH.md | 76 + docs/libcurl/opts/CURLOPT_MAIL_FROM.md | 69 + docs/libcurl/opts/CURLOPT_MAIL_RCPT.md | 80 + .../opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md | 81 + docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md | 71 + docs/libcurl/opts/CURLOPT_MAXCONNECTS.md | 75 + docs/libcurl/opts/CURLOPT_MAXFILESIZE.md | 69 + .../libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md | 70 + docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md | 73 + docs/libcurl/opts/CURLOPT_MAXREDIRS.md | 72 + .../opts/CURLOPT_MAX_RECV_SPEED_LARGE.md | 70 + .../opts/CURLOPT_MAX_SEND_SPEED_LARGE.md | 72 + docs/libcurl/opts/CURLOPT_MIMEPOST.md | 81 + docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md | 97 + docs/libcurl/opts/CURLOPT_NETRC.md | 141 + docs/libcurl/opts/CURLOPT_NETRC_FILE.md | 66 + .../opts/CURLOPT_NEW_DIRECTORY_PERMS.md | 64 + docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md | 60 + docs/libcurl/opts/CURLOPT_NOBODY.md | 78 + docs/libcurl/opts/CURLOPT_NOPROGRESS.md | 65 + docs/libcurl/opts/CURLOPT_NOPROXY.md | 91 + docs/libcurl/opts/CURLOPT_NOSIGNAL.md | 78 + docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md | 92 + .../opts/CURLOPT_OPENSOCKETFUNCTION.md | 132 + docs/libcurl/opts/CURLOPT_PASSWORD.md | 71 + docs/libcurl/opts/CURLOPT_PATH_AS_IS.md | 75 + docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md | 143 + docs/libcurl/opts/CURLOPT_PIPEWAIT.md | 78 + docs/libcurl/opts/CURLOPT_PORT.md | 72 + docs/libcurl/opts/CURLOPT_POST.md | 102 + docs/libcurl/opts/CURLOPT_POSTFIELDS.md | 124 + docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md | 71 + .../opts/CURLOPT_POSTFIELDSIZE_LARGE.md | 72 + docs/libcurl/opts/CURLOPT_POSTQUOTE.md | 72 + docs/libcurl/opts/CURLOPT_POSTREDIR.md | 81 + docs/libcurl/opts/CURLOPT_PREQUOTE.md | 76 + docs/libcurl/opts/CURLOPT_PREREQDATA.md | 73 + docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md | 125 + docs/libcurl/opts/CURLOPT_PRE_PROXY.md | 84 + docs/libcurl/opts/CURLOPT_PRIVATE.md | 72 + docs/libcurl/opts/CURLOPT_PROGRESSDATA.md | 80 + docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md | 125 + docs/libcurl/opts/CURLOPT_PROTOCOLS.md | 104 + docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md | 88 + docs/libcurl/opts/CURLOPT_PROXY.md | 146 + docs/libcurl/opts/CURLOPT_PROXYAUTH.md | 77 + docs/libcurl/opts/CURLOPT_PROXYHEADER.md | 80 + docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md | 70 + docs/libcurl/opts/CURLOPT_PROXYPORT.md | 68 + docs/libcurl/opts/CURLOPT_PROXYTYPE.md | 99 + docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md | 73 + docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md | 71 + docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md | 93 + .../libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md | 92 + docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md | 81 + docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md | 83 + docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md | 82 + .../opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md | 95 + docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md | 70 + .../opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md | 124 + .../opts/CURLOPT_PROXY_SERVICE_NAME.md | 65 + docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md | 79 + .../libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md | 75 + .../opts/CURLOPT_PROXY_SSLCERT_BLOB.md | 85 + docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md | 77 + docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md | 66 + .../libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md | 86 + docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md | 125 + .../opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md | 91 + .../libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md | 119 + .../opts/CURLOPT_PROXY_SSL_VERIFYHOST.md | 94 + .../opts/CURLOPT_PROXY_SSL_VERIFYPEER.md | 94 + .../opts/CURLOPT_PROXY_TLS13_CIPHERS.md | 78 + .../opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md | 71 + .../opts/CURLOPT_PROXY_TLSAUTH_TYPE.md | 80 + .../opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md | 71 + .../opts/CURLOPT_PROXY_TRANSFER_MODE.md | 69 + docs/libcurl/opts/CURLOPT_PUT.md | 89 + docs/libcurl/opts/CURLOPT_QUICK_EXIT.md | 62 + docs/libcurl/opts/CURLOPT_QUOTE.md | 161 + docs/libcurl/opts/CURLOPT_RANDOM_FILE.md | 67 + docs/libcurl/opts/CURLOPT_RANGE.md | 84 + docs/libcurl/opts/CURLOPT_READDATA.md | 77 + docs/libcurl/opts/CURLOPT_READFUNCTION.md | 123 + docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md | 115 + .../opts/CURLOPT_REDIR_PROTOCOLS_STR.md | 94 + docs/libcurl/opts/CURLOPT_REFERER.md | 67 + docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md | 67 + docs/libcurl/opts/CURLOPT_RESOLVE.md | 115 + .../opts/CURLOPT_RESOLVER_START_DATA.md | 70 + .../opts/CURLOPT_RESOLVER_START_FUNCTION.md | 88 + docs/libcurl/opts/CURLOPT_RESUME_FROM.md | 80 + .../libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md | 79 + docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md | 62 + docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md | 139 + docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md | 61 + docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md | 68 + docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md | 72 + docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md | 68 + docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md | 72 + docs/libcurl/opts/CURLOPT_SASL_IR.md | 72 + docs/libcurl/opts/CURLOPT_SEEKDATA.md | 71 + docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md | 102 + .../opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md | 75 + .../CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md | 74 + docs/libcurl/opts/CURLOPT_SERVICE_NAME.md | 66 + docs/libcurl/opts/CURLOPT_SHARE.md | 88 + docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md | 75 + docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md | 132 + docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md | 69 + .../libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md | 63 + .../opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md | 68 + docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md | 67 + docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md | 64 + docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md | 73 + .../opts/CURLOPT_SSH_HOSTKEYFUNCTION.md | 98 + .../opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md | 71 + .../CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md | 65 + docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md | 75 + docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md | 152 + docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md | 68 + .../opts/CURLOPT_SSH_PRIVATE_KEYFILE.md | 76 + .../opts/CURLOPT_SSH_PUBLIC_KEYFILE.md | 71 + docs/libcurl/opts/CURLOPT_SSLCERT.md | 87 + docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md | 71 + docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md | 83 + docs/libcurl/opts/CURLOPT_SSLENGINE.md | 74 + .../libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md | 70 + docs/libcurl/opts/CURLOPT_SSLKEY.md | 71 + docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md | 72 + docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md | 87 + docs/libcurl/opts/CURLOPT_SSLVERSION.md | 143 + docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md | 92 + docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md | 124 + docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md | 167 + docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md | 61 + docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md | 60 + docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md | 62 + docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md | 62 + docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md | 116 + .../opts/CURLOPT_SSL_SESSIONID_CACHE.md | 66 + docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md | 114 + docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md | 98 + docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md | 68 + docs/libcurl/opts/CURLOPT_STDERR.md | 65 + docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md | 77 + docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md | 80 + docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md | 81 + .../opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md | 103 + docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md | 64 + docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md | 71 + docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md | 70 + docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md | 69 + docs/libcurl/opts/CURLOPT_TCP_NODELAY.md | 71 + docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md | 66 + docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md | 63 + docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md | 78 + docs/libcurl/opts/CURLOPT_TIMECONDITION.md | 72 + docs/libcurl/opts/CURLOPT_TIMEOUT.md | 90 + docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md | 64 + docs/libcurl/opts/CURLOPT_TIMEVALUE.md | 69 + docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md | 71 + docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md | 80 + docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md | 70 + docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md | 75 + docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md | 69 + docs/libcurl/opts/CURLOPT_TRAILERDATA.md | 59 + docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md | 110 + docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md | 65 + .../libcurl/opts/CURLOPT_TRANSFER_ENCODING.md | 68 + docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md | 87 + .../libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md | 78 + .../opts/CURLOPT_UPKEEP_INTERVAL_MS.md | 82 + docs/libcurl/opts/CURLOPT_UPLOAD.md | 97 + .../libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md | 80 + docs/libcurl/opts/CURLOPT_URL.md | 145 + docs/libcurl/opts/CURLOPT_USERAGENT.md | 66 + docs/libcurl/opts/CURLOPT_USERNAME.md | 92 + docs/libcurl/opts/CURLOPT_USERPWD.md | 98 + docs/libcurl/opts/CURLOPT_USE_SSL.md | 86 + docs/libcurl/opts/CURLOPT_VERBOSE.md | 71 + docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md | 111 + docs/libcurl/opts/CURLOPT_WRITEDATA.md | 63 + docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md | 136 + docs/libcurl/opts/CURLOPT_WS_OPTIONS.md | 75 + docs/libcurl/opts/CURLOPT_XFERINFODATA.md | 80 + docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md | 120 + docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md | 67 + docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md | 77 + docs/libcurl/opts/CURLSHOPT_SHARE.md | 117 + docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md | 72 + docs/libcurl/opts/CURLSHOPT_UNSHARE.md | 84 + docs/libcurl/opts/CURLSHOPT_USERDATA.md | 62 + docs/libcurl/opts/Makefile.am | 44 + docs/libcurl/opts/Makefile.in | 1115 + docs/libcurl/opts/Makefile.inc | 424 + docs/libcurl/symbols-in-versions | 1147 + docs/libcurl/symbols.pl | 102 + docs/mk-ca-bundle.md | 128 + docs/options-in-versions | 270 + include/Makefile.am | 28 + include/Makefile.in | 775 + include/README.md | 20 + include/curl/Makefile.am | 41 + include/curl/Makefile.in | 726 + include/curl/curl.h | 3239 + include/curl/curlver.h | 79 + include/curl/easy.h | 125 + include/curl/header.h | 74 + include/curl/mprintf.h | 78 + include/curl/multi.h | 471 + include/curl/options.h | 70 + include/curl/stdcheaders.h | 35 + include/curl/system.h | 496 + include/curl/typecheck-gcc.h | 717 + include/curl/urlapi.h | 151 + include/curl/websockets.h | 84 + install-sh | 541 + lib/.checksrc | 1 + lib/CMakeLists.txt | 240 + lib/Makefile.am | 149 + lib/Makefile.in | 5422 ++ lib/Makefile.inc | 374 + lib/Makefile.mk | 334 + lib/Makefile.soname | 42 + lib/altsvc.c | 716 + lib/altsvc.h | 81 + lib/amigaos.c | 247 + lib/amigaos.h | 41 + lib/arpa_telnet.h | 117 + lib/asyn-ares.c | 958 + lib/asyn-thread.c | 985 + lib/asyn.h | 184 + lib/base64.c | 293 + lib/bufq.c | 656 + lib/bufq.h | 265 + lib/bufref.c | 127 + lib/bufref.h | 48 + lib/c-hyper.c | 1250 + lib/c-hyper.h | 59 + lib/cf-h1-proxy.c | 1095 + lib/cf-h1-proxy.h | 39 + lib/cf-h2-proxy.c | 1567 + lib/cf-h2-proxy.h | 39 + lib/cf-haproxy.c | 245 + lib/cf-haproxy.h | 39 + lib/cf-https-connect.c | 531 + lib/cf-https-connect.h | 58 + lib/cf-socket.c | 1985 + lib/cf-socket.h | 174 + lib/cfilters.c | 788 + lib/cfilters.h | 611 + lib/config-amigaos.h | 129 + lib/config-dos.h | 138 + lib/config-mac.h | 103 + lib/config-os400.h | 334 + lib/config-plan9.h | 147 + lib/config-riscos.h | 280 + lib/config-win32.h | 516 + lib/config-win32ce.h | 303 + lib/conncache.c | 588 + lib/conncache.h | 122 + lib/connect.c | 1439 + lib/connect.h | 132 + lib/content_encoding.c | 1052 + lib/content_encoding.h | 34 + lib/cookie.c | 1783 + lib/cookie.h | 138 + lib/curl_addrinfo.c | 592 + lib/curl_addrinfo.h | 108 + lib/curl_base64.h | 41 + lib/curl_config.h.cmake | 795 + lib/curl_config.h.in | 992 + lib/curl_ctype.h | 51 + lib/curl_des.c | 69 + lib/curl_des.h | 40 + lib/curl_endian.c | 84 + lib/curl_endian.h | 36 + lib/curl_fnmatch.c | 390 + lib/curl_fnmatch.h | 46 + lib/curl_get_line.c | 86 + lib/curl_get_line.h | 31 + lib/curl_gethostname.c | 102 + lib/curl_gethostname.h | 33 + lib/curl_gssapi.c | 152 + lib/curl_gssapi.h | 63 + lib/curl_hmac.h | 78 + lib/curl_krb5.h | 52 + lib/curl_ldap.h | 36 + lib/curl_md4.h | 39 + lib/curl_md5.h | 67 + lib/curl_memory.h | 178 + lib/curl_memrchr.c | 64 + lib/curl_memrchr.h | 44 + lib/curl_multibyte.c | 179 + lib/curl_multibyte.h | 91 + lib/curl_ntlm_core.c | 669 + lib/curl_ntlm_core.h | 79 + lib/curl_ntlm_wb.c | 500 + lib/curl_ntlm_wb.h | 45 + lib/curl_path.c | 199 + lib/curl_path.h | 49 + lib/curl_printf.h | 55 + lib/curl_range.c | 96 + lib/curl_range.h | 31 + lib/curl_rtmp.c | 338 + lib/curl_rtmp.h | 35 + lib/curl_sasl.c | 760 + lib/curl_sasl.h | 165 + lib/curl_setup.h | 868 + lib/curl_setup_once.h | 418 + lib/curl_sha256.h | 50 + lib/curl_sspi.c | 239 + lib/curl_sspi.h | 123 + lib/curl_threads.c | 153 + lib/curl_threads.h | 65 + lib/curl_trc.c | 243 + lib/curl_trc.h | 127 + lib/curlx.h | 118 + lib/dict.c | 323 + lib/dict.h | 31 + lib/doh.c | 995 + lib/doh.h | 128 + lib/dynbuf.c | 282 + lib/dynbuf.h | 93 + lib/dynhds.c | 396 + lib/dynhds.h | 183 + lib/easy.c | 1361 + lib/easy_lock.h | 111 + lib/easygetopt.c | 98 + lib/easyif.h | 41 + lib/easyoptions.c | 380 + lib/easyoptions.h | 37 + lib/escape.c | 234 + lib/escape.h | 44 + lib/file.c | 585 + lib/file.h | 42 + lib/fileinfo.c | 46 + lib/fileinfo.h | 40 + lib/fopen.c | 153 + lib/fopen.h | 30 + lib/formdata.c | 958 + lib/formdata.h | 59 + lib/ftp.c | 4437 ++ lib/ftp.h | 167 + lib/ftplistparser.c | 1041 + lib/ftplistparser.h | 77 + lib/functypes.h | 115 + lib/getenv.c | 80 + lib/getinfo.c | 628 + lib/getinfo.h | 29 + lib/gopher.c | 242 + lib/gopher.h | 34 + lib/hash.c | 370 + lib/hash.h | 102 + lib/headers.c | 394 + lib/headers.h | 55 + lib/hmac.c | 173 + lib/hostasyn.c | 123 + lib/hostip.c | 1469 + lib/hostip.h | 229 + lib/hostip4.c | 301 + lib/hostip6.c | 157 + lib/hostsyn.c | 104 + lib/hsts.c | 585 + lib/hsts.h | 69 + lib/http.c | 4941 ++ lib/http.h | 333 + lib/http1.c | 346 + lib/http1.h | 63 + lib/http2.c | 2849 + lib/http2.h | 77 + lib/http_aws_sigv4.c | 817 + lib/http_aws_sigv4.h | 31 + lib/http_chunks.c | 455 + lib/http_chunks.h | 138 + lib/http_digest.c | 185 + lib/http_digest.h | 44 + lib/http_negotiate.c | 224 + lib/http_negotiate.h | 43 + lib/http_ntlm.c | 275 + lib/http_ntlm.h | 44 + lib/http_proxy.c | 336 + lib/http_proxy.h | 61 + lib/idn.c | 287 + lib/idn.h | 44 + lib/if2ip.c | 260 + lib/if2ip.h | 92 + lib/imap.c | 2115 + lib/imap.h | 101 + lib/inet_ntop.c | 205 + lib/inet_ntop.h | 39 + lib/inet_pton.c | 243 + lib/inet_pton.h | 38 + lib/krb5.c | 913 + lib/ldap.c | 1107 + lib/libcurl.plist | 35 + lib/libcurl.plist.in | 35 + lib/libcurl.rc | 65 + lib/libcurl.vers.in | 13 + lib/llist.c | 146 + lib/llist.h | 52 + lib/macos.c | 55 + lib/macos.h | 39 + lib/md4.c | 524 + lib/md5.c | 656 + lib/memdebug.c | 463 + lib/memdebug.h | 202 + lib/mime.c | 2022 + lib/mime.h | 175 + lib/mprintf.c | 1213 + lib/mqtt.c | 844 + lib/mqtt.h | 63 + lib/multi.c | 3821 ++ lib/multihandle.h | 179 + lib/multiif.h | 97 + lib/netrc.c | 349 + lib/netrc.h | 43 + lib/nonblock.c | 84 + lib/nonblock.h | 32 + lib/noproxy.c | 265 + lib/noproxy.h | 45 + lib/openldap.c | 1219 + lib/parsedate.c | 644 + lib/parsedate.h | 38 + lib/pingpong.c | 429 + lib/pingpong.h | 160 + lib/pop3.c | 1583 + lib/pop3.h | 97 + lib/progress.c | 633 + lib/progress.h | 77 + lib/psl.c | 113 + lib/psl.h | 49 + lib/rand.c | 291 + lib/rand.h | 50 + lib/rename.c | 73 + lib/rename.h | 29 + lib/rtsp.c | 1032 + lib/rtsp.h | 80 + lib/select.c | 403 + lib/select.h | 114 + lib/sendf.c | 821 + lib/sendf.h | 193 + lib/setopt.c | 3179 + lib/setopt.h | 32 + lib/setup-os400.h | 144 + lib/setup-vms.h | 444 + lib/setup-win32.h | 138 + lib/sha256.c | 545 + lib/share.c | 290 + lib/share.h | 68 + lib/sigpipe.h | 80 + lib/slist.c | 146 + lib/slist.h | 41 + lib/smb.c | 1203 + lib/smb.h | 60 + lib/smtp.c | 1925 + lib/smtp.h | 100 + lib/sockaddr.h | 44 + lib/socketpair.c | 190 + lib/socketpair.h | 54 + lib/socks.c | 1276 + lib/socks.h | 61 + lib/socks_gssapi.c | 535 + lib/socks_sspi.c | 620 + lib/speedcheck.c | 79 + lib/speedcheck.h | 35 + lib/splay.c | 278 + lib/splay.h | 58 + lib/strcase.c | 204 + lib/strcase.h | 54 + lib/strdup.c | 143 + lib/strdup.h | 38 + lib/strerror.c | 1114 + lib/strerror.h | 39 + lib/strtok.c | 68 + lib/strtok.h | 36 + lib/strtoofft.c | 245 + lib/strtoofft.h | 54 + lib/system_win32.c | 270 + lib/system_win32.h | 77 + lib/telnet.c | 1642 + lib/telnet.h | 30 + lib/tftp.c | 1405 + lib/tftp.h | 33 + lib/timediff.c | 88 + lib/timediff.h | 52 + lib/timeval.c | 237 + lib/timeval.h | 62 + lib/transfer.c | 1718 + lib/transfer.h | 88 + lib/url.c | 4046 ++ lib/url.h | 81 + lib/urlapi-int.h | 39 + lib/urlapi.c | 1974 + lib/urldata.h | 2028 + lib/vauth/cleartext.c | 138 + lib/vauth/cram.c | 97 + lib/vauth/digest.c | 994 + lib/vauth/digest.h | 40 + lib/vauth/digest_sspi.c | 672 + lib/vauth/gsasl.c | 127 + lib/vauth/krb5_gssapi.c | 324 + lib/vauth/krb5_sspi.c | 475 + lib/vauth/ntlm.c | 780 + lib/vauth/ntlm.h | 143 + lib/vauth/ntlm_sspi.c | 372 + lib/vauth/oauth2.c | 108 + lib/vauth/spnego_gssapi.c | 281 + lib/vauth/spnego_sspi.c | 364 + lib/vauth/vauth.c | 163 + lib/vauth/vauth.h | 238 + lib/version.c | 678 + lib/version_win32.c | 319 + lib/version_win32.h | 56 + lib/vquic/curl_msh3.c | 1092 + lib/vquic/curl_msh3.h | 46 + lib/vquic/curl_ngtcp2.c | 2386 + lib/vquic/curl_ngtcp2.h | 61 + lib/vquic/curl_osslq.c | 2237 + lib/vquic/curl_osslq.h | 51 + lib/vquic/curl_quiche.c | 1598 + lib/vquic/curl_quiche.h | 50 + lib/vquic/vquic-tls.c | 609 + lib/vquic/vquic-tls.h | 98 + lib/vquic/vquic.c | 683 + lib/vquic/vquic.h | 64 + lib/vquic/vquic_int.h | 93 + lib/vssh/libssh.c | 2950 + lib/vssh/libssh2.c | 3830 ++ lib/vssh/ssh.h | 273 + lib/vssh/wolfssh.c | 1167 + lib/vtls/bearssl.c | 1226 + lib/vtls/bearssl.h | 34 + lib/vtls/gtls.c | 1677 + lib/vtls/gtls.h | 75 + lib/vtls/hostcheck.c | 135 + lib/vtls/hostcheck.h | 33 + lib/vtls/keylog.c | 166 + lib/vtls/keylog.h | 58 + lib/vtls/mbedtls.c | 1311 + lib/vtls/mbedtls.h | 34 + lib/vtls/mbedtls_threadlock.c | 134 + lib/vtls/mbedtls_threadlock.h | 50 + lib/vtls/openssl.c | 4954 ++ lib/vtls/openssl.h | 70 + lib/vtls/rustls.c | 730 + lib/vtls/rustls.h | 35 + lib/vtls/schannel.c | 2931 + lib/vtls/schannel.h | 86 + lib/vtls/schannel_int.h | 170 + lib/vtls/schannel_verify.c | 787 + lib/vtls/sectransp.c | 3493 ++ lib/vtls/sectransp.h | 34 + lib/vtls/vtls.c | 2173 + lib/vtls/vtls.h | 258 + lib/vtls/vtls_int.h | 207 + lib/vtls/wolfssl.c | 1418 + lib/vtls/wolfssl.h | 33 + lib/vtls/x509asn1.c | 1229 + lib/vtls/x509asn1.h | 80 + lib/warnless.c | 386 + lib/warnless.h | 106 + lib/ws.c | 1260 + lib/ws.h | 92 + libcurl.def | 94 + libcurl.pc.in | 41 + ltmain.sh | 11436 ++++ m4/curl-amissl.m4 | 69 + m4/curl-bearssl.m4 | 110 + m4/curl-compilers.m4 | 1627 + m4/curl-confopts.m4 | 668 + m4/curl-functions.m4 | 5918 ++ m4/curl-gnutls.m4 | 168 + m4/curl-mbedtls.m4 | 111 + m4/curl-openssl.m4 | 446 + m4/curl-override.m4 | 98 + m4/curl-reentrant.m4 | 506 + m4/curl-rustls.m4 | 111 + m4/curl-schannel.m4 | 48 + m4/curl-sectransp.m4 | 45 + m4/curl-sysconfig.m4 | 54 + m4/curl-wolfssl.m4 | 176 + m4/libtool.m4 | 8427 +++ m4/ltoptions.m4 | 437 + m4/ltsugar.m4 | 124 + m4/ltversion.m4 | 24 + m4/lt~obsolete.m4 | 99 + m4/xc-am-iface.m4 | 85 + m4/xc-cc-check.m4 | 97 + m4/xc-lt-iface.m4 | 466 + m4/xc-translit.m4 | 165 + m4/xc-val-flgs.m4 | 244 + m4/zz40-xc-ovr.m4 | 667 + m4/zz50-xc-ovr.m4 | 61 + m4/zz60-xc-ovr.m4 | 65 + maketgz | 220 + missing | 215 + packages/Makefile.am | 51 + packages/Makefile.in | 797 + packages/OS400/README.OS400 | 391 + packages/OS400/ccsidcurl.c | 1527 + packages/OS400/ccsidcurl.h | 113 + packages/OS400/config400.default | 55 + packages/OS400/curl.cmd | 32 + packages/OS400/curl.inc.in | 3425 ++ packages/OS400/curlcl.c | 177 + packages/OS400/curlmain.c | 121 + packages/OS400/initscript.sh | 287 + packages/OS400/make-include.sh | 106 + packages/OS400/make-lib.sh | 183 + packages/OS400/make-src.sh | 99 + packages/OS400/make-tests.sh | 145 + packages/OS400/makefile.sh | 123 + packages/OS400/os400sys.c | 1040 + packages/OS400/os400sys.h | 57 + packages/OS400/rpg-examples/HEADERAPI | 146 + packages/OS400/rpg-examples/HTTPPOST | 129 + packages/OS400/rpg-examples/INMEMORY | 159 + packages/OS400/rpg-examples/SIMPLE1 | 108 + packages/OS400/rpg-examples/SIMPLE2 | 108 + packages/OS400/rpg-examples/SMTPSRCMBR | 239 + packages/README.md | 12 + packages/vms/Makefile.am | 59 + packages/vms/Makefile.in | 629 + packages/vms/backup_gnv_curl_src.com | 130 + packages/vms/build_curl-config_script.com | 153 + packages/vms/build_gnv_curl.com | 36 + packages/vms/build_gnv_curl_pcsi_desc.com | 489 + packages/vms/build_gnv_curl_pcsi_text.com | 195 + packages/vms/build_gnv_curl_release_notes.com | 100 + packages/vms/build_libcurl_pc.com | 202 + packages/vms/build_vms.com | 1038 + packages/vms/clean_gnv_curl.com | 242 + packages/vms/compare_curl_source.com | 363 + packages/vms/config_h.com | 1972 + packages/vms/curl_crtl_init.c | 333 + packages/vms/curl_gnv_build_steps.txt | 290 + packages/vms/curl_release_note_start.txt | 77 + packages/vms/curl_startup.com | 98 + packages/vms/curlmsg.h | 143 + packages/vms/curlmsg.msg | 134 + packages/vms/curlmsg.sdl | 116 + packages/vms/curlmsg_vms.h | 143 + packages/vms/generate_config_vms_h_curl.com | 450 + packages/vms/generate_vax_transfer.com | 273 + packages/vms/gnv_conftest.c_first | 58 + packages/vms/gnv_curl_configure.sh | 44 + packages/vms/gnv_libcurl_symbols.opt | 181 + packages/vms/gnv_link_curl.com | 851 + packages/vms/macro32_exactcase.patch | 11 + packages/vms/make_gnv_curl_install.sh | 44 + packages/vms/make_pcsi_curl_kit_name.com | 188 + packages/vms/pcsi_gnv_curl_file_list.txt | 125 + packages/vms/pcsi_product_gnv_curl.com | 197 + packages/vms/readme | 228 + packages/vms/report_openssl_version.c | 100 + packages/vms/setup_gnv_curl_build.com | 286 + packages/vms/stage_curl_install.com | 170 + packages/vms/vms_eco_level.h | 30 + plan9/README | 55 + plan9/include/mkfile | 36 + plan9/lib/mkfile | 41 + plan9/lib/mkfile.inc | 27 + plan9/mkfile | 38 + plan9/mkfile.proto | 32 + plan9/src/mkfile | 47 + plan9/src/mkfile.inc | 27 + projects/README.md | 160 + projects/Windows/VC14.10/curl-all.sln | 298 + projects/Windows/VC14.10/lib/libcurl.sln | 181 + projects/Windows/VC14.10/lib/libcurl.vcxproj | 2696 + .../VC14.10/lib/libcurl.vcxproj.filters | 17 + projects/Windows/VC14.10/src/curl.sln | 181 + projects/Windows/VC14.10/src/curl.vcxproj | 2771 + .../Windows/VC14.10/src/curl.vcxproj.filters | 17 + projects/Windows/VC14.20/curl-all.sln | 298 + projects/Windows/VC14.20/lib/libcurl.sln | 181 + projects/Windows/VC14.20/lib/libcurl.vcxproj | 2696 + .../VC14.20/lib/libcurl.vcxproj.filters | 17 + projects/Windows/VC14.20/src/curl.sln | 181 + projects/Windows/VC14.20/src/curl.vcxproj | 2771 + .../Windows/VC14.20/src/curl.vcxproj.filters | 17 + projects/Windows/VC14.30/curl-all.sln | 298 + projects/Windows/VC14.30/lib/libcurl.sln | 181 + projects/Windows/VC14.30/lib/libcurl.vcxproj | 2696 + .../VC14.30/lib/libcurl.vcxproj.filters | 17 + projects/Windows/VC14.30/src/curl.sln | 181 + projects/Windows/VC14.30/src/curl.vcxproj | 2771 + .../Windows/VC14.30/src/curl.vcxproj.filters | 17 + projects/Windows/VC14/curl-all.sln | 298 + projects/Windows/VC14/lib/libcurl.sln | 181 + projects/Windows/VC14/lib/libcurl.vcxproj | 2724 + .../Windows/VC14/lib/libcurl.vcxproj.filters | 17 + projects/Windows/VC14/src/curl.sln | 181 + projects/Windows/VC14/src/curl.vcxproj | 2799 + .../Windows/VC14/src/curl.vcxproj.filters | 17 + projects/build-openssl.bat | 739 + projects/build-wolfssl.bat | 429 + projects/checksrc.bat | 225 + projects/generate.bat | 424 + projects/wolfssl_options.h | 308 + projects/wolfssl_override.props | 40 + scripts/Makefile.am | 63 + scripts/Makefile.in | 619 + scripts/cd2cd | 226 + scripts/cd2nroff | 373 + scripts/cdall | 44 + scripts/checksrc.pl | 988 + scripts/completion.pl | 166 + scripts/coverage.sh | 39 + scripts/firefox-db2pem.sh | 55 + scripts/mk-ca-bundle.pl | 713 + scripts/nroff2cd | 193 + scripts/schemetable.c | 207 + src/.checksrc | 1 + src/CMakeLists.txt | 134 + src/Makefile.am | 165 + src/Makefile.in | 2081 + src/Makefile.inc | 153 + src/Makefile.mk | 90 + src/curl.rc | 113 + src/mkhelp.pl | 234 + src/slist_wc.c | 74 + src/slist_wc.h | 57 + src/tool_binmode.c | 53 + src/tool_binmode.h | 38 + src/tool_bname.c | 51 + src/tool_bname.h | 36 + src/tool_cb_dbg.c | 300 + src/tool_cb_dbg.h | 36 + src/tool_cb_hdr.c | 442 + src/tool_cb_hdr.h | 58 + src/tool_cb_prg.c | 292 + src/tool_cb_prg.h | 54 + src/tool_cb_rea.c | 132 + src/tool_cb_rea.h | 42 + src/tool_cb_see.c | 121 + src/tool_cb_see.h | 46 + src/tool_cb_wrt.c | 371 + src/tool_cb_wrt.h | 38 + src/tool_cfgable.c | 194 + src/tool_cfgable.h | 336 + src/tool_dirhie.c | 167 + src/tool_dirhie.h | 32 + src/tool_doswin.c | 796 + src/tool_doswin.h | 72 + src/tool_easysrc.c | 238 + src/tool_easysrc.h | 58 + src/tool_filetime.c | 156 + src/tool_filetime.h | 42 + src/tool_findfile.c | 157 + src/tool_findfile.h | 36 + src/tool_formparse.c | 907 + src/tool_formparse.h | 73 + src/tool_getparam.c | 2858 + src/tool_getparam.h | 74 + src/tool_getpass.c | 207 + src/tool_getpass.h | 38 + src/tool_help.c | 235 + src/tool_help.h | 75 + src/tool_helpers.c | 136 + src/tool_helpers.h | 36 + src/tool_hugehelp.c | 13502 +++++ src/tool_hugehelp.h | 35 + src/tool_ipfs.c | 293 + src/tool_ipfs.h | 33 + src/tool_libinfo.c | 208 + src/tool_libinfo.h | 67 + src/tool_listhelp.c | 811 + src/tool_main.c | 297 + src/tool_main.h | 48 + src/tool_msgs.c | 150 + src/tool_msgs.h | 38 + src/tool_operate.c | 2813 + src/tool_operate.h | 86 + src/tool_operhlp.c | 254 + src/tool_operhlp.h | 42 + src/tool_paramhlp.c | 707 + src/tool_paramhlp.h | 63 + src/tool_parsecfg.c | 352 + src/tool_parsecfg.h | 30 + src/tool_progress.c | 321 + src/tool_progress.h | 41 + src/tool_sdecls.h | 133 + src/tool_setopt.c | 669 + src/tool_setopt.h | 150 + src/tool_setup.h | 77 + src/tool_sleep.c | 61 + src/tool_sleep.h | 30 + src/tool_stderr.c | 71 + src/tool_stderr.h | 32 + src/tool_strdup.c | 44 + src/tool_strdup.h | 32 + src/tool_urlglob.c | 721 + src/tool_urlglob.h | 78 + src/tool_util.c | 161 + src/tool_util.h | 42 + src/tool_version.h | 36 + src/tool_vms.c | 220 + src/tool_vms.h | 48 + src/tool_writeout.c | 675 + src/tool_writeout.h | 113 + src/tool_writeout_json.c | 173 + src/tool_writeout_json.h | 37 + src/tool_xattr.c | 138 + src/tool_xattr.h | 45 + src/var.c | 464 + src/var.h | 47 + tests/CMakeLists.txt | 55 + tests/FILEFORMAT.md | 678 + tests/Makefile.am | 133 + tests/Makefile.in | 871 + tests/README.md | 264 + tests/appveyor.pm | 130 + tests/azure.pm | 165 + tests/certs/EdelCurlRoot-ca.cacert | 95 + tests/certs/EdelCurlRoot-ca.cnf | 11 + tests/certs/EdelCurlRoot-ca.crt | 95 + tests/certs/EdelCurlRoot-ca.csr | 17 + tests/certs/EdelCurlRoot-ca.der | Bin 0 -> 1080 bytes tests/certs/EdelCurlRoot-ca.key | 28 + tests/certs/EdelCurlRoot-ca.prm | 30 + tests/certs/Makefile.am | 137 + tests/certs/Makefile.in | 882 + tests/certs/Server-localhost-firstSAN-sv.crl | 14 + tests/certs/Server-localhost-firstSAN-sv.crt | 100 + tests/certs/Server-localhost-firstSAN-sv.csr | 16 + tests/certs/Server-localhost-firstSAN-sv.der | Bin 0 -> 1123 bytes tests/certs/Server-localhost-firstSAN-sv.dhp | 0 tests/certs/Server-localhost-firstSAN-sv.key | 28 + tests/certs/Server-localhost-firstSAN-sv.pem | 167 + tests/certs/Server-localhost-firstSAN-sv.prm | 39 + .../Server-localhost-firstSAN-sv.pub.der | Bin 0 -> 294 bytes .../Server-localhost-firstSAN-sv.pub.pem | 9 + tests/certs/Server-localhost-lastSAN-sv.crl | 15 + tests/certs/Server-localhost-lastSAN-sv.crt | 100 + tests/certs/Server-localhost-lastSAN-sv.csr | 16 + tests/certs/Server-localhost-lastSAN-sv.der | Bin 0 -> 1123 bytes tests/certs/Server-localhost-lastSAN-sv.dhp | 0 tests/certs/Server-localhost-lastSAN-sv.key | 28 + tests/certs/Server-localhost-lastSAN-sv.pem | 166 + tests/certs/Server-localhost-lastSAN-sv.prm | 38 + .../certs/Server-localhost-lastSAN-sv.pub.der | Bin 0 -> 294 bytes .../certs/Server-localhost-lastSAN-sv.pub.pem | 9 + tests/certs/Server-localhost-sv.crl | 12 + tests/certs/Server-localhost-sv.crt | 99 + tests/certs/Server-localhost-sv.csr | 16 + tests/certs/Server-localhost-sv.der | Bin 0 -> 1096 bytes tests/certs/Server-localhost-sv.dhp | 0 tests/certs/Server-localhost-sv.key | 28 + tests/certs/Server-localhost-sv.pem | 165 + tests/certs/Server-localhost-sv.prm | 38 + tests/certs/Server-localhost-sv.pub.der | Bin 0 -> 294 bytes tests/certs/Server-localhost-sv.pub.pem | 9 + tests/certs/Server-localhost.nn-sv.crl | 13 + tests/certs/Server-localhost.nn-sv.crt | 99 + tests/certs/Server-localhost.nn-sv.csr | 16 + tests/certs/Server-localhost.nn-sv.der | Bin 0 -> 1102 bytes tests/certs/Server-localhost.nn-sv.dhp | 0 tests/certs/Server-localhost.nn-sv.key | 28 + tests/certs/Server-localhost.nn-sv.pem | 165 + tests/certs/Server-localhost.nn-sv.prm | 38 + tests/certs/Server-localhost.nn-sv.pub.der | Bin 0 -> 294 bytes tests/certs/Server-localhost.nn-sv.pub.pem | 9 + tests/certs/Server-localhost0h-sv.crl | 14 + tests/certs/Server-localhost0h-sv.crt | 99 + tests/certs/Server-localhost0h-sv.csr | 16 + tests/certs/Server-localhost0h-sv.der | Bin 0 -> 1098 bytes tests/certs/Server-localhost0h-sv.dhp | 0 tests/certs/Server-localhost0h-sv.key | 28 + tests/certs/Server-localhost0h-sv.pem | 166 + tests/certs/Server-localhost0h-sv.prm | 39 + tests/certs/Server-localhost0h-sv.pub.der | Bin 0 -> 294 bytes tests/certs/Server-localhost0h-sv.pub.pem | 9 + tests/certs/scripts/Makefile.am | 30 + tests/certs/scripts/Makefile.in | 598 + tests/certs/scripts/genroot.sh | 89 + tests/certs/scripts/genserv.sh | 143 + tests/certs/srp-verifier-conf | 3 + tests/certs/srp-verifier-db | 2 + tests/certs/stunnel-sv.crl | 15 + tests/certs/stunnel-sv.crt | 99 + tests/certs/stunnel-sv.csr | 16 + tests/certs/stunnel-sv.der | Bin 0 -> 1096 bytes tests/certs/stunnel-sv.dhp | 0 tests/certs/stunnel-sv.key | 28 + tests/certs/stunnel-sv.pem | 165 + tests/certs/stunnel-sv.prm | 38 + tests/certs/stunnel-sv.pub.pem | 9 + tests/config.in | 24 + tests/data/CMakeLists.txt | 26 + tests/data/DISABLED | 116 + tests/data/Makefile.am | 31 + tests/data/Makefile.in | 862 + tests/data/Makefile.inc | 262 + tests/data/test1 | 53 + tests/data/test10 | 64 + tests/data/test100 | 57 + tests/data/test1000 | 42 + tests/data/test1001 | 105 + tests/data/test1002 | 122 + tests/data/test1003 | 48 + tests/data/test1004 | 60 + tests/data/test1005 | 48 + tests/data/test1006 | 49 + tests/data/test1007 | 47 + tests/data/test1008 | 125 + tests/data/test1009 | 49 + tests/data/test101 | 58 + tests/data/test1010 | 58 + tests/data/test1011 | 74 + tests/data/test1012 | 77 + tests/data/test1013 | 37 + tests/data/test1014 | 37 + tests/data/test1015 | 52 + tests/data/test1016 | 39 + tests/data/test1017 | 40 + tests/data/test1018 | 39 + tests/data/test1019 | 42 + tests/data/test102 | 52 + tests/data/test1020 | 41 + tests/data/test1021 | 134 + tests/data/test1022 | 37 + tests/data/test1023 | 37 + tests/data/test1024 | 106 + tests/data/test1025 | 108 + tests/data/test1026 | 42 + tests/data/test1027 | 39 + tests/data/test1028 | 88 + tests/data/test1029 | 56 + tests/data/test103 | 54 + tests/data/test1030 | 106 + tests/data/test1031 | 75 + tests/data/test1032 | 54 + tests/data/test1033 | 58 + tests/data/test1034 | 57 + tests/data/test1035 | 50 + tests/data/test1036 | 61 + tests/data/test1037 | 54 + tests/data/test1038 | 53 + tests/data/test1039 | 53 + tests/data/test104 | 43 + tests/data/test1040 | 77 + tests/data/test1041 | 75 + tests/data/test1042 | 92 + tests/data/test1043 | 82 + tests/data/test1044 | 58 + tests/data/test1045 | 50 + tests/data/test1046 | 58 + tests/data/test1047 | 58 + tests/data/test1048 | 67 + tests/data/test1049 | 49 + tests/data/test105 | 51 + tests/data/test1050 | 66 + tests/data/test1051 | 115 + tests/data/test1052 | 110 + tests/data/test1053 | 130 + tests/data/test1054 | 79 + tests/data/test1055 | 93 + tests/data/test1056 | 85 + tests/data/test1057 | 52 + tests/data/test1058 | 51 + tests/data/test1059 | 57 + tests/data/test106 | 51 + tests/data/test1060 | 903 + tests/data/test1061 | 908 + tests/data/test1062 | 49 + tests/data/test1063 | 45 + tests/data/test1064 | 78 + tests/data/test1065 | 77 + tests/data/test1066 | 81 + tests/data/test1067 | 80 + tests/data/test1068 | 56 + tests/data/test1069 | 36 + tests/data/test107 | 51 + tests/data/test1070 | 63 + tests/data/test1071 | 112 + tests/data/test1072 | 80 + tests/data/test1073 | 74 + tests/data/test1074 | 76 + tests/data/test1075 | 91 + tests/data/test1076 | 77 + tests/data/test1077 | 75 + tests/data/test1078 | 99 + tests/data/test1079 | 75 + tests/data/test108 | 56 + tests/data/test1080 | 68 + tests/data/test1081 | 76 + tests/data/test1082 | 53 + tests/data/test1083 | 57 + tests/data/test1084 | 41 + tests/data/test1085 | 48 + tests/data/test1086 | 113 + tests/data/test1087 | 113 + tests/data/test1088 | 115 + tests/data/test1089 | 90 + tests/data/test109 | 48 + tests/data/test1090 | 97 + tests/data/test1091 | 47 + tests/data/test1092 | 55 + tests/data/test1093 | 49 + tests/data/test1094 | 55 + tests/data/test1095 | 82 + tests/data/test1096 | 51 + tests/data/test1097 | 80 + tests/data/test1098 | 73 + tests/data/test1099 | 52 + tests/data/test11 | 75 + tests/data/test110 | 52 + tests/data/test1100 | 114 + tests/data/test1101 | 52 + tests/data/test1102 | 51 + tests/data/test1103 | 48 + tests/data/test1104 | 88 + tests/data/test1105 | 69 + tests/data/test1106 | 56 + tests/data/test1107 | 53 + tests/data/test1108 | 45 + tests/data/test1109 | 44 + tests/data/test111 | 45 + tests/data/test1110 | 45 + tests/data/test1111 | 45 + tests/data/test1112 | 118 + tests/data/test1113 | 99 + tests/data/test1114 | 136 + tests/data/test1115 | 50 + tests/data/test1116 | 87 + tests/data/test1117 | 87 + tests/data/test1118 | 53 + tests/data/test1119 | 30 + tests/data/test112 | 49 + tests/data/test1120 | 46 + tests/data/test1121 | 45 + tests/data/test1122 | 69 + tests/data/test1123 | 198 + tests/data/test1124 | 67 + tests/data/test1125 | 67 + tests/data/test1126 | 50 + tests/data/test1127 | 59 + tests/data/test1128 | 84 + tests/data/test1129 | 96 + tests/data/test113 | 37 + tests/data/test1130 | 97 + tests/data/test1131 | 95 + tests/data/test1132 | 25 + tests/data/test1133 | 105 + tests/data/test1134 | 64 + tests/data/test1135 | 127 + tests/data/test1136 | 66 + tests/data/test1137 | 52 + tests/data/test1138 | 72 + tests/data/test1139 | 33 + tests/data/test114 | 38 + tests/data/test1140 | 32 + tests/data/test1141 | 72 + tests/data/test1142 | 65 + tests/data/test1143 | 48 + tests/data/test1144 | 72 + tests/data/test1145 | 40 + tests/data/test1146 | 45 + tests/data/test1147 | 68 + tests/data/test1148 | 67 + tests/data/test1149 | 64 + tests/data/test115 | 44 + tests/data/test1150 | 57 + tests/data/test1151 | 68 + tests/data/test1152 | 61 + tests/data/test1153 | 61 + tests/data/test1154 | 55 + tests/data/test1155 | 55 + tests/data/test1156 | 71 + tests/data/test1157 | 56 + tests/data/test1158 | 101 + tests/data/test1159 | 56 + tests/data/test116 | 55 + tests/data/test1160 | 55 + tests/data/test1161 | 55 + tests/data/test1162 | 56 + tests/data/test1163 | 52 + tests/data/test1164 | 54 + tests/data/test1165 | 25 + tests/data/test1166 | 52 + tests/data/test1167 | 24 + tests/data/test1168 | 77 + tests/data/test1169 | 34 + tests/data/test117 | 44 + tests/data/test1170 | 67 + tests/data/test1171 | 67 + tests/data/test1172 | 48 + tests/data/test1173 | 32 + tests/data/test1174 | 48 + tests/data/test1175 | 25 + tests/data/test1176 | 66 + tests/data/test1177 | 25 + tests/data/test1178 | 53 + tests/data/test1179 | 43 + tests/data/test118 | 49 + tests/data/test1180 | 48 + tests/data/test1181 | 48 + tests/data/test1182 | 36 + tests/data/test1183 | 48 + tests/data/test1184 | 108 + tests/data/test1185 | 184 + tests/data/test1186 | 101 + tests/data/test1187 | 66 + tests/data/test1188 | 56 + tests/data/test1189 | 111 + tests/data/test119 | 51 + tests/data/test1190 | 56 + tests/data/test1191 | 50 + tests/data/test1192 | 56 + tests/data/test1193 | 72 + tests/data/test1194 | 59 + tests/data/test1195 | 63 + tests/data/test1196 | 62 + tests/data/test1197 | 87 + tests/data/test1198 | 54 + tests/data/test1199 | 55 + tests/data/test12 | 54 + tests/data/test120 | 53 + tests/data/test1200 | 39 + tests/data/test1201 | 39 + tests/data/test1202 | 40 + tests/data/test1203 | 43 + tests/data/test1204 | 78 + tests/data/test1205 | 48 + tests/data/test1206 | 54 + tests/data/test1207 | 53 + tests/data/test1208 | 62 + tests/data/test1209 | 60 + tests/data/test121 | 51 + tests/data/test1210 | 61 + tests/data/test1211 | 55 + tests/data/test1212 | 52 + tests/data/test1213 | 54 + tests/data/test1214 | 54 + tests/data/test1215 | 96 + tests/data/test1216 | 66 + tests/data/test1217 | 57 + tests/data/test1218 | 65 + tests/data/test1219 | 49 + tests/data/test122 | 45 + tests/data/test1220 | 37 + tests/data/test1221 | 53 + tests/data/test1222 | 24 + tests/data/test1223 | 58 + tests/data/test1224 | 49 + tests/data/test1225 | 56 + tests/data/test1226 | 49 + tests/data/test1227 | 48 + tests/data/test1228 | 58 + tests/data/test1229 | 82 + tests/data/test123 | 40 + tests/data/test1230 | 78 + tests/data/test1231 | 60 + tests/data/test1232 | 67 + tests/data/test1233 | 47 + tests/data/test1234 | 33 + tests/data/test1235 | 88 + tests/data/test1236 | 33 + tests/data/test1237 | 45 + tests/data/test1238 | 65 + tests/data/test1239 | 66 + tests/data/test124 | 47 + tests/data/test1240 | 47 + tests/data/test1241 | 66 + tests/data/test1242 | 43 + tests/data/test1243 | 44 + tests/data/test1244 | 62 + tests/data/test1245 | 57 + tests/data/test1246 | 66 + tests/data/test1247 | 38 + tests/data/test1248 | 50 + tests/data/test1249 | 53 + tests/data/test125 | 41 + tests/data/test1250 | 51 + tests/data/test1251 | 52 + tests/data/test1252 | 53 + tests/data/test1253 | 54 + tests/data/test1254 | 54 + tests/data/test1255 | 51 + tests/data/test1256 | 55 + tests/data/test1257 | 55 + tests/data/test1258 | 56 + tests/data/test1259 | 45 + tests/data/test126 | 48 + tests/data/test1260 | 36 + tests/data/test1261 | 59 + tests/data/test1262 | 40 + tests/data/test1263 | 37 + tests/data/test1264 | 36 + tests/data/test1265 | 51 + tests/data/test1266 | 48 + tests/data/test1267 | 48 + tests/data/test1268 | 41 + tests/data/test1269 | 34 + tests/data/test127 | 46 + tests/data/test1270 | 67 + tests/data/test1271 | 46 + tests/data/test1272 | 43 + tests/data/test1273 | 81 + tests/data/test1274 | 75 + tests/data/test1275 | 25 + tests/data/test1276 | 25 + tests/data/test1277 | 206 + tests/data/test1278 | 48 + tests/data/test1279 | 31 + tests/data/test128 | 57 + tests/data/test1280 | 59 + tests/data/test1281 | 38 + tests/data/test1282 | 45 + tests/data/test1283 | 55 + tests/data/test1284 | 88 + tests/data/test1285 | 95 + tests/data/test1286 | 111 + tests/data/test1287 | 95 + tests/data/test1288 | 98 + tests/data/test1289 | 35 + tests/data/test129 | 57 + tests/data/test1290 | 46 + tests/data/test1291 | 44 + tests/data/test1292 | 48 + tests/data/test1293 | 68 + tests/data/test1294 | 65 + tests/data/test1295 | 81 + tests/data/test1296 | 54 + tests/data/test1297 | 65 + tests/data/test1298 | 54 + tests/data/test1299 | 53 + tests/data/test13 | 42 + tests/data/test130 | 64 + tests/data/test1300 | 22 + tests/data/test1301 | 21 + tests/data/test1302 | 22 + tests/data/test1303 | 22 + tests/data/test1304 | 30 + tests/data/test1305 | 26 + tests/data/test1306 | 30 + tests/data/test1307 | 24 + tests/data/test1308 | 32 + tests/data/test1309 | 1564 + tests/data/test131 | 63 + tests/data/test1310 | 124 + tests/data/test1311 | 62 + tests/data/test1312 | 62 + tests/data/test1313 | 62 + tests/data/test1314 | 81 + tests/data/test1315 | 86 + tests/data/test1316 | 81 + tests/data/test1317 | 54 + tests/data/test1318 | 59 + tests/data/test1319 | 81 + tests/data/test132 | 62 + tests/data/test1320 | 71 + tests/data/test1321 | 77 + tests/data/test1322 | 55 + tests/data/test1323 | 32 + tests/data/test1324 | 54 + tests/data/test1325 | 79 + tests/data/test1326 | 48 + tests/data/test1327 | 47 + tests/data/test1328 | 70 + tests/data/test1329 | 33 + tests/data/test133 | 62 + tests/data/test1330 | 48 + tests/data/test1331 | 92 + tests/data/test1332 | 78 + tests/data/test1333 | 53 + tests/data/test1334 | 74 + tests/data/test1335 | 71 + tests/data/test1336 | 79 + tests/data/test1337 | 76 + tests/data/test1338 | 75 + tests/data/test1339 | 72 + tests/data/test134 | 64 + tests/data/test1340 | 78 + tests/data/test1341 | 75 + tests/data/test1342 | 81 + tests/data/test1343 | 78 + tests/data/test1344 | 87 + tests/data/test1345 | 84 + tests/data/test1346 | 71 + tests/data/test1347 | 76 + tests/data/test1348 | 61 + tests/data/test1349 | 83 + tests/data/test135 | 54 + tests/data/test1350 | 80 + tests/data/test1351 | 84 + tests/data/test1352 | 81 + tests/data/test1353 | 83 + tests/data/test1354 | 78 + tests/data/test1355 | 61 + tests/data/test1356 | 79 + tests/data/test1357 | 99 + tests/data/test1358 | 96 + tests/data/test1359 | 100 + tests/data/test136 | 42 + tests/data/test1360 | 97 + tests/data/test1361 | 99 + tests/data/test1362 | 96 + tests/data/test1363 | 79 + tests/data/test1364 | 69 + tests/data/test1365 | 66 + tests/data/test1366 | 71 + tests/data/test1367 | 68 + tests/data/test1368 | 70 + tests/data/test1369 | 67 + tests/data/test137 | 47 + tests/data/test1370 | 72 + tests/data/test1371 | 69 + tests/data/test1372 | 76 + tests/data/test1373 | 73 + tests/data/test1374 | 79 + tests/data/test1375 | 76 + tests/data/test1376 | 66 + tests/data/test1377 | 68 + tests/data/test1378 | 56 + tests/data/test1379 | 76 + tests/data/test138 | 50 + tests/data/test1380 | 73 + tests/data/test1381 | 77 + tests/data/test1382 | 74 + tests/data/test1383 | 76 + tests/data/test1384 | 73 + tests/data/test1385 | 56 + tests/data/test1386 | 71 + tests/data/test1387 | 91 + tests/data/test1388 | 88 + tests/data/test1389 | 92 + tests/data/test139 | 47 + tests/data/test1390 | 89 + tests/data/test1391 | 91 + tests/data/test1392 | 88 + tests/data/test1393 | 71 + tests/data/test1394 | 26 + tests/data/test1395 | 21 + tests/data/test1396 | 24 + tests/data/test1397 | 22 + tests/data/test1398 | 23 + tests/data/test1399 | 22 + tests/data/test14 | 41 + tests/data/test140 | 42 + tests/data/test1400 | 110 + tests/data/test1401 | 133 + tests/data/test1402 | 115 + tests/data/test1403 | 110 + tests/data/test1404 | 193 + tests/data/test1405 | 144 + tests/data/test1406 | 134 + tests/data/test1407 | 112 + tests/data/test1408 | 73 + tests/data/test1409 | 31 + tests/data/test141 | 52 + tests/data/test1410 | 31 + tests/data/test1411 | 58 + tests/data/test1412 | 128 + tests/data/test1413 | 72 + tests/data/test1414 | 57 + tests/data/test1415 | 93 + tests/data/test1416 | 61 + tests/data/test1417 | 77 + tests/data/test1418 | 122 + tests/data/test1419 | 68 + tests/data/test142 | 190 + tests/data/test1420 | 116 + tests/data/test1421 | 74 + tests/data/test1422 | 62 + tests/data/test1423 | 55 + tests/data/test1424 | 74 + tests/data/test1425 | Bin 0 -> 1732 bytes tests/data/test1426 | Bin 0 -> 1669 bytes tests/data/test1427 | 29 + tests/data/test1428 | 81 + tests/data/test1429 | 68 + tests/data/test143 | 44 + tests/data/test1430 | 56 + tests/data/test1431 | 54 + tests/data/test1432 | 55 + tests/data/test1433 | 55 + tests/data/test1434 | 88 + tests/data/test1435 | 44 + tests/data/test1436 | 85 + tests/data/test1437 | 82 + tests/data/test1438 | 57 + tests/data/test1439 | 56 + tests/data/test144 | 49 + tests/data/test1440 | 35 + tests/data/test1441 | 35 + tests/data/test1442 | 35 + tests/data/test1443 | 66 + tests/data/test1444 | 52 + tests/data/test1445 | 35 + tests/data/test1446 | 42 + tests/data/test1447 | 39 + tests/data/test1448 | 92 + tests/data/test1449 | 38 + tests/data/test145 | 51 + tests/data/test1450 | 34 + tests/data/test1451 | 43 + tests/data/test1452 | 43 + tests/data/test1453 | 38 + tests/data/test1454 | 38 + tests/data/test1455 | 63 + tests/data/test1456 | 67 + tests/data/test1457 | 60 + tests/data/test1458 | 54 + tests/data/test1459 | 48 + tests/data/test146 | 55 + tests/data/test1460 | 59 + tests/data/test1461 | 53 + tests/data/test1462 | 61 + tests/data/test1463 | 45 + tests/data/test1464 | 45 + tests/data/test1465 | 118 + tests/data/test1466 | 45 + tests/data/test1467 | 60 + tests/data/test1468 | 64 + tests/data/test1469 | 30 + tests/data/test147 | 55 + tests/data/test1470 | 65 + tests/data/test1471 | 42 + tests/data/test1472 | 42 + tests/data/test1473 | 56 + tests/data/test1475 | 83 + tests/data/test1476 | 59 + tests/data/test1477 | 30 + tests/data/test1478 | 32 + tests/data/test148 | 49 + tests/data/test149 | 53 + tests/data/test15 | 55 + tests/data/test150 | 92 + tests/data/test1500 | 44 + tests/data/test1501 | 57 + tests/data/test1502 | 55 + tests/data/test1503 | 55 + tests/data/test1504 | 55 + tests/data/test1505 | 55 + tests/data/test1506 | 95 + tests/data/test1507 | 51 + tests/data/test1508 | 31 + tests/data/test1509 | 91 + tests/data/test151 | 45 + tests/data/test1510 | 96 + tests/data/test1511 | 71 + tests/data/test1512 | 80 + tests/data/test1513 | 50 + tests/data/test1514 | 64 + tests/data/test1515 | 62 + tests/data/test1516 | 58 + tests/data/test1517 | 78 + tests/data/test1518 | 62 + tests/data/test1519 | 62 + tests/data/test152 | 49 + tests/data/test1520 | 63 + tests/data/test1521 | 30 + tests/data/test1522 | 53 + tests/data/test1523 | 50 + tests/data/test1524 | 74 + tests/data/test1525 | 78 + tests/data/test1526 | 80 + tests/data/test1527 | 81 + tests/data/test1528 | 63 + tests/data/test1529 | 46 + tests/data/test153 | 156 + tests/data/test1530 | 30 + tests/data/test1531 | Bin 0 -> 571 bytes tests/data/test1532 | 49 + tests/data/test1533 | 74 + tests/data/test1534 | 51 + tests/data/test1535 | 50 + tests/data/test1536 | 50 + tests/data/test1537 | 45 + tests/data/test1538 | 195 + tests/data/test1539 | 43 + tests/data/test154 | 106 + tests/data/test1540 | 67 + tests/data/test1542 | 68 + tests/data/test1543 | 76 + tests/data/test1544 | 24 + tests/data/test1545 | 38 + tests/data/test155 | 130 + tests/data/test1550 | 29 + tests/data/test1551 | 69 + tests/data/test1552 | 52 + tests/data/test1553 | 57 + tests/data/test1554 | 105 + tests/data/test1555 | 51 + tests/data/test1556 | 60 + tests/data/test1557 | 36 + tests/data/test1558 | 46 + tests/data/test1559 | 45 + tests/data/test156 | 56 + tests/data/test1560 | 42 + tests/data/test1561 | 107 + tests/data/test1562 | 72 + tests/data/test1563 | 49 + tests/data/test1564 | 34 + tests/data/test1565 | 44 + tests/data/test1566 | 63 + tests/data/test1567 | 70 + tests/data/test1568 | 87 + tests/data/test1569 | 73 + tests/data/test157 | 45 + tests/data/test1570 | 73 + tests/data/test158 | 58 + tests/data/test159 | 81 + tests/data/test1590 | 57 + tests/data/test1591 | 64 + tests/data/test1592 | 39 + tests/data/test1593 | 46 + tests/data/test1594 | 49 + tests/data/test1595 | 48 + tests/data/test1596 | 49 + tests/data/test1597 | 32 + tests/data/test16 | 53 + tests/data/test160 | 73 + tests/data/test1600 | 23 + tests/data/test1601 | 22 + tests/data/test1602 | 22 + tests/data/test1603 | 22 + tests/data/test1604 | 21 + tests/data/test1605 | 21 + tests/data/test1606 | 22 + tests/data/test1607 | 22 + tests/data/test1608 | 23 + tests/data/test1609 | 22 + tests/data/test161 | 51 + tests/data/test1610 | 22 + tests/data/test1611 | 22 + tests/data/test1612 | 22 + tests/data/test1613 | 53 + tests/data/test1614 | 25 + tests/data/test162 | 60 + tests/data/test1620 | 22 + tests/data/test1621 | 23 + tests/data/test163 | 82 + tests/data/test1630 | 54 + tests/data/test1631 | 86 + tests/data/test1632 | 104 + tests/data/test1633 | 99 + tests/data/test1634 | 71 + tests/data/test1635 | 64 + tests/data/test164 | 66 + tests/data/test165 | 67 + tests/data/test1650 | 23 + tests/data/test1651 | 22 + tests/data/test1652 | 20 + tests/data/test1653 | 20 + tests/data/test1654 | 56 + tests/data/test1655 | 23 + tests/data/test166 | 63 + tests/data/test1660 | 83 + tests/data/test1661 | 22 + tests/data/test1662 | 67 + tests/data/test167 | 78 + tests/data/test1670 | 61 + tests/data/test1671 | 74 + tests/data/test168 | 98 + tests/data/test1680 | 55 + tests/data/test1681 | 61 + tests/data/test1682 | 58 + tests/data/test1683 | 59 + tests/data/test169 | 119 + tests/data/test17 | 54 + tests/data/test170 | 52 + tests/data/test1700 | 103 + tests/data/test1701 | 85 + tests/data/test1702 | 80 + tests/data/test1703 | 45 + tests/data/test1704 | 66 + tests/data/test171 | 60 + tests/data/test172 | 57 + tests/data/test173 | 82 + tests/data/test174 | 49 + tests/data/test175 | 83 + tests/data/test176 | 86 + tests/data/test177 | 51 + tests/data/test178 | 65 + tests/data/test179 | 59 + tests/data/test18 | 85 + tests/data/test180 | 65 + tests/data/test1800 | 56 + tests/data/test1801 | 67 + tests/data/test181 | 66 + tests/data/test182 | 43 + tests/data/test183 | 56 + tests/data/test184 | 76 + tests/data/test185 | 76 + tests/data/test186 | 65 + tests/data/test187 | 76 + tests/data/test188 | 75 + tests/data/test189 | 73 + tests/data/test19 | 37 + tests/data/test190 | 47 + tests/data/test1900 | 38 + tests/data/test1903 | 62 + tests/data/test1904 | 79 + tests/data/test1905 | 60 + tests/data/test1906 | 49 + tests/data/test1907 | 50 + tests/data/test1908 | 81 + tests/data/test1909 | 64 + tests/data/test191 | 41 + tests/data/test1910 | 65 + tests/data/test1911 | 29 + tests/data/test1912 | 30 + tests/data/test1913 | 41 + tests/data/test1914 | 42 + tests/data/test1915 | 59 + tests/data/test1916 | 57 + tests/data/test1917 | 61 + tests/data/test1918 | 33 + tests/data/test1919 | 51 + tests/data/test192 | 57 + tests/data/test193 | 81 + tests/data/test1933 | 69 + tests/data/test1934 | 69 + tests/data/test1935 | 69 + tests/data/test1936 | 69 + tests/data/test1937 | 72 + tests/data/test1938 | Bin 0 -> 1308 bytes tests/data/test1939 | 55 + tests/data/test194 | 71 + tests/data/test1940 | 66 + tests/data/test1941 | 76 + tests/data/test1942 | 66 + tests/data/test1943 | 62 + tests/data/test1944 | 66 + tests/data/test1945 | 76 + tests/data/test1946 | 68 + tests/data/test1947 | 71 + tests/data/test1948 | 72 + tests/data/test195 | 38 + tests/data/test1955 | 76 + tests/data/test1956 | 73 + tests/data/test1957 | 73 + tests/data/test1958 | 73 + tests/data/test1959 | 73 + tests/data/test196 | 42 + tests/data/test1960 | 52 + tests/data/test1964 | 68 + tests/data/test197 | 75 + tests/data/test1970 | 74 + tests/data/test1971 | 70 + tests/data/test1972 | 79 + tests/data/test1973 | 75 + tests/data/test1974 | 73 + tests/data/test1975 | 70 + tests/data/test198 | 70 + tests/data/test199 | 58 + tests/data/test2 | 48 + tests/data/test20 | 38 + tests/data/test200 | 41 + tests/data/test2000 | 73 + tests/data/test2001 | 96 + tests/data/test2002 | 117 + tests/data/test2003 | 146 + tests/data/test2004 | 79 + tests/data/test201 | 34 + tests/data/test202 | 37 + tests/data/test2023 | 159 + tests/data/test2024 | 173 + tests/data/test2025 | 262 + tests/data/test2026 | 217 + tests/data/test2027 | 245 + tests/data/test2028 | 306 + tests/data/test2029 | 230 + tests/data/test203 | 46 + tests/data/test2030 | 287 + tests/data/test2031 | 311 + tests/data/test2032 | 114 + tests/data/test2033 | 61 + tests/data/test2034 | 57 + tests/data/test2035 | 44 + tests/data/test2036 | 36 + tests/data/test2037 | 57 + tests/data/test2038 | 44 + tests/data/test2039 | 63 + tests/data/test204 | 40 + tests/data/test2040 | 68 + tests/data/test2041 | 57 + tests/data/test2042 | 44 + tests/data/test2043 | 33 + tests/data/test2044 | 33 + tests/data/test2045 | 54 + tests/data/test2046 | 98 + tests/data/test2047 | 101 + tests/data/test2048 | 40 + tests/data/test2049 | 65 + tests/data/test205 | 38 + tests/data/test2050 | 80 + tests/data/test2051 | 74 + tests/data/test2052 | 68 + tests/data/test2053 | 55 + tests/data/test2054 | 65 + tests/data/test2055 | 81 + tests/data/test2056 | 65 + tests/data/test2057 | 87 + tests/data/test2058 | 105 + tests/data/test2059 | 105 + tests/data/test206 | 108 + tests/data/test2060 | 105 + tests/data/test2061 | 82 + tests/data/test2062 | 82 + tests/data/test2063 | 82 + tests/data/test2064 | 82 + tests/data/test2065 | 82 + tests/data/test2066 | 82 + tests/data/test2067 | 88 + tests/data/test2068 | 88 + tests/data/test2069 | 88 + tests/data/test207 | 70 + tests/data/test2070 | 60 + tests/data/test2071 | 41 + tests/data/test2072 | 44 + tests/data/test2073 | 73 + tests/data/test2074 | 55 + tests/data/test2075 | 34 + tests/data/test2076 | 74 + tests/data/test2077 | 42 + tests/data/test2078 | 52 + tests/data/test2079 | 61 + tests/data/test208 | 73 + tests/data/test2080 | Bin 0 -> 20680 bytes tests/data/test2081 | 73 + tests/data/test2082 | 51 + tests/data/test2083 | 45 + tests/data/test2084 | 54 + tests/data/test2085 | 64 + tests/data/test2086 | 52 + tests/data/test2087 | 61 + tests/data/test209 | 115 + tests/data/test21 | 36 + tests/data/test210 | 52 + tests/data/test2100 | 92 + tests/data/test211 | 54 + tests/data/test212 | 64 + tests/data/test213 | 118 + tests/data/test214 | 52 + tests/data/test215 | 58 + tests/data/test216 | 45 + tests/data/test217 | 61 + tests/data/test218 | 60 + tests/data/test219 | 38 + tests/data/test22 | 42 + tests/data/test220 | 69 + tests/data/test2200 | 62 + tests/data/test2201 | 50 + tests/data/test2202 | 59 + tests/data/test2203 | 62 + tests/data/test2204 | 56 + tests/data/test2205 | 51 + tests/data/test221 | 72 + tests/data/test222 | 200 + tests/data/test223 | 93 + tests/data/test224 | 105 + tests/data/test225 | 28 + tests/data/test226 | 29 + tests/data/test227 | 57 + tests/data/test228 | 52 + tests/data/test229 | 41 + tests/data/test23 | 33 + tests/data/test230 | 201 + tests/data/test2300 | 62 + tests/data/test2301 | 65 + tests/data/test2302 | 70 + tests/data/test2303 | 59 + tests/data/test2304 | 69 + tests/data/test2305 | 59 + tests/data/test2306 | 76 + tests/data/test2307 | 71 + tests/data/test231 | 38 + tests/data/test232 | 200 + tests/data/test233 | 96 + tests/data/test234 | 99 + tests/data/test235 | 51 + tests/data/test236 | 53 + tests/data/test237 | 44 + tests/data/test238 | 42 + tests/data/test239 | 92 + tests/data/test24 | 48 + tests/data/test240 | 56 + tests/data/test2400 | 64 + tests/data/test2401 | 72 + tests/data/test2402 | 109 + tests/data/test2403 | 73 + tests/data/test2404 | 109 + tests/data/test241 | 54 + tests/data/test242 | 52 + tests/data/test243 | 121 + tests/data/test244 | 54 + tests/data/test245 | 85 + tests/data/test246 | 95 + tests/data/test247 | 47 + tests/data/test248 | 56 + tests/data/test249 | 52 + tests/data/test25 | 113 + tests/data/test250 | 59 + tests/data/test2500 | 78 + tests/data/test2501 | 70 + tests/data/test2502 | 104 + tests/data/test2503 | 70 + tests/data/test251 | 61 + tests/data/test252 | 60 + tests/data/test253 | 63 + tests/data/test254 | 61 + tests/data/test255 | 64 + tests/data/test256 | 65 + tests/data/test257 | 111 + tests/data/test258 | 137 + tests/data/test259 | 135 + tests/data/test26 | 42 + tests/data/test260 | 53 + tests/data/test2600 | 25 + tests/data/test2601 | 22 + tests/data/test2602 | 22 + tests/data/test2603 | 22 + tests/data/test261 | 48 + tests/data/test262 | Bin 0 -> 1225 bytes tests/data/test263 | 53 + tests/data/test264 | 50 + tests/data/test265 | 121 + tests/data/test266 | 81 + tests/data/test267 | 100 + tests/data/test268 | 59 + tests/data/test269 | 54 + tests/data/test27 | 59 + tests/data/test270 | 50 + tests/data/test271 | 48 + tests/data/test272 | 40 + tests/data/test273 | 82 + tests/data/test274 | 49 + tests/data/test275 | 90 + tests/data/test276 | 75 + tests/data/test277 | 58 + tests/data/test278 | 50 + tests/data/test279 | 51 + tests/data/test28 | 78 + tests/data/test280 | 63 + tests/data/test281 | 59 + tests/data/test282 | 43 + tests/data/test283 | 41 + tests/data/test284 | 72 + tests/data/test285 | 47 + tests/data/test286 | 97 + tests/data/test287 | 56 + tests/data/test288 | 48 + tests/data/test289 | 30 + tests/data/test29 | 50 + tests/data/test290 | 43 + tests/data/test291 | 47 + tests/data/test292 | 54 + tests/data/test293 | 58 + tests/data/test294 | 64 + tests/data/test295 | 45 + tests/data/test296 | 48 + tests/data/test297 | 46 + tests/data/test298 | 45 + tests/data/test299 | 52 + tests/data/test3 | 58 + tests/data/test30 | 41 + tests/data/test300 | 50 + tests/data/test3000 | 56 + tests/data/test3001 | 56 + tests/data/test3002 | 55 + tests/data/test3003 | 55 + tests/data/test3004 | 55 + tests/data/test3005 | 55 + tests/data/test3006 | 51 + tests/data/test3007 | 47 + tests/data/test3008 | 57 + tests/data/test3009 | 57 + tests/data/test301 | 55 + tests/data/test3010 | 57 + tests/data/test3011 | 57 + tests/data/test3012 | 61 + tests/data/test3013 | 68 + tests/data/test3014 | 56 + tests/data/test3015 | 78 + tests/data/test3016 | 35 + tests/data/test3017 | 67 + tests/data/test3018 | 65 + tests/data/test3019 | 36 + tests/data/test302 | 49 + tests/data/test3020 | 36 + tests/data/test3021 | 53 + tests/data/test3022 | 53 + tests/data/test3023 | 60 + tests/data/test3024 | 60 + tests/data/test3025 | 47 + tests/data/test3026 | 45 + tests/data/test3027 | 55 + tests/data/test3028 | 73 + tests/data/test3029 | 39 + tests/data/test303 | 57 + tests/data/test3030 | 43 + tests/data/test304 | 72 + tests/data/test305 | 32 + tests/data/test306 | 64 + tests/data/test307 | 54 + tests/data/test308 | 35 + tests/data/test309 | 81 + tests/data/test31 | 190 + tests/data/test310 | 56 + tests/data/test3100 | 85 + tests/data/test3101 | 88 + tests/data/test3102 | 51 + tests/data/test3103 | 60 + tests/data/test311 | 43 + tests/data/test312 | 43 + tests/data/test313 | 39 + tests/data/test314 | 196 + tests/data/test315 | 89 + tests/data/test316 | 196 + tests/data/test317 | 96 + tests/data/test318 | 97 + tests/data/test319 | 56 + tests/data/test32 | 53 + tests/data/test320 | 80 + tests/data/test3200 | 25 + tests/data/test3201 | 63 + tests/data/test3202 | 67 + tests/data/test321 | 33 + tests/data/test322 | 33 + tests/data/test323 | 33 + tests/data/test324 | 33 + tests/data/test325 | 64 + tests/data/test326 | 67 + tests/data/test327 | 75 + tests/data/test328 | 55 + tests/data/test329 | 77 + tests/data/test33 | 60 + tests/data/test330 | 93 + tests/data/test331 | 69 + tests/data/test332 | 47 + tests/data/test333 | 35 + tests/data/test334 | 42 + tests/data/test335 | 100 + tests/data/test336 | 58 + tests/data/test337 | 58 + tests/data/test338 | 62 + tests/data/test339 | 61 + tests/data/test34 | 64 + tests/data/test340 | 40 + tests/data/test341 | 54 + tests/data/test342 | 56 + tests/data/test343 | 59 + tests/data/test344 | 56 + tests/data/test345 | 59 + tests/data/test346 | 58 + tests/data/test347 | 60 + tests/data/test348 | 61 + tests/data/test349 | 45 + tests/data/test35 | Bin 0 -> 846 bytes tests/data/test350 | 57 + tests/data/test351 | 56 + tests/data/test352 | 57 + tests/data/test353 | 56 + tests/data/test354 | 50 + tests/data/test355 | 55 + tests/data/test356 | 71 + tests/data/test357 | 81 + tests/data/test358 | 94 + tests/data/test359 | 94 + tests/data/test36 | 64 + tests/data/test360 | 28 + tests/data/test361 | 50 + tests/data/test362 | 51 + tests/data/test363 | 88 + tests/data/test364 | 50 + tests/data/test365 | 65 + tests/data/test366 | 49 + tests/data/test367 | 48 + tests/data/test368 | 49 + tests/data/test369 | 47 + tests/data/test37 | 45 + tests/data/test370 | 36 + tests/data/test371 | 56 + tests/data/test372 | 49 + tests/data/test373 | 78 + tests/data/test374 | 49 + tests/data/test375 | 33 + tests/data/test376 | 64 + tests/data/test378 | 39 + tests/data/test379 | 71 + tests/data/test38 | 59 + tests/data/test380 | 63 + tests/data/test381 | 67 + tests/data/test383 | 56 + tests/data/test384 | 59 + tests/data/test385 | 56 + tests/data/test386 | 74 + tests/data/test387 | 59 + tests/data/test388 | 156 + tests/data/test389 | 57 + tests/data/test39 | 111 + tests/data/test390 | 48 + tests/data/test391 | 72 + tests/data/test392 | 64 + tests/data/test393 | 62 + tests/data/test394 | 61 + tests/data/test395 | 60 + tests/data/test396 | 200 + tests/data/test397 | 196 + tests/data/test398 | 64 + tests/data/test399 | 32 + tests/data/test4 | 61 + tests/data/test40 | 76 + tests/data/test400 | 62 + tests/data/test401 | 57 + tests/data/test402 | 36 + tests/data/test403 | 65 + tests/data/test404 | 32 + tests/data/test405 | 35 + tests/data/test406 | 67 + tests/data/test407 | 60 + tests/data/test408 | 62 + tests/data/test409 | 57 + tests/data/test41 | 35 + tests/data/test410 | 55 + tests/data/test411 | 43 + tests/data/test412 | 64 + tests/data/test413 | 64 + tests/data/test414 | 84 + tests/data/test415 | 65 + tests/data/test416 | 51 + tests/data/test417 | 83 + tests/data/test418 | 67 + tests/data/test419 | 35 + tests/data/test42 | 76 + tests/data/test420 | 75 + tests/data/test421 | 85 + tests/data/test422 | 44 + tests/data/test423 | 51 + tests/data/test424 | 68 + tests/data/test425 | 53 + tests/data/test426 | 34 + tests/data/test427 | 76 + tests/data/test428 | 68 + tests/data/test429 | 63 + tests/data/test43 | 81 + tests/data/test430 | 101 + tests/data/test431 | 95 + tests/data/test432 | 100 + tests/data/test433 | 59 + tests/data/test434 | 46 + tests/data/test435 | 71 + tests/data/test436 | 58 + tests/data/test437 | 68 + tests/data/test438 | 90 + tests/data/test439 | 58 + tests/data/test44 | 75 + tests/data/test440 | 73 + tests/data/test441 | 73 + tests/data/test442 | 213 + tests/data/test443 | 82 + tests/data/test444 | 193 + tests/data/test445 | 61 + tests/data/test446 | 84 + tests/data/test447 | 65 + tests/data/test448 | 67 + tests/data/test449 | 65 + tests/data/test45 | 75 + tests/data/test450 | 60 + tests/data/test451 | 59 + tests/data/test452 | 34 + tests/data/test453 | 33 + tests/data/test454 | 34 + tests/data/test455 | 52 + tests/data/test456 | 33 + tests/data/test457 | 69 + tests/data/test458 | 76 + tests/data/test459 | 63 + tests/data/test46 | 111 + tests/data/test460 | 28 + tests/data/test461 | 48 + tests/data/test47 | 47 + tests/data/test48 | 53 + tests/data/test49 | 72 + tests/data/test490 | 65 + tests/data/test491 | 61 + tests/data/test492 | 86 + tests/data/test493 | 72 + tests/data/test494 | 60 + tests/data/test495 | 56 + tests/data/test496 | 36 + tests/data/test497 | 62 + tests/data/test498 | 56 + tests/data/test5 | 51 + tests/data/test50 | 72 + tests/data/test500 | 58 + tests/data/test501 | 40 + tests/data/test502 | 47 + tests/data/test503 | 90 + tests/data/test504 | 46 + tests/data/test505 | 66 + tests/data/test506 | 251 + tests/data/test507 | 37 + tests/data/test508 | 58 + tests/data/test509 | 41 + tests/data/test51 | 72 + tests/data/test510 | 69 + tests/data/test511 | 52 + tests/data/test512 | 50 + tests/data/test513 | 51 + tests/data/test514 | 54 + tests/data/test515 | 51 + tests/data/test516 | 55 + tests/data/test517 | 45 + tests/data/test518 | 67 + tests/data/test519 | 78 + tests/data/test52 | 72 + tests/data/test520 | 53 + tests/data/test521 | 60 + tests/data/test522 | 57 + tests/data/test523 | 64 + tests/data/test524 | 46 + tests/data/test525 | 59 + tests/data/test526 | 63 + tests/data/test527 | 63 + tests/data/test528 | 65 + tests/data/test529 | 59 + tests/data/test53 | 55 + tests/data/test530 | 49 + tests/data/test531 | 59 + tests/data/test532 | 63 + tests/data/test533 | 55 + tests/data/test534 | 53 + tests/data/test535 | 69 + tests/data/test537 | 64 + tests/data/test538 | 45 + tests/data/test539 | 71 + tests/data/test54 | 43 + tests/data/test540 | 108 + tests/data/test541 | 57 + tests/data/test542 | 57 + tests/data/test543 | 37 + tests/data/test544 | 53 + tests/data/test545 | Bin 0 -> 819 bytes tests/data/test546 | 70 + tests/data/test547 | 122 + tests/data/test548 | 122 + tests/data/test549 | 63 + tests/data/test55 | 64 + tests/data/test550 | 63 + tests/data/test551 | 98 + tests/data/test552 | 90 + tests/data/test553 | 62 + tests/data/test554 | 136 + tests/data/test555 | 127 + tests/data/test556 | 47 + tests/data/test557 | 47 + tests/data/test558 | 59 + tests/data/test559 | 51 + tests/data/test56 | 65 + tests/data/test560 | 53 + tests/data/test561 | 64 + tests/data/test562 | 52 + tests/data/test563 | 59 + tests/data/test564 | 68 + tests/data/test565 | 113 + tests/data/test566 | 57 + tests/data/test567 | 49 + tests/data/test568 | 116 + tests/data/test569 | 110 + tests/data/test57 | 46 + tests/data/test570 | 76 + tests/data/test571 | 122 + tests/data/test572 | 121 + tests/data/test573 | 55 + tests/data/test574 | 98 + tests/data/test575 | 121 + tests/data/test576 | 192 + tests/data/test577 | 55 + tests/data/test578 | 52 + tests/data/test579 | 87 + tests/data/test58 | 48 + tests/data/test580 | 55 + tests/data/test581 | 55 + tests/data/test582 | 49 + tests/data/test583 | 45 + tests/data/test584 | 84 + tests/data/test585 | 66 + tests/data/test586 | 59 + tests/data/test587 | 64 + tests/data/test588 | 69 + tests/data/test589 | 55 + tests/data/test59 | 45 + tests/data/test590 | 113 + tests/data/test591 | 73 + tests/data/test592 | 74 + tests/data/test593 | 72 + tests/data/test594 | 74 + tests/data/test595 | 57 + tests/data/test596 | 60 + tests/data/test597 | 36 + tests/data/test598 | 83 + tests/data/test599 | 86 + tests/data/test6 | 50 + tests/data/test60 | 58 + tests/data/test600 | 42 + tests/data/test601 | 42 + tests/data/test602 | 43 + tests/data/test603 | 43 + tests/data/test604 | 33 + tests/data/test605 | 33 + tests/data/test606 | 33 + tests/data/test607 | 33 + tests/data/test608 | 49 + tests/data/test609 | 45 + tests/data/test61 | 83 + tests/data/test610 | 47 + tests/data/test611 | 47 + tests/data/test612 | 47 + tests/data/test613 | 46 + tests/data/test614 | 47 + tests/data/test615 | 44 + tests/data/test616 | 39 + tests/data/test617 | 39 + tests/data/test618 | 39 + tests/data/test619 | 39 + tests/data/test62 | 67 + tests/data/test620 | 38 + tests/data/test621 | 38 + tests/data/test622 | 43 + tests/data/test623 | 44 + tests/data/test624 | 47 + tests/data/test625 | 47 + tests/data/test626 | 42 + tests/data/test627 | 46 + tests/data/test628 | 33 + tests/data/test629 | 33 + tests/data/test63 | 53 + tests/data/test630 | 34 + tests/data/test631 | 34 + tests/data/test632 | 34 + tests/data/test633 | 42 + tests/data/test634 | 43 + tests/data/test635 | 42 + tests/data/test636 | 43 + tests/data/test637 | 44 + tests/data/test638 | 49 + tests/data/test639 | 49 + tests/data/test64 | 82 + tests/data/test640 | 41 + tests/data/test641 | 41 + tests/data/test642 | 42 + tests/data/test643 | 134 + tests/data/test644 | 85 + tests/data/test645 | 220 + tests/data/test646 | 101 + tests/data/test647 | 82 + tests/data/test648 | 78 + tests/data/test649 | 75 + tests/data/test65 | 82 + tests/data/test650 | 243 + tests/data/test651 | 75 + tests/data/test652 | 361 + tests/data/test653 | 96 + tests/data/test654 | 130 + tests/data/test655 | 50 + tests/data/test656 | 33 + tests/data/test658 | 49 + tests/data/test659 | 54 + tests/data/test66 | 43 + tests/data/test660 | 34 + tests/data/test661 | 73 + tests/data/test662 | 78 + tests/data/test663 | 82 + tests/data/test664 | 44 + tests/data/test665 | 44 + tests/data/test666 | 296 + tests/data/test667 | 92 + tests/data/test668 | 110 + tests/data/test669 | 63 + tests/data/test67 | 91 + tests/data/test670 | 75 + tests/data/test671 | 75 + tests/data/test672 | 75 + tests/data/test673 | 75 + tests/data/test674 | 54 + tests/data/test675 | 55 + tests/data/test676 | 86 + tests/data/test677 | 43 + tests/data/test678 | 59 + tests/data/test679 | 56 + tests/data/test68 | 90 + tests/data/test680 | 40 + tests/data/test681 | 51 + tests/data/test682 | 53 + tests/data/test683 | 53 + tests/data/test684 | 52 + tests/data/test685 | 52 + tests/data/test686 | 34 + tests/data/test687 | 62 + tests/data/test688 | 62 + tests/data/test689 | 53 + tests/data/test69 | 112 + tests/data/test7 | 60 + tests/data/test70 | 85 + tests/data/test700 | 58 + tests/data/test701 | 58 + tests/data/test702 | 47 + tests/data/test703 | 44 + tests/data/test704 | 39 + tests/data/test705 | 39 + tests/data/test706 | 62 + tests/data/test707 | 62 + tests/data/test708 | 61 + tests/data/test709 | 61 + tests/data/test71 | 81 + tests/data/test710 | 58 + tests/data/test711 | 57 + tests/data/test712 | 51 + tests/data/test713 | 52 + tests/data/test714 | 71 + tests/data/test715 | 73 + tests/data/test716 | 45 + tests/data/test717 | 66 + tests/data/test718 | 61 + tests/data/test719 | 63 + tests/data/test72 | 84 + tests/data/test720 | 62 + tests/data/test721 | 62 + tests/data/test722 | 52 + tests/data/test723 | 35 + tests/data/test724 | 58 + tests/data/test725 | 40 + tests/data/test726 | 40 + tests/data/test727 | 52 + tests/data/test728 | 64 + tests/data/test729 | 41 + tests/data/test73 | 56 + tests/data/test730 | 52 + tests/data/test731 | 58 + tests/data/test732 | 52 + tests/data/test733 | 52 + tests/data/test734 | 52 + tests/data/test735 | 52 + tests/data/test736 | 58 + tests/data/test737 | 58 + tests/data/test738 | 37 + tests/data/test739 | 34 + tests/data/test74 | 74 + tests/data/test740 | 60 + tests/data/test741 | 42 + tests/data/test742 | 66 + tests/data/test75 | 44 + tests/data/test76 | 36 + tests/data/test77 | 54 + tests/data/test78 | 66 + tests/data/test79 | 54 + tests/data/test799 | 53 + tests/data/test8 | 100 + tests/data/test80 | 81 + tests/data/test800 | 49 + tests/data/test801 | 46 + tests/data/test802 | 47 + tests/data/test803 | 45 + tests/data/test804 | 47 + tests/data/test805 | 62 + tests/data/test806 | 44 + tests/data/test807 | 45 + tests/data/test808 | 49 + tests/data/test809 | 43 + tests/data/test81 | 93 + tests/data/test810 | 43 + tests/data/test811 | 40 + tests/data/test812 | 40 + tests/data/test813 | 40 + tests/data/test814 | 41 + tests/data/test815 | 46 + tests/data/test816 | 49 + tests/data/test817 | 40 + tests/data/test818 | 46 + tests/data/test819 | 56 + tests/data/test82 | 54 + tests/data/test820 | 57 + tests/data/test821 | 59 + tests/data/test822 | 63 + tests/data/test823 | 63 + tests/data/test824 | 56 + tests/data/test825 | 56 + tests/data/test826 | 57 + tests/data/test827 | 63 + tests/data/test828 | 56 + tests/data/test829 | 29 + tests/data/test83 | 79 + tests/data/test830 | 56 + tests/data/test831 | 68 + tests/data/test832 | 58 + tests/data/test833 | 65 + tests/data/test834 | 77 + tests/data/test835 | 67 + tests/data/test836 | 59 + tests/data/test837 | 56 + tests/data/test838 | 56 + tests/data/test839 | 56 + tests/data/test84 | 54 + tests/data/test840 | 56 + tests/data/test841 | 51 + tests/data/test842 | 59 + tests/data/test843 | 57 + tests/data/test844 | 52 + tests/data/test845 | 54 + tests/data/test846 | 50 + tests/data/test847 | 49 + tests/data/test848 | 56 + tests/data/test849 | 51 + tests/data/test85 | 58 + tests/data/test850 | 49 + tests/data/test851 | 44 + tests/data/test852 | 47 + tests/data/test853 | 53 + tests/data/test854 | 45 + tests/data/test855 | 47 + tests/data/test856 | 48 + tests/data/test857 | 60 + tests/data/test858 | 41 + tests/data/test859 | 41 + tests/data/test86 | 94 + tests/data/test860 | 41 + tests/data/test861 | 52 + tests/data/test862 | 50 + tests/data/test863 | 41 + tests/data/test864 | 54 + tests/data/test865 | 57 + tests/data/test866 | 58 + tests/data/test867 | 60 + tests/data/test868 | 64 + tests/data/test869 | 64 + tests/data/test87 | 61 + tests/data/test870 | 57 + tests/data/test871 | 56 + tests/data/test872 | 57 + tests/data/test873 | 63 + tests/data/test874 | 56 + tests/data/test875 | 29 + tests/data/test876 | 57 + tests/data/test877 | 69 + tests/data/test878 | 59 + tests/data/test879 | 66 + tests/data/test88 | 98 + tests/data/test880 | 78 + tests/data/test881 | 68 + tests/data/test882 | 58 + tests/data/test883 | 57 + tests/data/test884 | 57 + tests/data/test885 | 56 + tests/data/test886 | 56 + tests/data/test887 | 58 + tests/data/test888 | 57 + tests/data/test889 | 56 + tests/data/test89 | 136 + tests/data/test890 | 55 + tests/data/test891 | 47 + tests/data/test892 | 57 + tests/data/test893 | 53 + tests/data/test894 | 37 + tests/data/test895 | 50 + tests/data/test896 | 38 + tests/data/test897 | 70 + tests/data/test898 | 94 + tests/data/test899 | 64 + tests/data/test9 | 75 + tests/data/test90 | 184 + tests/data/test900 | 51 + tests/data/test901 | 63 + tests/data/test902 | 57 + tests/data/test903 | 56 + tests/data/test904 | 57 + tests/data/test905 | 59 + tests/data/test906 | 63 + tests/data/test907 | 63 + tests/data/test908 | 56 + tests/data/test909 | 51 + tests/data/test91 | 113 + tests/data/test910 | 51 + tests/data/test911 | 46 + tests/data/test912 | 55 + tests/data/test913 | 50 + tests/data/test914 | 49 + tests/data/test915 | 51 + tests/data/test916 | 47 + tests/data/test917 | 55 + tests/data/test918 | 48 + tests/data/test919 | 55 + tests/data/test92 | 67 + tests/data/test920 | 56 + tests/data/test921 | 62 + tests/data/test922 | 55 + tests/data/test923 | 37 + tests/data/test924 | 43 + tests/data/test925 | 40 + tests/data/test926 | 44 + tests/data/test927 | 43 + tests/data/test928 | 41 + tests/data/test929 | 38 + tests/data/test93 | 51 + tests/data/test930 | 38 + tests/data/test931 | 29 + tests/data/test932 | 56 + tests/data/test933 | 68 + tests/data/test934 | 58 + tests/data/test935 | 65 + tests/data/test936 | 77 + tests/data/test937 | 67 + tests/data/test938 | 65 + tests/data/test939 | 50 + tests/data/test94 | 56 + tests/data/test940 | 45 + tests/data/test941 | 66 + tests/data/test942 | 56 + tests/data/test943 | 56 + tests/data/test944 | 55 + tests/data/test945 | 55 + tests/data/test946 | 57 + tests/data/test947 | 56 + tests/data/test948 | 58 + tests/data/test949 | 57 + tests/data/test95 | 81 + tests/data/test950 | 43 + tests/data/test951 | 45 + tests/data/test952 | 45 + tests/data/test953 | 56 + tests/data/test954 | 55 + tests/data/test955 | 59 + tests/data/test956 | 57 + tests/data/test957 | 51 + tests/data/test958 | 51 + tests/data/test959 | 60 + tests/data/test96 | 46 + tests/data/test960 | 58 + tests/data/test961 | 52 + tests/data/test962 | 63 + tests/data/test963 | 63 + tests/data/test964 | 49 + tests/data/test965 | 66 + tests/data/test966 | 66 + tests/data/test967 | 55 + tests/data/test968 | 52 + tests/data/test969 | 51 + tests/data/test97 | 50 + tests/data/test970 | 65 + tests/data/test971 | 30 + tests/data/test972 | 66 + tests/data/test973 | 88 + tests/data/test974 | 91 + tests/data/test975 | 88 + tests/data/test976 | 92 + tests/data/test977 | 62 + tests/data/test978 | 56 + tests/data/test979 | 64 + tests/data/test98 | 53 + tests/data/test980 | 52 + tests/data/test981 | 59 + tests/data/test982 | 57 + tests/data/test983 | 52 + tests/data/test984 | 56 + tests/data/test985 | 54 + tests/data/test986 | 53 + tests/data/test987 | 51 + tests/data/test988 | 48 + tests/data/test989 | 48 + tests/data/test99 | 67 + tests/data/test990 | 57 + tests/data/test991 | 60 + tests/data/test992 | 52 + tests/devtest.pl | 202 + tests/dictserver.py | 197 + tests/directories.pm | 307 + tests/ftpserver.pl | 3392 ++ tests/getpart.pm | 359 + tests/globalconfig.pm | 117 + tests/http-server.pl | 194 + tests/http/Makefile.am | 37 + tests/http/Makefile.in | 787 + tests/http/README.md | 128 + tests/http/clients/Makefile.am | 73 + tests/http/clients/Makefile.in | 904 + tests/http/clients/Makefile.inc | 33 + tests/http/clients/h2-download.c | 350 + tests/http/clients/h2-pausing.c | 339 + tests/http/clients/h2-serverpush.c | 271 + tests/http/clients/h2-upgrade-extreme.c | 249 + tests/http/clients/tls-session-reuse.c | 306 + tests/http/clients/ws-data.c | 263 + tests/http/clients/ws-pingpong.c | 158 + tests/http/config.ini.in | 37 + tests/http2-server.pl | 119 + tests/http3-server.pl | 119 + tests/libtest/.checksrc | 2 + tests/libtest/CMakeLists.txt | 88 + tests/libtest/Makefile.am | 140 + tests/libtest/Makefile.in | 6152 ++ tests/libtest/Makefile.inc | 700 + tests/libtest/chkhostname.c | 49 + tests/libtest/first.c | 189 + tests/libtest/lib1156.c | 173 + tests/libtest/lib1301.c | 62 + tests/libtest/lib1500.c | 92 + tests/libtest/lib1501.c | 113 + tests/libtest/lib1502.c | 159 + tests/libtest/lib1506.c | 139 + tests/libtest/lib1507.c | 152 + tests/libtest/lib1508.c | 51 + tests/libtest/lib1509.c | 99 + tests/libtest/lib1510.c | 103 + tests/libtest/lib1511.c | 77 + tests/libtest/lib1512.c | 97 + tests/libtest/lib1513.c | 78 + tests/libtest/lib1514.c | 86 + tests/libtest/lib1515.c | 152 + tests/libtest/lib1517.c | 123 + tests/libtest/lib1518.c | 106 + tests/libtest/lib1520.c | 115 + tests/libtest/lib1522.c | 101 + tests/libtest/lib1523.c | 85 + tests/libtest/lib1525.c | 100 + tests/libtest/lib1526.c | 105 + tests/libtest/lib1527.c | 102 + tests/libtest/lib1528.c | 75 + tests/libtest/lib1529.c | 63 + tests/libtest/lib1530.c | 70 + tests/libtest/lib1531.c | 160 + tests/libtest/lib1532.c | 82 + tests/libtest/lib1533.c | 201 + tests/libtest/lib1534.c | 131 + tests/libtest/lib1535.c | 138 + tests/libtest/lib1536.c | 131 + tests/libtest/lib1537.c | 91 + tests/libtest/lib1538.c | 60 + tests/libtest/lib1540.c | 118 + tests/libtest/lib1542.c | 84 + tests/libtest/lib1545.c | 56 + tests/libtest/lib1550.c | 48 + tests/libtest/lib1551.c | 53 + tests/libtest/lib1552.c | 95 + tests/libtest/lib1553.c | 111 + tests/libtest/lib1554.c | 95 + tests/libtest/lib1555.c | 83 + tests/libtest/lib1556.c | 80 + tests/libtest/lib1557.c | 64 + tests/libtest/lib1558.c | 69 + tests/libtest/lib1559.c | 76 + tests/libtest/lib1560.c | 1797 + tests/libtest/lib1564.c | 135 + tests/libtest/lib1565.c | 209 + tests/libtest/lib1567.c | 59 + tests/libtest/lib1568.c | 52 + tests/libtest/lib1569.c | 51 + tests/libtest/lib1591.c | 120 + tests/libtest/lib1592.c | 124 + tests/libtest/lib1593.c | 81 + tests/libtest/lib1594.c | 68 + tests/libtest/lib1597.c | 115 + tests/libtest/lib1662.c | 90 + tests/libtest/lib1900.c | 55 + tests/libtest/lib1903.c | 57 + tests/libtest/lib1905.c | 100 + tests/libtest/lib1906.c | 85 + tests/libtest/lib1907.c | 56 + tests/libtest/lib1908.c | 64 + tests/libtest/lib1910.c | 49 + tests/libtest/lib1911.c | 98 + tests/libtest/lib1912.c | 84 + tests/libtest/lib1913.c | 50 + tests/libtest/lib1915.c | 136 + tests/libtest/lib1916.c | 56 + tests/libtest/lib1918.c | 57 + tests/libtest/lib1919.c | 56 + tests/libtest/lib1933.c | 68 + tests/libtest/lib1934.c | 69 + tests/libtest/lib1935.c | 69 + tests/libtest/lib1936.c | 69 + tests/libtest/lib1937.c | 72 + tests/libtest/lib1938.c | 74 + tests/libtest/lib1939.c | 72 + tests/libtest/lib1940.c | 120 + tests/libtest/lib1945.c | 81 + tests/libtest/lib1947.c | 92 + tests/libtest/lib1948.c | 78 + tests/libtest/lib1955.c | 90 + tests/libtest/lib1956.c | 73 + tests/libtest/lib1957.c | 72 + tests/libtest/lib1958.c | 72 + tests/libtest/lib1959.c | 74 + tests/libtest/lib1960.c | 149 + tests/libtest/lib1964.c | 68 + tests/libtest/lib1970.c | 73 + tests/libtest/lib1971.c | 83 + tests/libtest/lib1972.c | 84 + tests/libtest/lib1973.c | 72 + tests/libtest/lib1974.c | 65 + tests/libtest/lib1975.c | 85 + tests/libtest/lib2301.c | 154 + tests/libtest/lib2302.c | 126 + tests/libtest/lib2304.c | 142 + tests/libtest/lib2305.c | 107 + tests/libtest/lib2306.c | 55 + tests/libtest/lib2402.c | 142 + tests/libtest/lib2404.c | 144 + tests/libtest/lib2502.c | 141 + tests/libtest/lib3010.c | 67 + tests/libtest/lib3025.c | 61 + tests/libtest/lib3026.c | 185 + tests/libtest/lib3027.c | 56 + tests/libtest/lib3100.c | 68 + tests/libtest/lib3101.c | 64 + tests/libtest/lib3102.c | 141 + tests/libtest/lib3103.c | 66 + tests/libtest/lib500.c | 158 + tests/libtest/lib501.c | 60 + tests/libtest/lib502.c | 93 + tests/libtest/lib503.c | 103 + tests/libtest/lib504.c | 115 + tests/libtest/lib505.c | 152 + tests/libtest/lib506.c | 382 + tests/libtest/lib507.c | 102 + tests/libtest/lib508.c | 105 + tests/libtest/lib509.c | 117 + tests/libtest/lib510.c | 132 + tests/libtest/lib511.c | 58 + tests/libtest/lib512.c | 76 + tests/libtest/lib513.c | 85 + tests/libtest/lib514.c | 81 + tests/libtest/lib515.c | 62 + tests/libtest/lib516.c | 63 + tests/libtest/lib517.c | 173 + tests/libtest/lib518.c | 507 + tests/libtest/lib519.c | 66 + tests/libtest/lib520.c | 57 + tests/libtest/lib521.c | 58 + tests/libtest/lib523.c | 59 + tests/libtest/lib524.c | 57 + tests/libtest/lib525.c | 164 + tests/libtest/lib526.c | 186 + tests/libtest/lib530.c | 391 + tests/libtest/lib533.c | 114 + tests/libtest/lib537.c | 511 + tests/libtest/lib539.c | 93 + tests/libtest/lib540.c | 256 + tests/libtest/lib541.c | 119 + tests/libtest/lib542.c | 75 + tests/libtest/lib543.c | 72 + tests/libtest/lib544.c | 84 + tests/libtest/lib547.c | 127 + tests/libtest/lib549.c | 67 + tests/libtest/lib552.c | 221 + tests/libtest/lib553.c | 113 + tests/libtest/lib554.c | 208 + tests/libtest/lib555.c | 156 + tests/libtest/lib556.c | 99 + tests/libtest/lib557.c | 1508 + tests/libtest/lib558.c | 54 + tests/libtest/lib559.c | 57 + tests/libtest/lib560.c | 115 + tests/libtest/lib562.c | 76 + tests/libtest/lib564.c | 95 + tests/libtest/lib566.c | 71 + tests/libtest/lib567.c | 72 + tests/libtest/lib568.c | 180 + tests/libtest/lib569.c | 128 + tests/libtest/lib570.c | 121 + tests/libtest/lib571.c | 215 + tests/libtest/lib572.c | 185 + tests/libtest/lib573.c | 115 + tests/libtest/lib574.c | 76 + tests/libtest/lib575.c | 116 + tests/libtest/lib576.c | 122 + tests/libtest/lib578.c | 102 + tests/libtest/lib579.c | 160 + tests/libtest/lib582.c | 363 + tests/libtest/lib583.c | 91 + tests/libtest/lib586.c | 246 + tests/libtest/lib589.c | 76 + tests/libtest/lib590.c | 73 + tests/libtest/lib591.c | 152 + tests/libtest/lib597.c | 133 + tests/libtest/lib598.c | 74 + tests/libtest/lib599.c | 103 + tests/libtest/lib643.c | 269 + tests/libtest/lib650.c | 213 + tests/libtest/lib651.c | 97 + tests/libtest/lib652.c | 133 + tests/libtest/lib653.c | 65 + tests/libtest/lib654.c | 169 + tests/libtest/lib655.c | 114 + tests/libtest/lib658.c | 79 + tests/libtest/lib659.c | 77 + tests/libtest/lib661.c | 168 + tests/libtest/lib666.c | 122 + tests/libtest/lib667.c | 114 + tests/libtest/lib668.c | 118 + tests/libtest/lib670.c | 264 + tests/libtest/lib674.c | 84 + tests/libtest/lib676.c | 70 + tests/libtest/lib677.c | 130 + tests/libtest/lib678.c | 122 + tests/libtest/libauthretry.c | 149 + tests/libtest/libntlmconnect.c | 237 + tests/libtest/libprereq.c | 99 + tests/libtest/mk-lib1521.pl | 369 + tests/libtest/notexists.pl | 38 + tests/libtest/sethostname.c | 41 + tests/libtest/stub_gssapi.c | 462 + tests/libtest/stub_gssapi.h | 184 + tests/libtest/test.h | 500 + tests/libtest/test1013.pl | 74 + tests/libtest/test1022.pl | 77 + tests/libtest/test307.pl | 42 + tests/libtest/test610.pl | 56 + tests/libtest/test613.pl | 146 + tests/libtest/testtrace.c | 145 + tests/libtest/testtrace.h | 38 + tests/libtest/testutil.c | 162 + tests/libtest/testutil.h | 49 + tests/memanalyze.pl | 434 + tests/negtelnetserver.py | 381 + tests/pathhelp.pm | 795 + tests/processhelp.pm | 417 + tests/rtspserver.pl | 136 + tests/runner.pm | 1482 + tests/runtests.1 | 230 + tests/runtests.pl | 3046 + tests/secureserver.pl | 379 + tests/server/CMakeLists.txt | 82 + tests/server/Makefile.am | 65 + tests/server/Makefile.in | 3663 ++ tests/server/Makefile.inc | 117 + tests/server/base64.pl | 32 + tests/server/disabled.c | 117 + tests/server/fake_ntlm.c | 286 + tests/server/getpart.c | 523 + tests/server/getpart.h | 36 + tests/server/mqttd.c | 1100 + tests/server/resolve.c | 156 + tests/server/rtspd.c | 1411 + tests/server/server_setup.h | 31 + tests/server/server_sockaddr.h | 43 + tests/server/sockfilt.c | 1592 + tests/server/socksd.c | 1175 + tests/server/sws.c | 2460 + tests/server/testpart.c | 51 + tests/server/tftp.h | 63 + tests/server/tftpd.c | 1378 + tests/server/util.c | 866 + tests/server/util.h | 98 + tests/serverhelp.pm | 280 + tests/servers.pm | 3010 + tests/smbserver.py | 454 + tests/sshhelp.pm | 427 + tests/sshserver.pl | 1199 + tests/stunnel.pem | 165 + tests/test1119.pl | 245 + tests/test1132.pl | 98 + tests/test1135.pl | 114 + tests/test1139.pl | 312 + tests/test1140.pl | 114 + tests/test1165.pl | 189 + tests/test1167.pl | 158 + tests/test1173.pl | 379 + tests/test1175.pl | 82 + tests/test1177.pl | 94 + tests/test1222.pl | 329 + tests/test1275.pl | 117 + tests/test1276.pl | 66 + tests/test1477.pl | 100 + tests/test1544.pl | 147 + tests/test971.pl | 125 + tests/testcurl.1 | 126 + tests/testcurl.pl | 787 + tests/testutil.pm | 217 + tests/tftpserver.pl | 133 + tests/unit/CMakeLists.txt | 42 + tests/unit/Makefile.am | 69 + tests/unit/Makefile.in | 1477 + tests/unit/Makefile.inc | 132 + tests/unit/README.md | 73 + tests/unit/curlcheck.h | 111 + tests/unit/unit1300.c | 223 + tests/unit/unit1302.c | 191 + tests/unit/unit1303.c | 153 + tests/unit/unit1304.c | 198 + tests/unit/unit1305.c | 132 + tests/unit/unit1307.c | 321 + tests/unit/unit1308.c | 98 + tests/unit/unit1309.c | 144 + tests/unit/unit1323.c | 68 + tests/unit/unit1330.c | 43 + tests/unit/unit1394.c | 133 + tests/unit/unit1395.c | 107 + tests/unit/unit1396.c | 117 + tests/unit/unit1397.c | 124 + tests/unit/unit1398.c | 98 + tests/unit/unit1399.c | 119 + tests/unit/unit1600.c | 75 + tests/unit/unit1601.c | 60 + tests/unit/unit1602.c | 81 + tests/unit/unit1603.c | 153 + tests/unit/unit1604.c | 358 + tests/unit/unit1605.c | 59 + tests/unit/unit1606.c | 93 + tests/unit/unit1607.c | 235 + tests/unit/unit1608.c | 89 + tests/unit/unit1609.c | 220 + tests/unit/unit1610.c | 66 + tests/unit/unit1611.c | 60 + tests/unit/unit1612.c | 70 + tests/unit/unit1614.c | 164 + tests/unit/unit1620.c | 93 + tests/unit/unit1621.c | 81 + tests/unit/unit1650.c | 297 + tests/unit/unit1651.c | 392 + tests/unit/unit1652.c | 143 + tests/unit/unit1653.c | 232 + tests/unit/unit1654.c | 113 + tests/unit/unit1655.c | 190 + tests/unit/unit1660.c | 179 + tests/unit/unit1661.c | 115 + tests/unit/unit2600.c | 399 + tests/unit/unit2601.c | 246 + tests/unit/unit2602.c | 148 + tests/unit/unit2603.c | 190 + tests/unit/unit3200.c | 180 + tests/util.py | 92 + tests/valgrind.pm | 50 + tests/valgrind.supp | 151 + winbuild/Makefile.vc | 310 + winbuild/MakefileBuild.vc | 711 + winbuild/README.md | 199 + winbuild/gen_resp_file.bat | 34 + 3764 files changed, 681191 insertions(+) create mode 100644 CHANGES create mode 100644 CMake/CMakeConfigurableFile.in create mode 100644 CMake/CurlSymbolHiding.cmake create mode 100644 CMake/CurlTests.c create mode 100644 CMake/FindBearSSL.cmake create mode 100644 CMake/FindBrotli.cmake create mode 100644 CMake/FindCARES.cmake create mode 100644 CMake/FindGSS.cmake create mode 100644 CMake/FindLibPSL.cmake create mode 100644 CMake/FindLibSSH2.cmake create mode 100644 CMake/FindMSH3.cmake create mode 100644 CMake/FindMbedTLS.cmake create mode 100644 CMake/FindNGHTTP2.cmake create mode 100644 CMake/FindNGHTTP3.cmake create mode 100644 CMake/FindNGTCP2.cmake create mode 100644 CMake/FindQUICHE.cmake create mode 100644 CMake/FindWolfSSL.cmake create mode 100644 CMake/FindZstd.cmake create mode 100644 CMake/Macros.cmake create mode 100644 CMake/OtherTests.cmake create mode 100644 CMake/PickyWarnings.cmake create mode 100644 CMake/Platforms/WindowsCache.cmake create mode 100644 CMake/Utilities.cmake create mode 100644 CMake/cmake_uninstall.cmake.in create mode 100644 CMake/curl-config.cmake.in create mode 100644 CMakeLists.txt create mode 100644 COPYING create mode 100755 MacOSX-Framework create mode 100644 Makefile create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 README create mode 100644 RELEASE-NOTES create mode 100644 acinclude.m4 create mode 100644 aclocal.m4 create mode 100755 buildconf create mode 100644 buildconf.bat create mode 100755 compile create mode 100755 config.guess create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.ac create mode 100644 curl-config.in create mode 100755 depcomp create mode 100644 docs/ALTSVC.md create mode 100644 docs/BINDINGS.md create mode 100644 docs/BUFREF.md create mode 100644 docs/BUG-BOUNTY.md create mode 100644 docs/BUGS.md create mode 100644 docs/CHECKSRC.md create mode 100644 docs/CIPHERS.md create mode 100644 docs/CLIENT-WRITERS.md create mode 100644 docs/CMakeLists.txt create mode 100644 docs/CODE_OF_CONDUCT.md create mode 100644 docs/CODE_REVIEW.md create mode 100644 docs/CODE_STYLE.md create mode 100644 docs/CONNECTION-FILTERS.md create mode 100644 docs/CONTRIBUTE.md create mode 100644 docs/CURL-DISABLE.md create mode 100644 docs/CURLDOWN.md create mode 100644 docs/DEPRECATE.md create mode 100644 docs/DYNBUF.md create mode 100644 docs/EARLY-RELEASE.md create mode 100644 docs/EXPERIMENTAL.md create mode 100644 docs/FAQ create mode 100644 docs/FEATURES.md create mode 100644 docs/GOVERNANCE.md create mode 100644 docs/HELP-US.md create mode 100644 docs/HISTORY.md create mode 100644 docs/HSTS.md create mode 100644 docs/HTTP-COOKIES.md create mode 100644 docs/HTTP2.md create mode 100644 docs/HTTP3.md create mode 100644 docs/HYPER.md create mode 100644 docs/INSTALL create mode 100644 docs/INSTALL-CMAKE.md create mode 100644 docs/INSTALL.md create mode 100644 docs/INTERNALS.md create mode 100644 docs/KNOWN_BUGS create mode 100644 docs/MAIL-ETIQUETTE create mode 100644 docs/MQTT.md create mode 100644 docs/Makefile.am create mode 100644 docs/Makefile.in create mode 100644 docs/NEW-PROTOCOL.md create mode 100644 docs/PARALLEL-TRANSFERS.md create mode 100644 docs/README.md create mode 100644 docs/RELEASE-PROCEDURE.md create mode 100644 docs/ROADMAP.md create mode 100644 docs/RUSTLS.md create mode 100644 docs/SECURITY-ADVISORY.md create mode 100644 docs/SSL-PROBLEMS.md create mode 100644 docs/SSLCERTS.md create mode 100644 docs/THANKS create mode 100644 docs/TODO create mode 100644 docs/TheArtOfHttpScripting.md create mode 100644 docs/URL-SYNTAX.md create mode 100644 docs/VERSIONS.md create mode 100644 docs/VULN-DISCLOSURE-POLICY.md create mode 100644 docs/WEBSOCKET.md create mode 100644 docs/cmdline-opts/CMakeLists.txt create mode 100644 docs/cmdline-opts/MANPAGE.md create mode 100644 docs/cmdline-opts/Makefile.am create mode 100644 docs/cmdline-opts/Makefile.in create mode 100644 docs/cmdline-opts/Makefile.inc create mode 100644 docs/cmdline-opts/_AUTHORS.md create mode 100644 docs/cmdline-opts/_BUGS.md create mode 100644 docs/cmdline-opts/_DESCRIPTION.md create mode 100644 docs/cmdline-opts/_ENVIRONMENT.md create mode 100644 docs/cmdline-opts/_EXITCODES.md create mode 100644 docs/cmdline-opts/_FILES.md create mode 100644 docs/cmdline-opts/_GLOBBING.md create mode 100644 docs/cmdline-opts/_NAME.md create mode 100644 docs/cmdline-opts/_OPTIONS.md create mode 100644 docs/cmdline-opts/_OUTPUT.md create mode 100644 docs/cmdline-opts/_PROGRESS.md create mode 100644 docs/cmdline-opts/_PROTOCOLS.md create mode 100644 docs/cmdline-opts/_PROXYPREFIX.md create mode 100644 docs/cmdline-opts/_SEEALSO.md create mode 100644 docs/cmdline-opts/_SYNOPSIS.md create mode 100644 docs/cmdline-opts/_URL.md create mode 100644 docs/cmdline-opts/_VARIABLES.md create mode 100644 docs/cmdline-opts/_VERSION.md create mode 100644 docs/cmdline-opts/_WWW.md create mode 100644 docs/cmdline-opts/abstract-unix-socket.md create mode 100644 docs/cmdline-opts/alt-svc.md create mode 100644 docs/cmdline-opts/anyauth.md create mode 100644 docs/cmdline-opts/append.md create mode 100644 docs/cmdline-opts/aws-sigv4.md create mode 100644 docs/cmdline-opts/basic.md create mode 100644 docs/cmdline-opts/ca-native.md create mode 100644 docs/cmdline-opts/cacert.md create mode 100644 docs/cmdline-opts/capath.md create mode 100644 docs/cmdline-opts/cert-status.md create mode 100644 docs/cmdline-opts/cert-type.md create mode 100644 docs/cmdline-opts/cert.md create mode 100644 docs/cmdline-opts/ciphers.md create mode 100644 docs/cmdline-opts/compressed-ssh.md create mode 100644 docs/cmdline-opts/compressed.md create mode 100644 docs/cmdline-opts/config.md create mode 100644 docs/cmdline-opts/connect-timeout.md create mode 100644 docs/cmdline-opts/connect-to.md create mode 100644 docs/cmdline-opts/continue-at.md create mode 100644 docs/cmdline-opts/cookie-jar.md create mode 100644 docs/cmdline-opts/cookie.md create mode 100644 docs/cmdline-opts/create-dirs.md create mode 100644 docs/cmdline-opts/create-file-mode.md create mode 100644 docs/cmdline-opts/crlf.md create mode 100644 docs/cmdline-opts/crlfile.md create mode 100644 docs/cmdline-opts/curves.md create mode 100644 docs/cmdline-opts/data-ascii.md create mode 100644 docs/cmdline-opts/data-binary.md create mode 100644 docs/cmdline-opts/data-raw.md create mode 100644 docs/cmdline-opts/data-urlencode.md create mode 100644 docs/cmdline-opts/data.md create mode 100644 docs/cmdline-opts/delegation.md create mode 100644 docs/cmdline-opts/digest.md create mode 100644 docs/cmdline-opts/disable-eprt.md create mode 100644 docs/cmdline-opts/disable-epsv.md create mode 100644 docs/cmdline-opts/disable.md create mode 100644 docs/cmdline-opts/disallow-username-in-url.md create mode 100644 docs/cmdline-opts/dns-interface.md create mode 100644 docs/cmdline-opts/dns-ipv4-addr.md create mode 100644 docs/cmdline-opts/dns-ipv6-addr.md create mode 100644 docs/cmdline-opts/dns-servers.md create mode 100644 docs/cmdline-opts/doh-cert-status.md create mode 100644 docs/cmdline-opts/doh-insecure.md create mode 100644 docs/cmdline-opts/doh-url.md create mode 100644 docs/cmdline-opts/dump-header.md create mode 100644 docs/cmdline-opts/egd-file.md create mode 100644 docs/cmdline-opts/engine.md create mode 100644 docs/cmdline-opts/etag-compare.md create mode 100644 docs/cmdline-opts/etag-save.md create mode 100644 docs/cmdline-opts/expect100-timeout.md create mode 100644 docs/cmdline-opts/fail-early.md create mode 100644 docs/cmdline-opts/fail-with-body.md create mode 100644 docs/cmdline-opts/fail.md create mode 100644 docs/cmdline-opts/false-start.md create mode 100644 docs/cmdline-opts/form-escape.md create mode 100644 docs/cmdline-opts/form-string.md create mode 100644 docs/cmdline-opts/form.md create mode 100644 docs/cmdline-opts/ftp-account.md create mode 100644 docs/cmdline-opts/ftp-alternative-to-user.md create mode 100644 docs/cmdline-opts/ftp-create-dirs.md create mode 100644 docs/cmdline-opts/ftp-method.md create mode 100644 docs/cmdline-opts/ftp-pasv.md create mode 100644 docs/cmdline-opts/ftp-port.md create mode 100644 docs/cmdline-opts/ftp-pret.md create mode 100644 docs/cmdline-opts/ftp-skip-pasv-ip.md create mode 100644 docs/cmdline-opts/ftp-ssl-ccc-mode.md create mode 100644 docs/cmdline-opts/ftp-ssl-ccc.md create mode 100644 docs/cmdline-opts/ftp-ssl-control.md create mode 100755 docs/cmdline-opts/gen.pl create mode 100644 docs/cmdline-opts/get.md create mode 100644 docs/cmdline-opts/globoff.md create mode 100644 docs/cmdline-opts/happy-eyeballs-timeout-ms.md create mode 100644 docs/cmdline-opts/haproxy-clientip.md create mode 100644 docs/cmdline-opts/haproxy-protocol.md create mode 100644 docs/cmdline-opts/head.md create mode 100644 docs/cmdline-opts/header.md create mode 100644 docs/cmdline-opts/help.md create mode 100644 docs/cmdline-opts/hostpubmd5.md create mode 100644 docs/cmdline-opts/hostpubsha256.md create mode 100644 docs/cmdline-opts/hsts.md create mode 100644 docs/cmdline-opts/http0.9.md create mode 100644 docs/cmdline-opts/http1.0.md create mode 100644 docs/cmdline-opts/http1.1.md create mode 100644 docs/cmdline-opts/http2-prior-knowledge.md create mode 100644 docs/cmdline-opts/http2.md create mode 100644 docs/cmdline-opts/http3-only.md create mode 100644 docs/cmdline-opts/http3.md create mode 100644 docs/cmdline-opts/ignore-content-length.md create mode 100644 docs/cmdline-opts/include.md create mode 100644 docs/cmdline-opts/insecure.md create mode 100644 docs/cmdline-opts/interface.md create mode 100644 docs/cmdline-opts/ipfs-gateway.md create mode 100644 docs/cmdline-opts/ipv4.md create mode 100644 docs/cmdline-opts/ipv6.md create mode 100644 docs/cmdline-opts/json.md create mode 100644 docs/cmdline-opts/junk-session-cookies.md create mode 100644 docs/cmdline-opts/keepalive-time.md create mode 100644 docs/cmdline-opts/key-type.md create mode 100644 docs/cmdline-opts/key.md create mode 100644 docs/cmdline-opts/krb.md create mode 100644 docs/cmdline-opts/libcurl.md create mode 100644 docs/cmdline-opts/limit-rate.md create mode 100644 docs/cmdline-opts/list-only.md create mode 100644 docs/cmdline-opts/local-port.md create mode 100644 docs/cmdline-opts/location-trusted.md create mode 100644 docs/cmdline-opts/location.md create mode 100644 docs/cmdline-opts/login-options.md create mode 100644 docs/cmdline-opts/mail-auth.md create mode 100644 docs/cmdline-opts/mail-from.md create mode 100644 docs/cmdline-opts/mail-rcpt-allowfails.md create mode 100644 docs/cmdline-opts/mail-rcpt.md create mode 100644 docs/cmdline-opts/mainpage.idx create mode 100644 docs/cmdline-opts/manual.md create mode 100644 docs/cmdline-opts/max-filesize.md create mode 100644 docs/cmdline-opts/max-redirs.md create mode 100644 docs/cmdline-opts/max-time.md create mode 100644 docs/cmdline-opts/metalink.md create mode 100644 docs/cmdline-opts/negotiate.md create mode 100644 docs/cmdline-opts/netrc-file.md create mode 100644 docs/cmdline-opts/netrc-optional.md create mode 100644 docs/cmdline-opts/netrc.md create mode 100644 docs/cmdline-opts/next.md create mode 100644 docs/cmdline-opts/no-alpn.md create mode 100644 docs/cmdline-opts/no-buffer.md create mode 100644 docs/cmdline-opts/no-clobber.md create mode 100644 docs/cmdline-opts/no-keepalive.md create mode 100644 docs/cmdline-opts/no-npn.md create mode 100644 docs/cmdline-opts/no-progress-meter.md create mode 100644 docs/cmdline-opts/no-sessionid.md create mode 100644 docs/cmdline-opts/noproxy.md create mode 100644 docs/cmdline-opts/ntlm-wb.md create mode 100644 docs/cmdline-opts/ntlm.md create mode 100644 docs/cmdline-opts/oauth2-bearer.md create mode 100644 docs/cmdline-opts/output-dir.md create mode 100644 docs/cmdline-opts/output.md create mode 100644 docs/cmdline-opts/parallel-immediate.md create mode 100644 docs/cmdline-opts/parallel-max.md create mode 100644 docs/cmdline-opts/parallel.md create mode 100644 docs/cmdline-opts/pass.md create mode 100644 docs/cmdline-opts/path-as-is.md create mode 100644 docs/cmdline-opts/pinnedpubkey.md create mode 100644 docs/cmdline-opts/post301.md create mode 100644 docs/cmdline-opts/post302.md create mode 100644 docs/cmdline-opts/post303.md create mode 100644 docs/cmdline-opts/preproxy.md create mode 100644 docs/cmdline-opts/progress-bar.md create mode 100644 docs/cmdline-opts/proto-default.md create mode 100644 docs/cmdline-opts/proto-redir.md create mode 100644 docs/cmdline-opts/proto.md create mode 100644 docs/cmdline-opts/proxy-anyauth.md create mode 100644 docs/cmdline-opts/proxy-basic.md create mode 100644 docs/cmdline-opts/proxy-ca-native.md create mode 100644 docs/cmdline-opts/proxy-cacert.md create mode 100644 docs/cmdline-opts/proxy-capath.md create mode 100644 docs/cmdline-opts/proxy-cert-type.md create mode 100644 docs/cmdline-opts/proxy-cert.md create mode 100644 docs/cmdline-opts/proxy-ciphers.md create mode 100644 docs/cmdline-opts/proxy-crlfile.md create mode 100644 docs/cmdline-opts/proxy-digest.md create mode 100644 docs/cmdline-opts/proxy-header.md create mode 100644 docs/cmdline-opts/proxy-http2.md create mode 100644 docs/cmdline-opts/proxy-insecure.md create mode 100644 docs/cmdline-opts/proxy-key-type.md create mode 100644 docs/cmdline-opts/proxy-key.md create mode 100644 docs/cmdline-opts/proxy-negotiate.md create mode 100644 docs/cmdline-opts/proxy-ntlm.md create mode 100644 docs/cmdline-opts/proxy-pass.md create mode 100644 docs/cmdline-opts/proxy-pinnedpubkey.md create mode 100644 docs/cmdline-opts/proxy-service-name.md create mode 100644 docs/cmdline-opts/proxy-ssl-allow-beast.md create mode 100644 docs/cmdline-opts/proxy-ssl-auto-client-cert.md create mode 100644 docs/cmdline-opts/proxy-tls13-ciphers.md create mode 100644 docs/cmdline-opts/proxy-tlsauthtype.md create mode 100644 docs/cmdline-opts/proxy-tlspassword.md create mode 100644 docs/cmdline-opts/proxy-tlsuser.md create mode 100644 docs/cmdline-opts/proxy-tlsv1.md create mode 100644 docs/cmdline-opts/proxy-user.md create mode 100644 docs/cmdline-opts/proxy.md create mode 100644 docs/cmdline-opts/proxy1.0.md create mode 100644 docs/cmdline-opts/proxytunnel.md create mode 100644 docs/cmdline-opts/pubkey.md create mode 100644 docs/cmdline-opts/quote.md create mode 100644 docs/cmdline-opts/random-file.md create mode 100644 docs/cmdline-opts/range.md create mode 100644 docs/cmdline-opts/rate.md create mode 100644 docs/cmdline-opts/raw.md create mode 100644 docs/cmdline-opts/referer.md create mode 100644 docs/cmdline-opts/remote-header-name.md create mode 100644 docs/cmdline-opts/remote-name-all.md create mode 100644 docs/cmdline-opts/remote-name.md create mode 100644 docs/cmdline-opts/remote-time.md create mode 100644 docs/cmdline-opts/remove-on-error.md create mode 100644 docs/cmdline-opts/request-target.md create mode 100644 docs/cmdline-opts/request.md create mode 100644 docs/cmdline-opts/resolve.md create mode 100644 docs/cmdline-opts/retry-all-errors.md create mode 100644 docs/cmdline-opts/retry-connrefused.md create mode 100644 docs/cmdline-opts/retry-delay.md create mode 100644 docs/cmdline-opts/retry-max-time.md create mode 100644 docs/cmdline-opts/retry.md create mode 100644 docs/cmdline-opts/sasl-authzid.md create mode 100644 docs/cmdline-opts/sasl-ir.md create mode 100644 docs/cmdline-opts/service-name.md create mode 100644 docs/cmdline-opts/show-error.md create mode 100644 docs/cmdline-opts/silent.md create mode 100644 docs/cmdline-opts/socks4.md create mode 100644 docs/cmdline-opts/socks4a.md create mode 100644 docs/cmdline-opts/socks5-basic.md create mode 100644 docs/cmdline-opts/socks5-gssapi-nec.md create mode 100644 docs/cmdline-opts/socks5-gssapi-service.md create mode 100644 docs/cmdline-opts/socks5-gssapi.md create mode 100644 docs/cmdline-opts/socks5-hostname.md create mode 100644 docs/cmdline-opts/socks5.md create mode 100644 docs/cmdline-opts/speed-limit.md create mode 100644 docs/cmdline-opts/speed-time.md create mode 100644 docs/cmdline-opts/ssl-allow-beast.md create mode 100644 docs/cmdline-opts/ssl-auto-client-cert.md create mode 100644 docs/cmdline-opts/ssl-no-revoke.md create mode 100644 docs/cmdline-opts/ssl-reqd.md create mode 100644 docs/cmdline-opts/ssl-revoke-best-effort.md create mode 100644 docs/cmdline-opts/ssl.md create mode 100644 docs/cmdline-opts/sslv2.md create mode 100644 docs/cmdline-opts/sslv3.md create mode 100644 docs/cmdline-opts/stderr.md create mode 100644 docs/cmdline-opts/styled-output.md create mode 100644 docs/cmdline-opts/suppress-connect-headers.md create mode 100644 docs/cmdline-opts/tcp-fastopen.md create mode 100644 docs/cmdline-opts/tcp-nodelay.md create mode 100644 docs/cmdline-opts/telnet-option.md create mode 100644 docs/cmdline-opts/tftp-blksize.md create mode 100644 docs/cmdline-opts/tftp-no-options.md create mode 100644 docs/cmdline-opts/time-cond.md create mode 100644 docs/cmdline-opts/tls-max.md create mode 100644 docs/cmdline-opts/tls13-ciphers.md create mode 100644 docs/cmdline-opts/tlsauthtype.md create mode 100644 docs/cmdline-opts/tlspassword.md create mode 100644 docs/cmdline-opts/tlsuser.md create mode 100644 docs/cmdline-opts/tlsv1.0.md create mode 100644 docs/cmdline-opts/tlsv1.1.md create mode 100644 docs/cmdline-opts/tlsv1.2.md create mode 100644 docs/cmdline-opts/tlsv1.3.md create mode 100644 docs/cmdline-opts/tlsv1.md create mode 100644 docs/cmdline-opts/tr-encoding.md create mode 100644 docs/cmdline-opts/trace-ascii.md create mode 100644 docs/cmdline-opts/trace-config.md create mode 100644 docs/cmdline-opts/trace-ids.md create mode 100644 docs/cmdline-opts/trace-time.md create mode 100644 docs/cmdline-opts/trace.md create mode 100644 docs/cmdline-opts/unix-socket.md create mode 100644 docs/cmdline-opts/upload-file.md create mode 100644 docs/cmdline-opts/url-query.md create mode 100644 docs/cmdline-opts/url.md create mode 100644 docs/cmdline-opts/use-ascii.md create mode 100644 docs/cmdline-opts/user-agent.md create mode 100644 docs/cmdline-opts/user.md create mode 100644 docs/cmdline-opts/variable.md create mode 100644 docs/cmdline-opts/verbose.md create mode 100644 docs/cmdline-opts/version.md create mode 100644 docs/cmdline-opts/write-out.md create mode 100644 docs/cmdline-opts/xattr.md create mode 100644 docs/curl-config.1 create mode 100644 docs/curl-config.md create mode 100644 docs/examples/.checksrc create mode 100644 docs/examples/10-at-a-time.c create mode 100644 docs/examples/Makefile.am create mode 100644 docs/examples/Makefile.example create mode 100644 docs/examples/Makefile.in create mode 100644 docs/examples/Makefile.inc create mode 100644 docs/examples/Makefile.mk create mode 100644 docs/examples/README.md create mode 100644 docs/examples/address-scope.c create mode 100644 docs/examples/altsvc.c create mode 100644 docs/examples/anyauthput.c create mode 100644 docs/examples/cacertinmem.c create mode 100644 docs/examples/certinfo.c create mode 100644 docs/examples/chkspeed.c create mode 100644 docs/examples/connect-to.c create mode 100644 docs/examples/cookie_interface.c create mode 100644 docs/examples/crawler.c create mode 100644 docs/examples/debug.c create mode 100644 docs/examples/default-scheme.c create mode 100644 docs/examples/ephiperfifo.c create mode 100644 docs/examples/evhiperfifo.c create mode 100644 docs/examples/externalsocket.c create mode 100644 docs/examples/fileupload.c create mode 100644 docs/examples/ftp-wildcard.c create mode 100644 docs/examples/ftpget.c create mode 100644 docs/examples/ftpgetinfo.c create mode 100644 docs/examples/ftpgetresp.c create mode 100644 docs/examples/ftpsget.c create mode 100644 docs/examples/ftpupload.c create mode 100644 docs/examples/ftpuploadfrommem.c create mode 100644 docs/examples/ftpuploadresume.c create mode 100644 docs/examples/getinfo.c create mode 100644 docs/examples/getinmemory.c create mode 100644 docs/examples/getredirect.c create mode 100644 docs/examples/getreferrer.c create mode 100644 docs/examples/ghiper.c create mode 100644 docs/examples/headerapi.c create mode 100644 docs/examples/hiperfifo.c create mode 100644 docs/examples/href_extractor.c create mode 100644 docs/examples/hsts-preload.c create mode 100644 docs/examples/htmltidy.c create mode 100644 docs/examples/htmltitle.cpp create mode 100644 docs/examples/http-options.c create mode 100644 docs/examples/http-post.c create mode 100644 docs/examples/http2-download.c create mode 100644 docs/examples/http2-pushinmemory.c create mode 100644 docs/examples/http2-serverpush.c create mode 100644 docs/examples/http2-upload.c create mode 100644 docs/examples/http3-present.c create mode 100644 docs/examples/http3.c create mode 100644 docs/examples/httpcustomheader.c create mode 100644 docs/examples/httpput-postfields.c create mode 100644 docs/examples/httpput.c create mode 100644 docs/examples/https.c create mode 100644 docs/examples/imap-append.c create mode 100644 docs/examples/imap-authzid.c create mode 100644 docs/examples/imap-copy.c create mode 100644 docs/examples/imap-create.c create mode 100644 docs/examples/imap-delete.c create mode 100644 docs/examples/imap-examine.c create mode 100644 docs/examples/imap-fetch.c create mode 100644 docs/examples/imap-list.c create mode 100644 docs/examples/imap-lsub.c create mode 100644 docs/examples/imap-multi.c create mode 100644 docs/examples/imap-noop.c create mode 100644 docs/examples/imap-search.c create mode 100644 docs/examples/imap-ssl.c create mode 100644 docs/examples/imap-store.c create mode 100644 docs/examples/imap-tls.c create mode 100644 docs/examples/interface.c create mode 100644 docs/examples/ipv6.c create mode 100644 docs/examples/keepalive.c create mode 100644 docs/examples/localport.c create mode 100644 docs/examples/maxconnects.c create mode 100644 docs/examples/multi-app.c create mode 100644 docs/examples/multi-debugcallback.c create mode 100644 docs/examples/multi-double.c create mode 100644 docs/examples/multi-event.c create mode 100644 docs/examples/multi-formadd.c create mode 100644 docs/examples/multi-legacy.c create mode 100644 docs/examples/multi-post.c create mode 100644 docs/examples/multi-single.c create mode 100644 docs/examples/multi-uv.c create mode 100644 docs/examples/multithread.c create mode 100644 docs/examples/netrc.c create mode 100644 docs/examples/parseurl.c create mode 100644 docs/examples/persistent.c create mode 100644 docs/examples/pop3-authzid.c create mode 100644 docs/examples/pop3-dele.c create mode 100644 docs/examples/pop3-list.c create mode 100644 docs/examples/pop3-multi.c create mode 100644 docs/examples/pop3-noop.c create mode 100644 docs/examples/pop3-retr.c create mode 100644 docs/examples/pop3-ssl.c create mode 100644 docs/examples/pop3-stat.c create mode 100644 docs/examples/pop3-tls.c create mode 100644 docs/examples/pop3-top.c create mode 100644 docs/examples/pop3-uidl.c create mode 100644 docs/examples/post-callback.c create mode 100644 docs/examples/postinmemory.c create mode 100644 docs/examples/postit2-formadd.c create mode 100644 docs/examples/postit2.c create mode 100644 docs/examples/progressfunc.c create mode 100644 docs/examples/protofeats.c create mode 100644 docs/examples/range.c create mode 100644 docs/examples/resolve.c create mode 100644 docs/examples/rtsp-options.c create mode 100644 docs/examples/sendrecv.c create mode 100644 docs/examples/sepheaders.c create mode 100644 docs/examples/sessioninfo.c create mode 100644 docs/examples/sftpget.c create mode 100644 docs/examples/sftpuploadresume.c create mode 100644 docs/examples/shared-connection-cache.c create mode 100644 docs/examples/simple.c create mode 100644 docs/examples/simplepost.c create mode 100644 docs/examples/simplessl.c create mode 100644 docs/examples/smooth-gtk-thread.c create mode 100644 docs/examples/smtp-authzid.c create mode 100644 docs/examples/smtp-expn.c create mode 100644 docs/examples/smtp-mail.c create mode 100644 docs/examples/smtp-mime.c create mode 100644 docs/examples/smtp-multi.c create mode 100644 docs/examples/smtp-ssl.c create mode 100644 docs/examples/smtp-tls.c create mode 100644 docs/examples/smtp-vrfy.c create mode 100644 docs/examples/sslbackend.c create mode 100644 docs/examples/synctime.c create mode 100644 docs/examples/threaded-ssl.c create mode 100644 docs/examples/unixsocket.c create mode 100644 docs/examples/url2file.c create mode 100644 docs/examples/urlapi.c create mode 100644 docs/examples/usercertinmem.c create mode 100755 docs/examples/version-check.pl create mode 100644 docs/examples/websocket-cb.c create mode 100644 docs/examples/websocket.c create mode 100644 docs/examples/xmlstream.c create mode 100644 docs/libcurl/ABI.md create mode 100644 docs/libcurl/CMakeLists.txt create mode 100644 docs/libcurl/Makefile.am create mode 100644 docs/libcurl/Makefile.in create mode 100644 docs/libcurl/Makefile.inc create mode 100644 docs/libcurl/curl_easy_cleanup.md create mode 100644 docs/libcurl/curl_easy_duphandle.md create mode 100644 docs/libcurl/curl_easy_escape.md create mode 100644 docs/libcurl/curl_easy_getinfo.md create mode 100644 docs/libcurl/curl_easy_header.md create mode 100644 docs/libcurl/curl_easy_init.md create mode 100644 docs/libcurl/curl_easy_nextheader.md create mode 100644 docs/libcurl/curl_easy_option_by_id.md create mode 100644 docs/libcurl/curl_easy_option_by_name.md create mode 100644 docs/libcurl/curl_easy_option_next.md create mode 100644 docs/libcurl/curl_easy_pause.md create mode 100644 docs/libcurl/curl_easy_perform.md create mode 100644 docs/libcurl/curl_easy_recv.md create mode 100644 docs/libcurl/curl_easy_reset.md create mode 100644 docs/libcurl/curl_easy_send.md create mode 100644 docs/libcurl/curl_easy_setopt.md create mode 100644 docs/libcurl/curl_easy_strerror.md create mode 100644 docs/libcurl/curl_easy_unescape.md create mode 100644 docs/libcurl/curl_easy_upkeep.md create mode 100644 docs/libcurl/curl_escape.md create mode 100644 docs/libcurl/curl_formadd.md create mode 100644 docs/libcurl/curl_formfree.md create mode 100644 docs/libcurl/curl_formget.md create mode 100644 docs/libcurl/curl_free.md create mode 100644 docs/libcurl/curl_getdate.md create mode 100644 docs/libcurl/curl_getenv.md create mode 100644 docs/libcurl/curl_global_cleanup.md create mode 100644 docs/libcurl/curl_global_init.md create mode 100644 docs/libcurl/curl_global_init_mem.md create mode 100644 docs/libcurl/curl_global_sslset.md create mode 100644 docs/libcurl/curl_global_trace.md create mode 100644 docs/libcurl/curl_mime_addpart.md create mode 100644 docs/libcurl/curl_mime_data.md create mode 100644 docs/libcurl/curl_mime_data_cb.md create mode 100644 docs/libcurl/curl_mime_encoder.md create mode 100644 docs/libcurl/curl_mime_filedata.md create mode 100644 docs/libcurl/curl_mime_filename.md create mode 100644 docs/libcurl/curl_mime_free.md create mode 100644 docs/libcurl/curl_mime_headers.md create mode 100644 docs/libcurl/curl_mime_init.md create mode 100644 docs/libcurl/curl_mime_name.md create mode 100644 docs/libcurl/curl_mime_subparts.md create mode 100644 docs/libcurl/curl_mime_type.md create mode 100644 docs/libcurl/curl_mprintf.md create mode 100644 docs/libcurl/curl_multi_add_handle.md create mode 100644 docs/libcurl/curl_multi_assign.md create mode 100644 docs/libcurl/curl_multi_cleanup.md create mode 100644 docs/libcurl/curl_multi_fdset.md create mode 100644 docs/libcurl/curl_multi_get_handles.md create mode 100644 docs/libcurl/curl_multi_info_read.md create mode 100644 docs/libcurl/curl_multi_init.md create mode 100644 docs/libcurl/curl_multi_perform.md create mode 100644 docs/libcurl/curl_multi_poll.md create mode 100644 docs/libcurl/curl_multi_remove_handle.md create mode 100644 docs/libcurl/curl_multi_setopt.md create mode 100644 docs/libcurl/curl_multi_socket.md create mode 100644 docs/libcurl/curl_multi_socket_action.md create mode 100644 docs/libcurl/curl_multi_socket_all.md create mode 100644 docs/libcurl/curl_multi_strerror.md create mode 100644 docs/libcurl/curl_multi_timeout.md create mode 100644 docs/libcurl/curl_multi_wait.md create mode 100644 docs/libcurl/curl_multi_wakeup.md create mode 100644 docs/libcurl/curl_pushheader_byname.md create mode 100644 docs/libcurl/curl_pushheader_bynum.md create mode 100644 docs/libcurl/curl_share_cleanup.md create mode 100644 docs/libcurl/curl_share_init.md create mode 100644 docs/libcurl/curl_share_setopt.md create mode 100644 docs/libcurl/curl_share_strerror.md create mode 100644 docs/libcurl/curl_slist_append.md create mode 100644 docs/libcurl/curl_slist_free_all.md create mode 100644 docs/libcurl/curl_strequal.md create mode 100644 docs/libcurl/curl_strnequal.md create mode 100644 docs/libcurl/curl_unescape.md create mode 100644 docs/libcurl/curl_url.md create mode 100644 docs/libcurl/curl_url_cleanup.md create mode 100644 docs/libcurl/curl_url_dup.md create mode 100644 docs/libcurl/curl_url_get.md create mode 100644 docs/libcurl/curl_url_set.md create mode 100644 docs/libcurl/curl_url_strerror.md create mode 100644 docs/libcurl/curl_version.md create mode 100644 docs/libcurl/curl_version_info.md create mode 100644 docs/libcurl/curl_ws_meta.md create mode 100644 docs/libcurl/curl_ws_recv.md create mode 100644 docs/libcurl/curl_ws_send.md create mode 100644 docs/libcurl/libcurl-easy.md create mode 100644 docs/libcurl/libcurl-env-dbg.md create mode 100644 docs/libcurl/libcurl-env.md create mode 100644 docs/libcurl/libcurl-errors.md create mode 100644 docs/libcurl/libcurl-multi.md create mode 100644 docs/libcurl/libcurl-security.md create mode 100644 docs/libcurl/libcurl-share.md create mode 100644 docs/libcurl/libcurl-symbols.md create mode 100644 docs/libcurl/libcurl-thread.md create mode 100644 docs/libcurl/libcurl-tutorial.md create mode 100644 docs/libcurl/libcurl-url.md create mode 100644 docs/libcurl/libcurl-ws.md create mode 100644 docs/libcurl/libcurl.m4 create mode 100644 docs/libcurl/libcurl.md create mode 100755 docs/libcurl/mksymbolsmanpage.pl create mode 100644 docs/libcurl/opts/CMakeLists.txt create mode 100644 docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md create mode 100644 docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md create mode 100644 docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_CAINFO.md create mode 100644 docs/libcurl/opts/CURLINFO_CAPATH.md create mode 100644 docs/libcurl/opts/CURLINFO_CERTINFO.md create mode 100644 docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md create mode 100644 docs/libcurl/opts/CURLINFO_CONNECT_TIME.md create mode 100644 docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_CONN_ID.md create mode 100644 docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md create mode 100644 docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md create mode 100644 docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md create mode 100644 docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md create mode 100644 docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md create mode 100644 docs/libcurl/opts/CURLINFO_COOKIELIST.md create mode 100644 docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md create mode 100644 docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md create mode 100644 docs/libcurl/opts/CURLINFO_FILETIME.md create mode 100644 docs/libcurl/opts/CURLINFO_FILETIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md create mode 100644 docs/libcurl/opts/CURLINFO_HEADER_SIZE.md create mode 100644 docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md create mode 100644 docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md create mode 100644 docs/libcurl/opts/CURLINFO_HTTP_VERSION.md create mode 100644 docs/libcurl/opts/CURLINFO_LASTSOCKET.md create mode 100644 docs/libcurl/opts/CURLINFO_LOCAL_IP.md create mode 100644 docs/libcurl/opts/CURLINFO_LOCAL_PORT.md create mode 100644 docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md create mode 100644 docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md create mode 100644 docs/libcurl/opts/CURLINFO_OS_ERRNO.md create mode 100644 docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md create mode 100644 docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_PRIMARY_IP.md create mode 100644 docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md create mode 100644 docs/libcurl/opts/CURLINFO_PRIVATE.md create mode 100644 docs/libcurl/opts/CURLINFO_PROTOCOL.md create mode 100644 docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md create mode 100644 docs/libcurl/opts/CURLINFO_PROXY_ERROR.md create mode 100644 docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md create mode 100644 docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md create mode 100644 docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md create mode 100644 docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_REDIRECT_URL.md create mode 100644 docs/libcurl/opts/CURLINFO_REFERER.md create mode 100644 docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md create mode 100644 docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md create mode 100644 docs/libcurl/opts/CURLINFO_RETRY_AFTER.md create mode 100644 docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md create mode 100644 docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md create mode 100644 docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md create mode 100644 docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md create mode 100644 docs/libcurl/opts/CURLINFO_SCHEME.md create mode 100644 docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md create mode 100644 docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md create mode 100644 docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md create mode 100644 docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md create mode 100644 docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md create mode 100644 docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md create mode 100644 docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md create mode 100644 docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md create mode 100644 docs/libcurl/opts/CURLINFO_SSL_ENGINES.md create mode 100644 docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md create mode 100644 docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md create mode 100644 docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_TLS_SESSION.md create mode 100644 docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md create mode 100644 docs/libcurl/opts/CURLINFO_TOTAL_TIME.md create mode 100644 docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md create mode 100644 docs/libcurl/opts/CURLINFO_XFER_ID.md create mode 100644 docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md create mode 100644 docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md create mode 100644 docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md create mode 100644 docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md create mode 100644 docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md create mode 100644 docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md create mode 100644 docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md create mode 100644 docs/libcurl/opts/CURLMOPT_PIPELINING.md create mode 100644 docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md create mode 100644 docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md create mode 100644 docs/libcurl/opts/CURLMOPT_PUSHDATA.md create mode 100644 docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md create mode 100644 docs/libcurl/opts/CURLMOPT_SOCKETDATA.md create mode 100644 docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md create mode 100644 docs/libcurl/opts/CURLMOPT_TIMERDATA.md create mode 100644 docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md create mode 100644 docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md create mode 100644 docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md create mode 100644 docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md create mode 100644 docs/libcurl/opts/CURLOPT_ALTSVC.md create mode 100644 docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md create mode 100644 docs/libcurl/opts/CURLOPT_APPEND.md create mode 100644 docs/libcurl/opts/CURLOPT_AUTOREFERER.md create mode 100644 docs/libcurl/opts/CURLOPT_AWS_SIGV4.md create mode 100644 docs/libcurl/opts/CURLOPT_BUFFERSIZE.md create mode 100644 docs/libcurl/opts/CURLOPT_CAINFO.md create mode 100644 docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_CAPATH.md create mode 100644 docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md create mode 100644 docs/libcurl/opts/CURLOPT_CERTINFO.md create mode 100644 docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_CHUNK_DATA.md create mode 100644 docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md create mode 100644 docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md create mode 100644 docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md create mode 100644 docs/libcurl/opts/CURLOPT_CONNECT_TO.md create mode 100644 docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_COOKIE.md create mode 100644 docs/libcurl/opts/CURLOPT_COOKIEFILE.md create mode 100644 docs/libcurl/opts/CURLOPT_COOKIEJAR.md create mode 100644 docs/libcurl/opts/CURLOPT_COOKIELIST.md create mode 100644 docs/libcurl/opts/CURLOPT_COOKIESESSION.md create mode 100644 docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md create mode 100644 docs/libcurl/opts/CURLOPT_CRLF.md create mode 100644 docs/libcurl/opts/CURLOPT_CRLFILE.md create mode 100644 docs/libcurl/opts/CURLOPT_CURLU.md create mode 100644 docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md create mode 100644 docs/libcurl/opts/CURLOPT_DEBUGDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md create mode 100644 docs/libcurl/opts/CURLOPT_DIRLISTONLY.md create mode 100644 docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md create mode 100644 docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md create mode 100644 docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md create mode 100644 docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md create mode 100644 docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md create mode 100644 docs/libcurl/opts/CURLOPT_DNS_SERVERS.md create mode 100644 docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md create mode 100644 docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md create mode 100644 docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md create mode 100644 docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md create mode 100644 docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md create mode 100644 docs/libcurl/opts/CURLOPT_DOH_URL.md create mode 100644 docs/libcurl/opts/CURLOPT_EGDSOCKET.md create mode 100644 docs/libcurl/opts/CURLOPT_ERRORBUFFER.md create mode 100644 docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md create mode 100644 docs/libcurl/opts/CURLOPT_FAILONERROR.md create mode 100644 docs/libcurl/opts/CURLOPT_FILETIME.md create mode 100644 docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md create mode 100644 docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md create mode 100644 docs/libcurl/opts/CURLOPT_FORBID_REUSE.md create mode 100644 docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md create mode 100644 docs/libcurl/opts/CURLOPT_FTPPORT.md create mode 100644 docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md create mode 100644 docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md create mode 100644 docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md create mode 100644 docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md create mode 100644 docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md create mode 100644 docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md create mode 100644 docs/libcurl/opts/CURLOPT_HEADER.md create mode 100644 docs/libcurl/opts/CURLOPT_HEADERDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_HEADEROPT.md create mode 100644 docs/libcurl/opts/CURLOPT_HSTS.md create mode 100644 docs/libcurl/opts/CURLOPT_HSTSREADDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_HSTS_CTRL.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTPAUTH.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTPGET.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTPHEADER.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTPPOST.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md create mode 100644 docs/libcurl/opts/CURLOPT_HTTP_VERSION.md create mode 100644 docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md create mode 100644 docs/libcurl/opts/CURLOPT_INFILESIZE.md create mode 100644 docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md create mode 100644 docs/libcurl/opts/CURLOPT_INTERFACE.md create mode 100644 docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_IOCTLDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_IPRESOLVE.md create mode 100644 docs/libcurl/opts/CURLOPT_ISSUERCERT.md create mode 100644 docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md create mode 100644 docs/libcurl/opts/CURLOPT_KEYPASSWD.md create mode 100644 docs/libcurl/opts/CURLOPT_KRBLEVEL.md create mode 100644 docs/libcurl/opts/CURLOPT_LOCALPORT.md create mode 100644 docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md create mode 100644 docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md create mode 100644 docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md create mode 100644 docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md create mode 100644 docs/libcurl/opts/CURLOPT_MAIL_AUTH.md create mode 100644 docs/libcurl/opts/CURLOPT_MAIL_FROM.md create mode 100644 docs/libcurl/opts/CURLOPT_MAIL_RCPT.md create mode 100644 docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md create mode 100644 docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md create mode 100644 docs/libcurl/opts/CURLOPT_MAXCONNECTS.md create mode 100644 docs/libcurl/opts/CURLOPT_MAXFILESIZE.md create mode 100644 docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md create mode 100644 docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md create mode 100644 docs/libcurl/opts/CURLOPT_MAXREDIRS.md create mode 100644 docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md create mode 100644 docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md create mode 100644 docs/libcurl/opts/CURLOPT_MIMEPOST.md create mode 100644 docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md create mode 100644 docs/libcurl/opts/CURLOPT_NETRC.md create mode 100644 docs/libcurl/opts/CURLOPT_NETRC_FILE.md create mode 100644 docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md create mode 100644 docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md create mode 100644 docs/libcurl/opts/CURLOPT_NOBODY.md create mode 100644 docs/libcurl/opts/CURLOPT_NOPROGRESS.md create mode 100644 docs/libcurl/opts/CURLOPT_NOPROXY.md create mode 100644 docs/libcurl/opts/CURLOPT_NOSIGNAL.md create mode 100644 docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_PASSWORD.md create mode 100644 docs/libcurl/opts/CURLOPT_PATH_AS_IS.md create mode 100644 docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md create mode 100644 docs/libcurl/opts/CURLOPT_PIPEWAIT.md create mode 100644 docs/libcurl/opts/CURLOPT_PORT.md create mode 100644 docs/libcurl/opts/CURLOPT_POST.md create mode 100644 docs/libcurl/opts/CURLOPT_POSTFIELDS.md create mode 100644 docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md create mode 100644 docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md create mode 100644 docs/libcurl/opts/CURLOPT_POSTQUOTE.md create mode 100644 docs/libcurl/opts/CURLOPT_POSTREDIR.md create mode 100644 docs/libcurl/opts/CURLOPT_PREQUOTE.md create mode 100644 docs/libcurl/opts/CURLOPT_PREREQDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_PRE_PROXY.md create mode 100644 docs/libcurl/opts/CURLOPT_PRIVATE.md create mode 100644 docs/libcurl/opts/CURLOPT_PROGRESSDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_PROTOCOLS.md create mode 100644 docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXYAUTH.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXYHEADER.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXYPORT.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXYTYPE.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md create mode 100644 docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md create mode 100644 docs/libcurl/opts/CURLOPT_PUT.md create mode 100644 docs/libcurl/opts/CURLOPT_QUICK_EXIT.md create mode 100644 docs/libcurl/opts/CURLOPT_QUOTE.md create mode 100644 docs/libcurl/opts/CURLOPT_RANDOM_FILE.md create mode 100644 docs/libcurl/opts/CURLOPT_RANGE.md create mode 100644 docs/libcurl/opts/CURLOPT_READDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_READFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md create mode 100644 docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md create mode 100644 docs/libcurl/opts/CURLOPT_REFERER.md create mode 100644 docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md create mode 100644 docs/libcurl/opts/CURLOPT_RESOLVE.md create mode 100644 docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md create mode 100644 docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_RESUME_FROM.md create mode 100644 docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md create mode 100644 docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md create mode 100644 docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md create mode 100644 docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md create mode 100644 docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md create mode 100644 docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md create mode 100644 docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md create mode 100644 docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md create mode 100644 docs/libcurl/opts/CURLOPT_SASL_IR.md create mode 100644 docs/libcurl/opts/CURLOPT_SEEKDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md create mode 100644 docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md create mode 100644 docs/libcurl/opts/CURLOPT_SERVICE_NAME.md create mode 100644 docs/libcurl/opts/CURLOPT_SHARE.md create mode 100644 docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md create mode 100644 docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md create mode 100644 docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md create mode 100644 docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLCERT.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLENGINE.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLKEY.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md create mode 100644 docs/libcurl/opts/CURLOPT_SSLVERSION.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md create mode 100644 docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md create mode 100644 docs/libcurl/opts/CURLOPT_STDERR.md create mode 100644 docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md create mode 100644 docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md create mode 100644 docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md create mode 100644 docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md create mode 100644 docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md create mode 100644 docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md create mode 100644 docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md create mode 100644 docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md create mode 100644 docs/libcurl/opts/CURLOPT_TCP_NODELAY.md create mode 100644 docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md create mode 100644 docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md create mode 100644 docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md create mode 100644 docs/libcurl/opts/CURLOPT_TIMECONDITION.md create mode 100644 docs/libcurl/opts/CURLOPT_TIMEOUT.md create mode 100644 docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md create mode 100644 docs/libcurl/opts/CURLOPT_TIMEVALUE.md create mode 100644 docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md create mode 100644 docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md create mode 100644 docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md create mode 100644 docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md create mode 100644 docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md create mode 100644 docs/libcurl/opts/CURLOPT_TRAILERDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md create mode 100644 docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md create mode 100644 docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md create mode 100644 docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md create mode 100644 docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md create mode 100644 docs/libcurl/opts/CURLOPT_UPLOAD.md create mode 100644 docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md create mode 100644 docs/libcurl/opts/CURLOPT_URL.md create mode 100644 docs/libcurl/opts/CURLOPT_USERAGENT.md create mode 100644 docs/libcurl/opts/CURLOPT_USERNAME.md create mode 100644 docs/libcurl/opts/CURLOPT_USERPWD.md create mode 100644 docs/libcurl/opts/CURLOPT_USE_SSL.md create mode 100644 docs/libcurl/opts/CURLOPT_VERBOSE.md create mode 100644 docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md create mode 100644 docs/libcurl/opts/CURLOPT_WRITEDATA.md create mode 100644 docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_WS_OPTIONS.md create mode 100644 docs/libcurl/opts/CURLOPT_XFERINFODATA.md create mode 100644 docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md create mode 100644 docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md create mode 100644 docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md create mode 100644 docs/libcurl/opts/CURLSHOPT_SHARE.md create mode 100644 docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md create mode 100644 docs/libcurl/opts/CURLSHOPT_UNSHARE.md create mode 100644 docs/libcurl/opts/CURLSHOPT_USERDATA.md create mode 100644 docs/libcurl/opts/Makefile.am create mode 100644 docs/libcurl/opts/Makefile.in create mode 100644 docs/libcurl/opts/Makefile.inc create mode 100644 docs/libcurl/symbols-in-versions create mode 100755 docs/libcurl/symbols.pl create mode 100644 docs/mk-ca-bundle.md create mode 100644 docs/options-in-versions create mode 100644 include/Makefile.am create mode 100644 include/Makefile.in create mode 100644 include/README.md create mode 100644 include/curl/Makefile.am create mode 100644 include/curl/Makefile.in create mode 100644 include/curl/curl.h create mode 100644 include/curl/curlver.h create mode 100644 include/curl/easy.h create mode 100644 include/curl/header.h create mode 100644 include/curl/mprintf.h create mode 100644 include/curl/multi.h create mode 100644 include/curl/options.h create mode 100644 include/curl/stdcheaders.h create mode 100644 include/curl/system.h create mode 100644 include/curl/typecheck-gcc.h create mode 100644 include/curl/urlapi.h create mode 100644 include/curl/websockets.h create mode 100755 install-sh create mode 100644 lib/.checksrc create mode 100644 lib/CMakeLists.txt create mode 100644 lib/Makefile.am create mode 100644 lib/Makefile.in create mode 100644 lib/Makefile.inc create mode 100644 lib/Makefile.mk create mode 100644 lib/Makefile.soname create mode 100644 lib/altsvc.c create mode 100644 lib/altsvc.h create mode 100644 lib/amigaos.c create mode 100644 lib/amigaos.h create mode 100644 lib/arpa_telnet.h create mode 100644 lib/asyn-ares.c create mode 100644 lib/asyn-thread.c create mode 100644 lib/asyn.h create mode 100644 lib/base64.c create mode 100644 lib/bufq.c create mode 100644 lib/bufq.h create mode 100644 lib/bufref.c create mode 100644 lib/bufref.h create mode 100644 lib/c-hyper.c create mode 100644 lib/c-hyper.h create mode 100644 lib/cf-h1-proxy.c create mode 100644 lib/cf-h1-proxy.h create mode 100644 lib/cf-h2-proxy.c create mode 100644 lib/cf-h2-proxy.h create mode 100644 lib/cf-haproxy.c create mode 100644 lib/cf-haproxy.h create mode 100644 lib/cf-https-connect.c create mode 100644 lib/cf-https-connect.h create mode 100644 lib/cf-socket.c create mode 100644 lib/cf-socket.h create mode 100644 lib/cfilters.c create mode 100644 lib/cfilters.h create mode 100644 lib/config-amigaos.h create mode 100644 lib/config-dos.h create mode 100644 lib/config-mac.h create mode 100644 lib/config-os400.h create mode 100644 lib/config-plan9.h create mode 100644 lib/config-riscos.h create mode 100644 lib/config-win32.h create mode 100644 lib/config-win32ce.h create mode 100644 lib/conncache.c create mode 100644 lib/conncache.h create mode 100644 lib/connect.c create mode 100644 lib/connect.h create mode 100644 lib/content_encoding.c create mode 100644 lib/content_encoding.h create mode 100644 lib/cookie.c create mode 100644 lib/cookie.h create mode 100644 lib/curl_addrinfo.c create mode 100644 lib/curl_addrinfo.h create mode 100644 lib/curl_base64.h create mode 100644 lib/curl_config.h.cmake create mode 100644 lib/curl_config.h.in create mode 100644 lib/curl_ctype.h create mode 100644 lib/curl_des.c create mode 100644 lib/curl_des.h create mode 100644 lib/curl_endian.c create mode 100644 lib/curl_endian.h create mode 100644 lib/curl_fnmatch.c create mode 100644 lib/curl_fnmatch.h create mode 100644 lib/curl_get_line.c create mode 100644 lib/curl_get_line.h create mode 100644 lib/curl_gethostname.c create mode 100644 lib/curl_gethostname.h create mode 100644 lib/curl_gssapi.c create mode 100644 lib/curl_gssapi.h create mode 100644 lib/curl_hmac.h create mode 100644 lib/curl_krb5.h create mode 100644 lib/curl_ldap.h create mode 100644 lib/curl_md4.h create mode 100644 lib/curl_md5.h create mode 100644 lib/curl_memory.h create mode 100644 lib/curl_memrchr.c create mode 100644 lib/curl_memrchr.h create mode 100644 lib/curl_multibyte.c create mode 100644 lib/curl_multibyte.h create mode 100644 lib/curl_ntlm_core.c create mode 100644 lib/curl_ntlm_core.h create mode 100644 lib/curl_ntlm_wb.c create mode 100644 lib/curl_ntlm_wb.h create mode 100644 lib/curl_path.c create mode 100644 lib/curl_path.h create mode 100644 lib/curl_printf.h create mode 100644 lib/curl_range.c create mode 100644 lib/curl_range.h create mode 100644 lib/curl_rtmp.c create mode 100644 lib/curl_rtmp.h create mode 100644 lib/curl_sasl.c create mode 100644 lib/curl_sasl.h create mode 100644 lib/curl_setup.h create mode 100644 lib/curl_setup_once.h create mode 100644 lib/curl_sha256.h create mode 100644 lib/curl_sspi.c create mode 100644 lib/curl_sspi.h create mode 100644 lib/curl_threads.c create mode 100644 lib/curl_threads.h create mode 100644 lib/curl_trc.c create mode 100644 lib/curl_trc.h create mode 100644 lib/curlx.h create mode 100644 lib/dict.c create mode 100644 lib/dict.h create mode 100644 lib/doh.c create mode 100644 lib/doh.h create mode 100644 lib/dynbuf.c create mode 100644 lib/dynbuf.h create mode 100644 lib/dynhds.c create mode 100644 lib/dynhds.h create mode 100644 lib/easy.c create mode 100644 lib/easy_lock.h create mode 100644 lib/easygetopt.c create mode 100644 lib/easyif.h create mode 100644 lib/easyoptions.c create mode 100644 lib/easyoptions.h create mode 100644 lib/escape.c create mode 100644 lib/escape.h create mode 100644 lib/file.c create mode 100644 lib/file.h create mode 100644 lib/fileinfo.c create mode 100644 lib/fileinfo.h create mode 100644 lib/fopen.c create mode 100644 lib/fopen.h create mode 100644 lib/formdata.c create mode 100644 lib/formdata.h create mode 100644 lib/ftp.c create mode 100644 lib/ftp.h create mode 100644 lib/ftplistparser.c create mode 100644 lib/ftplistparser.h create mode 100644 lib/functypes.h create mode 100644 lib/getenv.c create mode 100644 lib/getinfo.c create mode 100644 lib/getinfo.h create mode 100644 lib/gopher.c create mode 100644 lib/gopher.h create mode 100644 lib/hash.c create mode 100644 lib/hash.h create mode 100644 lib/headers.c create mode 100644 lib/headers.h create mode 100644 lib/hmac.c create mode 100644 lib/hostasyn.c create mode 100644 lib/hostip.c create mode 100644 lib/hostip.h create mode 100644 lib/hostip4.c create mode 100644 lib/hostip6.c create mode 100644 lib/hostsyn.c create mode 100644 lib/hsts.c create mode 100644 lib/hsts.h create mode 100644 lib/http.c create mode 100644 lib/http.h create mode 100644 lib/http1.c create mode 100644 lib/http1.h create mode 100644 lib/http2.c create mode 100644 lib/http2.h create mode 100644 lib/http_aws_sigv4.c create mode 100644 lib/http_aws_sigv4.h create mode 100644 lib/http_chunks.c create mode 100644 lib/http_chunks.h create mode 100644 lib/http_digest.c create mode 100644 lib/http_digest.h create mode 100644 lib/http_negotiate.c create mode 100644 lib/http_negotiate.h create mode 100644 lib/http_ntlm.c create mode 100644 lib/http_ntlm.h create mode 100644 lib/http_proxy.c create mode 100644 lib/http_proxy.h create mode 100644 lib/idn.c create mode 100644 lib/idn.h create mode 100644 lib/if2ip.c create mode 100644 lib/if2ip.h create mode 100644 lib/imap.c create mode 100644 lib/imap.h create mode 100644 lib/inet_ntop.c create mode 100644 lib/inet_ntop.h create mode 100644 lib/inet_pton.c create mode 100644 lib/inet_pton.h create mode 100644 lib/krb5.c create mode 100644 lib/ldap.c create mode 100644 lib/libcurl.plist create mode 100644 lib/libcurl.plist.in create mode 100644 lib/libcurl.rc create mode 100644 lib/libcurl.vers.in create mode 100644 lib/llist.c create mode 100644 lib/llist.h create mode 100644 lib/macos.c create mode 100644 lib/macos.h create mode 100644 lib/md4.c create mode 100644 lib/md5.c create mode 100644 lib/memdebug.c create mode 100644 lib/memdebug.h create mode 100644 lib/mime.c create mode 100644 lib/mime.h create mode 100644 lib/mprintf.c create mode 100644 lib/mqtt.c create mode 100644 lib/mqtt.h create mode 100644 lib/multi.c create mode 100644 lib/multihandle.h create mode 100644 lib/multiif.h create mode 100644 lib/netrc.c create mode 100644 lib/netrc.h create mode 100644 lib/nonblock.c create mode 100644 lib/nonblock.h create mode 100644 lib/noproxy.c create mode 100644 lib/noproxy.h create mode 100644 lib/openldap.c create mode 100644 lib/parsedate.c create mode 100644 lib/parsedate.h create mode 100644 lib/pingpong.c create mode 100644 lib/pingpong.h create mode 100644 lib/pop3.c create mode 100644 lib/pop3.h create mode 100644 lib/progress.c create mode 100644 lib/progress.h create mode 100644 lib/psl.c create mode 100644 lib/psl.h create mode 100644 lib/rand.c create mode 100644 lib/rand.h create mode 100644 lib/rename.c create mode 100644 lib/rename.h create mode 100644 lib/rtsp.c create mode 100644 lib/rtsp.h create mode 100644 lib/select.c create mode 100644 lib/select.h create mode 100644 lib/sendf.c create mode 100644 lib/sendf.h create mode 100644 lib/setopt.c create mode 100644 lib/setopt.h create mode 100644 lib/setup-os400.h create mode 100644 lib/setup-vms.h create mode 100644 lib/setup-win32.h create mode 100644 lib/sha256.c create mode 100644 lib/share.c create mode 100644 lib/share.h create mode 100644 lib/sigpipe.h create mode 100644 lib/slist.c create mode 100644 lib/slist.h create mode 100644 lib/smb.c create mode 100644 lib/smb.h create mode 100644 lib/smtp.c create mode 100644 lib/smtp.h create mode 100644 lib/sockaddr.h create mode 100644 lib/socketpair.c create mode 100644 lib/socketpair.h create mode 100644 lib/socks.c create mode 100644 lib/socks.h create mode 100644 lib/socks_gssapi.c create mode 100644 lib/socks_sspi.c create mode 100644 lib/speedcheck.c create mode 100644 lib/speedcheck.h create mode 100644 lib/splay.c create mode 100644 lib/splay.h create mode 100644 lib/strcase.c create mode 100644 lib/strcase.h create mode 100644 lib/strdup.c create mode 100644 lib/strdup.h create mode 100644 lib/strerror.c create mode 100644 lib/strerror.h create mode 100644 lib/strtok.c create mode 100644 lib/strtok.h create mode 100644 lib/strtoofft.c create mode 100644 lib/strtoofft.h create mode 100644 lib/system_win32.c create mode 100644 lib/system_win32.h create mode 100644 lib/telnet.c create mode 100644 lib/telnet.h create mode 100644 lib/tftp.c create mode 100644 lib/tftp.h create mode 100644 lib/timediff.c create mode 100644 lib/timediff.h create mode 100644 lib/timeval.c create mode 100644 lib/timeval.h create mode 100644 lib/transfer.c create mode 100644 lib/transfer.h create mode 100644 lib/url.c create mode 100644 lib/url.h create mode 100644 lib/urlapi-int.h create mode 100644 lib/urlapi.c create mode 100644 lib/urldata.h create mode 100644 lib/vauth/cleartext.c create mode 100644 lib/vauth/cram.c create mode 100644 lib/vauth/digest.c create mode 100644 lib/vauth/digest.h create mode 100644 lib/vauth/digest_sspi.c create mode 100644 lib/vauth/gsasl.c create mode 100644 lib/vauth/krb5_gssapi.c create mode 100644 lib/vauth/krb5_sspi.c create mode 100644 lib/vauth/ntlm.c create mode 100644 lib/vauth/ntlm.h create mode 100644 lib/vauth/ntlm_sspi.c create mode 100644 lib/vauth/oauth2.c create mode 100644 lib/vauth/spnego_gssapi.c create mode 100644 lib/vauth/spnego_sspi.c create mode 100644 lib/vauth/vauth.c create mode 100644 lib/vauth/vauth.h create mode 100644 lib/version.c create mode 100644 lib/version_win32.c create mode 100644 lib/version_win32.h create mode 100644 lib/vquic/curl_msh3.c create mode 100644 lib/vquic/curl_msh3.h create mode 100644 lib/vquic/curl_ngtcp2.c create mode 100644 lib/vquic/curl_ngtcp2.h create mode 100644 lib/vquic/curl_osslq.c create mode 100644 lib/vquic/curl_osslq.h create mode 100644 lib/vquic/curl_quiche.c create mode 100644 lib/vquic/curl_quiche.h create mode 100644 lib/vquic/vquic-tls.c create mode 100644 lib/vquic/vquic-tls.h create mode 100644 lib/vquic/vquic.c create mode 100644 lib/vquic/vquic.h create mode 100644 lib/vquic/vquic_int.h create mode 100644 lib/vssh/libssh.c create mode 100644 lib/vssh/libssh2.c create mode 100644 lib/vssh/ssh.h create mode 100644 lib/vssh/wolfssh.c create mode 100644 lib/vtls/bearssl.c create mode 100644 lib/vtls/bearssl.h create mode 100644 lib/vtls/gtls.c create mode 100644 lib/vtls/gtls.h create mode 100644 lib/vtls/hostcheck.c create mode 100644 lib/vtls/hostcheck.h create mode 100644 lib/vtls/keylog.c create mode 100644 lib/vtls/keylog.h create mode 100644 lib/vtls/mbedtls.c create mode 100644 lib/vtls/mbedtls.h create mode 100644 lib/vtls/mbedtls_threadlock.c create mode 100644 lib/vtls/mbedtls_threadlock.h create mode 100644 lib/vtls/openssl.c create mode 100644 lib/vtls/openssl.h create mode 100644 lib/vtls/rustls.c create mode 100644 lib/vtls/rustls.h create mode 100644 lib/vtls/schannel.c create mode 100644 lib/vtls/schannel.h create mode 100644 lib/vtls/schannel_int.h create mode 100644 lib/vtls/schannel_verify.c create mode 100644 lib/vtls/sectransp.c create mode 100644 lib/vtls/sectransp.h create mode 100644 lib/vtls/vtls.c create mode 100644 lib/vtls/vtls.h create mode 100644 lib/vtls/vtls_int.h create mode 100644 lib/vtls/wolfssl.c create mode 100644 lib/vtls/wolfssl.h create mode 100644 lib/vtls/x509asn1.c create mode 100644 lib/vtls/x509asn1.h create mode 100644 lib/warnless.c create mode 100644 lib/warnless.h create mode 100644 lib/ws.c create mode 100644 lib/ws.h create mode 100644 libcurl.def create mode 100644 libcurl.pc.in create mode 100755 ltmain.sh create mode 100644 m4/curl-amissl.m4 create mode 100644 m4/curl-bearssl.m4 create mode 100644 m4/curl-compilers.m4 create mode 100644 m4/curl-confopts.m4 create mode 100644 m4/curl-functions.m4 create mode 100644 m4/curl-gnutls.m4 create mode 100644 m4/curl-mbedtls.m4 create mode 100644 m4/curl-openssl.m4 create mode 100644 m4/curl-override.m4 create mode 100644 m4/curl-reentrant.m4 create mode 100644 m4/curl-rustls.m4 create mode 100644 m4/curl-schannel.m4 create mode 100644 m4/curl-sectransp.m4 create mode 100644 m4/curl-sysconfig.m4 create mode 100644 m4/curl-wolfssl.m4 create mode 100644 m4/libtool.m4 create mode 100644 m4/ltoptions.m4 create mode 100644 m4/ltsugar.m4 create mode 100644 m4/ltversion.m4 create mode 100644 m4/lt~obsolete.m4 create mode 100644 m4/xc-am-iface.m4 create mode 100644 m4/xc-cc-check.m4 create mode 100644 m4/xc-lt-iface.m4 create mode 100644 m4/xc-translit.m4 create mode 100644 m4/xc-val-flgs.m4 create mode 100644 m4/zz40-xc-ovr.m4 create mode 100644 m4/zz50-xc-ovr.m4 create mode 100644 m4/zz60-xc-ovr.m4 create mode 100755 maketgz create mode 100755 missing create mode 100644 packages/Makefile.am create mode 100644 packages/Makefile.in create mode 100644 packages/OS400/README.OS400 create mode 100644 packages/OS400/ccsidcurl.c create mode 100644 packages/OS400/ccsidcurl.h create mode 100644 packages/OS400/config400.default create mode 100644 packages/OS400/curl.cmd create mode 100644 packages/OS400/curl.inc.in create mode 100644 packages/OS400/curlcl.c create mode 100644 packages/OS400/curlmain.c create mode 100755 packages/OS400/initscript.sh create mode 100755 packages/OS400/make-include.sh create mode 100755 packages/OS400/make-lib.sh create mode 100755 packages/OS400/make-src.sh create mode 100755 packages/OS400/make-tests.sh create mode 100755 packages/OS400/makefile.sh create mode 100644 packages/OS400/os400sys.c create mode 100644 packages/OS400/os400sys.h create mode 100644 packages/OS400/rpg-examples/HEADERAPI create mode 100644 packages/OS400/rpg-examples/HTTPPOST create mode 100644 packages/OS400/rpg-examples/INMEMORY create mode 100644 packages/OS400/rpg-examples/SIMPLE1 create mode 100644 packages/OS400/rpg-examples/SIMPLE2 create mode 100644 packages/OS400/rpg-examples/SMTPSRCMBR create mode 100644 packages/README.md create mode 100644 packages/vms/Makefile.am create mode 100644 packages/vms/Makefile.in create mode 100644 packages/vms/backup_gnv_curl_src.com create mode 100644 packages/vms/build_curl-config_script.com create mode 100644 packages/vms/build_gnv_curl.com create mode 100644 packages/vms/build_gnv_curl_pcsi_desc.com create mode 100644 packages/vms/build_gnv_curl_pcsi_text.com create mode 100644 packages/vms/build_gnv_curl_release_notes.com create mode 100644 packages/vms/build_libcurl_pc.com create mode 100644 packages/vms/build_vms.com create mode 100644 packages/vms/clean_gnv_curl.com create mode 100644 packages/vms/compare_curl_source.com create mode 100644 packages/vms/config_h.com create mode 100644 packages/vms/curl_crtl_init.c create mode 100644 packages/vms/curl_gnv_build_steps.txt create mode 100644 packages/vms/curl_release_note_start.txt create mode 100644 packages/vms/curl_startup.com create mode 100644 packages/vms/curlmsg.h create mode 100644 packages/vms/curlmsg.msg create mode 100644 packages/vms/curlmsg.sdl create mode 100644 packages/vms/curlmsg_vms.h create mode 100644 packages/vms/generate_config_vms_h_curl.com create mode 100644 packages/vms/generate_vax_transfer.com create mode 100644 packages/vms/gnv_conftest.c_first create mode 100755 packages/vms/gnv_curl_configure.sh create mode 100644 packages/vms/gnv_libcurl_symbols.opt create mode 100644 packages/vms/gnv_link_curl.com create mode 100644 packages/vms/macro32_exactcase.patch create mode 100755 packages/vms/make_gnv_curl_install.sh create mode 100644 packages/vms/make_pcsi_curl_kit_name.com create mode 100644 packages/vms/pcsi_gnv_curl_file_list.txt create mode 100644 packages/vms/pcsi_product_gnv_curl.com create mode 100644 packages/vms/readme create mode 100644 packages/vms/report_openssl_version.c create mode 100644 packages/vms/setup_gnv_curl_build.com create mode 100644 packages/vms/stage_curl_install.com create mode 100644 packages/vms/vms_eco_level.h create mode 100644 plan9/README create mode 100644 plan9/include/mkfile create mode 100644 plan9/lib/mkfile create mode 100755 plan9/lib/mkfile.inc create mode 100644 plan9/mkfile create mode 100644 plan9/mkfile.proto create mode 100644 plan9/src/mkfile create mode 100755 plan9/src/mkfile.inc create mode 100644 projects/README.md create mode 100644 projects/Windows/VC14.10/curl-all.sln create mode 100644 projects/Windows/VC14.10/lib/libcurl.sln create mode 100644 projects/Windows/VC14.10/lib/libcurl.vcxproj create mode 100644 projects/Windows/VC14.10/lib/libcurl.vcxproj.filters create mode 100644 projects/Windows/VC14.10/src/curl.sln create mode 100644 projects/Windows/VC14.10/src/curl.vcxproj create mode 100644 projects/Windows/VC14.10/src/curl.vcxproj.filters create mode 100644 projects/Windows/VC14.20/curl-all.sln create mode 100644 projects/Windows/VC14.20/lib/libcurl.sln create mode 100644 projects/Windows/VC14.20/lib/libcurl.vcxproj create mode 100644 projects/Windows/VC14.20/lib/libcurl.vcxproj.filters create mode 100644 projects/Windows/VC14.20/src/curl.sln create mode 100644 projects/Windows/VC14.20/src/curl.vcxproj create mode 100644 projects/Windows/VC14.20/src/curl.vcxproj.filters create mode 100644 projects/Windows/VC14.30/curl-all.sln create mode 100644 projects/Windows/VC14.30/lib/libcurl.sln create mode 100644 projects/Windows/VC14.30/lib/libcurl.vcxproj create mode 100644 projects/Windows/VC14.30/lib/libcurl.vcxproj.filters create mode 100644 projects/Windows/VC14.30/src/curl.sln create mode 100644 projects/Windows/VC14.30/src/curl.vcxproj create mode 100644 projects/Windows/VC14.30/src/curl.vcxproj.filters create mode 100644 projects/Windows/VC14/curl-all.sln create mode 100644 projects/Windows/VC14/lib/libcurl.sln create mode 100644 projects/Windows/VC14/lib/libcurl.vcxproj create mode 100644 projects/Windows/VC14/lib/libcurl.vcxproj.filters create mode 100644 projects/Windows/VC14/src/curl.sln create mode 100644 projects/Windows/VC14/src/curl.vcxproj create mode 100644 projects/Windows/VC14/src/curl.vcxproj.filters create mode 100644 projects/build-openssl.bat create mode 100644 projects/build-wolfssl.bat create mode 100644 projects/checksrc.bat create mode 100644 projects/generate.bat create mode 100644 projects/wolfssl_options.h create mode 100644 projects/wolfssl_override.props create mode 100644 scripts/Makefile.am create mode 100644 scripts/Makefile.in create mode 100755 scripts/cd2cd create mode 100755 scripts/cd2nroff create mode 100755 scripts/cdall create mode 100755 scripts/checksrc.pl create mode 100755 scripts/completion.pl create mode 100755 scripts/coverage.sh create mode 100755 scripts/firefox-db2pem.sh create mode 100755 scripts/mk-ca-bundle.pl create mode 100755 scripts/nroff2cd create mode 100644 scripts/schemetable.c create mode 100644 src/.checksrc create mode 100644 src/CMakeLists.txt create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/Makefile.inc create mode 100644 src/Makefile.mk create mode 100644 src/curl.rc create mode 100755 src/mkhelp.pl create mode 100644 src/slist_wc.c create mode 100644 src/slist_wc.h create mode 100644 src/tool_binmode.c create mode 100644 src/tool_binmode.h create mode 100644 src/tool_bname.c create mode 100644 src/tool_bname.h create mode 100644 src/tool_cb_dbg.c create mode 100644 src/tool_cb_dbg.h create mode 100644 src/tool_cb_hdr.c create mode 100644 src/tool_cb_hdr.h create mode 100644 src/tool_cb_prg.c create mode 100644 src/tool_cb_prg.h create mode 100644 src/tool_cb_rea.c create mode 100644 src/tool_cb_rea.h create mode 100644 src/tool_cb_see.c create mode 100644 src/tool_cb_see.h create mode 100644 src/tool_cb_wrt.c create mode 100644 src/tool_cb_wrt.h create mode 100644 src/tool_cfgable.c create mode 100644 src/tool_cfgable.h create mode 100644 src/tool_dirhie.c create mode 100644 src/tool_dirhie.h create mode 100644 src/tool_doswin.c create mode 100644 src/tool_doswin.h create mode 100644 src/tool_easysrc.c create mode 100644 src/tool_easysrc.h create mode 100644 src/tool_filetime.c create mode 100644 src/tool_filetime.h create mode 100644 src/tool_findfile.c create mode 100644 src/tool_findfile.h create mode 100644 src/tool_formparse.c create mode 100644 src/tool_formparse.h create mode 100644 src/tool_getparam.c create mode 100644 src/tool_getparam.h create mode 100644 src/tool_getpass.c create mode 100644 src/tool_getpass.h create mode 100644 src/tool_help.c create mode 100644 src/tool_help.h create mode 100644 src/tool_helpers.c create mode 100644 src/tool_helpers.h create mode 100644 src/tool_hugehelp.c create mode 100644 src/tool_hugehelp.h create mode 100644 src/tool_ipfs.c create mode 100644 src/tool_ipfs.h create mode 100644 src/tool_libinfo.c create mode 100644 src/tool_libinfo.h create mode 100644 src/tool_listhelp.c create mode 100644 src/tool_main.c create mode 100644 src/tool_main.h create mode 100644 src/tool_msgs.c create mode 100644 src/tool_msgs.h create mode 100644 src/tool_operate.c create mode 100644 src/tool_operate.h create mode 100644 src/tool_operhlp.c create mode 100644 src/tool_operhlp.h create mode 100644 src/tool_paramhlp.c create mode 100644 src/tool_paramhlp.h create mode 100644 src/tool_parsecfg.c create mode 100644 src/tool_parsecfg.h create mode 100644 src/tool_progress.c create mode 100644 src/tool_progress.h create mode 100644 src/tool_sdecls.h create mode 100644 src/tool_setopt.c create mode 100644 src/tool_setopt.h create mode 100644 src/tool_setup.h create mode 100644 src/tool_sleep.c create mode 100644 src/tool_sleep.h create mode 100644 src/tool_stderr.c create mode 100644 src/tool_stderr.h create mode 100644 src/tool_strdup.c create mode 100644 src/tool_strdup.h create mode 100644 src/tool_urlglob.c create mode 100644 src/tool_urlglob.h create mode 100644 src/tool_util.c create mode 100644 src/tool_util.h create mode 100644 src/tool_version.h create mode 100644 src/tool_vms.c create mode 100644 src/tool_vms.h create mode 100644 src/tool_writeout.c create mode 100644 src/tool_writeout.h create mode 100644 src/tool_writeout_json.c create mode 100644 src/tool_writeout_json.h create mode 100644 src/tool_xattr.c create mode 100644 src/tool_xattr.h create mode 100644 src/var.c create mode 100644 src/var.h create mode 100644 tests/CMakeLists.txt create mode 100644 tests/FILEFORMAT.md create mode 100644 tests/Makefile.am create mode 100644 tests/Makefile.in create mode 100644 tests/README.md create mode 100644 tests/appveyor.pm create mode 100644 tests/azure.pm create mode 100644 tests/certs/EdelCurlRoot-ca.cacert create mode 100644 tests/certs/EdelCurlRoot-ca.cnf create mode 100644 tests/certs/EdelCurlRoot-ca.crt create mode 100644 tests/certs/EdelCurlRoot-ca.csr create mode 100644 tests/certs/EdelCurlRoot-ca.der create mode 100644 tests/certs/EdelCurlRoot-ca.key create mode 100644 tests/certs/EdelCurlRoot-ca.prm create mode 100644 tests/certs/Makefile.am create mode 100644 tests/certs/Makefile.in create mode 100644 tests/certs/Server-localhost-firstSAN-sv.crl create mode 100644 tests/certs/Server-localhost-firstSAN-sv.crt create mode 100644 tests/certs/Server-localhost-firstSAN-sv.csr create mode 100644 tests/certs/Server-localhost-firstSAN-sv.der create mode 100644 tests/certs/Server-localhost-firstSAN-sv.dhp create mode 100644 tests/certs/Server-localhost-firstSAN-sv.key create mode 100644 tests/certs/Server-localhost-firstSAN-sv.pem create mode 100644 tests/certs/Server-localhost-firstSAN-sv.prm create mode 100644 tests/certs/Server-localhost-firstSAN-sv.pub.der create mode 100644 tests/certs/Server-localhost-firstSAN-sv.pub.pem create mode 100644 tests/certs/Server-localhost-lastSAN-sv.crl create mode 100644 tests/certs/Server-localhost-lastSAN-sv.crt create mode 100644 tests/certs/Server-localhost-lastSAN-sv.csr create mode 100644 tests/certs/Server-localhost-lastSAN-sv.der create mode 100644 tests/certs/Server-localhost-lastSAN-sv.dhp create mode 100644 tests/certs/Server-localhost-lastSAN-sv.key create mode 100644 tests/certs/Server-localhost-lastSAN-sv.pem create mode 100644 tests/certs/Server-localhost-lastSAN-sv.prm create mode 100644 tests/certs/Server-localhost-lastSAN-sv.pub.der create mode 100644 tests/certs/Server-localhost-lastSAN-sv.pub.pem create mode 100644 tests/certs/Server-localhost-sv.crl create mode 100644 tests/certs/Server-localhost-sv.crt create mode 100644 tests/certs/Server-localhost-sv.csr create mode 100644 tests/certs/Server-localhost-sv.der create mode 100644 tests/certs/Server-localhost-sv.dhp create mode 100644 tests/certs/Server-localhost-sv.key create mode 100644 tests/certs/Server-localhost-sv.pem create mode 100644 tests/certs/Server-localhost-sv.prm create mode 100644 tests/certs/Server-localhost-sv.pub.der create mode 100644 tests/certs/Server-localhost-sv.pub.pem create mode 100644 tests/certs/Server-localhost.nn-sv.crl create mode 100644 tests/certs/Server-localhost.nn-sv.crt create mode 100644 tests/certs/Server-localhost.nn-sv.csr create mode 100644 tests/certs/Server-localhost.nn-sv.der create mode 100644 tests/certs/Server-localhost.nn-sv.dhp create mode 100644 tests/certs/Server-localhost.nn-sv.key create mode 100644 tests/certs/Server-localhost.nn-sv.pem create mode 100644 tests/certs/Server-localhost.nn-sv.prm create mode 100644 tests/certs/Server-localhost.nn-sv.pub.der create mode 100644 tests/certs/Server-localhost.nn-sv.pub.pem create mode 100644 tests/certs/Server-localhost0h-sv.crl create mode 100644 tests/certs/Server-localhost0h-sv.crt create mode 100644 tests/certs/Server-localhost0h-sv.csr create mode 100644 tests/certs/Server-localhost0h-sv.der create mode 100644 tests/certs/Server-localhost0h-sv.dhp create mode 100644 tests/certs/Server-localhost0h-sv.key create mode 100644 tests/certs/Server-localhost0h-sv.pem create mode 100644 tests/certs/Server-localhost0h-sv.prm create mode 100644 tests/certs/Server-localhost0h-sv.pub.der create mode 100644 tests/certs/Server-localhost0h-sv.pub.pem create mode 100644 tests/certs/scripts/Makefile.am create mode 100644 tests/certs/scripts/Makefile.in create mode 100755 tests/certs/scripts/genroot.sh create mode 100755 tests/certs/scripts/genserv.sh create mode 100644 tests/certs/srp-verifier-conf create mode 100644 tests/certs/srp-verifier-db create mode 100644 tests/certs/stunnel-sv.crl create mode 100644 tests/certs/stunnel-sv.crt create mode 100644 tests/certs/stunnel-sv.csr create mode 100644 tests/certs/stunnel-sv.der create mode 100644 tests/certs/stunnel-sv.dhp create mode 100644 tests/certs/stunnel-sv.key create mode 100644 tests/certs/stunnel-sv.pem create mode 100644 tests/certs/stunnel-sv.prm create mode 100644 tests/certs/stunnel-sv.pub.pem create mode 100644 tests/config.in create mode 100644 tests/data/CMakeLists.txt create mode 100644 tests/data/DISABLED create mode 100644 tests/data/Makefile.am create mode 100644 tests/data/Makefile.in create mode 100644 tests/data/Makefile.inc create mode 100644 tests/data/test1 create mode 100644 tests/data/test10 create mode 100644 tests/data/test100 create mode 100644 tests/data/test1000 create mode 100644 tests/data/test1001 create mode 100644 tests/data/test1002 create mode 100644 tests/data/test1003 create mode 100644 tests/data/test1004 create mode 100644 tests/data/test1005 create mode 100644 tests/data/test1006 create mode 100644 tests/data/test1007 create mode 100644 tests/data/test1008 create mode 100644 tests/data/test1009 create mode 100644 tests/data/test101 create mode 100644 tests/data/test1010 create mode 100644 tests/data/test1011 create mode 100644 tests/data/test1012 create mode 100644 tests/data/test1013 create mode 100644 tests/data/test1014 create mode 100644 tests/data/test1015 create mode 100644 tests/data/test1016 create mode 100644 tests/data/test1017 create mode 100644 tests/data/test1018 create mode 100644 tests/data/test1019 create mode 100644 tests/data/test102 create mode 100644 tests/data/test1020 create mode 100644 tests/data/test1021 create mode 100644 tests/data/test1022 create mode 100644 tests/data/test1023 create mode 100644 tests/data/test1024 create mode 100644 tests/data/test1025 create mode 100644 tests/data/test1026 create mode 100644 tests/data/test1027 create mode 100644 tests/data/test1028 create mode 100644 tests/data/test1029 create mode 100644 tests/data/test103 create mode 100644 tests/data/test1030 create mode 100644 tests/data/test1031 create mode 100644 tests/data/test1032 create mode 100644 tests/data/test1033 create mode 100644 tests/data/test1034 create mode 100644 tests/data/test1035 create mode 100644 tests/data/test1036 create mode 100644 tests/data/test1037 create mode 100644 tests/data/test1038 create mode 100644 tests/data/test1039 create mode 100644 tests/data/test104 create mode 100644 tests/data/test1040 create mode 100644 tests/data/test1041 create mode 100644 tests/data/test1042 create mode 100644 tests/data/test1043 create mode 100644 tests/data/test1044 create mode 100644 tests/data/test1045 create mode 100644 tests/data/test1046 create mode 100644 tests/data/test1047 create mode 100644 tests/data/test1048 create mode 100644 tests/data/test1049 create mode 100644 tests/data/test105 create mode 100644 tests/data/test1050 create mode 100644 tests/data/test1051 create mode 100644 tests/data/test1052 create mode 100644 tests/data/test1053 create mode 100644 tests/data/test1054 create mode 100644 tests/data/test1055 create mode 100644 tests/data/test1056 create mode 100644 tests/data/test1057 create mode 100644 tests/data/test1058 create mode 100644 tests/data/test1059 create mode 100644 tests/data/test106 create mode 100644 tests/data/test1060 create mode 100644 tests/data/test1061 create mode 100644 tests/data/test1062 create mode 100644 tests/data/test1063 create mode 100644 tests/data/test1064 create mode 100644 tests/data/test1065 create mode 100644 tests/data/test1066 create mode 100644 tests/data/test1067 create mode 100644 tests/data/test1068 create mode 100644 tests/data/test1069 create mode 100644 tests/data/test107 create mode 100644 tests/data/test1070 create mode 100644 tests/data/test1071 create mode 100644 tests/data/test1072 create mode 100644 tests/data/test1073 create mode 100644 tests/data/test1074 create mode 100644 tests/data/test1075 create mode 100644 tests/data/test1076 create mode 100644 tests/data/test1077 create mode 100644 tests/data/test1078 create mode 100644 tests/data/test1079 create mode 100644 tests/data/test108 create mode 100644 tests/data/test1080 create mode 100644 tests/data/test1081 create mode 100644 tests/data/test1082 create mode 100644 tests/data/test1083 create mode 100644 tests/data/test1084 create mode 100644 tests/data/test1085 create mode 100644 tests/data/test1086 create mode 100644 tests/data/test1087 create mode 100644 tests/data/test1088 create mode 100644 tests/data/test1089 create mode 100644 tests/data/test109 create mode 100644 tests/data/test1090 create mode 100644 tests/data/test1091 create mode 100644 tests/data/test1092 create mode 100644 tests/data/test1093 create mode 100644 tests/data/test1094 create mode 100644 tests/data/test1095 create mode 100644 tests/data/test1096 create mode 100644 tests/data/test1097 create mode 100644 tests/data/test1098 create mode 100644 tests/data/test1099 create mode 100644 tests/data/test11 create mode 100644 tests/data/test110 create mode 100644 tests/data/test1100 create mode 100644 tests/data/test1101 create mode 100644 tests/data/test1102 create mode 100644 tests/data/test1103 create mode 100644 tests/data/test1104 create mode 100644 tests/data/test1105 create mode 100644 tests/data/test1106 create mode 100644 tests/data/test1107 create mode 100644 tests/data/test1108 create mode 100644 tests/data/test1109 create mode 100644 tests/data/test111 create mode 100644 tests/data/test1110 create mode 100644 tests/data/test1111 create mode 100644 tests/data/test1112 create mode 100644 tests/data/test1113 create mode 100644 tests/data/test1114 create mode 100644 tests/data/test1115 create mode 100644 tests/data/test1116 create mode 100644 tests/data/test1117 create mode 100644 tests/data/test1118 create mode 100644 tests/data/test1119 create mode 100644 tests/data/test112 create mode 100644 tests/data/test1120 create mode 100644 tests/data/test1121 create mode 100644 tests/data/test1122 create mode 100644 tests/data/test1123 create mode 100644 tests/data/test1124 create mode 100644 tests/data/test1125 create mode 100644 tests/data/test1126 create mode 100644 tests/data/test1127 create mode 100644 tests/data/test1128 create mode 100644 tests/data/test1129 create mode 100644 tests/data/test113 create mode 100644 tests/data/test1130 create mode 100644 tests/data/test1131 create mode 100644 tests/data/test1132 create mode 100644 tests/data/test1133 create mode 100644 tests/data/test1134 create mode 100644 tests/data/test1135 create mode 100644 tests/data/test1136 create mode 100644 tests/data/test1137 create mode 100644 tests/data/test1138 create mode 100644 tests/data/test1139 create mode 100644 tests/data/test114 create mode 100644 tests/data/test1140 create mode 100644 tests/data/test1141 create mode 100644 tests/data/test1142 create mode 100644 tests/data/test1143 create mode 100644 tests/data/test1144 create mode 100644 tests/data/test1145 create mode 100644 tests/data/test1146 create mode 100644 tests/data/test1147 create mode 100644 tests/data/test1148 create mode 100644 tests/data/test1149 create mode 100644 tests/data/test115 create mode 100644 tests/data/test1150 create mode 100644 tests/data/test1151 create mode 100644 tests/data/test1152 create mode 100644 tests/data/test1153 create mode 100644 tests/data/test1154 create mode 100644 tests/data/test1155 create mode 100644 tests/data/test1156 create mode 100644 tests/data/test1157 create mode 100644 tests/data/test1158 create mode 100644 tests/data/test1159 create mode 100644 tests/data/test116 create mode 100644 tests/data/test1160 create mode 100644 tests/data/test1161 create mode 100644 tests/data/test1162 create mode 100644 tests/data/test1163 create mode 100644 tests/data/test1164 create mode 100644 tests/data/test1165 create mode 100644 tests/data/test1166 create mode 100644 tests/data/test1167 create mode 100644 tests/data/test1168 create mode 100644 tests/data/test1169 create mode 100644 tests/data/test117 create mode 100644 tests/data/test1170 create mode 100644 tests/data/test1171 create mode 100644 tests/data/test1172 create mode 100644 tests/data/test1173 create mode 100644 tests/data/test1174 create mode 100644 tests/data/test1175 create mode 100644 tests/data/test1176 create mode 100644 tests/data/test1177 create mode 100644 tests/data/test1178 create mode 100644 tests/data/test1179 create mode 100644 tests/data/test118 create mode 100644 tests/data/test1180 create mode 100644 tests/data/test1181 create mode 100644 tests/data/test1182 create mode 100644 tests/data/test1183 create mode 100644 tests/data/test1184 create mode 100644 tests/data/test1185 create mode 100644 tests/data/test1186 create mode 100644 tests/data/test1187 create mode 100644 tests/data/test1188 create mode 100644 tests/data/test1189 create mode 100644 tests/data/test119 create mode 100644 tests/data/test1190 create mode 100644 tests/data/test1191 create mode 100644 tests/data/test1192 create mode 100644 tests/data/test1193 create mode 100644 tests/data/test1194 create mode 100644 tests/data/test1195 create mode 100644 tests/data/test1196 create mode 100644 tests/data/test1197 create mode 100644 tests/data/test1198 create mode 100644 tests/data/test1199 create mode 100644 tests/data/test12 create mode 100644 tests/data/test120 create mode 100644 tests/data/test1200 create mode 100644 tests/data/test1201 create mode 100644 tests/data/test1202 create mode 100644 tests/data/test1203 create mode 100644 tests/data/test1204 create mode 100644 tests/data/test1205 create mode 100644 tests/data/test1206 create mode 100644 tests/data/test1207 create mode 100644 tests/data/test1208 create mode 100644 tests/data/test1209 create mode 100644 tests/data/test121 create mode 100644 tests/data/test1210 create mode 100644 tests/data/test1211 create mode 100644 tests/data/test1212 create mode 100644 tests/data/test1213 create mode 100644 tests/data/test1214 create mode 100644 tests/data/test1215 create mode 100644 tests/data/test1216 create mode 100644 tests/data/test1217 create mode 100644 tests/data/test1218 create mode 100644 tests/data/test1219 create mode 100644 tests/data/test122 create mode 100644 tests/data/test1220 create mode 100644 tests/data/test1221 create mode 100644 tests/data/test1222 create mode 100644 tests/data/test1223 create mode 100644 tests/data/test1224 create mode 100644 tests/data/test1225 create mode 100644 tests/data/test1226 create mode 100644 tests/data/test1227 create mode 100644 tests/data/test1228 create mode 100644 tests/data/test1229 create mode 100644 tests/data/test123 create mode 100644 tests/data/test1230 create mode 100644 tests/data/test1231 create mode 100644 tests/data/test1232 create mode 100644 tests/data/test1233 create mode 100644 tests/data/test1234 create mode 100644 tests/data/test1235 create mode 100644 tests/data/test1236 create mode 100644 tests/data/test1237 create mode 100644 tests/data/test1238 create mode 100644 tests/data/test1239 create mode 100644 tests/data/test124 create mode 100644 tests/data/test1240 create mode 100644 tests/data/test1241 create mode 100644 tests/data/test1242 create mode 100644 tests/data/test1243 create mode 100644 tests/data/test1244 create mode 100644 tests/data/test1245 create mode 100644 tests/data/test1246 create mode 100644 tests/data/test1247 create mode 100644 tests/data/test1248 create mode 100644 tests/data/test1249 create mode 100644 tests/data/test125 create mode 100644 tests/data/test1250 create mode 100644 tests/data/test1251 create mode 100644 tests/data/test1252 create mode 100644 tests/data/test1253 create mode 100644 tests/data/test1254 create mode 100644 tests/data/test1255 create mode 100644 tests/data/test1256 create mode 100644 tests/data/test1257 create mode 100644 tests/data/test1258 create mode 100644 tests/data/test1259 create mode 100644 tests/data/test126 create mode 100644 tests/data/test1260 create mode 100644 tests/data/test1261 create mode 100644 tests/data/test1262 create mode 100644 tests/data/test1263 create mode 100644 tests/data/test1264 create mode 100644 tests/data/test1265 create mode 100644 tests/data/test1266 create mode 100644 tests/data/test1267 create mode 100644 tests/data/test1268 create mode 100644 tests/data/test1269 create mode 100644 tests/data/test127 create mode 100644 tests/data/test1270 create mode 100644 tests/data/test1271 create mode 100644 tests/data/test1272 create mode 100644 tests/data/test1273 create mode 100644 tests/data/test1274 create mode 100644 tests/data/test1275 create mode 100644 tests/data/test1276 create mode 100644 tests/data/test1277 create mode 100644 tests/data/test1278 create mode 100644 tests/data/test1279 create mode 100644 tests/data/test128 create mode 100644 tests/data/test1280 create mode 100644 tests/data/test1281 create mode 100644 tests/data/test1282 create mode 100644 tests/data/test1283 create mode 100644 tests/data/test1284 create mode 100644 tests/data/test1285 create mode 100644 tests/data/test1286 create mode 100644 tests/data/test1287 create mode 100644 tests/data/test1288 create mode 100644 tests/data/test1289 create mode 100644 tests/data/test129 create mode 100644 tests/data/test1290 create mode 100644 tests/data/test1291 create mode 100644 tests/data/test1292 create mode 100644 tests/data/test1293 create mode 100644 tests/data/test1294 create mode 100644 tests/data/test1295 create mode 100644 tests/data/test1296 create mode 100644 tests/data/test1297 create mode 100644 tests/data/test1298 create mode 100644 tests/data/test1299 create mode 100644 tests/data/test13 create mode 100644 tests/data/test130 create mode 100644 tests/data/test1300 create mode 100644 tests/data/test1301 create mode 100644 tests/data/test1302 create mode 100644 tests/data/test1303 create mode 100644 tests/data/test1304 create mode 100644 tests/data/test1305 create mode 100644 tests/data/test1306 create mode 100644 tests/data/test1307 create mode 100644 tests/data/test1308 create mode 100644 tests/data/test1309 create mode 100644 tests/data/test131 create mode 100644 tests/data/test1310 create mode 100644 tests/data/test1311 create mode 100644 tests/data/test1312 create mode 100644 tests/data/test1313 create mode 100644 tests/data/test1314 create mode 100644 tests/data/test1315 create mode 100644 tests/data/test1316 create mode 100644 tests/data/test1317 create mode 100644 tests/data/test1318 create mode 100644 tests/data/test1319 create mode 100644 tests/data/test132 create mode 100644 tests/data/test1320 create mode 100644 tests/data/test1321 create mode 100644 tests/data/test1322 create mode 100644 tests/data/test1323 create mode 100644 tests/data/test1324 create mode 100644 tests/data/test1325 create mode 100644 tests/data/test1326 create mode 100644 tests/data/test1327 create mode 100644 tests/data/test1328 create mode 100644 tests/data/test1329 create mode 100644 tests/data/test133 create mode 100644 tests/data/test1330 create mode 100644 tests/data/test1331 create mode 100644 tests/data/test1332 create mode 100644 tests/data/test1333 create mode 100644 tests/data/test1334 create mode 100644 tests/data/test1335 create mode 100644 tests/data/test1336 create mode 100644 tests/data/test1337 create mode 100644 tests/data/test1338 create mode 100644 tests/data/test1339 create mode 100644 tests/data/test134 create mode 100644 tests/data/test1340 create mode 100644 tests/data/test1341 create mode 100644 tests/data/test1342 create mode 100644 tests/data/test1343 create mode 100644 tests/data/test1344 create mode 100644 tests/data/test1345 create mode 100644 tests/data/test1346 create mode 100644 tests/data/test1347 create mode 100644 tests/data/test1348 create mode 100644 tests/data/test1349 create mode 100644 tests/data/test135 create mode 100644 tests/data/test1350 create mode 100644 tests/data/test1351 create mode 100644 tests/data/test1352 create mode 100644 tests/data/test1353 create mode 100644 tests/data/test1354 create mode 100644 tests/data/test1355 create mode 100644 tests/data/test1356 create mode 100644 tests/data/test1357 create mode 100644 tests/data/test1358 create mode 100644 tests/data/test1359 create mode 100644 tests/data/test136 create mode 100644 tests/data/test1360 create mode 100644 tests/data/test1361 create mode 100644 tests/data/test1362 create mode 100644 tests/data/test1363 create mode 100644 tests/data/test1364 create mode 100644 tests/data/test1365 create mode 100644 tests/data/test1366 create mode 100644 tests/data/test1367 create mode 100644 tests/data/test1368 create mode 100644 tests/data/test1369 create mode 100644 tests/data/test137 create mode 100644 tests/data/test1370 create mode 100644 tests/data/test1371 create mode 100644 tests/data/test1372 create mode 100644 tests/data/test1373 create mode 100644 tests/data/test1374 create mode 100644 tests/data/test1375 create mode 100644 tests/data/test1376 create mode 100644 tests/data/test1377 create mode 100644 tests/data/test1378 create mode 100644 tests/data/test1379 create mode 100644 tests/data/test138 create mode 100644 tests/data/test1380 create mode 100644 tests/data/test1381 create mode 100644 tests/data/test1382 create mode 100644 tests/data/test1383 create mode 100644 tests/data/test1384 create mode 100644 tests/data/test1385 create mode 100644 tests/data/test1386 create mode 100644 tests/data/test1387 create mode 100644 tests/data/test1388 create mode 100644 tests/data/test1389 create mode 100644 tests/data/test139 create mode 100644 tests/data/test1390 create mode 100644 tests/data/test1391 create mode 100644 tests/data/test1392 create mode 100644 tests/data/test1393 create mode 100644 tests/data/test1394 create mode 100644 tests/data/test1395 create mode 100644 tests/data/test1396 create mode 100644 tests/data/test1397 create mode 100644 tests/data/test1398 create mode 100644 tests/data/test1399 create mode 100644 tests/data/test14 create mode 100644 tests/data/test140 create mode 100644 tests/data/test1400 create mode 100644 tests/data/test1401 create mode 100644 tests/data/test1402 create mode 100644 tests/data/test1403 create mode 100644 tests/data/test1404 create mode 100644 tests/data/test1405 create mode 100644 tests/data/test1406 create mode 100644 tests/data/test1407 create mode 100644 tests/data/test1408 create mode 100644 tests/data/test1409 create mode 100644 tests/data/test141 create mode 100644 tests/data/test1410 create mode 100644 tests/data/test1411 create mode 100644 tests/data/test1412 create mode 100644 tests/data/test1413 create mode 100644 tests/data/test1414 create mode 100644 tests/data/test1415 create mode 100644 tests/data/test1416 create mode 100644 tests/data/test1417 create mode 100644 tests/data/test1418 create mode 100644 tests/data/test1419 create mode 100644 tests/data/test142 create mode 100644 tests/data/test1420 create mode 100644 tests/data/test1421 create mode 100644 tests/data/test1422 create mode 100644 tests/data/test1423 create mode 100644 tests/data/test1424 create mode 100644 tests/data/test1425 create mode 100644 tests/data/test1426 create mode 100644 tests/data/test1427 create mode 100644 tests/data/test1428 create mode 100644 tests/data/test1429 create mode 100644 tests/data/test143 create mode 100644 tests/data/test1430 create mode 100644 tests/data/test1431 create mode 100644 tests/data/test1432 create mode 100644 tests/data/test1433 create mode 100644 tests/data/test1434 create mode 100644 tests/data/test1435 create mode 100644 tests/data/test1436 create mode 100644 tests/data/test1437 create mode 100644 tests/data/test1438 create mode 100644 tests/data/test1439 create mode 100644 tests/data/test144 create mode 100644 tests/data/test1440 create mode 100644 tests/data/test1441 create mode 100644 tests/data/test1442 create mode 100644 tests/data/test1443 create mode 100644 tests/data/test1444 create mode 100644 tests/data/test1445 create mode 100644 tests/data/test1446 create mode 100644 tests/data/test1447 create mode 100644 tests/data/test1448 create mode 100644 tests/data/test1449 create mode 100644 tests/data/test145 create mode 100644 tests/data/test1450 create mode 100644 tests/data/test1451 create mode 100644 tests/data/test1452 create mode 100644 tests/data/test1453 create mode 100644 tests/data/test1454 create mode 100644 tests/data/test1455 create mode 100644 tests/data/test1456 create mode 100644 tests/data/test1457 create mode 100644 tests/data/test1458 create mode 100644 tests/data/test1459 create mode 100644 tests/data/test146 create mode 100644 tests/data/test1460 create mode 100644 tests/data/test1461 create mode 100644 tests/data/test1462 create mode 100644 tests/data/test1463 create mode 100644 tests/data/test1464 create mode 100644 tests/data/test1465 create mode 100644 tests/data/test1466 create mode 100644 tests/data/test1467 create mode 100644 tests/data/test1468 create mode 100644 tests/data/test1469 create mode 100644 tests/data/test147 create mode 100644 tests/data/test1470 create mode 100644 tests/data/test1471 create mode 100644 tests/data/test1472 create mode 100644 tests/data/test1473 create mode 100644 tests/data/test1475 create mode 100644 tests/data/test1476 create mode 100644 tests/data/test1477 create mode 100644 tests/data/test1478 create mode 100644 tests/data/test148 create mode 100644 tests/data/test149 create mode 100644 tests/data/test15 create mode 100644 tests/data/test150 create mode 100644 tests/data/test1500 create mode 100644 tests/data/test1501 create mode 100644 tests/data/test1502 create mode 100644 tests/data/test1503 create mode 100644 tests/data/test1504 create mode 100644 tests/data/test1505 create mode 100644 tests/data/test1506 create mode 100644 tests/data/test1507 create mode 100644 tests/data/test1508 create mode 100644 tests/data/test1509 create mode 100644 tests/data/test151 create mode 100644 tests/data/test1510 create mode 100644 tests/data/test1511 create mode 100644 tests/data/test1512 create mode 100644 tests/data/test1513 create mode 100644 tests/data/test1514 create mode 100644 tests/data/test1515 create mode 100644 tests/data/test1516 create mode 100644 tests/data/test1517 create mode 100644 tests/data/test1518 create mode 100644 tests/data/test1519 create mode 100644 tests/data/test152 create mode 100644 tests/data/test1520 create mode 100644 tests/data/test1521 create mode 100644 tests/data/test1522 create mode 100644 tests/data/test1523 create mode 100644 tests/data/test1524 create mode 100644 tests/data/test1525 create mode 100644 tests/data/test1526 create mode 100644 tests/data/test1527 create mode 100644 tests/data/test1528 create mode 100644 tests/data/test1529 create mode 100644 tests/data/test153 create mode 100644 tests/data/test1530 create mode 100644 tests/data/test1531 create mode 100644 tests/data/test1532 create mode 100644 tests/data/test1533 create mode 100644 tests/data/test1534 create mode 100644 tests/data/test1535 create mode 100644 tests/data/test1536 create mode 100644 tests/data/test1537 create mode 100644 tests/data/test1538 create mode 100644 tests/data/test1539 create mode 100644 tests/data/test154 create mode 100644 tests/data/test1540 create mode 100644 tests/data/test1542 create mode 100644 tests/data/test1543 create mode 100644 tests/data/test1544 create mode 100644 tests/data/test1545 create mode 100644 tests/data/test155 create mode 100644 tests/data/test1550 create mode 100644 tests/data/test1551 create mode 100644 tests/data/test1552 create mode 100644 tests/data/test1553 create mode 100644 tests/data/test1554 create mode 100644 tests/data/test1555 create mode 100644 tests/data/test1556 create mode 100644 tests/data/test1557 create mode 100644 tests/data/test1558 create mode 100644 tests/data/test1559 create mode 100644 tests/data/test156 create mode 100644 tests/data/test1560 create mode 100644 tests/data/test1561 create mode 100644 tests/data/test1562 create mode 100644 tests/data/test1563 create mode 100644 tests/data/test1564 create mode 100644 tests/data/test1565 create mode 100644 tests/data/test1566 create mode 100644 tests/data/test1567 create mode 100644 tests/data/test1568 create mode 100644 tests/data/test1569 create mode 100644 tests/data/test157 create mode 100644 tests/data/test1570 create mode 100644 tests/data/test158 create mode 100644 tests/data/test159 create mode 100644 tests/data/test1590 create mode 100644 tests/data/test1591 create mode 100644 tests/data/test1592 create mode 100644 tests/data/test1593 create mode 100644 tests/data/test1594 create mode 100644 tests/data/test1595 create mode 100644 tests/data/test1596 create mode 100644 tests/data/test1597 create mode 100644 tests/data/test16 create mode 100644 tests/data/test160 create mode 100644 tests/data/test1600 create mode 100644 tests/data/test1601 create mode 100644 tests/data/test1602 create mode 100644 tests/data/test1603 create mode 100644 tests/data/test1604 create mode 100644 tests/data/test1605 create mode 100644 tests/data/test1606 create mode 100644 tests/data/test1607 create mode 100644 tests/data/test1608 create mode 100644 tests/data/test1609 create mode 100644 tests/data/test161 create mode 100644 tests/data/test1610 create mode 100644 tests/data/test1611 create mode 100644 tests/data/test1612 create mode 100644 tests/data/test1613 create mode 100644 tests/data/test1614 create mode 100644 tests/data/test162 create mode 100644 tests/data/test1620 create mode 100644 tests/data/test1621 create mode 100644 tests/data/test163 create mode 100644 tests/data/test1630 create mode 100644 tests/data/test1631 create mode 100644 tests/data/test1632 create mode 100644 tests/data/test1633 create mode 100644 tests/data/test1634 create mode 100644 tests/data/test1635 create mode 100644 tests/data/test164 create mode 100644 tests/data/test165 create mode 100644 tests/data/test1650 create mode 100644 tests/data/test1651 create mode 100644 tests/data/test1652 create mode 100644 tests/data/test1653 create mode 100644 tests/data/test1654 create mode 100644 tests/data/test1655 create mode 100644 tests/data/test166 create mode 100644 tests/data/test1660 create mode 100644 tests/data/test1661 create mode 100644 tests/data/test1662 create mode 100644 tests/data/test167 create mode 100644 tests/data/test1670 create mode 100644 tests/data/test1671 create mode 100644 tests/data/test168 create mode 100644 tests/data/test1680 create mode 100644 tests/data/test1681 create mode 100644 tests/data/test1682 create mode 100644 tests/data/test1683 create mode 100644 tests/data/test169 create mode 100644 tests/data/test17 create mode 100644 tests/data/test170 create mode 100644 tests/data/test1700 create mode 100644 tests/data/test1701 create mode 100644 tests/data/test1702 create mode 100644 tests/data/test1703 create mode 100644 tests/data/test1704 create mode 100644 tests/data/test171 create mode 100644 tests/data/test172 create mode 100644 tests/data/test173 create mode 100644 tests/data/test174 create mode 100644 tests/data/test175 create mode 100644 tests/data/test176 create mode 100644 tests/data/test177 create mode 100644 tests/data/test178 create mode 100644 tests/data/test179 create mode 100644 tests/data/test18 create mode 100644 tests/data/test180 create mode 100644 tests/data/test1800 create mode 100644 tests/data/test1801 create mode 100644 tests/data/test181 create mode 100644 tests/data/test182 create mode 100644 tests/data/test183 create mode 100644 tests/data/test184 create mode 100644 tests/data/test185 create mode 100644 tests/data/test186 create mode 100644 tests/data/test187 create mode 100644 tests/data/test188 create mode 100644 tests/data/test189 create mode 100644 tests/data/test19 create mode 100644 tests/data/test190 create mode 100644 tests/data/test1900 create mode 100644 tests/data/test1903 create mode 100644 tests/data/test1904 create mode 100644 tests/data/test1905 create mode 100644 tests/data/test1906 create mode 100644 tests/data/test1907 create mode 100644 tests/data/test1908 create mode 100644 tests/data/test1909 create mode 100644 tests/data/test191 create mode 100644 tests/data/test1910 create mode 100644 tests/data/test1911 create mode 100644 tests/data/test1912 create mode 100644 tests/data/test1913 create mode 100644 tests/data/test1914 create mode 100644 tests/data/test1915 create mode 100644 tests/data/test1916 create mode 100644 tests/data/test1917 create mode 100644 tests/data/test1918 create mode 100644 tests/data/test1919 create mode 100644 tests/data/test192 create mode 100644 tests/data/test193 create mode 100644 tests/data/test1933 create mode 100644 tests/data/test1934 create mode 100644 tests/data/test1935 create mode 100644 tests/data/test1936 create mode 100644 tests/data/test1937 create mode 100644 tests/data/test1938 create mode 100644 tests/data/test1939 create mode 100644 tests/data/test194 create mode 100644 tests/data/test1940 create mode 100644 tests/data/test1941 create mode 100644 tests/data/test1942 create mode 100644 tests/data/test1943 create mode 100644 tests/data/test1944 create mode 100644 tests/data/test1945 create mode 100644 tests/data/test1946 create mode 100644 tests/data/test1947 create mode 100644 tests/data/test1948 create mode 100644 tests/data/test195 create mode 100644 tests/data/test1955 create mode 100644 tests/data/test1956 create mode 100644 tests/data/test1957 create mode 100644 tests/data/test1958 create mode 100644 tests/data/test1959 create mode 100644 tests/data/test196 create mode 100644 tests/data/test1960 create mode 100644 tests/data/test1964 create mode 100644 tests/data/test197 create mode 100644 tests/data/test1970 create mode 100644 tests/data/test1971 create mode 100644 tests/data/test1972 create mode 100644 tests/data/test1973 create mode 100644 tests/data/test1974 create mode 100644 tests/data/test1975 create mode 100644 tests/data/test198 create mode 100644 tests/data/test199 create mode 100644 tests/data/test2 create mode 100644 tests/data/test20 create mode 100644 tests/data/test200 create mode 100644 tests/data/test2000 create mode 100644 tests/data/test2001 create mode 100644 tests/data/test2002 create mode 100644 tests/data/test2003 create mode 100644 tests/data/test2004 create mode 100644 tests/data/test201 create mode 100644 tests/data/test202 create mode 100644 tests/data/test2023 create mode 100644 tests/data/test2024 create mode 100644 tests/data/test2025 create mode 100644 tests/data/test2026 create mode 100644 tests/data/test2027 create mode 100644 tests/data/test2028 create mode 100644 tests/data/test2029 create mode 100644 tests/data/test203 create mode 100644 tests/data/test2030 create mode 100644 tests/data/test2031 create mode 100644 tests/data/test2032 create mode 100644 tests/data/test2033 create mode 100644 tests/data/test2034 create mode 100644 tests/data/test2035 create mode 100644 tests/data/test2036 create mode 100644 tests/data/test2037 create mode 100644 tests/data/test2038 create mode 100644 tests/data/test2039 create mode 100644 tests/data/test204 create mode 100644 tests/data/test2040 create mode 100644 tests/data/test2041 create mode 100644 tests/data/test2042 create mode 100644 tests/data/test2043 create mode 100644 tests/data/test2044 create mode 100644 tests/data/test2045 create mode 100644 tests/data/test2046 create mode 100644 tests/data/test2047 create mode 100644 tests/data/test2048 create mode 100644 tests/data/test2049 create mode 100644 tests/data/test205 create mode 100644 tests/data/test2050 create mode 100644 tests/data/test2051 create mode 100644 tests/data/test2052 create mode 100644 tests/data/test2053 create mode 100644 tests/data/test2054 create mode 100644 tests/data/test2055 create mode 100644 tests/data/test2056 create mode 100644 tests/data/test2057 create mode 100644 tests/data/test2058 create mode 100644 tests/data/test2059 create mode 100644 tests/data/test206 create mode 100644 tests/data/test2060 create mode 100644 tests/data/test2061 create mode 100644 tests/data/test2062 create mode 100644 tests/data/test2063 create mode 100644 tests/data/test2064 create mode 100644 tests/data/test2065 create mode 100644 tests/data/test2066 create mode 100644 tests/data/test2067 create mode 100644 tests/data/test2068 create mode 100644 tests/data/test2069 create mode 100644 tests/data/test207 create mode 100644 tests/data/test2070 create mode 100644 tests/data/test2071 create mode 100644 tests/data/test2072 create mode 100644 tests/data/test2073 create mode 100644 tests/data/test2074 create mode 100644 tests/data/test2075 create mode 100644 tests/data/test2076 create mode 100644 tests/data/test2077 create mode 100644 tests/data/test2078 create mode 100644 tests/data/test2079 create mode 100644 tests/data/test208 create mode 100644 tests/data/test2080 create mode 100644 tests/data/test2081 create mode 100644 tests/data/test2082 create mode 100644 tests/data/test2083 create mode 100644 tests/data/test2084 create mode 100644 tests/data/test2085 create mode 100644 tests/data/test2086 create mode 100644 tests/data/test2087 create mode 100644 tests/data/test209 create mode 100644 tests/data/test21 create mode 100644 tests/data/test210 create mode 100644 tests/data/test2100 create mode 100644 tests/data/test211 create mode 100644 tests/data/test212 create mode 100644 tests/data/test213 create mode 100644 tests/data/test214 create mode 100644 tests/data/test215 create mode 100644 tests/data/test216 create mode 100644 tests/data/test217 create mode 100644 tests/data/test218 create mode 100644 tests/data/test219 create mode 100644 tests/data/test22 create mode 100644 tests/data/test220 create mode 100644 tests/data/test2200 create mode 100644 tests/data/test2201 create mode 100644 tests/data/test2202 create mode 100644 tests/data/test2203 create mode 100644 tests/data/test2204 create mode 100644 tests/data/test2205 create mode 100644 tests/data/test221 create mode 100644 tests/data/test222 create mode 100644 tests/data/test223 create mode 100644 tests/data/test224 create mode 100644 tests/data/test225 create mode 100644 tests/data/test226 create mode 100644 tests/data/test227 create mode 100644 tests/data/test228 create mode 100644 tests/data/test229 create mode 100644 tests/data/test23 create mode 100644 tests/data/test230 create mode 100644 tests/data/test2300 create mode 100644 tests/data/test2301 create mode 100644 tests/data/test2302 create mode 100644 tests/data/test2303 create mode 100644 tests/data/test2304 create mode 100644 tests/data/test2305 create mode 100644 tests/data/test2306 create mode 100644 tests/data/test2307 create mode 100644 tests/data/test231 create mode 100644 tests/data/test232 create mode 100644 tests/data/test233 create mode 100644 tests/data/test234 create mode 100644 tests/data/test235 create mode 100644 tests/data/test236 create mode 100644 tests/data/test237 create mode 100644 tests/data/test238 create mode 100644 tests/data/test239 create mode 100644 tests/data/test24 create mode 100644 tests/data/test240 create mode 100644 tests/data/test2400 create mode 100644 tests/data/test2401 create mode 100644 tests/data/test2402 create mode 100644 tests/data/test2403 create mode 100644 tests/data/test2404 create mode 100644 tests/data/test241 create mode 100644 tests/data/test242 create mode 100644 tests/data/test243 create mode 100644 tests/data/test244 create mode 100644 tests/data/test245 create mode 100644 tests/data/test246 create mode 100644 tests/data/test247 create mode 100644 tests/data/test248 create mode 100644 tests/data/test249 create mode 100644 tests/data/test25 create mode 100644 tests/data/test250 create mode 100644 tests/data/test2500 create mode 100644 tests/data/test2501 create mode 100644 tests/data/test2502 create mode 100644 tests/data/test2503 create mode 100644 tests/data/test251 create mode 100644 tests/data/test252 create mode 100644 tests/data/test253 create mode 100644 tests/data/test254 create mode 100644 tests/data/test255 create mode 100644 tests/data/test256 create mode 100644 tests/data/test257 create mode 100644 tests/data/test258 create mode 100644 tests/data/test259 create mode 100644 tests/data/test26 create mode 100644 tests/data/test260 create mode 100644 tests/data/test2600 create mode 100644 tests/data/test2601 create mode 100644 tests/data/test2602 create mode 100644 tests/data/test2603 create mode 100644 tests/data/test261 create mode 100644 tests/data/test262 create mode 100644 tests/data/test263 create mode 100644 tests/data/test264 create mode 100644 tests/data/test265 create mode 100644 tests/data/test266 create mode 100644 tests/data/test267 create mode 100644 tests/data/test268 create mode 100644 tests/data/test269 create mode 100644 tests/data/test27 create mode 100644 tests/data/test270 create mode 100644 tests/data/test271 create mode 100644 tests/data/test272 create mode 100644 tests/data/test273 create mode 100644 tests/data/test274 create mode 100644 tests/data/test275 create mode 100644 tests/data/test276 create mode 100644 tests/data/test277 create mode 100644 tests/data/test278 create mode 100644 tests/data/test279 create mode 100644 tests/data/test28 create mode 100644 tests/data/test280 create mode 100644 tests/data/test281 create mode 100644 tests/data/test282 create mode 100644 tests/data/test283 create mode 100644 tests/data/test284 create mode 100644 tests/data/test285 create mode 100644 tests/data/test286 create mode 100644 tests/data/test287 create mode 100644 tests/data/test288 create mode 100644 tests/data/test289 create mode 100644 tests/data/test29 create mode 100644 tests/data/test290 create mode 100644 tests/data/test291 create mode 100644 tests/data/test292 create mode 100644 tests/data/test293 create mode 100644 tests/data/test294 create mode 100644 tests/data/test295 create mode 100644 tests/data/test296 create mode 100644 tests/data/test297 create mode 100644 tests/data/test298 create mode 100644 tests/data/test299 create mode 100644 tests/data/test3 create mode 100644 tests/data/test30 create mode 100644 tests/data/test300 create mode 100644 tests/data/test3000 create mode 100644 tests/data/test3001 create mode 100644 tests/data/test3002 create mode 100644 tests/data/test3003 create mode 100644 tests/data/test3004 create mode 100644 tests/data/test3005 create mode 100644 tests/data/test3006 create mode 100644 tests/data/test3007 create mode 100644 tests/data/test3008 create mode 100644 tests/data/test3009 create mode 100644 tests/data/test301 create mode 100644 tests/data/test3010 create mode 100644 tests/data/test3011 create mode 100644 tests/data/test3012 create mode 100644 tests/data/test3013 create mode 100644 tests/data/test3014 create mode 100644 tests/data/test3015 create mode 100644 tests/data/test3016 create mode 100644 tests/data/test3017 create mode 100644 tests/data/test3018 create mode 100644 tests/data/test3019 create mode 100644 tests/data/test302 create mode 100644 tests/data/test3020 create mode 100644 tests/data/test3021 create mode 100644 tests/data/test3022 create mode 100644 tests/data/test3023 create mode 100644 tests/data/test3024 create mode 100644 tests/data/test3025 create mode 100644 tests/data/test3026 create mode 100644 tests/data/test3027 create mode 100644 tests/data/test3028 create mode 100644 tests/data/test3029 create mode 100644 tests/data/test303 create mode 100644 tests/data/test3030 create mode 100644 tests/data/test304 create mode 100644 tests/data/test305 create mode 100644 tests/data/test306 create mode 100644 tests/data/test307 create mode 100644 tests/data/test308 create mode 100644 tests/data/test309 create mode 100644 tests/data/test31 create mode 100644 tests/data/test310 create mode 100644 tests/data/test3100 create mode 100644 tests/data/test3101 create mode 100644 tests/data/test3102 create mode 100644 tests/data/test3103 create mode 100644 tests/data/test311 create mode 100644 tests/data/test312 create mode 100644 tests/data/test313 create mode 100644 tests/data/test314 create mode 100644 tests/data/test315 create mode 100644 tests/data/test316 create mode 100644 tests/data/test317 create mode 100644 tests/data/test318 create mode 100644 tests/data/test319 create mode 100644 tests/data/test32 create mode 100644 tests/data/test320 create mode 100644 tests/data/test3200 create mode 100644 tests/data/test3201 create mode 100644 tests/data/test3202 create mode 100644 tests/data/test321 create mode 100644 tests/data/test322 create mode 100644 tests/data/test323 create mode 100644 tests/data/test324 create mode 100644 tests/data/test325 create mode 100644 tests/data/test326 create mode 100644 tests/data/test327 create mode 100644 tests/data/test328 create mode 100644 tests/data/test329 create mode 100644 tests/data/test33 create mode 100644 tests/data/test330 create mode 100644 tests/data/test331 create mode 100644 tests/data/test332 create mode 100644 tests/data/test333 create mode 100644 tests/data/test334 create mode 100644 tests/data/test335 create mode 100644 tests/data/test336 create mode 100644 tests/data/test337 create mode 100644 tests/data/test338 create mode 100644 tests/data/test339 create mode 100644 tests/data/test34 create mode 100644 tests/data/test340 create mode 100644 tests/data/test341 create mode 100644 tests/data/test342 create mode 100644 tests/data/test343 create mode 100644 tests/data/test344 create mode 100644 tests/data/test345 create mode 100644 tests/data/test346 create mode 100644 tests/data/test347 create mode 100644 tests/data/test348 create mode 100644 tests/data/test349 create mode 100644 tests/data/test35 create mode 100644 tests/data/test350 create mode 100644 tests/data/test351 create mode 100644 tests/data/test352 create mode 100644 tests/data/test353 create mode 100644 tests/data/test354 create mode 100644 tests/data/test355 create mode 100644 tests/data/test356 create mode 100644 tests/data/test357 create mode 100644 tests/data/test358 create mode 100644 tests/data/test359 create mode 100644 tests/data/test36 create mode 100644 tests/data/test360 create mode 100644 tests/data/test361 create mode 100644 tests/data/test362 create mode 100644 tests/data/test363 create mode 100644 tests/data/test364 create mode 100644 tests/data/test365 create mode 100644 tests/data/test366 create mode 100644 tests/data/test367 create mode 100644 tests/data/test368 create mode 100644 tests/data/test369 create mode 100644 tests/data/test37 create mode 100644 tests/data/test370 create mode 100644 tests/data/test371 create mode 100644 tests/data/test372 create mode 100644 tests/data/test373 create mode 100644 tests/data/test374 create mode 100644 tests/data/test375 create mode 100644 tests/data/test376 create mode 100644 tests/data/test378 create mode 100644 tests/data/test379 create mode 100644 tests/data/test38 create mode 100644 tests/data/test380 create mode 100644 tests/data/test381 create mode 100644 tests/data/test383 create mode 100644 tests/data/test384 create mode 100644 tests/data/test385 create mode 100644 tests/data/test386 create mode 100644 tests/data/test387 create mode 100644 tests/data/test388 create mode 100644 tests/data/test389 create mode 100644 tests/data/test39 create mode 100644 tests/data/test390 create mode 100644 tests/data/test391 create mode 100644 tests/data/test392 create mode 100644 tests/data/test393 create mode 100644 tests/data/test394 create mode 100644 tests/data/test395 create mode 100644 tests/data/test396 create mode 100644 tests/data/test397 create mode 100644 tests/data/test398 create mode 100644 tests/data/test399 create mode 100644 tests/data/test4 create mode 100644 tests/data/test40 create mode 100644 tests/data/test400 create mode 100644 tests/data/test401 create mode 100644 tests/data/test402 create mode 100644 tests/data/test403 create mode 100644 tests/data/test404 create mode 100644 tests/data/test405 create mode 100644 tests/data/test406 create mode 100644 tests/data/test407 create mode 100644 tests/data/test408 create mode 100644 tests/data/test409 create mode 100644 tests/data/test41 create mode 100644 tests/data/test410 create mode 100644 tests/data/test411 create mode 100644 tests/data/test412 create mode 100644 tests/data/test413 create mode 100644 tests/data/test414 create mode 100644 tests/data/test415 create mode 100644 tests/data/test416 create mode 100644 tests/data/test417 create mode 100644 tests/data/test418 create mode 100644 tests/data/test419 create mode 100644 tests/data/test42 create mode 100644 tests/data/test420 create mode 100644 tests/data/test421 create mode 100644 tests/data/test422 create mode 100644 tests/data/test423 create mode 100644 tests/data/test424 create mode 100644 tests/data/test425 create mode 100644 tests/data/test426 create mode 100644 tests/data/test427 create mode 100644 tests/data/test428 create mode 100644 tests/data/test429 create mode 100644 tests/data/test43 create mode 100644 tests/data/test430 create mode 100644 tests/data/test431 create mode 100644 tests/data/test432 create mode 100644 tests/data/test433 create mode 100644 tests/data/test434 create mode 100644 tests/data/test435 create mode 100644 tests/data/test436 create mode 100644 tests/data/test437 create mode 100644 tests/data/test438 create mode 100644 tests/data/test439 create mode 100644 tests/data/test44 create mode 100644 tests/data/test440 create mode 100644 tests/data/test441 create mode 100644 tests/data/test442 create mode 100644 tests/data/test443 create mode 100644 tests/data/test444 create mode 100644 tests/data/test445 create mode 100644 tests/data/test446 create mode 100644 tests/data/test447 create mode 100644 tests/data/test448 create mode 100644 tests/data/test449 create mode 100644 tests/data/test45 create mode 100644 tests/data/test450 create mode 100644 tests/data/test451 create mode 100644 tests/data/test452 create mode 100644 tests/data/test453 create mode 100644 tests/data/test454 create mode 100644 tests/data/test455 create mode 100644 tests/data/test456 create mode 100644 tests/data/test457 create mode 100644 tests/data/test458 create mode 100644 tests/data/test459 create mode 100644 tests/data/test46 create mode 100644 tests/data/test460 create mode 100644 tests/data/test461 create mode 100644 tests/data/test47 create mode 100644 tests/data/test48 create mode 100644 tests/data/test49 create mode 100644 tests/data/test490 create mode 100644 tests/data/test491 create mode 100644 tests/data/test492 create mode 100644 tests/data/test493 create mode 100644 tests/data/test494 create mode 100644 tests/data/test495 create mode 100644 tests/data/test496 create mode 100644 tests/data/test497 create mode 100644 tests/data/test498 create mode 100644 tests/data/test5 create mode 100644 tests/data/test50 create mode 100644 tests/data/test500 create mode 100644 tests/data/test501 create mode 100644 tests/data/test502 create mode 100644 tests/data/test503 create mode 100644 tests/data/test504 create mode 100644 tests/data/test505 create mode 100644 tests/data/test506 create mode 100644 tests/data/test507 create mode 100644 tests/data/test508 create mode 100644 tests/data/test509 create mode 100644 tests/data/test51 create mode 100644 tests/data/test510 create mode 100644 tests/data/test511 create mode 100644 tests/data/test512 create mode 100644 tests/data/test513 create mode 100644 tests/data/test514 create mode 100644 tests/data/test515 create mode 100644 tests/data/test516 create mode 100644 tests/data/test517 create mode 100644 tests/data/test518 create mode 100644 tests/data/test519 create mode 100644 tests/data/test52 create mode 100644 tests/data/test520 create mode 100644 tests/data/test521 create mode 100644 tests/data/test522 create mode 100644 tests/data/test523 create mode 100644 tests/data/test524 create mode 100644 tests/data/test525 create mode 100644 tests/data/test526 create mode 100644 tests/data/test527 create mode 100644 tests/data/test528 create mode 100644 tests/data/test529 create mode 100644 tests/data/test53 create mode 100644 tests/data/test530 create mode 100644 tests/data/test531 create mode 100644 tests/data/test532 create mode 100644 tests/data/test533 create mode 100644 tests/data/test534 create mode 100644 tests/data/test535 create mode 100644 tests/data/test537 create mode 100644 tests/data/test538 create mode 100644 tests/data/test539 create mode 100644 tests/data/test54 create mode 100644 tests/data/test540 create mode 100644 tests/data/test541 create mode 100644 tests/data/test542 create mode 100644 tests/data/test543 create mode 100644 tests/data/test544 create mode 100644 tests/data/test545 create mode 100644 tests/data/test546 create mode 100644 tests/data/test547 create mode 100644 tests/data/test548 create mode 100644 tests/data/test549 create mode 100644 tests/data/test55 create mode 100644 tests/data/test550 create mode 100644 tests/data/test551 create mode 100644 tests/data/test552 create mode 100644 tests/data/test553 create mode 100644 tests/data/test554 create mode 100644 tests/data/test555 create mode 100644 tests/data/test556 create mode 100644 tests/data/test557 create mode 100644 tests/data/test558 create mode 100644 tests/data/test559 create mode 100644 tests/data/test56 create mode 100644 tests/data/test560 create mode 100644 tests/data/test561 create mode 100644 tests/data/test562 create mode 100644 tests/data/test563 create mode 100644 tests/data/test564 create mode 100644 tests/data/test565 create mode 100644 tests/data/test566 create mode 100644 tests/data/test567 create mode 100644 tests/data/test568 create mode 100644 tests/data/test569 create mode 100644 tests/data/test57 create mode 100644 tests/data/test570 create mode 100644 tests/data/test571 create mode 100644 tests/data/test572 create mode 100644 tests/data/test573 create mode 100644 tests/data/test574 create mode 100644 tests/data/test575 create mode 100644 tests/data/test576 create mode 100644 tests/data/test577 create mode 100644 tests/data/test578 create mode 100644 tests/data/test579 create mode 100644 tests/data/test58 create mode 100644 tests/data/test580 create mode 100644 tests/data/test581 create mode 100644 tests/data/test582 create mode 100644 tests/data/test583 create mode 100644 tests/data/test584 create mode 100644 tests/data/test585 create mode 100644 tests/data/test586 create mode 100644 tests/data/test587 create mode 100644 tests/data/test588 create mode 100644 tests/data/test589 create mode 100644 tests/data/test59 create mode 100644 tests/data/test590 create mode 100644 tests/data/test591 create mode 100644 tests/data/test592 create mode 100644 tests/data/test593 create mode 100644 tests/data/test594 create mode 100644 tests/data/test595 create mode 100644 tests/data/test596 create mode 100644 tests/data/test597 create mode 100644 tests/data/test598 create mode 100644 tests/data/test599 create mode 100644 tests/data/test6 create mode 100644 tests/data/test60 create mode 100644 tests/data/test600 create mode 100644 tests/data/test601 create mode 100644 tests/data/test602 create mode 100644 tests/data/test603 create mode 100644 tests/data/test604 create mode 100644 tests/data/test605 create mode 100644 tests/data/test606 create mode 100644 tests/data/test607 create mode 100644 tests/data/test608 create mode 100644 tests/data/test609 create mode 100644 tests/data/test61 create mode 100644 tests/data/test610 create mode 100644 tests/data/test611 create mode 100644 tests/data/test612 create mode 100644 tests/data/test613 create mode 100644 tests/data/test614 create mode 100644 tests/data/test615 create mode 100644 tests/data/test616 create mode 100644 tests/data/test617 create mode 100644 tests/data/test618 create mode 100644 tests/data/test619 create mode 100644 tests/data/test62 create mode 100644 tests/data/test620 create mode 100644 tests/data/test621 create mode 100644 tests/data/test622 create mode 100644 tests/data/test623 create mode 100644 tests/data/test624 create mode 100644 tests/data/test625 create mode 100644 tests/data/test626 create mode 100644 tests/data/test627 create mode 100644 tests/data/test628 create mode 100644 tests/data/test629 create mode 100644 tests/data/test63 create mode 100644 tests/data/test630 create mode 100644 tests/data/test631 create mode 100644 tests/data/test632 create mode 100644 tests/data/test633 create mode 100644 tests/data/test634 create mode 100644 tests/data/test635 create mode 100644 tests/data/test636 create mode 100644 tests/data/test637 create mode 100644 tests/data/test638 create mode 100644 tests/data/test639 create mode 100644 tests/data/test64 create mode 100644 tests/data/test640 create mode 100644 tests/data/test641 create mode 100644 tests/data/test642 create mode 100644 tests/data/test643 create mode 100644 tests/data/test644 create mode 100644 tests/data/test645 create mode 100644 tests/data/test646 create mode 100644 tests/data/test647 create mode 100644 tests/data/test648 create mode 100644 tests/data/test649 create mode 100644 tests/data/test65 create mode 100644 tests/data/test650 create mode 100644 tests/data/test651 create mode 100644 tests/data/test652 create mode 100644 tests/data/test653 create mode 100644 tests/data/test654 create mode 100644 tests/data/test655 create mode 100644 tests/data/test656 create mode 100644 tests/data/test658 create mode 100644 tests/data/test659 create mode 100644 tests/data/test66 create mode 100644 tests/data/test660 create mode 100644 tests/data/test661 create mode 100644 tests/data/test662 create mode 100644 tests/data/test663 create mode 100644 tests/data/test664 create mode 100644 tests/data/test665 create mode 100644 tests/data/test666 create mode 100644 tests/data/test667 create mode 100644 tests/data/test668 create mode 100644 tests/data/test669 create mode 100644 tests/data/test67 create mode 100644 tests/data/test670 create mode 100644 tests/data/test671 create mode 100644 tests/data/test672 create mode 100644 tests/data/test673 create mode 100644 tests/data/test674 create mode 100644 tests/data/test675 create mode 100644 tests/data/test676 create mode 100644 tests/data/test677 create mode 100644 tests/data/test678 create mode 100644 tests/data/test679 create mode 100644 tests/data/test68 create mode 100644 tests/data/test680 create mode 100644 tests/data/test681 create mode 100644 tests/data/test682 create mode 100644 tests/data/test683 create mode 100644 tests/data/test684 create mode 100644 tests/data/test685 create mode 100644 tests/data/test686 create mode 100644 tests/data/test687 create mode 100644 tests/data/test688 create mode 100644 tests/data/test689 create mode 100644 tests/data/test69 create mode 100644 tests/data/test7 create mode 100644 tests/data/test70 create mode 100644 tests/data/test700 create mode 100644 tests/data/test701 create mode 100644 tests/data/test702 create mode 100644 tests/data/test703 create mode 100644 tests/data/test704 create mode 100644 tests/data/test705 create mode 100644 tests/data/test706 create mode 100644 tests/data/test707 create mode 100644 tests/data/test708 create mode 100644 tests/data/test709 create mode 100644 tests/data/test71 create mode 100644 tests/data/test710 create mode 100644 tests/data/test711 create mode 100644 tests/data/test712 create mode 100644 tests/data/test713 create mode 100644 tests/data/test714 create mode 100644 tests/data/test715 create mode 100644 tests/data/test716 create mode 100644 tests/data/test717 create mode 100644 tests/data/test718 create mode 100644 tests/data/test719 create mode 100644 tests/data/test72 create mode 100644 tests/data/test720 create mode 100644 tests/data/test721 create mode 100644 tests/data/test722 create mode 100644 tests/data/test723 create mode 100644 tests/data/test724 create mode 100644 tests/data/test725 create mode 100644 tests/data/test726 create mode 100644 tests/data/test727 create mode 100644 tests/data/test728 create mode 100644 tests/data/test729 create mode 100644 tests/data/test73 create mode 100644 tests/data/test730 create mode 100644 tests/data/test731 create mode 100644 tests/data/test732 create mode 100644 tests/data/test733 create mode 100644 tests/data/test734 create mode 100644 tests/data/test735 create mode 100644 tests/data/test736 create mode 100644 tests/data/test737 create mode 100644 tests/data/test738 create mode 100644 tests/data/test739 create mode 100644 tests/data/test74 create mode 100644 tests/data/test740 create mode 100644 tests/data/test741 create mode 100644 tests/data/test742 create mode 100644 tests/data/test75 create mode 100644 tests/data/test76 create mode 100644 tests/data/test77 create mode 100644 tests/data/test78 create mode 100644 tests/data/test79 create mode 100644 tests/data/test799 create mode 100644 tests/data/test8 create mode 100644 tests/data/test80 create mode 100644 tests/data/test800 create mode 100644 tests/data/test801 create mode 100644 tests/data/test802 create mode 100644 tests/data/test803 create mode 100644 tests/data/test804 create mode 100644 tests/data/test805 create mode 100644 tests/data/test806 create mode 100644 tests/data/test807 create mode 100644 tests/data/test808 create mode 100644 tests/data/test809 create mode 100644 tests/data/test81 create mode 100644 tests/data/test810 create mode 100644 tests/data/test811 create mode 100644 tests/data/test812 create mode 100644 tests/data/test813 create mode 100644 tests/data/test814 create mode 100644 tests/data/test815 create mode 100644 tests/data/test816 create mode 100644 tests/data/test817 create mode 100644 tests/data/test818 create mode 100644 tests/data/test819 create mode 100644 tests/data/test82 create mode 100644 tests/data/test820 create mode 100644 tests/data/test821 create mode 100644 tests/data/test822 create mode 100644 tests/data/test823 create mode 100644 tests/data/test824 create mode 100644 tests/data/test825 create mode 100644 tests/data/test826 create mode 100644 tests/data/test827 create mode 100644 tests/data/test828 create mode 100644 tests/data/test829 create mode 100644 tests/data/test83 create mode 100644 tests/data/test830 create mode 100644 tests/data/test831 create mode 100644 tests/data/test832 create mode 100644 tests/data/test833 create mode 100644 tests/data/test834 create mode 100644 tests/data/test835 create mode 100644 tests/data/test836 create mode 100644 tests/data/test837 create mode 100644 tests/data/test838 create mode 100644 tests/data/test839 create mode 100644 tests/data/test84 create mode 100644 tests/data/test840 create mode 100644 tests/data/test841 create mode 100644 tests/data/test842 create mode 100644 tests/data/test843 create mode 100644 tests/data/test844 create mode 100644 tests/data/test845 create mode 100644 tests/data/test846 create mode 100644 tests/data/test847 create mode 100644 tests/data/test848 create mode 100644 tests/data/test849 create mode 100644 tests/data/test85 create mode 100644 tests/data/test850 create mode 100644 tests/data/test851 create mode 100644 tests/data/test852 create mode 100644 tests/data/test853 create mode 100644 tests/data/test854 create mode 100644 tests/data/test855 create mode 100644 tests/data/test856 create mode 100644 tests/data/test857 create mode 100644 tests/data/test858 create mode 100644 tests/data/test859 create mode 100644 tests/data/test86 create mode 100644 tests/data/test860 create mode 100644 tests/data/test861 create mode 100644 tests/data/test862 create mode 100644 tests/data/test863 create mode 100644 tests/data/test864 create mode 100644 tests/data/test865 create mode 100644 tests/data/test866 create mode 100644 tests/data/test867 create mode 100644 tests/data/test868 create mode 100644 tests/data/test869 create mode 100644 tests/data/test87 create mode 100644 tests/data/test870 create mode 100644 tests/data/test871 create mode 100644 tests/data/test872 create mode 100644 tests/data/test873 create mode 100644 tests/data/test874 create mode 100644 tests/data/test875 create mode 100644 tests/data/test876 create mode 100644 tests/data/test877 create mode 100644 tests/data/test878 create mode 100644 tests/data/test879 create mode 100644 tests/data/test88 create mode 100644 tests/data/test880 create mode 100644 tests/data/test881 create mode 100644 tests/data/test882 create mode 100644 tests/data/test883 create mode 100644 tests/data/test884 create mode 100644 tests/data/test885 create mode 100644 tests/data/test886 create mode 100644 tests/data/test887 create mode 100644 tests/data/test888 create mode 100644 tests/data/test889 create mode 100644 tests/data/test89 create mode 100644 tests/data/test890 create mode 100644 tests/data/test891 create mode 100644 tests/data/test892 create mode 100644 tests/data/test893 create mode 100644 tests/data/test894 create mode 100644 tests/data/test895 create mode 100644 tests/data/test896 create mode 100644 tests/data/test897 create mode 100644 tests/data/test898 create mode 100644 tests/data/test899 create mode 100644 tests/data/test9 create mode 100644 tests/data/test90 create mode 100644 tests/data/test900 create mode 100644 tests/data/test901 create mode 100644 tests/data/test902 create mode 100644 tests/data/test903 create mode 100644 tests/data/test904 create mode 100644 tests/data/test905 create mode 100644 tests/data/test906 create mode 100644 tests/data/test907 create mode 100644 tests/data/test908 create mode 100644 tests/data/test909 create mode 100644 tests/data/test91 create mode 100644 tests/data/test910 create mode 100644 tests/data/test911 create mode 100644 tests/data/test912 create mode 100644 tests/data/test913 create mode 100644 tests/data/test914 create mode 100644 tests/data/test915 create mode 100644 tests/data/test916 create mode 100644 tests/data/test917 create mode 100644 tests/data/test918 create mode 100644 tests/data/test919 create mode 100644 tests/data/test92 create mode 100644 tests/data/test920 create mode 100644 tests/data/test921 create mode 100644 tests/data/test922 create mode 100644 tests/data/test923 create mode 100644 tests/data/test924 create mode 100644 tests/data/test925 create mode 100644 tests/data/test926 create mode 100644 tests/data/test927 create mode 100644 tests/data/test928 create mode 100644 tests/data/test929 create mode 100644 tests/data/test93 create mode 100644 tests/data/test930 create mode 100644 tests/data/test931 create mode 100644 tests/data/test932 create mode 100644 tests/data/test933 create mode 100644 tests/data/test934 create mode 100644 tests/data/test935 create mode 100644 tests/data/test936 create mode 100644 tests/data/test937 create mode 100644 tests/data/test938 create mode 100644 tests/data/test939 create mode 100644 tests/data/test94 create mode 100644 tests/data/test940 create mode 100644 tests/data/test941 create mode 100644 tests/data/test942 create mode 100644 tests/data/test943 create mode 100644 tests/data/test944 create mode 100644 tests/data/test945 create mode 100644 tests/data/test946 create mode 100644 tests/data/test947 create mode 100644 tests/data/test948 create mode 100644 tests/data/test949 create mode 100644 tests/data/test95 create mode 100644 tests/data/test950 create mode 100644 tests/data/test951 create mode 100644 tests/data/test952 create mode 100644 tests/data/test953 create mode 100644 tests/data/test954 create mode 100644 tests/data/test955 create mode 100644 tests/data/test956 create mode 100644 tests/data/test957 create mode 100644 tests/data/test958 create mode 100644 tests/data/test959 create mode 100644 tests/data/test96 create mode 100644 tests/data/test960 create mode 100644 tests/data/test961 create mode 100644 tests/data/test962 create mode 100644 tests/data/test963 create mode 100644 tests/data/test964 create mode 100644 tests/data/test965 create mode 100644 tests/data/test966 create mode 100644 tests/data/test967 create mode 100644 tests/data/test968 create mode 100644 tests/data/test969 create mode 100644 tests/data/test97 create mode 100644 tests/data/test970 create mode 100644 tests/data/test971 create mode 100644 tests/data/test972 create mode 100644 tests/data/test973 create mode 100644 tests/data/test974 create mode 100644 tests/data/test975 create mode 100644 tests/data/test976 create mode 100644 tests/data/test977 create mode 100644 tests/data/test978 create mode 100644 tests/data/test979 create mode 100644 tests/data/test98 create mode 100644 tests/data/test980 create mode 100644 tests/data/test981 create mode 100644 tests/data/test982 create mode 100644 tests/data/test983 create mode 100644 tests/data/test984 create mode 100644 tests/data/test985 create mode 100644 tests/data/test986 create mode 100644 tests/data/test987 create mode 100644 tests/data/test988 create mode 100644 tests/data/test989 create mode 100644 tests/data/test99 create mode 100644 tests/data/test990 create mode 100644 tests/data/test991 create mode 100644 tests/data/test992 create mode 100755 tests/devtest.pl create mode 100755 tests/dictserver.py create mode 100644 tests/directories.pm create mode 100755 tests/ftpserver.pl create mode 100644 tests/getpart.pm create mode 100644 tests/globalconfig.pm create mode 100755 tests/http-server.pl create mode 100644 tests/http/Makefile.am create mode 100644 tests/http/Makefile.in create mode 100644 tests/http/README.md create mode 100644 tests/http/clients/Makefile.am create mode 100644 tests/http/clients/Makefile.in create mode 100644 tests/http/clients/Makefile.inc create mode 100644 tests/http/clients/h2-download.c create mode 100644 tests/http/clients/h2-pausing.c create mode 100644 tests/http/clients/h2-serverpush.c create mode 100644 tests/http/clients/h2-upgrade-extreme.c create mode 100644 tests/http/clients/tls-session-reuse.c create mode 100644 tests/http/clients/ws-data.c create mode 100644 tests/http/clients/ws-pingpong.c create mode 100644 tests/http/config.ini.in create mode 100755 tests/http2-server.pl create mode 100755 tests/http3-server.pl create mode 100644 tests/libtest/.checksrc create mode 100644 tests/libtest/CMakeLists.txt create mode 100644 tests/libtest/Makefile.am create mode 100644 tests/libtest/Makefile.in create mode 100644 tests/libtest/Makefile.inc create mode 100644 tests/libtest/chkhostname.c create mode 100644 tests/libtest/first.c create mode 100644 tests/libtest/lib1156.c create mode 100644 tests/libtest/lib1301.c create mode 100644 tests/libtest/lib1500.c create mode 100644 tests/libtest/lib1501.c create mode 100644 tests/libtest/lib1502.c create mode 100644 tests/libtest/lib1506.c create mode 100644 tests/libtest/lib1507.c create mode 100644 tests/libtest/lib1508.c create mode 100644 tests/libtest/lib1509.c create mode 100644 tests/libtest/lib1510.c create mode 100644 tests/libtest/lib1511.c create mode 100644 tests/libtest/lib1512.c create mode 100644 tests/libtest/lib1513.c create mode 100644 tests/libtest/lib1514.c create mode 100644 tests/libtest/lib1515.c create mode 100644 tests/libtest/lib1517.c create mode 100644 tests/libtest/lib1518.c create mode 100644 tests/libtest/lib1520.c create mode 100644 tests/libtest/lib1522.c create mode 100644 tests/libtest/lib1523.c create mode 100644 tests/libtest/lib1525.c create mode 100644 tests/libtest/lib1526.c create mode 100644 tests/libtest/lib1527.c create mode 100644 tests/libtest/lib1528.c create mode 100644 tests/libtest/lib1529.c create mode 100644 tests/libtest/lib1530.c create mode 100644 tests/libtest/lib1531.c create mode 100644 tests/libtest/lib1532.c create mode 100644 tests/libtest/lib1533.c create mode 100644 tests/libtest/lib1534.c create mode 100644 tests/libtest/lib1535.c create mode 100644 tests/libtest/lib1536.c create mode 100644 tests/libtest/lib1537.c create mode 100644 tests/libtest/lib1538.c create mode 100644 tests/libtest/lib1540.c create mode 100644 tests/libtest/lib1542.c create mode 100644 tests/libtest/lib1545.c create mode 100644 tests/libtest/lib1550.c create mode 100644 tests/libtest/lib1551.c create mode 100644 tests/libtest/lib1552.c create mode 100644 tests/libtest/lib1553.c create mode 100644 tests/libtest/lib1554.c create mode 100644 tests/libtest/lib1555.c create mode 100644 tests/libtest/lib1556.c create mode 100644 tests/libtest/lib1557.c create mode 100644 tests/libtest/lib1558.c create mode 100644 tests/libtest/lib1559.c create mode 100644 tests/libtest/lib1560.c create mode 100644 tests/libtest/lib1564.c create mode 100644 tests/libtest/lib1565.c create mode 100644 tests/libtest/lib1567.c create mode 100644 tests/libtest/lib1568.c create mode 100644 tests/libtest/lib1569.c create mode 100644 tests/libtest/lib1591.c create mode 100644 tests/libtest/lib1592.c create mode 100644 tests/libtest/lib1593.c create mode 100644 tests/libtest/lib1594.c create mode 100644 tests/libtest/lib1597.c create mode 100644 tests/libtest/lib1662.c create mode 100644 tests/libtest/lib1900.c create mode 100644 tests/libtest/lib1903.c create mode 100644 tests/libtest/lib1905.c create mode 100644 tests/libtest/lib1906.c create mode 100644 tests/libtest/lib1907.c create mode 100644 tests/libtest/lib1908.c create mode 100644 tests/libtest/lib1910.c create mode 100644 tests/libtest/lib1911.c create mode 100644 tests/libtest/lib1912.c create mode 100644 tests/libtest/lib1913.c create mode 100644 tests/libtest/lib1915.c create mode 100644 tests/libtest/lib1916.c create mode 100644 tests/libtest/lib1918.c create mode 100644 tests/libtest/lib1919.c create mode 100644 tests/libtest/lib1933.c create mode 100644 tests/libtest/lib1934.c create mode 100644 tests/libtest/lib1935.c create mode 100644 tests/libtest/lib1936.c create mode 100644 tests/libtest/lib1937.c create mode 100644 tests/libtest/lib1938.c create mode 100644 tests/libtest/lib1939.c create mode 100644 tests/libtest/lib1940.c create mode 100644 tests/libtest/lib1945.c create mode 100644 tests/libtest/lib1947.c create mode 100644 tests/libtest/lib1948.c create mode 100644 tests/libtest/lib1955.c create mode 100644 tests/libtest/lib1956.c create mode 100644 tests/libtest/lib1957.c create mode 100644 tests/libtest/lib1958.c create mode 100644 tests/libtest/lib1959.c create mode 100644 tests/libtest/lib1960.c create mode 100644 tests/libtest/lib1964.c create mode 100644 tests/libtest/lib1970.c create mode 100644 tests/libtest/lib1971.c create mode 100644 tests/libtest/lib1972.c create mode 100644 tests/libtest/lib1973.c create mode 100644 tests/libtest/lib1974.c create mode 100644 tests/libtest/lib1975.c create mode 100644 tests/libtest/lib2301.c create mode 100644 tests/libtest/lib2302.c create mode 100644 tests/libtest/lib2304.c create mode 100644 tests/libtest/lib2305.c create mode 100644 tests/libtest/lib2306.c create mode 100644 tests/libtest/lib2402.c create mode 100644 tests/libtest/lib2404.c create mode 100644 tests/libtest/lib2502.c create mode 100644 tests/libtest/lib3010.c create mode 100644 tests/libtest/lib3025.c create mode 100644 tests/libtest/lib3026.c create mode 100644 tests/libtest/lib3027.c create mode 100644 tests/libtest/lib3100.c create mode 100644 tests/libtest/lib3101.c create mode 100644 tests/libtest/lib3102.c create mode 100644 tests/libtest/lib3103.c create mode 100644 tests/libtest/lib500.c create mode 100644 tests/libtest/lib501.c create mode 100644 tests/libtest/lib502.c create mode 100644 tests/libtest/lib503.c create mode 100644 tests/libtest/lib504.c create mode 100644 tests/libtest/lib505.c create mode 100644 tests/libtest/lib506.c create mode 100644 tests/libtest/lib507.c create mode 100644 tests/libtest/lib508.c create mode 100644 tests/libtest/lib509.c create mode 100644 tests/libtest/lib510.c create mode 100644 tests/libtest/lib511.c create mode 100644 tests/libtest/lib512.c create mode 100644 tests/libtest/lib513.c create mode 100644 tests/libtest/lib514.c create mode 100644 tests/libtest/lib515.c create mode 100644 tests/libtest/lib516.c create mode 100644 tests/libtest/lib517.c create mode 100644 tests/libtest/lib518.c create mode 100644 tests/libtest/lib519.c create mode 100644 tests/libtest/lib520.c create mode 100644 tests/libtest/lib521.c create mode 100644 tests/libtest/lib523.c create mode 100644 tests/libtest/lib524.c create mode 100644 tests/libtest/lib525.c create mode 100644 tests/libtest/lib526.c create mode 100644 tests/libtest/lib530.c create mode 100644 tests/libtest/lib533.c create mode 100644 tests/libtest/lib537.c create mode 100644 tests/libtest/lib539.c create mode 100644 tests/libtest/lib540.c create mode 100644 tests/libtest/lib541.c create mode 100644 tests/libtest/lib542.c create mode 100644 tests/libtest/lib543.c create mode 100644 tests/libtest/lib544.c create mode 100644 tests/libtest/lib547.c create mode 100644 tests/libtest/lib549.c create mode 100644 tests/libtest/lib552.c create mode 100644 tests/libtest/lib553.c create mode 100644 tests/libtest/lib554.c create mode 100644 tests/libtest/lib555.c create mode 100644 tests/libtest/lib556.c create mode 100644 tests/libtest/lib557.c create mode 100644 tests/libtest/lib558.c create mode 100644 tests/libtest/lib559.c create mode 100644 tests/libtest/lib560.c create mode 100644 tests/libtest/lib562.c create mode 100644 tests/libtest/lib564.c create mode 100644 tests/libtest/lib566.c create mode 100644 tests/libtest/lib567.c create mode 100644 tests/libtest/lib568.c create mode 100644 tests/libtest/lib569.c create mode 100644 tests/libtest/lib570.c create mode 100644 tests/libtest/lib571.c create mode 100644 tests/libtest/lib572.c create mode 100644 tests/libtest/lib573.c create mode 100644 tests/libtest/lib574.c create mode 100644 tests/libtest/lib575.c create mode 100644 tests/libtest/lib576.c create mode 100644 tests/libtest/lib578.c create mode 100644 tests/libtest/lib579.c create mode 100644 tests/libtest/lib582.c create mode 100644 tests/libtest/lib583.c create mode 100644 tests/libtest/lib586.c create mode 100644 tests/libtest/lib589.c create mode 100644 tests/libtest/lib590.c create mode 100644 tests/libtest/lib591.c create mode 100644 tests/libtest/lib597.c create mode 100644 tests/libtest/lib598.c create mode 100644 tests/libtest/lib599.c create mode 100644 tests/libtest/lib643.c create mode 100644 tests/libtest/lib650.c create mode 100644 tests/libtest/lib651.c create mode 100644 tests/libtest/lib652.c create mode 100644 tests/libtest/lib653.c create mode 100644 tests/libtest/lib654.c create mode 100644 tests/libtest/lib655.c create mode 100644 tests/libtest/lib658.c create mode 100644 tests/libtest/lib659.c create mode 100644 tests/libtest/lib661.c create mode 100644 tests/libtest/lib666.c create mode 100644 tests/libtest/lib667.c create mode 100644 tests/libtest/lib668.c create mode 100644 tests/libtest/lib670.c create mode 100644 tests/libtest/lib674.c create mode 100644 tests/libtest/lib676.c create mode 100644 tests/libtest/lib677.c create mode 100644 tests/libtest/lib678.c create mode 100644 tests/libtest/libauthretry.c create mode 100644 tests/libtest/libntlmconnect.c create mode 100644 tests/libtest/libprereq.c create mode 100755 tests/libtest/mk-lib1521.pl create mode 100755 tests/libtest/notexists.pl create mode 100644 tests/libtest/sethostname.c create mode 100644 tests/libtest/stub_gssapi.c create mode 100644 tests/libtest/stub_gssapi.h create mode 100644 tests/libtest/test.h create mode 100755 tests/libtest/test1013.pl create mode 100755 tests/libtest/test1022.pl create mode 100755 tests/libtest/test307.pl create mode 100755 tests/libtest/test610.pl create mode 100755 tests/libtest/test613.pl create mode 100644 tests/libtest/testtrace.c create mode 100644 tests/libtest/testtrace.h create mode 100644 tests/libtest/testutil.c create mode 100644 tests/libtest/testutil.h create mode 100755 tests/memanalyze.pl create mode 100755 tests/negtelnetserver.py create mode 100644 tests/pathhelp.pm create mode 100644 tests/processhelp.pm create mode 100755 tests/rtspserver.pl create mode 100644 tests/runner.pm create mode 100644 tests/runtests.1 create mode 100755 tests/runtests.pl create mode 100755 tests/secureserver.pl create mode 100644 tests/server/CMakeLists.txt create mode 100644 tests/server/Makefile.am create mode 100644 tests/server/Makefile.in create mode 100644 tests/server/Makefile.inc create mode 100755 tests/server/base64.pl create mode 100644 tests/server/disabled.c create mode 100644 tests/server/fake_ntlm.c create mode 100644 tests/server/getpart.c create mode 100644 tests/server/getpart.h create mode 100644 tests/server/mqttd.c create mode 100644 tests/server/resolve.c create mode 100644 tests/server/rtspd.c create mode 100644 tests/server/server_setup.h create mode 100644 tests/server/server_sockaddr.h create mode 100644 tests/server/sockfilt.c create mode 100644 tests/server/socksd.c create mode 100644 tests/server/sws.c create mode 100644 tests/server/testpart.c create mode 100644 tests/server/tftp.h create mode 100644 tests/server/tftpd.c create mode 100644 tests/server/util.c create mode 100644 tests/server/util.h create mode 100644 tests/serverhelp.pm create mode 100644 tests/servers.pm create mode 100755 tests/smbserver.py create mode 100644 tests/sshhelp.pm create mode 100755 tests/sshserver.pl create mode 100644 tests/stunnel.pem create mode 100755 tests/test1119.pl create mode 100755 tests/test1132.pl create mode 100755 tests/test1135.pl create mode 100755 tests/test1139.pl create mode 100755 tests/test1140.pl create mode 100755 tests/test1165.pl create mode 100755 tests/test1167.pl create mode 100755 tests/test1173.pl create mode 100755 tests/test1175.pl create mode 100755 tests/test1177.pl create mode 100755 tests/test1222.pl create mode 100755 tests/test1275.pl create mode 100755 tests/test1276.pl create mode 100755 tests/test1477.pl create mode 100755 tests/test1544.pl create mode 100755 tests/test971.pl create mode 100644 tests/testcurl.1 create mode 100755 tests/testcurl.pl create mode 100644 tests/testutil.pm create mode 100755 tests/tftpserver.pl create mode 100644 tests/unit/CMakeLists.txt create mode 100644 tests/unit/Makefile.am create mode 100644 tests/unit/Makefile.in create mode 100644 tests/unit/Makefile.inc create mode 100644 tests/unit/README.md create mode 100644 tests/unit/curlcheck.h create mode 100644 tests/unit/unit1300.c create mode 100644 tests/unit/unit1302.c create mode 100644 tests/unit/unit1303.c create mode 100644 tests/unit/unit1304.c create mode 100644 tests/unit/unit1305.c create mode 100644 tests/unit/unit1307.c create mode 100644 tests/unit/unit1308.c create mode 100644 tests/unit/unit1309.c create mode 100644 tests/unit/unit1323.c create mode 100644 tests/unit/unit1330.c create mode 100644 tests/unit/unit1394.c create mode 100644 tests/unit/unit1395.c create mode 100644 tests/unit/unit1396.c create mode 100644 tests/unit/unit1397.c create mode 100644 tests/unit/unit1398.c create mode 100644 tests/unit/unit1399.c create mode 100644 tests/unit/unit1600.c create mode 100644 tests/unit/unit1601.c create mode 100644 tests/unit/unit1602.c create mode 100644 tests/unit/unit1603.c create mode 100644 tests/unit/unit1604.c create mode 100644 tests/unit/unit1605.c create mode 100644 tests/unit/unit1606.c create mode 100644 tests/unit/unit1607.c create mode 100644 tests/unit/unit1608.c create mode 100644 tests/unit/unit1609.c create mode 100644 tests/unit/unit1610.c create mode 100644 tests/unit/unit1611.c create mode 100644 tests/unit/unit1612.c create mode 100644 tests/unit/unit1614.c create mode 100644 tests/unit/unit1620.c create mode 100644 tests/unit/unit1621.c create mode 100644 tests/unit/unit1650.c create mode 100644 tests/unit/unit1651.c create mode 100644 tests/unit/unit1652.c create mode 100644 tests/unit/unit1653.c create mode 100644 tests/unit/unit1654.c create mode 100644 tests/unit/unit1655.c create mode 100644 tests/unit/unit1660.c create mode 100644 tests/unit/unit1661.c create mode 100644 tests/unit/unit2600.c create mode 100644 tests/unit/unit2601.c create mode 100644 tests/unit/unit2602.c create mode 100644 tests/unit/unit2603.c create mode 100644 tests/unit/unit3200.c create mode 100755 tests/util.py create mode 100644 tests/valgrind.pm create mode 100644 tests/valgrind.supp create mode 100644 winbuild/Makefile.vc create mode 100644 winbuild/MakefileBuild.vc create mode 100644 winbuild/README.md create mode 100755 winbuild/gen_resp_file.bat diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..7c89263 --- /dev/null +++ b/CHANGES @@ -0,0 +1,10696 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + + Changelog + +Version 8.6.0 (31 Jan 2024) + +Daniel Stenberg (31 Jan 2024) + +- RELEASE-NOTES: synced + + curl 8.6.0 + +- THANKS: new contributors from 8.5.0 + +Jay Satiro (31 Jan 2024) + +- cd2nroff: use perl 'strict' and 'warnings' + + - Use strict and warnings pragmas. + + - If open() fails then show the reason. + + - Set STDIN io layer :crlf so that input is properly read on Windows. + + - When STDIN is used as input, the filename $f is now set to "STDIN". + + Various error messages in single() use $f for the filename and this way + it is not undefined when STDIN. + + Closes https://github.com/curl/curl/pull/12819 + +Daniel Stenberg (30 Jan 2024) + +- cd2nroff: fix duplicate output issue + + Assisted-by: Jay Satiro + Fixes https://github.com/curl/curl-www/issues/321 + Closes #12818 + +- lib: error out on multissl + http3 + + Since the QUIC/h3 code has no knowledge or handling of multissl it might + bring unintended consequences if we allow it. + + configure, cmake and curl_setup.h all now reject this combination. + + Assisted-by: Viktor Szakats + Assisted-by: Gisle Vanem + Ref: #12806 + Closes #12807 + +Patrick Monnerat (29 Jan 2024) + +- OS400: sync ILE/RPG binding + + Also do not force git CRLF line endings on *.cmd files for OS400. + + Closes #12815 + +Viktor Szakats (28 Jan 2024) + +- build: delete/replace 3 more clang warning pragmas + + - tool_msgs: delete redundant `-Wformat-nonliteral` suppression pragma. + + - whitespace formatting in `mprintf.h`, lib518, lib537. + + - lib518: fix wrong variable in `sizeof()`. + + - lib518: bump variables to `rlim_t`. + Follow-up to e2b394106d543c4615a60795b7fdce04bd4e5090 #1469 + + - lib518: sync error message with lib537 + Follow-up to 365322b8bcf9efb6a361473d227b70f2032212ce + + - lib518, lib537: replace `-Wformat-nonliteral` suppression pragmas + by reworking test code. + + Follow-up to 5b286c250829e06a135a6ba998e80beb7f43a734 #12812 + Follow-up to aee4ebe59161d0a5281743f96e7738ad97fe1cd4 #12803 + Follow-up to 09230127589eccc7e01c1a7217787ef8e64f3328 #12540 + Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489 + + Reviewed-by: Daniel Stenberg + Closes #12814 + +Richard Levitte (27 Jan 2024) + +- cmake: freshen up docs/INSTALL.cmake + + - Turn docs/INSTALL.cmake into a proper markdown file, + docs/INSTALL-CMAKE.md + - Move things around to divide the description into configuration, + building and installing sections + - Mention the more modern cmake options to configure, build and install, + but also retain the older variants as fallbacks + + Closes #12772 + +Viktor Szakats (27 Jan 2024) + +- build: delete/replace clang warning pragmas + + - delete redundant warning suppressions for `-Wformat-nonliteral`. + This now relies on `CURL_PRINTF()` and it's theoratically possible + that this macro isn't active but the warning is. We're ignoring this + as a corner-case here. + + - replace two pragmas with code changes to avoid the warnings. + + Follow-up to aee4ebe59161d0a5281743f96e7738ad97fe1cd4 #12803 + Follow-up to 09230127589eccc7e01c1a7217787ef8e64f3328 #12540 + Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489 + + Reviewed-by: Daniel Stenberg + Closes #12812 + +Daniel Stenberg (27 Jan 2024) + +- RELEASE-NOTES: synced + +- http: only act on 101 responses when they are HTTP/1.1 + + For 101 responses claiming to be any other protocol, bail out. This + would previously trigger an assert. + + Add test 1704 to verify. + + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66184 + Closes #12811 + +Scarlett McAllister (27 Jan 2024) + +- _VARIABLES.md: add missing 'be' into the sentence + + Closes #12809 + +Stefan Eissing (27 Jan 2024) + +- mqtt, remove remaining use of data->state.buffer + + Closes #12799 + +Daniel Stenberg (27 Jan 2024) + +- x509asn1: switch from malloc to dynbuf + + Closes #12808 + +- x509asn1: make utf8asn1str() use dynbuf instead of malloc + memcpy + + Closes #12808 + +- x509asn1: reduce malloc in Curl_extract_certinfo + + Using dynbuf + + Closes #12808 + +Jay Satiro (27 Jan 2024) + +- THANKS: add Alexander Bartel and Brennan Kinney + + They reported and investigated #10259 which was fixed by 7b2d98df. + + Ref: https://github.com/curl/curl/issues/10259 + +Daniel Stenberg (26 Jan 2024) + +- krb5: add prototype to silence clang warnings on mvsnprintf() + + "error: format string is not a string literal" + + Follow-up to 09230127589eccc7 which made the warning appear + + Assisted-by: Viktor Szakats + Closes #12803 + +- x509asn1: remove code for WANT_VERIFYHOST + + No code ever sets this anymore since we dropped gskit + + Follow-up to 78d6232f1f326b9ab4d + + Closes #12804 + +- socks: reduce the buffer size to 600 (from 8K) + + This is malloc'ed memory and it does not more. Test 742 helps us verify + this. + + Closes #12789 + +Stefan Eissing (26 Jan 2024) + +- file+ftp: use stack buffers instead of data->state.buffer + + Closes #12789 + +- vtls: receive max buffer + + - do not only receive one TLS record, but try to fill + the passed buffer + - consider <4K remaning space is "filled". + + Closes #12801 + +Daniel Stenberg (26 Jan 2024) + +- docs: do not start lines/sentences with So, But nor And + + Closes #12802 + +- docs: remove spurious ampersands from markdown + + They were leftovers from the nroff conversion. + + Follow-up to eefcc1bda4bccd800f5a5 + + Closes #12800 + +Patrick Monnerat (26 Jan 2024) + +- sasl: make login option string override http auth + + - Use http authentication mechanisms as a default, not a preset. + + Consider http authentication options which are mapped to SASL options as + a default (overriding the hardcoded default mask for the protocol) that + is ignored if a login option string is given. + + Prior to this change, if some HTTP auth options were given, sasl mapped + http authentication options to sasl ones but merged them with the login + options. + + That caused problems with the cli tool that sets the http login option + CURLAUTH_BEARER as a side-effect of --oauth2-bearer, because this flag + maps to more than one sasl mechanisms and the latter cannot be cleared + individually by the login options string. + + New test 992 checks this. + + Fixes https://github.com/curl/curl/issues/10259 + Closes https://github.com/curl/curl/pull/12790 + +Stefan Eissing (26 Jan 2024) + +- socks: use own buffer instead of data->state.buffer + + Closes #12788 + +Daniel Stenberg (26 Jan 2024) + +- socks: fix generic output string to say SOCKS instead of SOCKS4 + + ... since it was also logged for SOCKS5. + + Closes #12797 + +- test742: test SOCKS5 with max length user, password and hostname + + Adjusted the socksd server accordingly to allow for configuring that + long user name and password. + + Closes #12797 + +Stefan Eissing (25 Jan 2024) + +- ssh: use stack scratch buffer for seeks + + - instead of data->state.buffer + + Closes #12794 + +Daniel Stenberg (25 Jan 2024) + +- krb5: access the response buffer correctly + + As the pingpong code no longer uses the download buffer. + + Folllow-up to c2d973627bab12ab + Pointed-out-by: Stefan Eissing + Closes #12796 + +Stefan Eissing (25 Jan 2024) + +- mqtt: use stack scratch buffer for recv+publish + + - instead of data->state.buffer + + Closes #12792 + +- telnet, use stack scratch buffer for do + + - instead of data->state.buffer + + Closes #12793 + +- http, use stack scratch buffer + + - instead of data->state.buffer + + Closes #12791 + +- ntlm_wb: do not use data->state.buf any longer + + Closes #12787 + +- gitignore: the generated `libcurl-symbols.md` + + Closes #12795 + +Daniel Stenberg (25 Jan 2024) + +- tool: fix the listhelp generation command + + The previous command line to generate the tool_listhelp.c source file + broke with 2494b8dd5175cee7. + + Make 'make listhelp' invoked in src/ generate it. Also update the + comment in the file to mention the right procedure. + + Closes #12786 + +- http: check for "Host:" case insensitively + + When checking if the user wants to replace the header, the check should + be case insensitive. + + Adding test 461 to verify + + Found-by: Dan Fandrich + Ref: #12782 + Closes #12784 + +Tatsuhiro Tsujikawa (25 Jan 2024) + +- configure: add libngtcp2_crypto_boringssl detection + + If OpenSSL is found to be BoringSSL or AWS-LC, and ngtcp2 is requested, + try to detect libngtcp2_crypto_boringssl. + + Reported-by: ウã•ã‚“ + Fixes #12724 + Closes #12769 + +Daniel Stenberg (25 Jan 2024) + +- http: remove comment reference to a removed solution + + Follow-up to 58974d25d + + Closes #12785 + +Stefan Eissing (25 Jan 2024) + +- pytest: Scorecard tracking CPU and RSS + + Closes #12765 + +Graham Campbell (25 Jan 2024) + +- GHA: bump ngtcp2, gnutls, mod_h2, quiche + + - ngtcp2 to v1.2.0 + - gnutls to 3.8.3 + - mod_h2 to 2.0.26 + - quiche to 0.20.0 + + Closes #12778 + Closes #12779 + Closes #12780 + Closes #12781 + +Daniel Stenberg (25 Jan 2024) + +- ftpserver.pl: send 213 SIZE response without spurious newline + +- pingpong: stop using the download buffer + + The pingpong logic now uses its own dynbuf for receiving command + response data. + + When the "final" response header for a commanad has been received, that + final line is left first in the recvbuf for the protocols to parse at + will. If there is additional data behind the final response line, the + 'overflow' counter is indicate how many bytes. + + Closes #12757 + +- gen.pl: remove bold from .IP used for ## + + Reported-by: Viktor Szakats + Fixes #12776 + Closes #12777 + +Viktor Szakats (24 Jan 2024) + +- cmake: rework options to enable curl and libcurl docs + + Rework CMake options for building/using curl tool and libcurl manuals. + + - rename `ENABLE_MANUAL` to `ENABLE_CURL_MANUAL`, meaning: + to build man page and built-in manual for curl tool. + + - rename `BUILD_DOCS` to `BUILD_LIBCURL_DOCS`, meaning: + to build man pages for libcurl. + + - `BUILD_LIBCURL_DOCS` now works without having to enable + `ENABLE_CURL_MANUAL` too. + + - drop support for existing CMake-level `USE_MANUAL` option to avoid + confusion. (It used to work with the effect of current + `ENABLE_CURL_MANUAL`, but only by accident.) + + Assisted-by: Richard Levitte + Ref: #12771 + Closes #12773 + +Daniel Stenberg (24 Jan 2024) + +- urlapi: remove assert + + This assert triggers wrongly when CURLU_GUESS_SCHEME and + CURLU_NO_AUTHORITY are both set and the URL is a single path. + + I think this assert has played out its role. It was introduced in a + rather big refactor. + + Follow-up to 4cfa5bcc9a + + Reported-by: promptfuzz_ on hackerone + Closes #12775 + +Patrick Monnerat (24 Jan 2024) + +- tests: avoid int/size_t conversion size/sign warnings + + Closes #12768 + +Daniel Stenberg (24 Jan 2024) + +- GHA: add a job scanning for "bad words" in markdown + + This means words, phrases or things we have decided not to use - words that + are spelled right according to the dictionary but we want to avoid. In the + name of consistency and better documentation. + + Closes #12764 + +Viktor Szakats (23 Jan 2024) + +- cmake: speed up curldown processing, enable by default + + - cmake: enable `BUILD_DOCS` by default (this controls converting and + installing `.3` files from `.md` sources) + + - cmake: speed up generating `.3` files by using a single command per + directory, instead of a single command per file. This reduces external + commands by about a thousand. (There remains some CMake logic kicking + in resulting in 500 -one per file- external `-E touch_nocreate` calls.) + + - cd2nroff: add ability to process multiple input files. + + - cd2nroff: add `-k` option to use the source filename to form the + output filename. (instead of the default in-file `Title:` line.) + + Follow-up to 3f08d80b2244524646ce86915c585509ac54fb4c + Follow-up to ea0b575dab86a3c44dd1d547dc500276266aa382 #12753 + Follow-up to eefcc1bda4bccd800f5a56a0fe17a2f44a96e88b #12730 + + Closes #12762 + +Richard Levitte (23 Jan 2024) + +- docs: install curl.1 with cmake as well + + Closes #12759 + +Daniel Stenberg (23 Jan 2024) + +- osslq: remove the TLS library from the version output + + Since we only support using a single TLS library at any one time, we + know that the TLS library for QUIC is the same that is also shown for + regular TLS. + + Fixes #12763 + Reported-by: Viktor Szakats + Closes #12767 + +Stefan Eissing (23 Jan 2024) + +- CI: remove unnecessary OpenSSL 3 option `enable-tls1_3` + + .. and switch OpenSSL 3 libdir from lib64 to lib for consistency. + + Closes https://github.com/curl/curl/pull/12758 + +- GHA: bump nghttp2 version to v1.59.0 + + - Switch to v1.59.0 for GHA CI jobs that use a specific nghttp2-version. + + Closes https://github.com/curl/curl/pull/12766 + +Daniel Stenberg (23 Jan 2024) + +- RELEASE-NOTES: synced + +- docs/cmdline: change to .md for cmdline docs + + - switch all invidual files documenting command line options into .md, + as the documentation is now markdown-looking. + + - made the parser treat 4-space indents as quotes + + - switch to building the curl.1 manpage using the "mainpage.idx" file, + which lists the files to include to generate it, instead of using the + previous page-footer/headers. Also, those files are now also .md + ones, using the same format. I gave them underscore prefixes to make + them sort separately: + _NAME.md, _SYNOPSIS.md, _DESCRIPTION.md, _URL.md, _GLOBBING.md, + _VARIABLES.md, _OUTPUT.md, _PROTOCOLS.md, _PROGRESS.md, _VERSION.md, + _OPTIONS.md, _FILES.md, _ENVIRONMENT.md, _PROXYPREFIX.md, + _EXITCODES.md, _BUGS.md, _AUTHORS.md, _WWW.md, _SEEALSO.md + + - updated test cases accordingly + + Closes #12751 + +dependabot[bot] (23 Jan 2024) + +- CI: bump actions/cache from 3 to 4 + + Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. + - [Release notes](https://github.com/actions/cache/releases) + - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) + - [Commits](https://github.com/actions/cache/compare/v3...v4) + + --- + updated-dependencies: + - dependency-name: actions/cache + dependency-type: direct:production + update-type: version-update:semver-major + ... + + Signed-off-by: dependabot[bot] + Closes #12756 + +Daniel Stenberg (23 Jan 2024) + +- openssl: when verifystatus fails, remove session id from cache + + To prevent that it gets used in a subsequent transfer that skips the + verifystatus check since that check can't be done when the session id is + reused. + + Reported-by: Hiroki Kurosawa + Closes #12760 + +Viktor Szakats (23 Jan 2024) + +- cmake: add option to disable building docs + +Richard Levitte (23 Jan 2024) + +- cmake: use curldown to build man pages + + This throws away the previous HTML and PDF producers, to mimic what + Makefile.am does as faithfully as possible. + + Closes #12753 + +Daniel Stenberg (23 Jan 2024) + +- mksymbolsmanpage.pl: provide references to where the symbol is used + +- docs: introduce "curldown" for libcurl man page format + + curldown is this new file format for libcurl man pages. It is markdown + inspired with differences: + + - Each file has a set of leading headers with meta-data + - Supports a small subset of markdown + - Uses .md file extensions for editors/IDE/GitHub to treat them nicely + - Generates man pages very similar to the previous ones + - Generates man pages that still convert nicely to HTML on the website + - Detects and highlights mentions of curl symbols automatically (when + their man page section is specified) + + tools: + + - cd2nroff: converts from curldown to nroff man page + - nroff2cd: convert an (old) nroff man page to curldown + - cdall: convert many nroff pages to curldown versions + - cd2cd: verifies and updates a curldown to latest curldown + + This setup generates .3 versions of all the curldown versions at build time. + + CI: + + Since the documentation is now technically markdown in the eyes of many + things, the CI runs many more tests and checks on this documentation, + including proselint, link checkers and tests that make sure we capitalize the + first letter after a period... + + Closes #12730 + +Viktor Szakats (22 Jan 2024) + +- libssh2: use `libssh2_session_callback_set2()` with v1.11.1 + + To avoid a local hack to pass function pointers and to avoid + deprecation warnings when building with libssh2 v1.11.1 or newer: + ``` + lib/vssh/libssh2.c:3324:5: warning: 'libssh2_session_callback_set' is depreca + ted: since libssh2 1.11.1. Use libssh2_session_callback_set2() [-Wdeprecated- + declarations] + lib/vssh/libssh2.c:3326:5: warning: 'libssh2_session_callback_set' is depreca + ted: since libssh2 1.11.1. Use libssh2_session_callback_set2() [-Wdeprecated- + declarations] + ``` + Ref: https://github.com/curl/curl-for-win/actions/runs/7609484879/job/2072082 + 1100#step:3:4982 + + Ref: https://github.com/libssh2/libssh2/pull/1285 + Ref: https://github.com/libssh2/libssh2/commit/c0f69548be902147ce014ffa40b8db + 3cf1d4b0b4 + Reviewed-by: Daniel Stenberg + Closes #12754 + +Daniel Stenberg (22 Jan 2024) + +- transfer: make the select_bits_paused condition check both directions + + If there is activity in a direction that is not paused, return false. + + Reported-by: Sergey Bronnikov + Bug: https://curl.se/mail/lib-2024-01/0049.html + Closes #12740 + +Stefan Eissing (22 Jan 2024) + +- http3: initial support for OpenSSL 3.2 QUIC stack + + - HTTP/3 for curl using OpenSSL's own QUIC stack together + with nghttp3 + - configure with `--with-openssl-quic` to enable curl to + build this. This requires the nghttp3 library + - implementation with the following restrictions: + * macOS has to use an unconnected UDP socket due to an + issue in OpenSSL's datagram implementation + See https://github.com/openssl/openssl/issues/23251 + This makes connections to non-reponsive servers hang. + * GET requests will send the indicator that they have + no body in a separate QUIC packet. This may result + in processing delays or Transfer-Encodings on proxied + requests + * uploads that encounter blocks will use 100% cpu as + detection of these flow control issue is not working + (we have not figured out to pry that from OpenSSL). + + Closes #12734 + +Viktor Szakats (22 Jan 2024) + +- cmake: fix `ENABLE_MANUAL` option + + Fix the `ENABLE_MANUAL` option. Set it to default to `OFF`. + + Before this patch `ENABLE_MANUAL=ON` was a no-op, even though it was the + option designed to enable building and using the built-in curl manual. + (`USE_MANUAL=ON` option worked for this instead, by accident). + + Ref: https://github.com/curl/curl/pull/12730#issuecomment-1902572409 + Closes #12749 + +Mohammadreza Hendiani (19 Jan 2024) + +- TODO: update broken link to ratelimit-headers draft + + Closes #12741 + +Daniel Stenberg (19 Jan 2024) + +- cmake: when USE_MANUAL=YES, build the curl.1 man page + + Fixes KNOWN_BUG 15.4 + + Closes #12742 + +- cmdline-opts/write-out.d: remove spurious double quotes + +Stefan Eissing (19 Jan 2024) + +- rtsp: Convert assertion into debug log + + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65934 + + - write excess bytes to the client where the standard excess bytes + checks will report any wrongness and fail the transfer + + Fixes #12738 + Closes #12739 + +Daniel Stenberg (19 Jan 2024) + +- headers: remove assert from Curl_headers_push + + The fuzzer managed to reach the function without a terminating CR or LF + so let's handle it normally. While there, remove the goto. + + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65839 + + Closes #12721 + +- curl_easy_getinfo.3: remove the wrong time value count + + It said "six" time values but they are eight by now. Remove the mention + of the amount. + + Closes #12727 + +Viktor Szakats (18 Jan 2024) + +- mbedtls: fix `-Wnull-dereference` and `-Wredundant-decls` + + - Silence warning in mbedTLS v3.5.1 public headers: + ``` + ./mbedtls/_x64-linux-musl/usr/include/psa/crypto_extra.h:489:14: warning: r + edundant redeclaration of 'psa_set_key_domain_parameters' [-Wredundant-decls] + ./mbedtls/_x64-linux-musl/usr/include/psa/crypto_struct.h:354:14: note: pre + vious declaration of 'psa_set_key_domain_parameters' was here + ``` + Ref: https://github.com/libssh2/libssh2/commit/ecec68a2c13a9c63fe8c2dc457ae + 785a513e157c + Ref: https://github.com/libssh2/libssh2/pull/1226 + + - Fix compiler warnings seen with gcc 9.2.0 + cmake unity: + ``` + ./curl/lib/vtls/mbedtls.c: In function 'mbedtls_bio_cf_read': + ./curl/lib/vtls/mbedtls.c:189:11: warning: null pointer dereference [-Wnull + -dereference] + 189 | nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &res + ult); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ + ./curl/lib/vtls/mbedtls.c: In function 'mbedtls_bio_cf_write': + ./curl/lib/vtls/mbedtls.c:168:14: warning: null pointer dereference [-Wnull + -dereference] + 168 | nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, & + result); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~ + ``` + + - delete stray `#else`. + + Closes #12720 + +Daniel Stenberg (17 Jan 2024) + +- docs: cleanup nroff format use + + - remove use of .BI for code snippet + - stop using .br, just do a blank line + - remove use of .PP + - remove use for .sp + - remove backslash in .IP + - use .IP instead of .TP + + Closes #12731 + +Stefan Eissing (17 Jan 2024) + +- test2307: fix expected failure code after ws refactoring + + Fixes #12722 + Closes #12728 + +Jay Satiro (17 Jan 2024) + +- cf-socket: show errno in tcpkeepalive error messages + + - If the socket keepalive options (TCP_KEEPIDLE, etc) cannot be set + then show the errno in the verbose error messages. + + Ref: https://github.com/curl/curl/discussions/12715#discussioncomment-8151652 + + Closes https://github.com/curl/curl/pull/12726 + +- tool_getparam: stop supporting `@filename` style for --cookie + + The `@filename` style was never documented for --cookie + but prior to this change curl would accept it anyway and always treat a + @ prefixed string as a filename. + + That's a problem if the string also contains a = sign because then it is + documented to be interpreted as a cookie string and not a filename. + + Example: + + `--cookie @foo=bar` + + Before: Interpreted as load cookies from filename foo=bar. + + After: Interpreted as cookie `@foo=bar` (name `@foo` and value `bar`). + + Other curl options with a data/filename option-value use the `@filename` + to distinguish filenames which is probably how this happened. The + --cookie option has never been documented that way. + + Ref: https://curl.se/docs/manpage.html#-b + + Closes https://github.com/curl/curl/pull/12645 + +Stefan Eissing (16 Jan 2024) + +- websockets: refactor decode chain + + - use client writer stack for decoding frames + - move websocket protocol handler to ws.c + + Closes #12713 + +- websockets: check for negative payload lengths + + - in en- and decoding, check the websocket frame payload lengths for + negative values (from curl_off_t) and error the operation in that case + - add test 2307 to verify + + Closes #12707 + +Daniel Stenberg (16 Jan 2024) + +- docs: mention env vars not used by schannel + + Ref: #12704 + + Co-authored-by: Jay Satiro + + Closes #12711 + +- tool_operate: make --remove-on-error only remove "real" files + + Reported-by: Harry Sintonen + Assisted-by: Dan Fandrich + + Closes #12710 + +Jay Wu (16 Jan 2024) + +- url: don't set default CA paths for Secure Transport backend + + As the default for this backend is the native CA store. + + Closes #12704 + +Lin Sun (16 Jan 2024) + +- asyn-ares: with modern c-ares, use its default timeout + + Closes #12703 + +Daniel Stenberg (15 Jan 2024) + +- tool_operate: stop setting the file comment on Amiga + + - the URL is capped at 80 cols, which ruins it if longer + - it does not strip off URL credentials + - it is done unconditonally, not on --xattr + - we don't have Amiga in the CI which makes fixing it blindly fragile + + Someone who builds and tests on Amiga can add it back correctly in a + future if there is a desire. + + Reported-by: Harry Sintonen + Closes #12709 + +Stefan Eissing (15 Jan 2024) + +- rtsp: deal with borked server responses + + - enforce a response body length of 0, if the + response has no Content-lenght. This is according + to the RTSP spec. + - excess bytes in a response body are forwarded to + the client writers which will report and fail the + transfer + + Follow-up to d7b6ce6 + Fixes #12701 + Closes #12706 + +Daniel Stenberg (14 Jan 2024) + +- version: show only the libpsl version, not its dependencies + + The libpsl version output otherwise also includes version number for its + dependencies, like IDN lib, but since libcurl does not use libpsl's IDN + functionality those components are not important. + + Ref: https://github.com/curl/curl-for-win/issues/63 + Closes #12700 + +Brad Harder (14 Jan 2024) + +- curl.h: CURLOPT_DNS_SERVERS is only available with c-ares + + Closes #12695 + +Daniel Stenberg (14 Jan 2024) + +- cmdline-opts/gen.pl: error on initital blank line + + After the "---" separator, there should be no blank line and this script + now errors out if one is detected. + + Ref: #12696 + Closes #12698 + +- cf-h1-proxy: no CURLOPT_USERAGENT in CONNECT with hyper + + Follow-up to 693cd1679361828a which was incomplete + + Ref #12680 + Closes #12697 + +- curl_multi_fdset.3: remove mention of null pointer support + + ... since this funtion has not supported null pointer fd_set arguments since + at least 2006. (That's when I stopped my git blame journey) + + Fixes #12691 + Reported-by: sfan5 on github + Closes #12692 + +Mark Huang (14 Jan 2024) + +- docs/cmdline: remove unnecessary line breaks + + Closes #12696 + +Daniel Stenberg (14 Jan 2024) + +- transfer: remove warning: Value stored to 'blen' is never read + + Detected by scan-build + + Follow-up from 1cd2f0072f + + Closes #12693 + +Stefan Eissing (13 Jan 2024) + +- lib: replace readwrite with write_resp + + This clarifies the handling of server responses by folding the code for + the complicated protocols into their protocol handlers. This concerns + mainly HTTP and its bastard sibling RTSP. + + The terms "read" and "write" are often used without clear context if + they refer to the connect or the client/application side of a + transfer. This PR uses "read/write" for operations on the client side + and "send/receive" for the connection, e.g. server side. If this is + considered useful, we can revisit renaming of further methods in another + PR. + + Curl's protocol handler `readwrite()` method been changed: + + ```diff + - CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, + - const char *buf, size_t blen, + - size_t *pconsumed, bool *readmore); + + CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t ble + n, + + bool is_eos, bool *done); + ``` + + The name was changed to clarify that this writes reponse data to the + client side. The parameter changes are: + + * `conn` removed as it always operates on `data->conn` + * `pconsumed` removed as the method needs to handle all data on success + * `readmore` removed as no longer necessary + * `is_eos` as indicator that this is the last call for the transfer + response (end-of-stream). + * `done` TRUE on return iff the transfer response is to be treated as + finished + + This change affects many files only because of updated comments in + handlers that provide no implementation. The real change is that the + HTTP protocol handlers now provide an implementation. + + The HTTP protocol handlers `write_resp()` implementation will get passed + **all** raw data of a server response for the transfer. The HTTP/1.x + formatted status and headers, as well as the undecoded response + body. `Curl_http_write_resp_hds()` is used internally to parse the + response headers and pass them on. This method is public as the RTSP + protocol handler also uses it. + + HTTP/1.1 "chunked" transport encoding is now part of the general + *content encoding* writer stack, just like other encodings. A new flag + `CLIENTWRITE_EOS` was added for the last client write. This allows + writers to verify that they are in a valid end state. The chunked + decoder will check if it indeed has seen the last chunk. + + The general response handling in `transfer.c:466` happens in function + `readwrite_data()`. This mainly operates now like: + + ``` + static CURLcode readwrite_data(data, ...) + { + do { + Curl_xfer_recv_resp(data, buf) + ... + Curl_xfer_write_resp(data, buf) + ... + } while(interested); + ... + } + ``` + + All the response data handling is implemented in + `Curl_xfer_write_resp()`. It calls the protocol handler's `write_resp()` + implementation if available, or does the default behaviour. + + All raw response data needs to pass through this function. Which also + means that anyone in possession of such data may call + `Curl_xfer_write_resp()`. + + Closes #12480 + +Daniel Stenberg (13 Jan 2024) + +- RELEASE-NOTES: synced + +- TODO: TFTP doesn't convert LF to CRLF for mode=netascii + + Closes #12655 + Closes #12690 + +- gen: do italics/bold for a range of letters, not just single word + + Previously it would match only on a sequence of non-space, which made it + miss to highlight for example "public suffix list". + + Updated the recent cookie.d edit from 5da57193b732 to use bold instead + of italics. + + Closes #12689 + +- docs: describe and highlight super cookies + + Reported-by: Yadhu Krishna M + + Closes #12687 + +- configure: when enabling QUIC, check that TLS supports QUIC + + Most importantly perhaps is when using OpenSSL that the used + build/flavor has the QUIC API: the vanilla OpenSSL does not, only + BoringSSL, libressl, AWS-LC and quictls do. + + Ref: https://github.com/curl/curl/commit/5d044ad9480a9f556f4b6a252d7533b1ba7f + e57e#r136780413 + + Closes #12683 + +Stefan Eissing (11 Jan 2024) + +- vquic: extract TLS setup into own source + + - separate ngtcp2 specific parts out + - provide callback during init to allow ngtcp2 to apply its defaults + + Closes #12678 + +Sergey Markelov (11 Jan 2024) + +- multi: remove total timer reset in file_do() while fetching file:// + + The total timer is properly reset in MSTATE_INIT. MSTATE_CONNECT starts + with resetting the timer that is a start point for further multi states. + If file://, MSTATE_DO calls file_do() that should not reset the total + timer. Otherwise, the total time is always less than the pre-transfer + and the start transfer times. + + Closes #12682 + +Daniel Stenberg (11 Jan 2024) + +- http_proxy: a blank CURLOPT_USERAGENT should not be used in CONNECT + + Extended test 80 to verify this. + + Reported-by: Stefan Eissing + Fixes #12680 + Closes #12681 + +- sectransp: do verify_cert without memdup for blobs + + Since the information is then already stored in memory, this can avoid + an extra set of malloc + free calls. + + Closes #12679 + +- hsts: remove assert for zero length domain + + A zero length domain can happen if the HSTS parser is given invalid + input data which is not unheard of and is done by the fuzzer. + + Follow-up from cfe7902111ae547873 + + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65661 + + Closes #12676 + +- headers: make sure the trailing newline is not stored + + extended test1940 to verify blank header fields too + + Bug: https://curl.se/mail/lib-2024-01/0019.html + Reported-by: Dmitry Karpov + Closes #12675 + +- curl_easy_header.3: tiny language fix + + Closes #12672 + +- examples/range.c: add + + Closes #12671 + +- examples/netrc.c: add + + Closes #12671 + +- examples/ipv6.c: new example showing IPv6-only internet transfer + + Closes #12671 + +- examples/address-scope.c: renamed from ipv6.c + + It shows address scope use really + + Closes #12671 + +Stefan Eissing (9 Jan 2024) + +- multi: pollset adjust, init with FIRSTSOCKET during connect + + - `conn->sockfd` is set by `Curl_setup_transfer()`, but that + is called *after* the connection has been established + - use `conn->sock[FIRSTSOCKET]` instead + + Follow-up to a0f94800d507de + Closes #12664 + +Daniel Stenberg (9 Jan 2024) + +- WEBSOCKET.md: remove dead link + +- CI: spellcheck/appveyor: invoke configure --without-libpsl + + Follow-up to 2998874bb61ac6 + +- cmdline/docs/*.d: switch to using ## instead of .IP + + To make the editing easier. To write and to read. + + Closes #12667 + +- gen.pl: support ## for doing .IP in table-like lists + + Warn on use of .RS/.IP/.RE + + Closes #12667 + +Jay Satiro (9 Jan 2024) + +- cookie.d: Document use of empty string to enable cookie engine + + - Explain that --cookie "" can be used to enable the cookie engine + without reading any initial cookies. + + As is documented in CURLOPT_COOKIEFILE. + + Ref: https://curl.se/libcurl/c/CURLOPT_COOKIEFILE.html + + Bug: https://github.com/curl/curl/issues/12643#issuecomment-1879844420 + Reported-by: janko-js@users.noreply.github.com + + Closes https://github.com/curl/curl/pull/12646 + +Daniel Stenberg (9 Jan 2024) + +- setopt: use memdup0 when cloning COPYPOSTFIELDS + + Closes #12651 + +- telnet: use dynbuf instad of malloc for escape buffer + + Previously, send_telnet_data() would malloc + free a buffer every time + for escaping IAC codes. Now, it reuses a dynbuf for this purpose. + + Closes #12652 + +- CI: install libpsl or configure --without-libpsl in builds + + As a follow-up to the stricted libpsl check in configure + +- configure: make libpsl detection failure cause error + + To force users to explictily disable it if they really don't want it + used and make it harder to accidentally miss it. + + --without-libpsl is the option to use if PSL is not wanted. + + Closes #12661 + +- RELEASE-NOTES: synced + +- pop3: replace calloc + memcpy with memdup0 + + ... and make sure to return error on out of memory. + + Closes #12650 + +- lib: add debug log outputs for CURLE_BAD_FUNCTION_ARGUMENT + + Closes #12658 + +- mime: use memdup0 instead of malloc + memcpy + + Closes #12649 + +- tool_getparam: move the --rate logic into set_rate() + +- tool_getparam: switch to an enum for every option + + To make the big switch much easier to read/understand and to make it + easier to add new options. + +- tool_getparam: build post data using dynbuf (more) + +- tool_getparam: replace malloc + copy by dynbuf for --data + +- tool_getparam: make data_urlencode avoid direct malloc + + use aprintf() instead + +- tool_getparam: move the --url-query logic into url_query() + + This function is not doing post at all so it was always weirdly placed. + +- tool_getparam: move the --data logic into set_data() + +- tool_getparam: unify the cmdline switch() into a single one + + - easier to follow, easier to modify, easier to extend, possibly slightly + faster + + - each case now has the long option as a comment + +- tool_getparam: bsearch cmdline options + + - the option names are now alpha sorted and lookup is a lot faster + + - use case sensitive matching. It was previously case insensitive, but that + was not documented nor tested. + + - remove "partial match" feature. It was not documented, not tested and + was always fragile as existing use could break when we add a new + option + + - lookup short options via a table + + Closes #12631 + +Gabe (8 Jan 2024) + +- COPYING: update copyright year + + Closes #12654 + +Stefan Eissing (8 Jan 2024) + +- url: init conn->sockfd and writesockfd to CURL_SOCKET_BAD + + Also add more tracing to test 19 + + Follow-up to a0f9480 + + Fixes #12657 + Closes #12659 + +Daniel Stenberg (8 Jan 2024) + +- connect: remove margin from eyeballer alloc + + Presumably leftovers from debugging + + Closes #12647 + +- ftp: only consider entry path if it has a length + + Follow-up from 8edcfedc1a144f438bd1cdf814a0016cb + + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65631 + + Avoids a NULL pointer deref. + + Closes #12648 + +Stefan Eissing (7 Jan 2024) + +- transfer: adjust_pollset improvements + + - let `multi_getsock()` initialize the pollset in what the + transfer state requires in regards to SEND/RECV + - change connection filters `adjust_pollset()` implementation + to react on the presence of POLLIN/-OUT in the pollset and + no longer check CURL_WANT_SEND/CURL_WANT_RECV + - cf-socket will no longer add POLLIN on its own + - http2 and http/3 filters will only do adjustments if the + passed pollset wants to POLLIN/OUT for the transfer on + the socket. This is similar to the HTTP/2 proxy filter + and works in stacked filters. + + Closes #12640 + +Daniel Stenberg (6 Jan 2024) + +- ftp: use memdup0 to store the OS from a SYST 215 response + + avoid malloc + direct buffer fiddle + + Closes #12639 + +- ftp: use dynbuf to store entrypath + + avoid direct malloc + + Closes #12638 + +Lealem Amedie (6 Jan 2024) + +- wolfssl: load certificate *chain* for PEM client certs + + Closes #12634 + +Stefan Eissing (4 Jan 2024) + +- http: adjust_pollset fix + + do not add a socket for POLLIN when the transfer does not want to send + (for example is paused). + + Follow-up to 47f5b1a + + Reported-by: bubbleguuum on github + Fixes #12632 + Closes #12633 + +Daniel Stenberg (3 Jan 2024) + +- tool: make parser reject blank arguments if not supported + + Already in the getstr() function that clones the input argument. + + Closes #12620 + +dependabot[bot] (3 Jan 2024) + +- build(deps): bump github/codeql-action from 2 to 3 + + Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 + to 3. + - [Release notes](https://github.com/github/codeql-action/releases) + - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) + - [Commits](https://github.com/github/codeql-action/compare/v2...v3) + + --- + updated-dependencies: + - dependency-name: github/codeql-action + dependency-type: direct:production + update-type: version-update:semver-major + ... + + Signed-off-by: dependabot[bot] + + Closes #12625 + +- build(deps): bump actions/checkout from 3 to 4 + + Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. + - [Release notes](https://github.com/actions/checkout/releases) + - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) + - [Commits](https://github.com/actions/checkout/compare/v3...v4) + + --- + updated-dependencies: + - dependency-name: actions/checkout + dependency-type: direct:production + update-type: version-update:semver-major + ... + + Signed-off-by: dependabot[bot] + + Closes #12624 + +- build(deps): bump actions/upload-artifact from 3 to 4 + + Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) f + rom 3 to 4. + - [Release notes](https://github.com/actions/upload-artifact/releases) + - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) + + --- + updated-dependencies: + - dependency-name: actions/upload-artifact + dependency-type: direct:production + update-type: version-update:semver-major + ... + + Signed-off-by: dependabot[bot] + + Closes #12627 + +- build(deps): bump actions/download-artifact from 3 to 4 + + Bumps [actions/download-artifact](https://github.com/actions/download-artifac + t) from 3 to 4. + - [Release notes](https://github.com/actions/download-artifact/releases) + - [Commits](https://github.com/actions/download-artifact/compare/v3...v4) + + --- + updated-dependencies: + - dependency-name: actions/download-artifact + dependency-type: direct:production + update-type: version-update:semver-major + ... + + Signed-off-by: dependabot[bot] + + Closes #12626 + +Stefan Eissing (3 Jan 2024) + +- http3/quiche: fix result code on a stream reset + + - fixes pytest failures in test 07_22 + - aligns CURLcode values on stream reset with ngtcp2 + + Closes #12629 + +Daniel Stenberg (2 Jan 2024) + +- setopt: clear mimepost when formp is freed + + A precaution to avoid a possibly dangling pointer left behind. + + Reported-by: Thomas Ferguson + Fixes #12608 + Closes #12621 + +Andy Alt (2 Jan 2024) + +- CI: Add dependabot.yml + + This will cause dependabot to open a PR when various actions are + updated, provided that the action maintainer has issued a release. + + Closes #12623 + +Gisle Vanem (2 Jan 2024) + +- content_encoding: change return code to typedef'ed enum + + ... to work around a clang ubsan warning. + + Fixes #12618 + Closes #12622 + +Daniel Stenberg (2 Jan 2024) + +- tool: prepend output_dir in header callback + + When Content-Disposition parsing is used and an output dir is prepended, + make sure to store that new file name correctly so that it can be used + for setting the file timestamp when --remote-time is used. + + Extended test 3012 to verify. + + Co-Authored-by: Jay Satiro + Reported-by: hgdagon on github + Fixes #12614 + Closes #12617 + +- test1254: fix typo in name plus shorten it + +- RELEASE-NOTES: synced + +Viktor Szakats (2 Jan 2024) + +- schannel: fix `-Warith-conversion` gcc 13 warning + + ``` + lib/vtls/schannel.c:1201:22: warning: conversion to 'unsigned int' from 'int' + may change the sign of the result [-Warith-conversion] + 1201 | *extension_len = *list_len + + | ^ + ``` + + Closes #12616 + +- asyn-thread: silence `-Wcast-align` warning for Windows + + Seen with llvm/clang 17: + ``` + lib/asyn-thread.c:310:5: warning: cast from 'PCHAR' (aka 'char *') to 'struct + thread_sync_data *' increases required alignment from 1 to 8 [-Wcast-align] + 310 | CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlap + ped); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ + .../llvm-mingw/aarch64-w64-mingw32/include/winnt.h:717:48: note: expanded fro + m macro 'CONTAINING_RECORD' + 717 | #define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(addre + ss) - (ULONG_PTR)(&((type *)0)->field))) + | ^~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ``` + + Follow-up to a6bbc87f9e9ffb46a1801dfb983e7534825ed56b #12482 + + Ref: https://github.com/curl/curl/pull/12482#issuecomment-1873017261 + Closes #12615 + +Daniel Stenberg (2 Jan 2024) + +- tool_listhelp: regenerate after recent .d updates + + Makes it survive test 1478 + + Closes #12612 + +- test1478: verify src/tool_listhelp.c + + Verify that the source file on disk is identical to the output of gen.pl + listhelp, as otherwise they are out of sync and need attention. + + Closes #12612 + +- testutil: make runtests support %include + + Using this instruction, a test case can include the contents of a file + into the test during the preprocessing. + + Closes #12612 + +- runtests: for mode="text" on , fix newlines on both parts + + Closes #12612 + +Jay Satiro (2 Jan 2024) + +- quiche: return CURLE_HTTP3 on send to invalid stream + + Prior to this change if a send failed on a stream in an invalid state + (according to quiche) and not marked as closed (according to libcurl) + then the send function would return CURLE_SEND_ERROR. + + We already have similar code for ngtcp2 to return CURLE_HTTP3 in this + case. + + Caught by test test_07_upload.py: test_07_22_upload_parallel_fail. + + Fixes https://github.com/curl/curl/issues/12590 + Closes https://github.com/curl/curl/pull/12597 + +Daniel Stenberg (1 Jan 2024) + +- cmdline-opts: update availability for the *-ca-native options + + Closes #12613 + +Patrick Monnerat (31 Dec 2023) + +- openldap: fix STARTTLS + + It was not working anymore since introduction of connection filters. + + Also do not attempt to recover from a failing TLS negotiation with + CURLUSESSL_TRY. + + Closes #12610 + +Daniel Stenberg (31 Dec 2023) + +- haproxy-clientip.d: document the arg + + The arg keyword was missing and therefore not present in the man page. + + Closes #12611 + +annalee (29 Dec 2023) + +- configure: fix no default int compile error in ipv6 detection + + Closes #12607 + +Dan Fandrich (28 Dec 2023) + +- CI: Fix use of any-glob-to-all-files in the labeler + + Despite its name, this atom acts like one-glob-to-all-files and a + different syntax with braces must be used to get + any-glob-to-all-files semantics. Unfortunately, this makes the file + completely unreadable. + + Ref: https://github.com/actions/labeler/issues/731 + +Daniel Stenberg (29 Dec 2023) + +- CURLOPT_AUTOREFERER.3: mention CURLINFO_REFERER + +- CURLINFO_REFERER.3: clarify that it is the *request* header + + That libcurl itself sent in the most recent request + + Closes #12605 + +Jay Satiro (28 Dec 2023) + +- system_win32: fix a function pointer assignment warning + + - Use CURLX_FUNCTION_CAST to suppress a function pointer assignment + warning. + + a6bbc87f added lookups of some Windows API functions and then cast them + like `*(FARPROC*)&Curl_funcname = address`. Some versions of gcc warn + about that as breaking strict-aliasing rules so this PR changes those + assignments to use CURLX_FUNCTION_CAST. + + Bug: https://github.com/curl/curl/pull/12581#issuecomment-1869804317 + Reported-by: Marcel Raad + + Closes https://github.com/curl/curl/pull/12602 + +- verify-examples.pl: fail verification on unescaped backslash + + - Check that all backslashes in EXAMPLE are properly escaped. + + eg manpage must always use `\\n` never `\n`. + + This is because the manpage requires we always double blackslash to show + a single backslash. Prior to this change an erroneous single backslash + would pass through and compile even though it would not show correctly + in the manpage. + + Co-authored-by: Daniel Stenberg + + Ref: https://github.com/curl/curl/pull/12588 + + Closes https://github.com/curl/curl/pull/12589 + +- vtls: fix missing multissl version info + + - Fix erroneous buffer copy logic from ff74cef5. + + Prior to this change the MultiSSL version info returned to the user + was empty. + + Closes https://github.com/curl/curl/pull/12599 + +Daniel Stenberg (27 Dec 2023) + +- KNOWN_BUGS: [RTSP] Some methods do not support response bodies + + Closes #12414 + +Patrick Monnerat (27 Dec 2023) + +- openldap: fix an LDAP crash + + Reported-by: Ozan Cansel + Fixes #12593 + Closes #12600 + +Daniel Stenberg (27 Dec 2023) + +- getinfo: CURLINFO_QUEUE_TIME_T + + Returns the time, in microseconds, during which this transfer was held + in a waiting queue before it started "for real". A transfer might be put + in a queue if after getting started, it cannot create a new connection + etc due to set conditions and limits imposed by the application. + + Ref: #12293 + Closes #12368 + +- RELEASE-NOTES: synced + +Jay Satiro (26 Dec 2023) + +- examples/sendrecv: fix comment line length + + Caught by checksrc. + +Haydar Alaidrus (23 Dec 2023) + +- CURLOPT_POSTFIELDS.3: fix incorrect C string escape in example + + - Escape inner quotes with two backslashes. + + Two backslashes escapes the backslash for the man page and will show as + a single backslash. + + eg: "{\\"name\\": \\"daniel\\"}" shows as "{\"name\": \"daniel\"}". + + Closes https://github.com/curl/curl/pull/12588 + +Viktor Szakats (23 Dec 2023) + +- appveyor: tidy-ups + + - replace two remaining backslashes with forward slashes. + - tidy up the way we form and pass `TFLAGS`. + + Follow-up to 2d4d0c1fd32f5cc3f946c407c8eccd5477b287df #12572 + + Closes #12582 + +Stefan Eissing (22 Dec 2023) + +- transfer: fix upload rate limiting, add test cases + + - add test cases for rate limiting uploads for all + http versions + - fix transfer loop handling of limits. Signal a re-receive + attempt only on exhausting maxloops without an EAGAIN + - fix `data->state.selectbits` forcing re-receive to also + set re-sending when transfer is doing this. + + Reported-by: Karthikdasari0423 on github + Fixes #12559 + Closes #12586 + +Daniel Stenberg (22 Dec 2023) + +- mbedtls: free the entropy when threaded + + The entropy_free was never done for threaded builds, causing a small + (fixed) memory leak. + + Reported-by: RevaliQaQ on github + Fixes #12584 + Closes #12585 + +Stefan Eissing (22 Dec 2023) + +- http2: improved on_stream_close/data_done handling + + - there seems to be a code path that cleans up easy handles without + triggering DONE or DETACH events to the connection filters. This + would explain wh nghttp2 still holds stream user data + - add GOOD check to easy handle used in on_close_callback to + prevent crashes, ASSERTs in debug builds. + - NULL the stream user data early before submitting RST + - add checks in on_stream_close() to identify UNGOOD easy handles + + Reported-by: Hans-Christian Egtvedt + Fixes #10936 + Closes #12562 + +Daniel Stenberg (22 Dec 2023) + +- mprintf: overhaul and bugfixes + + In a test case using lots of snprintf() calls using many commonly used + %-codes per call, this version is around 30% faster than previous + version. + + It also fixes the #12561 bug which made it not behave correctly when + given unknown %-sequences. Fixing that flaw required a different take on + the problem, which resulted in the new two-arrays model. + + lib557: extended - Verify the #12561 fix and test more printf features + + unit1398: fix test: It used a $ only for one argument, which is not + supported. + + Fixes #12561 + Closes #12563 + +Viktor Szakats (21 Dec 2023) + +- appveyor: replace PowerShell with bash + parallel autotools + + PowerShell works (after a steep development curve), but one property of + it stuck and kept causing unresolvable usability issues: With + `$ErrorActionPreference=Stop`, it does abort on failures, but shows only + the first line of the error message. In `Continue` mode, it shows the + full error message, but doesn't stop on all errors. Another issue is + PowerShell considering any stderr output as if the command failed (this + has been improved in 7.2 (2021-Nov), but fixed versions aren't running + in CI and will not be for a long time in all test images.) + + Thus, we're going with bash. + + Also: + - use `-j2` with autotools tests, making them finish 5-15 minutes per + job faster. + - omit `POSIX_PATH_PREFIX`. + - use `WINDIR`. + - prefer forward slashes. + + Follow-up to: 75078a415d9c769419aed4153d3d525a8eba95af #11999 + Ref: #12444 + + Fixes #12560 + Closes #12572 + +Pavel Pavlov (21 Dec 2023) + +- asyn-thread: use GetAddrInfoExW on >= Windows 8 + + For doing async DNS resolution instead of starting a thread for each + request. + + Fixes #12481 + Closes #12482 + +Daniel Stenberg (21 Dec 2023) + +- strerror: repair get_winsock_error() + + It would try to read longer than the provided string and crash. + + Follow-up to ff74cef5d4a0cf60106517a1c7384 + Reported-by: calvin2021y on github + Fixes #12578 + Closes #12579 + +- CURLOPT_SSH_*_KEYFILE: clarify + + Closes #12554 + +ivanfywang (21 Dec 2023) + +- ngtcp2: put h3 at the front of alpn + + Closes #12576 + +Daniel Stenberg (21 Dec 2023) + +- test460: verify a command line using --expand with no argument + + This verifies the fix for #12565 + +- tool_getparam: do not try to expand without an argument + + This would lead to a segfault. + + Fixes #12565 + Reported-by: Geeknik Labs + Closes #12575 + +- RELEASE-NOTES: synced + + Bumped version to 8.6.0 because of changes + +- Makefile.am: fix the MSVC project generation + + It made the vcxproj files not get included in dist tarballs. + + Regression since 74423b5df4c8117891eb89 (8.5.0) + + Reported-by: iAroc on github + Fixes #12564 + Closes #12567 + +zengwei2000 (21 Dec 2023) + +- altsvc: free 'as' when returning error + + Closes #12570 + + Signed-off-by: zengwei + +Viktor Szakats (20 Dec 2023) + +- build: fix `-Wconversion`/`-Wsign-conversion` warnings + + Fix remaining warnings in examples and tests which are not suppressed + by the pragma in `lib/curl_setup.h`. + + Silence a toolchain issue causing warnings in `FD_SET()` calls with + older Cygwin/MSYS2 builds. Likely fixed on 2020-08-03 by: + https://cygwin.com/git/?p=newlib-cygwin.git;a=commitdiff;h=5717262b8ecfed0f7f + ab63e2c09c78991e36f9dd + + Follow-up to 2dbe75bd7f3c36837aa06fd87a442bdf3fb7faef #12492 + + Closes #12557 + +- build: fix some `-Wsign-conversion`/`-Warith-conversion` warnings + + - enable `-Wsign-conversion` warnings, but also setting them to not + raise errors. + - fix `-Warith-conversion` warnings seen in CI. + These are triggered by `-Wsign-converion` and causing errors unless + explicitly silenced. It makes more sense to fix them, there just a few + of them. + - fix some `-Wsign-conversion` warnings. + - hide `-Wsign-conversion` warnings with a `#pragma`. + - add macro `CURL_WARN_SIGN_CONVERSION` to unhide them on a per-build + basis. + - update a CI job to unhide them with the above macro: + https://github.com/curl/curl/actions/workflows/linux.yml -> OpenSSL -O3 + + Closes #12492 + +- cmake: tidy-up `OtherTests.cmake` + + - make more obvious which detection uses which prep steps. + - merge and streamline conditions. + - these should not alter detection results. + + Also align log output messages from + `Macros.cmake` / `curl_internal_test` with rest of the build. + + Closes #12551 + +- appveyor: switch to out-of-tree builds + + With cmake and autotools. + + Closes #12550 + +Daniel Stenberg (19 Dec 2023) + +- DEPRECATE.md: mention that NTLM_WB no longer works + + Ref: #12479 + Closes #12553 + +- CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: add + + Proposed-by: Yifei Kong + Ref: https://curl.se/mail/lib-2023-11/0023.html + Closes #12369 + +Viktor Szakats (18 Dec 2023) + +- build: more `-Wformat` fixes + + - memdebug: update to not trigger `-Wformat-nonliteral` warnings. + - imap: mark `imap_sendf()` with `CURL_PRINTF()`. + - tool_msgs: mark static function with `CURL_PRINTF()`. + + Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489 + + Closes #12540 + +- windows: delete redundant headers + + `winsock2.h` pulls in `windows.h`. `ws2tcpip.h` pulls in `winsock2.h`. + `winsock2.h` and `ws2tcpip.h` are also pulled by `curl/curl.h`. + + Keep only those headers that are not already included, or the code under + it uses something from that specific header. + + Closes #12539 + +- cmake: prefill/cache `HAVE_STRUCT_SOCKADDR_STORAGE` + + Also add missing include to `OtherTests.cmake`. It didn't cause an issue + because the parent already included this earlier by chance. + + Closes #12537 + +Daniel Stenberg (18 Dec 2023) + +- runner.pm: fix perl warning when running tests + + Use of uninitialized value $runner::gdbthis in numeric eq (==) at runner. + pm + + Follow-up from 3dcf301752a09d9 + + Closes #12549 + +- runtests: support -gl. Like -g but for lldb. + + Follow-up to 63b5748 + + Invokes the test case via lldb instead of gdb. Since using gdb is such a + pain on mac, using lldb is sometimes less quirky. + + Closes #12547 + +- curl.h: add CURLE_TOO_LARGE + + A new error code to be used when an internal field grows too large, like + when a dynbuf reaches its maximum. Previously it would return + CURLE_OUT_OF_MEMORY for this, which is highly misleading. + + Ref: #12268 + Closes #12269 + +- CI/circleci: disable MQTT in the HTTP-only build + + And remove the use of configure options that don't actually exist + + Closes #12546 + +Yedaya Katsman (18 Dec 2023) + +- tests: respect $TMPDIR when creating unix domain sockets + + When running on termux, where $TMPDIR isn't /tmp, running the tests + failed, since the server config tried creating sockets in /tmp, without + checking the temp dir config. Use the TMPDIR variable that makes it find + the correct directory everywhere [0] + + [0] https://perldoc.perl.org/File::Temp#tempfile + + Closes #12545 + +Viktor Szakats (17 Dec 2023) + +- ssh: fix namespace of two local macros + + Avoid using the libssh and libssh2 macro namespaces by prefixing + these local macro names with `CURL_`. + + Follow-up to 413a0fedd02c8c6df1d294534b8c6e306fcca7a2 #12346 + + Reviewed-by: Daniel Stenberg + Closes #12544 + +- cmake: whitespace tidy-up in `OtherTests.cmake` + + Closes #12538 + +Mark Sinkovics (16 Dec 2023) + +- cmake: fix generation for system name iOS + + This PR fixes a problem that happens during CMake configuration when + the `CMAKE_SYSTEM_NAME` set to `iOS` and not `Darwin`. This value is + available (as far as I remember) version 3.14. The final solution + (thanks to @vszakats) is to use `APPLE` which contains all the Apple + platforms https://cmake.org/cmake/help/latest/variable/APPLE.html. + + This issue was found when during vcpkg installation. Running command + `vcpkg install curl:arm64-ios` and `vcpkg install curl:x64-ios` failed + with message: + ``` + CMake Error: try_run() invoked in cross-compiling mode, please set the follow + ing cache variables appropriately: + HAVE_H_ERRNO_ASSIGNABLE_EXITCODE (advanced) + ``` + After this fix, I was able to compile the compile the binary without + any issue. + + In addition to that fix, this PR also contains an simplification to + check if the platform is not APPLE. + + Co-authored-by: Viktor Szakats + Closes #12515 + +Daniel Stenberg (16 Dec 2023) + +- RELEASE-NOTES: synced + +Baruch Siach (16 Dec 2023) + +- gnutls: fix build with --disable-verbose + + infof() parameters must be defined event with --disable-verbose since + commit dac293cfb702 ("lib: apache style infof and trace + macros/functions"). + + Move also 'ptr' definition under !CURL_DISABLE_VERBOSE_STRINGS. + + Fixes the following build failure: + + In file included from ../lib/sendf.h:29, + from vtls/gtls.c:44: + vtls/gtls.c: In function 'Curl_gtls_verifyserver': + vtls/gtls.c:841:34: error: 'version' undeclared (first use in this function); + did you mean 'session'? + 841 | gnutls_protocol_get_name(version), ptr); + | ^~~~~~~ + + Closes #12505 + +Viktor Szakats (16 Dec 2023) + +- build: delete unused `HAVE_{GSSHEIMDAL,GSSMIT,HEIMDAL}` + + Stop setting `HAVE_GSSHEIMDAL`, `HAVE_GSSMIT` and `HAVE_HEIMDAL`. + There was no place in the build system or source code that used them. + + Reviewed-by: Daniel Stenberg + Closes #12506 + +- build: remove redundant `CURL_PULL_*` settings + + These macros were not propagated to the source code from CMake. + + autotools set only one of them (`CURL_PULL_SYS_POLL_H`), initially to + address an AIX issue [1]. This later broke when introducing `system.h` + [2] without the logic it enabled. A subsequent fix [3] re-added the + logic, and also enabled it for AIX before its use, directly in + `system.h`. + + [1] 2012-11-23: 665adcd4b7bcdb7deb638cdc499fbe71f8d777f2 + [2] 2017-03-29: 9506d01ee50d5908138ebad0fd9fbd39b66bd64d #1373 + [3] 2017-08-25: 8a84fcc4b59e8b78d2acc6febf44a43d6bc81b59 #1828 #1833 + + Reviewed-by: Daniel Stenberg + Closes #12502 + +- system.h: sync mingw `CURL_TYPEOF_CURL_SOCKLEN_T` with other compilers + + Align mingw with the other Windows compilers and use the `int` type for + `CURL_TYPEOF_CURL_SOCKLEN_T` (and thus for `curl_socklent_t`). This + makes it unnecessary to make a mingw-specific trick and pull all Windows + headers early just for this type definition. This type is specific to + Windows, not to the compiler. mingw-w64's Windows header maps it to + `int` too. + + With this we also delete all remaining uses of `CURL_PULL_WS2TCPIP_H`. + + [ The official solution is to use `socklen_t` for all Windows compilers. + In this case we may want to update `curl/curl.h` to pull in Windows + headers before `system.h`. ] + + Reviewed-by: Daniel Stenberg + Reviewed-by: Jay Satiro + Closes #12501 + +- windows: simplify detecting and using system headers + + - autotools, cmake: assume that if we detect Windows, `windows.h`, + `winsock2.h` and `ws2tcpip.h` do exist. + - lib: fix 3 outlier `#if` conditions to use `USE_WINSOCK` instead of + looking for `winsock2.h`. + - autotools: merge 3 Windows check methods into one. + - move Watt-32 and lwIP socket support to `setup-win32.h` from + `config-win32.h`. It opens up using these with all build tools. Also + merge logic with Windows Sockets. + - fix to assume Windows sockets with the mingw32ce toolchain. + Follow-up to: 2748c64d605b19fb419ae56810ad8da36487a2d4 + - cmake: delete unused variable `signature_call_conv` since + eb33ccd5332435fa50f1758e5debb869c6942b7f. + - autotools: simplify `CURL_CHECK_WIN32_LARGEFILE` detection. + - examples/externalsocket: fix header order. + - cmake/OtherTests.cmake: delete Windows-specific `_source_epilogue` + that wasn't used anymore. + - cmake/OtherTests.cmake: set `WIN32_LEAN_AND_MEAN` for test + `SIZEOF_STRUCT_SOCKADDR_STORAGE`. + + After this patch curl universally uses `_WIN32` to guard + Windows-specific logic. It guards Windows Sockets-specific logic with + `USE_WINSOCK` (this might need further work). + + Reviewed-by: Jay Satiro + Closes #12495 + +- build: enable missing OpenSSF-recommended warnings, with fixes + + https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening + -Guide-for-C-and-C++.html + as of 2023-11-29 [1]. + + Enable new recommended warnings (except `-Wsign-conversion`): + + - enable `-Wformat=2` for clang (in both cmake and autotools). + - add `CURL_PRINTF()` internal attribute and mark functions accepting + printf arguments with it. This is a copy of existing + `CURL_TEMP_PRINTF()` but using `__printf__` to make it compatible + with redefinting the `printf` symbol: + https://gcc.gnu.org/onlinedocs/gcc-3.0.4/gcc_5.html#SEC94 + - fix `CURL_PRINTF()` and existing `CURL_TEMP_PRINTF()` for + mingw-w64 and enable it on this platform. + - enable `-Wimplicit-fallthrough`. + - enable `-Wtrampolines`. + - add `-Wsign-conversion` commented with a FIXME. + - cmake: enable `-pedantic-errors` the way we do it with autotools. + Follow-up to d5c0351055d5709da8f3e16c91348092fdb481aa #2747 + - lib/curl_trc.h: use `CURL_FORMAT()`, this also fixes it to enable format + checks. Previously it was always disabled due to the internal `printf` + macro. + + Fix them: + + - fix bug where an `set_ipv6_v6only()` call was missed in builds with + `--disable-verbose` / `CURL_DISABLE_VERBOSE_STRINGS=ON`. + - add internal `FALLTHROUGH()` macro. + - replace obsolete fall-through comments with `FALLTHROUGH()`. + - fix fallthrough markups: Delete redundant ones (showing up as + warnings in most cases). Add missing ones. Fix indentation. + - silence `-Wformat-nonliteral` warnings with llvm/clang. + - fix one `-Wformat-nonliteral` warning. + - fix new `-Wformat` and `-Wformat-security` warnings. + - fix `CURL_FORMAT_SOCKET_T` value for mingw-w64. Also move its + definition to `lib/curl_setup.h` allowing use in `tests/server`. + - lib: fix two wrongly passed string arguments in log outputs. + Co-authored-by: Jay Satiro + - fix new `-Wformat` warnings on mingw-w64. + + [1] https://github.com/ossf/wg-best-practices-os-developers/blob/56c0fde3895b + fc55c8a973ef49a2572c507b2ae1/docs/Compiler-Hardening-Guides/Compiler-Options- + Hardening-Guide-for-C-and-C%2B%2B.md + + Closes #12489 + +- Makefile.mk: drop Windows support + + And DLL-support with it. This leaves `Makefile.mk` for MS-DOS and Amiga. + + We recommend CMake instead. With unity mode it's much faster, and about + the same without. + + Ref: https://github.com/curl/curl/pull/12221#issuecomment-1783761806 + Reviewed-by: Daniel Stenberg + Closes #12224 + +Daniel Stenberg (16 Dec 2023) + +- cmdline-docs: use .IP consistently + + Remove use of .TP and some .B. The idea is to reduce nroff syntax as + much as possible and to use it consistently. Ultimately, we should be + able to introduce our own easier-to-use-and-read syntax/formatting and + convert on generation time. + + Closes #12535 + +Tatsuhiko Miyagawa (16 Dec 2023) + +- http: fix off-by-one error in request method length check + + It should allow one more byte. + + Closes #12534 + +Daniel Stenberg (15 Dec 2023) + +- curl: show ipfs and ipns as supported "protocols" + + They are accepted schemes in URLs passed to curl (the tool, not the + library). + + Also makes curl-config show the same list. + + Co-Authored-by: Jay Satiro + Reported-by: Chara White + Bug: https://curl.se/mail/archive-2023-12/0026.html + Closes #12508 + +- Revert "urldata: move async resolver state from easy handle to connectdata" + + This reverts commit 56a4db2e4e2bcb9a0dcb75b83560a78ef231fcc8 (#12198) + + We want the c-ares channel to be held in the easy handle, not per + connection - for performance. + + Closes #12524 + +Viktor Szakats (15 Dec 2023) + +- openssl: re-match LibreSSL deinit with init + + Earlier we switched to use modern initialization with LibreSSL v2.7.0 + and up, but did not touch deinitialization [1]. Fix it in this patch. + + Regression from bec0c5bbf34369920598678161d2df8bea0e243b #11611 + + [1] https://github.com/curl/curl/pull/11611#issuecomment-1668654014 + + Reported-by: Mike Hommey + Reviewed-by: Daniel Stenberg + Fixes #12525 + Closes #12526 + +Daniel Stenberg (14 Dec 2023) + +- libssh: supress warnings without version check + + Define unconditionally. + + Follow-up from d21bd2190c46ad7fa + + Closes #12523 + +- hostip: return error immediately when Curl_ip2addr() fails + + Closes #12522 + +Theo (14 Dec 2023) + +- libssh: improve the deprecation warning dismissal + + Previous code was compiler dependant, and dismissed all deprecation warnings + indiscriminately. + + libssh provides a way to disable the deprecation warnings for libssh only, an + d + naturally this is the preferred way. + + This commit uses that, to prevent the erroneous hiding of potential, unrelate + d + deprecation warnings. + + Fixes #12519 + Closes #12520 + +Daniel Stenberg (14 Dec 2023) + +- test1474: removed + + The test was already somewhat flaky and disabled on several platforms, + and after 1da640abb688 even more unstable. + +- readwrite_data: loop less + + This function is made to loop in order to drain incoming data + faster. Completely removing the loop has a measerably negative impact on + transfer speeds. + + Downsides with the looping include + + - it might call the progress callback much more seldom. Especially if + the write callback is slow. + + - rate limiting becomes less exact + + - a single transfer might "starve out" other parallel transfers + + - QUIC timers for other connections can't be maintained correctly + + The long term fix should be to remove the loop and optimize coming back + to avoid the transfer speed penalty. + + This fix lower the max loop count to reduce the starvation problem, and + avoids the loop completely for when rate-limiting is in progress. + + Ref: #12488 + Ref: https://curl.se/mail/lib-2023-12/0012.html + Closes #12504 + +Stefan Eissing (14 Dec 2023) + +- lib: eliminate `conn->cselect_bits` + + - use `data->state.dselect_bits` everywhere instead + - remove `bool *comeback` parameter as non-zero + `data->state.dselect_bits` will indicate that IO is + incomplete. + + Closes #12512 + +- connect: refactor `Curl_timeleft()` + + - less local vars, "better" readability + - added documentation + + Closes #12518 + +Dmitry Karpov (14 Dec 2023) + +- cookie: avoid fopen with empty file name + + Closes #12514 + +Viktor Szakats (13 Dec 2023) + +- tests/server: delete workaround for old-mingw + + mingw-w64 1.0 comes with w32api v3.12, thus doesn't need this. + + Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72 #11625 + + Reviewed-by: Jay Satiro + Closes #12510 + +- cmake: delete obsolete TODOs more [ci skip] + + - manual completed: 898b012a9bf388590c4be7f526815b5ab74feca1 #1288 + - soname completed: 5de6848f104d7cb0017080e31216265ac19d0dde #10023 + - bunch of others that are completed + - `NTLM_WB_ENABLED` is implemented in a basic form, and now also + scheduled for removal, so a TODO at this point isn't useful. + + And this 'to-check' item: + + Q: "The cmake build selected to run gcc with -fPIC on my box while the + plain configure script did not." + + A: With CMake, since 2ebc74c36a19a1700af394c16855ce144d9878e3 #11546 + and fc9bfb14520712672b4784e8b48256fb29204011 #11627, we explicitly + enable PIC for libcurl shared lib. Or when building libcurl for + shared and static lib in a single pass. We do this by default for + Windows or when enabled by the user via `SHARE_LIB_OBJECT`. + Otherwise we don't touch this setting. Meaning the default set by + CMake (if any) or the toolchain is used. On Debian Bookworm, this + means that PIC is disabled for static libs by default. Some platforms + (like macOS), has PIC enabled by default. + autotools supports the double-pass mode only, and in that case + CMake seems to match PIC behaviour now (as tested on Linux with gcc.) + + Follow-up to 5d5dfdbd1a6c40bd75e982b66f49e1fa3a7eeae7 #12500 + + Reviewed-by: Jay Satiro + Closes #12509 + +Stefan Eissing (12 Dec 2023) + +- CLIENT-WRITERS: design and use documentation + + Closes #12507 + +Viktor Szakats (12 Dec 2023) + +- cmake: delete obsolete TODO items [ci skip] + + There is always room for improvement, but CMake is up to par now with + autotools, so there is no longer a good reason to keep around these + inline TODO items. + + Answering one of questions: + + Q: "The gcc command line use neither -g nor any -O options. As a + developer, I also treasure our configure scripts's --enable-debug + option that sets a long range of "picky" compiler options." + + A: CMake offers the `CMAKE_BUILD_TYPE` variable to control debug info + and optimization level. E.g.: + - `Release` = `-O3` + no debug info + - `MinSizeRel` = `-Os` + no debug info + - `Debug` = `-O0` + debug info + + https://stackoverflow.com/questions/48754619/what-are-cmake-build-type-deb + ug-release-relwithdebinfo-and-minsizerel/59314670#59314670 + https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#defaul + t-and-custom-configurations + + For picky warnings we have the `PICKY_COMPILER` options, enabled by + default. + + Closes #12500 + +Stefan Eissing (11 Dec 2023) + +- CONNECTION-FILTERS: update documentation + + Closes #12497 + +Daniel Stenberg (11 Dec 2023) + +- lib: reduce use of strncpy + + - bearssl: select cipher without buffer copies + - http_aws_sigv4: avoid strncpy, require exact timestamp length + - http_aws_sigv4: use memcpy isntead of strncpy + - openssl: avoid strncpy calls + - schannel: check for 1.3 algos without buffer copies + - strerror: avoid strncpy calls + - telnet: avoid strncpy, return error on too long inputs + - vtls: avoid strncpy in multissl_version() + + Closes #12499 + +- CI/distcheck: run full tests + + To be able to detect missing files better, this now runs the full CI + test suite. If done before, it would have detected #12462 before + release. + + Closes #12503 + +- docs: clean up Protocols: for cmdline options + + ... and some other minor polish. + + Closes #12496 + +- cmdline/gen: fix the sorting of the man page options + + They were previously sorted based on the file names, which use a .d + extension, making "data" get placed after "data-binary" etc. Making the + sort ignore the extention fixes the ordering. + + Reported-by: Boris Verkhovskiy + Bug: https://curl.se/mail/archive-2023-12/0014.html + Closes #12494 + +Daniel Gustafsson (9 Dec 2023) + +- doh: remove unused local variable + + The nurl variable is no longer used during probing following + a refactoring, so remove. + + Closes #12491 + +Jay Satiro (8 Dec 2023) + +- build: fix Windows ADDRESS_FAMILY detection + + - Include winsock2.h for Windows ADDRESS_FAMILY detection. + + Prior to this change cmake detection didn't work because it included + ws2def.h by itself, which is missing needed types from winsock2.h. + + Prior to this change autotools detection didn't work because it did not + include any Windows header. + + In both cases libcurl would fall back on unsigned short as the address + family type, which is the same as ADDRESS_FAMILY. + + Co-authored-by: Viktor Szakats + + Closes https://github.com/curl/curl/pull/12441 + +Daniel Stenberg (8 Dec 2023) + +- lib: rename Curl_strndup to Curl_memdup0 to avoid misunderstanding + + Since the copy does not stop at a null byte, let's not call it anything + that makes you think it works like the common strndup() function. + + Based on feedback from Jay Satiro, Stefan Eissing and Patrick Monnerat + + Closes #12490 + +- convsrctest.pl: removed: not used, not shipped in tarballs + +- tests: rename tests scripts to the test number + + It is hard to name the scripts sensibly. Lots of them are similarly + named and the name did not tell which test that used them. + + The new approach is rather to name them based on the test number that + runs them. Also helps us see which scripts are for individual tests + rather than for general test infra. + + - badsymbols.pl -> test1167.pl + - check-deprecated.pl -> test1222.pl + - check-translatable-options.pl -> test1544.pl + - disable-scan.pl -> test1165.pl + - error-codes.pl -> test1175.pl + - errorcodes.pl -> test1477.pl + - extern-scan.pl -> test1135.pl + - manpage-scan.pl -> test1139.pl + - manpage-syntax.pl -> test1173.pl + - markdown-uppercase.pl -> test1275.pl + - mem-include-scan.pl -> test1132.pl + - nroff-scan.pl -> test1140.pl + - option-check.pl -> test1276.pl + - options-scan.pl -> test971.pl + - symbol-scan.pl -> test1119.pl + - version-scan.pl -> test1177.pl + + Closes #12487 + +MichaÅ‚ Antoniak (8 Dec 2023) + +- sendf: fix compiler warning with CURL_DISABLE_HEADERS_API + + fix MSVC warning C4189: 'htype': local variable is initialized but not + referenced - when CURL_DISABLE_HEADERS_API is defined. + + Closes #12485 + +Viktor Szakats (8 Dec 2023) + +- tidy-up: whitespace + + Closes #12484 + +Stefan Eissing (7 Dec 2023) + +- test_02_download: fix paramters to test_02_27 + + - it is a special client that only ever uses http/2 + + Closes #12467 + +MichaÅ‚ Antoniak (7 Dec 2023) + +- vtls: remove the Curl_cft_ssl_proxy object if CURL_DISABLE_PROXY + + Closes #12459 + +Daniel Stenberg (7 Dec 2023) + +- lib: strndup/memdup instead of malloc, memcpy and null-terminate + + - bufref: use strndup + - cookie: use strndup + - formdata: use strndup + - ftp: use strndup + - gtls: use aprintf instead of malloc + strcpy * 2 + - http: use strndup + - mbedtls: use strndup + - md4: use memdup + - ntlm: use memdup + - ntlm_sspi: use strndup + - pingpong: use memdup + - rtsp: use strndup instead of malloc, memcpy and null-terminate + - sectransp: use strndup + - socks_gssapi.c: use memdup + - vtls: use dynbuf instead of malloc, snprintf and memcpy + - vtls: use strdup instead of malloc + memcpy + - wolfssh: use strndup + + Closes #12453 + +- strdup: remove the memchr check from Curl_strndup + + It makes it possible to clone a binary chunk of data. + + Closes #12453 + +- ftp: handle the PORT parsing without allocation + + Also reduces amount of *cpy() calls. + + Closes #12456 + +- RELEASE-NOTES: synced + + Bumped to 8.5.1 + +- url: for disabled protocols, mention if found in redirect + + To help users better understand where the URL (and denied scheme) comes + from. Also removed "in libcurl" from the message, since the disabling + can be done by the application. + + The error message now says "not supported" or "disabled" depending on + why it was denied: + + Protocol "hej" not supported + Protocol "http" disabled + + And in redirects: + + Protocol "hej" not supported (in redirect) + Protocol "http" disabled (in redirect) + + Reported-by: Mauricio Scheffer + Fixes #12465 + Closes #12469 + +Stefan Eissing (6 Dec 2023) + +- sectransp_ make TLSCipherNameForNumber() available in non-verbose config + + Reported-by: Cajus Pollmeier + Closes #12476 + Fixes #12474 + +YX Hao (6 Dec 2023) + +- lib: fix variable undeclared error caused by `infof` changes + + `--disable-verbose` yields `CURL_DISABLE_VERBOSE_STRINGS` defined. + `infof` isn't `Curl_nop_stmt` anymore: dac293c. + + Follow-up to dac293c + + Closes #12470 + +Viktor Szakats (6 Dec 2023) + +- tidy-up: fix yamllint whitespace issues in labeler.yml + + Follow-up to bda212911457c6fadfbba50be61afc4ca513fa56 #12466 + + Reviewed-by: Dan Fandrich + Closes #12475 + +- tidy-up: fix yamllint whitespace issues + + Closes #12466 + +Chris Sauer (6 Dec 2023) + +- cmake: fix typo + + Follow-up to aace27b + Closes #12464 + +Daniel Stenberg (6 Dec 2023) + +- dist: add tests/errorcodes.pl to the tarball + + Used by test 1477 + + Reported-by: Xi Ruoyao + Follow-up to 0ca3a4ec9a7 + Fixes #12462 + Closes #12463 + +Dan Fandrich (6 Dec 2023) + +- github/labeler: update a missed key in the v5 upgrade + + Follow-up to ce03fe3ba + +Version 8.5.0 (6 Dec 2023) + +Daniel Stenberg (6 Dec 2023) + +- RELEASE-NOTES: synced + + The curl 8.5.0 release. + +Dan Fandrich (5 Dec 2023) + +- github/labeler: switch from the beta to labeler v5 + + Some keys were renamed and the dot option was made default. + + Closes #12458 + +Daniel Stenberg (5 Dec 2023) + +- DEPRECATE: remove NTLM_WB in June 2024 + + Ref: https://curl.se/mail/lib-2023-12/0010.html + + Closes #12451 + +Jacob Hoffman-Andrews (4 Dec 2023) + +- rustls: implement connect_blocking + + Closes #11647 + +Daniel Stenberg (4 Dec 2023) + +- examples/rtsp-options.c: add + + Just a bare bones RTSP example using CURLOPT_RTSP_SESSION_ID and + CURLOPT_RTSP_REQUEST set to CURL_RTSPREQ_OPTIONS. + + Closes #12452 + +Stefan Eissing (4 Dec 2023) + +- ngtcp2: ignore errors on unknown streams + + - expecially in is_alive checks on connections, we might + see incoming packets on streams already forgotten and closed, + leading to errors reported by nghttp3. Ignore those. + + Closes #12449 + +Daniel Stenberg (4 Dec 2023) + +- docs: make all examples in all libcurl man pages compile + + Closes #12448 + +- checksrc.pl: support #line instructions + + makes it identify the correct source file and line + +- GHA/man-examples: verify libcurl man page examples + +- verify-examples.pl: verify that all man page examples compile clean + +- RELEASE-NOTES: synced + +Graham Campbell (2 Dec 2023) + +- http3: bump ngtcp2 and nghttp3 versions + + nghttp3 v1.1.0 + ngtcp2 v1.1.0 + + In docs and CI + + Closes #12446 + +- CI/quiche: use `3.1.4+quic` consistently in CI workflows + + Closes #12447 + +Viktor Szakats (2 Dec 2023) + +- test1545: disable deprecation warnings + + Fixes: + https://ci.appveyor.com/project/curlorg/curl/builds/48631551/job/bhx74e0i66yr + p6pk#L1205 + + Same with details: + https://ci.appveyor.com/project/curlorg/curl/builds/48662893/job/ol8a78q9gmil + b6wt#L1263 + ``` + tests/libtest/lib1545.c:38:3: error: 'curl_formadd' is deprecated: since 7.56 + .0. Use curl_mime_init() [-Werror=deprecated-declarations] + 38 | curl_formadd(&m_formpost, &lastptr, CURLFORM_COPYNAME, "file", + | ^~~~~~~~~~~~ + [...] + ``` + + Follow-up to 07a3cd83e0456ca17dfd8c3104af7cf45b7a1ff5 #12421 + + Fixes #12445 + Closes #12444 + +Daniel Stenberg (2 Dec 2023) + +- INSTALL: update list of ports and CPU archs + +- symbols-in-versions: the CLOSEPOLICY options are deprecated + + The were used with the CURLOPT_CLOSEPOLICY option, which *never* worked. + +z2_ (1 Dec 2023) + +- build: fix builds that disable protocols but not digest auth + + - Build base64 functions if digest auth is not disabled. + + Prior to this change if some protocols were disabled but not digest auth + then a build error would occur due to missing base64 functions. + + Fixes https://github.com/curl/curl/issues/12440 + Closes https://github.com/curl/curl/pull/12442 + +MichaÅ‚ Antoniak (1 Dec 2023) + +- connect: reduce number of transportation providers + + Use only the ones necessary - the ones that are built-in. Saves a few + bytes in the resulting code. + + Closes #12438 + +David Benjamin (1 Dec 2023) + +- vtls: consistently use typedef names for OpenSSL structs + + The foo_st names don't appear in OpenSSL public API documentation. The + FOO typedefs are more common. This header was already referencing + SSL_CTX via . There is a comment about avoiding + , but OpenSSL actually declares all the typedefs in + , which is already included by (and + every other OpenSSL header), so just use that. Though I've included it + just to be explicit. + + (I'm also fairly sure including already triggers the + Schannel conflicts anyway. The comment was probably just out of date.) + + Closes #12439 + +Lau (1 Dec 2023) + +- libcurl-security.3: fix typo + + Fixed minimal typo. + + Closes #12437 + +Stefan Eissing (1 Dec 2023) + +- ngtcp2: fix races in stream handling + + - fix cases where ngtcp2 invokes callbacks on streams that + nghttp3 has already forgotten. Ignore the NGHTTP3_ERR_STREAM_NOT_FOUND + in these cases as it is normal behaviour. + + Closes #12435 + +Emanuele Torre (1 Dec 2023) + +- tool_writeout_json: fix JSON encoding of non-ascii bytes + + char variables if unspecified can be either signed or unsigned depending + on the platform according to the C standard; in most platforms, they are + signed. + + This meant that the *i<32 waas always true for bytes with the top bit + set. So they were always getting encoded as \uXXXX, and then since they + were also signed negative, they were getting extended with 1s causing + '\xe2' to be expanded to \uffffffe2, for example: + + $ curl --variable 'v=“' --expand-write-out '{{v:json}}\n' file:///dev/nul + l + \uffffffe2\uffffff80\uffffff9c + + I fixed this bug by making the code use explicitly unsigned char* + variables instead of char* variables. + + Test 268 verifies + + Reported-by: iconoclasthero + Closes #12434 + +Stefan Eissing (1 Dec 2023) + +- cf-socket: TCP trace output local address used in connect + + Closes #12427 + +Jay Satiro (1 Dec 2023) + +- CURLINFO_PRETRANSFER_TIME_T.3: fix time explanation + + - Change CURLINFO_PRETRANSFER_TIME_T explanation to say that it + includes protocol-specific instructions that trigger a transfer. + + Prior to this change it explicitly said that it did not include those + instructions in the time, but that is incorrect. + + The change is a copy of the fixed explanation already in + CURLINFO_PRETRANSFER_TIME, fixed by ec8dcd7b. + + Reported-by: eeverettrbx@users.noreply.github.com + + Fixes https://github.com/curl/curl/issues/12431 + Closes https://github.com/curl/curl/pull/12432 + +Daniel Stenberg (30 Nov 2023) + +- multi: during ratelimit multi_getsock should return no sockets + + ... as there is nothing to wait for then, it just waits. Otherwise, this + causes much more CPU work and updates than necessary during ratelimit + periods. + + Ref: https://curl.se/mail/lib-2023-11/0056.html + Closes #12430 + +Dmitry Karpov (30 Nov 2023) + +- transfer: abort pause send when connection is marked for closing + + This handles cases of some bi-directional "upgrade" scenarios + (i.e. WebSockets) where sending is paused until some "upgrade" handshake + is completed, but server rejects the handshake and closes the + connection. + + Closes #12428 + +Daniel Stenberg (28 Nov 2023) + +- RELEASE-NOTES: synced + +- openssl: when a session-ID is reused, skip OCSP stapling + + Fixes #12399 + Reported-by: Alexey Larikov + Closes #12418 + +- test1545: test doing curl_formadd twice with missing file + + Reproduces #12410 + Verifies the fix + Closes #12421 + +- Curl_http_body: cleanup properly when Curl_getformdata errors + + Reported-by: yushicheng7788 on github + Based-on-work-by: yushicheng7788 on github + Fixes #12410 + Closes #12421 + +- test1477: verify that libcurl-errors.3 and public headers are synced + + The script errorcodes.pl extracts all error codes from all headers and + checks that they are all documented, then checks that all documented + error codes are also specified in a header file. + + Closes #12424 + +- libcurl-errors.3: sync with current public headers + + Closes #12424 + +Stefan Eissing (28 Nov 2023) + +- test459: fix for parallel runs + + - change warniing message to work better with varying filename + length. + - adapt test output check to new formatting + + Follow-up to 97ccc4479f77ba3191c6 + Closes #12423 + +Daniel Stenberg (27 Nov 2023) + +- tool_cb_prg: make the carriage return fit for wide progress bars + + When the progress bar was made max width (256 columns), the fly() + function attempted to generate its output buffer too long so that the + trailing carriage return would not fit and then the output would show + wrongly. The fly function is called when the expected total transfer is + unknown, which could be one or more progress calls before the actual + progress meter get shown when the expected transfer size is provided. + + This new take also replaces the msnprintf() call with a much simpler + memset() for speed. + + Reported-by: Tim Hill + Fixes #12407 + Closes #12415 + +- tool_parsecfg: make warning output propose double-quoting + + When the config file parser detects a word that *probably* should be + quoted, mention double-quotes as a possible remedy. + + Test 459 verifies. + + Proposed-by: Jiehong on github + Fixes #12409 + Closes #12412 + +Jay Satiro (26 Nov 2023) + +- curl.rc: switch out the copyright symbol for plain ASCII + + .. like we already do for libcurl.rc. + + libcurl.rc copyright symbol used to cause a "non-ascii 8-bit codepoint" + warning so it was switched to ascii. + + Ref: https://github.com/curl/curl/commit/1ca62bb5#commitcomment-133474972 + + Suggested-by: Robert Southee + + Closes https://github.com/curl/curl/pull/12403 + +Daniel Stenberg (26 Nov 2023) + +- conncache: use the closure handle when disconnecting surplus connections + + Use the closure handle for disconnecting connection cache entries so + that anything that happens during the disconnect is not stored and + associated with the 'data' handle which already just finished a transfer + and it is important that details from the unrelated disconnect does not + taint meta-data in the data handle. + + Like storing the response code. + + This also adjust test 1506. Unfortunately it also removes a key part of + the test that verifies that a connection is closed since when this + output vanishes (because the closure handle is used), we don't know + exactly that the connection actually gets closed in this test... + + Reported-by: ohyeaah on github + Fixes #12367 + Closes #12405 + +- RELEASE-NOTES: synced + +Stefan Eissing (24 Nov 2023) + +- quic: make eyeballers connect retries stop at weird replies + + - when a connect immediately goes into DRAINING state, do + not attempt retries in the QUIC connection filter. Instead, + return CURLE_WEIRD_SERVER_REPLY + - When eyeballing, interpret CURLE_WEIRD_SERVER_REPLY as an + inconclusive answer. When all addresses have been attempted, + rewind the address list once on an inconclusive answer. + - refs #11832 where connects were retried indefinitely until + the overall timeout fired + + Closes #12400 + +Daniel Stenberg (24 Nov 2023) + +- CI: verify libcurl function SYNPOSIS sections + + With the .github/scripits/verify-synopsis.pl script + + Closes #12402 + +- docs/libcurl: SYNSOPSIS cleanup + + - use the correct include file + - make sure they are declared as in the header file + - fix minor nroff syntax mistakes (missing .fi) + + These are verified by verify-synopsis.pl, which extracts the SYNPOSIS + code and runs it through gcc. + + Closes #12402 + +- sendf: fix comment typo + +- fopen: allocate the dir after fopen + + Move the allocation of the directory name down to after the fopen() call + to allow that shortcut code path to avoid a superfluous malloc+free + cycle. + + Follow-up to 73b65e94f35311 + + Closes #12398 + +Stefan Eissing (24 Nov 2023) + +- transfer: cleanup done+excess handling + + - add `SingleRequest->download_done` as indicator that + all download bytes have been received + - remove `stop_reading` bool from readwrite functions + - move excess body handling into client download writer + + Closes #12371 + +Daniel Stenberg (23 Nov 2023) + +- fopen: create new file using old file's mode + + Because the function renames the temp file to the target name as a last + step, if the file was previously owned by a different user, not ORing + the old mode could otherwise end up creating a file that was no longer + readable by the original owner after save. + + Reported-by: Loïc Yhuel + Fixes #12299 + Closes #12395 + +- test1476: require proxy + + Follow-up from 323df4261c3542 + + Closes #12394 + +- fopen: create short(er) temporary file name + + Only using random letters in the name plus a ".tmp" extension. Not by + appending characters to the final file name. + + Reported-by: Maksymilian Arciemowicz + + Closes #12388 + +Stefan Eissing (23 Nov 2023) + +- tests: git ignore generated second-hsts.txt file + + File is generated in test lib1900 + + Follow-up to 7cb03229d9e9c5 + + Closes #12393 + +Viktor Szakats (23 Nov 2023) + +- openssl: enable `infof_certstack` for 1.1 and LibreSSL 3.6 + + Lower the barrier to enable `infof_certstack()` from OpenSSL 3 to + OpenSSL 1.1.x, and LibreSSL 3.6 or upper. + + With the caveat, that "group name" and "type name" are missing from + the log output with these TLS backends. + + Follow-up to b6e6d4ff8f253c8b8055bab9d4d6a10f9be109f3 #12030 + + Reviewed-by: Daniel Stenberg + Closes #12385 + +Daniel Stenberg (23 Nov 2023) + +- urldata: fix typo in comment + +- CI: codespell + + The list of words to ignore is in the file + .github/scripts/codespell-ignore.txt + + Closes #12390 + +- lib: fix comment typos + + Five separate ones, found by codespell + + Closes #12390 + +- test1476: verify cookie PSL mixed case + +- cookie: lowercase the domain names before PSL checks + + Reported-by: Harry Sintonen + + Closes #12387 + +Viktor Szakats (23 Nov 2023) + +- openssl: fix building with v3 `no-deprecated` + add CI test + + - build quictls with `no-deprecated` in CI to have test coverage for + this OpenSSL 3 configuration. + + - don't call `OpenSSL_add_all_algorithms()`, `OpenSSL_add_all_digests()`. + The caller code is meant for OpenSSL 3, while these two functions were + only necessary before OpenSSL 1.1.0. They are missing from OpenSSL 3 + if built with option `no-deprecated`, causing build errors: + ``` + vtls/openssl.c:4097:3: error: call to undeclared function 'OpenSSL_add_all_ + algorithms'; ISO C99 and later do not support implicit function declaration + s [-Wimplicit-function-declaration] + vtls/openssl.c:4098:3: error: call to undeclared function 'OpenSSL_add_all_ + digests'; ISO C99 and later do not support implicit function declarations [ + -Wimplicit-function-declaration] + ``` + Ref: https://ci.appveyor.com/project/curlorg/curl-for-win/builds/48587418?f + ullLog=true#L7667 + + Regression from b6e6d4ff8f253c8b8055bab9d4d6a10f9be109f3 #12030 + Bug: https://github.com/curl/curl/issues/12380#issuecomment-1822944669 + Reviewed-by: Alex Bozarth + + - vquic/curl_ngtcp2: fix using `SSL_get_peer_certificate` with + `no-deprecated` quictls 3 builds. + Do it by moving an existing solution for this from `vtls/openssl.c` + to `vtls/openssl.h` and adjusting caller code. + ``` + vquic/curl_ngtcp2.c:1950:19: error: implicit declaration of function 'SSL_g + et_peer_certificate'; did you mean 'SSL_get1_peer_certificate'? [-Wimplicit + -function-declaration] + ``` + Ref: https://github.com/curl/curl/actions/runs/6960723097/job/18940818625#s + tep:24:1178 + + - curl_ntlm_core: fix `-Wunused-parameter`, `-Wunused-variable` and + `-Wunused-function` when trying to build curl with NTLM enabled but + without the necessary TLS backend (with DES) support. + + Closes #12384 + +- curl.h: delete Symbian OS references + + curl deprecated Symbian OS in 3d64031fa7a80ac4ae3fd09a5939196268b92f81 + via #5989. Delete references to it from public headers, because there + is no fresh release to use those headers with. + + Reviewed-by: Dan Fandrich + Reviewed-by: Jay Satiro + Closes #12378 + +- windows: use built-in `_WIN32` macro to detect Windows + + Windows compilers define `_WIN32` automatically. Windows SDK headers + or build env defines `WIN32`, or we have to take care of it. The + agreement seems to be that `_WIN32` is the preferred practice here. + Make the source code rely on that to detect we're building for Windows. + + Public `curl.h` was using `WIN32`, `__WIN32__` and `CURL_WIN32` for + Windows detection, next to the official `_WIN32`. After this patch it + only uses `_WIN32` for this. Also, make it stop defining `CURL_WIN32`. + + There is a slight chance these break compatibility with Windows + compilers that fail to define `_WIN32`. I'm not aware of any obsolete + or modern compiler affected, but in case there is one, one possible + solution is to define this macro manually. + + grepping for `WIN32` remains useful to discover Windows-specific code. + + Also: + + - extend `checksrc` to ensure we're not using `WIN32` anymore. + + - apply minor formatting here and there. + + - delete unnecessary checks for `!MSDOS` when `_WIN32` is present. + + Co-authored-by: Jay Satiro + Reviewed-by: Daniel Stenberg + + Closes #12376 + +Stefan Eissing (22 Nov 2023) + +- url: ConnectionExists revisited + + - have common pattern of `if not match, continue` + - revert pages long if()s to return early + - move dead connection check to later since it may + be relatively expensive + - check multiuse also when NOT building with NGHTTP2 + - for MULTIUSE bundles, verify that the inspected + connection indeed supports multiplexing when in use + (bundles may contain a mix of connection, afaict) + + Closes #12373 + +Daniel Stenberg (22 Nov 2023) + +- CURLMOPT_MAX_CONCURRENT_STREAMS: make sure the set value is within range + + ... or use the default value. + + Also clarify the documentation language somewhat. + + Closes #12382 + +- urldata: make maxconnects a 32 bit value + + "2^32 idle connections ought to be enough for anybody" + + Closes #12375 + +- FEATURES: update the URL phrasing + + The URL is length limited since a while back so "no limit" simply is not + true anymore. Mention the URL RFC standard used instead. + + Closes #12383 + +- wolfssh: remove redundant static prototypes + + vssh/wolfssh.c:346:18: error: redundant redeclaration of ‘wscp_recv’ [-We + rror=redundant-decls] + + Closes #12381 + +- setopt: remove superfluous use of ternary expressions + + Closes #12374 + +- mime: store "form escape" as a single bit + + Closes #12374 + +- setopt: check CURLOPT_TFTP_BLKSIZE range on set + + ... instead of later when the transfer is about to happen. + + Closes #12374 + +Viktor Szakats (21 Nov 2023) + +- build: add more picky warnings and fix them + + Enable more picky compiler warnings. I've found these options in the + nghttp3 project when implementing the CMake quick picky warning + functionality for it [1]. + + `-Wunused-macros` was too noisy to keep around, but fixed a few issues + it revealed while testing. + + - autotools: reflect the more precisely-versioned clang warnings. + Follow-up to 033f8e2a08eb1d3102f08c4d8c8e85470f8b460e #12324 + - autotools: sync between clang and gcc the way we set `no-multichar`. + - autotools: avoid setting `-Wstrict-aliasing=3` twice. + - autotools: disable `-Wmissing-noreturn` for MSYS gcc targets [2]. + It triggers in libtool-generated stub code. + + - lib/timeval: delete a redundant `!MSDOS` guard from a `WIN32` branch. + + - lib/curl_setup.h: delete duplicate declaration for `fileno`. + Added in initial commit ae1912cb0d494b48d514d937826c9fe83ec96c4d + (1999-12-29). This suggests this may not be needed anymore, but if + it does, we may restore this for those specific (non-Windows) systems. + - lib: delete unused macro `FTP_BUFFER_ALLOCSIZE` since + c1d6fe2aaa5a26e49a69a4f2495b3cc7a24d9394. + - lib: delete unused macro `isxdigit_ascii` since + f65f750742068f579f4ee6d8539ed9d5f0afcb85. + - lib/mqtt: delete unused macro `MQTT_HEADER_LEN`. + - lib/multi: delete unused macro `SH_READ`/`SH_WRITE`. + - lib/hostip: add `noreturn` function attribute via new `CURL_NORETURN` + macro. + - lib/mprintf: delete duplicate declaration for `Curl_dyn_vprintf`. + - lib/rand: fix `-Wunreachable-code` and related fallouts [3]. + - lib/setopt: fix `-Wunreachable-code-break`. + - lib/system_win32 and lib/timeval: fix double declarations for + `Curl_freq` and `Curl_isVistaOrGreater` in CMake UNITY mode [4]. + - lib/warnless: fix double declarations in CMake UNITY mode [5]. + This was due to force-disabling the header guard of `warnless.h` to + to reapply it to source code coming after `warnless.c` in UNITY + builds. This reapplied declarations too, causing the warnings. + Solved by adding a header guard for the lines that actually need + to be reapplied. + - lib/vauth/digest: fix `-Wunreachable-code-break` [6]. + - lib/vssh/libssh2: fix `-Wunreachable-code-break` and delete redundant + block. + - lib/vtls/sectransp: fix `-Wunreachable-code-break` [7]. + - lib/vtls/sectransp: suppress `-Wunreachable-code`. + Detected in `else` branches of dynamic feature checks, with results + known at compile-time, e.g. + ```c + if(SecCertificateCopySubjectSummary) /* -> true */ + ``` + Likely fixable as a separate micro-project, but given SecureTransport + is deprecated anyway, let's just silence these locally. + - src/tool_help: delete duplicate declaration for `helptext`. + - src/tool_xattr: fix `-Wunreachable-code`. + - tests: delete duplicate declaration for `unitfail` [8]. + - tests: delete duplicate declaration for `strncasecompare`. + - tests/libtest: delete duplicate declaration for `gethostname`. + Originally added in 687df5c8c39c370a59999b9afc0917d808d978b7 + (2010-08-02). + Got complicated later: c49e9683b85ba9d12cbb6eebc4ab2c8dba68fbdc + If there are still systems around with warnings, we may restore the + prototype, but limited for those systems. + - tests/lib2305: delete duplicate declaration for + `libtest_debug_config`. + - tests/h2-download: fix `-Wunreachable-code-break`. + + [1] https://github.com/ngtcp2/nghttp3/blob/a70edb08e954d690e8fb2c1df999b5a056 + f8bf9f/cmake/PickyWarningsC.cmake + [2] https://ci.appveyor.com/project/curlorg/curl/builds/48553586/job/3qkgjaui + qla5fj45?fullLog=true#L1675 + [3] https://github.com/curl/curl/actions/runs/6880886309/job/18716044703?pr=1 + 2331#step:7:72 + https://github.com/curl/curl/actions/runs/6883016087/job/18722707368?pr=1 + 2331#step:7:109 + [4] https://ci.appveyor.com/project/curlorg/curl/builds/48555101/job/9g15qkrr + iklpf1ut#L204 + [5] https://ci.appveyor.com/project/curlorg/curl/builds/48555101/job/9g15qkrr + iklpf1ut#L218 + [6] https://github.com/curl/curl/actions/runs/6880886309/job/18716042927?pr=1 + 2331#step:7:290 + [7] https://github.com/curl/curl/actions/runs/6891484996/job/18746659406?pr=1 + 2331#step:9:1193 + [8] https://github.com/curl/curl/actions/runs/6882803986/job/18722082562?pr=1 + 2331#step:33:1870 + + Closes #12331 + +Daniel Stenberg (21 Nov 2023) + +- transfer: avoid unreachable expression + + If curl_off_t and size_t have the same size (which is common on modern + 64 bit systems), a condition cannot occur which Coverity pointed + out. Avoid the warning by having the code conditionally only used if + curl_off_t actually is larger. + + Follow-up to 1cd2f0072fa482e25baa2 + + Closes #12370 + +Stefan Eissing (21 Nov 2023) + +- transfer: readwrite improvements + + - changed header/chunk/handler->readwrite prototypes to accept `buf`, + `blen` and a `pconsumed` pointer. They now get the buffer to work on + and report back how many bytes they consumed + - eliminated `k->str` in SingleRequest + - improved excess data handling to properly calculate with any body data + left in the headerb buffer + - eliminated `k->badheader` enum to only be a bool + + Closes #12283 + +Daniel Stenberg (21 Nov 2023) + +- RELEASE-NOTES: synced + +Jiří HruÅ¡ka (21 Nov 2023) + +- transfer: avoid calling the read callback again after EOF + + Regression since 7f43f3dc5994d01b12 (7.84.0) + + Bug: https://curl.se/mail/lib-2023-11/0017.html + + Closes #12363 + +Daniel Stenberg (21 Nov 2023) + +- doh: provide better return code for responses w/o addresses + + Previously it was wrongly returning CURLE_OUT_OF_MEMORY when the + response did not contain any addresses. Now it more accurately returns + CURLE_COULDNT_RESOLVE_HOST. + + Reported-by: lRoccoon on github + + Fixes #12365 + Closes #12366 + +Stefan Eissing (21 Nov 2023) + +- HTTP/2, HTTP/3: handle detach of onoing transfers + + - refs #12356 where a UAF is reported when closing a connection + with a stream whose easy handle was cleaned up already + - handle DETACH events same as DONE events in h2/h3 filters + + Fixes #12356 + Reported-by: PaweÅ‚ Wegner + Closes #12364 + +Viktor Szakats (20 Nov 2023) + +- autotools: stop setting `-std=gnu89` with `--enable-warnings` + + Do not alter the C standard when building with `--enable-warnings` when + building with gcc. + + On one hand this alters warning results compared to a default build. + On the other, it may produce different binaries, which is unexpected. + + Also fix new warnings that appeared after removing `-std=gnu89`: + + - include: fix public curl headers to use the correct printf mask for + `CURL_FORMAT_CURL_OFF_T` and `CURL_FORMAT_CURL_OFF_TU` with mingw-w64 + and Visual Studio 2013 and newer. This fixes the printf mask warnings + in examples and tests. E.g. [1] + + - conncache: fix printf format string [2]. + + - http2: fix potential null pointer dereference [3]. + (seen on Slackware with gcc 11.) + + - libssh: fix printf format string in SFTP code [4]. + Also make MSVC builds compatible with old CRT versions. + + - libssh2: fix printf format string in SFTP code for MSVC. + Applying the same fix as for libssh above. + + - unit1395: fix `argument is null` and related issues [5]: + - stop calling `strcmp()` with NULL to avoid undefined behaviour. + - fix checking results if some of them were NULL. + - do not pass NULL to printf `%s`. + + - ci: keep a build job with `-std=gnu89` to continue testing for + C89-compliance. We can apply this to other gcc jobs as needed. + Ref: b23ce2cee7329bbf425f18b49973b7a5f23dfcb4 (2022-09-23) #9542 + + [1] https://dev.azure.com/daniel0244/curl/_build/results?buildId=18581&view=l + ogs&jobId=ccf9cc6d-2ef1-5cf2-2c09-30f0c14f923b + [2] https://github.com/curl/curl/actions/runs/6896854263/job/18763831142?pr=1 + 2346#step:6:67 + [3] https://github.com/curl/curl/actions/runs/6896854253/job/18763839238?pr=1 + 2346#step:30:214 + [4] https://github.com/curl/curl/actions/runs/6896854253/job/18763838007?pr=1 + 2346#step:29:895 + [5] https://github.com/curl/curl/actions/runs/6896854253/job/18763836775?pr=1 + 2346#step:33:1689 + + Closes #12346 + +- autotools: fix/improve gcc and Apple clang version detection + + - Before this patch we expected `n.n` `-dumpversion` output, but Ubuntu + may return `n-win32` (also with `-dumpfullversion`). Causing these + errors and failing to enable picky warnings: + ``` + ../configure: line 23845: test: : integer expression expected + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/6263453828/job/1700789 + 3718#step:5:143 + + Fix that by stripping any dash-suffix and handling a dotless (major-only) + version number by assuming `.0` in that case. + + `9.3-posix`, `9.3-win32`, `6`, `9.3.0`, `11`, `11.2`, `11.2.0` + Ref: https://github.com/mamedev/mame/pull/9767 + + - fix Apple clang version detection for releases between + 'Apple LLVM version 7.3.0' and 'Apple LLVM version 10.0.1' where the + version was under-detected as 3.7 llvm/clang equivalent. + + - fix Apple clang version detection for 'Apple clang version 11.0.0' + and newer where the Apple clang version was detected, instead of its + llvm/clang equivalent. + + - display detected clang/gcc/icc compiler version. + + Via libssh2: + - https://github.com/libssh2/libssh2/commit/00a3b88c51cdb407fbbb347a2e38c5c7d + 89875ad + https://github.com/libssh2/libssh2/pull/1187 + - https://github.com/libssh2/libssh2/commit/89ccc83c7da73e7ca3a112e3500081319 + 42b592e + https://github.com/libssh2/libssh2/pull/1232 + + Closes #12362 + +- autotools: delete LCC compiler support bits + + Follow-up to fd7ef00f4305a2919e6950def1cf83d0110a4acd #12222 + + Closes #12357 + +- cmake: add test for `DISABLE` options, add `CURL_DISABLE_HEADERS_API` + + - tests: verify CMake `DISABLE` options. + + Make an exception for 2 CMake-only ones, and one more that's + using a different naming scheme, also in autotools and source. + + - cmake: add support for `CURL_DISABLE_HEADERS_API`. + + Suggested-by: Daniel Stenberg + Ref: https://github.com/curl/curl/pull/12345#pullrequestreview-1736238641 + + Closes #12353 + +Jacob Hoffman-Andrews (20 Nov 2023) + +- hyper: temporarily remove HTTP/2 support + + The current design of the Hyper integration requires rebuilding the + Hyper clientconn for each request. However, building the clientconn + requires resending the HTTP/2 connection preface, which is incorrect + from a protocol perspective. That in turn causes servers to send GOAWAY + frames, effectively degrading performance to "no connection reuse" in + the best case. It may also be triggering some bugs where requests get + dropped entirely and reconnects take too long. + + This doesn't rule out HTTP/2 support with Hyper, but it may take a + redesign of the Hyper integration in order to make things work. + + Closes #12191 + +Jay Satiro (20 Nov 2023) + +- schannel: fix unused variable warning + + Bug: https://github.com/curl/curl/pull/12349#issuecomment-1818000846 + Reported-by: Viktor Szakats + + Closes https://github.com/curl/curl/pull/12361 + +Daniel Stenberg (19 Nov 2023) + +- url: find scheme with a "perfect hash" + + Instead of a loop to scan over the potentially 30+ scheme names, this + uses a "perfect hash" table. This works fine because the set of schemes + is known and cannot change in a build. The hash algorithm and table size + is made to only make a single scheme index per table entry. + + The perfect hash is generated by a separate tool (scripts/schemetable.c) + + Closes #12347 + +- scripts: add schemetable.c + + This tool generates a scheme-matching table. + + It iterates over a number of different initial and shift values in order + to find the hash algorithm that needs the smallest possible table. + + The generated hash function, table and table size then needs to be used + by the url.c:Curl_getn_scheme_handler() function. + +Stefan Eissing (19 Nov 2023) + +- vtls/vquic, keep peer name information together + + - add `struct ssl_peer` to keep hostname, dispname and sni + for a filter + - allocate `sni` for use in VTLS backend + - eliminate `Curl_ssl_snihost()` and its use of the download buffer + - use ssl_peer in SSL and QUIC filters + + Closes #12349 + +Viktor Szakats (18 Nov 2023) + +- build: always revert `#pragma GCC diagnostic` after use + + Before this patch some source files were overriding gcc warning options, + but without restoring them at the end of the file. In CMake UNITY builds + these options spilled over to the remainder of the source code, + effecitvely disabling them for a larger portion of the codebase than + intended. + + `#pragma clang diagnostic` didn't have such issue in the codebase. + + Reviewed-by: Marcel Raad + Closes #12352 + +- tidy-up: casing typos, delete unused Windows version aliases + + - cmake: fix casing of `UnixSockets` to match the rest of the codebase. + + - curl-compilers.m4: fix casing in a comment. + + - setup-win32: delete unused Windows version constant aliases. + + Reviewed-by: Marcel Raad + Closes #12351 + +- keylog: disable if unused + + Fully disable keylog code if there is no TLS or QUIC subsystem using it. + + Closes #12350 + +- cmake: add `CURL_DISABLE_BINDLOCAL` option + + To match similar autotools option. + + Default is `ON`. + + Reviewed-by: Daniel Stenberg + Closes #12345 + +- url: fix `-Wzero-length-array` with no protocols + + Fixes: + ``` + ./lib/url.c:178:56: warning: use of an empty initializer is a C2x extension [ + -Wc2x-extensions] + 178 | static const struct Curl_handler * const protocols[] = { + | ^ + ./lib/url.c:178:56: warning: zero size arrays are an extension [-Wzero-length + -array] + ``` + + Closes #12344 + +- url: fix builds with `CURL_DISABLE_HTTP` + + Fixes: + ``` + ./lib/url.c:456:35: error: no member named 'formp' in 'struct UrlState' + 456 | Curl_mime_cleanpart(data->state.formp); + | ~~~~~~~~~~~ ^ + ``` + + Regression from 74b87a8af13a155c659227f5acfa78243a8b2aa6 #11682 + + Closes #12343 + +- http: fix `-Wunused-parameter` with no auth and no proxy + + ``` + lib/http.c:734:26: warning: unused parameter 'proxy' [-Wunused-parameter] + bool proxy) + ^ + ``` + + Reviewed-by: Marcel Raad + Closes #12338 + +Daniel Stenberg (16 Nov 2023) + +- TODO: Some TLS options are not offered for HTTPS proxies + + Closes #12286 + Closes #12342 + +- RELEASE-NOTES: synced + +- duphandle: make dupset() not return with pointers to old alloced data + + As the blob pointers are to be duplicated, the function must not return + mid-function with lingering pointers to the old handle's allocated data, + as that would lead to double-free in OOM situations. + + Make sure to clear all destination pointers first to avoid this risk. + + Closes #12337 + +Viktor Szakats (16 Nov 2023) + +- http: fix `-Wunused-variable` compiler warning + + Fix compiler warnings in builds with disabled auths, NTLM and SPNEGO. + + E.g. with `CURL_DISABLE_BASIC_AUTH` + `CURL_DISABLE_BEARER_AUTH` + + `CURL_DISABLE_DIGEST_AUTH` + `CURL_DISABLE_NEGOTIATE_AUTH` + + `CURL_DISABLE_NTLM` on non-Windows. + + ``` + ./curl/lib/http.c:737:12: warning: unused variable 'result' [-Wunused-variabl + e] + CURLcode result = CURLE_OK; + ^ + ./curl/lib/http.c:995:18: warning: variable 'availp' set but not used [-Wunus + ed-but-set-variable] + unsigned long *availp; + ^ + ./curl/lib/http.c:996:16: warning: variable 'authp' set but not used [-Wunuse + d-but-set-variable] + struct auth *authp; + ^ + ``` + + Regression from e92edfbef64448ef461117769881f3ed776dec4e #11490 + + Fixes #12228 + Closes #12335 + +Jay Satiro (16 Nov 2023) + +- tool: support bold headers in Windows + + - If virtual terminal processing is enabled in Windows then use ANSI + escape codes Esc[1m and Esc[22m to turn bold on and off. + + Suggested-by: Gisle Vanem + + Ref: https://github.com/curl/curl/discussions/11770 + + Closes https://github.com/curl/curl/pull/12321 + +Viktor Szakats (15 Nov 2023) + +- build: fix libssh2 + `CURL_DISABLE_DIGEST_AUTH` + `CURL_DISABLE_AWS` + + Builds with libssh2 + `-DCURL_DISABLE_DIGEST_AUTH=ON` + + `-DCURL_DISABLE_AWS=ON` in combination with either Schannel on Windows, + or `-DCURL_DISABLE_NTLM=ON` on other operating systems failed while + compiling due to a missing HMAC declaration. + + The reason is that HMAC is required by `lib/sha256.c` which publishes + `Curl_sha256it()` which is required by `lib/vssh/libssh2.c` when + building for libssh2 v1.8.2 (2019-05-25) or older. + + Make sure to compile the HMAC bits for a successful build. + + Both HMAC and `Curl_sha256it()` rely on the same internals, so splitting + them into separate sources isn't practical. + + Fixes: + ``` + [...] + In file included from ./curl/_x64-win-ucrt-cmake-llvm-bld/lib/CMakeFiles/libc + url_object.dir/Unity/unity_0_c.c:310: + ./curl/lib/sha256.c:527:42: error: array has incomplete element type 'const s + truct HMAC_params' + 527 | const struct HMAC_params Curl_HMAC_SHA256[] = { + | ^ + ./curl/lib/curl_sha256.h:34:21: note: forward declaration of 'struct HMAC_par + ams' + [...] + ``` + + Regression from e92edfbef64448ef461117769881f3ed776dec4e #11490 + + Fixes #12273 + Closes #12332 + +Daniel Stenberg (15 Nov 2023) + +- duphandle: also free 'outcurl->cookies' in error path + + Fixes memory-leak when OOM mid-function + + Use plain free instead of safefree, since the entire struct is + freed below. + + Remove some free calls that is already freed in Curl_freeset() + + Closes #12329 + +Viktor Szakats (15 Nov 2023) + +- config-win32: set `HAVE_SNPRINTF` for mingw-w64 + + It's available in all mingw-w64 releases. We already pre-fill this + detection in CMake. + + Closes #12325 + +- sasl: fix `-Wunused-function` compiler warning + + In builds with disabled auths. + + ``` + lib/curl_sasl.c:266:17: warning: unused function 'get_server_message' [-Wunus + ed-function] + static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data, + ^ + 1 warning generated. + ``` + Ref: https://github.com/curl/trurl/actions/runs/6871732122/job/18689066151#st + ep:3:3822 + + Reviewed-by: Daniel Stenberg + Closes #12326 + +- build: picky warning updates + + - cmake: sync some picky gcc warnings with autotools. + - cmake, autotools: add `-Wold-style-definition` for clang too. + - cmake: more precise version info for old clang options. + - cmake: use `IN LISTS` syntax in `foreach()`. + + Reviewed-by: Daniel Stenberg + Reviewed-by: Marcel Raad + Closes #12324 + +Daniel Stenberg (15 Nov 2023) + +- urldata: move cookielist from UserDefined to UrlState + + 1. Because the value is not strictly set with a setopt option. + + 2. Because otherwise when duping a handle when all the set.* fields are + first copied and an error happens (think out of memory mid-function), + the function would easily free the list *before* it was deep-copied, + which could lead to a double-free. + + Closes #12323 + +Viktor Szakats (14 Nov 2023) + +- autotools: avoid passing `LDFLAGS` twice to libcurl + + autotools passes `LDFLAGS` automatically linker commands. curl's + `lib/Makefile.am` customizes libcurl linker flags. In that + customization, it added `LDFLAGS` to the custom flags. This resulted in + passing `LDFLAGS` _twice_ to the `libtool` command. + + Most of the time this is benign, but some `LDFLAGS` options can break + the build when passed twice. One such example is passing `.o` files, + e.g. `crt*.o` files necessary when customizing the C runtime, e.g. for + MUSL builds. + + Passing them twice resulted in duplicate symbol errors: + ``` + libtool: link: clang-15 --target=aarch64-unknown-linux-musl [...] /usr/lib/a + arch64-linux-musl/crt1.o [...] /usr/lib/aarch64-linux-musl/crt1.o [...] + ld.lld-15: error: duplicate symbol: _start + >>> defined at crt1.c + >>> /usr/lib/aarch64-linux-musl/crt1.o:(.text+0x0) + >>> defined at crt1.c + >>> /usr/lib/aarch64-linux-musl/crt1.o:(.text+0x0) + [...] + clang: error: linker command failed with exit code 1 (use -v to see invocatio + n) + ``` + + This behaviour came with commit 1a593191c2769a47b8c3e4d9715ec9f6dddf5e36 + (2013-07-23) as a fix for bug https://curl.haxx.se/bug/view.cgi?id=1217. + The patch was a works-for-me hack that ended up merged in curl: + https://sourceforge.net/p/curl/bugs/1217/#06ef + With the root cause remaining unclear. + + Perhaps the SUNPro 12 linker was sensitive to `-L` `-l` order, requiring + `-L` first? This would be unusual and suggests a bug in either the + linker or in `libtool`. + + The curl build does pass the list of detected libs via its own + `LIBCURL_LIBS` variable, which ends up before `LDFLAGS` on the `libtool` + command line, but it's the job of `libtool` to ensure that even + a peculiar linker gets the options in the expected order. Also because + autotools passes `LDFLAGS` last, making it hardly possible to pass + anything after it. + + Perhaps in the 10 years since this issue, this already got a fix + upstream. + + This patch deletes `LDFLAGS` from our customized libcurl options, + leaving a single copy of them as passed by autotools automatically. + + Reverts 1a593191c2769a47b8c3e4d9715ec9f6dddf5e36 + Closes #12310 + +- autotools: accept linker flags via `CURL_LDFLAGS_{LIB,BIN}` + + To allow passing `LDFLAGS` specific to libcurl (`CURL_LDFLAGS_LIB`) and + curl tool (`CURL_LDFLAGS_BIN`). + + This makes it possible to build libcurl and curl with a single + invocation with lib- and tool-specific custom linker flags. + + Such flag can be enabling `.map` files, a `.def` file for libcurl DLL, + controlling static/shared, incl. requesting a static curl tool (with + `-static-libtool-libs`) while building both shared and static libcurl. + + curl-for-win uses the above and some more. + + These options are already supported in `Makefile.mk`. CMake has built-in + variables for this. + + Closes #12312 + +Jay Satiro (14 Nov 2023) + +- tool_cb_hdr: add an additional parsing check + + - Don't dereference the past-the-end element when parsing the server's + Content-disposition header. + + As 'p' is advanced it can point to the past-the-end element and prior + to this change 'p' could be dereferenced in that case. + + Technically the past-the-end element is not out of bounds because dynbuf + (which manages the header line) automatically adds a null terminator to + every buffer and that is not included in the buffer length passed to + the header callback. + + Closes https://github.com/curl/curl/pull/12320 + +Philip Heiduck (14 Nov 2023) + +- .cirrus.yml: freebsd 14 + + ensure curl works on latest freebsd version + + Closes #12053 + +Daniel Stenberg (13 Nov 2023) + +- easy: in duphandle, init the cookies for the new handle + + ... not the source handle. + + Closes #12318 + +- duphandle: use strdup to clone *COPYPOSTFIELDS if size is not set + + Previously it would unconditionally use the size, which is set to -1 + when strlen is requested. + + Updated test 544 to verify. + + Closes #12317 + +- RELEASE-NOTES: synced + +- curl_easy_duphandle.3: clarify how HSTS and alt-svc are duped + + Closes #12315 + +- urldata: move hstslist from 'set' to 'state' + + To make it work properly with curl_easy_duphandle(). This, because + duphandle duplicates the entire 'UserDefined' struct by plain copy while + 'hstslist' is a linked curl_list of file names. This would lead to a + double-free when the second of the two involved easy handles were + closed. + + Closes #12315 + +- test1900: verify duphandle with HSTS using multiple files + + Closes #12315 + +Goro FUJI (13 Nov 2023) + +- http: allow longer HTTP/2 request method names + + - Increase the maximum request method name length from 11 to 23. + + For HTTP/1.1 and earlier there's not a specific limit in libcurl for + method length except that it is limited by the initial HTTP request + limit (DYN_HTTP_REQUEST). Prior to fc2f1e54 HTTP/2 was treated the same + and there was no specific limit. + + According to Internet Assigned Numbers Authority (IANA) the longest + registered method is UPDATEREDIRECTREF which is 17 characters. + + Also there are unregistered methods used by some companies that are + longer than 11 characters. + + The limit was originally added by 61f52a97 but not used until fc2f1e54. + + Ref: https://www.iana.org/assignments/http-methods/http-methods.xhtml + + Closes https://github.com/curl/curl/pull/12311 + +Jay Satiro (12 Nov 2023) + +- CURLOPT_CAINFO_BLOB.3: explain what CURL_BLOB_COPY does + + - Add an explanation of the CURL_BLOB_COPY flag to CURLOPT_CAINFO_BLOB + and CURLOPT_PROXY_CAINFO_BLOB docs. + + All the other _BLOB option docs already have the same explanation. + + Closes https://github.com/curl/curl/pull/12277 + +Viktor Szakats (11 Nov 2023) + +- tidy-up: dedupe Windows system libs in cmake + + Reviewed-by: Daniel Stenberg + Closes #12307 + +Junho Choi (11 Nov 2023) + +- ci: test with latest quiche release (0.19.0) + + Closes #12180 + +- quiche: use quiche_conn_peer_transport_params() + + In recent quiche, transport parameter API is separated + with quiche_conn_peer_transport_params(). + (https://github.com/cloudflare/quiche/pull/1575) + It breaks with bulding with latest(post 0.18.0) quiche. + + Closes #12180 + +Daniel Stenberg (11 Nov 2023) + +- Makefile: generate the VC 14.20 project files at dist-time + + Follow-up to 28287092cc5a6d6ef8 (#12282) + + Closes #12290 + +Sam James (11 Nov 2023) + +- misc: fix -Walloc-size warnings + + GCC 14 introduces a new -Walloc-size included in -Wextra which gives: + + ``` + src/tool_operate.c: In function ‘add_per_transfer’: + src/tool_operate.c:213:5: warning: allocation of insufficient size ‘1’ fo + r type ‘struct per_transfer’ with size ‘480’ [-Walloc-size] + 213 | p = calloc(sizeof(struct per_transfer), 1); + | ^ + src/var.c: In function ‘addvariable’: + src/var.c:361:5: warning: allocation of insufficient size ‘1’ for type †+ ˜struct var’ with size ‘32’ [-Walloc-size] + 361 | p = calloc(sizeof(struct var), 1); + | ^ + ``` + + The calloc prototype is: + ``` + void *calloc(size_t nmemb, size_t size); + ``` + + So, just swap the number of members and size arguments to match the + prototype, as we're initialising 1 struct of size `sizeof(struct + ...)`. GCC then sees we're not doing anything wrong. + + Closes #12292 + +Mark Gaiser (11 Nov 2023) + +- IPFS: bugfixes + + - Fixed endianness bug in gateway file parsing + - Use IPFS_PATH in tests where IPFS_DATA was used + - Fixed typos from traling -> trailing + - Fixed broken link in IPFS.md + + Follow-up to 859e88f6533f9e + + Reported-by: Michael Kaufmann + Bug: https://github.com/curl/curl/pull/12152#issuecomment-1798214137 + Closes #12305 + +Daniel Stenberg (11 Nov 2023) + +- VULN-DISCLOSURE-POLIC: remove broken link to hackerone + + It should ideally soon not be done from hackerone anyway + + Closes #12308 + +Andrew Kurushin (11 Nov 2023) + +- schannel: add CA cache support for files and memory blobs + + - Support CA bundle and blob caching. + + Cache timeout is 24 hours or can be set via CURLOPT_CA_CACHE_TIMEOUT. + + Closes https://github.com/curl/curl/pull/12261 + +Daniel Stenberg (10 Nov 2023) + +- RELEASE-NOTES: synced + +Charlie C (10 Nov 2023) + +- cmake: option to disable install & drop `curlu` target when unused + + This patch makes the following changes: + - adds the option `CURL_DISABLE_INSTALL` - to disable 'install' targets. + - Removes the target `curlu` when the option `BUILD_TESTING` is set to + `OFF` - to prevent it from being loaded in Visual Studio. + + Closes #12287 + +Kai Pastor (10 Nov 2023) + +- cmake: fix multiple include of CURL package + + Fixes errors on second `find_package(CURL)`. This is a frequent case + with transitive dependencies: + ``` + CMake Error at ...: + add_library cannot create ALIAS target "CURL::libcurl" because another + target with the same name already exists. + ``` + + Test to reproduce: + ```cmake + cmake_minimum_required(VERSION 3.27) # must be 3.18 or higher + + project(curl) + + set(CURL_DIR "example/lib/cmake/CURL/") + find_package(CURL CONFIG REQUIRED) + find_package(CURL CONFIG REQUIRED) # fails + + add_executable(main main.c) + target_link_libraries(main CURL::libcurl) + ``` + + Ref: https://cmake.org/cmake/help/latest/release/3.18.html#other-changes + Ref: https://cmake.org/cmake/help/v3.18/policy/CMP0107.html + Ref: #12300 + Assisted-by: Harry Mallon + Closes #11913 + +Viktor Szakats (8 Nov 2023) + +- tidy-up: use `OPENSSL_VERSION_NUMBER` + + Uniformly use `OPENSSL_VERSION_NUMBER` to check for OpenSSL version. + Before this patch some places used `OPENSSL_VERSION_MAJOR`. + + Also fix `lib/md4.c`, which included `opensslconf.h`, but that doesn't + define any version number in these implementations: BoringSSL, AWS-LC, + LibreSSL, wolfSSL. (Only in mainline OpenSSL/quictls). Switch that to + `opensslv.h`. This wasn't causing a deeper problem because the code is + looking for v3, which is only provided by OpenSSL/quictls as of now. + + According to https://github.com/openssl/openssl/issues/17517, the macro + `OPENSSL_VERSION_NUMBER` is safe to use and not deprecated. + + Reviewed-by: Marcel Raad + Closes #12298 + +Daniel Stenberg (8 Nov 2023) + +- resolve.d: drop a multi use-sentence + + Since the `multi:` keyword adds that message. + + Reported-by: ç©ä¸¹å°¼ Dan Jacobson + Fixes https://github.com/curl/curl/discussions/12294 + Closes #12295 + +- content_encoding: make Curl_all_content_encodings allocless + + - Fixes a memory leak pointed out by Coverity + - Also found by OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail? + id=63947 + - Avoids unncessary allocations + + Follow-up ad051e1cbec68b2456a22661b + + Closes #12289 + +Michael Kaufmann (7 Nov 2023) + +- vtls: use ALPN "http/1.1" for HTTP/1.x, including HTTP/1.0 + + Some servers don't support the ALPN protocol "http/1.0" (e.g. IIS 10), + avoid it and use "http/1.1" instead. + + This reverts commit df856cb5c9 (#10183). + + Fixes #12259 + Closes #12285 + +Daniel Stenberg (7 Nov 2023) + +- Makefile.am: drop vc10, vc11 and vc12 projects from dist + + They are end of life products. Support for generating them remain in the + repo for a while but this change drops them from distribution. + + Closes #12288 + +David Suter (7 Nov 2023) + +- projects: add VC14.20 project files + + Windows projects included VC14, VC14.10, VC14.30 but not VC14.20. + OpenSSL and Wolf SSL scripts mention VC14.20 so I don't see a reason why + this is missing. Updated the templates to produce a VC14.20 project. + Project opens in Visual Studio 2019 as expected. + + Closes #12282 + +Daniel Stenberg (7 Nov 2023) + +- curl: move IPFS code into src/tool_ipfs.[ch] + + - convert ensure_trailing into ensure_trailing_slash + - strdup the URL string to own it proper + - use shorter variable names + - combine some expressions + - simplify error handling in ipfs_gateway() + - add MAX_GATEWAY_URL_LEN + proper bailout if maximum is reached + - ipfs-gateway.d polish and simplification + - shorten ipfs error message + make them "synthetic" + + Closes #12281 + +Viktor Szakats (6 Nov 2023) + +- build: delete support bits for obsolete Windows compilers + + - Pelles C: Unclear status, failed to obtain a fresh copy a few months + ago. Possible website is HTTP-only. ~10 years ago I left this compiler + dealing with crashes and other issues with no response on the forum + for years. It has seen some activity in curl back in 2021. + - LCC: Last stable release in September 2002. + - Salford C: Misses winsock2 support, possibly abandoned? Last mentioned + in 2006. + - Borland C++: We dropped Borland C++ support in 2018. + - MS Visual C++ 6.0: Released in 1998. curl already requires VS 2010 + (or possibly 2008) as a minimum. + + Closes #12222 + +- build: delete `HAVE_STDINT_H` and `HAVE_INTTYPES_H` + + We use `stdint.h` unconditionally in all places except one. These uses + are imposed by external dependencies / features. nghttp2, quic, wolfSSL + and `HAVE_MACH_ABSOLUTE_TIME` do require this C99 header. It means that + any of these features make curl require a C99 compiler. (In case of + MSVC, this means Visual Studio 2010 or newer.) + + This patch changes the single use of `stdint.h` guarded by + `HAVE_STDINT_H` to use `stdint.h` unconditionally. Also stop using + `inttypes.h` as an alternative there. `HAVE_INTTYPES_H` wasn't used + anywhere else, allowing to delete this feature check as well. + + Closes #12275 + +Daniel Stenberg (6 Nov 2023) + +- tool_operate: do not mix memory models + + Make sure 'inputpath' only points to memory allocated by libcurl so that + curl_free works correctly. + + Pointed out by Coverity + + Follow-up to 859e88f6533f9e1f890 + + Closes #12280 + +Stefan Eissing (6 Nov 2023) + +- lib: client writer, part 2, accounting + logging + + This PR has these changes: + + Renaming of unencode_* to cwriter, e.g. client writers + - documentation of sendf.h functions + - move max decode stack checks back to content_encoding.c + - define writer phase which was used as order before + - introduce phases for monitoring inbetween decode phases + - offering default implementations for init/write/close + + Add type paramter to client writer's do_write() + - always pass all writes through the writer stack + - writers who only care about BODY data will pass other writes unchanged + + add RAW and PROTOCOL client writers + - RAW used for Curl_debug() logging of CURLINFO_DATA_IN + - PROTOCOL used for updates to data->req.bytecount, max_filesize checks and + Curl_pgrsSetDownloadCounter() + - remove all updates of data->req.bytecount and calls to + Curl_pgrsSetDownloadCounter() and Curl_debug() from other code + - adjust test457 expected output to no longer see the excess write + + Closes #12184 + +Daniel Stenberg (6 Nov 2023) + +- VULN-DISCLOSURE-POLICY: escape sequences are not a security flaw + + Closes #12278 + +Viktor Szakats (6 Nov 2023) + +- rand: fix build error with autotools + LibreSSL + + autotools unexpectedly detects `arc4random` because it is also looking + into dependency libs. One dependency, LibreSSL, happens to publish an + `arc4random` function (via its shared lib before v3.7, also via static + lib as of v3.8.2). When trying to use this function in `lib/rand.c`, + its protoype is missing. To fix that, curl included a prototype, but + that used a C99 type without including `stdint.h`, causing: + + ``` + ../../lib/rand.c:37:1: error: unknown type name 'uint32_t' + 37 | uint32_t arc4random(void); + | ^ + 1 error generated. + ``` + + This patch improves this by dropping the local prototype and instead + limiting `arc4random` use for non-OpenSSL builds. OpenSSL builds provide + their own random source anyway. + + The better fix would be to teach autotools to not link dependency libs + while detecting `arc4random`. + + LibreSSL publishing a non-namespaced `arc4random` tracked here: + https://github.com/libressl/portable/issues/928 + + Regression from 755ddbe901cd0c921fbc3ac5b3775c0dc683bc73 #10672 + + Reviewed-by: Daniel Stenberg + Fixes #12257 + Closes #12274 + +Daniel Stenberg (5 Nov 2023) + +- RELEASE-NOTES: synced + +- strdup: do Curl_strndup without strncpy + + To avoid (false positive) gcc-13 compiler warnings. + + Follow-up to 4855debd8a2c1cb + + Assisted-by: Jay Satiro + Reported-by: Viktor Szakats + Fixes #12258 + +Enno Boland (5 Nov 2023) + +- HTTP: fix empty-body warning + + This change fixes a compiler warning with gcc-12.2.0 when + `-DCURL_DISABLE_BEARER_AUTH=ON` is used. + + /home/tox/src/curl/lib/http.c: In function 'Curl_http_input_auth': + /home/tox/src/curl/lib/http.c:1147:12: warning: suggest braces around emp + ty body in an 'else' statement [-Wempty-body] + 1147 | ; + | ^ + + Closes #12262 + +Daniel Stenberg (5 Nov 2023) + +- openssl: identify the "quictls" backend correctly + + Since vanilla OpenSSL does not support the QUIC API I think it helps + users to identify the correct OpenSSL fork in version output. The best + (crude) way to do that right now seems to be to check if ngtcp2 support + is enabled. + + Closes #12270 + +Mark Gaiser (5 Nov 2023) + +- curl: improved IPFS and IPNS URL support + + Previously just ipfs:// and ipns:// was supported, which is + too strict for some usecases. + + This patch allows paths and query arguments to be used too. + Making this work according to normal http semantics: + + ipfs:///foo/bar?key=val + ipns:///foo/bar?key=val + + The gateway url support is changed. + It now only supports gateways in the form of: + + http:///foo/bar + http:// + + Query arguments here are explicitly not allowed and trigger an intended + malformed url error. + + There also was a crash when IPFS_PATH was set with a non trailing + forward slash. This has been fixed. + + Lastly, a load of test cases have been added to verify the above. + + Reported-by: Steven Allen + Fixes #12148 + Closes #12152 + +Harry Mallon (5 Nov 2023) + +- docs: KNOWN_BUGS cleanup + + * Remove other mention of hyper memory-leaks from `KNOWN_BUGS`. + Should have been removed in 629723ecf22a8eae78d64cceec2f3bdae703ec95 + + * Remove mention of aws-sigv4 sort query string from `KNOWN_BUGS`. + Fixed in #11806 + + * Remove mention of aws-sigv4 query empty value problems + + * Remove mention of aws-sigv4 missing amz-content-sha256 + Fixed in #9995 + +- http_aws_sigv4: canonicalise valueless query params + + Fixes #8107 + Closes #12244 + +Michael Kaufmann (4 Nov 2023) + +- docs: preserve the modification date when copying the prebuilt man page + + The previously built man page "curl.1" must be copied with the original + modification date, otherwise the man page is never updated. + + This fixes a bug that has been introduced with commit 2568441cab. + + Reviewed-by: Dan Fandrich + Reviewed-by: Daniel Stenberg + + Closes #12199 + +Daniel Stenberg (4 Nov 2023) + +- docs: remove bold from some man page SYNOPSIS sections + + In the name of consistency + + Closes #12267 + +- openssl: two multi pointer checks should probably rather be asserts + + ... so add the asserts now and consider removing the dynamic checks in a + future. + + Ref: #12261 + Closes #12264 + +boilingoden (4 Nov 2023) + +- docs: add supported version for the json write-out + + xref: https://curl.se/changes.html#7_70_0 + + Closes #12266 + +Viktor Szakats (3 Nov 2023) + +- appveyor: make VS2008-built curl tool runnable + + By linking the CRT statically. This avoids the error about missing + runtime DLL `MSVCR90.dll` when running the freshly built `curl.exe`. + + Closes #12263 + +Stefan Eissing (3 Nov 2023) + +- url: proxy ssl connection reuse fix + + - tunnel https proxy used for http: transfers does + no check if proxy-ssl configuration matches + - test cases added, test_10_12 fails on 8.4.0 + + Closes #12255 + +Jay Satiro (3 Nov 2023) + +- curl_sspi: support more revocation error names in error messages + + - Add these revocation errors to sspi error list: + CRYPT_E_NO_REVOCATION_DLL, CRYPT_E_NO_REVOCATION_CHECK, + CRYPT_E_REVOCATION_OFFLINE and CRYPT_E_NOT_IN_REVOCATION_DATABASE. + + Prior to this change those error codes were not matched to their macro + name and instead shown as "unknown error". + + Before: + + schannel: next InitializeSecurityContext failed: + Unknown error (0x80092013) - The revocation function was + unable to check revocation because the revocation server was offline. + + After: + + schannel: next InitializeSecurityContext failed: + CRYPT_E_REVOCATION_OFFLINE (0x80092013) - The revocation function was + unable to check revocation because the revocation server was offline. + + Bug: https://github.com/curl/curl/issues/12239 + Reported-by: Niracler Li + + Closes https://github.com/curl/curl/pull/12241 + +- strdup: don't allow Curl_strndup to read past a null terminator + + - Use malloc + strncpy instead of Curl_memdup to dupe the string before + null terminating it. + + Prior to this change if Curl_strndup was passed a length longer than + the allocated string then it could copy out of bounds. + + This change is for posterity. Curl_strndup was added in the parent + commit and currently none of the calls to it pass a length that would + cause it to read past the allocated length of the input. + + Follow-up to d3b3ba35. + + Closes https://github.com/curl/curl/pull/12254 + +Daniel Stenberg (2 Nov 2023) + +- lib: add and use Curl_strndup() + + The Curl_strndup() function is similar to memdup(), but copies 'n' bytes + then adds a terminating null byte ('\0'). + + Closes #12251 + +- CURPOST_POSTFIELDS.3: add CURLOPT_COPYPOSTFIELDS in SEE ALSO + +Stefan Eissing (2 Nov 2023) + +- pytest: use lower count in repeat tests + + - lower large iteration counts in some tests somewhat for + the same coverage with less duration + + Closes #12248 + +Daniel Stenberg (2 Nov 2023) + +- RELEASE-NOTES: synced + +- docs: clarify that curl passes on input unfiltered + + ... for several options. + + Reported-by: Ophir Lojkine + + Closes #12249 + +- urlapi: when URL encoding the fragment, pass in the right length + + A benign bug because it would only add an extra null terminator. + + Made lib1560 get a test that runs this code. + + Closes #12250 + +Stefan Eissing (2 Nov 2023) + +- vtls: late clone of connection ssl config + + - perform connection cache matching against `data->set.ssl.primary` + and proxy counterpart + - fully clone connection ssl config only when connection is used + + Closes #12237 + +- msh3: error when built with CURL_DISABLE_SOCKETPAIR set + + Reported-by: Gisle Vanem + Closes #12252 + Fixes #12213 + +Daniel Stenberg (2 Nov 2023) + +- hsts: skip single-dot hostname + + Reported-by: Maksymilian Arciemowicz + + Closes #12247 + +- vtls: fix build without proxy + + Follow-up to bf0e278a3c54bc7fee7360da17c + + closes #12243 + +- docs/example/keepalive.c: show TCP keep-alive options + + Closes #12242 + +- lib1560: verify appending blank URL encoded query string + +- urlapi: skip appending NULL pointer query + + Reported-by: kirbyn17 on hackerone + + Closes #12240 + +- lib1560: verify setting host to "" with and without URL encode + +- urlapi: avoid null deref if setting blank host to url encode + + Reported-by: kirbyn17 on hackerone + + Closes #12240 + +- dynbuf: assert for NULL pointer inputs + + Help us catch more mistakes. + + Closes #12238 + +- HTTP3: ngtcp2 builds are no longer experimental + + The other HTTP/3 backends are still experimental. + + Closes #12235 + +Stefan Eissing (31 Oct 2023) + +- vtls: cleanup SSL config management + + - remove `Curl_ssl_get_config()`, no longer needed + + Closes #12204 + +Daniel Stenberg (31 Oct 2023) + +- libcurl-thread.3: simplify the TLS section + + All TLS libraries curl can use are threadsafe since OpenSSL 1.1.x, August + 2016. + + Closes #12233 + +- configure: better --disable-http + + - disable HTTPS-proxy as well, since it can't work without HTTP + + - curl_setup: when HTTP is disabled, also disable all features that are + HTTP-only + + - version: HTTPS-proxy only exists if HTTP support exists + + Closes #12223 + +- http: consider resume with CURLOPT_FAILONERRROR and 416 to be fine + + Finding a 'Content-Range:' in the response changed the handling. + + Add test case 1475 to verify -C - with 416 and Content-Range: header, + which is almost exactly like test 194 which instead uses a fixed -C + offset. Adjusted test 194 to also be considered fine. + + Fixes #10521 + Reported-by: Smackd0wn + Fixes #12174 + Reported-by: Anubhav Rai + Closes #12176 + +Stefan Eissing (30 Oct 2023) + +- GHA: fix checkout of quictls repository to use correct branch name + + Follow-up to c868b0e30f10cd0ac7 + + Closes #12232 + +Daniel Stenberg (30 Oct 2023) + +- docs/example/localport.c: show off CURLOPT_LOCALPORT + + Closes #12230 + +- docs/examples/interface.c: show CURLOPT_INTERFACE use + + Although super simple. + + Closes #12229 + +Viktor Szakats (30 Oct 2023) + +- build: fix compiler warning with auths disabled + + ``` + ./curl/lib/http.c:979:12: warning: unused function 'is_valid_auth_separator' + [-Wunused-function] + static int is_valid_auth_separator(char ch) + ^ + 5 warnings generated. + ``` + + Follow-up to e92edfbef64448ef461117769881f3ed776dec4e #11490 + + Closes #12227 + +- build: require Windows XP or newer + + After this patch we assume availability of `getaddrinfo` and + `freeaddrinfo`, first introduced in Windows XP. Meaning curl + now requires building for Windows XP as a minimum. + + TODO: assume these also in autotools. + + Ref: https://github.com/curl/curl/pull/12221#issuecomment-1783761806 + Closes #12225 + +- appveyor: bump one job to OpenSSL 3.1 (was 1.1.1) + + Use 3.1 with the modern runner image. + + We still use 1.1.1 in 8 jobs. + + 1.1.1 is EOL since 2023-09-11: + https://www.openssl.org/blog/blog/2023/03/28/1.1.1-EOL/ + + Also: + - add missing SSL-backend to job descriptions. + - tidy up CPU in job descriptions. + + Closes #12226 + +Daniel Stenberg (30 Oct 2023) + +- RELEASE-NOTES: synced + +- GHA: bump ngtcp2, nghttp3, nghttp2 and quictls versions + + ngtcp2 1.0.1 + nghttp3 1.0.0 + nghttp2 1.58.0 + quictls 3.1.4+quic + + also sync HTTP3.md with these changes + + Closes #12132 + +Kareem (29 Oct 2023) + +- wolfssl: add default case for wolfssl_connect_step1 switch + + Closes #12218 + +Jay Satiro (29 Oct 2023) + +- curl_setup: disallow Windows IPv6 builds missing getaddrinfo + + - On Windows if IPv6 is enabled but getaddrinfo is missing then #error + the build. + + curl can be built with IPv6 support (ENABLE_IPV6) but without the + ability to resolve hosts to IPv6 addresses (HAVE_GETADDRINFO). On + Windows this is highly unlikely and should be considered a bad build + configuration. + + Such a bad configuration has already given us a bug that was hard to + diagnose. See #12134 and #12136 for discussion. + + Ref: https://github.com/curl/curl/issues/12134 + Ref: https://github.com/curl/curl/pull/12136 + + Closes https://github.com/curl/curl/pull/12221 + +Nico Rieck (29 Oct 2023) + +- openssl: make CURLSSLOPT_NATIVE_CA import Windows intermediate CAs + + - If CURLSSLOPT_NATIVE_CA on Windows then import from intermediate CA + "CA" store after importing from root CA "ROOT" store. + + This change allows curl to work in situations where a server does not + send all intermediate certs and they are present in the "CA" store (the + store with intermediate CAs). This is already allowed by the Schannel + backend. + + Also this change makes partial chain verification possible for those + certs since we allow partial chain verification by default for OpenSSL + (unless CURLSSLOPT_NO_PARTIALCHAIN). This is not allowed by the Schannel + backend. + + Prior to this change CURLSSLOPT_NATIVE_CA only imported "ROOT" certs. + + Fixes https://github.com/curl/curl/issues/12155 + Closes https://github.com/curl/curl/pull/12185 + +Viktor Szakats (28 Oct 2023) + +- Makefile.mk: fix `-rtmp` option for non-Windows [ci skip] + +Daniel Stenberg (28 Oct 2023) + +- asyn-ares: handle no connection in the addrinfo callback + + To avoid crashing. + + Follow-up from 56a4db2 + Closes #12219 + +Jay Satiro (28 Oct 2023) + +- hostip6: fix DEBUG_ADDRINFO builds + + - Removed unused and incorrect parameter from dump_addrinfo(). + + Bug: https://github.com/curl/curl/commit/56a4db2e#commitcomment-131050442 + Reported-by: Gisle Vanem + + Closes https://github.com/curl/curl/pull/12212 + +Viktor Szakats (28 Oct 2023) + +- Makefile.mk: restore `_mingw.h` for default `_WIN32_WINNT` + + In 8.4.0 we deleted `_mingw.h` as part of purging old-mingw support. + Turns out `_mingw.h` had the side-effect of setting a default + `_WIN32_WINNT` value expected by `lib/config-win32.h` to enable + `getaddrinfo` support in `Makefile.mk` mingw-w64 builds. This caused + disabling support for this unless specifying the value manually. + + Restore this header and update its comment to tell why we continue + to need it. + + This triggered a regression in official Windows curl builds starting + with 8.4.0_1. Fixed in 8.4.0_6. (8.5.0 will be using CMake.) + + Regression from 38029101e2d78ba125732b3bab6ec267b80a0e72 #11625 + + Reported-by: zhengqwe on github + Helped-by: Nico Rieck + Fixes #12134 + Fixes #12136 + Closes #12217 + +- hostip: silence compiler warning `-Wparentheses-equality` + + Seen with LLVM 17. + + ``` + hostip.c:1336:22: warning: equality comparison with extraneous parentheses [- + Wparentheses-equality] + 1336 | (a->ai_family == PF_INET)) { + | ~~~~~~~~~~~~~^~~~~~~~~~ + hostip.c:1336:22: note: remove extraneous parentheses around the comparison t + o silence this warning + 1336 | (a->ai_family == PF_INET)) { + | ~ ^ ~ + hostip.c:1336:22: note: use '=' to turn this equality comparison into an assi + gnment + 1336 | (a->ai_family == PF_INET)) { + | ^~ + | = + 1 warning generated. + ``` + + Follow-up to b651aba0962bb31353f55de4dc35f745952a1b10 #12145 + + Reviewed-by: Daniel Stenberg + Closes #12215 + +Stefan Eissing (27 Oct 2023) + +- doh: use PIPEWAIT when HTTP/2 is attempted + + Closes #12214 + +Daniel Stenberg (27 Oct 2023) + +- setopt: remove outdated cookie comment + + Closes #12206 + +Stefan Eissing (27 Oct 2023) + +- cfilter: provide call to tell connection to forget a socket + + - fixed libssh.c workaround for a socket being closed by + the library + - eliminate the terrible hack in cf-socket.c to guess when + this happened and try not closing the socket again. + - fixes race in eyeballing when socket could have failed to + be closed for a discarded connect attempt + + Closes #12207 + +- url: protocol handler lookup tidy-up + + - rename lookup to what it does + - use ARRAYSIZE instead of NULL check for end + - offer alternate lookup for 0-terminated strings + + Closes #12216 + +Viktor Szakats (27 Oct 2023) + +- build: variadic macro tidy-ups + + - delete unused `HAVE_VARIADIC_MACROS_C99/GCC` feature checks. + (both autotools and CMake.) + - delete duplicate `NULL` check in `Curl_trc_cf_infof()`. + - fix compiler warning in `CURL_DISABLE_VERBOSE_STRINGS` builds. + ``` + ./lib/cf-socket.c:122:41: warning: unused parameter 'data' [-Wunused-parame + ter] + static void nosigpipe(struct Curl_easy *data, + ^ + ``` + - fix `#ifdef` comments in `lib/curl_trc.{c,h}`. + - fix indentation in some `infof()` calls. + + Follow-up to dac293cfb7026b1ca4175d88b80f1432d3d3c684 #12167 + + Cherry-picked from #12105 + Closes #12210 + +- cmake: speed up threads setup for Windows + + Win32 threads are always available. We enabled them unconditionally + (with `ENABLE_THREADED_RESOLVER`). CMake built-in thread detection + logic has this condition hard-coded for Windows as well (since at least + 2007). + + Instead of doing all the work of detecting pthread combinations on + Windows, then discarding those results, skip these efforts and assume + built-in thread support when building for Windows. + + This saves 1-3 slow CMake configuration steps. + + Reviewed-by: Daniel Stenberg + Closes #12202 + +- cmake: speed up zstd detection + + Before this patch we detected the presence of a specific zstd API to + see if we can use the library. zstd published that API in its first + stable release: v1.0.0 (2016-08-31). + + Replace that method by detecting the zstd library version instead and + accepting if it's v1.0.0 or newer. Also display this detected version + and display a warning if the zstd found is unfit for curl. + + We use the same version detection method as zstd itself, via its public + C header. + + This deviates from autotools which keeps using the slow method of + looking for the API by building a test program. The outcome is the same + as long as zstd keeps offering this API. + + Ref: https://github.com/facebook/zstd/commit/5a0c8e24395079f8e8cdc90aa1659cd5 + ab1b7427 (2016-08-12, committed) + Ref: https://github.com/facebook/zstd/releases/tag/v0.8.1 (2016-08-18, first + released) + Ref: https://github.com/facebook/zstd/releases/tag/v1.0.0 + + Reviewed-by: Daniel Stenberg + Closes #12200 + +Daniel Stenberg (26 Oct 2023) + +- openssl: fix infof() to avoid compiler warning for %s with null + + vtls/openssl.c: In function ‘ossl_connect_step2’: + ../lib/curl_trc.h:120:10: error: ‘%s’ directive argument is null [-Werror + =format-overflow=] + 120 | Curl_infof(data, __VA_ARGS__); } while(0) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + vtls/openssl.c:4008:5: note: in expansion of macro ‘infof’ + 4008 | infof(data, "SSL connection using %s / %s / %s / %s", + | ^~~~~ + vtls/openssl.c:4008:49: note: format string is defined here + 4008 | infof(data, "SSL connection using %s / %s / %s / %s", + | ^~ + + Follow-up to b6e6d4ff8f253c8b8055bab + Closes #12196 + +Stefan Eissing (26 Oct 2023) + +- lib: apache style infof and trace macros/functions + + - test for a simplified C99 variadic check + - args to infof() in --disable-verbose are no longer disregarded but + must compile. + + Closes #12167 + Fixes #12083 + Fixes #11880 + Fixes #11891 + +Daniel Stenberg (26 Oct 2023) + +- RELEASE-NOTES: synced + +Stefan Eissing (26 Oct 2023) + +- urldata: move async resolver state from easy handle to connectdata + + - resolving is done for a connection, not for every transfer + - save create/dup/free of a cares channel for each transfer + - check values of setopt calls against a local channel if no + connection has been attached yet, when needed. + + Closes #12198 + +Daniel Stenberg (26 Oct 2023) + +- CURLOPT_WRITEFUNCTION.3: clarify what libcurl returns for CURL_WRITEFUNC_ERRO + R + + It returns CURLE_WRITE_ERROR. It was not previously stated clearly. + + Reported-by: enWILLYado on github + Fixes #12201 + Closes #12203 + +Viktor Szakats (25 Oct 2023) + +- autotools: update references to deleted `crypt-auth` option + + Delete leftovers of the `crypt-auth` `./configure` option and + add the new ones that replaced them. + + Follow-up to e92edfbef64448ef461117769881f3ed776dec4e #11490 + + Reviewed-by: Daniel Stenberg + Closes #12194 + +Stefan Eissing (25 Oct 2023) + +- lib: introduce struct easy_poll_set for poll information + + Connection filter had a `get_select_socks()` method, inspired by the + various `getsocks` functions involved during the lifetime of a + transfer. These, depending on transfer state (CONNECT/DO/DONE/ etc.), + return sockets to monitor and flag if this shall be done for POLLIN + and/or POLLOUT. + + Due to this design, sockets and flags could only be added, not + removed. This led to problems in filters like HTTP/2 where flow control + prohibits the sending of data until the peer increases the flow + window. The general transfer loop wants to write, adds POLLOUT, the + socket is writeable but no data can be written. + + This leads to cpu busy loops. To prevent that, HTTP/2 did set the + `SEND_HOLD` flag of such a blocked transfer, so the transfer loop cedes + further attempts. This works if only one such filter is involved. If a + HTTP/2 transfer goes through a HTTP/2 proxy, two filters are + setting/clearing this flag and may step on each other's toes. + + Connection filters `get_select_socks()` is replaced by + `adjust_pollset()`. They get passed a `struct easy_pollset` that keeps + up to `MAX_SOCKSPEREASYHANDLE` sockets and their `POLLIN|POLLOUT` + flags. This struct is initialized in `multi_getsock()` by calling the + various `getsocks()` implementations based on transfer state, as before. + + After protocol handlers/transfer loop have set the sockets and flags + they want, the `easy_pollset` is *always* passed to the filters. Filters + "higher" in the chain are called first, starting at the first + not-yet-connection one. Each filter may add sockets and/or change + flags. When all flags are removed, the socket itself is removed from the + pollset. + + Example: + + * transfer wants to send, adds POLLOUT + * http/2 filter has a flow control block, removes POLLOUT and adds + POLLIN (it is waiting on a WINDOW_UPDATE from the server) + * TLS filter is connected and changes nothing + * h2-proxy filter also has a flow control block on its tunnel stream, + removes POLLOUT and adds POLLIN also. + * socket filter is connected and changes nothing + * The resulting pollset is then mixed together with all other transfers + and their pollsets, just as before. + + Use of `SEND_HOLD` is no longer necessary in the filters. + + All filters are adapted for the changed method. The handling in + `multi.c` has been adjusted, but its state handling the the protocol + handlers' `getsocks` method are untouched. + + The most affected filters are http/2, ngtcp2, quiche and h2-proxy. TLS + filters needed to be adjusted for the connecting handshake read/write + handling. + + No noticeable difference in performance was detected in local scorecard + runs. + + Closes #11833 + +Daniel Stenberg (25 Oct 2023) + +- tests/README: SOCKS tests are not using OpenSSH, it has its own server + + Follow-up to 04fd67555cc + + Closes #12195 + +Jacob Hoffman-Andrews (25 Oct 2023) + +- tets: make test documentation more user-friendly + + Put the instructions to run tests right at the top of tests/README.md. + + Give instructions to read the runtests.1 man page for information + about flags. Delete redundant copy of the flags documentation in the + README. + + Add a mention in README.md of the important parallelism flag, to make + test runs go much faster. + + Move documentation of output line format into the runtests.1 man page, + and update it with missing flags. + + Fix the order of two flags in the man page. + + Closes #12193 + +Viktor Szakats (24 Oct 2023) + +- cmake: pre-fill rest of detection values for Windows + + The goal of this patch is to avoid unnecessary feature detection work + when doing Windows builds with CMake. Do this by pre-filling well-known + detection results for Windows and specifically for mingw-w64 and MSVC + compilers. Also limit feature checks to platforms where the results are + actually used. Drop a few redundant ones. And some tidying up. + + - pre-fill remaining detection values in Windows CMake builds. + + Based on actual detection results observed in CI runs, preceding + similar work over libssh2 and matching up values with + `lib/config-win32.h`. + + This brings down CMake configuration time from 58 to 14 seconds on the + same local machine. + + On AppVeyor CI this translates to: + - 128 seconds -> 50 seconds VS2022 MSVC with OpenSSL (per CMake job): + https://ci.appveyor.com/project/curlorg/curl/builds/48208419/job/4gw66ecr + jpy7necb#L296 + https://ci.appveyor.com/project/curlorg/curl/builds/48217440/job/8m4fwrr2 + fe249uo8#L186 + - 62 seconds -> 16 seconds VS2017 MINGW (per CMake job): + https://ci.appveyor.com/project/curlorg/curl/builds/48208419/job/s1y8q5iv + lcs7ub29?fullLog=true#L290 + https://ci.appveyor.com/project/curlorg/curl/builds/48217440/job/pchpxyjs + yc9kl13a?fullLog=true#L194 + + The formula is about 1-3 seconds delay for each detection. Almost all + of these trigger a full compile-link cycle behind the scenes, slow + even today, both cross and native, mingw-w64 and apparently MSVC too. + Enabling .map files or other custom build features slows it down + further. (Similar is expected for autotools configure.) + + - stop detecting `idn2.h` if idn2 was deselected. + autotools does this. + + - stop detecting `idn2.h` if idn2 was not found. + This deviates from autotools. Source code requires both header and + lib, so this is still correct, but faster. + + - limit `ADDRESS_FAMILY` detection to Windows. + + - normalize `HAVE_WIN32_WINNT` value to lowercase `0x0a12` format. + + - pre-fill `HAVE_WIN32_WINNT`-dependent detection results. + Saving 4 (slow) feature-detections in most builds: `getaddrinfo`, + `freeaddrinfo`, `inet_ntop`, `inet_pton` + + - fix pre-filled `HAVE_SYS_TIME_H`, `HAVE_SYS_PARAM_H`, + `HAVE_GETTIMEOFDAY` for mingw-w64. + Luckily this do not change build results, as `WIN32` took + priority over `HAVE_GETTIMEOFDAY` with the current source + code. + + - limit `HAVE_CLOCK_GETTIME_MONOTONIC_RAW` and + `HAVE_CLOCK_GETTIME_MONOTONIC` detections to non-Windows. + We're not using these in the source code for Windows. + + - reduce compiler warning noise in CMake internal logs: + - fix to include `winsock2.h` before `windows.h`. + Apply it to autotools test snippets too. + - delete previous `-D_WINSOCKAPI_=` hack that aimed to fix the above. + - cleanup `CMake/CurlTests.c` to emit less warnings. + + - delete redundant `HAVE_MACRO_SIGSETJMP` feature check. + It was the same check as `HAVE_SIGSETJMP`. + + - delete 'experimental' marking from `CURL_USE_OPENSSL`. + + - show CMake version via `CMakeLists.txt`. + Credit to the `zlib-ng` project for the idea: + https://github.com/zlib-ng/zlib-ng/blob/61e181c8ae93dbf56040336179c9954078b + d1399/CMakeLists.txt#L7 + + - make `CMake/CurlTests.c` pass `checksrc`. + + - `CMake/WindowsCache.cmake` tidy-ups. + + - replace `WIN32` guard with `_WIN32` in `CMake/CurlTests.c`. + + Closes #12044 + +Jay Satiro (24 Oct 2023) + +- page-footer: clarify exit code 25 + + - Clarify that curl tool exit code 25 means an upload failed to start. + + Exit code 25 is equivalent to CURLE_UPLOAD_FAILED (25). Prior to this + change the documentation only mentioned the case of FTP STOR failing. + + Reported-by: Emanuele Torre + + Ref: https://github.com/curl/curl/blob/curl-8_4_0/docs/libcurl/libcurl-errors + .3#L113-L115 + + Fixes https://github.com/curl/curl/issues/12189 + Closes https://github.com/curl/curl/pull/12190 + +Daniel Stenberg (24 Oct 2023) + +- scripts/cijobs.pl: adjust for appveyor + + Follow-up to a1d73a6bb + +Alex Bozarth (24 Oct 2023) + +- OpenSSL: Include SIG and KEM algorithms in verbose + + Currently the verbose output does not include which algorithms are used + for the signature and key exchange when using OpenSSL. Including the + algorithms used will enable better debugging when working on using new + algorithm implementations. Know what algorithms are used has become more + important with the fast growing research into new quantum-safe + algorithms. + + This implementation includes a build time check for the OpenSSL version + to use a new function that will be included in OpenSSL 3.2 that was + introduced in openssl/openssl@6866824 + + Based-on-patch-by: Martin Schmatz + Closes #12030 + +Daniel Stenberg (23 Oct 2023) + +- http2: provide an error callback and failf the message + + Getting nghttp2's error message helps users understand what's going + on. For example when the connection is brought down due a forbidden + header is used - as that header is then not displayed by curl itself. + + Example: + + curl: (92) Invalid HTTP header field was received: frame type: 1, + stream: 1, name: [upgrade], value: [h2,h2c] + + Ref: #12172 + Closes #12179 + +Turiiya (23 Oct 2023) + +- BINDINGS: add V binding + + Closes #12182 + +Daniel Stenberg (22 Oct 2023) + +- configure: check for the fseeko declaration too + + ... and make the code require both symbol and declaration. + + This is because for Android, the symbol is always present in the lib at + build-time even when not actually available in run-time. + + Assisted-by: Viktor Szakats + Reported-by: 12932 on github + Fixes #12086 + Closes #12158 + +Viktor Szakats (22 Oct 2023) + +- cmake: fix OpenSSL quic detection in quiche builds + + An orphan call to `CheckQuicSupportInOpenSSL()` remained after a recent + update when checking QUIC for quiche. Move back QUIC detection to + a function and fixup callers to use that. Also make sure that quiche + gets QUIC from BoringSSL, because it doesn't support other forks at this + time. + + Regression from dee310d54261f9a8416e87d50bccfe2cbe404949 #11555 + + Reported-by: Casey Bodley + Fixes #12160 + Closes #12162 + +Daniel Stenberg (22 Oct 2023) + +- RELEASE-NOTES: synced + + bump to 8.5.0 for pending release + +Dan Fandrich (21 Oct 2023) + +- test3103: add missing quotes around a test tag attribute + +Loïc Yhuel (21 Oct 2023) + +- tool: fix --capath when proxy support is disabled + + After 95e8515ca0, --capath always sets CURLOPT_PROXY_CAPATH, which fails + with CURLE_UNKNOWN_OPTION when proxy support is disabled. + + Closes #12089 + +Daniel Stenberg (21 Oct 2023) + +- openldap: move the alloc of ldapconninfo to *connect() + + Fixes a minor memory leak on LDAP connection reuse. + + Doing the allocation already in *setup_connection() is wrong since that + connect struct might get discarded early when an existing connection is + reused instead. + + Closes #12166 + +- openldap: set the callback argument in oldap_do + + ... to make sure it has the current 'data' pointer and not a stale old + one. + + Reported-by: Dan Fandrich + Closes #12166 + +- gnutls: support CURLSSLOPT_NATIVE_CA + + Remove the CURL_CA_FALLBACK logic. That build option was added to allow + primarily OpenSSL to use the default paths for loading the CA certs. For + GnuTLS it was instead made to load the "system certs", which is + different and not desirable. + + The native CA store loading is now asked for with this option. + + Follow-up to 7b55279d1d856 + + Co-authored-by: Jay Satiro + + Closes #12137 + +Stefan Eissing (21 Oct 2023) + +- RTSP: improved RTP parser + + - fix HTTP header parsing to report incomplete + lines it buffers as consumed! + - re-implement the RTP parser for interleave RTP + messages for robustness. It is now keeping its + state at the connection + - RTSP protocol handler "readwrite" implementation + now tracks if the response is before/in/after + header parsing or "in" a bod by calling + "Curl_http_readwrite_headers()" itself. This + allows it to know when non-RTP bytes are "junk" + or HEADER or BODY. + - tested with #12035 and various small receive + sizes where current master fails + + Closes #12052 + +- http2: header conversion tightening + + - fold the code to convert dynhds to the nghttp2 structs + into a dynhds internal method + - saves code duplication + - pacifies compiler analyzers + + Closes #12097 + +Daniel Stenberg (21 Oct 2023) + +- curl_ntlm_wb: fix elif typo + + Reported-by: Manfred Schwarb + Follow-up to d4314cdf65ae + Bug: https://github.com/curl/curl/commit/d4314cdf65aee295db627016934bd9eb621a + b077#r130551295 + +Dan Fandrich (20 Oct 2023) + +- test1683: remove commented-out check alternatives + + Python precheck/postcheck alternatives were included but commented out. + Since these are not used and perl is guaranteed to be available to run + the perl versions anyway, the Python ones are removed. + +Daniel Stenberg (20 Oct 2023) + +- hostip: show the list of IPs when resolving is done + + Getting 'curl.se' today then gets this verbose output which might help + debugging connectivity related matters. + + * Host curl.se:80 was resolved. + * IPv6: 2a04:4e42::347, 2a04:4e42:200::347, 2a04:4e42:400::347, + 2a04:4e42:600::347, 2a04:4e42:800::347, 2a04:4e42:a00::347, + 2a04:4e42:c00::347, 2a04:4e42:e00::347 + * IPv4: 151.101.193.91, 151.101.1.91, 151.101.65.91, 151.101.129.91 + + Co-authored-by: Jay Satiro + Closes #12145 + +rilysh (20 Oct 2023) + +- docs: fix function typo in curl_easy_option_next.3 + + Closes #12170 + +Daniel Stenberg (20 Oct 2023) + +- vssh: remove the #ifdef for Curl_ssh_init, use empty macro + + In the same style as other init calls + +- easy: remove duplicate wolfSSH init call + + It is already done in Curl_ssh_init() where it belongs. + + Closes #12168 + +- socks: make SOCKS5 use the CURLOPT_IPRESOLVE choice + + Fixes #11949 + Reported-by: Ammar Faizi + Closes #12163 + +- urldata: move the 'internal' boolean to the state struct + + ... where all the other state bits for the easy handles live. + + Closes #12165 + +- url: don't touch the multi handle when closing internal handles + + Reported-by: Maksymilian Arciemowicz + Closes #12165 + +Faraz Fallahi (19 Oct 2023) + +- getenv: PlayStation doesn't have getenv() + + Closes #12140 + +Daniel Stenberg (19 Oct 2023) + +- transfer: only reset the FTP wildcard engine in CLEAR state + + To avoid the state machine to start over and redownload all the files + *again*. + + Reported-by: lkordos on github + Regression from 843b3baa3e3cb228 (shipped in 8.1.0) + Bisect-by: Dan Fandrich + Fixes #11775 + Closes #12156 + +Stefan Eissing (19 Oct 2023) + +- GHA: move mod_h2 version in CI to v2.0.25 + + Closes #12157 + +Daniel Stenberg (19 Oct 2023) + +- ntlm_wb: use pipe instead of socketpair when possible + + Closes #12149 + +- RELEASE-NOTES: synced + +- asyn-thread: use pipe instead of socketpair for IPC when available + + If pipe() is present. Less overhead. + + Helped-by: Viktor Szakats + Closes #12146 + +Dan Fandrich (17 Oct 2023) + +- tests: Fix Windows test helper tool search & use it for handle64 + + The checkcmd() and checktestcmd() functions would not have worked on + Windows due to hard-coding the UNIX PATH separator character and not + adding .exe file extension. This meant that tools like stunnel, valgrind + and nghttpx would not have been found and used on Windows, and + inspection of previous test runs show none of those being found in pure + Windows CI builds. + + With this fixed, they can be used to detect the handle64.exe program + before attempting to use it. When handle64.exe was called + unconditionally without it existing, it caused perl to abort the test + run with the error + + The running command stopped because the preference variable + "ErrorActionPreference" or common parameter is set to Stop: + sh: handle64.exe: command not found + + Closes #12115 + +Daniel Stenberg (17 Oct 2023) + +- multi: use pipe instead of socketpair to *wakeup() + + If pipe() is present. Less overhead. + + Closes #12142 + +Jay Satiro (17 Oct 2023) + +- build: fix 'threadsafe' feature detection for older gcc + + - Add 'threadsafe' to the feature list shown during build if POSIX + threads are being used. + + This is a follow-up to 5adb6000 which added support for building a + thread-safe libcurl with older versions of gcc where atomic is not + available but pthread is. + + Reported-by: Dan Fandrich + Co-authored-by: Dan Fandrich + + Fixes https://github.com/curl/curl/issues/12125 + Closes https://github.com/curl/curl/pull/12127 + +Daniel Stenberg (16 Oct 2023) + +- test729: verify socks4a with excessive proxy user name length + +- socks: better buffer size checks for socks4a user and hostname + + Also limit the proxy user name to 255 bytes, which is the same limit as + in SOCKS5. + + Reported-by: sd0 on hackerone + Closes #12139 + +- curl.h: on FreeBSD include sys/param.h instead of osreldate.h + + Should things build on Playstation as well + + Fixes #12107 + Reported-by: Faraz Fallahi + Closes #12123 + +Marcin Rataj (16 Oct 2023) + +- tool_operate: fix links in ipfs errors + + URL fragment links generated from headers in + https://curl.se/docs/ipfs.html are lowercase. + + Closes #12133 + +Viktor Szakats (15 Oct 2023) + +- cmake: replace `check_library_exists_concat()` + + The idea of `check_library_exists_concat()` is that it detects an + optional component and adds it to the list of libs that we also use in + subsequent component checks. This caused problems when detecting + components with unnecessary dependencies that were not yet built. + + CMake offers the `CMAKE_REQUIRED_LIBRARIES` variable to set libs used + for component checks, which we already use in most cases. That left 4 + uses of `check_library_exists_concat()`. Only one of these actually + needed the 'concat' feature (ldap/lber). + + Delete this function and replace it with standard + `check_library_exists()` and manual management of our `CURL_LIBS` + list we use when linking build targets. And special logic to handle the + ldap/lber case. + + (We have a similar function for headers: `check_include_file_concat()`. + It works, but problematic for performance reasons and because it hides + the actual headers required in `check_symbol_exists()` calls.) + + Ref: #11537 #11558 + Fixes #11285 + Fixes #11648 + Closes #12070 + +LoRd_MuldeR (15 Oct 2023) + +- tool_cb_wrt: fix write output for very old Windows versions + + - Pass missing parameter for 'lpNumberOfCharsWritten' to WriteConsoleW() + function. + + Apparently this parameter was *not* optional on older Windows versions. + + Issue observed on Windows XP SP2. Issue not observed on Windows 7 SP1. + So at some point between those two Microsoft changed the behavior. + + Prior to this change, on those versions if parameter is NULL then the + function call fails with error ERROR_INVALID_ACCESS. + + Regression since af3f4e41. + + Ref: https://github.com/MicrosoftDocs/Console-Docs/issues/299 + + Fixes https://github.com/curl/curl/issues/12131 + Closes https://github.com/curl/curl/pull/12130 + +Jay Satiro (15 Oct 2023) + +- tool_urlglob: fix build for old gcc versions + + - Don't use __builtin_mul_overflow for GCC 4 and earlier. + + The function was added in GCC 5. + + Ref: https://gcc.gnu.org/gcc-5/changes.html + + Reported-by: Dan Fandrich + + Fixes https://github.com/curl/curl/issues/12124 + Closes https://github.com/curl/curl/pull/12128 + +Carlos Henrique Lima Melara (14 Oct 2023) + +- docs/libcurl: fix three minor man page format mistakes + + Reported-by: Samuel Henrique + + Closes https://github.com/curl/curl/pull/12126 + +Jay Satiro (14 Oct 2023) + +- tests/server: add more SOCKS5 handshake error checking + + - Add additional checking for missing and too-short SOCKS5 handshake + messages. + + Prior to this change the SOCKS5 test server did not check that all parts + of the handshake were received successfully. If those parts were missing + or too short then the server would access uninitialized memory. + + This issue was discovered in CI job 'memory-sanitizer' test results. + Test 2055 was failing due to the SOCKS5 test server not running. It was + not running because either it crashed or memory sanitizer aborted it + during Test 728. Test 728 connects to the SOCKS5 test server on a + redirect but does not send any data on purpose. The test server was not + prepared for that. + + Reported-by: Dan Fandrich + + Fixes https://github.com/curl/curl/issues/12117 + Closes https://github.com/curl/curl/pull/12118 + +Daniel Stenberg (14 Oct 2023) + +- RELEASE-NOTES: synced + +Sohom Datta (14 Oct 2023) + +- tool_getparam: limit --rate to be smaller than number of ms + + Currently, curl allows users to specify absurd request rates that might + be higher than the number of milliseconds in the unit (ex: curl --rate + 3600050/h http://localhost:8080 does not error out despite there being + only 3600000ms in a hour). + + This change adds a conditional check before the millisecond calculation + making sure that the number is not higher than the numerator (the unit) + If the number is higher, curl errors out with PARAM_NUMBER_TOO_LARGE + + Closes #12116 + +Daniel Stenberg (14 Oct 2023) + +- opts: fix two minor man page format mistakes + +Jay Satiro (14 Oct 2023) + +- curl_trc: remove a bad assertion + + - Remove DEBUGASSERT that an internal handle must not have user + private_data set before calling the user's debug callback. + + This is a follow-up to 0dc40b2a. The user can distinguish their easy + handle from an internal easy handle by setting CURLOPT_PRIVATE on their + easy handle. I had wrongly assumed that meant the user couldn't then + set CURLOPT_PRIVATE on an internal handle as well. + + Bug: https://github.com/curl/curl/pull/12060#issuecomment-1754594697 + Reported-by: Daniel Stenberg + + Closes https://github.com/curl/curl/pull/12104 + +Dan Fandrich (13 Oct 2023) + +- test613: stop showing an error on missing output file + + This test would show an error message if the output was missing during + the log post-processing step, but the message was not captured by the + test harness and wasn't useful since the normal golden log file + comparison would the problem more clearly. + +Stefan Eissing (13 Oct 2023) + +- quic: manage connection idle timeouts + + - configure a 120s idle timeout on our side of the connection + - track the timestamp when actual socket IO happens + - check IO timestamp to our *and* the peer's idle timeouts + in "is this connection alive" checks + + Reported-by: calvin2021y on github + Fixes #12064 + Closes #12077 + +Dan Fandrich (13 Oct 2023) + +- CI: ignore test 286 on Appveyor gcc 9 build + + This test fails sometimes with a super fast retry loop due to what may + just be a compiler bug. The test results are ignored on the one CI job + where it occurs because there seems to be nothing we can do to fix it. + + Fixes #12040 + Closes #12106 + +Viktor Szakats (13 Oct 2023) + +- lib: fix gcc warning in printf call + + Do not pass NULL to printf %s. + + Seen with gcc 13.2.0 on Debian: + ``` + .../curl/lib/connect.c:696:27: warning: '%s' directive argument is null [-Wfo + rmat-overflow=] + ``` + Ref: https://github.com/curl/curl-for-win/actions/runs/6476161689/job/1758442 + 6483#step:3:11104 + + Ref: #10284 + Co-authored-by: Jay Satiro + Closes #12082 + +Alex Klyubin (13 Oct 2023) + +- http2: safer invocation of populate_binsettings + + populate_binsettings now returns a negative value on error, instead of a + huge positive value. Both places which call this function have been + updated to handle this change in its contract. + + The way populate_binsettings had been used prior to this change the huge + positive values -- due to signed->unsigned conversion of the potentially + negative result of nghttp2_pack_settings_payload which returns negative + values on error -- are not possible. But only because http2.c currently + always provides a large enough output buffer and provides H2 SETTINGS + IVs which pass the verification logic inside nghttp2. If the + verification logic were to change or if http2.c started passing in more + IVs without increasing the output buffer size, the overflow could become + reachable, and libcurl/curl might start leaking memory contents to + servers/proxies... + + Closes #12101 + +Daniel Stenberg (13 Oct 2023) + +- openssl: avoid BN_num_bits() NULL pointer derefs + + Reported-by: icy17 on github + Fixes #12099 + Closes #12100 + +- wolfssl: require WOLFSSL_SYS_CA_CERTS for loading system CA + + This define is set in wolfssl's options.h file when this function and + feature is present. Handles both builds with the feature explicitly + disabled and wolfSSL versions before 5.5.2 - which introduced this API + call. + + Closes #12108 + +- tool_urlglob: make multiply() bail out on negative values + + - Does not work correctly with negative values + - use __builtin_mul_overflow() on gcc + + Reported-by: Torben Dury + Closes #12102 + +Loïc Yhuel (13 Oct 2023) + +- cmake: fix CURL_DISABLE_GETOPTIONS + + - Add CURL_DISABLE_GETOPTIONS to curl_config.h.cmake. + + Prior to this change the option had no effect because it was missing + from that file. + + Closes https://github.com/curl/curl/pull/12091 + +- easy_lock: add a pthread_mutex_t fallback + + This allows to keep the init threadsafe with gcc < 4.9.0 (no C11 + atomics). + + Closes https://github.com/curl/curl/pull/12090 + +Viktor Szakats (12 Oct 2023) + +- CI: add autotools, out-of-tree, debug build to distro check job + + Add a job that builds curl from a generated source tarball sample, with + autotools, out-of-tree, in debug mode. + + Ref: #12085 + Closes #12088 + +Daniel Stenberg (12 Oct 2023) + +- http: avoid Expect: 100-continue if Upgrade: is used + + Reported-by: Daniel Jelinski + Fixes #12022 + Closes #12062 + +Jan Alexander Steffens (heftig) (12 Oct 2023) + +- docs: use SOURCE_DATE_EPOCH for generated manpages + + This should make builds from Git reproducible. + + Closes #12092 + +Daniel Stenberg (12 Oct 2023) + +- RELEASE-NOTES: synced + + Bumped to 8.4.1 + +Viktor Szakats (12 Oct 2023) + +- cmake: fix `HAVE_H_ERRNO_ASSIGNABLE` detection + + Fix `HAVE_H_ERRNO_ASSIGNABLE` to not run, only compile its test snippet, + aligning this with autotools. This fixes an error when doing + cross-builds and also actually detects this feature. It affected systems + not allowlisted into this, e.g. SerenityOS. + + We used this detection result to enable `HAVE_GETADDRINFO_THREADSAFE`. + + Follow-up to 04a3a377d83fd72c4cf7a96c9cb6d44785e33264 #11979 + Ref: #12095 (closed in favour of this patch) + Ref: #11964 (effort to sync cmake detections with autotools) + + Reported-by: Kartatz on Github + Assisted-by: Kartatz on Github + Fixes #12093 + Closes #12094 + +- build: add `src/.checksrc` to source tarball + + Regression from e5bb88b8f824ed87620bd923552534c83c2a516e #11958 + + Bug: https://github.com/curl/curl/pull/11958#issuecomment-1757079071 + Reported-by: Romain Geissler + Fixes #12084 + Closes #12085 + +Version 8.4.0 (11 Oct 2023) + +Daniel Stenberg (11 Oct 2023) + +- RELEASE-NOTES: synced + +- THANKS: add contributors from 8.4.0 + +Jay Satiro (11 Oct 2023) + +- socks: return error if hostname too long for remote resolve + + Prior to this change the state machine attempted to change the remote + resolve to a local resolve if the hostname was longer than 255 + characters. Unfortunately that did not work as intended and caused a + security issue. + + Bug: https://curl.se/docs/CVE-2023-38545.html + +Stefan Eissing (10 Oct 2023) + +- CI: remove slowed-network tests + + - remove these tests as they are currently not reliable in our CI + setups. + + curl handles the test cases, but CI sometimes fails on these due to + additional conditions. Rather than mix them in, an additional CI job + will be added in the future that is specific to them. + + Closes https://github.com/curl/curl/pull/12075 + +Jay Satiro (10 Oct 2023) + +- libcurl-env-dbg.3: move debug variables from libcurl-env.3 + + - Move documentation of libcurl environment variables used only in debug + builds from libcurl-env into a separate document libcurl-env-dbg. + + - Document more debug environment variables. + + Previously undocumented or missing a description: + + CURL_ALTSVC_HTTP, CURL_DBG_SOCK_WBLOCK, CURL_DBG_SOCK_WPARTIAL, + CURL_DBG_QUIC_WBLOCK, CURL_DEBUG, CURL_DEBUG_SIZE, CURL_GETHOSTNAME, + CURL_HSTS_HTTP, CURL_FORCETIME, CURL_SMALLREQSEND, CURL_SMALLSENDS, + CURL_TIME. + + Closes https://github.com/curl/curl/pull/11811 + +Dan Fandrich (9 Oct 2023) + +- test670: increase the test timeout + + This should make it more immune to loaded servers. + + Ref: #11328 + +Stefan Eissing (9 Oct 2023) + +- MQTT: improve receive of ACKs + + - add `mq->recvbuf` to provide buffering of incomplete + ACK responses + - continue ACK reading until sufficient bytes available + - fixes test failures on low network receives + + Closes #12071 + +Viktor Szakats (9 Oct 2023) + +- quic: fix BoringSSL build + + Add guard around `SSL_CTX_set_ciphersuites()` use. + + Bug: https://github.com/curl/curl/pull/12065#issuecomment-1752171885 + + Follow-up to aa9a6a177017e4b74d33cdf85a3594900f4a7f81 + + Co-authored-by: Jay Satiro + Reviewed-by: Daniel Stenberg + Closes #12067 + +Stefan Eissing (9 Oct 2023) + +- test1540: improve reliability + + - print that bytes have been received on pausing, but not how many + + Closes #12069 + +- test2302: improve reliability + + - make result print collected write data, unless + change in meta flags is detected + - will show same result even when data arrives via + several writecb invocations + + Closes #12068 + +Daniel Stenberg (9 Oct 2023) + +- curl_easy_pause: set "in callback" true on exit if true + + Because it might have called another callback in the mean time that then + set the bit FALSE on exit. + + Reported-by: Jay Satiro + Fixes #12059 + Closes #12061 + +Viktor Szakats (8 Oct 2023) + +- h3: add support for ngtcp2 with AWS-LC builds + + ``` + curl 8.4.0-DEV (x86_64-apple-darwin) libcurl/8.4.0-DEV (SecureTransport) AWS- + LC/1.15.0 nghttp2/1.56.0 ngtcp2/0.19.1 nghttp3/0.15.0 + Release-Date: [unreleased] + Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps + mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss + Features: alt-svc AsynchDNS HSTS HTTP2 HTTP3 HTTPS-proxy IPv6 Largefile Multi + SSL NTLM SSL threadsafe UnixSockets + ``` + + Also delete an obsolete GnuTLS TODO and update the header comment in + `FindNGTCP2.cmake`. + + Reviewed-by: Daniel Stenberg + Closes #12066 + +- build: do not publish `HAVE_BORINGSSL`, `HAVE_AWSLC` macros + + Syncing this up with CMake. + + Source code uses the built-in `OPENSSL_IS_AWSLC` and + `OPENSSL_IS_BORINSSL` macros to detect BoringSSL and AWS-LC. No help is + necessary from the build tools. + + The one use of `HAVE_BORINGSSL` in the source turned out to be no longer + necessary for warning-free BoringSSL + Schannel builds. Ref: #1610 #2634 + + autotools detects this anyway for display purposes. + CMake detects this to decide whether to use the BoringSSL-specific + crypto lib with ngtcp2. It detects AWS-LC, but doesn't use the detection + result just yet (planned in #12066). + + Ref: #11964 + + Reviewed-by: Daniel Stenberg + Reviewed-by: Jay Satiro + Closes #12065 + +Marc Hoersken (8 Oct 2023) + +- CI: move distcheck job from Azure Pipelines to GitHub Actions + + This will allow for more trigger excludes within Azure Pipelines. + + Also fixes seemingly broken check with scripts/installcheck.sh. + Ref: 190374c74ec4e5247d9066544c86e8d095e1d7b5 + + Assisted-by: Philip Heiduck + Closes #9532 + +Daniel Stenberg (8 Oct 2023) + +- url: fall back to http/https proxy env-variable if ws/wss not set + + Reported-by: Craig Andrews + Fixes #12031 + Closes #12058 + +Stefan Eissing (8 Oct 2023) + +- cf-socket: simulate slow/blocked receives in debug + + add 2 env variables for non-UDP sockets: + 1. CURL_DBG_SOCK_RBLOCK: percentage of receive calls that randomly + should return EAGAIN + 2. CURL_DBG_SOCK_RMAX: max amount of bytes read from socket + + Closes #12035 + +- http2: refused stream handling for retry + + - answer HTTP/2 streams refused via a GOAWAY from the server to + respond with CURLE_RECV_ERROR in order to trigger a retry + on another connection + + Reported-by: black-desk on github + Ref #11859 + Closes #12054 + +Jay Satiro (8 Oct 2023) + +- CURLOPT_DEBUGFUNCTION.3: warn about internal handles + + - Warn that the user's debug callback may be called with the handle + parameter set to an internal handle. + + Without this warning the user may assume that the only handles their + debug callback receives are the easy handles on which they set + CURLOPT_DEBUGFUNCTION. + + This is a follow-up to f8cee8cc which changed DoH handles to inherit + the debug callback function set in the user's easy handle. As a result + those handles are now passed to the user's debug callback function. + + Closes https://github.com/curl/curl/pull/12034 + +- url: fix typo + +Daniel Stenberg (8 Oct 2023) + +- test458: verify --expand-output, expanding a file name accepting option + + Verifies the fix in #12055 (commit f2c8086ff15e6e995e1) + +- tool_getparam: accept variable expansion on file names too + + Reported-by: PBudmark on github + Fixes #12048 + Closes #12055 + +- RELEASE-NOTES: synced + +- multi: do CURLM_CALL_MULTI_PERFORM at two more places + + ... when it does a state transition but there is no particular socket or + timer activity. This was made apparent when commit b5bb84c removed a + superfluous timer expiry. + + Reported-by: Dan Fandrich. + Fixes #12033 + Closes #12056 + +Viktor Szakats (7 Oct 2023) + +- GHA/linux: mbedtls 3.5.0 + minor dep bumps + + Closes #12057 + +Dan Fandrich (7 Oct 2023) + +- CI: bump OpenLDAP package version on FreeBSD + + The old one is no longer available. + +Marc Hoersken (7 Oct 2023) + +- docs/libcurl/opts/Makefile.inc: add missing manpage files + + Detected with #9532 + +Dan Fandrich (7 Oct 2023) + +- tests: fix a race condition in ftp server disconnect + + If a client disconnected and reconnected quickly, before the ftp server + had a chance to respond, the protocol message/ack (ping/pong) sequence + got out of sync, causing messages sent to the old client to be delivered + to the new. A disconnect must now be acknowledged and intermediate + requests thrown out until it is, which ensures that such synchronization + problems can't occur. This problem could affect ftp, pop3, imap and smtp + tests. + + Fixes #12002 + Closes #12049 + +Viktor Szakats (7 Oct 2023) + +- appveyor: bump mingw-w64 job to gcc 13 (was: 8) + + This sets gcc 6, 7, 9, 13 in our test mix (was: 6, 7, 8, 9). + Adding a modern gcc version to the tests. + + (The gcc 8 job used to take around 50 minutes. The new image with gcc 13 + finished in 32, 35, 34 minutes in the 3 test runs so far.) + + It also adds a modern CMake version and OS env to our mingw-w64 builds. + + Closes #12051 + +David Benjamin (6 Oct 2023) + +- openssl: use X509_ALGOR_get0 instead of reaching into X509_ALGOR + + While the struct is still public in OpenSSL, there is a (somewhat + inconvenient) accessor. Use it to remain compatible if it becomes opaque + in the future. + + Closes #12038 + +Daniel Stenberg (6 Oct 2023) + +- curl_easy_pause.3: mention it works within callbacks + + Reported-by: Maxim Dzhura + Bug: https://curl.se/mail/lib-2023-10/0010.html + Closes #12046 + +- curl_easy_pause.3: mention h2/h3 buffering + + Asked-by: Maxim Dzhura + Ref: https://curl.se/mail/lib-2023-10/0011.html + + Closes #12045 + +Viktor Szakats (6 Oct 2023) + +- cmake: re-add missed C89 headers for specific detections + + We removed C89 `setjmp.h` and `signal.h` detections and excluded them + from the global header list we use when detecting functions [1]. Then + missed to re-add these headers to the specific functions which need + them to be detected [2]. Fix this omission in this patch. + + [1] Follow-up to 3795fcde995d96db641ddbcc8a04f9f0f03bef9f #11951 + [2] Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 + + Closes #12043 + +Daniel Stenberg (6 Oct 2023) + +- multi: set CURLM_CALL_MULTI_PERFORM after switch to DOING_MORE + + Since there is nothing to wait for there. Avoids the test 1233 hang + reported in #12033. + + Reported-by: Dan Fandrich + Closes #12042 + +Dan Fandrich (5 Oct 2023) + +- test1903: actually verify the cookies after the test + + The test otherwise could do just about anything (except leak memory in + debug mode) and its bad behaviour wouldn't be detected. Now, check the + resulting cookie file to ensure the cookies are still there. + + Closes #12041 + +- test: add missing s + + The tests will otherwise fail if curl has them disabled. + +- test1906: set a lower timeout since it's hit on Windows + + msys2 builds actually hit the connect timeout in normal operation, so + lower the timeout from 5 minutes to 5 seconds to reduce test time. + + Ref: #11328 + Closes #12036 + +Daniel Stenberg (5 Oct 2023) + +- RELEASE-NOTES: synced + +Jay Satiro (5 Oct 2023) + +- idn: fix WinIDN null ptr deref on bad host + + - Return CURLE_URL_MALFORMAT if IDN hostname cannot be converted from + UTF-8 to UTF-16. + + Prior to this change a failed conversion erroneously returned CURLE_OK + which meant 'decoded' pointer (what would normally point to the + punycode) would not be written to, remain NULL and be dereferenced + causing an access violation. + + Closes https://github.com/curl/curl/pull/11983 + +Dan Fandrich (4 Oct 2023) + +- tests: close the shell used to start sshd + + This shell isn't needed once sshd starts, so use "exec" so it doesn't + stick around. + + Closes #12032 + +Daniel Stenberg (4 Oct 2023) + +- base64: also build for curl + + Since the tool itself now uses the base64 code using the curlx way, it + needs to build also when the tool needs it. Starting now, the tool build + defines BULDING_CURL to allow lib-side code to use it. + + Follow-up to 2e160c9c6525 + + Closes #12010 + +Eduard Strehlau (4 Oct 2023) + +- tests: Fix zombie processes left behind by FTP tests. + + ftpserver.pl correctly cleans up spawned server processes, + but forgets to wait for the shell used to spawn them. + This is barely noticeable during a normal testrun, + but causes process exhaustion and test failure + during a complete torture run of the FTP tests. + + Fixes #12018 + Closes #12020 + +Dan Fandrich (4 Oct 2023) + +- github/labeler: improve labeler matches + +- test574: add a timeout to the test + + This one hangs occasionally, so this will speed up a test run and allow + logs to be seen when it does. + + Closes #12025 + +- tests: propagate errors in libtests + + Use the test macros to automatically propagate some errors, and check + and log others while running the tests. This can help in debugging + exactly why a test has failed. + +- tests: set --expect100-timeout to improve test reliability + + On an overloaded server, the default 1 second timeout can go by without + the test server having a chance to respond with the expected headers, + causing tests to fail. Increase the 1 second timeout to 99 seconds so + this failure mode is no longer a problem on test 1129. Some other tests + already set a high value, but make them consistently 99 seconds so if + something goes wrong the test is stalled for less time. + + Ref: #11328 + +- CI: ignore the "flaky" and "timing-dependent" test results in CMake + + This was already done for automake builds but CMake builds were missed. + Test 1086 actually causes the test harness to crash with: + + Warning: unable to close filehandle DWRITE properly: Broken pipe at C:/projec + ts/curl/tests/ftpserver.pl line 527 + + Rather than fix it now, this change leaves test 1086 entirely skipped on + those builds that show this problem. + + Follow-up to 589dca761 + + Ref: #11865 + +Viktor Szakats (4 Oct 2023) + +- cmake: improve OpenLDAP builds + + - cmake: detect OpenLDAP based on function `ldap_init_fd`. + autotools does this. autotools also publishes this detection result + in `HAVE_LDAP_INIT_FD`. We don't mimic that with CMake as the source + doesn't use this value. (it might need to be remove-listed in + `scripts/cmp-config.pl` for future OpenLDAP test builds.) + This also deletes existing self-declaration method via the + CMake-specific `CURL_USE_OPENLDAP` configuration. + + - cmake: define `LDAP_DEPRECATED=1` for OpenLDAP. + Like autotools does. This fixes a long list of these warnings: + ``` + /usr/local/opt/openldap/include/ldap.h:1049:5: warning: 'LDAP_DEPRECATED' i + s not defined, evaluates to 0 [-Wundef] + ``` + + - cmake: delete LDAP TODO comment no longer relevant. + + Also: + + - autotools: replace domain name `dummy` with `0.0.0.0` in LDAP feature + detection functions. + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #12024 + +- cmake: fix unity builds for more build combinations + + By using unique static function/variable names in source files + implementing these interfaces. + + - OpenLDAP combined with any SSH backend. + + - MultiSSL with mbedTLS, OpenSSL, wolfSSL, SecureTransport. + + Closes #12027 + +Daniel Stenberg (4 Oct 2023) + +- tests: remove leading spaces from some tags + + The threee tags ``, `` and `` were frequently used + with a leading space that this removes. The reason this habbit is so + widespread in testcases is probably that they have been copy and pasted. + + Hence, fixing them all now might curb this practice from now on. + + Closes #12028 + +Viktor Szakats (4 Oct 2023) + +- GHA: bump actions/checkout + + Follow-up to 2e0fa50fc16b9339f51e0a7bfff0352829323acb #11964 + Follow-up to c39585d9b7ef3cbfc1380812dec60e7b275b6af3 #12000 + + Closes #12023 + +- spelling: fix codespell 2.2.6 typos + + Closes #12019 + +Daniel Stenberg (3 Oct 2023) + +- GHA: add workflow to compare configure vs cmake outputs + + Uses scripts/cmp-config.pl two compare two curl_config.h files, + presumbly generated with configure and cmake. It displays the + differences and filters out a lot of known lines we ignore. + + The script also shows the matches that were *not* used. Possibly + subjects for removal. + + Closes #11964 + +- appveyor: enable test 571 + + Follow-up from 8a940fd55c175f7 / #12013 + + Closes #12017 + +Viktor Szakats (3 Oct 2023) + +- build: alpha-sort source files for lib and src + + Closes #12014 + +- cmake: delete old `HAVE_LDAP_URL_PARSE` logic + + Left there by accident after adding proper detection for this. + + Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006 + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #12015 + +Stefan Eissing (3 Oct 2023) + +- tests: increase lib571 timeout from 3s to 30s + + - 3s is too short for our CI, making this test fail occasionally + - test usually experiences no delay run locally, so 30s wont hurt + + Closes #12013 + +Viktor Szakats (3 Oct 2023) + +- cmake: fix unity with Windows Unicode + TrackMemory + + Found the root cause of the startup crash in unity builds with Unicode + and TrackMemory enabled at the same time. + + We must make sure that the `memdebug.h` header doesn't apply to + `lib/curl_multibyte.c` (as even noted in a comment there.) In unity + builds all headers apply to all sources, including `curl_multibyte.c`. + This probably resulted in an infinite loop on startup. + + Exclude this source from unity compilation with TrackMemory enabled, + in both libcurl and curl tool. Enable unity mode for a debug Unicode + CI job to keep it tested. Also delete the earlier workaround that + fully disabled unity for affected builds. + + Follow-up to d82b080f6374433ce7c98241329189ad2d3976f8 #12005 + Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095 + + Closes #11928 + +- cmake: disable unity mode with Windows Unicode + TrackMemory + + "TrackMemory" is `ENABLE_DEBUG=ON` (aka `ENABLE_CURLDEBUG=ON`, + aka `-DCURLDEBUG`). + + There is an issue with memory tracking and Unicode when built in "unity" + mode, which results in the curl tool crashing right on startup, even + without any command-line option. Interestingly this doesn't happen under + WINE (at least on the system I tested this on), but consistenly happens + on real Windows machines. Crash is 0xC0000374 heap corruption. Both + shared and static curl executables are affected. + + This limitation probably won't hit too many people, but it remains + a TODO to find and fix the root cause and drop this workaround. + + Example builds and runs: + https://ci.appveyor.com/project/curlorg/curl/builds/48169111/job/17cptxhtpubd + 7iwj#L313 (static) + https://ci.appveyor.com/project/curlorg/curl/builds/48169111/job/76e1ge758tby + qu9c#L317 (shared) + + Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095 + + Ref: #11928 + Closes #12005 + +- cmake: tidy-up `NOT_NEED_LBER_H` detection + + Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006 + +- appveyor: rewrite batch in PowerShell + CI improvements + + 1. Rewrite in PowerShell: + + - rewrite MS-DOS batch build script in PowerShell. + - move some bash operations into native PowerShell. + - fixups for PowerShell insisting on failure when a command outputs + something to stderr. + - fix to actually run `curl -V` after every build. + (and exclude ARM64 builds.) + - also say why we skipped `curl -V` if we had to skip. + - fix CMake warnings about unused configuration variables, by adapting + these dynamically for build cases. + - dedupe OpenSSL path into a variable. + - disable `test1451` failing with a warning anyway due to missing python + impacket. (after trying and failing to install impacket) + PowerShell promotes these warnings to errors by PowerShell. We can also + suppress they wholesale if they start causing issues in the future, + like we already to with `autoreconf` and `./configure`. + + PowerShell is better than MS-DOS batches, so the hope is this makes it + easier to extend and maintain the AppVeyor build logic. POSIX/bash isn't + supported inline by AppVeyor on Windows build machines, but we are okay + to keep it in an external script, so it's also an option. + + 2. CI improvements: + + - enable tests for a "unity" build job. + - speed-up CI initialization by using shallow clones of the curl repo. + - speed-up CMake MSVC jobs with `TrackFileAccess=false`. + - enable parallelism in `VisualStudioSolution` builds. + - display CMake version before builds. + - always show the CPU in job names. + - tell which jobs are build-only in job names. + - move `TESTING:` value next to `DISABLED_TESTS:` in two jobs. + - add `config.log` (autotools) to dumped logs (need to enable manually). + + 3. Style: + + - use single-quotes in YAML like we do in other CI YAML files. + It also allows to drop quoting characters and lighter to write/read. + (keep double quotes for PowerShell strings needing expansion.) + + Closes #11999 + +- cmake: fix `HAVE_LDAP_SSL`, `HAVE_LDAP_URL_PARSE` on non-Windows + + - set `HAVE_LDAP_URL_PARSE` if `ldap_url_parse` function exists. + Before this patch we set it based it on the presence of `stricmp`, + which correctly enabled it on e.g. Windows, but was inaccurate for + other platforms. + + - always set `HAVE_LDAP_SSL` if an LDAP backend is detected and + LDAPS is not explicitly disabled. This mimics autotools behaviour. + Previously we set it only for Windows LDAP. After this fix, LDAPS is + correctly enabled in default macOS builds. + + - enable LDAP[S] for a CMake macOS CI job. Target OS X 10.9 (Mavericks) + to avoid deprecation warnings for LDAP API. + + - always detect `HAVE_LDAP_SSL_H`, even with LDAPS explicitly disabled. + This doesn't make much sense, but let's do it to sync behaviour with + autotools. + + - fix benign typo in variable name. + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #12006 + +- autotools: restore `HAVE_IOCTL_*` detections + + This restores `CURL_CHECK_FUNC_IOCTL` detection. I deleted it in + 4d73854462f30948acab12984b611e9e33ee41e6 and + c3456652a0c72d1845d08df9769667db7e159949 (2022-08), because the + `HAVE_IOCTL` result it generated was unused in the source. But, + I did miss the fact that this had two dependent checks: + `CURL_CHECK_FUNC_IOCTL_FIONBIO`, + `CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR` that we do actually need: + `HAVE_IOCTL_FIONBIO`, `HAVE_IOCTL_SIOCGIFADDR`. + + Regression from 4d73854462f30948acab12984b611e9e33ee41e6 + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #12008 + +Daniel Stenberg (2 Oct 2023) + +- RELEASE-PROCEDURE.md: updated coming release dates + +- RELEASE-NOTES: synced + +Viktor Szakats (1 Oct 2023) + +- cmake: pre-cache `HAVE_POLL_FINE` on Windows + + Windows doesn't support `poll()`, so we can safely skip checking for + fine poll. + + Closes #12003 + +- gha: bump actions to latest versions + + - actions@checkout@v4 (from v3 and v2) + + - fsfe/reuse-action@v2 (from v1) + + Closes #12000 + +Stefan Eissing (30 Sep 2023) + +- h2: testcase and fix for pausing h2 streams + + - refs #11982 where it was noted that paused transfers may + close successfully without delivering the complete data + - made sample poc into tests/http/client/h2-pausing.c and + added test_02_27 to reproduce + + Closes #11989 + Fixes #11982 + Reported-by: Harry Sintonen + +Viktor Szakats (30 Sep 2023) + +- cmake: validate `CURL_DEFAULT_SSL_BACKEND` config value + + Before this patch CMake builds accepted any value and it was used at + runtime as-is. This patch make sure that the selected default backend + is also enabled in the build. It also enforces a full lowercase value. + + This improves reproducibility and brings CMake in sync with autotools + which already worked like described above. + + Follow-up to 26c7feb8b9d51a57fab3325571b4bbfa03b11af0 #11774 + + Closes #11998 + +- autotools: adjust `CURL_CA_PATH` value to CMake + + autotools was using the same value as CMake, but with an ending + slash. Delete the ending slash to match configurations. + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #11997 + +- cmake: detect `sys/wait.h` and `netinet/udp.h` + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #11996 + +Daniel Stenberg (30 Sep 2023) + +- lib: provide and use Curl_hexencode + + Generates a lower case ASCII hex output from a binary input. + + Closes #11990 + +- configure: check for the capath by default + + ... if the chosen TLS backend supports it: OpenSSL, GnuTLS, mbedTLS or wolfSS + L + + cmake: synced + + Assisted-by: Viktor Szakats + Closes #11987 + +- wolfssl: ignore errors in CA path + + The default wolfSSL_CTX_load_verify_locations() function is quite picky + with the certificates it loads and will for example return error if just + one of the certs has expired. + + With the *_ex() function and its WOLFSSL_LOAD_FLAG_IGNORE_ERR flag, it + behaves more similar to what OpenSSL does by default. + + Even the set of default certs on my Debian unstable has several expired + ones. + + Assisted-by: Juliusz Sosinowicz + Assisted-by: Michael Osipov + + Closes #11987 + +- create-dirs.d: clarify it also uses --output-dirs + + Reported-by: Robert Simpson + Fixes #11991 + Closes #11995 + +Viktor Szakats (30 Sep 2023) + +- appveyor: fix yamlint issues, indent + + Also: + - use double quotes in all batch if statements. + + Closes #11994 + +- cmake: detect `HAVE_CLOCK_GETTIME_MONOTONIC_RAW` + + Based on existing autotools logic. + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #11981 + +- cmake: detect `HAVE_GETADDRINFO_THREADSAFE` + + Based on existing autotools logic. + + autotools checks for old versions of the allowlisted target OSes and + disables this feature when seeing them. In CMake we assume we're running + on newer systems and enable regardless of OS version. + + autotools always runs all 3 probes for non-fast-tracked systems and + enables this feature if any one of them was successful. To save + configuration time, CMake stops at the first successful check. + + OpenBSD is not fast-tracked and then gets blocklisted as a generic BSD + system. I haven't double-checked if this is correct, but looks odd. + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #11979 + +- cmake: fix `HAVE_WRITABLE_ARGV` detection + + Move detection before the creation of detection results in + `curl_config.h`. + + Ref: #11964 (effort to sync cmake detections with autotools) + + Closes #11978 + +- appveyor: minor improvements + + - run `curl -V` after builds to see if they run and with what features. + Except for one job where a CRT DLL is missing. And ARM64 which should + fail, but is silently not launched instead. + + - copy libcurl DLL next to curl tool and tests binaries in shared mode. + This makes it possible to run the tests. (We don't run tests after + these builds yet.) + + - list the DLLs and EXEs present after the builds. + + - add `DEBUG` variable for CMake builds to allow disabling it, for + testing non-debug builds. (currently enabled for all) + + - add commented lines that dump CMake configuration logs for debugging + build/auto-detection issues. + + - add gcc version to jobs where missing. + + - switch a job to the native MSYS2 mingw-w64 toolchain. This adds gcc 9 + to the build mix. + + - make `SHARED=OFF` and `OPENSSL=OFF` defaults global. + + - delete a duplicate backslash. + + Closes #11976 + +- configure: replace adhoc domain with `localhost` in tests + + Reviewed-by: Daniel Stenberg + Closes #11988 + +- tidy-up: use more example domains + + Also make use of the example TLD: + https://en.wikipedia.org/wiki/.example + + Reviewed-by: Daniel Stenberg + Closes #11992 + +Dan Fandrich (29 Sep 2023) + +- runtests: display the test status if tests appear hung + + It sometimes happens that a test hangs during a test run and never + returns. The test harness will wait indefinitely for the results and on + CI servers the CI job will eventually be killed after an hour or two. + At the end of a test run, if results haven't come in within a couple of + minutes, display the status of all test runners and what tests they're + running to help in debugging the problem. + + This feature is really only kick in with parallel testing enabled, which + is fine because without parallel testing it's usually easy to tell what + test has hung. + + Closes #11980 + +- github/labeler: remove workaround for labeler + + This was added due to what seemed to be a bug regarding the sync-labels: + config option, but it looks like it wasn't necessary. + + Follow-up to b2b0534e7 + +Viktor Szakats (29 Sep 2023) + +- docs: upgrade an URL to HTTPS in `BINDINGS.md` [ci skip] + +Daniel Stenberg (29 Sep 2023) + +- docs: replace made up domains with example.com + + in FAQ and MANUAL.md + + - example.com was made for this purpose. + + - reduces the risk that one of those domains suddenly start hosting + something nasty and we provide links to them + + Closes #11986 + +Michael Osipov (29 Sep 2023) + +- acinclude.m4: Document proper system truststore on FreeBSD + + The default system truststore on FreeBSD has been /etc/ssl/certs for many + years now. It is managed canonically through certctl(8) and contains hashed + symlinks for OpenSSL and other TLS providers. + The previous ones require security/ca_root_nss which might not be installed o + r + will not contain any custom CA certificates. + + Closes #11985 + +Daniel Stenberg (29 Sep 2023) + +- FAQ: How do I upgrade curl.exe in Windows? + + This is a growing question, better answer it here to get somewhere to + point users to. + + Closes #11984 + +Viktor Szakats (28 Sep 2023) + +- cmake: pre-cache `HAVE_BASENAME` for mingw-w64 and MSVC + + `basename` is present in mingw-w64, missing from MSVC. Pre-cache + accordingly to make configure faster. + + Notice that `basename` has a bug so we later disable it even with + mingw-w64: + https://github.com/curl/curl/blob/781242ffa44a9f9b95b6da5ac5a1bf6372ec6257/li + b/curl_setup.h#L820-L825 + + Closes #11974 + +Daniel Stenberg (28 Sep 2023) + +- cmake: add missing checks + + - check for arc4random. To make rand.c use it accordingly. + - check for fcntl + - fix fseek detection + - add SIZEOF_CURL_SOCKET_T + - fix USE_UNIX_SOCKETS + - define HAVE_SNPRINTF to 1 + - check for fnmatch + - check for sched_yield + - remove HAVE_GETPPID duplicate from curl_config.h + - add HAVE_SENDMSG + + Ref: #11964 + + Co-authored-by: Viktor Szakats + Closes #11973 + +- configure: remove unused checks + + - for sys/uio.h + - for fork + - for connect + + Ref: #11964 + + Closes #11973 + +- lib: remove TIME_WITH_SYS_TIME + + It is not used in any code anywhere. + + Ref: #11964 + Closes #11975 + +- docs: update curl man page references + + Detected by the manpage-syntax update + + Closes #11963 + +- manpage-syntax: verify curl man page references + + 1. References to curl symbols are now checked that they indeed exist as + man pages. This for \f references as well as the names referenced in the + SEE ALSO section. + + Allowlist curl.1 since it is not always built in builds + + 2. References to curl symbols that lack section now causes warning, since tha + t + will prevent them from getting linked properly + + 3. Check for "bare" references to curl functions and warn, they should be + references + + Closes #11963 + +- cmake: add check for suseconds_t + + And fix the HAVE_LONGLONG define + + Ref: #11964 + Closes #11977 + +Viktor Szakats (28 Sep 2023) + +- tidy-up: whitespace fixes + + Closes #11972 + +- cmake: detect TLS-SRP in OpenSSL/wolfSSL/GnuTLS + + With new option `CURL_DISABLE_SRP=ON` to force-disable it. + To match existing option and detection logic in autotools. + + Also: + - fix detecting GnuTLS. + We assume `nettle` as a GnuTLS dependency. + - add CMake GnuTLS CI job. + - bump AppVeyor CMake OpenSSL MSVC job to OpenSSL 1.1.1 (from 1.0.2) + TLS-SRP fails to detect with 1.0.2 due to an OpenSSL header bug. + - fix compiler warning when building with GnuTLS and disabled TLS-SRP. + - fix comment typos, whitespace. + + Ref: #11964 + + Closes #11967 + +- tool: use our own stderr variable + + Earlier this year we changed our own stderr variable to use the standard + name `stderr` (to avoid bugs where someone is using `stderr` instead of + the curl-tool specific variable). This solution needed to override the + standard `stderr` symbol via the preprocessor. This in turn didn't play + well with unity builds and caused curl tool to crash or stay silent due + to an uninitialized stderr. This was a hard to find issue, fixed by + manually breaking out one file from the unity sources. + + To avoid two these two tricks, this patch implements a different + solution: Restore using our own local variable for our stderr output and + leave `stderr` as-is. To avoid using `stderr` by mistake, add a + `checksrc` rule (based on logic we already used in lib for `strerror`) + that detects any `stderr` use in `src` and points to using our own + variable instead: `tool_stderr`. + + Follow-up to 06133d3e9b8aeb9e9ca0b3370c246bdfbfc8619e + Follow-up to 2f17a9b654121dd1ecf4fc043c6d08a9da3522db + + Closes #11958 + +Loïc Yhuel (28 Sep 2023) + +- connect: only start the happy eyeballs timer when needed + + The timeout is only used when there is a second address family, for the + delayed eyeballer. + + Closes #11939 + +Daniel Stenberg (28 Sep 2023) + +- tool_operate: free 'gateway' correctly + + Pointed out by Coverity. The fix in 93885cf3a8d4e was incomplete. + + Also removed repeated wording in IPFS related error messages. + + Closes #11969 + +Stefan Eissing (28 Sep 2023) + +- lib: move handling of `data->req.writer_stack` into Curl_client_write() + + - move definitions from content_encoding.h to sendf.h + - move create/cleanup/add code into sendf.c + - installed content_encoding writers will always be called + on Curl_client_write(CLIENTWRITE_BODY) + - Curl_client_cleanup() frees writers and tempbuffers from + paused transfers, irregardless of protocol + + Closes #11908 + +Loïc Yhuel (28 Sep 2023) + +- multi: round the timeout up to prevent early wakeups + + Curl_timediff rounds down to the millisecond, so curl_multi_perform can + be called too early, then we get a timeout of 0 and call it again. + + The code already handled the case of timeouts which expired less than + 1ms in the future. By rounding up, we make sure we will never ask the + platform to wake up too early. + + Closes #11938 + +Daniel Stenberg (28 Sep 2023) + +- RELEASE-NOTES: spell out that IPFS is via gateway + +- RELEASE-NOTES: synced + +- tool_operate: avoid strlen() -1 on zero length content from file + + Follow-up to 65b563a96a226649ba12cb1e + + Closes #11959 + +- tool_operate: fix memory mixups + + Switch to plain getenv() from curl_getenv() to avoid the allocation and + having to keep track of which free() or curl_free() that need to be + used. + + Coverity found issues and a memory leak. + + Follow-up to 65b563a96a226649ba12cb1e + + Closes #11959 + +Viktor Szakats (27 Sep 2023) + +- curl-functions.m4: fixup recent bad edits + + Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 + + Closes #11966 + +Daniel Stenberg (27 Sep 2023) + +- curl-functions.m4: fix include line + + This made the getaddrinfo detection fail, but we did not spot it in the + CI because it graciously falled back to using legacy functions instead! + + Follow-up to 96c29900bcec (#11940) + + Closes #11965 + +- inet_ntop: add typecast to silence Coverity + + CID 1024653: Integer handling issues (SIGN_EXTENSION) + + Suspicious implicit sign extension: "src[i]" with type "unsigned char + const" (8 bits, unsigned) is promoted in "src[i] << (1 - i % 2 << 3)" to + type "int" (32 bits, signed), then sign-extended to type "unsigned long" + (64 bits, unsigned). If "src[i] << (1 - i % 2 << 3)" is greater than + 0x7FFFFFFF, the upper bits of the result will all be 1. + + 111 words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); + + The value will not be greater than 0x7FFFFFFF so this still cannot + happen. + + Also, switch to ints here instead of longs. The values stored are 16 bit + so at least no need to use 64 bit variables. Also, longs are 32 bit on + some platforms so this logic still needs to work with 32 bits. + + Closes #11960 + +- docs: adapt SEE ALSO sections to new requirements + + To please manpage-syntax.pl used by test 1173 + + Closes #11957 + +- manpage-syntax.pl: verify SEE ALSO syntax + + - Enforce a single reference per .BR line + - Skip the quotes around the section number for example (3) + - Insist on trailing commas on all lines except the last + - Error on comma on the last SEE ALSO entry + + - List the entries alpha-sorted, not enforced just recommended + + Closes #11957 + +- connect: expire the timeout when trying next + + ... so that it gets called again immediately and can continue trying + addresses to connect to. Otherwise it might unnecessarily wait for a + while there. + + Fixes #11920 + Reported-by: Loïc Yhuel + Closes #11935 + +- http: remove wrong comment for http_should_fail + + Reported-by: Christian Schmitz + Ref: #11936 + Closes #11941 + +Dan Fandrich (26 Sep 2023) + +- tool_setopt: remove unused function tool_setopt_flags + + This function is identical to tool_setopt_bitmask except that it treats + the argument as unsigned. + + Closes #11943 + +Viktor Szakats (26 Sep 2023) + +- cmake: add feature checks for `memrchr` and `getifaddrs` + + - `HAVE_MEMRCHR` for `memrchr`. + - `HAVE_GETIFADDRS` for `getifaddrs`. + This was present in `lib/curl_config.h.cmake` but missed the detection + logic. + + To match existing autotools feature checks. + + Closes #11954 + +- cmake: move global headers to specific checks + + Before this patch we added standard headers unconditionally to the + global list of headers used for feature checks. This is unnecessary + and also doesn't help CMake 'Generate' performance. This patch moves + these headers to each feature check where they are actually needed. + Stop using `stddef.h`, as it seems unnecessary. + + I've used autotools' `m4/curl-functions.m4` to figure out these + dependencies. + + Also delete checking for the C89 standard header `time.h`, that I + missed in the earlier commit. + + Ref: 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 + + Closes #11951 + +- src/mkhelp: make generated code pass `checksrc` + + Closes #11955 + +- tests: show which curl tool `runtests.pl` is using + + To help debugging when there is issue finding or running it. + + Closes #11953 + +- CI/azure: make `MAKEFLAGS` global to parallelize all jobs + + https://dev.azure.com/daniel0244/curl/_build/results?buildId=17528 (before) + https://dev.azure.com/daniel0244/curl/_build/results?buildId=17545 (after, wi + th -j3) + + Closes #11952 + +- CI/azure: migrate old mingw MSYS1 jobs to MSYS2 + + Also delete an accidental variable reference. + + Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72 + + Closes #11945 + +Daniel Stenberg (26 Sep 2023) + +- docs: add see also curl_multi_get_handles to some man pages + + Assisted-by: Jay Satiro + + Closes #11942 + +Viktor Szakats (26 Sep 2023) + +- cmake: assume `_fseeki64` and no `fseeko` on Windows + + `_fseeki64` is present in mingw-w64 1.0 (2011-09-26) headers, and + at least Watcom C 1.9 (2010) headers and MSVS 2008 [1]. + + `fseeko` is not present in any of these. + + (mingw-w64 1.0 also offers `fseeko64`.) + + [1] https://github.com/curl/curl/pull/11944#issuecomment-1734995004 + + Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918 + + Closes #11950 + +- build: delete checks for C89 standard headers + + Delete checks and guards for standard C89 headers and assume these are + available: `stdio.h`, `string.h`, `time.h`, `setjmp.h`, `stdlib.h`, + `stddef.h`, `signal.h`. + + Some of these we already used unconditionally, some others we only used + for feature checks. + + Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918 (for `stdio.h` i + n CMake) + + Closes #11940 + +Stefan Eissing (26 Sep 2023) + +- multiif.h: remove Curl_multi_dump declaration + + Follow-up to d850eea2 which removed the Curl_multi_dump definition. + + Closes https://github.com/curl/curl/pull/11946 + +Jay Satiro (26 Sep 2023) + +- config-win32: define HAVE__FSEEKI64 + + Follow-up to 9c7165e9 which added an fseeko wrapper to the lib that + calls _fseeki64 if it is available. + + Closes https://github.com/curl/curl/pull/11944 + +- docs: explain how PINNEDPUBLICKEY is independent of VERIFYPEER + + - Explain that peer verification via CURLOPT_PINNEDPUBLICKEY takes place + even if peer verification via CURLOPT_SSL_VERIFYPEER is turned off. + + The behavior is verified by test2048. + + Bug: https://github.com/curl/curl/issues/2935#issuecomment-418371872 + Reported-by: claudiusaiz@users.noreply.github.com + + Bug: https://github.com/curl/curl/discussions/11910 + Reported-by: Hakan Sunay Halil + + Closes https://github.com/curl/curl/pull/11930 + +Stefan Eissing (26 Sep 2023) + +- openssl: improve ssl shutdown handling + + - If SSL shutdown is not finished then make an additional call to + SSL_read to gather additional tracing. + + - Fix http2 and h2-proxy filters to forward do_close() calls to the next + filter. + + For example h2 and SSL shutdown before and after this change: + + Before: + + Curl_conn_close -> cf_hc_close -> Curl_conn_cf_discard_chain -> + ssl_cf_destroy + + After: + + Curl_conn_close -> cf_hc_close -> cf_h2_close -> cf_setup_close -> + ssl_cf_close + + Note that currently the tracing does not show output on the connection + closure handle. Refer to discussion in #11878. + + Ref: https://github.com/curl/curl/discussions/11878 + + Closes https://github.com/curl/curl/pull/11858 + +Loïc Yhuel (26 Sep 2023) + +- multi: fix small timeouts + + Since Curl_timediff rounds down to the millisecond, timeouts which + expire in less than 1ms are considered as outdated and removed from the + list. We can use Curl_timediff_us instead, big timeouts could saturate + but this is not an issue. + + Closes #11937 + +Viktor Szakats (25 Sep 2023) + +- cmake: fix stderr initialization in unity builds + + Before this patch, in certain build configurations the curl tool may + not have displayed anything (debug, macOS), or crashed at startup + (debug, Windows). + + Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 + Necessary after 2f17a9b654121dd1ecf4fc043c6d08a9da3522db + + Closes #11929 + +- cmake: fix missing `zlib.h` when compiling `libcurltool` + + Came up while testing debug/testing build for Windows. I'm not sure why + it didn't come up in earlier tests with similar config. + `tool_hugehelp.c` might indeed require `zlib.h` and without linking + `CURL_LIBS` to the `curltool` target, CMake doesn't seem to add detected + dependency headers to the compiler command. + + ``` + [ 25%] Building C object src/CMakeFiles/curltool.dir/tool_hugehelp.c.obj + cd .../curl/bld-cmake-llvm-x64/src && /usr/local/opt/llvm/bin/clang + --target=x86_64-w64-mingw32 --sysroot=/usr/local/opt/mingw-w64/toolchain-x8 + 6_64 + -DCURLDEBUG -DCURL_STATICLIB -DHAVE_CONFIG_H -DUNICODE -DUNITTESTS -D_UNICO + DE + -I.../curl/include -I.../curl/lib -I.../curl/bld-cmake-llvm-x64/lib + -I.../curl/bld-cmake-llvm-x64/include -I.../curl/src -Wno-unused-command-li + ne-argument + -D_UCRT -DDEBUGBUILD -DHAS_ALPN -DUSE_MANUAL=1 -fuse-ld=lld -Wl,-s -static + -libgcc + -lucrt [...] -O3 -DNDEBUG -municode -MD + -MT src/CMakeFiles/curltool.dir/tool_hugehelp.c.obj + -MF CMakeFiles/curltool.dir/tool_hugehelp.c.obj.d + -o CMakeFiles/curltool.dir/tool_hugehelp.c.obj -c .../curl/bld-cmake-llvm-x + 64/src/tool_hugehelp.c + .../curl/bld-cmake-llvm-x64/src/tool_hugehelp.c:6:10: fatal error: 'zlib.h' f + ile not found + 6 | #include + | ^~~~~~~~ + ``` + + Follow-up to 39e7c22bb459c2e818f079984989a26a09741860 + + Closes #11927 + +- cmake: fix duplicate symbols when linking tests + + The linker resolves this automatically in non-unity builds. In unity + builds the linker cannot drop a single object with the duplicates, + resulting in these errors. The root issue is that we started including + certain objects both via both libcurlu and libcurltool libs. + + Regression from 39e7c22bb459c2e818f079984989a26a09741860 + + Windows errors: + ``` + [ 3%] Linking C executable unit1303.exe + [ 3%] Building C object tests/server/CMakeFiles/rtspd.dir/__/__/lib/curl_mul + tibyte.c.obj + ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_convert_UTF8_to_wch + ar': + C:/projects/curl/lib/curl_multibyte.c:44: multiple definition of `curlx_conve + rt_UTF8_to_wchar' + ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte. + c:44: first defined here + ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_convert_wchar_to_UT + F8': + C:/projects/curl/lib/curl_multibyte.c:66: multiple definition of `curlx_conve + rt_wchar_to_UTF8' + ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte. + c:66: first defined here + ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_win32_open': + C:/projects/curl/lib/curl_multibyte.c:92: multiple definition of `curlx_win32 + _open' + ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte. + c:92: first defined here + ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_win32_fopen': + C:/projects/curl/lib/curl_multibyte.c:120: multiple definition of `curlx_win3 + 2_fopen' + ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte. + c:120: first defined here + ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_win32_stat': + [...] + ``` + Ref: https://ci.appveyor.com/project/curlorg/curl/builds/48110107/job/nvlhpt9 + aa4ehny5q#L247 + + macOS errors: + ``` + [ 56%] Linking C executable unit1302 + duplicate symbol '_curlx_sotouz' in: + ../../lib/libcurlu.a(unity_0_c.c.o) + ../../src/libcurltool.a(unity_0_c.c.o) + duplicate symbol '_curlx_sitouz' in: + ../../lib/libcurlu.a(unity_0_c.c.o) + ../../src/libcurltool.a(unity_0_c.c.o) + duplicate symbol '_curlx_uztosz' in: + ../../lib/libcurlu.a(unity_0_c.c.o) + ../../src/libcurltool.a(unity_0_c.c.o) + [...] + ``` + with config: + ``` + -DCMAKE_UNITY_BUILD=ON \ + -DENABLE_DEBUG=ON -DBUILD_TESTING=ON -DCMAKE_C_FLAGS=-DDEBUGBUILD \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_STATIC_LIBS=OFF + ``` + + Closes #11926 + +- cmake: lib `CURL_STATICLIB` fixes (Windows) + + - always define `CURL_STATICLIB` when building libcurl for Windows. + + This disables `__declspec(dllexport)` for exported libcurl symbols. + In normal mode (hide symbols) these exported symbols are specified + via `libcurl.def`. When not hiding symbols, all symbols are exported + by default. + + Regression from 1199308dbc902c52be67fc805c72dd2582520d30 + + Fixes #11844 + + - fix to omit `libcurl.def` when not hiding private symbols. + + Regression from 2ebc74c36a19a1700af394c16855ce144d9878e3 + + - fix `ENABLED_DEBUG=ON` + shared curl tool Windows builds by also + omitting `libcurl.def` in this case, and exporting all symbols + instead. This ensures that a shared curl tool can access all debug + functions which are not normally exported from libcurl DLL. + + - delete `INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"` for "objects" + target. + + Follow-up to 2ebc74c36a19a1700af394c16855ce144d9878e3 + + - delete duplicate `BUILDING_LIBCURL` definitions. + + - fix `HIDES_CURL_PRIVATE_SYMBOLS` to not overwrite earlier build settings. + + Follow-up to 1199308dbc902c52be67fc805c72dd2582520d30 + + Closes #11914 + +Daniel Stenberg (25 Sep 2023) + +- RELEASE-NOTES: synced + +Dan Fandrich (25 Sep 2023) + +- tests: fix log directory path in IPFS tests + + Hard-coding the log directory name fails with parallel tests. + + Follow-up to 65b563a96 + + Ref: #8805 + +Daniel Stenberg (25 Sep 2023) + +- curl_multi_get_handles: get easy handles from a multi handle + + Closes #11750 + +Stefan Eissing (25 Sep 2023) + +- http: h1/h2 proxy unification + + - use shared code for setting up the CONNECT request + when tunneling, used in HTTP/1.x and HTTP/2 proxying + - eliminate use of Curl_buffer_send() and other manipulations + of `data->req` or `data->state.ulbuf` + + Closes #11808 + +Natanael Copa (25 Sep 2023) + +- lib: use wrapper for curl_mime_data fseek callback + + fseek uses long offset which does not match with curl_off_t. This leads + to undefined behavior when calling the callback and caused failure on + arm 32 bit. + + Use a wrapper to solve this and use fseeko which uses off_t instead of + long. + + Thanks to the nice people at Libera IRC #musl for helping finding this + out. + + Fixes #11882 + Fixes #11900 + Closes #11918 + +- configure: sort AC_CHECK_FUNCS + + No functional changes. + +Daniel Stenberg (25 Sep 2023) + +- warnless: remove unused functions + + Previously put there for use with the intel compiler + + Closes #11932 + +- GHA/linux: run singleuse to detect single-use global functions + + Use --unit for configure --enable-debug builds + + Closes #11932 + +- singleuse: add scan for use in other source codes + + This should reduce false-positive to almost zero. Checks for presence in + unit tests if --unit is specified, which is intended for debug builds + where unit testing is enabled. + + Closes #11932 + +- multi: remove Curl_multi_dump + + A debug-only function that is basically never used. Removed to ease the + use of the singleuse script to detect non-static functions not used + outside the file where it is defined. + + Closes #11931 + +Viktor Szakats (24 Sep 2023) + +- tests: fix compiler warnings + + Seen with llvm 17 on Windows x64. + + ``` + .../curl/tests/server/rtspd.c:136:13: warning: no previous extern declaration + for non-static variable 'logdir' [-Wmissing-variable-declarations] + 136 | const char *logdir = "log"; + | ^ + .../curl/tests/server/rtspd.c:136:7: note: declare 'static' if the variable i + s not intended to be used outside of this translation unit + 136 | const char *logdir = "log"; + | ^ + .../curl/tests/server/rtspd.c:137:6: warning: no previous extern declaration + for non-static variable 'loglockfile' [-Wmissing-variable-declarations] + 137 | char loglockfile[256]; + | ^ + .../curl/tests/server/rtspd.c:137:1: note: declare 'static' if the variable i + s not intended to be used outside of this translation unit + 137 | char loglockfile[256]; + | ^ + .../curl/tests/server/fake_ntlm.c:43:13: warning: no previous extern declarat + ion for non-static variable 'logdir' [-Wmissing-variable-declarations] + 43 | const char *logdir = "log"; + | ^ + .../curl/tests/server/fake_ntlm.c:43:7: note: declare 'static' if the variabl + e is not intended to be used outside of this translation unit + 43 | const char *logdir = "log"; + | ^ + .../curl/src/tool_doswin.c:350:8: warning: possible misuse of comma operator + here [-Wcomma] + 350 | ++d, ++s; + | ^ + .../curl/src/tool_doswin.c:350:5: note: cast expression to void to silence wa + rning + 350 | ++d, ++s; + | ^~~ + | (void)( ) + ``` + + ``` + .../curl/tests/libtest/lib540.c:146:27: warning: result of comparison 'long' + > 2147483647 is always false [-Wtautological-type-limit-compare] + 146 | int itimeout = (L > (long)INT_MAX) ? INT_MAX : (int)L; + | ~ ^ ~~~~~~~~~~~~~ + 1 warning generated. + + .../curl/tests/libtest/libntlmconnect.c:195:31: warning: result of comparison + 'long' > 2147483647 is always false [-Wtautological-type-limit-compare] + 195 | int itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeo + ut; + | ~~~~~~~ ^ ~~~~~~~~~~~~~ + 1 warning generated. + + .../curl/tests/libtest/lib591.c:117:31: warning: result of comparison 'long' + > 2147483647 is always false [-Wtautological-type-limit-compare] + 117 | int itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeo + ut; + | ~~~~~~~ ^ ~~~~~~~~~~~~~ + 1 warning generated. + .../curl/tests/libtest/lib597.c:99:31: warning: result of comparison 'long' > + 2147483647 is always false [-Wtautological-type-limit-compare] + 99 | int itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeo + ut; + | ~~~~~~~ ^ ~~~~~~~~~~~~~ + 1 warning generated. + ``` + + Seen on macOS Intel: + ``` + .../curl/tests/server/sws.c:440:64: warning: field precision should have type + 'int', but argument has type 'size_t' (aka 'unsigned long') [-Wformat] + msnprintf(logbuf, sizeof(logbuf), "Got request: %s %.*s HTTP/%d.%d" + , + ~~^~ + 1 warning generated. + ``` + + Closes #11925 + +Jay Satiro (24 Sep 2023) + +- url: fix netrc info message + + - Fix netrc info message to use the generic ".netrc" filename if the + user did not specify a netrc location. + + - Update --netrc doc to add that recent versions of curl on Windows + prefer .netrc over _netrc. + + Before: + * Couldn't find host google.com in the (nil) file; using defaults + + After: + * Couldn't find host google.com in the .netrc file; using defaults + + Closes https://github.com/curl/curl/pull/11904 + +Dan Fandrich (23 Sep 2023) + +- wolfssh: do cleanup in Curl_ssh_cleanup + + Closes: #11921 + +Daniel Stenberg (24 Sep 2023) + +- tool_listhelp: regenerated + + Polished the --ipfs-gateway description + + Fixed the --trace-config description + + The script also fixed some other small mistakes + + Closes #11923 + +Viktor Szakats (23 Sep 2023) + +- Makefile.mk: always set `CURL_STATICLIB` for lib (Windows) + + Also fix to export all symbols in Windows debug builds, making + `-debug-dyn` builds work with `-DCURL_STATICLIB` set. + + Ref: https://github.com/curl/curl/pull/11914 (same for CMake) + + Closes #11924 + +Daniel Stenberg (23 Sep 2023) + +- quic: set ciphers/curves the same way regular TLS does + + for OpenSSL/BoringSSL + + Fixes #11796 + Reported-by: Karthikdasari0423 on github + Assisted-by: Jay Satiro + Closes #11836 + +- test457: verify --max-filesize with chunked encoding + +- lib: let the max filesize option stop too big transfers too + + Previously it would only stop them from getting started if the size is + known to be too big then. + + Update the libcurl and curl docs accordingly. + + Fixes #11810 + Reported-by: Elliot Killick + Assisted-by: Jay Satiro + Closes #11820 + +Viktor Szakats (23 Sep 2023) + +- mingw: delete support for legacy mingw.org toolchain + + Drop support for "old" / "legacy" / "classic" / "v1" / "mingw32" MinGW: + https://en.wikipedia.org/wiki/MinGW, https://osdn.net/projects/mingw/ + Its homepage used to be http://mingw.org/ [no HTTPS], and broken now. + It supported the x86 CPU only and used a old Windows API header and + implib set, often causing issues. It also misses most modern Windows + features, offering old versions of both binutils and gcc (no llvm/clang + support). It was last updated 2 years ago. + + curl now relies on toolchains based on the mingw-w64 project: + https://www.mingw-w64.org/ https://sourceforge.net/projects/mingw-w64/ + https://www.msys2.org/ https://github.com/msys2/msys2 + https://github.com/mstorsjo/llvm-mingw + (Also available via Linux and macOS package managers.) + + Closes #11625 + +Mark Gaiser (23 Sep 2023) + +- curl: add support for the IPFS protocols: + + - ipfs:// + - ipns:// + + This allows you tu use ipfs in curl like: + curl ipfs:// + and + curl ipns:// + + For more information consult the readme at: + https://curl.se/docs/ipfs.html + + Closes #8805 + +Daniel Stenberg (23 Sep 2023) + +- bufq: remove Curl_bufq_skip_and_shift (unused) + + Closes #11915 + +- scripts/singleuse.pl: add curl_global_trace + +Viktor Szakats (22 Sep 2023) + +- cmake: fix unity symbol collisions in h2 builds + + Regression from 331b89a319d0067fa1e6441719307cfef9c7960f + + Reviewed-by: Daniel Stenberg + Reviewed-by: Jay Satiro + Closes #11912 + +Daniel Stenberg (22 Sep 2023) + +- RELEASE-NOTES: synced + +Dan Fandrich (21 Sep 2023) + +- github/labeler: improve the match patterns + + This includes new rules for setting the appleOS and logging labels and + matches on some example files. Also, enable dot mode for wildcard + matches in the .github directory. + +Daniel Stenberg (21 Sep 2023) + +- upload-file.d: describe the file name slash/backslash handling + + Closes #11911 + +Jakub Jelen (21 Sep 2023) + +- libssh: cap SFTP packet size sent + + Due to libssh limitations + + Signed-off-by: Jakub Jelen + + Closes #11804 + +Daniel Stenberg (21 Sep 2023) + +- curl.h: mark CURLSSLBACKEND_NSS as deprecated since 8.3.0 + + Closes #11905 + +- mailmap: unify Michael Osipov under a single email + +Ted Lyngmo (21 Sep 2023) + +- docs: use CURLSSLBACKEND_NONE + + [ssl] use CURLSSLBACKEND_NONE instead of (curl_sslbackend)-1 in + documentation and examples. + + Signed-off-by: Ted Lyngmo + + Closes #11909 + +Dan Fandrich (21 Sep 2023) + +- github/labeler: give the sync-labels config item a default value + + This shouldn't be necessary and is likely a bug with this beta version + of the labeller. + + Also, fix the negative matches for the documentation label. + + Follow-up to dd12b452a + Closes #11907 + +- github/labeler: fix up more the labeler config format + + The new version didn't like the workaround we had for a bug in the + previous labeler version, and it should no longer be needed. + + Follow-up to dd12b452a + Closes #11906 + +- github/labeler: fix indenting to try to appease labeller + + Follow-up to dd12b452a + +Jay Satiro (21 Sep 2023) + +- libssh2: fix error message on failed pubkey-from-file + + - If libssh2_userauth_publickey_fromfile_ex returns -1 then show error + message "SSH public key authentication failed: Reason unknown (-1)". + + When libssh2_userauth_publickey_fromfile_ex returns -1 it does so as a + generic error and therefore doesn't set an error message. AFAICT that is + not documented behavior. + + Prior to this change libcurl retrieved the last set error message which + would be from a previous function failing. That resulted in misleading + auth failed error messages in verbose mode. + + Bug: https://github.com/curl/curl/issues/11837#issue-1891827355 + Reported-by: consulion@users.noreply.github.com + + Closes https://github.com/curl/curl/pull/11881 + +Stefan Eissing (21 Sep 2023) + +- pytest: exclude test_03_goaway in CI runs due to timing dependency + + Closes #11860 + +- lib: disambiguate Curl_client_write flag semantics + + - use CLIENTWRITE_BODY *only* when data is actually body data + - add CLIENTWRITE_INFO for meta data that is *not* a HEADER + - debug assertions that BODY/INFO/HEADER is not used mixed + - move `data->set.include_header` check into Curl_client_write + so protocol handlers no longer have to care + - add special in FTP for `data->set.include_header` for historic, + backward compatible reasons + - move unpausing of client writes from easy.c to sendf.c, so that + code is in one place and can forward flags correctly + + Closes #11885 + +Patrick Monnerat (21 Sep 2023) + +- tftpd: always use curl's own tftp.h + + Using the system's provided arpa/tftp.h and optimizing, GCC 12 detects + and reports a stringop-overread warning: + + tftpd.c: In function ‘write_behind.isra’: + tftpd.c:485:12: warning: ‘write’ reading between 1 and 2147483647 bytes f + rom a region of size 0 [-Wstringop-overread] + 485 | return write(test->ofile, writebuf, count); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + In file included from tftpd.c:71: + /usr/include/arpa/tftp.h:58:30: note: source object ‘tu_data’ of size 0 + 58 | char tu_data[0]; /* data or error stri + ng */ + | ^~~~~~~ + + This occurs because writebuf points to this field and the latter + cannot be considered as being of dynamic length because it is not + the last field in the structure. Thus it is bound to its declared + size. + + This commit always uses curl's own version of tftp.h where the + target field is last in its structure, effectively avoiding the + warning. + + As HAVE_ARPA_TFTP_H is not used anymore, cmake/configure checks for + arpa/tftp.h are removed. + + Closes #11897 + +Dan Fandrich (20 Sep 2023) + +- test1474: make precheck more robust on non-Solaris systems + + If uname -r returns something odd, perl could return an error code and + the test would be erroneously skipped. The qx// syntax avoid this. + + Followup to 08f9b2148 + +- github/labeler: switch to the 5 beta version + + This version adds an important feature that will allow more PRs to be + labelled. Rather than being limited to labeling PRs with files that + match a single glob, it can now label them if multiple changed files + match any one of a number of globs. + +Daniel Stenberg (20 Sep 2023) + +- lib: enable hmac for digest as well + + Previously a build that disabled NTLM and aws-sigv4 would fail to build + since the hmac was disabled, but it is also needed for digest auth. + + Follow-up to e92edfbef64448ef + + Fixes #11890 + Reported-by: Aleksander Mazur + Closes #11896 + +- idn: if idn2_check_version returns NULL, return error + + ... this avoids a NULL dereference for this unusual case. + + Reported-by: s0urc3_ on hackerone + Closes #11898 + +- http: fix CURL_DISABLE_BEARER_AUTH breakage + + When bearer auth was disabled, the if/else logic got wrong and caused + problems. + + Follow-up to e92edfbef64448ef461 + Fixes #11892 + Reported-by: Aleksander Mazur + Closes #11895 + +Michael Osipov (20 Sep 2023) + +- wolfssl: allow capath with CURLOPT_CAINFO_BLOB + + Remain consistent with OpenSSL. While CAfile is nulled as documented + with CURLOPT_CAINFO_BLOB, CApath remains intact. + + Closes #11886 + +- wolfssl: use ssl_cafile/ssl_capath variables consistent with openssl.c + + Closes #11886 + +Dan Fandrich (19 Sep 2023) + +- test1474: disable test on NetBSD, OpenBSD and Solaris 10 + + These kernels only send a fraction of the requested amount of the first + large block, invalidating the assumptions of the test and causing it to + fail. + + Assisted-by: Christian Weisgerber + Ref: https://curl.se/mail/lib-2023-09/0021.html + Closes #11888 + +Ryan Schmidt (20 Sep 2023) + +- cmake, configure: also link with CoreServices + + When linking with CoreFoundation, also link with CoreServices which is + apparently required to avoid an NSInvalidArgumentException in software + linking with libcurl on macOS Sonoma 14 and later. + + Fixes #11893 + Closes #11894 + +Marc Hoersken (19 Sep 2023) + +- CI/azure: remove pip, wheel, cryptography, pyopenssl and impacket + + These dependencies are now already included in the Docker image. + + Ref: https://github.com/mback2k/curl-docker-winbuildenv/commit/2607a31bcab544 + b41d15606e97f38cf312c1ce56 + + Closes #11889 + +Daniel Stenberg (19 Sep 2023) + +- wolfssl: if CURLOPT_CAINFO_BLOB is set, ignore the CA files + + Ref: #11883 + Reported-by: Michael Osipov + Closes #11884 + +- RELEASE-NOTES: synced + +- test3103: CURLOPT_COOKIELIST test + +- cookie: set ->running in cookie_init even if data is NULL + + This is a regression introduced in b1b326ec500 (shipped in curl 8.1.0) + + Test 3103 verifies. + + Fixes #11875 + Reported-by: wangp on github + Closes #11876 + +- test498: total header size for all redirects is larger than accepted + +- http: use per-request counter to check too large headers + + Not the counter that accumulates all headers over all redirects. + + Follow-up to 3ee79c1674fd6 + + Do a second check for 20 times the limit for the accumulated size for + all headers. + + Fixes #11871 + Reported-by: Joshix-1 on github + Closes #11872 + +Jay Satiro (18 Sep 2023) + +- THANKS: add Eric Murphy + + He reported #11850 (quiche build error) but I forgot to add a + 'reported-by' entry in the fix 267e14f1. + +Daniel Stenberg (18 Sep 2023) + +- h2-proxy: remove left-over mistake in drain_tunnel() + + Left-over from 331b89a319 + + Reported-by: å—å®«é›ªçŠ + + Closes https://github.com/curl/curl/pull/11877 + +vvb2060 (18 Sep 2023) + +- lib: failf/infof compiler warnings + + Closes #11874 + +Daniel Stenberg (17 Sep 2023) + +- rand: fix 'alnum': array is too small to include a terminating null character + + It was that small on purpose, but this change now adds the null byte to + avoid the error. + + Follow-up to 3aa3cc9b052353b1 + + Reported-by: Dan Fandrich + Ref: #11838 + Closes #11870 + +Mathias Fuchs (16 Sep 2023) + +- cmake: fix the help text to the static build option in CMakeLists.txt + + Closes #11843 + +John Haugabook (16 Sep 2023) + +- MANUAL.md: change domain to example.com + + Closes #11866 + +Daniel Stenberg (16 Sep 2023) + +- doh: inherit DEBUGFUNCTION/DATA + + When creating new transfers for doing DoH, they now inherit the debug + settings from the initiating transfer, so that the application can + redirect and handle the verbose output correctly even for the DoH + transfers. + + Reported-by: calvin2021y on github + Fixes #11864 + Closes #11869 + +Dan Fandrich (16 Sep 2023) + +- http_aws_sigv4: fix sorting with empty parts + + When comparing with an empty part, the non-empty one is always + considered greater-than. Previously, the two would be considered equal + which would randomly place empty parts amongst non-empty ones. This + showed as a test 439 failure on Solaris as it uses a different + implementation of qsort() that compares parts differently. + + Fixes #11855 + Closes #11868 + +- CI: ignore the "flaky" and "timing-dependent" test results + + CI builds will now run these tests, but will ignore the results if they + fail. The relevant tests are ones that are sensitive to timing or + have edge conditions that make them more likely to fail on CI servers, + which are often heavily overloaded and slow. + + This change only adds two additional tests to be ignored, since the + others already had the flaky keyword. + + Closes #11865 + +- runtests: eliminate a warning on old perl versions + + The warning "Use of implicit split to @_ is deprecated" showed between + perl versions about 5.8 through 5.11. + +- tests: log the test result code after each libtest + + This makes it easier to determine the test status. Also, capitalize + FAILURE and ABORT messages in log lines to make them easier to spot. + +Harry Sintonen (16 Sep 2023) + +- misc: better random strings + + Generate alphanumerical random strings. + + Prior this change curl used to create random hex strings. This was + mostly okay, but having alphanumerical random strings is better: The + strings have more entropy in the same space. + + The MIME multipart boundary used to be mere 64-bits of randomness due + to being 16 hex chars. With these changes the boundary is 22 + alphanumerical chars, or little over 130 bits of randomness. + + Closes #11838 + +Daniel Stenberg (15 Sep 2023) + +- cookie: reduce variable scope, add const + +- cookie: do not store the expire or max-age strings + + Convert it to an expire time at once and save memory. + + Closes #11862 + +- cookie: remove unnecessary struct fields + + Plus: reduce the hash table size from 256 to 63. It seems unlikely to + make much of a speed difference for most use cases but saves 1.5KB of + data per instance. + + Closes #11862 + +- RELEASE-NOTES: synced + + Bumped to 8.4.0, the next presumed version + +Dan Fandrich (14 Sep 2023) + +- test2600: remove special case handling for USE_ALARM_TIMEOUT + + This was originally added to handle platforms that supported only 1 + second granularity in connect timeouts, but after some recent changes + the test currently permafails on several Windows platforms. + + The need for this special-case was removed in commit 8627416, which + increased the connect timeout in all cases to well above 1 second. + + Fixes #11767 + Closes #11849 + +Daniel Stenberg (14 Sep 2023) + +- SECURITY-PROCESS.md. call it vulnerability disclosure policy + + SECURITY-PROCESS.md -> VULN-DISCLOSURE-POLICY.md + + This a name commonly used for a document like this. This name helps + users find it. + + Closes #11852 + +Junho Choi (14 Sep 2023) + +- quiche: fix build error with --with-ca-fallback + + - Fix build error when curl is built with --with-quiche + and --with-ca-fallback. + + - Add --with-ca-fallback to the quiche CI job. + + Fixes https://github.com/curl/curl/issues/11850 + Closes https://github.com/curl/curl/pull/11847 + +Jay Satiro (14 Sep 2023) + +- escape: replace Curl_isunreserved with ISUNRESERVED + + - Use the ALLCAPS version of the macro so that it is clear a macro is + being called that evaluates the variable multiple times. + + - Also capitalize macro isurlpuntcs => ISURLPUNTCS since it evaluates + a variable multiple times. + + This is a follow-up to 291d225a which changed Curl_isunreserved into an + alias macro for ISUNRESERVED. The problem is the former is not easily + identified as a macro by the caller, which could lead to a bug. + + For example, ISUNRESERVED(*foo++) is easily identifiable as wrong but + Curl_isunreserved(*foo++) is not even though they both are the same. + + Closes https://github.com/curl/curl/pull/11846 + +Dan Fandrich (13 Sep 2023) + +- tests: increase the default server logs lock timeout + + This timeout is used to wait for the server to finish writing its logs + before checking them against the expected values. An overloaded machine + could take more than the two seconds previously allocated, so increase + the timeout to 5 seconds. + + Ref: #11328 + Closes #11834 + +- tests: increase TEST_HANG_TIMEOUT in two tests + + These tests had a 5 second timeout compared to 60 seconds for all other + tests. Make these consistent with the others for more reliability on + heavily-loaded machines. + + Ref: #11328 + +- test1056: disable on Windows + + This test relies on the IPv6 scope field being ignored when connecting to + ipv6-localhost (i.e. [::1%259999] is treated as [::1]). Maybe this is a bit + dodgy, but it works on all our test platforms except Windows. This + test was disabled manually on all Windows CI builds already, so instead + add an incompatible feature and precheck so it's skipped on Windows + everywhere automatically. + +- test587: add a slight delay after test + + This test is designed to connect to the server, then immediately send a + few bytes and disconnect. In some situations, such as on a loaded + server, this doesn't give the server enough time to write its lock file + before its existence is checked. The test harness then fails to find the + server's input log file (because it hasn't been written yet) and fails + the test. By adding a short delay after the test, the HTTP server has + enough time to write its lock file which gives itself more time to write + its remaining files. + + Ref: #11328 + +- tests: stop overriding the lock timeout + + These tests reduce the server lock wait timeout which can increase + flakiness on loaded machines. Since this is merely an optimization, + eliminate them in favour of reliability. + + Ref: #11328 + +- tests: add some --expect100-timeout to reduce timing dependencies + + These tests can fail when the test machine is so slow that the test HTTP + server didn't get a chance to complete before the client's one second + 100-continue timeout triggered. Increase that 1 second to 999 seconds so + this situation doesn't happen. + + Ref: #11328 + +- test661: return from test early in case of curl error + +- tests: add the timing-dependent keyword on several tests + + These are ones likely to fail on heavily-loaded machines that alter the + normal test timing. Most of these tests already had the flaky keyword + since this condition makes them more likely to fail on CI. + +- test1592: greatly increase the maximum test timeout + + It was too short to be reliable on heavily loaded CI machines, and + as a fail-safe only, it didn't need to be short. + + Ref: #11328 + +- test: minor test cleanups + + Remove an obsolete block of code in tests 2032 & 576. + Add a comment in test 1474. + +- tests: quadruple the %FTPTIME2 and %FTPTIME3 timeouts + + This gives more of a margin for error when running on overloaded CI + servers. + + Ref: #11328 + +- tests: improve SLOWDOWN test reliability by reducing sent data + + These tests are run in SLOWDOWN mode which adds a 10 msec delay after + each character output, which means it takes at least 1.6 seconds (and + 320 kernel calls) just to get through the long welcome banner. On an + overloaded system, this can end up taking much more than 1.6 seconds, + and even more than the 7 or 16 second curl timeout that the tests rely + on, causing them to fail. Reducing the size of the welcome banner drops + the total number of characters sent before the transfer starts by more + than half, which reduces the opportunity for test-breaking slowdowns by + the same amount. + + Ref: #11328 + +- test650: fix an end tag typo + +Jay Satiro (13 Sep 2023) + +- tool_cb_wrt: fix debug assertion + + - Fix off-by-one out-of-bounds array index in Windows debug assertion. + + Bug: https://github.com/curl/curl/commit/af3f4e41#r127212213 + Reported-by: Gisle Vanem + +Daniel Stenberg (13 Sep 2023) + +- ctype: add ISUNRESERVED() + + ... and make Curl_isunreserved() use that macro instead of providing a + separate funtion for the purpose. + + Closes #11840 + +Version 8.3.0 (13 Sep 2023) + +Daniel Stenberg (13 Sep 2023) + +- RELEASE-NOTES: syn ced + + curl 8.3.0 release + +- THANKS: contributors from 8.3.0 + +Thorsten Klein (12 Sep 2023) + +- cmake: set SIZEOF_LONG_LONG in curl_config.h + + in order to support 32bit builds regarding wolfssl CTC_SETTINGS + + Closes #11839 + +Jay Satiro (12 Sep 2023) + +- curl_ngtcp2: fix error message + +- http_aws_sigv4: handle no-value user header entries + + - Handle user headers in format 'name:' and 'name;' with no value. + + The former is used when the user wants to remove an internal libcurl + header and the latter is used when the user actually wants to send a + no-value header in the format 'name:' (note the semi-colon is converted + by libcurl to a colon). + + Prior to this change the AWS header import code did not special case + either of those and the generated AWS SignedHeaders would be incorrect. + + Reported-by: apparentorder@users.noreply.github.com + + Ref: https://curl.se/docs/manpage.html#-H + + Fixes https://github.com/curl/curl/issues/11664 + Closes https://github.com/curl/curl/pull/11668 + +Dan Fandrich (11 Sep 2023) + +- CI: run pytest with the -v option + + This lists of the test cases being run so it can be tracked over time. + + Closes #11824 + +Daniel Stenberg (11 Sep 2023) + +- HTTP3: the msquic backend is not functional + + I ask that we do not submit bugs for this backend just yet as we know it + does not fully work. + + Closes #11831 + Closes #11819 + +- aws_sigv4: the query canon code miscounted URL encoded input + + Added some extra ampersands to test 439 to verify "blank" query parts + + Follow-up to fc76a24c53b08cdf + + Closes #11829 + +vvb2060 (11 Sep 2023) + +- quic: don't set SNI if hostname is an IP address + + We already do this for TLS connections. + + RFC 6066 says: Literal IPv4 and IPv6 addresses are not permitted in + "HostName". + + Ref: https://www.rfc-editor.org/rfc/rfc6066#section-3 + + Fixes https://github.com/curl/curl/issues/11827 + Closes https://github.com/curl/curl/pull/11828 + +Daniel Stenberg (10 Sep 2023) + +- RELEASE-NOTES: synced + +Benoit Pierre (10 Sep 2023) + +- configure: fix `HAVE_TIME_T_UNSIGNED` check + + The syntax was incorrect (need a proper main body), and the test + condition was wrong (resulting in a signed `time_t` detected as + unsigned). + + Closes #11825 + +Daniel Stenberg (9 Sep 2023) + +- THANKS-filter: pszlazak on github + +pszlazak (9 Sep 2023) + +- include.d: explain headers not printed with --fail before 7.75.0 + + Prior to 7.75.0 response headers were not printed if -f/--fail was used + and an error was reported by server. This was fixed in ab525c0 + (precedes 7.75.0). + + Closes #11822 + +Daniel Stenberg (8 Sep 2023) + +- http_aws_sigv4: skip the op if the query pair is zero bytes + + Follow-up to fc76a24c53b08cdf + + Spotted by OSS-Fuzz + + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=62175 + Closes #11823 + +- cmdline-docs: use present tense, not future + + + some smaller cleanups + + Closes #11821 + +- cmdline-docs: make sure to phrase it as "added in ...." + + References to things that were added or changed in a specific version + should be specified as "(added in [version]) for two reasons: + + 1 - consistency + + 2 - to allow gen.pl to strip them out if deemed referring to too old + versions + + Closes #11821 + +Jay Satiro (8 Sep 2023) + +- docs: mark --ssl-revoke-best-effort as Schannel specific + + Closes https://github.com/curl/curl/pull/11760 + +Nathan Moinvaziri (8 Sep 2023) + +- schannel: fix ordering of cert chain info + + - Use CERT_CONTEXT's pbCertEncoded to determine chain order. + + CERT_CONTEXT from SECPKG_ATTR_REMOTE_CERT_CONTEXT contains + end-entity/server certificate in pbCertEncoded. We can use this pointer + to determine the order of certificates when enumerating hCertStore using + CertEnumCertificatesInStore. + + This change is to help ensure that the ordering of the certificate chain + requested by the user via CURLINFO_CERTINFO has the same ordering on all + versions of Windows. + + Prior to this change Schannel certificate order was reversed in 8986df80 + but that was later reverted in f540a39b when it was discovered that + Windows 11 22H2 does the reversal on its own. + + Ref: https://github.com/curl/curl/issues/9706 + + Closes https://github.com/curl/curl/pull/11632 + +Chris Talbot (8 Sep 2023) + +- digest: Use hostname to generate spn instead of realm + + In https://www.rfc-editor.org/rfc/rfc2831#section-2.1.2 + + digest-uri-value should be serv-type "/" host , where host is: + + The DNS host name or IP address for the service requested. The + DNS host name must be the fully-qualified canonical name of the + host. The DNS host name is the preferred form; see notes on server + processing of the digest-uri. + + Realm may not be the host, so we must specify the host explicitly. + + Note this change only affects the non-SSPI digest code. The digest code + used by SSPI builds already uses the hostname to generate the spn. + + Ref: https://github.com/curl/curl/issues/11369 + + Closes https://github.com/curl/curl/pull/11395 + +Daniel Stenberg (7 Sep 2023) + +- docs: remove use of the word 'very' + + It is mostly superfluous. proselint would complain. + + Closes #11818 + +- curl_multi_remove_handle.3: clarify what happens with connection + + Closes #11817 + +- RELEASE-NOTES: synced + +- test439: verify query canonization for aws-sigv4 + +- tool_operate: make aws-sigv4 not require TLS to be used + + Maybe not used too often, but we want it for testing and it should work. + +- http_aws_sigv4: canonicalize the query + + Percent encoding needs to be done using uppercase, and most + non-alphanumerical must be percent-encoded. + + Fixes #11794 + Reported-by: John Walker + Closes #11806 + +Wyatt O'Day (7 Sep 2023) + +- lib: add ability to disable auths individually + + Both with configure and cmake + + Closes #11490 + +Stefan Eissing (7 Sep 2023) + +- ngtcp2: fix handling of large requests + + - requests >64K are send in parts to the filter + - fix parsing of the request to assemble it correctly + from several sends + - open a QUIC stream only when the complete request has + been collected + + Closes #11815 + +- openssl: when CURLOPT_SSL_CTX_FUNCTION is registered, init x509 store before + + - we delay loading the x509 store to shorten the handshake time. + However an application callback installed via CURLOPT_SSL_CTX_FUNCTION + may need to have the store loaded and try to manipulate it. + - load the x509 store before invoking the app callback + + Fixes #11800 + Reported-by: guoxinvmware on github + Cloes #11805 + +Daniel Stenberg (7 Sep 2023) + +- krb5: fix "implicit conversion loses integer precision" warnings + + conversions to/from enum and unsigned chars + + Closes #11814 + +Stefan Eissing (7 Sep 2023) + +- pytest: improvements + + - set CURL_CI for pytest runs in CI environments + - exclude timing sensitive tests from CI runs + - for failed results, list only the log and stat of + the failed transfer + + - fix type in http.c comment + + Closes #11812 + +- CI: move on to ngtcp2 v0.19.1 + + Closes #11809 + +Dan Fandrich (5 Sep 2023) + +- CI: run Circle macOS builds on x86 for now + + The ARM machines aren't ready for us and requesting them now causes + warnings e-mails to be sent to some PR pushers. + + Ref: #11771 + +Viktor Szakats (5 Sep 2023) + +- http3: adjust cast for ngtcp2 v0.19.0 + + ngtcp2 v0.19.0 made size of `ecn` member of `ngtcp2_pkt_info` + an `uint8_t` (was: `uint32_t`). Adjust our local cast accordingly. + + Fixes: + ``` + ./curl/lib/vquic/curl_ngtcp2.c:1912:12: warning: implicit conversion loses in + teger precision: 'uint32_t' (aka 'unsigned int') to 'uint8_t' (aka 'unsigned + char') [-Wimplicit-int-conversion] + pi.ecn = (uint32_t)ecn; + ~ ^~~~~~~~~~~~~ + ``` + + Also bump ngtcp2, nghttp3 and nghttp2 to their latest versions in our + docs and CI. + + Ref: https://github.com/ngtcp2/ngtcp2/commit/80447281bbc94af53f8aa7a4cfc19175 + 782894a3 + Ref: https://github.com/ngtcp2/ngtcp2/pull/877 + Closes #11798 + +Stefan Eissing (5 Sep 2023) + +- http: fix sending of large requests + + - refs #11342 where errors with git https interactions + were observed + - problem was caused by 1st sends of size larger than 64KB + which resulted in later retries of 64KB only + - limit sending of 1st block to 64KB + - adjust h2/h3 filters to cope with parsing the HTTP/1.1 + formatted request in chunks + + - introducing Curl_nwrite() as companion to Curl_write() + for the many cases where the sockindex is already known + + Fixes #11342 (again) + Closes #11803 + +- pytest: fix check for slow_network skips to only apply when intended + + Closes #11801 + +Daniel Stenberg (5 Sep 2023) + +- curl_url_get/set.3: add missing semicolon in SYNOPSIS + +- CURLOPT_URL.3: explain curl_url_set() uses the same parser + +- CURLOPT_URL.3: add two URL API calls in the see-also section + +Dan Fandrich (4 Sep 2023) + +- CI: add a 32-bit i686 Linux build + + This is done by cross-compiling under regular x86_64 Linux. Since the + kernel offers backwards compatibility, the binaries can be tested as + normal. + + Closes #11799 + +- tests: fix a type warning on 32-bit x86 + +Viktor Szakats (4 Sep 2023) + +- tests: delete stray `.orig` file + + Follow-up to 331b89a319d0067fa1e6441719307cfef9c7960f + Closes #11797 + +Daniel Stenberg (4 Sep 2023) + +- RELEASE-NOTES: synced + +Viktor Szakats (4 Sep 2023) + +- lib: silence compiler warning in inet_ntop6 + + ``` + ./curl/lib/inet_ntop.c:121:21: warning: possible misuse of comma operator her + e [-Wcomma] + cur.base = i, cur.len = 1; + ^ + ./curl/lib/inet_ntop.c:121:9: note: cast expression to void to silence warnin + g + cur.base = i, cur.len = 1; + ^~~~~~~~~~~~ + (void)( ) + ``` + + Closes #11790 + +Daniel Stenberg (4 Sep 2023) + +- transfer: also stop the sending on closed connection + + Previously this cleared the receiving bit only but in some cases it is + also still sending (like a request-body) when disconnected and neither + direction can continue then. + + Fixes #11769 + Reported-by: Oleg Jukovec + Closes #11795 + +John Bampton (4 Sep 2023) + +- docs: change `sub-domain` to `subdomain` + + https://en.wikipedia.org/wiki/Subdomain + + Closes #11793 + +Stefan Eissing (4 Sep 2023) + +- multi: more efficient pollfd count for poll + + - do not use separate pollfds for sockets that have POLLIN+POLLOUT + + Closes #11792 + +- http2: polish things around POST + + - added test cases for various code paths + - fixed handling of blocked write when stream had + been closed inbetween attempts + - re-enabled DEBUGASSERT on send with smaller data size + + - in debug builds, environment variables can be set to simulate a slow + network when sending data. cf-socket.c and vquic.c support + * CURL_DBG_SOCK_WBLOCK: percentage of send() calls that should be + answered with a EAGAIN. TCP/UNIX sockets. + This is chosen randomly. + * CURL_DBG_SOCK_WPARTIAL: percentage of data that shall be written + to the network. TCP/UNIX sockets. + Example: 80 means a send with 1000 bytes would only send 800 + This is applied to every send. + * CURL_DBG_QUIC_WBLOCK: percentage of send() calls that should be + answered with EAGAIN. QUIC only. + This is chosen randomly. + + Closes #11756 + +Daniel Stenberg (4 Sep 2023) + +- docs: add curl_global_trace to some SEE ALSO sections + + Closes #11791 + +- os400: fix checksrc nits + + Closes #11789 + +Nicholas Nethercote (3 Sep 2023) + +- hyper: remove `hyptransfer->endtask` + + `Curl_hyper_stream` needs to distinguish between two kinds of + `HYPER_TASK_EMPTY` tasks: (a) the `foreach` tasks it creates itself, and + (b) background tasks that hyper produces. It does this by recording the + address of any `foreach` task in `hyptransfer->endtask` before pushing + it into the executor, and then comparing that against the address of + tasks later polled out of the executor. + + This works right now, but there is no guarantee from hyper that the + addresses are stable. `hyper_executor_push` says "The executor takes + ownership of the task, which should not be accessed again unless + returned back to the user with `hyper_executor_poll`". That wording is a + bit ambiguous but with my Rust programmer's hat on I read it as meaning + the task returned with `hyper_executor_poll` may be conceptually the + same as a task that was pushed, but that there are no other guarantees + and comparing addresses is a bad idea. + + This commit instead uses `hyper_task_set_userdata` to mark the `foreach` + task with a `USERDATA_RESP_BODY` value which can then be checked for, + removing the need for `hyptransfer->endtask`. This makes the code look + more like that hyper C API examples, which use userdata for every task + and never look at task addresses. + + Closes #11779 + +Dave Cottlehuber (3 Sep 2023) + +- ws: fix spelling mistakes in examples and tests + + Closes #11784 + +Daniel Stenberg (3 Sep 2023) + +- tool_filetime: make -z work with file dates before 1970 + + Fixes #11785 + Reported-by: Harry Sintonen + Closes #11786 + +Dan Fandrich (1 Sep 2023) + +- build: fix portability of mancheck and checksrc targets + + At least FreeBSD preserves cwd across makefile lines, so rules + consisting of more than one "cd X; do_something" must be explicitly run + in a subshell to avoid this. This problem caused the Cirrus FreeBSD + build to fail when parallel make jobs were enabled. + +- CI: adjust labeler match patterns for new & obsolete files + +- configure: trust pkg-config when it's used for zlib + + The library flags retrieved from pkg-config were later thrown out and + harded-coded, which negates the whole reason to use pkg-config. + Also, previously, the assumption was made that --libs-only-l and + --libs-only-L are the full decomposition of --libs, which is untrue and + would not allow linking against a static zlib. The new approach is + better in that it uses --libs, although only if --libs-only-l returns + nothing. + + Bug: https://curl.se/mail/lib-2023-08/0081.html + Reported-by: Randall + Closes #11778 + +Stefan Eissing (1 Sep 2023) + +- CI/ngtcp2: clear wolfssl for when cache is ignored + + Closes #11783 + +Daniel Stenberg (1 Sep 2023) + +- RELEASE-NOTES: synced + +Nicholas Nethercote (1 Sep 2023) + +- hyper: fix a progress upload counter bug + + `Curl_pgrsSetUploadCounter` should be a passed a total count, not an + increment. + + This changes the failing diff for test 579 with hyper from this: + ``` + Progress callback called with UL 0 out of 0[LF] + -Progress callback called with UL 8 out of 0[LF] + -Progress callback called with UL 16 out of 0[LF] + -Progress callback called with UL 26 out of 0[LF] + -Progress callback called with UL 61 out of 0[LF] + -Progress callback called with UL 66 out of 0[LF] + +Progress callback called with UL 29 out of 0[LF] + ``` + to this: + ``` + Progress callback called with UL 0 out of 0[LF] + -Progress callback called with UL 8 out of 0[LF] + -Progress callback called with UL 16 out of 0[LF] + -Progress callback called with UL 26 out of 0[LF] + -Progress callback called with UL 61 out of 0[LF] + -Progress callback called with UL 66 out of 0[LF] + +Progress callback called with UL 40 out of 0[LF] + ``` + Presumably a step in the right direction. + + Closes #11780 + +Daniel Stenberg (1 Sep 2023) + +- awssiv4: avoid freeing the date pointer on error + + Since it was not allocated, don't free it even if it was wrong syntax + + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=61908 + + Follow-up to b137634ba3adb + + Closes #11782 + +Stefan Eissing (1 Sep 2023) + +- CI: ngtcp2-linux: use separate caches for tls libraries + + allow ever changing master for wolfssl + + Closes #11766 + +- replace `master` as wolfssl-version with recent commit + +- wolfssl, use master again in CI + + - with the shared session update fix landed in master, it + is time to use that in our CI again + +Nicholas Nethercote (31 Aug 2023) + +- tests: fix formatting errors in `FILEFORMAT.md`. + + Without the surrounding backticks, these tags get swallowed when the + markdown is rendered. + + Closes #11777 + +Viktor Szakats (31 Aug 2023) + +- cmake: add support for `CURL_DEFAULT_SSL_BACKEND` + + Allow overriding the default TLS backend via a CMake setting. + + E.g.: + `cmake [...] -DCURL_DEFAULT_SSL_BACKEND=mbedtls` + + Accepted values: bearssl, gnutls, mbedtls, openssl, rustls, + schannel, secure-transport, wolfssl + + The passed string is baked into the curl/libcurl binaries. + The value is case-insensitive. + + We added a similar option to autotools in 2017 via + c7170e20d0a18ec8a514b4daa53bcdbb4dcb3a05. + + TODO: Convert to lowercase to improve reproducibility. + + Closes #11774 + +- sectransp: fix compiler warnings + + https://github.com/curl/curl-for-win/actions/runs/6037489221/job/16381860220# + step:3:11046 + ``` + /Users/runner/work/curl-for-win/curl-for-win/curl/lib/vtls/sectransp.c:2435:1 + 4: warning: unused variable 'success' [-Wunused-variable] + OSStatus success; + ^ + /Users/runner/work/curl-for-win/curl-for-win/curl/lib/vtls/sectransp.c:3300:4 + 4: warning: unused parameter 'sha256len' [-Wunused-parameter] + size_t sha256len) + ^ + ``` + + Closes #11773 + +- tidy-up: mostly whitespace nits + + - delete completed TODO from `./CMakeLists.txt`. + - convert a C++ comment to C89 in `./CMake/CurlTests.c`. + - delete duplicate EOLs from EOF. + - add missing EOL at EOF. + - delete whitespace at EOL (except from expected test results). + - convert tabs to spaces. + - convert CRLF EOLs to LF in GHA yaml. + - text casing fixes in `./CMakeLists.txt`. + - fix a codespell typo in `packages/OS400/initscript.sh`. + + Closes #11772 + +Dan Fandrich (31 Aug 2023) + +- CI: remove Windows builds from Cirrus, without replacement + + If we don't do this, all coverage on Cirrus will cease in a few days. By + removing the Windows builds, the FreeBSD one should still continue + as before. The Windows builds will need be moved to another service to + maintain test coverage. + + Closes #11771 + +- CI: switch macOS ARM build from Cirrus to Circle CI + + Cirrus is drastically reducing their free tier on Sept. 1, so they will + no longer perform all these builds for us. All but one build has been + moved, with the LibreSSL one being dropped because of linking problems + on Circle. + + One important note about this change is that Circle CI is currently + directing all these builds to x86_64 hardware, despite them requesting + ARM. This is because ARM nodes are scheduled to be available on the + free tier only in December. This reduces our architectural diversity + until then but it should automatically come back once those machines are + enabled. + +- CI: use the right variable for BSD make + + BSD uses MAKEFLAGS instead of MAKE_FLAGS so it wasn't doing parallel + builds before. + +- CI: drop the FreeBSD 12.X build + + Cirrus' new free tier won't let us have many builds, so drop the + nonessential ones. The FreeBSD 13.X build will still give us the most + relevant FreeBSD coverage. + +- CI: move the Alpine build from Cirrus to GHA + + Cirrus is reducing their free tier to next to nothing, so we must move + builds elsewhere. + +Stefan Eissing (30 Aug 2023) + +- test_07_upload.py: fix test_07_34 curl args + + - Pass correct filename to --data-binary. + + Prior to this change --data-binary was passed an incorrect filename due + to a missing separator in the arguments list. Since aacbeae7 curl will + error on incorrect filenames for POST. + + Fixes https://github.com/curl/curl/issues/11761 + Closes https://github.com/curl/curl/pull/11763 + +Nicholas Nethercote (30 Aug 2023) + +- tests: document which tests fail due to hyper's lack of trailer support. + + Closes #11762 + +- docs: removing "pausing transfers" from HYPER.md. + + It's a reference to #8600, which was fixed by #9070. + + Closes #11764 + +Patrick Monnerat (30 Aug 2023) + +- os400: handle CURL_TEMP_PRINTF() while building bind source + + Closes #11547 + +- os400: build test servers + + Also fix a non-compliant main prototype in disabled.c. + + Closes #11547 + +- tests: fix compilation error for os400 + + OS400 uses BSD 4.3 setsockopt() prototype by default: this does not + define parameter as const, resulting in an error if actual parameter is + const. Remove the const keyword from the actual parameter cast: this + works in all conditions, even if the formal parameter uses it. + + Closes #11547 + +- os400: make programs and command name configurable + + Closes #11547 + +- os400: move build configuration parameters to a separate script + + They can then easily be overriden in a script named "config400.override" + that is not part of the distribution. + + Closes #11547 + +- os400: implement CLI tool + + This is provided as a QADRT (ascii) program, a link to it in the IFS and + a minimal CL command. + + Closes #11547 + +Matthias Gatto (30 Aug 2023) + +- lib: fix aws-sigv4 having date header twice in some cases + + When the user was providing the header X-XXX-Date, the header was + re-added during signature computation, and we had it twice in the + request. + + Reported-by: apparentorder@users.noreply.github.com + + Signed-off-by: Matthias Gatto + + Fixes: https://github.com/curl/curl/issues/11738 + Closes: https://github.com/curl/curl/pull/11754 + +Jay Satiro (30 Aug 2023) + +- multi: remove 'processing: ' debug message + + - Remove debug message added by e024d566. + + Closes https://github.com/curl/curl/pull/11759 + +- ftp: fix temp write of ipv6 address + + - During the check to differentiate between a port and IPv6 address + without brackets, write the binary IPv6 address to an in6_addr. + + Prior to this change the binary IPv6 address was erroneously written to + a sockaddr_in6 'sa6' when it should have been written to its in6_addr + member 'sin6_addr'. There's no fallout because no members of 'sa6' are + accessed before it is later overwritten. + + Closes https://github.com/curl/curl/pull/11747 + +- tool: change some fopen failures from warnings to errors + + - Error on missing input file for --data, --data-binary, + --data-urlencode, --header, --variable, --write-out. + + Prior to this change if a user of the curl tool specified an input file + for one of the above options and that file could not be opened then it + would be treated as zero length data instead of an error. For example, a + POST using `--data @filenametypo` would cause a zero length POST which + is probably not what the user intended. + + Closes https://github.com/curl/curl/pull/11677 + +- hostip: fix typo + +Davide Masserut (29 Aug 2023) + +- tool: avoid including leading spaces in the Location hyperlink + + Co-authored-by: Dan Fandrich + + Closes #11735 + +Daniel Stenberg (29 Aug 2023) + +- SECURITY-PROCESS.md: not a sec issue: Tricking user to run a cmdline + + Closes #11757 + +- connect: stop halving the remaining timeout when less than 600 ms left + + When curl wants to connect to a host, it always has a TIMEOUT. The + maximum time it is allowed to spend until a connect is confirmed. + + curl will try to connect to each of the IP adresses returned for the + host. Two loops, one for each IP family. + + During the connect loop, while curl has more than one IP address left to + try within a single address family, curl has traditionally allowed (time + left/2) for *this* connect attempt. This, to not get stuck on the + initial addresses in case the timeout but still allow later addresses to + get attempted. + + This has the downside that when users set a very short timeout and the + host has a large number of IP addresses, the effective result might be + that every attempt gets a little too short time. + + This change stop doing the divided-by-two if the total time left is + below a threshold. This threshold is 600 milliseconds. + + Closes #11693 + +- asyn-ares: reduce timeout to 2000ms + + When UDP packets get lost this makes for slightly faster retries. This + lower timeout is used by @c-ares itself by default starting next + release. + + Closes #11753 + +John Bampton (29 Aug 2023) + +- misc: remove duplicate words + + Closes #11740 + +Daniel Stenberg (29 Aug 2023) + +- RELEASE-NOTES: synced + +- wolfSSL: avoid the OpenSSL compat API when not needed + + ... and instead call wolfSSL functions directly. + + Closes #11752 + +Viktor Szakats (28 Aug 2023) + +- lib: fix null ptr derefs and uninitialized vars (h2/h3) + + Fixing compiler warnings with gcc 13.2.0 in unity builds. + + Assisted-by: Jay Satiro + Assisted-by: Stefan Eissing + Closes #11739 + +Jay Satiro (28 Aug 2023) + +- secureserver.pl: fix stunnel version parsing + + - Allow the stunnel minor-version version part to be zero. + + Prior to this change with the stunnel version scheme of . + if either part was 0 then version parsing would fail, causing + secureserver.pl to fail with error "No stunnel", causing tests that use + the SSL protocol to be skipped. As a practical matter this bug can only + be caused by a minor-version part of 0, since the major-version part is + always greater than 0. + + Closes https://github.com/curl/curl/pull/11722 + +- secureserver.pl: fix stunnel path quoting + + - Store the stunnel path in the private variable $stunnel unquoted and + instead quote it in the command strings. + + Prior to this change the quoted stunnel path was passed to perl's file + operators which cannot handle quoted paths. For example: + + $stunnel = "\"/C/Program Files (x86)/stunnel/bin/tstunnel\""; + if(-x $stunnel or -x "$stunnel") + # false even if path exists and is executable + + Our other test scripts written in perl, unlike this one, use servers.pm + which has a global $stunnel variable with the path stored unquoted and + therefore those scripts don't have this problem. + + Closes https://github.com/curl/curl/pull/11721 + +Daniel Stenberg (28 Aug 2023) + +- altsvc: accept and parse IPv6 addresses in response headers + + Store numerical IPv6 addresses in the alt-svc file with the brackets + present. + + Verify with test 437 and 438 + + Fixes #11737 + Reported-by: oliverpool on github + Closes #11743 + +- libtest: use curl_free() to free libcurl allocated data + + In several test programs. These mistakes are not detected or a problem + as long as memdebug.h is included, as that provides the debug wrappers + for all memory functions in the same style libcurl internals do it, + which makes curl_free and free effectively the same call. + + Reported-by: Nicholas Nethercote + Closes #11746 + +Jay Satiro (28 Aug 2023) + +- disable.d: explain --disable not implemented prior to 7.50.0 + + Option -q/--disable was added in 5.0 but only -q was actually + implemented. Later --disable was implemented in e200034 (precedes + 7.49.0), but incorrectly, and fixed in 6dbc23c (precedes 7.50.0). + + Reported-by: pszlazak@users.noreply.github.com + + Fixes https://github.com/curl/curl/issues/11710 + Closes #11712 + +Nicholas Nethercote (28 Aug 2023) + +- hyper: fix ownership problems + + Some of these changes come from comparing `Curl_http` and + `start_CONNECT`, which are similar, and adding things to them that are + present in one and missing in another. + + The most important changes: + - In `start_CONNECT`, add a missing `hyper_clientconn_free` call on the + happy path. + - In `start_CONNECT`, add a missing `hyper_request_free` on the error + path. + - In `bodysend`, add a missing `hyper_body_free` on an early-exit path. + - In `bodysend`, remove an unnecessary `hyper_body_free` on a different + error path that would cause a double-free. + https://docs.rs/hyper/latest/hyper/ffi/fn.hyper_request_set_body.html + says of `hyper_request_set_body`: "This takes ownership of the + hyper_body *, you must not use it or free it after setting it on the + request." This is true even if `hyper_request_set_body` returns an + error; I confirmed this by looking at the hyper source code. + + Other changes are minor but make things slightly nicer. + + Closes #11745 + +Daniel Stenberg (28 Aug 2023) + +- multi.h: the 'revents' field of curl_waitfd is supported + + Since 6d30f8ebed34e7276 + + Reported-by: Nicolás Ojeda Bär + Ref: #11748 + Closes #11749 + +Gerome Fournier (27 Aug 2023) + +- tool_paramhlp: improve str2num(): avoid unnecessary call to strlen() + + Closes #11742 + +Daniel Stenberg (27 Aug 2023) + +- docs: mention critical files in same directories as curl saves + + ... cannot be fully protected. Don't do it. + + Co-authored-by: Jay Satiro + Reported-by: Harry Sintonen + Fixes #11530 + Closes #11701 + +John Hawthorn (26 Aug 2023) + +- OpenSSL: clear error queue after SSL_shutdown + + We've seen errors left in the OpenSSL error queue (specifically, + "shutdown while in init") by adding some logging it revealed that the + source was this file. + + Since we call SSL_read and SSL_shutdown here, but don't check the return + code for an error, we should clear the OpenSSL error queue in case one + was raised. + + This didn't affect curl because we call ERR_clear_error before every + write operation (a0dd9df9ab35528eb9eb669e741a5df4b1fb833c), but when + libcurl is used in a process with other OpenSSL users, they may detect + an OpenSSL error pushed by libcurl's SSL_shutdown as if it was their + own. + + Co-authored-by: Satana de Sant'Ana + + Closes #11736 + +Alexander Kanavin (25 Aug 2023) + +- tests: update cookie expiry dates to far in the future + + This allows testing Y2038 with system time set to after that, so that + actual Y2038 issues can be exposed, and not masked by expiry errors. + + Fixes #11576 + Closes #11610 + +John Bampton (25 Aug 2023) + +- misc: fix spelling + + Closes #11733 + +Daniel Stenberg (25 Aug 2023) + +- cmdline-opts/page-header: clarify stronger that !opt == URL + + Everything provided on the command line that is not an option (or an + argument to an option) is treated as a URL. + + Closes #11734 + +- tests/runner: fix %else handling + + Getting the show state proper for %else and %endif did not properly work + in nested cases. + + Follow-up to 3d089c41ea9 + + Closes #11731 + +Nicholas Nethercote (25 Aug 2023) + +- docs: Remove mention of #10803 from `KNOWN_BUGS`. + + Because the leaks have been fixed. + +- c-hyper: fix another memory leak in `Curl_http`. + + There is a `hyper_clientconn_free` call on the happy path, but not one + on the error path. This commit adds one. + + Fixes the second memory leak reported by Valgrind in #10803. + + Fixes #10803 + Closes #11729 + +- c-hyper: fix a memory leak in `Curl_http`. + + A request created with `hyper_request_new` must be consumed by either + `hyper_clientconn_send` or `hyper_request_free`. + + This is not terrifically clear from the hyper docs -- + `hyper_request_free` is documented only with "Free an HTTP request if + not going to send it on a client" -- but a perusal of the hyper code + confirms it. + + This commit adds a `hyper_request_free` to the `error:` path in + `Curl_http` so that the request is consumed when an error occurs after + the request is created but before it is sent. + + Fixes the first memory leak reported by Valgrind in #10803. + + Closes #11729 + +Daniel Stenberg (25 Aug 2023) + +- RELEASE-NOTES: synced + +John Bampton (25 Aug 2023) + +- misc: spellfixes + + Closes #11730 + +Daniel Stenberg (25 Aug 2023) + +- tests: add support for nested %if conditions + + Provides more flexiblity to test cases. + + Also warn and bail out if there is an '%else' or %endif' without a + preceeding '%if'. + + Ref: #11610 + Closes #11728 + +- time-cond.d: mention what happens on a missing file + + Closes #11727 + +Christian Hesse (24 Aug 2023) + +- docs/cmdline-opts: match the current output + + The release date has been added in output, reflect that in documentation. + + Closes #11723 + +Daniel Stenberg (24 Aug 2023) + +- lib: minor comment corrections + +- docs: rewrite to present tense + + ... instead of using future tense. + + + numerous cleanups and improvements + + stick to "reuse" not "re-use" + + fewer contractions + + Closes #11713 + +- urlapi: setting a blank URL ("") is not an ok URL + + Test it in 1560 + Fixes #11714 + Reported-by: ad0p on github + Closes #11715 + +- spelling: use 'reuse' not 're-use' in code and elsewhere + + Unify the spelling as both versions were previously used intermittently + + Closes #11717 + +Michael Osipov (23 Aug 2023) + +- system.h: add CURL_OFF_T definitions on HP-UX with HP aCC + + HP-UX on IA64 provides two modes: 32 and 64 bit while 32 bit being the + default one. Use "long long" in 32 bit mode and just "long" in 64 bit + mode. + + Closes #11718 + +Dan Fandrich (22 Aug 2023) + +- tests: don't call HTTP errors OK in test cases + + Some HTTP errors codes were accompanied by the text OK, which causes + some cognitive dissonance when reading them. + +- http: close the connection after a late 417 is received + + In this situation, only part of the data has been sent before aborting + so the connection is no longer usable. + + Assisted-by: Jay Satiro + Fixes #11678 + Closes #11679 + +- runtests: slightly increase the longest log file displayed + + The new limit provides enough space for a 64 KiB data block to be logged + in a trace file, plus a few lines at the start and end for context. This + happens to be the amount of data sent at a time in a PUT request. + +- tests: add delay command to the HTTP server + + This adds a delay after client connect. + +Daniel Stenberg (22 Aug 2023) + +- cirrus: install everthing with pkg, avoid pip + + Assisted-by: Sevan Janiyan + + Closes #11711 + +- curl_url*.3: update function descriptions + + - expand and clarify several descriptions + - avoid using future tense all over + + Closes #11708 + +- RELEASE-NOTES: synced + +Stefan Eissing (21 Aug 2023) + +- CI/cirrus: disable python install on FreeBSD + + - python cryptography package does not build build FreeBSD + - install just mentions "error" + - this gets the build and the main test suite going again + + Closes #11705 + +- test2600: fix flakiness on low cpu + + - refs #11355 where failures to to low cpu resources in CI + are reported + - vastly extend CURLOPT_CONNECTTIMEOUT_MS and max durations + to test cases + - trigger Curl_expire() in test filter to allow re-checks before + the usual 1second interval + + Closes #11690 + +Maksim Sciepanienka (20 Aug 2023) + +- tool_urlglob: use the correct format specifier for curl_off_t in msnprintf + + Closes #11698 + +Daniel Stenberg (20 Aug 2023) + +- test687/688: two more basic --xattr tests + + Closes #11697 + +- cmdline-opts/docs: mentioned the negative option part + + ... for --no-alpn and --no-buffer in the same style done for other --no- + options: + + "Note that this is the negated option name documented." + + Closes #11695 + +Emanuele Torre (19 Aug 2023) + +- tool/var: also error when expansion result starts with NUL + + Expansions whose output starts with NUL were being expanded to the empty + string, and not being recognised as values that contain a NUL byte, and + should error. + + Closes #11694 + +Daniel Stenberg (19 Aug 2023) + +- tests: add 'large-time' as a testable feature + + This allows test cases to require this feature to run and to be used in + %if conditions. + + Large here means larger than 32 bits. Ie does not suffer from y2038. + + Closes #11696 + +- tests/Makefile: add check-translatable-options.pl to tarball + + Used in test 1544 + + Follow-up to ae806395abc8c + +- gen.pl: fix a long version generation mistake + + Too excessive escaping made the parsing not find the correct long names + later and instead add "wrong" links. + + Follow-up to 439ff2052e219 + + Reported-by: Lukas Tribus + Fixes #11688 + Closes #11689 + +- lib: move mimepost data from ->req.p.http to ->state + + When the legacy CURLOPT_HTTPPOST option is used, it gets converted into + the modem mimpost struct at first use. This data is (now) kept for the + entire transfer and not only per single HTTP request. This re-enables + rewind in the beginning of the second request instead of in end of the + first, as brought by 1b39731. + + The request struct is per-request data only. + + Extend test 650 to verify. + + Fixes #11680 + Reported-by: yushicheng7788 on github + Closes #11682 + +Patrick Monnerat (17 Aug 2023) + +- os400: do not check translatable options at build time + + Now that there is a test for this, the build time check is not needed + anymore. + + Closes #11650 + +- test1554: check translatable string options in OS400 wrapper + + This test runs a perl script that checks all string options are properly + translated by the OS400 character code conversion wrapper. It also + verifies these options are listed in alphanumeric order in the wrapper + switch statement. + + Closes #11650 + +Daniel Stenberg (17 Aug 2023) + +- unit3200: skip testing if function is not present + + Fake a successful run since we have no easy mechanism to skip this test + for this advanced condition. + +- unit2600: fix build warning if built without verbose messages + +- test1608: make it build and get skipped without shuffle DNS support + +- lib: --disable-bindlocal builds curl without local binding support + +- test1304: build and skip without netrc support + +- lib: build fixups when built with most things disabled + + Closes #11687 + +- workflows/macos.yml: disable zstd and alt-svc in the http-only build + + Closes #11683 + +Stefan Eissing (17 Aug 2023) + +- bearssl: handshake fix, provide proper get_select_socks() implementation + + - bring bearssl handshake times down from +200ms down to other TLS backends + - vtls: improve generic get_select_socks() implementation + - tests: provide Apache with a suitable ssl session cache + + Closes #11675 + +- tests: TLS session sharing test + + - test TLS session sharing with special test client + - expect failure with wolfSSL + - disable flaky wolfSSL test_02_07b + + Closes #11675 + +Daniel Stenberg (17 Aug 2023) + +- CURLOPT_*TIMEOUT*: extend and clarify + + Closes #11686 + +- urlapi: return CURLUE_BAD_HOSTNAME if puny2idn encoding fails + + And document it. Only return out of memory when it actually is a memory + problem. + + Pointed-out-by: Jacob Mealey + Closes #11674 + +Mathew Benson (17 Aug 2023) + +- cmake: add GnuTLS option + + - Option to use GNUTLS was missing. Hence was not able to use GNUTLS + with ngtcp2 for http3. + + Closes #11685 + +Daniel Stenberg (16 Aug 2023) + +- RELEASE-NOTES: synced + +- http: remove the p_pragma struct field + + unused since 40e8b4e52 (2008) + + Closes #11681 + +Jay Satiro (16 Aug 2023) + +- CURLINFO_CERTINFO.3: better explain curl_certinfo struct + + Closes https://github.com/curl/curl/pull/11666 + +- CURLINFO_TLS_SSL_PTR.3: clarify a recommendation + + - Remove the out-of-date SSL backend list supported by + CURLOPT_SSL_CTX_FUNCTION. + + It makes more sense to just refer to that document instead of having + a separate list that has to be kept in sync. + + Closes https://github.com/curl/curl/pull/11665 + +- write-out.d: clarify %{time_starttransfer} + + sync it up with CURLINFO_STARTTRANSFER_TIME_T + +Daniel Stenberg (15 Aug 2023) + +- transfer: don't set TIMER_STARTTRANSFER on first send + + The time stamp is for measuring the first *received* byte + + Fixes #11669 + Reported-by: JazJas on github + Closes #11670 + +trrui-huawei (15 Aug 2023) + +- quiche: enable quiche to handle timeout events + + In parallel with ngtcp2, quiche also offers the `quiche_conn_on_timeout` + interface for the application to invoke upon timer + expiration. Therefore, invoking the `on_timeout` function of the + Connection is crucial to ensure seamless functionality of quiche with + timeout events. + + Closes #11654 + +- quiche: adjust quiche `QUIC_IDLE_TIMEOUT` to 60s + + Set the `QUIC_IDLE_TIMEOUT` parameter to match ngtcp2 for consistency. + +Daniel Stenberg (15 Aug 2023) + +- KNOWN_BUGS: LDAPS requests to ActiveDirectory server hang + + Closes #9580 + +- imap: add a check for failing strdup() + +- imap: remove the only sscanf() call in the IMAP code + + Avoids the use of a stack buffer. + + Closes #11673 + +- imap: use a dynbuf in imap_atom + + Avoid a calculation + malloc. Build the output in a dynbuf. + + Closes #11672 + +Marin Hannache (14 Aug 2023) + +- http: do not require a user name when using CURLAUTH_NEGOTIATE + + In order to get Negotiate (SPNEGO) authentication to work in HTTP you + used to be required to provide a (fake) user name (this concerned both + curl and the lib) because the code wrongly only considered + authentication if there was a user name provided, as in: + + curl -u : --negotiate https://example.com/ + + This commit leverages the `struct auth` want member to figure out if the + user enabled CURLAUTH_NEGOTIATE, effectively removing the requirement of + setting a user name both in curl and the lib. + + Signed-off-by: Marin Hannache + Reported-by: Enrico Scholz + Fixes https://sourceforge.net/p/curl/bugs/440/ + Fixes #1161 + Closes #9047 + +Viktor Szakats (13 Aug 2023) + +- build: streamline non-UWP wincrypt detections + + - with CMake, use the variable `WINDOWS_STORE` to detect an UWP build + and disable our non-UWP-compatible use the Windows crypto API. This + allows to drop two dynamic feature checks. + + `WINDOWS_STORE` is true when invoking CMake with + `CMAKE_SYSTEM_NAME` == `WindowsStore`. Introduced in CMake v3.1. + + Ref: https://cmake.org/cmake/help/latest/variable/WINDOWS_STORE.html + + - with autotools, drop the separate feature check for `wincrypt.h`. On + one hand this header has been present for long (even Borland C 5.5 had + it from year 2000), on the other we used the check result solely to + enable another check for certain crypto functions. This fails anyway + with the header not present. We save one dynamic feature check at the + configure stage. + + Reviewed-by: Marcel Raad + Closes #11657 + +Nicholas Nethercote (13 Aug 2023) + +- docs/HYPER.md: update hyper build instructions + + Nightly Rust and `-Z unstable-options` are not needed. + + The instructions here now match the hyper docs exactly: + https://github.com/hyperium/hyper/commit/bd7928f3dd6a8461f0f0fdf7ee0fd95c2f15 + 6f88 + + Closes #11662 + +Daniel Stenberg (13 Aug 2023) + +- RELEASE-NOTES: synced + +- urlapi: CURLU_PUNY2IDN - convert from punycode to IDN name + + Asssisted-by: Jay Satiro + Closes #11655 + +- spellcheck: adapt to backslashed minuses + + As the curl.1 has more backslashed minus, the cleanup sed lines xneed to + adapt. + + Adjusted some docs slighly. + + Follow-up to 439ff2052e + + Closes #11663 + +- gen: escape more minus + + Detected since it was still hard to search for option names using dashes + in the middle in the man page. + + Closes #11660 + +- cookie-jar.d: enphasize that this option is ONLY writing cookies + + Reported-by: Dan Jacobson + Tweaked-by: Jay Satiro + Ref: #11642 + Closes #11661 + +Nicholas Nethercote (11 Aug 2023) + +- docs/HYPER.md: document a workaround for a link error + + Closes #11653 + +Jay Satiro (11 Aug 2023) + +- schannel: verify hostname independent of verify cert + + Prior to this change when CURLOPT_SSL_VERIFYPEER (verifypeer) was off + and CURLOPT_SSL_VERIFYHOST (verifyhost) was on we did not verify the + hostname in schannel code. + + This fixes KNOWN_BUG 2.8 "Schannel disable CURLOPT_SSL_VERIFYPEER and + verify hostname". We discussed a fix several years ago in #3285 but it + went stale. + + Assisted-by: Daniel Stenberg + + Bug: https://curl.haxx.se/mail/lib-2018-10/0113.html + Reported-by: Martin Galvan + + Ref: https://github.com/curl/curl/pull/3285 + + Fixes https://github.com/curl/curl/issues/3284 + Closes https://github.com/curl/curl/pull/10056 + +Daniel Stenberg (11 Aug 2023) + +- curl_quiche: remove superfluous NULL check + + 'stream' is always non-NULL at this point + + Pointed out by Coverity + + Closes #11656 + +- curl/urlapi.h: tiny typo + +- github/labeler: make HYPER.md set Hyper and not TLS + +- docs/cmdline-opts/gen.pl: hide "added in" before 7.50.0 + + 7.50.0 shipped on Jul 21 2016, over seven years ago. We no longer need + to specify version changes for earlier releases in the generated output. + + This ups the limit from the previous 7.30.0 (Apr 12 2013) + + This hides roughly 35 "added in" mentions. + + Closes #11651 + +Jay Satiro (10 Aug 2023) + +- bug_report: require reporters to specify curl and os versions + + - Change curl version and os sections from single-line input to + multi-line textarea. + + - Require curl version and os sections to be filled out before report + can be submitted. + + Closes https://github.com/curl/curl/pull/11636 + +Daniel Stenberg (9 Aug 2023) + +- gen.pl: replace all single quotes with aq + + - this prevents man from using a unicode sequence for them + - which then allows search to work properly + + Closes #11645 + +Viktor Szakats (9 Aug 2023) + +- cmake: fix to use variable for the curl namespace + + Replace (wrong) literal with a variable to specify the curl + namespace. + + Follow-up to 1199308dbc902c52be67fc805c72dd2582520d30 #11505 + + Reported-by: balikalina on Github + Fixes https://github.com/curl/curl/commit/1199308dbc902c52be67fc805c72dd25825 + 20d30#r123923098 + Closes #11629 + +- cmake: allow `SHARE_LIB_OBJECT=ON` on all platforms + + 2ebc74c36a19a1700af394c16855ce144d9878e3 #11546 introduced sharing + libcurl objects for shared and static targets. + + The above automatically enabled for Windows builds, with an option to + disable with `SHARE_LIB_OBJECT=OFF`. + + This patch extend this feature to all platforms as a manual option. + You can enable it by setting `SHARE_LIB_OBJECT=ON`. Then shared objects + are built in PIC mode, meaning the static lib will also have PIC code. + + [EXPERIMENTAL] + + Closes #11627 + +- cmake: assume `wldap32` availability on Windows + + This system library first shipped with Windows ME, available as an extra + install for some older releases (according to [1]). The import library + was present already in old MinGW 3.4.2 (year 2007). + + Drop the feature check and its associated `HAVE_WLDAP32` variable. + + To manually disable `wldap32`, you can use the `USE_WIN32_LDAP=OFF` + CMake option, like before. + + [1]: https://dlcdn.apache.org/httpd/binaries/win32/LEGACY.html + + Reviewed-by: Jay Satiro + Closes #11624 + +Daniel Stenberg (9 Aug 2023) + +- page-header: move up a URL paragraph from GLOBBING to URL + +- variable.d: output the function names table style + + Also correct the url function name in the header + + Closes #11641 + +- haproxy-clientip.d: remove backticks + + This is not markdown + + Follow-up to 0a75964d0d94a4 + + Closes #11639 + +- RELEASE-NOTES: synced + +- gen.pl: escape all dashes (ascii minus) to avoid unicode hyphens + + Reported-by: FC Stegerman + Fixes #11635 + Closes #11637 + +- cmdline-opts/page-header: reorder, clean up + + - removed some unnecessary blurb to focus + - moved up the more important URL details + - put "globbing" into its own subtitle and moved down a little + - mention the online man page in the version section + + Closes #11638 + +- c-hyper: adjust the hyper to curlcode conversion + + Closes #11621 + +- test2306: make it use a persistent connection + + + enable verbose already from the start + + Closes #11621 + +eppesuig (8 Aug 2023) + +- list-only.d: mention SFTP as supported protocol + + Closes #11628 + +Daniel Stenberg (8 Aug 2023) + +- request.d: use .TP for protocol "labels" + + To render the section nicer in man page. + + Closes #11630 + +- cf-haproxy: make CURLOPT_HAPROXY_CLIENT_IP set the *source* IP + + ... as documented. + + Update test 3201 and 3202 accordingly. + + Reported-by: Markus Sommer + Fixes #11619 + Closes #11626 + +- page-footer: QLOGDIR works with ngtcp2 and quiche + + It previously said "both" backends which is confusing as we currently + have three... + + Closes #11631 + +Stefan Eissing (8 Aug 2023) + +- http3: quiche, handshake optimization, trace cleanup + + - load x509 store after clienthello + - cleanup of tracing + + Closes #11618 + +Daniel Stenberg (8 Aug 2023) + +- ngtcp2: remove dead code + + 'result' is always zero (CURLE_OK) at this point + + Detected by Coverity + + Closes #11622 + +Viktor Szakats (8 Aug 2023) + +- openssl: auto-detect `SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED` + + OpenSSL 1.1.1 defines this macro, but no ealier version, or any of the + popular forks (yet). Use the macro itself to detect its presence, + replacing the hard-wired fork-specific conditions. + + This way the feature will enable automatically when forks implement it, + while also shorter and possibly requiring less future maintenance. + + Follow-up to 94241a9e78397a2aaf89a213e6ada61e7de7ee02 #6721 + + Reviewed-by: Jay Satiro + Closes #11617 + +- openssl: use `SSL_CTX_set_ciphersuites` with LibreSSL 3.4.1 + + LibreSSL 3.4.1 (2021-10-14) added support for + `SSL_CTX_set_ciphersuites`. + + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.4.1-relnotes.txt + + Reviewed-by: Jay Satiro + Closes #11616 + +- openssl: use `SSL_CTX_set_keylog_callback` with LibreSSL 3.5.0 + + LibreSSL 3.5.0 (2022-02-24) added support for + `SSL_CTX_set_keylog_callback`. + + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt + + Reviewed-by: Jay Satiro + Closes #11615 + +- cmake: drop `HAVE_LIBWINMM` and `HAVE_LIBWS2_32` feature checks + + - `HAVE_LIBWINMM` was detected but unused. The `winmm` system library is + also not used by curl, but it is by its optional dependency `librtmp`. + Change the logic to always add `winmm` when `USE_LIBRTMP` is set. This + library has been available since the early days of Windows. + + - `HAVE_LIBWS2_32` detected `ws2_32` lib on Windows. This lib is present + since Windows 95 OSR2 (AFAIR). Winsock1 already wasn't supported and + other existing logic already assumed this lib being present, so delete + the check and replace the detection variable with `WIN32` and always + add `ws2_32` on Windows. + + Closes #11612 + +Daniel Gustafsson (8 Aug 2023) + +- crypto: ensure crypto initialization works + + Make sure that context initialization during hash setup works to avoid + going forward with the risk of a null pointer dereference. + + Reported-by: Philippe Antoine on HackerOne + Assisted-by: Jay Satiro + Assisted-by: Daniel Stenberg + + Closes #11614 + +Viktor Szakats (7 Aug 2023) + +- openssl: switch to modern init for LibreSSL 2.7.0+ + + LibreSSL 2.7.0 (2018-03-21) introduced automatic initialization, + `OPENSSL_init_ssl()` function and deprecated the old, manual init + method, as seen in OpenSSL 1.1.0. Switch to the modern method when + available. + + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.7.0-relnotes.txt + + Reviewed-by: Daniel Stenberg + Closes #11611 + +Daniel Stenberg (7 Aug 2023) + +- gskit: remove + + We remove support for building curl with gskit. + + - This is a niche TLS library, only running on some IBM systems + - no regular curl contributors use this backend + - no CI builds use or verify this backend + - gskit, or the curl adaption for it, lacks many modern TLS features + making it an inferior solution + - build breakages in this code take weeks or more to get detected + - fixing gskit code is mostly done "flying blind" + + This removal has been advertized in DEPRECATED in Jan 2, 2023 and it has + been mentioned on the curl-library mailing list. + + It could be brought back, this is not a ban. Given proper effort and + will, gskit support is welcome back into the curl TLS backend family. + + Closes #11460 + +- RELEASE-NOTES: synced + +Dan Fandrich (7 Aug 2023) + +- THANKS-filter: add a name typo + +Stefan Eissing (7 Aug 2023) + +- http3/ngtcp2: shorten handshake, trace cleanup + + - shorten handshake timing by delayed x509 store load (OpenSSL) + as we do for HTTP/2 + - cleanup of trace output, align with HTTP/2 output + + Closes #11609 + +Daniel Stenberg (7 Aug 2023) + +- headers: accept leading whitespaces on first response header + + This is a bad header fold but since the popular browsers accept this + violation, so does curl now. Unless built with hyper. + + Add test 1473 to verify and adjust test 2306. + + Reported-by: junsik on github + Fixes #11605 + Closes #11607 + +- include/curl/mprintf.h: add __attribute__ for the prototypes + + - if gcc or clang is used + - if __STDC_VERSION__ >= 199901L, which means greater than C90 + - if not using mingw + - if CURL_NO_FMT_CHECKS is not defined + + Closes #11589 + +- tests: fix bad printf format flags in test code + +- tests: fix header scan tools for attribute edits in mprintf.h + +- cf-socket: log successful interface bind + + When the setsockopt SO_BINDTODEVICE operation succeeds, output that in + the verbose output. + + Ref: #11599 + Closes #11608 + +- CURLOPT_SSL_VERIFYPEER.3: mention it does not load CA certs when disabled + + Ref: #11457 + Closes #11606 + +- CURLOPT_SSL_VERIFYPEER.3: add two more see also options + + CURLINFO_CAINFO and CURLINFO_CAPATH + + Closes #11603 + +- KNOWN_BUGS: aws-sigv4 does not behave well with AWS VPC Lattice + + Closes #11007 + +Graham Campbell (6 Aug 2023) + +- CI: use openssl 3.0.10+quic, nghttp3 0.14.0, ngtcp2 0.18.0 + + Closes #11585 + +Daniel Stenberg (6 Aug 2023) + +- TODO: add *5* entries for aws-sigv4 + + Closes #7559 + Closes #8107 + Closes #8810 + Closes #9717 + Closes #10129 + +- TODO: LDAP Certificate-Based Authentication + + Closes #9641 + +Stefan Eissing (6 Aug 2023) + +- http2: cleanup trace messages + + - more compact format with bracketed stream id + - all frames traced in and out + + Closes #11592 + +Daniel Stenberg (6 Aug 2023) + +- tests/tftpd+mqttd: make variables static to silence picky warnings + + Closes #11594 + +- docs/cmdline: remove repeated working for negotiate + ntlm + + The extra wording is added automatically by the gen.pl tool + + Closes #11597 + +- docs/cmdline: add small "warning" to verbose options + + "Note that verbose output of curl activities and network traffic might + contain sensitive data, including user names, credentials or secret data + content. Be aware and be careful when sharing trace logs with others." + + Closes #11596 + +- RELEASE-NOTES: synced + +- pingpong: don't use *bump_headersize + + We use that for HTTP(S) only. + + Follow-up to 3ee79c1674fd6 + + Closes #11590 + +- urldata: remove spurious parenthesis to unbreak no-proxy build + + Follow-up to e12b39e13382 + + Closes #11591 + +- easy: don't call Curl_trc_opt() in disabled-verbose builds + + Follow-up to e12b39e133822c6a0 + + Closes #11588 + +- http: use %u for printfing int + + Follow-up to 3ee79c1674fd6f99e8efca5 + + Closes #11587 + +Goro FUJI (3 Aug 2023) + +- vquic: show stringified messages for errno + + Closes #11584 + +Stefan Eissing (3 Aug 2023) + +- trace: make tracing available in non-debug builds + + Add --trace-config to curl + + Add curl_global_trace() to libcurl + + Closes #11421 + +Daniel Stenberg (3 Aug 2023) + +- TODO: remove "Support intermediate & root pinning for PINNEDPUBLICKEY" + + See also https://github.com/curl/curl/pull/7507 + +- TODO: add "WebSocket read callback" + + remove "Upgrade to websockets" as we already have this + + Closes #11402 + +- test497: verify rejecting too large incoming headers + +- http: return error when receiving too large header set + + To avoid abuse. The limit is set to 300 KB for the accumulated size of + all received HTTP headers for a single response. Incomplete research + suggests that Chrome uses a 256-300 KB limit, while Firefox allows up to + 1MB. + + Closes #11582 + +Stefan Eissing (3 Aug 2023) + +- http2: upgrade tests and add fix for non-existing stream + + - check in h2 filter recv that stream actually exists + and return error if not + - add test for parallel, extreme h2 upgrades that fail if + connections get reused before fully switched + - add h2 upgrade upload test just for completeness + + Closes #11563 + +Viktor Szakats (3 Aug 2023) + +- tests: ensure `libcurl.def` contains all exports + + Add `test1279` to verify that `libcurl.def` lists all exported API + functions found in libcurl headers. + + Also: + + - extend test suite XML `stdout` tag with the `loadfile` attribute. + + - fix `tests/extern-scan.pl` and `test1135` to include websocket API. + + - use all headers (sorted) in `test1135` instead of a manual list. + + - add options `--sort`, `--heading=` to `tests/extern-scan.pl`. + + - add `libcurl.def` to the auto-labeler GHA task. + + Follow-up to 2ebc74c36a19a1700af394c16855ce144d9878e3 + + Closes #11570 + +Daniel Stenberg (2 Aug 2023) + +- url: change default value for CURLOPT_MAXREDIRS to 30 + + It was previously unlimited by default, but that's not a sensible + default. While changing this has a remote risk of breaking an existing + use case, I figure it is more likely to actually save users from loops. + + Closes #11581 + +- lib: fix a few *printf() flag mistakes + + Reported-by: Gisle Vanem + Ref: #11574 + Closes #11579 + +Samuel Chiang (2 Aug 2023) + +- openssl: make aws-lc version support OCSP + + And bump version in CI + + Closes #11568 + +Daniel Stenberg (2 Aug 2023) + +- tool: make the length argument an int for printf()-.* flags + + Closes #11578 + +- tool_operate: fix memory leak when SSL_CERT_DIR is used + + Detected by Coverity + + Follow-up to 29bce9857a12b6cfa726a5 + + Closes #11577 + +- tool/var: free memory on OOM + + Coverity detected this memory leak in OOM situation + + Follow-up to 2e160c9c652504e + + Closes #11575 + +Viktor Szakats (2 Aug 2023) + +- gha: bump libressl and mbedtls versions + + Closes #11573 + +Jay Satiro (2 Aug 2023) + +- schannel: fix user-set legacy algorithms in Windows 10 & 11 + + - If the user set a legacy algorithm list (CURLOPT_SSL_CIPHER_LIST) then + use the SCHANNEL_CRED legacy structure to pass the list to Schannel. + + - If the user set both a legacy algorithm list and a TLS 1.3 cipher list + then abort. + + Although MS doesn't document it, Schannel will not negotiate TLS 1.3 + when SCHANNEL_CRED is used. That means setting a legacy algorithm list + limits the user to earlier versions of TLS. + + Prior to this change, since 8beff435 (precedes 7.85.0), libcurl would + ignore legacy algorithms in Windows 10 1809 and later. + + Reported-by: zhihaoy@users.noreply.github.com + + Fixes https://github.com/curl/curl/pull/10741 + Closes https://github.com/curl/curl/pull/10746 + +Daniel Stenberg (2 Aug 2023) + +- variable.d: setting a variable again overwrites it + + Reported-by: Niall McGee + Bug: https://twitter.com/niallmcgee/status/1686523075423322113 + Closes #11571 + +Jay Satiro (2 Aug 2023) + +- CURLOPT_PROXY_SSL_OPTIONS.3: sync formatting + + - Re-wrap CURLSSLOPT_ALLOW_BEAST description. + +Daniel Stenberg (2 Aug 2023) + +- RELEASE-NOTES: synced + +- resolve: use PF_INET6 family lookups when CURL_IPRESOLVE_V6 is set + + Previously it would always do PF_UNSPEC if CURL_IPRESOLVE_V4 is not + used, thus unnecessarily asking for addresses that will not be used. + + Reported-by: Joseph Tharayil + Fixes #11564 + Closes #11565 + +- docs: link to the website versions instead of markdowns + + ... to make the links work when the markdown is converted to webpages on + https://curl.se + + Reported-by: Maurício Meneghini Fauth + Fixes https://github.com/curl/curl-www/issues/272 + Closes #11569 + +Viktor Szakats (1 Aug 2023) + +- cmake: cache more config and delete unused ones + + - cache more Windows config results for faster initialization. + + - delete unused config macros `HAVE_SYS_UTSNAME_H`, `HAVE_SSL_H`. + + - delete dead references to `sys/utsname.h`. + + Closes #11551 + +- egd: delete feature detection and related source code + + EGD is Entropy Gathering Daemon, a socket-based entropy source supported + by pre-OpenSSL v1.1 versions and now deprecated. curl also deprecated it + a while ago. + + Its detection in CMake was broken all along because OpenSSL libs were + not linked at the point of feature check. + + Delete detection from both cmake and autotools, along with the related + source snippet, and the `--with-egd-socket=` `./configure` option. + + Closes #11556 + +Stefan Eissing (1 Aug 2023) + +- tests: fix h3 server check and parallel instances + + - fix check for availability of nghttpx server + - add `tcp` frontend config for same port as quic, as + without this, port 3000 is bound which clashes for parallel + testing + + Closes #11553 + +Daniel Stenberg (1 Aug 2023) + +- docs/cmdline-opts: spellfixes, typos and polish + + To make them accepted by the spell checker + + Closes #11562 + +- CI/spellcheck: build curl.1 and spellcheck it + + Added acceptable words + + Closes #11562 + +Alexander Jaeger (1 Aug 2023) + +- misc: fix various typos + + Closes #11561 + +Daniel Stenberg (1 Aug 2023) + +- http2: avoid too early connection re-use/multiplexing + + HTTP/1 connections that are upgraded to HTTP/2 should not be picked up + for reuse and multiplexing by other handles until the 101 switching + process is completed. + + Lots-of-debgging-by: Stefan Eissing + Reported-by: Richard W.M. Jones + Bug: https://curl.se/mail/lib-2023-07/0045.html + Closes #11557 + +- Revert "KNOWN_BUGS: build for iOS simulator on macOS 13.2 with Xcode 14" + + This reverts commit 2e8a3d7cb73c85a9aa151e263315f8a496dbb9d4. + + It's a user error for supplying incomplete information to the build system. + + Reported-by: Ryan Schmidt + Ref: https://github.com/curl/curl/issues/11215#issuecomment-1658729367 + +Viktor Szakats (1 Aug 2023) + +- cmake: add support for single libcurl compilation pass + + Before this patch CMake builds used two separate compilation passes to + build the shared and static libcurl respectively. This patch allows to + reduce that to a single pass if the target platform and build settings + allow it. + + This reduces CMake build times when building both static and shared + libcurl at the same time, making these dual builds an almost zero-cost + option. + + Enable this feature for Windows builds, where the difference between the + two passes was the use of `__declspec(dllexport)` attribute for exported + API functions for the shared builds. This patch replaces this method + with the use of `libcurl.def` at DLL link time. + + Also update `Makefile.mk` to use `libcurl.def` to export libcurl API + symbols on Windows. This simplifies (or fixes) this build method (e.g. + in curl-for-win, which generated a `libcurl.def` from `.h` files using + an elaborate set of transformations). + + `libcurl.def` has the maintenance cost of keeping the list of public + libcurl API symbols up-to-date. This list seldom changes, so the cost + is low. + + Closes #11546 + +- cmake: detect `SSL_set0_wbio` in OpenSSL + + Present in OpenSSL 1.1.0 and BoringSSL. + Missing from LibreSSL 3.8.0. + + Follow-up to f39472ea9f4f4e12cfbc0500c4580a8d52ce4a59 + + While here, also fix `RAND_egd()` detection which was broken, likely all + along. This feature is probably broken with CMake builds and also + requires a sufficiently obsolete OpenSSL version, so this part of the + update was not tested. + + Closes #11555 diff --git a/CMake/CMakeConfigurableFile.in b/CMake/CMakeConfigurableFile.in new file mode 100644 index 0000000..a3d2bc4 --- /dev/null +++ b/CMake/CMakeConfigurableFile.in @@ -0,0 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +@CMAKE_CONFIGURABLE_FILE_CONTENT@ diff --git a/CMake/CurlSymbolHiding.cmake b/CMake/CurlSymbolHiding.cmake new file mode 100644 index 0000000..8289b49 --- /dev/null +++ b/CMake/CurlSymbolHiding.cmake @@ -0,0 +1,84 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +include(CheckCSourceCompiles) + +option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) +mark_as_advanced(CURL_HIDDEN_SYMBOLS) + +if(WIN32 AND ENABLE_CURLDEBUG) + # We need to export internal debug functions (e.g. curl_dbg_*), so disable + # symbol hiding for debug builds. + set(CURL_HIDDEN_SYMBOLS OFF) +endif() + +if(CURL_HIDDEN_SYMBOLS) + set(SUPPORTS_SYMBOL_HIDING FALSE) + + if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC) + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + elseif(CMAKE_COMPILER_IS_GNUCC) + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4) + # note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0) + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__global") + set(_CFLAG_SYMBOLS_HIDE "-xldscope=hidden") + elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0) + # note: this should probably just check for version 9.1.045 but I'm not 100% sure + # so let's do it the same way autotools do. + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + check_c_source_compiles("#include + int main (void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug) + if(NOT _no_bug) + set(SUPPORTS_SYMBOL_HIDING FALSE) + set(_SYMBOL_EXTERN "") + set(_CFLAG_SYMBOLS_HIDE "") + endif() + elseif(MSVC) + set(SUPPORTS_SYMBOL_HIDING TRUE) + endif() + + set(HIDES_CURL_PRIVATE_SYMBOLS ${SUPPORTS_SYMBOL_HIDING}) +elseif(MSVC) + if(NOT CMAKE_VERSION VERSION_LESS 3.7) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) #present since 3.4.3 but broken + set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) + else() + message(WARNING "Hiding private symbols regardless CURL_HIDDEN_SYMBOLS being disabled.") + set(HIDES_CURL_PRIVATE_SYMBOLS TRUE) + endif() +else() + set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) +endif() + +set(CURL_CFLAG_SYMBOLS_HIDE ${_CFLAG_SYMBOLS_HIDE}) +set(CURL_EXTERN_SYMBOL ${_SYMBOL_EXTERN}) diff --git a/CMake/CurlTests.c b/CMake/CurlTests.c new file mode 100644 index 0000000..83d743d --- /dev/null +++ b/CMake/CurlTests.c @@ -0,0 +1,430 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifdef HAVE_FCNTL_O_NONBLOCK +/* headers for FCNTL_O_NONBLOCK test */ +#include +#include +#include +/* */ +#if defined(sun) || defined(__sun__) || \ + defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# if defined(__SVR4) || defined(__srv4__) +# define PLATFORM_SOLARIS +# else +# define PLATFORM_SUNOS4 +# endif +#endif +#if (defined(_AIX) || defined(__xlC__)) && !defined(_AIX41) +# define PLATFORM_AIX_V3 +#endif +/* */ +#if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3) +#error "O_NONBLOCK does not work on this platform" +#endif + +int main(void) +{ + /* O_NONBLOCK source test */ + int flags = 0; + if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK)) + return 1; + return 0; +} +#endif + +/* tests for gethostbyname_r */ +#if defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \ + defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ + defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) +# define _REENTRANT + /* no idea whether _REENTRANT is always set, just invent a new flag */ +# define TEST_GETHOSTBYFOO_REENTRANT +#endif +#if defined(HAVE_GETHOSTBYNAME_R_3) || \ + defined(HAVE_GETHOSTBYNAME_R_5) || \ + defined(HAVE_GETHOSTBYNAME_R_6) || \ + defined(TEST_GETHOSTBYFOO_REENTRANT) +#include +#include +int main(void) +{ + char *address = "example.com"; + int length = 0; + int type = 0; + struct hostent h; + int rc = 0; +#if defined(HAVE_GETHOSTBYNAME_R_3) || \ + defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) + struct hostent_data hdata; +#elif defined(HAVE_GETHOSTBYNAME_R_5) || \ + defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ + defined(HAVE_GETHOSTBYNAME_R_6) || \ + defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) + char buffer[8192]; + int h_errnop; + struct hostent *hp; +#endif + +#if defined(HAVE_GETHOSTBYNAME_R_3) || \ + defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) + rc = gethostbyname_r(address, &h, &hdata); +#elif defined(HAVE_GETHOSTBYNAME_R_5) || \ + defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) + rc = gethostbyname_r(address, &h, buffer, 8192, &h_errnop); + (void)hp; /* not used for test */ +#elif defined(HAVE_GETHOSTBYNAME_R_6) || \ + defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) + rc = gethostbyname_r(address, &h, buffer, 8192, &hp, &h_errnop); +#endif + + (void)length; + (void)type; + (void)rc; + return 0; +} +#endif + +#ifdef HAVE_IN_ADDR_T +#include +#include +#include +int main(void) +{ + if((in_addr_t *) 0) + return 0; + if(sizeof(in_addr_t)) + return 0; + ; + return 0; +} +#endif + +#ifdef HAVE_BOOL_T +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_STDBOOL_H +#include +#endif +int main(void) +{ + if(sizeof(bool *)) + return 0; + ; + return 0; +} +#endif + +#ifdef STDC_HEADERS +#include +#include +#include +#include +int main(void) { return 0; } +#endif + +#ifdef HAVE_FILE_OFFSET_BITS +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int main(void) { ; return 0; } +#endif + +#ifdef HAVE_IOCTLSOCKET +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif +int main(void) +{ + /* ioctlsocket source code */ + int socket; + unsigned long flags = ioctlsocket(socket, FIONBIO, &flags); + ; + return 0; +} + +#endif + +#ifdef HAVE_IOCTLSOCKET_CAMEL +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif +int main(void) +{ + /* IoctlSocket source code */ + if(0 != IoctlSocket(0, 0, 0)) + return 1; + ; + return 0; +} +#endif + +#ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif +int main(void) +{ + /* IoctlSocket source code */ + long flags = 0; + if(0 != IoctlSocket(0, FIONBIO, &flags)) + return 1; + ; + return 0; +} +#endif + +#ifdef HAVE_IOCTLSOCKET_FIONBIO +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif +int main(void) +{ + int flags = 0; + if(0 != ioctlsocket(0, FIONBIO, &flags)) + return 1; + ; + return 0; +} +#endif + +#ifdef HAVE_IOCTL_FIONBIO +/* headers for FIONBIO test */ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_STROPTS_H +# include +#endif +int main(void) +{ + int flags = 0; + if(0 != ioctl(0, FIONBIO, &flags)) + return 1; + ; + return 0; +} +#endif + +#ifdef HAVE_IOCTL_SIOCGIFADDR +/* headers for FIONBIO test */ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_STROPTS_H +# include +#endif +#include +int main(void) +{ + struct ifreq ifr; + if(0 != ioctl(0, SIOCGIFADDR, &ifr)) + return 1; + ; + return 0; +} +#endif + +#ifdef HAVE_SETSOCKOPT_SO_NONBLOCK +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +/* includes end */ +int main(void) +{ + if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0)) + return 1; + ; + return 0; +} +#endif + +#ifdef HAVE_GLIBC_STRERROR_R +#include +#include + +void check(char c) {} + +int main(void) +{ + char buffer[1024]; + /* This will not compile if strerror_r does not return a char* */ + check(strerror_r(EACCES, buffer, sizeof(buffer))[0]); + return 0; +} +#endif + +#ifdef HAVE_POSIX_STRERROR_R +#include +#include + +/* float, because a pointer can't be implicitly cast to float */ +void check(float f) {} + +int main(void) +{ + char buffer[1024]; + /* This will not compile if strerror_r does not return an int */ + check(strerror_r(EACCES, buffer, sizeof(buffer))); + return 0; +} +#endif + +#ifdef HAVE_FSETXATTR_6 +#include /* header from libc, not from libattr */ +int main(void) +{ + fsetxattr(0, 0, 0, 0, 0, 0); + return 0; +} +#endif + +#ifdef HAVE_FSETXATTR_5 +#include /* header from libc, not from libattr */ +int main(void) +{ + fsetxattr(0, 0, 0, 0, 0); + return 0; +} +#endif + +#ifdef HAVE_CLOCK_GETTIME_MONOTONIC +#include +int main(void) +{ + struct timespec ts = {0, 0}; + clock_gettime(CLOCK_MONOTONIC, &ts); + return 0; +} +#endif + +#ifdef HAVE_BUILTIN_AVAILABLE +int main(void) +{ + if(__builtin_available(macOS 10.12, *)) {} + return 0; +} +#endif + +#ifdef HAVE_ATOMIC +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_STDATOMIC_H +# include +#endif +/* includes end */ + +int main(void) +{ + _Atomic int i = 1; + i = 0; /* Force an atomic-write operation. */ + return i; +} +#endif + +#ifdef HAVE_WIN32_WINNT +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOGDI +# define NOGDI +# endif +# include +#endif +/* includes end */ + +#define enquote(x) #x +#define expand(x) enquote(x) +#pragma message("_WIN32_WINNT=" expand(_WIN32_WINNT)) + +int main(void) +{ + return 0; +} +#endif diff --git a/CMake/FindBearSSL.cmake b/CMake/FindBearSSL.cmake new file mode 100644 index 0000000..56a064e --- /dev/null +++ b/CMake/FindBearSSL.cmake @@ -0,0 +1,32 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +find_path(BEARSSL_INCLUDE_DIRS bearssl.h) + +find_library(BEARSSL_LIBRARY bearssl) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(BEARSSL DEFAULT_MSG + BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) + +mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) diff --git a/CMake/FindBrotli.cmake b/CMake/FindBrotli.cmake new file mode 100644 index 0000000..11ab7f8 --- /dev/null +++ b/CMake/FindBrotli.cmake @@ -0,0 +1,43 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +include(FindPackageHandleStandardArgs) + +find_path(BROTLI_INCLUDE_DIR "brotli/decode.h") + +find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon) +find_library(BROTLIDEC_LIBRARY NAMES brotlidec) + +find_package_handle_standard_args(Brotli + FOUND_VAR + BROTLI_FOUND + REQUIRED_VARS + BROTLIDEC_LIBRARY + BROTLICOMMON_LIBRARY + BROTLI_INCLUDE_DIR + FAIL_MESSAGE + "Could NOT find Brotli" +) + +set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR}) +set(BROTLI_LIBRARIES ${BROTLICOMMON_LIBRARY} ${BROTLIDEC_LIBRARY}) diff --git a/CMake/FindCARES.cmake b/CMake/FindCARES.cmake new file mode 100644 index 0000000..fa75891 --- /dev/null +++ b/CMake/FindCARES.cmake @@ -0,0 +1,47 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# - Find c-ares +# Find the c-ares includes and library +# This module defines +# CARES_INCLUDE_DIR, where to find ares.h, etc. +# CARES_LIBRARIES, the libraries needed to use c-ares. +# CARES_FOUND, If false, do not try to use c-ares. +# also defined, but not for general use are +# CARES_LIBRARY, where to find the c-ares library. + +find_path(CARES_INCLUDE_DIR ares.h) + +set(CARES_NAMES ${CARES_NAMES} cares) +find_library(CARES_LIBRARY + NAMES ${CARES_NAMES} + ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CARES + REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR) + +mark_as_advanced( + CARES_LIBRARY + CARES_INCLUDE_DIR + ) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake new file mode 100644 index 0000000..b244e61 --- /dev/null +++ b/CMake/FindGSS.cmake @@ -0,0 +1,312 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# - Try to find the GSS Kerberos library +# Once done this will define +# +# GSS_ROOT_DIR - Set this variable to the root installation of GSS +# +# Read-Only variables: +# GSS_FOUND - system has the Heimdal library +# GSS_FLAVOUR - "MIT" or "Heimdal" if anything found. +# GSS_INCLUDE_DIR - the Heimdal include directory +# GSS_LIBRARIES - The libraries needed to use GSS +# GSS_LINK_DIRECTORIES - Directories to add to linker search path +# GSS_LINKER_FLAGS - Additional linker flags +# GSS_COMPILER_FLAGS - Additional compiler flags +# GSS_VERSION - This is set to version advertised by pkg-config or read from manifest. +# In case the library is found but no version info available it'll be set to "unknown" + +set(_MIT_MODNAME mit-krb5-gssapi) +set(_HEIMDAL_MODNAME heimdal-gssapi) + +include(CheckIncludeFile) +include(CheckIncludeFiles) +include(CheckTypeSize) + +set(_GSS_ROOT_HINTS + "${GSS_ROOT_DIR}" + "$ENV{GSS_ROOT_DIR}" +) + +# try to find library using system pkg-config if user didn't specify root dir +if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}") + if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME}) + list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}") + elseif(WIN32) + list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]") + endif() +endif() + +if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach. + find_file(_GSS_CONFIGURE_SCRIPT + NAMES + "krb5-config" + HINTS + ${_GSS_ROOT_HINTS} + PATH_SUFFIXES + bin + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + ) + + # if not found in user-supplied directories, maybe system knows better + find_file(_GSS_CONFIGURE_SCRIPT + NAMES + "krb5-config" + PATH_SUFFIXES + bin + ) + + if(_GSS_CONFIGURE_SCRIPT) + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi" + OUTPUT_VARIABLE _GSS_CFLAGS + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + message(STATUS "CFLAGS: ${_GSS_CFLAGS}") + if(NOT _GSS_CONFIGURE_FAILED) # 0 means success + # should also work in an odd case when multiple directories are given + string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS) + string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}") + string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}") + + foreach(_flag ${_GSS_CFLAGS}) + if(_flag MATCHES "^-I.*") + string(REGEX REPLACE "^-I" "" _val "${_flag}") + list(APPEND _GSS_INCLUDE_DIR "${_val}") + else() + list(APPEND _GSS_COMPILER_FLAGS "${_flag}") + endif() + endforeach() + endif() + + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi" + OUTPUT_VARIABLE _GSS_LIB_FLAGS + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}") + + if(NOT _GSS_CONFIGURE_FAILED) # 0 means success + # this script gives us libraries and link directories. Blah. We have to deal with it. + string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS) + string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") + string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") + + foreach(_flag ${_GSS_LIB_FLAGS}) + if(_flag MATCHES "^-l.*") + string(REGEX REPLACE "^-l" "" _val "${_flag}") + list(APPEND _GSS_LIBRARIES "${_val}") + elseif(_flag MATCHES "^-L.*") + string(REGEX REPLACE "^-L" "" _val "${_flag}") + list(APPEND _GSS_LINK_DIRECTORIES "${_val}") + else() + list(APPEND _GSS_LINKER_FLAGS "${_flag}") + endif() + endforeach() + endif() + + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version" + OUTPUT_VARIABLE _GSS_VERSION + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # older versions may not have the "--version" parameter. In this case we just don't care. + if(_GSS_CONFIGURE_FAILED) + set(_GSS_VERSION 0) + endif() + + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor" + OUTPUT_VARIABLE _GSS_VENDOR + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # older versions may not have the "--vendor" parameter. In this case we just don't care. + if(_GSS_CONFIGURE_FAILED) + set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter + else() + if(_GSS_VENDOR MATCHES ".*H|heimdal.*") + set(GSS_FLAVOUR "Heimdal") + else() + set(GSS_FLAVOUR "MIT") + endif() + endif() + + else() # either there is no config script or we are on a platform that doesn't provide one (Windows?) + + find_path(_GSS_INCLUDE_DIR + NAMES + "gssapi/gssapi.h" + HINTS + ${_GSS_ROOT_HINTS} + PATH_SUFFIXES + include + inc + ) + + if(_GSS_INCLUDE_DIR) #jay, we've found something + set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}") + check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS) + + if(_GSS_HAVE_MIT_HEADERS) + set(GSS_FLAVOUR "MIT") + else() + # prevent compiling the header - just check if we can include it + list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__ROKEN_H__) + check_include_file( "roken.h" _GSS_HAVE_ROKEN_H) + + check_include_file( "heimdal/roken.h" _GSS_HAVE_HEIMDAL_ROKEN_H) + if(_GSS_HAVE_ROKEN_H OR _GSS_HAVE_HEIMDAL_ROKEN_H) + set(GSS_FLAVOUR "Heimdal") + endif() + list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D__ROKEN_H__) + endif() + else() + # I'm not convinced if this is the right way but this is what autotools do at the moment + find_path(_GSS_INCLUDE_DIR + NAMES + "gssapi.h" + HINTS + ${_GSS_ROOT_HINTS} + PATH_SUFFIXES + include + inc + ) + + if(_GSS_INCLUDE_DIR) + set(GSS_FLAVOUR "Heimdal") + endif() + endif() + + # if we have headers, check if we can link libraries + if(GSS_FLAVOUR) + set(_GSS_LIBDIR_SUFFIXES "") + set(_GSS_LIBDIR_HINTS ${_GSS_ROOT_HINTS}) + get_filename_component(_GSS_CALCULATED_POTENTIAL_ROOT "${_GSS_INCLUDE_DIR}" PATH) + list(APPEND _GSS_LIBDIR_HINTS ${_GSS_CALCULATED_POTENTIAL_ROOT}) + + if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND _GSS_LIBDIR_SUFFIXES "lib/AMD64") + if(GSS_FLAVOUR STREQUAL "MIT") + set(_GSS_LIBNAME "gssapi64") + else() + set(_GSS_LIBNAME "libgssapi") + endif() + else() + list(APPEND _GSS_LIBDIR_SUFFIXES "lib/i386") + if(GSS_FLAVOUR STREQUAL "MIT") + set(_GSS_LIBNAME "gssapi32") + else() + set(_GSS_LIBNAME "libgssapi") + endif() + endif() + else() + list(APPEND _GSS_LIBDIR_SUFFIXES "lib;lib64") # those suffixes are not checked for HINTS + if(GSS_FLAVOUR STREQUAL "MIT") + set(_GSS_LIBNAME "gssapi_krb5") + else() + set(_GSS_LIBNAME "gssapi") + endif() + endif() + + find_library(_GSS_LIBRARIES + NAMES + ${_GSS_LIBNAME} + HINTS + ${_GSS_LIBDIR_HINTS} + PATH_SUFFIXES + ${_GSS_LIBDIR_SUFFIXES} + ) + + endif() + endif() +else() + if(_GSS_PKG_${_MIT_MODNAME}_VERSION) + set(GSS_FLAVOUR "MIT") + set(_GSS_VERSION _GSS_PKG_${_MIT_MODNAME}_VERSION) + else() + set(GSS_FLAVOUR "Heimdal") + set(_GSS_VERSION _GSS_PKG_${_MIT_HEIMDAL}_VERSION) + endif() +endif() + +set(GSS_INCLUDE_DIR ${_GSS_INCLUDE_DIR}) +set(GSS_LIBRARIES ${_GSS_LIBRARIES}) +set(GSS_LINK_DIRECTORIES ${_GSS_LINK_DIRECTORIES}) +set(GSS_LINKER_FLAGS ${_GSS_LINKER_FLAGS}) +set(GSS_COMPILER_FLAGS ${_GSS_COMPILER_FLAGS}) +set(GSS_VERSION ${_GSS_VERSION}) + +if(GSS_FLAVOUR) + if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.amd64.manifest") + else() + set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.x86.manifest") + endif() + + if(EXISTS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}") + file(STRINGS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}" heimdal_version_str + REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$") + + string(REGEX MATCH "[0-9]\\.[^\"]+" + GSS_VERSION "${heimdal_version_str}") + endif() + + if(NOT GSS_VERSION) + set(GSS_VERSION "Heimdal Unknown") + endif() + elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT") + get_filename_component(_MIT_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE) + if(WIN32 AND _MIT_VERSION) + set(GSS_VERSION "${_MIT_VERSION}") + else() + set(GSS_VERSION "MIT Unknown") + endif() + endif() +endif() + +include(FindPackageHandleStandardArgs) + +set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR) + +find_package_handle_standard_args(GSS + REQUIRED_VARS + ${_GSS_REQUIRED_VARS} + VERSION_VAR + GSS_VERSION + FAIL_MESSAGE + "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR" +) + +mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES) diff --git a/CMake/FindLibPSL.cmake b/CMake/FindLibPSL.cmake new file mode 100644 index 0000000..e3bd68d --- /dev/null +++ b/CMake/FindLibPSL.cmake @@ -0,0 +1,45 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# - Try to find the libpsl library +# Once done this will define +# +# LIBPSL_FOUND - system has the libpsl library +# LIBPSL_INCLUDE_DIR - the libpsl include directory +# LIBPSL_LIBRARY - the libpsl library name + +find_path(LIBPSL_INCLUDE_DIR libpsl.h) + +find_library(LIBPSL_LIBRARY NAMES psl libpsl) + +if(LIBPSL_INCLUDE_DIR) + file(STRINGS "${LIBPSL_INCLUDE_DIR}/libpsl.h" libpsl_version_str REGEX "^#define[\t ]+PSL_VERSION[\t ]+\"(.*)\"") + string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1" LIBPSL_VERSION "${libpsl_version_str}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibPSL + REQUIRED_VARS LIBPSL_LIBRARY LIBPSL_INCLUDE_DIR + VERSION_VAR LIBPSL_VERSION) + +mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY) diff --git a/CMake/FindLibSSH2.cmake b/CMake/FindLibSSH2.cmake new file mode 100644 index 0000000..a0c251a --- /dev/null +++ b/CMake/FindLibSSH2.cmake @@ -0,0 +1,45 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# - Try to find the libssh2 library +# Once done this will define +# +# LIBSSH2_FOUND - system has the libssh2 library +# LIBSSH2_INCLUDE_DIR - the libssh2 include directory +# LIBSSH2_LIBRARY - the libssh2 library name + +find_path(LIBSSH2_INCLUDE_DIR libssh2.h) + +find_library(LIBSSH2_LIBRARY NAMES ssh2 libssh2) + +if(LIBSSH2_INCLUDE_DIR) + file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION[\t ]+\"(.*)\"") + string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1" LIBSSH2_VERSION "${libssh2_version_str}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibSSH2 + REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR + VERSION_VAR LIBSSH2_VERSION) + +mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY) diff --git a/CMake/FindMSH3.cmake b/CMake/FindMSH3.cmake new file mode 100644 index 0000000..7d9c6b6 --- /dev/null +++ b/CMake/FindMSH3.cmake @@ -0,0 +1,70 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#[=======================================================================[.rst: +FindMSH3 +---------- + +Find the msh3 library + +Result Variables +^^^^^^^^^^^^^^^^ + +``MSH3_FOUND`` + System has msh3 +``MSH3_INCLUDE_DIRS`` + The msh3 include directories. +``MSH3_LIBRARIES`` + The libraries needed to use msh3 +#]=======================================================================] +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_MSH3 libmsh3) +endif() + +find_path(MSH3_INCLUDE_DIR msh3.h + HINTS + ${PC_MSH3_INCLUDEDIR} + ${PC_MSH3_INCLUDE_DIRS} +) + +find_library(MSH3_LIBRARY NAMES msh3 + HINTS + ${PC_MSH3_LIBDIR} + ${PC_MSH3_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MSH3 + REQUIRED_VARS + MSH3_LIBRARY + MSH3_INCLUDE_DIR +) + +if(MSH3_FOUND) + set(MSH3_LIBRARIES ${MSH3_LIBRARY}) + set(MSH3_INCLUDE_DIRS ${MSH3_INCLUDE_DIR}) +endif() + +mark_as_advanced(MSH3_INCLUDE_DIRS MSH3_LIBRARIES) diff --git a/CMake/FindMbedTLS.cmake b/CMake/FindMbedTLS.cmake new file mode 100644 index 0000000..814bd97 --- /dev/null +++ b/CMake/FindMbedTLS.cmake @@ -0,0 +1,36 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h) + +find_library(MBEDTLS_LIBRARY mbedtls) +find_library(MBEDX509_LIBRARY mbedx509) +find_library(MBEDCRYPTO_LIBRARY mbedcrypto) + +set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MbedTLS DEFAULT_MSG + MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) + +mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) diff --git a/CMake/FindNGHTTP2.cmake b/CMake/FindNGHTTP2.cmake new file mode 100644 index 0000000..3957646 --- /dev/null +++ b/CMake/FindNGHTTP2.cmake @@ -0,0 +1,41 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +include(FindPackageHandleStandardArgs) + +find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h") + +find_library(NGHTTP2_LIBRARY NAMES nghttp2) + +find_package_handle_standard_args(NGHTTP2 + FOUND_VAR + NGHTTP2_FOUND + REQUIRED_VARS + NGHTTP2_LIBRARY + NGHTTP2_INCLUDE_DIR +) + +set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR}) +set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY}) + +mark_as_advanced(NGHTTP2_INCLUDE_DIRS NGHTTP2_LIBRARIES) diff --git a/CMake/FindNGHTTP3.cmake b/CMake/FindNGHTTP3.cmake new file mode 100644 index 0000000..9b13e6c --- /dev/null +++ b/CMake/FindNGHTTP3.cmake @@ -0,0 +1,78 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#[=======================================================================[.rst: +FindNGHTTP3 +---------- + +Find the nghttp3 library + +Result Variables +^^^^^^^^^^^^^^^^ + +``NGHTTP3_FOUND`` + System has nghttp3 +``NGHTTP3_INCLUDE_DIRS`` + The nghttp3 include directories. +``NGHTTP3_LIBRARIES`` + The libraries needed to use nghttp3 +``NGHTTP3_VERSION`` + version of nghttp3. +#]=======================================================================] + +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_NGHTTP3 libnghttp3) +endif() + +find_path(NGHTTP3_INCLUDE_DIR nghttp3/nghttp3.h + HINTS + ${PC_NGHTTP3_INCLUDEDIR} + ${PC_NGHTTP3_INCLUDE_DIRS} +) + +find_library(NGHTTP3_LIBRARY NAMES nghttp3 + HINTS + ${PC_NGHTTP3_LIBDIR} + ${PC_NGHTTP3_LIBRARY_DIRS} +) + +if(PC_NGHTTP3_VERSION) + set(NGHTTP3_VERSION ${PC_NGHTTP3_VERSION}) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NGHTTP3 + REQUIRED_VARS + NGHTTP3_LIBRARY + NGHTTP3_INCLUDE_DIR + VERSION_VAR NGHTTP3_VERSION +) + +if(NGHTTP3_FOUND) + set(NGHTTP3_LIBRARIES ${NGHTTP3_LIBRARY}) + set(NGHTTP3_INCLUDE_DIRS ${NGHTTP3_INCLUDE_DIR}) +endif() + +mark_as_advanced(NGHTTP3_INCLUDE_DIRS NGHTTP3_LIBRARIES) diff --git a/CMake/FindNGTCP2.cmake b/CMake/FindNGTCP2.cmake new file mode 100644 index 0000000..7ea4665 --- /dev/null +++ b/CMake/FindNGTCP2.cmake @@ -0,0 +1,117 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#[=======================================================================[.rst: +FindNGTCP2 +---------- + +Find the ngtcp2 library + +This module accepts optional COMPONENTS to control the crypto library (these are +mutually exclusive):: + + quictls, LibreSSL: Use libngtcp2_crypto_quictls + BoringSSL, AWS-LC: Use libngtcp2_crypto_boringssl + wolfSSL: Use libngtcp2_crypto_wolfssl + GnuTLS: Use libngtcp2_crypto_gnutls + +Result Variables +^^^^^^^^^^^^^^^^ + +``NGTCP2_FOUND`` + System has ngtcp2 +``NGTCP2_INCLUDE_DIRS`` + The ngtcp2 include directories. +``NGTCP2_LIBRARIES`` + The libraries needed to use ngtcp2 +``NGTCP2_VERSION`` + version of ngtcp2. +#]=======================================================================] + +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_NGTCP2 libngtcp2) +endif() + +find_path(NGTCP2_INCLUDE_DIR ngtcp2/ngtcp2.h + HINTS + ${PC_NGTCP2_INCLUDEDIR} + ${PC_NGTCP2_INCLUDE_DIRS} +) + +find_library(NGTCP2_LIBRARY NAMES ngtcp2 + HINTS + ${PC_NGTCP2_LIBDIR} + ${PC_NGTCP2_LIBRARY_DIRS} +) + +if(PC_NGTCP2_VERSION) + set(NGTCP2_VERSION ${PC_NGTCP2_VERSION}) +endif() + +if(NGTCP2_FIND_COMPONENTS) + set(NGTCP2_CRYPTO_BACKEND "") + foreach(component IN LISTS NGTCP2_FIND_COMPONENTS) + if(component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS)") + if(NGTCP2_CRYPTO_BACKEND) + message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected") + endif() + set(NGTCP2_CRYPTO_BACKEND ${component}) + endif() + endforeach() + + if(NGTCP2_CRYPTO_BACKEND) + string(TOLOWER "ngtcp2_crypto_${NGTCP2_CRYPTO_BACKEND}" _crypto_library) + if(UNIX) + pkg_search_module(PC_${_crypto_library} lib${_crypto_library}) + endif() + find_library(${_crypto_library}_LIBRARY + NAMES + ${_crypto_library} + HINTS + ${PC_${_crypto_library}_LIBDIR} + ${PC_${_crypto_library}_LIBRARY_DIRS} + ) + if(${_crypto_library}_LIBRARY) + set(NGTCP2_${NGTCP2_CRYPTO_BACKEND}_FOUND TRUE) + set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library}_LIBRARY}) + endif() + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NGTCP2 + REQUIRED_VARS + NGTCP2_LIBRARY + NGTCP2_INCLUDE_DIR + VERSION_VAR NGTCP2_VERSION + HANDLE_COMPONENTS +) + +if(NGTCP2_FOUND) + set(NGTCP2_LIBRARIES ${NGTCP2_LIBRARY} ${NGTCP2_CRYPTO_LIBRARY}) + set(NGTCP2_INCLUDE_DIRS ${NGTCP2_INCLUDE_DIR}) +endif() + +mark_as_advanced(NGTCP2_INCLUDE_DIRS NGTCP2_LIBRARIES) diff --git a/CMake/FindQUICHE.cmake b/CMake/FindQUICHE.cmake new file mode 100644 index 0000000..0488463 --- /dev/null +++ b/CMake/FindQUICHE.cmake @@ -0,0 +1,70 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#[=======================================================================[.rst: +FindQUICHE +---------- + +Find the quiche library + +Result Variables +^^^^^^^^^^^^^^^^ + +``QUICHE_FOUND`` + System has quiche +``QUICHE_INCLUDE_DIRS`` + The quiche include directories. +``QUICHE_LIBRARIES`` + The libraries needed to use quiche +#]=======================================================================] +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_QUICHE quiche) +endif() + +find_path(QUICHE_INCLUDE_DIR quiche.h + HINTS + ${PC_QUICHE_INCLUDEDIR} + ${PC_QUICHE_INCLUDE_DIRS} +) + +find_library(QUICHE_LIBRARY NAMES quiche + HINTS + ${PC_QUICHE_LIBDIR} + ${PC_QUICHE_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(QUICHE + REQUIRED_VARS + QUICHE_LIBRARY + QUICHE_INCLUDE_DIR +) + +if(QUICHE_FOUND) + set(QUICHE_LIBRARIES ${QUICHE_LIBRARY}) + set(QUICHE_INCLUDE_DIRS ${QUICHE_INCLUDE_DIR}) +endif() + +mark_as_advanced(QUICHE_INCLUDE_DIRS QUICHE_LIBRARIES) diff --git a/CMake/FindWolfSSL.cmake b/CMake/FindWolfSSL.cmake new file mode 100644 index 0000000..d67c0eb --- /dev/null +++ b/CMake/FindWolfSSL.cmake @@ -0,0 +1,36 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +find_path(WolfSSL_INCLUDE_DIR NAMES wolfssl/ssl.h) +find_library(WolfSSL_LIBRARY NAMES wolfssl) +mark_as_advanced(WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WolfSSL + REQUIRED_VARS WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY + ) + +if(WolfSSL_FOUND) + set(WolfSSL_INCLUDE_DIRS ${WolfSSL_INCLUDE_DIR}) + set(WolfSSL_LIBRARIES ${WolfSSL_LIBRARY}) +endif() diff --git a/CMake/FindZstd.cmake b/CMake/FindZstd.cmake new file mode 100644 index 0000000..0ea9e0c --- /dev/null +++ b/CMake/FindZstd.cmake @@ -0,0 +1,78 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#[=======================================================================[.rst: +FindZstd +---------- + +Find the zstd library + +Result Variables +^^^^^^^^^^^^^^^^ + +``Zstd_FOUND`` + System has zstd +``Zstd_INCLUDE_DIRS`` + The zstd include directories. +``Zstd_LIBRARIES`` + The libraries needed to use zstd +#]=======================================================================] + +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_Zstd libzstd) +endif() + +find_path(Zstd_INCLUDE_DIR zstd.h + HINTS + ${PC_Zstd_INCLUDEDIR} + ${PC_Zstd_INCLUDE_DIRS} +) + +find_library(Zstd_LIBRARY NAMES zstd + HINTS + ${PC_Zstd_LIBDIR} + ${PC_Zstd_LIBRARY_DIRS} +) + +if(Zstd_INCLUDE_DIR) + file(READ "${Zstd_INCLUDE_DIR}/zstd.h" _zstd_header) + string(REGEX MATCH ".*define ZSTD_VERSION_MAJOR *([0-9]+).*define ZSTD_VERSION_MINOR *([0-9]+).*define ZSTD_VERSION_RELEASE *([0-9]+)" _zstd_ver "${_zstd_header}") + set(Zstd_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Zstd + REQUIRED_VARS + Zstd_LIBRARY + Zstd_INCLUDE_DIR + VERSION_VAR Zstd_VERSION +) + +if(Zstd_FOUND) + set(Zstd_LIBRARIES ${Zstd_LIBRARY}) + set(Zstd_INCLUDE_DIRS ${Zstd_INCLUDE_DIR}) +endif() + +mark_as_advanced(Zstd_INCLUDE_DIRS Zstd_LIBRARIES) diff --git a/CMake/Macros.cmake b/CMake/Macros.cmake new file mode 100644 index 0000000..9ff62ea --- /dev/null +++ b/CMake/Macros.cmake @@ -0,0 +1,109 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +#File defines convenience macros for available feature testing + +# Check if header file exists and add it to the list. +# This macro is intended to be called multiple times with a sequence of +# possibly dependent header files. Some headers depend on others to be +# compiled correctly. +macro(check_include_file_concat FILE VARIABLE) + check_include_files("${CURL_INCLUDES};${FILE}" ${VARIABLE}) + if(${VARIABLE}) + set(CURL_INCLUDES ${CURL_INCLUDES} ${FILE}) + set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${VARIABLE}") + endif() +endmacro() + +# For other curl specific tests, use this macro. +macro(curl_internal_test CURL_TEST) + if(NOT DEFINED "${CURL_TEST}") + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-D${CURL_TEST} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}") + if(CMAKE_REQUIRED_LIBRARIES) + set(CURL_TEST_ADD_LIBRARIES + "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") + endif() + + message(STATUS "Performing Test ${CURL_TEST}") + try_compile(${CURL_TEST} + ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CURL_TEST_ADD_LIBRARIES}" + OUTPUT_VARIABLE OUTPUT) + if(${CURL_TEST}) + set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}") + message(STATUS "Performing Test ${CURL_TEST} - Success") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing Test ${CURL_TEST} passed with the following output:\n" + "${OUTPUT}\n") + else() + message(STATUS "Performing Test ${CURL_TEST} - Failed") + set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Test ${CURL_TEST} failed with the following output:\n" + "${OUTPUT}\n") + endif() + endif() +endmacro() + +macro(curl_nroff_check) + find_program(NROFF NAMES gnroff nroff) + if(NROFF) + # Need a way to write to stdin, this will do + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test") + # Tests for a valid nroff option to generate a manpage + foreach(_MANOPT "-man" "-mandoc") + execute_process(COMMAND "${NROFF}" ${_MANOPT} + OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT + INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" + ERROR_QUIET) + # Save the option if it was valid + if(NROFF_MANOPT_OUTPUT) + message("Found *nroff option: -- ${_MANOPT}") + set(NROFF_MANOPT ${_MANOPT}) + set(NROFF_USEFUL ON) + break() + endif() + endforeach() + # No need for the temporary file + file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt") + if(NOT NROFF_USEFUL) + message(WARNING "Found no *nroff option to get plaintext from man pages") + endif() + else() + message(WARNING "Found no *nroff program") + endif() +endmacro() + +macro(optional_dependency DEPENDENCY) + set(CURL_${DEPENDENCY} AUTO CACHE STRING "Build curl with ${DEPENDENCY} support (AUTO, ON or OFF)") + set_property(CACHE CURL_${DEPENDENCY} PROPERTY STRINGS AUTO ON OFF) + + if(CURL_${DEPENDENCY} STREQUAL AUTO) + find_package(${DEPENDENCY}) + elseif(CURL_${DEPENDENCY}) + find_package(${DEPENDENCY} REQUIRED) + endif() +endmacro() diff --git a/CMake/OtherTests.cmake b/CMake/OtherTests.cmake new file mode 100644 index 0000000..7701c0e --- /dev/null +++ b/CMake/OtherTests.cmake @@ -0,0 +1,184 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +include(CheckCSourceCompiles) +include(CheckCSourceRuns) +include(CheckTypeSize) + +macro(add_header_include check header) + if(${check}) + set(_source_epilogue "${_source_epilogue} + #include <${header}>") + endif() +endmacro() + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +if(NOT DEFINED HAVE_STRUCT_SOCKADDR_STORAGE) + set(CMAKE_EXTRA_INCLUDE_FILES) + if(WIN32) + set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h") + set(CMAKE_REQUIRED_DEFINITIONS "-DWIN32_LEAN_AND_MEAN") + set(CMAKE_REQUIRED_LIBRARIES "ws2_32") + elseif(HAVE_SYS_SOCKET_H) + set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h") + endif() + check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE) + set(HAVE_STRUCT_SOCKADDR_STORAGE ${HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE}) +endif() + +if(NOT WIN32) + set(_source_epilogue "#undef inline") + add_header_include(HAVE_SYS_TYPES_H "sys/types.h") + add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h") + check_c_source_compiles("${_source_epilogue} + int main(void) + { + int flag = MSG_NOSIGNAL; + (void)flag; + return 0; + }" HAVE_MSG_NOSIGNAL) +endif() + +set(_source_epilogue "#undef inline") +add_header_include(HAVE_SYS_TIME_H "sys/time.h") +check_c_source_compiles("${_source_epilogue} + #include + int main(void) + { + struct timeval ts; + ts.tv_sec = 0; + ts.tv_usec = 0; + (void)ts; + return 0; + }" HAVE_STRUCT_TIMEVAL) + +unset(CMAKE_TRY_COMPILE_TARGET_TYPE) + +if(NOT CMAKE_CROSSCOMPILING AND NOT APPLE) + set(_source_epilogue "#undef inline") + add_header_include(HAVE_SYS_POLL_H "sys/poll.h") + add_header_include(HAVE_POLL_H "poll.h") + check_c_source_runs("${_source_epilogue} + #include + #include + int main(void) + { + if(0 != poll(0, 0, 10)) { + return 1; /* fail */ + } + else { + /* detect the 10.12 poll() breakage */ + struct timeval before, after; + int rc; + size_t us; + + gettimeofday(&before, NULL); + rc = poll(NULL, 0, 500); + gettimeofday(&after, NULL); + + us = (after.tv_sec - before.tv_sec) * 1000000 + + (after.tv_usec - before.tv_usec); + + if(us < 400000) { + return 1; + } + } + return 0; + }" HAVE_POLL_FINE) +endif() + +# Detect HAVE_GETADDRINFO_THREADSAFE + +if(WIN32) + set(HAVE_GETADDRINFO_THREADSAFE ${HAVE_GETADDRINFO}) +elseif(NOT HAVE_GETADDRINFO) + set(HAVE_GETADDRINFO_THREADSAFE FALSE) +elseif(APPLE OR + CMAKE_SYSTEM_NAME STREQUAL "AIX" OR + CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "HP-UX" OR + CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "SunOS") + set(HAVE_GETADDRINFO_THREADSAFE TRUE) +elseif(CMAKE_SYSTEM_NAME MATCHES "BSD") + set(HAVE_GETADDRINFO_THREADSAFE FALSE) +endif() + +if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE) + set(_source_epilogue "#undef inline") + add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h") + add_header_include(HAVE_SYS_TIME_H "sys/time.h") + add_header_include(HAVE_NETDB_H "netdb.h") + check_c_source_compiles("${_source_epilogue} + int main(void) + { + #ifdef h_errno + return 0; + #else + force compilation error + #endif + }" HAVE_H_ERRNO) + + if(NOT HAVE_H_ERRNO) + check_c_source_compiles("${_source_epilogue} + int main(void) + { + h_errno = 2; + return h_errno != 0 ? 1 : 0; + }" HAVE_H_ERRNO_ASSIGNABLE) + + if(NOT HAVE_H_ERRNO_ASSIGNABLE) + check_c_source_compiles("${_source_epilogue} + int main(void) + { + #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) + return 0; + #elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700) + return 0; + #else + force compilation error + #endif + }" HAVE_H_ERRNO_SBS_ISSUE_7) + endif() + endif() + + if(HAVE_H_ERRNO OR HAVE_H_ERRNO_ASSIGNABLE OR HAVE_H_ERRNO_SBS_ISSUE_7) + set(HAVE_GETADDRINFO_THREADSAFE TRUE) + endif() +endif() + +if(NOT WIN32 AND NOT DEFINED HAVE_CLOCK_GETTIME_MONOTONIC_RAW) + set(_source_epilogue "#undef inline") + add_header_include(HAVE_SYS_TYPES_H "sys/types.h") + add_header_include(HAVE_SYS_TIME_H "sys/time.h") + check_c_source_compiles("${_source_epilogue} + #include + int main(void) + { + struct timespec ts; + (void)clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + return 0; + }" HAVE_CLOCK_GETTIME_MONOTONIC_RAW) +endif() diff --git a/CMake/PickyWarnings.cmake b/CMake/PickyWarnings.cmake new file mode 100644 index 0000000..d82bbb1 --- /dev/null +++ b/CMake/PickyWarnings.cmake @@ -0,0 +1,232 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +include(CheckCCompilerFlag) + +unset(WPICKY) + +if(CURL_WERROR AND CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0) + set(WPICKY "${WPICKY} -pedantic-errors") +endif() + +if(PICKY_COMPILER) + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") + + # https://clang.llvm.org/docs/DiagnosticsReference.html + # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html + + # WPICKY_ENABLE = Options we want to enable as-is. + # WPICKY_DETECT = Options we want to test first and enable if available. + + # Prefer the -Wextra alias with clang. + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(WPICKY_ENABLE "-Wextra") + else() + set(WPICKY_ENABLE "-W") + endif() + + list(APPEND WPICKY_ENABLE + -Wall -pedantic + ) + + # ---------------------------------- + # Add new options here, if in doubt: + # ---------------------------------- + set(WPICKY_DETECT + ) + + # Assume these options always exist with both clang and gcc. + # Require clang 3.0 / gcc 2.95 or later. + list(APPEND WPICKY_ENABLE + -Wbad-function-cast # clang 2.7 gcc 2.95 + -Wconversion # clang 2.7 gcc 2.95 + -Winline # clang 1.0 gcc 1.0 + -Wmissing-declarations # clang 1.0 gcc 2.7 + -Wmissing-prototypes # clang 1.0 gcc 1.0 + -Wnested-externs # clang 1.0 gcc 2.7 + -Wno-long-long # clang 1.0 gcc 2.95 + -Wno-multichar # clang 1.0 gcc 2.95 + -Wpointer-arith # clang 1.0 gcc 1.4 + -Wshadow # clang 1.0 gcc 2.95 + -Wsign-compare # clang 1.0 gcc 2.95 + -Wundef # clang 1.0 gcc 2.95 + -Wunused # clang 1.1 gcc 2.95 + -Wwrite-strings # clang 1.0 gcc 1.4 + ) + + # Always enable with clang, version dependent with gcc + set(WPICKY_COMMON_OLD + -Waddress # clang 2.7 gcc 4.3 + -Wattributes # clang 2.7 gcc 4.1 + -Wcast-align # clang 1.0 gcc 4.2 + -Wdeclaration-after-statement # clang 1.0 gcc 3.4 + -Wdiv-by-zero # clang 2.7 gcc 4.1 + -Wempty-body # clang 2.7 gcc 4.3 + -Wendif-labels # clang 1.0 gcc 3.3 + -Wfloat-equal # clang 1.0 gcc 2.96 (3.0) + -Wformat-security # clang 2.7 gcc 4.1 + -Wignored-qualifiers # clang 2.8 gcc 4.3 + -Wmissing-field-initializers # clang 2.7 gcc 4.1 + -Wmissing-noreturn # clang 2.7 gcc 4.1 + -Wno-format-nonliteral # clang 1.0 gcc 2.96 (3.0) + -Wno-system-headers # clang 1.0 gcc 3.0 + # -Wpadded # clang 2.9 gcc 4.1 # Not used because we cannot change public structs + -Wold-style-definition # clang 2.7 gcc 3.4 + -Wredundant-decls # clang 2.7 gcc 4.1 + -Wsign-conversion # clang 2.9 gcc 4.3 + -Wno-error=sign-conversion # FIXME + -Wstrict-prototypes # clang 1.0 gcc 3.3 + # -Wswitch-enum # clang 2.7 gcc 4.1 # Not used because this basically disallows default case + -Wtype-limits # clang 2.7 gcc 4.3 + -Wunreachable-code # clang 2.7 gcc 4.1 + # -Wunused-macros # clang 2.7 gcc 4.1 # Not practical + -Wunused-parameter # clang 2.7 gcc 4.1 + -Wvla # clang 2.8 gcc 4.3 + ) + + set(WPICKY_COMMON + -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.3 + -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.6 g++ 11.0 + -Wpragmas # clang 3.5 gcc 4.1 appleclang 6.0 + -Wunused-const-variable # clang 3.4 gcc 6.0 appleclang 5.1 + ) + + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + list(APPEND WPICKY_ENABLE + ${WPICKY_COMMON_OLD} + -Wshift-sign-overflow # clang 2.9 + -Wshorten-64-to-32 # clang 1.0 + -Wlanguage-extension-token # clang 3.0 + -Wformat=2 # clang 3.0 gcc 4.8 + ) + # Enable based on compiler version + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3)) + list(APPEND WPICKY_ENABLE + ${WPICKY_COMMON} + -Wunreachable-code-break # clang 3.5 appleclang 6.0 + -Wheader-guard # clang 3.4 appleclang 5.1 + -Wsometimes-uninitialized # clang 3.2 appleclang 4.6 + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.9) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.3)) + list(APPEND WPICKY_ENABLE + -Wcomma # clang 3.9 appleclang 8.3 + -Wmissing-variable-declarations # clang 3.2 appleclang 4.6 + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.3)) + list(APPEND WPICKY_ENABLE + -Wassign-enum # clang 7.0 appleclang 10.3 + -Wextra-semi-stmt # clang 7.0 appleclang 10.3 + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.4)) + list(APPEND WPICKY_ENABLE + -Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 12.4 # we have silencing markup for clang 10.0 and above only + ) + endif() + else() # gcc + list(APPEND WPICKY_DETECT + ${WPICKY_COMMON} + ) + # Enable based on compiler version + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3) + list(APPEND WPICKY_ENABLE + ${WPICKY_COMMON_OLD} + -Wclobbered # gcc 4.3 + -Wmissing-parameter-type # gcc 4.3 + -Wold-style-declaration # gcc 4.3 + -Wstrict-aliasing=3 # gcc 4.0 + -Wtrampolines # gcc 4.3 + ) + endif() + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW) + list(APPEND WPICKY_ENABLE + -Wno-pedantic-ms-format # gcc 4.5 (mingw-only) + ) + endif() + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8) + list(APPEND WPICKY_ENABLE + -Wformat=2 # clang 3.0 gcc 4.8 + ) + endif() + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0) + list(APPEND WPICKY_ENABLE + -Warray-bounds=2 -ftree-vrp # clang 3.0 gcc 5.0 (clang default: -Warray-bounds) + ) + endif() + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0) + list(APPEND WPICKY_ENABLE + -Wduplicated-cond # gcc 6.0 + -Wnull-dereference # clang 3.0 gcc 6.0 (clang default) + -fdelete-null-pointer-checks + -Wshift-negative-value # clang 3.7 gcc 6.0 (clang default) + -Wshift-overflow=2 # clang 3.0 gcc 6.0 (clang default: -Wshift-overflow) + ) + endif() + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0) + list(APPEND WPICKY_ENABLE + -Walloc-zero # gcc 7.0 + -Wduplicated-branches # gcc 7.0 + -Wformat-overflow=2 # gcc 7.0 + -Wformat-truncation=2 # gcc 7.0 + -Wimplicit-fallthrough # clang 4.0 gcc 7.0 + -Wrestrict # gcc 7.0 + ) + endif() + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0) + list(APPEND WPICKY_ENABLE + -Warith-conversion # gcc 10.0 + ) + endif() + endif() + + # + + foreach(_CCOPT IN LISTS WPICKY_ENABLE) + set(WPICKY "${WPICKY} ${_CCOPT}") + endforeach() + + foreach(_CCOPT IN LISTS WPICKY_DETECT) + # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new + # test result in. + string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname) + # GCC only warns about unknown -Wno- options if there are also other diagnostic messages, + # so test for the positive form instead + string(REPLACE "-Wno-" "-W" _CCOPT_ON "${_CCOPT}") + check_c_compiler_flag(${_CCOPT_ON} ${_optvarname}) + if(${_optvarname}) + set(WPICKY "${WPICKY} ${_CCOPT}") + endif() + endforeach() + endif() +endif() + +if(WPICKY) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WPICKY}") + message(STATUS "Picky compiler options:${WPICKY}") +endif() diff --git a/CMake/Platforms/WindowsCache.cmake b/CMake/Platforms/WindowsCache.cmake new file mode 100644 index 0000000..d3391d9 --- /dev/null +++ b/CMake/Platforms/WindowsCache.cmake @@ -0,0 +1,188 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +if(NOT WIN32) + message(FATAL_ERROR "This file should be included on Windows platform only") +endif() + +set(HAVE_LOCALE_H 1) + +if(MINGW) + set(HAVE_SNPRINTF 1) + set(HAVE_UNISTD_H 1) + set(HAVE_LIBGEN_H 1) + set(HAVE_STDDEF_H 1) # detected by CMake internally in check_type_size() + set(HAVE_STDBOOL_H 1) + set(HAVE_BOOL_T "${HAVE_STDBOOL_H}") + set(HAVE_STRTOLL 1) + set(HAVE_BASENAME 1) + set(HAVE_STRCASECMP 1) + set(HAVE_FTRUNCATE 1) + set(HAVE_SYS_PARAM_H 1) + set(HAVE_SYS_TIME_H 1) + set(HAVE_GETTIMEOFDAY 1) +else() + set(HAVE_LIBGEN_H 0) + set(HAVE_STRCASECMP 0) + set(HAVE_FTRUNCATE 0) + set(HAVE_SYS_PARAM_H 0) + set(HAVE_SYS_TIME_H 0) + set(HAVE_GETTIMEOFDAY 0) + if(MSVC) + set(HAVE_UNISTD_H 0) + set(HAVE_LOCALE_H 1) + set(HAVE_STDDEF_H 1) # detected by CMake internally in check_type_size() + set(HAVE_STDATOMIC_H 0) + if(NOT MSVC_VERSION LESS 1800) + set(HAVE_STDBOOL_H 1) + set(HAVE_STRTOLL 1) + else() + set(HAVE_STDBOOL_H 0) + set(HAVE_STRTOLL 0) + endif() + set(HAVE_BOOL_T "${HAVE_STDBOOL_H}") + if(NOT MSVC_VERSION LESS 1900) + set(HAVE_SNPRINTF 1) + else() + set(HAVE_SNPRINTF 0) + endif() + set(HAVE_BASENAME 0) + set(HAVE_STRTOK_R 0) + set(HAVE_FILE_OFFSET_BITS 0) + set(HAVE_ATOMIC 0) + endif() +endif() + +# Available in Windows XP and newer +set(HAVE_GETADDRINFO 1) +set(HAVE_FREEADDRINFO 1) + +set(HAVE_FCHMOD 0) +set(HAVE_SOCKETPAIR 0) +set(HAVE_SENDMSG 0) +set(HAVE_ALARM 0) +set(HAVE_FCNTL 0) +set(HAVE_GETPPID 0) +set(HAVE_UTIMES 0) +set(HAVE_GETPWUID_R 0) +set(HAVE_STRERROR_R 0) +set(HAVE_SIGINTERRUPT 0) +set(HAVE_PIPE 0) +set(HAVE_IF_NAMETOINDEX 0) +set(HAVE_GETRLIMIT 0) +set(HAVE_SETRLIMIT 0) +set(HAVE_FSETXATTR 0) +set(HAVE_LIBSOCKET 0) +set(HAVE_SETLOCALE 1) +set(HAVE_SETMODE 1) +set(HAVE_GETPEERNAME 1) +set(HAVE_GETSOCKNAME 1) +set(HAVE_GETHOSTNAME 1) +set(HAVE_LIBZ 0) + +set(HAVE_RECV 1) +set(HAVE_SEND 1) +set(HAVE_STROPTS_H 0) +set(HAVE_SYS_XATTR_H 0) +set(HAVE_ARC4RANDOM 0) +set(HAVE_FNMATCH 0) +set(HAVE_SCHED_YIELD 0) +set(HAVE_ARPA_INET_H 0) +set(HAVE_FCNTL_H 1) +set(HAVE_IFADDRS_H 0) +set(HAVE_IO_H 1) +set(HAVE_NETDB_H 0) +set(HAVE_NETINET_IN_H 0) +set(HAVE_NETINET_TCP_H 0) +set(HAVE_NETINET_UDP_H 0) +set(HAVE_NET_IF_H 0) +set(HAVE_IOCTL_SIOCGIFADDR 0) +set(HAVE_POLL_H 0) +set(HAVE_POLL_FINE 0) +set(HAVE_PWD_H 0) +set(HAVE_STRINGS_H 0) # mingw-w64 has it (wrapper to string.h) +set(HAVE_SYS_FILIO_H 0) +set(HAVE_SYS_WAIT_H 0) +set(HAVE_SYS_IOCTL_H 0) +set(HAVE_SYS_POLL_H 0) +set(HAVE_SYS_RESOURCE_H 0) +set(HAVE_SYS_SELECT_H 0) +set(HAVE_SYS_SOCKET_H 0) +set(HAVE_SYS_SOCKIO_H 0) +set(HAVE_SYS_STAT_H 1) +set(HAVE_SYS_TYPES_H 1) +set(HAVE_SYS_UN_H 0) +set(HAVE_SYS_UTIME_H 1) +set(HAVE_TERMIOS_H 0) +set(HAVE_TERMIO_H 0) +set(HAVE_UTIME_H 0) # mingw-w64 has it (wrapper to sys/utime.h) + +set(HAVE_FSEEKO 0) +set(HAVE__FSEEKI64 1) +set(HAVE_SOCKET 1) +set(HAVE_SELECT 1) +set(HAVE_STRDUP 1) +set(HAVE_STRICMP 1) +set(HAVE_STRCMPI 1) +set(HAVE_MEMRCHR 0) +set(HAVE_CLOSESOCKET 1) +set(HAVE_SIGSETJMP 0) +set(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1) +set(HAVE_GETPASS_R 0) +set(HAVE_GETPWUID 0) +set(HAVE_GETEUID 0) +set(HAVE_UTIME 1) +set(HAVE_GMTIME_R 0) +set(HAVE_GETHOSTBYNAME_R 0) +set(HAVE_SIGNAL 1) +set(HAVE_SIGACTION 0) +set(HAVE_LINUX_TCP_H 0) +set(HAVE_GLIBC_STRERROR_R 0) +set(HAVE_MACH_ABSOLUTE_TIME 0) +set(HAVE_GETIFADDRS 0) +set(HAVE_FCNTL_O_NONBLOCK 0) +set(HAVE_IOCTLSOCKET 1) +set(HAVE_IOCTLSOCKET_CAMEL 0) +set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0) +set(HAVE_IOCTLSOCKET_FIONBIO 1) +set(HAVE_IOCTL_FIONBIO 0) +set(HAVE_SETSOCKOPT_SO_NONBLOCK 0) +set(HAVE_POSIX_STRERROR_R 0) +set(HAVE_BUILTIN_AVAILABLE 0) +set(HAVE_MSG_NOSIGNAL 0) +set(HAVE_STRUCT_TIMEVAL 1) +set(HAVE_STRUCT_SOCKADDR_STORAGE 1) + +set(HAVE_GETHOSTBYNAME_R_3 0) +set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0) +set(HAVE_GETHOSTBYNAME_R_5 0) +set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0) +set(HAVE_GETHOSTBYNAME_R_6 0) +set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0) + +set(HAVE_O_NONBLOCK 0) +set(HAVE_IN_ADDR_T 0) +set(STDC_HEADERS 1) + +set(HAVE_SIZEOF_SUSECONDS_T 0) +set(HAVE_SIZEOF_SA_FAMILY_T 0) diff --git a/CMake/Utilities.cmake b/CMake/Utilities.cmake new file mode 100644 index 0000000..9ff38e3 --- /dev/null +++ b/CMake/Utilities.cmake @@ -0,0 +1,35 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# File containing various utilities + +# Returns a list of arguments that evaluate to true +function(count_true output_count_var) + set(lst_len 0) + foreach(option_var IN LISTS ARGN) + if(${option_var}) + math(EXPR lst_len "${lst_len} + 1") + endif() + endforeach() + set(${output_count_var} ${lst_len} PARENT_SCOPE) +endfunction() diff --git a/CMake/cmake_uninstall.cmake.in b/CMake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..47aec8d --- /dev/null +++ b/CMake/cmake_uninstall.cmake.in @@ -0,0 +1,49 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") +endif() + +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") +endif() +message(${CMAKE_INSTALL_PREFIX}) + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif() + else() + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif() +endforeach() diff --git a/CMake/curl-config.cmake.in b/CMake/curl-config.cmake.in new file mode 100644 index 0000000..9adb96e --- /dev/null +++ b/CMake/curl-config.cmake.in @@ -0,0 +1,40 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +if(@USE_OPENSSL@) + find_dependency(OpenSSL @OPENSSL_VERSION_MAJOR@) +endif() +if(@USE_ZLIB@) + find_dependency(ZLIB @ZLIB_VERSION_MAJOR@) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") +check_required_components("@PROJECT_NAME@") + +# Alias for either shared or static library +if(NOT TARGET @PROJECT_NAME@::libcurl) + add_library(@PROJECT_NAME@::libcurl ALIAS @PROJECT_NAME@::@LIB_SELECTED@) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1b5ea67 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,1754 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# by Tetetest and Sukender (Benoit Neil) + +# Note: By default this CMake build script detects the version of some +# dependencies using `check_symbol_exists`. Those checks do not work +# in the case that both CURL and its dependency are included as +# sub-projects in a larger build using `FetchContent`. To support +# that case, additional variables may be defined by the parent +# project, ideally in the "extra" find package redirect file: +# https://cmake.org/cmake/help/latest/module/FetchContent.html#integrating-with-find-package +# +# The following variables are available: +# HAVE_SSL_SET0_WBIO: `SSL_set0_wbio` present in OpenSSL/wolfSSL +# HAVE_OPENSSL_SRP: `SSL_CTX_set_srp_username` present in OpenSSL/wolfSSL +# HAVE_GNUTLS_SRP: `gnutls_srp_verifier` present in GnuTLS +# HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL/wolfSSL +# HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in QUICHE +# +# For each of the above variables, if the variable is DEFINED (either +# to ON or OFF), the symbol detection will be skipped. If the +# variable is NOT DEFINED, the symbol detection will be performed. + +cmake_minimum_required(VERSION 3.7...3.16 FATAL_ERROR) +message(STATUS "Using CMake version ${CMAKE_VERSION}") + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") +include(Utilities) +include(Macros) +include(CMakeDependentOption) +include(CheckCCompilerFlag) + +project(CURL C) + +file(STRINGS ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS REGEX "#define LIBCURL_VERSION( |_NUM )") +string(REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" + CURL_VERSION ${CURL_VERSION_H_CONTENTS}) +string(REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION}) +string(REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+" + CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS}) +string(REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM}) + + +# Setup package meta-data +# SET(PACKAGE "curl") +message(STATUS "curl version=[${CURL_VERSION}]") +# SET(PACKAGE_TARNAME "curl") +# SET(PACKAGE_NAME "curl") +# SET(PACKAGE_VERSION "-") +# SET(PACKAGE_STRING "curl-") +# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.se/mail/") +set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}") +if(CMAKE_C_COMPILER_TARGET) + set(OS "\"${CMAKE_C_COMPILER_TARGET}\"") +else() + set(OS "\"${CMAKE_SYSTEM_NAME}\"") +endif() + +include_directories(${CURL_SOURCE_DIR}/include) + +set(CMAKE_UNITY_BUILD_BATCH_SIZE 0) + +option(CURL_WERROR "Turn compiler warnings into errors" OFF) +option(PICKY_COMPILER "Enable picky compiler options" ON) +option(BUILD_CURL_EXE "Set to ON to build curl executable." ON) +option(BUILD_SHARED_LIBS "Build shared libraries" ON) +option(BUILD_STATIC_LIBS "Build static libraries" OFF) +option(BUILD_STATIC_CURL "Build curl executable with static libcurl" OFF) +option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) +option(CURL_DISABLE_INSTALL "Set to ON to disable installation targets" OFF) + +if(WIN32) + option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF) + option(ENABLE_UNICODE "Set to ON to use the Unicode version of the Windows API functions" OFF) + set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string") + if(CURL_TARGET_WINDOWS_VERSION) + add_definitions(-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}) + set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}") + endif() + if(ENABLE_UNICODE) + add_definitions(-DUNICODE -D_UNICODE) + if(MINGW) + add_compile_options(-municode) + endif() + endif() +endif() +option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF) + +cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup" + ON "NOT ENABLE_ARES" + OFF) + +option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF) +option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF) + +include(PickyWarnings) + +if(ENABLE_DEBUG) + # DEBUGBUILD will be defined only for Debug builds + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$:DEBUGBUILD>) + set(ENABLE_CURLDEBUG ON) +endif() + +if(ENABLE_CURLDEBUG) + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG) +endif() + +# For debug libs and exes, add "-d" postfix +if(NOT DEFINED CMAKE_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "-d") +endif() + +set(LIB_STATIC "libcurl_static") +set(LIB_SHARED "libcurl_shared") + +if(NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS) + set(BUILD_STATIC_LIBS ON) +endif() +if(NOT BUILD_STATIC_CURL AND NOT BUILD_SHARED_LIBS) + set(BUILD_STATIC_CURL ON) +elseif(BUILD_STATIC_CURL AND NOT BUILD_STATIC_LIBS) + set(BUILD_STATIC_CURL OFF) +endif() + +# lib flavour selected for curl tool +if(BUILD_STATIC_CURL) + set(LIB_SELECTED_FOR_EXE ${LIB_STATIC}) +else() + set(LIB_SELECTED_FOR_EXE ${LIB_SHARED}) +endif() + +# lib flavour selected for example and test programs. +if(BUILD_SHARED_LIBS) + set(LIB_SELECTED ${LIB_SHARED}) +else() + set(LIB_SELECTED ${LIB_STATIC}) +endif() + +# initialize CURL_LIBS +set(CURL_LIBS "") + +if(ENABLE_ARES) + set(USE_ARES 1) + find_package(CARES REQUIRED) + list(APPEND CURL_LIBS ${CARES_LIBRARY}) +endif() + +include(CurlSymbolHiding) + +option(CURL_ENABLE_EXPORT_TARGET "to enable cmake export target" ON) +mark_as_advanced(CURL_ENABLE_EXPORT_TARGET) + +option(CURL_DISABLE_ALTSVC "disables alt-svc support" OFF) +mark_as_advanced(CURL_DISABLE_ALTSVC) +option(CURL_DISABLE_SRP "disables TLS-SRP support" OFF) +mark_as_advanced(CURL_DISABLE_SRP) +option(CURL_DISABLE_COOKIES "disables cookies support" OFF) +mark_as_advanced(CURL_DISABLE_COOKIES) +option(CURL_DISABLE_BASIC_AUTH "disables Basic authentication" OFF) +mark_as_advanced(CURL_DISABLE_BASIC_AUTH) +option(CURL_DISABLE_BEARER_AUTH "disables Bearer authentication" OFF) +mark_as_advanced(CURL_DISABLE_BEARER_AUTH) +option(CURL_DISABLE_DIGEST_AUTH "disables Digest authentication" OFF) +mark_as_advanced(CURL_DISABLE_DIGEST_AUTH) +option(CURL_DISABLE_KERBEROS_AUTH "disables Kerberos authentication" OFF) +mark_as_advanced(CURL_DISABLE_KERBEROS_AUTH) +option(CURL_DISABLE_NEGOTIATE_AUTH "disables negotiate authentication" OFF) +mark_as_advanced(CURL_DISABLE_NEGOTIATE_AUTH) +option(CURL_DISABLE_AWS "disables AWS-SIG4" OFF) +mark_as_advanced(CURL_DISABLE_AWS) +option(CURL_DISABLE_DICT "disables DICT" OFF) +mark_as_advanced(CURL_DISABLE_DICT) +option(CURL_DISABLE_DOH "disables DNS-over-HTTPS" OFF) +mark_as_advanced(CURL_DISABLE_DOH) +option(CURL_DISABLE_FILE "disables FILE" OFF) +mark_as_advanced(CURL_DISABLE_FILE) +cmake_dependent_option(CURL_DISABLE_FORM_API "disables form api" OFF + "NOT CURL_DISABLE_MIME" ON) +mark_as_advanced(CURL_DISABLE_FORM_API) +option(CURL_DISABLE_FTP "disables FTP" OFF) +mark_as_advanced(CURL_DISABLE_FTP) +option(CURL_DISABLE_GETOPTIONS "disables curl_easy_options API for existing options to curl_easy_setopt" OFF) +mark_as_advanced(CURL_DISABLE_GETOPTIONS) +option(CURL_DISABLE_GOPHER "disables Gopher" OFF) +mark_as_advanced(CURL_DISABLE_GOPHER) +option(CURL_DISABLE_HEADERS_API "disables headers-api support" OFF) +mark_as_advanced(CURL_DISABLE_HEADERS_API) +option(CURL_DISABLE_HSTS "disables HSTS support" OFF) +mark_as_advanced(CURL_DISABLE_HSTS) +option(CURL_DISABLE_HTTP "disables HTTP" OFF) +mark_as_advanced(CURL_DISABLE_HTTP) +option(CURL_DISABLE_HTTP_AUTH "disables all HTTP authentication methods" OFF) +mark_as_advanced(CURL_DISABLE_HTTP_AUTH) +option(CURL_DISABLE_IMAP "disables IMAP" OFF) +mark_as_advanced(CURL_DISABLE_IMAP) +option(CURL_DISABLE_LDAP "disables LDAP" OFF) +mark_as_advanced(CURL_DISABLE_LDAP) +option(CURL_DISABLE_LDAPS "disables LDAPS" OFF) +mark_as_advanced(CURL_DISABLE_LDAPS) +option(CURL_DISABLE_LIBCURL_OPTION "disables --libcurl option from the curl tool" OFF) +mark_as_advanced(CURL_DISABLE_LIBCURL_OPTION) +option(CURL_DISABLE_MIME "disables MIME support" OFF) +mark_as_advanced(CURL_DISABLE_MIME) +option(CURL_DISABLE_MQTT "disables MQTT" OFF) +mark_as_advanced(CURL_DISABLE_BINDLOCAL) +option(CURL_DISABLE_BINDLOCAL "disables local binding support" OFF) +mark_as_advanced(CURL_DISABLE_MQTT) +option(CURL_DISABLE_NETRC "disables netrc parser" OFF) +mark_as_advanced(CURL_DISABLE_NETRC) +option(CURL_DISABLE_NTLM "disables NTLM support" OFF) +mark_as_advanced(CURL_DISABLE_NTLM) +option(CURL_DISABLE_PARSEDATE "disables date parsing" OFF) +mark_as_advanced(CURL_DISABLE_PARSEDATE) +option(CURL_DISABLE_POP3 "disables POP3" OFF) +mark_as_advanced(CURL_DISABLE_POP3) +option(CURL_DISABLE_PROGRESS_METER "disables built-in progress meter" OFF) +mark_as_advanced(CURL_DISABLE_PROGRESS_METER) +option(CURL_DISABLE_PROXY "disables proxy support" OFF) +mark_as_advanced(CURL_DISABLE_PROXY) +option(CURL_DISABLE_RTSP "disables RTSP" OFF) +mark_as_advanced(CURL_DISABLE_RTSP) +option(CURL_DISABLE_SHUFFLE_DNS "disables shuffle DNS feature" OFF) +mark_as_advanced(CURL_DISABLE_SHUFFLE_DNS) +option(CURL_DISABLE_SMB "disables SMB" OFF) +mark_as_advanced(CURL_DISABLE_SMB) +option(CURL_DISABLE_SMTP "disables SMTP" OFF) +mark_as_advanced(CURL_DISABLE_SMTP) +option(CURL_DISABLE_SOCKETPAIR "disables use of socketpair for curl_multi_poll" OFF) +mark_as_advanced(CURL_DISABLE_SOCKETPAIR) +option(CURL_DISABLE_TELNET "disables Telnet" OFF) +mark_as_advanced(CURL_DISABLE_TELNET) +option(CURL_DISABLE_TFTP "disables TFTP" OFF) +mark_as_advanced(CURL_DISABLE_TFTP) +option(CURL_DISABLE_VERBOSE_STRINGS "disables verbose strings" OFF) +mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS) + +# Corresponds to HTTP_ONLY in lib/curl_setup.h +option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) +mark_as_advanced(HTTP_ONLY) + +if(HTTP_ONLY) + set(CURL_DISABLE_DICT ON) + set(CURL_DISABLE_FILE ON) + set(CURL_DISABLE_FTP ON) + set(CURL_DISABLE_GOPHER ON) + set(CURL_DISABLE_IMAP ON) + set(CURL_DISABLE_LDAP ON) + set(CURL_DISABLE_LDAPS ON) + set(CURL_DISABLE_MQTT ON) + set(CURL_DISABLE_POP3 ON) + set(CURL_DISABLE_RTSP ON) + set(CURL_DISABLE_SMB ON) + set(CURL_DISABLE_SMTP ON) + set(CURL_DISABLE_TELNET ON) + set(CURL_DISABLE_TFTP ON) +endif() + +option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON) +mark_as_advanced(ENABLE_IPV6) +if(ENABLE_IPV6 AND NOT WIN32) + include(CheckStructHasMember) + check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" + HAVE_SOCKADDR_IN6_SIN6_ADDR) + check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h" + HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) + if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR) + message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support") + # Force the feature off as this name is used as guard macro... + set(ENABLE_IPV6 OFF + CACHE BOOL "Define if you want to enable IPv6 support" FORCE) + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT ENABLE_ARES) + set(use_core_foundation_and_core_services ON) + + find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration") + if(NOT SYSTEMCONFIGURATION_FRAMEWORK) + message(FATAL_ERROR "SystemConfiguration framework not found") + endif() + + list(APPEND CURL_LIBS "-framework SystemConfiguration") + endif() +endif() + +find_package(Perl) + +option(BUILD_LIBCURL_DOCS "to build libcurl man pages" ON) +# curl source release tarballs come with the curl man page pre-built. +option(ENABLE_CURL_MANUAL "to build the man page for curl and enable its -M/--manual option" OFF) + +if(ENABLE_CURL_MANUAL OR BUILD_LIBCURL_DOCS) + if(PERL_FOUND) + curl_nroff_check() + if(NROFF_USEFUL) + set(HAVE_MANUAL_TOOLS ON) + endif() + endif() + if(NOT HAVE_MANUAL_TOOLS) + message(WARNING "Perl not found, or nroff not useful. Will not build manuals.") + endif() +endif() + +if(CURL_STATIC_CRT) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") +endif() + +# Disable warnings on Borland to avoid changing 3rd party code. +if(BORLAND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-") +endif() + +# If we are on AIX, do the _ALL_SOURCE magic +if(${CMAKE_SYSTEM_NAME} MATCHES AIX) + set(_ALL_SOURCE 1) +endif() + +# If we are on Haiku, make sure that the network library is brought in. +if(${CMAKE_SYSTEM_NAME} MATCHES Haiku) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lnetwork") +endif() + +# Include all the necessary files for macros +include(CMakePushCheckState) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckIncludeFiles) +include(CheckLibraryExists) +include(CheckSymbolExists) +include(CheckTypeSize) +include(CheckCSourceCompiles) + +# On windows preload settings +if(WIN32) + include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake) +endif() + +if(ENABLE_THREADED_RESOLVER) + if(WIN32) + set(USE_THREADS_WIN32 ON) + else() + find_package(Threads REQUIRED) + set(USE_THREADS_POSIX ${CMAKE_USE_PTHREADS_INIT}) + set(HAVE_PTHREAD_H ${CMAKE_USE_PTHREADS_INIT}) + set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + endif() +endif() + +# Check for all needed libraries +check_library_exists("socket" "connect" "" HAVE_LIBSOCKET) +if(HAVE_LIBSOCKET) + set(CURL_LIBS "socket;${CURL_LIBS}") +endif() + +check_function_exists(gethostname HAVE_GETHOSTNAME) + +if(WIN32) + list(APPEND CURL_LIBS "ws2_32" "bcrypt") + if(USE_LIBRTMP) + list(APPEND CURL_LIBS "winmm") + endif() +endif() + +# check SSL libraries +option(CURL_ENABLE_SSL "Enable SSL support" ON) + +if(CURL_DEFAULT_SSL_BACKEND) + set(valid_default_ssl_backend FALSE) +endif() + +if(APPLE) + cmake_dependent_option(CURL_USE_SECTRANSP "Enable Apple OS native SSL/TLS" OFF CURL_ENABLE_SSL OFF) +endif() +if(WIN32) + cmake_dependent_option(CURL_USE_SCHANNEL "Enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF) + cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without OpenSSL" ON + CURL_USE_SCHANNEL OFF) +endif() +cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF) +cmake_dependent_option(CURL_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF) +cmake_dependent_option(CURL_USE_WOLFSSL "Enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF) +cmake_dependent_option(CURL_USE_GNUTLS "Enable GnuTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF) + +set(openssl_default ON) +if(WIN32 OR CURL_USE_SECTRANSP OR CURL_USE_SCHANNEL OR CURL_USE_MBEDTLS OR CURL_USE_WOLFSSL) + set(openssl_default OFF) +endif() +cmake_dependent_option(CURL_USE_OPENSSL "Enable OpenSSL for SSL/TLS" ${openssl_default} CURL_ENABLE_SSL OFF) +option(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG "Disable automatic loading of OpenSSL configuration" OFF) + +count_true(enabled_ssl_options_count + CURL_USE_SCHANNEL + CURL_USE_SECTRANSP + CURL_USE_OPENSSL + CURL_USE_MBEDTLS + CURL_USE_BEARSSL + CURL_USE_WOLFSSL +) +if(enabled_ssl_options_count GREATER "1") + set(CURL_WITH_MULTI_SSL ON) +endif() + +if(CURL_USE_SCHANNEL) + set(SSL_ENABLED ON) + set(USE_SCHANNEL ON) # Windows native SSL/TLS support + set(USE_WINDOWS_SSPI ON) # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI + + if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "schannel") + set(valid_default_ssl_backend TRUE) + endif() +endif() +if(CURL_WINDOWS_SSPI) + set(USE_WINDOWS_SSPI ON) +endif() + +if(CURL_USE_SECTRANSP) + set(use_core_foundation_and_core_services ON) + + find_library(SECURITY_FRAMEWORK "Security") + if(NOT SECURITY_FRAMEWORK) + message(FATAL_ERROR "Security framework not found") + endif() + + set(SSL_ENABLED ON) + set(USE_SECTRANSP ON) + list(APPEND CURL_LIBS "-framework Security") + + if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "secure-transport") + set(valid_default_ssl_backend TRUE) + endif() +endif() + +if(use_core_foundation_and_core_services) + find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation") + find_library(CORESERVICES_FRAMEWORK "CoreServices") + + if(NOT COREFOUNDATION_FRAMEWORK) + message(FATAL_ERROR "CoreFoundation framework not found") + endif() + if(NOT CORESERVICES_FRAMEWORK) + message(FATAL_ERROR "CoreServices framework not found") + endif() + + list(APPEND CURL_LIBS "-framework CoreFoundation -framework CoreServices") +endif() + +if(CURL_USE_OPENSSL) + find_package(OpenSSL REQUIRED) + set(SSL_ENABLED ON) + set(USE_OPENSSL ON) + + # Depend on OpenSSL via imported targets if supported by the running + # version of CMake. This allows our dependents to get our dependencies + # transitively. + if(NOT CMAKE_VERSION VERSION_LESS 3.4) + list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto) + else() + list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES}) + include_directories(${OPENSSL_INCLUDE_DIR}) + endif() + + if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "openssl") + set(valid_default_ssl_backend TRUE) + endif() + + set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + if(NOT DEFINED HAVE_BORINGSSL) + check_symbol_exists(OPENSSL_IS_BORINGSSL "openssl/base.h" HAVE_BORINGSSL) + endif() + if(NOT DEFINED HAVE_AWSLC) + check_symbol_exists(OPENSSL_IS_AWSLC "openssl/base.h" HAVE_AWSLC) + endif() +endif() + +if(CURL_USE_MBEDTLS) + find_package(MbedTLS REQUIRED) + set(SSL_ENABLED ON) + set(USE_MBEDTLS ON) + list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES}) + include_directories(${MBEDTLS_INCLUDE_DIRS}) + + if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "mbedtls") + set(valid_default_ssl_backend TRUE) + endif() +endif() + +if(CURL_USE_BEARSSL) + find_package(BearSSL REQUIRED) + set(SSL_ENABLED ON) + set(USE_BEARSSL ON) + list(APPEND CURL_LIBS ${BEARSSL_LIBRARY}) + include_directories(${BEARSSL_INCLUDE_DIRS}) + + if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "bearssl") + set(valid_default_ssl_backend TRUE) + endif() +endif() + +if(CURL_USE_WOLFSSL) + find_package(WolfSSL REQUIRED) + set(SSL_ENABLED ON) + set(USE_WOLFSSL ON) + list(APPEND CURL_LIBS ${WolfSSL_LIBRARIES}) + include_directories(${WolfSSL_INCLUDE_DIRS}) + + if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "wolfssl") + set(valid_default_ssl_backend TRUE) + endif() +endif() + +if(CURL_USE_GNUTLS) + find_package(GnuTLS REQUIRED) + set(SSL_ENABLED ON) + set(USE_GNUTLS ON) + list(APPEND CURL_LIBS ${GNUTLS_LIBRARIES} "nettle") + include_directories(${GNUTLS_INCLUDE_DIRS}) + + if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "gnutls") + set(valid_default_ssl_backend TRUE) + endif() + + if(NOT DEFINED HAVE_GNUTLS_SRP AND NOT CURL_DISABLE_SRP) + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${GNUTLS_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${GNUTLS_LIBRARIES}) + check_symbol_exists(gnutls_srp_verifier "gnutls/gnutls.h" HAVE_GNUTLS_SRP) + cmake_pop_check_state() + endif() +endif() + +if(CURL_DEFAULT_SSL_BACKEND AND NOT valid_default_ssl_backend) + message(FATAL_ERROR "CURL_DEFAULT_SSL_BACKEND '${CURL_DEFAULT_SSL_BACKEND}' not enabled.") +endif() + +# Keep ZLIB detection after TLS detection, +# and before calling openssl_check_symbol_exists(). + +set(HAVE_LIBZ OFF) +set(USE_ZLIB OFF) +optional_dependency(ZLIB) +if(ZLIB_FOUND) + set(HAVE_LIBZ ON) + set(USE_ZLIB ON) + + # Depend on ZLIB via imported targets if supported by the running + # version of CMake. This allows our dependents to get our dependencies + # transitively. + if(NOT CMAKE_VERSION VERSION_LESS 3.4) + list(APPEND CURL_LIBS ZLIB::ZLIB) + else() + list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) + include_directories(${ZLIB_INCLUDE_DIRS}) + endif() + list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) +endif() + +option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF) +set(HAVE_BROTLI OFF) +if(CURL_BROTLI) + find_package(Brotli REQUIRED) + if(BROTLI_FOUND) + set(HAVE_BROTLI ON) + set(CURL_LIBS "${BROTLI_LIBRARIES};${CURL_LIBS}") # For 'ld' linker. Emulate `list(PREPEND ...)` to stay compatible with \n") + endforeach() + + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DLDAP_DEPRECATED=1) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) + set(CURL_LIBS "${CMAKE_LDAP_LIB};${CURL_LIBS}") + if(HAVE_LIBLBER) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) + set(CURL_LIBS "${CMAKE_LBER_LIB};${CURL_LIBS}") + endif() + + check_c_source_compiles(" + ${_INCLUDE_STRING} + int main(int argc, char ** argv) + { + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + ber_free(bep, 1); + return 0; + }" NOT_NEED_LBER_H) + if(NOT_NEED_LBER_H) + set(NEED_LBER_H OFF) + else() + set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H") + endif() + + check_function_exists(ldap_url_parse HAVE_LDAP_URL_PARSE) + check_function_exists(ldap_init_fd HAVE_LDAP_INIT_FD) + + unset(CMAKE_REQUIRED_LIBRARIES) + + check_include_file("ldap_ssl.h" HAVE_LDAP_SSL_H) + + if(HAVE_LDAP_INIT_FD) + set(USE_OPENLDAP ON) + add_definitions("-DLDAP_DEPRECATED=1") + endif() + if(NOT CURL_DISABLE_LDAPS) + set(HAVE_LDAP_SSL ON) + endif() + endif() + endif() +endif() + +# No ldap, no ldaps. +if(CURL_DISABLE_LDAP) + if(NOT CURL_DISABLE_LDAPS) + message(STATUS "LDAP needs to be enabled to support LDAPS") + set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE) + endif() +endif() + +# Check for idn2 +option(USE_LIBIDN2 "Use libidn2 for IDN support" ON) +if(USE_LIBIDN2) + check_library_exists("idn2" "idn2_lookup_ul" "" HAVE_LIBIDN2) + if(HAVE_LIBIDN2) + set(CURL_LIBS "idn2;${CURL_LIBS}") + check_include_file_concat("idn2.h" HAVE_IDN2_H) + endif() +else() + set(HAVE_LIBIDN2 OFF) +endif() + +if(WIN32) + option(USE_WIN32_IDN "Use WinIDN for IDN support" OFF) + if(USE_WIN32_IDN) + list(APPEND CURL_LIBS "normaliz") + endif() +endif() + +#libpsl +option(CURL_USE_LIBPSL "Use libPSL" ON) +mark_as_advanced(CURL_USE_LIBPSL) +set(USE_LIBPSL OFF) + +if(CURL_USE_LIBPSL) + find_package(LibPSL) + if(LIBPSL_FOUND) + list(APPEND CURL_LIBS ${LIBPSL_LIBRARY}) + list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBPSL_INCLUDE_DIR}") + include_directories("${LIBPSL_INCLUDE_DIR}") + set(USE_LIBPSL ON) + endif() +endif() + +#libSSH2 +option(CURL_USE_LIBSSH2 "Use libSSH2" ON) +mark_as_advanced(CURL_USE_LIBSSH2) +set(USE_LIBSSH2 OFF) + +if(CURL_USE_LIBSSH2) + find_package(LibSSH2) + if(LIBSSH2_FOUND) + list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY}) + list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") + include_directories("${LIBSSH2_INCLUDE_DIR}") + set(USE_LIBSSH2 ON) + endif() +endif() + +# libssh +option(CURL_USE_LIBSSH "Use libSSH" OFF) +mark_as_advanced(CURL_USE_LIBSSH) +if(NOT USE_LIBSSH2 AND CURL_USE_LIBSSH) + find_package(libssh CONFIG) + if(libssh_FOUND) + message(STATUS "Found libssh ${libssh_VERSION}") + # Use imported target for include and library paths. + list(APPEND CURL_LIBS ssh) + set(USE_LIBSSH ON) + endif() +endif() + +option(CURL_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF) +mark_as_advanced(CURL_USE_GSSAPI) + +if(CURL_USE_GSSAPI) + find_package(GSS) + + set(HAVE_GSSAPI ${GSS_FOUND}) + if(GSS_FOUND) + + message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"") + + list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR}) + check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) + check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) + check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H) + + if(NOT GSS_FLAVOUR STREQUAL "Heimdal") + # MIT + set(_INCLUDE_LIST "") + if(HAVE_GSSAPI_GSSAPI_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi.h") + endif() + if(HAVE_GSSAPI_GSSAPI_GENERIC_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h") + endif() + if(HAVE_GSSAPI_GSSAPI_KRB5_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h") + endif() + + string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}") + string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}") + + foreach(_dir ${GSS_LINK_DIRECTORIES}) + set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"") + endforeach() + + if(NOT DEFINED HAVE_GSS_C_NT_HOSTBASED_SERVICE) + set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}") + set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES}) + check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE) + unset(CMAKE_REQUIRED_LIBRARIES) + endif() + if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) + set(HAVE_OLD_GSSMIT ON) + endif() + endif() + + include_directories(${GSS_INCLUDE_DIR}) + link_directories(${GSS_LINK_DIRECTORIES}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}") + string(REPLACE ";" " " GSS_LINKER_FLAGS "${GSS_LINKER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") + list(APPEND CURL_LIBS ${GSS_LIBRARIES}) + + else() + message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.") + endif() +endif() + +option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON) +if(ENABLE_UNIX_SOCKETS) + include(CheckStructHasMember) + if(WIN32) + set(USE_UNIX_SOCKETS ON) + else() + check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) + endif() +else() + unset(USE_UNIX_SOCKETS CACHE) +endif() + + +# +# CA handling +# +set(CURL_CA_BUNDLE "auto" CACHE STRING + "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") +set(CURL_CA_FALLBACK OFF CACHE BOOL + "Set ON to use built-in CA store of TLS backend. Defaults to OFF") +set(CURL_CA_PATH "auto" CACHE STRING + "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") + +if("${CURL_CA_BUNDLE}" STREQUAL "") + message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.") +elseif("${CURL_CA_BUNDLE}" STREQUAL "none") + unset(CURL_CA_BUNDLE CACHE) +elseif("${CURL_CA_BUNDLE}" STREQUAL "auto") + unset(CURL_CA_BUNDLE CACHE) + if(NOT CMAKE_CROSSCOMPILING) + set(CURL_CA_BUNDLE_AUTODETECT TRUE) + endif() +else() + set(CURL_CA_BUNDLE_SET TRUE) +endif() + +if("${CURL_CA_PATH}" STREQUAL "") + message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.") +elseif("${CURL_CA_PATH}" STREQUAL "none") + unset(CURL_CA_PATH CACHE) +elseif("${CURL_CA_PATH}" STREQUAL "auto") + unset(CURL_CA_PATH CACHE) + if(NOT CMAKE_CROSSCOMPILING) + set(CURL_CA_PATH_AUTODETECT TRUE) + endif() +else() + set(CURL_CA_PATH_SET TRUE) +endif() + +if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT) + # Skip autodetection of unset CA path because CA bundle is set explicitly +elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT) + # Skip autodetection of unset CA bundle because CA path is set explicitly +elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT) + # first try autodetecting a CA bundle, then a CA path + + if(CURL_CA_BUNDLE_AUTODETECT) + set(SEARCH_CA_BUNDLE_PATHS + /etc/ssl/certs/ca-certificates.crt + /etc/pki/tls/certs/ca-bundle.crt + /usr/share/ssl/certs/ca-bundle.crt + /usr/local/share/certs/ca-root-nss.crt + /etc/ssl/cert.pem) + + foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS}) + if(EXISTS "${SEARCH_CA_BUNDLE_PATH}") + message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}") + set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}" CACHE STRING + "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") + set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set") + break() + endif() + endforeach() + endif() + + if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET)) + if(EXISTS "/etc/ssl/certs") + set(CURL_CA_PATH "/etc/ssl/certs" CACHE STRING + "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") + set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set") + endif() + endif() +endif() + +if(CURL_CA_PATH_SET AND + NOT USE_OPENSSL AND + NOT USE_WOLFSSL AND + NOT USE_GNUTLS AND + NOT USE_MBEDTLS) + message(STATUS + "CA path only supported by OpenSSL, wolfSSL, GnuTLS or mbedTLS. " + "Set CURL_CA_PATH=none or enable one of those TLS backends.") +endif() + +# Check for header files +if(WIN32) + set(CURL_INCLUDES ${CURL_INCLUDES} "winsock2.h") + set(CURL_INCLUDES ${CURL_INCLUDES} "ws2tcpip.h") + set(CURL_INCLUDES ${CURL_INCLUDES} "windows.h") +endif() + +if(WIN32) + # detect actual value of _WIN32_WINNT and store as HAVE_WIN32_WINNT + curl_internal_test(HAVE_WIN32_WINNT) + if(HAVE_WIN32_WINNT) + string(REGEX MATCH ".*_WIN32_WINNT=0x[0-9a-fA-F]+" OUTPUT "${OUTPUT}") + string(REGEX REPLACE ".*_WIN32_WINNT=" "" OUTPUT "${OUTPUT}") + string(REGEX REPLACE "0x([0-9a-f][0-9a-f][0-9a-f])$" "0x0\\1" OUTPUT "${OUTPUT}") # pad to 4 digits + string(TOLOWER "${OUTPUT}" HAVE_WIN32_WINNT) + message(STATUS "Found _WIN32_WINNT=${HAVE_WIN32_WINNT}") + endif() + # avoid storing HAVE_WIN32_WINNT in CMake cache + unset(HAVE_WIN32_WINNT CACHE) + + if(HAVE_WIN32_WINNT) + if(HAVE_WIN32_WINNT STRLESS "0x0501") + # Windows XP is required for freeaddrinfo, getaddrinfo + message(FATAL_ERROR "Building for Windows XP or newer is required.") + endif() + + # pre-fill detection results based on target OS version + if(MINGW OR MSVC) + if(HAVE_WIN32_WINNT STRLESS "0x0600") + set(HAVE_INET_NTOP 0) + set(HAVE_INET_PTON 0) + else() # Windows Vista or newer + set(HAVE_INET_NTOP 1) + set(HAVE_INET_PTON 1) + endif() + unset(HAVE_INET_NTOP CACHE) + unset(HAVE_INET_PTON CACHE) + endif() + endif() +endif() + +check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H) +check_include_file_concat("sys/wait.h" HAVE_SYS_WAIT_H) +check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H) +check_include_file_concat("sys/param.h" HAVE_SYS_PARAM_H) +check_include_file_concat("sys/poll.h" HAVE_SYS_POLL_H) +check_include_file_concat("sys/resource.h" HAVE_SYS_RESOURCE_H) +check_include_file_concat("sys/select.h" HAVE_SYS_SELECT_H) +check_include_file_concat("sys/socket.h" HAVE_SYS_SOCKET_H) +check_include_file_concat("sys/sockio.h" HAVE_SYS_SOCKIO_H) +check_include_file_concat("sys/stat.h" HAVE_SYS_STAT_H) +check_include_file_concat("sys/time.h" HAVE_SYS_TIME_H) +check_include_file_concat("sys/types.h" HAVE_SYS_TYPES_H) +check_include_file_concat("sys/un.h" HAVE_SYS_UN_H) +check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H) +check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H) +check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H) +check_include_file_concat("fcntl.h" HAVE_FCNTL_H) +check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) +check_include_file_concat("io.h" HAVE_IO_H) +check_include_file_concat("libgen.h" HAVE_LIBGEN_H) +check_include_file_concat("locale.h" HAVE_LOCALE_H) +check_include_file_concat("net/if.h" HAVE_NET_IF_H) +check_include_file_concat("netdb.h" HAVE_NETDB_H) +check_include_file_concat("netinet/in.h" HAVE_NETINET_IN_H) +check_include_file_concat("netinet/tcp.h" HAVE_NETINET_TCP_H) +check_include_file_concat("netinet/udp.h" HAVE_NETINET_UDP_H) +check_include_file("linux/tcp.h" HAVE_LINUX_TCP_H) + +check_include_file_concat("poll.h" HAVE_POLL_H) +check_include_file_concat("pwd.h" HAVE_PWD_H) +check_include_file_concat("stdatomic.h" HAVE_STDATOMIC_H) +check_include_file_concat("stdbool.h" HAVE_STDBOOL_H) +check_include_file_concat("strings.h" HAVE_STRINGS_H) +check_include_file_concat("stropts.h" HAVE_STROPTS_H) +check_include_file_concat("termio.h" HAVE_TERMIO_H) +check_include_file_concat("termios.h" HAVE_TERMIOS_H) +check_include_file_concat("unistd.h" HAVE_UNISTD_H) +check_include_file_concat("utime.h" HAVE_UTIME_H) + +check_type_size(size_t SIZEOF_SIZE_T) +check_type_size(ssize_t SIZEOF_SSIZE_T) +check_type_size("long long" SIZEOF_LONG_LONG) +check_type_size("long" SIZEOF_LONG) +check_type_size("int" SIZEOF_INT) +check_type_size("__int64" SIZEOF___INT64) +check_type_size("time_t" SIZEOF_TIME_T) +check_type_size("suseconds_t" SIZEOF_SUSECONDS_T) +if(NOT HAVE_SIZEOF_SSIZE_T) + if(SIZEOF_LONG EQUAL SIZEOF_SIZE_T) + set(ssize_t long) + endif() + if(NOT ssize_t AND SIZEOF___INT64 EQUAL SIZEOF_SIZE_T) + set(ssize_t __int64) + endif() +endif() +# off_t is sized later, after the HAVE_FILE_OFFSET_BITS test + +if(SIZEOF_LONG_LONG) + set(HAVE_LONGLONG 1) +endif() +if(SIZEOF_SUSECONDS_T) + set(HAVE_SUSECONDS_T 1) +endif() + +if(NOT CMAKE_CROSSCOMPILING) + find_file(RANDOM_FILE urandom /dev) + mark_as_advanced(RANDOM_FILE) +endif() + +# Check for some functions that are used +if(WIN32) + set(CMAKE_REQUIRED_LIBRARIES ws2_32) +elseif(HAVE_LIBSOCKET) + set(CMAKE_REQUIRED_LIBRARIES socket) +endif() + +check_symbol_exists(fnmatch "${CURL_INCLUDES};fnmatch.h" HAVE_FNMATCH) +check_symbol_exists(basename "${CURL_INCLUDES};string.h" HAVE_BASENAME) +check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET) +check_symbol_exists(sched_yield "${CURL_INCLUDES};sched.h" HAVE_SCHED_YIELD) +check_symbol_exists(socketpair "${CURL_INCLUDES}" HAVE_SOCKETPAIR) +check_symbol_exists(recv "${CURL_INCLUDES}" HAVE_RECV) +check_symbol_exists(send "${CURL_INCLUDES}" HAVE_SEND) +check_symbol_exists(sendmsg "${CURL_INCLUDES}" HAVE_SENDMSG) +check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT) +check_symbol_exists(strdup "${CURL_INCLUDES};string.h" HAVE_STRDUP) +check_symbol_exists(strtok_r "${CURL_INCLUDES};string.h" HAVE_STRTOK_R) +check_symbol_exists(strcasecmp "${CURL_INCLUDES};string.h" HAVE_STRCASECMP) +check_symbol_exists(stricmp "${CURL_INCLUDES};string.h" HAVE_STRICMP) +check_symbol_exists(strcmpi "${CURL_INCLUDES};string.h" HAVE_STRCMPI) +check_symbol_exists(memrchr "${CURL_INCLUDES};string.h" HAVE_MEMRCHR) +check_symbol_exists(alarm "${CURL_INCLUDES}" HAVE_ALARM) +check_symbol_exists(arc4random "${CURL_INCLUDES};stdlib.h" HAVE_ARC4RANDOM) +check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) +check_symbol_exists(getppid "${CURL_INCLUDES}" HAVE_GETPPID) +check_symbol_exists(utimes "${CURL_INCLUDES}" HAVE_UTIMES) + +check_symbol_exists(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY) +check_symbol_exists(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET) +check_symbol_exists(sigsetjmp "${CURL_INCLUDES};setjmp.h" HAVE_SIGSETJMP) +check_symbol_exists(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R) +check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID) +check_symbol_exists(getpwuid_r "${CURL_INCLUDES}" HAVE_GETPWUID_R) +check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID) +check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME) +check_symbol_exists(gmtime_r "${CURL_INCLUDES};stdlib.h;time.h" HAVE_GMTIME_R) + +check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R) + +check_symbol_exists(signal "${CURL_INCLUDES};signal.h" HAVE_SIGNAL) +check_symbol_exists(strtoll "${CURL_INCLUDES};stdlib.h" HAVE_STRTOLL) +check_symbol_exists(strerror_r "${CURL_INCLUDES};stdlib.h;string.h" HAVE_STRERROR_R) +check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION) +check_symbol_exists(siginterrupt "${CURL_INCLUDES};signal.h" HAVE_SIGINTERRUPT) +check_symbol_exists(getaddrinfo "${CURL_INCLUDES};stdlib.h;string.h" HAVE_GETADDRINFO) +check_symbol_exists(getifaddrs "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS) +check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO) +check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) +check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) +check_symbol_exists(fseeko "${CURL_INCLUDES};stdio.h" HAVE_FSEEKO) +check_symbol_exists(_fseeki64 "${CURL_INCLUDES};stdio.h" HAVE__FSEEKI64) +check_symbol_exists(getpeername "${CURL_INCLUDES}" HAVE_GETPEERNAME) +check_symbol_exists(getsockname "${CURL_INCLUDES}" HAVE_GETSOCKNAME) +check_symbol_exists(if_nametoindex "${CURL_INCLUDES}" HAVE_IF_NAMETOINDEX) +check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) +check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) +check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE) +check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) + +if(HAVE_FSEEKO) + set(HAVE_DECL_FSEEKO 1) +endif() + +if(NOT MSVC OR (MSVC_VERSION GREATER_EQUAL 1900)) + # earlier MSVC compilers had faulty snprintf implementations + check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) +endif() +check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) +check_symbol_exists(inet_ntop "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_NTOP) +if(MSVC AND (MSVC_VERSION LESS_EQUAL 1600)) + set(HAVE_INET_NTOP OFF) +endif() +check_symbol_exists(inet_pton "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_PTON) + +check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR) +if(HAVE_FSETXATTR) + foreach(CURL_TEST HAVE_FSETXATTR_5 HAVE_FSETXATTR_6) + curl_internal_test(${CURL_TEST}) + endforeach() +endif() + +set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h") +check_type_size("sa_family_t" SIZEOF_SA_FAMILY_T) +set(HAVE_SA_FAMILY_T ${HAVE_SIZEOF_SA_FAMILY_T}) +set(CMAKE_EXTRA_INCLUDE_FILES "") + +if(WIN32) + set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h") + check_type_size("ADDRESS_FAMILY" SIZEOF_ADDRESS_FAMILY) + set(HAVE_ADDRESS_FAMILY ${HAVE_SIZEOF_ADDRESS_FAMILY}) + set(CMAKE_EXTRA_INCLUDE_FILES "") +endif() + +# Do curl specific tests +foreach(CURL_TEST + HAVE_FCNTL_O_NONBLOCK + HAVE_IOCTLSOCKET + HAVE_IOCTLSOCKET_CAMEL + HAVE_IOCTLSOCKET_CAMEL_FIONBIO + HAVE_IOCTLSOCKET_FIONBIO + HAVE_IOCTL_FIONBIO + HAVE_IOCTL_SIOCGIFADDR + HAVE_SETSOCKOPT_SO_NONBLOCK + HAVE_O_NONBLOCK + HAVE_GETHOSTBYNAME_R_3 + HAVE_GETHOSTBYNAME_R_5 + HAVE_GETHOSTBYNAME_R_6 + HAVE_GETHOSTBYNAME_R_3_REENTRANT + HAVE_GETHOSTBYNAME_R_5_REENTRANT + HAVE_GETHOSTBYNAME_R_6_REENTRANT + HAVE_IN_ADDR_T + HAVE_BOOL_T + STDC_HEADERS + HAVE_FILE_OFFSET_BITS + HAVE_ATOMIC + ) + curl_internal_test(${CURL_TEST}) +endforeach() + +if(HAVE_FILE_OFFSET_BITS) + set(_FILE_OFFSET_BITS 64) + set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") +endif() +check_type_size("off_t" SIZEOF_OFF_T) + +# include this header to get the type +set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCE_DIR}/include") +set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h") +check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) +set(CMAKE_EXTRA_INCLUDE_FILES "curl/curl.h") +check_type_size("curl_socket_t" SIZEOF_CURL_SOCKET_T) +set(CMAKE_EXTRA_INCLUDE_FILES "") + +if(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING) + # on not-Windows and not-crosscompiling, check for writable argv[] + include(CheckCSourceRuns) + check_c_source_runs(" + int main(int argc, char **argv) + { + (void)argc; + argv[0][0] = ' '; + return (argv[0][0] == ' ')?0:1; + }" HAVE_WRITABLE_ARGV) +endif() + +set(CMAKE_REQUIRED_FLAGS) + +option(ENABLE_WEBSOCKETS "Set to ON to enable EXPERIMENTAL websockets" OFF) + +if(ENABLE_WEBSOCKETS) + if(${SIZEOF_CURL_OFF_T} GREATER "4") + set(USE_WEBSOCKETS ON) + else() + message(WARNING "curl_off_t is too small to enable WebSockets") + endif() +endif() + +foreach(CURL_TEST + HAVE_GLIBC_STRERROR_R + HAVE_POSIX_STRERROR_R + ) + curl_internal_test(${CURL_TEST}) +endforeach() + +# Check for reentrant +foreach(CURL_TEST + HAVE_GETHOSTBYNAME_R_3 + HAVE_GETHOSTBYNAME_R_5 + HAVE_GETHOSTBYNAME_R_6) + if(NOT ${CURL_TEST}) + if(${CURL_TEST}_REENTRANT) + set(NEED_REENTRANT 1) + endif() + endif() +endforeach() + +if(NEED_REENTRANT) + foreach(CURL_TEST + HAVE_GETHOSTBYNAME_R_3 + HAVE_GETHOSTBYNAME_R_5 + HAVE_GETHOSTBYNAME_R_6) + set(${CURL_TEST} 0) + if(${CURL_TEST}_REENTRANT) + set(${CURL_TEST} 1) + endif() + endforeach() +endif() + +if(NOT WIN32) + # Check clock_gettime(CLOCK_MONOTONIC, x) support + curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC) +endif() + +# Check compiler support of __builtin_available() +curl_internal_test(HAVE_BUILTIN_AVAILABLE) + +# Some other minor tests + +if(NOT HAVE_IN_ADDR_T) + set(in_addr_t "unsigned long") +endif() + +# Check for nonblocking +set(HAVE_DISABLED_NONBLOCKING 1) +if(HAVE_FIONBIO OR + HAVE_IOCTLSOCKET OR + HAVE_IOCTLSOCKET_CASE OR + HAVE_O_NONBLOCK) + set(HAVE_DISABLED_NONBLOCKING) +endif() + +if(CMAKE_COMPILER_IS_GNUCC AND APPLE) + include(CheckCCompilerFlag) + check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double) + if(HAVE_C_FLAG_Wno_long_double) + # The Mac version of GCC warns about use of long double. Disable it. + get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS) + if(MPRINTF_COMPILE_FLAGS) + set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double") + else() + set(MPRINTF_COMPILE_FLAGS "-Wno-long-double") + endif() + set_source_files_properties(mprintf.c PROPERTIES + COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS}) + endif() +endif() + +include(CMake/OtherTests.cmake) + +add_definitions(-DHAVE_CONFIG_H) + +# For Windows, all compilers used by CMake should support large files +if(WIN32) + set(USE_WIN32_LARGE_FILES ON) + + # Use the manifest embedded in the Windows Resource + set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DCURL_EMBED_MANIFEST") + + # We use crypto functions that are not available for UWP apps + if(NOT WINDOWS_STORE) + set(USE_WIN32_CRYPTO ON) + endif() + + # Link required libraries for USE_WIN32_CRYPTO or USE_SCHANNEL + if(USE_WIN32_CRYPTO OR USE_SCHANNEL) + list(APPEND CURL_LIBS "advapi32" "crypt32") + endif() +endif() + +if(MSVC) + # Disable default manifest added by CMake + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") + + add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) + if(CMAKE_C_FLAGS MATCHES "/W[0-4]") + string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") + endif() + + # Use multithreaded compilation on VS 2008+ + if(MSVC_VERSION GREATER_EQUAL 1500) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") + endif() +endif() + +if(CURL_WERROR) + if(MSVC_VERSION) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") + else() + # this assumes clang or gcc style options + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + endif() +endif() + +if(CURL_LTO) + if(CMAKE_VERSION VERSION_LESS 3.9) + message(FATAL_ERROR "Requested LTO but your cmake version ${CMAKE_VERSION} is to old. You need at least 3.9") + endif() + + cmake_policy(SET CMP0069 NEW) + + include(CheckIPOSupported) + check_ipo_supported(RESULT CURL_HAS_LTO OUTPUT CURL_LTO_ERROR LANGUAGES C) + if(CURL_HAS_LTO) + message(STATUS "LTO supported and enabled") + else() + message(FATAL_ERROR "LTO was requested - but compiler doesn't support it\n${CURL_LTO_ERROR}") + endif() +endif() + + +# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it). +function(transform_makefile_inc INPUT_FILE OUTPUT_FILE) + file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT) + string(REPLACE "$(top_srcdir)" "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + + string(REGEX REPLACE "\\\\\n" "!Ï€!α!" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + string(REPLACE "!Ï€!α!" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + + string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace $() with ${} + string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace @@ with ${}, even if that may not be read by CMake scripts. + file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT}) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${INPUT_FILE}") +endfunction() + +include(GNUInstallDirs) + +set(CURL_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) +set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") +set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") +set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake") +set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") + +if(HAVE_MANUAL_TOOLS) + add_subdirectory(docs) +endif() + +add_subdirectory(lib) + +if(BUILD_CURL_EXE) + add_subdirectory(src) +endif() + +cmake_dependent_option(BUILD_TESTING "Build tests" + ON "PERL_FOUND;NOT CURL_DISABLE_TESTS" + OFF) +if(BUILD_TESTING) + add_subdirectory(tests) +endif() + +if(NOT CURL_DISABLE_INSTALL) + + # Helper to populate a list (_items) with a label when conditions (the remaining + # args) are satisfied + macro(_add_if label) + # needs to be a macro to allow this indirection + if(${ARGN}) + set(_items ${_items} "${label}") + endif() + endmacro() + + # NTLM support requires crypto function adaptions from various SSL libs + if(NOT (CURL_DISABLE_NTLM) AND + (USE_OPENSSL OR USE_MBEDTLS OR USE_DARWINSSL OR USE_WIN32_CRYPTO OR USE_GNUTLS)) + set(use_curl_ntlm_core ON) + endif() + + # Clear list and try to detect available features + set(_items) + _add_if("SSL" SSL_ENABLED) + _add_if("IPv6" ENABLE_IPV6) + _add_if("UnixSockets" USE_UNIX_SOCKETS) + _add_if("libz" HAVE_LIBZ) + _add_if("brotli" HAVE_BROTLI) + _add_if("zstd" HAVE_ZSTD) + _add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32) + _add_if("IDN" HAVE_LIBIDN2 OR USE_WIN32_IDN) + _add_if("Largefile" (SIZEOF_CURL_OFF_T GREATER 4) AND + ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES)) + _add_if("SSPI" USE_WINDOWS_SSPI) + _add_if("GSS-API" HAVE_GSSAPI) + _add_if("alt-svc" NOT CURL_DISABLE_ALTSVC) + _add_if("HSTS" NOT CURL_DISABLE_HSTS) + _add_if("SPNEGO" NOT CURL_DISABLE_NEGOTIATE_AUTH AND + (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) + _add_if("Kerberos" NOT CURL_DISABLE_KERBEROS_AUTH AND + (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) + _add_if("NTLM" NOT (CURL_DISABLE_NTLM) AND + (use_curl_ntlm_core OR USE_WINDOWS_SSPI)) + _add_if("NTLM_WB" NOT (CURL_DISABLE_NTLM) AND + (use_curl_ntlm_core OR USE_WINDOWS_SSPI) AND + NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) + _add_if("TLS-SRP" USE_TLS_SRP) + _add_if("HTTP2" USE_NGHTTP2) + _add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE) + _add_if("MultiSSL" CURL_WITH_MULTI_SSL) + # TODO wolfSSL only support this from v5.0.0 onwards + _add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS + OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR + USE_MBEDTLS OR USE_SECTRANSP)) + _add_if("unicode" ENABLE_UNICODE) + _add_if("threadsafe" HAVE_ATOMIC OR + (USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR + (WIN32 AND HAVE_WIN32_WINNT GREATER_EQUAL 0x600)) + _add_if("PSL" USE_LIBPSL) + string(REPLACE ";" " " SUPPORT_FEATURES "${_items}") + message(STATUS "Enabled features: ${SUPPORT_FEATURES}") + + # Clear list and try to detect available protocols + set(_items) + _add_if("HTTP" NOT CURL_DISABLE_HTTP) + _add_if("IPFS" NOT CURL_DISABLE_HTTP) + _add_if("IPNS" NOT CURL_DISABLE_HTTP) + _add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED) + _add_if("FTP" NOT CURL_DISABLE_FTP) + _add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED) + _add_if("FILE" NOT CURL_DISABLE_FILE) + _add_if("TELNET" NOT CURL_DISABLE_TELNET) + _add_if("LDAP" NOT CURL_DISABLE_LDAP) + # CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS + _add_if("LDAPS" NOT CURL_DISABLE_LDAPS AND + ((USE_OPENLDAP AND SSL_ENABLED) OR + (NOT USE_OPENLDAP AND HAVE_LDAP_SSL))) + _add_if("DICT" NOT CURL_DISABLE_DICT) + _add_if("TFTP" NOT CURL_DISABLE_TFTP) + _add_if("GOPHER" NOT CURL_DISABLE_GOPHER) + _add_if("GOPHERS" NOT CURL_DISABLE_GOPHER AND SSL_ENABLED) + _add_if("POP3" NOT CURL_DISABLE_POP3) + _add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED) + _add_if("IMAP" NOT CURL_DISABLE_IMAP) + _add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED) + _add_if("SMB" NOT CURL_DISABLE_SMB AND + use_curl_ntlm_core AND (SIZEOF_CURL_OFF_T GREATER 4)) + _add_if("SMBS" NOT CURL_DISABLE_SMB AND SSL_ENABLED AND + use_curl_ntlm_core AND (SIZEOF_CURL_OFF_T GREATER 4)) + _add_if("SMTP" NOT CURL_DISABLE_SMTP) + _add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED) + _add_if("SCP" USE_LIBSSH2 OR USE_LIBSSH) + _add_if("SFTP" USE_LIBSSH2 OR USE_LIBSSH) + _add_if("RTSP" NOT CURL_DISABLE_RTSP) + _add_if("RTMP" USE_LIBRTMP) + _add_if("MQTT" NOT CURL_DISABLE_MQTT) + _add_if("WS" USE_WEBSOCKETS) + _add_if("WSS" USE_WEBSOCKETS) + if(_items) + list(SORT _items) + endif() + string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}") + message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}") + + # Clear list and collect SSL backends + set(_items) + _add_if("Schannel" SSL_ENABLED AND USE_SCHANNEL) + _add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) + _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP) + _add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS) + _add_if("BearSSL" SSL_ENABLED AND USE_BEARSSL) + _add_if("wolfSSL" SSL_ENABLED AND USE_WOLFSSL) + _add_if("GnuTLS" SSL_ENABLED AND USE_GNUTLS) + + if(_items) + list(SORT _items) + endif() + string(REPLACE ";" " " SSL_BACKENDS "${_items}") + message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}") + if(CURL_DEFAULT_SSL_BACKEND) + message(STATUS "Default SSL backend: ${CURL_DEFAULT_SSL_BACKEND}") + endif() + + # curl-config needs the following options to be set. + set(CC "${CMAKE_C_COMPILER}") + # TODO probably put a -D... options here? + set(CONFIGURE_OPTIONS "") + set(CURLVERSION "${CURL_VERSION}") + set(exec_prefix "\${prefix}") + set(includedir "\${prefix}/include") + set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + set(LIBCURL_LIBS "") + set(libdir "${CMAKE_INSTALL_PREFIX}/lib") + foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) + if(TARGET "${_lib}") + set(_libname "${_lib}") + get_target_property(_imported "${_libname}" IMPORTED) + if(NOT _imported) + # Reading the LOCATION property on non-imported target will error out. + # Assume the user won't need this information in the .pc file. + continue() + endif() + get_target_property(_lib "${_libname}" LOCATION) + if(NOT _lib) + message(WARNING "Bad lib in library list: ${_libname}") + continue() + endif() + endif() + if(_lib MATCHES ".*/.*" OR _lib MATCHES "^-") + set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}") + else() + set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") + endif() + endforeach() + if(BUILD_SHARED_LIBS) + set(ENABLE_SHARED "yes") + set(LIBCURL_NO_SHARED "") + set(CPPFLAG_CURL_STATICLIB "") + else() + set(ENABLE_SHARED "no") + set(LIBCURL_NO_SHARED "${LIBCURL_LIBS}") + set(CPPFLAG_CURL_STATICLIB "-DCURL_STATICLIB") + endif() + if(BUILD_STATIC_LIBS) + set(ENABLE_STATIC "yes") + else() + set(ENABLE_STATIC "no") + endif() + # "a" (Linux) or "lib" (Windows) + string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(prefix "${CMAKE_INSTALL_PREFIX}") + # Set this to "yes" to append all libraries on which -lcurl is dependent + set(REQUIRE_LIB_DEPS "no") + # SUPPORT_FEATURES + # SUPPORT_PROTOCOLS + set(VERSIONNUM "${CURL_VERSION_NUM}") + + # Finally generate a "curl-config" matching this config + # Use: + # * ENABLE_SHARED + # * ENABLE_STATIC + configure_file("${CURL_SOURCE_DIR}/curl-config.in" + "${CURL_BINARY_DIR}/curl-config" @ONLY) + install(FILES "${CURL_BINARY_DIR}/curl-config" + DESTINATION ${CMAKE_INSTALL_BINDIR} + PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) + + # Finally generate a pkg-config file matching this config + configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in" + "${CURL_BINARY_DIR}/libcurl.pc" @ONLY) + install(FILES "${CURL_BINARY_DIR}/libcurl.pc" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + + # install headers + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h") + + include(CMakePackageConfigHelpers) + write_basic_package_version_file( + "${version_config}" + VERSION ${CURL_VERSION} + COMPATIBILITY SameMajorVersion + ) + file(READ "${version_config}" generated_version_config) + file(WRITE "${version_config}" + "if(NOT PACKAGE_FIND_VERSION_RANGE AND PACKAGE_FIND_VERSION_MAJOR STREQUAL \"7\") + # Version 8 satisfies version 7... requirements + set(PACKAGE_FIND_VERSION_MAJOR 8) + set(PACKAGE_FIND_VERSION_COUNT 1) + endif() + ${generated_version_config}" + ) + + # Use: + # * TARGETS_EXPORT_NAME + # * PROJECT_NAME + configure_package_config_file(CMake/curl-config.cmake.in + "${project_config}" + INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR} + ) + + if(CURL_ENABLE_EXPORT_TARGET) + install( + EXPORT "${TARGETS_EXPORT_NAME}" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION ${CURL_INSTALL_CMAKE_DIR} + ) + endif() + + install( + FILES ${version_config} ${project_config} + DESTINATION ${CURL_INSTALL_CMAKE_DIR} + ) + + # Workaround for MSVS10 to avoid the Dialog Hell + # FIXME: This could be removed with future version of CMake. + if(MSVC_VERSION EQUAL 1600) + set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln") + if(EXISTS "${CURL_SLN_FILENAME}") + file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n") + endif() + endif() + + if(NOT TARGET curl_uninstall) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake + IMMEDIATE @ONLY) + + add_custom_target(curl_uninstall + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake) + endif() +endif() diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d9e7e0b --- /dev/null +++ b/COPYING @@ -0,0 +1,22 @@ +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1996 - 2024, Daniel Stenberg, , and many +contributors, see the THANKS file. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. diff --git a/MacOSX-Framework b/MacOSX-Framework new file mode 100755 index 0000000..5ac5376 --- /dev/null +++ b/MacOSX-Framework @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# This script performs all of the steps needed to build a +# universal binary libcurl.framework for Mac OS X 10.4 or greater. +# +# Hendrik Visage: +# Generalizations added since Snowleopard (10.6) do not include +# the 10.4u SDK. +# +# Also note: +# 10.5 is the *ONLY* SDK that support PPC64 :( -- 10.6 do not have ppc64 support +#If you need to have PPC64 support then change below to 1 +PPC64_NEEDED=0 +# Apple does not support building for PPC anymore in Xcode 4 and later. +# If you're using Xcode 3 or earlier and need PPC support, then change +# the setting below to 1 +PPC_NEEDED=0 + +# For me the default is to develop for the platform I am on, and if you +#desire compatibility with older versions then change USE_OLD to 1 :) +USE_OLD=0 + +VERSION=`/usr/bin/sed -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' include/curl/curlver.h` +FRAMEWORK_VERSION=Versions/Release-$VERSION + +#I also wanted to "copy over" the system, and thus the reason I added the +# version to Versions/Release-7.20.1 etc. +# now a simple rsync -vaP libcurl.framework /Library/Frameworks will install it +# and setup the right paths to this version, leaving the system version +# "intact", so you can "fix" it later with the links to Versions/A/... + +DEVELOPER_PATH=`xcode-select --print-path` +# Around Xcode 4.3, SDKs were moved from the Developer folder into the +# MacOSX.platform folder +if test -d "$DEVELOPER_PATH/Platforms/MacOSX.platform/Developer/SDKs"; then + SDK_PATH="$DEVELOPER_PATH/Platforms/MacOSX.platform/Developer/SDKs" +else + SDK_PATH="$DEVELOPER_PATH/SDKs" +fi +OLD_SDK=`ls $SDK_PATH|head -1` +NEW_SDK=`ls -r $SDK_PATH|head -1` + +if test "0"$USE_OLD -gt 0 +then + SDK32=$OLD_SDK +else + SDK32=$NEW_SDK +fi + +MACVER=`echo $SDK32|sed -e s/[a-zA-Z]//g -e s/.\$//` + +SDK32_DIR=$SDK_PATH/$SDK32 +MINVER32='-mmacosx-version-min='$MACVER +if test $PPC_NEEDED -gt 0; then + ARCHES32='-arch i386 -arch ppc' +else + ARCHES32='-arch i386' +fi + +if test $PPC64_NEEDED -gt 0 +then + SDK64=10.5 + ARCHES64='-arch x86_64 -arch ppc64' + SDK64=`ls $SDK_PATH | grep "10\.5" | head -1` +else + ARCHES64='-arch x86_64' + #We "know" that 10.4 and earlier do not support 64bit + OLD_SDK64=`ls $SDK_PATH | grep -v "10\.[0-4]" | head -1` + NEW_SDK64=`ls -r $SDK_PATH | grep -v "10\.[0-4][^0-9]" | head -1` + if test $USE_OLD -gt 0 + then + SDK64=$OLD_SDK64 + else + SDK64=$NEW_SDK64 + fi +fi + +SDK64_DIR=$SDK_PATH/$SDK64 +MACVER64=`echo $SDK64|sed -e s/[a-zA-Z]//g -e s/.\$//` + +MINVER64='-mmacosx-version-min='$MACVER64 + +if test ! -z $SDK32; then + echo "----Configuring libcurl for 32 bit universal framework..." + make clean + ./configure --disable-dependency-tracking --disable-static --with-gssapi --with-secure-transport \ + CFLAGS="-Os -isysroot $SDK32_DIR $ARCHES32" \ + LDFLAGS="-Wl,-syslibroot,$SDK32_DIR $ARCHES32 -Wl,-headerpad_max_install_names" \ + CC=$CC + + echo "----Building 32 bit libcurl..." + make -j `sysctl -n hw.logicalcpu_max` + + echo "----Creating 32 bit framework..." + rm -r libcurl.framework + mkdir -p libcurl.framework/${FRAMEWORK_VERSION}/Resources + cp lib/.libs/libcurl.dylib libcurl.framework/${FRAMEWORK_VERSION}/libcurl + install_name_tool -id @rpath/libcurl.framework/${FRAMEWORK_VERSION}/libcurl libcurl.framework/${FRAMEWORK_VERSION}/libcurl + cp lib/libcurl.plist libcurl.framework/${FRAMEWORK_VERSION}/Resources/Info.plist + mkdir -p libcurl.framework/${FRAMEWORK_VERSION}/Headers/curl + cp include/curl/*.h libcurl.framework/${FRAMEWORK_VERSION}/Headers/curl + pushd libcurl.framework + ln -fs ${FRAMEWORK_VERSION}/libcurl libcurl + ln -fs ${FRAMEWORK_VERSION}/Resources Resources + ln -fs ${FRAMEWORK_VERSION}/Headers Headers + cd Versions + ln -fs $(basename "${FRAMEWORK_VERSION}") Current + + echo Testing for SDK64 + if test -d $SDK64_DIR; then + echo entering... + popd + make clean + echo "----Configuring libcurl for 64 bit universal framework..." + ./configure --disable-dependency-tracking --disable-static --with-gssapi --with-secure-transport \ + CFLAGS="-Os -isysroot $SDK64_DIR $ARCHES64" \ + LDFLAGS="-Wl,-syslibroot,$SDK64_DIR $ARCHES64 -Wl,-headerpad_max_install_names" \ + CC=$CC + + echo "----Building 64 bit libcurl..." + make -j `sysctl -n hw.logicalcpu_max` + + echo "----Appending 64 bit framework to 32 bit framework..." + cp lib/.libs/libcurl.dylib libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 + install_name_tool -id @rpath/libcurl.framework/${FRAMEWORK_VERSION}/libcurl libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 + cp libcurl.framework/${FRAMEWORK_VERSION}/libcurl libcurl.framework/${FRAMEWORK_VERSION}/libcurl32 + pwd + lipo libcurl.framework/${FRAMEWORK_VERSION}/libcurl32 libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 -create -output libcurl.framework/${FRAMEWORK_VERSION}/libcurl + rm libcurl.framework/${FRAMEWORK_VERSION}/libcurl32 libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 + fi + + pwd + lipo -info libcurl.framework/${FRAMEWORK_VERSION}/libcurl + echo "libcurl.framework is built and can now be included in other projects." + echo "Copy libcurl.framework to your bundle's Contents/Frameworks folder, ~/Library/Frameworks or /Library/Frameworks." +else + echo "Building libcurl.framework requires Mac OS X 10.4 or later with the MacOSX10.4/5/6 SDK installed." +fi diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3db331a --- /dev/null +++ b/Makefile @@ -0,0 +1,71 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +all: + ./configure + make + +ssl: + ./configure --with-openssl + make + +vc: + cd winbuild + nmake /f Makefile.vc MACHINE=x86 + +vc-x64: + cd winbuild + nmake /f Makefile.vc MACHINE=x64 + +djgpp%: + $(MAKE) -C lib -f Makefile.mk CFG=$@ CROSSPREFIX=i586-pc-msdosdjgpp- + $(MAKE) -C src -f Makefile.mk CFG=$@ CROSSPREFIX=i586-pc-msdosdjgpp- + +cygwin: + ./configure + make + +cygwin-ssl: + ./configure --with-openssl + make + +amiga%: + $(MAKE) -C lib -f Makefile.mk CFG=$@ CROSSPREFIX=m68k-amigaos- + $(MAKE) -C src -f Makefile.mk CFG=$@ CROSSPREFIX=m68k-amigaos- + +unix: all + +unix-ssl: ssl + +linux: all + +linux-ssl: ssl + +ca-bundle: scripts/mk-ca-bundle.pl + @echo "generate a fresh ca-bundle.crt" + @perl $< -b -l -u lib/ca-bundle.crt + +ca-firefox: lib/firefox-db2pem.sh + @echo "generate a fresh ca-bundle.crt" + ./lib/firefox-db2pem.sh lib/ca-bundle.crt diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..b56ca1a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,535 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +AUTOMAKE_OPTIONS = foreign + +ACLOCAL_AMFLAGS = -I m4 + +CMAKE_DIST = \ + CMake/cmake_uninstall.cmake.in \ + CMake/CMakeConfigurableFile.in \ + CMake/curl-config.cmake.in \ + CMake/CurlSymbolHiding.cmake \ + CMake/CurlTests.c \ + CMake/FindBearSSL.cmake \ + CMake/FindBrotli.cmake \ + CMake/FindCARES.cmake \ + CMake/FindGSS.cmake \ + CMake/FindLibPSL.cmake \ + CMake/FindLibSSH2.cmake \ + CMake/FindMbedTLS.cmake \ + CMake/FindMSH3.cmake \ + CMake/FindNGHTTP2.cmake \ + CMake/FindNGHTTP3.cmake \ + CMake/FindNGTCP2.cmake \ + CMake/FindQUICHE.cmake \ + CMake/FindWolfSSL.cmake \ + CMake/FindZstd.cmake \ + CMake/Macros.cmake \ + CMake/OtherTests.cmake \ + CMake/PickyWarnings.cmake \ + CMake/Platforms/WindowsCache.cmake \ + CMake/Utilities.cmake \ + CMakeLists.txt + +VC14_LIBTMPL = projects/Windows/VC14/lib/libcurl.tmpl +VC14_LIBVCXPROJ = projects/Windows/VC14/lib/libcurl.vcxproj.dist +VC14_LIBVCXPROJ_DEPS = $(VC14_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_SRCTMPL = projects/Windows/VC14/src/curl.tmpl +VC14_SRCVCXPROJ = projects/Windows/VC14/src/curl.vcxproj.dist +VC14_SRCVCXPROJ_DEPS = $(VC14_SRCTMPL) Makefile.am src/Makefile.inc + +VC14_10_LIBTMPL = projects/Windows/VC14.10/lib/libcurl.tmpl +VC14_10_LIBVCXPROJ = projects/Windows/VC14.10/lib/libcurl.vcxproj.dist +VC14_10_LIBVCXPROJ_DEPS = $(VC14_10_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_10_SRCTMPL = projects/Windows/VC14.10/src/curl.tmpl +VC14_10_SRCVCXPROJ = projects/Windows/VC14.10/src/curl.vcxproj.dist +VC14_10_SRCVCXPROJ_DEPS = $(VC14_10_SRCTMPL) Makefile.am src/Makefile.inc + +VC14_20_LIBTMPL = projects/Windows/VC14.20/lib/libcurl.tmpl +VC14_20_LIBVCXPROJ = projects/Windows/VC14.20/lib/libcurl.vcxproj.dist +VC14_20_LIBVCXPROJ_DEPS = $(VC14_20_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_20_SRCTMPL = projects/Windows/VC14.20/src/curl.tmpl +VC14_20_SRCVCXPROJ = projects/Windows/VC14.20/src/curl.vcxproj.dist +VC14_20_SRCVCXPROJ_DEPS = $(VC14_20_SRCTMPL) Makefile.am src/Makefile.inc + +VC14_30_LIBTMPL = projects/Windows/VC14.30/lib/libcurl.tmpl +VC14_30_LIBVCXPROJ = projects/Windows/VC14.30/lib/libcurl.vcxproj.dist +VC14_30_LIBVCXPROJ_DEPS = $(VC14_30_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_30_SRCTMPL = projects/Windows/VC14.30/src/curl.tmpl +VC14_30_SRCVCXPROJ = projects/Windows/VC14.30/src/curl.vcxproj.dist +VC14_30_SRCVCXPROJ_DEPS = $(VC14_30_SRCTMPL) Makefile.am src/Makefile.inc + +VC_DIST = projects/README.md \ + projects/build-openssl.bat \ + projects/build-wolfssl.bat \ + projects/checksrc.bat \ + projects/Windows/VC14/curl-all.sln \ + projects/Windows/VC14/lib/libcurl.sln \ + projects/Windows/VC14/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14/src/curl.sln \ + projects/Windows/VC14/src/curl.vcxproj.filters \ + projects/Windows/VC14.10/curl-all.sln \ + projects/Windows/VC14.10/lib/libcurl.sln \ + projects/Windows/VC14.10/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14.10/src/curl.sln \ + projects/Windows/VC14.10/src/curl.vcxproj.filters \ + projects/Windows/VC14.20/curl-all.sln \ + projects/Windows/VC14.20/lib/libcurl.sln \ + projects/Windows/VC14.20/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14.20/src/curl.sln \ + projects/Windows/VC14.20/src/curl.vcxproj.filters \ + projects/Windows/VC14.30/curl-all.sln \ + projects/Windows/VC14.30/lib/libcurl.sln \ + projects/Windows/VC14.30/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14.30/src/curl.sln \ + projects/Windows/VC14.30/src/curl.vcxproj.filters \ + projects/generate.bat \ + projects/wolfssl_options.h \ + projects/wolfssl_override.props + +WINBUILD_DIST = winbuild/README.md winbuild/gen_resp_file.bat \ + winbuild/MakefileBuild.vc winbuild/Makefile.vc + +PLAN9_DIST = plan9/include/mkfile \ + plan9/include/mkfile \ + plan9/mkfile.proto \ + plan9/mkfile \ + plan9/README \ + plan9/lib/mkfile.inc \ + plan9/lib/mkfile \ + plan9/src/mkfile.inc \ + plan9/src/mkfile + +EXTRA_DIST = CHANGES COPYING maketgz Makefile.dist curl-config.in \ + RELEASE-NOTES buildconf libcurl.pc.in MacOSX-Framework $(CMAKE_DIST) \ + $(VC_DIST) $(WINBUILD_DIST) $(PLAN9_DIST) lib/libcurl.vers.in buildconf.bat \ + libcurl.def + +CLEANFILES = $(VC14_LIBVCXPROJ) $(VC14_SRCVCXPROJ) \ + $(VC14_10_LIBVCXPROJ) $(VC14_10_SRCVCXPROJ) \ + $(VC14_20_LIBVCXPROJ) $(VC14_20_SRCVCXPROJ) \ + $(VC14_30_LIBVCXPROJ) $(VC14_30_SRCVCXPROJ) + +bin_SCRIPTS = curl-config + +SUBDIRS = lib src +DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libcurl.pc + +# List of files required to generate VC IDE .dsp, .vcproj and .vcxproj files +include lib/Makefile.inc +include src/Makefile.inc + +dist-hook: + rm -rf $(top_builddir)/tests/log + find $(distdir) -name "*.dist" -exec rm {} \; + (distit=`find $(srcdir) -name "*.dist" | grep -v ./ares/`; \ + for file in $$distit; do \ + strip=`echo $$file | sed -e s/^$(srcdir)// -e s/\.dist//`; \ + cp -p $$file $(distdir)$$strip; \ + done) + +check: test examples check-docs + +if CROSSCOMPILING +test-full: test +test-torture: test + +test: + @echo "NOTICE: we can't run the tests when cross-compiling!" + +else + +test: + @(cd tests; $(MAKE) all quiet-test) + +test-full: + @(cd tests; $(MAKE) all full-test) + +test-nonflaky: + @(cd tests; $(MAKE) all nonflaky-test) + +test-torture: + @(cd tests; $(MAKE) all torture-test) + +test-event: + @(cd tests; $(MAKE) all event-test) + +test-am: + @(cd tests; $(MAKE) all am-test) + +test-ci: + @(cd tests; $(MAKE) all ci-test) + +endif + +examples: + @(cd docs/examples; $(MAKE) check) + +check-docs: + @(cd docs/libcurl; $(MAKE) check) + +# Build source and binary rpms. For rpm-3.0 and above, the ~/.rpmmacros +# must contain the following line: +# %_topdir /home/loic/local/rpm +# and that /home/loic/local/rpm contains the directory SOURCES, BUILD etc. +# +# cd /home/loic/local/rpm ; mkdir -p SOURCES BUILD RPMS/i386 SPECS SRPMS +# +# If additional configure flags are needed to build the package, add the +# following in ~/.rpmmacros +# %configure CFLAGS="%{optflags}" ./configure %{_target_platform} --prefix=%{_prefix} ${AM_CONFIGFLAGS} +# and run make rpm in the following way: +# AM_CONFIGFLAGS='--with-uri=/home/users/loic/local/RedHat-6.2' make rpm +# + +rpms: + $(MAKE) RPMDIST=curl rpm + $(MAKE) RPMDIST=curl-ssl rpm + +rpm: + RPM_TOPDIR=`rpm --showrc | $(PERL) -n -e 'print if(s/.*_topdir\s+(.*)/$$1/)'` ; \ + cp $(srcdir)/packages/Linux/RPM/$(RPMDIST).spec $$RPM_TOPDIR/SPECS ; \ + cp $(PACKAGE)-$(VERSION).tar.gz $$RPM_TOPDIR/SOURCES ; \ + rpm -ba --clean --rmsource $$RPM_TOPDIR/SPECS/$(RPMDIST).spec ; \ + mv $$RPM_TOPDIR/RPMS/i386/$(RPMDIST)-*.rpm . ; \ + mv $$RPM_TOPDIR/SRPMS/$(RPMDIST)-*.src.rpm . + +# +# Build a Solaris pkgadd format file +# run 'make pkgadd' once you've done './configure' and 'make' to make a Solaris pkgadd format +# file (which ends up back in this directory). +# The pkgadd file is in 'pkgtrans' format, so to install on Solaris, do +# pkgadd -d ./HAXXcurl-* +# + +# gak - libtool requires an absolute directory, hence the pwd below... +pkgadd: + umask 022 ; \ + $(MAKE) install DESTDIR=`/bin/pwd`/packages/Solaris/root ; \ + cat COPYING > $(srcdir)/packages/Solaris/copyright ; \ + cd $(srcdir)/packages/Solaris && $(MAKE) package + +# +# Build a cygwin binary tarball installation file +# resulting .tar.bz2 file will end up at packages/Win32/cygwin +cygwinbin: + $(MAKE) -C packages/Win32/cygwin cygwinbin + +# We extend the standard install with a custom hook: +install-data-hook: + (cd include && $(MAKE) install) + (cd docs && $(MAKE) install) + (cd docs/libcurl && $(MAKE) install) + +# We extend the standard uninstall with a custom hook: +uninstall-hook: + (cd include && $(MAKE) uninstall) + (cd docs && $(MAKE) uninstall) + (cd docs/libcurl && $(MAKE) uninstall) + +ca-bundle: $(srcdir)/scripts/mk-ca-bundle.pl + @echo "generating a fresh ca-bundle.crt" + @perl $(srcdir)/scripts/mk-ca-bundle.pl -b -l -u lib/ca-bundle.crt + +ca-firefox: $(srcdir)/scripts/firefox-db2pem.sh + @echo "generating a fresh ca-bundle.crt" + $(srcdir)/scripts/firefox-db2pem.sh lib/ca-bundle.crt + +checksrc: + (cd lib && $(MAKE) checksrc) + (cd src && $(MAKE) checksrc) + (cd tests && $(MAKE) checksrc) + (cd include/curl && $(MAKE) checksrc) + (cd docs/examples && $(MAKE) checksrc) + (cd packages && $(MAKE) checksrc) + +.PHONY: vc-ide + +vc-ide: $(VC14_LIBVCXPROJ_DEPS) $(VC14_SRCVCXPROJ_DEPS) \ + $(VC14_10_LIBVCXPROJ_DEPS) $(VC14_10_SRCVCXPROJ_DEPS) \ + $(VC14_20_LIBVCXPROJ_DEPS) $(VC14_20_SRCVCXPROJ_DEPS) \ + $(VC14_30_LIBVCXPROJ_DEPS) $(VC14_30_SRCVCXPROJ_DEPS) + @(win32_lib_srcs='$(LIB_CFILES)'; \ + win32_lib_hdrs='$(LIB_HFILES) config-win32.h'; \ + win32_lib_rc='$(LIB_RCFILES)'; \ + win32_lib_vauth_srcs='$(LIB_VAUTH_CFILES)'; \ + win32_lib_vauth_hdrs='$(LIB_VAUTH_HFILES)'; \ + win32_lib_vquic_srcs='$(LIB_VQUIC_CFILES)'; \ + win32_lib_vquic_hdrs='$(LIB_VQUIC_HFILES)'; \ + win32_lib_vssh_srcs='$(LIB_VSSH_CFILES)'; \ + win32_lib_vssh_hdrs='$(LIB_VSSH_HFILES)'; \ + win32_lib_vtls_srcs='$(LIB_VTLS_CFILES)'; \ + win32_lib_vtls_hdrs='$(LIB_VTLS_HFILES)'; \ + win32_src_srcs='$(CURL_CFILES)'; \ + win32_src_hdrs='$(CURL_HFILES)'; \ + win32_src_rc='$(CURL_RCFILES)'; \ + win32_src_x_srcs='$(CURLX_CFILES)'; \ + win32_src_x_hdrs='$(CURLX_HFILES) ../lib/config-win32.h'; \ + \ + sorted_lib_srcs=`for file in $$win32_lib_srcs; do echo $$file; done | sort`; \ + sorted_lib_hdrs=`for file in $$win32_lib_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vauth_srcs=`for file in $$win32_lib_vauth_srcs; do echo $$file; done | sort`; \ + sorted_lib_vauth_hdrs=`for file in $$win32_lib_vauth_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vquic_srcs=`for file in $$win32_lib_vquic_srcs; do echo $$file; done | sort`; \ + sorted_lib_vquic_hdrs=`for file in $$win32_lib_vquic_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vssh_srcs=`for file in $$win32_lib_vssh_srcs; do echo $$file; done | sort`; \ + sorted_lib_vssh_hdrs=`for file in $$win32_lib_vssh_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vtls_srcs=`for file in $$win32_lib_vtls_srcs; do echo $$file; done | sort`; \ + sorted_lib_vtls_hdrs=`for file in $$win32_lib_vtls_hdrs; do echo $$file; done | sort`; \ + sorted_src_srcs=`for file in $$win32_src_srcs; do echo $$file; done | sort`; \ + sorted_src_hdrs=`for file in $$win32_src_hdrs; do echo $$file; done | sort`; \ + sorted_src_x_srcs=`for file in $$win32_src_x_srcs; do echo $$file; done | sort`; \ + sorted_src_x_hdrs=`for file in $$win32_src_x_hdrs; do echo $$file; done | sort`; \ + \ + awk_code='\ +function gen_element(type, dir, file)\ +{\ + sub(/vauth\//, "", file);\ + sub(/vquic\//, "", file);\ + sub(/vssh\//, "", file);\ + sub(/vtls\//, "", file);\ +\ + spaces=" ";\ + if(dir == "lib\\vauth" ||\ + dir == "lib\\vquic" ||\ + dir == "lib\\vssh" ||\ + dir == "lib\\vtls")\ + tabs=" ";\ + else\ + tabs=" ";\ +\ + if(type == "dsp") {\ + printf("# Begin Source File\r\n");\ + printf("\r\n");\ + printf("SOURCE=..\\..\\..\\..\\%s\\%s\r\n", dir, file);\ + printf("# End Source File\r\n");\ + }\ + else if(type == "vcproj1") {\ + printf("%s\r\n",\ + tabs, dir, file);\ + printf("%s\r\n", tabs);\ + }\ + else if(type == "vcproj2") {\ + printf("%s\r\n", tabs);\ + printf("%s\r\n", tabs);\ + }\ + else if(type == "vcxproj") {\ + i = index(file, ".");\ + ext = substr(file, i == 0 ? 0 : i + 1);\ +\ + if(ext == "c")\ + printf("%s\r\n",\ + spaces, dir, file);\ + else if(ext == "h")\ + printf("%s\r\n",\ + spaces, dir, file);\ + else if(ext == "rc")\ + printf("%s\r\n",\ + spaces, dir, file);\ + }\ +}\ +\ +{\ +\ + if($$0 == "CURL_LIB_C_FILES") {\ + split(lib_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_H_FILES") {\ + split(lib_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_RC_FILES") {\ + split(lib_rc, arr);\ + for(val in arr) gen_element(proj_type, "lib", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VAUTH_C_FILES") {\ + split(lib_vauth_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vauth", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VAUTH_H_FILES") {\ + split(lib_vauth_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vauth", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VQUIC_C_FILES") {\ + split(lib_vquic_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vquic", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VQUIC_H_FILES") {\ + split(lib_vquic_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vquic", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VSSH_C_FILES") {\ + split(lib_vssh_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vssh", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VSSH_H_FILES") {\ + split(lib_vssh_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vssh", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VTLS_C_FILES") {\ + split(lib_vtls_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vtls", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VTLS_H_FILES") {\ + split(lib_vtls_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vtls", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_C_FILES") {\ + split(src_srcs, arr);\ + for(val in arr) gen_element(proj_type, "src", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_H_FILES") {\ + split(src_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "src", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_RC_FILES") {\ + split(src_rc, arr);\ + for(val in arr) gen_element(proj_type, "src", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_X_C_FILES") {\ + split(src_x_srcs, arr);\ + for(val in arr) {\ + sub(/..\/lib\//, "", arr[val]);\ + gen_element(proj_type, "lib", arr[val]);\ + }\ + }\ + else if($$0 == "CURL_SRC_X_H_FILES") {\ + split(src_x_hdrs, arr);\ + for(val in arr) {\ + sub(/..\/lib\//, "", arr[val]);\ + gen_element(proj_type, "lib", arr[val]);\ + }\ + }\ + else\ + printf("%s\r\n", $$0);\ +}';\ + \ + echo "generating '$(VC14_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_LIBTMPL) > $(VC14_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_SRCTMPL) > $(VC14_SRCVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_10_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_10_LIBTMPL) > $(VC14_10_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_10_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_10_SRCTMPL) > $(VC14_10_SRCVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_20_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_20_LIBTMPL) > $(VC14_20_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_20_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_20_SRCTMPL) > $(VC14_20_SRCVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_30_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_30_LIBTMPL) > $(VC14_30_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_30_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_30_SRCTMPL) > $(VC14_30_SRCVCXPROJ) || { exit 1; };) + +tidy: + (cd src && $(MAKE) tidy) + (cd lib && $(MAKE) tidy) diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..95dd27e --- /dev/null +++ b/Makefile.in @@ -0,0 +1,2085 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# ./src/Makefile.inc +# Using the backslash as line continuation character might be problematic with +# some make flavours. If we ever want to change this in a portable manner then +# we should consider this idea : +# CSRC1 = file1.c file2.c file3.c +# CSRC2 = file4.c file5.c file6.c +# CSOURCES = $(CSRC1) $(CSRC2) + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = curl-config libcurl.pc +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)" +SCRIPTS = $(bin_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DATA = $(pkgconfig_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir distdir-am dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/curl-config.in \ + $(srcdir)/lib/Makefile.inc $(srcdir)/libcurl.pc.in \ + $(srcdir)/src/Makefile.inc COPYING README compile config.guess \ + config.sub depcomp install-sh ltmain.sh missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +# Exists only to be overridden by the user if desired. +AM_DISTCHECK_DVI_TARGET = dvi +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 +CMAKE_DIST = \ + CMake/cmake_uninstall.cmake.in \ + CMake/CMakeConfigurableFile.in \ + CMake/curl-config.cmake.in \ + CMake/CurlSymbolHiding.cmake \ + CMake/CurlTests.c \ + CMake/FindBearSSL.cmake \ + CMake/FindBrotli.cmake \ + CMake/FindCARES.cmake \ + CMake/FindGSS.cmake \ + CMake/FindLibPSL.cmake \ + CMake/FindLibSSH2.cmake \ + CMake/FindMbedTLS.cmake \ + CMake/FindMSH3.cmake \ + CMake/FindNGHTTP2.cmake \ + CMake/FindNGHTTP3.cmake \ + CMake/FindNGTCP2.cmake \ + CMake/FindQUICHE.cmake \ + CMake/FindWolfSSL.cmake \ + CMake/FindZstd.cmake \ + CMake/Macros.cmake \ + CMake/OtherTests.cmake \ + CMake/PickyWarnings.cmake \ + CMake/Platforms/WindowsCache.cmake \ + CMake/Utilities.cmake \ + CMakeLists.txt + +VC14_LIBTMPL = projects/Windows/VC14/lib/libcurl.tmpl +VC14_LIBVCXPROJ = projects/Windows/VC14/lib/libcurl.vcxproj.dist +VC14_LIBVCXPROJ_DEPS = $(VC14_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_SRCTMPL = projects/Windows/VC14/src/curl.tmpl +VC14_SRCVCXPROJ = projects/Windows/VC14/src/curl.vcxproj.dist +VC14_SRCVCXPROJ_DEPS = $(VC14_SRCTMPL) Makefile.am src/Makefile.inc +VC14_10_LIBTMPL = projects/Windows/VC14.10/lib/libcurl.tmpl +VC14_10_LIBVCXPROJ = projects/Windows/VC14.10/lib/libcurl.vcxproj.dist +VC14_10_LIBVCXPROJ_DEPS = $(VC14_10_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_10_SRCTMPL = projects/Windows/VC14.10/src/curl.tmpl +VC14_10_SRCVCXPROJ = projects/Windows/VC14.10/src/curl.vcxproj.dist +VC14_10_SRCVCXPROJ_DEPS = $(VC14_10_SRCTMPL) Makefile.am src/Makefile.inc +VC14_20_LIBTMPL = projects/Windows/VC14.20/lib/libcurl.tmpl +VC14_20_LIBVCXPROJ = projects/Windows/VC14.20/lib/libcurl.vcxproj.dist +VC14_20_LIBVCXPROJ_DEPS = $(VC14_20_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_20_SRCTMPL = projects/Windows/VC14.20/src/curl.tmpl +VC14_20_SRCVCXPROJ = projects/Windows/VC14.20/src/curl.vcxproj.dist +VC14_20_SRCVCXPROJ_DEPS = $(VC14_20_SRCTMPL) Makefile.am src/Makefile.inc +VC14_30_LIBTMPL = projects/Windows/VC14.30/lib/libcurl.tmpl +VC14_30_LIBVCXPROJ = projects/Windows/VC14.30/lib/libcurl.vcxproj.dist +VC14_30_LIBVCXPROJ_DEPS = $(VC14_30_LIBTMPL) Makefile.am lib/Makefile.inc +VC14_30_SRCTMPL = projects/Windows/VC14.30/src/curl.tmpl +VC14_30_SRCVCXPROJ = projects/Windows/VC14.30/src/curl.vcxproj.dist +VC14_30_SRCVCXPROJ_DEPS = $(VC14_30_SRCTMPL) Makefile.am src/Makefile.inc +VC_DIST = projects/README.md \ + projects/build-openssl.bat \ + projects/build-wolfssl.bat \ + projects/checksrc.bat \ + projects/Windows/VC14/curl-all.sln \ + projects/Windows/VC14/lib/libcurl.sln \ + projects/Windows/VC14/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14/src/curl.sln \ + projects/Windows/VC14/src/curl.vcxproj.filters \ + projects/Windows/VC14.10/curl-all.sln \ + projects/Windows/VC14.10/lib/libcurl.sln \ + projects/Windows/VC14.10/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14.10/src/curl.sln \ + projects/Windows/VC14.10/src/curl.vcxproj.filters \ + projects/Windows/VC14.20/curl-all.sln \ + projects/Windows/VC14.20/lib/libcurl.sln \ + projects/Windows/VC14.20/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14.20/src/curl.sln \ + projects/Windows/VC14.20/src/curl.vcxproj.filters \ + projects/Windows/VC14.30/curl-all.sln \ + projects/Windows/VC14.30/lib/libcurl.sln \ + projects/Windows/VC14.30/lib/libcurl.vcxproj.filters \ + projects/Windows/VC14.30/src/curl.sln \ + projects/Windows/VC14.30/src/curl.vcxproj.filters \ + projects/generate.bat \ + projects/wolfssl_options.h \ + projects/wolfssl_override.props + +WINBUILD_DIST = winbuild/README.md winbuild/gen_resp_file.bat \ + winbuild/MakefileBuild.vc winbuild/Makefile.vc + +PLAN9_DIST = plan9/include/mkfile \ + plan9/include/mkfile \ + plan9/mkfile.proto \ + plan9/mkfile \ + plan9/README \ + plan9/lib/mkfile.inc \ + plan9/lib/mkfile \ + plan9/src/mkfile.inc \ + plan9/src/mkfile + +EXTRA_DIST = CHANGES COPYING maketgz Makefile.dist curl-config.in \ + RELEASE-NOTES buildconf libcurl.pc.in MacOSX-Framework $(CMAKE_DIST) \ + $(VC_DIST) $(WINBUILD_DIST) $(PLAN9_DIST) lib/libcurl.vers.in buildconf.bat \ + libcurl.def + +CLEANFILES = $(VC14_LIBVCXPROJ) $(VC14_SRCVCXPROJ) \ + $(VC14_10_LIBVCXPROJ) $(VC14_10_SRCVCXPROJ) \ + $(VC14_20_LIBVCXPROJ) $(VC14_20_SRCVCXPROJ) \ + $(VC14_30_LIBVCXPROJ) $(VC14_30_SRCVCXPROJ) + +bin_SCRIPTS = curl-config +SUBDIRS = lib src +DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libcurl.pc +LIB_VAUTH_CFILES = \ + vauth/cleartext.c \ + vauth/cram.c \ + vauth/digest.c \ + vauth/digest_sspi.c \ + vauth/gsasl.c \ + vauth/krb5_gssapi.c \ + vauth/krb5_sspi.c \ + vauth/ntlm.c \ + vauth/ntlm_sspi.c \ + vauth/oauth2.c \ + vauth/spnego_gssapi.c \ + vauth/spnego_sspi.c \ + vauth/vauth.c + +LIB_VAUTH_HFILES = \ + vauth/digest.h \ + vauth/ntlm.h \ + vauth/vauth.h + +LIB_VTLS_CFILES = \ + vtls/bearssl.c \ + vtls/gtls.c \ + vtls/hostcheck.c \ + vtls/keylog.c \ + vtls/mbedtls.c \ + vtls/mbedtls_threadlock.c \ + vtls/openssl.c \ + vtls/rustls.c \ + vtls/schannel.c \ + vtls/schannel_verify.c \ + vtls/sectransp.c \ + vtls/vtls.c \ + vtls/wolfssl.c \ + vtls/x509asn1.c + +LIB_VTLS_HFILES = \ + vtls/bearssl.h \ + vtls/gtls.h \ + vtls/hostcheck.h \ + vtls/keylog.h \ + vtls/mbedtls.h \ + vtls/mbedtls_threadlock.h \ + vtls/openssl.h \ + vtls/rustls.h \ + vtls/schannel.h \ + vtls/schannel_int.h \ + vtls/sectransp.h \ + vtls/vtls.h \ + vtls/vtls_int.h \ + vtls/wolfssl.h \ + vtls/x509asn1.h + +LIB_VQUIC_CFILES = \ + vquic/curl_msh3.c \ + vquic/curl_ngtcp2.c \ + vquic/curl_osslq.c \ + vquic/curl_quiche.c \ + vquic/vquic.c \ + vquic/vquic-tls.c + +LIB_VQUIC_HFILES = \ + vquic/curl_msh3.h \ + vquic/curl_ngtcp2.h \ + vquic/curl_osslq.h \ + vquic/curl_quiche.h \ + vquic/vquic.h \ + vquic/vquic_int.h \ + vquic/vquic-tls.h + +LIB_VSSH_CFILES = \ + vssh/libssh.c \ + vssh/libssh2.c \ + vssh/wolfssh.c + +LIB_VSSH_HFILES = \ + vssh/ssh.h + +LIB_CFILES = \ + altsvc.c \ + amigaos.c \ + asyn-ares.c \ + asyn-thread.c \ + base64.c \ + bufq.c \ + bufref.c \ + c-hyper.c \ + cf-h1-proxy.c \ + cf-h2-proxy.c \ + cf-haproxy.c \ + cf-https-connect.c \ + cf-socket.c \ + cfilters.c \ + conncache.c \ + connect.c \ + content_encoding.c \ + cookie.c \ + curl_addrinfo.c \ + curl_des.c \ + curl_endian.c \ + curl_fnmatch.c \ + curl_get_line.c \ + curl_gethostname.c \ + curl_gssapi.c \ + curl_memrchr.c \ + curl_multibyte.c \ + curl_ntlm_core.c \ + curl_ntlm_wb.c \ + curl_path.c \ + curl_range.c \ + curl_rtmp.c \ + curl_sasl.c \ + curl_sspi.c \ + curl_threads.c \ + curl_trc.c \ + dict.c \ + doh.c \ + dynbuf.c \ + dynhds.c \ + easy.c \ + easygetopt.c \ + easyoptions.c \ + escape.c \ + file.c \ + fileinfo.c \ + fopen.c \ + formdata.c \ + ftp.c \ + ftplistparser.c \ + getenv.c \ + getinfo.c \ + gopher.c \ + hash.c \ + headers.c \ + hmac.c \ + hostasyn.c \ + hostip.c \ + hostip4.c \ + hostip6.c \ + hostsyn.c \ + hsts.c \ + http.c \ + http1.c \ + http2.c \ + http_aws_sigv4.c \ + http_chunks.c \ + http_digest.c \ + http_negotiate.c \ + http_ntlm.c \ + http_proxy.c \ + idn.c \ + if2ip.c \ + imap.c \ + inet_ntop.c \ + inet_pton.c \ + krb5.c \ + ldap.c \ + llist.c \ + macos.c \ + md4.c \ + md5.c \ + memdebug.c \ + mime.c \ + mprintf.c \ + mqtt.c \ + multi.c \ + netrc.c \ + nonblock.c \ + noproxy.c \ + openldap.c \ + parsedate.c \ + pingpong.c \ + pop3.c \ + progress.c \ + psl.c \ + rand.c \ + rename.c \ + rtsp.c \ + select.c \ + sendf.c \ + setopt.c \ + sha256.c \ + share.c \ + slist.c \ + smb.c \ + smtp.c \ + socketpair.c \ + socks.c \ + socks_gssapi.c \ + socks_sspi.c \ + speedcheck.c \ + splay.c \ + strcase.c \ + strdup.c \ + strerror.c \ + strtok.c \ + strtoofft.c \ + system_win32.c \ + telnet.c \ + tftp.c \ + timediff.c \ + timeval.c \ + transfer.c \ + url.c \ + urlapi.c \ + version.c \ + version_win32.c \ + warnless.c \ + ws.c + +LIB_HFILES = \ + altsvc.h \ + amigaos.h \ + arpa_telnet.h \ + asyn.h \ + bufq.h \ + bufref.h \ + c-hyper.h \ + cf-h1-proxy.h \ + cf-h2-proxy.h \ + cf-haproxy.h \ + cf-https-connect.h \ + cf-socket.h \ + cfilters.h \ + conncache.h \ + connect.h \ + content_encoding.h \ + cookie.h \ + curl_addrinfo.h \ + curl_base64.h \ + curl_ctype.h \ + curl_des.h \ + curl_endian.h \ + curl_fnmatch.h \ + curl_get_line.h \ + curl_gethostname.h \ + curl_gssapi.h \ + curl_hmac.h \ + curl_krb5.h \ + curl_ldap.h \ + curl_md4.h \ + curl_md5.h \ + curl_memory.h \ + curl_memrchr.h \ + curl_multibyte.h \ + curl_ntlm_core.h \ + curl_ntlm_wb.h \ + curl_path.h \ + curl_printf.h \ + curl_range.h \ + curl_rtmp.h \ + curl_sasl.h \ + curl_setup.h \ + curl_setup_once.h \ + curl_sha256.h \ + curl_sspi.h \ + curl_threads.h \ + curl_trc.h \ + curlx.h \ + dict.h \ + doh.h \ + dynbuf.h \ + dynhds.h \ + easy_lock.h \ + easyif.h \ + easyoptions.h \ + escape.h \ + file.h \ + fileinfo.h \ + fopen.h \ + formdata.h \ + ftp.h \ + ftplistparser.h \ + functypes.h \ + getinfo.h \ + gopher.h \ + hash.h \ + headers.h \ + hostip.h \ + hsts.h \ + http.h \ + http1.h \ + http2.h \ + http_aws_sigv4.h \ + http_chunks.h \ + http_digest.h \ + http_negotiate.h \ + http_ntlm.h \ + http_proxy.h \ + idn.h \ + if2ip.h \ + imap.h \ + inet_ntop.h \ + inet_pton.h \ + llist.h \ + macos.h \ + memdebug.h \ + mime.h \ + mqtt.h \ + multihandle.h \ + multiif.h \ + netrc.h \ + nonblock.h \ + noproxy.h \ + parsedate.h \ + pingpong.h \ + pop3.h \ + progress.h \ + psl.h \ + rand.h \ + rename.h \ + rtsp.h \ + select.h \ + sendf.h \ + setopt.h \ + setup-vms.h \ + share.h \ + sigpipe.h \ + slist.h \ + smb.h \ + smtp.h \ + sockaddr.h \ + socketpair.h \ + socks.h \ + speedcheck.h \ + splay.h \ + strcase.h \ + strdup.h \ + strerror.h \ + strtok.h \ + strtoofft.h \ + system_win32.h \ + telnet.h \ + tftp.h \ + timediff.h \ + timeval.h \ + transfer.h \ + url.h \ + urlapi-int.h \ + urldata.h \ + version_win32.h \ + warnless.h \ + ws.h + +LIB_RCFILES = libcurl.rc +CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \ + $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) + +HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \ + $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) + + +# libcurl sources to include in curltool lib we use for test binaries +CURLTOOL_LIBCURL_CFILES = \ + ../lib/base64.c \ + ../lib/dynbuf.c + + +# libcurl has sources that provide functions named curlx_* that aren't part of +# the official API, but we reuse the code here to avoid duplication. +CURLX_CFILES = \ + ../lib/base64.c \ + ../lib/curl_multibyte.c \ + ../lib/dynbuf.c \ + ../lib/nonblock.c \ + ../lib/strtoofft.c \ + ../lib/timediff.c \ + ../lib/version_win32.c \ + ../lib/warnless.c + +CURLX_HFILES = \ + ../lib/curl_ctype.h \ + ../lib/curl_multibyte.h \ + ../lib/curl_setup.h \ + ../lib/dynbuf.h \ + ../lib/nonblock.h \ + ../lib/strtoofft.h \ + ../lib/timediff.h \ + ../lib/version_win32.h \ + ../lib/warnless.h + +CURL_CFILES = \ + slist_wc.c \ + tool_binmode.c \ + tool_bname.c \ + tool_cb_dbg.c \ + tool_cb_hdr.c \ + tool_cb_prg.c \ + tool_cb_rea.c \ + tool_cb_see.c \ + tool_cb_wrt.c \ + tool_cfgable.c \ + tool_dirhie.c \ + tool_doswin.c \ + tool_easysrc.c \ + tool_filetime.c \ + tool_findfile.c \ + tool_formparse.c \ + tool_getparam.c \ + tool_getpass.c \ + tool_help.c \ + tool_helpers.c \ + tool_hugehelp.c \ + tool_ipfs.c \ + tool_libinfo.c \ + tool_listhelp.c \ + tool_main.c \ + tool_msgs.c \ + tool_operate.c \ + tool_operhlp.c \ + tool_paramhlp.c \ + tool_parsecfg.c \ + tool_progress.c \ + tool_setopt.c \ + tool_sleep.c \ + tool_stderr.c \ + tool_strdup.c \ + tool_urlglob.c \ + tool_util.c \ + tool_vms.c \ + tool_writeout.c \ + tool_writeout_json.c \ + tool_xattr.c \ + var.c + +CURL_HFILES = \ + slist_wc.h \ + tool_binmode.h \ + tool_bname.h \ + tool_cb_dbg.h \ + tool_cb_hdr.h \ + tool_cb_prg.h \ + tool_cb_rea.h \ + tool_cb_see.h \ + tool_cb_wrt.h \ + tool_cfgable.h \ + tool_dirhie.h \ + tool_doswin.h \ + tool_easysrc.h \ + tool_filetime.h \ + tool_findfile.h \ + tool_formparse.h \ + tool_getparam.h \ + tool_getpass.h \ + tool_help.h \ + tool_helpers.h \ + tool_hugehelp.h \ + tool_ipfs.h \ + tool_libinfo.h \ + tool_main.h \ + tool_msgs.h \ + tool_operate.h \ + tool_operhlp.h \ + tool_paramhlp.h \ + tool_parsecfg.h \ + tool_progress.h \ + tool_sdecls.h \ + tool_setopt.h \ + tool_setup.h \ + tool_sleep.h \ + tool_stderr.h \ + tool_strdup.h \ + tool_urlglob.h \ + tool_util.h \ + tool_version.h \ + tool_vms.h \ + tool_writeout.h \ + tool_writeout_json.h \ + tool_xattr.h \ + var.h + +CURL_RCFILES = curl.rc + +# curl_SOURCES is special and gets assigned in src/Makefile.am +CURL_FILES = $(CURL_CFILES) $(CURLX_CFILES) $(CURL_HFILES) +all: all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/lib/Makefile.inc $(srcdir)/src/Makefile.inc $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/lib/Makefile.inc $(srcdir)/src/Makefile.inc $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): +curl-config: $(top_builddir)/config.status $(srcdir)/curl-config.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +libcurl.pc: $(top_builddir)/config.status $(srcdir)/libcurl.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-zstd: distdir + tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + *.tar.zst*) \ + zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(SCRIPTS) $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-pkgconfigDATA + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binSCRIPTS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binSCRIPTS uninstall-pkgconfigDATA + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +.MAKE: $(am__recursive_targets) install-am install-data-am \ + install-strip uninstall-am + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \ + dist-tarZ dist-xz dist-zip dist-zstd distcheck distclean \ + distclean-generic distclean-libtool distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-binSCRIPTS \ + install-data install-data-am install-data-hook install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkgconfigDATA install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-binSCRIPTS uninstall-hook \ + uninstall-pkgconfigDATA + +.PRECIOUS: Makefile + + +# List of files required to generate VC IDE .dsp, .vcproj and .vcxproj files + +dist-hook: + rm -rf $(top_builddir)/tests/log + find $(distdir) -name "*.dist" -exec rm {} \; + (distit=`find $(srcdir) -name "*.dist" | grep -v ./ares/`; \ + for file in $$distit; do \ + strip=`echo $$file | sed -e s/^$(srcdir)// -e s/\.dist//`; \ + cp -p $$file $(distdir)$$strip; \ + done) + +check: test examples check-docs + +@CROSSCOMPILING_TRUE@test-full: test +@CROSSCOMPILING_TRUE@test-torture: test + +@CROSSCOMPILING_TRUE@test: +@CROSSCOMPILING_TRUE@ @echo "NOTICE: we can't run the tests when cross-compiling!" + +@CROSSCOMPILING_FALSE@test: +@CROSSCOMPILING_FALSE@ @(cd tests; $(MAKE) all quiet-test) + +@CROSSCOMPILING_FALSE@test-full: +@CROSSCOMPILING_FALSE@ @(cd tests; $(MAKE) all full-test) + +@CROSSCOMPILING_FALSE@test-nonflaky: +@CROSSCOMPILING_FALSE@ @(cd tests; $(MAKE) all nonflaky-test) + +@CROSSCOMPILING_FALSE@test-torture: +@CROSSCOMPILING_FALSE@ @(cd tests; $(MAKE) all torture-test) + +@CROSSCOMPILING_FALSE@test-event: +@CROSSCOMPILING_FALSE@ @(cd tests; $(MAKE) all event-test) + +@CROSSCOMPILING_FALSE@test-am: +@CROSSCOMPILING_FALSE@ @(cd tests; $(MAKE) all am-test) + +@CROSSCOMPILING_FALSE@test-ci: +@CROSSCOMPILING_FALSE@ @(cd tests; $(MAKE) all ci-test) + +examples: + @(cd docs/examples; $(MAKE) check) + +check-docs: + @(cd docs/libcurl; $(MAKE) check) + +# Build source and binary rpms. For rpm-3.0 and above, the ~/.rpmmacros +# must contain the following line: +# %_topdir /home/loic/local/rpm +# and that /home/loic/local/rpm contains the directory SOURCES, BUILD etc. +# +# cd /home/loic/local/rpm ; mkdir -p SOURCES BUILD RPMS/i386 SPECS SRPMS +# +# If additional configure flags are needed to build the package, add the +# following in ~/.rpmmacros +# %configure CFLAGS="%{optflags}" ./configure %{_target_platform} --prefix=%{_prefix} ${AM_CONFIGFLAGS} +# and run make rpm in the following way: +# AM_CONFIGFLAGS='--with-uri=/home/users/loic/local/RedHat-6.2' make rpm +# + +rpms: + $(MAKE) RPMDIST=curl rpm + $(MAKE) RPMDIST=curl-ssl rpm + +rpm: + RPM_TOPDIR=`rpm --showrc | $(PERL) -n -e 'print if(s/.*_topdir\s+(.*)/$$1/)'` ; \ + cp $(srcdir)/packages/Linux/RPM/$(RPMDIST).spec $$RPM_TOPDIR/SPECS ; \ + cp $(PACKAGE)-$(VERSION).tar.gz $$RPM_TOPDIR/SOURCES ; \ + rpm -ba --clean --rmsource $$RPM_TOPDIR/SPECS/$(RPMDIST).spec ; \ + mv $$RPM_TOPDIR/RPMS/i386/$(RPMDIST)-*.rpm . ; \ + mv $$RPM_TOPDIR/SRPMS/$(RPMDIST)-*.src.rpm . + +# +# Build a Solaris pkgadd format file +# run 'make pkgadd' once you've done './configure' and 'make' to make a Solaris pkgadd format +# file (which ends up back in this directory). +# The pkgadd file is in 'pkgtrans' format, so to install on Solaris, do +# pkgadd -d ./HAXXcurl-* +# + +# gak - libtool requires an absolute directory, hence the pwd below... +pkgadd: + umask 022 ; \ + $(MAKE) install DESTDIR=`/bin/pwd`/packages/Solaris/root ; \ + cat COPYING > $(srcdir)/packages/Solaris/copyright ; \ + cd $(srcdir)/packages/Solaris && $(MAKE) package + +# +# Build a cygwin binary tarball installation file +# resulting .tar.bz2 file will end up at packages/Win32/cygwin +cygwinbin: + $(MAKE) -C packages/Win32/cygwin cygwinbin + +# We extend the standard install with a custom hook: +install-data-hook: + (cd include && $(MAKE) install) + (cd docs && $(MAKE) install) + (cd docs/libcurl && $(MAKE) install) + +# We extend the standard uninstall with a custom hook: +uninstall-hook: + (cd include && $(MAKE) uninstall) + (cd docs && $(MAKE) uninstall) + (cd docs/libcurl && $(MAKE) uninstall) + +ca-bundle: $(srcdir)/scripts/mk-ca-bundle.pl + @echo "generating a fresh ca-bundle.crt" + @perl $(srcdir)/scripts/mk-ca-bundle.pl -b -l -u lib/ca-bundle.crt + +ca-firefox: $(srcdir)/scripts/firefox-db2pem.sh + @echo "generating a fresh ca-bundle.crt" + $(srcdir)/scripts/firefox-db2pem.sh lib/ca-bundle.crt + +checksrc: + (cd lib && $(MAKE) checksrc) + (cd src && $(MAKE) checksrc) + (cd tests && $(MAKE) checksrc) + (cd include/curl && $(MAKE) checksrc) + (cd docs/examples && $(MAKE) checksrc) + (cd packages && $(MAKE) checksrc) + +.PHONY: vc-ide + +vc-ide: $(VC14_LIBVCXPROJ_DEPS) $(VC14_SRCVCXPROJ_DEPS) \ + $(VC14_10_LIBVCXPROJ_DEPS) $(VC14_10_SRCVCXPROJ_DEPS) \ + $(VC14_20_LIBVCXPROJ_DEPS) $(VC14_20_SRCVCXPROJ_DEPS) \ + $(VC14_30_LIBVCXPROJ_DEPS) $(VC14_30_SRCVCXPROJ_DEPS) + @(win32_lib_srcs='$(LIB_CFILES)'; \ + win32_lib_hdrs='$(LIB_HFILES) config-win32.h'; \ + win32_lib_rc='$(LIB_RCFILES)'; \ + win32_lib_vauth_srcs='$(LIB_VAUTH_CFILES)'; \ + win32_lib_vauth_hdrs='$(LIB_VAUTH_HFILES)'; \ + win32_lib_vquic_srcs='$(LIB_VQUIC_CFILES)'; \ + win32_lib_vquic_hdrs='$(LIB_VQUIC_HFILES)'; \ + win32_lib_vssh_srcs='$(LIB_VSSH_CFILES)'; \ + win32_lib_vssh_hdrs='$(LIB_VSSH_HFILES)'; \ + win32_lib_vtls_srcs='$(LIB_VTLS_CFILES)'; \ + win32_lib_vtls_hdrs='$(LIB_VTLS_HFILES)'; \ + win32_src_srcs='$(CURL_CFILES)'; \ + win32_src_hdrs='$(CURL_HFILES)'; \ + win32_src_rc='$(CURL_RCFILES)'; \ + win32_src_x_srcs='$(CURLX_CFILES)'; \ + win32_src_x_hdrs='$(CURLX_HFILES) ../lib/config-win32.h'; \ + \ + sorted_lib_srcs=`for file in $$win32_lib_srcs; do echo $$file; done | sort`; \ + sorted_lib_hdrs=`for file in $$win32_lib_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vauth_srcs=`for file in $$win32_lib_vauth_srcs; do echo $$file; done | sort`; \ + sorted_lib_vauth_hdrs=`for file in $$win32_lib_vauth_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vquic_srcs=`for file in $$win32_lib_vquic_srcs; do echo $$file; done | sort`; \ + sorted_lib_vquic_hdrs=`for file in $$win32_lib_vquic_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vssh_srcs=`for file in $$win32_lib_vssh_srcs; do echo $$file; done | sort`; \ + sorted_lib_vssh_hdrs=`for file in $$win32_lib_vssh_hdrs; do echo $$file; done | sort`; \ + sorted_lib_vtls_srcs=`for file in $$win32_lib_vtls_srcs; do echo $$file; done | sort`; \ + sorted_lib_vtls_hdrs=`for file in $$win32_lib_vtls_hdrs; do echo $$file; done | sort`; \ + sorted_src_srcs=`for file in $$win32_src_srcs; do echo $$file; done | sort`; \ + sorted_src_hdrs=`for file in $$win32_src_hdrs; do echo $$file; done | sort`; \ + sorted_src_x_srcs=`for file in $$win32_src_x_srcs; do echo $$file; done | sort`; \ + sorted_src_x_hdrs=`for file in $$win32_src_x_hdrs; do echo $$file; done | sort`; \ + \ + awk_code='\ +function gen_element(type, dir, file)\ +{\ + sub(/vauth\//, "", file);\ + sub(/vquic\//, "", file);\ + sub(/vssh\//, "", file);\ + sub(/vtls\//, "", file);\ +\ + spaces=" ";\ + if(dir == "lib\\vauth" ||\ + dir == "lib\\vquic" ||\ + dir == "lib\\vssh" ||\ + dir == "lib\\vtls")\ + tabs=" ";\ + else\ + tabs=" ";\ +\ + if(type == "dsp") {\ + printf("# Begin Source File\r\n");\ + printf("\r\n");\ + printf("SOURCE=..\\..\\..\\..\\%s\\%s\r\n", dir, file);\ + printf("# End Source File\r\n");\ + }\ + else if(type == "vcproj1") {\ + printf("%s\r\n",\ + tabs, dir, file);\ + printf("%s\r\n", tabs);\ + }\ + else if(type == "vcproj2") {\ + printf("%s\r\n", tabs);\ + printf("%s\r\n", tabs);\ + }\ + else if(type == "vcxproj") {\ + i = index(file, ".");\ + ext = substr(file, i == 0 ? 0 : i + 1);\ +\ + if(ext == "c")\ + printf("%s\r\n",\ + spaces, dir, file);\ + else if(ext == "h")\ + printf("%s\r\n",\ + spaces, dir, file);\ + else if(ext == "rc")\ + printf("%s\r\n",\ + spaces, dir, file);\ + }\ +}\ +\ +{\ +\ + if($$0 == "CURL_LIB_C_FILES") {\ + split(lib_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_H_FILES") {\ + split(lib_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_RC_FILES") {\ + split(lib_rc, arr);\ + for(val in arr) gen_element(proj_type, "lib", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VAUTH_C_FILES") {\ + split(lib_vauth_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vauth", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VAUTH_H_FILES") {\ + split(lib_vauth_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vauth", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VQUIC_C_FILES") {\ + split(lib_vquic_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vquic", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VQUIC_H_FILES") {\ + split(lib_vquic_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vquic", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VSSH_C_FILES") {\ + split(lib_vssh_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vssh", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VSSH_H_FILES") {\ + split(lib_vssh_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vssh", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VTLS_C_FILES") {\ + split(lib_vtls_srcs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vtls", arr[val]);\ + }\ + else if($$0 == "CURL_LIB_VTLS_H_FILES") {\ + split(lib_vtls_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "lib\\vtls", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_C_FILES") {\ + split(src_srcs, arr);\ + for(val in arr) gen_element(proj_type, "src", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_H_FILES") {\ + split(src_hdrs, arr);\ + for(val in arr) gen_element(proj_type, "src", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_RC_FILES") {\ + split(src_rc, arr);\ + for(val in arr) gen_element(proj_type, "src", arr[val]);\ + }\ + else if($$0 == "CURL_SRC_X_C_FILES") {\ + split(src_x_srcs, arr);\ + for(val in arr) {\ + sub(/..\/lib\//, "", arr[val]);\ + gen_element(proj_type, "lib", arr[val]);\ + }\ + }\ + else if($$0 == "CURL_SRC_X_H_FILES") {\ + split(src_x_hdrs, arr);\ + for(val in arr) {\ + sub(/..\/lib\//, "", arr[val]);\ + gen_element(proj_type, "lib", arr[val]);\ + }\ + }\ + else\ + printf("%s\r\n", $$0);\ +}';\ + \ + echo "generating '$(VC14_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_LIBTMPL) > $(VC14_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_SRCTMPL) > $(VC14_SRCVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_10_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_10_LIBTMPL) > $(VC14_10_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_10_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_10_SRCTMPL) > $(VC14_10_SRCVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_20_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_20_LIBTMPL) > $(VC14_20_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_20_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_20_SRCTMPL) > $(VC14_20_SRCVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_30_LIBVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v lib_srcs="$$sorted_lib_srcs" \ + -v lib_hdrs="$$sorted_lib_hdrs" \ + -v lib_rc="$$win32_lib_rc" \ + -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ + -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ + -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ + -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ + -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ + -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ + -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ + -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_30_LIBTMPL) > $(VC14_30_LIBVCXPROJ) || { exit 1; }; \ + \ + echo "generating '$(VC14_30_SRCVCXPROJ)'"; \ + awk -v proj_type=vcxproj \ + -v src_srcs="$$sorted_src_srcs" \ + -v src_hdrs="$$sorted_src_hdrs" \ + -v src_rc="$$win32_src_rc" \ + -v src_x_srcs="$$sorted_src_x_srcs" \ + -v src_x_hdrs="$$sorted_src_x_hdrs" \ + "$$awk_code" $(srcdir)/$(VC14_30_SRCTMPL) > $(VC14_30_SRCVCXPROJ) || { exit 1; };) + +tidy: + (cd src && $(MAKE) tidy) + (cd lib && $(MAKE) tidy) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/README b/README new file mode 100644 index 0000000..f5efbd7 --- /dev/null +++ b/README @@ -0,0 +1,55 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + +README + + Curl is a command line tool for transferring data specified with URL + syntax. Find out how to use curl by reading the curl.1 man page or the + MANUAL document. Find out how to install Curl by reading the INSTALL + document. + + libcurl is the library curl is using to do its job. It is readily + available to be used by your software. Read the libcurl.3 man page to + learn how. + + You find answers to the most frequent questions we get in the FAQ document. + + Study the COPYING file for distribution terms. + + Those documents and more can be found in the docs/ directory. + +CONTACT + + If you have problems, questions, ideas or suggestions, please contact us + by posting to a suitable mailing list. See https://curl.se/mail/ + + All contributors to the project are listed in the THANKS document. + +WEBSITE + + Visit the curl website for the latest news and downloads: + + https://curl.se/ + +GIT + + To download the latest source code off the GIT server, do this: + + git clone https://github.com/curl/curl.git + + (you will get a directory named curl created, filled with the source code) + +SECURITY PROBLEMS + + Report suspected security problems via our HackerOne page and not in public. + + https://hackerone.com/curl + +NOTICE + + Curl contains pieces of source code that is Copyright (c) 1998, 1999 + Kungliga Tekniska Högskolan. This notice is included here to comply with the + distribution terms. diff --git a/RELEASE-NOTES b/RELEASE-NOTES new file mode 100644 index 0000000..0bb5a8d --- /dev/null +++ b/RELEASE-NOTES @@ -0,0 +1,365 @@ +curl and libcurl 8.6.0 + + Public curl releases: 254 + Command line options: 258 + curl_easy_setopt() options: 304 + Public functions in libcurl: 93 + Contributors: 3078 + +This release includes the following changes: + + o add CURLE_TOO_LARGE [48] + o add CURLINFO_QUEUE_TIME_T [76] + o add CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: add [39] + o asyn-thread: use GetAddrInfoExW on >= Windows 8 [55] + o configure: make libpsl detection failure cause error [109] + o docs/cmdline: change to .md for cmdline docs [77] + o docs: introduce "curldown" for libcurl man page format [102] + o runtests: support -gl. Like -g but for lldb. [47] + +This release includes the following bugfixes: + + o altsvc: free 'as' when returning error [23] + o appveyor: replace PowerShell with bash + parallel autotools [54] + o appveyor: switch to out-of-tree builds [29] + o asyn-ares: with modern c-ares, use its default timeout [127] + o build: delete unused `HAVE_{GSSHEIMDAL,GSSMIT,HEIMDAL}` [4] + o build: delete/replace clang warning pragmas [111] + o build: enable missing OpenSSF-recommended warnings, with fixes [11] + o build: fix `-Wconversion`/`-Wsign-conversion` warnings [26] + o build: fix Windows ADDRESS_FAMILY detection [35] + o build: more `-Wformat` fixes [40] + o build: remove redundant `CURL_PULL_*` settings [8] + o cf-h1-proxy: no CURLOPT_USERAGENT in CONNECT with hyper [133] + o cf-socket: show errno in tcpkeepalive error messages [120] + o CI/distcheck: run full tests [31] + o cmake: add option to disable building docs + o cmake: fix generation for system name iOS [53] + o cmake: fix typo [5] + o cmake: freshen up docs/INSTALL.cmake [101] + o cmake: prefill/cache `HAVE_STRUCT_SOCKADDR_STORAGE` [45] + o cmake: rework options to enable curl and libcurl docs [161] + o cmake: when USE_MANUAL=YES, build the curl.1 man page [113] + o cmdline-opts/write-out.d: remove spurious double quotes + o cmdline-opts: update availability for the *-ca-native options [66] + o cmdline/gen: fix the sorting of the man page options [33] + o configure: add libngtcp2_crypto_boringssl detection [155] + o configure: fix no default int compile error in ipv6 detection [69] + o configure: when enabling QUIC, check that TLS supports QUIC [87] + o connect: remove margin from eyeballer alloc [79] + o content_encoding: change return code to typedef'ed enum [94] + o cookie.d: document use of empty string to enable cookie engine [106] + o cookie: avoid fopen with empty file name [24] + o curl.h: CURLOPT_DNS_SERVERS is only available with c-ares [131] + o curl: show ipfs and ipns as supported "protocols" [15] + o curl_easy_getinfo.3: remove the wrong time value count [116] + o curl_multi_fdset.3: remove mention of null pointer support [134] + o CURLINFO_REFERER.3: clarify that it is the *request* header [70] + o CURLOPT_AUTOREFERER.3: mention CURLINFO_REFERER + o CURLOPT_POSTFIELDS.3: fix incorrect C string escape in example [27] + o CURLOPT_SSH_*_KEYFILE: clarify [57] + o dist: add tests/errorcodes.pl to the tarball [6] + o docs: clean up Protocols: for cmdline options [32] + o docs: describe and highlight super cookies [80] + o docs: do not start lines/sentences with So, But nor And [140] + o docs: install curl.1 with cmake [166] + o docs: mention env vars not used by schannel [124] + o doh: remove unused local variable [34] + o examples: add four new examples [99] + o file+ftp: use stack buffers instead of data->state.buffer [138] + o ftp: handle the PORT parsing without allocation [44] + o ftp: use dynbuf to store entrypath [83] + o ftp: use memdup0 to store the OS from a SYST 215 response [82] + o ftpserver.pl: send 213 SIZE response without spurious newline + o gen.pl: support ## for doing .IP in table-like lists [105] + o gen: do italics/bold for a range of letters, not just single word [78] + o GHA: add a job scanning for "bad words" in markdown [164] + o GHA: bump ngtcp2, gnutls, mod_h2, quiche [158] + o gnutls: fix build with --disable-verbose [3] + o haproxy-clientip.d: document the arg [68] + o headers: make sure the trailing newline is not stored [97] + o headers: remove assert from Curl_headers_push [115] + o hostip: return error immediately when Curl_ip2addr() fails [19] + o hsts: remove assert for zero length domain [96] + o http2: improved on_stream_close/data_done handling [49] + o http3/quiche: fix result code on a stream reset [91] + o http3: initial support for OpenSSL 3.2 QUIC stack [110] + o http: adjust_pollset fix [85] + o http: check for "Host:" case insensitively [154] + o http: fix off-by-one error in request method length check [14] + o http: only act on 101 responses when they are HTTP/1.1 [98] + o http: remove comment reference to a removed solution [156] + o http: use stack scratch buffer [150] + o http_proxy: a blank CURLOPT_USERAGENT should not be used in CONNECT [90] + o krb5: add prototype to silence clang warnings on mvsnprintf() [119] + o lib: add debug log outputs for CURLE_BAD_FUNCTION_ARGUMENT [62] + o lib: error out on multissl + http3 [13] + o lib: fix variable undeclared error caused by `infof` changes [2] + o lib: reduce use of strncpy [30] + o lib: rename Curl_strndup to Curl_memdup0 to avoid misunderstanding [36] + o lib: replace readwrite with write_resp [137] + o lib: strndup/memdup instead of malloc, memcpy and null-terminate [42] + o libssh2: use `libssh2_session_callback_set2()` with v1.11.1 [103] + o libssh: improve the deprecation warning dismissal [20] + o libssh: supress warnings without version check [18] + o Makefile.am: fix the MSVC project generation [22] + o Makefile.mk: drop Windows support [12] + o mbedtls: fix `-Wnull-dereference` and `-Wredundant-decls` [117] + o mbedtls: free the entropy when threaded [46] + o mime: use memdup0 instead of malloc + memcpy [63] + o mksymbolsmanpage.pl: provide references to where the symbol is used + o mprintf: overhaul and bugfixes [52] + o mqtt: use stack scratch buffer for recv+publish [148] + o multi: remove total timer reset in file_do() while fetching file:// [89] + o ngtcp2: put h3 at the front of alpn [58] + o ntlm_wb: do not use data->state.buffer any longer [151] + o openldap: fix an LDAP crash [75] + o openldap: fix STARTTLS [67] + o openssl: re-match LibreSSL deinit with init [17] + o openssl: when verifystatus fails, remove session id from cache [100] + o OS400: sync ILE/RPG binding [114] + o pingpong: stop using the download buffer [159] + o pop3: replace calloc + memcpy with memdup0 [60] + o pytest: scorecard tracking CPU and RSS [157] + o quiche: return CURLE_HTTP3 on send to invalid stream [65] + o readwrite_data: loop less [21] + o Revert "urldata: move async resolver state from easy handle to connectdata" [16] + o rtsp: deal with borked server responses [129] + o runtests: for mode="text" on , fix newlines on both parts [64] + o sasl: make login option string override http auth [142] + o schannel: fix `-Warith-conversion` gcc 13 warning [28] + o sectransp: do verify_cert without memdup for blobs [93] + o sectransp_ make TLSCipherNameForNumber() available in non-verbose config [1] + o sendf: fix compiler warning with CURL_DISABLE_HEADERS_API [38] + o setopt: clear mimepost when formp is freed [92] + o setopt: use memdup0 when cloning COPYPOSTFIELDS [107] + o socks: fix generic output string to say SOCKS instead of SOCKS4 [144] + o socks: use own buffer instead of data->state.buffer [143] + o ssh: fix namespace of two local macros [51] + o ssh: use stack scratch buffer for seeks [146] + o strerror: repair get_winsock_error() [56] + o system.h: sync mingw `CURL_TYPEOF_CURL_SOCKLEN_T` with other compilers [9] + o system_win32: fix a function pointer assignment warning [71] + o telnet: use dynbuf instad of malloc for escape buffer [108] + o telnet: use stack scratch buffer for do [149] + o tests/server: delete workaround for old-mingw [25] + o tests: avoid int/size_t conversion size/sign warnings [163] + o tests: respect $TMPDIR when creating unix domain sockets [50] + o tool: make parser reject blank arguments if not supported [86] + o tool: prepend output_dir in header callback [95] + o tool_getparam: bsearch cmdline options [74] + o tool_getparam: do not try to expand without an argument [59] + o tool_getparam: stop supporting `@filename` style for --cookie [121] + o tool_listhelp: regenerate after recent .d updates [61] + o tool_operate: make --remove-on-error only remove "real" files [125] + o tool_operate: stop setting the file comment on Amiga [128] + o transfer: adjust_pollset improvements [81] + o transfer: fix upload rate limiting, add test cases [37] + o transfer: make the select_bits_paused condition check both directions [104] + o transfer: remove warning: Value stored to 'blen' is never read [136] + o url: don't set default CA paths for Secure Transport backend [126] + o url: for disabled protocols, mention if found in redirect [7] + o urlapi: remove assert [162] + o verify-examples.pl: fail verification on unescaped backslash [72] + o version: show only the libpsl version, not its dependencies [130] + o vquic: extract TLS setup into own source [88] + o vtls: fix missing multissl version info [73] + o vtls: receive max buffer [139] + o vtls: remove the Curl_cft_ssl_proxy object if CURL_DISABLE_PROXY [41] + o websockets: check for negative payload lengths [123] + o websockets: refactor decode chain [122] + o windows: delete redundant headers [43] + o windows: simplify detecting and using system headers [10] + o wolfssl: load certificate *chain* for PEM client certs [84] + o x509asn1: remove code for WANT_VERIFYHOST [132] + o x509asn1: switch from malloc to dynbuf [112] + +This release includes the following known bugs: + + o see docs/KNOWN_BUGS (https://curl.se/docs/knownbugs.html) + +Planned upcoming removals include: + + o support for space-separated NOPROXY patterns + + See https://curl.se/dev/deprecate.html for details + +This release would not have looked like this without help, code, reports and +advice from friends like these: + + Andy Alt, annalee, Baruch Siach, Ben, Boris Verkhovskiy, Brad Harder, + bubbleguuum on github, Cajus Pollmeier, calvin2021y on github, Chara White, + Chris Sauer, Dan Fandrich, Daniel Gustafsson, Daniel Stenberg, + dependabot[bot], Dmitry Karpov, Gabe, Geeknik Labs, Gisle Vanem, + Graham Campbell, Hans-Christian Egtvedt, Harry Sintonen, Haydar Alaidrus, + hgdagon on github, Hiroki Kurosawa, iAroc on github, ivanfywang, + janko-js on github, Jay Wu, Jess Lowe, Karthikdasari0423 on github, + Lealem Amedie, Lin Sun, Marcel Raad, Mark Huang, Mark Sinkovics, + Mauricio Scheffer, MichaÅ‚ Antoniak, Mike Hommey, Mohammadreza Hendiani, + Ozan Cansel, Patrick Monnerat, Pavel Pavlov, promptfuzz_ on hackerone, + Ray Satiro, RevaliQaQ on github, Richard Levitte, Scarlett McAllister, + Sergey Bronnikov, Sergey Markelov, sfan5 on github, Stefan Eissing, + Tatsuhiko Miyagawa, Tatsuhiro Tsujikawa, Theo, Thomas Ferguson, + Viktor Szakats, Xi Ruoyao, Yadhu Krishna M, Yedaya Katsman, Yifei Kong, + YX Hao, zengwei, zengwei2000, ウã•ã‚“ + (65 contributors) + +References to bug reports and discussions on issues: + + [1] = https://curl.se/bug/?i=12474 + [2] = https://curl.se/bug/?i=12470 + [3] = https://curl.se/bug/?i=12505 + [4] = https://curl.se/bug/?i=12506 + [5] = https://curl.se/bug/?i=12464 + [6] = https://curl.se/bug/?i=12462 + [7] = https://curl.se/bug/?i=12466 + [8] = https://curl.se/bug/?i=12502 + [9] = https://curl.se/bug/?i=12501 + [10] = https://curl.se/bug/?i=12495 + [11] = https://curl.se/bug/?i=12489 + [12] = https://curl.se/bug/?i=12224 + [13] = https://curl.se/bug/?i=12807 + [14] = https://curl.se/bug/?i=12534 + [15] = https://curl.se/mail/archive-2023-12/0026.html + [16] = https://curl.se/bug/?i=12524 + [17] = https://curl.se/bug/?i=12525 + [18] = https://curl.se/bug/?i=12523 + [19] = https://curl.se/bug/?i=12522 + [20] = https://curl.se/bug/?i=12519 + [21] = https://curl.se/bug/?i=12504 + [22] = https://curl.se/bug/?i=12564 + [23] = https://curl.se/bug/?i=12570 + [24] = https://curl.se/bug/?i=12514 + [25] = https://curl.se/bug/?i=12510 + [26] = https://curl.se/bug/?i=12557 + [27] = https://curl.se/bug/?i=12588 + [28] = https://curl.se/bug/?i=12616 + [29] = https://curl.se/bug/?i=12550 + [30] = https://curl.se/bug/?i=12499 + [31] = https://curl.se/bug/?i=12503 + [32] = https://curl.se/bug/?i=12496 + [33] = https://curl.se/mail/archive-2023-12/0014.html + [34] = https://curl.se/bug/?i=12491 + [35] = https://curl.se/bug/?i=12441 + [36] = https://curl.se/bug/?i=12490 + [37] = https://curl.se/bug/?i=12559 + [38] = https://curl.se/bug/?i=12485 + [39] = https://curl.se/bug/?i=12369 + [40] = https://curl.se/bug/?i=12540 + [41] = https://curl.se/bug/?i=12459 + [42] = https://curl.se/bug/?i=12453 + [43] = https://curl.se/bug/?i=12539 + [44] = https://curl.se/bug/?i=12456 + [45] = https://curl.se/bug/?i=12537 + [46] = https://curl.se/bug/?i=12584 + [47] = https://curl.se/bug/?i=12547 + [48] = https://curl.se/bug/?i=12269 + [49] = https://curl.se/bug/?i=10936 + [50] = https://curl.se/bug/?i=12545 + [51] = https://curl.se/bug/?i=12544 + [52] = https://curl.se/bug/?i=12561 + [53] = https://curl.se/bug/?i=12515 + [54] = https://curl.se/bug/?i=12560 + [55] = https://curl.se/bug/?i=12481 + [56] = https://curl.se/bug/?i=12578 + [57] = https://curl.se/bug/?i=12554 + [58] = https://curl.se/bug/?i=12576 + [59] = https://curl.se/bug/?i=12565 + [60] = https://curl.se/bug/?i=12650 + [61] = https://curl.se/bug/?i=12612 + [62] = https://curl.se/bug/?i=12658 + [63] = https://curl.se/bug/?i=12649 + [64] = https://curl.se/bug/?i=12612 + [65] = https://curl.se/bug/?i=12590 + [66] = https://curl.se/bug/?i=12613 + [67] = https://curl.se/bug/?i=12610 + [68] = https://curl.se/bug/?i=12611 + [69] = https://curl.se/bug/?i=12607 + [70] = https://curl.se/bug/?i=12605 + [71] = https://curl.se/bug/?i=12581 + [72] = https://curl.se/bug/?i=12589 + [73] = https://curl.se/bug/?i=12599 + [74] = https://curl.se/bug/?i=12631 + [75] = https://curl.se/bug/?i=12593 + [76] = https://curl.se/bug/?i=12368 + [77] = https://curl.se/bug/?i=12751 + [78] = https://curl.se/bug/?i=12689 + [79] = https://curl.se/bug/?i=12647 + [80] = https://curl.se/bug/?i=12687 + [81] = https://curl.se/bug/?i=12640 + [82] = https://curl.se/bug/?i=12639 + [83] = https://curl.se/bug/?i=12638 + [84] = https://curl.se/bug/?i=12634 + [85] = https://curl.se/bug/?i=12632 + [86] = https://curl.se/bug/?i=12620 + [87] = https://curl.se/bug/?i=12683 + [88] = https://curl.se/bug/?i=12678 + [89] = https://curl.se/bug/?i=12682 + [90] = https://curl.se/bug/?i=12680 + [91] = https://curl.se/bug/?i=12629 + [92] = https://curl.se/bug/?i=12608 + [93] = https://curl.se/bug/?i=12679 + [94] = https://curl.se/bug/?i=12618 + [95] = https://curl.se/bug/?i=12614 + [96] = https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65661 + [97] = https://curl.se/mail/lib-2024-01/0019.html + [98] = https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66184 + [99] = https://curl.se/bug/?i=12671 + [100] = https://curl.se/bug/?i=12760 + [101] = https://curl.se/bug/?i=12772 + [102] = https://curl.se/bug/?i=12730 + [103] = https://curl.se/bug/?i=12754 + [104] = https://curl.se/mail/lib-2024-01/0049.html + [105] = https://curl.se/bug/?i=12667 + [106] = https://curl.se/bug/?i=12643 + [107] = https://curl.se/bug/?i=12651 + [108] = https://curl.se/bug/?i=12652 + [109] = https://curl.se/bug/?i=12661 + [110] = https://curl.se/bug/?i=12734 + [111] = https://curl.se/bug/?i=12812 + [112] = https://curl.se/bug/?i=12808 + [113] = https://curl.se/bug/?i=12742 + [114] = https://curl.se/bug/?i=12815 + [115] = https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65839 + [116] = https://curl.se/bug/?i=12727 + [117] = https://curl.se/bug/?i=12720 + [119] = https://curl.se/bug/?i=12803 + [120] = https://curl.se/bug/?i=12726 + [121] = https://curl.se/bug/?i=12645 + [122] = https://curl.se/bug/?i=12713 + [123] = https://curl.se/bug/?i=12707 + [124] = https://curl.se/bug/?i=12711 + [125] = https://curl.se/bug/?i=12710 + [126] = https://curl.se/bug/?i=12704 + [127] = https://curl.se/bug/?i=12703 + [128] = https://curl.se/bug/?i=12709 + [129] = https://curl.se/bug/?i=12701 + [130] = https://curl.se/bug/?i=12700 + [131] = https://curl.se/bug/?i=12695 + [132] = https://curl.se/bug/?i=12804 + [133] = https://curl.se/bug/?i=12697 + [134] = https://curl.se/bug/?i=12691 + [136] = https://curl.se/bug/?i=12693 + [137] = https://curl.se/bug/?i=12480 + [138] = https://curl.se/bug/?i=12789 + [139] = https://curl.se/bug/?i=12801 + [140] = https://curl.se/bug/?i=12802 + [142] = https://curl.se/bug/?i=10259 + [143] = https://curl.se/bug/?i=12788 + [144] = https://curl.se/bug/?i=12797 + [146] = https://curl.se/bug/?i=12794 + [148] = https://curl.se/bug/?i=12792 + [149] = https://curl.se/bug/?i=12793 + [150] = https://curl.se/bug/?i=12791 + [151] = https://curl.se/bug/?i=12787 + [154] = https://curl.se/bug/?i=12784 + [155] = https://curl.se/bug/?i=12724 + [156] = https://curl.se/bug/?i=12785 + [157] = https://curl.se/bug/?i=12765 + [158] = https://curl.se/bug/?i=12778 + [159] = https://curl.se/bug/?i=12757 + [161] = https://curl.se/bug/?i=12773 + [162] = https://curl.se/bug/?i=12775 + [163] = https://curl.se/bug/?i=12768 + [164] = https://curl.se/bug/?i=12764 + [166] = https://curl.se/bug/?i=12759 diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..a44ae35 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,1663 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +dnl CURL_CHECK_DEF (SYMBOL, [INCLUDES], [SILENT]) +dnl ------------------------------------------------- +dnl Use the C preprocessor to find out if the given object-style symbol +dnl is defined and get its expansion. This macro will not use default +dnl includes even if no INCLUDES argument is given. This macro will run +dnl silently when invoked with three arguments. If the expansion would +dnl result in a set of double-quoted strings the returned expansion will +dnl actually be a single double-quoted string concatenating all them. + +AC_DEFUN([CURL_CHECK_DEF], [ + AC_REQUIRE([CURL_CPP_P])dnl + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + AS_VAR_PUSHDEF([ac_HaveDef], [curl_cv_have_def_$1])dnl + AS_VAR_PUSHDEF([ac_Def], [curl_cv_def_$1])dnl + if test -z "$SED"; then + AC_MSG_ERROR([SED not set. Cannot continue without SED being set.]) + fi + if test -z "$GREP"; then + AC_MSG_ERROR([GREP not set. Cannot continue without GREP being set.]) + fi + ifelse($3,,[AC_MSG_CHECKING([for preprocessor definition of $1])]) + tmp_exp="" + AC_PREPROC_IFELSE([ + AC_LANG_SOURCE( +ifelse($2,,,[$2])[[ +#ifdef $1 +CURL_DEF_TOKEN $1 +#endif + ]]) + ],[ + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[[ ]][[ ]]*//' 2>/dev/null | \ + "$SED" 's/[["]][[ ]]*[["]]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "$1"; then + tmp_exp="" + fi + ]) + if test -z "$tmp_exp"; then + AS_VAR_SET(ac_HaveDef, no) + ifelse($3,,[AC_MSG_RESULT([no])]) + else + AS_VAR_SET(ac_HaveDef, yes) + AS_VAR_SET(ac_Def, $tmp_exp) + ifelse($3,,[AC_MSG_RESULT([$tmp_exp])]) + fi + AS_VAR_POPDEF([ac_Def])dnl + AS_VAR_POPDEF([ac_HaveDef])dnl + CPPFLAGS=$OLDCPPFLAGS +]) + + +dnl CURL_CHECK_DEF_CC (SYMBOL, [INCLUDES], [SILENT]) +dnl ------------------------------------------------- +dnl Use the C compiler to find out only if the given symbol is defined +dnl or not, this can not find out its expansion. This macro will not use +dnl default includes even if no INCLUDES argument is given. This macro +dnl will run silently when invoked with three arguments. + +AC_DEFUN([CURL_CHECK_DEF_CC], [ + AS_VAR_PUSHDEF([ac_HaveDef], [curl_cv_have_def_$1])dnl + ifelse($3,,[AC_MSG_CHECKING([for compiler definition of $1])]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE( +ifelse($2,,,[$2])[[ +int main (void) +{ +#ifdef $1 + return 0; +#else + force compilation error +#endif +} + ]]) + ],[ + tst_symbol_defined="yes" + ],[ + tst_symbol_defined="no" + ]) + if test "$tst_symbol_defined" = "yes"; then + AS_VAR_SET(ac_HaveDef, yes) + ifelse($3,,[AC_MSG_RESULT([yes])]) + else + AS_VAR_SET(ac_HaveDef, no) + ifelse($3,,[AC_MSG_RESULT([no])]) + fi + AS_VAR_POPDEF([ac_HaveDef])dnl +]) + + +dnl CURL_CHECK_LIB_XNET +dnl ------------------------------------------------- +dnl Verify if X/Open network library is required. + +AC_DEFUN([CURL_CHECK_LIB_XNET], [ + AC_MSG_CHECKING([if X/Open network library is required]) + tst_lib_xnet_required="no" + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ +int main (void) +{ +#if defined(__hpux) && defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600) + return 0; +#elif defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED) + return 0; +#else + force compilation error +#endif +} + ]]) + ],[ + tst_lib_xnet_required="yes" + LIBS="-lxnet $LIBS" + ]) + AC_MSG_RESULT([$tst_lib_xnet_required]) +]) + + +dnl CURL_CHECK_AIX_ALL_SOURCE +dnl ------------------------------------------------- +dnl Provides a replacement of traditional AC_AIX with +dnl an uniform behavior across all autoconf versions, +dnl and with our own placement rules. + +AC_DEFUN([CURL_CHECK_AIX_ALL_SOURCE], [ + AH_VERBATIM([_ALL_SOURCE], + [/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif]) + AC_BEFORE([$0], [AC_SYS_LARGEFILE])dnl + AC_BEFORE([$0], [CURL_CONFIGURE_REENTRANT])dnl + AC_MSG_CHECKING([if OS is AIX (to define _ALL_SOURCE)]) + AC_EGREP_CPP([yes_this_is_aix],[ +#ifdef _AIX + yes_this_is_aix +#endif + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE(_ALL_SOURCE) + ],[ + AC_MSG_RESULT([no]) + ]) +]) + + +dnl CURL_CHECK_NATIVE_WINDOWS +dnl ------------------------------------------------- +dnl Check if building a native Windows target + +AC_DEFUN([CURL_CHECK_NATIVE_WINDOWS], [ + AC_CACHE_CHECK([whether build target is a native Windows one], [curl_cv_native_windows], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ +#ifdef _WIN32 + int dummy=1; +#else + Not a native Windows build target. +#endif + ]]) + ],[ + curl_cv_native_windows="yes" + ],[ + curl_cv_native_windows="no" + ]) + ]) + AM_CONDITIONAL(DOING_NATIVE_WINDOWS, test "x$curl_cv_native_windows" = xyes) +]) + + +dnl CURL_CHECK_HEADER_LBER +dnl ------------------------------------------------- +dnl Check for compilable and valid lber.h header, +dnl and check if it is needed even with ldap.h + +AC_DEFUN([CURL_CHECK_HEADER_LBER], [ + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + AC_CACHE_CHECK([for lber.h], [curl_cv_header_lber_h], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef NULL +#define NULL (void *)0 +#endif +#include + ]],[[ + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + ber_free(bep, 1); + ]]) + ],[ + curl_cv_header_lber_h="yes" + ],[ + curl_cv_header_lber_h="no" + ]) + ]) + if test "$curl_cv_header_lber_h" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_LBER_H, 1, + [Define to 1 if you have the lber.h header file.]) + # + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef NULL +#define NULL (void *)0 +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#include + ]],[[ + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + ber_free(bep, 1); + ]]) + ],[ + curl_cv_need_header_lber_h="no" + ],[ + curl_cv_need_header_lber_h="yes" + ]) + # + case "$curl_cv_need_header_lber_h" in + yes) + AC_DEFINE_UNQUOTED(NEED_LBER_H, 1, + [Define to 1 if you need the lber.h header file even with ldap.h]) + ;; + esac + fi +]) + + +dnl CURL_CHECK_HEADER_LDAP +dnl ------------------------------------------------- +dnl Check for compilable and valid ldap.h header + +AC_DEFUN([CURL_CHECK_HEADER_LDAP], [ + AC_REQUIRE([CURL_CHECK_HEADER_LBER])dnl + AC_CACHE_CHECK([for ldap.h], [curl_cv_header_ldap_h], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#ifdef NEED_LBER_H +#include +#endif +#include + ]],[[ + LDAP *ldp = ldap_init("0.0.0.0", LDAP_PORT); + int res = ldap_unbind(ldp); + ]]) + ],[ + curl_cv_header_ldap_h="yes" + ],[ + curl_cv_header_ldap_h="no" + ]) + ]) + case "$curl_cv_header_ldap_h" in + yes) + AC_DEFINE_UNQUOTED(HAVE_LDAP_H, 1, + [Define to 1 if you have the ldap.h header file.]) + ;; + esac +]) + + +dnl CURL_CHECK_HEADER_LDAP_SSL +dnl ------------------------------------------------- +dnl Check for compilable and valid ldap_ssl.h header + +AC_DEFUN([CURL_CHECK_HEADER_LDAP_SSL], [ + AC_REQUIRE([CURL_CHECK_HEADER_LDAP])dnl + AC_CACHE_CHECK([for ldap_ssl.h], [curl_cv_header_ldap_ssl_h], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#ifdef NEED_LBER_H +#include +#endif +#ifdef HAVE_LDAP_H +#include +#endif +#include + ]],[[ + LDAP *ldp = ldapssl_init("0.0.0.0", LDAPS_PORT, 1); + ]]) + ],[ + curl_cv_header_ldap_ssl_h="yes" + ],[ + curl_cv_header_ldap_ssl_h="no" + ]) + ]) + case "$curl_cv_header_ldap_ssl_h" in + yes) + AC_DEFINE_UNQUOTED(HAVE_LDAP_SSL_H, 1, + [Define to 1 if you have the ldap_ssl.h header file.]) + ;; + esac +]) + + +dnl CURL_CHECK_LIBS_WINLDAP +dnl ------------------------------------------------- +dnl Check for libraries needed for WINLDAP support, +dnl and prepended to LIBS any needed libraries. +dnl This macro can take an optional parameter with a +dnl whitespace separated list of libraries to check +dnl before the WINLDAP default ones. + +AC_DEFUN([CURL_CHECK_LIBS_WINLDAP], [ + AC_REQUIRE([CURL_CHECK_HEADER_WINBER])dnl + # + AC_MSG_CHECKING([for WINLDAP libraries]) + # + u_libs="" + # + ifelse($1,,,[ + for x_lib in $1; do + case "$x_lib" in + -l*) + l_lib="$x_lib" + ;; + *) + l_lib="-l$x_lib" + ;; + esac + if test -z "$u_libs"; then + u_libs="$l_lib" + else + u_libs="$u_libs $l_lib" + fi + done + ]) + # + curl_cv_save_LIBS="$LIBS" + curl_cv_ldap_LIBS="unknown" + # + for x_nlibs in '' "$u_libs" \ + '-lwldap32' ; do + if test "$curl_cv_ldap_LIBS" = "unknown"; then + if test -z "$x_nlibs"; then + LIBS="$curl_cv_save_LIBS" + else + LIBS="$x_nlibs $curl_cv_save_LIBS" + fi + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#ifdef HAVE_WINBER_H +#include +#endif +#endif + ]],[[ + BERVAL *bvp = NULL; + BerElement *bep = ber_init(bvp); + LDAP *ldp = ldap_init("0.0.0.0", LDAP_PORT); + ULONG res = ldap_unbind(ldp); + ber_free(bep, 1); + ]]) + ],[ + curl_cv_ldap_LIBS="$x_nlibs" + ]) + fi + done + # + LIBS="$curl_cv_save_LIBS" + # + case X-"$curl_cv_ldap_LIBS" in + X-unknown) + AC_MSG_RESULT([cannot find WINLDAP libraries]) + ;; + X-) + AC_MSG_RESULT([no additional lib required]) + ;; + *) + if test -z "$curl_cv_save_LIBS"; then + LIBS="$curl_cv_ldap_LIBS" + else + LIBS="$curl_cv_ldap_LIBS $curl_cv_save_LIBS" + fi + AC_MSG_RESULT([$curl_cv_ldap_LIBS]) + ;; + esac + # +]) + + +dnl CURL_CHECK_LIBS_LDAP +dnl ------------------------------------------------- +dnl Check for libraries needed for LDAP support, +dnl and prepended to LIBS any needed libraries. +dnl This macro can take an optional parameter with a +dnl whitespace separated list of libraries to check +dnl before the default ones. + +AC_DEFUN([CURL_CHECK_LIBS_LDAP], [ + AC_REQUIRE([CURL_CHECK_HEADER_LDAP])dnl + # + AC_MSG_CHECKING([for LDAP libraries]) + # + u_libs="" + # + ifelse($1,,,[ + for x_lib in $1; do + case "$x_lib" in + -l*) + l_lib="$x_lib" + ;; + *) + l_lib="-l$x_lib" + ;; + esac + if test -z "$u_libs"; then + u_libs="$l_lib" + else + u_libs="$u_libs $l_lib" + fi + done + ]) + # + curl_cv_save_LIBS="$LIBS" + curl_cv_ldap_LIBS="unknown" + # + for x_nlibs in '' "$u_libs" \ + '-lldap' \ + '-lldap -llber' \ + '-llber -lldap' \ + '-lldapssl -lldapx -lldapsdk' \ + '-lldapsdk -lldapx -lldapssl' \ + '-lldap -llber -lssl -lcrypto' ; do + + if test "$curl_cv_ldap_LIBS" = "unknown"; then + if test -z "$x_nlibs"; then + LIBS="$curl_cv_save_LIBS" + else + LIBS="$x_nlibs $curl_cv_save_LIBS" + fi + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef NULL +#define NULL (void *)0 +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#ifdef NEED_LBER_H +#include +#endif +#ifdef HAVE_LDAP_H +#include +#endif + ]],[[ + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + LDAP *ldp = ldap_init("0.0.0.0", LDAP_PORT); + int res = ldap_unbind(ldp); + ber_free(bep, 1); + ]]) + ],[ + curl_cv_ldap_LIBS="$x_nlibs" + ]) + fi + done + # + LIBS="$curl_cv_save_LIBS" + # + case X-"$curl_cv_ldap_LIBS" in + X-unknown) + AC_MSG_RESULT([cannot find LDAP libraries]) + ;; + X-) + AC_MSG_RESULT([no additional lib required]) + ;; + *) + if test -z "$curl_cv_save_LIBS"; then + LIBS="$curl_cv_ldap_LIBS" + else + LIBS="$curl_cv_ldap_LIBS $curl_cv_save_LIBS" + fi + AC_MSG_RESULT([$curl_cv_ldap_LIBS]) + ;; + esac + # +]) + + +dnl TYPE_SOCKADDR_STORAGE +dnl ------------------------------------------------- +dnl Check for struct sockaddr_storage. Most IPv6-enabled +dnl hosts have it, but AIX 4.3 is one known exception. + +AC_DEFUN([TYPE_SOCKADDR_STORAGE], +[ + AC_CHECK_TYPE([struct sockaddr_storage], + AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE, 1, + [if struct sockaddr_storage is defined]), , + [ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#endif + ]) +]) + +dnl CURL_CHECK_FUNC_RECV +dnl ------------------------------------------------- +dnl Test if the socket recv() function is available, + +AC_DEFUN([CURL_CHECK_FUNC_RECV], [ + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + AC_CHECK_HEADERS(sys/types.h sys/socket.h) + # + AC_MSG_CHECKING([for recv]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +$curl_includes_bsdsocket +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#endif + ]],[[ + recv(0, 0, 0, 0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + curl_cv_recv="yes" + ],[ + AC_MSG_RESULT([no]) + curl_cv_recv="no" + ]) + # + if test "$curl_cv_recv" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_RECV, 1, + [Define to 1 if you have the recv function.]) + curl_cv_func_recv="yes" + else + AC_MSG_ERROR([Unable to link function recv]) + fi +]) + + +dnl CURL_CHECK_FUNC_SEND +dnl ------------------------------------------------- +dnl Test if the socket send() function is available, + +AC_DEFUN([CURL_CHECK_FUNC_SEND], [ + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + AC_CHECK_HEADERS(sys/types.h sys/socket.h) + # + AC_MSG_CHECKING([for send]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +$curl_includes_bsdsocket +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#endif + ]],[[ + send(0, 0, 0, 0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + curl_cv_send="yes" + ],[ + AC_MSG_RESULT([no]) + curl_cv_send="no" + ]) + # + if test "$curl_cv_send" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SEND, 1, + [Define to 1 if you have the send function.]) + curl_cv_func_send="yes" + else + AC_MSG_ERROR([Unable to link function send]) + fi +]) + +dnl CURL_CHECK_MSG_NOSIGNAL +dnl ------------------------------------------------- +dnl Check for MSG_NOSIGNAL + +AC_DEFUN([CURL_CHECK_MSG_NOSIGNAL], [ + AC_CHECK_HEADERS(sys/types.h sys/socket.h) + AC_CACHE_CHECK([for MSG_NOSIGNAL], [curl_cv_msg_nosignal], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#endif + ]],[[ + int flag=MSG_NOSIGNAL; + ]]) + ],[ + curl_cv_msg_nosignal="yes" + ],[ + curl_cv_msg_nosignal="no" + ]) + ]) + case "$curl_cv_msg_nosignal" in + yes) + AC_DEFINE_UNQUOTED(HAVE_MSG_NOSIGNAL, 1, + [Define to 1 if you have the MSG_NOSIGNAL flag.]) + ;; + esac +]) + + +dnl CURL_CHECK_STRUCT_TIMEVAL +dnl ------------------------------------------------- +dnl Check for timeval struct + +AC_DEFUN([CURL_CHECK_STRUCT_TIMEVAL], [ + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + AC_CHECK_HEADERS(sys/types.h sys/time.h sys/socket.h) + AC_CACHE_CHECK([for struct timeval], [curl_cv_struct_timeval], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + ]],[[ + struct timeval ts; + ts.tv_sec = 0; + ts.tv_usec = 0; + ]]) + ],[ + curl_cv_struct_timeval="yes" + ],[ + curl_cv_struct_timeval="no" + ]) + ]) + case "$curl_cv_struct_timeval" in + yes) + AC_DEFINE_UNQUOTED(HAVE_STRUCT_TIMEVAL, 1, + [Define to 1 if you have the timeval struct.]) + ;; + esac +]) + + +dnl TYPE_IN_ADDR_T +dnl ------------------------------------------------- +dnl Check for in_addr_t: it is used to receive the return code of inet_addr() +dnl and a few other things. + +AC_DEFUN([TYPE_IN_ADDR_T], [ + AC_CHECK_TYPE([in_addr_t], ,[ + dnl in_addr_t not available + AC_CACHE_CHECK([for in_addr_t equivalent], + [curl_cv_in_addr_t_equiv], [ + curl_cv_in_addr_t_equiv="unknown" + for t in "unsigned long" int size_t unsigned long; do + if test "$curl_cv_in_addr_t_equiv" = "unknown"; then + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#endif + ]],[[ + $t data = inet_addr ("1.2.3.4"); + ]]) + ],[ + curl_cv_in_addr_t_equiv="$t" + ]) + fi + done + ]) + case "$curl_cv_in_addr_t_equiv" in + unknown) + AC_MSG_ERROR([Cannot find a type to use in place of in_addr_t]) + ;; + *) + AC_DEFINE_UNQUOTED(in_addr_t, $curl_cv_in_addr_t_equiv, + [Type to use in place of in_addr_t when system does not provide it.]) + ;; + esac + ],[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#endif + ]) +]) + + +dnl CURL_CHECK_FUNC_CLOCK_GETTIME_MONOTONIC +dnl ------------------------------------------------- +dnl Check if monotonic clock_gettime is available. + +AC_DEFUN([CURL_CHECK_FUNC_CLOCK_GETTIME_MONOTONIC], [ + AC_CHECK_HEADERS(sys/types.h sys/time.h) + AC_MSG_CHECKING([for monotonic clock_gettime]) + # + if test "x$dontwant_rt" = "xno" ; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + ]],[[ + struct timespec ts; + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + ]]) + ],[ + AC_MSG_RESULT([yes]) + curl_func_clock_gettime="yes" + ],[ + AC_MSG_RESULT([no]) + curl_func_clock_gettime="no" + ]) + fi + dnl Definition of HAVE_CLOCK_GETTIME_MONOTONIC is intentionally postponed + dnl until library linking and run-time checks for clock_gettime succeed. +]) + +dnl CURL_CHECK_FUNC_CLOCK_GETTIME_MONOTONIC_RAW +dnl ------------------------------------------------- +dnl Check if monotonic clock_gettime is available. + +AC_DEFUN([CURL_CHECK_FUNC_CLOCK_GETTIME_MONOTONIC_RAW], [ + AC_CHECK_HEADERS(sys/types.h sys/time.h) + AC_MSG_CHECKING([for raw monotonic clock_gettime]) + # + if test "x$dontwant_rt" = "xno" ; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + ]],[[ + struct timespec ts; + (void)clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_CLOCK_GETTIME_MONOTONIC_RAW, 1, + [Define to 1 if you have the clock_gettime function and raw monotonic timer.]) + ],[ + AC_MSG_RESULT([no]) + ]) + fi +]) + + +dnl CURL_CHECK_LIBS_CLOCK_GETTIME_MONOTONIC +dnl ------------------------------------------------- +dnl If monotonic clock_gettime is available then, +dnl check and prepended to LIBS any needed libraries. + +AC_DEFUN([CURL_CHECK_LIBS_CLOCK_GETTIME_MONOTONIC], [ + AC_REQUIRE([CURL_CHECK_FUNC_CLOCK_GETTIME_MONOTONIC])dnl + # + if test "$curl_func_clock_gettime" = "yes"; then + # + AC_MSG_CHECKING([for clock_gettime in libraries]) + # + curl_cv_save_LIBS="$LIBS" + curl_cv_gclk_LIBS="unknown" + # + for x_xlibs in '' '-lrt' '-lposix4' ; do + if test "$curl_cv_gclk_LIBS" = "unknown"; then + if test -z "$x_xlibs"; then + LIBS="$curl_cv_save_LIBS" + else + LIBS="$x_xlibs $curl_cv_save_LIBS" + fi + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + ]],[[ + struct timespec ts; + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + ]]) + ],[ + curl_cv_gclk_LIBS="$x_xlibs" + ]) + fi + done + # + LIBS="$curl_cv_save_LIBS" + # + case X-"$curl_cv_gclk_LIBS" in + X-unknown) + AC_MSG_RESULT([cannot find clock_gettime]) + AC_MSG_WARN([HAVE_CLOCK_GETTIME_MONOTONIC will not be defined]) + curl_func_clock_gettime="no" + ;; + X-) + AC_MSG_RESULT([no additional lib required]) + curl_func_clock_gettime="yes" + ;; + *) + if test -z "$curl_cv_save_LIBS"; then + LIBS="$curl_cv_gclk_LIBS" + else + LIBS="$curl_cv_gclk_LIBS $curl_cv_save_LIBS" + fi + AC_MSG_RESULT([$curl_cv_gclk_LIBS]) + curl_func_clock_gettime="yes" + ;; + esac + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$curl_func_clock_gettime" = "yes"; then + AC_MSG_CHECKING([if monotonic clock_gettime works]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + ]],[[ + struct timespec ts; + if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) + exit(0); + else + exit(1); + ]]) + ],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_WARN([HAVE_CLOCK_GETTIME_MONOTONIC will not be defined]) + curl_func_clock_gettime="no" + LIBS="$curl_cv_save_LIBS" + ]) + fi + # + case "$curl_func_clock_gettime" in + yes) + AC_DEFINE_UNQUOTED(HAVE_CLOCK_GETTIME_MONOTONIC, 1, + [Define to 1 if you have the clock_gettime function and monotonic timer.]) + ;; + esac + # + fi + # +]) + + +dnl CURL_CHECK_LIBS_CONNECT +dnl ------------------------------------------------- +dnl Verify if network connect function is already available +dnl using current libraries or if another one is required. + +AC_DEFUN([CURL_CHECK_LIBS_CONNECT], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + AC_MSG_CHECKING([for connect in libraries]) + tst_connect_save_LIBS="$LIBS" + tst_connect_need_LIBS="unknown" + for tst_lib in '' '-lsocket' ; do + if test "$tst_connect_need_LIBS" = "unknown"; then + LIBS="$tst_lib $tst_connect_save_LIBS" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + #if !defined(_WIN32) && !defined(HAVE_PROTO_BSDSOCKET_H) + int connect(int, void*, int); + #endif + ]],[[ + if(0 != connect(0, 0, 0)) + return 1; + ]]) + ],[ + tst_connect_need_LIBS="$tst_lib" + ]) + fi + done + LIBS="$tst_connect_save_LIBS" + # + case X-"$tst_connect_need_LIBS" in + X-unknown) + AC_MSG_RESULT([cannot find connect]) + AC_MSG_ERROR([cannot find connect function in libraries.]) + ;; + X-) + AC_MSG_RESULT([yes]) + ;; + *) + AC_MSG_RESULT([$tst_connect_need_LIBS]) + LIBS="$tst_connect_need_LIBS $tst_connect_save_LIBS" + ;; + esac +]) + + +dnl CURL_DEFINE_UNQUOTED (VARIABLE, [VALUE]) +dnl ------------------------------------------------- +dnl Like AC_DEFINE_UNQUOTED this macro will define a C preprocessor +dnl symbol that can be further used in custom template configuration +dnl files. This macro, unlike AC_DEFINE_UNQUOTED, does not use a third +dnl argument for the description. Symbol definitions done with this +dnl macro are intended to be exclusively used in handcrafted *.h.in +dnl template files. Contrary to what AC_DEFINE_UNQUOTED does, this one +dnl prevents autoheader generation and insertion of symbol template +dnl stub and definition into the first configuration header file. Do +dnl not use this macro as a replacement for AC_DEFINE_UNQUOTED, each +dnl one serves different functional needs. + +AC_DEFUN([CURL_DEFINE_UNQUOTED], [ +cat >>confdefs.h <<_EOF +[@%:@define] $1 ifelse($#, 2, [$2], 1) +_EOF +]) + + +dnl CURL_CHECK_FUNC_SELECT +dnl ------------------------------------------------- +dnl Test if the socket select() function is available. + +AC_DEFUN([CURL_CHECK_FUNC_SELECT], [ + AC_REQUIRE([CURL_CHECK_STRUCT_TIMEVAL])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + AC_CHECK_HEADERS(sys/select.h sys/socket.h) + # + AC_MSG_CHECKING([for select]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include +#ifndef _WIN32 +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +$curl_includes_bsdsocket +#endif + ]],[[ + select(0, 0, 0, 0, 0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + curl_cv_select="yes" + ],[ + AC_MSG_RESULT([no]) + curl_cv_select="no" + ]) + # + if test "$curl_cv_select" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SELECT, 1, + [Define to 1 if you have the select function.]) + curl_cv_func_select="yes" + fi +]) + + +dnl CURL_VERIFY_RUNTIMELIBS +dnl ------------------------------------------------- +dnl Verify that the shared libs found so far can be used when running +dnl programs, since otherwise the situation will create odd configure errors +dnl that are misleading people. +dnl +dnl Make sure this test is run BEFORE the first test in the script that +dnl runs anything, which at the time of this writing is the AC_CHECK_SIZEOF +dnl macro. It must also run AFTER all lib-checking macros are complete. + +AC_DEFUN([CURL_VERIFY_RUNTIMELIBS], [ + + dnl this test is of course not sensible if we are cross-compiling! + if test "x$cross_compiling" != xyes; then + + dnl just run a program to verify that the libs checked for previous to this + dnl point also is available run-time! + AC_MSG_CHECKING([run-time libs availability]) + CURL_RUN_IFELSE([ +int main() +{ + return 0; +} +], + AC_MSG_RESULT([fine]), + AC_MSG_RESULT([failed]) + AC_MSG_ERROR([one or more libs available at link-time are not available run-time. Libs used at link-time: $LIBS]) + ) + + dnl if this test fails, configure has already stopped + fi +]) + + +dnl CURL_CHECK_CA_BUNDLE +dnl ------------------------------------------------- +dnl Check if a default ca-bundle should be used +dnl +dnl regarding the paths this will scan: +dnl /etc/ssl/certs/ca-certificates.crt Debian systems +dnl /etc/pki/tls/certs/ca-bundle.crt Redhat and Mandriva +dnl /usr/share/ssl/certs/ca-bundle.crt old(er) Redhat +dnl /usr/local/share/certs/ca-root-nss.crt MidnightBSD +dnl /etc/ssl/cert.pem OpenBSD, MidnightBSD (symlink) +dnl /etc/ssl/certs (CA path) SUSE, FreeBSD + +AC_DEFUN([CURL_CHECK_CA_BUNDLE], [ + + AC_MSG_CHECKING([default CA cert bundle/path]) + + AC_ARG_WITH(ca-bundle, +AS_HELP_STRING([--with-ca-bundle=FILE], +[Path to a file containing CA certificates (example: /etc/ca-bundle.crt)]) +AS_HELP_STRING([--without-ca-bundle], [Don't use a default CA bundle]), + [ + want_ca="$withval" + if test "x$want_ca" = "xyes"; then + AC_MSG_ERROR([--with-ca-bundle=FILE requires a path to the CA bundle]) + fi + ], + [ want_ca="unset" ]) + AC_ARG_WITH(ca-path, +AS_HELP_STRING([--with-ca-path=DIRECTORY], +[Path to a directory containing CA certificates stored individually, with \ +their filenames in a hash format. This option can be used with the OpenSSL, \ +GnuTLS, mbedTLS and wolfSSL backends. Refer to OpenSSL c_rehash for details. \ +(example: /etc/certificates)]) +AS_HELP_STRING([--without-ca-path], [Don't use a default CA path]), + [ + want_capath="$withval" + if test "x$want_capath" = "xyes"; then + AC_MSG_ERROR([--with-ca-path=DIRECTORY requires a path to the CA path directory]) + fi + ], + [ want_capath="unset"]) + + ca_warning=" (warning: certs not found)" + capath_warning=" (warning: certs not found)" + check_capath="" + + if test "x$want_ca" != "xno" -a "x$want_ca" != "xunset" -a \ + "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then + dnl both given + ca="$want_ca" + capath="$want_capath" + elif test "x$want_ca" != "xno" -a "x$want_ca" != "xunset"; then + dnl --with-ca-bundle given + ca="$want_ca" + capath="no" + elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then + dnl --with-ca-path given + if test "x$OPENSSL_ENABLED" != "x1" -a \ + "x$GNUTLS_ENABLED" != "x1" -a \ + "x$MBEDTLS_ENABLED" != "x1" -a \ + "x$WOLFSSL_ENABLED" != "x1"; then + AC_MSG_ERROR([--with-ca-path only works with OpenSSL, GnuTLS, mbedTLS or wolfSSL]) + fi + capath="$want_capath" + ca="no" + else + dnl first try autodetecting a CA bundle , then a CA path + dnl both autodetections can be skipped by --without-ca-* + ca="no" + capath="no" + if test "x$cross_compiling" != "xyes"; then + dnl NOT cross-compiling and... + dnl neither of the --with-ca-* options are provided + if test "x$want_ca" = "xunset"; then + dnl the path we previously would have installed the curl ca bundle + dnl to, and thus we now check for an already existing cert in that + dnl place in case we find no other + if test "x$prefix" != xNONE; then + cac="${prefix}/share/curl/curl-ca-bundle.crt" + else + cac="$ac_default_prefix/share/curl/curl-ca-bundle.crt" + fi + + for a in /etc/ssl/certs/ca-certificates.crt \ + /etc/pki/tls/certs/ca-bundle.crt \ + /usr/share/ssl/certs/ca-bundle.crt \ + /usr/local/share/certs/ca-root-nss.crt \ + /etc/ssl/cert.pem \ + "$cac"; do + if test -f "$a"; then + ca="$a" + break + fi + done + fi + AC_MSG_NOTICE([want $want_capath ca $ca]) + if test "x$want_capath" = "xunset"; then + if test "x$OPENSSL_ENABLED" = "x1" -o \ + "x$GNUTLS_ENABLED" = "x1" -o \ + "x$MBEDTLS_ENABLED" = "x1" -o \ + "x$WOLFSSL_ENABLED" = "x1"; then + check_capath="/etc/ssl/certs" + fi + fi + else + dnl no option given and cross-compiling + AC_MSG_WARN([skipped the ca-cert path detection when cross-compiling]) + fi + fi + + if test "x$ca" = "xno" || test -f "$ca"; then + ca_warning="" + fi + + if test "x$capath" != "xno"; then + check_capath="$capath" + fi + + if test ! -z "$check_capath"; then + for a in "$check_capath"; do + if test -d "$a" && ls "$a"/[[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]].0 >/dev/null 2>/dev/null; then + if test "x$capath" = "xno"; then + capath="$a" + fi + capath_warning="" + break + fi + done + fi + + if test "x$capath" = "xno"; then + capath_warning="" + fi + + if test "x$ca" != "xno"; then + CURL_CA_BUNDLE='"'$ca'"' + AC_DEFINE_UNQUOTED(CURL_CA_BUNDLE, "$ca", [Location of default ca bundle]) + AC_SUBST(CURL_CA_BUNDLE) + AC_MSG_RESULT([$ca]) + fi + if test "x$capath" != "xno"; then + CURL_CA_PATH="\"$capath\"" + AC_DEFINE_UNQUOTED(CURL_CA_PATH, "$capath", [Location of default ca path]) + AC_MSG_RESULT([$capath (capath)]) + fi + if test "x$ca" = "xno" && test "x$capath" = "xno"; then + AC_MSG_RESULT([no]) + fi + + AC_MSG_CHECKING([whether to use builtin CA store of SSL library]) + AC_ARG_WITH(ca-fallback, +AS_HELP_STRING([--with-ca-fallback], [Use the built in CA store of the SSL library]) +AS_HELP_STRING([--without-ca-fallback], [Don't use the built in CA store of the SSL library]), + [ + if test "x$with_ca_fallback" != "xyes" -a "x$with_ca_fallback" != "xno"; then + AC_MSG_ERROR([--with-ca-fallback only allows yes or no as parameter]) + fi + ], + [ with_ca_fallback="no"]) + AC_MSG_RESULT([$with_ca_fallback]) + if test "x$with_ca_fallback" = "xyes"; then + if test "x$OPENSSL_ENABLED" != "x1" -a "x$GNUTLS_ENABLED" != "x1"; then + AC_MSG_ERROR([--with-ca-fallback only works with OpenSSL or GnuTLS]) + fi + AC_DEFINE_UNQUOTED(CURL_CA_FALLBACK, 1, [define "1" to use built in CA store of SSL library ]) + fi +]) + +dnl CURL_CHECK_WIN32_LARGEFILE +dnl ------------------------------------------------- +dnl Check if curl's WIN32 large file will be used + +AC_DEFUN([CURL_CHECK_WIN32_LARGEFILE], [ + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + AC_MSG_CHECKING([whether build target supports WIN32 file API]) + curl_win32_file_api="no" + if test "$curl_cv_native_windows" = "yes"; then + if test x"$enable_largefile" != "xno"; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ +#if !defined(_WIN32_WCE) && (defined(__MINGW32__) || defined(_MSC_VER)) + int dummy=1; +#else + WIN32 large file API not supported. +#endif + ]]) + ],[ + curl_win32_file_api="win32_large_files" + ]) + fi + if test "$curl_win32_file_api" = "no"; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ +#if defined(_WIN32_WCE) || defined(__MINGW32__) || defined(_MSC_VER) + int dummy=1; +#else + WIN32 small file API not supported. +#endif + ]]) + ],[ + curl_win32_file_api="win32_small_files" + ]) + fi + fi + case "$curl_win32_file_api" in + win32_large_files) + AC_MSG_RESULT([yes (large file enabled)]) + AC_DEFINE_UNQUOTED(USE_WIN32_LARGE_FILES, 1, + [Define to 1 if you are building a Windows target with large file support.]) + AC_SUBST(USE_WIN32_LARGE_FILES, [1]) + ;; + win32_small_files) + AC_MSG_RESULT([yes (large file disabled)]) + AC_DEFINE_UNQUOTED(USE_WIN32_SMALL_FILES, 1, + [Define to 1 if you are building a Windows target without large file support.]) + AC_SUBST(USE_WIN32_SMALL_FILES, [1]) + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +]) + +dnl CURL_CHECK_WIN32_CRYPTO +dnl ------------------------------------------------- +dnl Check if curl's WIN32 crypto lib can be used + +AC_DEFUN([CURL_CHECK_WIN32_CRYPTO], [ + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + AC_MSG_CHECKING([whether build target supports WIN32 crypto API]) + curl_win32_crypto_api="no" + if test "$curl_cv_native_windows" = "yes"; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#undef inline +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + ]],[[ + HCRYPTPROV hCryptProv; + if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + CryptReleaseContext(hCryptProv, 0); + } + ]]) + ],[ + curl_win32_crypto_api="yes" + ]) + fi + case "$curl_win32_crypto_api" in + yes) + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(USE_WIN32_CRYPTO, 1, + [Define to 1 if you are building a Windows target with crypto API support.]) + AC_SUBST(USE_WIN32_CRYPTO, [1]) + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +]) + +dnl CURL_EXPORT_PCDIR ($pcdir) +dnl ------------------------ +dnl if $pcdir is not empty, set PKG_CONFIG_LIBDIR to $pcdir and export +dnl +dnl we need this macro since pkg-config distinguishes among empty and unset +dnl variable while checking PKG_CONFIG_LIBDIR +dnl + +AC_DEFUN([CURL_EXPORT_PCDIR], [ + if test -n "$1"; then + PKG_CONFIG_LIBDIR="$1" + export PKG_CONFIG_LIBDIR + fi +]) + +dnl CURL_CHECK_PKGCONFIG ($module, [$pcdir]) +dnl ------------------------ +dnl search for the pkg-config tool. Set the PKGCONFIG variable to hold the +dnl path to it, or 'no' if not found/present. +dnl +dnl If pkg-config is present, check that it has info about the $module or +dnl return "no" anyway! +dnl +dnl Optionally PKG_CONFIG_LIBDIR may be given as $pcdir. +dnl + +AC_DEFUN([CURL_CHECK_PKGCONFIG], [ + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no], + [$PATH:/usr/bin:/usr/local/bin]) + fi + + if test "x$PKGCONFIG" != "xno"; then + AC_MSG_CHECKING([for $1 options with pkg-config]) + dnl ask pkg-config about $1 + itexists=`CURL_EXPORT_PCDIR([$2]) dnl + $PKGCONFIG --exists $1 >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + dnl pkg-config does not have info about the given module! set the + dnl variable to 'no' + PKGCONFIG="no" + AC_MSG_RESULT([no]) + else + AC_MSG_RESULT([found]) + fi + fi +]) + + +dnl CURL_GENERATE_CONFIGUREHELP_PM +dnl ------------------------------------------------- +dnl Generate test harness configurehelp.pm module, defining and +dnl initializing some perl variables with values which are known +dnl when the configure script runs. For portability reasons, test +dnl harness needs information on how to run the C preprocessor. + +AC_DEFUN([CURL_GENERATE_CONFIGUREHELP_PM], [ + AC_REQUIRE([AC_PROG_CPP])dnl + tmp_cpp=`eval echo "$ac_cpp" 2>/dev/null` + if test -z "$tmp_cpp"; then + tmp_cpp='cpp' + fi + cat >./tests/configurehelp.pm <<_EOF +[@%:@] This is a generated file. Do not edit. + +package configurehelp; + +use strict; +use warnings; +use Exporter; + +use vars qw( + @ISA + @EXPORT_OK + \$Cpreprocessor + ); + +@ISA = qw(Exporter); + +@EXPORT_OK = qw( + \$Cpreprocessor + ); + +\$Cpreprocessor = '$tmp_cpp'; + +1; +_EOF +]) + +dnl CURL_CPP_P +dnl +dnl Check if $cpp -P should be used for extract define values due to gcc 5 +dnl splitting up strings and defines between line outputs. gcc by default +dnl (without -P) will show TEST EINVAL TEST as +dnl +dnl # 13 "conftest.c" +dnl TEST +dnl # 13 "conftest.c" 3 4 +dnl 22 +dnl # 13 "conftest.c" +dnl TEST + +AC_DEFUN([CURL_CPP_P], [ + AC_MSG_CHECKING([if cpp -P is needed]) + AC_EGREP_CPP([TEST.*TEST], [ + #include +TEST EINVAL TEST + ], [cpp=no], [cpp=yes]) + AC_MSG_RESULT([$cpp]) + + dnl we need cpp -P so check if it works then + if test "x$cpp" = "xyes"; then + AC_MSG_CHECKING([if cpp -P works]) + OLDCPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -P" + AC_EGREP_CPP([TEST.*TEST], [ + #include +TEST EINVAL TEST + ], [cpp_p=yes], [cpp_p=no]) + AC_MSG_RESULT([$cpp_p]) + + if test "x$cpp_p" = "xno"; then + AC_MSG_WARN([failed to figure out cpp -P alternative]) + # without -P + CPPPFLAG="" + else + # with -P + CPPPFLAG="-P" + fi + dnl restore CPPFLAGS + CPPFLAGS=$OLDCPPFLAGS + else + # without -P + CPPPFLAG="" + fi +]) + + +dnl CURL_DARWIN_CFLAGS +dnl +dnl Set -Werror=partial-availability to detect possible breaking code +dnl with very low deployment targets. +dnl + +AC_DEFUN([CURL_DARWIN_CFLAGS], [ + + tst_cflags="no" + case $host_os in + darwin*) + tst_cflags="yes" + ;; + esac + + AC_MSG_CHECKING([for good-to-use Darwin CFLAGS]) + AC_MSG_RESULT([$tst_cflags]); + + if test "$tst_cflags" = "yes"; then + old_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Werror=partial-availability" + AC_MSG_CHECKING([whether $CC accepts -Werror=partial-availability]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + CFLAGS=$old_CFLAGS]) + fi + +]) + + +dnl CURL_SUPPORTS_BUILTIN_AVAILABLE +dnl +dnl Check to see if the compiler supports __builtin_available. This built-in +dnl compiler function first appeared in Apple LLVM 9.0.0. It's so new that, at +dnl the time this macro was written, the function was not yet documented. Its +dnl purpose is to return true if the code is running under a certain OS version +dnl or later. + +AC_DEFUN([CURL_SUPPORTS_BUILTIN_AVAILABLE], [ + AC_MSG_CHECKING([to see if the compiler supports __builtin_available()]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ + if (__builtin_available(macOS 10.8, iOS 5.0, *)) {} + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_BUILTIN_AVAILABLE, 1, + [Define to 1 if you have the __builtin_available function.]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..a1af02c --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1252 @@ +# generated automatically by aclocal 1.16.5 -*- Autoconf -*- + +# Copyright (C) 1996-2021 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, +[m4_warning([this file was generated for autoconf 2.71. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.16' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.16.5], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.16.5])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_COND_IF -*- Autoconf -*- + +# Copyright (C) 2008-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_COND_IF +# _AM_COND_ELSE +# _AM_COND_ENDIF +# -------------- +# These macros are only used for tracing. +m4_define([_AM_COND_IF]) +m4_define([_AM_COND_ELSE]) +m4_define([_AM_COND_ENDIF]) + +# AM_COND_IF(COND, [IF-TRUE], [IF-FALSE]) +# --------------------------------------- +# If the shell condition COND is true, execute IF-TRUE, otherwise execute +# IF-FALSE. Allow automake to learn about conditional instantiating macros +# (the AC_CONFIG_FOOS). +AC_DEFUN([AM_COND_IF], +[m4_ifndef([_AM_COND_VALUE_$1], + [m4_fatal([$0: no such condition "$1"])])dnl +_AM_COND_IF([$1])dnl +if test -z "$$1_TRUE"; then : + m4_n([$2])[]dnl +m4_ifval([$3], +[_AM_COND_ELSE([$1])dnl +else + $3 +])dnl +_AM_COND_ENDIF([$1])dnl +fi[]dnl +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? + done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE="gmake" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking is enabled. +# This creates each '.Po' and '.Plo' makefile fragment that we'll need in +# order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +m4_ifdef([_$0_ALREADY_INIT], + [m4_fatal([$0 expanded multiple times +]m4_defn([_$0_ALREADY_INIT]))], + [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi +AC_SUBST([CTAGS]) +if test -z "$ETAGS"; then + ETAGS=etags +fi +AC_SUBST([ETAGS]) +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi +AC_SUBST([CSCOPE]) + +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. +AC_DEFUN([AM_MAKE_INCLUDE], +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + MISSING="\${SHELL} '$am_aux_dir/missing'" +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2021 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/curl-amissl.m4]) +m4_include([m4/curl-bearssl.m4]) +m4_include([m4/curl-compilers.m4]) +m4_include([m4/curl-confopts.m4]) +m4_include([m4/curl-functions.m4]) +m4_include([m4/curl-gnutls.m4]) +m4_include([m4/curl-mbedtls.m4]) +m4_include([m4/curl-openssl.m4]) +m4_include([m4/curl-override.m4]) +m4_include([m4/curl-reentrant.m4]) +m4_include([m4/curl-rustls.m4]) +m4_include([m4/curl-schannel.m4]) +m4_include([m4/curl-sectransp.m4]) +m4_include([m4/curl-sysconfig.m4]) +m4_include([m4/curl-wolfssl.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) +m4_include([m4/xc-am-iface.m4]) +m4_include([m4/xc-cc-check.m4]) +m4_include([m4/xc-lt-iface.m4]) +m4_include([m4/xc-translit.m4]) +m4_include([m4/xc-val-flgs.m4]) +m4_include([m4/zz40-xc-ovr.m4]) +m4_include([m4/zz50-xc-ovr.m4]) +m4_include([m4/zz60-xc-ovr.m4]) +m4_include([acinclude.m4]) diff --git a/buildconf b/buildconf new file mode 100755 index 0000000..ee6a280 --- /dev/null +++ b/buildconf @@ -0,0 +1,8 @@ +#!/bin/sh +# +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +echo "*** Do not use buildconf. Instead, just use: autoreconf -fi" >&2 +exec ${AUTORECONF:-autoreconf} -fi "${@}" diff --git a/buildconf.bat b/buildconf.bat new file mode 100644 index 0000000..118a70d --- /dev/null +++ b/buildconf.bat @@ -0,0 +1,319 @@ +@echo off +rem *************************************************************************** +rem * _ _ ____ _ +rem * Project ___| | | | _ \| | +rem * / __| | | | |_) | | +rem * | (__| |_| | _ <| |___ +rem * \___|\___/|_| \_\_____| +rem * +rem * Copyright (C) Daniel Stenberg, , et al. +rem * +rem * This software is licensed as described in the file COPYING, which +rem * you should have received as part of this distribution. The terms +rem * are also available at https://curl.se/docs/copyright.html. +rem * +rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell +rem * copies of the Software, and permit persons to whom the Software is +rem * furnished to do so, under the terms of the COPYING file. +rem * +rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +rem * KIND, either express or implied. +rem * +rem * SPDX-License-Identifier: curl +rem * +rem *************************************************************************** + +rem NOTES +rem +rem This batch file must be used to set up a git tree to build on systems where +rem there is no autotools support (i.e. DOS and Windows). +rem + +:begin + rem Set our variables + if "%OS%" == "Windows_NT" setlocal + set MODE=GENERATE + + rem Switch to this batch file's directory + cd /d "%~0\.." 1>NUL 2>&1 + + rem Check we are running from a curl git repository + if not exist GIT-INFO goto norepo + + rem Detect programs. HAVE_ + rem When not found the variable is set undefined. The undefined pattern + rem allows for statements like "if not defined HAVE_PERL (command)" + groff --version NUL 2>&1 + if errorlevel 1 (set HAVE_GROFF=) else (set HAVE_GROFF=Y) + nroff --version NUL 2>&1 + if errorlevel 1 (set HAVE_NROFF=) else (set HAVE_NROFF=Y) + perl --version NUL 2>&1 + if errorlevel 1 (set HAVE_PERL=) else (set HAVE_PERL=Y) + gzip --version NUL 2>&1 + if errorlevel 1 (set HAVE_GZIP=) else (set HAVE_GZIP=Y) + +:parseArgs + if "%~1" == "" goto start + + if /i "%~1" == "-clean" ( + set MODE=CLEAN + ) else if /i "%~1" == "-?" ( + goto syntax + ) else if /i "%~1" == "-h" ( + goto syntax + ) else if /i "%~1" == "-help" ( + goto syntax + ) else ( + goto unknown + ) + + shift & goto parseArgs + +:start + if "%MODE%" == "GENERATE" ( + echo. + echo Generating prerequisite files + + call :generate + if errorlevel 3 goto nogenhugehelp + if errorlevel 2 goto nogenmakefile + if errorlevel 1 goto warning + + ) else ( + echo. + echo Removing prerequisite files + + call :clean + if errorlevel 2 goto nocleanhugehelp + if errorlevel 1 goto nocleanmakefile + ) + + goto success + +rem Main generate function. +rem +rem Returns: +rem +rem 0 - success +rem 1 - success with simplified tool_hugehelp.c +rem 2 - failed to generate Makefile +rem 3 - failed to generate tool_hugehelp.c +rem +:generate + if "%OS%" == "Windows_NT" setlocal + set BASIC_HUGEHELP=0 + + rem Create Makefile + echo * %CD%\Makefile + if exist Makefile.dist ( + copy /Y Makefile.dist Makefile 1>NUL 2>&1 + if errorlevel 1 ( + if "%OS%" == "Windows_NT" endlocal + exit /B 2 + ) + ) + + rem Create tool_hugehelp.c + echo * %CD%\src\tool_hugehelp.c + call :genHugeHelp + if errorlevel 2 ( + if "%OS%" == "Windows_NT" endlocal + exit /B 3 + ) + if errorlevel 1 ( + set BASIC_HUGEHELP=1 + ) + cmd /c exit 0 + + rem Setup c-ares git tree + if exist ares\buildconf.bat ( + echo. + echo Configuring c-ares build environment + cd ares + call buildconf.bat + cd .. + ) + + if "%BASIC_HUGEHELP%" == "1" ( + if "%OS%" == "Windows_NT" endlocal + exit /B 1 + ) + + if "%OS%" == "Windows_NT" endlocal + exit /B 0 + +rem Main clean function. +rem +rem Returns: +rem +rem 0 - success +rem 1 - failed to clean Makefile +rem 2 - failed to clean tool_hugehelp.c +rem +:clean + rem Remove Makefile + echo * %CD%\Makefile + if exist Makefile ( + del Makefile 2>NUL + if exist Makefile ( + exit /B 1 + ) + ) + + rem Remove tool_hugehelp.c + echo * %CD%\src\tool_hugehelp.c + if exist src\tool_hugehelp.c ( + del src\tool_hugehelp.c 2>NUL + if exist src\tool_hugehelp.c ( + exit /B 2 + ) + ) + + exit /B + +rem Function to generate src\tool_hugehelp.c +rem +rem Returns: +rem +rem 0 - full tool_hugehelp.c generated +rem 1 - simplified tool_hugehelp.c +rem 2 - failure +rem +:genHugeHelp + if "%OS%" == "Windows_NT" setlocal + set LC_ALL=C + set ROFFCMD= + set BASIC=1 + + if defined HAVE_PERL ( + if defined HAVE_GROFF ( + set ROFFCMD=groff -mtty-char -Tascii -P-c -man + ) else if defined HAVE_NROFF ( + set ROFFCMD=nroff -c -Tascii -man + ) + ) + + if defined ROFFCMD ( + echo #include "tool_setup.h"> src\tool_hugehelp.c + echo #include "tool_hugehelp.h">> src\tool_hugehelp.c + + if defined HAVE_GZIP ( + echo #ifndef HAVE_LIBZ>> src\tool_hugehelp.c + ) + + %ROFFCMD% docs\curl.1 2>NUL | perl src\mkhelp.pl docs\MANUAL >> src\tool_hugehelp.c + if defined HAVE_GZIP ( + echo #else>> src\tool_hugehelp.c + %ROFFCMD% docs\curl.1 2>NUL | perl src\mkhelp.pl -c docs\MANUAL >> src\tool_hugehelp.c + echo #endif /^* HAVE_LIBZ ^*/>> src\tool_hugehelp.c + ) + + set BASIC=0 + ) else ( + if exist src\tool_hugehelp.c.cvs ( + copy /Y src\tool_hugehelp.c.cvs src\tool_hugehelp.c 1>NUL 2>&1 + ) else ( + echo #include "tool_setup.h"> src\tool_hugehelp.c + echo #include "tool_hugehelp.h">> src\tool_hugehelp.c + echo.>> src\tool_hugehelp.c + echo void hugehelp(void^)>> src\tool_hugehelp.c + echo {>> src\tool_hugehelp.c + echo #ifdef USE_MANUAL>> src\tool_hugehelp.c + echo fputs("Built-in manual not included\n", stdout^);>> src\tool_hugehelp.c + echo #endif>> src\tool_hugehelp.c + echo }>> src\tool_hugehelp.c + ) + ) + + findstr "/C:void hugehelp(void)" src\tool_hugehelp.c 1>NUL 2>&1 + if errorlevel 1 ( + if "%OS%" == "Windows_NT" endlocal + exit /B 2 + ) + + if "%BASIC%" == "1" ( + if "%OS%" == "Windows_NT" endlocal + exit /B 1 + ) + + if "%OS%" == "Windows_NT" endlocal + exit /B 0 + +rem Function to clean-up local variables under DOS, Windows 3.x and +rem Windows 9x as setlocal isn't available until Windows NT +rem +:dosCleanup + set MODE= + set HAVE_GROFF= + set HAVE_NROFF= + set HAVE_PERL= + set HAVE_GZIP= + set BASIC_HUGEHELP= + set LC_ALL + set ROFFCMD= + set BASIC= + + exit /B + +:syntax + rem Display the help + echo. + echo Usage: buildconf [-clean] + echo. + echo -clean - Removes the files + goto error + +:unknown + echo. + echo Error: Unknown argument '%1' + goto error + +:norepo + echo. + echo Error: This batch file should only be used with a curl git repository + goto error + +:nogenmakefile + echo. + echo Error: Unable to generate Makefile + goto error + +:nogenhugehelp + echo. + echo Error: Unable to generate src\tool_hugehelp.c + goto error + +:nocleanmakefile + echo. + echo Error: Unable to clean Makefile + goto error + +:nocleanhugehelp + echo. + echo Error: Unable to clean src\tool_hugehelp.c + goto error + +:warning + echo. + echo Warning: The curl manual could not be integrated in the source. This means when + echo you build curl the manual will not be available (curl --man^). Integration of + echo the manual is not required and a summary of the options will still be available + echo (curl --help^). To integrate the manual your PATH is required to have + echo groff/nroff, perl and optionally gzip for compression. + goto success + +:error + if "%OS%" == "Windows_NT" ( + endlocal + ) else ( + call :dosCleanup + ) + exit /B 1 + +:success + if "%OS%" == "Windows_NT" ( + endlocal + ) else ( + call :dosCleanup + ) + exit /B 0 diff --git a/compile b/compile new file mode 100755 index 0000000..df363c8 --- /dev/null +++ b/compile @@ -0,0 +1,348 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN* | MSYS*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/* | msys/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..7f76b62 --- /dev/null +++ b/config.guess @@ -0,0 +1,1754 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-09' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess +# +# Please send patches to . + + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2022 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# Just in case it came from the environment. +GUESS= + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD=$driver + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if test -f /.attbin/uname ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case $UNAME_SYSTEM in +Linux|GNU|GNU/*) + LIBC=unknown + + set_cc_for_build + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #elif defined(__GLIBC__) + LIBC=gnu + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif + #endif + EOF + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case $UNAME_MACHINE_ARCH in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case $UNAME_MACHINE_ARCH in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case $UNAME_VERSION in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + GUESS=$machine-${os}${release}${abi-} + ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; + *:MidnightBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; + *:ekkoBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; + *:SolidBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; + *:OS108:*:*) + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; + macppc:MirBSD:*:*) + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; + *:MirBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; + *:Sortix:*:*) + GUESS=$UNAME_MACHINE-unknown-sortix + ;; + *:Twizzler:*:*) + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; + *:Redox:*:*) + GUESS=$UNAME_MACHINE-unknown-redox + ;; + mips:OSF1:*.*) + GUESS=mips-dec-osf1 + ;; + alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case $ALPHA_CPU_TYPE in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; + Amiga*:UNIX_System_V:4.0:*) + GUESS=m68k-unknown-sysv4 + ;; + *:[Aa]miga[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; + *:[Mm]orph[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-morphos + ;; + *:OS/390:*:*) + GUESS=i370-ibm-openedition + ;; + *:z/VM:*:*) + GUESS=s390-ibm-zvmoe + ;; + *:OS400:*:*) + GUESS=powerpc-ibm-os400 + ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + GUESS=arm-unknown-riscos + ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + GUESS=hppa1.1-hitachi-hiuxmpp + ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; + NILE*:*:*:dcosx) + GUESS=pyramid-pyramid-svr4 + ;; + DRS?6000:unix:4.0:6*) + GUESS=sparc-icl-nx6 + ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; + s390x:SunOS:*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; + sun4H:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; + sun4*:SunOS:*:*) + case `/usr/bin/arch -k` in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; + sun3*:SunOS:*:*) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case `/bin/arch` in + sun3) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun4) + GUESS=sparc-sun-sunos$UNAME_RELEASE + ;; + esac + ;; + aushp:SunOS:*:*) + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; + m68k:machten:*:*) + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; + powerpc:machten:*:*) + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; + RISC*:Mach:*:*) + GUESS=mips-dec-mach_bsd4.3 + ;; + RISC*:ULTRIX:*:*) + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; + VAX*:ULTRIX*:*:*) + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; + Motorola:PowerMAX_OS:*:*) + GUESS=powerpc-motorola-powermax + ;; + Motorola:*:4.3:PL8-*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:Power_UNIX:*:*) + GUESS=powerpc-harris-powerunix + ;; + m88k:CX/UX:7*:*) + GUESS=m88k-harris-cxux7 + ;; + m88k:*:4*:R4*) + GUESS=m88k-motorola-sysv4 + ;; + m88k:*:3*:R3*) + GUESS=m88k-motorola-sysv3 + ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 + then + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x + then + GUESS=m88k-dg-dgux$UNAME_RELEASE + else + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE + fi + else + GUESS=i586-dg-dgux$UNAME_RELEASE + fi + ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + GUESS=m88k-dolphin-sysv3 + ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + GUESS=m88k-motorola-sysv3 + ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + GUESS=m88k-tektronix-sysv3 + ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + GUESS=m68k-tektronix-bsd + ;; + *:IRIX*:*:*) + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + GUESS=i386-ibm-aix + ;; + ia64:AIX:*:*) + if test -x /usr/bin/oslevel ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + GUESS=$SYSTEM_NAME + else + GUESS=rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + GUESS=rs6000-ibm-aix3.2.4 + else + GUESS=rs6000-ibm-aix3.2 + fi + ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; + *:AIX:*:*) + GUESS=rs6000-ibm-aix + ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + GUESS=romp-ibm-bsd4.4 + ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + GUESS=rs6000-bull-bosx + ;; + DPX/2?00:B.O.S.:*:*) + GUESS=m68k-bull-sysv3 + ;; + 9000/[34]??:4.3bsd:1.*:*) + GUESS=m68k-hp-bsd + ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + GUESS=m68k-hp-bsd4.4 + ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if test -x /usr/bin/getconf; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case $sc_cpu_version in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case $sc_kernel_bits in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if test "$HP_ARCH" = ""; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if test "$HP_ARCH" = hppa2.0w + then + set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; + 3050*:HI-UX:*:*) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=unknown-hitachi-hiuxwe2 + ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + GUESS=hppa1.1-hp-bsd + ;; + 9000/8??:4.3bsd:*:*) + GUESS=hppa1.0-hp-bsd + ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + GUESS=hppa1.0-hp-mpeix + ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + GUESS=hppa1.1-hp-osf + ;; + hp8??:OSF1:*:*) + GUESS=hppa1.0-hp-osf + ;; + i*86:OSF1:*:*) + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk + else + GUESS=$UNAME_MACHINE-unknown-osf1 + fi + ;; + parisc*:Lites*:*:*) + GUESS=hppa1.1-hp-lites + ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + GUESS=c1-convex-bsd + ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + GUESS=c34-convex-bsd + ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + GUESS=c38-convex-bsd + ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + GUESS=c4-convex-bsd + ;; + CRAY*Y-MP:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; + CRAY*T3E:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; + CRAY*SV1:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; + *:UNICOS/mp:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; + sparc*:BSD/OS:*:*) + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; + *:BSD/OS:*:*) + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi + else + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf + fi + ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case $UNAME_PROCESSOR in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; + i*:CYGWIN*:*) + GUESS=$UNAME_MACHINE-pc-cygwin + ;; + *:MINGW64*:*) + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; + *:MINGW*:*) + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; + *:MSYS*:*) + GUESS=$UNAME_MACHINE-pc-msys + ;; + i*:PW*:*) + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; + *:Interix*:*) + case $UNAME_MACHINE in + x86) + GUESS=i586-pc-interix$UNAME_RELEASE + ;; + authenticamd | genuineintel | EM64T) + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; + IA64) + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; + esac ;; + i*:UWIN*:*) + GUESS=$UNAME_MACHINE-pc-uwin + ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + GUESS=x86_64-pc-cygwin + ;; + prep*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; + *:GNU:*:*) + # the GNU system + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; + aarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arm*:Linux:*:*) + set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi + else + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf + fi + fi + ;; + avr32*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + cris:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + crisv32:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + e2k:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + frv:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + hexagon:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:Linux:*:*) + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; + ia64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + k1om:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m32r*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m68*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + mips:Linux:*:* | mips64:Linux:*:*) + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + MIPS_ENDIAN=el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + MIPS_ENDIAN= + #else + MIPS_ENDIAN= + #endif + #endif +EOF + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } + ;; + mips64el:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + openrisc*:Linux:*:*) + GUESS=or1k-unknown-linux-$LIBC + ;; + or32:Linux:*:* | or1k*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + padre:Linux:*:*) + GUESS=sparc-unknown-linux-$LIBC + ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + GUESS=hppa64-unknown-linux-$LIBC + ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; + esac + ;; + ppc64:Linux:*:*) + GUESS=powerpc64-unknown-linux-$LIBC + ;; + ppc:Linux:*:*) + GUESS=powerpc-unknown-linux-$LIBC + ;; + ppc64le:Linux:*:*) + GUESS=powerpc64le-unknown-linux-$LIBC + ;; + ppcle:Linux:*:*) + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + s390:Linux:*:* | s390x:Linux:*:*) + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; + sh64*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sh*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + tile*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + vax:Linux:*:*) + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; + x86_64:Linux:*:*) + set_cc_for_build + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_X32 >/dev/null + then + LIBCABI=${LIBC}x32 + fi + fi + GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI + ;; + xtensa*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + GUESS=i386-sequent-sysv4 + ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; + i*86:XTS-300:*:STOP) + GUESS=$UNAME_MACHINE-unknown-stop + ;; + i*86:atheos:*:*) + GUESS=$UNAME_MACHINE-unknown-atheos + ;; + i*86:syllable:*:*) + GUESS=$UNAME_MACHINE-pc-syllable + ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; + i*86:*DOS:*:*) + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL + fi + ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv32 + fi + ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + GUESS=i586-pc-msdosdjgpp + ;; + Intel:Mach:3*:*) + GUESS=i386-pc-mach3 + ;; + paragon:*:*:*) + GUESS=i860-intel-osf1 + ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 + fi + ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + GUESS=m68010-convergent-sysv + ;; + mc68k:UNIX:SYSTEM5:3.51m) + GUESS=m68k-convergent-sysv + ;; + M680?0:D-NIX:5.3:*) + GUESS=m68k-diab-dnix + ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; + mc68030:UNIX_System_V:4.*:*) + GUESS=m68k-atari-sysv4 + ;; + TSUNAMI:LynxOS:2.*:*) + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; + rs6000:LynxOS:2.*:*) + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; + SM[BE]S:UNIX_SV:*:*) + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; + RM*:ReliantUNIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + RM*:SINIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + GUESS=$UNAME_MACHINE-sni-sysv4 + else + GUESS=ns32k-sni-sysv + fi + ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + GUESS=i586-unisys-sysv4 + ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + GUESS=hppa1.1-stratus-sysv4 + ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + GUESS=i860-stratus-sysv4 + ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=$UNAME_MACHINE-stratus-vos + ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=hppa1.1-stratus-vos + ;; + mc68*:A/UX:*:*) + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; + news*:NEWS-OS:6*:*) + GUESS=mips-sony-newsos6 + ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE + else + GUESS=mips-unknown-sysv$UNAME_RELEASE + fi + ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + GUESS=powerpc-be-beos + ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + GUESS=powerpc-apple-beos + ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + GUESS=i586-pc-beos + ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + GUESS=i586-pc-haiku + ;; + x86_64:Haiku:*:*) + GUESS=x86_64-unknown-haiku + ;; + SX-4:SUPER-UX:*:*) + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; + SX-5:SUPER-UX:*:*) + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; + SX-6:SUPER-UX:*:*) + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; + SX-7:SUPER-UX:*:*) + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; + SX-8:SUPER-UX:*:*) + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; + SX-8R:SUPER-UX:*:*) + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; + SX-ACE:SUPER-UX:*:*) + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; + Power*:Rhapsody:*:*) + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; + *:Rhapsody:*:*) + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build + fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE + fi + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; + *:QNX:*:4*) + GUESS=i386-pc-qnx + ;; + NEO-*:NONSTOP_KERNEL:*:*) + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; + NSE-*:NONSTOP_KERNEL:*:*) + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; + NSR-*:NONSTOP_KERNEL:*:*) + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; + NSV-*:NONSTOP_KERNEL:*:*) + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; + NSX-*:NONSTOP_KERNEL:*:*) + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; + *:NonStop-UX:*:*) + GUESS=mips-compaq-nonstopux + ;; + BS2000:POSIX*:*:*) + GUESS=bs2000-siemens-sysv + ;; + DS/*:UNIX_System_V:*:*) + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "${cputype-}" = 386; then + UNAME_MACHINE=i386 + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype + fi + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; + *:TOPS-10:*:*) + GUESS=pdp10-unknown-tops10 + ;; + *:TENEX:*:*) + GUESS=pdp10-unknown-tenex + ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + GUESS=pdp10-dec-tops20 + ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + GUESS=pdp10-xkl-tops20 + ;; + *:TOPS-20:*:*) + GUESS=pdp10-unknown-tops20 + ;; + *:ITS:*:*) + GUESS=pdp10-unknown-its + ;; + SEI:*:*:SEIUX) + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; + *:DragonFly:*:*) + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; + esac ;; + *:XENIX:*:SysV) + GUESS=i386-pc-xenix + ;; + i*86:skyos:*:*) + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; + i*86:rdos:*:*) + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; + x86_64:VMkernel:*:*) + GUESS=$UNAME_MACHINE-unknown-esx + ;; + amd64:Isilon\ OneFS:*:*) + GUESS=x86_64-unknown-onefs + ;; + *:Unleashed:*:*) + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; +esac + +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" < +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); +#endif + +#if defined (vax) +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } + +echo "$0: unable to guess system type" >&2 + +case $UNAME_MACHINE:$UNAME_SYSTEM in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF +fi + +exit 1 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..dba16e8 --- /dev/null +++ b/config.sub @@ -0,0 +1,1890 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-03' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2022 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Split fields of configuration type +# shellcheck disable=SC2162 +saved_IFS=$IFS +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` + ;; + + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read cpu vendor <&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if test x$basic_os != x +then + +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` + ;; + os2-emx) + kernel=os2 + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` + ;; + nto-qnx*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` + ;; + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read kernel os <&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ + | linux-musl* | linux-relibc* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) + vendor=acorn + ;; + *-sunos*) + vendor=sun + ;; + *-cnk* | *-aix*) + vendor=ibm + ;; + *-beos*) + vendor=be + ;; + *-hpux*) + vendor=hp + ;; + *-mpeix*) + vendor=hp + ;; + *-hiux*) + vendor=hitachi + ;; + *-unos*) + vendor=crds + ;; + *-dgux*) + vendor=dg + ;; + *-luna*) + vendor=omron + ;; + *-genix*) + vendor=ns + ;; + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) + vendor=ibm + ;; + s390-* | s390x-*) + vendor=ibm + ;; + *-ptx*) + vendor=sequent + ;; + *-tpf*) + vendor=ibm + ;; + *-vxsim* | *-vxworks* | *-windiss*) + vendor=wrs + ;; + *-aux*) + vendor=apple + ;; + *-hms*) + vendor=hitachi + ;; + *-mpw* | *-macos*) + vendor=apple + ;; + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) + vendor=atari + ;; + *-vos*) + vendor=stratus + ;; + esac + ;; +esac + +echo "$cpu-$vendor-${kernel:+$kernel-}$os" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..da9f3b7 --- /dev/null +++ b/configure @@ -0,0 +1,48774 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.71 for curl -. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +# +# Copyright (C) Daniel Stenberg, +# This configure script may be copied, distributed and modified under the +# terms of the curl license; see COPYING for more details + +## -------------------------------- ## +## XC_CONFIGURE_PREAMBLE ver: 1.0 ## +## -------------------------------- ## + +xc_configure_preamble_ver_major='1' +xc_configure_preamble_ver_minor='0' + +# +# Set IFS to space, tab and newline. +# + +xc_space=' ' +xc_tab=' ' +xc_newline=' +' +IFS="$xc_space$xc_tab$xc_newline" + +# +# Set internationalization behavior variables. +# + +LANG='C' +LC_ALL='C' +LANGUAGE='C' +export LANG +export LC_ALL +export LANGUAGE + +# +# Some useful variables. +# + +xc_msg_warn='configure: WARNING:' +xc_msg_abrt='Can not continue.' +xc_msg_err='configure: error:' + +# +# Verify that 'echo' command is available, otherwise abort. +# + +xc_tst_str='unknown' +(`echo "$xc_tst_str" >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in # (( + xsuccess) + : + ;; + *) + # Try built-in echo, and fail. + echo "$xc_msg_err 'echo' command not found. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'test' command is available, otherwise abort. +# + +xc_tst_str='unknown' +(`test -n "$xc_tst_str" >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in # (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'test' command not found. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'PATH' variable is set, otherwise abort. +# + +xc_tst_str='unknown' +(`test -n "$PATH" >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in # (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'PATH' variable not set. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'expr' command is available, otherwise abort. +# + +xc_tst_str='unknown' +xc_tst_str=`expr "$xc_tst_str" : '.*' 2>/dev/null` +case "x$xc_tst_str" in # (( + x7) + : + ;; + *) + echo "$xc_msg_err 'expr' command not found. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'sed' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown' +xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ + | sed -e 's:unknown:success:' 2>/dev/null` +case "x$xc_tst_str" in # (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'sed' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'grep' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown' +(`echo "$xc_tst_str" 2>/dev/null \ + | grep 'unknown' >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in # (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'grep' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'tr' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str="${xc_tab}98s7u6c5c4e3s2s10" +xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ + | tr -d "0123456789$xc_tab" 2>/dev/null` +case "x$xc_tst_str" in # (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'tr' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'wc' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown unknown unknown unknown' +xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ + | wc -w 2>/dev/null | tr -d "$xc_space$xc_tab" 2>/dev/null` +case "x$xc_tst_str" in # (( + x4) + : + ;; + *) + echo "$xc_msg_err 'wc' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Verify that 'cat' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown' +xc_tst_str=`cat <<_EOT 2>/dev/null \ + | wc -l 2>/dev/null | tr -d "$xc_space$xc_tab" 2>/dev/null +unknown +unknown +unknown +_EOT` +case "x$xc_tst_str" in # (( + x3) + : + ;; + *) + echo "$xc_msg_err 'cat' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac + +# +# Auto-detect and set 'PATH_SEPARATOR', unless it is already non-empty set. +# + +# Directory count in 'PATH' when using a colon separator. +xc_tst_dirs_col='x' +xc_tst_prev_IFS=$IFS; IFS=':' +for xc_tst_dir in $PATH; do + IFS=$xc_tst_prev_IFS + xc_tst_dirs_col="x$xc_tst_dirs_col" +done +IFS=$xc_tst_prev_IFS +xc_tst_dirs_col=`expr "$xc_tst_dirs_col" : '.*'` + +# Directory count in 'PATH' when using a semicolon separator. +xc_tst_dirs_sem='x' +xc_tst_prev_IFS=$IFS; IFS=';' +for xc_tst_dir in $PATH; do + IFS=$xc_tst_prev_IFS + xc_tst_dirs_sem="x$xc_tst_dirs_sem" +done +IFS=$xc_tst_prev_IFS +xc_tst_dirs_sem=`expr "$xc_tst_dirs_sem" : '.*'` + +if test $xc_tst_dirs_sem -eq $xc_tst_dirs_col; then + # When both counting methods give the same result we do not want to + # chose one over the other, and consider auto-detection not possible. + if test -z "$PATH_SEPARATOR"; then + # User should provide the correct 'PATH_SEPARATOR' definition. + # Until then, guess that it is colon! + echo "$xc_msg_warn path separator not determined, guessing colon" >&2 + PATH_SEPARATOR=':' + fi +else + # Separator with the greater directory count is the auto-detected one. + if test $xc_tst_dirs_sem -gt $xc_tst_dirs_col; then + xc_tst_auto_separator=';' + else + xc_tst_auto_separator=':' + fi + if test -z "$PATH_SEPARATOR"; then + # Simply use the auto-detected one when not already set. + PATH_SEPARATOR=$xc_tst_auto_separator + elif test "x$PATH_SEPARATOR" != "x$xc_tst_auto_separator"; then + echo "$xc_msg_warn 'PATH_SEPARATOR' does not match auto-detected one." >&2 + fi +fi +xc_PATH_SEPARATOR=$PATH_SEPARATOR + +xc_configure_preamble_result='yes' + + +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else $as_nop + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. +as_nl=' +' +export as_nl +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi + + + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else \$as_nop + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : + +else \$as_nop + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" + if (eval "$as_required") 2>/dev/null +then : + as_have_required=yes +else $as_nop + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : + +else $as_nop + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$as_shell as_have_required=yes + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : + break 2 +fi +fi + done;; + esac + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi + + + if test "x$CONFIG_SHELL" != x +then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." + else + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and a suitable curl +$0: mailing list: https://curl.se/mail/ about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else $as_nop + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else $as_nop + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + printf "%s\n" "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='curl' +PACKAGE_TARNAME='curl' +PACKAGE_VERSION='-' +PACKAGE_STRING='curl -' +PACKAGE_BUGREPORT='a suitable curl mailing list: https://curl.se/mail/' +PACKAGE_URL='' + +ac_unique_file="lib/urldata.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_STDIO_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_header_c_list= +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +SSL_BACKENDS +SUPPORT_PROTOCOLS +SUPPORT_FEATURES +LIBCURL_NO_SHARED +ENABLE_STATIC +ENABLE_SHARED +CROSSCOMPILING_FALSE +CROSSCOMPILING_TRUE +BLANK_AT_MAKETIME +CURL_NETWORK_AND_TIME_LIBS +CURL_NETWORK_LIBS +LIBCURL_LIBS +CFLAG_CURL_SYMBOL_HIDING +DOING_CURL_SYMBOL_HIDING_FALSE +DOING_CURL_SYMBOL_HIDING_TRUE +USE_UNIX_SOCKETS +BUILD_LIBHOSTNAME_FALSE +BUILD_LIBHOSTNAME_TRUE +USE_ARES +USE_MANUAL_FALSE +USE_MANUAL_TRUE +MANOPT +NROFF +PERL +FISH_FUNCTIONS_DIR +ZSH_FUNCTIONS_DIR +USE_MSH3 +USE_QUICHE +USE_OPENSSL_H3 +USE_NGTCP2_H3 +USE_NGHTTP3 +USE_OPENSSL_QUIC +USE_NGTCP2_CRYPTO_WOLFSSL +USE_NGTCP2_CRYPTO_GNUTLS +USE_NGTCP2_CRYPTO_BORINGSSL +USE_NGTCP2_CRYPTO_QUICTLS +USE_NGTCP2 +USE_NGHTTP2 +IDN_ENABLED +CURL_PLIST_VERSION +CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE +CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE +CURL_LT_SHLIB_VERSIONED_FLAVOUR +USE_LIBRTMP +USE_WOLFSSH +USE_LIBSSH +USE_LIBSSH2 +USE_GSASL_FALSE +USE_GSASL_TRUE +USE_LIBPSL_FALSE +USE_LIBPSL_TRUE +CURL_CA_BUNDLE +CURL_WITH_MULTI_SSL +SSL_ENABLED +USE_RUSTLS +USE_BEARSSL +USE_WOLFSSL +USE_MBEDTLS +HAVE_GNUTLS_SRP +USE_GNUTLS +HAVE_OPENSSL_QUIC +HAVE_OPENSSL_SRP +RANDOM_FILE +SSL_LIBS +USE_SECTRANSP +USE_WINDOWS_SSPI +USE_SCHANNEL +DEFAULT_SSL_BACKEND +BUILD_STUB_GSS_FALSE +BUILD_STUB_GSS_TRUE +IPV6_ENABLED +USE_OPENLDAP +HAVE_ZSTD +HAVE_BROTLI +ZLIB_LIBS +HAVE_LIBZ_FALSE +HAVE_LIBZ_TRUE +HAVE_LIBZ +HAVE_PROTO_BSDSOCKET_H +CURL_DISABLE_MQTT +CURL_DISABLE_GOPHER +CURL_DISABLE_SMTP +CURL_DISABLE_SMB +CURL_DISABLE_IMAP +CURL_DISABLE_POP3 +CURL_DISABLE_TFTP +CURL_DISABLE_TELNET +CURL_DISABLE_DICT +CURL_DISABLE_PROXY +USE_HYPER +PKGCONFIG +HAVE_LDAP_SSL +CURL_DISABLE_LDAPS +CURL_DISABLE_LDAP +CURL_DISABLE_FILE +CURL_DISABLE_FTP +CURL_DISABLE_RTSP +CURL_DISABLE_HTTP +HAVE_WINDRES_FALSE +HAVE_WINDRES_TRUE +USE_WIN32_CRYPTO +USE_WIN32_SMALL_FILES +USE_WIN32_LARGE_FILES +BUILD_UNITTESTS_FALSE +BUILD_UNITTESTS_TRUE +CURLDEBUG_FALSE +CURLDEBUG_TRUE +CURL_CFLAG_EXTRAS +DOING_NATIVE_WINDOWS_FALSE +DOING_NATIVE_WINDOWS_TRUE +USE_EXPLICIT_LIB_DEPS_FALSE +USE_EXPLICIT_LIB_DEPS_TRUE +REQUIRE_LIB_DEPS +CPPFLAG_CURL_STATICLIB +USE_CPPFLAG_CURL_STATICLIB_FALSE +USE_CPPFLAG_CURL_STATICLIB_TRUE +CURL_LT_SHLIB_USE_MIMPURE_TEXT_FALSE +CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE +CURL_LT_SHLIB_USE_NO_UNDEFINED_FALSE +CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE +CURL_LT_SHLIB_USE_VERSION_INFO_FALSE +CURL_LT_SHLIB_USE_VERSION_INFO_TRUE +RC +LT_SYS_LIBRARY_PATH +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +FILECMD +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +LIBTOOL +OBJDUMP +DLLTOOL +AS +AR_FLAGS +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +HTTPD_NGHTTPX +APACHECTL +HTTPD +APXS +CADDY +TEST_NGHTTPX +PKGADD_VENDOR +PKGADD_NAME +PKGADD_PKG +VERSIONNUM +CURLVERSION +CSCOPE +ETAGS +CTAGS +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__include +DEPDIR +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +LCOV +GCOV +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +libext +AR +EGREP +GREP +SED +CONFIGURE_OPTIONS +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +SHELL +PATH_SEPARATOR +am__quote' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_maintainer_mode +enable_silent_rules +enable_debug +enable_optimize +enable_warnings +enable_werror +enable_curldebug +enable_symbol_hiding +enable_ares +enable_rt +enable_ech +enable_code_coverage +enable_dependency_tracking +with_schannel +with_secure_transport +with_amissl +with_ssl +with_openssl +with_gnutls +with_mbedtls +with_wolfssl +with_bearssl +with_rustls +with_test_nghttpx +with_test_caddy +with_test_httpd +with_darwinssl +enable_largefile +enable_shared +enable_static +with_pic +enable_fast_install +with_aix_soname +with_gnu_ld +with_sysroot +enable_libtool_lock +enable_http +enable_ftp +enable_file +enable_ldap +enable_ldaps +with_hyper +enable_rtsp +enable_proxy +enable_dict +enable_telnet +enable_tftp +enable_pop3 +enable_imap +enable_smb +enable_smtp +enable_gopher +enable_mqtt +enable_manual +enable_libcurl_option +enable_libgcc +with_zlib +with_brotli +with_zstd +with_ldap_lib +with_lber_lib +enable_ipv6 +with_gssapi_includes +with_gssapi_libs +with_gssapi +with_default_ssl_backend +with_random +enable_openssl_auto_load_config +with_ca_bundle +with_ca_path +with_ca_fallback +with_libpsl +with_libgsasl +with_libmetalink +with_libssh2 +with_libssh +with_wolfssh +with_librtmp +enable_versioned_symbols +with_winidn +with_libidn2 +with_nghttp2 +with_ngtcp2 +with_openssl_quic +with_nghttp3 +with_quiche +with_msh3 +with_zsh_functions_dir +with_fish_functions_dir +enable_threaded_resolver +enable_pthreads +enable_verbose +enable_sspi +enable_basic_auth +enable_bearer_auth +enable_digest_auth +enable_kerberos_auth +enable_negotiate_auth +enable_aws +enable_ntlm +enable_ntlm_wb +enable_tls_srp +enable_unix_sockets +enable_cookies +enable_socketpair +enable_http_auth +enable_doh +enable_mime +enable_bindlocal +enable_form_api +enable_dateparse +enable_netrc +enable_progress_meter +enable_dnsshuffle +enable_get_easy_options +enable_alt_svc +enable_headers_api +enable_hsts +enable_websockets +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +LT_SYS_LIBRARY_PATH' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures curl - to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/curl] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of curl -:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-debug Enable debug build options + --disable-debug Disable debug build options + --enable-optimize Enable compiler optimizations + --disable-optimize Disable compiler optimizations + --enable-warnings Enable strict compiler warnings + --disable-warnings Disable strict compiler warnings + --enable-werror Enable compiler warnings as errors + --disable-werror Disable compiler warnings as errors + --enable-curldebug Enable curl debug memory tracking + --disable-curldebug Disable curl debug memory tracking + --enable-symbol-hiding Enable hiding of library internal symbols + --disable-symbol-hiding Disable hiding of library internal symbols + --enable-ares[=PATH] Enable c-ares for DNS lookups + --disable-ares Disable c-ares for DNS lookups + --disable-rt disable dependency on -lrt + --enable-ech Enable ECH support + --disable-ech Disable ECH support + --enable-code-coverage Provide code coverage + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --disable-largefile omit support for large files + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-http Enable HTTP support + --disable-http Disable HTTP support + --enable-ftp Enable FTP support + --disable-ftp Disable FTP support + --enable-file Enable FILE support + --disable-file Disable FILE support + --enable-ldap Enable LDAP support + --disable-ldap Disable LDAP support + --enable-ldaps Enable LDAPS support + --disable-ldaps Disable LDAPS support + --enable-rtsp Enable RTSP support + --disable-rtsp Disable RTSP support + --enable-proxy Enable proxy support + --disable-proxy Disable proxy support + --enable-dict Enable DICT support + --disable-dict Disable DICT support + --enable-telnet Enable TELNET support + --disable-telnet Disable TELNET support + --enable-tftp Enable TFTP support + --disable-tftp Disable TFTP support + --enable-pop3 Enable POP3 support + --disable-pop3 Disable POP3 support + --enable-imap Enable IMAP support + --disable-imap Disable IMAP support + --enable-smb Enable SMB/CIFS support + --disable-smb Disable SMB/CIFS support + --enable-smtp Enable SMTP support + --disable-smtp Disable SMTP support + --enable-gopher Enable Gopher support + --disable-gopher Disable Gopher support + --enable-mqtt Enable MQTT support + --disable-mqtt Disable MQTT support + --enable-manual Enable built-in manual + --disable-manual Disable built-in manual + --enable-libcurl-option Enable --libcurl C code generation support + --disable-libcurl-option + Disable --libcurl C code generation support + --enable-libgcc use libgcc when linking + --enable-ipv6 Enable IPv6 (with IPv4) support + --disable-ipv6 Disable IPv6 support + --enable-openssl-auto-load-config + Enable automatic loading of OpenSSL configuration + --disable-openssl-auto-load-config + Disable automatic loading of OpenSSL configuration + --enable-versioned-symbols + Enable versioned symbols in shared library + --disable-versioned-symbols + Disable versioned symbols in shared library + --enable-threaded-resolver + Enable threaded resolver + --disable-threaded-resolver + Disable threaded resolver + --enable-pthreads Enable POSIX threads (default for threaded resolver) + --disable-pthreads Disable POSIX threads + --enable-verbose Enable verbose strings + --disable-verbose Disable verbose strings + --enable-sspi Enable SSPI + --disable-sspi Disable SSPI + --enable-basic-auth Enable basic authentication (default) + --disable-basic-auth Disable basic authentication + --enable-bearer-auth Enable bearer authentication (default) + --disable-bearer-auth Disable bearer authentication + --enable-digest-auth Enable digest authentication (default) + --disable-digest-auth Disable digest authentication + --enable-kerberos-auth Enable kerberos authentication (default) + --disable-kerberos-auth Disable kerberos authentication + --enable-negotiate-auth Enable negotiate authentication (default) + --disable-negotiate-auth + Disable negotiate authentication + --enable-aws Enable AWS sig support (default) + --disable-aws Disable AWS sig support + --enable-ntlm Enable NTLM support + --disable-ntlm Disable NTLM support + --enable-ntlm-wb[=FILE] Enable NTLM delegation to winbind's ntlm_auth + helper, where FILE is ntlm_auth's absolute filename + (default: /usr/bin/ntlm_auth) + --disable-ntlm-wb Disable NTLM delegation to winbind's ntlm_auth + helper + --enable-tls-srp Enable TLS-SRP authentication + --disable-tls-srp Disable TLS-SRP authentication + --enable-unix-sockets Enable Unix domain sockets + --disable-unix-sockets Disable Unix domain sockets + --enable-cookies Enable cookies support + --disable-cookies Disable cookies support + --enable-socketpair Enable socketpair support + --disable-socketpair Disable socketpair support + --enable-http-auth Enable HTTP authentication support + --disable-http-auth Disable HTTP authentication support + --enable-doh Enable DoH support + --disable-doh Disable DoH support + --enable-mime Enable mime API support + --disable-mime Disable mime API support + --enable-bindlocal Enable local binding support + --disable-bindlocal Disable local binding support + --enable-form-api Enable form API support + --disable-form-api Disable form API support + --enable-dateparse Enable date parsing + --disable-dateparse Disable date parsing + --enable-netrc Enable netrc parsing + --disable-netrc Disable netrc parsing + --enable-progress-meter Enable progress-meter + --disable-progress-meter + Disable progress-meter + --enable-dnsshuffle Enable DNS shuffling + --disable-dnsshuffle Disable DNS shuffling + --enable-get-easy-options + Enable curl_easy_options + --disable-get-easy-options + Disable curl_easy_options + --enable-alt-svc Enable alt-svc support + --disable-alt-svc Disable alt-svc support + --enable-headers-api Enable headers-api support + --disable-headers-api Disable headers-api support + --enable-hsts Enable HSTS support + --disable-hsts Disable HSTS support + --enable-websockets Enable WebSockets support + --disable-websockets Disable WebSockets support + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-schannel enable Windows native SSL/TLS + --with-secure-transport enable Apple OS native SSL/TLS + --with-amissl enable Amiga native SSL/TLS (AmiSSL) + --with-ssl=PATH old version of --with-openssl + --without-ssl build without any TLS library + --with-openssl=PATH Where to look for OpenSSL, PATH points to the SSL + installation (default: /usr/local/ssl); when + possible, set the PKG_CONFIG_PATH environment + variable instead of using this option + --with-gnutls=PATH where to look for GnuTLS, PATH points to the + installation root + --with-mbedtls=PATH where to look for mbedTLS, PATH points to the + installation root + --with-wolfssl=PATH where to look for WolfSSL, PATH points to the + installation root (default: system lib default) + --with-bearssl=PATH where to look for BearSSL, PATH points to the + installation root + --with-rustls=PATH where to look for rustls, PATH points to the + installation root + --with-test-nghttpx=PATH + where to find nghttpx for testing + --with-test-caddy=PATH where to find caddy for testing + --with-test-httpd=PATH where to find httpd/apache2 for testing + + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-aix-soname=aix|svr4|both + shared library versioning (aka "SONAME") variant to + provide on AIX, [default=aix]. + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot[=DIR] Search for dependent libraries within DIR (or the + compiler's sysroot if not specified). + --with-hyper=PATH Enable hyper usage + --without-hyper Disable hyper usage + --with-zlib=PATH search for zlib in PATH + --without-zlib disable use of zlib + --with-brotli=PATH Where to look for brotli, PATH points to the BROTLI + installation; when possible, set the PKG_CONFIG_PATH + environment variable instead of using this option + --without-brotli disable BROTLI + --with-zstd=PATH Where to look for libzstd, PATH points to the + libzstd installation; when possible, set the + PKG_CONFIG_PATH environment variable instead of + using this option + --without-zstd disable libzstd + --with-ldap-lib=libname Specify name of ldap lib file + --with-lber-lib=libname Specify name of lber lib file + --with-gssapi-includes=DIR + Specify location of GSS-API headers + --with-gssapi-libs=DIR Specify location of GSS-API libs + --with-gssapi=DIR Where to look for GSS-API + --with-default-ssl-backend=NAME + Use NAME as default SSL backend + --without-default-ssl-backend + Use implicit default SSL backend + --with-random=FILE read randomness from FILE (default=/dev/urandom) + --with-ca-bundle=FILE Path to a file containing CA certificates (example: + /etc/ca-bundle.crt) + --without-ca-bundle Don't use a default CA bundle + --with-ca-path=DIRECTORY + Path to a directory containing CA certificates + stored individually, with their filenames in a hash + format. This option can be used with the OpenSSL, + GnuTLS, mbedTLS and wolfSSL backends. Refer to + OpenSSL c_rehash for details. (example: + /etc/certificates) + --without-ca-path Don't use a default CA path + --with-ca-fallback Use the built in CA store of the SSL library + --without-ca-fallback Don't use the built in CA store of the SSL library + --without-libpsl disable support for libpsl + --without-libgsasl disable libgsasl support for SCRAM + --with-libssh2=PATH Where to look for libssh2, PATH points to the + libssh2 installation; when possible, set the + PKG_CONFIG_PATH environment variable instead of + using this option + --with-libssh2 enable libssh2 + --with-libssh=PATH Where to look for libssh, PATH points to the libssh + installation; when possible, set the PKG_CONFIG_PATH + environment variable instead of using this option + --with-libssh enable libssh + --with-wolfssh=PATH Where to look for wolfssh, PATH points to the + wolfSSH installation; when possible, set the + PKG_CONFIG_PATH environment variable instead of + using this option + --with-wolfssh enable wolfssh + --with-librtmp=PATH Where to look for librtmp, PATH points to the + LIBRTMP installation; when possible, set the + PKG_CONFIG_PATH environment variable instead of + using this option + --without-librtmp disable LIBRTMP + --with-winidn=PATH enable Windows native IDN + --without-winidn disable Windows native IDN + --with-libidn2=PATH Enable libidn2 usage + --without-libidn2 Disable libidn2 usage + --with-nghttp2=PATH Enable nghttp2 usage + --without-nghttp2 Disable nghttp2 usage + --with-ngtcp2=PATH Enable ngtcp2 usage + --without-ngtcp2 Disable ngtcp2 usage + --with-openssl-quic Enable OpenSSL QUIC usage + --without-openssl-quic Disable OpenSSL QUIC usage + --with-nghttp3=PATH Enable nghttp3 usage + --without-nghttp3 Disable nghttp3 usage + --with-quiche=PATH Enable quiche usage + --without-quiche Disable quiche usage + --with-msh3=PATH Enable msh3 usage + --without-msh3 Disable msh3 usage + --with-zsh-functions-dir=PATH + Install zsh completions to PATH + --without-zsh-functions-dir + Do not install zsh completions + --with-fish-functions-dir=PATH + Install fish completions to PATH + --without-fish-functions-dir + Do not install fish completions + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + LT_SYS_LIBRARY_PATH + User-defined run-time library search path. + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +curl configure - +generated by GNU Autoconf 2.71 + +Copyright (C) 2021 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. + +Copyright (C) Daniel Stenberg, +This configure script may be copied, distributed and modified under the +terms of the curl license; see COPYING for more details +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define $2 innocuous_$2 +#ifdef __STDC__ +# include +#else +# include +#endif +#undef $2 +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int main (void) +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_type LINENO SIZEOF_LONG_LONG VAR INCLUDES +# ------------------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int main (void) +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int main (void) +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR +# ------------------------------------------------------------------ +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. +ac_fn_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +printf %s "checking whether $as_decl_name is declared... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + eval ac_save_FLAGS=\$$6 + as_fn_append $6 " $5" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int main (void) +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + eval $6=\$ac_save_FLAGS + +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_check_decl + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +printf %s "checking for $2.$3... " >&6; } +if eval test \${$4+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int main (void) +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$4=yes" +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int main (void) +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$4=yes" +else $as_nop + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +eval ac_res=\$$4 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by curl $as_me -, which was +generated by GNU Autoconf 2.71. Invocation command line was + + $ $0$ac_configure_args_raw + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" + # Save into config.log some information that might help in debugging. + { + echo + + printf "%s\n" "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + printf "%s\n" "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + printf "%s\n" "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + printf "%s\n" "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + printf "%s\n" "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + printf "%s\n" "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +printf "%s\n" "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + ac_site_files="$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" +else + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" +fi + +for ac_site_file in $ac_site_files +do + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif + +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="ltmain.sh config.guess config.sub missing compile install-sh" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# using curl-override.m4 + + + + + +ac_config_headers="$ac_config_headers lib/curl_config.h" + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test ${enable_maintainer_mode+y} +then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else $as_nop + USE_MAINTAINER_MODE=no +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +printf "%s\n" "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + +# Check whether --enable-silent-rules was given. +if test ${enable_silent_rules+y} +then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=0;; +esac +am_make=${MAKE-make} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +printf %s "checking whether $am_make supports nested variables... " >&6; } +if test ${am_cv_make_support_nested_variables+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if printf "%s\n" 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable debug build options" >&5 +printf %s "checking whether to enable debug build options... " >&6; } + OPT_DEBUG_BUILD="default" + # Check whether --enable-debug was given. +if test ${enable_debug+y} +then : + enableval=$enable_debug; OPT_DEBUG_BUILD=$enableval +fi + + case "$OPT_DEBUG_BUILD" in + no) + want_debug="no" + ;; + default) + want_debug="no" + ;; + *) + want_debug="yes" + +printf "%s\n" "#define DEBUGBUILD 1" >>confdefs.h + + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_debug" >&5 +printf "%s\n" "$want_debug" >&6; } + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable compiler optimizer" >&5 +printf %s "checking whether to enable compiler optimizer... " >&6; } + OPT_COMPILER_OPTIMIZE="default" + # Check whether --enable-optimize was given. +if test ${enable_optimize+y} +then : + enableval=$enable_optimize; OPT_COMPILER_OPTIMIZE=$enableval +fi + + case "$OPT_COMPILER_OPTIMIZE" in + no) + want_optimize="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + default) + if test "$want_debug" = "yes"; then + want_optimize="assume_no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: (assumed) no" >&5 +printf "%s\n" "(assumed) no" >&6; } + else + want_optimize="assume_yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: (assumed) yes" >&5 +printf "%s\n" "(assumed) yes" >&6; } + fi + ;; + *) + want_optimize="yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable strict compiler warnings" >&5 +printf %s "checking whether to enable strict compiler warnings... " >&6; } + OPT_COMPILER_WARNINGS="default" + # Check whether --enable-warnings was given. +if test ${enable_warnings+y} +then : + enableval=$enable_warnings; OPT_COMPILER_WARNINGS=$enableval +fi + + case "$OPT_COMPILER_WARNINGS" in + no) + want_warnings="no" + ;; + default) + want_warnings="$want_debug" + ;; + *) + want_warnings="yes" + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_warnings" >&5 +printf "%s\n" "$want_warnings" >&6; } + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable compiler warnings as errors" >&5 +printf %s "checking whether to enable compiler warnings as errors... " >&6; } + OPT_COMPILER_WERROR="default" + # Check whether --enable-werror was given. +if test ${enable_werror+y} +then : + enableval=$enable_werror; OPT_COMPILER_WERROR=$enableval +fi + + case "$OPT_COMPILER_WERROR" in + no) + want_werror="no" + ;; + default) + want_werror="no" + ;; + *) + want_werror="yes" + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_werror" >&5 +printf "%s\n" "$want_werror" >&6; } + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable curl debug memory tracking" >&5 +printf %s "checking whether to enable curl debug memory tracking... " >&6; } + OPT_CURLDEBUG_BUILD="default" + # Check whether --enable-curldebug was given. +if test ${enable_curldebug+y} +then : + enableval=$enable_curldebug; OPT_CURLDEBUG_BUILD=$enableval +fi + + case "$OPT_CURLDEBUG_BUILD" in + no) + want_curldebug="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + default) + if test "$want_debug" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: (assumed) yes" >&5 +printf "%s\n" "(assumed) yes" >&6; } + +printf "%s\n" "#define CURLDEBUG 1" >>confdefs.h + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + want_curldebug_assumed="yes" + want_curldebug="$want_debug" + ;; + *) + want_curldebug="yes" + +printf "%s\n" "#define CURLDEBUG 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable hiding of library internal symbols" >&5 +printf %s "checking whether to enable hiding of library internal symbols... " >&6; } + OPT_SYMBOL_HIDING="default" + # Check whether --enable-symbol-hiding was given. +if test ${enable_symbol_hiding+y} +then : + enableval=$enable_symbol_hiding; OPT_SYMBOL_HIDING=$enableval +fi + + case "$OPT_SYMBOL_HIDING" in + no) + want_symbol_hiding="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + default) + want_symbol_hiding="yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + *) + want_symbol_hiding="yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable c-ares for DNS lookups" >&5 +printf %s "checking whether to enable c-ares for DNS lookups... " >&6; } + OPT_ARES="default" + # Check whether --enable-ares was given. +if test ${enable_ares+y} +then : + enableval=$enable_ares; OPT_ARES=$enableval +fi + + case "$OPT_ARES" in + no) + want_ares="no" + ;; + default) + want_ares="no" + ;; + *) + want_ares="yes" + if test -n "$enableval" && test "$enableval" != "yes"; then + want_ares_path="$enableval" + fi + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_ares" >&5 +printf "%s\n" "$want_ares" >&6; } + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to disable dependency on -lrt" >&5 +printf %s "checking whether to disable dependency on -lrt... " >&6; } + OPT_RT="default" + # Check whether --enable-rt was given. +if test ${enable_rt+y} +then : + enableval=$enable_rt; OPT_RT=$enableval +fi + + case "$OPT_RT" in + no) + dontwant_rt="yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + default) + dontwant_rt="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: (assumed no)" >&5 +printf "%s\n" "(assumed no)" >&6; } + ;; + *) + dontwant_rt="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + esac + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable ECH support" >&5 +printf %s "checking whether to enable ECH support... " >&6; } + OPT_ECH="default" + # Check whether --enable-ech was given. +if test ${enable_ech+y} +then : + enableval=$enable_ech; OPT_ECH=$enableval +fi + + case "$OPT_ECH" in + no) + want_ech="no" + curl_ech_msg="no (--enable-ech)" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + default) + want_ech="no" + curl_ech_msg="no (--enable-ech)" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + *) + want_ech="yes" + curl_ech_msg="enabled (--disable-ech)" + experimental="ech" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac + + +# +# Check that 'XC_CONFIGURE_PREAMBLE' has already run. +# + +if test -z "$xc_configure_preamble_result"; then + as_fn_error $? "xc_configure_preamble_result not set (internal problem)" "$LINENO" 5 +fi + +# +# Check that 'PATH_SEPARATOR' has already been set. +# + +if test -z "$xc_PATH_SEPARATOR"; then + as_fn_error $? "xc_PATH_SEPARATOR not set (internal problem)" "$LINENO" 5 +fi +if test -z "$PATH_SEPARATOR"; then + as_fn_error $? "PATH_SEPARATOR not set (internal or config.site problem)" "$LINENO" 5 +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for path separator" >&5 +printf %s "checking for path separator... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PATH_SEPARATOR" >&5 +printf "%s\n" "$PATH_SEPARATOR" >&6; } +if test "x$PATH_SEPARATOR" != "x$xc_PATH_SEPARATOR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for initial path separator" >&5 +printf %s "checking for initial path separator... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_PATH_SEPARATOR" >&5 +printf "%s\n" "$xc_PATH_SEPARATOR" >&6; } + as_fn_error $? "path separator mismatch (internal or config.site problem)" "$LINENO" 5 +fi + + +# +# save the configure arguments +# +CONFIGURE_OPTIONS="\"$ac_configure_args\"" + + +if test -z "$SED"; then + # Extract the first word of "sed", so it can be a program name with args. +set dummy sed; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_SED+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $SED in + [\\/]* | ?:[\\/]*) + ac_cv_path_SED="$SED" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_SED="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_SED" && ac_cv_path_SED="not_found" + ;; +esac +fi +SED=$ac_cv_path_SED +if test -n "$SED"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 +printf "%s\n" "$SED" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test -z "$SED" || test "$SED" = "not_found"; then + as_fn_error $? "sed not found in PATH. Cannot continue without sed." "$LINENO" 5 + fi +fi + + +if test -z "$GREP"; then + # Extract the first word of "grep", so it can be a program name with args. +set dummy grep; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $GREP in + [\\/]* | ?:[\\/]*) + ac_cv_path_GREP="$GREP" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_GREP="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GREP" && ac_cv_path_GREP="not_found" + ;; +esac +fi +GREP=$ac_cv_path_GREP +if test -n "$GREP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GREP" >&5 +printf "%s\n" "$GREP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test -z "$GREP" || test "$GREP" = "not_found"; then + as_fn_error $? "grep not found in PATH. Cannot continue without grep." "$LINENO" 5 + fi +fi + + +if test -z "$EGREP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that grep -E works" >&5 +printf %s "checking that grep -E works... " >&6; } + if echo a | ($GREP -E '(a|b)') >/dev/null 2>&1; then + EGREP="$GREP -E" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + # Extract the first word of "egrep", so it can be a program name with args. +set dummy egrep; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $EGREP in + [\\/]* | ?:[\\/]*) + ac_cv_path_EGREP="$EGREP" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_EGREP="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_EGREP" && ac_cv_path_EGREP="not_found" + ;; +esac +fi +EGREP=$ac_cv_path_EGREP +if test -n "$EGREP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EGREP" >&5 +printf "%s\n" "$EGREP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + fi +fi +if test -z "$EGREP" || test "$EGREP" = "not_found"; then + as_fn_error $? "grep -E is not working and egrep is not found in PATH. Cannot continue." "$LINENO" 5 +fi + + +if test -z "$AR"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $AR in + [\\/]* | ?:[\\/]*) + ac_cv_path_AR="$AR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_AR="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +AR=$ac_cv_path_AR +if test -n "$AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf "%s\n" "$AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_AR"; then + ac_pt_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_AR in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_AR="$ac_pt_AR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_AR="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_AR=$ac_cv_path_ac_pt_AR +if test -n "$ac_pt_AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_AR" >&5 +printf "%s\n" "$ac_pt_AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_AR" = x; then + AR="not_found" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_pt_AR + fi +else + AR="$ac_cv_path_AR" +fi + + if test -z "$AR" || test "$AR" = "not_found"; then + as_fn_error $? "ar not found in PATH. Cannot continue without ar." "$LINENO" 5 + fi +fi + + + + +CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)".*/\1/p' ${srcdir}/include/curl/curlver.h` + + xc_prog_cc_prev_IFS=$IFS + xc_prog_cc_prev_LIBS=$LIBS + xc_prog_cc_prev_CFLAGS=$CFLAGS + xc_prog_cc_prev_LDFLAGS=$LDFLAGS + xc_prog_cc_prev_CPPFLAGS=$CPPFLAGS + + + + xc_bad_var_libs=no + for xc_word in $LIBS; do + case "$xc_word" in + -l* | --library=*) + : + ;; + *) + xc_bad_var_libs=yes + ;; + esac + done + if test $xc_bad_var_libs = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using LIBS: $LIBS" >&5 +printf "%s\n" "$as_me: using LIBS: $LIBS" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: LIBS note: LIBS should only be used to specify libraries (-lname)." >&5 +printf "%s\n" "$as_me: LIBS note: LIBS should only be used to specify libraries (-lname)." >&6;} + fi + + + xc_bad_var_ldflags=no + for xc_word in $LDFLAGS; do + case "$xc_word" in + -D*) + xc_bad_var_ldflags=yes + ;; + -U*) + xc_bad_var_ldflags=yes + ;; + -I*) + xc_bad_var_ldflags=yes + ;; + -l* | --library=*) + xc_bad_var_ldflags=yes + ;; + esac + done + if test $xc_bad_var_ldflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using LDFLAGS: $LDFLAGS" >&5 +printf "%s\n" "$as_me: using LDFLAGS: $LDFLAGS" >&6;} + xc_bad_var_msg="LDFLAGS note: LDFLAGS should only be used to specify linker flags, not" + for xc_word in $LDFLAGS; do + case "$xc_word" in + -D*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -U*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -I*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -l* | --library=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&6;} + ;; + esac + done + fi + + + xc_bad_var_cppflags=no + for xc_word in $CPPFLAGS; do + case "$xc_word" in + -rpath*) + xc_bad_var_cppflags=yes + ;; + -L* | --library-path=*) + xc_bad_var_cppflags=yes + ;; + -l* | --library=*) + xc_bad_var_cppflags=yes + ;; + esac + done + if test $xc_bad_var_cppflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using CPPFLAGS: $CPPFLAGS" >&5 +printf "%s\n" "$as_me: using CPPFLAGS: $CPPFLAGS" >&6;} + xc_bad_var_msg="CPPFLAGS note: CPPFLAGS should only be used to specify C preprocessor flags, not" + for xc_word in $CPPFLAGS; do + case "$xc_word" in + -rpath*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -L* | --library-path=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -l* | --library=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&6;} + ;; + esac + done + fi + + + xc_bad_var_cflags=no + for xc_word in $CFLAGS; do + case "$xc_word" in + -D*) + xc_bad_var_cflags=yes + ;; + -U*) + xc_bad_var_cflags=yes + ;; + -I*) + xc_bad_var_cflags=yes + ;; + -rpath*) + xc_bad_var_cflags=yes + ;; + -L* | --library-path=*) + xc_bad_var_cflags=yes + ;; + -l* | --library=*) + xc_bad_var_cflags=yes + ;; + esac + done + if test $xc_bad_var_cflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using CFLAGS: $CFLAGS" >&5 +printf "%s\n" "$as_me: using CFLAGS: $CFLAGS" >&6;} + xc_bad_var_msg="CFLAGS note: CFLAGS should only be used to specify C compiler flags, not" + for xc_word in $CFLAGS; do + case "$xc_word" in + -D*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -U*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -I*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -rpath*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -L* | --library-path=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -l* | --library=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&6;} + ;; + esac + done + fi + + if test $xc_bad_var_libs = yes || + test $xc_bad_var_cflags = yes || + test $xc_bad_var_ldflags = yes || + test $xc_bad_var_cppflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Continuing even with errors mentioned immediately above this line." >&5 +printf "%s\n" "$as_me: WARNING: Continuing even with errors mentioned immediately above this line." >&2;} + fi + + + + # Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else $as_nop + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +case $as_dir in #(( + ./ | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test ${ac_cv_path_install+y}; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + + + + + + + + + + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion -version; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else $as_nop + ac_file='' +fi +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int main (void) +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_compiler_gnu=yes +else $as_nop + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+y} +ac_save_CFLAGS=$CFLAGS +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +else $as_nop + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +printf %s "checking whether $CC understands -c and -o together... " >&6; } +if test ${am_cv_prog_cc_c_o+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test ${ac_cv_prog_CPP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + +else $as_nop + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + +else $as_nop + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : + +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + IFS=$xc_prog_cc_prev_IFS + LIBS=$xc_prog_cc_prev_LIBS + CFLAGS=$xc_prog_cc_prev_CFLAGS + LDFLAGS=$xc_prog_cc_prev_LDFLAGS + CPPFLAGS=$xc_prog_cc_prev_CPPFLAGS + + + + + + +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done + + + + + + + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi + + for ac_header in stdatomic.h +do : + ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default" +if test "x$ac_cv_header_stdatomic_h" = xyes +then : + printf "%s\n" "#define HAVE_STDATOMIC_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _Atomic is available" >&5 +printf %s "checking if _Atomic is available... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_unistd + +int main (void) +{ + + _Atomic int i = 0; + i = 4; // Force an atomic-write operation. + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_ATOMIC 1" >>confdefs.h + + tst_atomic="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_atomic="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi + +done + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +printf %s "checking for a sed that does not truncate output... " >&6; } +if test ${ac_cv_path_SED+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in sed gsed + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +printf "%s\n" "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for code coverage support" >&5 +printf %s "checking for code coverage support... " >&6; } + coverage="no" + curl_coverage_msg="disabled" + + # Check whether --enable-code-coverage was given. +if test ${enable_code_coverage+y} +then : + enableval=$enable_code_coverage; coverage="$enableval" +fi + + + if test "$GCC" != "yes" +then : + coverage="no" +fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $coverage" >&5 +printf "%s\n" "$coverage" >&6; } + + if test "x$coverage" = "xyes"; then + curl_coverage_msg="enabled" + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcov", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcov; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GCOV+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$GCOV"; then + ac_cv_prog_GCOV="$GCOV" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_GCOV="${ac_tool_prefix}gcov" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GCOV=$ac_cv_prog_GCOV +if test -n "$GCOV"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GCOV" >&5 +printf "%s\n" "$GCOV" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_GCOV"; then + ac_ct_GCOV=$GCOV + # Extract the first word of "gcov", so it can be a program name with args. +set dummy gcov; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_GCOV+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_GCOV"; then + ac_cv_prog_ac_ct_GCOV="$ac_ct_GCOV" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_GCOV="gcov" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_GCOV=$ac_cv_prog_ac_ct_GCOV +if test -n "$ac_ct_GCOV"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GCOV" >&5 +printf "%s\n" "$ac_ct_GCOV" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_GCOV" = x; then + GCOV="gcov" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + GCOV=$ac_ct_GCOV + fi +else + GCOV="$ac_cv_prog_GCOV" +fi + + if test -z "$GCOV"; then + as_fn_error $? "needs gcov for code coverage" "$LINENO" 5 + fi + # Extract the first word of "lcov", so it can be a program name with args. +set dummy lcov; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LCOV+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$LCOV"; then + ac_cv_prog_LCOV="$LCOV" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_LCOV="lcov" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LCOV=$ac_cv_prog_LCOV +if test -n "$LCOV"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LCOV" >&5 +printf "%s\n" "$LCOV" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test -z "$LCOV"; then + as_fn_error $? "needs lcov for code coverage" "$LINENO" 5 + fi + + CPPFLAGS="$CPPFLAGS -DNDEBUG" + CFLAGS="$CFLAGS -O0 -g -fprofile-arcs -ftest-coverage" + LIBS="$LIBS -lgcov" + fi + + +am__api_version='1.16' + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +printf %s "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` + + + if test x"${MISSING+set}" != xset; then + MISSING="\${SHELL} '$am_aux_dir/missing'" +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +printf "%s\n" "$STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +printf "%s\n" "$ac_ct_STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 +printf %s "checking for a race-free mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test ${ac_cv_path_mkdir+y} +then : + printf %s "(cached) " >&6 +else $as_nop + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue + case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir ('*'coreutils) '* | \ + 'BusyBox '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test ${ac_cv_path_mkdir+y}; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +printf "%s\n" "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AWK+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +printf "%s\n" "$AWK" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval test \${ac_cv_prog_make_${ac_make}_set+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + SET_MAKE= +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 + (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + case $?:`cat confinc.out 2>/dev/null` in #( + '0:this is the am__doit target') : + case $s in #( + BSD) : + am__include='.include' am__quote='"' ;; #( + *) : + am__include='include' am__quote='' ;; +esac ;; #( + *) : + ;; +esac + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +printf "%s\n" "${_am_result}" >&6; } + +# Check whether --enable-dependency-tracking was given. +if test ${enable_dependency_tracking+y} +then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +## --------------------------------------- ## +## Start of automake initialization code ## +## --------------------------------------- ## + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='curl' + VERSION='-' + + +printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h + + +printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + +depcc="$CC" am_compiler_list= + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CC_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi + +if test -z "$ETAGS"; then + ETAGS=etags +fi + +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + +## ------------------------------------- ## +## End of automake initialization code ## +## ------------------------------------- ## + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking curl version" >&5 +printf %s "checking curl version... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CURLVERSION" >&5 +printf "%s\n" "$CURLVERSION" >&6; } + + + +VERSIONNUM=`$SED -ne 's/^#define LIBCURL_VERSION_NUM 0x\([0-9A-Fa-f]*\).*/\1/p' ${srcdir}/include/curl/curlver.h` + + +PKGADD_PKG="HAXXcurl" +PKGADD_NAME="curl - a client that groks URLs" +PKGADD_VENDOR="curl.se" + + + + + curl_ssl_msg="no (--with-{openssl,gnutls,mbedtls,wolfssl,schannel,secure-transport,amissl,bearssl,rustls} )" + curl_ssh_msg="no (--with-{libssh,libssh2})" + curl_zlib_msg="no (--with-zlib)" + curl_brotli_msg="no (--with-brotli)" + curl_zstd_msg="no (--with-zstd)" + curl_gss_msg="no (--with-gssapi)" + curl_gsasl_msg="no (--with-gsasl)" +curl_tls_srp_msg="no (--enable-tls-srp)" + curl_res_msg="default (--enable-ares / --enable-threaded-resolver)" + curl_ipv6_msg="no (--enable-ipv6)" +curl_unix_sockets_msg="no (--enable-unix-sockets)" + curl_idn_msg="no (--with-{libidn2,winidn})" + curl_manual_msg="no (--enable-manual)" +curl_libcurl_msg="enabled (--disable-libcurl-option)" +curl_verbose_msg="enabled (--disable-verbose)" + curl_sspi_msg="no (--enable-sspi)" + curl_ldap_msg="no (--enable-ldap / --with-ldap-lib / --with-lber-lib)" + curl_ldaps_msg="no (--enable-ldaps)" + curl_rtsp_msg="no (--enable-rtsp)" + curl_rtmp_msg="no (--with-librtmp)" + curl_psl_msg="no (--with-libpsl)" + curl_altsvc_msg="enabled (--disable-alt-svc)" +curl_headers_msg="enabled (--disable-headers-api)" + curl_hsts_msg="enabled (--disable-hsts)" + curl_ws_msg="no (--enable-websockets)" + ssl_backends= + curl_h1_msg="enabled (internal)" + curl_h2_msg="no (--with-nghttp2)" + curl_h3_msg="no (--with-ngtcp2 --with-nghttp3, --with-quiche, --with-openssl-quic, --with-msh3)" + +enable_altsvc="yes" +hsts="yes" + +INITIAL_LDFLAGS=$LDFLAGS +INITIAL_LIBS=$LIBS + +compilersh="run-compiler" +CURL_SAVED_CC="$CC" +export CURL_SAVED_CC +CURL_SAVED_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" +export CURL_SAVED_LD_LIBRARY_PATH +cat <<\EOF > "$compilersh" +CC="$CURL_SAVED_CC" +export CC +LD_LIBRARY_PATH="$CURL_SAVED_LD_LIBRARY_PATH" +export LD_LIBRARY_PATH +exec $CC "$@" +EOF + +OPT_SCHANNEL=no + +# Check whether --with-schannel was given. +if test ${with_schannel+y} +then : + withval=$with_schannel; OPT_SCHANNEL=$withval + TLSCHOICE="schannel" +fi + + +OPT_SECURETRANSPORT=no + +# Check whether --with-secure-transport was given. +if test ${with_secure_transport+y} +then : + withval=$with_secure_transport; + OPT_SECURETRANSPORT=$withval + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }Secure-Transport" + +fi + + +OPT_AMISSL=no + +# Check whether --with-amissl was given. +if test ${with_amissl+y} +then : + withval=$with_amissl; + OPT_AMISSL=$withval + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }AmiSSL" + +fi + + +OPT_OPENSSL=no +ca="no" + +# Check whether --with-ssl was given. +if test ${with_ssl+y} +then : + withval=$with_ssl; + OPT_SSL=$withval + OPT_OPENSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }OpenSSL" + else + SSL_DISABLED="D" + fi + +fi + + + +# Check whether --with-openssl was given. +if test ${with_openssl+y} +then : + withval=$with_openssl; + OPT_OPENSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }OpenSSL" + fi + +fi + + +OPT_GNUTLS=no + +# Check whether --with-gnutls was given. +if test ${with_gnutls+y} +then : + withval=$with_gnutls; + OPT_GNUTLS=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }GnuTLS" + fi + +fi + + +OPT_MBEDTLS=no + +# Check whether --with-mbedtls was given. +if test ${with_mbedtls+y} +then : + withval=$with_mbedtls; + OPT_MBEDTLS=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }mbedTLS" + fi + +fi + + +OPT_WOLFSSL=no + +# Check whether --with-wolfssl was given. +if test ${with_wolfssl+y} +then : + withval=$with_wolfssl; + OPT_WOLFSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }wolfSSL" + fi + +fi + + +OPT_BEARSSL=no + +# Check whether --with-bearssl was given. +if test ${with_bearssl+y} +then : + withval=$with_bearssl; + OPT_BEARSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }BearSSL" + fi + +fi + + +OPT_RUSTLS=no + +# Check whether --with-rustls was given. +if test ${with_rustls+y} +then : + withval=$with_rustls; + OPT_RUSTLS=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }rustls" + experimental="$experimental rustls" + fi + +fi + + +TEST_NGHTTPX=nghttpx + +# Check whether --with-test-nghttpx was given. +if test ${with_test_nghttpx+y} +then : + withval=$with_test_nghttpx; TEST_NGHTTPX=$withval + if test X"$OPT_TEST_NGHTTPX" = "Xno" ; then + TEST_NGHTTPX="" + fi + +fi + + + +CADDY=caddy + +# Check whether --with-test-caddy was given. +if test ${with_test_caddy+y} +then : + withval=$with_test_caddy; CADDY=$withval + if test X"$OPT_CADDY" = "Xno" ; then + CADDY="" + fi + +fi + + + +HTTPD_ENABLED="maybe" + +# Check whether --with-test-httpd was given. +if test ${with_test_httpd+y} +then : + withval=$with_test_httpd; request_httpd=$withval +else $as_nop + request_httpd=check +fi + +if test x"$request_httpd" = "xcheck" -o x"$request_httpd" = "xyes"; then + if test -x "/usr/sbin/apache2" -a -x "/usr/sbin/apache2ctl"; then + # common location on distros (debian/ubuntu) + HTTPD="/usr/sbin/apache2" + APACHECTL="/usr/sbin/apache2ctl" + # Extract the first word of "apxs", so it can be a program name with args. +set dummy apxs; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_APXS+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $APXS in + [\\/]* | ?:[\\/]*) + ac_cv_path_APXS="$APXS" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_APXS="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +APXS=$ac_cv_path_APXS +if test -n "$APXS"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $APXS" >&5 +printf "%s\n" "$APXS" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test "x$APXS" = "x"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: apache2-dev not installed, httpd tests disabled" >&5 +printf "%s\n" "$as_me: apache2-dev not installed, httpd tests disabled" >&6;} + HTTPD_ENABLED="no" + fi + else + # Extract the first word of "httpd", so it can be a program name with args. +set dummy httpd; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_HTTPD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $HTTPD in + [\\/]* | ?:[\\/]*) + ac_cv_path_HTTPD="$HTTPD" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_HTTPD="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +HTTPD=$ac_cv_path_HTTPD +if test -n "$HTTPD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HTTPD" >&5 +printf "%s\n" "$HTTPD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test "x$HTTPD" = "x"; then + # Extract the first word of "apache2", so it can be a program name with args. +set dummy apache2; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_HTTPD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $HTTPD in + [\\/]* | ?:[\\/]*) + ac_cv_path_HTTPD="$HTTPD" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_HTTPD="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +HTTPD=$ac_cv_path_HTTPD +if test -n "$HTTPD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HTTPD" >&5 +printf "%s\n" "$HTTPD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + fi + # Extract the first word of "apachectl", so it can be a program name with args. +set dummy apachectl; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_APACHECTL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $APACHECTL in + [\\/]* | ?:[\\/]*) + ac_cv_path_APACHECTL="$APACHECTL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_APACHECTL="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +APACHECTL=$ac_cv_path_APACHECTL +if test -n "$APACHECTL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $APACHECTL" >&5 +printf "%s\n" "$APACHECTL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + # Extract the first word of "apxs", so it can be a program name with args. +set dummy apxs; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_APXS+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $APXS in + [\\/]* | ?:[\\/]*) + ac_cv_path_APXS="$APXS" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_APXS="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +APXS=$ac_cv_path_APXS +if test -n "$APXS"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $APXS" >&5 +printf "%s\n" "$APXS" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test "x$HTTPD" = "x" -o "x$APACHECTL" = "x"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: httpd/apache2 not in PATH, http tests disabled" >&5 +printf "%s\n" "$as_me: httpd/apache2 not in PATH, http tests disabled" >&6;} + HTTPD_ENABLED="no" + fi + if test "x$APXS" = "x"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: apxs not in PATH, http tests disabled" >&5 +printf "%s\n" "$as_me: apxs not in PATH, http tests disabled" >&6;} + HTTPD_ENABLED="no" + fi + fi +elif test x"$request_httpd" != "xno"; then + HTTPD="${request_httpd}/bin/httpd" + APACHECTL="${request_httpd}/bin/apachectl" + APXS="${request_httpd}/bin/apxs" + if test ! -x "${HTTPD}"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: httpd not found as ${HTTPD}, http tests disabled" >&5 +printf "%s\n" "$as_me: httpd not found as ${HTTPD}, http tests disabled" >&6;} + HTTPD_ENABLED="no" + elif test ! -x "${APACHECTL}"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: apachectl not found as ${APACHECTL}, http tests disabled" >&5 +printf "%s\n" "$as_me: apachectl not found as ${APACHECTL}, http tests disabled" >&6;} + HTTPD_ENABLED="no" + elif test ! -x "${APXS}"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: apxs not found as ${APXS}, http tests disabled" >&5 +printf "%s\n" "$as_me: apxs not found as ${APXS}, http tests disabled" >&6;} + HTTPD_ENABLED="no" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using HTTPD=$HTTPD for tests" >&5 +printf "%s\n" "$as_me: using HTTPD=$HTTPD for tests" >&6;} + fi +fi +if test x"$HTTPD_ENABLED" = "xno"; then + HTTPD="" + APACHECTL="" + APXS="" +fi + + + + +if test "x$TEST_NGHTTPX" != "x" -a "x$TEST_NGHTTPX" != "xnghttpx"; then + HTTPD_NGHTTPX="$TEST_NGHTTPX" +else + # Extract the first word of "nghttpx", so it can be a program name with args. +set dummy nghttpx; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_HTTPD_NGHTTPX+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $HTTPD_NGHTTPX in + [\\/]* | ?:[\\/]*) + ac_cv_path_HTTPD_NGHTTPX="$HTTPD_NGHTTPX" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_HTTPD_NGHTTPX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +HTTPD_NGHTTPX=$ac_cv_path_HTTPD_NGHTTPX +if test -n "$HTTPD_NGHTTPX"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HTTPD_NGHTTPX" >&5 +printf "%s\n" "$HTTPD_NGHTTPX" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi + + +if test "x$TEST_CADDY" != "x"; then + CADDY="$TEST_CADDY" +else + # Extract the first word of "caddy", so it can be a program name with args. +set dummy caddy; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_CADDY+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $CADDY in + [\\/]* | ?:[\\/]*) + ac_cv_path_CADDY="$CADDY" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_CADDY="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +CADDY=$ac_cv_path_CADDY +if test -n "$CADDY"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CADDY" >&5 +printf "%s\n" "$CADDY" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi + + +if test -z "$TLSCHOICE"; then + if test "x$OPT_SSL" != "xno"; then + as_fn_error $? "select TLS backend(s) or disable TLS with --without-ssl. + +Select from these: + + --with-amissl + --with-bearssl + --with-gnutls + --with-mbedtls + --with-openssl (also works for BoringSSL and libressl) + --with-rustls + --with-schannel + --with-secure-transport + --with-wolfssl +" "$LINENO" 5 + fi +fi + + +# Check whether --with-darwinssl was given. +if test ${with_darwinssl+y} +then : + withval=$with_darwinssl; as_fn_error $? "--with-darwin-ssl and --without-darwin-ssl no longer work!" "$LINENO" 5 +fi + + + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +printf "%s\n" "#define OS \"${host}\"" >>confdefs.h + + +# Silence warning: ar: 'u' modifier ignored since 'D' is the default +AR_FLAGS=cr + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +printf %s "checking for grep that handles long lines and -e... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in grep ggrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +printf "%s\n" "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +printf %s "checking for egrep... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in egrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +printf "%s\n" "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if OS is AIX (to define _ALL_SOURCE)" >&5 +printf %s "checking if OS is AIX (to define _ALL_SOURCE)... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef _AIX + yes_this_is_aix +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "yes_this_is_aix" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -rf conftest* + + + + + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _THREAD_SAFE is already defined" >&5 +printf %s "checking if _THREAD_SAFE is already defined... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#ifdef _THREAD_SAFE + int dummy=1; +#else + force compilation error +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tmp_thread_safe_initially_defined="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tmp_thread_safe_initially_defined="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # + if test "$tmp_thread_safe_initially_defined" = "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _THREAD_SAFE is actually needed" >&5 +printf %s "checking if _THREAD_SAFE is actually needed... " >&6; } + + case $host_os in + aix[123].* | aix4.[012].*) + tmp_need_thread_safe="no" + ;; + aix*) + tmp_need_thread_safe="yes" + ;; + *) + tmp_need_thread_safe="no" + ;; + esac + + if test "$tmp_need_thread_safe" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _THREAD_SAFE is onwards defined" >&5 +printf %s "checking if _THREAD_SAFE is onwards defined... " >&6; } + if test "$tmp_thread_safe_initially_defined" = "yes" || + test "$tmp_need_thread_safe" = "yes"; then + + +printf "%s\n" "#define NEED_THREAD_SAFE 1" >>confdefs.h + +cat >>confdefs.h <<_EOF +#ifndef _THREAD_SAFE +# define _THREAD_SAFE +#endif +_EOF + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + # + + + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _REENTRANT is already defined" >&5 +printf %s "checking if _REENTRANT is already defined... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#ifdef _REENTRANT + int dummy=1; +#else + force compilation error +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tmp_reentrant_initially_defined="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tmp_reentrant_initially_defined="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # + if test "$tmp_reentrant_initially_defined" = "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _REENTRANT is actually needed" >&5 +printf %s "checking if _REENTRANT is actually needed... " >&6; } + + case $host_os in + solaris*) + tmp_need_reentrant="yes" + ;; + *) + tmp_need_reentrant="no" + ;; + esac + + if test "$tmp_need_reentrant" = "no"; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + + if(0 != errno) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tmp_errno="yes" + +else $as_nop + + tmp_errno="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "$tmp_errno" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + +#ifdef errno + int dummy=1; +#else + force compilation error +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tmp_errno="errno_macro_defined" + +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define _REENTRANT +#include + +int main (void) +{ + +#ifdef errno + int dummy=1; +#else + force compilation error +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tmp_errno="errno_macro_needs_reentrant" + tmp_need_reentrant="yes" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + + fi + if test "$tmp_need_reentrant" = "no"; then + + if test "$tmp_need_reentrant" = "no"; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define gmtime_r innocuous_gmtime_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef gmtime_r +#ifdef __cplusplus +extern "C" +#endif +char gmtime_r (); +#if defined __stub_gmtime_r || defined __stub___gmtime_r +choke me +#endif + +int main (void) +{ +return gmtime_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_gmtime_r="yes" + +else $as_nop + + tmp_gmtime_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test "$tmp_gmtime_r" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gmtime_r" >/dev/null 2>&1 +then : + + tmp_gmtime_r="proto_declared" + +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _REENTRANT +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gmtime_r" >/dev/null 2>&1 +then : + + tmp_gmtime_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + +fi +rm -rf conftest* + + +fi +rm -rf conftest* + + fi + + fi + if test "$tmp_need_reentrant" = "no"; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define localtime_r innocuous_localtime_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef localtime_r +#ifdef __cplusplus +extern "C" +#endif +char localtime_r (); +#if defined __stub_localtime_r || defined __stub___localtime_r +choke me +#endif + +int main (void) +{ +return localtime_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_localtime_r="yes" + +else $as_nop + + tmp_localtime_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test "$tmp_localtime_r" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "localtime_r" >/dev/null 2>&1 +then : + + tmp_localtime_r="proto_declared" + +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _REENTRANT +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "localtime_r" >/dev/null 2>&1 +then : + + tmp_localtime_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + +fi +rm -rf conftest* + + +fi +rm -rf conftest* + + fi + + fi + if test "$tmp_need_reentrant" = "no"; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strerror_r innocuous_strerror_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strerror_r +#ifdef __cplusplus +extern "C" +#endif +char strerror_r (); +#if defined __stub_strerror_r || defined __stub___strerror_r +choke me +#endif + +int main (void) +{ +return strerror_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_strerror_r="yes" + +else $as_nop + + tmp_strerror_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test "$tmp_strerror_r" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strerror_r" >/dev/null 2>&1 +then : + + tmp_strerror_r="proto_declared" + +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _REENTRANT +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strerror_r" >/dev/null 2>&1 +then : + + tmp_strerror_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + +fi +rm -rf conftest* + + +fi +rm -rf conftest* + + fi + + fi + if test "$tmp_need_reentrant" = "no"; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strtok_r innocuous_strtok_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strtok_r +#ifdef __cplusplus +extern "C" +#endif +char strtok_r (); +#if defined __stub_strtok_r || defined __stub___strtok_r +choke me +#endif + +int main (void) +{ +return strtok_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_strtok_r="yes" + +else $as_nop + + tmp_strtok_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test "$tmp_strtok_r" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strtok_r" >/dev/null 2>&1 +then : + + tmp_strtok_r="proto_declared" + +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _REENTRANT +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strtok_r" >/dev/null 2>&1 +then : + + tmp_strtok_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + +fi +rm -rf conftest* + + +fi +rm -rf conftest* + + fi + + fi + if test "$tmp_need_reentrant" = "no"; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define gethostbyname_r innocuous_gethostbyname_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef gethostbyname_r +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname_r (); +#if defined __stub_gethostbyname_r || defined __stub___gethostbyname_r +choke me +#endif + +int main (void) +{ +return gethostbyname_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_gethostbyname_r="yes" + +else $as_nop + + tmp_gethostbyname_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test "$tmp_gethostbyname_r" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gethostbyname_r" >/dev/null 2>&1 +then : + + tmp_gethostbyname_r="proto_declared" + +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _REENTRANT +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gethostbyname_r" >/dev/null 2>&1 +then : + + tmp_gethostbyname_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + +fi +rm -rf conftest* + + +fi +rm -rf conftest* + + fi + + fi + if test "$tmp_need_reentrant" = "no"; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define getprotobyname_r innocuous_getprotobyname_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef getprotobyname_r +#ifdef __cplusplus +extern "C" +#endif +char getprotobyname_r (); +#if defined __stub_getprotobyname_r || defined __stub___getprotobyname_r +choke me +#endif + +int main (void) +{ +return getprotobyname_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_getprotobyname_r="yes" + +else $as_nop + + tmp_getprotobyname_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test "$tmp_getprotobyname_r" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "getprotobyname_r" >/dev/null 2>&1 +then : + + tmp_getprotobyname_r="proto_declared" + +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _REENTRANT +#include +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "getprotobyname_r" >/dev/null 2>&1 +then : + + tmp_getprotobyname_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + +fi +rm -rf conftest* + + +fi +rm -rf conftest* + + fi + + fi + + fi + if test "$tmp_need_reentrant" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _REENTRANT is onwards defined" >&5 +printf %s "checking if _REENTRANT is onwards defined... " >&6; } + if test "$tmp_reentrant_initially_defined" = "yes" || + test "$tmp_need_reentrant" = "yes"; then + + +printf "%s\n" "#define NEED_REENTRANT 1" >>confdefs.h + +cat >>confdefs.h <<_EOF +#ifndef _REENTRANT +# define _REENTRANT +#endif +_EOF + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + # + + +# Check whether --enable-largefile was given. +if test ${enable_largefile+y} +then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +printf %s "checking for special C compiler options needed for large files... " >&6; } +if test ${ac_cv_sys_largefile_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int main (void) +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO" +then : + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if test ${ac_cv_sys_file_offset_bits+y} +then : + printf %s "(cached) " >&6 +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } +if test ${ac_cv_sys_large_files+y} +then : + printf %s "(cached) " >&6 +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +printf "%s\n" "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h +;; +esac +rm -rf conftest* + fi +fi + + +case `pwd` in + *\ * | *\ *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.7' +macro_revision='2.4.7' + + + + + + + + + + + + + + +ltmain=$ac_aux_dir/ltmain.sh + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +printf %s "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case $ECHO in + printf*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +printf "%s\n" "printf" >&6; } ;; + print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +printf "%s\n" "print -r" >&6; } ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +printf "%s\n" "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +printf %s "checking for a sed that does not truncate output... " >&6; } +if test ${ac_cv_path_SED+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in sed gsed + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +printf "%s\n" "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +printf %s "checking for fgrep... " >&6; } +if test ${ac_cv_path_FGREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in fgrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +printf "%s\n" "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test ${with_gnu_ld+y} +then : + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes +else $as_nop + with_gnu_ld=no +fi + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +printf %s "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +printf %s "checking for GNU ld... " >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +printf %s "checking for non-GNU ld... " >&6; } +fi +if test ${lt_cv_path_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +printf "%s\n" "$LD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +printf %s "checking if the linker ($LD) is GNU ld... " >&6; } +if test ${lt_cv_prog_gnu_ld+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test ${lt_cv_path_NM+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +printf "%s\n" "$lt_cv_path_NM" >&6; } +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DUMPBIN+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +printf "%s\n" "$DUMPBIN" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DUMPBIN+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +printf "%s\n" "$ac_ct_DUMPBIN" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +printf %s "checking the name lister ($NM) interface... " >&6; } +if test ${lt_cv_nm_interface+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +printf "%s\n" "$lt_cv_nm_interface" >&6; } + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +printf %s "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +printf "%s\n" "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +printf %s "checking the maximum length of command line arguments... " >&6; } +if test ${lt_cv_sys_max_cmd_len+y} +then : + printf %s "(cached) " >&6 +else $as_nop + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n "$lt_cv_sys_max_cmd_len"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 +printf "%s\n" "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +printf %s "checking how to convert $build file names to $host format... " >&6; } +if test ${lt_cv_to_host_file_cmd+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +printf %s "checking how to convert $build file names to toolchain format... " >&6; } +if test ${lt_cv_to_tool_file_cmd+y} +then : + printf %s "(cached) " >&6 +else $as_nop + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +printf %s "checking for $LD option to reload object files... " >&6; } +if test ${lt_cv_ld_reload_flag+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_ld_reload_flag='-r' +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +printf "%s\n" "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test yes != "$GCC"; then + reload_cmds=false + fi + ;; + darwin*) + if test yes = "$GCC"; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}file", so it can be a program name with args. +set dummy ${ac_tool_prefix}file; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_FILECMD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$FILECMD"; then + ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_FILECMD="${ac_tool_prefix}file" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +FILECMD=$ac_cv_prog_FILECMD +if test -n "$FILECMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 +printf "%s\n" "$FILECMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_FILECMD"; then + ac_ct_FILECMD=$FILECMD + # Extract the first word of "file", so it can be a program name with args. +set dummy file; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_FILECMD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_FILECMD"; then + ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_FILECMD="file" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_FILECMD=$ac_cv_prog_ac_ct_FILECMD +if test -n "$ac_ct_FILECMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 +printf "%s\n" "$ac_ct_FILECMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_FILECMD" = x; then + FILECMD=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + FILECMD=$ac_ct_FILECMD + fi +else + FILECMD="$ac_cv_prog_FILECMD" +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_OBJDUMP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +printf "%s\n" "$OBJDUMP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_OBJDUMP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +printf "%s\n" "$ac_ct_OBJDUMP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +printf %s "checking how to recognize dependent libraries... " >&6; } +if test ${lt_cv_deplibs_check_method+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='$FILECMD -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly* | midnightbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=$FILECMD + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=$FILECMD + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=$FILECMD + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +printf "%s\n" "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DLLTOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +printf "%s\n" "$DLLTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DLLTOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +printf "%s\n" "$ac_ct_DLLTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +printf %s "checking how to associate runtime and link libraries... " >&6; } +if test ${lt_cv_sharedlib_from_linklib_cmd+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf "%s\n" "$AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +printf "%s\n" "$ac_ct_AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} + + + + + + +# Use ARFLAGS variable as AR's operation code to sync the variable naming with +# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have +# higher priority because thats what people were doing historically (setting +# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS +# variable obsoleted/removed. + +test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} +lt_ar_flags=$AR_FLAGS + + + + + + +# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override +# by AR_FLAGS because that was never working and AR_FLAGS is about to die. + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +printf %s "checking for archiver @FILE support... " >&6; } +if test ${lt_cv_ar_at_file+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +printf "%s\n" "$lt_cv_ar_at_file" >&6; } + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +printf "%s\n" "$STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +printf "%s\n" "$ac_ct_STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf "%s\n" "$RANLIB" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf "%s\n" "$ac_ct_RANLIB" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +printf %s "checking command to parse $NM output from $compiler object... " >&6; } +if test ${lt_cv_sys_global_symbol_pipe+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++ or ICC, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 + if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +printf "%s\n" "failed" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +printf "%s\n" "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +printf %s "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test ${with_sysroot+y} +then : + withval=$with_sysroot; +else $as_nop + with_sysroot=no +fi + + +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 +printf "%s\n" "$with_sysroot" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +printf "%s\n" "${lt_sysroot:-no}" >&6; } + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 +printf %s "checking for a working dd... " >&6; } +if test ${ac_cv_path_lt_DD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +if test -z "$lt_DD"; then + ac_path_lt_DD_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in dd + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_lt_DD" || continue +if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi + $ac_path_lt_DD_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_lt_DD"; then + : + fi +else + ac_cv_path_lt_DD=$lt_DD +fi + +rm -f conftest.i conftest2.i conftest.out +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 +printf "%s\n" "$ac_cv_path_lt_DD" >&6; } + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 +printf %s "checking how to truncate binary pipes... " >&6; } +if test ${lt_cv_truncate_bin+y} +then : + printf %s "(cached) " >&6 +else $as_nop + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 +printf "%s\n" "$lt_cv_truncate_bin" >&6; } + + + + + + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + +# Check whether --enable-libtool-lock was given. +if test ${enable_libtool_lock+y} +then : + enableval=$enable_libtool_lock; +fi + +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `$FILECMD conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + emul=elf + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `$FILECMD conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `$FILECMD conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +printf %s "checking whether the C compiler needs -belf... " >&6; } +if test ${lt_cv_cc_needs_belf+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + lt_cv_cc_needs_belf=yes +else $as_nop + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `$FILECMD conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_MANIFEST_TOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +printf "%s\n" "$MANIFEST_TOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if test ${lt_cv_path_mainfest_tool+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DSYMUTIL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +printf "%s\n" "$DSYMUTIL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_NMEDIT+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +printf "%s\n" "$NMEDIT" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_NMEDIT+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +printf "%s\n" "$ac_ct_NMEDIT" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LIPO+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +printf "%s\n" "$LIPO" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_LIPO+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +printf "%s\n" "$ac_ct_LIPO" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_OTOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +printf "%s\n" "$OTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_OTOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +printf "%s\n" "$ac_ct_OTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_OTOOL64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +printf "%s\n" "$OTOOL64" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_OTOOL64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +printf "%s\n" "$ac_ct_OTOOL64" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +printf %s "checking for -single_module linker flag... " >&6; } +if test ${lt_cv_apple_cc_single_mod+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +printf %s "checking for -exported_symbols_list linker flag... " >&6; } +if test ${lt_cv_ld_exported_symbols_list+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + lt_cv_ld_exported_symbols_list=yes +else $as_nop + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +printf %s "checking for -force_load linker flag... " >&6; } +if test ${lt_cv_ld_force_load+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 + $AR $AR_FLAGS libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +printf "%s\n" "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) + case $MACOSX_DEPLOYMENT_TARGET,$host in + 10.[012],*|,*powerpc*-darwin[5-8]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + *) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + +ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes +then : + printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h + +fi + +# ------------------------------------ # +# Determine libtool default behavior # +# ------------------------------------ # + +# +# Default behavior is to enable shared and static libraries on systems +# where libtool knows how to build both library versions, and does not +# require separate configuration and build runs for each flavor. +# + +xc_lt_want_enable_shared='yes' +xc_lt_want_enable_static='yes' + +# +# User may have disabled shared or static libraries. +# +case "x$enable_shared" in # ( + xno) + xc_lt_want_enable_shared='no' + ;; +esac +case "x$enable_static" in # ( + xno) + xc_lt_want_enable_static='no' + ;; +esac +if test "x$xc_lt_want_enable_shared" = 'xno' && + test "x$xc_lt_want_enable_static" = 'xno'; then + as_fn_error $? "can not disable shared and static libraries simultaneously" "$LINENO" 5 +fi + +# +# Default behavior on systems that require independent configuration +# and build runs for shared and static is to enable shared libraries +# and disable static ones. On these systems option '--disable-shared' +# must be used in order to build a proper static library. +# + +if test "x$xc_lt_want_enable_shared" = 'xyes' && + test "x$xc_lt_want_enable_static" = 'xyes'; then + case $host_os in # ( + pw32* | cegcc* | os2* | aix*) + xc_lt_want_enable_static='no' + ;; + esac +fi + +# +# Make libtool aware of current shared and static library preferences +# taking in account that, depending on host characteristics, libtool +# may modify these option preferences later in this configure script. +# + +enable_shared=$xc_lt_want_enable_shared +enable_static=$xc_lt_want_enable_static + +# +# Default behavior is to build PIC objects for shared libraries and +# non-PIC objects for static libraries. +# + +xc_lt_want_with_pic='default' + +# +# User may have specified PIC preference. +# + +case "x$with_pic" in # (( + xno) + xc_lt_want_with_pic='no' + ;; + xyes) + xc_lt_want_with_pic='yes' + ;; +esac + +# +# Default behavior on some systems where building a shared library out +# of non-PIC compiled objects will fail with following linker error +# "relocation R_X86_64_32 can not be used when making a shared object" +# is to build PIC objects even for static libraries. This behavior may +# be overridden using 'configure --disable-shared --without-pic'. +# + +if test "x$xc_lt_want_with_pic" = 'xdefault'; then + case $host_cpu in # ( + x86_64 | amd64 | ia64) + case $host_os in # ( + linux* | freebsd* | midnightbsd*) + xc_lt_want_with_pic='yes' + ;; + esac + ;; + esac +fi + +# +# Make libtool aware of current PIC preference taking in account that, +# depending on host characteristics, libtool may modify PIC default +# behavior to fit host system idiosyncrasies later in this script. +# + +with_pic=$xc_lt_want_with_pic + +## ----------------------- ## +## Start of libtool code ## +## ----------------------- ## + + + + +# Set options +enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AS+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_AS="${ac_tool_prefix}as" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AS=$ac_cv_prog_AS +if test -n "$AS"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 +printf "%s\n" "$AS" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AS"; then + ac_ct_AS=$AS + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_AS+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_AS"; then + ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AS="as" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AS=$ac_cv_prog_ac_ct_AS +if test -n "$ac_ct_AS"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 +printf "%s\n" "$ac_ct_AS" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_AS" = x; then + AS="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AS=$ac_ct_AS + fi +else + AS="$ac_cv_prog_AS" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DLLTOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +printf "%s\n" "$DLLTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DLLTOOL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +printf "%s\n" "$ac_ct_DLLTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_OBJDUMP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +printf "%s\n" "$OBJDUMP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_OBJDUMP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +printf "%s\n" "$ac_ct_OBJDUMP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + + ;; +esac + +test -z "$AS" && AS=as + + + + + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + enable_dlopen=no + + + + # Check whether --enable-shared was given. +if test ${enable_shared+y} +then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else $as_nop + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test ${enable_static+y} +then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else $as_nop + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test ${with_pic+y} +then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else $as_nop + pic_mode=default +fi + + + + + + + + + # Check whether --enable-fast-install was given. +if test ${enable_fast_install+y} +then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else $as_nop + enable_fast_install=yes +fi + + + + + + + + + shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[5-9]*,yes) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 +printf %s "checking which variant of shared library versioning to provide... " >&6; } + +# Check whether --with-aix-soname was given. +if test ${with_aix_soname+y} +then : + withval=$with_aix_soname; case $withval in + aix|svr4|both) + ;; + *) + as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname +else $as_nop + if test ${lt_cv_with_aix_soname+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_with_aix_soname=aix +fi + + with_aix_soname=$lt_cv_with_aix_soname +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 +printf "%s\n" "$with_aix_soname" >&6; } + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +printf %s "checking for objdir... " >&6; } +if test ${lt_cv_objdir+y} +then : + printf %s "(cached) " >&6 +else $as_nop + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +printf "%s\n" "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC and +# ICC, which need '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +printf %s "checking for ${ac_tool_prefix}file... " >&6; } +if test ${lt_cv_path_MAGIC_CMD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/${ac_tool_prefix}file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +printf "%s\n" "$MAGIC_CMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +printf %s "checking for file... " >&6; } +if test ${lt_cv_path_MAGIC_CMD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +printf "%s\n" "$MAGIC_CMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC=$CC +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test ${lt_cv_prog_compiler_rtti_exceptions+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test yes = "$GCC"; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # flang / f18. f95 an alias for gfortran or flang on Debian + flang* | f18* | f95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +printf %s "checking for $compiler option to produce PIC... " >&6; } +if test ${lt_cv_prog_compiler_pic+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test ${lt_cv_prog_compiler_pic_works+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_pic_works"; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test ${lt_cv_prog_compiler_static_works+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_prog_compiler_static_works=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_static_works"; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test ${lt_cv_prog_compiler_c_o+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test ${lt_cv_prog_compiler_c_o+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +printf %s "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +printf "%s\n" "$hard_links" >&6; } + if test no = "$hard_links"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +printf "%s\n" "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + export_dynamic_flag_spec='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='$wl--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + file_list_spec='@' + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + export_dynamic_flag_spec='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test no = "$ld_shlibs"; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct=no + hardcode_direct_absolute=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + export_dynamic_flag_spec='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if test ${lt_cv_aix_libpath_+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if test ${lt_cv_aix_libpath_+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' $wl-bernotok' + allow_undefined_flag=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl* | icl*) + # Native MSVC or ICC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC and ICC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly* | midnightbsd*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test yes = "$GCC"; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +printf %s "checking if $CC understands -b... " >&6; } +if test ${lt_cv_prog_compiler__b+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_prog_compiler__b=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } + +if test yes = "$lt_cv_prog_compiler__b"; then + archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if test ${lt_cv_irix_exported_symbol+y} +then : + printf %s "(cached) " >&6 +else $as_nop + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + lt_cv_irix_exported_symbol=yes +else $as_nop + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + link_all_deplibs=no + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + ld_shlibs=yes + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + else + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + file_list_spec='@' + ;; + + osf3*) + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='$wl-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='$wl-z,text' + allow_undefined_flag='$wl-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='$wl-Blargedynsym' + ;; + esac + fi + fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +printf "%s\n" "$ld_shlibs" >&6; } +test no = "$ld_shlibs" && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +printf %s "checking whether -lc should be explicitly linked in... " >&6; } +if test ${lt_cv_archive_cmds_need_lc+y} +then : + printf %s "(cached) " >&6 +else $as_nop + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +printf %s "checking dynamic linker characteristics... " >&6; } + +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([A-Za-z]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + + + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl* | *,icl*) + # Native MSVC or ICC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC and ICC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly* | midnightbsd*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if test ${lt_cv_shlibpath_overrides_runpath+y} +then : + printf %s "(cached) " >&6 +else $as_nop + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null +then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +printf "%s\n" "$dynamic_linker" >&6; } +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +printf %s "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test yes = "$hardcode_automatic"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && + test no != "$hardcode_minus_L"; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +printf "%s\n" "$hardcode_action" >&6; } + +if test relink = "$hardcode_action" || + test yes = "$inherit_rpath"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +printf %s "checking for dlopen in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlopen+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int main (void) +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dl_dlopen=yes +else $as_nop + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes +then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else $as_nop + + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes +then : + lt_cv_dlopen=shl_load +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +printf %s "checking for shl_load in -ldld... " >&6; } +if test ${ac_cv_lib_dld_shl_load+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int main (void) +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dld_shl_load=yes +else $as_nop + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes +then : + lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld +else $as_nop + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes +then : + lt_cv_dlopen=dlopen +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +printf %s "checking for dlopen in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlopen+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int main (void) +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dl_dlopen=yes +else $as_nop + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes +then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +printf %s "checking for dlopen in -lsvld... " >&6; } +if test ${ac_cv_lib_svld_dlopen+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int main (void) +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_svld_dlopen=yes +else $as_nop + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes +then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +printf %s "checking for dld_link in -ldld... " >&6; } +if test ${ac_cv_lib_dld_dld_link+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int main (void) +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dld_dld_link=yes +else $as_nop + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +printf "%s\n" "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes +then : + lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +printf %s "checking whether a program can dlopen itself... " >&6; } +if test ${lt_cv_dlopen_self+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +printf "%s\n" "$lt_cv_dlopen_self" >&6; } + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +printf %s "checking whether a statically linked program can dlopen itself... " >&6; } +if test ${lt_cv_dlopen_self_static+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +printf "%s\n" "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +printf %s "checking whether stripping libraries is possible... " >&6; } +if test -z "$STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +else + if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + case $host_os in + darwin*) + # FIXME - insert some real tests, host_os isn't really good enough + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + freebsd*) + if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + esac + fi +fi + + + + + + + + + + + + + # Report what library types will actually be built + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +printf %s "checking if libtool supports shared libraries... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +printf "%s\n" "$can_build_shared" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +printf %s "checking whether to build shared libraries... " >&6; } + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +printf "%s\n" "$enable_shared" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +printf %s "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +printf "%s\n" "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + +## --------------------- ## +## End of libtool code ## +## --------------------- ## + +# +# Verify if finally libtool shared libraries will be built +# + +case "x$enable_shared" in # (( + xyes | xno) + xc_lt_build_shared=$enable_shared + ;; + *) + as_fn_error $? "unexpected libtool enable_shared value: $enable_shared" "$LINENO" 5 + ;; +esac + +# +# Verify if finally libtool static libraries will be built +# + +case "x$enable_static" in # (( + xyes | xno) + xc_lt_build_static=$enable_static + ;; + *) + as_fn_error $? "unexpected libtool enable_static value: $enable_static" "$LINENO" 5 + ;; +esac + +# +# Verify if libtool shared libraries should be linked using flag -version-info +# + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries with -version-info" >&5 +printf %s "checking whether to build shared libraries with -version-info... " >&6; } +xc_lt_shlib_use_version_info='yes' +if test "x$version_type" = 'xnone'; then + xc_lt_shlib_use_version_info='no' +fi +case $host_os in # ( + amigaos*) + xc_lt_shlib_use_version_info='yes' + ;; +esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_lt_shlib_use_version_info" >&5 +printf "%s\n" "$xc_lt_shlib_use_version_info" >&6; } + +# +# Verify if libtool shared libraries should be linked using flag -no-undefined +# + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries with -no-undefined" >&5 +printf %s "checking whether to build shared libraries with -no-undefined... " >&6; } +xc_lt_shlib_use_no_undefined='no' +if test "x$allow_undefined" = 'xno'; then + xc_lt_shlib_use_no_undefined='yes' +elif test "x$allow_undefined_flag" = 'xunsupported'; then + xc_lt_shlib_use_no_undefined='yes' +fi +case $host_os in # ( + cygwin* | mingw* | pw32* | cegcc* | os2* | aix*) + xc_lt_shlib_use_no_undefined='yes' + ;; +esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_lt_shlib_use_no_undefined" >&5 +printf "%s\n" "$xc_lt_shlib_use_no_undefined" >&6; } + +# +# Verify if libtool shared libraries should be linked using flag -mimpure-text +# + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries with -mimpure-text" >&5 +printf %s "checking whether to build shared libraries with -mimpure-text... " >&6; } +xc_lt_shlib_use_mimpure_text='no' +case $host_os in # ( + solaris2*) + if test "x$GCC" = 'xyes'; then + xc_lt_shlib_use_mimpure_text='yes' + fi + ;; +esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_lt_shlib_use_mimpure_text" >&5 +printf "%s\n" "$xc_lt_shlib_use_mimpure_text" >&6; } + +# +# Find out whether libtool libraries would be built with PIC +# + +case "x$pic_mode" in # (((( + xdefault) + xc_lt_build_shared_with_pic='yes' + xc_lt_build_static_with_pic='no' + ;; + xyes) + xc_lt_build_shared_with_pic='yes' + xc_lt_build_static_with_pic='yes' + ;; + xno) + xc_lt_build_shared_with_pic='no' + xc_lt_build_static_with_pic='no' + ;; + *) + xc_lt_build_shared_with_pic='unknown' + xc_lt_build_static_with_pic='unknown' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unexpected libtool pic_mode value: $pic_mode" >&5 +printf "%s\n" "$as_me: WARNING: unexpected libtool pic_mode value: $pic_mode" >&2;} + ;; +esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries with PIC" >&5 +printf %s "checking whether to build shared libraries with PIC... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_lt_build_shared_with_pic" >&5 +printf "%s\n" "$xc_lt_build_shared_with_pic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries with PIC" >&5 +printf %s "checking whether to build static libraries with PIC... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_lt_build_static_with_pic" >&5 +printf "%s\n" "$xc_lt_build_static_with_pic" >&6; } + +# +# Verify if libtool shared libraries will be built while static not built +# + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries only" >&5 +printf %s "checking whether to build shared libraries only... " >&6; } +if test "$xc_lt_build_shared" = 'yes' && + test "$xc_lt_build_static" = 'no'; then + xc_lt_build_shared_only='yes' +else + xc_lt_build_shared_only='no' +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_lt_build_shared_only" >&5 +printf "%s\n" "$xc_lt_build_shared_only" >&6; } + +# +# Verify if libtool static libraries will be built while shared not built +# + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries only" >&5 +printf %s "checking whether to build static libraries only... " >&6; } +if test "$xc_lt_build_static" = 'yes' && + test "$xc_lt_build_shared" = 'no'; then + xc_lt_build_static_only='yes' +else + xc_lt_build_static_only='no' +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xc_lt_build_static_only" >&5 +printf "%s\n" "$xc_lt_build_static_only" >&6; } + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. +set dummy ${ac_tool_prefix}windres; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$RC"; then + ac_cv_prog_RC="$RC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_RC="${ac_tool_prefix}windres" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RC=$ac_cv_prog_RC +if test -n "$RC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RC" >&5 +printf "%s\n" "$RC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RC"; then + ac_ct_RC=$RC + # Extract the first word of "windres", so it can be a program name with args. +set dummy windres; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_RC"; then + ac_cv_prog_ac_ct_RC="$ac_ct_RC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RC="windres" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RC=$ac_cv_prog_ac_ct_RC +if test -n "$ac_ct_RC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RC" >&5 +printf "%s\n" "$ac_ct_RC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_RC" = x; then + RC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RC=$ac_ct_RC + fi +else + RC="$ac_cv_prog_RC" +fi + + + + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +objext_RC=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code=$lt_simple_compile_test_code + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +compiler_RC=$CC +func_cc_basename $compiler +cc_basename=$func_cc_basename_result + +lt_cv_prog_compiler_c_o_RC=yes + +if test -n "$compiler"; then + : + + + +fi + +GCC=$lt_save_GCC +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS + + +# +# Automake conditionals based on libtool related checks +# + + if test "x$xc_lt_shlib_use_version_info" = 'xyes'; then + CURL_LT_SHLIB_USE_VERSION_INFO_TRUE= + CURL_LT_SHLIB_USE_VERSION_INFO_FALSE='#' +else + CURL_LT_SHLIB_USE_VERSION_INFO_TRUE='#' + CURL_LT_SHLIB_USE_VERSION_INFO_FALSE= +fi + + if test "x$xc_lt_shlib_use_no_undefined" = 'xyes'; then + CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE= + CURL_LT_SHLIB_USE_NO_UNDEFINED_FALSE='#' +else + CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE='#' + CURL_LT_SHLIB_USE_NO_UNDEFINED_FALSE= +fi + + if test "x$xc_lt_shlib_use_mimpure_text" = 'xyes'; then + CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE= + CURL_LT_SHLIB_USE_MIMPURE_TEXT_FALSE='#' +else + CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE='#' + CURL_LT_SHLIB_USE_MIMPURE_TEXT_FALSE= +fi + + +# +# Due to libtool and automake machinery limitations of not allowing +# specifying separate CPPFLAGS or CFLAGS when compiling objects for +# inclusion of these in shared or static libraries, we are forced to +# build using separate configure runs for shared and static libraries +# on systems where different CPPFLAGS or CFLAGS are mandatory in order +# to compile objects for each kind of library. Notice that relying on +# the '-DPIC' CFLAG that libtool provides is not valid given that the +# user might for example choose to build static libraries with PIC. +# + +# +# Make our Makefile.am files use the staticlib CPPFLAG only when strictly +# targeting a static library and not building its shared counterpart. +# + + if test "x$xc_lt_build_static_only" = 'xyes'; then + USE_CPPFLAG_CURL_STATICLIB_TRUE= + USE_CPPFLAG_CURL_STATICLIB_FALSE='#' +else + USE_CPPFLAG_CURL_STATICLIB_TRUE='#' + USE_CPPFLAG_CURL_STATICLIB_FALSE= +fi + + +# +# Make staticlib CPPFLAG variable and its definition visible in output +# files unconditionally, providing an empty definition unless strictly +# targeting a static library and not building its shared counterpart. +# + +CPPFLAG_CURL_STATICLIB= +if test "x$xc_lt_build_static_only" = 'xyes'; then + CPPFLAG_CURL_STATICLIB='-DCURL_STATICLIB' +fi + + + +# Determine whether all dependent libraries must be specified when linking +if test "X$enable_shared" = "Xyes" -a "X$link_all_deplibs" = "Xno" +then + REQUIRE_LIB_DEPS=no +else + REQUIRE_LIB_DEPS=yes +fi + + if test x$REQUIRE_LIB_DEPS = xyes; then + USE_EXPLICIT_LIB_DEPS_TRUE= + USE_EXPLICIT_LIB_DEPS_FALSE='#' +else + USE_EXPLICIT_LIB_DEPS_TRUE='#' + USE_EXPLICIT_LIB_DEPS_FALSE= +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +printf %s "checking for inline... " >&6; } +if test ${ac_cv_c_inline+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo (void) {return 0; } +$ac_kw foo_t foo (void) {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +printf "%s\n" "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if cpp -P is needed" >&5 +printf %s "checking if cpp -P is needed... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +TEST EINVAL TEST + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "TEST.*TEST" >/dev/null 2>&1 +then : + cpp=no +else $as_nop + cpp=yes +fi +rm -rf conftest* + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cpp" >&5 +printf "%s\n" "$cpp" >&6; } + + if test "x$cpp" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if cpp -P works" >&5 +printf %s "checking if cpp -P works... " >&6; } + OLDCPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -P" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +TEST EINVAL TEST + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "TEST.*TEST" >/dev/null 2>&1 +then : + cpp_p=yes +else $as_nop + cpp_p=no +fi +rm -rf conftest* + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cpp_p" >&5 +printf "%s\n" "$cpp_p" >&6; } + + if test "x$cpp_p" = "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: failed to figure out cpp -P alternative" >&5 +printf "%s\n" "$as_me: WARNING: failed to figure out cpp -P alternative" >&2;} + # without -P + CPPPFLAG="" + else + # with -P + CPPPFLAG="-P" + fi + CPPFLAGS=$OLDCPPFLAGS + else + # without -P + CPPPFLAG="" + fi + + + # + compiler_id="unknown" + compiler_num="0" + # + flags_dbg_yes="unknown" + flags_opt_all="unknown" + flags_opt_yes="unknown" + flags_opt_off="unknown" + # + flags_prefer_cppflags="no" + # + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is DEC/Compaq/HP C" >&5 +printf %s "checking if compiler is DEC/Compaq/HP C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __DECC +CURL_DEF_TOKEN __DECC +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__DECC"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___DECC=no + + else + curl_cv_have_def___DECC=yes + curl_cv_def___DECC=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __DECC_VER +CURL_DEF_TOKEN __DECC_VER +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__DECC_VER"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___DECC_VER=no + + else + curl_cv_have_def___DECC_VER=yes + curl_cv_def___DECC_VER=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___DECC" = "yes" && + test "$curl_cv_have_def___DECC_VER" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="DEC_C" + flags_dbg_yes="-g2" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4" + flags_opt_yes="-O1" + flags_opt_off="-O0" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is HP-UX C" >&5 +printf %s "checking if compiler is HP-UX C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __HP_cc +CURL_DEF_TOKEN __HP_cc +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__HP_cc"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___HP_cc=no + + else + curl_cv_have_def___HP_cc=yes + curl_cv_def___HP_cc=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___HP_cc" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="HP_UX_C" + flags_dbg_yes="-g" + flags_opt_all="-O +O0 +O1 +O2 +O3 +O4" + flags_opt_yes="+O2" + flags_opt_off="+O0" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is IBM C" >&5 +printf %s "checking if compiler is IBM C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __IBMC__ +CURL_DEF_TOKEN __IBMC__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__IBMC__"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___IBMC__=no + + else + curl_cv_have_def___IBMC__=yes + curl_cv_def___IBMC__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___IBMC__" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="IBM_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4 -O5" + flags_opt_all="$flags_opt_all -qnooptimize" + flags_opt_all="$flags_opt_all -qoptimize=0" + flags_opt_all="$flags_opt_all -qoptimize=1" + flags_opt_all="$flags_opt_all -qoptimize=2" + flags_opt_all="$flags_opt_all -qoptimize=3" + flags_opt_all="$flags_opt_all -qoptimize=4" + flags_opt_all="$flags_opt_all -qoptimize=5" + flags_opt_yes="-O2" + flags_opt_off="-qnooptimize" + flags_prefer_cppflags="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is Intel C" >&5 +printf %s "checking if compiler is Intel C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __INTEL_COMPILER +CURL_DEF_TOKEN __INTEL_COMPILER +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__INTEL_COMPILER"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___INTEL_COMPILER=no + + else + curl_cv_have_def___INTEL_COMPILER=yes + curl_cv_def___INTEL_COMPILER=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___INTEL_COMPILER" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking compiler version" >&5 +printf %s "checking compiler version... " >&6; } + compiler_num="$curl_cv_def___INTEL_COMPILER" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Intel C '$compiler_num'" >&5 +printf "%s\n" "Intel C '$compiler_num'" >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __unix__ +CURL_DEF_TOKEN __unix__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = ""; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___unix__=no + + else + curl_cv_have_def___unix__=yes + curl_cv_def___unix__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___unix__" = "yes"; then + compiler_id="INTEL_UNIX_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + compiler_id="INTEL_WINDOWS_C" + flags_dbg_yes="/Zi /Oy-" + flags_opt_all="/O /O0 /O1 /O2 /O3 /Od /Og /Og- /Oi /Oi-" + flags_opt_yes="/O2" + flags_opt_off="/Od" + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is clang" >&5 +printf %s "checking if compiler is clang... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __clang__ +CURL_DEF_TOKEN __clang__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__clang__"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___clang__=no + + else + curl_cv_have_def___clang__=yes + curl_cv_def___clang__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___clang__" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is xlclang" >&5 +printf %s "checking if compiler is xlclang... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __ibmxl__ +CURL_DEF_TOKEN __ibmxl__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__ibmxl__"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___ibmxl__=no + + else + curl_cv_have_def___ibmxl__=yes + curl_cv_def___ibmxl__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___ibmxl__" = "yes" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="XLCLANG" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + compiler_id="CLANG" + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking compiler version" >&5 +printf %s "checking compiler version... " >&6; } + fullclangver=`$CC -v 2>&1 | grep version` + if echo $fullclangver | grep 'Apple' >/dev/null; then + appleclang=1 + else + appleclang=0 + fi + clangver=`echo $fullclangver | grep "based on LLVM " | "$SED" 's/.*(based on LLVM \([0-9]*\.[0-9]*\).*)/\1/'` + if test -z "$clangver"; then + clangver=`echo $fullclangver | "$SED" 's/.*version \([0-9]*\.[0-9]*\).*/\1/'` + oldapple=0 + else + oldapple=1 + fi + clangvhi=`echo $clangver | cut -d . -f1` + clangvlo=`echo $clangver | cut -d . -f2` + compiler_num=`(expr $clangvhi "*" 100 + $clangvlo) 2>/dev/null` + if test "$appleclang" = '1' && test "$oldapple" = '0'; then + if test "$compiler_num" -ge '1300'; then compiler_num='1200' + elif test "$compiler_num" -ge '1205'; then compiler_num='1101' + elif test "$compiler_num" -ge '1204'; then compiler_num='1000' + elif test "$compiler_num" -ge '1107'; then compiler_num='900' + elif test "$compiler_num" -ge '1103'; then compiler_num='800' + elif test "$compiler_num" -ge '1003'; then compiler_num='700' + elif test "$compiler_num" -ge '1001'; then compiler_num='600' + elif test "$compiler_num" -ge '904'; then compiler_num='500' + elif test "$compiler_num" -ge '902'; then compiler_num='400' + elif test "$compiler_num" -ge '803'; then compiler_num='309' + elif test "$compiler_num" -ge '703'; then compiler_num='308' + else compiler_num='307' + fi + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: clang '$compiler_num' (raw: '$fullclangver' / '$clangver')" >&5 +printf "%s\n" "clang '$compiler_num' (raw: '$fullclangver' / '$clangver')" >&6; } + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -Os -O3 -O4" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is GNU C" >&5 +printf %s "checking if compiler is GNU C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __GNUC__ +CURL_DEF_TOKEN __GNUC__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__GNUC__"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___GNUC__=no + + else + curl_cv_have_def___GNUC__=yes + curl_cv_def___GNUC__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___GNUC__" = "yes" && + test "$compiler_id" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="GNU_C" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking compiler version" >&5 +printf %s "checking compiler version... " >&6; } + # strip '-suffix' parts, e.g. Ubuntu Windows cross-gcc returns '10-win32' + gccver=`$CC -dumpversion | sed -E 's/-.+$//'` + gccvhi=`echo $gccver | cut -d . -f1` + if echo $gccver | grep -F '.' >/dev/null; then + gccvlo=`echo $gccver | cut -d . -f2` + else + gccvlo="0" + fi + compiler_num=`(expr $gccvhi "*" 100 + $gccvlo) 2>/dev/null` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: gcc '$compiler_num' (raw: '$gccver')" >&5 +printf "%s\n" "gcc '$compiler_num' (raw: '$gccver')" >&6; } + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os -Og -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is SGI MIPSpro C" >&5 +printf %s "checking if compiler is SGI MIPSpro C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __GNUC__ +CURL_DEF_TOKEN __GNUC__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__GNUC__"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___GNUC__=no + + else + curl_cv_have_def___GNUC__=yes + curl_cv_def___GNUC__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef _COMPILER_VERSION +CURL_DEF_TOKEN _COMPILER_VERSION +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "_COMPILER_VERSION"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def__COMPILER_VERSION=no + + else + curl_cv_have_def__COMPILER_VERSION=yes + curl_cv_def__COMPILER_VERSION=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef _SGI_COMPILER_VERSION +CURL_DEF_TOKEN _SGI_COMPILER_VERSION +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "_SGI_COMPILER_VERSION"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def__SGI_COMPILER_VERSION=no + + else + curl_cv_have_def__SGI_COMPILER_VERSION=yes + curl_cv_def__SGI_COMPILER_VERSION=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___GNUC__" = "no" && + (test "$curl_cv_have_def__SGI_COMPILER_VERSION" = "yes" || + test "$curl_cv_have_def__COMPILER_VERSION" = "yes"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="SGI_MIPSPRO_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is SGI MIPS C" >&5 +printf %s "checking if compiler is SGI MIPS C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __GNUC__ +CURL_DEF_TOKEN __GNUC__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__GNUC__"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___GNUC__=no + + else + curl_cv_have_def___GNUC__=yes + curl_cv_def___GNUC__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __sgi +CURL_DEF_TOKEN __sgi +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__sgi"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___sgi=no + + else + curl_cv_have_def___sgi=yes + curl_cv_def___sgi=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___GNUC__" = "no" && + test "$curl_cv_have_def___sgi" = "yes" && + test "$compiler_id" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="SGI_MIPS_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is SunPro C" >&5 +printf %s "checking if compiler is SunPro C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __SUNPRO_C +CURL_DEF_TOKEN __SUNPRO_C +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__SUNPRO_C"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___SUNPRO_C=no + + else + curl_cv_have_def___SUNPRO_C=yes + curl_cv_def___SUNPRO_C=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___SUNPRO_C" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="SUNPRO_C" + flags_dbg_yes="-g" + flags_opt_all="-O -xO -xO1 -xO2 -xO3 -xO4 -xO5" + flags_opt_yes="-xO2" + flags_opt_off="" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is Tiny C" >&5 +printf %s "checking if compiler is Tiny C... " >&6; } + + OLDCPPFLAGS=$CPPFLAGS + # CPPPFLAG comes from CURL_CPP_P + CPPFLAGS="$CPPFLAGS $CPPPFLAG" + if test -z "$SED"; then + as_fn_error $? "SED not set. Cannot continue without SED being set." "$LINENO" 5 + fi + if test -z "$GREP"; then + as_fn_error $? "GREP not set. Cannot continue without GREP being set." "$LINENO" 5 + fi + + tmp_exp="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __TINYC__ +CURL_DEF_TOKEN __TINYC__ +#endif + + +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + + tmp_exp=`eval "$ac_cpp conftest.$ac_ext" 2>/dev/null | \ + "$GREP" CURL_DEF_TOKEN 2>/dev/null | \ + "$SED" 's/.*CURL_DEF_TOKEN[ ][ ]*//' 2>/dev/null | \ + "$SED" 's/["][ ]*["]//g' 2>/dev/null` + if test -z "$tmp_exp" || test "$tmp_exp" = "__TINYC__"; then + tmp_exp="" + fi + +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test -z "$tmp_exp"; then + curl_cv_have_def___TINYC__=no + + else + curl_cv_have_def___TINYC__=yes + curl_cv_def___TINYC__=$tmp_exp + + fi + CPPFLAGS=$OLDCPPFLAGS + + if test "$curl_cv_have_def___TINYC__" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + compiler_id="TINY_C" + flags_dbg_yes="-g" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + # + if test "$compiler_id" = "unknown"; then + cat <<_EOF 1>&2 +*** +*** Warning: This configure script does not have information about the +*** compiler you are using, relative to the flags required to enable or +*** disable generation of debug info, optimization options or warnings. +*** +*** Whatever settings are present in CFLAGS will be used for this run. +*** +*** If you wish to help the curl project to better support your compiler +*** you can report this and the required info on the libcurl development +*** mailing list: https://lists.haxx.selistinfo/curl-library/ +*** +_EOF + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build target is a native Windows one" >&5 +printf %s "checking whether build target is a native Windows one... " >&6; } +if test ${curl_cv_native_windows+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#ifdef _WIN32 + int dummy=1; +#else + Not a native Windows build target. +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_native_windows="yes" + +else $as_nop + + curl_cv_native_windows="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_native_windows" >&5 +printf "%s\n" "$curl_cv_native_windows" >&6; } + if test "x$curl_cv_native_windows" = xyes; then + DOING_NATIVE_WINDOWS_TRUE= + DOING_NATIVE_WINDOWS_FALSE='#' +else + DOING_NATIVE_WINDOWS_TRUE='#' + DOING_NATIVE_WINDOWS_FALSE= +fi + + + +squeeze() { + _sqz_result="" + eval _sqz_input=\$$1 + for _sqz_token in $_sqz_input; do + if test -z "$_sqz_result"; then + _sqz_result="$_sqz_token" + else + _sqz_result="$_sqz_result $_sqz_token" + fi + done + eval $1=\$_sqz_result + return 0 +} + + + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CPPFLAGS="$CPPFLAGS" + tmp_save_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="" + tmp_CFLAGS="" + # + case "$compiler_id" in + # + CLANG) + # + tmp_CFLAGS="$tmp_CFLAGS -Qunused-arguments" + ;; + # + DEC_C) + # + tmp_CFLAGS="$tmp_CFLAGS -std1" + tmp_CFLAGS="$tmp_CFLAGS -noansi_alias" + tmp_CFLAGS="$tmp_CFLAGS -warnprotos" + tmp_CFLAGS="$tmp_CFLAGS -msg_fatal toofewargs,toomanyargs" + ;; + # + GNU_C) + # + if test "$compiler_num" -ge "295"; then + tmp_CFLAGS="$tmp_CFLAGS -Werror-implicit-function-declaration" + fi + ;; + # + HP_UX_C) + # + tmp_CFLAGS="$tmp_CFLAGS -z" + tmp_CFLAGS="$tmp_CFLAGS +W 4227,4255" + ;; + # + IBM_C) + # + tmp_CPPFLAGS="$tmp_CPPFLAGS -qthreaded" + tmp_CPPFLAGS="$tmp_CPPFLAGS -qnoansialias" + tmp_CPPFLAGS="$tmp_CPPFLAGS -qhalt=e" + ;; + # + INTEL_UNIX_C) + # + tmp_CFLAGS="$tmp_CFLAGS -std=gnu89" + tmp_CPPFLAGS="$tmp_CPPFLAGS -diag-error 140,147,165,266" + tmp_CPPFLAGS="$tmp_CPPFLAGS -diag-disable 279,981,1025,1469,2259" + ;; + # + INTEL_WINDOWS_C) + # + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SGI_MIPS_C) + # + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SGI_MIPSPRO_C) + # + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SUNPRO_C) + # + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + TINY_C) + # + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + esac + # + squeeze tmp_CPPFLAGS + squeeze tmp_CFLAGS + # + if test ! -z "$tmp_CFLAGS" || test ! -z "$tmp_CPPFLAGS"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts some basic options" >&5 +printf %s "checking if compiler accepts some basic options... " >&6; } + CPPFLAGS="$tmp_save_CPPFLAGS $tmp_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" + squeeze CPPFLAGS + squeeze CFLAGS + + tmp_compiler_works="unknown" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + int i = 1; + return i; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tmp_compiler_works="yes" + +else $as_nop + + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/cc-fail: /' conftest.err >&6 + echo " " >&6 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "$tmp_compiler_works" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + int i = 1; + return i; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_compiler_works="yes" + +else $as_nop + + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/link-fail: /' conftest.err >&6 + echo " " >&6 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + if test "x$cross_compiling" != "xyes" && + test "$tmp_compiler_works" = "yes"; then + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# ifdef __STDC__ +# include +# endif + +int main (void) +{ + + int i = 0; + exit(i); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + tmp_compiler_works="yes" + +else $as_nop + tmp_compiler_works="no" + echo " " >&6 + echo "run-fail: test program exited with status $ac_status" >&6 + echo " " >&6 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# ifdef __STDC__ +# include +# endif + +int main (void) +{ + + int i = 0; + exit(i); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + tmp_compiler_works="yes" + +else $as_nop + tmp_compiler_works="no" + echo " " >&6 + echo "run-fail: test program exited with status $ac_status" >&6 + echo " " >&6 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + if test "$tmp_compiler_works" = "yes"; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS" >&5 +printf "%s\n" "$as_me: compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS" >&6;} + + else + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS" >&5 +printf "%s\n" "$as_me: WARNING: compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS" >&2;} + CPPFLAGS="$tmp_save_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS" + + fi + + fi + # + fi + + + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CFLAGS="$CFLAGS" + tmp_save_CPPFLAGS="$CPPFLAGS" + # + tmp_options="" + tmp_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="$CPPFLAGS" + # + if test "$want_debug" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts debug enabling options" >&5 +printf %s "checking if compiler accepts debug enabling options... " >&6; } + tmp_options="$flags_dbg_yes" + fi + # + if test "$flags_prefer_cppflags" = "yes"; then + CPPFLAGS="$tmp_CPPFLAGS $tmp_options" + CFLAGS="$tmp_CFLAGS" + else + CPPFLAGS="$tmp_CPPFLAGS" + CFLAGS="$tmp_CFLAGS $tmp_options" + fi + squeeze CPPFLAGS + squeeze CFLAGS + fi + + + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CFLAGS="$CFLAGS" + tmp_save_CPPFLAGS="$CPPFLAGS" + # + tmp_options="" + tmp_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="$CPPFLAGS" + honor_optimize_option="yes" + # + # + if test "$want_optimize" = "assume_no" || + test "$want_optimize" = "assume_yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler optimizer assumed setting might be used" >&5 +printf %s "checking if compiler optimizer assumed setting might be used... " >&6; } + + + ac_var_match_word="no" + for word1 in $tmp_CFLAGS; do + for word2 in $flags_opt_all; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "yes"; then + + honor_optimize_option="no" + + + fi + + + + ac_var_match_word="no" + for word1 in $tmp_CPPFLAGS; do + for word2 in $flags_opt_all; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "yes"; then + + honor_optimize_option="no" + + + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $honor_optimize_option" >&5 +printf "%s\n" "$honor_optimize_option" >&6; } + if test "$honor_optimize_option" = "yes"; then + if test "$want_optimize" = "assume_yes"; then + want_optimize="yes" + fi + if test "$want_optimize" = "assume_no"; then + want_optimize="no" + fi + fi + fi + # + if test "$honor_optimize_option" = "yes"; then + + ac_var_stripped="" + for word1 in $tmp_CFLAGS; do + ac_var_strip_word="no" + for word2 in $flags_opt_all; do + if test "$word1" = "$word2"; then + ac_var_strip_word="yes" + fi + done + if test "$ac_var_strip_word" = "no"; then + ac_var_stripped="$ac_var_stripped $word1" + fi + done + tmp_CFLAGS="$ac_var_stripped" + squeeze tmp_CFLAGS + + + ac_var_stripped="" + for word1 in $tmp_CPPFLAGS; do + ac_var_strip_word="no" + for word2 in $flags_opt_all; do + if test "$word1" = "$word2"; then + ac_var_strip_word="yes" + fi + done + if test "$ac_var_strip_word" = "no"; then + ac_var_stripped="$ac_var_stripped $word1" + fi + done + tmp_CPPFLAGS="$ac_var_stripped" + squeeze tmp_CPPFLAGS + + if test "$want_optimize" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts optimizer enabling options" >&5 +printf %s "checking if compiler accepts optimizer enabling options... " >&6; } + tmp_options="$flags_opt_yes" + fi + if test "$want_optimize" = "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts optimizer disabling options" >&5 +printf %s "checking if compiler accepts optimizer disabling options... " >&6; } + tmp_options="$flags_opt_off" + fi + if test "$flags_prefer_cppflags" = "yes"; then + CPPFLAGS="$tmp_CPPFLAGS $tmp_options" + CFLAGS="$tmp_CFLAGS" + else + CPPFLAGS="$tmp_CPPFLAGS" + CFLAGS="$tmp_CFLAGS $tmp_options" + fi + squeeze CPPFLAGS + squeeze CFLAGS + + tmp_compiler_works="unknown" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + int i = 1; + return i; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tmp_compiler_works="yes" + +else $as_nop + + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/cc-fail: /' conftest.err >&6 + echo " " >&6 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "$tmp_compiler_works" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + int i = 1; + return i; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_compiler_works="yes" + +else $as_nop + + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/link-fail: /' conftest.err >&6 + echo " " >&6 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + if test "x$cross_compiling" != "xyes" && + test "$tmp_compiler_works" = "yes"; then + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# ifdef __STDC__ +# include +# endif + +int main (void) +{ + + int i = 0; + exit(i); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + tmp_compiler_works="yes" + +else $as_nop + tmp_compiler_works="no" + echo " " >&6 + echo "run-fail: test program exited with status $ac_status" >&6 + echo " " >&6 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# ifdef __STDC__ +# include +# endif + +int main (void) +{ + + int i = 0; + exit(i); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + tmp_compiler_works="yes" + +else $as_nop + tmp_compiler_works="no" + echo " " >&6 + echo "run-fail: test program exited with status $ac_status" >&6 + echo " " >&6 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + if test "$tmp_compiler_works" = "yes"; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: compiler options added: $tmp_options" >&5 +printf "%s\n" "$as_me: compiler options added: $tmp_options" >&6;} + + else + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: compiler options rejected: $tmp_options" >&5 +printf "%s\n" "$as_me: WARNING: compiler options rejected: $tmp_options" >&2;} + CPPFLAGS="$tmp_save_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS" + + fi + + fi + # + fi + + + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CPPFLAGS="$CPPFLAGS" + tmp_save_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="" + tmp_CFLAGS="" + # + case "$compiler_id" in + # + CLANG) + # + if test "$want_warnings" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -pedantic" + + ac_var_added_warnings="" + for warning in all extra; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in pointer-arith write-strings; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in shadow; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in inline nested-externs; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in missing-declarations; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in missing-prototypes; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wno-long-long" + + ac_var_added_warnings="" + for warning in float-equal; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in sign-compare; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wno-multichar" + + ac_var_added_warnings="" + for warning in undef; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wno-format-nonliteral" + + ac_var_added_warnings="" + for warning in endif-labels strict-prototypes; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in declaration-after-statement; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in cast-align; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wno-system-headers" + + ac_var_added_warnings="" + for warning in shorten-64-to-32; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + # + if test "$compiler_num" -ge "101"; then + + ac_var_added_warnings="" + for warning in unused; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "207"; then + + ac_var_added_warnings="" + for warning in address; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in attributes; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in bad-function-cast; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in conversion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in div-by-zero format-security; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in empty-body; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in missing-field-initializers; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in missing-noreturn; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in old-style-definition; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in redundant-decls; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case + + ac_var_added_warnings="" + for warning in type-limits; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical + + ac_var_added_warnings="" + for warning in unreachable-code unused-parameter; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "208"; then + + ac_var_added_warnings="" + for warning in ignored-qualifiers; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in vla; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "209"; then + + ac_var_added_warnings="" + for warning in sign-conversion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wno-error=sign-conversion" # FIXME + + ac_var_added_warnings="" + for warning in shift-sign-overflow; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs + fi + # + if test "$compiler_num" -ge "300"; then + + ac_var_added_warnings="" + for warning in language-extension-token; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wformat=2" + fi + # + if test "$compiler_num" -ge "302"; then + + ac_var_added_warnings="" + for warning in enum-conversion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in sometimes-uninitialized; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + case $host_os in + cygwin* | mingw*) + ;; + *) + + ac_var_added_warnings="" + for warning in missing-variable-declarations; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + ;; + esac + fi + # + if test "$compiler_num" -ge "304"; then + + ac_var_added_warnings="" + for warning in header-guard; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in unused-const-variable; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "305"; then + + ac_var_added_warnings="" + for warning in pragmas; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in unreachable-code-break; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "306"; then + + ac_var_added_warnings="" + for warning in double-promotion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "309"; then + + ac_var_added_warnings="" + for warning in comma; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + # avoid the varargs warning, fixed in 4.0 + # https://bugs.llvm.org/show_bug.cgi?id=29140 + if test "$compiler_num" -lt "400"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-varargs" + fi + fi + if test "$compiler_num" -ge "700"; then + + ac_var_added_warnings="" + for warning in assign-enum; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in extra-semi-stmt; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + if test "$compiler_num" -ge "1000"; then + tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough" # we have silencing markup for clang 10.0 and above only + fi + fi + tmp_CFLAGS="$tmp_CFLAGS -Wno-pointer-bool-conversion" + ;; + # + DEC_C) + # + if test "$want_warnings" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -msg_enable level3" + fi + ;; + # + GNU_C) + # + if test "$want_warnings" = "yes"; then + # + if test "x$cross_compiling" != "xyes" || + test "$compiler_num" -ge "300"; then + tmp_CFLAGS="$tmp_CFLAGS -pedantic" + fi + # + + ac_var_added_warnings="" + for warning in all; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -W" + # + if test "$compiler_num" -ge "104"; then + + ac_var_added_warnings="" + for warning in pointer-arith write-strings; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + if test "x$cross_compiling" != "xyes" || + test "$compiler_num" -ge "300"; then + + ac_var_added_warnings="" + for warning in unused shadow; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + fi + # + if test "$compiler_num" -ge "207"; then + + ac_var_added_warnings="" + for warning in inline nested-externs; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + if test "x$cross_compiling" != "xyes" || + test "$compiler_num" -ge "300"; then + + ac_var_added_warnings="" + for warning in missing-declarations; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in missing-prototypes; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + fi + # + if test "$compiler_num" -ge "295"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-long-long" + + ac_var_added_warnings="" + for warning in bad-function-cast; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "296"; then + + ac_var_added_warnings="" + for warning in float-equal; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wno-multichar" + + ac_var_added_warnings="" + for warning in sign-compare; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in undef; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "297"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-format-nonliteral" + fi + # + if test "$compiler_num" -ge "300"; then + tmp_CFLAGS="$tmp_CFLAGS" + fi + # + if test "$compiler_num" -ge "303"; then + + ac_var_added_warnings="" + for warning in endif-labels strict-prototypes; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "304"; then + + ac_var_added_warnings="" + for warning in declaration-after-statement; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in old-style-definition; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "400"; then + tmp_CFLAGS="$tmp_CFLAGS -Wstrict-aliasing=3" + fi + # + if test "$compiler_num" -ge "401"; then + + ac_var_added_warnings="" + for warning in attributes; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in div-by-zero format-security; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in missing-field-initializers; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + case $host in + *-*-msys*) + ;; + *) + + ac_var_added_warnings="" + for warning in missing-noreturn; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + # Seen to clash with libtool-generated stub code + ;; + esac + + ac_var_added_warnings="" + for warning in unreachable-code unused-parameter; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs + + ac_var_added_warnings="" + for warning in pragmas; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in redundant-decls; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical + fi + # + if test "$compiler_num" -ge "402"; then + + ac_var_added_warnings="" + for warning in cast-align; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "403"; then + + ac_var_added_warnings="" + for warning in address; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in type-limits old-style-declaration; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in missing-parameter-type empty-body; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in clobbered ignored-qualifiers; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in conversion trampolines; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in sign-conversion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wno-error=sign-conversion" # FIXME + + ac_var_added_warnings="" + for warning in vla; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -ftree-vrp" + fi + # + if test "$compiler_num" -ge "405"; then + if test "$curl_cv_native_windows" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-pedantic-ms-format" + fi + fi + # + if test "$compiler_num" -ge "406"; then + + ac_var_added_warnings="" + for warning in double-promotion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "408"; then + tmp_CFLAGS="$tmp_CFLAGS -Wformat=2" + fi + # + if test "$compiler_num" -ge "500"; then + tmp_CFLAGS="$tmp_CFLAGS -Warray-bounds=2" + fi + # + if test "$compiler_num" -ge "600"; then + + ac_var_added_warnings="" + for warning in shift-negative-value; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wshift-overflow=2" + + ac_var_added_warnings="" + for warning in null-dereference; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -fdelete-null-pointer-checks" + + ac_var_added_warnings="" + for warning in duplicated-cond; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in unused-const-variable; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + if test "$compiler_num" -ge "700"; then + + ac_var_added_warnings="" + for warning in duplicated-branches; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in restrict; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in alloc-zero; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + tmp_CFLAGS="$tmp_CFLAGS -Wformat-overflow=2" + tmp_CFLAGS="$tmp_CFLAGS -Wformat-truncation=2" + tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough" + fi + # + if test "$compiler_num" -ge "1000"; then + + ac_var_added_warnings="" + for warning in arith-conversion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in enum-conversion; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + # + fi + # + if test "$compiler_num" -ge "300"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-system-headers" + else + if test "x$cross_compiling" = "xyes"; then + if test "$compiler_num" -ge "104"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-unused -Wno-shadow" + fi + if test "$compiler_num" -ge "207"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-missing-declarations" + tmp_CFLAGS="$tmp_CFLAGS -Wno-missing-prototypes" + fi + fi + fi + ;; + # + HP_UX_C) + # + if test "$want_warnings" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS +w1" + fi + ;; + # + IBM_C) + # + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + INTEL_UNIX_C) + # + if test "$want_warnings" = "yes"; then + if test "$compiler_num" -gt "600"; then + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wall -w2" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wcheck" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wcomment" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wdeprecated" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wmissing-prototypes" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wp64" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wpointer-arith" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wreturn-type" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wshadow" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wuninitialized" + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wunused-function" + fi + fi + tmp_CFLAGS="$tmp_CFLAGS -fno-omit-frame-pointer" + tmp_CFLAGS="$tmp_CFLAGS -fno-strict-aliasing" + tmp_CFLAGS="$tmp_CFLAGS -fp-model precise" + ;; + # + INTEL_WINDOWS_C) + # + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SGI_MIPS_C) + # + if test "$want_warnings" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -fullwarn" + fi + ;; + # + SGI_MIPSPRO_C) + # + if test "$want_warnings" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -fullwarn" + tmp_CFLAGS="$tmp_CFLAGS -woff 1209" + fi + ;; + # + SUNPRO_C) + # + if test "$want_warnings" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -v" + fi + ;; + # + TINY_C) + # + if test "$want_warnings" = "yes"; then + + ac_var_added_warnings="" + for warning in all; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in write-strings; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + + ac_var_added_warnings="" + for warning in unsupported; do + + ac_var_match_word="no" + for word1 in $CFLAGS; do + for word2 in -Wno-$warning -W$warning; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done + + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + tmp_CFLAGS="$tmp_CFLAGS $ac_var_added_warnings" + squeeze tmp_CFLAGS + + fi + ;; + # + esac + # + squeeze tmp_CPPFLAGS + squeeze tmp_CFLAGS + # + if test ! -z "$tmp_CFLAGS" || test ! -z "$tmp_CPPFLAGS"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts strict warning options" >&5 +printf %s "checking if compiler accepts strict warning options... " >&6; } + CPPFLAGS="$tmp_save_CPPFLAGS $tmp_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" + squeeze CPPFLAGS + squeeze CFLAGS + + tmp_compiler_works="unknown" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + int i = 1; + return i; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tmp_compiler_works="yes" + +else $as_nop + + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/cc-fail: /' conftest.err >&6 + echo " " >&6 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "$tmp_compiler_works" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + int i = 1; + return i; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_compiler_works="yes" + +else $as_nop + + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/link-fail: /' conftest.err >&6 + echo " " >&6 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + if test "x$cross_compiling" != "xyes" && + test "$tmp_compiler_works" = "yes"; then + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# ifdef __STDC__ +# include +# endif + +int main (void) +{ + + int i = 0; + exit(i); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + tmp_compiler_works="yes" + +else $as_nop + tmp_compiler_works="no" + echo " " >&6 + echo "run-fail: test program exited with status $ac_status" >&6 + echo " " >&6 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# ifdef __STDC__ +# include +# endif + +int main (void) +{ + + int i = 0; + exit(i); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + tmp_compiler_works="yes" + +else $as_nop + tmp_compiler_works="no" + echo " " >&6 + echo "run-fail: test program exited with status $ac_status" >&6 + echo " " >&6 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + if test "$tmp_compiler_works" = "yes"; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS" >&5 +printf "%s\n" "$as_me: compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS" >&6;} + + else + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS" >&5 +printf "%s\n" "$as_me: WARNING: compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS" >&2;} + CPPFLAGS="$tmp_save_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS" + + fi + + fi + # + fi + + +if test "$compiler_id" = "INTEL_UNIX_C"; then + # + if test "$compiler_num" -ge "1000"; then + CFLAGS="$CFLAGS -shared-intel" + elif test "$compiler_num" -ge "900"; then + CFLAGS="$CFLAGS -i-dynamic" + fi + # +fi + +CURL_CFLAG_EXTRAS="" +if test X"$want_werror" = Xyes; then + CURL_CFLAG_EXTRAS="-Werror" + if test "$compiler_id" = "GNU_C"; then + if test "$compiler_num" -ge "500"; then + CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors" + fi + fi +fi + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler halts on compilation errors" >&5 +printf %s "checking if compiler halts on compilation errors... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + force compilation error + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + as_fn_error $? "compiler does not halt on compilation errors." "$LINENO" 5 + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler halts on negative sized arrays" >&5 +printf %s "checking if compiler halts on negative sized arrays... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + typedef char bad_t[sizeof(char) == sizeof(int) ? -1 : -1 ]; + +int main (void) +{ + + bad_t dummy; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + as_fn_error $? "compiler does not halt on negative sized arrays." "$LINENO" 5 + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler halts on function prototype mismatch" >&5 +printf %s "checking if compiler halts on function prototype mismatch... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# include + int rand(int n); + int rand(int n) + { + if(n) + return ++n; + else + return n; + } + +int main (void) +{ + + int i[2]={0,0}; + int j = rand(i[0]); + if(j) + return j; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + as_fn_error $? "compiler does not halt on function prototype mismatch." "$LINENO" 5 + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports hiding library internal symbols" >&5 +printf %s "checking if compiler supports hiding library internal symbols... " >&6; } + supports_symbol_hiding="no" + symbol_hiding_CFLAGS="" + symbol_hiding_EXTERN="" + tmp_CFLAGS="" + tmp_EXTERN="" + case "$compiler_id" in + CLANG) + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" + ;; + GNU_C) + if test "$compiler_num" -ge "304"; then + if $CC --help --verbose 2>/dev/null | grep fvisibility= >/dev/null ; then + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" + fi + fi + ;; + INTEL_UNIX_C) + if test "$compiler_num" -ge "900"; then + if $CC --help --verbose 2>&1 | grep fvisibility= > /dev/null ; then + tmp_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +# include + +int main (void) +{ + + printf("icc fvisibility bug test"); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$tmp_save_CFLAGS" + fi + fi + ;; + SUNPRO_C) + if $CC 2>&1 | grep flags >/dev/null && $CC -flags | grep xldscope= >/dev/null ; then + tmp_EXTERN="__global" + tmp_CFLAGS="-xldscope=hidden" + supports_symbol_hiding="yes" + fi + ;; + esac + if test "$supports_symbol_hiding" = "yes"; then + tmp_save_CFLAGS="$CFLAGS" + CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" + squeeze CFLAGS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $tmp_EXTERN char *dummy(char *buff); + char *dummy(char *buff) + { + if(buff) + return ++buff; + else + return buff; + } + +int main (void) +{ + + char b[16]; + char *r = dummy(&b[0]); + if(r) + return (int)*r; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + supports_symbol_hiding="yes" + if test -f conftest.err; then + grep 'visibility' conftest.err >/dev/null + if test "$?" -eq "0"; then + supports_symbol_hiding="no" + fi + fi + +else $as_nop + + supports_symbol_hiding="no" + echo " " >&6 + sed 's/^/cc-src: /' conftest.$ac_ext >&6 + sed 's/^/cc-err: /' conftest.err >&6 + echo " " >&6 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS="$tmp_save_CFLAGS" + fi + if test "$supports_symbol_hiding" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + symbol_hiding_CFLAGS="$tmp_CFLAGS" + symbol_hiding_EXTERN="$tmp_EXTERN" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + + + supports_curldebug="unknown" + if test "$want_curldebug" = "yes"; then + if test "x$enable_shared" != "xno" && + test "x$enable_shared" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unknown enable_shared setting." >&5 +printf "%s\n" "$as_me: WARNING: unknown enable_shared setting." >&2;} + supports_curldebug="no" + fi + if test "x$enable_static" != "xno" && + test "x$enable_static" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unknown enable_static setting." >&5 +printf "%s\n" "$as_me: WARNING: unknown enable_static setting." >&2;} + supports_curldebug="no" + fi + if test "$supports_curldebug" != "no"; then + if test "$enable_shared" = "yes" && + test "x$xc_lt_shlib_use_no_undefined" = 'xyes'; then + supports_curldebug="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: shared library does not support undefined symbols." >&5 +printf "%s\n" "$as_me: WARNING: shared library does not support undefined symbols." >&2;} + fi + fi + fi + # + if test "$want_curldebug" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if curl debug memory tracking can be enabled" >&5 +printf %s "checking if curl debug memory tracking can be enabled... " >&6; } + test "$supports_curldebug" = "no" || supports_curldebug="yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $supports_curldebug" >&5 +printf "%s\n" "$supports_curldebug" >&6; } + if test "$supports_curldebug" = "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot enable curl debug memory tracking." >&5 +printf "%s\n" "$as_me: WARNING: cannot enable curl debug memory tracking." >&2;} + want_curldebug="no" + fi + fi + + if test x$want_curldebug = xyes; then + CURLDEBUG_TRUE= + CURLDEBUG_FALSE='#' +else + CURLDEBUG_TRUE='#' + CURLDEBUG_FALSE= +fi + + +supports_unittests=yes +# cross-compilation of unit tests static library/programs fails when +# libcurl shared library is built. This might be due to a libtool or +# automake issue. In this case we disable unit tests. +if test "x$cross_compiling" != "xno" && + test "x$enable_shared" != "xno"; then + supports_unittests=no +fi + +# IRIX 6.5.24 gcc 3.3 autobuilds fail unittests library compilation due to +# a problem related with OpenSSL headers and library versions not matching. +# Disable unit tests while time to further investigate this is found. +case $host in + mips-sgi-irix6.5) + if test "$compiler_id" = "GNU_C"; then + supports_unittests=no + fi + ;; +esac + +# All AIX autobuilds fails unit tests linking against unittests library +# due to unittests library being built with no symbols or members. Libtool ? +# Disable unit tests while time to further investigate this is found. +case $host_os in + aix*) + supports_unittests=no + ;; +esac + +if test "x$want_debug" = "xyes" && + test "x$supports_unittests" = "xyes"; then + want_unittests=yes +else + want_unittests=no +fi + if test x$want_unittests = xyes; then + BUILD_UNITTESTS_TRUE= + BUILD_UNITTESTS_FALSE='#' +else + BUILD_UNITTESTS_TRUE='#' + BUILD_UNITTESTS_FALSE= +fi + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build target supports WIN32 file API" >&5 +printf %s "checking whether build target supports WIN32 file API... " >&6; } + curl_win32_file_api="no" + if test "$curl_cv_native_windows" = "yes"; then + if test x"$enable_largefile" != "xno"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#if !defined(_WIN32_WCE) && (defined(__MINGW32__) || defined(_MSC_VER)) + int dummy=1; +#else + WIN32 large file API not supported. +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_win32_file_api="win32_large_files" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + if test "$curl_win32_file_api" = "no"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#if defined(_WIN32_WCE) || defined(__MINGW32__) || defined(_MSC_VER) + int dummy=1; +#else + WIN32 small file API not supported. +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_win32_file_api="win32_small_files" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + fi + case "$curl_win32_file_api" in + win32_large_files) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (large file enabled)" >&5 +printf "%s\n" "yes (large file enabled)" >&6; } + +printf "%s\n" "#define USE_WIN32_LARGE_FILES 1" >>confdefs.h + + USE_WIN32_LARGE_FILES=1 + + ;; + win32_small_files) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (large file disabled)" >&5 +printf "%s\n" "yes (large file disabled)" >&6; } + +printf "%s\n" "#define USE_WIN32_SMALL_FILES 1" >>confdefs.h + + USE_WIN32_SMALL_FILES=1 + + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + esac + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build target supports WIN32 crypto API" >&5 +printf %s "checking whether build target supports WIN32 crypto API... " >&6; } + curl_win32_crypto_api="no" + if test "$curl_cv_native_windows" = "yes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +int main (void) +{ + + HCRYPTPROV hCryptProv; + if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + CryptReleaseContext(hCryptProv, 0); + } + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_win32_crypto_api="yes" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + case "$curl_win32_crypto_api" in + yes) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define USE_WIN32_CRYPTO 1" >>confdefs.h + + USE_WIN32_CRYPTO=1 + + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + esac + + + + + tst_cflags="no" + case $host_os in + darwin*) + tst_cflags="yes" + ;; + esac + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for good-to-use Darwin CFLAGS" >&5 +printf %s "checking for good-to-use Darwin CFLAGS... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tst_cflags" >&5 +printf "%s\n" "$tst_cflags" >&6; }; + + if test "$tst_cflags" = "yes"; then + old_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Werror=partial-availability" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Werror=partial-availability" >&5 +printf %s "checking whether $CC accepts -Werror=partial-availability... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS=$old_CFLAGS +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks" >&5 +printf %s "checking whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks... " >&6; } +case $host_os in + darwin*) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + +#if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) + return 0; +#else +#error Not macOS +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + build_for_macos="yes" + +else $as_nop + + build_for_macos="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "x$build_for_macos" != xno; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + LDFLAGS="$LDFLAGS -framework CoreFoundation -framework CoreServices -framework SystemConfiguration" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +esac + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking to see if the compiler supports __builtin_available()" >&5 +printf %s "checking to see if the compiler supports __builtin_available()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + + if (__builtin_available(macOS 10.8, iOS 5.0, *)) {} + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_BUILTIN_AVAILABLE 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + + if test "$curl_cv_native_windows" = "yes" && test -n "${RC}"; then + HAVE_WINDRES_TRUE= + HAVE_WINDRES_FALSE='#' +else + HAVE_WINDRES_TRUE='#' + HAVE_WINDRES_FALSE= +fi + + +if test "$curl_cv_native_windows" = "yes"; then + if test -z "$HAVE_WINDRES_TRUE"; then : + else + as_fn_error $? "windres not found in PATH. Windows builds require windres. Cannot continue." "$LINENO" 5 +fi +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support http" >&5 +printf %s "checking whether to support http... " >&6; } +# Check whether --enable-http was given. +if test ${enable_http+y} +then : + enableval=$enable_http; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_HTTP 1" >>confdefs.h + + disable_http="yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: disable HTTP disables FTP over proxy and RTSP" >&5 +printf "%s\n" "$as_me: WARNING: disable HTTP disables FTP over proxy and RTSP" >&2;} + CURL_DISABLE_HTTP=1 + + +printf "%s\n" "#define CURL_DISABLE_RTSP 1" >>confdefs.h + + CURL_DISABLE_RTSP=1 + + +printf "%s\n" "#define CURL_DISABLE_ALTSVC 1" >>confdefs.h + + +printf "%s\n" "#define CURL_DISABLE_HSTS 1" >>confdefs.h + + curl_h1_msg="no (--enable-http, --with-hyper)" + curl_altsvc_msg="no"; + curl_hsts_msg="no (--enable-hsts)"; + enable_altsvc="no" + hsts="no" + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support ftp" >&5 +printf %s "checking whether to support ftp... " >&6; } +# Check whether --enable-ftp was given. +if test ${enable_ftp+y} +then : + enableval=$enable_ftp; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_FTP 1" >>confdefs.h + + CURL_DISABLE_FTP=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support file" >&5 +printf %s "checking whether to support file... " >&6; } +# Check whether --enable-file was given. +if test ${enable_file+y} +then : + enableval=$enable_file; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_FILE 1" >>confdefs.h + + CURL_DISABLE_FILE=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support ldap" >&5 +printf %s "checking whether to support ldap... " >&6; } +# Check whether --enable-ldap was given. +if test ${enable_ldap+y} +then : + enableval=$enable_ldap; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_LDAP 1" >>confdefs.h + + CURL_DISABLE_LDAP=1 + + ;; + yes) + ldap_askedfor="yes" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support ldaps" >&5 +printf %s "checking whether to support ldaps... " >&6; } +# Check whether --enable-ldaps was given. +if test ${enable_ldaps+y} +then : + enableval=$enable_ldaps; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_LDAPS 1" >>confdefs.h + + CURL_DISABLE_LDAPS=1 + + ;; + *) if test "x$CURL_DISABLE_LDAP" = "x1" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: LDAP needs to be enabled to support LDAPS" >&5 +printf "%s\n" "LDAP needs to be enabled to support LDAPS" >&6; } + +printf "%s\n" "#define CURL_DISABLE_LDAPS 1" >>confdefs.h + + CURL_DISABLE_LDAPS=1 + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_LDAP_SSL 1" >>confdefs.h + + HAVE_LDAP_SSL=1 + + fi + ;; + esac +else $as_nop + + if test "x$CURL_DISABLE_LDAP" = "x1" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_LDAPS 1" >>confdefs.h + + CURL_DISABLE_LDAPS=1 + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_LDAP_SSL 1" >>confdefs.h + + HAVE_LDAP_SSL=1 + + fi + +fi + + + +OPT_HYPER="no" + + +# Check whether --with-hyper was given. +if test ${with_hyper+y} +then : + withval=$with_hyper; OPT_HYPER=$withval +fi + +case "$OPT_HYPER" in + no) + want_hyper="no" + ;; + yes) + want_hyper="default" + want_hyper_path="" + ;; + *) + want_hyper="yes" + want_hyper_path="$withval" + ;; +esac + +if test X"$want_hyper" != Xno; then + if test "x$disable_http" = "xyes"; then + as_fn_error $? "--with-hyper is not compatible with --disable-http" "$LINENO" 5 + fi + + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hyper options with pkg-config" >&5 +printf %s "checking for hyper options with pkg-config... " >&6; } + itexists=` + if test -n "$want_hyper_path"; then + PKG_CONFIG_LIBDIR="$want_hyper_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists hyper >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_HYPER=` + if test -n "$want_hyper_path"; then + PKG_CONFIG_LIBDIR="$want_hyper_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l hyper` + CPP_HYPER=` + if test -n "$want_hyper_path"; then + PKG_CONFIG_LIBDIR="$want_hyper_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I hyper` + LD_HYPER=` + if test -n "$want_hyper_path"; then + PKG_CONFIG_LIBDIR="$want_hyper_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L hyper` + else + LIB_HYPER="-lhyper -ldl -lpthread -lm" + if test X"$want_hyper" != Xdefault; then + CPP_HYPER=-I"$want_hyper_path/capi/include" + LD_HYPER="-L$want_hyper_path/target/release -L$want_hyper_path/target/debug" + fi + fi + if test -n "$LIB_HYPER"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_HYPER" >&5 +printf "%s\n" "$as_me: -l is $LIB_HYPER" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_HYPER" >&5 +printf "%s\n" "$as_me: -I is $CPP_HYPER" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_HYPER" >&5 +printf "%s\n" "$as_me: -L is $LD_HYPER" >&6;} + + LDFLAGS="$LDFLAGS $LD_HYPER" + CPPFLAGS="$CPPFLAGS $CPP_HYPER" + LIBS="$LIB_HYPER $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_HYPER=`echo $LD_HYPER | $SED -e 's/^-L//' -e 's/ -L/:/g'` + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hyper_io_new in -lhyper" >&5 +printf %s "checking for hyper_io_new in -lhyper... " >&6; } +if test ${ac_cv_lib_hyper_hyper_io_new+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lhyper $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char hyper_io_new (); +int main (void) +{ +return hyper_io_new (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_hyper_hyper_io_new=yes +else $as_nop + ac_cv_lib_hyper_hyper_io_new=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_hyper_hyper_io_new" >&5 +printf "%s\n" "$ac_cv_lib_hyper_hyper_io_new" >&6; } +if test "x$ac_cv_lib_hyper_hyper_io_new" = xyes +then : + + for ac_header in hyper.h +do : + ac_fn_c_check_header_compile "$LINENO" "hyper.h" "ac_cv_header_hyper_h" "$ac_includes_default" +if test "x$ac_cv_header_hyper_h" = xyes +then : + printf "%s\n" "#define HAVE_HYPER_H 1" >>confdefs.h + experimental="$experimental Hyper" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Hyper support is experimental" >&5 +printf "%s\n" "$as_me: Hyper support is experimental" >&6;} + curl_h1_msg="enabled (Hyper)" + HYPER_ENABLED=1 + +printf "%s\n" "#define USE_HYPER 1" >>confdefs.h + + USE_HYPER=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_HYPER" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_HYPER to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_HYPER to CURL_LIBRARY_PATH" >&6;} +fi + +done + +else $as_nop + for d in `echo $DIR_HYPER | $SED -e 's/:/ /'`; do + if test -f "$d/libhyper.a"; then + as_fn_error $? "hyper was found in $d but was probably built with wrong flags. See docs/HYPER.md." "$LINENO" 5 + fi + done + as_fn_error $? "--with-hyper but hyper was not found. See docs/HYPER.md." "$LINENO" 5 + +fi + + fi +fi + +if test X"$want_hyper" != Xno; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Disable RTSP support with hyper" >&5 +printf "%s\n" "$as_me: Disable RTSP support with hyper" >&6;} + +printf "%s\n" "#define CURL_DISABLE_RTSP 1" >>confdefs.h + + CURL_DISABLE_RTSP=1 + +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support rtsp" >&5 +printf %s "checking whether to support rtsp... " >&6; } + # Check whether --enable-rtsp was given. +if test ${enable_rtsp+y} +then : + enableval=$enable_rtsp; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_RTSP 1" >>confdefs.h + + CURL_DISABLE_RTSP=1 + + ;; + *) + if test x$CURL_DISABLE_HTTP = x1 ; then + as_fn_error $? "HTTP support needs to be enabled in order to enable RTSP support!" "$LINENO" 5 + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + curl_rtsp_msg="enabled" + fi + ;; + esac +else $as_nop + if test "x$CURL_DISABLE_HTTP" != "x1"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + curl_rtsp_msg="enabled" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + +fi + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support proxies" >&5 +printf %s "checking whether to support proxies... " >&6; } +# Check whether --enable-proxy was given. +if test ${enable_proxy+y} +then : + enableval=$enable_proxy; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_PROXY 1" >>confdefs.h + + CURL_DISABLE_PROXY=1 + + https_proxy="no" + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support dict" >&5 +printf %s "checking whether to support dict... " >&6; } +# Check whether --enable-dict was given. +if test ${enable_dict+y} +then : + enableval=$enable_dict; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_DICT 1" >>confdefs.h + + CURL_DISABLE_DICT=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support telnet" >&5 +printf %s "checking whether to support telnet... " >&6; } +# Check whether --enable-telnet was given. +if test ${enable_telnet+y} +then : + enableval=$enable_telnet; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_TELNET 1" >>confdefs.h + + CURL_DISABLE_TELNET=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support tftp" >&5 +printf %s "checking whether to support tftp... " >&6; } +# Check whether --enable-tftp was given. +if test ${enable_tftp+y} +then : + enableval=$enable_tftp; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_TFTP 1" >>confdefs.h + + CURL_DISABLE_TFTP=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support pop3" >&5 +printf %s "checking whether to support pop3... " >&6; } +# Check whether --enable-pop3 was given. +if test ${enable_pop3+y} +then : + enableval=$enable_pop3; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_POP3 1" >>confdefs.h + + CURL_DISABLE_POP3=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support imap" >&5 +printf %s "checking whether to support imap... " >&6; } +# Check whether --enable-imap was given. +if test ${enable_imap+y} +then : + enableval=$enable_imap; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_IMAP 1" >>confdefs.h + + CURL_DISABLE_IMAP=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support smb" >&5 +printf %s "checking whether to support smb... " >&6; } +# Check whether --enable-smb was given. +if test ${enable_smb+y} +then : + enableval=$enable_smb; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_SMB 1" >>confdefs.h + + CURL_DISABLE_SMB=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support smtp" >&5 +printf %s "checking whether to support smtp... " >&6; } +# Check whether --enable-smtp was given. +if test ${enable_smtp+y} +then : + enableval=$enable_smtp; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_SMTP 1" >>confdefs.h + + CURL_DISABLE_SMTP=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support gopher" >&5 +printf %s "checking whether to support gopher... " >&6; } +# Check whether --enable-gopher was given. +if test ${enable_gopher+y} +then : + enableval=$enable_gopher; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_GOPHER 1" >>confdefs.h + + CURL_DISABLE_GOPHER=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support mqtt" >&5 +printf %s "checking whether to support mqtt... " >&6; } +# Check whether --enable-mqtt was given. +if test ${enable_mqtt+y} +then : + enableval=$enable_mqtt; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_MQTT 1" >>confdefs.h + + CURL_DISABLE_MQTT=1 + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to provide built-in manual" >&5 +printf %s "checking whether to provide built-in manual... " >&6; } +# Check whether --enable-manual was given. +if test ${enable_manual+y} +then : + enableval=$enable_manual; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + USE_MANUAL="1" + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + USE_MANUAL="1" + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable generation of C code" >&5 +printf %s "checking whether to enable generation of C code... " >&6; } +# Check whether --enable-libcurl_option was given. +if test ${enable_libcurl_option+y} +then : + enableval=$enable_libcurl_option; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_LIBCURL_OPTION 1" >>confdefs.h + + curl_libcurl_msg="no" + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use libgcc" >&5 +printf %s "checking whether to use libgcc... " >&6; } +# Check whether --enable-libgcc was given. +if test ${enable_libgcc+y} +then : + enableval=$enable_libgcc; case "$enableval" in + yes) + LIBS="-lgcc $LIBS" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if X/Open network library is required" >&5 +printf %s "checking if X/Open network library is required... " >&6; } + tst_lib_xnet_required="no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int main (void) +{ +#if defined(__hpux) && defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600) + return 0; +#elif defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED) + return 0; +#else + force compilation error +#endif +} + + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tst_lib_xnet_required="yes" + LIBS="-lxnet $LIBS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tst_lib_xnet_required" >&5 +printf "%s\n" "$tst_lib_xnet_required" >&6; } + + +ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" +if test "x$ac_cv_func_gethostbyname" = xyes +then : + HAVE_GETHOSTBYNAME="1" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +printf %s "checking for gethostbyname in -lnsl... " >&6; } +if test ${ac_cv_lib_nsl_gethostbyname+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int main (void) +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_nsl_gethostbyname=yes +else $as_nop + ac_cv_lib_nsl_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 +printf "%s\n" "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes +then : + HAVE_GETHOSTBYNAME="1" + LIBS="-lnsl $LIBS" + +fi + + +fi + + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lsocket" >&5 +printf %s "checking for gethostbyname in -lsocket... " >&6; } +if test ${ac_cv_lib_socket_gethostbyname+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int main (void) +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_socket_gethostbyname=yes +else $as_nop + ac_cv_lib_socket_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_gethostbyname" >&5 +printf "%s\n" "$ac_cv_lib_socket_gethostbyname" >&6; } +if test "x$ac_cv_lib_socket_gethostbyname" = xyes +then : + HAVE_GETHOSTBYNAME="1" + LIBS="-lsocket $LIBS" + +fi + +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lwatt" >&5 +printf %s "checking for gethostbyname in -lwatt... " >&6; } +if test ${ac_cv_lib_watt_gethostbyname+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lwatt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int main (void) +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_watt_gethostbyname=yes +else $as_nop + ac_cv_lib_watt_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_watt_gethostbyname" >&5 +printf "%s\n" "$ac_cv_lib_watt_gethostbyname" >&6; } +if test "x$ac_cv_lib_watt_gethostbyname" = xyes +then : + HAVE_GETHOSTBYNAME="1" + CPPFLAGS="-I/dev/env/WATT_ROOT/inc" + LDFLAGS="-L/dev/env/WATT_ROOT/lib" + LIBS="-lwatt $LIBS" + +fi + +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname with both nsl and socket libs" >&5 +printf %s "checking for gethostbyname with both nsl and socket libs... " >&6; } + my_ac_save_LIBS=$LIBS + LIBS="-lnsl -lsocket $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + gethostbyname(); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_GETHOSTBYNAME="1" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + LIBS=$my_ac_save_LIBS + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + if test "$curl_cv_native_windows" = "yes"; then + winsock_LIB="-lws2_32" + if test ! -z "$winsock_LIB"; then + my_ac_save_LIBS=$LIBS + LIBS="$winsock_LIB $LIBS" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in $winsock_LIB" >&5 +printf %s "checking for gethostbyname in $winsock_LIB... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +int main (void) +{ + + gethostbyname("localhost"); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_GETHOSTBYNAME="1" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + winsock_LIB="" + LIBS=$my_ac_save_LIBS + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + fi +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname for Minix 3" >&5 +printf %s "checking for gethostbyname for Minix 3... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +/* Older Minix versions may need here instead */ +#include + +int main (void) +{ + + gethostbyname("localhost"); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_GETHOSTBYNAME="1" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname for eCos" >&5 +printf %s "checking for gethostbyname for eCos... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +#include + +int main (void) +{ + + gethostbyname("localhost"); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_GETHOSTBYNAME="1" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" -o "${with_amissl+set}" = set +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname for AmigaOS bsdsocket.library" >&5 +printf %s "checking for gethostbyname for AmigaOS bsdsocket.library... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #define __USE_INLINE__ + #include + #ifdef __amigaos4__ + struct SocketIFace *ISocket = NULL; + #else + struct Library *SocketBase = NULL; + #endif + +int main (void) +{ + + gethostbyname("localhost"); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_GETHOSTBYNAME="1" + HAVE_PROTO_BSDSOCKET_H="1" + +printf "%s\n" "#define HAVE_PROTO_BSDSOCKET_H 1" >>confdefs.h + + HAVE_PROTO_BSDSOCKET_H=1 + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnetwork" >&5 +printf %s "checking for gethostbyname in -lnetwork... " >&6; } +if test ${ac_cv_lib_network_gethostbyname+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnetwork $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int main (void) +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_network_gethostbyname=yes +else $as_nop + ac_cv_lib_network_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_gethostbyname" >&5 +printf "%s\n" "$ac_cv_lib_network_gethostbyname" >&6; } +if test "x$ac_cv_lib_network_gethostbyname" = xyes +then : + HAVE_GETHOSTBYNAME="1" + LIBS="-lnetwork $LIBS" + +fi + +fi + +if test "$HAVE_GETHOSTBYNAME" != "1"; then + as_fn_error $? "couldn't find libraries for gethostbyname()" "$LINENO" 5 +fi + + +curl_includes_winsock2="\ +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif +/* includes end */" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build target is a native Windows one" >&5 +printf %s "checking whether build target is a native Windows one... " >&6; } +if test ${curl_cv_native_windows+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#ifdef _WIN32 + int dummy=1; +#else + Not a native Windows build target. +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_native_windows="yes" + +else $as_nop + + curl_cv_native_windows="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_native_windows" >&5 +printf "%s\n" "$curl_cv_native_windows" >&6; } + if test "x$curl_cv_native_windows" = xyes; then + DOING_NATIVE_WINDOWS_TRUE= + DOING_NATIVE_WINDOWS_FALSE='#' +else + DOING_NATIVE_WINDOWS_TRUE='#' + DOING_NATIVE_WINDOWS_FALSE= +fi + + + + +curl_includes_bsdsocket="\ +/* includes start */ +#if defined(HAVE_PROTO_BSDSOCKET_H) +# define __NO_NET_API +# define __USE_INLINE__ +# include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif +# ifdef __amigaos4__ +struct SocketIFace *ISocket = NULL; +# else +struct Library *SocketBase = NULL; +# endif +# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "proto/bsdsocket.h" "ac_cv_header_proto_bsdsocket_h" "$curl_includes_bsdsocket +" +if test "x$ac_cv_header_proto_bsdsocket_h" = xyes +then : + printf "%s\n" "#define HAVE_PROTO_BSDSOCKET_H 1" >>confdefs.h + +fi + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in libraries" >&5 +printf %s "checking for connect in libraries... " >&6; } + tst_connect_save_LIBS="$LIBS" + tst_connect_need_LIBS="unknown" + for tst_lib in '' '-lsocket' ; do + if test "$tst_connect_need_LIBS" = "unknown"; then + LIBS="$tst_lib $tst_connect_save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + #if !defined(_WIN32) && !defined(HAVE_PROTO_BSDSOCKET_H) + int connect(int, void*, int); + #endif + +int main (void) +{ + + if(0 != connect(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + tst_connect_need_LIBS="$tst_lib" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + done + LIBS="$tst_connect_save_LIBS" + # + case X-"$tst_connect_need_LIBS" in + X-unknown) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cannot find connect" >&5 +printf "%s\n" "cannot find connect" >&6; } + as_fn_error $? "cannot find connect function in libraries." "$LINENO" 5 + ;; + X-) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tst_connect_need_LIBS" >&5 +printf "%s\n" "$tst_connect_need_LIBS" >&6; } + LIBS="$tst_connect_need_LIBS $tst_connect_save_LIBS" + ;; + esac + + +CURL_NETWORK_LIBS=$LIBS + + + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for monotonic clock_gettime" >&5 +printf %s "checking for monotonic clock_gettime... " >&6; } + # + if test "x$dontwant_rt" = "xno" ; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +int main (void) +{ + + struct timespec ts; + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + curl_func_clock_gettime="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_func_clock_gettime="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + + + # + if test "$curl_func_clock_gettime" = "yes"; then + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in libraries" >&5 +printf %s "checking for clock_gettime in libraries... " >&6; } + # + curl_cv_save_LIBS="$LIBS" + curl_cv_gclk_LIBS="unknown" + # + for x_xlibs in '' '-lrt' '-lposix4' ; do + if test "$curl_cv_gclk_LIBS" = "unknown"; then + if test -z "$x_xlibs"; then + LIBS="$curl_cv_save_LIBS" + else + LIBS="$x_xlibs $curl_cv_save_LIBS" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +int main (void) +{ + + struct timespec ts; + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + curl_cv_gclk_LIBS="$x_xlibs" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + done + # + LIBS="$curl_cv_save_LIBS" + # + case X-"$curl_cv_gclk_LIBS" in + X-unknown) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cannot find clock_gettime" >&5 +printf "%s\n" "cannot find clock_gettime" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: HAVE_CLOCK_GETTIME_MONOTONIC will not be defined" >&5 +printf "%s\n" "$as_me: WARNING: HAVE_CLOCK_GETTIME_MONOTONIC will not be defined" >&2;} + curl_func_clock_gettime="no" + ;; + X-) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no additional lib required" >&5 +printf "%s\n" "no additional lib required" >&6; } + curl_func_clock_gettime="yes" + ;; + *) + if test -z "$curl_cv_save_LIBS"; then + LIBS="$curl_cv_gclk_LIBS" + else + LIBS="$curl_cv_gclk_LIBS $curl_cv_save_LIBS" + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_gclk_LIBS" >&5 +printf "%s\n" "$curl_cv_gclk_LIBS" >&6; } + curl_func_clock_gettime="yes" + ;; + esac + # + if test "x$cross_compiling" != "xyes" && + test "$curl_func_clock_gettime" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if monotonic clock_gettime works" >&5 +printf %s "checking if monotonic clock_gettime works... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +int main (void) +{ + + struct timespec ts; + if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) + exit(0); + else + exit(1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: HAVE_CLOCK_GETTIME_MONOTONIC will not be defined" >&5 +printf "%s\n" "$as_me: WARNING: HAVE_CLOCK_GETTIME_MONOTONIC will not be defined" >&2;} + curl_func_clock_gettime="no" + LIBS="$curl_cv_save_LIBS" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +int main (void) +{ + + struct timespec ts; + if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) + exit(0); + else + exit(1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: HAVE_CLOCK_GETTIME_MONOTONIC will not be defined" >&5 +printf "%s\n" "$as_me: WARNING: HAVE_CLOCK_GETTIME_MONOTONIC will not be defined" >&2;} + curl_func_clock_gettime="no" + LIBS="$curl_cv_save_LIBS" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + case "$curl_func_clock_gettime" in + yes) + +printf "%s\n" "#define HAVE_CLOCK_GETTIME_MONOTONIC 1" >>confdefs.h + + ;; + esac + # + fi + # + + + + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for raw monotonic clock_gettime" >&5 +printf %s "checking for raw monotonic clock_gettime... " >&6; } + # + if test "x$dontwant_rt" = "xno" ; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +int main (void) +{ + + struct timespec ts; + (void)clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + + +CURL_NETWORK_AND_TIME_LIBS=$LIBS + + + +clean_CPPFLAGS=$CPPFLAGS +clean_LDFLAGS=$LDFLAGS +clean_LIBS=$LIBS +ZLIB_LIBS="" + +# Check whether --with-zlib was given. +if test ${with_zlib+y} +then : + withval=$with_zlib; OPT_ZLIB="$withval" +fi + + +if test "$OPT_ZLIB" = "no" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: zlib disabled" >&5 +printf "%s\n" "$as_me: WARNING: zlib disabled" >&2;} +else + if test "$OPT_ZLIB" = "yes" ; then + OPT_ZLIB="" + fi + + if test -z "$OPT_ZLIB" ; then + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib options with pkg-config" >&5 +printf %s "checking for zlib options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists zlib >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + ZLIB_LIBS="`$PKGCONFIG --libs-only-l zlib`" + if test -n "$ZLIB_LIBS"; then + LDFLAGS="$LDFLAGS `$PKGCONFIG --libs-only-L zlib`" + else + ZLIB_LIBS="`$PKGCONFIG --libs zlib`" + fi + LIBS="$ZLIB_LIBS $LIBS" + CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags zlib`" + OPT_ZLIB="" + HAVE_LIBZ="1" + fi + + if test -z "$HAVE_LIBZ"; then + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5 +printf %s "checking for inflateEnd in -lz... " >&6; } +if test ${ac_cv_lib_z_inflateEnd+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char inflateEnd (); +int main (void) +{ +return inflateEnd (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_z_inflateEnd=yes +else $as_nop + ac_cv_lib_z_inflateEnd=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5 +printf "%s\n" "$ac_cv_lib_z_inflateEnd" >&6; } +if test "x$ac_cv_lib_z_inflateEnd" = xyes +then : + HAVE_LIBZ="1" + ZLIB_LIBS="-lz" + LIBS="$ZLIB_LIBS $LIBS" +else $as_nop + OPT_ZLIB="/usr/local" +fi + + fi + fi + + if test -n "$OPT_ZLIB"; then + CPPFLAGS="$CPPFLAGS -I$OPT_ZLIB/include" + LDFLAGS="$LDFLAGS -L$OPT_ZLIB/lib$libsuff" + fi + + ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = xyes +then : + + HAVE_ZLIB_H="1" + if test "$HAVE_LIBZ" != "1"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gzread in -lz" >&5 +printf %s "checking for gzread in -lz... " >&6; } +if test ${ac_cv_lib_z_gzread+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gzread (); +int main (void) +{ +return gzread (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_z_gzread=yes +else $as_nop + ac_cv_lib_z_gzread=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 +printf "%s\n" "$ac_cv_lib_z_gzread" >&6; } +if test "x$ac_cv_lib_z_gzread" = xyes +then : + + HAVE_LIBZ="1" + ZLIB_LIBS="-lz" + LIBS="$ZLIB_LIBS $LIBS" + +else $as_nop + CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS +fi + + fi + +else $as_nop + + CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS + +fi + + + if test "$HAVE_LIBZ" = "1" && test "$HAVE_ZLIB_H" != "1" + then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: configure found only the libz lib, not the header file!" >&5 +printf "%s\n" "$as_me: WARNING: configure found only the libz lib, not the header file!" >&2;} + HAVE_LIBZ="" + CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS + LIBS=$clean_LIBS + ZLIB_LIBS="" + elif test "$HAVE_LIBZ" != "1" && test "$HAVE_ZLIB_H" = "1" + then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: configure found only the libz header file, not the lib!" >&5 +printf "%s\n" "$as_me: WARNING: configure found only the libz header file, not the lib!" >&2;} + CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS + LIBS=$clean_LIBS + ZLIB_LIBS="" + elif test "$HAVE_LIBZ" = "1" && test "$HAVE_ZLIB_H" = "1" + then + + +printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h + + LIBS="$ZLIB_LIBS $clean_LIBS" + + AMFIXLIB="1" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: found both libz and libz.h header" >&5 +printf "%s\n" "$as_me: found both libz and libz.h header" >&6;} + curl_zlib_msg="enabled" + fi +fi + + if test x"$AMFIXLIB" = x1; then + HAVE_LIBZ_TRUE= + HAVE_LIBZ_FALSE='#' +else + HAVE_LIBZ_TRUE='#' + HAVE_LIBZ_FALSE= +fi + + + + + +OPT_BROTLI=off + +# Check whether --with-brotli was given. +if test ${with_brotli+y} +then : + withval=$with_brotli; OPT_BROTLI=$withval +fi + + +if test X"$OPT_BROTLI" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_BROTLI" in + yes) + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libbrotlidec options with pkg-config" >&5 +printf %s "checking for libbrotlidec options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libbrotlidec >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_BROTLI=`$PKGCONFIG --libs-only-l libbrotlidec` + LD_BROTLI=`$PKGCONFIG --libs-only-L libbrotlidec` + CPP_BROTLI=`$PKGCONFIG --cflags-only-I libbrotlidec` + version=`$PKGCONFIG --modversion libbrotlidec` + DIR_BROTLI=`echo $LD_BROTLI | $SED -e 's/^-L//'` + fi + + ;; + off) + ;; + *) + PREFIX_BROTLI=$OPT_BROTLI + ;; + esac + + if test -n "$PREFIX_BROTLI"; then + LIB_BROTLI="-lbrotlidec" + LD_BROTLI=-L${PREFIX_BROTLI}/lib$libsuff + CPP_BROTLI=-I${PREFIX_BROTLI}/include + DIR_BROTLI=${PREFIX_BROTLI}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_BROTLI" + CPPFLAGS="$CPPFLAGS $CPP_BROTLI" + LIBS="$LIB_BROTLI $LIBS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BrotliDecoderDecompress in -lbrotlidec" >&5 +printf %s "checking for BrotliDecoderDecompress in -lbrotlidec... " >&6; } +if test ${ac_cv_lib_brotlidec_BrotliDecoderDecompress+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbrotlidec $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char BrotliDecoderDecompress (); +int main (void) +{ +return BrotliDecoderDecompress (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_brotlidec_BrotliDecoderDecompress=yes +else $as_nop + ac_cv_lib_brotlidec_BrotliDecoderDecompress=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_brotlidec_BrotliDecoderDecompress" >&5 +printf "%s\n" "$ac_cv_lib_brotlidec_BrotliDecoderDecompress" >&6; } +if test "x$ac_cv_lib_brotlidec_BrotliDecoderDecompress" = xyes +then : + printf "%s\n" "#define HAVE_LIBBROTLIDEC 1" >>confdefs.h + + LIBS="-lbrotlidec $LIBS" + +fi + + + for ac_header in brotli/decode.h +do : + ac_fn_c_check_header_compile "$LINENO" "brotli/decode.h" "ac_cv_header_brotli_decode_h" "$ac_includes_default" +if test "x$ac_cv_header_brotli_decode_h" = xyes +then : + printf "%s\n" "#define HAVE_BROTLI_DECODE_H 1" >>confdefs.h + curl_brotli_msg="enabled (libbrotlidec)" + HAVE_BROTLI=1 + +printf "%s\n" "#define HAVE_BROTLI 1" >>confdefs.h + + HAVE_BROTLI=1 + + +fi + +done + + if test X"$OPT_BROTLI" != Xoff && + test "$HAVE_BROTLI" != "1"; then + as_fn_error $? "BROTLI libs and/or directories were not found where specified!" "$LINENO" 5 + fi + + if test "$HAVE_BROTLI" = "1"; then + if test -n "$DIR_BROTLI"; then + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_BROTLI" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_BROTLI to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_BROTLI to CURL_LIBRARY_PATH" >&6;} + fi + fi + else + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +fi + + +OPT_ZSTD=off + +# Check whether --with-zstd was given. +if test ${with_zstd+y} +then : + withval=$with_zstd; OPT_ZSTD=$withval +fi + + +if test X"$OPT_ZSTD" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_ZSTD" in + yes) + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libzstd options with pkg-config" >&5 +printf %s "checking for libzstd options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libzstd >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_ZSTD=`$PKGCONFIG --libs-only-l libzstd` + LD_ZSTD=`$PKGCONFIG --libs-only-L libzstd` + CPP_ZSTD=`$PKGCONFIG --cflags-only-I libzstd` + version=`$PKGCONFIG --modversion libzstd` + DIR_ZSTD=`echo $LD_ZSTD | $SED -e 's/-L//'` + fi + + ;; + off) + ;; + *) + PREFIX_ZSTD=$OPT_ZSTD + ;; + esac + + if test -n "$PREFIX_ZSTD"; then + LIB_ZSTD="-lzstd" + LD_ZSTD=-L${PREFIX_ZSTD}/lib$libsuff + CPP_ZSTD=-I${PREFIX_ZSTD}/include + DIR_ZSTD=${PREFIX_ZSTD}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_ZSTD" + CPPFLAGS="$CPPFLAGS $CPP_ZSTD" + LIBS="$LIB_ZSTD $LIBS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ZSTD_createDStream in -lzstd" >&5 +printf %s "checking for ZSTD_createDStream in -lzstd... " >&6; } +if test ${ac_cv_lib_zstd_ZSTD_createDStream+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lzstd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ZSTD_createDStream (); +int main (void) +{ +return ZSTD_createDStream (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_zstd_ZSTD_createDStream=yes +else $as_nop + ac_cv_lib_zstd_ZSTD_createDStream=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_zstd_ZSTD_createDStream" >&5 +printf "%s\n" "$ac_cv_lib_zstd_ZSTD_createDStream" >&6; } +if test "x$ac_cv_lib_zstd_ZSTD_createDStream" = xyes +then : + printf "%s\n" "#define HAVE_LIBZSTD 1" >>confdefs.h + + LIBS="-lzstd $LIBS" + +fi + + + for ac_header in zstd.h +do : + ac_fn_c_check_header_compile "$LINENO" "zstd.h" "ac_cv_header_zstd_h" "$ac_includes_default" +if test "x$ac_cv_header_zstd_h" = xyes +then : + printf "%s\n" "#define HAVE_ZSTD_H 1" >>confdefs.h + curl_zstd_msg="enabled (libzstd)" + HAVE_ZSTD=1 + +printf "%s\n" "#define HAVE_ZSTD 1" >>confdefs.h + + HAVE_ZSTD=1 + + +fi + +done + + if test X"$OPT_ZSTD" != Xoff && + test "$HAVE_ZSTD" != "1"; then + as_fn_error $? "libzstd was not found where specified!" "$LINENO" 5 + fi + + if test "$HAVE_ZSTD" = "1"; then + if test -n "$DIR_ZSTD"; then + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_ZSTD" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_ZSTD to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_ZSTD to CURL_LIBRARY_PATH" >&6;} + fi + fi + else + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +fi + + +LDAPLIBNAME="" + +# Check whether --with-ldap-lib was given. +if test ${with_ldap_lib+y} +then : + withval=$with_ldap_lib; LDAPLIBNAME="$withval" +fi + + +LBERLIBNAME="" + +# Check whether --with-lber-lib was given. +if test ${with_lber_lib+y} +then : + withval=$with_lber_lib; LBERLIBNAME="$withval" +fi + + +if test x$CURL_DISABLE_LDAP != x1 ; then + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lber.h" >&5 +printf %s "checking for lber.h... " >&6; } +if test ${curl_cv_header_lber_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef NULL +#define NULL (void *)0 +#endif +#include + +int main (void) +{ + + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + ber_free(bep, 1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_header_lber_h="yes" + +else $as_nop + + curl_cv_header_lber_h="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_header_lber_h" >&5 +printf "%s\n" "$curl_cv_header_lber_h" >&6; } + if test "$curl_cv_header_lber_h" = "yes"; then + +printf "%s\n" "#define HAVE_LBER_H 1" >>confdefs.h + + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef NULL +#define NULL (void *)0 +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#include + +int main (void) +{ + + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + ber_free(bep, 1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_need_header_lber_h="no" + +else $as_nop + + curl_cv_need_header_lber_h="yes" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # + case "$curl_cv_need_header_lber_h" in + yes) + +printf "%s\n" "#define NEED_LBER_H 1" >>confdefs.h + + ;; + esac + fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ldap.h" >&5 +printf %s "checking for ldap.h... " >&6; } +if test ${curl_cv_header_ldap_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#ifdef NEED_LBER_H +#include +#endif +#include + +int main (void) +{ + + LDAP *ldp = ldap_init("0.0.0.0", LDAP_PORT); + int res = ldap_unbind(ldp); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_header_ldap_h="yes" + +else $as_nop + + curl_cv_header_ldap_h="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_header_ldap_h" >&5 +printf "%s\n" "$curl_cv_header_ldap_h" >&6; } + case "$curl_cv_header_ldap_h" in + yes) + +printf "%s\n" "#define HAVE_LDAP_H 1" >>confdefs.h + + ;; + esac + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ldap_ssl.h" >&5 +printf %s "checking for ldap_ssl.h... " >&6; } +if test ${curl_cv_header_ldap_ssl_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#ifdef NEED_LBER_H +#include +#endif +#ifdef HAVE_LDAP_H +#include +#endif +#include + +int main (void) +{ + + LDAP *ldp = ldapssl_init("0.0.0.0", LDAPS_PORT, 1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_header_ldap_ssl_h="yes" + +else $as_nop + + curl_cv_header_ldap_ssl_h="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_header_ldap_ssl_h" >&5 +printf "%s\n" "$curl_cv_header_ldap_ssl_h" >&6; } + case "$curl_cv_header_ldap_ssl_h" in + yes) + +printf "%s\n" "#define HAVE_LDAP_SSL_H 1" >>confdefs.h + + ;; + esac + + + if test -z "$LDAPLIBNAME" ; then + if test "$curl_cv_native_windows" = "yes"; then + LDAPLIBNAME="wldap32" + LBERLIBNAME="no" + fi + fi + + if test "$LDAPLIBNAME" ; then + as_ac_Lib=`printf "%s\n" "ac_cv_lib_"$LDAPLIBNAME"""_ldap_init" | $as_tr_sh` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ldap_init in -l\"$LDAPLIBNAME\"" >&5 +printf %s "checking for ldap_init in -l\"$LDAPLIBNAME\"... " >&6; } +if eval test \${$as_ac_Lib+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-l"$LDAPLIBNAME" $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ldap_init (); +int main (void) +{ +return ldap_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$as_ac_Lib=yes" +else $as_nop + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_LIB"$LDAPLIBNAME"" | $as_tr_cpp` 1 +_ACEOF + + LIBS="-l"$LDAPLIBNAME" $LIBS" + +else $as_nop + + if test -n "$ldap_askedfor"; then + as_fn_error $? "couldn't detect the LDAP libraries" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"$LDAPLIBNAME\" is not an LDAP library: LDAP disabled" >&5 +printf "%s\n" "$as_me: WARNING: \"$LDAPLIBNAME\" is not an LDAP library: LDAP disabled" >&2;} + +printf "%s\n" "#define CURL_DISABLE_LDAP 1" >>confdefs.h + + CURL_DISABLE_LDAP=1 + + +printf "%s\n" "#define CURL_DISABLE_LDAPS 1" >>confdefs.h + + CURL_DISABLE_LDAPS=1 + +fi + + else + + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LDAP libraries" >&5 +printf %s "checking for LDAP libraries... " >&6; } + # + u_libs="" + # + + # + curl_cv_save_LIBS="$LIBS" + curl_cv_ldap_LIBS="unknown" + # + for x_nlibs in '' "$u_libs" \ + '-lldap' \ + '-lldap -llber' \ + '-llber -lldap' \ + '-lldapssl -lldapx -lldapsdk' \ + '-lldapsdk -lldapx -lldapssl' \ + '-lldap -llber -lssl -lcrypto' ; do + + if test "$curl_cv_ldap_LIBS" = "unknown"; then + if test -z "$x_nlibs"; then + LIBS="$curl_cv_save_LIBS" + else + LIBS="$x_nlibs $curl_cv_save_LIBS" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#endif +#ifndef NULL +#define NULL (void *)0 +#endif +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif +#ifdef NEED_LBER_H +#include +#endif +#ifdef HAVE_LDAP_H +#include +#endif + +int main (void) +{ + + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + LDAP *ldp = ldap_init("0.0.0.0", LDAP_PORT); + int res = ldap_unbind(ldp); + ber_free(bep, 1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + curl_cv_ldap_LIBS="$x_nlibs" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + done + # + LIBS="$curl_cv_save_LIBS" + # + case X-"$curl_cv_ldap_LIBS" in + X-unknown) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cannot find LDAP libraries" >&5 +printf "%s\n" "cannot find LDAP libraries" >&6; } + ;; + X-) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no additional lib required" >&5 +printf "%s\n" "no additional lib required" >&6; } + ;; + *) + if test -z "$curl_cv_save_LIBS"; then + LIBS="$curl_cv_ldap_LIBS" + else + LIBS="$curl_cv_ldap_LIBS $curl_cv_save_LIBS" + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_ldap_LIBS" >&5 +printf "%s\n" "$curl_cv_ldap_LIBS" >&6; } + ;; + esac + # + + case X-"$curl_cv_ldap_LIBS" in + X-unknown) + if test -n "$ldap_askedfor"; then + as_fn_error $? "couldn't detect the LDAP libraries" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find libraries for LDAP support: LDAP disabled" >&5 +printf "%s\n" "$as_me: WARNING: Cannot find libraries for LDAP support: LDAP disabled" >&2;} + +printf "%s\n" "#define CURL_DISABLE_LDAP 1" >>confdefs.h + + CURL_DISABLE_LDAP=1 + + +printf "%s\n" "#define CURL_DISABLE_LDAPS 1" >>confdefs.h + + CURL_DISABLE_LDAPS=1 + + ;; + esac + fi +fi + +if test x$CURL_DISABLE_LDAP != x1 ; then + + if test "$LBERLIBNAME" ; then + if test "$LBERLIBNAME" != "no" ; then + as_ac_Lib=`printf "%s\n" "ac_cv_lib_"$LBERLIBNAME"""_ber_free" | $as_tr_sh` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ber_free in -l\"$LBERLIBNAME\"" >&5 +printf %s "checking for ber_free in -l\"$LBERLIBNAME\"... " >&6; } +if eval test \${$as_ac_Lib+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-l"$LBERLIBNAME" $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ber_free (); +int main (void) +{ +return ber_free (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$as_ac_Lib=yes" +else $as_nop + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_LIB"$LBERLIBNAME"" | $as_tr_cpp` 1 +_ACEOF + + LIBS="-l"$LBERLIBNAME" $LIBS" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"$LBERLIBNAME\" is not an LBER library: LDAP disabled" >&5 +printf "%s\n" "$as_me: WARNING: \"$LBERLIBNAME\" is not an LBER library: LDAP disabled" >&2;} + +printf "%s\n" "#define CURL_DISABLE_LDAP 1" >>confdefs.h + + CURL_DISABLE_LDAP=1 + + +printf "%s\n" "#define CURL_DISABLE_LDAPS 1" >>confdefs.h + + CURL_DISABLE_LDAPS=1 + +fi + + fi + fi +fi + +if test x$CURL_DISABLE_LDAP != x1 ; then + ac_fn_c_check_func "$LINENO" "ldap_url_parse" "ac_cv_func_ldap_url_parse" +if test "x$ac_cv_func_ldap_url_parse" = xyes +then : + printf "%s\n" "#define HAVE_LDAP_URL_PARSE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ldap_init_fd" "ac_cv_func_ldap_init_fd" +if test "x$ac_cv_func_ldap_init_fd" = xyes +then : + printf "%s\n" "#define HAVE_LDAP_INIT_FD 1" >>confdefs.h + +fi + + + if test "$LDAPLIBNAME" = "wldap32"; then + curl_ldap_msg="enabled (winldap)" + +printf "%s\n" "#define USE_WIN32_LDAP 1" >>confdefs.h + + else + if test "x$ac_cv_func_ldap_init_fd" = "xyes"; then + curl_ldap_msg="enabled (OpenLDAP)" + +printf "%s\n" "#define USE_OPENLDAP 1" >>confdefs.h + + USE_OPENLDAP=1 + + else + curl_ldap_msg="enabled (ancient OpenLDAP)" + fi + fi +fi + +if test x$CURL_DISABLE_LDAPS != x1 ; then + curl_ldaps_msg="enabled" +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable IPv6" >&5 +printf %s "checking whether to enable IPv6... " >&6; } +# Check whether --enable-ipv6 was given. +if test ${enable_ipv6+y} +then : + enableval=$enable_ipv6; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ipv6=no + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ipv6=yes + ;; + esac +else $as_nop + if test "$cross_compiling" = yes +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ipv6=yes + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* are AF_INET6 and sockaddr_in6 available? */ +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#if defined (__TANDEM) +# include +#endif +#endif + +int main(void) +{ + struct sockaddr_in6 s; + (void)s; + return socket(AF_INET6, SOCK_STREAM, 0) < 0; +} + + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ipv6=yes +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ipv6=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + + +if test "$ipv6" = yes; then + curl_ipv6_msg="enabled" + +printf "%s\n" "#define ENABLE_IPV6 1" >>confdefs.h + + IPV6_ENABLED=1 + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if struct sockaddr_in6 has sin6_scope_id member" >&5 +printf %s "checking if struct sockaddr_in6 has sin6_scope_id member... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef _WIN32 +#include +#include +#else +#include +#if defined (__TANDEM) +# include +#endif +#endif + +int main (void) +{ + + struct sockaddr_in6 s; + s.sin6_scope_id = 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if argv can be written to" >&5 +printf %s "checking if argv can be written to... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + curl_cv_writable_argv=cross + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main(int argc, char **argv) +{ +#ifdef _WIN32 + /* on Windows, writing to the argv does not hide the argument in + process lists so it can just be skipped */ + (void)argc; + (void)argv; + return 1; +#else + (void)argc; + argv[0][0] = ' '; + return (argv[0][0] == ' ')?0:1; +#endif +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + curl_cv_writable_argv=yes + +else $as_nop + curl_cv_writable_argv=no + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + curl_cv_writable_argv=cross + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main(int argc, char **argv) +{ +#ifdef _WIN32 + /* on Windows, writing to the argv does not hide the argument in + process lists so it can just be skipped */ + (void)argc; + (void)argv; + return 1; +#else + (void)argc; + argv[0][0] = ' '; + return (argv[0][0] == ' ')?0:1; +#endif +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + curl_cv_writable_argv=yes + +else $as_nop + curl_cv_writable_argv=no + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + +case $curl_cv_writable_argv in +yes) + +printf "%s\n" "#define HAVE_WRITABLE_ARGV 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; +no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; +*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: the previous check could not be made default was used" >&5 +printf "%s\n" "$as_me: WARNING: the previous check could not be made default was used" >&2;} + ;; +esac + + + +GSSAPI_ROOT="/usr" + +# Check whether --with-gssapi-includes was given. +if test ${with_gssapi_includes+y} +then : + withval=$with_gssapi_includes; GSSAPI_INCS="-I$withval" + want_gss="yes" + +fi + + + +# Check whether --with-gssapi-libs was given. +if test ${with_gssapi_libs+y} +then : + withval=$with_gssapi_libs; GSSAPI_LIB_DIR="-L$withval" + want_gss="yes" + +fi + + + +# Check whether --with-gssapi was given. +if test ${with_gssapi+y} +then : + withval=$with_gssapi; + GSSAPI_ROOT="$withval" + if test x"$GSSAPI_ROOT" != xno; then + want_gss="yes" + if test x"$GSSAPI_ROOT" = xyes; then + GSSAPI_ROOT="/usr" + fi + fi + +fi + + +: ${KRB5CONFIG:="$GSSAPI_ROOT/bin/krb5-config"} + +save_CPPFLAGS="$CPPFLAGS" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if GSS-API support is requested" >&5 +printf %s "checking if GSS-API support is requested... " >&6; } +if test x"$want_gss" = xyes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + + if test $GSSAPI_ROOT != "/usr"; then + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mit-krb5-gssapi options with pkg-config" >&5 +printf %s "checking for mit-krb5-gssapi options with pkg-config... " >&6; } + itexists=` + if test -n "$GSSAPI_ROOT/lib/pkgconfig"; then + PKG_CONFIG_LIBDIR="$GSSAPI_ROOT/lib/pkgconfig" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists mit-krb5-gssapi >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + else + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mit-krb5-gssapi options with pkg-config" >&5 +printf %s "checking for mit-krb5-gssapi options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists mit-krb5-gssapi >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + fi + if test -z "$GSSAPI_INCS"; then + if test -n "$host_alias" -a -f "$GSSAPI_ROOT/bin/$host_alias-krb5-config"; then + GSSAPI_INCS=`$GSSAPI_ROOT/bin/$host_alias-krb5-config --cflags gssapi` + elif test "$PKGCONFIG" != "no" ; then + GSSAPI_INCS=`$PKGCONFIG --cflags mit-krb5-gssapi` + elif test -f "$KRB5CONFIG"; then + GSSAPI_INCS=`$KRB5CONFIG --cflags gssapi` + elif test "$GSSAPI_ROOT" != "yes"; then + GSSAPI_INCS="-I$GSSAPI_ROOT/include" + fi + fi + + CPPFLAGS="$CPPFLAGS $GSSAPI_INCS" + + ac_fn_c_check_header_compile "$LINENO" "gss.h" "ac_cv_header_gss_h" "$ac_includes_default" +if test "x$ac_cv_header_gss_h" = xyes +then : + + +printf "%s\n" "#define HAVE_GSSGNU 1" >>confdefs.h + + gnu_gss=yes + +else $as_nop + + for ac_header in gssapi/gssapi.h +do : + ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi.h" "ac_cv_header_gssapi_gssapi_h" "$ac_includes_default" +if test "x$ac_cv_header_gssapi_gssapi_h" = xyes +then : + printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_H 1" >>confdefs.h + +else $as_nop + not_mit=1 +fi + +done + for ac_header in gssapi/gssapi_generic.h gssapi/gssapi_krb5.h +do : + as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" " +$ac_includes_default +#ifdef HAVE_GSSAPI_GSSAPI_H +#include +#endif + +" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else $as_nop + not_mit=1 +fi + +done + if test "x$not_mit" = "x1"; then + ac_fn_c_check_header_compile "$LINENO" "gssapi.h" "ac_cv_header_gssapi_h" "$ac_includes_default" +if test "x$ac_cv_header_gssapi_h" = xyes +then : + +else $as_nop + + want_gss=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: disabling GSS-API support since no header files were found" >&5 +printf "%s\n" "$as_me: WARNING: disabling GSS-API support since no header files were found" >&2;} + + +fi + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if GSS-API headers declare GSS_C_NT_HOSTBASED_SERVICE" >&5 +printf %s "checking if GSS-API headers declare GSS_C_NT_HOSTBASED_SERVICE... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +#include +#include + +int main (void) +{ + + gss_import_name( + (OM_uint32 *)0, + (gss_buffer_t)0, + GSS_C_NT_HOSTBASED_SERVICE, + (gss_name_t *)0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define HAVE_OLD_GSSMIT 1" >>confdefs.h + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + + +fi + +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi +if test x"$want_gss" = xyes; then + +printf "%s\n" "#define HAVE_GSSAPI 1" >>confdefs.h + + HAVE_GSSAPI=1 + curl_gss_msg="enabled (MIT Kerberos/Heimdal)" + + if test -n "$gnu_gss"; then + curl_gss_msg="enabled (GNU GSS)" + LDFLAGS="$LDFLAGS $GSSAPI_LIB_DIR" + LIBS="-lgss $LIBS" + elif test -z "$GSSAPI_LIB_DIR"; then + case $host in + *-*-darwin*) + LIBS="-lgssapi_krb5 -lresolv $LIBS" + ;; + *) + if test $GSSAPI_ROOT != "/usr"; then + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mit-krb5-gssapi options with pkg-config" >&5 +printf %s "checking for mit-krb5-gssapi options with pkg-config... " >&6; } + itexists=` + if test -n "$GSSAPI_ROOT/lib/pkgconfig"; then + PKG_CONFIG_LIBDIR="$GSSAPI_ROOT/lib/pkgconfig" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists mit-krb5-gssapi >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + else + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mit-krb5-gssapi options with pkg-config" >&5 +printf %s "checking for mit-krb5-gssapi options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists mit-krb5-gssapi >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + fi + if test -n "$host_alias" -a -f "$GSSAPI_ROOT/bin/$host_alias-krb5-config"; then + gss_libs=`$GSSAPI_ROOT/bin/$host_alias-krb5-config --libs gssapi` + LIBS="$gss_libs $LIBS" + elif test "$PKGCONFIG" != "no" ; then + gss_libs=`$PKGCONFIG --libs mit-krb5-gssapi` + LIBS="$gss_libs $LIBS" + elif test -f "$KRB5CONFIG"; then + gss_libs=`$KRB5CONFIG --libs gssapi` + LIBS="$gss_libs $LIBS" + else + case $host in + *-hp-hpux*) + gss_libname="gss" + ;; + *) + gss_libname="gssapi" + ;; + esac + + if test "$GSSAPI_ROOT" != "yes"; then + LDFLAGS="$LDFLAGS -L$GSSAPI_ROOT/lib$libsuff" + LIBS="-l$gss_libname $LIBS" + else + LIBS="-l$gss_libname $LIBS" + fi + fi + ;; + esac + else + LDFLAGS="$LDFLAGS $GSSAPI_LIB_DIR" + case $host in + *-hp-hpux*) + LIBS="-lgss $LIBS" + ;; + *) + LIBS="-lgssapi $LIBS" + ;; + esac + fi +else + CPPFLAGS="$save_CPPFLAGS" +fi + +if test x"$want_gss" = xyes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can link against GSS-API library" >&5 +printf %s "checking if we can link against GSS-API library... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define gss_init_sec_context innocuous_gss_init_sec_context +#ifdef __STDC__ +# include +#else +# include +#endif +#undef gss_init_sec_context +#ifdef __cplusplus +extern "C" +#endif +char gss_init_sec_context (); +#if defined __stub_gss_init_sec_context || defined __stub___gss_init_sec_context +choke me +#endif + +int main (void) +{ +return gss_init_sec_context (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + as_fn_error $? "--with-gssapi was specified, but a GSS-API library was not found." "$LINENO" 5 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + +build_libstubgss=no +if test x"$want_gss" = "xyes"; then + build_libstubgss=yes +fi + + if test "x$build_libstubgss" = "xyes"; then + BUILD_STUB_GSS_TRUE= + BUILD_STUB_GSS_FALSE='#' +else + BUILD_STUB_GSS_TRUE='#' + BUILD_STUB_GSS_FALSE= +fi + + + +DEFAULT_SSL_BACKEND=no +VALID_DEFAULT_SSL_BACKEND= + +# Check whether --with-default-ssl-backend was given. +if test ${with_default_ssl_backend+y} +then : + withval=$with_default_ssl_backend; DEFAULT_SSL_BACKEND=$withval +fi + +case "$DEFAULT_SSL_BACKEND" in + no) + ;; + default|yes) + as_fn_error $? "The name of the default SSL backend is required." "$LINENO" 5 + ;; + *) + + VALID_DEFAULT_SSL_BACKEND=no + ;; +esac + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable Windows native SSL/TLS" >&5 +printf %s "checking whether to enable Windows native SSL/TLS... " >&6; } +if test "x$OPT_SCHANNEL" != xno; then + ssl_msg= + if test "x$OPT_SCHANNEL" != "xno" && + test "x$curl_cv_native_windows" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define USE_SCHANNEL 1" >>confdefs.h + + USE_SCHANNEL=1 + + ssl_msg="Schannel" + test schannel != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + SCHANNEL_ENABLED=1 + # --with-schannel implies --enable-sspi + +printf "%s\n" "#define USE_WINDOWS_SSPI 1" >>confdefs.h + + USE_WINDOWS_SSPI=1 + + curl_sspi_msg="enabled" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable Secure Transport" >&5 +printf %s "checking whether to enable Secure Transport... " >&6; } +if test "x$OPT_SECURETRANSPORT" != xno; then + if test "x$OPT_SECURETRANSPORT" != "xno" && + (test "x$cross_compiling" != "xno" || test -d "/System/Library/Frameworks/Security.framework"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define USE_SECTRANSP 1" >>confdefs.h + + USE_SECTRANSP=1 + + ssl_msg="Secure Transport" + test secure-transport != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + SECURETRANSPORT_ENABLED=1 + LDFLAGS="$LDFLAGS -framework CoreFoundation -framework CoreServices -framework Security" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable Amiga native SSL/TLS (AmiSSL v5)" >&5 +printf %s "checking whether to enable Amiga native SSL/TLS (AmiSSL v5)... " >&6; } +if test "$HAVE_PROTO_BSDSOCKET_H" = "1"; then + if test "x$OPT_AMISSL" != xno; then + ssl_msg= + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + #include + +int main (void) +{ + + #if defined(AMISSL_CURRENT_VERSION) && defined(AMISSL_V3xx) && \ + (OPENSSL_VERSION_NUMBER >= 0x30000000L) && \ + defined(PROTO_AMISSL_H) + return 0; + #else + #error not AmiSSL v5 / OpenSSL 3 + #endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ssl_msg="AmiSSL" + test amissl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + AMISSL_ENABLED=1 + OPENSSL_ENABLED=1 + # Use AmiSSL's built-in ca bundle + check_for_ca_bundle=1 + with_ca_fallback=yes + LIBS="-lamisslstubs -lamisslauto $LIBS" + +printf "%s\n" "#define USE_AMISSL 1" >>confdefs.h + + +printf "%s\n" "#define USE_OPENSSL 1" >>confdefs.h + + +printf "%s\n" "#define HAVE_OPENSSL3 1" >>confdefs.h + + ac_fn_c_check_header_compile "$LINENO" "openssl/x509.h" "ac_cv_header_openssl_x509_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_x509_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_X509_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "openssl/rsa.h" "ac_cv_header_openssl_rsa_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_rsa_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_RSA_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "openssl/crypto.h" "ac_cv_header_openssl_crypto_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_crypto_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_CRYPTO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "openssl/pem.h" "ac_cv_header_openssl_pem_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_pem_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_PEM_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_ssl_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_SSL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "openssl/err.h" "ac_cv_header_openssl_err_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_err_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_ERR_H 1" >>confdefs.h + +fi + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + +if test "x$OPT_OPENSSL" != xno; then + ssl_msg= + + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case $host in + *-*-msys* | *-*-mingw*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdi32" >&5 +printf %s "checking for gdi32... " >&6; } + my_ac_save_LIBS=$LIBS + LIBS="-lgdi32 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int main (void) +{ + + GdiFlush(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop + LIBS=$my_ac_save_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + ;; + esac + + case "$OPT_OPENSSL" in + yes) + PKGTEST="yes" + PREFIX_OPENSSL= + ;; + *) + PKGTEST="no" + PREFIX_OPENSSL=$OPT_OPENSSL + + OPENSSL_PCDIR="$OPT_OPENSSL/lib/pkgconfig" + if test -f "$OPENSSL_PCDIR/openssl.pc"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: PKG_CONFIG_LIBDIR will be set to \"$OPENSSL_PCDIR\"" >&5 +printf "%s\n" "$as_me: PKG_CONFIG_LIBDIR will be set to \"$OPENSSL_PCDIR\"" >&6;} + PKGTEST="yes" + fi + + if test "$PKGTEST" != "yes"; then + # try lib64 instead + OPENSSL_PCDIR="$OPT_OPENSSL/lib64/pkgconfig" + if test -f "$OPENSSL_PCDIR/openssl.pc"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: PKG_CONFIG_LIBDIR will be set to \"$OPENSSL_PCDIR\"" >&5 +printf "%s\n" "$as_me: PKG_CONFIG_LIBDIR will be set to \"$OPENSSL_PCDIR\"" >&6;} + PKGTEST="yes" + fi + fi + + if test "$PKGTEST" != "yes"; then + if test ! -f "$PREFIX_OPENSSL/include/openssl/ssl.h"; then + as_fn_error $? "$PREFIX_OPENSSL is a bad --with-openssl prefix!" "$LINENO" 5 + fi + fi + + LIB_OPENSSL="$PREFIX_OPENSSL/lib$libsuff" + if test "$PREFIX_OPENSSL" != "/usr" ; then + SSL_LDFLAGS="-L$LIB_OPENSSL" + SSL_CPPFLAGS="-I$PREFIX_OPENSSL/include" + fi + ;; + esac + + if test "$PKGTEST" = "yes"; then + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openssl options with pkg-config" >&5 +printf %s "checking for openssl options with pkg-config... " >&6; } + itexists=` + if test -n "$OPENSSL_PCDIR"; then + PKG_CONFIG_LIBDIR="$OPENSSL_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists openssl >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + SSL_LIBS=` + if test -n "$OPENSSL_PCDIR"; then + PKG_CONFIG_LIBDIR="$OPENSSL_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --libs-only-l --libs-only-other openssl 2>/dev/null` + + SSL_LDFLAGS=` + if test -n "$OPENSSL_PCDIR"; then + PKG_CONFIG_LIBDIR="$OPENSSL_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --libs-only-L openssl 2>/dev/null` + + SSL_CPPFLAGS=` + if test -n "$OPENSSL_PCDIR"; then + PKG_CONFIG_LIBDIR="$OPENSSL_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I openssl 2>/dev/null` + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: SSL_LIBS: \"$SSL_LIBS\"" >&5 +printf "%s\n" "$as_me: pkg-config: SSL_LIBS: \"$SSL_LIBS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: SSL_LDFLAGS: \"$SSL_LDFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: SSL_LDFLAGS: \"$SSL_LDFLAGS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: SSL_CPPFLAGS: \"$SSL_CPPFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: SSL_CPPFLAGS: \"$SSL_CPPFLAGS\"" >&6;} + + LIB_OPENSSL=`echo $SSL_LDFLAGS | sed -e 's/^-L//'` + + LIBS="$SSL_LIBS $LIBS" + fi + fi + + CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS" + LDFLAGS="$LDFLAGS $SSL_LDFLAGS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for HMAC_Update in -lcrypto" >&5 +printf %s "checking for HMAC_Update in -lcrypto... " >&6; } +if test ${ac_cv_lib_crypto_HMAC_Update+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char HMAC_Update (); +int main (void) +{ +return HMAC_Update (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_crypto_HMAC_Update=yes +else $as_nop + ac_cv_lib_crypto_HMAC_Update=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_HMAC_Update" >&5 +printf "%s\n" "$ac_cv_lib_crypto_HMAC_Update" >&6; } +if test "x$ac_cv_lib_crypto_HMAC_Update" = xyes +then : + + HAVECRYPTO="yes" + LIBS="-lcrypto $LIBS" + +else $as_nop + + if test -n "$LIB_OPENSSL" ; then + LDFLAGS="$CLEANLDFLAGS -L$LIB_OPENSSL" + fi + if test "$PKGCONFIG" = "no" -a -n "$PREFIX_OPENSSL" ; then + # only set this if pkg-config wasn't used + CPPFLAGS="$CLEANCPPFLAGS -I$PREFIX_OPENSSL/include" + fi + # Linking previously failed, try extra paths from --with-openssl or + # pkg-config. Use a different function name to avoid reusing the earlier + # cached result. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for HMAC_Init_ex in -lcrypto" >&5 +printf %s "checking for HMAC_Init_ex in -lcrypto... " >&6; } +if test ${ac_cv_lib_crypto_HMAC_Init_ex+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char HMAC_Init_ex (); +int main (void) +{ +return HMAC_Init_ex (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_crypto_HMAC_Init_ex=yes +else $as_nop + ac_cv_lib_crypto_HMAC_Init_ex=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_HMAC_Init_ex" >&5 +printf "%s\n" "$ac_cv_lib_crypto_HMAC_Init_ex" >&6; } +if test "x$ac_cv_lib_crypto_HMAC_Init_ex" = xyes +then : + + HAVECRYPTO="yes" + LIBS="-lcrypto $LIBS" +else $as_nop + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OpenSSL linking with -ldl" >&5 +printf %s "checking OpenSSL linking with -ldl... " >&6; } + LIBS="-lcrypto $CLEANLIBS -ldl" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int main (void) +{ + + ERR_clear_error(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVECRYPTO="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OpenSSL linking with -ldl and -lpthread" >&5 +printf %s "checking OpenSSL linking with -ldl and -lpthread... " >&6; } + LIBS="-lcrypto $CLEANLIBS -ldl -lpthread" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + +int main (void) +{ + + ERR_clear_error(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVECRYPTO="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + LDFLAGS="$CLEANLDFLAGS" + CPPFLAGS="$CLEANCPPFLAGS" + LIBS="$CLEANLIBS" + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + +fi + + +fi + + + if test X"$HAVECRYPTO" = X"yes"; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_connect in -lssl" >&5 +printf %s "checking for SSL_connect in -lssl... " >&6; } +if test ${ac_cv_lib_ssl_SSL_connect+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char SSL_connect (); +int main (void) +{ +return SSL_connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ssl_SSL_connect=yes +else $as_nop + ac_cv_lib_ssl_SSL_connect=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_connect" >&5 +printf "%s\n" "$ac_cv_lib_ssl_SSL_connect" >&6; } +if test "x$ac_cv_lib_ssl_SSL_connect" = xyes +then : + printf "%s\n" "#define HAVE_LIBSSL 1" >>confdefs.h + + LIBS="-lssl $LIBS" + +fi + + + if test "$ac_cv_lib_ssl_SSL_connect" != yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ssl with RSAglue/rsaref libs in use" >&5 +printf %s "checking for ssl with RSAglue/rsaref libs in use... " >&6; }; + OLIBS=$LIBS + LIBS="-lRSAglue -lrsaref $LIBS" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_connect in -lssl" >&5 +printf %s "checking for SSL_connect in -lssl... " >&6; } +if test ${ac_cv_lib_ssl_SSL_connect+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char SSL_connect (); +int main (void) +{ +return SSL_connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ssl_SSL_connect=yes +else $as_nop + ac_cv_lib_ssl_SSL_connect=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_connect" >&5 +printf "%s\n" "$ac_cv_lib_ssl_SSL_connect" >&6; } +if test "x$ac_cv_lib_ssl_SSL_connect" = xyes +then : + printf "%s\n" "#define HAVE_LIBSSL 1" >>confdefs.h + + LIBS="-lssl $LIBS" + +fi + + if test "$ac_cv_lib_ssl_SSL_connect" != yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + LIBS=$OLIBS + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + fi + + else + + for ac_header in openssl/x509.h openssl/rsa.h openssl/crypto.h openssl/pem.h openssl/ssl.h openssl/err.h +do : + as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + ssl_msg="OpenSSL" + test openssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + OPENSSL_ENABLED=1 + +printf "%s\n" "#define USE_OPENSSL 1" >>confdefs.h + +fi + +done + + if test $ac_cv_header_openssl_x509_h = no; then + ac_fn_c_check_header_compile "$LINENO" "x509.h" "ac_cv_header_x509_h" "$ac_includes_default" +if test "x$ac_cv_header_x509_h" = xyes +then : + printf "%s\n" "#define HAVE_X509_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "rsa.h" "ac_cv_header_rsa_h" "$ac_includes_default" +if test "x$ac_cv_header_rsa_h" = xyes +then : + printf "%s\n" "#define HAVE_RSA_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "crypto.h" "ac_cv_header_crypto_h" "$ac_includes_default" +if test "x$ac_cv_header_crypto_h" = xyes +then : + printf "%s\n" "#define HAVE_CRYPTO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "pem.h" "ac_cv_header_pem_h" "$ac_includes_default" +if test "x$ac_cv_header_pem_h" = xyes +then : + printf "%s\n" "#define HAVE_PEM_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "ssl.h" "ac_cv_header_ssl_h" "$ac_includes_default" +if test "x$ac_cv_header_ssl_h" = xyes +then : + printf "%s\n" "#define HAVE_SSL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "err.h" "ac_cv_header_err_h" "$ac_includes_default" +if test "x$ac_cv_header_err_h" = xyes +then : + printf "%s\n" "#define HAVE_ERR_H 1" >>confdefs.h + +fi + + + if test $ac_cv_header_x509_h = yes && + test $ac_cv_header_crypto_h = yes && + test $ac_cv_header_ssl_h = yes; then + ssl_msg="OpenSSL" + OPENSSL_ENABLED=1 + fi + fi + fi + + if test X"$OPENSSL_ENABLED" != X"1"; then + LIBS="$CLEANLIBS" + fi + + if test X"$OPT_OPENSSL" != Xoff && + test "$OPENSSL_ENABLED" != "1"; then + as_fn_error $? "OpenSSL libs and/or directories were not found where specified!" "$LINENO" 5 + fi + fi + + if test X"$OPENSSL_ENABLED" = X"1"; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BoringSSL" >&5 +printf %s "checking for BoringSSL... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + +int main (void) +{ + + #ifndef OPENSSL_IS_BORINGSSL + #error not boringssl + #endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ssl_msg="BoringSSL" + OPENSSL_IS_BORINGSSL=1 + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for AWS-LC" >&5 +printf %s "checking for AWS-LC... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + +int main (void) +{ + + #ifndef OPENSSL_IS_AWSLC + #error not AWS-LC + #endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ssl_msg="AWS-LC" + OPENSSL_IS_BORINGSSL=1 + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libressl" >&5 +printf %s "checking for libressl... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + + int dummy = LIBRESSL_VERSION_NUMBER; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_LIBRESSL 1" >>confdefs.h + + ssl_msg="libressl" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OpenSSL >= v3" >&5 +printf %s "checking for OpenSSL >= v3... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + + #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + return 0; + #else + #error older than 3 + #endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_OPENSSL3 1" >>confdefs.h + + ssl_msg="OpenSSL v3+" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + + + for ac_func in SSL_set_quic_use_legacy_codepoint +do : + ac_fn_c_check_func "$LINENO" "SSL_set_quic_use_legacy_codepoint" "ac_cv_func_SSL_set_quic_use_legacy_codepoint" +if test "x$ac_cv_func_SSL_set_quic_use_legacy_codepoint" = xyes +then : + printf "%s\n" "#define HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT 1" >>confdefs.h + QUIC_ENABLED=yes +fi + +done + if test "$QUIC_ENABLED" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenSSL fork speaks QUIC API" >&5 +printf "%s\n" "$as_me: OpenSSL fork speaks QUIC API" >&6;} + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenSSL version does not speak QUIC API" >&5 +printf "%s\n" "$as_me: OpenSSL version does not speak QUIC API" >&6;} + fi + + if test "$OPENSSL_ENABLED" = "1"; then + if test -n "$LIB_OPENSSL"; then + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_OPENSSL" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $LIB_OPENSSL to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $LIB_OPENSSL to CURL_LIBRARY_PATH" >&6;} + fi + fi + check_for_ca_bundle=1 + fi + + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + +if test X"$OPT_OPENSSL" != Xno && + test "$OPENSSL_ENABLED" != "1"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OPT_OPENSSL: $OPT_OPENSSL" >&5 +printf "%s\n" "$as_me: OPT_OPENSSL: $OPT_OPENSSL" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OPENSSL_ENABLED: $OPENSSL_ENABLED" >&5 +printf "%s\n" "$as_me: OPENSSL_ENABLED: $OPENSSL_ENABLED" >&6;} + as_fn_error $? "--with-openssl was given but OpenSSL could not be detected" "$LINENO" 5 +fi + + +if test X"$OPENSSL_ENABLED" = X"1"; then + +# Check whether --with-random was given. +if test ${with_random+y} +then : + withval=$with_random; RANDOM_FILE="$withval" +else $as_nop + + if test x$cross_compiling != xyes; then + as_ac_File=`printf "%s\n" "ac_cv_file_"/dev/urandom"" | $as_tr_sh` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"/dev/urandom\"" >&5 +printf %s "checking for \"/dev/urandom\"... " >&6; } +if eval test \${$as_ac_File+y} +then : + printf %s "(cached) " >&6 +else $as_nop + test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 +if test -r ""/dev/urandom""; then + eval "$as_ac_File=yes" +else + eval "$as_ac_File=no" +fi +fi +eval ac_res=\$$as_ac_File + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_File"\" = x"yes" +then : + RANDOM_FILE="/dev/urandom" +fi + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: skipped the /dev/urandom detection when cross-compiling" >&5 +printf "%s\n" "$as_me: WARNING: skipped the /dev/urandom detection when cross-compiling" >&2;} + fi + + +fi + + if test -n "$RANDOM_FILE" && test X"$RANDOM_FILE" != Xno ; then + + +printf "%s\n" "#define RANDOM_FILE \"$RANDOM_FILE\"" >>confdefs.h + + fi +fi + +if test "$OPENSSL_ENABLED" = "1"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SRP support in OpenSSL" >&5 +printf %s "checking for SRP support in OpenSSL... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + + SSL_CTX_set_srp_username(NULL, ""); + SSL_CTX_set_srp_password(NULL, ""); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_OPENSSL_SRP 1" >>confdefs.h + + HAVE_OPENSSL_SRP=1 + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + +if test X"$OPENSSL_ENABLED" = X"1"; then +# Check whether --enable-openssl-auto-load-config was given. +if test ${enable_openssl_auto_load_config+y} +then : + enableval=$enable_openssl_auto_load_config; if test X"$enableval" = X"no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: automatic loading of OpenSSL configuration disabled" >&5 +printf "%s\n" "$as_me: automatic loading of OpenSSL configuration disabled" >&6;} + +printf "%s\n" "#define CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1" >>confdefs.h + + fi + +fi + +fi + +if test "$OPENSSL_ENABLED" = "1"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for QUIC support in OpenSSL" >&5 +printf %s "checking for QUIC support in OpenSSL... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main (void) +{ + + OSSL_QUIC_client_method(); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_OPENSSL_QUIC 1" >>confdefs.h + + HAVE_OPENSSL_QUIC=1 + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + + +if test "x$OPT_GNUTLS" != xno; then + ssl_msg= + + if test X"$OPT_GNUTLS" != Xno; then + + addld="" + addlib="" + gtlslib="" + version="" + addcflags="" + + if test "x$OPT_GNUTLS" = "xyes"; then + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnutls options with pkg-config" >&5 +printf %s "checking for gnutls options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists gnutls >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + addlib=`$PKGCONFIG --libs-only-l gnutls` + addld=`$PKGCONFIG --libs-only-L gnutls` + addcflags=`$PKGCONFIG --cflags-only-I gnutls` + version=`$PKGCONFIG --modversion gnutls` + gtlslib=`echo $addld | $SED -e 's/^-L//'` + else + check=`libgnutls-config --version 2>/dev/null` + if test -n "$check"; then + addlib=`libgnutls-config --libs` + addcflags=`libgnutls-config --cflags` + version=`libgnutls-config --version` + gtlslib=`libgnutls-config --prefix`/lib$libsuff + fi + fi + else + cfg=$OPT_GNUTLS/bin/libgnutls-config + check=`$cfg --version 2>/dev/null` + if test -n "$check"; then + addlib=`$cfg --libs` + addcflags=`$cfg --cflags` + version=`$cfg --version` + gtlslib=`$cfg --prefix`/lib$libsuff + else + addlib=-lgnutls + addld=-L$OPT_GNUTLS/lib$libsuff + addcflags=-I$OPT_GNUTLS/include + version="" # we just don't know + gtlslib=$OPT_GNUTLS/lib$libsuff + fi + fi + + if test -z "$version"; then + version="unknown" + fi + + if test -n "$addlib"; then + + CLEANLIBS="$LIBS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLDFLAGS="$LDFLAGS" + + LIBS="$addlib $LIBS" + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnutls_x509_crt_get_dn2 in -lgnutls" >&5 +printf %s "checking for gnutls_x509_crt_get_dn2 in -lgnutls... " >&6; } +if test ${ac_cv_lib_gnutls_gnutls_x509_crt_get_dn2+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnutls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gnutls_x509_crt_get_dn2 (); +int main (void) +{ +return gnutls_x509_crt_get_dn2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_gnutls_gnutls_x509_crt_get_dn2=yes +else $as_nop + ac_cv_lib_gnutls_gnutls_x509_crt_get_dn2=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_x509_crt_get_dn2" >&5 +printf "%s\n" "$ac_cv_lib_gnutls_gnutls_x509_crt_get_dn2" >&6; } +if test "x$ac_cv_lib_gnutls_gnutls_x509_crt_get_dn2" = xyes +then : + + +printf "%s\n" "#define USE_GNUTLS 1" >>confdefs.h + + USE_GNUTLS=1 + + GNUTLS_ENABLED=1 + USE_GNUTLS="yes" + ssl_msg="GnuTLS" + QUIC_ENABLED=yes + test gnutls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +else $as_nop + + LIBS="$CLEANLIBS" + CPPFLAGS="$CLEANCPPFLAGS" + +fi + + + if test "x$USE_GNUTLS" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: detected GnuTLS version $version" >&5 +printf "%s\n" "$as_me: detected GnuTLS version $version" >&6;} + check_for_ca_bundle=1 + if test -n "$gtlslib"; then + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$gtlslib" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $gtlslib to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $gtlslib to CURL_LIBRARY_PATH" >&6;} + fi + fi + fi + + fi + + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + + +if test "$GNUTLS_ENABLED" = "1"; then + USE_GNUTLS_NETTLE= + # First check if we can detect either crypto library via transitive linking + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nettle_MD5Init in -lgnutls" >&5 +printf %s "checking for nettle_MD5Init in -lgnutls... " >&6; } +if test ${ac_cv_lib_gnutls_nettle_MD5Init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnutls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char nettle_MD5Init (); +int main (void) +{ +return nettle_MD5Init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_gnutls_nettle_MD5Init=yes +else $as_nop + ac_cv_lib_gnutls_nettle_MD5Init=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_nettle_MD5Init" >&5 +printf "%s\n" "$ac_cv_lib_gnutls_nettle_MD5Init" >&6; } +if test "x$ac_cv_lib_gnutls_nettle_MD5Init" = xyes +then : + USE_GNUTLS_NETTLE=1 +fi + + + # If not, try linking directly to both of them to see if they are available + if test "$USE_GNUTLS_NETTLE" = ""; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nettle_MD5Init in -lnettle" >&5 +printf %s "checking for nettle_MD5Init in -lnettle... " >&6; } +if test ${ac_cv_lib_nettle_nettle_MD5Init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnettle $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char nettle_MD5Init (); +int main (void) +{ +return nettle_MD5Init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_nettle_nettle_MD5Init=yes +else $as_nop + ac_cv_lib_nettle_nettle_MD5Init=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nettle_nettle_MD5Init" >&5 +printf "%s\n" "$ac_cv_lib_nettle_nettle_MD5Init" >&6; } +if test "x$ac_cv_lib_nettle_nettle_MD5Init" = xyes +then : + USE_GNUTLS_NETTLE=1 +fi + + fi + if test "$USE_GNUTLS_NETTLE" = ""; then + as_fn_error $? "GnuTLS found, but nettle was not found" "$LINENO" 5 + fi + LIBS="-lnettle $LIBS" +fi + +if test "$GNUTLS_ENABLED" = "1"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnutls_srp_verifier in -lgnutls" >&5 +printf %s "checking for gnutls_srp_verifier in -lgnutls... " >&6; } +if test ${ac_cv_lib_gnutls_gnutls_srp_verifier+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnutls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gnutls_srp_verifier (); +int main (void) +{ +return gnutls_srp_verifier (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_gnutls_gnutls_srp_verifier=yes +else $as_nop + ac_cv_lib_gnutls_gnutls_srp_verifier=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_srp_verifier" >&5 +printf "%s\n" "$ac_cv_lib_gnutls_gnutls_srp_verifier" >&6; } +if test "x$ac_cv_lib_gnutls_gnutls_srp_verifier" = xyes +then : + + +printf "%s\n" "#define HAVE_GNUTLS_SRP 1" >>confdefs.h + + HAVE_GNUTLS_SRP=1 + + +fi + +fi + + + + +if test "x$OPT_MBEDTLS" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + ssl_msg= + + if test X"$OPT_MBEDTLS" != Xno; then + + if test "$OPT_MBEDTLS" = "yes"; then + OPT_MBEDTLS="" + fi + + if test -z "$OPT_MBEDTLS" ; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mbedtls_havege_init in -lmbedtls" >&5 +printf %s "checking for mbedtls_havege_init in -lmbedtls... " >&6; } +if test ${ac_cv_lib_mbedtls_mbedtls_havege_init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmbedtls -lmbedx509 -lmbedcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char mbedtls_havege_init (); +int main (void) +{ +return mbedtls_havege_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_mbedtls_mbedtls_havege_init=yes +else $as_nop + ac_cv_lib_mbedtls_mbedtls_havege_init=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mbedtls_mbedtls_havege_init" >&5 +printf "%s\n" "$ac_cv_lib_mbedtls_mbedtls_havege_init" >&6; } +if test "x$ac_cv_lib_mbedtls_mbedtls_havege_init" = xyes +then : + + +printf "%s\n" "#define USE_MBEDTLS 1" >>confdefs.h + + USE_MBEDTLS=1 + + MBEDTLS_ENABLED=1 + USE_MBEDTLS="yes" + ssl_msg="mbedTLS" + test mbedtls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +fi + + fi + + addld="" + addlib="" + addcflags="" + mbedtlslib="" + + if test "x$USE_MBEDTLS" != "xyes"; then + addld=-L$OPT_MBEDTLS/lib$libsuff + addcflags=-I$OPT_MBEDTLS/include + mbedtlslib=$OPT_MBEDTLS/lib$libsuff + + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mbedtls_ssl_init in -lmbedtls" >&5 +printf %s "checking for mbedtls_ssl_init in -lmbedtls... " >&6; } +if test ${ac_cv_lib_mbedtls_mbedtls_ssl_init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmbedtls -lmbedx509 -lmbedcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char mbedtls_ssl_init (); +int main (void) +{ +return mbedtls_ssl_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_mbedtls_mbedtls_ssl_init=yes +else $as_nop + ac_cv_lib_mbedtls_mbedtls_ssl_init=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mbedtls_mbedtls_ssl_init" >&5 +printf "%s\n" "$ac_cv_lib_mbedtls_mbedtls_ssl_init" >&6; } +if test "x$ac_cv_lib_mbedtls_mbedtls_ssl_init" = xyes +then : + + +printf "%s\n" "#define USE_MBEDTLS 1" >>confdefs.h + + USE_MBEDTLS=1 + + MBEDTLS_ENABLED=1 + USE_MBEDTLS="yes" + ssl_msg="mbedTLS" + test mbedtls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +else $as_nop + + CPPFLAGS=$_cppflags + LDFLAGS=$_ldflags + +fi + + fi + + if test "x$USE_MBEDTLS" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: detected mbedTLS" >&5 +printf "%s\n" "$as_me: detected mbedTLS" >&6;} + check_for_ca_bundle=1 + + LIBS="-lmbedtls -lmbedx509 -lmbedcrypto $LIBS" + + if test -n "$mbedtlslib"; then + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$mbedtlslib" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $mbedtlslib to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $mbedtlslib to CURL_LIBRARY_PATH" >&6;} + fi + fi + fi + + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + + + + +case "$OPT_WOLFSSL" in + yes|no) + wolfpkg="" + ;; + *) + wolfpkg="$withval/lib/pkgconfig" + ;; +esac + +if test "x$OPT_WOLFSSL" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + + ssl_msg= + + if test X"$OPT_WOLFSSL" != Xno; then + + if test "$OPT_WOLFSSL" = "yes"; then + OPT_WOLFSSL="" + fi + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wolfssl options with pkg-config" >&5 +printf %s "checking for wolfssl options with pkg-config... " >&6; } + itexists=` + if test -n "$wolfpkg"; then + PKG_CONFIG_LIBDIR="$wolfpkg" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists wolfssl >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Check dir $wolfpkg" >&5 +printf "%s\n" "$as_me: Check dir $wolfpkg" >&6;} + + addld="" + addlib="" + addcflags="" + if test "$PKGCONFIG" != "no" ; then + addlib=` + if test -n "$wolfpkg"; then + PKG_CONFIG_LIBDIR="$wolfpkg" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l wolfssl` + addld=` + if test -n "$wolfpkg"; then + PKG_CONFIG_LIBDIR="$wolfpkg" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L wolfssl` + addcflags=` + if test -n "$wolfpkg"; then + PKG_CONFIG_LIBDIR="$wolfpkg" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --cflags-only-I wolfssl` + version=` + if test -n "$wolfpkg"; then + PKG_CONFIG_LIBDIR="$wolfpkg" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --modversion wolfssl` + wolfssllibpath=`echo $addld | $SED -e 's/^-L//'` + else + addlib=-lwolfssl + if test -n "$OPT_WOLFSSL"; then + addld=-L$OPT_WOLFSSL/lib$libsuff + addcflags=-I$OPT_WOLFSSL/include + wolfssllibpath=$OPT_WOLFSSL/lib$libsuff + fi + fi + + if test "x$USE_WOLFSSL" != "xyes"; then + + LDFLAGS="$LDFLAGS $addld" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Add $addld to LDFLAGS" >&5 +printf "%s\n" "$as_me: Add $addld to LDFLAGS" >&6;} + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Add $addcflags to CPPFLAGS" >&5 +printf "%s\n" "$as_me: Add $addcflags to CPPFLAGS" >&6;} + fi + + my_ac_save_LIBS="$LIBS" + LIBS="$addlib $LIBS" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Add $addlib to LIBS" >&5 +printf "%s\n" "$as_me: Add $addlib to LIBS" >&6;} + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wolfSSL_Init in -lwolfssl" >&5 +printf %s "checking for wolfSSL_Init in -lwolfssl... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +/* These aren't needed for detection and confuse WolfSSL. + They are set up properly later if it is detected. */ +#undef SIZEOF_LONG +#undef SIZEOF_LONG_LONG +#include +#include + +int main (void) +{ + + return wolfSSL_Init(); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define USE_WOLFSSL 1" >>confdefs.h + + USE_WOLFSSL=1 + + WOLFSSL_ENABLED=1 + USE_WOLFSSL="yes" + ssl_msg="WolfSSL" + QUIC_ENABLED=yes + test wolfssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CPPFLAGS=$_cppflags + LDFLAGS=$_ldflags + wolfssllibpath="" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$my_ac_save_LIBS" + fi + + if test "x$USE_WOLFSSL" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: detected wolfSSL" >&5 +printf "%s\n" "$as_me: detected wolfSSL" >&6;} + check_for_ca_bundle=1 + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 +printf %s "checking size of long long... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(long long) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of long long" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_long long" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_LONG_LONG $r" >>confdefs.h + + + + + LIBS="$addlib -lm $LIBS" + + ac_fn_c_check_func "$LINENO" "wolfSSL_get_peer_certificate" "ac_cv_func_wolfSSL_get_peer_certificate" +if test "x$ac_cv_func_wolfSSL_get_peer_certificate" = xyes +then : + printf "%s\n" "#define HAVE_WOLFSSL_GET_PEER_CERTIFICATE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "wolfSSL_UseALPN" "ac_cv_func_wolfSSL_UseALPN" +if test "x$ac_cv_func_wolfSSL_UseALPN" = xyes +then : + printf "%s\n" "#define HAVE_WOLFSSL_USEALPN 1" >>confdefs.h + +fi + + + ac_fn_c_check_func "$LINENO" "wolfSSL_DES_ecb_encrypt" "ac_cv_func_wolfSSL_DES_ecb_encrypt" +if test "x$ac_cv_func_wolfSSL_DES_ecb_encrypt" = xyes +then : + + +printf "%s\n" "#define HAVE_WOLFSSL_DES_ECB_ENCRYPT 1" >>confdefs.h + + WOLFSSL_NTLM=1 + + +fi + + + ac_fn_c_check_func "$LINENO" "wolfSSL_BIO_set_shutdown" "ac_cv_func_wolfSSL_BIO_set_shutdown" +if test "x$ac_cv_func_wolfSSL_BIO_set_shutdown" = xyes +then : + + +printf "%s\n" "#define HAVE_WOLFSSL_FULL_BIO 1" >>confdefs.h + + WOLFSSL_FULL_BIO=1 + + +fi + + + if test -n "$wolfssllibpath"; then + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$wolfssllibpath" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $wolfssllibpath to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $wolfssllibpath to CURL_LIBRARY_PATH" >&6;} + fi + fi + else + as_fn_error $? "--with-wolfssl but wolfSSL was not found or doesn't work" "$LINENO" 5 + fi + + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + + + + +if test "x$OPT_BEARSSL" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + ssl_msg= + + if test X"$OPT_BEARSSL" != Xno; then + + if test "$OPT_BEARSSL" = "yes"; then + OPT_BEARSSL="" + fi + + if test -z "$OPT_BEARSSL" ; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for br_ssl_client_init_full in -lbearssl" >&5 +printf %s "checking for br_ssl_client_init_full in -lbearssl... " >&6; } +if test ${ac_cv_lib_bearssl_br_ssl_client_init_full+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbearssl -lbearssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char br_ssl_client_init_full (); +int main (void) +{ +return br_ssl_client_init_full (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_bearssl_br_ssl_client_init_full=yes +else $as_nop + ac_cv_lib_bearssl_br_ssl_client_init_full=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bearssl_br_ssl_client_init_full" >&5 +printf "%s\n" "$ac_cv_lib_bearssl_br_ssl_client_init_full" >&6; } +if test "x$ac_cv_lib_bearssl_br_ssl_client_init_full" = xyes +then : + + +printf "%s\n" "#define USE_BEARSSL 1" >>confdefs.h + + USE_BEARSSL=1 + + BEARSSL_ENABLED=1 + USE_BEARSSL="yes" + ssl_msg="BearSSL" + test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +fi + + fi + + addld="" + addlib="" + addcflags="" + bearssllib="" + + if test "x$USE_BEARSSL" != "xyes"; then + addld=-L$OPT_BEARSSL/lib$libsuff + addcflags=-I$OPT_BEARSSL/include + bearssllib=$OPT_BEARSSL/lib$libsuff + + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for br_ssl_client_init_full in -lbearssl" >&5 +printf %s "checking for br_ssl_client_init_full in -lbearssl... " >&6; } +if test ${ac_cv_lib_bearssl_br_ssl_client_init_full+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbearssl -lbearssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char br_ssl_client_init_full (); +int main (void) +{ +return br_ssl_client_init_full (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_bearssl_br_ssl_client_init_full=yes +else $as_nop + ac_cv_lib_bearssl_br_ssl_client_init_full=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bearssl_br_ssl_client_init_full" >&5 +printf "%s\n" "$ac_cv_lib_bearssl_br_ssl_client_init_full" >&6; } +if test "x$ac_cv_lib_bearssl_br_ssl_client_init_full" = xyes +then : + + +printf "%s\n" "#define USE_BEARSSL 1" >>confdefs.h + + USE_BEARSSL=1 + + BEARSSL_ENABLED=1 + USE_BEARSSL="yes" + ssl_msg="BearSSL" + test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +else $as_nop + + CPPFLAGS=$_cppflags + LDFLAGS=$_ldflags + +fi + + fi + + if test "x$USE_BEARSSL" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: detected BearSSL" >&5 +printf "%s\n" "$as_me: detected BearSSL" >&6;} + check_for_ca_bundle=1 + + LIBS="-lbearssl $LIBS" + + if test -n "$bearssllib"; then + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$bearssllib" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $bearssllib to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $bearssllib to CURL_LIBRARY_PATH" >&6;} + fi + fi + fi + + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + + + +if test "x$OPT_RUSTLS" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + ssl_msg= + + if test X"$OPT_RUSTLS" != Xno; then + + if test "$OPT_RUSTLS" = "yes"; then + OPT_RUSTLS="" + fi + + case $host_os in + darwin*) + LDFLAGS="$LDFLAGS -framework Security" + ;; + *) + ;; + esac + + if test -z "$OPT_RUSTLS" ; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rustls_client_session_read in -lrustls" >&5 +printf %s "checking for rustls_client_session_read in -lrustls... " >&6; } +if test ${ac_cv_lib_rustls_rustls_client_session_read+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrustls -lpthread -ldl -lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char rustls_client_session_read (); +int main (void) +{ +return rustls_client_session_read (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_rustls_rustls_client_session_read=yes +else $as_nop + ac_cv_lib_rustls_rustls_client_session_read=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rustls_rustls_client_session_read" >&5 +printf "%s\n" "$ac_cv_lib_rustls_rustls_client_session_read" >&6; } +if test "x$ac_cv_lib_rustls_rustls_client_session_read" = xyes +then : + + +printf "%s\n" "#define USE_RUSTLS 1" >>confdefs.h + + USE_RUSTLS=1 + + RUSTLS_ENABLED=1 + USE_RUSTLS="yes" + ssl_msg="rustls" + test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +fi + + fi + + if test "x$USE_RUSTLS" != "xyes"; then + addld=-L$OPT_RUSTLS/lib$libsuff + addcflags=-I$OPT_RUSTLS/include + rustlslib=$OPT_RUSTLS/lib$libsuff + + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rustls_connection_read in -lrustls" >&5 +printf %s "checking for rustls_connection_read in -lrustls... " >&6; } +if test ${ac_cv_lib_rustls_rustls_connection_read+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrustls -lpthread -ldl -lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char rustls_connection_read (); +int main (void) +{ +return rustls_connection_read (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_rustls_rustls_connection_read=yes +else $as_nop + ac_cv_lib_rustls_rustls_connection_read=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rustls_rustls_connection_read" >&5 +printf "%s\n" "$ac_cv_lib_rustls_rustls_connection_read" >&6; } +if test "x$ac_cv_lib_rustls_rustls_connection_read" = xyes +then : + + +printf "%s\n" "#define USE_RUSTLS 1" >>confdefs.h + + USE_RUSTLS=1 + + RUSTLS_ENABLED=1 + USE_RUSTLS="yes" + ssl_msg="rustls" + test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + +else $as_nop + as_fn_error $? "--with-rustls was specified but could not find rustls." "$LINENO" 5 +fi + + fi + + if test "x$USE_RUSTLS" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: detected rustls" >&5 +printf "%s\n" "$as_me: detected rustls" >&6;} + check_for_ca_bundle=1 + + LIBS="-lrustls -lpthread -ldl -lm $LIBS" + + if test -n "$rustlslib"; then + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$rustlslib" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $rustlslib to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $rustlslib to CURL_LIBRARY_PATH" >&6;} + fi + fi + fi + + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + + +if test "x$USE_WIN32_CRYPTO" = "x1" -o "x$USE_SCHANNEL" = "x1"; then + LIBS="-ladvapi32 -lcrypt32 $LIBS" +fi + +if test "x$curl_cv_native_windows" = "xyes"; then + LIBS="-lbcrypt $LIBS" +fi + +case "x$SSL_DISABLED$OPENSSL_ENABLED$GNUTLS_ENABLED$MBEDTLS_ENABLED$WOLFSSL_ENABLED$SCHANNEL_ENABLED$SECURETRANSPORT_ENABLED$BEARSSL_ENABLED$RUSTLS_ENABLED" +in +x) + as_fn_error $? "TLS not detected, you will not be able to use HTTPS, FTPS, NTLM and more. +Use --with-openssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-schannel, --with-secure-transport, --with-amissl, --with-bearssl or --with-rustls to address this." "$LINENO" 5 + ;; +x1) + # one SSL backend is enabled + + SSL_ENABLED="1" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: built with one SSL backend" >&5 +printf "%s\n" "$as_me: built with one SSL backend" >&6;} + ;; +xD) + # explicitly built without TLS + ;; +xD*) + as_fn_error $? "--without-ssl has been set together with an explicit option to use an ssl library +(e.g. --with-openssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-schannel, --with-secure-transport, --with-amissl, --with-bearssl, --with-rustls). +Since these are conflicting parameters, verify which is the desired one and drop the other." "$LINENO" 5 + ;; +*) + # more than one SSL backend is enabled + + SSL_ENABLED="1" + + CURL_WITH_MULTI_SSL="1" + +printf "%s\n" "#define CURL_WITH_MULTI_SSL 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: built with multiple SSL backends" >&5 +printf "%s\n" "$as_me: built with multiple SSL backends" >&6;} + ;; +esac + +if test -n "$ssl_backends"; then + curl_ssl_msg="enabled ($ssl_backends)" +fi + +if test no = "$VALID_DEFAULT_SSL_BACKEND" +then + if test -n "$SSL_ENABLED" + then + as_fn_error $? "Default SSL backend $DEFAULT_SSL_BACKEND not enabled!" "$LINENO" 5 + else + as_fn_error $? "Default SSL backend requires SSL!" "$LINENO" 5 + fi +elif test yes = "$VALID_DEFAULT_SSL_BACKEND" +then + +printf "%s\n" "#define CURL_DEFAULT_SSL_BACKEND \"$DEFAULT_SSL_BACKEND\"" >>confdefs.h + +fi + + +if test -n "$check_for_ca_bundle"; then + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking default CA cert bundle/path" >&5 +printf %s "checking default CA cert bundle/path... " >&6; } + + +# Check whether --with-ca-bundle was given. +if test ${with_ca_bundle+y} +then : + withval=$with_ca_bundle; + want_ca="$withval" + if test "x$want_ca" = "xyes"; then + as_fn_error $? "--with-ca-bundle=FILE requires a path to the CA bundle" "$LINENO" 5 + fi + +else $as_nop + want_ca="unset" +fi + + +# Check whether --with-ca-path was given. +if test ${with_ca_path+y} +then : + withval=$with_ca_path; + want_capath="$withval" + if test "x$want_capath" = "xyes"; then + as_fn_error $? "--with-ca-path=DIRECTORY requires a path to the CA path directory" "$LINENO" 5 + fi + +else $as_nop + want_capath="unset" +fi + + + ca_warning=" (warning: certs not found)" + capath_warning=" (warning: certs not found)" + check_capath="" + + if test "x$want_ca" != "xno" -a "x$want_ca" != "xunset" -a \ + "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then + ca="$want_ca" + capath="$want_capath" + elif test "x$want_ca" != "xno" -a "x$want_ca" != "xunset"; then + ca="$want_ca" + capath="no" + elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then + if test "x$OPENSSL_ENABLED" != "x1" -a \ + "x$GNUTLS_ENABLED" != "x1" -a \ + "x$MBEDTLS_ENABLED" != "x1" -a \ + "x$WOLFSSL_ENABLED" != "x1"; then + as_fn_error $? "--with-ca-path only works with OpenSSL, GnuTLS, mbedTLS or wolfSSL" "$LINENO" 5 + fi + capath="$want_capath" + ca="no" + else + ca="no" + capath="no" + if test "x$cross_compiling" != "xyes"; then + if test "x$want_ca" = "xunset"; then + if test "x$prefix" != xNONE; then + cac="${prefix}/share/curl/curl-ca-bundle.crt" + else + cac="$ac_default_prefix/share/curl/curl-ca-bundle.crt" + fi + + for a in /etc/ssl/certs/ca-certificates.crt \ + /etc/pki/tls/certs/ca-bundle.crt \ + /usr/share/ssl/certs/ca-bundle.crt \ + /usr/local/share/certs/ca-root-nss.crt \ + /etc/ssl/cert.pem \ + "$cac"; do + if test -f "$a"; then + ca="$a" + break + fi + done + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: want $want_capath ca $ca" >&5 +printf "%s\n" "$as_me: want $want_capath ca $ca" >&6;} + if test "x$want_capath" = "xunset"; then + if test "x$OPENSSL_ENABLED" = "x1" -o \ + "x$GNUTLS_ENABLED" = "x1" -o \ + "x$MBEDTLS_ENABLED" = "x1" -o \ + "x$WOLFSSL_ENABLED" = "x1"; then + check_capath="/etc/ssl/certs" + fi + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: skipped the ca-cert path detection when cross-compiling" >&5 +printf "%s\n" "$as_me: WARNING: skipped the ca-cert path detection when cross-compiling" >&2;} + fi + fi + + if test "x$ca" = "xno" || test -f "$ca"; then + ca_warning="" + fi + + if test "x$capath" != "xno"; then + check_capath="$capath" + fi + + if test ! -z "$check_capath"; then + for a in "$check_capath"; do + if test -d "$a" && ls "$a"/[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].0 >/dev/null 2>/dev/null; then + if test "x$capath" = "xno"; then + capath="$a" + fi + capath_warning="" + break + fi + done + fi + + if test "x$capath" = "xno"; then + capath_warning="" + fi + + if test "x$ca" != "xno"; then + CURL_CA_BUNDLE='"'$ca'"' + +printf "%s\n" "#define CURL_CA_BUNDLE \"$ca\"" >>confdefs.h + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ca" >&5 +printf "%s\n" "$ca" >&6; } + fi + if test "x$capath" != "xno"; then + CURL_CA_PATH="\"$capath\"" + +printf "%s\n" "#define CURL_CA_PATH \"$capath\"" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $capath (capath)" >&5 +printf "%s\n" "$capath (capath)" >&6; } + fi + if test "x$ca" = "xno" && test "x$capath" = "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use builtin CA store of SSL library" >&5 +printf %s "checking whether to use builtin CA store of SSL library... " >&6; } + +# Check whether --with-ca-fallback was given. +if test ${with_ca_fallback+y} +then : + withval=$with_ca_fallback; + if test "x$with_ca_fallback" != "xyes" -a "x$with_ca_fallback" != "xno"; then + as_fn_error $? "--with-ca-fallback only allows yes or no as parameter" "$LINENO" 5 + fi + +else $as_nop + with_ca_fallback="no" +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_ca_fallback" >&5 +printf "%s\n" "$with_ca_fallback" >&6; } + if test "x$with_ca_fallback" = "xyes"; then + if test "x$OPENSSL_ENABLED" != "x1" -a "x$GNUTLS_ENABLED" != "x1"; then + as_fn_error $? "--with-ca-fallback only works with OpenSSL or GnuTLS" "$LINENO" 5 + fi + +printf "%s\n" "#define CURL_CA_FALLBACK 1" >>confdefs.h + + fi + +fi + + + +# Check whether --with-libpsl was given. +if test ${with_libpsl+y} +then : + withval=$with_libpsl; with_libpsl=$withval +else $as_nop + with_libpsl=yes +fi + +curl_psl_msg="no (libpsl disabled)" +if test $with_libpsl != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing psl_builtin" >&5 +printf %s "checking for library containing psl_builtin... " >&6; } +if test ${ac_cv_search_psl_builtin+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char psl_builtin (); +int main (void) +{ +return psl_builtin (); + ; + return 0; +} +_ACEOF +for ac_lib in '' psl +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" +then : + ac_cv_search_psl_builtin=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext + if test ${ac_cv_search_psl_builtin+y} +then : + break +fi +done +if test ${ac_cv_search_psl_builtin+y} +then : + +else $as_nop + ac_cv_search_psl_builtin=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_psl_builtin" >&5 +printf "%s\n" "$ac_cv_search_psl_builtin" >&6; } +ac_res=$ac_cv_search_psl_builtin +if test "$ac_res" != no +then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + curl_psl_msg="enabled"; + +printf "%s\n" "#define USE_LIBPSL 1" >>confdefs.h + + +else $as_nop + as_fn_error $? "libpsl was not found" "$LINENO" 5 + +fi + +fi + if test "$curl_psl_msg" = "enabled"; then + USE_LIBPSL_TRUE= + USE_LIBPSL_FALSE='#' +else + USE_LIBPSL_TRUE='#' + USE_LIBPSL_FALSE= +fi + + + + + +# Check whether --with-libgsasl was given. +if test ${with_libgsasl+y} +then : + withval=$with_libgsasl; with_libgsasl=$withval +else $as_nop + with_libgsasl=yes +fi + +if test $with_libgsasl != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing gsasl_init" >&5 +printf %s "checking for library containing gsasl_init... " >&6; } +if test ${ac_cv_search_gsasl_init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char gsasl_init (); +int main (void) +{ +return gsasl_init (); + ; + return 0; +} +_ACEOF +for ac_lib in '' gsasl +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" +then : + ac_cv_search_gsasl_init=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext + if test ${ac_cv_search_gsasl_init+y} +then : + break +fi +done +if test ${ac_cv_search_gsasl_init+y} +then : + +else $as_nop + ac_cv_search_gsasl_init=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gsasl_init" >&5 +printf "%s\n" "$ac_cv_search_gsasl_init" >&6; } +ac_res=$ac_cv_search_gsasl_init +if test "$ac_res" != no +then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + curl_gsasl_msg="enabled"; + +printf "%s\n" "#define USE_GSASL 1" >>confdefs.h + + +else $as_nop + curl_gsasl_msg="no (libgsasl not found)"; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: libgsasl was not found" >&5 +printf "%s\n" "$as_me: WARNING: libgsasl was not found" >&2;} + + +fi + +fi + if test "$curl_gsasl_msg" = "enabled"; then + USE_GSASL_TRUE= + USE_GSASL_FALSE='#' +else + USE_GSASL_TRUE='#' + USE_GSASL_FALSE= +fi + + + +# Check whether --with-libmetalink was given. +if test ${with_libmetalink+y} +then : + withval=$with_libmetalink; as_fn_error $? "--with-libmetalink and --without-libmetalink no longer work!" "$LINENO" 5 +fi + + + +OPT_LIBSSH2=off + +# Check whether --with-libssh2 was given. +if test ${with_libssh2+y} +then : + withval=$with_libssh2; OPT_LIBSSH2=$withval +else $as_nop + OPT_LIBSSH2=no +fi + + + +OPT_LIBSSH=off + +# Check whether --with-libssh was given. +if test ${with_libssh+y} +then : + withval=$with_libssh; OPT_LIBSSH=$withval +else $as_nop + OPT_LIBSSH=no +fi + + +OPT_WOLFSSH=off + +# Check whether --with-wolfssh was given. +if test ${with_wolfssh+y} +then : + withval=$with_wolfssh; OPT_WOLFSSH=$withval +else $as_nop + OPT_WOLFSSH=no +fi + + +if test X"$OPT_LIBSSH2" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBSSH2" in + yes) + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libssh2 options with pkg-config" >&5 +printf %s "checking for libssh2 options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libssh2 >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_SSH2=`$PKGCONFIG --libs-only-l libssh2` + LD_SSH2=`$PKGCONFIG --libs-only-L libssh2` + CPP_SSH2=`$PKGCONFIG --cflags-only-I libssh2` + version=`$PKGCONFIG --modversion libssh2` + DIR_SSH2=`echo $LD_SSH2 | $SED -e 's/^-L//'` + fi + + ;; + off) + ;; + *) + PREFIX_SSH2=$OPT_LIBSSH2 + ;; + esac + + if test -n "$PREFIX_SSH2"; then + LIB_SSH2="-lssh2" + LD_SSH2=-L${PREFIX_SSH2}/lib$libsuff + CPP_SSH2=-I${PREFIX_SSH2}/include + DIR_SSH2=${PREFIX_SSH2}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_SSH2" + CPPFLAGS="$CPPFLAGS $CPP_SSH2" + LIBS="$LIB_SSH2 $LIBS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libssh2_session_block_directions in -lssh2" >&5 +printf %s "checking for libssh2_session_block_directions in -lssh2... " >&6; } +if test ${ac_cv_lib_ssh2_libssh2_session_block_directions+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssh2 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char libssh2_session_block_directions (); +int main (void) +{ +return libssh2_session_block_directions (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ssh2_libssh2_session_block_directions=yes +else $as_nop + ac_cv_lib_ssh2_libssh2_session_block_directions=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssh2_libssh2_session_block_directions" >&5 +printf "%s\n" "$ac_cv_lib_ssh2_libssh2_session_block_directions" >&6; } +if test "x$ac_cv_lib_ssh2_libssh2_session_block_directions" = xyes +then : + printf "%s\n" "#define HAVE_LIBSSH2 1" >>confdefs.h + + LIBS="-lssh2 $LIBS" + +fi + + + ac_fn_c_check_header_compile "$LINENO" "libssh2.h" "ac_cv_header_libssh2_h" "$ac_includes_default" +if test "x$ac_cv_header_libssh2_h" = xyes +then : + curl_ssh_msg="enabled (libSSH2)" + LIBSSH2_ENABLED=1 + +printf "%s\n" "#define USE_LIBSSH2 1" >>confdefs.h + + USE_LIBSSH2=1 + + +fi + + + if test X"$OPT_LIBSSH2" != Xoff && + test "$LIBSSH2_ENABLED" != "1"; then + as_fn_error $? "libSSH2 libs and/or directories were not found where specified!" "$LINENO" 5 + fi + + if test "$LIBSSH2_ENABLED" = "1"; then + if test -n "$DIR_SSH2"; then + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH2" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_SSH2 to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_SSH2 to CURL_LIBRARY_PATH" >&6;} + fi + fi + else + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +elif test X"$OPT_LIBSSH" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBSSH" in + yes) + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libssh options with pkg-config" >&5 +printf %s "checking for libssh options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libssh >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_SSH=`$PKGCONFIG --libs-only-l libssh` + LD_SSH=`$PKGCONFIG --libs-only-L libssh` + CPP_SSH=`$PKGCONFIG --cflags-only-I libssh` + version=`$PKGCONFIG --modversion libssh` + DIR_SSH=`echo $LD_SSH | $SED -e 's/^-L//'` + fi + + ;; + off) + ;; + *) + PREFIX_SSH=$OPT_LIBSSH + ;; + esac + + if test -n "$PREFIX_SSH"; then + LIB_SSH="-lssh" + LD_SSH=-L${PREFIX_SSH}/lib$libsuff + CPP_SSH=-I${PREFIX_SSH}/include + DIR_SSH=${PREFIX_SSH}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_SSH" + CPPFLAGS="$CPPFLAGS $CPP_SSH" + LIBS="$LIB_SSH $LIBS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ssh_new in -lssh" >&5 +printf %s "checking for ssh_new in -lssh... " >&6; } +if test ${ac_cv_lib_ssh_ssh_new+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssh $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ssh_new (); +int main (void) +{ +return ssh_new (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ssh_ssh_new=yes +else $as_nop + ac_cv_lib_ssh_ssh_new=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssh_ssh_new" >&5 +printf "%s\n" "$ac_cv_lib_ssh_ssh_new" >&6; } +if test "x$ac_cv_lib_ssh_ssh_new" = xyes +then : + printf "%s\n" "#define HAVE_LIBSSH 1" >>confdefs.h + + LIBS="-lssh $LIBS" + +fi + + + ac_fn_c_check_header_compile "$LINENO" "libssh/libssh.h" "ac_cv_header_libssh_libssh_h" "$ac_includes_default" +if test "x$ac_cv_header_libssh_libssh_h" = xyes +then : + curl_ssh_msg="enabled (libSSH)" + LIBSSH_ENABLED=1 + +printf "%s\n" "#define USE_LIBSSH 1" >>confdefs.h + + USE_LIBSSH=1 + + +fi + + + if test X"$OPT_LIBSSH" != Xoff && + test "$LIBSSH_ENABLED" != "1"; then + as_fn_error $? "libSSH libs and/or directories were not found where specified!" "$LINENO" 5 + fi + + if test "$LIBSSH_ENABLED" = "1"; then + if test -n "$DIR_SSH"; then + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_SSH to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_SSH to CURL_LIBRARY_PATH" >&6;} + fi + fi + else + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +elif test X"$OPT_WOLFSSH" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test "$OPT_WOLFSSH" != yes; then + WOLFCONFIG="$OPT_WOLFSSH/bin/wolfssh-config" + LDFLAGS="$LDFLAGS `$WOLFCONFIG --libs`" + CPPFLAGS="$CPPFLAGS `$WOLFCONFIG --cflags`" + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wolfSSH_Init in -lwolfssh" >&5 +printf %s "checking for wolfSSH_Init in -lwolfssh... " >&6; } +if test ${ac_cv_lib_wolfssh_wolfSSH_Init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lwolfssh $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char wolfSSH_Init (); +int main (void) +{ +return wolfSSH_Init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_wolfssh_wolfSSH_Init=yes +else $as_nop + ac_cv_lib_wolfssh_wolfSSH_Init=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wolfssh_wolfSSH_Init" >&5 +printf "%s\n" "$ac_cv_lib_wolfssh_wolfSSH_Init" >&6; } +if test "x$ac_cv_lib_wolfssh_wolfSSH_Init" = xyes +then : + printf "%s\n" "#define HAVE_LIBWOLFSSH 1" >>confdefs.h + + LIBS="-lwolfssh $LIBS" + +fi + + + for ac_header in wolfssh/ssh.h +do : + ac_fn_c_check_header_compile "$LINENO" "wolfssh/ssh.h" "ac_cv_header_wolfssh_ssh_h" "$ac_includes_default" +if test "x$ac_cv_header_wolfssh_ssh_h" = xyes +then : + printf "%s\n" "#define HAVE_WOLFSSH_SSH_H 1" >>confdefs.h + curl_ssh_msg="enabled (wolfSSH)" + WOLFSSH_ENABLED=1 + +printf "%s\n" "#define USE_WOLFSSH 1" >>confdefs.h + + USE_WOLFSSH=1 + + +fi + +done + +fi + + +OPT_LIBRTMP=off + +# Check whether --with-librtmp was given. +if test ${with_librtmp+y} +then : + withval=$with_librtmp; OPT_LIBRTMP=$withval +fi + + +if test X"$OPT_LIBRTMP" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBRTMP" in + yes) + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for librtmp options with pkg-config" >&5 +printf %s "checking for librtmp options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists librtmp >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_RTMP=`$PKGCONFIG --libs-only-l librtmp` + LD_RTMP=`$PKGCONFIG --libs-only-L librtmp` + CPP_RTMP=`$PKGCONFIG --cflags-only-I librtmp` + version=`$PKGCONFIG --modversion librtmp` + DIR_RTMP=`echo $LD_RTMP | $SED -e 's/^-L//'` + else + as_fn_error $? "--librtmp was specified but could not find librtmp pkgconfig file." "$LINENO" 5 + fi + + ;; + off) + LIB_RTMP="-lrtmp" + ;; + *) + LIB_RTMP="-lrtmp" + PREFIX_RTMP=$OPT_LIBRTMP + ;; + esac + + if test -n "$PREFIX_RTMP"; then + LD_RTMP=-L${PREFIX_RTMP}/lib$libsuff + CPP_RTMP=-I${PREFIX_RTMP}/include + DIR_RTMP=${PREFIX_RTMP}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_RTMP" + CPPFLAGS="$CPPFLAGS $CPP_RTMP" + LIBS="$LIB_RTMP $LIBS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for RTMP_Init in -lrtmp" >&5 +printf %s "checking for RTMP_Init in -lrtmp... " >&6; } +if test ${ac_cv_lib_rtmp_RTMP_Init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrtmp $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char RTMP_Init (); +int main (void) +{ +return RTMP_Init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_rtmp_RTMP_Init=yes +else $as_nop + ac_cv_lib_rtmp_RTMP_Init=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rtmp_RTMP_Init" >&5 +printf "%s\n" "$ac_cv_lib_rtmp_RTMP_Init" >&6; } +if test "x$ac_cv_lib_rtmp_RTMP_Init" = xyes +then : + + for ac_header in librtmp/rtmp.h +do : + ac_fn_c_check_header_compile "$LINENO" "librtmp/rtmp.h" "ac_cv_header_librtmp_rtmp_h" "$ac_includes_default" +if test "x$ac_cv_header_librtmp_rtmp_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBRTMP_RTMP_H 1" >>confdefs.h + curl_rtmp_msg="enabled (librtmp)" + LIBRTMP_ENABLED=1 + +printf "%s\n" "#define USE_LIBRTMP 1" >>confdefs.h + + USE_LIBRTMP=1 + + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + + + if test X"$OPT_LIBRTMP" != Xoff && + test "$LIBRTMP_ENABLED" != "1"; then + as_fn_error $? "librtmp libs and/or directories were not found where specified!" "$LINENO" 5 + fi + +fi + + +versioned_symbols_flavour= +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether versioned symbols are wanted" >&5 +printf %s "checking whether versioned symbols are wanted... " >&6; } +# Check whether --enable-versioned-symbols was given. +if test ${enable_versioned_symbols+y} +then : + enableval=$enable_versioned_symbols; case "$enableval" in + yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libraries can be versioned" >&5 +printf %s "checking if libraries can be versioned... " >&6; } + GLD=`$LD --help < /dev/null 2>/dev/null | grep version-script` + if test -z "$GLD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: You need an ld version supporting the --version-script option" >&5 +printf "%s\n" "$as_me: WARNING: You need an ld version supporting the --version-script option" >&2;} + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + if test "x$CURL_WITH_MULTI_SSL" = "x1"; then + versioned_symbols_flavour="MULTISSL_" + elif test "x$OPENSSL_ENABLED" = "x1"; then + versioned_symbols_flavour="OPENSSL_" + elif test "x$GNUTLS_ENABLED" = "x1"; then + versioned_symbols_flavour="GNUTLS_" + elif test "x$WOLFSSL_ENABLED" = "x1"; then + versioned_symbols_flavour="WOLFSSL_" + elif test "x$SCHANNEL_ENABLED" = "x1"; then + versioned_symbols_flavour="SCHANNEL_" + elif test "x$SECURETRANSPORT_ENABLED" = "x1"; then + versioned_symbols_flavour="SECURE_TRANSPORT_" + else + versioned_symbols_flavour="" + fi + versioned_symbols="yes" + fi + ;; + + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + esac + +else $as_nop + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + +fi + + +CURL_LT_SHLIB_VERSIONED_FLAVOUR="$versioned_symbols_flavour" + + if test "x$versioned_symbols" = 'xyes'; then + CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE= + CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE='#' +else + CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE='#' + CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE= +fi + + +CURL_PLIST_VERSION="$CURLVERSION" + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable Windows native IDN (Windows native builds only)" >&5 +printf %s "checking whether to enable Windows native IDN (Windows native builds only)... " >&6; } +OPT_WINIDN="default" + +# Check whether --with-winidn was given. +if test ${with_winidn+y} +then : + withval=$with_winidn; OPT_WINIDN=$withval +fi + +case "$OPT_WINIDN" in + no|default) + want_winidn="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + yes) + want_winidn="yes" + want_winidn_path="default" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + *) + want_winidn="yes" + want_winidn_path="$withval" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($withval)" >&5 +printf "%s\n" "yes ($withval)" >&6; } + ;; +esac + +if test "$want_winidn" = "yes"; then + clean_CFLAGS="$CFLAGS" + clean_CPPFLAGS="$CPPFLAGS" + clean_LDFLAGS="$LDFLAGS" + clean_LIBS="$LIBS" + WINIDN_LIBS="-lnormaliz" + WINIDN_CPPFLAGS="" + # + if test "$want_winidn_path" != "default"; then + WINIDN_LDFLAGS="-L$want_winidn_path/lib$libsuff" + WINIDN_CPPFLAGS="-I$want_winidn_path/include" + WINIDN_DIR="$want_winidn_path/lib$libsuff" + fi + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + +int main (void) +{ + + #if (WINVER < 0x600) && (_WIN32_WINNT < 0x600) + #error + #endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + +else $as_nop + + CFLAGS=`echo $CFLAGS | $SED -e 's/-DWINVER=[^ ]*//g'` + CFLAGS=`echo $CFLAGS | $SED -e 's/-D_WIN32_WINNT=[^ ]*//g'` + CPPFLAGS=`echo $CPPFLAGS | $SED -e 's/-DWINVER=[^ ]*//g'` + CPPFLAGS=`echo $CPPFLAGS | $SED -e 's/-D_WIN32_WINNT=[^ ]*//g'` + WINIDN_CPPFLAGS="$WINIDN_CPPFLAGS -DWINVER=0x0600" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # + CPPFLAGS="$CPPFLAGS $WINIDN_CPPFLAGS" + LDFLAGS="$LDFLAGS $WINIDN_LDFLAGS" + LIBS="$WINIDN_LIBS $LIBS" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IdnToUnicode can be linked" >&5 +printf %s "checking if IdnToUnicode can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + +int main (void) +{ + + IdnToUnicode(0, NULL, 0, NULL, 0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_winidn="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_winidn="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_winidn" = "yes"; then + +printf "%s\n" "#define USE_WIN32_IDN 1" >>confdefs.h + + IDN_ENABLED=1 + + curl_idn_msg="enabled (Windows-native)" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find libraries for IDN support: IDN disabled" >&5 +printf "%s\n" "$as_me: WARNING: Cannot find libraries for IDN support: IDN disabled" >&2;} + CFLAGS="$clean_CFLAGS" + CPPFLAGS="$clean_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS" + LIBS="$clean_LIBS" + fi +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build with libidn2" >&5 +printf %s "checking whether to build with libidn2... " >&6; } +OPT_IDN="default" + +# Check whether --with-libidn2 was given. +if test ${with_libidn2+y} +then : + withval=$with_libidn2; OPT_IDN=$withval +fi + +if test "x$tst_links_winidn" = "xyes"; then + want_idn="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (using winidn instead)" >&5 +printf "%s\n" "no (using winidn instead)" >&6; } +else + case "$OPT_IDN" in + no) + want_idn="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + default) + want_idn="yes" + want_idn_path="default" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: (assumed) yes" >&5 +printf "%s\n" "(assumed) yes" >&6; } + ;; + yes) + want_idn="yes" + want_idn_path="default" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + *) + want_idn="yes" + want_idn_path="$withval" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($withval)" >&5 +printf "%s\n" "yes ($withval)" >&6; } + ;; + esac +fi + +if test "$want_idn" = "yes"; then + clean_CPPFLAGS="$CPPFLAGS" + clean_LDFLAGS="$LDFLAGS" + clean_LIBS="$LIBS" + PKGCONFIG="no" + # + if test "$want_idn_path" != "default"; then + IDN_PCDIR="$want_idn_path/lib$libsuff/pkgconfig" + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libidn2 options with pkg-config" >&5 +printf %s "checking for libidn2 options with pkg-config... " >&6; } + itexists=` + if test -n "$IDN_PCDIR"; then + PKG_CONFIG_LIBDIR="$IDN_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libidn2 >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + if test "$PKGCONFIG" != "no"; then + IDN_LIBS=` + if test -n "$IDN_PCDIR"; then + PKG_CONFIG_LIBDIR="$IDN_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --libs-only-l libidn2 2>/dev/null` + IDN_LDFLAGS=` + if test -n "$IDN_PCDIR"; then + PKG_CONFIG_LIBDIR="$IDN_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --libs-only-L libidn2 2>/dev/null` + IDN_CPPFLAGS=` + if test -n "$IDN_PCDIR"; then + PKG_CONFIG_LIBDIR="$IDN_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libidn2 2>/dev/null` + IDN_DIR=`echo $IDN_LDFLAGS | $SED -e 's/^-L//'` + else + IDN_LIBS="-lidn2" + IDN_LDFLAGS="-L$want_idn_path/lib$libsuff" + IDN_CPPFLAGS="-I$want_idn_path/include" + IDN_DIR="$want_idn_path/lib$libsuff" + fi + else + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libidn2 options with pkg-config" >&5 +printf %s "checking for libidn2 options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libidn2 >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + if test "$PKGCONFIG" != "no"; then + IDN_LIBS=`$PKGCONFIG --libs-only-l libidn2 2>/dev/null` + IDN_LDFLAGS=`$PKGCONFIG --libs-only-L libidn2 2>/dev/null` + IDN_CPPFLAGS=`$PKGCONFIG --cflags-only-I libidn2 2>/dev/null` + IDN_DIR=`echo $IDN_LDFLAGS | $SED -e 's/^-L//'` + else + IDN_LIBS="-lidn2" + fi + fi + # + if test "$PKGCONFIG" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: IDN_LIBS: \"$IDN_LIBS\"" >&5 +printf "%s\n" "$as_me: pkg-config: IDN_LIBS: \"$IDN_LIBS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: IDN_LDFLAGS: \"$IDN_LDFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: IDN_LDFLAGS: \"$IDN_LDFLAGS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: IDN_CPPFLAGS: \"$IDN_CPPFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: IDN_CPPFLAGS: \"$IDN_CPPFLAGS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: IDN_DIR: \"$IDN_DIR\"" >&5 +printf "%s\n" "$as_me: pkg-config: IDN_DIR: \"$IDN_DIR\"" >&6;} + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: IDN_LIBS: \"$IDN_LIBS\"" >&5 +printf "%s\n" "$as_me: IDN_LIBS: \"$IDN_LIBS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: IDN_LDFLAGS: \"$IDN_LDFLAGS\"" >&5 +printf "%s\n" "$as_me: IDN_LDFLAGS: \"$IDN_LDFLAGS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: IDN_CPPFLAGS: \"$IDN_CPPFLAGS\"" >&5 +printf "%s\n" "$as_me: IDN_CPPFLAGS: \"$IDN_CPPFLAGS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: IDN_DIR: \"$IDN_DIR\"" >&5 +printf "%s\n" "$as_me: IDN_DIR: \"$IDN_DIR\"" >&6;} + fi + # + CPPFLAGS="$CPPFLAGS $IDN_CPPFLAGS" + LDFLAGS="$LDFLAGS $IDN_LDFLAGS" + LIBS="$IDN_LIBS $LIBS" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if idn2_lookup_ul can be linked" >&5 +printf %s "checking if idn2_lookup_ul can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define idn2_lookup_ul innocuous_idn2_lookup_ul +#ifdef __STDC__ +# include +#else +# include +#endif +#undef idn2_lookup_ul +#ifdef __cplusplus +extern "C" +#endif +char idn2_lookup_ul (); +#if defined __stub_idn2_lookup_ul || defined __stub___idn2_lookup_ul +choke me +#endif + +int main (void) +{ +return idn2_lookup_ul (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_libidn="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_libidn="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + ac_fn_c_check_header_compile "$LINENO" "idn2.h" "ac_cv_header_idn2_h" "$ac_includes_default" +if test "x$ac_cv_header_idn2_h" = xyes +then : + printf "%s\n" "#define HAVE_IDN2_H 1" >>confdefs.h + +fi + + + if test "$tst_links_libidn" = "yes"; then + +printf "%s\n" "#define HAVE_LIBIDN2 1" >>confdefs.h + + + IDN_ENABLED=1 + + curl_idn_msg="enabled (libidn2)" + if test -n "$IDN_DIR" -a "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$IDN_DIR" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $IDN_DIR to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $IDN_DIR to CURL_LIBRARY_PATH" >&6;} + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find libraries for IDN support: IDN disabled" >&5 +printf "%s\n" "$as_me: WARNING: Cannot find libraries for IDN support: IDN disabled" >&2;} + CPPFLAGS="$clean_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS" + LIBS="$clean_LIBS" + fi +fi + + +OPT_H2="yes" + +if test "x$disable_http" = "xyes" -o X"$want_hyper" != Xno; then + # without HTTP or with Hyper, nghttp2 is no use + OPT_H2="no" +fi + + +# Check whether --with-nghttp2 was given. +if test ${with_nghttp2+y} +then : + withval=$with_nghttp2; OPT_H2=$withval +fi + +case "$OPT_H2" in + no) + want_nghttp2="no" + ;; + yes) + want_nghttp2="default" + want_nghttp2_path="" + want_nghttp2_pkg_config_path="" + ;; + *) + want_nghttp2="yes" + want_nghttp2_path="$withval" + want_nghttp2_pkg_config_path="$withval/lib/pkgconfig" + ;; +esac + +if test X"$want_nghttp2" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libnghttp2 options with pkg-config" >&5 +printf %s "checking for libnghttp2 options with pkg-config... " >&6; } + itexists=` + if test -n "$want_nghttp2_pkg_config_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp2_pkg_config_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libnghttp2 >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_H2=` + if test -n "$want_nghttp2_pkg_config_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp2_pkg_config_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libnghttp2` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_H2" >&5 +printf "%s\n" "$as_me: -l is $LIB_H2" >&6;} + + CPP_H2=` + if test -n "$want_nghttp2_pkg_config_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp2_pkg_config_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libnghttp2` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_H2" >&5 +printf "%s\n" "$as_me: -I is $CPP_H2" >&6;} + + LD_H2=` + if test -n "$want_nghttp2_pkg_config_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp2_pkg_config_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libnghttp2` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_H2" >&5 +printf "%s\n" "$as_me: -L is $LD_H2" >&6;} + + DIR_H2=`echo $LD_H2 | $SED -e 's/^-L//'` + elif test x"$want_nghttp2_path" != x; then + LIB_H2="-lnghttp2" + LD_H2=-L${want_nghttp2_path}/lib$libsuff + CPP_H2=-I${want_nghttp2_path}/include + DIR_H2=${want_nghttp2_path}/lib$libsuff + elif test X"$want_nghttp2" != Xdefault; then + as_fn_error $? "--with-nghttp2 was specified but could not find libnghttp2 pkg-config file." "$LINENO" 5 + else + LIB_H2="-lnghttp2" + fi + + LDFLAGS="$LDFLAGS $LD_H2" + CPPFLAGS="$CPPFLAGS $CPP_H2" + LIBS="$LIB_H2 $LIBS" + + # use nghttp2_session_get_stream_local_window_size to require nghttp2 + # >= 1.15.0 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nghttp2_session_get_stream_local_window_size in -lnghttp2" >&5 +printf %s "checking for nghttp2_session_get_stream_local_window_size in -lnghttp2... " >&6; } +if test ${ac_cv_lib_nghttp2_nghttp2_session_get_stream_local_window_size+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnghttp2 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char nghttp2_session_get_stream_local_window_size (); +int main (void) +{ +return nghttp2_session_get_stream_local_window_size (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_nghttp2_nghttp2_session_get_stream_local_window_size=yes +else $as_nop + ac_cv_lib_nghttp2_nghttp2_session_get_stream_local_window_size=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nghttp2_nghttp2_session_get_stream_local_window_size" >&5 +printf "%s\n" "$ac_cv_lib_nghttp2_nghttp2_session_get_stream_local_window_size" >&6; } +if test "x$ac_cv_lib_nghttp2_nghttp2_session_get_stream_local_window_size" = xyes +then : + + for ac_header in nghttp2/nghttp2.h +do : + ac_fn_c_check_header_compile "$LINENO" "nghttp2/nghttp2.h" "ac_cv_header_nghttp2_nghttp2_h" "$ac_includes_default" +if test "x$ac_cv_header_nghttp2_nghttp2_h" = xyes +then : + printf "%s\n" "#define HAVE_NGHTTP2_NGHTTP2_H 1" >>confdefs.h + curl_h2_msg="enabled (nghttp2)" + NGHTTP2_ENABLED=1 + +printf "%s\n" "#define USE_NGHTTP2 1" >>confdefs.h + + USE_NGHTTP2=1 + + +fi + +done + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_H2" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_H2 to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_H2 to CURL_LIBRARY_PATH" >&6;} + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + +fi + + +OPT_TCP2="no" + +if test "x$disable_http" = "xyes"; then + # without HTTP, ngtcp2 is no use + OPT_TCP2="no" +fi + + +# Check whether --with-ngtcp2 was given. +if test ${with_ngtcp2+y} +then : + withval=$with_ngtcp2; OPT_TCP2=$withval +fi + +case "$OPT_TCP2" in + no) + want_tcp2="no" + ;; + yes) + want_tcp2="default" + want_tcp2_path="" + ;; + *) + want_tcp2="yes" + want_tcp2_path="$withval/lib/pkgconfig" + ;; +esac + +curl_tcp2_msg="no (--with-ngtcp2)" +if test X"$want_tcp2" != Xno; then + + if test "$QUIC_ENABLED" != "yes"; then + as_fn_error $? "the detected TLS library does not support QUIC, making --with-ngtcp2 a no-no" "$LINENO" 5 + fi + + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libngtcp2 options with pkg-config" >&5 +printf %s "checking for libngtcp2 options with pkg-config... " >&6; } + itexists=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libngtcp2 >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_TCP2=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libngtcp2` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_TCP2" >&5 +printf "%s\n" "$as_me: -l is $LIB_TCP2" >&6;} + + CPP_TCP2=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libngtcp2` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_TCP2" >&5 +printf "%s\n" "$as_me: -I is $CPP_TCP2" >&6;} + + LD_TCP2=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libngtcp2` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_TCP2" >&5 +printf "%s\n" "$as_me: -L is $LD_TCP2" >&6;} + + LDFLAGS="$LDFLAGS $LD_TCP2" + CPPFLAGS="$CPPFLAGS $CPP_TCP2" + LIBS="$LIB_TCP2 $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_TCP2=`echo $LD_TCP2 | $SED -e 's/^-L//'` + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_conn_client_new_versioned in -lngtcp2" >&5 +printf %s "checking for ngtcp2_conn_client_new_versioned in -lngtcp2... " >&6; } +if test ${ac_cv_lib_ngtcp2_ngtcp2_conn_client_new_versioned+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lngtcp2 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ngtcp2_conn_client_new_versioned (); +int main (void) +{ +return ngtcp2_conn_client_new_versioned (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ngtcp2_ngtcp2_conn_client_new_versioned=yes +else $as_nop + ac_cv_lib_ngtcp2_ngtcp2_conn_client_new_versioned=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_ngtcp2_conn_client_new_versioned" >&5 +printf "%s\n" "$ac_cv_lib_ngtcp2_ngtcp2_conn_client_new_versioned" >&6; } +if test "x$ac_cv_lib_ngtcp2_ngtcp2_conn_client_new_versioned" = xyes +then : + + for ac_header in ngtcp2/ngtcp2.h +do : + ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2.h" "ac_cv_header_ngtcp2_ngtcp2_h" "$ac_includes_default" +if test "x$ac_cv_header_ngtcp2_ngtcp2_h" = xyes +then : + printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_H 1" >>confdefs.h + NGTCP2_ENABLED=1 + +printf "%s\n" "#define USE_NGTCP2 1" >>confdefs.h + + USE_NGTCP2=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_TCP2" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_TCP2 to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_TCP2 to CURL_LIBRARY_PATH" >&6;} + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + + + else + if test X"$want_tcp2" != Xdefault; then + as_fn_error $? "--with-ngtcp2 was specified but could not find ngtcp2 pkg-config file." "$LINENO" 5 + fi + fi + +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$OPENSSL_ENABLED" = "x1" -a "x$OPENSSL_IS_BORINGSSL" != "x1"; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libngtcp2_crypto_quictls options with pkg-config" >&5 +printf %s "checking for libngtcp2_crypto_quictls options with pkg-config... " >&6; } + itexists=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libngtcp2_crypto_quictls >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_QUICTLS=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libngtcp2_crypto_quictls` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_NGTCP2_CRYPTO_QUICTLS" >&5 +printf "%s\n" "$as_me: -l is $LIB_NGTCP2_CRYPTO_QUICTLS" >&6;} + + CPP_NGTCP2_CRYPTO_QUICTLS=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libngtcp2_crypto_quictls` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_NGTCP2_CRYPTO_QUICTLS" >&5 +printf "%s\n" "$as_me: -I is $CPP_NGTCP2_CRYPTO_QUICTLS" >&6;} + + LD_NGTCP2_CRYPTO_QUICTLS=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libngtcp2_crypto_quictls` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_NGTCP2_CRYPTO_QUICTLS" >&5 +printf "%s\n" "$as_me: -L is $LD_NGTCP2_CRYPTO_QUICTLS" >&6;} + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_QUICTLS" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_QUICTLS" + LIBS="$LIB_NGTCP2_CRYPTO_QUICTLS $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_QUICTLS=`echo $LD_NGTCP2_CRYPTO_QUICTLS | $SED -e 's/^-L//'` + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_quictls" >&5 +printf %s "checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_quictls... " >&6; } +if test ${ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_recv_client_initial_cb+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lngtcp2_crypto_quictls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ngtcp2_crypto_recv_client_initial_cb (); +int main (void) +{ +return ngtcp2_crypto_recv_client_initial_cb (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_recv_client_initial_cb=yes +else $as_nop + ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_recv_client_initial_cb=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_recv_client_initial_cb" >&5 +printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_recv_client_initial_cb" >&6; } +if test "x$ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_recv_client_initial_cb" = xyes +then : + + for ac_header in ngtcp2/ngtcp2_crypto.h +do : + ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2_crypto.h" "ac_cv_header_ngtcp2_ngtcp2_crypto_h" "$ac_includes_default" +if test "x$ac_cv_header_ngtcp2_ngtcp2_crypto_h" = xyes +then : + printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_CRYPTO_H 1" >>confdefs.h + NGTCP2_ENABLED=1 + +printf "%s\n" "#define USE_NGTCP2_CRYPTO_QUICTLS 1" >>confdefs.h + + USE_NGTCP2_CRYPTO_QUICTLS=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_QUICTLS" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH" >&6;} + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + + + else + if test X"$want_tcp2" != Xdefault; then + as_fn_error $? "--with-ngtcp2 was specified but could not find ngtcp2_crypto_quictls pkg-config file." "$LINENO" 5 + fi + fi +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$OPENSSL_ENABLED" = "x1" -a "x$OPENSSL_IS_BORINGSSL" = "x1"; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libngtcp2_crypto_boringssl options with pkg-config" >&5 +printf %s "checking for libngtcp2_crypto_boringssl options with pkg-config... " >&6; } + itexists=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libngtcp2_crypto_boringssl >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_BORINGSSL=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libngtcp2_crypto_boringssl` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_NGTCP2_CRYPTO_BORINGSSL" >&5 +printf "%s\n" "$as_me: -l is $LIB_NGTCP2_CRYPTO_BORINGSSL" >&6;} + + CPP_NGTCP2_CRYPTO_BORINGSSL=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libngtcp2_crypto_boringssl` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_NGTCP2_CRYPTO_BORINGSSL" >&5 +printf "%s\n" "$as_me: -I is $CPP_NGTCP2_CRYPTO_BORINGSSL" >&6;} + + LD_NGTCP2_CRYPTO_BORINGSSL=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libngtcp2_crypto_boringssl` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_NGTCP2_CRYPTO_BORINGSSL" >&5 +printf "%s\n" "$as_me: -L is $LD_NGTCP2_CRYPTO_BORINGSSL" >&6;} + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_BORINGSSL" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_BORINGSSL" + LIBS="$LIB_NGTCP2_CRYPTO_BORINGSSL $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_BORINGSSL=`echo $LD_NGTCP2_CRYPTO_BORINGSSL | $SED -e 's/^-L//'` + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_boringssl" >&5 +printf %s "checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_boringssl... " >&6; } +if test ${ac_cv_lib_ngtcp2_crypto_boringssl_ngtcp2_crypto_recv_client_initial_cb+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lngtcp2_crypto_boringssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ngtcp2_crypto_recv_client_initial_cb (); +int main (void) +{ +return ngtcp2_crypto_recv_client_initial_cb (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ngtcp2_crypto_boringssl_ngtcp2_crypto_recv_client_initial_cb=yes +else $as_nop + ac_cv_lib_ngtcp2_crypto_boringssl_ngtcp2_crypto_recv_client_initial_cb=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_boringssl_ngtcp2_crypto_recv_client_initial_cb" >&5 +printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_boringssl_ngtcp2_crypto_recv_client_initial_cb" >&6; } +if test "x$ac_cv_lib_ngtcp2_crypto_boringssl_ngtcp2_crypto_recv_client_initial_cb" = xyes +then : + + for ac_header in ngtcp2/ngtcp2_crypto.h +do : + ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2_crypto.h" "ac_cv_header_ngtcp2_ngtcp2_crypto_h" "$ac_includes_default" +if test "x$ac_cv_header_ngtcp2_ngtcp2_crypto_h" = xyes +then : + printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_CRYPTO_H 1" >>confdefs.h + NGTCP2_ENABLED=1 + +printf "%s\n" "#define USE_NGTCP2_CRYPTO_BORINGSSL 1" >>confdefs.h + + USE_NGTCP2_CRYPTO_BORINGSSL=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_BORINGSSL" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH" >&6;} + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + + + else + if test X"$want_tcp2" != Xdefault; then + as_fn_error $? "--with-ngtcp2 was specified but could not find ngtcp2_crypto_boringssl pkg-config file." "$LINENO" 5 + fi + fi +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$GNUTLS_ENABLED" = "x1"; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libngtcp2_crypto_gnutls options with pkg-config" >&5 +printf %s "checking for libngtcp2_crypto_gnutls options with pkg-config... " >&6; } + itexists=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libngtcp2_crypto_gnutls >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_GNUTLS=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libngtcp2_crypto_gnutls` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_NGTCP2_CRYPTO_GNUTLS" >&5 +printf "%s\n" "$as_me: -l is $LIB_NGTCP2_CRYPTO_GNUTLS" >&6;} + + CPP_NGTCP2_CRYPTO_GNUTLS=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libngtcp2_crypto_gnutls` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_NGTCP2_CRYPTO_GNUTLS" >&5 +printf "%s\n" "$as_me: -I is $CPP_NGTCP2_CRYPTO_GNUTLS" >&6;} + + LD_NGTCP2_CRYPTO_GNUTLS=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libngtcp2_crypto_gnutls` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_NGTCP2_CRYPTO_GNUTLS" >&5 +printf "%s\n" "$as_me: -L is $LD_NGTCP2_CRYPTO_GNUTLS" >&6;} + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_GNUTLS" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_GNUTLS" + LIBS="$LIB_NGTCP2_CRYPTO_GNUTLS $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_GNUTLS=`echo $LD_NGTCP2_CRYPTO_GNUTLS | $SED -e 's/^-L//'` + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_gnutls" >&5 +printf %s "checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_gnutls... " >&6; } +if test ${ac_cv_lib_ngtcp2_crypto_gnutls_ngtcp2_crypto_recv_client_initial_cb+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lngtcp2_crypto_gnutls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ngtcp2_crypto_recv_client_initial_cb (); +int main (void) +{ +return ngtcp2_crypto_recv_client_initial_cb (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ngtcp2_crypto_gnutls_ngtcp2_crypto_recv_client_initial_cb=yes +else $as_nop + ac_cv_lib_ngtcp2_crypto_gnutls_ngtcp2_crypto_recv_client_initial_cb=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_gnutls_ngtcp2_crypto_recv_client_initial_cb" >&5 +printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_gnutls_ngtcp2_crypto_recv_client_initial_cb" >&6; } +if test "x$ac_cv_lib_ngtcp2_crypto_gnutls_ngtcp2_crypto_recv_client_initial_cb" = xyes +then : + + for ac_header in ngtcp2/ngtcp2_crypto.h +do : + ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2_crypto.h" "ac_cv_header_ngtcp2_ngtcp2_crypto_h" "$ac_includes_default" +if test "x$ac_cv_header_ngtcp2_ngtcp2_crypto_h" = xyes +then : + printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_CRYPTO_H 1" >>confdefs.h + NGTCP2_ENABLED=1 + +printf "%s\n" "#define USE_NGTCP2_CRYPTO_GNUTLS 1" >>confdefs.h + + USE_NGTCP2_CRYPTO_GNUTLS=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_GNUTLS" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH" >&6;} + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + + + else + if test X"$want_tcp2" != Xdefault; then + as_fn_error $? "--with-ngtcp2 was specified but could not find ngtcp2_crypto_gnutls pkg-config file." "$LINENO" 5 + fi + fi +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$WOLFSSL_ENABLED" = "x1"; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libngtcp2_crypto_wolfssl options with pkg-config" >&5 +printf %s "checking for libngtcp2_crypto_wolfssl options with pkg-config... " >&6; } + itexists=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libngtcp2_crypto_wolfssl >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_WOLFSSL=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libngtcp2_crypto_wolfssl` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_NGTCP2_CRYPTO_WOLFSSL" >&5 +printf "%s\n" "$as_me: -l is $LIB_NGTCP2_CRYPTO_WOLFSSL" >&6;} + + CPP_NGTCP2_CRYPTO_WOLFSSL=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libngtcp2_crypto_wolfssl` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_NGTCP2_CRYPTO_WOLFSSL" >&5 +printf "%s\n" "$as_me: -I is $CPP_NGTCP2_CRYPTO_WOLFSSL" >&6;} + + LD_NGTCP2_CRYPTO_WOLFSSL=` + if test -n "$want_tcp2_path"; then + PKG_CONFIG_LIBDIR="$want_tcp2_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libngtcp2_crypto_wolfssl` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_NGTCP2_CRYPTO_WOLFSSL" >&5 +printf "%s\n" "$as_me: -L is $LD_NGTCP2_CRYPTO_WOLFSSL" >&6;} + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_WOLFSSL" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_WOLFSSL" + LIBS="$LIB_NGTCP2_CRYPTO_WOLFSSL $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_WOLFSSL=`echo $LD_NGTCP2_CRYPTO_WOLFSSL | $SED -e 's/^-L//'` + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_wolfssl" >&5 +printf %s "checking for ngtcp2_crypto_recv_client_initial_cb in -lngtcp2_crypto_wolfssl... " >&6; } +if test ${ac_cv_lib_ngtcp2_crypto_wolfssl_ngtcp2_crypto_recv_client_initial_cb+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lngtcp2_crypto_wolfssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char ngtcp2_crypto_recv_client_initial_cb (); +int main (void) +{ +return ngtcp2_crypto_recv_client_initial_cb (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ngtcp2_crypto_wolfssl_ngtcp2_crypto_recv_client_initial_cb=yes +else $as_nop + ac_cv_lib_ngtcp2_crypto_wolfssl_ngtcp2_crypto_recv_client_initial_cb=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_wolfssl_ngtcp2_crypto_recv_client_initial_cb" >&5 +printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_wolfssl_ngtcp2_crypto_recv_client_initial_cb" >&6; } +if test "x$ac_cv_lib_ngtcp2_crypto_wolfssl_ngtcp2_crypto_recv_client_initial_cb" = xyes +then : + + for ac_header in ngtcp2/ngtcp2_crypto.h +do : + ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2_crypto.h" "ac_cv_header_ngtcp2_ngtcp2_crypto_h" "$ac_includes_default" +if test "x$ac_cv_header_ngtcp2_ngtcp2_crypto_h" = xyes +then : + printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_CRYPTO_H 1" >>confdefs.h + NGTCP2_ENABLED=1 + +printf "%s\n" "#define USE_NGTCP2_CRYPTO_WOLFSSL 1" >>confdefs.h + + USE_NGTCP2_CRYPTO_WOLFSSL=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_WOLFSSL" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH" >&6;} + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + + + else + if test X"$want_tcp2" != Xdefault; then + as_fn_error $? "--with-ngtcp2 was specified but could not find ngtcp2_crypto_wolfssl pkg-config file." "$LINENO" 5 + fi + fi +fi + + +OPT_OPENSSL_QUIC="no" + +if test "x$disable_http" = "xyes" -o "x$OPENSSL_ENABLED" != "x1"; then + # without HTTP or without openssl, no use + OPT_OPENSSL_QUIC="no" +fi + + +# Check whether --with-openssl-quic was given. +if test ${with_openssl_quic+y} +then : + withval=$with_openssl_quic; OPT_OPENSSL_QUIC=$withval +fi + +case "$OPT_OPENSSL_QUIC" in + no) + want_openssl_quic="no" + ;; + yes) + want_openssl_quic="yes" + ;; +esac + +curl_openssl_quic_msg="no (--with-openssl-quic)" +if test "x$want_openssl_quic" = "xyes"; then + + if test "$NGTCP2_ENABLED" = 1; then + as_fn_error $? "--with-openssl-quic and --with-ngtcp2 are mutually exclusive" "$LINENO" 5 + fi + if test "$HAVE_OPENSSL_QUIC" != 1; then + as_fn_error $? "--with-openssl-quic requires quic support in OpenSSL" "$LINENO" 5 + fi + +printf "%s\n" "#define USE_OPENSSL_QUIC 1" >>confdefs.h + + USE_OPENSSL_QUIC=1 + +fi + + +OPT_NGHTTP3="yes" + +if test "x$USE_NGTCP2" = "x" -a "$USE_OPENSSL_QUIC" = "x"; then + # without ngtcp2 or openssl quic, nghttp3 is of no use for us + OPT_NGHTTP3="no" +fi + + +# Check whether --with-nghttp3 was given. +if test ${with_nghttp3+y} +then : + withval=$with_nghttp3; OPT_NGHTTP3=$withval +fi + +case "$OPT_NGHTTP3" in + no) + want_nghttp3="no" + ;; + yes) + want_nghttp3="default" + want_nghttp3_path="" + ;; + *) + want_nghttp3="yes" + want_nghttp3_path="$withval/lib/pkgconfig" + ;; +esac + +curl_http3_msg="no (--with-nghttp3)" +if test X"$want_nghttp3" != Xno; then + + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libnghttp3 options with pkg-config" >&5 +printf %s "checking for libnghttp3 options with pkg-config... " >&6; } + itexists=` + if test -n "$want_nghttp3_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp3_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libnghttp3 >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_NGHTTP3=` + if test -n "$want_nghttp3_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp3_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libnghttp3` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_NGHTTP3" >&5 +printf "%s\n" "$as_me: -l is $LIB_NGHTTP3" >&6;} + + CPP_NGHTTP3=` + if test -n "$want_nghttp3_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp3_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I libnghttp3` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_NGHTTP3" >&5 +printf "%s\n" "$as_me: -I is $CPP_NGHTTP3" >&6;} + + LD_NGHTTP3=` + if test -n "$want_nghttp3_path"; then + PKG_CONFIG_LIBDIR="$want_nghttp3_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libnghttp3` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_NGHTTP3" >&5 +printf "%s\n" "$as_me: -L is $LD_NGHTTP3" >&6;} + + LDFLAGS="$LDFLAGS $LD_NGHTTP3" + CPPFLAGS="$CPPFLAGS $CPP_NGHTTP3" + LIBS="$LIB_NGHTTP3 $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGHTTP3=`echo $LD_NGHTTP3 | $SED -e 's/^-L//'` + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nghttp3_conn_client_new_versioned in -lnghttp3" >&5 +printf %s "checking for nghttp3_conn_client_new_versioned in -lnghttp3... " >&6; } +if test ${ac_cv_lib_nghttp3_nghttp3_conn_client_new_versioned+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnghttp3 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char nghttp3_conn_client_new_versioned (); +int main (void) +{ +return nghttp3_conn_client_new_versioned (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_nghttp3_nghttp3_conn_client_new_versioned=yes +else $as_nop + ac_cv_lib_nghttp3_nghttp3_conn_client_new_versioned=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nghttp3_nghttp3_conn_client_new_versioned" >&5 +printf "%s\n" "$ac_cv_lib_nghttp3_nghttp3_conn_client_new_versioned" >&6; } +if test "x$ac_cv_lib_nghttp3_nghttp3_conn_client_new_versioned" = xyes +then : + + for ac_header in nghttp3/nghttp3.h +do : + ac_fn_c_check_header_compile "$LINENO" "nghttp3/nghttp3.h" "ac_cv_header_nghttp3_nghttp3_h" "$ac_includes_default" +if test "x$ac_cv_header_nghttp3_nghttp3_h" = xyes +then : + printf "%s\n" "#define HAVE_NGHTTP3_NGHTTP3_H 1" >>confdefs.h + +printf "%s\n" "#define USE_NGHTTP3 1" >>confdefs.h + + USE_NGHTTP3=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGHTTP3" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH" >&6;} + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + + + else + if test X"$want_nghttp3" != Xdefault; then + as_fn_error $? "--with-nghttp3 was specified but could not find nghttp3 pkg-config file." "$LINENO" 5 + fi + fi + +fi + + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$USE_NGHTTP3" = "x1"; then + +printf "%s\n" "#define USE_NGTCP2_H3 1" >>confdefs.h + + USE_NGTCP2_H3=1 + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: HTTP3 support is experimental" >&5 +printf "%s\n" "$as_me: HTTP3 support is experimental" >&6;} + curl_h3_msg="enabled (ngtcp2 + nghttp3)" +fi + + +if test "x$USE_OPENSSL_QUIC" = "x1" -a "x$USE_NGHTTP3" = "x1"; then + experimental="$experimental HTTP3" + +printf "%s\n" "#define USE_OPENSSL_H3 1" >>confdefs.h + + USE_OPENSSL_H3=1 + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: HTTP3 support is experimental" >&5 +printf "%s\n" "$as_me: HTTP3 support is experimental" >&6;} + curl_h3_msg="enabled (openssl + nghttp3)" +fi + + +OPT_QUICHE="no" + +if test "x$disable_http" = "xyes" -o "x$USE_NGTCP" = "x1"; then + # without HTTP or with ngtcp2, quiche is no use + OPT_QUICHE="no" +fi + + +# Check whether --with-quiche was given. +if test ${with_quiche+y} +then : + withval=$with_quiche; OPT_QUICHE=$withval +fi + +case "$OPT_QUICHE" in + no) + want_quiche="no" + ;; + yes) + want_quiche="default" + want_quiche_path="" + ;; + *) + want_quiche="yes" + want_quiche_path="$withval" + ;; +esac + +if test X"$want_quiche" != Xno; then + + if test "$QUIC_ENABLED" != "yes"; then + as_fn_error $? "the detected TLS library does not support QUIC, making --with-quiche a no-no" "$LINENO" 5 + fi + + if test "$NGHTTP3_ENABLED" = 1; then + as_fn_error $? "--with-quiche and --with-ngtcp2 are mutually exclusive" "$LINENO" 5 + fi + + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for quiche options with pkg-config" >&5 +printf %s "checking for quiche options with pkg-config... " >&6; } + itexists=` + if test -n "$want_quiche_path"; then + PKG_CONFIG_LIBDIR="$want_quiche_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists quiche >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + + if test "$PKGCONFIG" != "no" ; then + LIB_QUICHE=` + if test -n "$want_quiche_path"; then + PKG_CONFIG_LIBDIR="$want_quiche_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l quiche` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -l is $LIB_QUICHE" >&5 +printf "%s\n" "$as_me: -l is $LIB_QUICHE" >&6;} + + CPP_QUICHE=` + if test -n "$want_quiche_path"; then + PKG_CONFIG_LIBDIR="$want_quiche_path" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --cflags-only-I quiche` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -I is $CPP_QUICHE" >&5 +printf "%s\n" "$as_me: -I is $CPP_QUICHE" >&6;} + + LD_QUICHE=` + if test -n "$want_quiche_path"; then + PKG_CONFIG_LIBDIR="$want_quiche_path" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L quiche` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -L is $LD_QUICHE" >&5 +printf "%s\n" "$as_me: -L is $LD_QUICHE" >&6;} + + LDFLAGS="$LDFLAGS $LD_QUICHE" + CPPFLAGS="$CPPFLAGS $CPP_QUICHE" + LIBS="$LIB_QUICHE $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_QUICHE=`echo $LD_QUICHE | $SED -e 's/^-L//'` + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for quiche_conn_send_ack_eliciting in -lquiche" >&5 +printf %s "checking for quiche_conn_send_ack_eliciting in -lquiche... " >&6; } +if test ${ac_cv_lib_quiche_quiche_conn_send_ack_eliciting+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lquiche $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char quiche_conn_send_ack_eliciting (); +int main (void) +{ +return quiche_conn_send_ack_eliciting (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_quiche_quiche_conn_send_ack_eliciting=yes +else $as_nop + ac_cv_lib_quiche_quiche_conn_send_ack_eliciting=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_quiche_quiche_conn_send_ack_eliciting" >&5 +printf "%s\n" "$ac_cv_lib_quiche_quiche_conn_send_ack_eliciting" >&6; } +if test "x$ac_cv_lib_quiche_quiche_conn_send_ack_eliciting" = xyes +then : + + for ac_header in quiche.h +do : + ac_fn_c_check_header_compile "$LINENO" "quiche.h" "ac_cv_header_quiche_h" " +$ac_includes_default +#include + + +" +if test "x$ac_cv_header_quiche_h" = xyes +then : + printf "%s\n" "#define HAVE_QUICHE_H 1" >>confdefs.h + experimental="$experimental HTTP3" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: HTTP3 support is experimental" >&5 +printf "%s\n" "$as_me: HTTP3 support is experimental" >&6;} + curl_h3_msg="enabled (quiche)" + QUICHE_ENABLED=1 + +printf "%s\n" "#define USE_QUICHE 1" >>confdefs.h + + USE_QUICHE=1 + + ac_fn_c_check_func "$LINENO" "quiche_conn_set_qlog_fd" "ac_cv_func_quiche_conn_set_qlog_fd" +if test "x$ac_cv_func_quiche_conn_set_qlog_fd" = xyes +then : + printf "%s\n" "#define HAVE_QUICHE_CONN_SET_QLOG_FD 1" >>confdefs.h + +fi + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_QUICHE" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_QUICHE to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_QUICHE to CURL_LIBRARY_PATH" >&6;} +fi + +done + +else $as_nop + as_fn_error $? "couldn't use quiche" "$LINENO" 5 + +fi + + else + if test X"$want_quiche" != Xdefault; then + as_fn_error $? "--with-quiche was specified but could not find quiche pkg-config file." "$LINENO" 5 + fi + fi +fi + + +OPT_MSH3="no" + +if test "x$disable_http" = "xyes" -o "x$USE_NGTCP" = "x1"; then + # without HTTP or with ngtcp2, msh3 is no use + OPT_MSH3="no" +fi + + +# Check whether --with-msh3 was given. +if test ${with_msh3+y} +then : + withval=$with_msh3; OPT_MSH3=$withval +fi + +case "$OPT_MSH3" in + no) + want_msh3="no" + ;; + yes) + want_msh3="default" + want_msh3_path="" + ;; + *) + want_msh3="yes" + want_msh3_path="$withval" + ;; +esac + +if test X"$want_msh3" != Xno; then + + if test "$curl_cv_native_windows" != "yes"; then + if test "$QUIC_ENABLED" != "yes"; then + as_fn_error $? "the detected TLS library does not support QUIC, making --with-msh3 a no-no" "$LINENO" 5 + fi + if test "$OPENSSL_ENABLED" != "1"; then + as_fn_error $? "msh3 requires OpenSSL" "$LINENO" 5 + fi + fi + + if test "$NGHTTP3_ENABLED" = 1; then + as_fn_error $? "--with-msh3 and --with-ngtcp2 are mutually exclusive" "$LINENO" 5 + fi + if test "$QUICHE_ENABLED" = 1; then + as_fn_error $? "--with-msh3 and --with-quiche are mutually exclusive" "$LINENO" 5 + fi + + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + if test -n "$want_msh3_path"; then + LD_MSH3="-L$want_msh3_path/lib" + CPP_MSH3="-I$want_msh3_path/include" + DIR_MSH3="$want_msh3_path/lib" + LDFLAGS="$LDFLAGS $LD_MSH3" + CPPFLAGS="$CPPFLAGS $CPP_MSH3" + fi + LIBS="-lmsh3 $LIBS" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MsH3ApiOpen in -lmsh3" >&5 +printf %s "checking for MsH3ApiOpen in -lmsh3... " >&6; } +if test ${ac_cv_lib_msh3_MsH3ApiOpen+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmsh3 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char MsH3ApiOpen (); +int main (void) +{ +return MsH3ApiOpen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_msh3_MsH3ApiOpen=yes +else $as_nop + ac_cv_lib_msh3_MsH3ApiOpen=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_msh3_MsH3ApiOpen" >&5 +printf "%s\n" "$ac_cv_lib_msh3_MsH3ApiOpen" >&6; } +if test "x$ac_cv_lib_msh3_MsH3ApiOpen" = xyes +then : + + for ac_header in msh3.h +do : + ac_fn_c_check_header_compile "$LINENO" "msh3.h" "ac_cv_header_msh3_h" "$ac_includes_default" +if test "x$ac_cv_header_msh3_h" = xyes +then : + printf "%s\n" "#define HAVE_MSH3_H 1" >>confdefs.h + curl_h3_msg="enabled (msh3)" + MSH3_ENABLED=1 + +printf "%s\n" "#define USE_MSH3 1" >>confdefs.h + + USE_MSH3=1 + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_MSH3" + export CURL_LIBRARY_PATH + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_MSH3 to CURL_LIBRARY_PATH" >&5 +printf "%s\n" "$as_me: Added $DIR_MSH3 to CURL_LIBRARY_PATH" >&6;} +else $as_nop + experimental="$experimental HTTP3" + +fi + +done + +else $as_nop + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + +fi + +fi + + +OPT_ZSH_FPATH=default + +# Check whether --with-zsh-functions-dir was given. +if test ${with_zsh_functions_dir+y} +then : + withval=$with_zsh_functions_dir; OPT_ZSH_FPATH=$withval +fi + +case "$OPT_ZSH_FPATH" in + no) + ;; + default|yes) + ZSH_FUNCTIONS_DIR="$datarootdir/zsh/site-functions" + + ;; + *) + ZSH_FUNCTIONS_DIR="$withval" + + ;; +esac + + +OPT_FISH_FPATH=default + +# Check whether --with-fish-functions-dir was given. +if test ${with_fish_functions_dir+y} +then : + withval=$with_fish_functions_dir; OPT_FISH_FPATH=$withval +fi + +case "$OPT_FISH_FPATH" in + no) + ;; + default|yes) + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fish options with pkg-config" >&5 +printf %s "checking for fish options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists fish >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + if test "$PKGCONFIG" != "no" ; then + FISH_FUNCTIONS_DIR="$($PKGCONFIG --variable completionsdir fish)" + else + FISH_FUNCTIONS_DIR="$datarootdir/fish/vendor_completions.d" + fi + + ;; + *) + FISH_FUNCTIONS_DIR="$withval" + + ;; +esac + +ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_time_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_select_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_ioctl_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_unistd_h" = xyes +then : + printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_stdlib_h" = xyes +then : + printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_arpa_inet_h" = xyes +then : + printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_net_if_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_netinet_in_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/in6.h" "ac_cv_header_netinet_in6_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_netinet_in6_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_IN6_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_un_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/tcp.h" "ac_cv_header_linux_tcp_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_linux_tcp_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_TCP_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_netinet_tcp_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_TCP_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/udp.h" "ac_cv_header_netinet_udp_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_netinet_udp_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_UDP_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_netdb_h" = xyes +then : + printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sockio.h" "ac_cv_header_sys_sockio_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_sockio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKIO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_stat_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_STAT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_param_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "termios.h" "ac_cv_header_termios_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_termios_h" = xyes +then : + printf "%s\n" "#define HAVE_TERMIOS_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "termio.h" "ac_cv_header_termio_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_termio_h" = xyes +then : + printf "%s\n" "#define HAVE_TERMIO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_fcntl_h" = xyes +then : + printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "io.h" "ac_cv_header_io_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_io_h" = xyes +then : + printf "%s\n" "#define HAVE_IO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "pwd.h" "ac_cv_header_pwd_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_pwd_h" = xyes +then : + printf "%s\n" "#define HAVE_PWD_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_utime_h" = xyes +then : + printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/utime.h" "ac_cv_header_sys_utime_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_utime_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_UTIME_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_poll_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_POLL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_poll_h" = xyes +then : + printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "socket.h" "ac_cv_header_socket_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SOCKET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_resource_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_RESOURCE_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "libgen.h" "ac_cv_header_libgen_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_libgen_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBGEN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "locale.h" "ac_cv_header_locale_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_locale_h" = xyes +then : + printf "%s\n" "#define HAVE_LOCALE_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_stdbool_h" = xyes +then : + printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_filio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_FILIO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_sys_wait_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + +" +if test "x$ac_cv_header_setjmp_h" = xyes +then : + printf "%s\n" "#define HAVE_SETJMP_H 1" >>confdefs.h + +fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +printf %s "checking for an ANSI C-conforming const... " >&6; } +if test ${ac_cv_c_const+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ + +#ifndef __cplusplus + /* Ultrix mips cc rejects this sort of thing. */ + typedef int charset[2]; + const charset cs = { 0, 0 }; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* IBM XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this sort of thing. */ + char tx; + char *t = &tx; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; } bx; + struct s *b = &bx; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_c_const=yes +else $as_nop + ac_cv_c_const=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +printf "%s\n" "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +printf "%s\n" "#define const /**/" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes +then : + +else $as_nop + +printf "%s\n" "#define size_t unsigned int" >>confdefs.h + +fi + + + + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timeval" >&5 +printf %s "checking for struct timeval... " >&6; } +if test ${curl_cv_struct_timeval+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +int main (void) +{ + + struct timeval ts; + ts.tv_sec = 0; + ts.tv_usec = 0; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_struct_timeval="yes" + +else $as_nop + + curl_cv_struct_timeval="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_struct_timeval" >&5 +printf "%s\n" "$curl_cv_struct_timeval" >&6; } + case "$curl_cv_struct_timeval" in + yes) + +printf "%s\n" "#define HAVE_STRUCT_TIMEVAL 1" >>confdefs.h + + ;; + esac + + + + if test "x$cross_compiling" != xyes; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking run-time libs availability" >&5 +printf %s "checking run-time libs availability... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main() +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: fine" >&5 +printf "%s\n" "fine" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +printf "%s\n" "failed" >&6; } + as_fn_error $? "one or more libs available at link-time are not available run-time. Libs used at link-time: $LIBS" "$LINENO" 5 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main() +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: fine" >&5 +printf "%s\n" "fine" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +printf "%s\n" "failed" >&6; } + as_fn_error $? "one or more libs available at link-time are not available run-time. Libs used at link-time: $LIBS" "$LINENO" 5 + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + + fi + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 +printf %s "checking size of size_t... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(size_t) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of size_t" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_size_t" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_SIZE_T $r" >>confdefs.h + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +printf %s "checking size of long... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(long) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of long" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_long" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_LONG $r" >>confdefs.h + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +printf %s "checking size of int... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(int) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of int" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_int" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_INT $r" >>confdefs.h + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 +printf %s "checking size of time_t... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(time_t) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of time_t" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_time_t" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_TIME_T $r" >>confdefs.h + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 +printf %s "checking size of off_t... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(off_t) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of off_t" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_off_t" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_OFF_T $r" >>confdefs.h + + + + +o=$CPPFLAGS +CPPFLAGS="-I$srcdir/include $CPPFLAGS" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of curl_off_t" >&5 +printf %s "checking size of curl_off_t... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(curl_off_t) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of curl_off_t" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_curl_off_t" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_CURL_OFF_T $r" >>confdefs.h + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of curl_socket_t" >&5 +printf %s "checking size of curl_socket_t... " >&6; } + r=0 + for typesize in 8 4 2 16 1; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +#include + + +int main (void) +{ +switch(0) { + case 0: + case (sizeof(curl_socket_t) == $typesize):; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + r=$typesize +else $as_nop + + r=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + as_fn_error $? "Failed to find size of curl_socket_t" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5 +printf "%s\n" "$r" >&6; } + tname=$(echo "ac_cv_sizeof_curl_socket_t" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + +printf "%s\n" "#define SIZEOF_CURL_SOCKET_T $r" >>confdefs.h + + + +CPPFLAGS=$o + +ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default" +if test "x$ac_cv_type_long_long" = xyes +then : + +printf "%s\n" "#define HAVE_LONGLONG 1" >>confdefs.h + + longlong="yes" + +fi + + +if test ${ac_cv_sizeof_curl_off_t} -lt 8; then + as_fn_error $? "64 bit curl_off_t is required" "$LINENO" 5 +fi + +# check for ssize_t +ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = xyes +then : + +else $as_nop + +printf "%s\n" "#define ssize_t int" >>confdefs.h + +fi + + +# check for bool type +ac_fn_c_check_type "$LINENO" "bool" "ac_cv_type_bool" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_STDBOOL_H +#include +#endif + +" +if test "x$ac_cv_type_bool" = xyes +then : + + +printf "%s\n" "#define HAVE_BOOL_T 1" >>confdefs.h + + +fi + + +# check for sa_family_t +ac_fn_c_check_type "$LINENO" "sa_family_t" "ac_cv_type_sa_family_t" " +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_type_sa_family_t" = xyes +then : + +printf "%s\n" "#define CURL_SA_FAMILY_T sa_family_t" >>confdefs.h + +else $as_nop + + # The windows name? + ac_fn_c_check_type "$LINENO" "ADDRESS_FAMILY" "ac_cv_type_ADDRESS_FAMILY" " +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_type_ADDRESS_FAMILY" = xyes +then : + +printf "%s\n" "#define CURL_SA_FAMILY_T ADDRESS_FAMILY" >>confdefs.h + +else $as_nop + +printf "%s\n" "#define CURL_SA_FAMILY_T unsigned short" >>confdefs.h + +fi + + +fi + + +# check for suseconds_t +ac_fn_c_check_type "$LINENO" "suseconds_t" "ac_cv_type_suseconds_t" " +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + +" +if test "x$ac_cv_type_suseconds_t" = xyes +then : + + +printf "%s\n" "#define HAVE_SUSECONDS_T 1" >>confdefs.h + + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if time_t is unsigned" >&5 +printf %s "checking if time_t is unsigned... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + int main(void) { + time_t t = -1; + return (t < 0); + } + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_TIME_T_UNSIGNED 1" >>confdefs.h + + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + int main(void) { + time_t t = -1; + return (t < 0); + } + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_TIME_T_UNSIGNED 1" >>confdefs.h + + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + + + ac_fn_c_check_type "$LINENO" "in_addr_t" "ac_cv_type_in_addr_t" " +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#endif + +" +if test "x$ac_cv_type_in_addr_t" = xyes +then : + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for in_addr_t equivalent" >&5 +printf %s "checking for in_addr_t equivalent... " >&6; } +if test ${curl_cv_in_addr_t_equiv+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + curl_cv_in_addr_t_equiv="unknown" + for t in "unsigned long" int size_t unsigned long; do + if test "$curl_cv_in_addr_t_equiv" = "unknown"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#endif + +int main (void) +{ + + $t data = inet_addr ("1.2.3.4"); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + curl_cv_in_addr_t_equiv="$t" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + done + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_in_addr_t_equiv" >&5 +printf "%s\n" "$curl_cv_in_addr_t_equiv" >&6; } + case "$curl_cv_in_addr_t_equiv" in + unknown) + as_fn_error $? "Cannot find a type to use in place of in_addr_t" "$LINENO" 5 + ;; + *) + +printf "%s\n" "#define in_addr_t $curl_cv_in_addr_t_equiv" >>confdefs.h + + ;; + esac + +fi + + + + + ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" " +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#endif + +" +if test "x$ac_cv_type_struct_sockaddr_storage" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h + +fi + + + + + ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_select_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi + + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for select" >&5 +printf %s "checking for select... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include +#ifndef _WIN32 +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +$curl_includes_bsdsocket +#endif + +int main (void) +{ + + select(0, 0, 0, 0, 0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + curl_cv_select="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_select="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$curl_cv_select" = "yes"; then + +printf "%s\n" "#define HAVE_SELECT 1" >>confdefs.h + + curl_cv_func_select="yes" + fi + + + + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi + + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for recv" >&5 +printf %s "checking for recv... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +$curl_includes_bsdsocket +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#endif + +int main (void) +{ + + recv(0, 0, 0, 0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + curl_cv_recv="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_recv="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$curl_cv_recv" = "yes"; then + +printf "%s\n" "#define HAVE_RECV 1" >>confdefs.h + + curl_cv_func_recv="yes" + else + as_fn_error $? "Unable to link function recv" "$LINENO" 5 + fi + + + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi + + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for send" >&5 +printf %s "checking for send... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +$curl_includes_bsdsocket +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#endif + +int main (void) +{ + + send(0, 0, 0, 0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + curl_cv_send="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_send="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$curl_cv_send" = "yes"; then + +printf "%s\n" "#define HAVE_SEND 1" >>confdefs.h + + curl_cv_func_send="yes" + else + as_fn_error $? "Unable to link function send" "$LINENO" 5 + fi + + + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MSG_NOSIGNAL" >&5 +printf %s "checking for MSG_NOSIGNAL... " >&6; } +if test ${curl_cv_msg_nosignal+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#undef inline +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#endif + +int main (void) +{ + + int flag=MSG_NOSIGNAL; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_msg_nosignal="yes" + +else $as_nop + + curl_cv_msg_nosignal="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_msg_nosignal" >&5 +printf "%s\n" "$curl_cv_msg_nosignal" >&6; } + case "$curl_cv_msg_nosignal" in + yes) + +printf "%s\n" "#define HAVE_MSG_NOSIGNAL 1" >>confdefs.h + + ;; + esac + + + +curl_includes_unistd="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_unistd +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$curl_includes_unistd +" +if test "x$ac_cv_header_unistd_h" = xyes +then : + printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h + +fi + + + + # + tst_links_alarm="unknown" + tst_proto_alarm="unknown" + tst_compi_alarm="unknown" + tst_allow_alarm="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if alarm can be linked" >&5 +printf %s "checking if alarm can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define alarm innocuous_alarm +#ifdef __STDC__ +# include +#else +# include +#endif +#undef alarm +#ifdef __cplusplus +extern "C" +#endif +char alarm (); +#if defined __stub_alarm || defined __stub___alarm +choke me +#endif + +int main (void) +{ +return alarm (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_alarm="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_alarm="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_alarm" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if alarm is prototyped" >&5 +printf %s "checking if alarm is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_unistd + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "alarm" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_alarm="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_alarm="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_alarm" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if alarm is compilable" >&5 +printf %s "checking if alarm is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_unistd + +int main (void) +{ + + if(0 != alarm(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_alarm="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_alarm="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_alarm" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if alarm usage allowed" >&5 +printf %s "checking if alarm usage allowed... " >&6; } + if test "x$curl_disallow_alarm" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_alarm="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_alarm="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if alarm might be used" >&5 +printf %s "checking if alarm might be used... " >&6; } + if test "$tst_links_alarm" = "yes" && + test "$tst_proto_alarm" = "yes" && + test "$tst_compi_alarm" = "yes" && + test "$tst_allow_alarm" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_ALARM 1" >>confdefs.h + + curl_cv_func_alarm="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_alarm="no" + fi + + +curl_includes_string="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +#ifdef HAVE_STRINGS_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_string +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "strings.h" "ac_cv_header_strings_h" "$curl_includes_string +" +if test "x$ac_cv_header_strings_h" = xyes +then : + printf "%s\n" "#define HAVE_STRINGS_H 1" >>confdefs.h + +fi + + + +curl_includes_libgen="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_LIBGEN_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_libgen +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "libgen.h" "ac_cv_header_libgen_h" "$curl_includes_libgen +" +if test "x$ac_cv_header_libgen_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBGEN_H 1" >>confdefs.h + +fi + + + + # + tst_links_basename="unknown" + tst_proto_basename="unknown" + tst_compi_basename="unknown" + tst_allow_basename="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if basename can be linked" >&5 +printf %s "checking if basename can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define basename innocuous_basename +#ifdef __STDC__ +# include +#else +# include +#endif +#undef basename +#ifdef __cplusplus +extern "C" +#endif +char basename (); +#if defined __stub_basename || defined __stub___basename +choke me +#endif + +int main (void) +{ +return basename (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_basename="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_basename="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_basename" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if basename is prototyped" >&5 +printf %s "checking if basename is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + $curl_includes_libgen + $curl_includes_unistd + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "basename" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_basename="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_basename="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_basename" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if basename is compilable" >&5 +printf %s "checking if basename is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + $curl_includes_libgen + $curl_includes_unistd + +int main (void) +{ + + if(0 != basename(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_basename="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_basename="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_basename" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if basename usage allowed" >&5 +printf %s "checking if basename usage allowed... " >&6; } + if test "x$curl_disallow_basename" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_basename="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_basename="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if basename might be used" >&5 +printf %s "checking if basename might be used... " >&6; } + if test "$tst_links_basename" = "yes" && + test "$tst_proto_basename" = "yes" && + test "$tst_compi_basename" = "yes" && + test "$tst_allow_basename" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_BASENAME 1" >>confdefs.h + + curl_cv_func_basename="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_basename="no" + fi + + +curl_includes_socket="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SOCKET_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_socket +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "socket.h" "ac_cv_header_socket_h" "$curl_includes_socket +" +if test "x$ac_cv_header_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SOCKET_H 1" >>confdefs.h + +fi + + + + # + tst_links_closesocket="unknown" + tst_proto_closesocket="unknown" + tst_compi_closesocket="unknown" + tst_allow_closesocket="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if closesocket can be linked" >&5 +printf %s "checking if closesocket can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_socket + +int main (void) +{ + + if(0 != closesocket(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_closesocket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_closesocket="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_closesocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if closesocket is prototyped" >&5 +printf %s "checking if closesocket is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + $curl_includes_socket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "closesocket" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_closesocket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_closesocket="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_closesocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if closesocket is compilable" >&5 +printf %s "checking if closesocket is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_socket + +int main (void) +{ + + if(0 != closesocket(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_closesocket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_closesocket="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_closesocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if closesocket usage allowed" >&5 +printf %s "checking if closesocket usage allowed... " >&6; } + if test "x$curl_disallow_closesocket" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_closesocket="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_closesocket="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if closesocket might be used" >&5 +printf %s "checking if closesocket might be used... " >&6; } + if test "$tst_links_closesocket" = "yes" && + test "$tst_proto_closesocket" = "yes" && + test "$tst_compi_closesocket" = "yes" && + test "$tst_allow_closesocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_CLOSESOCKET 1" >>confdefs.h + + curl_cv_func_closesocket="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_closesocket="no" + fi + + +curl_includes_sys_socket="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_sys_socket +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$curl_includes_sys_socket +" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi + + + + # + tst_links_closesocket_camel="unknown" + tst_proto_closesocket_camel="unknown" + tst_compi_closesocket_camel="unknown" + tst_allow_closesocket_camel="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if CloseSocket can be linked" >&5 +printf %s "checking if CloseSocket can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_bsdsocket + $curl_includes_sys_socket + +int main (void) +{ + + if(0 != CloseSocket(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_closesocket_camel="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_closesocket_camel="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_closesocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if CloseSocket is prototyped" >&5 +printf %s "checking if CloseSocket is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_bsdsocket + $curl_includes_sys_socket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "CloseSocket" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_closesocket_camel="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_closesocket_camel="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_closesocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if CloseSocket is compilable" >&5 +printf %s "checking if CloseSocket is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_bsdsocket + $curl_includes_sys_socket + +int main (void) +{ + + if(0 != CloseSocket(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_closesocket_camel="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_closesocket_camel="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_closesocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if CloseSocket usage allowed" >&5 +printf %s "checking if CloseSocket usage allowed... " >&6; } + if test "x$curl_disallow_closesocket_camel" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_closesocket_camel="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_closesocket_camel="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if CloseSocket might be used" >&5 +printf %s "checking if CloseSocket might be used... " >&6; } + if test "$tst_links_closesocket_camel" = "yes" && + test "$tst_proto_closesocket_camel" = "yes" && + test "$tst_compi_closesocket_camel" = "yes" && + test "$tst_allow_closesocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_CLOSESOCKET_CAMEL 1" >>confdefs.h + + curl_cv_func_closesocket_camel="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_closesocket_camel="no" + fi + + +curl_includes_fcntl="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_fcntl +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$curl_includes_fcntl +" +if test "x$ac_cv_header_unistd_h" = xyes +then : + printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$curl_includes_fcntl +" +if test "x$ac_cv_header_fcntl_h" = xyes +then : + printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h + +fi + + + + # + tst_links_fcntl="unknown" + tst_proto_fcntl="unknown" + tst_compi_fcntl="unknown" + tst_allow_fcntl="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl can be linked" >&5 +printf %s "checking if fcntl can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define fcntl innocuous_fcntl +#ifdef __STDC__ +# include +#else +# include +#endif +#undef fcntl +#ifdef __cplusplus +extern "C" +#endif +char fcntl (); +#if defined __stub_fcntl || defined __stub___fcntl +choke me +#endif + +int main (void) +{ +return fcntl (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_fcntl="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_fcntl="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_fcntl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl is prototyped" >&5 +printf %s "checking if fcntl is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_fcntl + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "fcntl" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_fcntl="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_fcntl="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_fcntl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl is compilable" >&5 +printf %s "checking if fcntl is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_fcntl + +int main (void) +{ + + if(0 != fcntl(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_fcntl="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_fcntl="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_fcntl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl usage allowed" >&5 +printf %s "checking if fcntl usage allowed... " >&6; } + if test "x$curl_disallow_fcntl" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_fcntl="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_fcntl="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl might be used" >&5 +printf %s "checking if fcntl might be used... " >&6; } + if test "$tst_links_fcntl" = "yes" && + test "$tst_proto_fcntl" = "yes" && + test "$tst_compi_fcntl" = "yes" && + test "$tst_allow_fcntl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_FCNTL 1" >>confdefs.h + + curl_cv_func_fcntl="yes" + + # + tst_compi_fcntl_o_nonblock="unknown" + tst_allow_fcntl_o_nonblock="unknown" + # + case $host_os in + sunos4* | aix3*) + curl_disallow_fcntl_o_nonblock="yes" + ;; + esac + # + if test "$curl_cv_func_fcntl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl O_NONBLOCK is compilable" >&5 +printf %s "checking if fcntl O_NONBLOCK is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_fcntl + +int main (void) +{ + + int flags = 0; + if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_fcntl_o_nonblock="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_fcntl_o_nonblock="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_fcntl_o_nonblock" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl O_NONBLOCK usage allowed" >&5 +printf %s "checking if fcntl O_NONBLOCK usage allowed... " >&6; } + if test "x$curl_disallow_fcntl_o_nonblock" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_fcntl_o_nonblock="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_fcntl_o_nonblock="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fcntl O_NONBLOCK might be used" >&5 +printf %s "checking if fcntl O_NONBLOCK might be used... " >&6; } + if test "$tst_compi_fcntl_o_nonblock" = "yes" && + test "$tst_allow_fcntl_o_nonblock" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_FCNTL_O_NONBLOCK 1" >>confdefs.h + + curl_cv_func_fcntl_o_nonblock="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_fcntl_o_nonblock="no" + fi + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_fcntl="no" + fi + + +curl_includes_ws2tcpip="\ +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +#endif +/* includes end */" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build target is a native Windows one" >&5 +printf %s "checking whether build target is a native Windows one... " >&6; } +if test ${curl_cv_native_windows+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#ifdef _WIN32 + int dummy=1; +#else + Not a native Windows build target. +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + curl_cv_native_windows="yes" + +else $as_nop + + curl_cv_native_windows="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_native_windows" >&5 +printf "%s\n" "$curl_cv_native_windows" >&6; } + if test "x$curl_cv_native_windows" = xyes; then + DOING_NATIVE_WINDOWS_TRUE= + DOING_NATIVE_WINDOWS_FALSE='#' +else + DOING_NATIVE_WINDOWS_TRUE='#' + DOING_NATIVE_WINDOWS_FALSE= +fi + + + + +curl_includes_netdb="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_netdb +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$curl_includes_netdb +" +if test "x$ac_cv_header_netdb_h" = xyes +then : + printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h + +fi + + + + # + tst_links_freeaddrinfo="unknown" + tst_proto_freeaddrinfo="unknown" + tst_compi_freeaddrinfo="unknown" + tst_allow_freeaddrinfo="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if freeaddrinfo can be linked" >&5 +printf %s "checking if freeaddrinfo can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ + + freeaddrinfo(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_freeaddrinfo="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_freeaddrinfo="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_freeaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if freeaddrinfo is prototyped" >&5 +printf %s "checking if freeaddrinfo is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "freeaddrinfo" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_freeaddrinfo="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_freeaddrinfo="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_freeaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if freeaddrinfo is compilable" >&5 +printf %s "checking if freeaddrinfo is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ + + freeaddrinfo(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_freeaddrinfo="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_freeaddrinfo="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_freeaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if freeaddrinfo usage allowed" >&5 +printf %s "checking if freeaddrinfo usage allowed... " >&6; } + if test "x$curl_disallow_freeaddrinfo" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_freeaddrinfo="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_freeaddrinfo="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if freeaddrinfo might be used" >&5 +printf %s "checking if freeaddrinfo might be used... " >&6; } + if test "$tst_links_freeaddrinfo" = "yes" && + test "$tst_proto_freeaddrinfo" = "yes" && + test "$tst_compi_freeaddrinfo" = "yes" && + test "$tst_allow_freeaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_FREEADDRINFO 1" >>confdefs.h + + curl_cv_func_freeaddrinfo="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_freeaddrinfo="no" + fi + + +curl_includes_sys_xattr="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_XATTR_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_sys_xattr +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/xattr.h" "ac_cv_header_sys_xattr_h" "$curl_includes_sys_xattr +" +if test "x$ac_cv_header_sys_xattr_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_XATTR_H 1" >>confdefs.h + +fi + + + + # + tst_links_fsetxattr="unknown" + tst_proto_fsetxattr="unknown" + tst_compi_fsetxattr="unknown" + tst_allow_fsetxattr="unknown" + tst_nargs_fsetxattr="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsetxattr can be linked" >&5 +printf %s "checking if fsetxattr can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define fsetxattr innocuous_fsetxattr +#ifdef __STDC__ +# include +#else +# include +#endif +#undef fsetxattr +#ifdef __cplusplus +extern "C" +#endif +char fsetxattr (); +#if defined __stub_fsetxattr || defined __stub___fsetxattr +choke me +#endif + +int main (void) +{ +return fsetxattr (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_fsetxattr="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_fsetxattr="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_fsetxattr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsetxattr is prototyped" >&5 +printf %s "checking if fsetxattr is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_sys_xattr + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "fsetxattr" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_fsetxattr="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_fsetxattr="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_fsetxattr" = "yes"; then + if test "$tst_nargs_fsetxattr" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsetxattr takes 5 args." >&5 +printf %s "checking if fsetxattr takes 5 args.... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_sys_xattr + +int main (void) +{ + + if(0 != fsetxattr(0, 0, 0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_fsetxattr="yes" + tst_nargs_fsetxattr="5" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_fsetxattr="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + if test "$tst_nargs_fsetxattr" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsetxattr takes 6 args." >&5 +printf %s "checking if fsetxattr takes 6 args.... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_sys_xattr + +int main (void) +{ + + if(0 != fsetxattr(0, 0, 0, 0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_fsetxattr="yes" + tst_nargs_fsetxattr="6" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_fsetxattr="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsetxattr is compilable" >&5 +printf %s "checking if fsetxattr is compilable... " >&6; } + if test "$tst_compi_fsetxattr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + fi + # + if test "$tst_compi_fsetxattr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsetxattr usage allowed" >&5 +printf %s "checking if fsetxattr usage allowed... " >&6; } + if test "x$curl_disallow_fsetxattr" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_fsetxattr="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_fsetxattr="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsetxattr might be used" >&5 +printf %s "checking if fsetxattr might be used... " >&6; } + if test "$tst_links_fsetxattr" = "yes" && + test "$tst_proto_fsetxattr" = "yes" && + test "$tst_compi_fsetxattr" = "yes" && + test "$tst_allow_fsetxattr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_FSETXATTR 1" >>confdefs.h + + # + if test "$tst_nargs_fsetxattr" -eq "5"; then + +printf "%s\n" "#define HAVE_FSETXATTR_5 1" >>confdefs.h + + elif test "$tst_nargs_fsetxattr" -eq "6"; then + +printf "%s\n" "#define HAVE_FSETXATTR_6 1" >>confdefs.h + + fi + # + curl_cv_func_fsetxattr="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_fsetxattr="no" + fi + + + # + tst_links_ftruncate="unknown" + tst_proto_ftruncate="unknown" + tst_compi_ftruncate="unknown" + tst_allow_ftruncate="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ftruncate can be linked" >&5 +printf %s "checking if ftruncate can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define ftruncate innocuous_ftruncate +#ifdef __STDC__ +# include +#else +# include +#endif +#undef ftruncate +#ifdef __cplusplus +extern "C" +#endif +char ftruncate (); +#if defined __stub_ftruncate || defined __stub___ftruncate +choke me +#endif + +int main (void) +{ +return ftruncate (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_ftruncate="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_ftruncate="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_ftruncate" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ftruncate is prototyped" >&5 +printf %s "checking if ftruncate is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_unistd + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "ftruncate" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_ftruncate="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_ftruncate="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_ftruncate" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ftruncate is compilable" >&5 +printf %s "checking if ftruncate is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_unistd + +int main (void) +{ + + if(0 != ftruncate(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ftruncate="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ftruncate="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ftruncate" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ftruncate usage allowed" >&5 +printf %s "checking if ftruncate usage allowed... " >&6; } + if test "x$curl_disallow_ftruncate" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ftruncate="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ftruncate="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ftruncate might be used" >&5 +printf %s "checking if ftruncate might be used... " >&6; } + if test "$tst_links_ftruncate" = "yes" && + test "$tst_proto_ftruncate" = "yes" && + test "$tst_compi_ftruncate" = "yes" && + test "$tst_allow_ftruncate" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_FTRUNCATE 1" >>confdefs.h + + curl_cv_func_ftruncate="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ftruncate="no" + fi + + +curl_includes_stdlib="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_stdlib +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi + + + + # + tst_links_getaddrinfo="unknown" + tst_proto_getaddrinfo="unknown" + tst_compi_getaddrinfo="unknown" + tst_works_getaddrinfo="unknown" + tst_allow_getaddrinfo="unknown" + tst_tsafe_getaddrinfo="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo can be linked" >&5 +printf %s "checking if getaddrinfo can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ + + if(0 != getaddrinfo(0, 0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_getaddrinfo="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_getaddrinfo="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_getaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo is prototyped" >&5 +printf %s "checking if getaddrinfo is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "getaddrinfo" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_getaddrinfo="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_getaddrinfo="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_getaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo is compilable" >&5 +printf %s "checking if getaddrinfo is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ + + if(0 != getaddrinfo(0, 0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_getaddrinfo="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_getaddrinfo="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_getaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo seems to work" >&5 +printf %s "checking if getaddrinfo seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_ws2tcpip + $curl_includes_stdlib + $curl_includes_string + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ + + struct addrinfo hints; + struct addrinfo *ai = 0; + int error; + + #ifdef _WIN32 + WSADATA wsa; + if(WSAStartup(MAKEWORD(2, 2), &wsa)) + exit(2); + #endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo("127.0.0.1", 0, &hints, &ai); + if(error || !ai) + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_getaddrinfo="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_getaddrinfo="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_ws2tcpip + $curl_includes_stdlib + $curl_includes_string + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ + + struct addrinfo hints; + struct addrinfo *ai = 0; + int error; + + #ifdef _WIN32 + WSADATA wsa; + if(WSAStartup(MAKEWORD(2, 2), &wsa)) + exit(2); + #endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo("127.0.0.1", 0, &hints, &ai); + if(error || !ai) + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_getaddrinfo="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_getaddrinfo="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_compi_getaddrinfo" = "yes" && + test "$tst_works_getaddrinfo" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo usage allowed" >&5 +printf %s "checking if getaddrinfo usage allowed... " >&6; } + if test "x$curl_disallow_getaddrinfo" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_getaddrinfo="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_getaddrinfo="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo might be used" >&5 +printf %s "checking if getaddrinfo might be used... " >&6; } + if test "$tst_links_getaddrinfo" = "yes" && + test "$tst_proto_getaddrinfo" = "yes" && + test "$tst_compi_getaddrinfo" = "yes" && + test "$tst_allow_getaddrinfo" = "yes" && + test "$tst_works_getaddrinfo" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h + + curl_cv_func_getaddrinfo="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_getaddrinfo="no" + curl_cv_func_getaddrinfo_threadsafe="no" + fi + # + if test "$curl_cv_func_getaddrinfo" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo is threadsafe" >&5 +printf %s "checking if getaddrinfo is threadsafe... " >&6; } + case $host_os in + aix[1234].* | aix5.[01].*) + tst_tsafe_getaddrinfo="no" + ;; + aix*) + tst_tsafe_getaddrinfo="yes" + ;; + darwin[12345].*) + tst_tsafe_getaddrinfo="no" + ;; + darwin*) + tst_tsafe_getaddrinfo="yes" + ;; + freebsd[1234].* | freebsd5.[1234]*) + tst_tsafe_getaddrinfo="no" + ;; + freebsd*) + tst_tsafe_getaddrinfo="yes" + ;; + hpux[123456789].* | hpux10.* | hpux11.0* | hpux11.10*) + tst_tsafe_getaddrinfo="no" + ;; + hpux*) + tst_tsafe_getaddrinfo="yes" + ;; + midnightbsd*) + tst_tsafe_getaddrinfo="yes" + ;; + netbsd[123].*) + tst_tsafe_getaddrinfo="no" + ;; + netbsd*) + tst_tsafe_getaddrinfo="yes" + ;; + *bsd*) + tst_tsafe_getaddrinfo="no" + ;; + solaris2*) + tst_tsafe_getaddrinfo="yes" + ;; + esac + if test "$tst_tsafe_getaddrinfo" = "unknown" && + test "$curl_cv_native_windows" = "yes"; then + tst_tsafe_getaddrinfo="yes" + fi + if test "$tst_tsafe_getaddrinfo" = "unknown"; then + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ +#ifdef h_errno + return 0; +#else + force compilation error +#endif +} + + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tst_symbol_defined="yes" + +else $as_nop + + tst_symbol_defined="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "$tst_symbol_defined" = "yes"; then + curl_cv_have_def_h_errno=yes + + else + curl_cv_have_def_h_errno=no + + fi + + if test "$curl_cv_have_def_h_errno" = "yes"; then + tst_h_errno_macro="yes" + else + tst_h_errno_macro="no" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_sys_socket + $curl_includes_netdb + +int main (void) +{ + + h_errno = 2; + if(0 != h_errno) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tst_h_errno_modifiable_lvalue="yes" + +else $as_nop + + tst_h_errno_modifiable_lvalue="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) + return 0; +#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700) + return 0; +#else + force compilation error +#endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tst_h_errno_sbs_issue_7="yes" + +else $as_nop + + tst_h_errno_sbs_issue_7="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "$tst_h_errno_macro" = "no" && + test "$tst_h_errno_modifiable_lvalue" = "no" && + test "$tst_h_errno_sbs_issue_7" = "no"; then + tst_tsafe_getaddrinfo="no" + else + tst_tsafe_getaddrinfo="yes" + fi + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tst_tsafe_getaddrinfo" >&5 +printf "%s\n" "$tst_tsafe_getaddrinfo" >&6; } + if test "$tst_tsafe_getaddrinfo" = "yes"; then + +printf "%s\n" "#define HAVE_GETADDRINFO_THREADSAFE 1" >>confdefs.h + + curl_cv_func_getaddrinfo_threadsafe="yes" + else + curl_cv_func_getaddrinfo_threadsafe="no" + fi + fi + + + # + tst_links_gethostbyname="unknown" + tst_proto_gethostbyname="unknown" + tst_compi_gethostbyname="unknown" + tst_allow_gethostbyname="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname can be linked" >&5 +printf %s "checking if gethostbyname can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_netdb + +int main (void) +{ + + if(0 != gethostbyname(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_gethostbyname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_gethostbyname="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_gethostbyname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname is prototyped" >&5 +printf %s "checking if gethostbyname is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_netdb + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gethostbyname" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_gethostbyname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_gethostbyname="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_gethostbyname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname is compilable" >&5 +printf %s "checking if gethostbyname is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_netdb + +int main (void) +{ + + if(0 != gethostbyname(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_gethostbyname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_gethostbyname="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_gethostbyname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname usage allowed" >&5 +printf %s "checking if gethostbyname usage allowed... " >&6; } + if test "x$curl_disallow_gethostbyname" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_gethostbyname="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_gethostbyname="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname might be used" >&5 +printf %s "checking if gethostbyname might be used... " >&6; } + if test "$tst_links_gethostbyname" = "yes" && + test "$tst_proto_gethostbyname" = "yes" && + test "$tst_compi_gethostbyname" = "yes" && + test "$tst_allow_gethostbyname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GETHOSTBYNAME 1" >>confdefs.h + + curl_cv_func_gethostbyname="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_gethostbyname="no" + fi + + + # + tst_links_gethostbyname_r="unknown" + tst_proto_gethostbyname_r="unknown" + tst_compi_gethostbyname_r="unknown" + tst_allow_gethostbyname_r="unknown" + tst_nargs_gethostbyname_r="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r can be linked" >&5 +printf %s "checking if gethostbyname_r can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define gethostbyname_r innocuous_gethostbyname_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef gethostbyname_r +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname_r (); +#if defined __stub_gethostbyname_r || defined __stub___gethostbyname_r +choke me +#endif + +int main (void) +{ +return gethostbyname_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_gethostbyname_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_gethostbyname_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_gethostbyname_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r is prototyped" >&5 +printf %s "checking if gethostbyname_r is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_netdb + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gethostbyname_r" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_gethostbyname_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_gethostbyname_r="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_gethostbyname_r" = "yes"; then + if test "$tst_nargs_gethostbyname_r" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r takes 3 args." >&5 +printf %s "checking if gethostbyname_r takes 3 args.... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_netdb + $curl_includes_bsdsocket + +int main (void) +{ + + if(0 != gethostbyname_r(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_gethostbyname_r="yes" + tst_nargs_gethostbyname_r="3" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_gethostbyname_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + if test "$tst_nargs_gethostbyname_r" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r takes 5 args." >&5 +printf %s "checking if gethostbyname_r takes 5 args.... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_netdb + $curl_includes_bsdsocket + +int main (void) +{ + + if(0 != gethostbyname_r(0, 0, 0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_gethostbyname_r="yes" + tst_nargs_gethostbyname_r="5" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_gethostbyname_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + if test "$tst_nargs_gethostbyname_r" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r takes 6 args." >&5 +printf %s "checking if gethostbyname_r takes 6 args.... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_netdb + $curl_includes_bsdsocket + +int main (void) +{ + + if(0 != gethostbyname_r(0, 0, 0, 0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_gethostbyname_r="yes" + tst_nargs_gethostbyname_r="6" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_gethostbyname_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r is compilable" >&5 +printf %s "checking if gethostbyname_r is compilable... " >&6; } + if test "$tst_compi_gethostbyname_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + fi + # + if test "$tst_compi_gethostbyname_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r usage allowed" >&5 +printf %s "checking if gethostbyname_r usage allowed... " >&6; } + if test "x$curl_disallow_gethostbyname_r" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_gethostbyname_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_gethostbyname_r="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostbyname_r might be used" >&5 +printf %s "checking if gethostbyname_r might be used... " >&6; } + if test "$tst_links_gethostbyname_r" = "yes" && + test "$tst_proto_gethostbyname_r" = "yes" && + test "$tst_compi_gethostbyname_r" = "yes" && + test "$tst_allow_gethostbyname_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h + + # + if test "$tst_nargs_gethostbyname_r" -eq "3"; then + +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R_3 1" >>confdefs.h + + elif test "$tst_nargs_gethostbyname_r" -eq "5"; then + +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R_5 1" >>confdefs.h + + elif test "$tst_nargs_gethostbyname_r" -eq "6"; then + +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R_6 1" >>confdefs.h + + fi + # + curl_cv_func_gethostbyname_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_gethostbyname_r="no" + fi + + +curl_preprocess_callconv="\ +/* preprocess start */ +#ifdef _WIN32 +# define FUNCALLCONV __stdcall +#else +# define FUNCALLCONV +#endif +/* preprocess end */" + + + # + tst_links_gethostname="unknown" + tst_proto_gethostname="unknown" + tst_compi_gethostname="unknown" + tst_allow_gethostname="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostname can be linked" >&5 +printf %s "checking if gethostname can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + +int main (void) +{ + + if(0 != gethostname(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_gethostname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_gethostname="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_gethostname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostname is prototyped" >&5 +printf %s "checking if gethostname is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gethostname" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_gethostname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_gethostname="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_gethostname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostname is compilable" >&5 +printf %s "checking if gethostname is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + +int main (void) +{ + + if(0 != gethostname(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_gethostname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_gethostname="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_gethostname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostname arg 2 data type" >&5 +printf %s "checking for gethostname arg 2 data type... " >&6; } + tst_gethostname_type_arg2="unknown" + for tst_arg1 in 'char *' 'unsigned char *' 'void *'; do + for tst_arg2 in 'int' 'unsigned int' 'size_t'; do + if test "$tst_gethostname_type_arg2" = "unknown"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + $curl_preprocess_callconv + extern int FUNCALLCONV gethostname($tst_arg1, $tst_arg2); + +int main (void) +{ + + if(0 != gethostname(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tst_gethostname_type_arg2="$tst_arg2" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + done + done + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tst_gethostname_type_arg2" >&5 +printf "%s\n" "$tst_gethostname_type_arg2" >&6; } + if test "$tst_gethostname_type_arg2" != "unknown"; then + +printf "%s\n" "#define GETHOSTNAME_TYPE_ARG2 $tst_gethostname_type_arg2" >>confdefs.h + + fi + fi + # + if test "$tst_compi_gethostname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostname usage allowed" >&5 +printf %s "checking if gethostname usage allowed... " >&6; } + if test "x$curl_disallow_gethostname" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_gethostname="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_gethostname="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethostname might be used" >&5 +printf %s "checking if gethostname might be used... " >&6; } + if test "$tst_links_gethostname" = "yes" && + test "$tst_proto_gethostname" = "yes" && + test "$tst_compi_gethostname" = "yes" && + test "$tst_allow_gethostname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GETHOSTNAME 1" >>confdefs.h + + curl_cv_func_gethostname="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_gethostname="no" + fi + + + # + tst_links_getpeername="unknown" + tst_proto_getpeername="unknown" + tst_compi_getpeername="unknown" + tst_allow_getpeername="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getpeername can be linked" >&5 +printf %s "checking if getpeername can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + +int main (void) +{ + + if(0 != getpeername(0, (void *)0, (void *)0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_getpeername="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_getpeername="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_getpeername" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getpeername is prototyped" >&5 +printf %s "checking if getpeername is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "getpeername" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_getpeername="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_getpeername="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_getpeername" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getpeername is compilable" >&5 +printf %s "checking if getpeername is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + +int main (void) +{ + + if(0 != getpeername(0, (void *)0, (void *)0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_getpeername="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_getpeername="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_getpeername" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getpeername usage allowed" >&5 +printf %s "checking if getpeername usage allowed... " >&6; } + if test "x$curl_disallow_getpeername" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_getpeername="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_getpeername="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getpeername might be used" >&5 +printf %s "checking if getpeername might be used... " >&6; } + if test "$tst_links_getpeername" = "yes" && + test "$tst_proto_getpeername" = "yes" && + test "$tst_compi_getpeername" = "yes" && + test "$tst_allow_getpeername" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GETPEERNAME 1" >>confdefs.h + + curl_cv_func_getpeername="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_getpeername="no" + fi + + + # + tst_links_getsockname="unknown" + tst_proto_getsockname="unknown" + tst_compi_getsockname="unknown" + tst_allow_getsockname="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getsockname can be linked" >&5 +printf %s "checking if getsockname can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + +int main (void) +{ + + if(0 != getsockname(0, (void *)0, (void *)0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_getsockname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_getsockname="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_getsockname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getsockname is prototyped" >&5 +printf %s "checking if getsockname is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "getsockname" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_getsockname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_getsockname="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_getsockname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getsockname is compilable" >&5 +printf %s "checking if getsockname is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + +int main (void) +{ + + if(0 != getsockname(0, (void *)0, (void *)0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_getsockname="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_getsockname="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_getsockname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getsockname usage allowed" >&5 +printf %s "checking if getsockname usage allowed... " >&6; } + if test "x$curl_disallow_getsockname" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_getsockname="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_getsockname="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getsockname might be used" >&5 +printf %s "checking if getsockname might be used... " >&6; } + if test "$tst_links_getsockname" = "yes" && + test "$tst_proto_getsockname" = "yes" && + test "$tst_compi_getsockname" = "yes" && + test "$tst_allow_getsockname" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GETSOCKNAME 1" >>confdefs.h + + curl_cv_func_getsockname="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_getsockname="no" + fi + + +curl_includes_netif="\ +/* includes start */ +#ifdef HAVE_NET_IF_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "$curl_includes_netif +" +if test "x$ac_cv_header_net_if_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_H 1" >>confdefs.h + +fi + + + + # + tst_links_if_nametoindex="unknown" + tst_proto_if_nametoindex="unknown" + tst_compi_if_nametoindex="unknown" + tst_allow_if_nametoindex="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if if_nametoindex can be linked" >&5 +printf %s "checking if if_nametoindex can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + #include + +int main (void) +{ + + if(0 != if_nametoindex("")) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_if_nametoindex="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_if_nametoindex="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_if_nametoindex" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if if_nametoindex is prototyped" >&5 +printf %s "checking if if_nametoindex is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + $curl_includes_netif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "if_nametoindex" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_if_nametoindex="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_if_nametoindex="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_if_nametoindex" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if if_nametoindex is compilable" >&5 +printf %s "checking if if_nametoindex is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_netif + +int main (void) +{ + + if(0 != if_nametoindex("")) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_if_nametoindex="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_if_nametoindex="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_if_nametoindex" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if if_nametoindex usage allowed" >&5 +printf %s "checking if if_nametoindex usage allowed... " >&6; } + if test "x$curl_disallow_if_nametoindex" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_if_nametoindex="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_if_nametoindex="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if if_nametoindex might be used" >&5 +printf %s "checking if if_nametoindex might be used... " >&6; } + if test "$tst_links_if_nametoindex" = "yes" && + test "$tst_proto_if_nametoindex" = "yes" && + test "$tst_compi_if_nametoindex" = "yes" && + test "$tst_allow_if_nametoindex" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IF_NAMETOINDEX 1" >>confdefs.h + + curl_cv_func_if_nametoindex="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_if_nametoindex="no" + fi + + +curl_includes_ifaddrs="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_IFADDRS_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_ifaddrs +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$curl_includes_ifaddrs +" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$curl_includes_ifaddrs +" +if test "x$ac_cv_header_netinet_in_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$curl_includes_ifaddrs +" +if test "x$ac_cv_header_ifaddrs_h" = xyes +then : + printf "%s\n" "#define HAVE_IFADDRS_H 1" >>confdefs.h + +fi + + + + # + tst_links_getifaddrs="unknown" + tst_proto_getifaddrs="unknown" + tst_compi_getifaddrs="unknown" + tst_works_getifaddrs="unknown" + tst_allow_getifaddrs="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getifaddrs can be linked" >&5 +printf %s "checking if getifaddrs can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define getifaddrs innocuous_getifaddrs +#ifdef __STDC__ +# include +#else +# include +#endif +#undef getifaddrs +#ifdef __cplusplus +extern "C" +#endif +char getifaddrs (); +#if defined __stub_getifaddrs || defined __stub___getifaddrs +choke me +#endif + +int main (void) +{ +return getifaddrs (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_getifaddrs="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_getifaddrs="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_getifaddrs" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getifaddrs is prototyped" >&5 +printf %s "checking if getifaddrs is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_ifaddrs + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "getifaddrs" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_getifaddrs="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_getifaddrs="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_getifaddrs" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getifaddrs is compilable" >&5 +printf %s "checking if getifaddrs is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_ifaddrs + +int main (void) +{ + + if(0 != getifaddrs(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_getifaddrs="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_getifaddrs="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_getifaddrs" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getifaddrs seems to work" >&5 +printf %s "checking if getifaddrs seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_ifaddrs + +int main (void) +{ + + struct ifaddrs *ifa = 0; + int error; + + error = getifaddrs(&ifa); + if(error || !ifa) + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_getifaddrs="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_getifaddrs="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_ifaddrs + +int main (void) +{ + + struct ifaddrs *ifa = 0; + int error; + + error = getifaddrs(&ifa); + if(error || !ifa) + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_getifaddrs="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_getifaddrs="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_compi_getifaddrs" = "yes" && + test "$tst_works_getifaddrs" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getifaddrs usage allowed" >&5 +printf %s "checking if getifaddrs usage allowed... " >&6; } + if test "x$curl_disallow_getifaddrs" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_getifaddrs="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_getifaddrs="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getifaddrs might be used" >&5 +printf %s "checking if getifaddrs might be used... " >&6; } + if test "$tst_links_getifaddrs" = "yes" && + test "$tst_proto_getifaddrs" = "yes" && + test "$tst_compi_getifaddrs" = "yes" && + test "$tst_allow_getifaddrs" = "yes" && + test "$tst_works_getifaddrs" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GETIFADDRS 1" >>confdefs.h + + curl_cv_func_getifaddrs="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_getifaddrs="no" + fi + + +curl_includes_time="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_time +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$curl_includes_time +" +if test "x$ac_cv_header_sys_time_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h + +fi + + + + # + tst_links_gmtime_r="unknown" + tst_proto_gmtime_r="unknown" + tst_compi_gmtime_r="unknown" + tst_works_gmtime_r="unknown" + tst_allow_gmtime_r="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gmtime_r can be linked" >&5 +printf %s "checking if gmtime_r can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define gmtime_r innocuous_gmtime_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef gmtime_r +#ifdef __cplusplus +extern "C" +#endif +char gmtime_r (); +#if defined __stub_gmtime_r || defined __stub___gmtime_r +choke me +#endif + +int main (void) +{ +return gmtime_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_gmtime_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_gmtime_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_gmtime_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gmtime_r is prototyped" >&5 +printf %s "checking if gmtime_r is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_time + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gmtime_r" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_gmtime_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_gmtime_r="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_gmtime_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gmtime_r is compilable" >&5 +printf %s "checking if gmtime_r is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_time + +int main (void) +{ + + if(0 != gmtime_r(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_gmtime_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_gmtime_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_gmtime_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gmtime_r seems to work" >&5 +printf %s "checking if gmtime_r seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_time + +int main (void) +{ + + time_t local = 1170352587; + struct tm *gmt = 0; + struct tm result; + gmt = gmtime_r(&local, &result); + if(gmt) + exit(0); + else + exit(1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_gmtime_r="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_gmtime_r="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_time + +int main (void) +{ + + time_t local = 1170352587; + struct tm *gmt = 0; + struct tm result; + gmt = gmtime_r(&local, &result); + if(gmt) + exit(0); + else + exit(1); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_gmtime_r="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_gmtime_r="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_compi_gmtime_r" = "yes" && + test "$tst_works_gmtime_r" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gmtime_r usage allowed" >&5 +printf %s "checking if gmtime_r usage allowed... " >&6; } + if test "x$curl_disallow_gmtime_r" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_gmtime_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_gmtime_r="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gmtime_r might be used" >&5 +printf %s "checking if gmtime_r might be used... " >&6; } + if test "$tst_links_gmtime_r" = "yes" && + test "$tst_proto_gmtime_r" = "yes" && + test "$tst_compi_gmtime_r" = "yes" && + test "$tst_allow_gmtime_r" = "yes" && + test "$tst_works_gmtime_r" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h + + curl_cv_func_gmtime_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_gmtime_r="no" + fi + + +curl_includes_arpa_inet="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef _WIN32 +#include +#include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_arpa_inet +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$curl_includes_arpa_inet +" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$curl_includes_arpa_inet +" +if test "x$ac_cv_header_netinet_in_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$curl_includes_arpa_inet +" +if test "x$ac_cv_header_arpa_inet_h" = xyes +then : + printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h + +fi + + + + # + tst_links_inet_ntop="unknown" + tst_proto_inet_ntop="unknown" + tst_compi_inet_ntop="unknown" + tst_works_inet_ntop="unknown" + tst_allow_inet_ntop="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_ntop can be linked" >&5 +printf %s "checking if inet_ntop can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define inet_ntop innocuous_inet_ntop +#ifdef __STDC__ +# include +#else +# include +#endif +#undef inet_ntop +#ifdef __cplusplus +extern "C" +#endif +char inet_ntop (); +#if defined __stub_inet_ntop || defined __stub___inet_ntop +choke me +#endif + +int main (void) +{ +return inet_ntop (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_inet_ntop="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_inet_ntop="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_inet_ntop" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_ntop is prototyped" >&5 +printf %s "checking if inet_ntop is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_arpa_inet + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "inet_ntop" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_inet_ntop="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_inet_ntop="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_inet_ntop" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_ntop is compilable" >&5 +printf %s "checking if inet_ntop is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_arpa_inet + +int main (void) +{ + + if(0 != inet_ntop(0, 0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_inet_ntop="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_inet_ntop="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_inet_ntop" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_ntop seems to work" >&5 +printf %s "checking if inet_ntop seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_arpa_inet + $curl_includes_string + +int main (void) +{ + + char ipv6res[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + char ipv4res[sizeof "255.255.255.255"]; + unsigned char ipv6a[26]; + unsigned char ipv4a[5]; + char *ipv6ptr = 0; + char *ipv4ptr = 0; + /* - */ + ipv4res[0] = '\0'; + ipv4a[0] = 0xc0; + ipv4a[1] = 0xa8; + ipv4a[2] = 0x64; + ipv4a[3] = 0x01; + ipv4a[4] = 0x01; + /* - */ + ipv4ptr = inet_ntop(AF_INET, ipv4a, ipv4res, sizeof(ipv4res)); + if(!ipv4ptr) + exit(1); /* fail */ + if(ipv4ptr != ipv4res) + exit(1); /* fail */ + if(!ipv4ptr[0]) + exit(1); /* fail */ + if(memcmp(ipv4res, "192.168.100.1", 13) != 0) + exit(1); /* fail */ + /* - */ + ipv6res[0] = '\0'; + memset(ipv6a, 0, sizeof(ipv6a)); + ipv6a[0] = 0xfe; + ipv6a[1] = 0x80; + ipv6a[8] = 0x02; + ipv6a[9] = 0x14; + ipv6a[10] = 0x4f; + ipv6a[11] = 0xff; + ipv6a[12] = 0xfe; + ipv6a[13] = 0x0b; + ipv6a[14] = 0x76; + ipv6a[15] = 0xc8; + ipv6a[25] = 0x01; + /* - */ + ipv6ptr = inet_ntop(AF_INET6, ipv6a, ipv6res, sizeof(ipv6res)); + if(!ipv6ptr) + exit(1); /* fail */ + if(ipv6ptr != ipv6res) + exit(1); /* fail */ + if(!ipv6ptr[0]) + exit(1); /* fail */ + if(memcmp(ipv6res, "fe80::214:4fff:fe0b:76c8", 24) != 0) + exit(1); /* fail */ + /* - */ + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_inet_ntop="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_inet_ntop="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_arpa_inet + $curl_includes_string + +int main (void) +{ + + char ipv6res[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + char ipv4res[sizeof "255.255.255.255"]; + unsigned char ipv6a[26]; + unsigned char ipv4a[5]; + char *ipv6ptr = 0; + char *ipv4ptr = 0; + /* - */ + ipv4res[0] = '\0'; + ipv4a[0] = 0xc0; + ipv4a[1] = 0xa8; + ipv4a[2] = 0x64; + ipv4a[3] = 0x01; + ipv4a[4] = 0x01; + /* - */ + ipv4ptr = inet_ntop(AF_INET, ipv4a, ipv4res, sizeof(ipv4res)); + if(!ipv4ptr) + exit(1); /* fail */ + if(ipv4ptr != ipv4res) + exit(1); /* fail */ + if(!ipv4ptr[0]) + exit(1); /* fail */ + if(memcmp(ipv4res, "192.168.100.1", 13) != 0) + exit(1); /* fail */ + /* - */ + ipv6res[0] = '\0'; + memset(ipv6a, 0, sizeof(ipv6a)); + ipv6a[0] = 0xfe; + ipv6a[1] = 0x80; + ipv6a[8] = 0x02; + ipv6a[9] = 0x14; + ipv6a[10] = 0x4f; + ipv6a[11] = 0xff; + ipv6a[12] = 0xfe; + ipv6a[13] = 0x0b; + ipv6a[14] = 0x76; + ipv6a[15] = 0xc8; + ipv6a[25] = 0x01; + /* - */ + ipv6ptr = inet_ntop(AF_INET6, ipv6a, ipv6res, sizeof(ipv6res)); + if(!ipv6ptr) + exit(1); /* fail */ + if(ipv6ptr != ipv6res) + exit(1); /* fail */ + if(!ipv6ptr[0]) + exit(1); /* fail */ + if(memcmp(ipv6res, "fe80::214:4fff:fe0b:76c8", 24) != 0) + exit(1); /* fail */ + /* - */ + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_inet_ntop="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_inet_ntop="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_compi_inet_ntop" = "yes" && + test "$tst_works_inet_ntop" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_ntop usage allowed" >&5 +printf %s "checking if inet_ntop usage allowed... " >&6; } + if test "x$curl_disallow_inet_ntop" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_inet_ntop="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_inet_ntop="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_ntop might be used" >&5 +printf %s "checking if inet_ntop might be used... " >&6; } + if test "$tst_links_inet_ntop" = "yes" && + test "$tst_proto_inet_ntop" = "yes" && + test "$tst_compi_inet_ntop" = "yes" && + test "$tst_allow_inet_ntop" = "yes" && + test "$tst_works_inet_ntop" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_INET_NTOP 1" >>confdefs.h + + curl_cv_func_inet_ntop="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_inet_ntop="no" + fi + + + # + tst_links_inet_pton="unknown" + tst_proto_inet_pton="unknown" + tst_compi_inet_pton="unknown" + tst_works_inet_pton="unknown" + tst_allow_inet_pton="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_pton can be linked" >&5 +printf %s "checking if inet_pton can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define inet_pton innocuous_inet_pton +#ifdef __STDC__ +# include +#else +# include +#endif +#undef inet_pton +#ifdef __cplusplus +extern "C" +#endif +char inet_pton (); +#if defined __stub_inet_pton || defined __stub___inet_pton +choke me +#endif + +int main (void) +{ +return inet_pton (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_inet_pton="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_inet_pton="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_inet_pton" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_pton is prototyped" >&5 +printf %s "checking if inet_pton is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_arpa_inet + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "inet_pton" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_inet_pton="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_inet_pton="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_inet_pton" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_pton is compilable" >&5 +printf %s "checking if inet_pton is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_arpa_inet + +int main (void) +{ + + if(0 != inet_pton(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_inet_pton="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_inet_pton="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_inet_pton" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_pton seems to work" >&5 +printf %s "checking if inet_pton seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_arpa_inet + $curl_includes_string + +int main (void) +{ + + unsigned char ipv6a[16+1]; + unsigned char ipv4a[4+1]; + const char *ipv6src = "fe80::214:4fff:fe0b:76c8"; + const char *ipv4src = "192.168.100.1"; + /* - */ + memset(ipv4a, 1, sizeof(ipv4a)); + if(1 != inet_pton(AF_INET, ipv4src, ipv4a)) + exit(1); /* fail */ + /* - */ + if( (ipv4a[0] != 0xc0) || + (ipv4a[1] != 0xa8) || + (ipv4a[2] != 0x64) || + (ipv4a[3] != 0x01) || + (ipv4a[4] != 0x01) ) + exit(1); /* fail */ + /* - */ + memset(ipv6a, 1, sizeof(ipv6a)); + if(1 != inet_pton(AF_INET6, ipv6src, ipv6a)) + exit(1); /* fail */ + /* - */ + if( (ipv6a[0] != 0xfe) || + (ipv6a[1] != 0x80) || + (ipv6a[8] != 0x02) || + (ipv6a[9] != 0x14) || + (ipv6a[10] != 0x4f) || + (ipv6a[11] != 0xff) || + (ipv6a[12] != 0xfe) || + (ipv6a[13] != 0x0b) || + (ipv6a[14] != 0x76) || + (ipv6a[15] != 0xc8) || + (ipv6a[16] != 0x01) ) + exit(1); /* fail */ + /* - */ + if( (ipv6a[2] != 0x0) || + (ipv6a[3] != 0x0) || + (ipv6a[4] != 0x0) || + (ipv6a[5] != 0x0) || + (ipv6a[6] != 0x0) || + (ipv6a[7] != 0x0) ) + exit(1); /* fail */ + /* - */ + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_inet_pton="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_inet_pton="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_arpa_inet + $curl_includes_string + +int main (void) +{ + + unsigned char ipv6a[16+1]; + unsigned char ipv4a[4+1]; + const char *ipv6src = "fe80::214:4fff:fe0b:76c8"; + const char *ipv4src = "192.168.100.1"; + /* - */ + memset(ipv4a, 1, sizeof(ipv4a)); + if(1 != inet_pton(AF_INET, ipv4src, ipv4a)) + exit(1); /* fail */ + /* - */ + if( (ipv4a[0] != 0xc0) || + (ipv4a[1] != 0xa8) || + (ipv4a[2] != 0x64) || + (ipv4a[3] != 0x01) || + (ipv4a[4] != 0x01) ) + exit(1); /* fail */ + /* - */ + memset(ipv6a, 1, sizeof(ipv6a)); + if(1 != inet_pton(AF_INET6, ipv6src, ipv6a)) + exit(1); /* fail */ + /* - */ + if( (ipv6a[0] != 0xfe) || + (ipv6a[1] != 0x80) || + (ipv6a[8] != 0x02) || + (ipv6a[9] != 0x14) || + (ipv6a[10] != 0x4f) || + (ipv6a[11] != 0xff) || + (ipv6a[12] != 0xfe) || + (ipv6a[13] != 0x0b) || + (ipv6a[14] != 0x76) || + (ipv6a[15] != 0xc8) || + (ipv6a[16] != 0x01) ) + exit(1); /* fail */ + /* - */ + if( (ipv6a[2] != 0x0) || + (ipv6a[3] != 0x0) || + (ipv6a[4] != 0x0) || + (ipv6a[5] != 0x0) || + (ipv6a[6] != 0x0) || + (ipv6a[7] != 0x0) ) + exit(1); /* fail */ + /* - */ + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_inet_pton="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_inet_pton="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_compi_inet_pton" = "yes" && + test "$tst_works_inet_pton" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_pton usage allowed" >&5 +printf %s "checking if inet_pton usage allowed... " >&6; } + if test "x$curl_disallow_inet_pton" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_inet_pton="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_inet_pton="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if inet_pton might be used" >&5 +printf %s "checking if inet_pton might be used... " >&6; } + if test "$tst_links_inet_pton" = "yes" && + test "$tst_proto_inet_pton" = "yes" && + test "$tst_compi_inet_pton" = "yes" && + test "$tst_allow_inet_pton" = "yes" && + test "$tst_works_inet_pton" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_INET_PTON 1" >>confdefs.h + + curl_cv_func_inet_pton="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_inet_pton="no" + fi + + +curl_includes_stropts="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_STROPTS_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_stropts +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$curl_includes_stropts +" +if test "x$ac_cv_header_unistd_h" = xyes +then : + printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$curl_includes_stropts +" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$curl_includes_stropts +" +if test "x$ac_cv_header_sys_ioctl_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "stropts.h" "ac_cv_header_stropts_h" "$curl_includes_stropts +" +if test "x$ac_cv_header_stropts_h" = xyes +then : + printf "%s\n" "#define HAVE_STROPTS_H 1" >>confdefs.h + +fi + + + + # + tst_links_ioctl="unknown" + tst_proto_ioctl="unknown" + tst_compi_ioctl="unknown" + tst_allow_ioctl="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl can be linked" >&5 +printf %s "checking if ioctl can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define ioctl innocuous_ioctl +#ifdef __STDC__ +# include +#else +# include +#endif +#undef ioctl +#ifdef __cplusplus +extern "C" +#endif +char ioctl (); +#if defined __stub_ioctl || defined __stub___ioctl +choke me +#endif + +int main (void) +{ +return ioctl (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_ioctl="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_ioctl="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_ioctl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl is prototyped" >&5 +printf %s "checking if ioctl is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_stropts + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "ioctl" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_ioctl="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_ioctl="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_ioctl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl is compilable" >&5 +printf %s "checking if ioctl is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stropts + +int main (void) +{ + + if(0 != ioctl(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ioctl="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ioctl="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ioctl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl usage allowed" >&5 +printf %s "checking if ioctl usage allowed... " >&6; } + if test "x$curl_disallow_ioctl" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ioctl="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ioctl="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl might be used" >&5 +printf %s "checking if ioctl might be used... " >&6; } + if test "$tst_links_ioctl" = "yes" && + test "$tst_proto_ioctl" = "yes" && + test "$tst_compi_ioctl" = "yes" && + test "$tst_allow_ioctl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IOCTL 1" >>confdefs.h + + curl_cv_func_ioctl="yes" + + # + tst_compi_ioctl_fionbio="unknown" + tst_allow_ioctl_fionbio="unknown" + # + if test "$curl_cv_func_ioctl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl FIONBIO is compilable" >&5 +printf %s "checking if ioctl FIONBIO is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stropts + +int main (void) +{ + + int flags = 0; + if(0 != ioctl(0, FIONBIO, &flags)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ioctl_fionbio="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ioctl_fionbio="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ioctl_fionbio" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl FIONBIO usage allowed" >&5 +printf %s "checking if ioctl FIONBIO usage allowed... " >&6; } + if test "x$curl_disallow_ioctl_fionbio" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ioctl_fionbio="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ioctl_fionbio="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl FIONBIO might be used" >&5 +printf %s "checking if ioctl FIONBIO might be used... " >&6; } + if test "$tst_compi_ioctl_fionbio" = "yes" && + test "$tst_allow_ioctl_fionbio" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IOCTL_FIONBIO 1" >>confdefs.h + + curl_cv_func_ioctl_fionbio="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ioctl_fionbio="no" + fi + + + # + tst_compi_ioctl_siocgifaddr="unknown" + tst_allow_ioctl_siocgifaddr="unknown" + # + if test "$curl_cv_func_ioctl" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl SIOCGIFADDR is compilable" >&5 +printf %s "checking if ioctl SIOCGIFADDR is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stropts + #include + +int main (void) +{ + + struct ifreq ifr; + if(0 != ioctl(0, SIOCGIFADDR, &ifr)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ioctl_siocgifaddr="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ioctl_siocgifaddr="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ioctl_siocgifaddr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl SIOCGIFADDR usage allowed" >&5 +printf %s "checking if ioctl SIOCGIFADDR usage allowed... " >&6; } + if test "x$curl_disallow_ioctl_siocgifaddr" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ioctl_siocgifaddr="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ioctl_siocgifaddr="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctl SIOCGIFADDR might be used" >&5 +printf %s "checking if ioctl SIOCGIFADDR might be used... " >&6; } + if test "$tst_compi_ioctl_siocgifaddr" = "yes" && + test "$tst_allow_ioctl_siocgifaddr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IOCTL_SIOCGIFADDR 1" >>confdefs.h + + curl_cv_func_ioctl_siocgifaddr="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ioctl_siocgifaddr="no" + fi + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ioctl="no" + fi + + + # + tst_links_ioctlsocket="unknown" + tst_proto_ioctlsocket="unknown" + tst_compi_ioctlsocket="unknown" + tst_allow_ioctlsocket="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket can be linked" >&5 +printf %s "checking if ioctlsocket can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + +int main (void) +{ + + if(0 != ioctlsocket(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_ioctlsocket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_ioctlsocket="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_ioctlsocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket is prototyped" >&5 +printf %s "checking if ioctlsocket is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "ioctlsocket" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_ioctlsocket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_ioctlsocket="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_ioctlsocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket is compilable" >&5 +printf %s "checking if ioctlsocket is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + +int main (void) +{ + + if(0 != ioctlsocket(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ioctlsocket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ioctlsocket="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ioctlsocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket usage allowed" >&5 +printf %s "checking if ioctlsocket usage allowed... " >&6; } + if test "x$curl_disallow_ioctlsocket" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ioctlsocket="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ioctlsocket="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket might be used" >&5 +printf %s "checking if ioctlsocket might be used... " >&6; } + if test "$tst_links_ioctlsocket" = "yes" && + test "$tst_proto_ioctlsocket" = "yes" && + test "$tst_compi_ioctlsocket" = "yes" && + test "$tst_allow_ioctlsocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IOCTLSOCKET 1" >>confdefs.h + + curl_cv_func_ioctlsocket="yes" + + # + tst_compi_ioctlsocket_fionbio="unknown" + tst_allow_ioctlsocket_fionbio="unknown" + # + if test "$curl_cv_func_ioctlsocket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket FIONBIO is compilable" >&5 +printf %s "checking if ioctlsocket FIONBIO is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + +int main (void) +{ + + int flags = 0; + if(0 != ioctlsocket(0, FIONBIO, &flags)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ioctlsocket_fionbio="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ioctlsocket_fionbio="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ioctlsocket_fionbio" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket FIONBIO usage allowed" >&5 +printf %s "checking if ioctlsocket FIONBIO usage allowed... " >&6; } + if test "x$curl_disallow_ioctlsocket_fionbio" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ioctlsocket_fionbio="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ioctlsocket_fionbio="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ioctlsocket FIONBIO might be used" >&5 +printf %s "checking if ioctlsocket FIONBIO might be used... " >&6; } + if test "$tst_compi_ioctlsocket_fionbio" = "yes" && + test "$tst_allow_ioctlsocket_fionbio" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IOCTLSOCKET_FIONBIO 1" >>confdefs.h + + curl_cv_func_ioctlsocket_fionbio="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ioctlsocket_fionbio="no" + fi + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ioctlsocket="no" + fi + + + # + tst_links_ioctlsocket_camel="unknown" + tst_proto_ioctlsocket_camel="unknown" + tst_compi_ioctlsocket_camel="unknown" + tst_allow_ioctlsocket_camel="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket can be linked" >&5 +printf %s "checking if IoctlSocket can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_bsdsocket + +int main (void) +{ + + IoctlSocket(0, 0, 0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_ioctlsocket_camel="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_ioctlsocket_camel="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_ioctlsocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket is prototyped" >&5 +printf %s "checking if IoctlSocket is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_bsdsocket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "IoctlSocket" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_ioctlsocket_camel="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_ioctlsocket_camel="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_ioctlsocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket is compilable" >&5 +printf %s "checking if IoctlSocket is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_bsdsocket + +int main (void) +{ + + if(0 != IoctlSocket(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ioctlsocket_camel="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ioctlsocket_camel="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ioctlsocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket usage allowed" >&5 +printf %s "checking if IoctlSocket usage allowed... " >&6; } + if test "x$curl_disallow_ioctlsocket_camel" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ioctlsocket_camel="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ioctlsocket_camel="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket might be used" >&5 +printf %s "checking if IoctlSocket might be used... " >&6; } + if test "$tst_links_ioctlsocket_camel" = "yes" && + test "$tst_proto_ioctlsocket_camel" = "yes" && + test "$tst_compi_ioctlsocket_camel" = "yes" && + test "$tst_allow_ioctlsocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IOCTLSOCKET_CAMEL 1" >>confdefs.h + + curl_cv_func_ioctlsocket_camel="yes" + + # + tst_compi_ioctlsocket_camel_fionbio="unknown" + tst_allow_ioctlsocket_camel_fionbio="unknown" + # + if test "$curl_cv_func_ioctlsocket_camel" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket FIONBIO is compilable" >&5 +printf %s "checking if IoctlSocket FIONBIO is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_bsdsocket + +int main (void) +{ + + long flags = 0; + if(0 != IoctlSocket(0, FIONBIO, &flags)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_ioctlsocket_camel_fionbio="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_ioctlsocket_camel_fionbio="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_ioctlsocket_camel_fionbio" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket FIONBIO usage allowed" >&5 +printf %s "checking if IoctlSocket FIONBIO usage allowed... " >&6; } + if test "x$curl_disallow_ioctlsocket_camel_fionbio" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_ioctlsocket_camel_fionbio="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_ioctlsocket_camel_fionbio="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if IoctlSocket FIONBIO might be used" >&5 +printf %s "checking if IoctlSocket FIONBIO might be used... " >&6; } + if test "$tst_compi_ioctlsocket_camel_fionbio" = "yes" && + test "$tst_allow_ioctlsocket_camel_fionbio" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1" >>confdefs.h + + curl_cv_func_ioctlsocket_camel_fionbio="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ioctlsocket_camel_fionbio="no" + fi + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_ioctlsocket_camel="no" + fi + + + # + tst_links_memrchr="unknown" + tst_macro_memrchr="unknown" + tst_proto_memrchr="unknown" + tst_compi_memrchr="unknown" + tst_allow_memrchr="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memrchr can be linked" >&5 +printf %s "checking if memrchr can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define memrchr innocuous_memrchr +#ifdef __STDC__ +# include +#else +# include +#endif +#undef memrchr +#ifdef __cplusplus +extern "C" +#endif +char memrchr (); +#if defined __stub_memrchr || defined __stub___memrchr +choke me +#endif + +int main (void) +{ +return memrchr (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_memrchr="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_memrchr="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_memrchr" = "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memrchr seems a macro" >&5 +printf %s "checking if memrchr seems a macro... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != memrchr(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_macro_memrchr="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_macro_memrchr="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + # + if test "$tst_links_memrchr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memrchr is prototyped" >&5 +printf %s "checking if memrchr is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memrchr" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_memrchr="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_memrchr="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_memrchr" = "yes" || + test "$tst_macro_memrchr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memrchr is compilable" >&5 +printf %s "checking if memrchr is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != memrchr(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_memrchr="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_memrchr="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_memrchr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memrchr usage allowed" >&5 +printf %s "checking if memrchr usage allowed... " >&6; } + if test "x$curl_disallow_memrchr" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_memrchr="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_memrchr="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memrchr might be used" >&5 +printf %s "checking if memrchr might be used... " >&6; } + if (test "$tst_proto_memrchr" = "yes" || + test "$tst_macro_memrchr" = "yes") && + test "$tst_compi_memrchr" = "yes" && + test "$tst_allow_memrchr" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_MEMRCHR 1" >>confdefs.h + + curl_cv_func_memrchr="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_memrchr="no" + fi + + +curl_includes_poll="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_POLL_H +# include +#endif +#ifdef HAVE_SYS_POLL_H +# include +#endif +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_poll +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$curl_includes_poll +" +if test "x$ac_cv_header_poll_h" = xyes +then : + printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$curl_includes_poll +" +if test "x$ac_cv_header_sys_poll_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_POLL_H 1" >>confdefs.h + +fi + + + + # + tst_links_poll="unknown" + tst_proto_poll="unknown" + tst_compi_poll="unknown" + tst_works_poll="unknown" + tst_allow_poll="unknown" + # + case $host_os in + darwin*|interix*) + curl_disallow_poll="yes" + tst_compi_poll="no" + ;; + esac + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if poll can be linked" >&5 +printf %s "checking if poll can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_poll + +int main (void) +{ + + if(0 != poll(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_poll="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_poll="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_poll" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if poll is prototyped" >&5 +printf %s "checking if poll is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_poll + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "poll" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_poll="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_poll="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_poll" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if poll is compilable" >&5 +printf %s "checking if poll is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_poll + +int main (void) +{ + + if(0 != poll(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_poll="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_poll="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_poll" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if poll seems to work" >&5 +printf %s "checking if poll seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_poll + $curl_includes_time + +int main (void) +{ + + /* detect the original poll() breakage */ + if(0 != poll(0, 0, 10)) + exit(1); /* fail */ + else { + /* detect the 10.12 poll() breakage */ + struct timeval before, after; + int rc; + size_t us; + + gettimeofday(&before, NULL); + rc = poll(NULL, 0, 500); + gettimeofday(&after, NULL); + + us = (after.tv_sec - before.tv_sec) * 1000000 + + (after.tv_usec - before.tv_usec); + + if(us < 400000) + exit(1); + } + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_poll="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_poll="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_poll + $curl_includes_time + +int main (void) +{ + + /* detect the original poll() breakage */ + if(0 != poll(0, 0, 10)) + exit(1); /* fail */ + else { + /* detect the 10.12 poll() breakage */ + struct timeval before, after; + int rc; + size_t us; + + gettimeofday(&before, NULL); + rc = poll(NULL, 0, 500); + gettimeofday(&after, NULL); + + us = (after.tv_sec - before.tv_sec) * 1000000 + + (after.tv_usec - before.tv_usec); + + if(us < 400000) + exit(1); + } + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_poll="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_poll="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_compi_poll" = "yes" && + test "$tst_works_poll" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if poll usage allowed" >&5 +printf %s "checking if poll usage allowed... " >&6; } + if test "x$curl_disallow_poll" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_poll="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_poll="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if poll might be used" >&5 +printf %s "checking if poll might be used... " >&6; } + if test "$tst_links_poll" = "yes" && + test "$tst_proto_poll" = "yes" && + test "$tst_compi_poll" = "yes" && + test "$tst_allow_poll" = "yes" && + test "$tst_works_poll" != "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_POLL_FINE 1" >>confdefs.h + + curl_cv_func_poll="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_poll="no" + fi + + +curl_includes_signal="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_signal +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi + + + + # + tst_links_sigaction="unknown" + tst_proto_sigaction="unknown" + tst_compi_sigaction="unknown" + tst_allow_sigaction="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigaction can be linked" >&5 +printf %s "checking if sigaction can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define sigaction innocuous_sigaction +#ifdef __STDC__ +# include +#else +# include +#endif +#undef sigaction +#ifdef __cplusplus +extern "C" +#endif +char sigaction (); +#if defined __stub_sigaction || defined __stub___sigaction +choke me +#endif + +int main (void) +{ +return sigaction (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_sigaction="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_sigaction="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_sigaction" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigaction is prototyped" >&5 +printf %s "checking if sigaction is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_signal + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "sigaction" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_sigaction="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_sigaction="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_sigaction" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigaction is compilable" >&5 +printf %s "checking if sigaction is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_signal + +int main (void) +{ + + if(0 != sigaction(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_sigaction="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_sigaction="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_sigaction" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigaction usage allowed" >&5 +printf %s "checking if sigaction usage allowed... " >&6; } + if test "x$curl_disallow_sigaction" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_sigaction="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_sigaction="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigaction might be used" >&5 +printf %s "checking if sigaction might be used... " >&6; } + if test "$tst_links_sigaction" = "yes" && + test "$tst_proto_sigaction" = "yes" && + test "$tst_compi_sigaction" = "yes" && + test "$tst_allow_sigaction" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h + + curl_cv_func_sigaction="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_sigaction="no" + fi + + + # + tst_links_siginterrupt="unknown" + tst_proto_siginterrupt="unknown" + tst_compi_siginterrupt="unknown" + tst_allow_siginterrupt="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if siginterrupt can be linked" >&5 +printf %s "checking if siginterrupt can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define siginterrupt innocuous_siginterrupt +#ifdef __STDC__ +# include +#else +# include +#endif +#undef siginterrupt +#ifdef __cplusplus +extern "C" +#endif +char siginterrupt (); +#if defined __stub_siginterrupt || defined __stub___siginterrupt +choke me +#endif + +int main (void) +{ +return siginterrupt (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_siginterrupt="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_siginterrupt="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_siginterrupt" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if siginterrupt is prototyped" >&5 +printf %s "checking if siginterrupt is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_signal + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "siginterrupt" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_siginterrupt="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_siginterrupt="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_siginterrupt" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if siginterrupt is compilable" >&5 +printf %s "checking if siginterrupt is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_signal + +int main (void) +{ + + if(0 != siginterrupt(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_siginterrupt="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_siginterrupt="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_siginterrupt" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if siginterrupt usage allowed" >&5 +printf %s "checking if siginterrupt usage allowed... " >&6; } + if test "x$curl_disallow_siginterrupt" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_siginterrupt="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_siginterrupt="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if siginterrupt might be used" >&5 +printf %s "checking if siginterrupt might be used... " >&6; } + if test "$tst_links_siginterrupt" = "yes" && + test "$tst_proto_siginterrupt" = "yes" && + test "$tst_compi_siginterrupt" = "yes" && + test "$tst_allow_siginterrupt" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SIGINTERRUPT 1" >>confdefs.h + + curl_cv_func_siginterrupt="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_siginterrupt="no" + fi + + + # + tst_links_signal="unknown" + tst_proto_signal="unknown" + tst_compi_signal="unknown" + tst_allow_signal="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if signal can be linked" >&5 +printf %s "checking if signal can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define signal innocuous_signal +#ifdef __STDC__ +# include +#else +# include +#endif +#undef signal +#ifdef __cplusplus +extern "C" +#endif +char signal (); +#if defined __stub_signal || defined __stub___signal +choke me +#endif + +int main (void) +{ +return signal (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_signal="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_signal="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_signal" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if signal is prototyped" >&5 +printf %s "checking if signal is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_signal + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "signal" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_signal="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_signal="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_signal" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if signal is compilable" >&5 +printf %s "checking if signal is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_signal + +int main (void) +{ + + if(0 != signal(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_signal="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_signal="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_signal" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if signal usage allowed" >&5 +printf %s "checking if signal usage allowed... " >&6; } + if test "x$curl_disallow_signal" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_signal="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_signal="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if signal might be used" >&5 +printf %s "checking if signal might be used... " >&6; } + if test "$tst_links_signal" = "yes" && + test "$tst_proto_signal" = "yes" && + test "$tst_compi_signal" = "yes" && + test "$tst_allow_signal" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SIGNAL 1" >>confdefs.h + + curl_cv_func_signal="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_signal="no" + fi + + +curl_includes_setjmp="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +/* includes end */" + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$curl_includes_setjmp +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi + + + + # + tst_links_sigsetjmp="unknown" + tst_macro_sigsetjmp="unknown" + tst_proto_sigsetjmp="unknown" + tst_compi_sigsetjmp="unknown" + tst_allow_sigsetjmp="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigsetjmp can be linked" >&5 +printf %s "checking if sigsetjmp can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define sigsetjmp innocuous_sigsetjmp +#ifdef __STDC__ +# include +#else +# include +#endif +#undef sigsetjmp +#ifdef __cplusplus +extern "C" +#endif +char sigsetjmp (); +#if defined __stub_sigsetjmp || defined __stub___sigsetjmp +choke me +#endif + +int main (void) +{ +return sigsetjmp (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_sigsetjmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_sigsetjmp="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_sigsetjmp" = "no"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigsetjmp seems a macro" >&5 +printf %s "checking if sigsetjmp seems a macro... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_setjmp + +int main (void) +{ + + sigjmp_buf env; + if(0 != sigsetjmp(env, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_macro_sigsetjmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_macro_sigsetjmp="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + # + if test "$tst_links_sigsetjmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigsetjmp is prototyped" >&5 +printf %s "checking if sigsetjmp is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_setjmp + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "sigsetjmp" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_sigsetjmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_sigsetjmp="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_sigsetjmp" = "yes" || + test "$tst_macro_sigsetjmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigsetjmp is compilable" >&5 +printf %s "checking if sigsetjmp is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_setjmp + +int main (void) +{ + + sigjmp_buf env; + if(0 != sigsetjmp(env, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_sigsetjmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_sigsetjmp="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_sigsetjmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigsetjmp usage allowed" >&5 +printf %s "checking if sigsetjmp usage allowed... " >&6; } + if test "x$curl_disallow_sigsetjmp" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_sigsetjmp="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_sigsetjmp="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigsetjmp might be used" >&5 +printf %s "checking if sigsetjmp might be used... " >&6; } + if (test "$tst_proto_sigsetjmp" = "yes" || + test "$tst_macro_sigsetjmp" = "yes") && + test "$tst_compi_sigsetjmp" = "yes" && + test "$tst_allow_sigsetjmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SIGSETJMP 1" >>confdefs.h + + curl_cv_func_sigsetjmp="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_sigsetjmp="no" + fi + + + # + tst_links_socket="unknown" + tst_proto_socket="unknown" + tst_compi_socket="unknown" + tst_allow_socket="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socket can be linked" >&5 +printf %s "checking if socket can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + $curl_includes_socket + +int main (void) +{ + + if(0 != socket(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_socket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_socket="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_socket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socket is prototyped" >&5 +printf %s "checking if socket is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + $curl_includes_socket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "socket" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_socket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_socket="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_socket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socket is compilable" >&5 +printf %s "checking if socket is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + $curl_includes_socket + +int main (void) +{ + + if(0 != socket(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_socket="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_socket="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_socket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socket usage allowed" >&5 +printf %s "checking if socket usage allowed... " >&6; } + if test "x$curl_disallow_socket" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_socket="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_socket="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socket might be used" >&5 +printf %s "checking if socket might be used... " >&6; } + if test "$tst_links_socket" = "yes" && + test "$tst_proto_socket" = "yes" && + test "$tst_compi_socket" = "yes" && + test "$tst_allow_socket" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h + + curl_cv_func_socket="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_socket="no" + fi + + + # + tst_links_socketpair="unknown" + tst_proto_socketpair="unknown" + tst_compi_socketpair="unknown" + tst_allow_socketpair="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socketpair can be linked" >&5 +printf %s "checking if socketpair can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define socketpair innocuous_socketpair +#ifdef __STDC__ +# include +#else +# include +#endif +#undef socketpair +#ifdef __cplusplus +extern "C" +#endif +char socketpair (); +#if defined __stub_socketpair || defined __stub___socketpair +choke me +#endif + +int main (void) +{ +return socketpair (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_socketpair="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_socketpair="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_socketpair" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socketpair is prototyped" >&5 +printf %s "checking if socketpair is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_sys_socket + $curl_includes_socket + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "socketpair" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_socketpair="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_socketpair="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_socketpair" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socketpair is compilable" >&5 +printf %s "checking if socketpair is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_sys_socket + $curl_includes_socket + +int main (void) +{ + + int sv[2]; + if(0 != socketpair(0, 0, 0, sv)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_socketpair="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_socketpair="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_socketpair" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socketpair usage allowed" >&5 +printf %s "checking if socketpair usage allowed... " >&6; } + if test "x$curl_disallow_socketpair" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_socketpair="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_socketpair="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if socketpair might be used" >&5 +printf %s "checking if socketpair might be used... " >&6; } + if test "$tst_links_socketpair" = "yes" && + test "$tst_proto_socketpair" = "yes" && + test "$tst_compi_socketpair" = "yes" && + test "$tst_allow_socketpair" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SOCKETPAIR 1" >>confdefs.h + + curl_cv_func_socketpair="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_socketpair="no" + fi + + + # + tst_links_strcasecmp="unknown" + tst_proto_strcasecmp="unknown" + tst_compi_strcasecmp="unknown" + tst_allow_strcasecmp="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcasecmp can be linked" >&5 +printf %s "checking if strcasecmp can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strcasecmp innocuous_strcasecmp +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strcasecmp +#ifdef __cplusplus +extern "C" +#endif +char strcasecmp (); +#if defined __stub_strcasecmp || defined __stub___strcasecmp +choke me +#endif + +int main (void) +{ +return strcasecmp (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_strcasecmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_strcasecmp="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_strcasecmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcasecmp is prototyped" >&5 +printf %s "checking if strcasecmp is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strcasecmp" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_strcasecmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_strcasecmp="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_strcasecmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcasecmp is compilable" >&5 +printf %s "checking if strcasecmp is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != strcasecmp(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_strcasecmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_strcasecmp="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_strcasecmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcasecmp usage allowed" >&5 +printf %s "checking if strcasecmp usage allowed... " >&6; } + if test "x$curl_disallow_strcasecmp" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_strcasecmp="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_strcasecmp="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcasecmp might be used" >&5 +printf %s "checking if strcasecmp might be used... " >&6; } + if test "$tst_links_strcasecmp" = "yes" && + test "$tst_proto_strcasecmp" = "yes" && + test "$tst_compi_strcasecmp" = "yes" && + test "$tst_allow_strcasecmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h + + curl_cv_func_strcasecmp="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_strcasecmp="no" + fi + + + # + tst_links_strcmpi="unknown" + tst_proto_strcmpi="unknown" + tst_compi_strcmpi="unknown" + tst_allow_strcmpi="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcmpi can be linked" >&5 +printf %s "checking if strcmpi can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strcmpi innocuous_strcmpi +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strcmpi +#ifdef __cplusplus +extern "C" +#endif +char strcmpi (); +#if defined __stub_strcmpi || defined __stub___strcmpi +choke me +#endif + +int main (void) +{ +return strcmpi (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_strcmpi="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_strcmpi="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_strcmpi" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcmpi is prototyped" >&5 +printf %s "checking if strcmpi is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strcmpi" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_strcmpi="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_strcmpi="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_strcmpi" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcmpi is compilable" >&5 +printf %s "checking if strcmpi is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != strcmpi(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_strcmpi="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_strcmpi="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_strcmpi" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcmpi usage allowed" >&5 +printf %s "checking if strcmpi usage allowed... " >&6; } + if test "x$curl_disallow_strcmpi" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_strcmpi="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_strcmpi="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strcmpi might be used" >&5 +printf %s "checking if strcmpi might be used... " >&6; } + if test "$tst_links_strcmpi" = "yes" && + test "$tst_proto_strcmpi" = "yes" && + test "$tst_compi_strcmpi" = "yes" && + test "$tst_allow_strcmpi" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_STRCMPI 1" >>confdefs.h + + curl_cv_func_strcmpi="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_strcmpi="no" + fi + + + # + tst_links_strdup="unknown" + tst_proto_strdup="unknown" + tst_compi_strdup="unknown" + tst_allow_strdup="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strdup can be linked" >&5 +printf %s "checking if strdup can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strdup innocuous_strdup +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strdup +#ifdef __cplusplus +extern "C" +#endif +char strdup (); +#if defined __stub_strdup || defined __stub___strdup +choke me +#endif + +int main (void) +{ +return strdup (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_strdup="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_strdup="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_strdup" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strdup is prototyped" >&5 +printf %s "checking if strdup is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strdup" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_strdup="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_strdup="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_strdup" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strdup is compilable" >&5 +printf %s "checking if strdup is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != strdup(0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_strdup="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_strdup="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_strdup" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strdup usage allowed" >&5 +printf %s "checking if strdup usage allowed... " >&6; } + if test "x$curl_disallow_strdup" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_strdup="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_strdup="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strdup might be used" >&5 +printf %s "checking if strdup might be used... " >&6; } + if test "$tst_links_strdup" = "yes" && + test "$tst_proto_strdup" = "yes" && + test "$tst_compi_strdup" = "yes" && + test "$tst_allow_strdup" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h + + curl_cv_func_strdup="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_strdup="no" + fi + + + # + tst_links_strerror_r="unknown" + tst_proto_strerror_r="unknown" + tst_compi_strerror_r="unknown" + tst_glibc_strerror_r="unknown" + tst_posix_strerror_r="unknown" + tst_allow_strerror_r="unknown" + tst_works_glibc_strerror_r="unknown" + tst_works_posix_strerror_r="unknown" + tst_glibc_strerror_r_type_arg3="unknown" + tst_posix_strerror_r_type_arg3="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r can be linked" >&5 +printf %s "checking if strerror_r can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strerror_r innocuous_strerror_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strerror_r +#ifdef __cplusplus +extern "C" +#endif +char strerror_r (); +#if defined __stub_strerror_r || defined __stub___strerror_r +choke me +#endif + +int main (void) +{ +return strerror_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_strerror_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_strerror_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_strerror_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r is prototyped" >&5 +printf %s "checking if strerror_r is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strerror_r" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_strerror_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_strerror_r="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_strerror_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r is compilable" >&5 +printf %s "checking if strerror_r is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != strerror_r(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_strerror_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_strerror_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_strerror_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r is glibc like" >&5 +printf %s "checking if strerror_r is glibc like... " >&6; } + tst_glibc_strerror_r_type_arg3="unknown" + for arg3 in 'size_t' 'int' 'unsigned int'; do + if test "$tst_glibc_strerror_r_type_arg3" = "unknown"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + char *strerror_r(int errnum, char *workbuf, $arg3 bufsize); + +int main (void) +{ + + if(0 != strerror_r(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tst_glibc_strerror_r_type_arg3="$arg3" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + done + case "$tst_glibc_strerror_r_type_arg3" in + unknown) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_glibc_strerror_r="no" + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_glibc_strerror_r="yes" + ;; + esac + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_glibc_strerror_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r seems to work" >&5 +printf %s "checking if strerror_r seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_string +# include + +int main (void) +{ + + char buffer[1024]; + char *string = 0; + buffer[0] = '\0'; + string = strerror_r(EACCES, buffer, sizeof(buffer)); + if(!string) + exit(1); /* fail */ + if(!string[0]) + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_glibc_strerror_r="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_glibc_strerror_r="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_string +# include + +int main (void) +{ + + char buffer[1024]; + char *string = 0; + buffer[0] = '\0'; + string = strerror_r(EACCES, buffer, sizeof(buffer)); + if(!string) + exit(1); /* fail */ + if(!string[0]) + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_glibc_strerror_r="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_glibc_strerror_r="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_compi_strerror_r" = "yes" && + test "$tst_works_glibc_strerror_r" != "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r is POSIX like" >&5 +printf %s "checking if strerror_r is POSIX like... " >&6; } + tst_posix_strerror_r_type_arg3="unknown" + for arg3 in 'size_t' 'int' 'unsigned int'; do + if test "$tst_posix_strerror_r_type_arg3" = "unknown"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + int strerror_r(int errnum, char *resultbuf, $arg3 bufsize); + +int main (void) +{ + + if(0 != strerror_r(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + tst_posix_strerror_r_type_arg3="$arg3" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + done + case "$tst_posix_strerror_r_type_arg3" in + unknown) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_posix_strerror_r="no" + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_posix_strerror_r="yes" + ;; + esac + fi + # + if test "x$cross_compiling" != "xyes" && + test "$tst_posix_strerror_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r seems to work" >&5 +printf %s "checking if strerror_r seems to work... " >&6; } + + case $host_os in + darwin*) + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_string +# include + +int main (void) +{ + + char buffer[1024]; + int error = 1; + buffer[0] = '\0'; + error = strerror_r(EACCES, buffer, sizeof(buffer)); + if(error) + exit(1); /* fail */ + if(buffer[0] == '\0') + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_posix_strerror_r="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_posix_strerror_r="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + $curl_includes_string +# include + +int main (void) +{ + + char buffer[1024]; + int error = 1; + buffer[0] = '\0'; + error = strerror_r(EACCES, buffer, sizeof(buffer)); + if(error) + exit(1); /* fail */ + if(buffer[0] == '\0') + exit(1); /* fail */ + else + exit(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_works_posix_strerror_r="yes" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_works_posix_strerror_r="no" + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac + + fi + # + if test "$tst_works_glibc_strerror_r" = "yes"; then + tst_posix_strerror_r="no" + fi + if test "$tst_works_posix_strerror_r" = "yes"; then + tst_glibc_strerror_r="no" + fi + if test "$tst_glibc_strerror_r" = "yes" && + test "$tst_works_glibc_strerror_r" != "no" && + test "$tst_posix_strerror_r" != "yes"; then + tst_allow_strerror_r="check" + fi + if test "$tst_posix_strerror_r" = "yes" && + test "$tst_works_posix_strerror_r" != "no" && + test "$tst_glibc_strerror_r" != "yes"; then + tst_allow_strerror_r="check" + fi + if test "$tst_allow_strerror_r" = "check"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r usage allowed" >&5 +printf %s "checking if strerror_r usage allowed... " >&6; } + if test "x$curl_disallow_strerror_r" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_strerror_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_strerror_r="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strerror_r might be used" >&5 +printf %s "checking if strerror_r might be used... " >&6; } + if test "$tst_links_strerror_r" = "yes" && + test "$tst_proto_strerror_r" = "yes" && + test "$tst_compi_strerror_r" = "yes" && + test "$tst_allow_strerror_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + if test "$tst_glibc_strerror_r" = "yes"; then + +printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h + + +printf "%s\n" "#define HAVE_GLIBC_STRERROR_R 1" >>confdefs.h + + fi + if test "$tst_posix_strerror_r" = "yes"; then + +printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h + + +printf "%s\n" "#define HAVE_POSIX_STRERROR_R 1" >>confdefs.h + + fi + curl_cv_func_strerror_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_strerror_r="no" + fi + # + if test "$tst_compi_strerror_r" = "yes" && + test "$tst_allow_strerror_r" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot determine strerror_r() style: edit lib/curl_config.h manually." >&5 +printf "%s\n" "$as_me: WARNING: cannot determine strerror_r() style: edit lib/curl_config.h manually." >&2;} + fi + # + + + # + tst_links_stricmp="unknown" + tst_proto_stricmp="unknown" + tst_compi_stricmp="unknown" + tst_allow_stricmp="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if stricmp can be linked" >&5 +printf %s "checking if stricmp can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define stricmp innocuous_stricmp +#ifdef __STDC__ +# include +#else +# include +#endif +#undef stricmp +#ifdef __cplusplus +extern "C" +#endif +char stricmp (); +#if defined __stub_stricmp || defined __stub___stricmp +choke me +#endif + +int main (void) +{ +return stricmp (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_stricmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_stricmp="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_stricmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if stricmp is prototyped" >&5 +printf %s "checking if stricmp is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "stricmp" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_stricmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_stricmp="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_stricmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if stricmp is compilable" >&5 +printf %s "checking if stricmp is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != stricmp(0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_stricmp="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_stricmp="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_stricmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if stricmp usage allowed" >&5 +printf %s "checking if stricmp usage allowed... " >&6; } + if test "x$curl_disallow_stricmp" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_stricmp="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_stricmp="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if stricmp might be used" >&5 +printf %s "checking if stricmp might be used... " >&6; } + if test "$tst_links_stricmp" = "yes" && + test "$tst_proto_stricmp" = "yes" && + test "$tst_compi_stricmp" = "yes" && + test "$tst_allow_stricmp" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_STRICMP 1" >>confdefs.h + + curl_cv_func_stricmp="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_stricmp="no" + fi + + + # + tst_links_strtok_r="unknown" + tst_proto_strtok_r="unknown" + tst_compi_strtok_r="unknown" + tst_allow_strtok_r="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtok_r can be linked" >&5 +printf %s "checking if strtok_r can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strtok_r innocuous_strtok_r +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strtok_r +#ifdef __cplusplus +extern "C" +#endif +char strtok_r (); +#if defined __stub_strtok_r || defined __stub___strtok_r +choke me +#endif + +int main (void) +{ +return strtok_r (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_strtok_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_strtok_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_strtok_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtok_r is prototyped" >&5 +printf %s "checking if strtok_r is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_string + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strtok_r" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_strtok_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_strtok_r="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_strtok_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtok_r is compilable" >&5 +printf %s "checking if strtok_r is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_string + +int main (void) +{ + + if(0 != strtok_r(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_strtok_r="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_strtok_r="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_strtok_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtok_r usage allowed" >&5 +printf %s "checking if strtok_r usage allowed... " >&6; } + if test "x$curl_disallow_strtok_r" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_strtok_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_strtok_r="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtok_r might be used" >&5 +printf %s "checking if strtok_r might be used... " >&6; } + if test "$tst_links_strtok_r" = "yes" && + test "$tst_proto_strtok_r" = "yes" && + test "$tst_compi_strtok_r" = "yes" && + test "$tst_allow_strtok_r" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_STRTOK_R 1" >>confdefs.h + + curl_cv_func_strtok_r="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_strtok_r="no" + fi + + + # + tst_links_strtoll="unknown" + tst_proto_strtoll="unknown" + tst_compi_strtoll="unknown" + tst_allow_strtoll="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtoll can be linked" >&5 +printf %s "checking if strtoll can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define strtoll innocuous_strtoll +#ifdef __STDC__ +# include +#else +# include +#endif +#undef strtoll +#ifdef __cplusplus +extern "C" +#endif +char strtoll (); +#if defined __stub_strtoll || defined __stub___strtoll +choke me +#endif + +int main (void) +{ +return strtoll (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_strtoll="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_strtoll="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_strtoll" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtoll is prototyped" >&5 +printf %s "checking if strtoll is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $curl_includes_stdlib + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "strtoll" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_strtoll="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_strtoll="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_strtoll" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtoll is compilable" >&5 +printf %s "checking if strtoll is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $curl_includes_stdlib + +int main (void) +{ + + if(0 != strtoll(0, 0, 0)) + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_strtoll="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_strtoll="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_strtoll" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtoll usage allowed" >&5 +printf %s "checking if strtoll usage allowed... " >&6; } + if test "x$curl_disallow_strtoll" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_strtoll="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_strtoll="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if strtoll might be used" >&5 +printf %s "checking if strtoll might be used... " >&6; } + if test "$tst_links_strtoll" = "yes" && + test "$tst_proto_strtoll" = "yes" && + test "$tst_compi_strtoll" = "yes" && + test "$tst_allow_strtoll" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_STRTOLL 1" >>confdefs.h + + curl_cv_func_strtoll="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_cv_func_strtoll="no" + fi + + +case $host in + *msdosdjgpp) + ac_cv_func_pipe=no + skipcheck_pipe=yes + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: skip check for pipe on msdosdjgpp" >&5 +printf "%s\n" "$as_me: skip check for pipe on msdosdjgpp" >&6;} + ;; +esac + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 +printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } +if test ${ac_cv_c_undeclared_builtin_options+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_CFLAGS=$CFLAGS + ac_cv_c_undeclared_builtin_options='cannot detect' + for ac_arg in '' -fno-builtin; do + CFLAGS="$ac_save_CFLAGS $ac_arg" + # This test program should *not* compile successfully. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main (void) +{ +(void) strchr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + # This test program should compile successfully. + # No library function is consistently available on + # freestanding implementations, so test against a dummy + # declaration. Include always-available headers on the + # off chance that they somehow elicit warnings. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +extern void ac_decl (int, char *); + +int main (void) +{ +(void) ac_decl (0, (char *) 0); + (void) ac_decl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + if test x"$ac_arg" = x +then : + ac_cv_c_undeclared_builtin_options='none needed' +else $as_nop + ac_cv_c_undeclared_builtin_options=$ac_arg +fi + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done + CFLAGS=$ac_save_CFLAGS + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 +printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } + case $ac_cv_c_undeclared_builtin_options in #( + 'cannot detect') : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot make $CC report undeclared builtins +See \`config.log' for more details" "$LINENO" 5; } ;; #( + 'none needed') : + ac_c_undeclared_builtin_options='' ;; #( + *) : + ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; +esac + +ac_fn_check_decl "$LINENO" "getpwuid_r" "ac_cv_have_decl_getpwuid_r" "#include + #include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_getpwuid_r" = xyes +then : + ac_have_decl=1 +else $as_nop + ac_have_decl=0 +fi +printf "%s\n" "#define HAVE_DECL_GETPWUID_R $ac_have_decl" >>confdefs.h +if test $ac_have_decl = 1 +then : + +else $as_nop + +printf "%s\n" "#define HAVE_DECL_GETPWUID_R_MISSING 1" >>confdefs.h + +fi + + + + for ac_func in _fseeki64 arc4random fnmatch fseeko geteuid getpass_r getppid getpwuid getpwuid_r getrlimit gettimeofday if_nametoindex mach_absolute_time pipe sched_yield sendmsg setlocale setmode setrlimit snprintf utime utimes +do : + as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + + +else $as_nop + + func="$ac_func" + eval skipcheck=\$skipcheck_$func + if test "x$skipcheck" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking deeper for $func" >&5 +printf %s "checking deeper for $func... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + +int main (void) +{ + + $func (); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + eval "ac_cv_func_$func=yes" + +cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$func" | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' | sed 's/^A-Z0-9_/_/g'` 1 +_ACEOF + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: but still no" >&5 +printf "%s\n" "but still no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + fi + +fi + +done + +ac_fn_check_decl "$LINENO" "fseeko" "ac_cv_have_decl_fseeko" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_fseeko" = xyes +then : + +printf "%s\n" "#define HAVE_DECL_FSEEKO 1" >>confdefs.h + +fi + + + # + tst_method="unknown" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to set a socket into non-blocking mode" >&5 +printf %s "checking how to set a socket into non-blocking mode... " >&6; } + if test "x$curl_cv_func_fcntl_o_nonblock" = "xyes"; then + tst_method="fcntl O_NONBLOCK" + elif test "x$curl_cv_func_ioctl_fionbio" = "xyes"; then + tst_method="ioctl FIONBIO" + elif test "x$curl_cv_func_ioctlsocket_fionbio" = "xyes"; then + tst_method="ioctlsocket FIONBIO" + elif test "x$curl_cv_func_ioctlsocket_camel_fionbio" = "xyes"; then + tst_method="IoctlSocket FIONBIO" + elif test "x$curl_cv_func_setsockopt_so_nonblock" = "xyes"; then + tst_method="setsockopt SO_NONBLOCK" + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tst_method" >&5 +printf "%s\n" "$tst_method" >&6; } + if test "$tst_method" = "unknown"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot determine non-blocking socket method." >&5 +printf "%s\n" "$as_me: WARNING: cannot determine non-blocking socket method." >&2;} + fi + + + +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PERL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/local/bin/perl:/usr/bin/:/usr/local/bin " +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PERL="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +printf "%s\n" "$PERL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + + +for ac_prog in gnroff nroff +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_NROFF+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $NROFF in + [\\/]* | ?:[\\/]*) + ac_cv_path_NROFF="$NROFF" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin/:/usr/local/bin " +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_NROFF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +NROFF=$ac_cv_path_NROFF +if test -n "$NROFF"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NROFF" >&5 +printf "%s\n" "$NROFF" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$NROFF" && break +done + + + +if test -n "$NROFF"; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to use *nroff to get plain text from man pages" >&5 +printf %s "checking how to use *nroff to get plain text from man pages... " >&6; } + MANOPT="-man" + mancheck=`echo foo | $NROFF $MANOPT 2>/dev/null` + if test -z "$mancheck"; then + MANOPT="-mandoc" + mancheck=`echo foo | $NROFF $MANOPT 2>/dev/null` + if test -z "$mancheck"; then + MANOPT="" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +printf "%s\n" "failed" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: found no *nroff option to get plaintext from man pages" >&5 +printf "%s\n" "$as_me: WARNING: found no *nroff option to get plaintext from man pages" >&2;} + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANOPT" >&5 +printf "%s\n" "$MANOPT" >&6; } + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANOPT" >&5 +printf "%s\n" "$MANOPT" >&6; } + fi + +fi + +if test -z "$MANOPT" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: disabling built-in manual" >&5 +printf "%s\n" "$as_me: WARNING: disabling built-in manual" >&2;} + USE_MANUAL="no"; +fi + + +if test "$USE_MANUAL" = "1"; then + +printf "%s\n" "#define USE_MANUAL 1" >>confdefs.h + + curl_manual_msg="enabled" +fi + + if test x"$USE_MANUAL" = x1; then + USE_MANUAL_TRUE= + USE_MANUAL_FALSE='#' +else + USE_MANUAL_TRUE='#' + USE_MANUAL_FALSE= +fi + + + + # + if test "$want_ares" = "yes"; then + clean_CPPFLAGS="$CPPFLAGS" + clean_LDFLAGS="$LDFLAGS" + clean_LIBS="$LIBS" + configure_runpath=`pwd` + if test -n "$want_ares_path"; then + ARES_PCDIR="$want_ares_path/lib/pkgconfig" + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libcares options with pkg-config" >&5 +printf %s "checking for libcares options with pkg-config... " >&6; } + itexists=` + if test -n "$ARES_PCDIR"; then + PKG_CONFIG_LIBDIR="$ARES_PCDIR" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libcares >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + if test "$PKGCONFIG" != "no" ; then + ares_LIBS=` + if test -n "$ARES_PCDIR"; then + PKG_CONFIG_LIBDIR="$ARES_PCDIR" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-l libcares` + ares_LDFLAGS=` + if test -n "$ARES_PCDIR"; then + PKG_CONFIG_LIBDIR="$ARES_PCDIR" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --libs-only-L libcares` + ares_CPPFLAGS=` + if test -n "$ARES_PCDIR"; then + PKG_CONFIG_LIBDIR="$ARES_PCDIR" + export PKG_CONFIG_LIBDIR + fi + + $PKGCONFIG --cflags-only-I libcares` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: ares LIBS: \"$ares_LIBS\"" >&5 +printf "%s\n" "$as_me: pkg-config: ares LIBS: \"$ares_LIBS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: ares LDFLAGS: \"$ares_LDFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: ares LDFLAGS: \"$ares_LDFLAGS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: ares CPPFLAGS: \"$ares_CPPFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: ares CPPFLAGS: \"$ares_CPPFLAGS\"" >&6;} + else + ares_CPPFLAGS="-I$want_ares_path/include" + ares_LDFLAGS="-L$want_ares_path/lib" + ares_LIBS="-lcares" + fi + else + + if test -n "$PKG_CONFIG"; then + PKGCONFIG="$PKG_CONFIG" + else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKGCONFIG=$ac_cv_path_PKGCONFIG +if test -n "$PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +printf "%s\n" "$PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKGCONFIG"; then + ac_pt_PKGCONFIG=$PKGCONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKGCONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKGCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/usr/bin:/usr/local/bin" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG +if test -n "$ac_pt_PKGCONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 +printf "%s\n" "$ac_pt_PKGCONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKGCONFIG" = x; then + PKGCONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKGCONFIG=$ac_pt_PKGCONFIG + fi +else + PKGCONFIG="$ac_cv_path_PKGCONFIG" +fi + + fi + + if test "x$PKGCONFIG" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libcares options with pkg-config" >&5 +printf %s "checking for libcares options with pkg-config... " >&6; } + itexists=` + if test -n ""; then + PKG_CONFIG_LIBDIR="" + export PKG_CONFIG_LIBDIR + fi + $PKGCONFIG --exists libcares >/dev/null 2>&1 && echo 1` + + if test -z "$itexists"; then + PKGCONFIG="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + fi + fi + + if test "$PKGCONFIG" != "no" ; then + ares_LIBS=`$PKGCONFIG --libs-only-l libcares` + ares_LDFLAGS=`$PKGCONFIG --libs-only-L libcares` + ares_CPPFLAGS=`$PKGCONFIG --cflags-only-I libcares` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: ares_LIBS: \"$ares_LIBS\"" >&5 +printf "%s\n" "$as_me: pkg-config: ares_LIBS: \"$ares_LIBS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: ares_LDFLAGS: \"$ares_LDFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: ares_LDFLAGS: \"$ares_LDFLAGS\"" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pkg-config: ares_CPPFLAGS: \"$ares_CPPFLAGS\"" >&5 +printf "%s\n" "$as_me: pkg-config: ares_CPPFLAGS: \"$ares_CPPFLAGS\"" >&6;} + else + ares_CPPFLAGS="" + ares_LDFLAGS="" + ares_LIBS="-lcares" + fi + fi + # + CPPFLAGS="$clean_CPPFLAGS $ares_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS $ares_LDFLAGS" + LIBS="$ares_LIBS $clean_LIBS" + # + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that c-ares is good and recent enough" >&5 +printf %s "checking that c-ares is good and recent enough... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + /* set of dummy functions in case c-ares was built with debug */ + void curl_dofree() { } + void curl_sclose() { } + void curl_domalloc() { } + void curl_docalloc() { } + void curl_socket() { } + +int main (void) +{ + + ares_channel channel; + ares_cancel(channel); /* added in 1.2.0 */ + ares_process_fd(channel, 0, 0); /* added in 1.4.0 */ + ares_dup(&channel, channel); /* added in 1.6.0 */ + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + as_fn_error $? "c-ares library defective or too old" "$LINENO" 5 + CPPFLAGS="$clean_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS" + LIBS="$clean_LIBS" + # prevent usage + want_ares="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + if test "$want_ares" = "yes"; then + +printf "%s\n" "#define USE_ARES 1" >>confdefs.h + + USE_ARES=1 + + curl_res_msg="c-ares" + fi + fi + + +if test "x$curl_cv_native_windows" != "xyes" && + test "x$enable_shared" = "xyes"; then + build_libhostname=yes +else + build_libhostname=no +fi + if test x$build_libhostname = xyes; then + BUILD_LIBHOSTNAME_TRUE= + BUILD_LIBHOSTNAME_FALSE='#' +else + BUILD_LIBHOSTNAME_TRUE='#' + BUILD_LIBHOSTNAME_FALSE= +fi + + +if test "x$want_ares" != xyes; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable the threaded resolver" >&5 +printf %s "checking whether to enable the threaded resolver... " >&6; } + OPT_THRES="default" + # Check whether --enable-threaded_resolver was given. +if test ${enable_threaded_resolver+y} +then : + enableval=$enable_threaded_resolver; OPT_THRES=$enableval +fi + + case "$OPT_THRES" in + no) + want_thres="no" + ;; + *) + want_thres="yes" + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_thres" >&5 +printf "%s\n" "$want_thres" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use POSIX threads for threaded resolver" >&5 +printf %s "checking whether to use POSIX threads for threaded resolver... " >&6; } +# Check whether --enable-pthreads was given. +if test ${enable_pthreads+y} +then : + enableval=$enable_pthreads; case "$enableval" in + no) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + want_pthreads=no + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + want_pthreads=yes + ;; + esac +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: auto" >&5 +printf "%s\n" "auto" >&6; } + want_pthreads=auto + + +fi + + +if test "$want_pthreads" != "no"; then + if test "$want_pthreads" = "yes" && test "$dontwant_rt" = "yes"; then + as_fn_error $? "options --enable-pthreads and --disable-rt are mutually exclusive" "$LINENO" 5 + fi + if test "$dontwant_rt" != "no"; then + if test "$want_pthreads" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --enable-pthreads Ignored since librt is disabled." >&5 +printf "%s\n" "$as_me: WARNING: --enable-pthreads Ignored since librt is disabled." >&2;} + fi + want_pthreads=no + fi +fi + +if test "$want_pthreads" != "no" && test "$want_thres" != "yes"; then + want_pthreads=no +fi + +if test "$want_pthreads" != "no"; then + ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : + +printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + + LIBS= + ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" +if test "x$ac_cv_func_pthread_create" = xyes +then : + USE_THREADS_POSIX=1 +fi + + LIBS="$save_LIBS" + + case $host in + *-hp-hpux*) + USE_THREADS_POSIX="" + ;; + *) + ;; + esac + + if test "$USE_THREADS_POSIX" != "1" + then + # assign PTHREAD for pkg-config use + PTHREAD=" -pthread" + + case $host in + *-ibm-aix*) + COMPILER_VERSION=`"$CC" -qversion 2>/dev/null` + if test x"$COMPILER_VERSION" = "x"; then + CFLAGS="$CFLAGS -pthread" + else + CFLAGS="$CFLAGS -qthreaded" + fi + ;; + powerpc-*amigaos*) + PTHREAD=" -lpthread" + ;; + *) + CFLAGS="$CFLAGS -pthread" + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int main (void) +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_pthread_pthread_create=yes +else $as_nop + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : + USE_THREADS_POSIX=1 +else $as_nop + CFLAGS="$save_CFLAGS" +fi + + fi + + if test "x$USE_THREADS_POSIX" = "x1" + then + +printf "%s\n" "#define USE_THREADS_POSIX 1" >>confdefs.h + + curl_res_msg="POSIX threaded" + fi + +fi + +fi + +if test "$want_thres" = "yes" && test "x$USE_THREADS_POSIX" != "x1"; then + if test "$want_pthreads" = "yes"; then + as_fn_error $? "--enable-pthreads but pthreads was not found" "$LINENO" 5 + fi + if test "$curl_cv_native_windows" = "yes"; then + USE_THREADS_WIN32=1 + +printf "%s\n" "#define USE_THREADS_WIN32 1" >>confdefs.h + + curl_res_msg="Win32 threaded" + else + as_fn_error $? "Threaded resolver enabled but no thread library found" "$LINENO" 5 + fi +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking convert -I options to -isystem" >&5 +printf %s "checking convert -I options to -isystem... " >&6; } + if test "$compiler_id" = "GNU_C" || + test "$compiler_id" = "CLANG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tmp_has_include="no" + tmp_chg_FLAGS="$CFLAGS" + for word1 in $tmp_chg_FLAGS; do + case "$word1" in + -I*) + tmp_has_include="yes" + ;; + esac + done + if test "$tmp_has_include" = "yes"; then + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` + CFLAGS="$tmp_chg_FLAGS" + squeeze CFLAGS + fi + tmp_has_include="no" + tmp_chg_FLAGS="$CPPFLAGS" + for word1 in $tmp_chg_FLAGS; do + case "$word1" in + -I*) + tmp_has_include="yes" + ;; + esac + done + if test "$tmp_has_include" = "yes"; then + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` + CPPFLAGS="$tmp_chg_FLAGS" + squeeze CPPFLAGS + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable verbose strings" >&5 +printf %s "checking whether to enable verbose strings... " >&6; } +# Check whether --enable-verbose was given. +if test ${enable_verbose+y} +then : + enableval=$enable_verbose; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_VERBOSE_STRINGS 1" >>confdefs.h + + curl_verbose_msg="no" + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable SSPI support (Windows native builds only)" >&5 +printf %s "checking whether to enable SSPI support (Windows native builds only)... " >&6; } +# Check whether --enable-sspi was given. +if test ${enable_sspi+y} +then : + enableval=$enable_sspi; case "$enableval" in + yes) + if test "$curl_cv_native_windows" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define USE_WINDOWS_SSPI 1" >>confdefs.h + + USE_WINDOWS_SSPI=1 + + curl_sspi_msg="enabled" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --enable-sspi Ignored. Only supported on native Windows builds." >&5 +printf "%s\n" "$as_me: WARNING: --enable-sspi Ignored. Only supported on native Windows builds." >&2;} + fi + ;; + *) + if test "x$SCHANNEL_ENABLED" = "x1"; then + # --with-schannel implies --enable-sspi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + ;; + esac +else $as_nop + if test "x$SCHANNEL_ENABLED" = "x1"; then + # --with-schannel implies --enable-sspi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable basic authentication method" >&5 +printf %s "checking whether to enable basic authentication method... " >&6; } +# Check whether --enable-basic-auth was given. +if test ${enable_basic_auth+y} +then : + enableval=$enable_basic_auth; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_BASIC_AUTH 1" >>confdefs.h + + CURL_DISABLE_BASIC_AUTH=1 + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable bearer authentication method" >&5 +printf %s "checking whether to enable bearer authentication method... " >&6; } +# Check whether --enable-bearer-auth was given. +if test ${enable_bearer_auth+y} +then : + enableval=$enable_bearer_auth; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_BEARER_AUTH 1" >>confdefs.h + + CURL_DISABLE_BEARER_AUTH=1 + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable digest authentication method" >&5 +printf %s "checking whether to enable digest authentication method... " >&6; } +# Check whether --enable-digest-auth was given. +if test ${enable_digest_auth+y} +then : + enableval=$enable_digest_auth; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_DIGEST_AUTH 1" >>confdefs.h + + CURL_DISABLE_DIGEST_AUTH=1 + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable kerberos authentication method" >&5 +printf %s "checking whether to enable kerberos authentication method... " >&6; } +# Check whether --enable-kerberos-auth was given. +if test ${enable_kerberos_auth+y} +then : + enableval=$enable_kerberos_auth; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_KERBEROS_AUTH 1" >>confdefs.h + + CURL_DISABLE_KERBEROS_AUTH=1 + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable negotiate authentication method" >&5 +printf %s "checking whether to enable negotiate authentication method... " >&6; } +# Check whether --enable-negotiate-auth was given. +if test ${enable_negotiate_auth+y} +then : + enableval=$enable_negotiate_auth; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_NEGOTIATE_AUTH 1" >>confdefs.h + + CURL_DISABLE_NEGOTIATE_AUTH=1 + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable aws sig methods" >&5 +printf %s "checking whether to enable aws sig methods... " >&6; } +# Check whether --enable-aws was given. +if test ${enable_aws+y} +then : + enableval=$enable_aws; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_AWS 1" >>confdefs.h + + CURL_DISABLE_AWS=1 + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support NTLM" >&5 +printf %s "checking whether to support NTLM... " >&6; } +# Check whether --enable-ntlm was given. +if test ${enable_ntlm+y} +then : + enableval=$enable_ntlm; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_NTLM 1" >>confdefs.h + + CURL_DISABLE_NTLM=1 + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + + + OPT_NTLM_WB="default" + # Check whether --enable-ntlm-wb was given. +if test ${enable_ntlm_wb+y} +then : + enableval=$enable_ntlm_wb; OPT_NTLM_WB=$enableval +fi + + want_ntlm_wb_file="/usr/bin/ntlm_auth" + case "$OPT_NTLM_WB" in + no) + want_ntlm_wb="no" + ;; + default) + want_ntlm_wb="yes" + ;; + *) + want_ntlm_wb="yes" + if test -n "$enableval" && test "$enableval" != "yes"; then + want_ntlm_wb_file="$enableval" + fi + ;; + esac + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable NTLM delegation to winbind's helper" >&5 +printf %s "checking whether to enable NTLM delegation to winbind's helper... " >&6; } + if test "$curl_cv_native_windows" = "yes" || + test "x$SSL_ENABLED" = "x"; then + want_ntlm_wb_file="" + want_ntlm_wb="no" + elif test "x$ac_cv_func_fork" != "xyes"; then + want_ntlm_wb="no" + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_ntlm_wb" >&5 +printf "%s\n" "$want_ntlm_wb" >&6; } + if test "$want_ntlm_wb" = "yes"; then + +printf "%s\n" "#define NTLM_WB_ENABLED 1" >>confdefs.h + + +printf "%s\n" "#define NTLM_WB_FILE \"$want_ntlm_wb_file\"" >>confdefs.h + + NTLM_WB_ENABLED=1 + fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable TLS-SRP authentication" >&5 +printf %s "checking whether to enable TLS-SRP authentication... " >&6; } +# Check whether --enable-tls-srp was given. +if test ${enable_tls_srp+y} +then : + enableval=$enable_tls_srp; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + want_tls_srp=no + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + want_tls_srp=yes + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + want_tls_srp=yes + +fi + + +if test "$want_tls_srp" = "yes" && ( test "x$HAVE_GNUTLS_SRP" = "x1" || test "x$HAVE_OPENSSL_SRP" = "x1") ; then + +printf "%s\n" "#define USE_TLS_SRP 1" >>confdefs.h + + USE_TLS_SRP=1 + curl_tls_srp_msg="enabled" +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable Unix domain sockets" >&5 +printf %s "checking whether to enable Unix domain sockets... " >&6; } +# Check whether --enable-unix-sockets was given. +if test ${enable_unix_sockets+y} +then : + enableval=$enable_unix_sockets; case "$enableval" in + no) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + want_unix_sockets=no + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + want_unix_sockets=yes + ;; + esac +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: auto" >&5 +printf "%s\n" "auto" >&6; } + want_unix_sockets=auto + + +fi + +if test "x$want_unix_sockets" != "xno"; then + if test "x$curl_cv_native_windows" = "xyes"; then + USE_UNIX_SOCKETS=1 + +printf "%s\n" "#define USE_UNIX_SOCKETS 1" >>confdefs.h + + curl_unix_sockets_msg="enabled" + else + ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_path" "ac_cv_member_struct_sockaddr_un_sun_path" " + #include + +" +if test "x$ac_cv_member_struct_sockaddr_un_sun_path" = xyes +then : + + +printf "%s\n" "#define USE_UNIX_SOCKETS 1" >>confdefs.h + + USE_UNIX_SOCKETS=1 + + curl_unix_sockets_msg="enabled" + +else $as_nop + + if test "x$want_unix_sockets" = "xyes"; then + as_fn_error $? "--enable-unix-sockets is not available on this platform!" "$LINENO" 5 + fi + +fi + + fi +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support cookies" >&5 +printf %s "checking whether to support cookies... " >&6; } +# Check whether --enable-cookies was given. +if test ${enable_cookies+y} +then : + enableval=$enable_cookies; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_COOKIES 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support socketpair" >&5 +printf %s "checking whether to support socketpair... " >&6; } +# Check whether --enable-socketpair was given. +if test ${enable_socketpair+y} +then : + enableval=$enable_socketpair; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_SOCKETPAIR 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support HTTP authentication" >&5 +printf %s "checking whether to support HTTP authentication... " >&6; } +# Check whether --enable-http-auth was given. +if test ${enable_http_auth+y} +then : + enableval=$enable_http_auth; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_HTTP_AUTH 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support DoH" >&5 +printf %s "checking whether to support DoH... " >&6; } +# Check whether --enable-doh was given. +if test ${enable_doh+y} +then : + enableval=$enable_doh; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_DOH 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support the MIME API" >&5 +printf %s "checking whether to support the MIME API... " >&6; } +# Check whether --enable-mime was given. +if test ${enable_mime+y} +then : + enableval=$enable_mime; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_MIME 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support binding connections locally" >&5 +printf %s "checking whether to support binding connections locally... " >&6; } +# Check whether --enable-bindlocal was given. +if test ${enable_bindlocal+y} +then : + enableval=$enable_bindlocal; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_BINDLOCAL 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support the form API" >&5 +printf %s "checking whether to support the form API... " >&6; } +# Check whether --enable-form-api was given. +if test ${enable_form_api+y} +then : + enableval=$enable_form_api; case "$enableval" in + no) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_FORM_API 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + test "$enable_mime" = no && + as_fn_error $? "MIME support needs to be enabled in order to enable form API support" "$LINENO" 5 + ;; + esac +else $as_nop + + if test "$enable_mime" = no; then + enable_form_api=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_FORM_API 1" >>confdefs.h + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + fi + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support date parsing" >&5 +printf %s "checking whether to support date parsing... " >&6; } +# Check whether --enable-dateparse was given. +if test ${enable_dateparse+y} +then : + enableval=$enable_dateparse; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_PARSEDATE 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support netrc parsing" >&5 +printf %s "checking whether to support netrc parsing... " >&6; } +# Check whether --enable-netrc was given. +if test ${enable_netrc+y} +then : + enableval=$enable_netrc; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_NETRC 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support progress-meter" >&5 +printf %s "checking whether to support progress-meter... " >&6; } +# Check whether --enable-progress-meter was given. +if test ${enable_progress_meter+y} +then : + enableval=$enable_progress_meter; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_PROGRESS_METER 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support DNS shuffling" >&5 +printf %s "checking whether to support DNS shuffling... " >&6; } +# Check whether --enable-dnsshuffle was given. +if test ${enable_dnsshuffle+y} +then : + enableval=$enable_dnsshuffle; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_SHUFFLE_DNS 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support curl_easy_option*" >&5 +printf %s "checking whether to support curl_easy_option*... " >&6; } +# Check whether --enable-get-easy-options was given. +if test ${enable_get_easy_options+y} +then : + enableval=$enable_get_easy_options; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_GETOPTIONS 1" >>confdefs.h + + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support alt-svc" >&5 +printf %s "checking whether to support alt-svc... " >&6; } +# Check whether --enable-alt-svc was given. +if test ${enable_alt_svc+y} +then : + enableval=$enable_alt_svc; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define CURL_DISABLE_ALTSVC 1" >>confdefs.h + + curl_altsvc_msg="no"; + enable_altsvc="no" + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support headers-api" >&5 +printf %s "checking whether to support headers-api... " >&6; } +# Check whether --enable-headers-api was given. +if test ${enable_headers_api+y} +then : + enableval=$enable_headers_api; case "$enableval" in + no) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + curl_headers_msg="no (--enable-headers-api)" + +printf "%s\n" "#define CURL_DISABLE_HEADERS_API 1" >>confdefs.h + + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +if test -n "$SSL_ENABLED"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support HSTS" >&5 +printf %s "checking whether to support HSTS... " >&6; } + # Check whether --enable-hsts was given. +if test ${enable_hsts+y} +then : + enableval=$enable_hsts; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + hsts="no" + ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hsts" >&5 +printf "%s\n" "$hsts" >&6; } + +fi + +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: disables HSTS due to lack of SSL" >&5 +printf "%s\n" "$as_me: disables HSTS due to lack of SSL" >&6;} + hsts="no" +fi + +if test "x$hsts" != "xyes"; then + curl_hsts_msg="no (--enable-hsts)"; + +printf "%s\n" "#define CURL_DISABLE_HSTS 1" >>confdefs.h + +fi + +if test "x$want_ech" != "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ECH support is available" >&5 +printf %s "checking whether ECH support is available... " >&6; } + + ECH_ENABLED=0 + ECH_SUPPORT='' + + if test "x$OPENSSL_ENABLED" = "x1"; then + + for ac_func in SSL_get_ech_status +do : + ac_fn_c_check_func "$LINENO" "SSL_get_ech_status" "ac_cv_func_SSL_get_ech_status" +if test "x$ac_cv_func_SSL_get_ech_status" = xyes +then : + printf "%s\n" "#define HAVE_SSL_GET_ECH_STATUS 1" >>confdefs.h + ECH_SUPPORT="ECH support available (OpenSSL with SSL_get_ech_status)" + ECH_ENABLED=1 +fi + +done + + fi + + if test "x$ECH_ENABLED" = "x1"; then + +printf "%s\n" "#define USE_ECH 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ECH_SUPPORT" >&5 +printf "%s\n" "$ECH_SUPPORT" >&6; } + experimental="$experimental ECH" + else + as_fn_error $? "--enable-ech ignored: No ECH support found" "$LINENO" 5 + fi +fi + +if test "x$OPENSSL_ENABLED" = "x1"; then + ac_fn_c_check_func "$LINENO" "SSL_set0_wbio" "ac_cv_func_SSL_set0_wbio" +if test "x$ac_cv_func_SSL_set0_wbio" = xyes +then : + printf "%s\n" "#define HAVE_SSL_SET0_WBIO 1" >>confdefs.h + +fi + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support WebSockets" >&5 +printf %s "checking whether to support WebSockets... " >&6; } +# Check whether --enable-websockets was given. +if test ${enable_websockets+y} +then : + enableval=$enable_websockets; case "$enableval" in + no) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + *) + if test ${ac_cv_sizeof_curl_off_t} -gt 4; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + curl_ws_msg="enabled" + +printf "%s\n" "#define USE_WEBSOCKETS 1" >>confdefs.h + + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS WS" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS WSS" + fi + experimental="$experimental Websockets" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Websockets disabled due to lack of >32 bit curl_off_t" >&5 +printf "%s\n" "$as_me: WARNING: Websockets disabled due to lack of >32 bit curl_off_t" >&2;} + fi + ;; + esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether hiding of library internal symbols will actually happen" >&5 +printf %s "checking whether hiding of library internal symbols will actually happen... " >&6; } + CFLAG_CURL_SYMBOL_HIDING="" + doing_symbol_hiding="no" + if test "$want_symbol_hiding" = "yes" && + test "$supports_symbol_hiding" = "yes"; then + doing_symbol_hiding="yes" + CFLAG_CURL_SYMBOL_HIDING="$symbol_hiding_CFLAGS" + +printf "%s\n" "#define CURL_EXTERN_SYMBOL $symbol_hiding_EXTERN" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + if test x$doing_symbol_hiding = xyes; then + DOING_CURL_SYMBOL_HIDING_TRUE= + DOING_CURL_SYMBOL_HIDING_FALSE='#' +else + DOING_CURL_SYMBOL_HIDING_TRUE='#' + DOING_CURL_SYMBOL_HIDING_FALSE= +fi + + + + +LIBCURL_LIBS="$LIBS$PTHREAD" + + + + + +BLANK_AT_MAKETIME= + + + if test x$cross_compiling = xyes; then + CROSSCOMPILING_TRUE= + CROSSCOMPILING_FALSE='#' +else + CROSSCOMPILING_TRUE='#' + CROSSCOMPILING_FALSE= +fi + + +ENABLE_SHARED="$enable_shared" + + +ENABLE_STATIC="$enable_static" + + +if test "x$enable_shared" = "xno"; then + LIBCURL_NO_SHARED=$LIBCURL_LIBS +else + LIBCURL_NO_SHARED= +fi + + +rm $compilersh + + +if test "x$OPENSSL_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES SSL" +elif test -n "$SSL_ENABLED"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES SSL" +fi +if test "x$IPV6_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES IPv6" +fi +if test "x$USE_UNIX_SOCKETS" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES UnixSockets" +fi +if test "x$HAVE_LIBZ" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES libz" +fi +if test "x$HAVE_BROTLI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES brotli" +fi +if test "x$HAVE_ZSTD" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES zstd" +fi +if test "x$USE_ARES" = "x1" -o "x$USE_THREADS_POSIX" = "x1" \ + -o "x$USE_THREADS_WIN32" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS" +fi +if test "x$IDN_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES IDN" +fi +if test "x$USE_WINDOWS_SSPI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES SSPI" +fi + +if test "x$HAVE_GSSAPI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES GSS-API" +fi + +if test "x$curl_psl_msg" = "xenabled"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES PSL" +fi + +if test "x$curl_gsasl_msg" = "xenabled"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES GSASL" +fi + +if test "x$enable_altsvc" = "xyes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES alt-svc" +fi +if test "x$hsts" = "xyes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HSTS" +fi + +if test "x$CURL_DISABLE_NEGOTIATE_AUTH" != "x1" -a \ + \( "x$HAVE_GSSAPI" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \); then + SUPPORT_FEATURES="$SUPPORT_FEATURES SPNEGO" +fi + +if test "x$CURL_DISABLE_KERBEROS_AUTH" != "x1" -a \ + \( "x$HAVE_GSSAPI" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \); then + SUPPORT_FEATURES="$SUPPORT_FEATURES Kerberos" +fi + +use_curl_ntlm_core=no + +if test "x$CURL_DISABLE_NTLM" != "x1"; then + if test "x$OPENSSL_ENABLED" = "x1" -o "x$MBEDTLS_ENABLED" = "x1" \ + -o "x$GNUTLS_ENABLED" = "x1" \ + -o "x$SECURETRANSPORT_ENABLED" = "x1" \ + -o "x$USE_WIN32_CRYPTO" = "x1" \ + -o "x$WOLFSSL_NTLM" = "x1"; then + use_curl_ntlm_core=yes + fi + + if test "x$use_curl_ntlm_core" = "xyes" \ + -o "x$USE_WINDOWS_SSPI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM" + + if test "x$CURL_DISABLE_HTTP" != "x1" -a \ + "x$NTLM_WB_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM_WB" + fi + fi +fi + +if test "x$USE_TLS_SRP" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES TLS-SRP" +fi + +if test "x$USE_NGHTTP2" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTP2" +fi + +if test "x$USE_NGTCP2_H3" = "x1" -o "x$USE_QUICHE" = "x1" \ + -o "x$USE_OPENSSL_H3" = "x1" -o "x$USE_MSH3" = "x1"; then + if test "x$CURL_WITH_MULTI_SSL" = "x1"; then + as_fn_error $? "MultiSSL cannot be enabled with HTTP/3 and vice versa" "$LINENO" 5 + fi + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTP3" +fi + +if test "x$CURL_WITH_MULTI_SSL" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES MultiSSL" +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if this build supports HTTPS-proxy" >&5 +printf %s "checking if this build supports HTTPS-proxy... " >&6; } +if test "x$CURL_DISABLE_HTTP" != "x1"; then + if test "x$https_proxy" != "xno"; then + if test "x$OPENSSL_ENABLED" = "x1" \ + -o "x$GNUTLS_ENABLED" = "x1" \ + -o "x$SECURETRANSPORT_ENABLED" = "x1" \ + -o "x$RUSTLS_ENABLED" = "x1" \ + -o "x$BEARSSL_ENABLED" = "x1" \ + -o "x$SCHANNEL_ENABLED" = "x1" \ + -o "x$GNUTLS_ENABLED" = "x1" \ + -o "x$MBEDTLS_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPS-proxy" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + elif test "x$WOLFSSL_ENABLED" = "x1" -a "x$WOLFSSL_FULL_BIO" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPS-proxy" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + +if test "x$ECH_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES ECH" +fi + +if test ${ac_cv_sizeof_curl_off_t} -gt 4; then + if test ${ac_cv_sizeof_off_t} -gt 4 -o \ + "$curl_win32_file_api" = "win32_large_files"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES Largefile" + fi +fi + +if test "$tst_atomic" = "yes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe" +elif test "x$USE_THREADS_POSIX" = "x1" -a \ + "x$ac_cv_header_pthread_h" = "xyes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + +int main (void) +{ + + #if (WINVER < 0x600) && (_WIN32_WINNT < 0x600) + #error + #endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort | tr '\012' ' '` + + +if test "x$CURL_DISABLE_HTTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTP IPFS IPNS" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTPS" + fi +fi +if test "x$CURL_DISABLE_FTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS FTP" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS FTPS" + fi +fi +if test "x$CURL_DISABLE_FILE" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS FILE" +fi +if test "x$CURL_DISABLE_TELNET" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TELNET" +fi +if test "x$CURL_DISABLE_LDAP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS LDAP" + if test "x$CURL_DISABLE_LDAPS" != "x1"; then + if (test "x$USE_OPENLDAP" = "x1" && test "x$SSL_ENABLED" = "x1") || + (test "x$USE_OPENLDAP" != "x1" && test "x$HAVE_LDAP_SSL" = "x1"); then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS LDAPS" + fi + fi +fi +if test "x$CURL_DISABLE_DICT" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS DICT" +fi +if test "x$CURL_DISABLE_TFTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TFTP" +fi +if test "x$CURL_DISABLE_GOPHER" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS GOPHER" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS GOPHERS" + fi +fi +if test "x$CURL_DISABLE_MQTT" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS MQTT" +fi +if test "x$CURL_DISABLE_POP3" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3S" + fi +fi +if test "x$CURL_DISABLE_IMAP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IMAP" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IMAPS" + fi +fi +if test "x$CURL_DISABLE_SMB" != "x1" \ + -a "x$use_curl_ntlm_core" = "xyes"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMB" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMBS" + fi +fi +if test "x$CURL_DISABLE_SMTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMTP" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMTPS" + fi +fi +if test "x$USE_LIBSSH2" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi +if test "x$USE_LIBSSH" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi +if test "x$USE_WOLFSSH" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi +if test "x$CURL_DISABLE_RTSP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP" +fi +if test "x$USE_LIBRTMP" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTMP" +fi + +SUPPORT_PROTOCOLS=`echo $SUPPORT_PROTOCOLS | tr ' ' '\012' | sort | tr '\012' ' '` + + + + +squeeze CFLAGS +squeeze CPPFLAGS +squeeze DEFS +squeeze LDFLAGS +squeeze LIBS + +squeeze LIBCURL_LIBS +squeeze CURL_NETWORK_LIBS +squeeze CURL_NETWORK_AND_TIME_LIBS + +squeeze SUPPORT_FEATURES +squeeze SUPPORT_PROTOCOLS + + + + xc_bad_var_libs=no + for xc_word in $LIBS; do + case "$xc_word" in + -l* | --library=*) + : + ;; + *) + xc_bad_var_libs=yes + ;; + esac + done + if test $xc_bad_var_libs = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using LIBS: $LIBS" >&5 +printf "%s\n" "$as_me: using LIBS: $LIBS" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: LIBS note: LIBS should only be used to specify libraries (-lname)." >&5 +printf "%s\n" "$as_me: LIBS note: LIBS should only be used to specify libraries (-lname)." >&6;} + fi + + + xc_bad_var_ldflags=no + for xc_word in $LDFLAGS; do + case "$xc_word" in + -D*) + xc_bad_var_ldflags=yes + ;; + -U*) + xc_bad_var_ldflags=yes + ;; + -I*) + xc_bad_var_ldflags=yes + ;; + -l* | --library=*) + xc_bad_var_ldflags=yes + ;; + esac + done + if test $xc_bad_var_ldflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using LDFLAGS: $LDFLAGS" >&5 +printf "%s\n" "$as_me: using LDFLAGS: $LDFLAGS" >&6;} + xc_bad_var_msg="LDFLAGS note: LDFLAGS should only be used to specify linker flags, not" + for xc_word in $LDFLAGS; do + case "$xc_word" in + -D*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -U*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -I*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -l* | --library=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&6;} + ;; + esac + done + fi + + + xc_bad_var_cppflags=no + for xc_word in $CPPFLAGS; do + case "$xc_word" in + -rpath*) + xc_bad_var_cppflags=yes + ;; + -L* | --library-path=*) + xc_bad_var_cppflags=yes + ;; + -l* | --library=*) + xc_bad_var_cppflags=yes + ;; + esac + done + if test $xc_bad_var_cppflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using CPPFLAGS: $CPPFLAGS" >&5 +printf "%s\n" "$as_me: using CPPFLAGS: $CPPFLAGS" >&6;} + xc_bad_var_msg="CPPFLAGS note: CPPFLAGS should only be used to specify C preprocessor flags, not" + for xc_word in $CPPFLAGS; do + case "$xc_word" in + -rpath*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -L* | --library-path=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -l* | --library=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&6;} + ;; + esac + done + fi + + + xc_bad_var_cflags=no + for xc_word in $CFLAGS; do + case "$xc_word" in + -D*) + xc_bad_var_cflags=yes + ;; + -U*) + xc_bad_var_cflags=yes + ;; + -I*) + xc_bad_var_cflags=yes + ;; + -rpath*) + xc_bad_var_cflags=yes + ;; + -L* | --library-path=*) + xc_bad_var_cflags=yes + ;; + -l* | --library=*) + xc_bad_var_cflags=yes + ;; + esac + done + if test $xc_bad_var_cflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using CFLAGS: $CFLAGS" >&5 +printf "%s\n" "$as_me: using CFLAGS: $CFLAGS" >&6;} + xc_bad_var_msg="CFLAGS note: CFLAGS should only be used to specify C compiler flags, not" + for xc_word in $CFLAGS; do + case "$xc_word" in + -D*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -U*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -I*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word" >&6;} + ;; + -rpath*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -L* | --library-path=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word" >&6;} + ;; + -l* | --library=*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&5 +printf "%s\n" "$as_me: $xc_bad_var_msg libraries. Use LIBS for: $xc_word" >&6;} + ;; + esac + done + fi + + if test $xc_bad_var_libs = yes || + test $xc_bad_var_cflags = yes || + test $xc_bad_var_ldflags = yes || + test $xc_bad_var_cppflags = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Continuing even with errors mentioned immediately above this line." >&5 +printf "%s\n" "$as_me: WARNING: Continuing even with errors mentioned immediately above this line." >&2;} + fi + + +SSL_BACKENDS=${ssl_backends} + + +if test "x$want_curldebug_assumed" = "xyes" && + test "x$want_curldebug" = "xyes" && test "x$USE_ARES" = "x1"; then + ac_configure_args="$ac_configure_args --enable-curldebug" +fi + +ac_config_files="$ac_config_files Makefile docs/Makefile docs/examples/Makefile docs/libcurl/Makefile docs/libcurl/opts/Makefile docs/cmdline-opts/Makefile include/Makefile include/curl/Makefile src/Makefile lib/Makefile scripts/Makefile lib/libcurl.vers lib/libcurl.plist tests/Makefile tests/config tests/certs/Makefile tests/certs/scripts/Makefile tests/data/Makefile tests/server/Makefile tests/libtest/Makefile tests/unit/Makefile tests/http/config.ini tests/http/Makefile tests/http/clients/Makefile packages/Makefile packages/vms/Makefile curl-config libcurl.pc" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +printf %s "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 +printf "%s\n" "done" >&6; } +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${CURL_LT_SHLIB_USE_VERSION_INFO_TRUE}" && test -z "${CURL_LT_SHLIB_USE_VERSION_INFO_FALSE}"; then + as_fn_error $? "conditional \"CURL_LT_SHLIB_USE_VERSION_INFO\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE}" && test -z "${CURL_LT_SHLIB_USE_NO_UNDEFINED_FALSE}"; then + as_fn_error $? "conditional \"CURL_LT_SHLIB_USE_NO_UNDEFINED\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE}" && test -z "${CURL_LT_SHLIB_USE_MIMPURE_TEXT_FALSE}"; then + as_fn_error $? "conditional \"CURL_LT_SHLIB_USE_MIMPURE_TEXT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_CPPFLAG_CURL_STATICLIB_TRUE}" && test -z "${USE_CPPFLAG_CURL_STATICLIB_FALSE}"; then + as_fn_error $? "conditional \"USE_CPPFLAG_CURL_STATICLIB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_EXPLICIT_LIB_DEPS_TRUE}" && test -z "${USE_EXPLICIT_LIB_DEPS_FALSE}"; then + as_fn_error $? "conditional \"USE_EXPLICIT_LIB_DEPS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DOING_NATIVE_WINDOWS_TRUE}" && test -z "${DOING_NATIVE_WINDOWS_FALSE}"; then + as_fn_error $? "conditional \"DOING_NATIVE_WINDOWS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CURLDEBUG_TRUE}" && test -z "${CURLDEBUG_FALSE}"; then + as_fn_error $? "conditional \"CURLDEBUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_UNITTESTS_TRUE}" && test -z "${BUILD_UNITTESTS_FALSE}"; then + as_fn_error $? "conditional \"BUILD_UNITTESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_WINDRES_TRUE}" && test -z "${HAVE_WINDRES_FALSE}"; then + as_fn_error $? "conditional \"HAVE_WINDRES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DOING_NATIVE_WINDOWS_TRUE}" && test -z "${DOING_NATIVE_WINDOWS_FALSE}"; then + as_fn_error $? "conditional \"DOING_NATIVE_WINDOWS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_LIBZ_TRUE}" && test -z "${HAVE_LIBZ_FALSE}"; then + as_fn_error $? "conditional \"HAVE_LIBZ\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_STUB_GSS_TRUE}" && test -z "${BUILD_STUB_GSS_FALSE}"; then + as_fn_error $? "conditional \"BUILD_STUB_GSS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_LIBPSL_TRUE}" && test -z "${USE_LIBPSL_FALSE}"; then + as_fn_error $? "conditional \"USE_LIBPSL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_GSASL_TRUE}" && test -z "${USE_GSASL_FALSE}"; then + as_fn_error $? "conditional \"USE_GSASL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE}" && test -z "${CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE}"; then + as_fn_error $? "conditional \"CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DOING_NATIVE_WINDOWS_TRUE}" && test -z "${DOING_NATIVE_WINDOWS_FALSE}"; then + as_fn_error $? "conditional \"DOING_NATIVE_WINDOWS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_MANUAL_TRUE}" && test -z "${USE_MANUAL_FALSE}"; then + as_fn_error $? "conditional \"USE_MANUAL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_LIBHOSTNAME_TRUE}" && test -z "${BUILD_LIBHOSTNAME_FALSE}"; then + as_fn_error $? "conditional \"BUILD_LIBHOSTNAME\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DOING_CURL_SYMBOL_HIDING_TRUE}" && test -z "${DOING_CURL_SYMBOL_HIDING_FALSE}"; then + as_fn_error $? "conditional \"DOING_CURL_SYMBOL_HIDING\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CROSSCOMPILING_TRUE}" && test -z "${CROSSCOMPILING_FALSE}"; then + as_fn_error $? "conditional \"CROSSCOMPILING\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else $as_nop + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. +as_nl=' +' +export as_nl +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi + + + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + printf "%s\n" "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else $as_nop + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else $as_nop + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by curl $as_me -, which was +generated by GNU Autoconf 2.71. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config='$ac_cs_config_escaped' +ac_cs_version="\\ +curl config.status - +configured by $0, generated by GNU Autoconf 2.71, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2021 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + printf "%s\n" "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + printf "%s\n" "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + printf "%s\n" "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + printf "%s\n" "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' +configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +LD_RC='`$ECHO "$LD_RC" | $SED "$delay_single_quote_subst"`' +reload_flag_RC='`$ECHO "$reload_flag_RC" | $SED "$delay_single_quote_subst"`' +reload_cmds_RC='`$ECHO "$reload_cmds_RC" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_RC='`$ECHO "$old_archive_cmds_RC" | $SED "$delay_single_quote_subst"`' +compiler_RC='`$ECHO "$compiler_RC" | $SED "$delay_single_quote_subst"`' +GCC_RC='`$ECHO "$GCC_RC" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_RC='`$ECHO "$lt_prog_compiler_no_builtin_flag_RC" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_RC='`$ECHO "$lt_prog_compiler_pic_RC" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_RC='`$ECHO "$lt_prog_compiler_wl_RC" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_RC='`$ECHO "$lt_prog_compiler_static_RC" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_RC='`$ECHO "$lt_cv_prog_compiler_c_o_RC" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_RC='`$ECHO "$archive_cmds_need_lc_RC" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_RC='`$ECHO "$enable_shared_with_static_runtimes_RC" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_RC='`$ECHO "$export_dynamic_flag_spec_RC" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_RC='`$ECHO "$whole_archive_flag_spec_RC" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_RC='`$ECHO "$compiler_needs_object_RC" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_RC='`$ECHO "$old_archive_from_new_cmds_RC" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_RC='`$ECHO "$old_archive_from_expsyms_cmds_RC" | $SED "$delay_single_quote_subst"`' +archive_cmds_RC='`$ECHO "$archive_cmds_RC" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_RC='`$ECHO "$archive_expsym_cmds_RC" | $SED "$delay_single_quote_subst"`' +module_cmds_RC='`$ECHO "$module_cmds_RC" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_RC='`$ECHO "$module_expsym_cmds_RC" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_RC='`$ECHO "$with_gnu_ld_RC" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_RC='`$ECHO "$allow_undefined_flag_RC" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_RC='`$ECHO "$no_undefined_flag_RC" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_RC='`$ECHO "$hardcode_libdir_flag_spec_RC" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_RC='`$ECHO "$hardcode_libdir_separator_RC" | $SED "$delay_single_quote_subst"`' +hardcode_direct_RC='`$ECHO "$hardcode_direct_RC" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_RC='`$ECHO "$hardcode_direct_absolute_RC" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_RC='`$ECHO "$hardcode_minus_L_RC" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_RC='`$ECHO "$hardcode_shlibpath_var_RC" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_RC='`$ECHO "$hardcode_automatic_RC" | $SED "$delay_single_quote_subst"`' +inherit_rpath_RC='`$ECHO "$inherit_rpath_RC" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_RC='`$ECHO "$link_all_deplibs_RC" | $SED "$delay_single_quote_subst"`' +always_export_symbols_RC='`$ECHO "$always_export_symbols_RC" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_RC='`$ECHO "$export_symbols_cmds_RC" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_RC='`$ECHO "$exclude_expsyms_RC" | $SED "$delay_single_quote_subst"`' +include_expsyms_RC='`$ECHO "$include_expsyms_RC" | $SED "$delay_single_quote_subst"`' +prelink_cmds_RC='`$ECHO "$prelink_cmds_RC" | $SED "$delay_single_quote_subst"`' +postlink_cmds_RC='`$ECHO "$postlink_cmds_RC" | $SED "$delay_single_quote_subst"`' +file_list_spec_RC='`$ECHO "$file_list_spec_RC" | $SED "$delay_single_quote_subst"`' +hardcode_action_RC='`$ECHO "$hardcode_action_RC" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in AS \ +DLLTOOL \ +OBJDUMP \ +SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +FILECMD \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +sharedlib_from_linklib_cmd \ +AR \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_import \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_cv_nm_interface \ +nm_file_list_spec \ +lt_cv_truncate_bin \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +LD_RC \ +reload_flag_RC \ +compiler_RC \ +lt_prog_compiler_no_builtin_flag_RC \ +lt_prog_compiler_pic_RC \ +lt_prog_compiler_wl_RC \ +lt_prog_compiler_static_RC \ +lt_cv_prog_compiler_c_o_RC \ +export_dynamic_flag_spec_RC \ +whole_archive_flag_spec_RC \ +compiler_needs_object_RC \ +with_gnu_ld_RC \ +allow_undefined_flag_RC \ +no_undefined_flag_RC \ +hardcode_libdir_flag_spec_RC \ +hardcode_libdir_separator_RC \ +exclude_expsyms_RC \ +include_expsyms_RC \ +file_list_spec_RC; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +configure_time_dlsearch_path \ +configure_time_lt_sys_library_path \ +reload_cmds_RC \ +old_archive_cmds_RC \ +old_archive_from_new_cmds_RC \ +old_archive_from_expsyms_cmds_RC \ +archive_cmds_RC \ +archive_expsym_cmds_RC \ +module_cmds_RC \ +module_expsym_cmds_RC \ +export_symbols_cmds_RC \ +prelink_cmds_RC \ +postlink_cmds_RC; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' + +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "lib/curl_config.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/curl_config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "docs/Makefile") CONFIG_FILES="$CONFIG_FILES docs/Makefile" ;; + "docs/examples/Makefile") CONFIG_FILES="$CONFIG_FILES docs/examples/Makefile" ;; + "docs/libcurl/Makefile") CONFIG_FILES="$CONFIG_FILES docs/libcurl/Makefile" ;; + "docs/libcurl/opts/Makefile") CONFIG_FILES="$CONFIG_FILES docs/libcurl/opts/Makefile" ;; + "docs/cmdline-opts/Makefile") CONFIG_FILES="$CONFIG_FILES docs/cmdline-opts/Makefile" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "include/curl/Makefile") CONFIG_FILES="$CONFIG_FILES include/curl/Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; + "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;; + "lib/libcurl.vers") CONFIG_FILES="$CONFIG_FILES lib/libcurl.vers" ;; + "lib/libcurl.plist") CONFIG_FILES="$CONFIG_FILES lib/libcurl.plist" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; + "tests/config") CONFIG_FILES="$CONFIG_FILES tests/config" ;; + "tests/certs/Makefile") CONFIG_FILES="$CONFIG_FILES tests/certs/Makefile" ;; + "tests/certs/scripts/Makefile") CONFIG_FILES="$CONFIG_FILES tests/certs/scripts/Makefile" ;; + "tests/data/Makefile") CONFIG_FILES="$CONFIG_FILES tests/data/Makefile" ;; + "tests/server/Makefile") CONFIG_FILES="$CONFIG_FILES tests/server/Makefile" ;; + "tests/libtest/Makefile") CONFIG_FILES="$CONFIG_FILES tests/libtest/Makefile" ;; + "tests/unit/Makefile") CONFIG_FILES="$CONFIG_FILES tests/unit/Makefile" ;; + "tests/http/config.ini") CONFIG_FILES="$CONFIG_FILES tests/http/config.ini" ;; + "tests/http/Makefile") CONFIG_FILES="$CONFIG_FILES tests/http/Makefile" ;; + "tests/http/clients/Makefile") CONFIG_FILES="$CONFIG_FILES tests/http/clients/Makefile" ;; + "packages/Makefile") CONFIG_FILES="$CONFIG_FILES packages/Makefile" ;; + "packages/vms/Makefile") CONFIG_FILES="$CONFIG_FILES packages/vms/Makefile" ;; + "curl-config") CONFIG_FILES="$CONFIG_FILES curl-config" ;; + "libcurl.pc") CONFIG_FILES="$CONFIG_FILES libcurl.pc" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers + test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`printf "%s\n" "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +printf "%s\n" "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$am_mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? + done + if test $am_rc -ne 0; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE=\"gmake\" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See \`config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# The names of the tagged configurations supported by this script. +available_tags='RC ' + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Assembler program. +AS=$lt_AS + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Object dumper program. +OBJDUMP=$lt_OBJDUMP + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec=$shared_archive_member_spec + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# A file(cmd) program that detects file types. +FILECMD=$lt_FILECMD + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive (by configure). +lt_ar_flags=$lt_ar_flags + +# Flags to create an archive. +AR_FLAGS=\${ARFLAGS-"\$lt_ar_flags"} + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm into a list of symbols to manually relocate. +global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name lister interface. +nm_interface=$lt_lt_cv_nm_interface + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and where our libraries should be installed. +lt_sysroot=$lt_sysroot + +# Command to truncate a binary pipe. +lt_truncate_bin=$lt_lt_cv_truncate_bin + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + + +ltmain=$ac_aux_dir/ltmain.sh + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + $SED '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: RC + +# The linker used to build libraries. +LD=$lt_LD_RC + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_RC +reload_cmds=$lt_reload_cmds_RC + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_RC + +# A language specific compiler. +CC=$lt_compiler_RC + +# Is the compiler the GNU compiler? +with_gcc=$GCC_RC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_RC + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_RC + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_RC + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_RC + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_RC + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_RC +archive_expsym_cmds=$lt_archive_expsym_cmds_RC + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_RC +module_expsym_cmds=$lt_module_expsym_cmds_RC + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_RC + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_RC + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_RC + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_RC + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_RC + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_RC + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_RC + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_RC + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_RC + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_RC + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_RC + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_RC + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_RC + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_RC + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_RC + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_RC + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_RC + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_RC + +# ### END LIBTOOL TAG CONFIG: RC +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + + + tmp_cpp=`eval echo "$ac_cpp" 2>/dev/null` + if test -z "$tmp_cpp"; then + tmp_cpp='cpp' + fi + cat >./tests/configurehelp.pm <<_EOF +# This is a generated file. Do not edit. + +package configurehelp; + +use strict; +use warnings; +use Exporter; + +use vars qw( + @ISA + @EXPORT_OK + \$Cpreprocessor + ); + +@ISA = qw(Exporter); + +@EXPORT_OK = qw( + \$Cpreprocessor + ); + +\$Cpreprocessor = '$tmp_cpp'; + +1; +_EOF + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configured to build curl/libcurl: + + Host setup: ${host} + Install prefix: ${prefix} + Compiler: ${CC} + CFLAGS: ${CFLAGS} + CPPFLAGS: ${CPPFLAGS} + LDFLAGS: ${LDFLAGS} + LIBS: ${LIBS} + + curl version: ${CURLVERSION} + SSL: ${curl_ssl_msg} + SSH: ${curl_ssh_msg} + zlib: ${curl_zlib_msg} + brotli: ${curl_brotli_msg} + zstd: ${curl_zstd_msg} + GSS-API: ${curl_gss_msg} + GSASL: ${curl_gsasl_msg} + TLS-SRP: ${curl_tls_srp_msg} + resolver: ${curl_res_msg} + IPv6: ${curl_ipv6_msg} + Unix sockets: ${curl_unix_sockets_msg} + IDN: ${curl_idn_msg} + Build libcurl: Shared=${enable_shared}, Static=${enable_static} + Built-in manual: ${curl_manual_msg} + --libcurl option: ${curl_libcurl_msg} + Verbose errors: ${curl_verbose_msg} + Code coverage: ${curl_coverage_msg} + SSPI: ${curl_sspi_msg} + ca cert bundle: ${ca}${ca_warning} + ca cert path: ${capath}${capath_warning} + ca fallback: ${with_ca_fallback} + LDAP: ${curl_ldap_msg} + LDAPS: ${curl_ldaps_msg} + RTSP: ${curl_rtsp_msg} + RTMP: ${curl_rtmp_msg} + PSL: ${curl_psl_msg} + Alt-svc: ${curl_altsvc_msg} + Headers API: ${curl_headers_msg} + HSTS: ${curl_hsts_msg} + HTTP1: ${curl_h1_msg} + HTTP2: ${curl_h2_msg} + HTTP3: ${curl_h3_msg} + ECH: ${curl_ech_msg} + WebSockets: ${curl_ws_msg} + Protocols: ${SUPPORT_PROTOCOLS} + Features: ${SUPPORT_FEATURES} +" >&5 +printf "%s\n" "$as_me: Configured to build curl/libcurl: + + Host setup: ${host} + Install prefix: ${prefix} + Compiler: ${CC} + CFLAGS: ${CFLAGS} + CPPFLAGS: ${CPPFLAGS} + LDFLAGS: ${LDFLAGS} + LIBS: ${LIBS} + + curl version: ${CURLVERSION} + SSL: ${curl_ssl_msg} + SSH: ${curl_ssh_msg} + zlib: ${curl_zlib_msg} + brotli: ${curl_brotli_msg} + zstd: ${curl_zstd_msg} + GSS-API: ${curl_gss_msg} + GSASL: ${curl_gsasl_msg} + TLS-SRP: ${curl_tls_srp_msg} + resolver: ${curl_res_msg} + IPv6: ${curl_ipv6_msg} + Unix sockets: ${curl_unix_sockets_msg} + IDN: ${curl_idn_msg} + Build libcurl: Shared=${enable_shared}, Static=${enable_static} + Built-in manual: ${curl_manual_msg} + --libcurl option: ${curl_libcurl_msg} + Verbose errors: ${curl_verbose_msg} + Code coverage: ${curl_coverage_msg} + SSPI: ${curl_sspi_msg} + ca cert bundle: ${ca}${ca_warning} + ca cert path: ${capath}${capath_warning} + ca fallback: ${with_ca_fallback} + LDAP: ${curl_ldap_msg} + LDAPS: ${curl_ldaps_msg} + RTSP: ${curl_rtsp_msg} + RTMP: ${curl_rtmp_msg} + PSL: ${curl_psl_msg} + Alt-svc: ${curl_altsvc_msg} + Headers API: ${curl_headers_msg} + HSTS: ${curl_hsts_msg} + HTTP1: ${curl_h1_msg} + HTTP2: ${curl_h2_msg} + HTTP3: ${curl_h3_msg} + ECH: ${curl_ech_msg} + WebSockets: ${curl_ws_msg} + Protocols: ${SUPPORT_PROTOCOLS} + Features: ${SUPPORT_FEATURES} +" >&6;} +if test -n "$experimental"; then + cat >&2 << _EOF + WARNING: $experimental enabled but marked EXPERIMENTAL. Use with caution! +_EOF +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..be66be9 --- /dev/null +++ b/configure.ac @@ -0,0 +1,4971 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59) + +dnl We don't know the version number "statically" so we use a dash here +AC_INIT([curl], [-], [a suitable curl mailing list: https://curl.se/mail/]) + +XC_OVR_ZZ50 +XC_OVR_ZZ60 +CURL_OVERRIDE_AUTOCONF + +dnl configure script copyright +AC_COPYRIGHT([Copyright (C) Daniel Stenberg, +This configure script may be copied, distributed and modified under the +terms of the curl license; see COPYING for more details]) + +AC_CONFIG_SRCDIR([lib/urldata.h]) +AC_CONFIG_HEADERS(lib/curl_config.h) +AC_CONFIG_MACRO_DIR([m4]) +AM_MAINTAINER_MODE +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +CURL_CHECK_OPTION_DEBUG +CURL_CHECK_OPTION_OPTIMIZE +CURL_CHECK_OPTION_WARNINGS +CURL_CHECK_OPTION_WERROR +CURL_CHECK_OPTION_CURLDEBUG +CURL_CHECK_OPTION_SYMBOL_HIDING +CURL_CHECK_OPTION_ARES +CURL_CHECK_OPTION_RT +CURL_CHECK_OPTION_ECH + +XC_CHECK_PATH_SEPARATOR + +# +# save the configure arguments +# +CONFIGURE_OPTIONS="\"$ac_configure_args\"" +AC_SUBST(CONFIGURE_OPTIONS) + +dnl SED is mandatory for configure process and libtool. +dnl Set it now, allowing it to be changed later. +if test -z "$SED"; then + dnl allow it to be overridden + AC_PATH_PROG([SED], [sed], [not_found], + [$PATH:/usr/bin:/usr/local/bin]) + if test -z "$SED" || test "$SED" = "not_found"; then + AC_MSG_ERROR([sed not found in PATH. Cannot continue without sed.]) + fi +fi +AC_SUBST([SED]) + +dnl GREP is mandatory for configure process and libtool. +dnl Set it now, allowing it to be changed later. +if test -z "$GREP"; then + dnl allow it to be overridden + AC_PATH_PROG([GREP], [grep], [not_found], + [$PATH:/usr/bin:/usr/local/bin]) + if test -z "$GREP" || test "$GREP" = "not_found"; then + AC_MSG_ERROR([grep not found in PATH. Cannot continue without grep.]) + fi +fi +AC_SUBST([GREP]) + +dnl 'grep -E' is mandatory for configure process and libtool. +dnl Set it now, allowing it to be changed later. +if test -z "$EGREP"; then + dnl allow it to be overridden + AC_MSG_CHECKING([that grep -E works]) + if echo a | ($GREP -E '(a|b)') >/dev/null 2>&1; then + EGREP="$GREP -E" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_PATH_PROG([EGREP], [egrep], [not_found], + [$PATH:/usr/bin:/usr/local/bin]) + fi +fi +if test -z "$EGREP" || test "$EGREP" = "not_found"; then + AC_MSG_ERROR([grep -E is not working and egrep is not found in PATH. Cannot continue.]) +fi +AC_SUBST([EGREP]) + +dnl AR is mandatory for configure process and libtool. +dnl This is target dependent, so check it as a tool. +if test -z "$AR"; then + dnl allow it to be overridden + AC_PATH_TOOL([AR], [ar], [not_found], + [$PATH:/usr/bin:/usr/local/bin]) + if test -z "$AR" || test "$AR" = "not_found"; then + AC_MSG_ERROR([ar not found in PATH. Cannot continue without ar.]) + fi +fi +AC_SUBST([AR]) + +AC_SUBST(libext) + +dnl figure out the libcurl version +CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)".*/\1/p' ${srcdir}/include/curl/curlver.h` +XC_CHECK_PROG_CC +CURL_ATOMIC + +dnl for --enable-code-coverage +CURL_COVERAGE + +XC_AUTOMAKE +AC_MSG_CHECKING([curl version]) +AC_MSG_RESULT($CURLVERSION) + +AC_SUBST(CURLVERSION) + +dnl +dnl we extract the numerical version for curl-config only +VERSIONNUM=`$SED -ne 's/^#define LIBCURL_VERSION_NUM 0x\([0-9A-Fa-f]*\).*/\1/p' ${srcdir}/include/curl/curlver.h` +AC_SUBST(VERSIONNUM) + +dnl Solaris pkgadd support definitions +PKGADD_PKG="HAXXcurl" +PKGADD_NAME="curl - a client that groks URLs" +PKGADD_VENDOR="curl.se" +AC_SUBST(PKGADD_PKG) +AC_SUBST(PKGADD_NAME) +AC_SUBST(PKGADD_VENDOR) + +dnl +dnl initialize all the info variables + curl_ssl_msg="no (--with-{openssl,gnutls,mbedtls,wolfssl,schannel,secure-transport,amissl,bearssl,rustls} )" + curl_ssh_msg="no (--with-{libssh,libssh2})" + curl_zlib_msg="no (--with-zlib)" + curl_brotli_msg="no (--with-brotli)" + curl_zstd_msg="no (--with-zstd)" + curl_gss_msg="no (--with-gssapi)" + curl_gsasl_msg="no (--with-gsasl)" +curl_tls_srp_msg="no (--enable-tls-srp)" + curl_res_msg="default (--enable-ares / --enable-threaded-resolver)" + curl_ipv6_msg="no (--enable-ipv6)" +curl_unix_sockets_msg="no (--enable-unix-sockets)" + curl_idn_msg="no (--with-{libidn2,winidn})" + curl_manual_msg="no (--enable-manual)" +curl_libcurl_msg="enabled (--disable-libcurl-option)" +curl_verbose_msg="enabled (--disable-verbose)" + curl_sspi_msg="no (--enable-sspi)" + curl_ldap_msg="no (--enable-ldap / --with-ldap-lib / --with-lber-lib)" + curl_ldaps_msg="no (--enable-ldaps)" + curl_rtsp_msg="no (--enable-rtsp)" + curl_rtmp_msg="no (--with-librtmp)" + curl_psl_msg="no (--with-libpsl)" + curl_altsvc_msg="enabled (--disable-alt-svc)" +curl_headers_msg="enabled (--disable-headers-api)" + curl_hsts_msg="enabled (--disable-hsts)" + curl_ws_msg="no (--enable-websockets)" + ssl_backends= + curl_h1_msg="enabled (internal)" + curl_h2_msg="no (--with-nghttp2)" + curl_h3_msg="no (--with-ngtcp2 --with-nghttp3, --with-quiche, --with-openssl-quic, --with-msh3)" + +enable_altsvc="yes" +hsts="yes" + +dnl +dnl Save some initial values the user might have provided +dnl +INITIAL_LDFLAGS=$LDFLAGS +INITIAL_LIBS=$LIBS + +dnl +dnl Generates a shell script to run the compiler with LD_LIBRARY_PATH set to +dnl the value used right now. This lets CURL_RUN_IFELSE set LD_LIBRARY_PATH to +dnl something different but only have that affect the execution of the results +dnl of the compile, not change the libraries for the compiler itself. +dnl +compilersh="run-compiler" +CURL_SAVED_CC="$CC" +export CURL_SAVED_CC +CURL_SAVED_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" +export CURL_SAVED_LD_LIBRARY_PATH +cat <<\EOF > "$compilersh" +CC="$CURL_SAVED_CC" +export CC +LD_LIBRARY_PATH="$CURL_SAVED_LD_LIBRARY_PATH" +export LD_LIBRARY_PATH +exec $CC "$@" +EOF + +dnl ********************************************************************** +dnl See which TLS backend(s) that are requested. Just do all the +dnl TLS AC_ARG_WITH() invokes here and do the checks later +dnl ********************************************************************** +OPT_SCHANNEL=no +AC_ARG_WITH(schannel,dnl +AS_HELP_STRING([--with-schannel],[enable Windows native SSL/TLS]), + OPT_SCHANNEL=$withval + TLSCHOICE="schannel") + +OPT_SECURETRANSPORT=no +AC_ARG_WITH(secure-transport,dnl +AS_HELP_STRING([--with-secure-transport],[enable Apple OS native SSL/TLS]),[ + OPT_SECURETRANSPORT=$withval + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }Secure-Transport" +]) + +OPT_AMISSL=no +AC_ARG_WITH(amissl,dnl +AS_HELP_STRING([--with-amissl],[enable Amiga native SSL/TLS (AmiSSL)]),[ + OPT_AMISSL=$withval + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }AmiSSL" +]) + +OPT_OPENSSL=no +dnl Default to no CA bundle +ca="no" +AC_ARG_WITH(ssl,dnl +AS_HELP_STRING([--with-ssl=PATH],[old version of --with-openssl]) +AS_HELP_STRING([--without-ssl], [build without any TLS library]),[ + OPT_SSL=$withval + OPT_OPENSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }OpenSSL" + else + SSL_DISABLED="D" + fi +]) + +AC_ARG_WITH(openssl,dnl +AS_HELP_STRING([--with-openssl=PATH],[Where to look for OpenSSL, PATH points to the SSL installation (default: /usr/local/ssl); when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]),[ + OPT_OPENSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }OpenSSL" + fi +]) + +OPT_GNUTLS=no +AC_ARG_WITH(gnutls,dnl +AS_HELP_STRING([--with-gnutls=PATH],[where to look for GnuTLS, PATH points to the installation root]),[ + OPT_GNUTLS=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }GnuTLS" + fi +]) + +OPT_MBEDTLS=no +AC_ARG_WITH(mbedtls,dnl +AS_HELP_STRING([--with-mbedtls=PATH],[where to look for mbedTLS, PATH points to the installation root]),[ + OPT_MBEDTLS=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }mbedTLS" + fi +]) + +OPT_WOLFSSL=no +AC_ARG_WITH(wolfssl,dnl +AS_HELP_STRING([--with-wolfssl=PATH],[where to look for WolfSSL, PATH points to the installation root (default: system lib default)]),[ + OPT_WOLFSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }wolfSSL" + fi +]) + +OPT_BEARSSL=no +AC_ARG_WITH(bearssl,dnl +AS_HELP_STRING([--with-bearssl=PATH],[where to look for BearSSL, PATH points to the installation root]),[ + OPT_BEARSSL=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }BearSSL" + fi +]) + +OPT_RUSTLS=no +AC_ARG_WITH(rustls,dnl +AS_HELP_STRING([--with-rustls=PATH],[where to look for rustls, PATH points to the installation root]),[ + OPT_RUSTLS=$withval + if test X"$withval" != Xno; then + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }rustls" + experimental="$experimental rustls" + fi +]) + +TEST_NGHTTPX=nghttpx +AC_ARG_WITH(test-nghttpx,dnl +AS_HELP_STRING([--with-test-nghttpx=PATH],[where to find nghttpx for testing]), + TEST_NGHTTPX=$withval + if test X"$OPT_TEST_NGHTTPX" = "Xno" ; then + TEST_NGHTTPX="" + fi +) +AC_SUBST(TEST_NGHTTPX) + +CADDY=caddy +AC_ARG_WITH(test-caddy,dnl +AS_HELP_STRING([--with-test-caddy=PATH],[where to find caddy for testing]), + CADDY=$withval + if test X"$OPT_CADDY" = "Xno" ; then + CADDY="" + fi +) +AC_SUBST(CADDY) + +dnl we'd like a httpd+apachectl as test server +dnl +HTTPD_ENABLED="maybe" +AC_ARG_WITH(test-httpd, [AS_HELP_STRING([--with-test-httpd=PATH], + [where to find httpd/apache2 for testing])], + [request_httpd=$withval], [request_httpd=check]) +if test x"$request_httpd" = "xcheck" -o x"$request_httpd" = "xyes"; then + if test -x "/usr/sbin/apache2" -a -x "/usr/sbin/apache2ctl"; then + # common location on distros (debian/ubuntu) + HTTPD="/usr/sbin/apache2" + APACHECTL="/usr/sbin/apache2ctl" + AC_PATH_PROG([APXS], [apxs]) + if test "x$APXS" = "x"; then + AC_MSG_NOTICE([apache2-dev not installed, httpd tests disabled]) + HTTPD_ENABLED="no" + fi + else + AC_PATH_PROG([HTTPD], [httpd]) + if test "x$HTTPD" = "x"; then + AC_PATH_PROG([HTTPD], [apache2]) + fi + AC_PATH_PROG([APACHECTL], [apachectl]) + AC_PATH_PROG([APXS], [apxs]) + if test "x$HTTPD" = "x" -o "x$APACHECTL" = "x"; then + AC_MSG_NOTICE([httpd/apache2 not in PATH, http tests disabled]) + HTTPD_ENABLED="no" + fi + if test "x$APXS" = "x"; then + AC_MSG_NOTICE([apxs not in PATH, http tests disabled]) + HTTPD_ENABLED="no" + fi + fi +elif test x"$request_httpd" != "xno"; then + HTTPD="${request_httpd}/bin/httpd" + APACHECTL="${request_httpd}/bin/apachectl" + APXS="${request_httpd}/bin/apxs" + if test ! -x "${HTTPD}"; then + AC_MSG_NOTICE([httpd not found as ${HTTPD}, http tests disabled]) + HTTPD_ENABLED="no" + elif test ! -x "${APACHECTL}"; then + AC_MSG_NOTICE([apachectl not found as ${APACHECTL}, http tests disabled]) + HTTPD_ENABLED="no" + elif test ! -x "${APXS}"; then + AC_MSG_NOTICE([apxs not found as ${APXS}, http tests disabled]) + HTTPD_ENABLED="no" + else + AC_MSG_NOTICE([using HTTPD=$HTTPD for tests]) + fi +fi +if test x"$HTTPD_ENABLED" = "xno"; then + HTTPD="" + APACHECTL="" + APXS="" +fi +AC_SUBST(HTTPD) +AC_SUBST(APACHECTL) +AC_SUBST(APXS) + +dnl the nghttpx we might use in httpd testing +if test "x$TEST_NGHTTPX" != "x" -a "x$TEST_NGHTTPX" != "xnghttpx"; then + HTTPD_NGHTTPX="$TEST_NGHTTPX" +else + AC_PATH_PROG([HTTPD_NGHTTPX], [nghttpx], [], + [$PATH:/usr/bin:/usr/local/bin]) +fi +AC_SUBST(HTTPD_NGHTTPX) + +dnl the Caddy server we might use in testing +if test "x$TEST_CADDY" != "x"; then + CADDY="$TEST_CADDY" +else + AC_PATH_PROG([CADDY], [caddy]) +fi +AC_SUBST(CADDY) + +dnl If no TLS choice has been made, check if it was explicitly disabled or +dnl error out to force the user to decide. +if test -z "$TLSCHOICE"; then + if test "x$OPT_SSL" != "xno"; then + AC_MSG_ERROR([select TLS backend(s) or disable TLS with --without-ssl. + +Select from these: + + --with-amissl + --with-bearssl + --with-gnutls + --with-mbedtls + --with-openssl (also works for BoringSSL and libressl) + --with-rustls + --with-schannel + --with-secure-transport + --with-wolfssl +]) + fi +fi + +AC_ARG_WITH(darwinssl,, + AC_MSG_ERROR([--with-darwin-ssl and --without-darwin-ssl no longer work!])) + +dnl +dnl Detect the canonical host and target build environment +dnl + +AC_CANONICAL_HOST +dnl Get system canonical name +AC_DEFINE_UNQUOTED(OS, "${host}", [cpu-machine-OS]) + +# Silence warning: ar: 'u' modifier ignored since 'D' is the default +AC_SUBST(AR_FLAGS, [cr]) + +dnl This defines _ALL_SOURCE for AIX +CURL_CHECK_AIX_ALL_SOURCE + +dnl Our configure and build reentrant settings +CURL_CONFIGURE_THREAD_SAFE +CURL_CONFIGURE_REENTRANT + +dnl check for how to do large files +AC_SYS_LARGEFILE + +XC_LIBTOOL + +LT_LANG([Windows Resource]) + +# +# Automake conditionals based on libtool related checks +# + +AM_CONDITIONAL([CURL_LT_SHLIB_USE_VERSION_INFO], + [test "x$xc_lt_shlib_use_version_info" = 'xyes']) +AM_CONDITIONAL([CURL_LT_SHLIB_USE_NO_UNDEFINED], + [test "x$xc_lt_shlib_use_no_undefined" = 'xyes']) +AM_CONDITIONAL([CURL_LT_SHLIB_USE_MIMPURE_TEXT], + [test "x$xc_lt_shlib_use_mimpure_text" = 'xyes']) + +# +# Due to libtool and automake machinery limitations of not allowing +# specifying separate CPPFLAGS or CFLAGS when compiling objects for +# inclusion of these in shared or static libraries, we are forced to +# build using separate configure runs for shared and static libraries +# on systems where different CPPFLAGS or CFLAGS are mandatory in order +# to compile objects for each kind of library. Notice that relying on +# the '-DPIC' CFLAG that libtool provides is not valid given that the +# user might for example choose to build static libraries with PIC. +# + +# +# Make our Makefile.am files use the staticlib CPPFLAG only when strictly +# targeting a static library and not building its shared counterpart. +# + +AM_CONDITIONAL([USE_CPPFLAG_CURL_STATICLIB], + [test "x$xc_lt_build_static_only" = 'xyes']) + +# +# Make staticlib CPPFLAG variable and its definition visible in output +# files unconditionally, providing an empty definition unless strictly +# targeting a static library and not building its shared counterpart. +# + +CPPFLAG_CURL_STATICLIB= +if test "x$xc_lt_build_static_only" = 'xyes'; then + CPPFLAG_CURL_STATICLIB='-DCURL_STATICLIB' +fi +AC_SUBST([CPPFLAG_CURL_STATICLIB]) + + +# Determine whether all dependent libraries must be specified when linking +if test "X$enable_shared" = "Xyes" -a "X$link_all_deplibs" = "Xno" +then + REQUIRE_LIB_DEPS=no +else + REQUIRE_LIB_DEPS=yes +fi +AC_SUBST(REQUIRE_LIB_DEPS) +AM_CONDITIONAL(USE_EXPLICIT_LIB_DEPS, test x$REQUIRE_LIB_DEPS = xyes) + +dnl check if there's a way to force code inline +AC_C_INLINE + +dnl ********************************************************************** +dnl platform/compiler/architecture specific checks/flags +dnl ********************************************************************** + +CURL_CHECK_COMPILER +CURL_CHECK_NATIVE_WINDOWS +CURL_SET_COMPILER_BASIC_OPTS +CURL_SET_COMPILER_DEBUG_OPTS +CURL_SET_COMPILER_OPTIMIZE_OPTS +CURL_SET_COMPILER_WARNING_OPTS + +if test "$compiler_id" = "INTEL_UNIX_C"; then + # + if test "$compiler_num" -ge "1000"; then + dnl icc 10.X or later + CFLAGS="$CFLAGS -shared-intel" + elif test "$compiler_num" -ge "900"; then + dnl icc 9.X specific + CFLAGS="$CFLAGS -i-dynamic" + fi + # +fi + +CURL_CFLAG_EXTRAS="" +if test X"$want_werror" = Xyes; then + CURL_CFLAG_EXTRAS="-Werror" + if test "$compiler_id" = "GNU_C"; then + dnl enable -pedantic-errors for GCC 5 and later, + dnl as before that it was the same as -Werror=pedantic + if test "$compiler_num" -ge "500"; then + CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors" + fi + fi +fi +AC_SUBST(CURL_CFLAG_EXTRAS) + +CURL_CHECK_COMPILER_HALT_ON_ERROR +CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE +CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH +CURL_CHECK_COMPILER_SYMBOL_HIDING + +CURL_CHECK_CURLDEBUG +AM_CONDITIONAL(CURLDEBUG, test x$want_curldebug = xyes) + +supports_unittests=yes +# cross-compilation of unit tests static library/programs fails when +# libcurl shared library is built. This might be due to a libtool or +# automake issue. In this case we disable unit tests. +if test "x$cross_compiling" != "xno" && + test "x$enable_shared" != "xno"; then + supports_unittests=no +fi + +# IRIX 6.5.24 gcc 3.3 autobuilds fail unittests library compilation due to +# a problem related with OpenSSL headers and library versions not matching. +# Disable unit tests while time to further investigate this is found. +case $host in + mips-sgi-irix6.5) + if test "$compiler_id" = "GNU_C"; then + supports_unittests=no + fi + ;; +esac + +# All AIX autobuilds fails unit tests linking against unittests library +# due to unittests library being built with no symbols or members. Libtool ? +# Disable unit tests while time to further investigate this is found. +case $host_os in + aix*) + supports_unittests=no + ;; +esac + +dnl Build unit tests when option --enable-debug is given. +if test "x$want_debug" = "xyes" && + test "x$supports_unittests" = "xyes"; then + want_unittests=yes +else + want_unittests=no +fi +AM_CONDITIONAL(BUILD_UNITTESTS, test x$want_unittests = xyes) + +dnl ********************************************************************** +dnl Compilation based checks should not be done before this point. +dnl ********************************************************************** + +CURL_CHECK_WIN32_LARGEFILE +CURL_CHECK_WIN32_CRYPTO + +CURL_DARWIN_CFLAGS +CURL_DARWIN_SYSTEMCONFIGURATION +CURL_SUPPORTS_BUILTIN_AVAILABLE + +AM_CONDITIONAL([HAVE_WINDRES], + [test "$curl_cv_native_windows" = "yes" && test -n "${RC}"]) + +if test "$curl_cv_native_windows" = "yes"; then + AM_COND_IF([HAVE_WINDRES],, + [AC_MSG_ERROR([windres not found in PATH. Windows builds require windres. Cannot continue.])]) +fi + +dnl ************************************************************ +dnl switch off particular protocols +dnl +AC_MSG_CHECKING([whether to support http]) +AC_ARG_ENABLE(http, +AS_HELP_STRING([--enable-http],[Enable HTTP support]) +AS_HELP_STRING([--disable-http],[Disable HTTP support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_HTTP, 1, [to disable HTTP]) + disable_http="yes" + AC_MSG_WARN([disable HTTP disables FTP over proxy and RTSP]) + AC_SUBST(CURL_DISABLE_HTTP, [1]) + AC_DEFINE(CURL_DISABLE_RTSP, 1, [to disable RTSP]) + AC_SUBST(CURL_DISABLE_RTSP, [1]) + dnl toggle off alt-svc too when HTTP is disabled + AC_DEFINE(CURL_DISABLE_ALTSVC, 1, [disable alt-svc]) + AC_DEFINE(CURL_DISABLE_HSTS, 1, [disable HSTS]) + curl_h1_msg="no (--enable-http, --with-hyper)" + curl_altsvc_msg="no"; + curl_hsts_msg="no (--enable-hsts)"; + enable_altsvc="no" + hsts="no" + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) +AC_MSG_CHECKING([whether to support ftp]) +AC_ARG_ENABLE(ftp, +AS_HELP_STRING([--enable-ftp],[Enable FTP support]) +AS_HELP_STRING([--disable-ftp],[Disable FTP support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_FTP, 1, [to disable FTP]) + AC_SUBST(CURL_DISABLE_FTP, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) +AC_MSG_CHECKING([whether to support file]) +AC_ARG_ENABLE(file, +AS_HELP_STRING([--enable-file],[Enable FILE support]) +AS_HELP_STRING([--disable-file],[Disable FILE support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_FILE, 1, [to disable FILE]) + AC_SUBST(CURL_DISABLE_FILE, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) +AC_MSG_CHECKING([whether to support ldap]) +AC_ARG_ENABLE(ldap, +AS_HELP_STRING([--enable-ldap],[Enable LDAP support]) +AS_HELP_STRING([--disable-ldap],[Disable LDAP support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_LDAP, 1, [to disable LDAP]) + AC_SUBST(CURL_DISABLE_LDAP, [1]) + ;; + yes) + ldap_askedfor="yes" + AC_MSG_RESULT(yes) + ;; + *) + AC_MSG_RESULT(yes) + ;; + esac ],[ + AC_MSG_RESULT(yes) ] +) +AC_MSG_CHECKING([whether to support ldaps]) +AC_ARG_ENABLE(ldaps, +AS_HELP_STRING([--enable-ldaps],[Enable LDAPS support]) +AS_HELP_STRING([--disable-ldaps],[Disable LDAPS support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_LDAPS, 1, [to disable LDAPS]) + AC_SUBST(CURL_DISABLE_LDAPS, [1]) + ;; + *) if test "x$CURL_DISABLE_LDAP" = "x1" ; then + AC_MSG_RESULT(LDAP needs to be enabled to support LDAPS) + AC_DEFINE(CURL_DISABLE_LDAPS, 1, [to disable LDAPS]) + AC_SUBST(CURL_DISABLE_LDAPS, [1]) + else + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LDAP_SSL, 1, [Use LDAPS implementation]) + AC_SUBST(HAVE_LDAP_SSL, [1]) + fi + ;; + esac ],[ + if test "x$CURL_DISABLE_LDAP" = "x1" ; then + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_LDAPS, 1, [to disable LDAPS]) + AC_SUBST(CURL_DISABLE_LDAPS, [1]) + else + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LDAP_SSL, 1, [Use LDAPS implementation]) + AC_SUBST(HAVE_LDAP_SSL, [1]) + fi ] +) + +dnl ********************************************************************** +dnl Check for Hyper +dnl ********************************************************************** + +OPT_HYPER="no" + +AC_ARG_WITH(hyper, +AS_HELP_STRING([--with-hyper=PATH],[Enable hyper usage]) +AS_HELP_STRING([--without-hyper],[Disable hyper usage]), + [OPT_HYPER=$withval]) +case "$OPT_HYPER" in + no) + dnl --without-hyper option used + want_hyper="no" + ;; + yes) + dnl --with-hyper option used without path + want_hyper="default" + want_hyper_path="" + ;; + *) + dnl --with-hyper option used with path + want_hyper="yes" + want_hyper_path="$withval" + ;; +esac + +if test X"$want_hyper" != Xno; then + if test "x$disable_http" = "xyes"; then + AC_MSG_ERROR([--with-hyper is not compatible with --disable-http]) + fi + + dnl backup the pre-hyper variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(hyper, $want_hyper_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_HYPER=`CURL_EXPORT_PCDIR([$want_hyper_path]) + $PKGCONFIG --libs-only-l hyper` + CPP_HYPER=`CURL_EXPORT_PCDIR([$want_hyper_path]) dnl + $PKGCONFIG --cflags-only-I hyper` + LD_HYPER=`CURL_EXPORT_PCDIR([$want_hyper_path]) + $PKGCONFIG --libs-only-L hyper` + else + dnl no hyper pkg-config found + LIB_HYPER="-lhyper -ldl -lpthread -lm" + if test X"$want_hyper" != Xdefault; then + CPP_HYPER=-I"$want_hyper_path/capi/include" + LD_HYPER="-L$want_hyper_path/target/release -L$want_hyper_path/target/debug" + fi + fi + if test -n "$LIB_HYPER"; then + AC_MSG_NOTICE([-l is $LIB_HYPER]) + AC_MSG_NOTICE([-I is $CPP_HYPER]) + AC_MSG_NOTICE([-L is $LD_HYPER]) + + LDFLAGS="$LDFLAGS $LD_HYPER" + CPPFLAGS="$CPPFLAGS $CPP_HYPER" + LIBS="$LIB_HYPER $LIBS" + + if test "x$cross_compiling" != "xyes"; then + dnl remove -L, separate with colon if more than one + DIR_HYPER=`echo $LD_HYPER | $SED -e 's/^-L//' -e 's/ -L/:/g'` + fi + + AC_CHECK_LIB(hyper, hyper_io_new, + [ + AC_CHECK_HEADERS(hyper.h, + experimental="$experimental Hyper" + AC_MSG_NOTICE([Hyper support is experimental]) + curl_h1_msg="enabled (Hyper)" + HYPER_ENABLED=1 + AC_DEFINE(USE_HYPER, 1, [if hyper is in use]) + AC_SUBST(USE_HYPER, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_HYPER" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_HYPER to CURL_LIBRARY_PATH]), + ) + ], + for d in `echo $DIR_HYPER | $SED -e 's/:/ /'`; do + if test -f "$d/libhyper.a"; then + AC_MSG_ERROR([hyper was found in $d but was probably built with wrong flags. See docs/HYPER.md.]) + fi + done + AC_MSG_ERROR([--with-hyper but hyper was not found. See docs/HYPER.md.]) + ) + fi +fi + +if test X"$want_hyper" != Xno; then + AC_MSG_NOTICE([Disable RTSP support with hyper]) + AC_DEFINE(CURL_DISABLE_RTSP, 1, [to disable RTSP]) + AC_SUBST(CURL_DISABLE_RTSP, [1]) +else + AC_MSG_CHECKING([whether to support rtsp]) + AC_ARG_ENABLE(rtsp, +AS_HELP_STRING([--enable-rtsp],[Enable RTSP support]) +AS_HELP_STRING([--disable-rtsp],[Disable RTSP support]), + [ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_RTSP, 1, [to disable RTSP]) + AC_SUBST(CURL_DISABLE_RTSP, [1]) + ;; + *) + if test x$CURL_DISABLE_HTTP = x1 ; then + AC_MSG_ERROR(HTTP support needs to be enabled in order to enable RTSP support!) + else + AC_MSG_RESULT(yes) + curl_rtsp_msg="enabled" + fi + ;; + esac ], + if test "x$CURL_DISABLE_HTTP" != "x1"; then + AC_MSG_RESULT(yes) + curl_rtsp_msg="enabled" + else + AC_MSG_RESULT(no) + fi + ) +fi + +AC_MSG_CHECKING([whether to support proxies]) +AC_ARG_ENABLE(proxy, +AS_HELP_STRING([--enable-proxy],[Enable proxy support]) +AS_HELP_STRING([--disable-proxy],[Disable proxy support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_PROXY, 1, [to disable proxies]) + AC_SUBST(CURL_DISABLE_PROXY, [1]) + https_proxy="no" + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +AC_MSG_CHECKING([whether to support dict]) +AC_ARG_ENABLE(dict, +AS_HELP_STRING([--enable-dict],[Enable DICT support]) +AS_HELP_STRING([--disable-dict],[Disable DICT support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_DICT, 1, [to disable DICT]) + AC_SUBST(CURL_DISABLE_DICT, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) +AC_MSG_CHECKING([whether to support telnet]) +AC_ARG_ENABLE(telnet, +AS_HELP_STRING([--enable-telnet],[Enable TELNET support]) +AS_HELP_STRING([--disable-telnet],[Disable TELNET support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_TELNET, 1, [to disable TELNET]) + AC_SUBST(CURL_DISABLE_TELNET, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) +AC_MSG_CHECKING([whether to support tftp]) +AC_ARG_ENABLE(tftp, +AS_HELP_STRING([--enable-tftp],[Enable TFTP support]) +AS_HELP_STRING([--disable-tftp],[Disable TFTP support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_TFTP, 1, [to disable TFTP]) + AC_SUBST(CURL_DISABLE_TFTP, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +AC_MSG_CHECKING([whether to support pop3]) +AC_ARG_ENABLE(pop3, +AS_HELP_STRING([--enable-pop3],[Enable POP3 support]) +AS_HELP_STRING([--disable-pop3],[Disable POP3 support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_POP3, 1, [to disable POP3]) + AC_SUBST(CURL_DISABLE_POP3, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + + +AC_MSG_CHECKING([whether to support imap]) +AC_ARG_ENABLE(imap, +AS_HELP_STRING([--enable-imap],[Enable IMAP support]) +AS_HELP_STRING([--disable-imap],[Disable IMAP support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_IMAP, 1, [to disable IMAP]) + AC_SUBST(CURL_DISABLE_IMAP, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + + +AC_MSG_CHECKING([whether to support smb]) +AC_ARG_ENABLE(smb, +AS_HELP_STRING([--enable-smb],[Enable SMB/CIFS support]) +AS_HELP_STRING([--disable-smb],[Disable SMB/CIFS support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_SMB, 1, [to disable SMB/CIFS]) + AC_SUBST(CURL_DISABLE_SMB, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +AC_MSG_CHECKING([whether to support smtp]) +AC_ARG_ENABLE(smtp, +AS_HELP_STRING([--enable-smtp],[Enable SMTP support]) +AS_HELP_STRING([--disable-smtp],[Disable SMTP support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_SMTP, 1, [to disable SMTP]) + AC_SUBST(CURL_DISABLE_SMTP, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +AC_MSG_CHECKING([whether to support gopher]) +AC_ARG_ENABLE(gopher, +AS_HELP_STRING([--enable-gopher],[Enable Gopher support]) +AS_HELP_STRING([--disable-gopher],[Disable Gopher support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_GOPHER, 1, [to disable Gopher]) + AC_SUBST(CURL_DISABLE_GOPHER, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +AC_MSG_CHECKING([whether to support mqtt]) +AC_ARG_ENABLE(mqtt, +AS_HELP_STRING([--enable-mqtt],[Enable MQTT support]) +AS_HELP_STRING([--disable-mqtt],[Disable MQTT support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_MQTT, 1, [to disable MQTT]) + AC_SUBST(CURL_DISABLE_MQTT, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(no) +) + +dnl ********************************************************************** +dnl Check for built-in manual +dnl ********************************************************************** + +AC_MSG_CHECKING([whether to provide built-in manual]) +AC_ARG_ENABLE(manual, +AS_HELP_STRING([--enable-manual],[Enable built-in manual]) +AS_HELP_STRING([--disable-manual],[Disable built-in manual]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + ;; + *) AC_MSG_RESULT(yes) + USE_MANUAL="1" + ;; + esac ], + AC_MSG_RESULT(yes) + USE_MANUAL="1" +) +dnl The actual use of the USE_MANUAL variable is done much later in this +dnl script to allow other actions to disable it as well. + +dnl ************************************************************ +dnl disable C code generation support +dnl +AC_MSG_CHECKING([whether to enable generation of C code]) +AC_ARG_ENABLE(libcurl_option, +AS_HELP_STRING([--enable-libcurl-option],[Enable --libcurl C code generation support]) +AS_HELP_STRING([--disable-libcurl-option],[Disable --libcurl C code generation support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_LIBCURL_OPTION, 1, [to disable --libcurl C code generation option]) + curl_libcurl_msg="no" + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ********************************************************************** +dnl Checks for libraries. +dnl ********************************************************************** + +AC_MSG_CHECKING([whether to use libgcc]) +AC_ARG_ENABLE(libgcc, +AS_HELP_STRING([--enable-libgcc],[use libgcc when linking]), +[ case "$enableval" in + yes) + LIBS="-lgcc $LIBS" + AC_MSG_RESULT(yes) + ;; + *) AC_MSG_RESULT(no) + ;; + esac ], + AC_MSG_RESULT(no) +) + +CURL_CHECK_LIB_XNET + +dnl gethostbyname without lib or in the nsl lib? +AC_CHECK_FUNC(gethostbyname, + [HAVE_GETHOSTBYNAME="1" + ], + [ AC_CHECK_LIB(nsl, gethostbyname, + [HAVE_GETHOSTBYNAME="1" + LIBS="-lnsl $LIBS" + ]) + ]) + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + dnl gethostbyname in the socket lib? + AC_CHECK_LIB(socket, gethostbyname, + [HAVE_GETHOSTBYNAME="1" + LIBS="-lsocket $LIBS" + ]) +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + dnl gethostbyname in the watt lib? + AC_CHECK_LIB(watt, gethostbyname, + [HAVE_GETHOSTBYNAME="1" + CPPFLAGS="-I/dev/env/WATT_ROOT/inc" + LDFLAGS="-L/dev/env/WATT_ROOT/lib" + LIBS="-lwatt $LIBS" + ]) +fi + +dnl At least one system has been identified to require BOTH nsl and socket +dnl libs at the same time to link properly. +if test "$HAVE_GETHOSTBYNAME" != "1" +then + AC_MSG_CHECKING([for gethostbyname with both nsl and socket libs]) + my_ac_save_LIBS=$LIBS + LIBS="-lnsl -lsocket $LIBS" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ + gethostbyname(); + ]]) + ],[ + AC_MSG_RESULT([yes]) + HAVE_GETHOSTBYNAME="1" + ],[ + AC_MSG_RESULT([no]) + LIBS=$my_ac_save_LIBS + ]) +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + dnl This is for winsock systems + if test "$curl_cv_native_windows" = "yes"; then + winsock_LIB="-lws2_32" + if test ! -z "$winsock_LIB"; then + my_ac_save_LIBS=$LIBS + LIBS="$winsock_LIB $LIBS" + AC_MSG_CHECKING([for gethostbyname in $winsock_LIB]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + ]],[[ + gethostbyname("localhost"); + ]]) + ],[ + AC_MSG_RESULT([yes]) + HAVE_GETHOSTBYNAME="1" + ],[ + AC_MSG_RESULT([no]) + winsock_LIB="" + LIBS=$my_ac_save_LIBS + ]) + fi + fi +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + dnl This is for Minix 3.1 + AC_MSG_CHECKING([for gethostbyname for Minix 3]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +/* Older Minix versions may need here instead */ +#include + ]],[[ + gethostbyname("localhost"); + ]]) + ],[ + AC_MSG_RESULT([yes]) + HAVE_GETHOSTBYNAME="1" + ],[ + AC_MSG_RESULT([no]) + ]) +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + dnl This is for eCos with a stubbed DNS implementation + AC_MSG_CHECKING([for gethostbyname for eCos]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#include +#include + ]],[[ + gethostbyname("localhost"); + ]]) + ],[ + AC_MSG_RESULT([yes]) + HAVE_GETHOSTBYNAME="1" + ],[ + AC_MSG_RESULT([no]) + ]) +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" -o "${with_amissl+set}" = set +then + dnl This is for AmigaOS with bsdsocket.library - needs testing before -lnet + AC_MSG_CHECKING([for gethostbyname for AmigaOS bsdsocket.library]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + #define __USE_INLINE__ + #include + #ifdef __amigaos4__ + struct SocketIFace *ISocket = NULL; + #else + struct Library *SocketBase = NULL; + #endif + ]],[[ + gethostbyname("localhost"); + ]]) + ],[ + AC_MSG_RESULT([yes]) + HAVE_GETHOSTBYNAME="1" + HAVE_PROTO_BSDSOCKET_H="1" + AC_DEFINE(HAVE_PROTO_BSDSOCKET_H, 1, [if Amiga bsdsocket.library is in use]) + AC_SUBST(HAVE_PROTO_BSDSOCKET_H, [1]) + ],[ + AC_MSG_RESULT([no]) + ]) +fi + +if test "$HAVE_GETHOSTBYNAME" != "1" +then + dnl gethostbyname in the network lib - for Haiku OS + AC_CHECK_LIB(network, gethostbyname, + [HAVE_GETHOSTBYNAME="1" + LIBS="-lnetwork $LIBS" + ]) +fi + +if test "$HAVE_GETHOSTBYNAME" != "1"; then + AC_MSG_ERROR([couldn't find libraries for gethostbyname()]) +fi + +CURL_CHECK_LIBS_CONNECT + +CURL_NETWORK_LIBS=$LIBS + +dnl ********************************************************************** +dnl In case that function clock_gettime with monotonic timer is available, +dnl check for additional required libraries. +dnl ********************************************************************** +CURL_CHECK_LIBS_CLOCK_GETTIME_MONOTONIC + +dnl Check for even better option +CURL_CHECK_FUNC_CLOCK_GETTIME_MONOTONIC_RAW + +dnl ********************************************************************** +dnl The preceding library checks are all potentially useful for test +dnl servers and libtest cases which require networking and clock_gettime +dnl support. Save the list of required libraries at this point for use +dnl while linking those test servers and programs. +dnl ********************************************************************** +CURL_NETWORK_AND_TIME_LIBS=$LIBS + +dnl ********************************************************************** +dnl Check for the presence of ZLIB libraries and headers +dnl ********************************************************************** + +dnl Check for & handle argument to --with-zlib. + +clean_CPPFLAGS=$CPPFLAGS +clean_LDFLAGS=$LDFLAGS +clean_LIBS=$LIBS +ZLIB_LIBS="" +AC_ARG_WITH(zlib, +AS_HELP_STRING([--with-zlib=PATH],[search for zlib in PATH]) +AS_HELP_STRING([--without-zlib],[disable use of zlib]), + [OPT_ZLIB="$withval"]) + +if test "$OPT_ZLIB" = "no" ; then + AC_MSG_WARN([zlib disabled]) +else + if test "$OPT_ZLIB" = "yes" ; then + OPT_ZLIB="" + fi + + if test -z "$OPT_ZLIB" ; then + CURL_CHECK_PKGCONFIG(zlib) + + if test "$PKGCONFIG" != "no" ; then + ZLIB_LIBS="`$PKGCONFIG --libs-only-l zlib`" + if test -n "$ZLIB_LIBS"; then + LDFLAGS="$LDFLAGS `$PKGCONFIG --libs-only-L zlib`" + else + ZLIB_LIBS="`$PKGCONFIG --libs zlib`" + fi + LIBS="$ZLIB_LIBS $LIBS" + CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags zlib`" + OPT_ZLIB="" + HAVE_LIBZ="1" + fi + + if test -z "$HAVE_LIBZ"; then + + dnl Check for the lib without setting any new path, since many + dnl people have it in the default path + + AC_CHECK_LIB(z, inflateEnd, + dnl libz found, set the variable + [HAVE_LIBZ="1" + ZLIB_LIBS="-lz" + LIBS="$ZLIB_LIBS $LIBS"], + dnl if no lib found, try /usr/local + [OPT_ZLIB="/usr/local"]) + fi + fi + + dnl Add a nonempty path to the compiler flags + if test -n "$OPT_ZLIB"; then + CPPFLAGS="$CPPFLAGS -I$OPT_ZLIB/include" + LDFLAGS="$LDFLAGS -L$OPT_ZLIB/lib$libsuff" + fi + + AC_CHECK_HEADER(zlib.h, + [ + dnl zlib.h was found + HAVE_ZLIB_H="1" + dnl if the lib wasn't found already, try again with the new paths + if test "$HAVE_LIBZ" != "1"; then + AC_CHECK_LIB(z, gzread, + [ + dnl the lib was found! + HAVE_LIBZ="1" + ZLIB_LIBS="-lz" + LIBS="$ZLIB_LIBS $LIBS" + ], + [ CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS]) + fi + ], + [ + dnl zlib.h was not found, restore the flags + CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS] + ) + + if test "$HAVE_LIBZ" = "1" && test "$HAVE_ZLIB_H" != "1" + then + AC_MSG_WARN([configure found only the libz lib, not the header file!]) + HAVE_LIBZ="" + CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS + LIBS=$clean_LIBS + ZLIB_LIBS="" + elif test "$HAVE_LIBZ" != "1" && test "$HAVE_ZLIB_H" = "1" + then + AC_MSG_WARN([configure found only the libz header file, not the lib!]) + CPPFLAGS=$clean_CPPFLAGS + LDFLAGS=$clean_LDFLAGS + LIBS=$clean_LIBS + ZLIB_LIBS="" + elif test "$HAVE_LIBZ" = "1" && test "$HAVE_ZLIB_H" = "1" + then + dnl both header and lib were found! + AC_SUBST(HAVE_LIBZ) + AC_DEFINE(HAVE_LIBZ, 1, [if zlib is available]) + LIBS="$ZLIB_LIBS $clean_LIBS" + + dnl replace 'HAVE_LIBZ' in the automake makefile.ams + AMFIXLIB="1" + AC_MSG_NOTICE([found both libz and libz.h header]) + curl_zlib_msg="enabled" + fi +fi + +dnl set variable for use in automakefile(s) +AM_CONDITIONAL(HAVE_LIBZ, test x"$AMFIXLIB" = x1) +AC_SUBST(ZLIB_LIBS) + +dnl ********************************************************************** +dnl Check for the presence of BROTLI decoder libraries and headers +dnl ********************************************************************** + +dnl Brotli project home page: https://github.com/google/brotli + +dnl Default to compiler & linker defaults for BROTLI files & libraries. +OPT_BROTLI=off +AC_ARG_WITH(brotli,dnl +AS_HELP_STRING([--with-brotli=PATH],[Where to look for brotli, PATH points to the BROTLI installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--without-brotli], [disable BROTLI]), + OPT_BROTLI=$withval) + +if test X"$OPT_BROTLI" != Xno; then + dnl backup the pre-brotli variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_BROTLI" in + yes) + dnl --with-brotli (without path) used + CURL_CHECK_PKGCONFIG(libbrotlidec) + + if test "$PKGCONFIG" != "no" ; then + LIB_BROTLI=`$PKGCONFIG --libs-only-l libbrotlidec` + LD_BROTLI=`$PKGCONFIG --libs-only-L libbrotlidec` + CPP_BROTLI=`$PKGCONFIG --cflags-only-I libbrotlidec` + version=`$PKGCONFIG --modversion libbrotlidec` + DIR_BROTLI=`echo $LD_BROTLI | $SED -e 's/^-L//'` + fi + + ;; + off) + dnl no --with-brotli option given, just check default places + ;; + *) + dnl use the given --with-brotli spot + PREFIX_BROTLI=$OPT_BROTLI + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_BROTLI"; then + LIB_BROTLI="-lbrotlidec" + LD_BROTLI=-L${PREFIX_BROTLI}/lib$libsuff + CPP_BROTLI=-I${PREFIX_BROTLI}/include + DIR_BROTLI=${PREFIX_BROTLI}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_BROTLI" + CPPFLAGS="$CPPFLAGS $CPP_BROTLI" + LIBS="$LIB_BROTLI $LIBS" + + AC_CHECK_LIB(brotlidec, BrotliDecoderDecompress) + + AC_CHECK_HEADERS(brotli/decode.h, + curl_brotli_msg="enabled (libbrotlidec)" + HAVE_BROTLI=1 + AC_DEFINE(HAVE_BROTLI, 1, [if BROTLI is in use]) + AC_SUBST(HAVE_BROTLI, [1]) + ) + + if test X"$OPT_BROTLI" != Xoff && + test "$HAVE_BROTLI" != "1"; then + AC_MSG_ERROR([BROTLI libs and/or directories were not found where specified!]) + fi + + if test "$HAVE_BROTLI" = "1"; then + if test -n "$DIR_BROTLI"; then + dnl when the brotli shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH + dnl to prevent further configure tests to fail due to this + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_BROTLI" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_BROTLI to CURL_LIBRARY_PATH]) + fi + fi + else + dnl no brotli, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +fi + +dnl ********************************************************************** +dnl Check for libzstd +dnl ********************************************************************** + +dnl Default to compiler & linker defaults for libzstd +OPT_ZSTD=off +AC_ARG_WITH(zstd,dnl +AS_HELP_STRING([--with-zstd=PATH],[Where to look for libzstd, PATH points to the libzstd installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--without-zstd], [disable libzstd]), + OPT_ZSTD=$withval) + +if test X"$OPT_ZSTD" != Xno; then + dnl backup the pre-zstd variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_ZSTD" in + yes) + dnl --with-zstd (without path) used + CURL_CHECK_PKGCONFIG(libzstd) + + if test "$PKGCONFIG" != "no" ; then + LIB_ZSTD=`$PKGCONFIG --libs-only-l libzstd` + LD_ZSTD=`$PKGCONFIG --libs-only-L libzstd` + CPP_ZSTD=`$PKGCONFIG --cflags-only-I libzstd` + version=`$PKGCONFIG --modversion libzstd` + DIR_ZSTD=`echo $LD_ZSTD | $SED -e 's/-L//'` + fi + + ;; + off) + dnl no --with-zstd option given, just check default places + ;; + *) + dnl use the given --with-zstd spot + PREFIX_ZSTD=$OPT_ZSTD + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_ZSTD"; then + LIB_ZSTD="-lzstd" + LD_ZSTD=-L${PREFIX_ZSTD}/lib$libsuff + CPP_ZSTD=-I${PREFIX_ZSTD}/include + DIR_ZSTD=${PREFIX_ZSTD}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_ZSTD" + CPPFLAGS="$CPPFLAGS $CPP_ZSTD" + LIBS="$LIB_ZSTD $LIBS" + + AC_CHECK_LIB(zstd, ZSTD_createDStream) + + AC_CHECK_HEADERS(zstd.h, + curl_zstd_msg="enabled (libzstd)" + HAVE_ZSTD=1 + AC_DEFINE(HAVE_ZSTD, 1, [if libzstd is in use]) + AC_SUBST(HAVE_ZSTD, [1]) + ) + + if test X"$OPT_ZSTD" != Xoff && + test "$HAVE_ZSTD" != "1"; then + AC_MSG_ERROR([libzstd was not found where specified!]) + fi + + if test "$HAVE_ZSTD" = "1"; then + if test -n "$DIR_ZSTD"; then + dnl when the zstd shared lib were found in a path that the run-time + dnl linker doesn't search through, we need to add it to + dnl CURL_LIBRARY_PATH to prevent further configure tests to fail due to + dnl this + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_ZSTD" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_ZSTD to CURL_LIBRARY_PATH]) + fi + fi + else + dnl no zstd, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +fi + +dnl ********************************************************************** +dnl Check for LDAP +dnl ********************************************************************** + +LDAPLIBNAME="" +AC_ARG_WITH(ldap-lib, +AS_HELP_STRING([--with-ldap-lib=libname],[Specify name of ldap lib file]), + [LDAPLIBNAME="$withval"]) + +LBERLIBNAME="" +AC_ARG_WITH(lber-lib, +AS_HELP_STRING([--with-lber-lib=libname],[Specify name of lber lib file]), + [LBERLIBNAME="$withval"]) + +if test x$CURL_DISABLE_LDAP != x1 ; then + + CURL_CHECK_HEADER_LBER + CURL_CHECK_HEADER_LDAP + CURL_CHECK_HEADER_LDAP_SSL + + if test -z "$LDAPLIBNAME" ; then + if test "$curl_cv_native_windows" = "yes"; then + dnl Windows uses a single and unique LDAP library name + LDAPLIBNAME="wldap32" + LBERLIBNAME="no" + fi + fi + + if test "$LDAPLIBNAME" ; then + AC_CHECK_LIB("$LDAPLIBNAME", ldap_init,, [ + if test -n "$ldap_askedfor"; then + AC_MSG_ERROR([couldn't detect the LDAP libraries]) + fi + AC_MSG_WARN(["$LDAPLIBNAME" is not an LDAP library: LDAP disabled]) + AC_DEFINE(CURL_DISABLE_LDAP, 1, [to disable LDAP]) + AC_SUBST(CURL_DISABLE_LDAP, [1]) + AC_DEFINE(CURL_DISABLE_LDAPS, 1, [to disable LDAPS]) + AC_SUBST(CURL_DISABLE_LDAPS, [1])]) + else + dnl Try to find the right ldap libraries for this system + CURL_CHECK_LIBS_LDAP + case X-"$curl_cv_ldap_LIBS" in + X-unknown) + if test -n "$ldap_askedfor"; then + AC_MSG_ERROR([couldn't detect the LDAP libraries]) + fi + AC_MSG_WARN([Cannot find libraries for LDAP support: LDAP disabled]) + AC_DEFINE(CURL_DISABLE_LDAP, 1, [to disable LDAP]) + AC_SUBST(CURL_DISABLE_LDAP, [1]) + AC_DEFINE(CURL_DISABLE_LDAPS, 1, [to disable LDAPS]) + AC_SUBST(CURL_DISABLE_LDAPS, [1]) + ;; + esac + fi +fi + +if test x$CURL_DISABLE_LDAP != x1 ; then + + if test "$LBERLIBNAME" ; then + dnl If name is "no" then don't define this library at all + dnl (it's only needed if libldap.so's dependencies are broken). + if test "$LBERLIBNAME" != "no" ; then + AC_CHECK_LIB("$LBERLIBNAME", ber_free,, [ + AC_MSG_WARN(["$LBERLIBNAME" is not an LBER library: LDAP disabled]) + AC_DEFINE(CURL_DISABLE_LDAP, 1, [to disable LDAP]) + AC_SUBST(CURL_DISABLE_LDAP, [1]) + AC_DEFINE(CURL_DISABLE_LDAPS, 1, [to disable LDAPS]) + AC_SUBST(CURL_DISABLE_LDAPS, [1])]) + fi + fi +fi + +if test x$CURL_DISABLE_LDAP != x1 ; then + AC_CHECK_FUNCS([ldap_url_parse \ + ldap_init_fd]) + + if test "$LDAPLIBNAME" = "wldap32"; then + curl_ldap_msg="enabled (winldap)" + AC_DEFINE(USE_WIN32_LDAP, 1, [Use Windows LDAP implementation]) + else + if test "x$ac_cv_func_ldap_init_fd" = "xyes"; then + curl_ldap_msg="enabled (OpenLDAP)" + AC_DEFINE(USE_OPENLDAP, 1, [Use OpenLDAP-specific code]) + AC_SUBST(USE_OPENLDAP, [1]) + else + curl_ldap_msg="enabled (ancient OpenLDAP)" + fi + fi +fi + +if test x$CURL_DISABLE_LDAPS != x1 ; then + curl_ldaps_msg="enabled" +fi + +dnl ********************************************************************** +dnl Checks for IPv6 +dnl ********************************************************************** + +AC_MSG_CHECKING([whether to enable IPv6]) +AC_ARG_ENABLE(ipv6, +AS_HELP_STRING([--enable-ipv6],[Enable IPv6 (with IPv4) support]) +AS_HELP_STRING([--disable-ipv6],[Disable IPv6 support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + ipv6=no + ;; + *) AC_MSG_RESULT(yes) + ipv6=yes + ;; + esac ], + + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +/* are AF_INET6 and sockaddr_in6 available? */ +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#if defined (__TANDEM) +# include +#endif +#endif + +int main(void) +{ + struct sockaddr_in6 s; + (void)s; + return socket(AF_INET6, SOCK_STREAM, 0) < 0; +} +]]) +], + AC_MSG_RESULT(yes) + ipv6=yes, + AC_MSG_RESULT(no) + ipv6=no, + AC_MSG_RESULT(yes) + ipv6=yes +)) + +if test "$ipv6" = yes; then + curl_ipv6_msg="enabled" + AC_DEFINE(ENABLE_IPV6, 1, [Define if you want to enable IPv6 support]) + IPV6_ENABLED=1 + AC_SUBST(IPV6_ENABLED) + + AC_MSG_CHECKING([if struct sockaddr_in6 has sin6_scope_id member]) + AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ +#include +#ifdef _WIN32 +#include +#include +#else +#include +#if defined (__TANDEM) +# include +#endif +#endif +]], [[ + struct sockaddr_in6 s; + s.sin6_scope_id = 0; +]])], [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID, 1, [Define to 1 if struct sockaddr_in6 has the sin6_scope_id member]) + ], [ + AC_MSG_RESULT([no]) + ]) +fi + +dnl ********************************************************************** +dnl Check if the operating system allows programs to write to their own argv[] +dnl ********************************************************************** + +AC_MSG_CHECKING([if argv can be written to]) +CURL_RUN_IFELSE([[ +int main(int argc, char **argv) +{ +#ifdef _WIN32 + /* on Windows, writing to the argv does not hide the argument in + process lists so it can just be skipped */ + (void)argc; + (void)argv; + return 1; +#else + (void)argc; + argv[0][0] = ' '; + return (argv[0][0] == ' ')?0:1; +#endif +} +]],[ + curl_cv_writable_argv=yes +],[ + curl_cv_writable_argv=no +],[ + curl_cv_writable_argv=cross +]) +case $curl_cv_writable_argv in +yes) + AC_DEFINE(HAVE_WRITABLE_ARGV, 1, [Define this symbol if your OS supports changing the contents of argv]) + AC_MSG_RESULT(yes) + ;; +no) + AC_MSG_RESULT(no) + ;; +*) + AC_MSG_RESULT(no) + AC_MSG_WARN([the previous check could not be made default was used]) + ;; +esac + +dnl ********************************************************************** +dnl Check for GSS-API libraries +dnl ********************************************************************** + +dnl check for GSS-API stuff in the /usr as default + +GSSAPI_ROOT="/usr" +AC_ARG_WITH(gssapi-includes, + AS_HELP_STRING([--with-gssapi-includes=DIR], + [Specify location of GSS-API headers]), + [ GSSAPI_INCS="-I$withval" + want_gss="yes" ] +) + +AC_ARG_WITH(gssapi-libs, + AS_HELP_STRING([--with-gssapi-libs=DIR], + [Specify location of GSS-API libs]), + [ GSSAPI_LIB_DIR="-L$withval" + want_gss="yes" ] +) + +AC_ARG_WITH(gssapi, + AS_HELP_STRING([--with-gssapi=DIR], + [Where to look for GSS-API]), [ + GSSAPI_ROOT="$withval" + if test x"$GSSAPI_ROOT" != xno; then + want_gss="yes" + if test x"$GSSAPI_ROOT" = xyes; then + dnl if yes, then use default root + GSSAPI_ROOT="/usr" + fi + fi +]) + +: ${KRB5CONFIG:="$GSSAPI_ROOT/bin/krb5-config"} + +save_CPPFLAGS="$CPPFLAGS" +AC_MSG_CHECKING([if GSS-API support is requested]) +if test x"$want_gss" = xyes; then + AC_MSG_RESULT(yes) + + if test $GSSAPI_ROOT != "/usr"; then + CURL_CHECK_PKGCONFIG(mit-krb5-gssapi, $GSSAPI_ROOT/lib/pkgconfig) + else + CURL_CHECK_PKGCONFIG(mit-krb5-gssapi) + fi + if test -z "$GSSAPI_INCS"; then + if test -n "$host_alias" -a -f "$GSSAPI_ROOT/bin/$host_alias-krb5-config"; then + GSSAPI_INCS=`$GSSAPI_ROOT/bin/$host_alias-krb5-config --cflags gssapi` + elif test "$PKGCONFIG" != "no" ; then + GSSAPI_INCS=`$PKGCONFIG --cflags mit-krb5-gssapi` + elif test -f "$KRB5CONFIG"; then + GSSAPI_INCS=`$KRB5CONFIG --cflags gssapi` + elif test "$GSSAPI_ROOT" != "yes"; then + GSSAPI_INCS="-I$GSSAPI_ROOT/include" + fi + fi + + CPPFLAGS="$CPPFLAGS $GSSAPI_INCS" + + AC_CHECK_HEADER(gss.h, + [ + dnl found in the given dirs + AC_DEFINE(HAVE_GSSGNU, 1, [if you have GNU GSS]) + gnu_gss=yes + ], + [ + dnl not found, check Heimdal or MIT + AC_CHECK_HEADERS([gssapi/gssapi.h], [], [not_mit=1]) + AC_CHECK_HEADERS( + [gssapi/gssapi_generic.h gssapi/gssapi_krb5.h], + [], + [not_mit=1], + [ +AC_INCLUDES_DEFAULT +#ifdef HAVE_GSSAPI_GSSAPI_H +#include +#endif + ]) + if test "x$not_mit" = "x1"; then + dnl MIT not found, check for Heimdal + AC_CHECK_HEADER(gssapi.h, + [], + [ + dnl no header found, disabling GSS + want_gss=no + AC_MSG_WARN(disabling GSS-API support since no header files were found) + ] + ) + else + dnl MIT found + dnl check if we have a really old MIT Kerberos version (<= 1.2) + AC_MSG_CHECKING([if GSS-API headers declare GSS_C_NT_HOSTBASED_SERVICE]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include +#include +#include + ]],[[ + gss_import_name( + (OM_uint32 *)0, + (gss_buffer_t)0, + GSS_C_NT_HOSTBASED_SERVICE, + (gss_name_t *)0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_DEFINE(HAVE_OLD_GSSMIT, 1, + [if you have an old MIT Kerberos version, lacking GSS_C_NT_HOSTBASED_SERVICE]) + ]) + fi + ] + ) +else + AC_MSG_RESULT(no) +fi +if test x"$want_gss" = xyes; then + AC_DEFINE(HAVE_GSSAPI, 1, [if you have GSS-API libraries]) + HAVE_GSSAPI=1 + curl_gss_msg="enabled (MIT Kerberos/Heimdal)" + + if test -n "$gnu_gss"; then + curl_gss_msg="enabled (GNU GSS)" + LDFLAGS="$LDFLAGS $GSSAPI_LIB_DIR" + LIBS="-lgss $LIBS" + elif test -z "$GSSAPI_LIB_DIR"; then + case $host in + *-*-darwin*) + LIBS="-lgssapi_krb5 -lresolv $LIBS" + ;; + *) + if test $GSSAPI_ROOT != "/usr"; then + CURL_CHECK_PKGCONFIG(mit-krb5-gssapi, $GSSAPI_ROOT/lib/pkgconfig) + else + CURL_CHECK_PKGCONFIG(mit-krb5-gssapi) + fi + if test -n "$host_alias" -a -f "$GSSAPI_ROOT/bin/$host_alias-krb5-config"; then + dnl krb5-config doesn't have --libs-only-L or similar, put everything + dnl into LIBS + gss_libs=`$GSSAPI_ROOT/bin/$host_alias-krb5-config --libs gssapi` + LIBS="$gss_libs $LIBS" + elif test "$PKGCONFIG" != "no" ; then + gss_libs=`$PKGCONFIG --libs mit-krb5-gssapi` + LIBS="$gss_libs $LIBS" + elif test -f "$KRB5CONFIG"; then + dnl krb5-config doesn't have --libs-only-L or similar, put everything + dnl into LIBS + gss_libs=`$KRB5CONFIG --libs gssapi` + LIBS="$gss_libs $LIBS" + else + case $host in + *-hp-hpux*) + gss_libname="gss" + ;; + *) + gss_libname="gssapi" + ;; + esac + + if test "$GSSAPI_ROOT" != "yes"; then + LDFLAGS="$LDFLAGS -L$GSSAPI_ROOT/lib$libsuff" + LIBS="-l$gss_libname $LIBS" + else + LIBS="-l$gss_libname $LIBS" + fi + fi + ;; + esac + else + LDFLAGS="$LDFLAGS $GSSAPI_LIB_DIR" + case $host in + *-hp-hpux*) + LIBS="-lgss $LIBS" + ;; + *) + LIBS="-lgssapi $LIBS" + ;; + esac + fi +else + CPPFLAGS="$save_CPPFLAGS" +fi + +if test x"$want_gss" = xyes; then + AC_MSG_CHECKING([if we can link against GSS-API library]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([gss_init_sec_context]) + ],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([--with-gssapi was specified, but a GSS-API library was not found.]) + ]) +fi + +build_libstubgss=no +if test x"$want_gss" = "xyes"; then + build_libstubgss=yes +fi + +AM_CONDITIONAL(BUILD_STUB_GSS, test "x$build_libstubgss" = "xyes") + +dnl ------------------------------------------------------------- +dnl parse --with-default-ssl-backend so it can be validated below +dnl ------------------------------------------------------------- + +DEFAULT_SSL_BACKEND=no +VALID_DEFAULT_SSL_BACKEND= +AC_ARG_WITH(default-ssl-backend, +AS_HELP_STRING([--with-default-ssl-backend=NAME],[Use NAME as default SSL backend]) +AS_HELP_STRING([--without-default-ssl-backend],[Use implicit default SSL backend]), + [DEFAULT_SSL_BACKEND=$withval]) +case "$DEFAULT_SSL_BACKEND" in + no) + dnl --without-default-ssl-backend option used + ;; + default|yes) + dnl --with-default-ssl-backend option used without name + AC_MSG_ERROR([The name of the default SSL backend is required.]) + ;; + *) + dnl --with-default-ssl-backend option used with name + AC_SUBST(DEFAULT_SSL_BACKEND) + dnl needs to be validated below + VALID_DEFAULT_SSL_BACKEND=no + ;; +esac + +CURL_WITH_SCHANNEL +CURL_WITH_SECURETRANSPORT +CURL_WITH_AMISSL +CURL_WITH_OPENSSL +CURL_WITH_GNUTLS +CURL_WITH_MBEDTLS +CURL_WITH_WOLFSSL +CURL_WITH_BEARSSL +CURL_WITH_RUSTLS + +dnl link required libraries for USE_WIN32_CRYPTO or USE_SCHANNEL +if test "x$USE_WIN32_CRYPTO" = "x1" -o "x$USE_SCHANNEL" = "x1"; then + LIBS="-ladvapi32 -lcrypt32 $LIBS" +fi + +dnl link bcrypt for BCryptGenRandom() (used when building for Vista or newer) +if test "x$curl_cv_native_windows" = "xyes"; then + LIBS="-lbcrypt $LIBS" +fi + +case "x$SSL_DISABLED$OPENSSL_ENABLED$GNUTLS_ENABLED$MBEDTLS_ENABLED$WOLFSSL_ENABLED$SCHANNEL_ENABLED$SECURETRANSPORT_ENABLED$BEARSSL_ENABLED$RUSTLS_ENABLED" +in +x) + AC_MSG_ERROR([TLS not detected, you will not be able to use HTTPS, FTPS, NTLM and more. +Use --with-openssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-schannel, --with-secure-transport, --with-amissl, --with-bearssl or --with-rustls to address this.]) + ;; +x1) + # one SSL backend is enabled + AC_SUBST(SSL_ENABLED) + SSL_ENABLED="1" + AC_MSG_NOTICE([built with one SSL backend]) + ;; +xD) + # explicitly built without TLS + ;; +xD*) + AC_MSG_ERROR([--without-ssl has been set together with an explicit option to use an ssl library +(e.g. --with-openssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-schannel, --with-secure-transport, --with-amissl, --with-bearssl, --with-rustls). +Since these are conflicting parameters, verify which is the desired one and drop the other.]) + ;; +*) + # more than one SSL backend is enabled + AC_SUBST(SSL_ENABLED) + SSL_ENABLED="1" + AC_SUBST(CURL_WITH_MULTI_SSL) + CURL_WITH_MULTI_SSL="1" + AC_DEFINE(CURL_WITH_MULTI_SSL, 1, [built with multiple SSL backends]) + AC_MSG_NOTICE([built with multiple SSL backends]) + ;; +esac + +if test -n "$ssl_backends"; then + curl_ssl_msg="enabled ($ssl_backends)" +fi + +if test no = "$VALID_DEFAULT_SSL_BACKEND" +then + if test -n "$SSL_ENABLED" + then + AC_MSG_ERROR([Default SSL backend $DEFAULT_SSL_BACKEND not enabled!]) + else + AC_MSG_ERROR([Default SSL backend requires SSL!]) + fi +elif test yes = "$VALID_DEFAULT_SSL_BACKEND" +then + AC_DEFINE_UNQUOTED([CURL_DEFAULT_SSL_BACKEND], ["$DEFAULT_SSL_BACKEND"], [Default SSL backend]) +fi + +dnl ********************************************************************** +dnl Check for the CA bundle +dnl ********************************************************************** + +if test -n "$check_for_ca_bundle"; then + CURL_CHECK_CA_BUNDLE +fi + +dnl ********************************************************************** +dnl Check for libpsl +dnl ********************************************************************** + +AC_ARG_WITH(libpsl, + AS_HELP_STRING([--without-libpsl], + [disable support for libpsl]), + with_libpsl=$withval, + with_libpsl=yes) +curl_psl_msg="no (libpsl disabled)" +if test $with_libpsl != "no"; then + AC_SEARCH_LIBS(psl_builtin, psl, + [curl_psl_msg="enabled"; + AC_DEFINE([USE_LIBPSL], [1], [PSL support enabled]) + ], + [AC_MSG_ERROR([libpsl was not found]) ] + ) +fi +AM_CONDITIONAL([USE_LIBPSL], [test "$curl_psl_msg" = "enabled"]) + + +dnl ********************************************************************** +dnl Check for libgsasl +dnl ********************************************************************** + +AC_ARG_WITH(libgsasl, + AS_HELP_STRING([--without-libgsasl], + [disable libgsasl support for SCRAM]), + with_libgsasl=$withval, + with_libgsasl=yes) +if test $with_libgsasl != "no"; then + AC_SEARCH_LIBS(gsasl_init, gsasl, + [curl_gsasl_msg="enabled"; + AC_DEFINE([USE_GSASL], [1], [GSASL support enabled]) + ], + [curl_gsasl_msg="no (libgsasl not found)"; + AC_MSG_WARN([libgsasl was not found]) + ] + ) +fi +AM_CONDITIONAL([USE_GSASL], [test "$curl_gsasl_msg" = "enabled"]) + +AC_ARG_WITH(libmetalink,, + AC_MSG_ERROR([--with-libmetalink and --without-libmetalink no longer work!])) + +dnl ********************************************************************** +dnl Check for the presence of LIBSSH2 libraries and headers +dnl ********************************************************************** + +dnl Default to compiler & linker defaults for LIBSSH2 files & libraries. +OPT_LIBSSH2=off +AC_ARG_WITH(libssh2,dnl +AS_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points to the libssh2 installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--with-libssh2], [enable libssh2]), + OPT_LIBSSH2=$withval, OPT_LIBSSH2=no) + + +OPT_LIBSSH=off +AC_ARG_WITH(libssh,dnl +AS_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to the libssh installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--with-libssh], [enable libssh]), + OPT_LIBSSH=$withval, OPT_LIBSSH=no) + +OPT_WOLFSSH=off +AC_ARG_WITH(wolfssh,dnl +AS_HELP_STRING([--with-wolfssh=PATH],[Where to look for wolfssh, PATH points to the wolfSSH installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--with-wolfssh], [enable wolfssh]), + OPT_WOLFSSH=$withval, OPT_WOLFSSH=no) + +if test X"$OPT_LIBSSH2" != Xno; then + dnl backup the pre-libssh2 variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBSSH2" in + yes) + dnl --with-libssh2 (without path) used + CURL_CHECK_PKGCONFIG(libssh2) + + if test "$PKGCONFIG" != "no" ; then + LIB_SSH2=`$PKGCONFIG --libs-only-l libssh2` + LD_SSH2=`$PKGCONFIG --libs-only-L libssh2` + CPP_SSH2=`$PKGCONFIG --cflags-only-I libssh2` + version=`$PKGCONFIG --modversion libssh2` + DIR_SSH2=`echo $LD_SSH2 | $SED -e 's/^-L//'` + fi + + ;; + off) + dnl no --with-libssh2 option given, just check default places + ;; + *) + dnl use the given --with-libssh2 spot + PREFIX_SSH2=$OPT_LIBSSH2 + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_SSH2"; then + LIB_SSH2="-lssh2" + LD_SSH2=-L${PREFIX_SSH2}/lib$libsuff + CPP_SSH2=-I${PREFIX_SSH2}/include + DIR_SSH2=${PREFIX_SSH2}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_SSH2" + CPPFLAGS="$CPPFLAGS $CPP_SSH2" + LIBS="$LIB_SSH2 $LIBS" + + dnl check for function added in libssh2 version 1.0 + AC_CHECK_LIB(ssh2, libssh2_session_block_directions) + + AC_CHECK_HEADER(libssh2.h, + curl_ssh_msg="enabled (libSSH2)" + LIBSSH2_ENABLED=1 + AC_DEFINE(USE_LIBSSH2, 1, [if libSSH2 is in use]) + AC_SUBST(USE_LIBSSH2, [1]) + ) + + if test X"$OPT_LIBSSH2" != Xoff && + test "$LIBSSH2_ENABLED" != "1"; then + AC_MSG_ERROR([libSSH2 libs and/or directories were not found where specified!]) + fi + + if test "$LIBSSH2_ENABLED" = "1"; then + if test -n "$DIR_SSH2"; then + dnl when the libssh2 shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH + dnl to prevent further configure tests to fail due to this + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH2" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_SSH2 to CURL_LIBRARY_PATH]) + fi + fi + else + dnl no libssh2, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +elif test X"$OPT_LIBSSH" != Xno; then + dnl backup the pre-libssh variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBSSH" in + yes) + dnl --with-libssh (without path) used + CURL_CHECK_PKGCONFIG(libssh) + + if test "$PKGCONFIG" != "no" ; then + LIB_SSH=`$PKGCONFIG --libs-only-l libssh` + LD_SSH=`$PKGCONFIG --libs-only-L libssh` + CPP_SSH=`$PKGCONFIG --cflags-only-I libssh` + version=`$PKGCONFIG --modversion libssh` + DIR_SSH=`echo $LD_SSH | $SED -e 's/^-L//'` + fi + + ;; + off) + dnl no --with-libssh option given, just check default places + ;; + *) + dnl use the given --with-libssh spot + PREFIX_SSH=$OPT_LIBSSH + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_SSH"; then + LIB_SSH="-lssh" + LD_SSH=-L${PREFIX_SSH}/lib$libsuff + CPP_SSH=-I${PREFIX_SSH}/include + DIR_SSH=${PREFIX_SSH}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_SSH" + CPPFLAGS="$CPPFLAGS $CPP_SSH" + LIBS="$LIB_SSH $LIBS" + + AC_CHECK_LIB(ssh, ssh_new) + + AC_CHECK_HEADER(libssh/libssh.h, + curl_ssh_msg="enabled (libSSH)" + LIBSSH_ENABLED=1 + AC_DEFINE(USE_LIBSSH, 1, [if libSSH is in use]) + AC_SUBST(USE_LIBSSH, [1]) + ) + + if test X"$OPT_LIBSSH" != Xoff && + test "$LIBSSH_ENABLED" != "1"; then + AC_MSG_ERROR([libSSH libs and/or directories were not found where specified!]) + fi + + if test "$LIBSSH_ENABLED" = "1"; then + if test -n "$DIR_SSH"; then + dnl when the libssh shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH + dnl to prevent further configure tests to fail due to this + + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_SSH to CURL_LIBRARY_PATH]) + fi + fi + else + dnl no libssh, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +elif test X"$OPT_WOLFSSH" != Xno; then + dnl backup the pre-wolfssh variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test "$OPT_WOLFSSH" != yes; then + WOLFCONFIG="$OPT_WOLFSSH/bin/wolfssh-config" + LDFLAGS="$LDFLAGS `$WOLFCONFIG --libs`" + CPPFLAGS="$CPPFLAGS `$WOLFCONFIG --cflags`" + fi + + AC_CHECK_LIB(wolfssh, wolfSSH_Init) + + AC_CHECK_HEADERS(wolfssh/ssh.h, + curl_ssh_msg="enabled (wolfSSH)" + WOLFSSH_ENABLED=1 + AC_DEFINE(USE_WOLFSSH, 1, [if wolfSSH is in use]) + AC_SUBST(USE_WOLFSSH, [1]) + ) + +fi + +dnl ********************************************************************** +dnl Check for the presence of LIBRTMP libraries and headers +dnl ********************************************************************** + +dnl Default to compiler & linker defaults for LIBRTMP files & libraries. +OPT_LIBRTMP=off +AC_ARG_WITH(librtmp,dnl +AS_HELP_STRING([--with-librtmp=PATH],[Where to look for librtmp, PATH points to the LIBRTMP installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--without-librtmp], [disable LIBRTMP]), + OPT_LIBRTMP=$withval) + +if test X"$OPT_LIBRTMP" != Xno; then + dnl backup the pre-librtmp variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBRTMP" in + yes) + dnl --with-librtmp (without path) used + CURL_CHECK_PKGCONFIG(librtmp) + + if test "$PKGCONFIG" != "no" ; then + LIB_RTMP=`$PKGCONFIG --libs-only-l librtmp` + LD_RTMP=`$PKGCONFIG --libs-only-L librtmp` + CPP_RTMP=`$PKGCONFIG --cflags-only-I librtmp` + version=`$PKGCONFIG --modversion librtmp` + DIR_RTMP=`echo $LD_RTMP | $SED -e 's/^-L//'` + else + dnl To avoid link errors, we do not allow --librtmp without + dnl a pkgconfig file + AC_MSG_ERROR([--librtmp was specified but could not find librtmp pkgconfig file.]) + fi + + ;; + off) + dnl no --with-librtmp option given, just check default places + LIB_RTMP="-lrtmp" + ;; + *) + dnl use the given --with-librtmp spot + LIB_RTMP="-lrtmp" + PREFIX_RTMP=$OPT_LIBRTMP + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_RTMP"; then + LD_RTMP=-L${PREFIX_RTMP}/lib$libsuff + CPP_RTMP=-I${PREFIX_RTMP}/include + DIR_RTMP=${PREFIX_RTMP}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_RTMP" + CPPFLAGS="$CPPFLAGS $CPP_RTMP" + LIBS="$LIB_RTMP $LIBS" + + AC_CHECK_LIB(rtmp, RTMP_Init, + [ + AC_CHECK_HEADERS(librtmp/rtmp.h, + curl_rtmp_msg="enabled (librtmp)" + LIBRTMP_ENABLED=1 + AC_DEFINE(USE_LIBRTMP, 1, [if librtmp is in use]) + AC_SUBST(USE_LIBRTMP, [1]) + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) + + if test X"$OPT_LIBRTMP" != Xoff && + test "$LIBRTMP_ENABLED" != "1"; then + AC_MSG_ERROR([librtmp libs and/or directories were not found where specified!]) + fi + +fi + +dnl ********************************************************************** +dnl Check for linker switch for versioned symbols +dnl ********************************************************************** + +versioned_symbols_flavour= +AC_MSG_CHECKING([whether versioned symbols are wanted]) +AC_ARG_ENABLE(versioned-symbols, +AS_HELP_STRING([--enable-versioned-symbols], [Enable versioned symbols in shared library]) +AS_HELP_STRING([--disable-versioned-symbols], [Disable versioned symbols in shared library]), +[ case "$enableval" in + yes) AC_MSG_RESULT(yes) + AC_MSG_CHECKING([if libraries can be versioned]) + GLD=`$LD --help < /dev/null 2>/dev/null | grep version-script` + if test -z "$GLD"; then + AC_MSG_RESULT(no) + AC_MSG_WARN([You need an ld version supporting the --version-script option]) + else + AC_MSG_RESULT(yes) + if test "x$CURL_WITH_MULTI_SSL" = "x1"; then + versioned_symbols_flavour="MULTISSL_" + elif test "x$OPENSSL_ENABLED" = "x1"; then + versioned_symbols_flavour="OPENSSL_" + elif test "x$GNUTLS_ENABLED" = "x1"; then + versioned_symbols_flavour="GNUTLS_" + elif test "x$WOLFSSL_ENABLED" = "x1"; then + versioned_symbols_flavour="WOLFSSL_" + elif test "x$SCHANNEL_ENABLED" = "x1"; then + versioned_symbols_flavour="SCHANNEL_" + elif test "x$SECURETRANSPORT_ENABLED" = "x1"; then + versioned_symbols_flavour="SECURE_TRANSPORT_" + else + versioned_symbols_flavour="" + fi + versioned_symbols="yes" + fi + ;; + + *) AC_MSG_RESULT(no) + ;; + esac +], [ +AC_MSG_RESULT(no) +] +) + +AC_SUBST([CURL_LT_SHLIB_VERSIONED_FLAVOUR], + ["$versioned_symbols_flavour"]) +AM_CONDITIONAL([CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS], + [test "x$versioned_symbols" = 'xyes']) + +dnl Update .plist file with current version +AC_SUBST([CURL_PLIST_VERSION], + ["$CURLVERSION"]) + +dnl ------------------------------------------------- +dnl check winidn option before other IDN libraries +dnl ------------------------------------------------- + +AC_MSG_CHECKING([whether to enable Windows native IDN (Windows native builds only)]) +OPT_WINIDN="default" +AC_ARG_WITH(winidn, +AS_HELP_STRING([--with-winidn=PATH],[enable Windows native IDN]) +AS_HELP_STRING([--without-winidn], [disable Windows native IDN]), + OPT_WINIDN=$withval) +case "$OPT_WINIDN" in + no|default) + dnl --without-winidn option used or configure option not specified + want_winidn="no" + AC_MSG_RESULT([no]) + ;; + yes) + dnl --with-winidn option used without path + want_winidn="yes" + want_winidn_path="default" + AC_MSG_RESULT([yes]) + ;; + *) + dnl --with-winidn option used with path + want_winidn="yes" + want_winidn_path="$withval" + AC_MSG_RESULT([yes ($withval)]) + ;; +esac + +if test "$want_winidn" = "yes"; then + dnl winidn library support has been requested + clean_CFLAGS="$CFLAGS" + clean_CPPFLAGS="$CPPFLAGS" + clean_LDFLAGS="$LDFLAGS" + clean_LIBS="$LIBS" + WINIDN_LIBS="-lnormaliz" + WINIDN_CPPFLAGS="" + # + if test "$want_winidn_path" != "default"; then + dnl path has been specified + dnl pkg-config not available or provides no info + WINIDN_LDFLAGS="-L$want_winidn_path/lib$libsuff" + WINIDN_CPPFLAGS="-I$want_winidn_path/include" + WINIDN_DIR="$want_winidn_path/lib$libsuff" + fi + # + dnl WinIDN requires a minimum supported OS version of at least Vista (0x0600) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include + ]],[[ + #if (WINVER < 0x600) && (_WIN32_WINNT < 0x600) + #error + #endif + ]]) + ],[ + ],[ + CFLAGS=`echo $CFLAGS | $SED -e 's/-DWINVER=[[^ ]]*//g'` + CFLAGS=`echo $CFLAGS | $SED -e 's/-D_WIN32_WINNT=[[^ ]]*//g'` + CPPFLAGS=`echo $CPPFLAGS | $SED -e 's/-DWINVER=[[^ ]]*//g'` + CPPFLAGS=`echo $CPPFLAGS | $SED -e 's/-D_WIN32_WINNT=[[^ ]]*//g'` + WINIDN_CPPFLAGS="$WINIDN_CPPFLAGS -DWINVER=0x0600" + ]) + # + CPPFLAGS="$CPPFLAGS $WINIDN_CPPFLAGS" + LDFLAGS="$LDFLAGS $WINIDN_LDFLAGS" + LIBS="$WINIDN_LIBS $LIBS" + # + AC_MSG_CHECKING([if IdnToUnicode can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + #include + ]],[[ + IdnToUnicode(0, NULL, 0, NULL, 0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_winidn="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_winidn="no" + ]) + # + if test "$tst_links_winidn" = "yes"; then + AC_DEFINE(USE_WIN32_IDN, 1, [Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz).]) + AC_SUBST([IDN_ENABLED], [1]) + curl_idn_msg="enabled (Windows-native)" + else + AC_MSG_WARN([Cannot find libraries for IDN support: IDN disabled]) + CFLAGS="$clean_CFLAGS" + CPPFLAGS="$clean_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS" + LIBS="$clean_LIBS" + fi +fi + +dnl ********************************************************************** +dnl Check for the presence of IDN libraries and headers +dnl ********************************************************************** + +AC_MSG_CHECKING([whether to build with libidn2]) +OPT_IDN="default" +AC_ARG_WITH(libidn2, +AS_HELP_STRING([--with-libidn2=PATH],[Enable libidn2 usage]) +AS_HELP_STRING([--without-libidn2],[Disable libidn2 usage]), + [OPT_IDN=$withval]) +if test "x$tst_links_winidn" = "xyes"; then + want_idn="no" + AC_MSG_RESULT([no (using winidn instead)]) +else + case "$OPT_IDN" in + no) + dnl --without-libidn2 option used + want_idn="no" + AC_MSG_RESULT([no]) + ;; + default) + dnl configure option not specified + want_idn="yes" + want_idn_path="default" + AC_MSG_RESULT([(assumed) yes]) + ;; + yes) + dnl --with-libidn2 option used without path + want_idn="yes" + want_idn_path="default" + AC_MSG_RESULT([yes]) + ;; + *) + dnl --with-libidn2 option used with path + want_idn="yes" + want_idn_path="$withval" + AC_MSG_RESULT([yes ($withval)]) + ;; + esac +fi + +if test "$want_idn" = "yes"; then + dnl idn library support has been requested + clean_CPPFLAGS="$CPPFLAGS" + clean_LDFLAGS="$LDFLAGS" + clean_LIBS="$LIBS" + PKGCONFIG="no" + # + if test "$want_idn_path" != "default"; then + dnl path has been specified + IDN_PCDIR="$want_idn_path/lib$libsuff/pkgconfig" + CURL_CHECK_PKGCONFIG(libidn2, [$IDN_PCDIR]) + if test "$PKGCONFIG" != "no"; then + IDN_LIBS=`CURL_EXPORT_PCDIR([$IDN_PCDIR]) dnl + $PKGCONFIG --libs-only-l libidn2 2>/dev/null` + IDN_LDFLAGS=`CURL_EXPORT_PCDIR([$IDN_PCDIR]) dnl + $PKGCONFIG --libs-only-L libidn2 2>/dev/null` + IDN_CPPFLAGS=`CURL_EXPORT_PCDIR([$IDN_PCDIR]) dnl + $PKGCONFIG --cflags-only-I libidn2 2>/dev/null` + IDN_DIR=`echo $IDN_LDFLAGS | $SED -e 's/^-L//'` + else + dnl pkg-config not available or provides no info + IDN_LIBS="-lidn2" + IDN_LDFLAGS="-L$want_idn_path/lib$libsuff" + IDN_CPPFLAGS="-I$want_idn_path/include" + IDN_DIR="$want_idn_path/lib$libsuff" + fi + else + dnl path not specified + CURL_CHECK_PKGCONFIG(libidn2) + if test "$PKGCONFIG" != "no"; then + IDN_LIBS=`$PKGCONFIG --libs-only-l libidn2 2>/dev/null` + IDN_LDFLAGS=`$PKGCONFIG --libs-only-L libidn2 2>/dev/null` + IDN_CPPFLAGS=`$PKGCONFIG --cflags-only-I libidn2 2>/dev/null` + IDN_DIR=`echo $IDN_LDFLAGS | $SED -e 's/^-L//'` + else + dnl pkg-config not available or provides no info + IDN_LIBS="-lidn2" + fi + fi + # + if test "$PKGCONFIG" != "no"; then + AC_MSG_NOTICE([pkg-config: IDN_LIBS: "$IDN_LIBS"]) + AC_MSG_NOTICE([pkg-config: IDN_LDFLAGS: "$IDN_LDFLAGS"]) + AC_MSG_NOTICE([pkg-config: IDN_CPPFLAGS: "$IDN_CPPFLAGS"]) + AC_MSG_NOTICE([pkg-config: IDN_DIR: "$IDN_DIR"]) + else + AC_MSG_NOTICE([IDN_LIBS: "$IDN_LIBS"]) + AC_MSG_NOTICE([IDN_LDFLAGS: "$IDN_LDFLAGS"]) + AC_MSG_NOTICE([IDN_CPPFLAGS: "$IDN_CPPFLAGS"]) + AC_MSG_NOTICE([IDN_DIR: "$IDN_DIR"]) + fi + # + CPPFLAGS="$CPPFLAGS $IDN_CPPFLAGS" + LDFLAGS="$LDFLAGS $IDN_LDFLAGS" + LIBS="$IDN_LIBS $LIBS" + # + AC_MSG_CHECKING([if idn2_lookup_ul can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([idn2_lookup_ul]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_libidn="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_libidn="no" + ]) + # + AC_CHECK_HEADERS( idn2.h ) + + if test "$tst_links_libidn" = "yes"; then + AC_DEFINE(HAVE_LIBIDN2, 1, [Define to 1 if you have the `idn2' library (-lidn2).]) + dnl different versions of libidn have different setups of these: + + AC_SUBST([IDN_ENABLED], [1]) + curl_idn_msg="enabled (libidn2)" + if test -n "$IDN_DIR" -a "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$IDN_DIR" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $IDN_DIR to CURL_LIBRARY_PATH]) + fi + else + AC_MSG_WARN([Cannot find libraries for IDN support: IDN disabled]) + CPPFLAGS="$clean_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS" + LIBS="$clean_LIBS" + fi +fi + +dnl ********************************************************************** +dnl Check for nghttp2 +dnl ********************************************************************** + +OPT_H2="yes" + +if test "x$disable_http" = "xyes" -o X"$want_hyper" != Xno; then + # without HTTP or with Hyper, nghttp2 is no use + OPT_H2="no" +fi + +AC_ARG_WITH(nghttp2, +AS_HELP_STRING([--with-nghttp2=PATH],[Enable nghttp2 usage]) +AS_HELP_STRING([--without-nghttp2],[Disable nghttp2 usage]), + [OPT_H2=$withval]) +case "$OPT_H2" in + no) + dnl --without-nghttp2 option used + want_nghttp2="no" + ;; + yes) + dnl --with-nghttp2 option used without path + want_nghttp2="default" + want_nghttp2_path="" + want_nghttp2_pkg_config_path="" + ;; + *) + dnl --with-nghttp2 option used with path + want_nghttp2="yes" + want_nghttp2_path="$withval" + want_nghttp2_pkg_config_path="$withval/lib/pkgconfig" + ;; +esac + +if test X"$want_nghttp2" != Xno; then + dnl backup the pre-nghttp2 variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(libnghttp2, $want_nghttp2_pkg_config_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_H2=`CURL_EXPORT_PCDIR([$want_nghttp2_pkg_config_path]) + $PKGCONFIG --libs-only-l libnghttp2` + AC_MSG_NOTICE([-l is $LIB_H2]) + + CPP_H2=`CURL_EXPORT_PCDIR([$want_nghttp2_pkg_config_path]) dnl + $PKGCONFIG --cflags-only-I libnghttp2` + AC_MSG_NOTICE([-I is $CPP_H2]) + + LD_H2=`CURL_EXPORT_PCDIR([$want_nghttp2_pkg_config_path]) + $PKGCONFIG --libs-only-L libnghttp2` + AC_MSG_NOTICE([-L is $LD_H2]) + + DIR_H2=`echo $LD_H2 | $SED -e 's/^-L//'` + elif test x"$want_nghttp2_path" != x; then + LIB_H2="-lnghttp2" + LD_H2=-L${want_nghttp2_path}/lib$libsuff + CPP_H2=-I${want_nghttp2_path}/include + DIR_H2=${want_nghttp2_path}/lib$libsuff + elif test X"$want_nghttp2" != Xdefault; then + dnl no nghttp2 pkg-config found and no custom directory specified, + dnl deal with it + AC_MSG_ERROR([--with-nghttp2 was specified but could not find libnghttp2 pkg-config file.]) + else + LIB_H2="-lnghttp2" + fi + + LDFLAGS="$LDFLAGS $LD_H2" + CPPFLAGS="$CPPFLAGS $CPP_H2" + LIBS="$LIB_H2 $LIBS" + + # use nghttp2_session_get_stream_local_window_size to require nghttp2 + # >= 1.15.0 + AC_CHECK_LIB(nghttp2, nghttp2_session_get_stream_local_window_size, + [ + AC_CHECK_HEADERS(nghttp2/nghttp2.h, + curl_h2_msg="enabled (nghttp2)" + NGHTTP2_ENABLED=1 + AC_DEFINE(USE_NGHTTP2, 1, [if nghttp2 is in use]) + AC_SUBST(USE_NGHTTP2, [1]) + ) + + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_H2" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_H2 to CURL_LIBRARY_PATH]) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) +fi + +dnl ********************************************************************** +dnl Check for ngtcp2 (QUIC) +dnl ********************************************************************** + +OPT_TCP2="no" + +if test "x$disable_http" = "xyes"; then + # without HTTP, ngtcp2 is no use + OPT_TCP2="no" +fi + +AC_ARG_WITH(ngtcp2, +AS_HELP_STRING([--with-ngtcp2=PATH],[Enable ngtcp2 usage]) +AS_HELP_STRING([--without-ngtcp2],[Disable ngtcp2 usage]), + [OPT_TCP2=$withval]) +case "$OPT_TCP2" in + no) + dnl --without-ngtcp2 option used + want_tcp2="no" + ;; + yes) + dnl --with-ngtcp2 option used without path + want_tcp2="default" + want_tcp2_path="" + ;; + *) + dnl --with-ngtcp2 option used with path + want_tcp2="yes" + want_tcp2_path="$withval/lib/pkgconfig" + ;; +esac + +curl_tcp2_msg="no (--with-ngtcp2)" +if test X"$want_tcp2" != Xno; then + + if test "$QUIC_ENABLED" != "yes"; then + AC_MSG_ERROR([the detected TLS library does not support QUIC, making --with-ngtcp2 a no-no]) + fi + + dnl backup the pre-ngtcp2 variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(libngtcp2, $want_tcp2_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_TCP2=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-l libngtcp2` + AC_MSG_NOTICE([-l is $LIB_TCP2]) + + CPP_TCP2=`CURL_EXPORT_PCDIR([$want_tcp2_path]) dnl + $PKGCONFIG --cflags-only-I libngtcp2` + AC_MSG_NOTICE([-I is $CPP_TCP2]) + + LD_TCP2=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-L libngtcp2` + AC_MSG_NOTICE([-L is $LD_TCP2]) + + LDFLAGS="$LDFLAGS $LD_TCP2" + CPPFLAGS="$CPPFLAGS $CPP_TCP2" + LIBS="$LIB_TCP2 $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_TCP2=`echo $LD_TCP2 | $SED -e 's/^-L//'` + fi + AC_CHECK_LIB(ngtcp2, ngtcp2_conn_client_new_versioned, + [ + AC_CHECK_HEADERS(ngtcp2/ngtcp2.h, + NGTCP2_ENABLED=1 + AC_DEFINE(USE_NGTCP2, 1, [if ngtcp2 is in use]) + AC_SUBST(USE_NGTCP2, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_TCP2" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_TCP2 to CURL_LIBRARY_PATH]) + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) + + else + dnl no ngtcp2 pkg-config found, deal with it + if test X"$want_tcp2" != Xdefault; then + dnl To avoid link errors, we do not allow --with-ngtcp2 without + dnl a pkgconfig file + AC_MSG_ERROR([--with-ngtcp2 was specified but could not find ngtcp2 pkg-config file.]) + fi + fi + +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$OPENSSL_ENABLED" = "x1" -a "x$OPENSSL_IS_BORINGSSL" != "x1"; then + dnl backup the pre-ngtcp2_crypto_quictls variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(libngtcp2_crypto_quictls, $want_tcp2_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_QUICTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-l libngtcp2_crypto_quictls` + AC_MSG_NOTICE([-l is $LIB_NGTCP2_CRYPTO_QUICTLS]) + + CPP_NGTCP2_CRYPTO_QUICTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path]) dnl + $PKGCONFIG --cflags-only-I libngtcp2_crypto_quictls` + AC_MSG_NOTICE([-I is $CPP_NGTCP2_CRYPTO_QUICTLS]) + + LD_NGTCP2_CRYPTO_QUICTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-L libngtcp2_crypto_quictls` + AC_MSG_NOTICE([-L is $LD_NGTCP2_CRYPTO_QUICTLS]) + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_QUICTLS" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_QUICTLS" + LIBS="$LIB_NGTCP2_CRYPTO_QUICTLS $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_QUICTLS=`echo $LD_NGTCP2_CRYPTO_QUICTLS | $SED -e 's/^-L//'` + fi + AC_CHECK_LIB(ngtcp2_crypto_quictls, ngtcp2_crypto_recv_client_initial_cb, + [ + AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h, + NGTCP2_ENABLED=1 + AC_DEFINE(USE_NGTCP2_CRYPTO_QUICTLS, 1, [if ngtcp2_crypto_quictls is in use]) + AC_SUBST(USE_NGTCP2_CRYPTO_QUICTLS, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_QUICTLS" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH]) + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) + + else + dnl no ngtcp2_crypto_quictls pkg-config found, deal with it + if test X"$want_tcp2" != Xdefault; then + dnl To avoid link errors, we do not allow --with-ngtcp2 without + dnl a pkgconfig file + AC_MSG_ERROR([--with-ngtcp2 was specified but could not find ngtcp2_crypto_quictls pkg-config file.]) + fi + fi +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$OPENSSL_ENABLED" = "x1" -a "x$OPENSSL_IS_BORINGSSL" = "x1"; then + dnl backup the pre-ngtcp2_crypto_boringssl variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(libngtcp2_crypto_boringssl, $want_tcp2_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_BORINGSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-l libngtcp2_crypto_boringssl` + AC_MSG_NOTICE([-l is $LIB_NGTCP2_CRYPTO_BORINGSSL]) + + CPP_NGTCP2_CRYPTO_BORINGSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path]) dnl + $PKGCONFIG --cflags-only-I libngtcp2_crypto_boringssl` + AC_MSG_NOTICE([-I is $CPP_NGTCP2_CRYPTO_BORINGSSL]) + + LD_NGTCP2_CRYPTO_BORINGSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-L libngtcp2_crypto_boringssl` + AC_MSG_NOTICE([-L is $LD_NGTCP2_CRYPTO_BORINGSSL]) + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_BORINGSSL" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_BORINGSSL" + LIBS="$LIB_NGTCP2_CRYPTO_BORINGSSL $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_BORINGSSL=`echo $LD_NGTCP2_CRYPTO_BORINGSSL | $SED -e 's/^-L//'` + fi + AC_CHECK_LIB(ngtcp2_crypto_boringssl, ngtcp2_crypto_recv_client_initial_cb, + [ + AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h, + NGTCP2_ENABLED=1 + AC_DEFINE(USE_NGTCP2_CRYPTO_BORINGSSL, 1, [if ngtcp2_crypto_boringssl is in use]) + AC_SUBST(USE_NGTCP2_CRYPTO_BORINGSSL, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_BORINGSSL" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH]) + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) + + else + dnl no ngtcp2_crypto_boringssl pkg-config found, deal with it + if test X"$want_tcp2" != Xdefault; then + dnl To avoid link errors, we do not allow --with-ngtcp2 without + dnl a pkgconfig file + AC_MSG_ERROR([--with-ngtcp2 was specified but could not find ngtcp2_crypto_boringssl pkg-config file.]) + fi + fi +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$GNUTLS_ENABLED" = "x1"; then + dnl backup the pre-ngtcp2_crypto_gnutls variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(libngtcp2_crypto_gnutls, $want_tcp2_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_GNUTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-l libngtcp2_crypto_gnutls` + AC_MSG_NOTICE([-l is $LIB_NGTCP2_CRYPTO_GNUTLS]) + + CPP_NGTCP2_CRYPTO_GNUTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path]) dnl + $PKGCONFIG --cflags-only-I libngtcp2_crypto_gnutls` + AC_MSG_NOTICE([-I is $CPP_NGTCP2_CRYPTO_GNUTLS]) + + LD_NGTCP2_CRYPTO_GNUTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-L libngtcp2_crypto_gnutls` + AC_MSG_NOTICE([-L is $LD_NGTCP2_CRYPTO_GNUTLS]) + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_GNUTLS" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_GNUTLS" + LIBS="$LIB_NGTCP2_CRYPTO_GNUTLS $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_GNUTLS=`echo $LD_NGTCP2_CRYPTO_GNUTLS | $SED -e 's/^-L//'` + fi + AC_CHECK_LIB(ngtcp2_crypto_gnutls, ngtcp2_crypto_recv_client_initial_cb, + [ + AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h, + NGTCP2_ENABLED=1 + AC_DEFINE(USE_NGTCP2_CRYPTO_GNUTLS, 1, [if ngtcp2_crypto_gnutls is in use]) + AC_SUBST(USE_NGTCP2_CRYPTO_GNUTLS, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_GNUTLS" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH]) + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) + + else + dnl no ngtcp2_crypto_gnutls pkg-config found, deal with it + if test X"$want_tcp2" != Xdefault; then + dnl To avoid link errors, we do not allow --with-ngtcp2 without + dnl a pkgconfig file + AC_MSG_ERROR([--with-ngtcp2 was specified but could not find ngtcp2_crypto_gnutls pkg-config file.]) + fi + fi +fi + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$WOLFSSL_ENABLED" = "x1"; then + dnl backup the pre-ngtcp2_crypto_wolfssl variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(libngtcp2_crypto_wolfssl, $want_tcp2_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_NGTCP2_CRYPTO_WOLFSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-l libngtcp2_crypto_wolfssl` + AC_MSG_NOTICE([-l is $LIB_NGTCP2_CRYPTO_WOLFSSL]) + + CPP_NGTCP2_CRYPTO_WOLFSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path]) dnl + $PKGCONFIG --cflags-only-I libngtcp2_crypto_wolfssl` + AC_MSG_NOTICE([-I is $CPP_NGTCP2_CRYPTO_WOLFSSL]) + + LD_NGTCP2_CRYPTO_WOLFSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path]) + $PKGCONFIG --libs-only-L libngtcp2_crypto_wolfssl` + AC_MSG_NOTICE([-L is $LD_NGTCP2_CRYPTO_WOLFSSL]) + + LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_WOLFSSL" + CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_WOLFSSL" + LIBS="$LIB_NGTCP2_CRYPTO_WOLFSSL $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGTCP2_CRYPTO_WOLFSSL=`echo $LD_NGTCP2_CRYPTO_WOLFSSL | $SED -e 's/^-L//'` + fi + AC_CHECK_LIB(ngtcp2_crypto_wolfssl, ngtcp2_crypto_recv_client_initial_cb, + [ + AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h, + NGTCP2_ENABLED=1 + AC_DEFINE(USE_NGTCP2_CRYPTO_WOLFSSL, 1, [if ngtcp2_crypto_wolfssl is in use]) + AC_SUBST(USE_NGTCP2_CRYPTO_WOLFSSL, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_WOLFSSL" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH]) + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) + + else + dnl no ngtcp2_crypto_wolfssl pkg-config found, deal with it + if test X"$want_tcp2" != Xdefault; then + dnl To avoid link errors, we do not allow --with-ngtcp2 without + dnl a pkgconfig file + AC_MSG_ERROR([--with-ngtcp2 was specified but could not find ngtcp2_crypto_wolfssl pkg-config file.]) + fi + fi +fi + +dnl ********************************************************************** +dnl Check for OpenSSL QUIC +dnl ********************************************************************** + +OPT_OPENSSL_QUIC="no" + +if test "x$disable_http" = "xyes" -o "x$OPENSSL_ENABLED" != "x1"; then + # without HTTP or without openssl, no use + OPT_OPENSSL_QUIC="no" +fi + +AC_ARG_WITH(openssl-quic, +AS_HELP_STRING([--with-openssl-quic],[Enable OpenSSL QUIC usage]) +AS_HELP_STRING([--without-openssl-quic],[Disable OpenSSL QUIC usage]), + [OPT_OPENSSL_QUIC=$withval]) +case "$OPT_OPENSSL_QUIC" in + no) + dnl --without-openssl-quic option used + want_openssl_quic="no" + ;; + yes) + dnl --with-openssl-quic option used + want_openssl_quic="yes" + ;; +esac + +curl_openssl_quic_msg="no (--with-openssl-quic)" +if test "x$want_openssl_quic" = "xyes"; then + + if test "$NGTCP2_ENABLED" = 1; then + AC_MSG_ERROR([--with-openssl-quic and --with-ngtcp2 are mutually exclusive]) + fi + if test "$HAVE_OPENSSL_QUIC" != 1; then + AC_MSG_ERROR([--with-openssl-quic requires quic support in OpenSSL]) + fi + AC_DEFINE(USE_OPENSSL_QUIC, 1, [if openssl QUIC is in use]) + AC_SUBST(USE_OPENSSL_QUIC, [1]) +fi + +dnl ********************************************************************** +dnl Check for nghttp3 (HTTP/3 with ngtcp2) +dnl ********************************************************************** + +OPT_NGHTTP3="yes" + +if test "x$USE_NGTCP2" = "x" -a "$USE_OPENSSL_QUIC" = "x"; then + # without ngtcp2 or openssl quic, nghttp3 is of no use for us + OPT_NGHTTP3="no" +fi + +AC_ARG_WITH(nghttp3, +AS_HELP_STRING([--with-nghttp3=PATH],[Enable nghttp3 usage]) +AS_HELP_STRING([--without-nghttp3],[Disable nghttp3 usage]), + [OPT_NGHTTP3=$withval]) +case "$OPT_NGHTTP3" in + no) + dnl --without-nghttp3 option used + want_nghttp3="no" + ;; + yes) + dnl --with-nghttp3 option used without path + want_nghttp3="default" + want_nghttp3_path="" + ;; + *) + dnl --with-nghttp3 option used with path + want_nghttp3="yes" + want_nghttp3_path="$withval/lib/pkgconfig" + ;; +esac + +curl_http3_msg="no (--with-nghttp3)" +if test X"$want_nghttp3" != Xno; then + + dnl backup the pre-nghttp3 variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(libnghttp3, $want_nghttp3_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_NGHTTP3=`CURL_EXPORT_PCDIR([$want_nghttp3_path]) + $PKGCONFIG --libs-only-l libnghttp3` + AC_MSG_NOTICE([-l is $LIB_NGHTTP3]) + + CPP_NGHTTP3=`CURL_EXPORT_PCDIR([$want_nghttp3_path]) dnl + $PKGCONFIG --cflags-only-I libnghttp3` + AC_MSG_NOTICE([-I is $CPP_NGHTTP3]) + + LD_NGHTTP3=`CURL_EXPORT_PCDIR([$want_nghttp3_path]) + $PKGCONFIG --libs-only-L libnghttp3` + AC_MSG_NOTICE([-L is $LD_NGHTTP3]) + + LDFLAGS="$LDFLAGS $LD_NGHTTP3" + CPPFLAGS="$CPPFLAGS $CPP_NGHTTP3" + LIBS="$LIB_NGHTTP3 $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_NGHTTP3=`echo $LD_NGHTTP3 | $SED -e 's/^-L//'` + fi + AC_CHECK_LIB(nghttp3, nghttp3_conn_client_new_versioned, + [ + AC_CHECK_HEADERS(nghttp3/nghttp3.h, + AC_DEFINE(USE_NGHTTP3, 1, [if nghttp3 is in use]) + AC_SUBST(USE_NGHTTP3, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGHTTP3" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH]) + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) + + else + dnl no nghttp3 pkg-config found, deal with it + if test X"$want_nghttp3" != Xdefault; then + dnl To avoid link errors, we do not allow --with-nghttp3 without + dnl a pkgconfig file + AC_MSG_ERROR([--with-nghttp3 was specified but could not find nghttp3 pkg-config file.]) + fi + fi + +fi + +dnl ********************************************************************** +dnl Check for ngtcp2 and nghttp3 (HTTP/3 with ngtcp2 + nghttp3) +dnl ********************************************************************** + +if test "x$NGTCP2_ENABLED" = "x1" -a "x$USE_NGHTTP3" = "x1"; then + AC_DEFINE(USE_NGTCP2_H3, 1, [if ngtcp2 + nghttp3 is in use]) + AC_SUBST(USE_NGTCP2_H3, [1]) + AC_MSG_NOTICE([HTTP3 support is experimental]) + curl_h3_msg="enabled (ngtcp2 + nghttp3)" +fi + +dnl ********************************************************************** +dnl Check for OpenSSL and nghttp3 (HTTP/3 with nghttp3 using OpenSSL QUIC) +dnl ********************************************************************** + +if test "x$USE_OPENSSL_QUIC" = "x1" -a "x$USE_NGHTTP3" = "x1"; then + experimental="$experimental HTTP3" + AC_DEFINE(USE_OPENSSL_H3, 1, [if openssl quic + nghttp3 is in use]) + AC_SUBST(USE_OPENSSL_H3, [1]) + AC_MSG_NOTICE([HTTP3 support is experimental]) + curl_h3_msg="enabled (openssl + nghttp3)" +fi + +dnl ********************************************************************** +dnl Check for quiche (QUIC) +dnl ********************************************************************** + +OPT_QUICHE="no" + +if test "x$disable_http" = "xyes" -o "x$USE_NGTCP" = "x1"; then + # without HTTP or with ngtcp2, quiche is no use + OPT_QUICHE="no" +fi + +AC_ARG_WITH(quiche, +AS_HELP_STRING([--with-quiche=PATH],[Enable quiche usage]) +AS_HELP_STRING([--without-quiche],[Disable quiche usage]), + [OPT_QUICHE=$withval]) +case "$OPT_QUICHE" in + no) + dnl --without-quiche option used + want_quiche="no" + ;; + yes) + dnl --with-quiche option used without path + want_quiche="default" + want_quiche_path="" + ;; + *) + dnl --with-quiche option used with path + want_quiche="yes" + want_quiche_path="$withval" + ;; +esac + +if test X"$want_quiche" != Xno; then + + if test "$QUIC_ENABLED" != "yes"; then + AC_MSG_ERROR([the detected TLS library does not support QUIC, making --with-quiche a no-no]) + fi + + if test "$NGHTTP3_ENABLED" = 1; then + AC_MSG_ERROR([--with-quiche and --with-ngtcp2 are mutually exclusive]) + fi + + dnl backup the pre-quiche variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + CURL_CHECK_PKGCONFIG(quiche, $want_quiche_path) + + if test "$PKGCONFIG" != "no" ; then + LIB_QUICHE=`CURL_EXPORT_PCDIR([$want_quiche_path]) + $PKGCONFIG --libs-only-l quiche` + AC_MSG_NOTICE([-l is $LIB_QUICHE]) + + CPP_QUICHE=`CURL_EXPORT_PCDIR([$want_quiche_path]) dnl + $PKGCONFIG --cflags-only-I quiche` + AC_MSG_NOTICE([-I is $CPP_QUICHE]) + + LD_QUICHE=`CURL_EXPORT_PCDIR([$want_quiche_path]) + $PKGCONFIG --libs-only-L quiche` + AC_MSG_NOTICE([-L is $LD_QUICHE]) + + LDFLAGS="$LDFLAGS $LD_QUICHE" + CPPFLAGS="$CPPFLAGS $CPP_QUICHE" + LIBS="$LIB_QUICHE $LIBS" + + if test "x$cross_compiling" != "xyes"; then + DIR_QUICHE=`echo $LD_QUICHE | $SED -e 's/^-L//'` + fi + AC_CHECK_LIB(quiche, quiche_conn_send_ack_eliciting, + [ + AC_CHECK_HEADERS(quiche.h, + experimental="$experimental HTTP3" + AC_MSG_NOTICE([HTTP3 support is experimental]) + curl_h3_msg="enabled (quiche)" + QUICHE_ENABLED=1 + AC_DEFINE(USE_QUICHE, 1, [if quiche is in use]) + AC_SUBST(USE_QUICHE, [1]) + AC_CHECK_FUNCS([quiche_conn_set_qlog_fd]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_QUICHE" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_QUICHE to CURL_LIBRARY_PATH]), + [], + [ +AC_INCLUDES_DEFAULT +#include + ] + ) + ], + dnl not found, revert back to clean variables + AC_MSG_ERROR([couldn't use quiche]) + ) + else + dnl no quiche pkg-config found, deal with it + if test X"$want_quiche" != Xdefault; then + dnl To avoid link errors, we do not allow --with-quiche without + dnl a pkgconfig file + AC_MSG_ERROR([--with-quiche was specified but could not find quiche pkg-config file.]) + fi + fi +fi + +dnl ********************************************************************** +dnl Check for msh3 (QUIC) +dnl ********************************************************************** + +OPT_MSH3="no" + +if test "x$disable_http" = "xyes" -o "x$USE_NGTCP" = "x1"; then + # without HTTP or with ngtcp2, msh3 is no use + OPT_MSH3="no" +fi + +AC_ARG_WITH(msh3, +AS_HELP_STRING([--with-msh3=PATH],[Enable msh3 usage]) +AS_HELP_STRING([--without-msh3],[Disable msh3 usage]), + [OPT_MSH3=$withval]) +case "$OPT_MSH3" in + no) + dnl --without-msh3 option used + want_msh3="no" + ;; + yes) + dnl --with-msh3 option used without path + want_msh3="default" + want_msh3_path="" + ;; + *) + dnl --with-msh3 option used with path + want_msh3="yes" + want_msh3_path="$withval" + ;; +esac + +if test X"$want_msh3" != Xno; then + + dnl msh3 on non-Windows needs an OpenSSL with the QUIC API + if test "$curl_cv_native_windows" != "yes"; then + if test "$QUIC_ENABLED" != "yes"; then + AC_MSG_ERROR([the detected TLS library does not support QUIC, making --with-msh3 a no-no]) + fi + if test "$OPENSSL_ENABLED" != "1"; then + AC_MSG_ERROR([msh3 requires OpenSSL]) + fi + fi + + if test "$NGHTTP3_ENABLED" = 1; then + AC_MSG_ERROR([--with-msh3 and --with-ngtcp2 are mutually exclusive]) + fi + if test "$QUICHE_ENABLED" = 1; then + AC_MSG_ERROR([--with-msh3 and --with-quiche are mutually exclusive]) + fi + + dnl backup the pre-msh3 variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + if test -n "$want_msh3_path"; then + LD_MSH3="-L$want_msh3_path/lib" + CPP_MSH3="-I$want_msh3_path/include" + DIR_MSH3="$want_msh3_path/lib" + LDFLAGS="$LDFLAGS $LD_MSH3" + CPPFLAGS="$CPPFLAGS $CPP_MSH3" + fi + LIBS="-lmsh3 $LIBS" + + AC_CHECK_LIB(msh3, MsH3ApiOpen, + [ + AC_CHECK_HEADERS(msh3.h, + curl_h3_msg="enabled (msh3)" + MSH3_ENABLED=1 + AC_DEFINE(USE_MSH3, 1, [if msh3 is in use]) + AC_SUBST(USE_MSH3, [1]) + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_MSH3" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_MSH3 to CURL_LIBRARY_PATH]), + experimental="$experimental HTTP3" + ) + ], + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + ) +fi + +dnl ********************************************************************** +dnl Check for zsh completion path +dnl ********************************************************************** + +OPT_ZSH_FPATH=default +AC_ARG_WITH(zsh-functions-dir, +AS_HELP_STRING([--with-zsh-functions-dir=PATH],[Install zsh completions to PATH]) +AS_HELP_STRING([--without-zsh-functions-dir],[Do not install zsh completions]), + [OPT_ZSH_FPATH=$withval]) +case "$OPT_ZSH_FPATH" in + no) + dnl --without-zsh-functions-dir option used + ;; + default|yes) + dnl --with-zsh-functions-dir option used without path + ZSH_FUNCTIONS_DIR="$datarootdir/zsh/site-functions" + AC_SUBST(ZSH_FUNCTIONS_DIR) + ;; + *) + dnl --with-zsh-functions-dir option used with path + ZSH_FUNCTIONS_DIR="$withval" + AC_SUBST(ZSH_FUNCTIONS_DIR) + ;; +esac + +dnl ********************************************************************** +dnl Check for fish completion path +dnl ********************************************************************** + +OPT_FISH_FPATH=default +AC_ARG_WITH(fish-functions-dir, +AS_HELP_STRING([--with-fish-functions-dir=PATH],[Install fish completions to PATH]) +AS_HELP_STRING([--without-fish-functions-dir],[Do not install fish completions]), + [OPT_FISH_FPATH=$withval]) +case "$OPT_FISH_FPATH" in + no) + dnl --without-fish-functions-dir option used + ;; + default|yes) + dnl --with-fish-functions-dir option used without path + CURL_CHECK_PKGCONFIG(fish) + if test "$PKGCONFIG" != "no" ; then + FISH_FUNCTIONS_DIR="$($PKGCONFIG --variable completionsdir fish)" + else + FISH_FUNCTIONS_DIR="$datarootdir/fish/vendor_completions.d" + fi + AC_SUBST(FISH_FUNCTIONS_DIR) + ;; + *) + dnl --with-fish-functions-dir option used with path + FISH_FUNCTIONS_DIR="$withval" + AC_SUBST(FISH_FUNCTIONS_DIR) + ;; +esac + +dnl Now check for the very most basic headers. Then we can use these +dnl ones as default-headers when checking for the rest! +AC_CHECK_HEADERS( + sys/types.h \ + sys/time.h \ + sys/select.h \ + sys/socket.h \ + sys/ioctl.h \ + unistd.h \ + stdlib.h \ + arpa/inet.h \ + net/if.h \ + netinet/in.h \ + netinet/in6.h \ + sys/un.h \ + linux/tcp.h \ + netinet/tcp.h \ + netinet/udp.h \ + netdb.h \ + sys/sockio.h \ + sys/stat.h \ + sys/param.h \ + termios.h \ + termio.h \ + fcntl.h \ + io.h \ + pwd.h \ + utime.h \ + sys/utime.h \ + sys/poll.h \ + poll.h \ + socket.h \ + sys/resource.h \ + libgen.h \ + locale.h \ + stdbool.h \ + sys/filio.h \ + sys/wait.h \ + setjmp.h, +dnl to do if not found +[], +dnl to do if found +[], +dnl default includes +[ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +] +) + + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T + +CURL_CHECK_STRUCT_TIMEVAL +CURL_VERIFY_RUNTIMELIBS + +CURL_SIZEOF(size_t) +CURL_SIZEOF(long) +CURL_SIZEOF(int) +CURL_SIZEOF(time_t) +CURL_SIZEOF(off_t) + +o=$CPPFLAGS +CPPFLAGS="-I$srcdir/include $CPPFLAGS" +CURL_SIZEOF(curl_off_t, [ +#include +]) +CURL_SIZEOF(curl_socket_t, [ +#include +]) +CPPFLAGS=$o + +AC_CHECK_TYPE(long long, + [AC_DEFINE(HAVE_LONGLONG, 1, + [Define to 1 if the compiler supports the 'long long' data type.])] + longlong="yes" +) + +if test ${ac_cv_sizeof_curl_off_t} -lt 8; then + AC_MSG_ERROR([64 bit curl_off_t is required]) +fi + +# check for ssize_t +AC_CHECK_TYPE(ssize_t, , + AC_DEFINE(ssize_t, int, [the signed version of size_t])) + +# check for bool type +AC_CHECK_TYPE([bool],[ + AC_DEFINE(HAVE_BOOL_T, 1, + [Define to 1 if bool is an available type.]) +], ,[ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_STDBOOL_H +#include +#endif +]) + +# check for sa_family_t +AC_CHECK_TYPE(sa_family_t, + AC_DEFINE(CURL_SA_FAMILY_T, sa_family_t, [IP address type in sockaddr]), + [ + # The windows name? + AC_CHECK_TYPE(ADDRESS_FAMILY, + AC_DEFINE(CURL_SA_FAMILY_T, ADDRESS_FAMILY, [IP address type in sockaddr]), + AC_DEFINE(CURL_SA_FAMILY_T, unsigned short, [IP address type in sockaddr]), + [ +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + ]) + ], +[ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +]) + +# check for suseconds_t +AC_CHECK_TYPE([suseconds_t],[ + AC_DEFINE(HAVE_SUSECONDS_T, 1, + [Define to 1 if suseconds_t is an available type.]) +], ,[ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +]) + +AC_MSG_CHECKING([if time_t is unsigned]) +CURL_RUN_IFELSE( + [ + #include + #include + int main(void) { + time_t t = -1; + return (t < 0); + } + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_TIME_T_UNSIGNED, 1, [Define this if time_t is unsigned]) +],[ + AC_MSG_RESULT([no]) +],[ + dnl cross-compiling, most systems are unsigned + AC_MSG_RESULT([no]) +]) + +TYPE_IN_ADDR_T + +TYPE_SOCKADDR_STORAGE + +CURL_CHECK_FUNC_SELECT + +CURL_CHECK_FUNC_RECV +CURL_CHECK_FUNC_SEND +CURL_CHECK_MSG_NOSIGNAL + +CURL_CHECK_FUNC_ALARM +CURL_CHECK_FUNC_BASENAME +CURL_CHECK_FUNC_CLOSESOCKET +CURL_CHECK_FUNC_CLOSESOCKET_CAMEL +CURL_CHECK_FUNC_FCNTL +CURL_CHECK_FUNC_FREEADDRINFO +CURL_CHECK_FUNC_FSETXATTR +CURL_CHECK_FUNC_FTRUNCATE +CURL_CHECK_FUNC_GETADDRINFO +CURL_CHECK_FUNC_GETHOSTBYNAME +CURL_CHECK_FUNC_GETHOSTBYNAME_R +CURL_CHECK_FUNC_GETHOSTNAME +CURL_CHECK_FUNC_GETPEERNAME +CURL_CHECK_FUNC_GETSOCKNAME +CURL_CHECK_FUNC_IF_NAMETOINDEX +CURL_CHECK_FUNC_GETIFADDRS +CURL_CHECK_FUNC_GMTIME_R +CURL_CHECK_FUNC_INET_NTOP +CURL_CHECK_FUNC_INET_PTON +CURL_CHECK_FUNC_IOCTL +CURL_CHECK_FUNC_IOCTLSOCKET +CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL +CURL_CHECK_FUNC_MEMRCHR +CURL_CHECK_FUNC_POLL +CURL_CHECK_FUNC_SIGACTION +CURL_CHECK_FUNC_SIGINTERRUPT +CURL_CHECK_FUNC_SIGNAL +CURL_CHECK_FUNC_SIGSETJMP +CURL_CHECK_FUNC_SOCKET +CURL_CHECK_FUNC_SOCKETPAIR +CURL_CHECK_FUNC_STRCASECMP +CURL_CHECK_FUNC_STRCMPI +CURL_CHECK_FUNC_STRDUP +CURL_CHECK_FUNC_STRERROR_R +CURL_CHECK_FUNC_STRICMP +CURL_CHECK_FUNC_STRTOK_R +CURL_CHECK_FUNC_STRTOLL + +case $host in + *msdosdjgpp) + ac_cv_func_pipe=no + skipcheck_pipe=yes + AC_MSG_NOTICE([skip check for pipe on msdosdjgpp]) + ;; +esac + +AC_CHECK_DECLS([getpwuid_r], [], [AC_DEFINE(HAVE_DECL_GETPWUID_R_MISSING, 1, "Set if getpwuid_r() declaration is missing")], + [[#include + #include ]]) + +AC_CHECK_FUNCS([\ + _fseeki64 \ + arc4random \ + fnmatch \ + fseeko \ + geteuid \ + getpass_r \ + getppid \ + getpwuid \ + getpwuid_r \ + getrlimit \ + gettimeofday \ + if_nametoindex \ + mach_absolute_time \ + pipe \ + sched_yield \ + sendmsg \ + setlocale \ + setmode \ + setrlimit \ + snprintf \ + utime \ + utimes \ +],[ +],[ + func="$ac_func" + eval skipcheck=\$skipcheck_$func + if test "x$skipcheck" != "xyes"; then + AC_MSG_CHECKING([deeper for $func]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ + $func (); + ]]) + ],[ + AC_MSG_RESULT([yes]) + eval "ac_cv_func_$func=yes" + AC_DEFINE_UNQUOTED(XC_SH_TR_CPP([HAVE_$func]), [1], + [Define to 1 if you have the $func function.]) + ],[ + AC_MSG_RESULT([but still no]) + ]) + fi +]) + +dnl On Android, the only way to know if fseeko can be used is to see if it is +dnl declared or not (for this API level), as the symbol always exists in the +dnl lib. +AC_CHECK_DECL([fseeko], + [AC_DEFINE([HAVE_DECL_FSEEKO], [1], + [Define to 1 if you have the fseeko declaration])], + [], + [[#include ]]) + +CURL_CHECK_NONBLOCKING_SOCKET + +dnl ************************************************************ +dnl nroff tool stuff +dnl + +AC_PATH_PROG( PERL, perl, , + $PATH:/usr/local/bin/perl:/usr/bin/:/usr/local/bin ) +AC_SUBST(PERL) + +AC_PATH_PROGS( NROFF, gnroff nroff, , + $PATH:/usr/bin/:/usr/local/bin ) +AC_SUBST(NROFF) + +if test -n "$NROFF"; then + dnl only check for nroff options if an nroff command was found + + AC_MSG_CHECKING([how to use *nroff to get plain text from man pages]) + MANOPT="-man" + mancheck=`echo foo | $NROFF $MANOPT 2>/dev/null` + if test -z "$mancheck"; then + MANOPT="-mandoc" + mancheck=`echo foo | $NROFF $MANOPT 2>/dev/null` + if test -z "$mancheck"; then + MANOPT="" + AC_MSG_RESULT([failed]) + AC_MSG_WARN([found no *nroff option to get plaintext from man pages]) + else + AC_MSG_RESULT([$MANOPT]) + fi + else + AC_MSG_RESULT([$MANOPT]) + fi + AC_SUBST(MANOPT) +fi + +if test -z "$MANOPT" +then + dnl if no nroff tool was found, or no option that could convert man pages + dnl was found, then disable the built-in manual stuff + AC_MSG_WARN([disabling built-in manual]) + USE_MANUAL="no"; +fi + +dnl ************************************************************************* +dnl If the manual variable still is set, then we go with providing a built-in +dnl manual + +if test "$USE_MANUAL" = "1"; then + AC_DEFINE(USE_MANUAL, 1, [If you want to build curl with the built-in manual]) + curl_manual_msg="enabled" +fi + +dnl set variable for use in automakefile(s) +AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1) + +CURL_CHECK_LIB_ARES + +if test "x$curl_cv_native_windows" != "xyes" && + test "x$enable_shared" = "xyes"; then + build_libhostname=yes +else + build_libhostname=no +fi +AM_CONDITIONAL(BUILD_LIBHOSTNAME, test x$build_libhostname = xyes) + +if test "x$want_ares" != xyes; then + CURL_CHECK_OPTION_THREADED_RESOLVER +fi + +dnl ************************************************************ +dnl disable POSIX threads +dnl +AC_MSG_CHECKING([whether to use POSIX threads for threaded resolver]) +AC_ARG_ENABLE(pthreads, +AS_HELP_STRING([--enable-pthreads], + [Enable POSIX threads (default for threaded resolver)]) +AS_HELP_STRING([--disable-pthreads],[Disable POSIX threads]), +[ case "$enableval" in + no) AC_MSG_RESULT(no) + want_pthreads=no + ;; + *) AC_MSG_RESULT(yes) + want_pthreads=yes + ;; + esac ], [ + AC_MSG_RESULT(auto) + want_pthreads=auto + ] +) + +dnl turn off pthreads if rt is disabled +if test "$want_pthreads" != "no"; then + if test "$want_pthreads" = "yes" && test "$dontwant_rt" = "yes"; then + AC_MSG_ERROR([options --enable-pthreads and --disable-rt are mutually exclusive]) + fi + if test "$dontwant_rt" != "no"; then + dnl if --enable-pthreads was explicit then warn it's being ignored + if test "$want_pthreads" = "yes"; then + AC_MSG_WARN([--enable-pthreads Ignored since librt is disabled.]) + fi + want_pthreads=no + fi +fi + +dnl turn off pthreads if no threaded resolver +if test "$want_pthreads" != "no" && test "$want_thres" != "yes"; then + want_pthreads=no +fi + +dnl detect pthreads +if test "$want_pthreads" != "no"; then + AC_CHECK_HEADER(pthread.h, + [ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have ]) + save_CFLAGS="$CFLAGS" + dnl When statically linking against boringssl, -lpthread is added to LIBS. + dnl Make sure to that this does not pass the check below, we really want + dnl -pthread in CFLAGS as recommended for GCC. This also ensures that + dnl lib1541 and lib1565 tests are built with these options. Otherwise + dnl they fail the build since tests/libtest/Makefile.am clears LIBS. + save_LIBS="$LIBS" + + LIBS= + dnl Check for libc variants without a separate pthread lib like bionic + AC_CHECK_FUNC(pthread_create, [USE_THREADS_POSIX=1] ) + LIBS="$save_LIBS" + + dnl on HPUX, life is more complicated... + case $host in + *-hp-hpux*) + dnl it doesn't actually work without -lpthread + USE_THREADS_POSIX="" + ;; + *) + ;; + esac + + dnl if it wasn't found without lib, search for it in pthread lib + if test "$USE_THREADS_POSIX" != "1" + then + # assign PTHREAD for pkg-config use + PTHREAD=" -pthread" + + case $host in + *-ibm-aix*) + dnl Check if compiler is xlC + COMPILER_VERSION=`"$CC" -qversion 2>/dev/null` + if test x"$COMPILER_VERSION" = "x"; then + CFLAGS="$CFLAGS -pthread" + else + CFLAGS="$CFLAGS -qthreaded" + fi + ;; + powerpc-*amigaos*) + dnl No -pthread option, but link with -lpthread + PTHREAD=" -lpthread" + ;; + *) + CFLAGS="$CFLAGS -pthread" + ;; + esac + AC_CHECK_LIB(pthread, pthread_create, + [USE_THREADS_POSIX=1], + [ CFLAGS="$save_CFLAGS"]) + fi + + if test "x$USE_THREADS_POSIX" = "x1" + then + AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup]) + curl_res_msg="POSIX threaded" + fi + ]) +fi + +dnl threaded resolver check +if test "$want_thres" = "yes" && test "x$USE_THREADS_POSIX" != "x1"; then + if test "$want_pthreads" = "yes"; then + AC_MSG_ERROR([--enable-pthreads but pthreads was not found]) + fi + dnl If native Windows fallback on Win32 threads since no POSIX threads + if test "$curl_cv_native_windows" = "yes"; then + USE_THREADS_WIN32=1 + AC_DEFINE(USE_THREADS_WIN32, 1, [if you want Win32 threaded DNS lookup]) + curl_res_msg="Win32 threaded" + else + AC_MSG_ERROR([Threaded resolver enabled but no thread library found]) + fi +fi + +CURL_CONVERT_INCLUDE_TO_ISYSTEM + +dnl ************************************************************ +dnl disable verbose text strings +dnl +AC_MSG_CHECKING([whether to enable verbose strings]) +AC_ARG_ENABLE(verbose, +AS_HELP_STRING([--enable-verbose],[Enable verbose strings]) +AS_HELP_STRING([--disable-verbose],[Disable verbose strings]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_VERBOSE_STRINGS, 1, [to disable verbose strings]) + curl_verbose_msg="no" + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl enable SSPI support +dnl +AC_MSG_CHECKING([whether to enable SSPI support (Windows native builds only)]) +AC_ARG_ENABLE(sspi, +AS_HELP_STRING([--enable-sspi],[Enable SSPI]) +AS_HELP_STRING([--disable-sspi],[Disable SSPI]), +[ case "$enableval" in + yes) + if test "$curl_cv_native_windows" = "yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_WINDOWS_SSPI, 1, [to enable SSPI support]) + AC_SUBST(USE_WINDOWS_SSPI, [1]) + curl_sspi_msg="enabled" + else + AC_MSG_RESULT(no) + AC_MSG_WARN([--enable-sspi Ignored. Only supported on native Windows builds.]) + fi + ;; + *) + if test "x$SCHANNEL_ENABLED" = "x1"; then + # --with-schannel implies --enable-sspi + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + ;; + esac ], + if test "x$SCHANNEL_ENABLED" = "x1"; then + # --with-schannel implies --enable-sspi + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi +) + +dnl ************************************************************ +dnl disable basic authentication +dnl +AC_MSG_CHECKING([whether to enable basic authentication method]) +AC_ARG_ENABLE(basic-auth, +AS_HELP_STRING([--enable-basic-auth],[Enable basic authentication (default)]) +AS_HELP_STRING([--disable-basic-auth],[Disable basic authentication]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_BASIC_AUTH, 1, [to disable basic authentication]) + CURL_DISABLE_BASIC_AUTH=1 + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable bearer authentication +dnl +AC_MSG_CHECKING([whether to enable bearer authentication method]) +AC_ARG_ENABLE(bearer-auth, +AS_HELP_STRING([--enable-bearer-auth],[Enable bearer authentication (default)]) +AS_HELP_STRING([--disable-bearer-auth],[Disable bearer authentication]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_BEARER_AUTH, 1, [to disable bearer authentication]) + CURL_DISABLE_BEARER_AUTH=1 + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable digest authentication +dnl +AC_MSG_CHECKING([whether to enable digest authentication method]) +AC_ARG_ENABLE(digest-auth, +AS_HELP_STRING([--enable-digest-auth],[Enable digest authentication (default)]) +AS_HELP_STRING([--disable-digest-auth],[Disable digest authentication]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_DIGEST_AUTH, 1, [to disable digest authentication]) + CURL_DISABLE_DIGEST_AUTH=1 + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable kerberos authentication +dnl +AC_MSG_CHECKING([whether to enable kerberos authentication method]) +AC_ARG_ENABLE(kerberos-auth, +AS_HELP_STRING([--enable-kerberos-auth],[Enable kerberos authentication (default)]) +AS_HELP_STRING([--disable-kerberos-auth],[Disable kerberos authentication]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_KERBEROS_AUTH, 1, [to disable kerberos authentication]) + CURL_DISABLE_KERBEROS_AUTH=1 + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable negotiate authentication +dnl +AC_MSG_CHECKING([whether to enable negotiate authentication method]) +AC_ARG_ENABLE(negotiate-auth, +AS_HELP_STRING([--enable-negotiate-auth],[Enable negotiate authentication (default)]) +AS_HELP_STRING([--disable-negotiate-auth],[Disable negotiate authentication]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_NEGOTIATE_AUTH, 1, [to disable negotiate authentication]) + CURL_DISABLE_NEGOTIATE_AUTH=1 + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + + +dnl ************************************************************ +dnl disable aws +dnl +AC_MSG_CHECKING([whether to enable aws sig methods]) +AC_ARG_ENABLE(aws, +AS_HELP_STRING([--enable-aws],[Enable AWS sig support (default)]) +AS_HELP_STRING([--disable-aws],[Disable AWS sig support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_AWS, 1, [to disable AWS sig support]) + CURL_DISABLE_AWS=1 + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable NTLM support +dnl +AC_MSG_CHECKING([whether to support NTLM]) +AC_ARG_ENABLE(ntlm, +AS_HELP_STRING([--enable-ntlm],[Enable NTLM support]) +AS_HELP_STRING([--disable-ntlm],[Disable NTLM support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_NTLM, 1, [to disable NTLM support]) + CURL_DISABLE_NTLM=1 + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +CURL_CHECK_OPTION_NTLM_WB + +CURL_CHECK_NTLM_WB + +dnl ************************************************************ +dnl disable TLS-SRP authentication +dnl +AC_MSG_CHECKING([whether to enable TLS-SRP authentication]) +AC_ARG_ENABLE(tls-srp, +AS_HELP_STRING([--enable-tls-srp],[Enable TLS-SRP authentication]) +AS_HELP_STRING([--disable-tls-srp],[Disable TLS-SRP authentication]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + want_tls_srp=no + ;; + *) AC_MSG_RESULT(yes) + want_tls_srp=yes + ;; + esac ], + AC_MSG_RESULT(yes) + want_tls_srp=yes +) + +if test "$want_tls_srp" = "yes" && ( test "x$HAVE_GNUTLS_SRP" = "x1" || test "x$HAVE_OPENSSL_SRP" = "x1") ; then + AC_DEFINE(USE_TLS_SRP, 1, [Use TLS-SRP authentication]) + USE_TLS_SRP=1 + curl_tls_srp_msg="enabled" +fi + +dnl ************************************************************ +dnl disable Unix domain sockets support +dnl +AC_MSG_CHECKING([whether to enable Unix domain sockets]) +AC_ARG_ENABLE(unix-sockets, +AS_HELP_STRING([--enable-unix-sockets],[Enable Unix domain sockets]) +AS_HELP_STRING([--disable-unix-sockets],[Disable Unix domain sockets]), +[ case "$enableval" in + no) AC_MSG_RESULT(no) + want_unix_sockets=no + ;; + *) AC_MSG_RESULT(yes) + want_unix_sockets=yes + ;; + esac ], [ + AC_MSG_RESULT(auto) + want_unix_sockets=auto + ] +) +if test "x$want_unix_sockets" != "xno"; then + if test "x$curl_cv_native_windows" = "xyes"; then + USE_UNIX_SOCKETS=1 + AC_DEFINE(USE_UNIX_SOCKETS, 1, [Use Unix domain sockets]) + curl_unix_sockets_msg="enabled" + else + AC_CHECK_MEMBER([struct sockaddr_un.sun_path], [ + AC_DEFINE(USE_UNIX_SOCKETS, 1, [Use Unix domain sockets]) + AC_SUBST(USE_UNIX_SOCKETS, [1]) + curl_unix_sockets_msg="enabled" + ], [ + if test "x$want_unix_sockets" = "xyes"; then + AC_MSG_ERROR([--enable-unix-sockets is not available on this platform!]) + fi + ], [ + #include + ]) + fi +fi + +dnl ************************************************************ +dnl disable cookies support +dnl +AC_MSG_CHECKING([whether to support cookies]) +AC_ARG_ENABLE(cookies, +AS_HELP_STRING([--enable-cookies],[Enable cookies support]) +AS_HELP_STRING([--disable-cookies],[Disable cookies support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_COOKIES, 1, [to disable cookies support]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable socketpair +dnl +AC_MSG_CHECKING([whether to support socketpair]) +AC_ARG_ENABLE(socketpair, +AS_HELP_STRING([--enable-socketpair],[Enable socketpair support]) +AS_HELP_STRING([--disable-socketpair],[Disable socketpair support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_SOCKETPAIR, 1, [to disable socketpair support]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable HTTP authentication support +dnl +AC_MSG_CHECKING([whether to support HTTP authentication]) +AC_ARG_ENABLE(http-auth, +AS_HELP_STRING([--enable-http-auth],[Enable HTTP authentication support]) +AS_HELP_STRING([--disable-http-auth],[Disable HTTP authentication support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_HTTP_AUTH, 1, [disable HTTP authentication]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable DoH support +dnl +AC_MSG_CHECKING([whether to support DoH]) +AC_ARG_ENABLE(doh, +AS_HELP_STRING([--enable-doh],[Enable DoH support]) +AS_HELP_STRING([--disable-doh],[Disable DoH support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_DOH, 1, [disable DoH]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable mime API support +dnl +AC_MSG_CHECKING([whether to support the MIME API]) +AC_ARG_ENABLE(mime, +AS_HELP_STRING([--enable-mime],[Enable mime API support]) +AS_HELP_STRING([--disable-mime],[Disable mime API support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_MIME, 1, [disable mime API]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable bindlocal +dnl +AC_MSG_CHECKING([whether to support binding connections locally]) +AC_ARG_ENABLE(bindlocal, +AS_HELP_STRING([--enable-bindlocal],[Enable local binding support]) +AS_HELP_STRING([--disable-bindlocal],[Disable local binding support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_BINDLOCAL, 1, [disable local binding support]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable form API support +dnl +AC_MSG_CHECKING([whether to support the form API]) +AC_ARG_ENABLE(form-api, +AS_HELP_STRING([--enable-form-api],[Enable form API support]) +AS_HELP_STRING([--disable-form-api],[Disable form API support]), +[ case "$enableval" in + no) AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_FORM_API, 1, [disable form API]) + ;; + *) AC_MSG_RESULT(yes) + test "$enable_mime" = no && + AC_MSG_ERROR(MIME support needs to be enabled in order to enable form API support) + ;; + esac ], +[ + if test "$enable_mime" = no; then + enable_form_api=no + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_FORM_API, 1, [disable form API]) + else + AC_MSG_RESULT(yes) + fi ] +) + +dnl ************************************************************ +dnl disable date parsing +dnl +AC_MSG_CHECKING([whether to support date parsing]) +AC_ARG_ENABLE(dateparse, +AS_HELP_STRING([--enable-dateparse],[Enable date parsing]) +AS_HELP_STRING([--disable-dateparse],[Disable date parsing]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_PARSEDATE, 1, [disable date parsing]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable netrc +dnl +AC_MSG_CHECKING([whether to support netrc parsing]) +AC_ARG_ENABLE(netrc, +AS_HELP_STRING([--enable-netrc],[Enable netrc parsing]) +AS_HELP_STRING([--disable-netrc],[Disable netrc parsing]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_NETRC, 1, [disable netrc parsing]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable progress-meter +dnl +AC_MSG_CHECKING([whether to support progress-meter]) +AC_ARG_ENABLE(progress-meter, +AS_HELP_STRING([--enable-progress-meter],[Enable progress-meter]) +AS_HELP_STRING([--disable-progress-meter],[Disable progress-meter]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_PROGRESS_METER, 1, [disable progress-meter]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable shuffle DNS support +dnl +AC_MSG_CHECKING([whether to support DNS shuffling]) +AC_ARG_ENABLE(dnsshuffle, +AS_HELP_STRING([--enable-dnsshuffle],[Enable DNS shuffling]) +AS_HELP_STRING([--disable-dnsshuffle],[Disable DNS shuffling]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_SHUFFLE_DNS, 1, [disable DNS shuffling]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl disable the curl_easy_options API +dnl +AC_MSG_CHECKING([whether to support curl_easy_option*]) +AC_ARG_ENABLE(get-easy-options, +AS_HELP_STRING([--enable-get-easy-options],[Enable curl_easy_options]) +AS_HELP_STRING([--disable-get-easy-options],[Disable curl_easy_options]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_GETOPTIONS, 1, [to disable curl_easy_options]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl switch on/off alt-svc +dnl +AC_MSG_CHECKING([whether to support alt-svc]) +AC_ARG_ENABLE(alt-svc, +AS_HELP_STRING([--enable-alt-svc],[Enable alt-svc support]) +AS_HELP_STRING([--disable-alt-svc],[Disable alt-svc support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_ALTSVC, 1, [disable alt-svc]) + curl_altsvc_msg="no"; + enable_altsvc="no" + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl ************************************************************ +dnl switch on/off headers-api +dnl +AC_MSG_CHECKING([whether to support headers-api]) +AC_ARG_ENABLE(headers-api, +AS_HELP_STRING([--enable-headers-api],[Enable headers-api support]) +AS_HELP_STRING([--disable-headers-api],[Disable headers-api support]), +[ case "$enableval" in + no) AC_MSG_RESULT(no) + curl_headers_msg="no (--enable-headers-api)" + AC_DEFINE(CURL_DISABLE_HEADERS_API, 1, [disable headers-api]) + ;; + *) + AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + +dnl only check for HSTS if there's SSL present +if test -n "$SSL_ENABLED"; then + dnl ************************************************************ + dnl switch on/off hsts + dnl + AC_MSG_CHECKING([whether to support HSTS]) + AC_ARG_ENABLE(hsts, +AS_HELP_STRING([--enable-hsts],[Enable HSTS support]) +AS_HELP_STRING([--disable-hsts],[Disable HSTS support]), + [ case "$enableval" in + no) + AC_MSG_RESULT(no) + hsts="no" + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT($hsts) + ) +else + AC_MSG_NOTICE([disables HSTS due to lack of SSL]) + hsts="no" +fi + +if test "x$hsts" != "xyes"; then + curl_hsts_msg="no (--enable-hsts)"; + AC_DEFINE(CURL_DISABLE_HSTS, 1, [disable alt-svc]) +fi + +dnl ************************************************************* +dnl check whether ECH support, if desired, is actually available +dnl +if test "x$want_ech" != "xno"; then + AC_MSG_CHECKING([whether ECH support is available]) + + dnl assume NOT and look for sufficient condition + ECH_ENABLED=0 + ECH_SUPPORT='' + + dnl OpenSSL with a chosen ECH function should be enough + dnl so more exhaustive checking seems unnecessary for now + if test "x$OPENSSL_ENABLED" = "x1"; then + AC_CHECK_FUNCS(SSL_get_ech_status, + ECH_SUPPORT="ECH support available (OpenSSL with SSL_get_ech_status)" + ECH_ENABLED=1) + + dnl add 'elif' chain here for additional implementations + fi + + dnl now deal with whatever we found + if test "x$ECH_ENABLED" = "x1"; then + AC_DEFINE(USE_ECH, 1, [if ECH support is available]) + AC_MSG_RESULT($ECH_SUPPORT) + experimental="$experimental ECH" + else + AC_MSG_ERROR([--enable-ech ignored: No ECH support found]) + fi +fi + +dnl ************************************************************* +dnl check whether OpenSSL (lookalikes) have SSL_set0_wbio +dnl +if test "x$OPENSSL_ENABLED" = "x1"; then + AC_CHECK_FUNCS([SSL_set0_wbio]) +fi + +dnl ************************************************************* +dnl WebSockets +dnl +AC_MSG_CHECKING([whether to support WebSockets]) +AC_ARG_ENABLE(websockets, +AS_HELP_STRING([--enable-websockets],[Enable WebSockets support]) +AS_HELP_STRING([--disable-websockets],[Disable WebSockets support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + ;; + *) + if test ${ac_cv_sizeof_curl_off_t} -gt 4; then + AC_MSG_RESULT(yes) + curl_ws_msg="enabled" + AC_DEFINE_UNQUOTED(USE_WEBSOCKETS, [1], [enable websockets support]) + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS WS" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS WSS" + fi + experimental="$experimental Websockets" + else + dnl websockets requires >32 bit curl_off_t + AC_MSG_RESULT(no) + AC_MSG_WARN([Websockets disabled due to lack of >32 bit curl_off_t]) + fi + ;; + esac ], + AC_MSG_RESULT(no) +) + + +dnl ************************************************************ +dnl hiding of library internal symbols +dnl +CURL_CONFIGURE_SYMBOL_HIDING + +dnl +dnl All the library dependencies put into $LIB apply to libcurl only. +dnl +LIBCURL_LIBS="$LIBS$PTHREAD" + +AC_SUBST(LIBCURL_LIBS) +AC_SUBST(CURL_NETWORK_LIBS) +AC_SUBST(CURL_NETWORK_AND_TIME_LIBS) + +dnl BLANK_AT_MAKETIME may be used in our Makefile.am files to blank +dnl LIBS variable used in generated makefile at makefile processing +dnl time. Doing this functionally prevents LIBS from being used for +dnl all link targets in given makefile. +BLANK_AT_MAKETIME= +AC_SUBST(BLANK_AT_MAKETIME) + +AM_CONDITIONAL(CROSSCOMPILING, test x$cross_compiling = xyes) + +dnl yes or no +ENABLE_SHARED="$enable_shared" +AC_SUBST(ENABLE_SHARED) + +dnl to let curl-config output the static libraries correctly +ENABLE_STATIC="$enable_static" +AC_SUBST(ENABLE_STATIC) + +dnl merge the pkg-config Libs.private field into Libs when static-only +if test "x$enable_shared" = "xno"; then + LIBCURL_NO_SHARED=$LIBCURL_LIBS +else + LIBCURL_NO_SHARED= +fi +AC_SUBST(LIBCURL_NO_SHARED) + +rm $compilersh + +dnl +dnl For keeping supported features and protocols also in pkg-config file +dnl since it is more cross-compile friendly than curl-config +dnl + +if test "x$OPENSSL_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES SSL" +elif test -n "$SSL_ENABLED"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES SSL" +fi +if test "x$IPV6_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES IPv6" +fi +if test "x$USE_UNIX_SOCKETS" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES UnixSockets" +fi +if test "x$HAVE_LIBZ" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES libz" +fi +if test "x$HAVE_BROTLI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES brotli" +fi +if test "x$HAVE_ZSTD" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES zstd" +fi +if test "x$USE_ARES" = "x1" -o "x$USE_THREADS_POSIX" = "x1" \ + -o "x$USE_THREADS_WIN32" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS" +fi +if test "x$IDN_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES IDN" +fi +if test "x$USE_WINDOWS_SSPI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES SSPI" +fi + +if test "x$HAVE_GSSAPI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES GSS-API" +fi + +if test "x$curl_psl_msg" = "xenabled"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES PSL" +fi + +if test "x$curl_gsasl_msg" = "xenabled"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES GSASL" +fi + +if test "x$enable_altsvc" = "xyes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES alt-svc" +fi +if test "x$hsts" = "xyes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HSTS" +fi + +if test "x$CURL_DISABLE_NEGOTIATE_AUTH" != "x1" -a \ + \( "x$HAVE_GSSAPI" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \); then + SUPPORT_FEATURES="$SUPPORT_FEATURES SPNEGO" +fi + +if test "x$CURL_DISABLE_KERBEROS_AUTH" != "x1" -a \ + \( "x$HAVE_GSSAPI" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \); then + SUPPORT_FEATURES="$SUPPORT_FEATURES Kerberos" +fi + +use_curl_ntlm_core=no + +if test "x$CURL_DISABLE_NTLM" != "x1"; then + if test "x$OPENSSL_ENABLED" = "x1" -o "x$MBEDTLS_ENABLED" = "x1" \ + -o "x$GNUTLS_ENABLED" = "x1" \ + -o "x$SECURETRANSPORT_ENABLED" = "x1" \ + -o "x$USE_WIN32_CRYPTO" = "x1" \ + -o "x$WOLFSSL_NTLM" = "x1"; then + use_curl_ntlm_core=yes + fi + + if test "x$use_curl_ntlm_core" = "xyes" \ + -o "x$USE_WINDOWS_SSPI" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM" + + if test "x$CURL_DISABLE_HTTP" != "x1" -a \ + "x$NTLM_WB_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM_WB" + fi + fi +fi + +if test "x$USE_TLS_SRP" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES TLS-SRP" +fi + +if test "x$USE_NGHTTP2" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTP2" +fi + +if test "x$USE_NGTCP2_H3" = "x1" -o "x$USE_QUICHE" = "x1" \ + -o "x$USE_OPENSSL_H3" = "x1" -o "x$USE_MSH3" = "x1"; then + if test "x$CURL_WITH_MULTI_SSL" = "x1"; then + AC_MSG_ERROR([MultiSSL cannot be enabled with HTTP/3 and vice versa]) + fi + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTP3" +fi + +if test "x$CURL_WITH_MULTI_SSL" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES MultiSSL" +fi + +AC_MSG_CHECKING([if this build supports HTTPS-proxy]) +dnl if not explicitly turned off, HTTPS-proxy comes with some TLS backends +if test "x$CURL_DISABLE_HTTP" != "x1"; then + if test "x$https_proxy" != "xno"; then + if test "x$OPENSSL_ENABLED" = "x1" \ + -o "x$GNUTLS_ENABLED" = "x1" \ + -o "x$SECURETRANSPORT_ENABLED" = "x1" \ + -o "x$RUSTLS_ENABLED" = "x1" \ + -o "x$BEARSSL_ENABLED" = "x1" \ + -o "x$SCHANNEL_ENABLED" = "x1" \ + -o "x$GNUTLS_ENABLED" = "x1" \ + -o "x$MBEDTLS_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPS-proxy" + AC_MSG_RESULT([yes]) + elif test "x$WOLFSSL_ENABLED" = "x1" -a "x$WOLFSSL_FULL_BIO" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPS-proxy" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + else + AC_MSG_RESULT([no]) + fi +else + AC_MSG_RESULT([no]) +fi + +if test "x$ECH_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES ECH" +fi + +if test ${ac_cv_sizeof_curl_off_t} -gt 4; then + if test ${ac_cv_sizeof_off_t} -gt 4 -o \ + "$curl_win32_file_api" = "win32_large_files"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES Largefile" + fi +fi + +if test "$tst_atomic" = "yes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe" +elif test "x$USE_THREADS_POSIX" = "x1" -a \ + "x$ac_cv_header_pthread_h" = "xyes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe" +else + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include + ]],[[ + #if (WINVER < 0x600) && (_WIN32_WINNT < 0x600) + #error + #endif + ]]) + ],[ + SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe" + ],[ + ]) +fi + +dnl replace spaces with newlines +dnl sort the lines +dnl replace the newlines back to spaces +SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort | tr '\012' ' '` +AC_SUBST(SUPPORT_FEATURES) + +dnl For supported protocols in pkg-config file +if test "x$CURL_DISABLE_HTTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTP IPFS IPNS" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTPS" + fi +fi +if test "x$CURL_DISABLE_FTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS FTP" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS FTPS" + fi +fi +if test "x$CURL_DISABLE_FILE" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS FILE" +fi +if test "x$CURL_DISABLE_TELNET" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TELNET" +fi +if test "x$CURL_DISABLE_LDAP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS LDAP" + if test "x$CURL_DISABLE_LDAPS" != "x1"; then + if (test "x$USE_OPENLDAP" = "x1" && test "x$SSL_ENABLED" = "x1") || + (test "x$USE_OPENLDAP" != "x1" && test "x$HAVE_LDAP_SSL" = "x1"); then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS LDAPS" + fi + fi +fi +if test "x$CURL_DISABLE_DICT" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS DICT" +fi +if test "x$CURL_DISABLE_TFTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TFTP" +fi +if test "x$CURL_DISABLE_GOPHER" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS GOPHER" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS GOPHERS" + fi +fi +if test "x$CURL_DISABLE_MQTT" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS MQTT" +fi +if test "x$CURL_DISABLE_POP3" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3S" + fi +fi +if test "x$CURL_DISABLE_IMAP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IMAP" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IMAPS" + fi +fi +if test "x$CURL_DISABLE_SMB" != "x1" \ + -a "x$use_curl_ntlm_core" = "xyes"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMB" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMBS" + fi +fi +if test "x$CURL_DISABLE_SMTP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMTP" + if test "x$SSL_ENABLED" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMTPS" + fi +fi +if test "x$USE_LIBSSH2" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi +if test "x$USE_LIBSSH" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi +if test "x$USE_WOLFSSH" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi +if test "x$CURL_DISABLE_RTSP" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP" +fi +if test "x$USE_LIBRTMP" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTMP" +fi + +dnl replace spaces with newlines +dnl sort the lines +dnl replace the newlines back to spaces +SUPPORT_PROTOCOLS=`echo $SUPPORT_PROTOCOLS | tr ' ' '\012' | sort | tr '\012' ' '` + +AC_SUBST(SUPPORT_PROTOCOLS) + +dnl squeeze whitespace out of some variables + +squeeze CFLAGS +squeeze CPPFLAGS +squeeze DEFS +squeeze LDFLAGS +squeeze LIBS + +squeeze LIBCURL_LIBS +squeeze CURL_NETWORK_LIBS +squeeze CURL_NETWORK_AND_TIME_LIBS + +squeeze SUPPORT_FEATURES +squeeze SUPPORT_PROTOCOLS + +XC_CHECK_BUILD_FLAGS + +SSL_BACKENDS=${ssl_backends} +AC_SUBST(SSL_BACKENDS) + +if test "x$want_curldebug_assumed" = "xyes" && + test "x$want_curldebug" = "xyes" && test "x$USE_ARES" = "x1"; then + ac_configure_args="$ac_configure_args --enable-curldebug" +fi + +AC_CONFIG_FILES([Makefile \ + docs/Makefile \ + docs/examples/Makefile \ + docs/libcurl/Makefile \ + docs/libcurl/opts/Makefile \ + docs/cmdline-opts/Makefile \ + include/Makefile \ + include/curl/Makefile \ + src/Makefile \ + lib/Makefile \ + scripts/Makefile \ + lib/libcurl.vers \ + lib/libcurl.plist \ + tests/Makefile \ + tests/config \ + tests/certs/Makefile \ + tests/certs/scripts/Makefile \ + tests/data/Makefile \ + tests/server/Makefile \ + tests/libtest/Makefile \ + tests/unit/Makefile \ + tests/http/config.ini \ + tests/http/Makefile \ + tests/http/clients/Makefile \ + packages/Makefile \ + packages/vms/Makefile \ + curl-config \ + libcurl.pc +]) +AC_OUTPUT + +CURL_GENERATE_CONFIGUREHELP_PM + +AC_MSG_NOTICE([Configured to build curl/libcurl: + + Host setup: ${host} + Install prefix: ${prefix} + Compiler: ${CC} + CFLAGS: ${CFLAGS} + CPPFLAGS: ${CPPFLAGS} + LDFLAGS: ${LDFLAGS} + LIBS: ${LIBS} + + curl version: ${CURLVERSION} + SSL: ${curl_ssl_msg} + SSH: ${curl_ssh_msg} + zlib: ${curl_zlib_msg} + brotli: ${curl_brotli_msg} + zstd: ${curl_zstd_msg} + GSS-API: ${curl_gss_msg} + GSASL: ${curl_gsasl_msg} + TLS-SRP: ${curl_tls_srp_msg} + resolver: ${curl_res_msg} + IPv6: ${curl_ipv6_msg} + Unix sockets: ${curl_unix_sockets_msg} + IDN: ${curl_idn_msg} + Build libcurl: Shared=${enable_shared}, Static=${enable_static} + Built-in manual: ${curl_manual_msg} + --libcurl option: ${curl_libcurl_msg} + Verbose errors: ${curl_verbose_msg} + Code coverage: ${curl_coverage_msg} + SSPI: ${curl_sspi_msg} + ca cert bundle: ${ca}${ca_warning} + ca cert path: ${capath}${capath_warning} + ca fallback: ${with_ca_fallback} + LDAP: ${curl_ldap_msg} + LDAPS: ${curl_ldaps_msg} + RTSP: ${curl_rtsp_msg} + RTMP: ${curl_rtmp_msg} + PSL: ${curl_psl_msg} + Alt-svc: ${curl_altsvc_msg} + Headers API: ${curl_headers_msg} + HSTS: ${curl_hsts_msg} + HTTP1: ${curl_h1_msg} + HTTP2: ${curl_h2_msg} + HTTP3: ${curl_h3_msg} + ECH: ${curl_ech_msg} + WebSockets: ${curl_ws_msg} + Protocols: ${SUPPORT_PROTOCOLS} + Features: ${SUPPORT_FEATURES} +]) +if test -n "$experimental"; then + cat >&2 << _EOF + WARNING: $experimental enabled but marked EXPERIMENTAL. Use with caution! +_EOF +fi diff --git a/curl-config.in b/curl-config.in new file mode 100644 index 0000000..54f92d9 --- /dev/null +++ b/curl-config.in @@ -0,0 +1,196 @@ +#! /bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +prefix="@prefix@" +exec_prefix=@exec_prefix@ +includedir=@includedir@ +cppflag_curl_staticlib=@CPPFLAG_CURL_STATICLIB@ + +usage() +{ + cat <&2 + exit 1 + fi + ;; + + --configure) + echo @CONFIGURE_OPTIONS@ + ;; + + *) + echo "unknown option: $1" + usage 1 + ;; + esac + shift +done + +exit 0 diff --git a/depcomp b/depcomp new file mode 100755 index 0000000..715e343 --- /dev/null +++ b/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2021 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The second -e expression handles DOS-style file names with drive + # letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like '#:fec' to the end of the + # dependency line. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ + | tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool generates 2 separate objects for the 2 libraries. These + # two compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E \ + | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + | sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/docs/ALTSVC.md b/docs/ALTSVC.md new file mode 100644 index 0000000..18d2d2a --- /dev/null +++ b/docs/ALTSVC.md @@ -0,0 +1,44 @@ +# Alt-Svc + +curl features support for the Alt-Svc: HTTP header. + +## Enable Alt-Svc in build + +`./configure --enable-alt-svc` + +(enabled by default since 7.73.0) + +## Standard + +[RFC 7838](https://datatracker.ietf.org/doc/html/rfc7838) + +# Alt-Svc cache file format + +This is a text based file with one line per entry and each line consists of nine +space separated fields. + +## Example + + h2 quic.tech 8443 h3-22 quic.tech 8443 "20190808 06:18:37" 0 0 + +## Fields + +1. The ALPN id for the source origin +2. The hostname for the source origin +3. The port number for the source origin +4. The ALPN id for the destination host +5. The hostname for the destination host +6. The host number for the destination host +7. The expiration date and time of this entry within double quotes. The date format is "YYYYMMDD HH:MM:SS" and the time zone is GMT. +8. Boolean (1 or 0) if "persist" was set for this entry +9. Integer priority value (not currently used) + +If the hostname is an IPv6 numerical address, it is stored with brackets such +as `[::1]`. + +# TODO + +- handle multiple response headers, when one of them says `clear` (should + override them all) +- using `Age:` value for caching age as per spec +- `CURLALTSVC_IMMEDIATELY` support diff --git a/docs/BINDINGS.md b/docs/BINDINGS.md new file mode 100644 index 0000000..7f5da42 --- /dev/null +++ b/docs/BINDINGS.md @@ -0,0 +1,138 @@ +libcurl bindings +================ + + Creative people have written bindings or interfaces for various environments + and programming languages. Using one of these allows you to take advantage of + curl powers from within your favourite language or system. + + This is a list of all known interfaces as of this writing. + + The bindings listed below are not part of the curl/libcurl distribution + archives, but must be downloaded and installed separately. + + + +[Ada95](https://web.archive.org/web/20070403105909/www.almroth.com/adacurl/index.html) Written by Andreas Almroth + +[Basic](https://scriptbasic.com/) ScriptBasic bindings written by Peter Verhas + +C++: [curlpp](https://github.com/jpbarrette/curlpp/) Written by Jean-Philippe Barrette-LaPierre, +[curlcpp](https://github.com/JosephP91/curlcpp) by Giuseppe Persico and [C++ +Requests](https://github.com/libcpr/cpr) by Huu Nguyen + +[Ch](https://chcurl.sourceforge.net/) Written by Stephen Nestinger and Jonathan Rogado + +Cocoa: [BBHTTP](https://github.com/biasedbit/BBHTTP) written by Bruno de Carvalho +[curlhandle](https://github.com/karelia/curlhandle) Written by Dan Wood + +Clojure: [clj-curl](https://github.com/lsevero/clj-curl) by Lucas Severo + +[D](https://dlang.org/library/std/net/curl.html) Written by Kenneth Bogert + +[Delphi](https://github.com/Mercury13/curl4delphi) Written by Mikhail Merkuryev + +[Dylan](https://dylanlibs.sourceforge.net/) Written by Chris Double + +[Eiffel](https://iron.eiffel.com/repository/20.11/package/ABEF6975-37AC-45FD-9C67-52D10BA0669B) Written by Eiffel Software + +[Euphoria](https://web.archive.org/web/20050204080544/rays-web.com/eulibcurl.htm) Written by Ray Smith + +[Falcon](http://www.falconpl.org/project_docs/curl/) + +[Ferite](https://web.archive.org/web/20150102192018/ferite.org/) Written by Paul Querna + +[Fortran](https://github.com/interkosmos/fortran-curl) Written by Philipp Engel + +[Gambas](https://gambas.sourceforge.net/) + +[glib/GTK+](https://web.archive.org/web/20100526203452/atterer.net/glibcurl) Written by Richard Atterer + +Go: [go-curl](https://github.com/andelf/go-curl) by ShuYu Wang + +[Guile](https://github.com/spk121/guile-curl) Written by Michael L. Gran + +[Harbour](https://github.com/vszakats/hb/tree/main/contrib/hbcurl) Written by Viktor Szakats + +[Haskell](https://hackage.haskell.org/package/curl) Written by Galois, Inc + +[Hollywood](https://www.hollywood-mal.com/download.html) hURL by Andreas Falkenhahn + +[Java](https://github.com/pjlegato/curl-java) + +[Julia](https://github.com/JuliaWeb/LibCURL.jl) Written by Amit Murthy + +[Kapito](https://github.com/puzza007/katipo) is an Erlang HTTP library around libcurl. + +[Lisp](https://common-lisp.net/project/cl-curl/) Written by Liam Healy + +Lua: [luacurl](https://web.archive.org/web/20201205052437/luacurl.luaforge.net/) by Alexander Marinov, [Lua-cURL](https://github.com/Lua-cURL) by Jürgen Hötzel + +[Mono](https://web.archive.org/web/20070606064500/https://forge.novell.com/modules/xfmod/project/?libcurl-mono) Written by Jeffrey Phillips + +[.NET](https://sourceforge.net/projects/libcurl-net/) libcurl-net by Jeffrey Phillips + +[Nim](https://nimble.directory/pkg/libcurl) wrapper for libcurl + +[node.js](https://github.com/JCMais/node-libcurl) node-libcurl by Jonathan Cardoso Machado + +[Object-Pascal](https://web.archive.org/web/20020610214926/www.tekool.com/opcurl) Free Pascal, Delphi and Kylix binding written by Christophe Espern. + +[OCaml](https://opam.ocaml.org/packages/ocurl/) Written by Lars Nilsson and ygrek + +[Pascal](https://web.archive.org/web/20030804091414/houston.quik.com/jkp/curlpas/) Free Pascal, Delphi and Kylix binding written by Jeffrey Pohlmeyer. + +Perl: [WWW::Curl](https://github.com/szbalint/WWW--Curl) Maintained by Cris +Bailiff and Bálint Szilakszi, +[perl6-net-curl](https://github.com/azawawi/perl6-net-curl) by Ahmad M. Zawawi +[NET::Curl](https://metacpan.org/pod/Net::Curl) by Przemyslaw Iskra + +[PHP](https://php.net/curl) Originally written by Sterling Hughes + +[PostgreSQL](https://github.com/pramsey/pgsql-http) - HTTP client for PostgreSQL + +[PostgreSQL](https://github.com/RekGRpth/pg_curl) - cURL client for PostgreSQL + +[PureBasic](https://www.purebasic.com/documentation/http/index.html) uses libcurl in its "native" HTTP subsystem + +[Python](http://pycurl.io/) PycURL by Kjetil Jacobsen + +[Q](https://q-lang.sourceforge.net/) The libcurl module is part of the default install + +[R](https://cran.r-project.org/package=curl) + +[Rexx](https://rexxcurl.sourceforge.net/) Written Mark Hessling + +[Ring](https://ring-lang.sourceforge.io/doc1.3/libcurl.html) RingLibCurl by Mahmoud Fayed + +RPG, support for ILE/RPG on OS/400 is included in source distribution + +Ruby: [curb](https://github.com/taf2/curb) written by Ross Bamford, +[ruby-curl-multi](https://github.com/kball/curl_multi.rb) by Kristjan Petursson and Keith Rarick + +[Rust](https://github.com/alexcrichton/curl-rust) curl-rust - by Carl Lerche + +[Scheme](https://www.metapaper.net/lisovsky/web/curl/) Bigloo binding by Kirill Lisovsky + +[Scilab](https://help.scilab.org/docs/current/fr_FR/getURL.html) binding by Sylvestre Ledru + +[S-Lang](https://www.jedsoft.org/slang/modules/curl.html) by John E Davis + +[Smalltalk](https://www.squeaksource.com/CurlPlugin/) Written by Danil Osipchuk + +[SP-Forth](https://sourceforge.net/p/spf/spf/ci/master/tree/devel/~ac/lib/lin/curl/) Written by Andrey Cherezov + +[SPL](https://web.archive.org/web/20210203022158/www.clifford.at/spl/spldoc/curl.html) Written by Clifford Wolf + +[Tcl](https://web.archive.org/web/20160826011806/mirror.yellow5.com/tclcurl/) Tclcurl by Andrés García + +[Vibe](https://github.com/ttytm/vibe) HTTP requests through libcurl in V + +[Visual Basic](https://sourceforge.net/projects/libcurl-vb/) libcurl-vb by Jeffrey Phillips + +[Visual Foxpro](https://web.archive.org/web/20130730181523/www.ctl32.com.ar/libcurl.asp) by Carlos Alloatti + +[wxWidgets](https://wxcode.sourceforge.net/components/wxcurl/) Written by Casey O'Donnell + +[XBLite](https://web.archive.org/web/20060426150418/perso.wanadoo.fr/xblite/libraries.html) Written by David Szafranski + +[Xojo](https://github.com/charonn0/RB-libcURL) Written by Andrew Lambert diff --git a/docs/BUFREF.md b/docs/BUFREF.md new file mode 100644 index 0000000..14f41b3 --- /dev/null +++ b/docs/BUFREF.md @@ -0,0 +1,81 @@ +# bufref + +This is an internal module for handling buffer references. A referenced +buffer is associated with its destructor function that is implicitly called +when the reference is invalidated. Once referenced, a buffer cannot be +reallocated. + +A data length is stored within the reference for binary data handling +purposes; it is not used by the bufref API. + +The `struct bufref` is used to hold data referencing a buffer. The members of +that structure **MUST NOT** be accessed or modified without using the dedicated +bufref API. + +## `init` + +```c +void Curl_bufref_init(struct bufref *br); +``` + +Initializes a `bufref` structure. This function **MUST** be called before any +other operation is performed on the structure. + +Upon completion, the referenced buffer is `NULL` and length is zero. + +This function may also be called to bypass referenced buffer destruction while +invalidating the current reference. + +## `free` + +```c +void Curl_bufref_free(struct bufref *br); +``` + +Destroys the previously referenced buffer using its destructor and +reinitializes the structure for a possible subsequent reuse. + +## `set` + +```c +void Curl_bufref_set(struct bufref *br, const void *buffer, size_t length, + void (*destructor)(void *)); +``` + +Releases the previously referenced buffer, then assigns the new `buffer` to +the structure, associated with its `destructor` function. The latter can be +specified as `NULL`: this will be the case when the referenced buffer is +static. + +if `buffer` is NULL, `length` must be zero. + +## `memdup` + +```c +CURLcode Curl_bufref_memdup(struct bufref *br, const void *data, size_t length); +``` + +Releases the previously referenced buffer, then duplicates the `length`-byte +`data` into a buffer allocated via `malloc()` and references the latter +associated with destructor `curl_free()`. + +An additional trailing byte is allocated and set to zero as a possible string +null-terminator; it is not counted in the stored length. + +Returns `CURLE_OK` if successful, else `CURLE_OUT_OF_MEMORY`. + +## `ptr` + +```c +const unsigned char *Curl_bufref_ptr(const struct bufref *br); +``` + +Returns a `const unsigned char *` to the referenced buffer. + +## `len` + +```c +size_t Curl_bufref_len(const struct bufref *br); +``` + +Returns the stored length of the referenced buffer. diff --git a/docs/BUG-BOUNTY.md b/docs/BUG-BOUNTY.md new file mode 100644 index 0000000..3714efd --- /dev/null +++ b/docs/BUG-BOUNTY.md @@ -0,0 +1,78 @@ +# The curl bug bounty + +The curl project runs a bug bounty program in association with +[HackerOne](https://www.hackerone.com) and the [Internet Bug +Bounty](https://internetbugbounty.org). + +## How does it work? + +Start out by posting your suspected security vulnerability directly to [curl's +HackerOne program](https://hackerone.com/curl). + +After you have reported a security issue, it has been deemed credible, and a +patch and advisory has been made public, you may be eligible for a bounty from +this program. See the [Security Process](https://curl.se/dev/secprocess.html) +document for how we work with security issues. + +## What are the reward amounts? + +The curl project offers monetary compensation for reported and published +security vulnerabilities. The amount of money that is rewarded depends on how +serious the flaw is determined to be. + +Since 2021, the Bug Bounty is managed in association with the Internet Bug +Bounty and they will set the reward amounts. If it would turn out that they +set amounts that are way lower than we can accept, the curl project intends to +"top up" rewards. + +In 2022, typical "Medium" rated vulnerabilities have been rewarded 2,400 USD +each. + +## Who is eligible for a reward? + +Everyone and anyone who reports a security problem in a released curl version +that has not already been reported can ask for a bounty. + +Dedicated - paid for - security audits that are performed in collaboration +with curl developers are not eligible for bounties. + +Vulnerabilities in features that are off by default and documented as +experimental are not eligible for a reward. + +The vulnerability has to be fixed and publicly announced (by the curl project) +before a bug bounty will be considered. + +Once the vulnerability has been published by curl, the researcher can request +their bounty from the [Internet Bug Bounty](https://hackerone.com/ibb). + +Bounties need to be requested within twelve months from the publication of the +vulnerability. + +## Product vulnerabilities only + +This bug bounty only concerns the curl and libcurl products and thus their +respective source codes - when running on existing hardware. It does not +include curl documentation, curl websites, or other curl related +infrastructure. + +The curl security team is the sole arbiter if a reported flaw is subject to a +bounty or not. + +## How are vulnerabilities graded? + +The grading of each reported vulnerability that makes a reward claim will be +performed by the curl security team. The grading will be based on the CVSS +(Common Vulnerability Scoring System) 3.0. + +## How are reward amounts determined? + +The curl security team gives the vulnerability a score or severity level, as +mentioned above. The actual monetary reward amount is decided and paid by the +Internet Bug Bounty.. + +## Regarding taxes, etc. on the bounties + +In the event that the individual receiving a bug bounty needs to pay taxes on +the reward money, the responsibility lies with the receiver. The curl project +or its security team never actually receive any of this money, hold the money, +or pay out the money. diff --git a/docs/BUGS.md b/docs/BUGS.md new file mode 100644 index 0000000..7333baa --- /dev/null +++ b/docs/BUGS.md @@ -0,0 +1,265 @@ +# BUGS + +## There are still bugs + + Curl and libcurl keep being developed. Adding features and changing code + means that bugs will sneak in, no matter how hard we try to keep them out. + + Of course there are lots of bugs left. Not to mention misfeatures. + + To help us make curl the stable and solid product we want it to be, we need + bug reports and bug fixes. + +## Where to report + + If you cannot fix a bug yourself and submit a fix for it, try to report an as + detailed report as possible to a curl mailing list to allow one of us to have + a go at a solution. You can optionally also submit your problem in [curl's + bug tracking system](https://github.com/curl/curl/issues). + + Please read the rest of this document below first before doing that. + + If you feel you need to ask around first, find a suitable [mailing list]( + https://curl.se/mail/) and post your questions there. + +## Security bugs + + If you find a bug or problem in curl or libcurl that you think has a security + impact, for example a bug that can put users in danger or make them + vulnerable if the bug becomes public knowledge, then please report that bug + using our security development process. + + Security related bugs or bugs that are suspected to have a security impact, + should be reported on the [curl security tracker at + HackerOne](https://hackerone.com/curl). + + This ensures that the report reaches the curl security team so that they + first can deal with the report away from the public to minimize the harm + and impact it will have on existing users out there who might be using the + vulnerable versions. + + The curl project's process for handling security related issues is + [documented separately](https://curl.se/dev/secprocess.html). + +## What to report + + When reporting a bug, you should include all information that will help us + understand what is wrong, what you expected to happen and how to repeat the + bad behavior. You therefore need to tell us: + + - your operating system's name and version number + + - what version of curl you are using (`curl -V` is fine) + + - versions of the used libraries that libcurl is built to use + + - what URL you were working with (if possible), at least which protocol + + and anything and everything else you think matters. Tell us what you expected + to happen, tell use what did happen, tell us how you could make it work + another way. Dig around, try out, test. Then include all the tiny bits and + pieces in your report. You will benefit from this yourself, as it will enable + us to help you quicker and more accurately. + + Since curl deals with networks, it often helps us if you include a protocol + debug dump with your bug report. The output you get by using the `-v` or + `--trace` options. + + If curl crashed, causing a core dump (in Unix), there is hardly any use to + send that huge file to anyone of us. Unless we have the same system setup as + you, we cannot do much with it. Instead, we ask you to get a stack trace and + send that (much smaller) output to us instead. + + The address and how to subscribe to the mailing lists are detailed in the + `MANUAL.md` file. + +## libcurl problems + + When you have written your own application with libcurl to perform transfers, + it is even more important to be specific and detailed when reporting bugs. + + Tell us the libcurl version and your operating system. Tell us the name and + version of all relevant sub-components like for example the SSL library + you are using and what name resolving your libcurl uses. If you use SFTP or + SCP, the libssh2 version is relevant etc. + + Showing us a real source code example repeating your problem is the best way + to get our attention and it will greatly increase our chances to understand + your problem and to work on a fix (if we agree it truly is a problem). + + Lots of problems that appear to be libcurl problems are actually just abuses + of the libcurl API or other malfunctions in your applications. It is advised + that you run your problematic program using a memory debug tool like valgrind + or similar before you post memory-related or "crashing" problems to us. + +## Who will fix the problems + + If the problems or bugs you describe are considered to be bugs, we want to + have the problems fixed. + + There are no developers in the curl project that are paid to work on bugs. + All developers that take on reported bugs do this on a voluntary basis. We do + it out of an ambition to keep curl and libcurl excellent products and out of + pride. + + Please do not assume that you can just lump over something to us and it will + then magically be fixed after some given time. Most often we need feedback + and help to understand what you have experienced and how to repeat a + problem. Then we may only be able to assist YOU to debug the problem and to + track down the proper fix. + + We get reports from many people every month and each report can take a + considerable amount of time to really go to the bottom with. + +## How to get a stack trace + + First, you must make sure that you compile all sources with `-g` and that you + do not 'strip' the final executable. Try to avoid optimizing the code as well, + remove `-O`, `-O2` etc from the compiler options. + + Run the program until it cores. + + Run your debugger on the core file, like ` curl + core`. `` should be replaced with the name of your debugger, in + most cases that will be `gdb`, but `dbx` and others also occur. + + When the debugger has finished loading the core file and presents you a + prompt, enter `where` (without quotes) and press return. + + The list that is presented is the stack trace. If everything worked, it is + supposed to contain the chain of functions that were called when curl + crashed. Include the stack trace with your detailed bug report, it will help a + lot. + +## Bugs in libcurl bindings + + There will of course pop up bugs in libcurl bindings. You should then + primarily approach the team that works on that particular binding and see + what you can do to help them fix the problem. + + If you suspect that the problem exists in the underlying libcurl, then please + convert your program over to plain C and follow the steps outlined above. + +## Bugs in old versions + + The curl project typically releases new versions every other month, and we + fix several hundred bugs per year. For a huge table of releases, number of + bug fixes and more, see: https://curl.se/docs/releases.html + + The developers in the curl project do not have bandwidth or energy enough to + maintain several branches or to spend much time on hunting down problems in + old versions when chances are we already fixed them or at least that they have + changed nature and appearance in later versions. + + When you experience a problem and want to report it, you really SHOULD + include the version number of the curl you are using when you experience the + issue. If that version number shows us that you are using an out-of-date curl, + you should also try out a modern curl version to see if the problem persists + or how/if it has changed in appearance. + + Even if you cannot immediately upgrade your application/system to run the + latest curl version, you can most often at least run a test version or + experimental build or similar, to get this confirmed or not. + + At times people insist that they cannot upgrade to a modern curl version, but + instead, they "just want the bug fixed". That is fine, just do not count on us + spending many cycles on trying to identify which single commit, if that is + even possible, that at some point in the past fixed the problem you are now + experiencing. + + Security wise, it is almost always a bad idea to lag behind the current curl + versions by a lot. We keep discovering and reporting security problems + over time see you can see in [this + table](https://curl.se/docs/vulnerabilities.html) + +# Bug fixing procedure + +## What happens on first filing + + When a new issue is posted in the issue tracker or on the mailing list, the + team of developers first needs to see the report. Maybe they took the day off, + maybe they are off in the woods hunting. Have patience. Allow at least a few + days before expecting someone to have responded. + + In the issue tracker, you can expect that some labels will be set on the issue + to help categorize it. + +## First response + + If your issue/bug report was not perfect at once (and few are), chances are + that someone will ask follow-up questions. Which version did you use? Which + options did you use? How often does the problem occur? How can we reproduce + this problem? Which protocols does it involve? Or perhaps much more specific + and deep diving questions. It all depends on your specific issue. + + You should then respond to these follow-up questions and provide more info + about the problem, so that we can help you figure it out. Or maybe you can + help us figure it out. An active back-and-forth communication is important + and the key for finding a cure and landing a fix. + +## Not reproducible + + We may require further work from you who actually see or experience the + problem if we cannot reproduce it and cannot understand it even after having + gotten all the info we need and having studied the source code over again. + +## Unresponsive + + If the problem have not been understood or reproduced, and there is nobody + responding to follow-up questions or questions asking for clarifications or + for discussing possible ways to move forward with the task, we take that as a + strong suggestion that the bug is unimportant. + + Unimportant issues will be closed as inactive sooner or later as they cannot + be fixed. The inactivity period (waiting for responses) should not be shorter + than two weeks but may extend months. + +## Lack of time/interest + + Bugs that are filed and are understood can unfortunately end up in the + "nobody cares enough about it to work on it" category. Such bugs are + perfectly valid problems that *should* get fixed but apparently are not. We + try to mark such bugs as `KNOWN_BUGS material` after a time of inactivity and + if no activity is noticed after yet some time those bugs are added to the + `KNOWN_BUGS` document and are closed in the issue tracker. + +## `KNOWN_BUGS` + + This is a list of known bugs. Bugs we know exist and that have been pointed + out but that have not yet been fixed. The reasons for why they have not been + fixed can involve anything really, but the primary reason is that nobody has + considered these problems to be important enough to spend the necessary time + and effort to have them fixed. + + The `KNOWN_BUGS` items are always up for grabs and we love the ones who bring + one of them back to life and offer solutions to them. + + The `KNOWN_BUGS` document has a sibling document known as `TODO`. + +## `TODO` + + Issues that are filed or reported that are not really bugs but more missing + features or ideas for future improvements and so on are marked as + 'enhancement' or 'feature-request' and will be added to the `TODO` document + and the issues are closed. We do not keep TODO items open in the issue + tracker. + + The `TODO` document is full of ideas and suggestions of what we can add or + fix one day. You are always encouraged and free to grab one of those items and + take up a discussion with the curl development team on how that could be + implemented or provided in the project so that you can work on ticking it odd + that document. + + If an issue is rather a bug and not a missing feature or functionality, it is + listed in `KNOWN_BUGS` instead. + +## Closing off stalled bugs + + The [issue and pull request trackers](https://github.com/curl/curl) only + hold "active" entries open (using a non-precise definition of what active + actually is, but they are at least not completely dead). Those that are + abandoned or in other ways dormant will be closed and sometimes added to + `TODO` and `KNOWN_BUGS` instead. + + This way, we only have "active" issues open on GitHub. Irrelevant issues and + pull requests will not distract developers or casual visitors. diff --git a/docs/CHECKSRC.md b/docs/CHECKSRC.md new file mode 100644 index 0000000..f73e7a8 --- /dev/null +++ b/docs/CHECKSRC.md @@ -0,0 +1,184 @@ +# checksrc + +This is the tool we use within the curl project to scan C source code and +check that it adheres to our [Source Code Style guide](CODE_STYLE.md). + +## Usage + + checksrc.pl [options] [file1] [file2] ... + +## Command line options + +`-W[file]` skip that file and exclude it from being checked. Helpful +when, for example, one of the files is generated. + +`-D[dir]` directory name to prepend to file names when accessing them. + +`-h` shows the help output, that also lists all recognized warnings + +## What does `checksrc` warn for? + +`checksrc` does not check and verify the code against the entire style guide. +The script is an effort to detect the most common mistakes and syntax mistakes +that contributors make before they get accustomed to our code style. Heck, +many of us regulars do the mistakes too and this script helps us keep the code +in shape. + + checksrc.pl -h + +Lists how to use the script and it lists all existing warnings it has and +problems it detects. At the time of this writing, the existing `checksrc` +warnings are: + +- `ASSIGNWITHINCONDITION`: Assignment within a conditional expression. The + code style mandates the assignment to be done outside of it. + +- `ASTERISKNOSPACE`: A pointer was declared like `char* name` instead of the + more appropriate `char *name` style. The asterisk should sit next to the + name. + +- `ASTERISKSPACE`: A pointer was declared like `char * name` instead of the + more appropriate `char *name` style. The asterisk should sit right next to + the name without a space in between. + +- `BADCOMMAND`: There is a bad `checksrc` instruction in the code. See the + **Ignore certain warnings** section below for details. + +- `BANNEDFUNC`: A banned function was used. The functions sprintf, vsprintf, + strcat, strncat, gets are **never** allowed in curl source code. + +- `BRACEELSE`: '} else' on the same line. The else is supposed to be on the + following line. + +- `BRACEPOS`: wrong position for an open brace (`{`). + +- `BRACEWHILE`: more than once space between end brace and while keyword + +- `COMMANOSPACE`: a comma without following space + +- `COPYRIGHT`: the file is missing a copyright statement + +- `CPPCOMMENTS`: `//` comment detected, that is not C89 compliant + +- `DOBRACE`: only use one space after do before open brace + +- `EMPTYLINEBRACE`: found empty line before open brace + +- `EQUALSNOSPACE`: no space after `=` sign + +- `EQUALSNULL`: comparison with `== NULL` used in if/while. We use `!var`. + +- `EXCLAMATIONSPACE`: space found after exclamations mark + +- `FOPENMODE`: `fopen()` needs a macro for the mode string, use it + +- `INDENTATION`: detected a wrong start column for code. Note that this + warning only checks some specific places and will certainly miss many bad + indentations. + +- `LONGLINE`: A line is longer than 79 columns. + +- `MULTISPACE`: Multiple spaces were found where only one should be used. + +- `NOSPACEEQUALS`: An equals sign was found without preceding space. We prefer + `a = 2` and *not* `a=2`. + +- `NOTEQUALSZERO`: check found using `!= 0`. We use plain `if(var)`. + +- `ONELINECONDITION`: do not put the conditional block on the same line as `if()` + +- `OPENCOMMENT`: File ended with a comment (`/*`) still "open". + +- `PARENBRACE`: `){` was used without sufficient space in between. + +- `RETURNNOSPACE`: `return` was used without space between the keyword and the + following value. + +- `SEMINOSPACE`: There was no space (or newline) following a semicolon. + +- `SIZEOFNOPAREN`: Found use of sizeof without parentheses. We prefer + `sizeof(int)` style. + +- `SNPRINTF` - Found use of `snprintf()`. Since we use an internal replacement + with a different return code etc, we prefer `msnprintf()`. + +- `SPACEAFTERPAREN`: there was a space after open parenthesis, `( text`. + +- `SPACEBEFORECLOSE`: there was a space before a close parenthesis, `text )`. + +- `SPACEBEFORECOMMA`: there was a space before a comma, `one , two`. + +- `SPACEBEFOREPAREN`: there was a space before an open parenthesis, `if (`, + where one was not expected + +- `SPACESEMICOLON`: there was a space before semicolon, ` ;`. + +- `TABS`: TAB characters are not allowed + +- `TRAILINGSPACE`: Trailing whitespace on the line + +- `TYPEDEFSTRUCT`: we frown upon (most) typedefed structs + +- `UNUSEDIGNORE`: a `checksrc` inlined warning ignore was asked for but not + used, that is an ignore that should be removed or changed to get used. + +### Extended warnings + +Some warnings are quite computationally expensive to perform, so they are +turned off by default. To enable these warnings, place a `.checksrc` file in +the directory where they should be activated with commands to enable the +warnings you are interested in. The format of the file is to enable one +warning per line like so: `enable ` + +Currently these are the extended warnings which can be enabled: + +- `COPYRIGHTYEAR`: the current changeset has not updated the copyright year in + the source file + +- `STRERROR`: use of banned function strerror() + +- `STDERR`: use of banned variable `stderr` + +## Ignore certain warnings + +Due to the nature of the source code and the flaws of the `checksrc` tool, +there is sometimes a need to ignore specific warnings. `checksrc` allows a few +different ways to do this. + +### Inline ignore + +You can control what to ignore within a specific source file by providing +instructions to `checksrc` in the source code itself. See examples below. The +instruction can ask to ignore a specific warning a specific number of times or +you ignore all of them until you mark the end of the ignored section. + +Inline ignores are only done for that single specific source code file. + +Example + + /* !checksrc! disable LONGLINE all */ + +This will ignore the warning for overly long lines until it is re-enabled with: + + /* !checksrc! enable LONGLINE */ + +If the enabling is not performed before the end of the file, it will be enabled +automatically for the next file. + +You can also opt to ignore just N violations so that if you have a single long +line you just cannot shorten and is agreed to be fine anyway: + + /* !checksrc! disable LONGLINE 1 */ + +... and the warning for long lines will be enabled again automatically after +it has ignored that single warning. The number `1` can of course be changed to +any other integer number. It can be used to make sure only the exact intended +instances are ignored and nothing extra. + +### Directory wide ignore patterns + +This is a method we have transitioned away from. Use inline ignores as far as +possible. + +Make a `checksrc.skip` file in the directory of the source code with the +false positive, and include the full offending line into this file. diff --git a/docs/CIPHERS.md b/docs/CIPHERS.md new file mode 100644 index 0000000..f616f49 --- /dev/null +++ b/docs/CIPHERS.md @@ -0,0 +1,427 @@ +# Ciphers + +With curl's options +[`CURLOPT_SSL_CIPHER_LIST`](https://curl.se/libcurl/c/CURLOPT_SSL_CIPHER_LIST.html) +and +[`--ciphers`](https://curl.se/docs/manpage.html#--ciphers) +users can control which ciphers to consider when negotiating TLS connections. + +TLS 1.3 ciphers are supported since curl 7.61 for OpenSSL 1.1.1+, and since +curl 7.85 for Schannel with options +[`CURLOPT_TLS13_CIPHERS`](https://curl.se/libcurl/c/CURLOPT_TLS13_CIPHERS.html) +and +[`--tls13-ciphers`](https://curl.se/docs/manpage.html#--tls13-ciphers) +. If you are using a different SSL backend you can try setting TLS 1.3 cipher +suites by using the respective regular cipher option. + +The names of the known ciphers differ depending on which TLS backend that +libcurl was built to use. This is an attempt to list known cipher names. + +## OpenSSL + +(based on [OpenSSL docs](https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html)) + +When specifying multiple cipher names, separate them with colon (`:`). + +### SSL3 cipher suites + +`NULL-MD5` +`NULL-SHA` +`RC4-MD5` +`RC4-SHA` +`IDEA-CBC-SHA` +`DES-CBC3-SHA` +`DH-DSS-DES-CBC3-SHA` +`DH-RSA-DES-CBC3-SHA` +`DHE-DSS-DES-CBC3-SHA` +`DHE-RSA-DES-CBC3-SHA` +`ADH-RC4-MD5` +`ADH-DES-CBC3-SHA` + +### TLS v1.0 cipher suites + +`NULL-MD5` +`NULL-SHA` +`RC4-MD5` +`RC4-SHA` +`IDEA-CBC-SHA` +`DES-CBC3-SHA` +`DHE-DSS-DES-CBC3-SHA` +`DHE-RSA-DES-CBC3-SHA` +`ADH-RC4-MD5` +`ADH-DES-CBC3-SHA` + +### AES cipher suites from RFC 3268, extending TLS v1.0 + +`AES128-SHA` +`AES256-SHA` +`DH-DSS-AES128-SHA` +`DH-DSS-AES256-SHA` +`DH-RSA-AES128-SHA` +`DH-RSA-AES256-SHA` +`DHE-DSS-AES128-SHA` +`DHE-DSS-AES256-SHA` +`DHE-RSA-AES128-SHA` +`DHE-RSA-AES256-SHA` +`ADH-AES128-SHA` +`ADH-AES256-SHA` + +### SEED cipher suites from RFC 4162, extending TLS v1.0 + +`SEED-SHA` +`DH-DSS-SEED-SHA` +`DH-RSA-SEED-SHA` +`DHE-DSS-SEED-SHA` +`DHE-RSA-SEED-SHA` +`ADH-SEED-SHA` + +### GOST cipher suites, extending TLS v1.0 + +`GOST94-GOST89-GOST89` +`GOST2001-GOST89-GOST89` +`GOST94-NULL-GOST94` +`GOST2001-NULL-GOST94` + +### Elliptic curve cipher suites + +`ECDHE-RSA-NULL-SHA` +`ECDHE-RSA-RC4-SHA` +`ECDHE-RSA-DES-CBC3-SHA` +`ECDHE-RSA-AES128-SHA` +`ECDHE-RSA-AES256-SHA` +`ECDHE-ECDSA-NULL-SHA` +`ECDHE-ECDSA-RC4-SHA` +`ECDHE-ECDSA-DES-CBC3-SHA` +`ECDHE-ECDSA-AES128-SHA` +`ECDHE-ECDSA-AES256-SHA` +`AECDH-NULL-SHA` +`AECDH-RC4-SHA` +`AECDH-DES-CBC3-SHA` +`AECDH-AES128-SHA` +`AECDH-AES256-SHA` + +### TLS v1.2 cipher suites + +`NULL-SHA256` +`AES128-SHA256` +`AES256-SHA256` +`AES128-GCM-SHA256` +`AES256-GCM-SHA384` +`DH-RSA-AES128-SHA256` +`DH-RSA-AES256-SHA256` +`DH-RSA-AES128-GCM-SHA256` +`DH-RSA-AES256-GCM-SHA384` +`DH-DSS-AES128-SHA256` +`DH-DSS-AES256-SHA256` +`DH-DSS-AES128-GCM-SHA256` +`DH-DSS-AES256-GCM-SHA384` +`DHE-RSA-AES128-SHA256` +`DHE-RSA-AES256-SHA256` +`DHE-RSA-AES128-GCM-SHA256` +`DHE-RSA-AES256-GCM-SHA384` +`DHE-DSS-AES128-SHA256` +`DHE-DSS-AES256-SHA256` +`DHE-DSS-AES128-GCM-SHA256` +`DHE-DSS-AES256-GCM-SHA384` +`ECDHE-RSA-AES128-SHA256` +`ECDHE-RSA-AES256-SHA384` +`ECDHE-RSA-AES128-GCM-SHA256` +`ECDHE-RSA-AES256-GCM-SHA384` +`ECDHE-ECDSA-AES128-SHA256` +`ECDHE-ECDSA-AES256-SHA384` +`ECDHE-ECDSA-AES128-GCM-SHA256` +`ECDHE-ECDSA-AES256-GCM-SHA384` +`ADH-AES128-SHA256` +`ADH-AES256-SHA256` +`ADH-AES128-GCM-SHA256` +`ADH-AES256-GCM-SHA384` +`AES128-CCM` +`AES256-CCM` +`DHE-RSA-AES128-CCM` +`DHE-RSA-AES256-CCM` +`AES128-CCM8` +`AES256-CCM8` +`DHE-RSA-AES128-CCM8` +`DHE-RSA-AES256-CCM8` +`ECDHE-ECDSA-AES128-CCM` +`ECDHE-ECDSA-AES256-CCM` +`ECDHE-ECDSA-AES128-CCM8` +`ECDHE-ECDSA-AES256-CCM8` + +### Camellia HMAC-Based cipher suites from RFC 6367, extending TLS v1.2 + +`ECDHE-ECDSA-CAMELLIA128-SHA256` +`ECDHE-ECDSA-CAMELLIA256-SHA384` +`ECDHE-RSA-CAMELLIA128-SHA256` +`ECDHE-RSA-CAMELLIA256-SHA384` + +### TLS 1.3 cipher suites + +(Note these ciphers are set with `CURLOPT_TLS13_CIPHERS` and `--tls13-ciphers`) + +`TLS_AES_256_GCM_SHA384` +`TLS_CHACHA20_POLY1305_SHA256` +`TLS_AES_128_GCM_SHA256` +`TLS_AES_128_CCM_8_SHA256` +`TLS_AES_128_CCM_SHA256` + +## WolfSSL + +`RC4-SHA`, +`RC4-MD5`, +`DES-CBC3-SHA`, +`AES128-SHA`, +`AES256-SHA`, +`NULL-SHA`, +`NULL-SHA256`, +`DHE-RSA-AES128-SHA`, +`DHE-RSA-AES256-SHA`, +`DHE-PSK-AES256-GCM-SHA384`, +`DHE-PSK-AES128-GCM-SHA256`, +`PSK-AES256-GCM-SHA384`, +`PSK-AES128-GCM-SHA256`, +`DHE-PSK-AES256-CBC-SHA384`, +`DHE-PSK-AES128-CBC-SHA256`, +`PSK-AES256-CBC-SHA384`, +`PSK-AES128-CBC-SHA256`, +`PSK-AES128-CBC-SHA`, +`PSK-AES256-CBC-SHA`, +`DHE-PSK-AES128-CCM`, +`DHE-PSK-AES256-CCM`, +`PSK-AES128-CCM`, +`PSK-AES256-CCM`, +`PSK-AES128-CCM-8`, +`PSK-AES256-CCM-8`, +`DHE-PSK-NULL-SHA384`, +`DHE-PSK-NULL-SHA256`, +`PSK-NULL-SHA384`, +`PSK-NULL-SHA256`, +`PSK-NULL-SHA`, +`HC128-MD5`, +`HC128-SHA`, +`HC128-B2B256`, +`AES128-B2B256`, +`AES256-B2B256`, +`RABBIT-SHA`, +`NTRU-RC4-SHA`, +`NTRU-DES-CBC3-SHA`, +`NTRU-AES128-SHA`, +`NTRU-AES256-SHA`, +`AES128-CCM-8`, +`AES256-CCM-8`, +`ECDHE-ECDSA-AES128-CCM`, +`ECDHE-ECDSA-AES128-CCM-8`, +`ECDHE-ECDSA-AES256-CCM-8`, +`ECDHE-RSA-AES128-SHA`, +`ECDHE-RSA-AES256-SHA`, +`ECDHE-ECDSA-AES128-SHA`, +`ECDHE-ECDSA-AES256-SHA`, +`ECDHE-RSA-RC4-SHA`, +`ECDHE-RSA-DES-CBC3-SHA`, +`ECDHE-ECDSA-RC4-SHA`, +`ECDHE-ECDSA-DES-CBC3-SHA`, +`AES128-SHA256`, +`AES256-SHA256`, +`DHE-RSA-AES128-SHA256`, +`DHE-RSA-AES256-SHA256`, +`ECDH-RSA-AES128-SHA`, +`ECDH-RSA-AES256-SHA`, +`ECDH-ECDSA-AES128-SHA`, +`ECDH-ECDSA-AES256-SHA`, +`ECDH-RSA-RC4-SHA`, +`ECDH-RSA-DES-CBC3-SHA`, +`ECDH-ECDSA-RC4-SHA`, +`ECDH-ECDSA-DES-CBC3-SHA`, +`AES128-GCM-SHA256`, +`AES256-GCM-SHA384`, +`DHE-RSA-AES128-GCM-SHA256`, +`DHE-RSA-AES256-GCM-SHA384`, +`ECDHE-RSA-AES128-GCM-SHA256`, +`ECDHE-RSA-AES256-GCM-SHA384`, +`ECDHE-ECDSA-AES128-GCM-SHA256`, +`ECDHE-ECDSA-AES256-GCM-SHA384`, +`ECDH-RSA-AES128-GCM-SHA256`, +`ECDH-RSA-AES256-GCM-SHA384`, +`ECDH-ECDSA-AES128-GCM-SHA256`, +`ECDH-ECDSA-AES256-GCM-SHA384`, +`CAMELLIA128-SHA`, +`DHE-RSA-CAMELLIA128-SHA`, +`CAMELLIA256-SHA`, +`DHE-RSA-CAMELLIA256-SHA`, +`CAMELLIA128-SHA256`, +`DHE-RSA-CAMELLIA128-SHA256`, +`CAMELLIA256-SHA256`, +`DHE-RSA-CAMELLIA256-SHA256`, +`ECDHE-RSA-AES128-SHA256`, +`ECDHE-ECDSA-AES128-SHA256`, +`ECDH-RSA-AES128-SHA256`, +`ECDH-ECDSA-AES128-SHA256`, +`ECDHE-RSA-AES256-SHA384`, +`ECDHE-ECDSA-AES256-SHA384`, +`ECDH-RSA-AES256-SHA384`, +`ECDH-ECDSA-AES256-SHA384`, +`ECDHE-RSA-CHACHA20-POLY1305`, +`ECDHE-ECDSA-CHACHA20-POLY1305`, +`DHE-RSA-CHACHA20-POLY1305`, +`ECDHE-RSA-CHACHA20-POLY1305-OLD`, +`ECDHE-ECDSA-CHACHA20-POLY1305-OLD`, +`DHE-RSA-CHACHA20-POLY1305-OLD`, +`ADH-AES128-SHA`, +`QSH`, +`RENEGOTIATION-INFO`, +`IDEA-CBC-SHA`, +`ECDHE-ECDSA-NULL-SHA`, +`ECDHE-PSK-NULL-SHA256`, +`ECDHE-PSK-AES128-CBC-SHA256`, +`PSK-CHACHA20-POLY1305`, +`ECDHE-PSK-CHACHA20-POLY1305`, +`DHE-PSK-CHACHA20-POLY1305`, +`EDH-RSA-DES-CBC3-SHA`, + +## Schannel + +Schannel allows the enabling and disabling of encryption algorithms, but not +specific cipher suites, prior to TLS 1.3. The algorithms are +[defined](https://docs.microsoft.com/windows/desktop/SecCrypto/alg-id) by +Microsoft. + +The algorithms below are for TLS 1.2 and earlier. TLS 1.3 is covered in the +next section. + +There is also the case that the selected algorithm is not supported by the +protocol or does not match the ciphers offered by the server during the SSL +negotiation. In this case curl will return error +`CURLE_SSL_CONNECT_ERROR (35) SEC_E_ALGORITHM_MISMATCH` +and the request will fail. + +`CALG_MD2`, +`CALG_MD4`, +`CALG_MD5`, +`CALG_SHA`, +`CALG_SHA1`, +`CALG_MAC`, +`CALG_RSA_SIGN`, +`CALG_DSS_SIGN`, +`CALG_NO_SIGN`, +`CALG_RSA_KEYX`, +`CALG_DES`, +`CALG_3DES_112`, +`CALG_3DES`, +`CALG_DESX`, +`CALG_RC2`, +`CALG_RC4`, +`CALG_SEAL`, +`CALG_DH_SF`, +`CALG_DH_EPHEM`, +`CALG_AGREEDKEY_ANY`, +`CALG_HUGHES_MD5`, +`CALG_SKIPJACK`, +`CALG_TEK`, +`CALG_CYLINK_MEK`, +`CALG_SSL3_SHAMD5`, +`CALG_SSL3_MASTER`, +`CALG_SCHANNEL_MASTER_HASH`, +`CALG_SCHANNEL_MAC_KEY`, +`CALG_SCHANNEL_ENC_KEY`, +`CALG_PCT1_MASTER`, +`CALG_SSL2_MASTER`, +`CALG_TLS1_MASTER`, +`CALG_RC5`, +`CALG_HMAC`, +`CALG_TLS1PRF`, +`CALG_HASH_REPLACE_OWF`, +`CALG_AES_128`, +`CALG_AES_192`, +`CALG_AES_256`, +`CALG_AES`, +`CALG_SHA_256`, +`CALG_SHA_384`, +`CALG_SHA_512`, +`CALG_ECDH`, +`CALG_ECMQV`, +`CALG_ECDSA`, +`CALG_ECDH_EPHEM`, + +As of curl 7.77.0, you can also pass `SCH_USE_STRONG_CRYPTO` as a cipher name +to [constrain the set of available ciphers as specified in the Schannel +documentation](https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022). +Note that the supported ciphers in this case follow the OS version, so if you +are running an outdated OS you might still be supporting weak ciphers. + +### TLS 1.3 cipher suites + +You can set TLS 1.3 ciphers for Schannel by using `CURLOPT_TLS13_CIPHERS` or +`--tls13-ciphers` with the names below. + +If TLS 1.3 cipher suites are set then libcurl will add or restrict Schannel TLS +1.3 algorithms automatically. Essentially, libcurl is emulating support for +individual TLS 1.3 cipher suites since Schannel does not support it directly. + +`TLS_AES_256_GCM_SHA384` +`TLS_AES_128_GCM_SHA256` +`TLS_CHACHA20_POLY1305_SHA256` +`TLS_AES_128_CCM_8_SHA256` +`TLS_AES_128_CCM_SHA256` + +Note if you set TLS 1.3 ciphers without also setting the minimum TLS version +to 1.3 then it is possible Schannel may negotiate an earlier TLS version and +cipher suite if your libcurl and OS settings allow it. You can set the minimum +TLS version by using `CURLOPT_SSLVERSION` or `--tlsv1.3`. + +## BearSSL + +BearSSL ciphers can be specified by either the OpenSSL name (`ECDHE-RSA-AES128-GCM-SHA256`) or the IANA name (`TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`). + +Since BearSSL 0.1: + +`DES-CBC3-SHA` +`AES128-SHA` +`AES256-SHA` +`AES128-SHA256` +`AES256-SHA256` +`AES128-GCM-SHA256` +`AES256-GCM-SHA384` +`ECDH-ECDSA-DES-CBC3-SHA` +`ECDH-ECDSA-AES128-SHA` +`ECDH-ECDSA-AES256-SHA` +`ECDHE-ECDSA-DES-CBC3-SHA` +`ECDHE-ECDSA-AES128-SHA` +`ECDHE-ECDSA-AES256-SHA` +`ECDH-RSA-DES-CBC3-SHA` +`ECDH-RSA-AES128-SHA` +`ECDH-RSA-AES256-SHA` +`ECDHE-RSA-DES-CBC3-SHA` +`ECDHE-RSA-AES128-SHA` +`ECDHE-RSA-AES256-SHA` +`ECDHE-ECDSA-AES128-SHA256` +`ECDHE-ECDSA-AES256-SHA384` +`ECDH-ECDSA-AES128-SHA256` +`ECDH-ECDSA-AES256-SHA384` +`ECDHE-RSA-AES128-SHA256` +`ECDHE-RSA-AES256-SHA384` +`ECDH-RSA-AES128-SHA256` +`ECDH-RSA-AES256-SHA384` +`ECDHE-ECDSA-AES128-GCM-SHA256` +`ECDHE-ECDSA-AES256-GCM-SHA384` +`ECDH-ECDSA-AES128-GCM-SHA256` +`ECDH-ECDSA-AES256-GCM-SHA384` +`ECDHE-RSA-AES128-GCM-SHA256` +`ECDHE-RSA-AES256-GCM-SHA384` +`ECDH-RSA-AES128-GCM-SHA256` +`ECDH-RSA-AES256-GCM-SHA384` + +Since BearSSL 0.2: + +`ECDHE-RSA-CHACHA20-POLY1305` +`ECDHE-ECDSA-CHACHA20-POLY1305` + +Since BearSSL 0.6: + +`AES128-CCM` +`AES256-CCM` +`AES128-CCM8` +`AES256-CCM8` +`ECDHE-ECDSA-AES128-CCM` +`ECDHE-ECDSA-AES256-CCM` +`ECDHE-ECDSA-AES128-CCM8` +`ECDHE-ECDSA-AES256-CCM8` diff --git a/docs/CLIENT-WRITERS.md b/docs/CLIENT-WRITERS.md new file mode 100644 index 0000000..7a92882 --- /dev/null +++ b/docs/CLIENT-WRITERS.md @@ -0,0 +1,104 @@ +# curl client writers + +Client writers is a design in the internals of libcurl, not visible in its public API. They were started +in curl v8.5.0. This document describes the concepts, its high level implementation and the motivations. + +## Naming + +`libcurl` operates between clients and servers. A *client* is the application using libcurl, like the command line tool `curl` itself. Data to be uploaded to a server is **read** from the client and **send** to the server, the servers response is **received** by `libcurl` and then **written** to the client. + +With this naming established, client writers are concerned with writing responses from the server to the application. Applications register callbacks via `CURLOPT_WRITEFUNCTION` and `CURLOPT_HEADERFUNCTION` to be invoked by `libcurl` when the response is received. + +## Invoking + +All code in `libcurl` that handles response data is ultimately expected to forward this data via `Curl_client_write()` to the application. The exact prototype of this function is: + +``` +CURLcode Curl_client_write(struct Curl_easy *data, int type, char *buf, size_t blen); +``` +The `type` argument specifies what the bytes in `buf` actually are. The following bits are defined: + +``` +#define CLIENTWRITE_BODY (1<<0) /* non-meta information, BODY */ +#define CLIENTWRITE_INFO (1<<1) /* meta information, not a HEADER */ +#define CLIENTWRITE_HEADER (1<<2) /* meta information, HEADER */ +#define CLIENTWRITE_STATUS (1<<3) /* a special status HEADER */ +#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */ +#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */ +#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */ +``` + +The main types here are `CLIENTWRITE_BODY` and `CLIENTWRITE_HEADER`. They are +mutually exclusive. The other bits are enhancements to `CLIENTWRITE_HEADER` to +specify what the header is about. They are only used in HTTP and related +protocols (RTSP and WebSocket). + +The implementation of `Curl_client_write()` uses a chain of *client writer* instances to process the call and make sure that the bytes reach the proper application callbacks. This is similar to the design of connection filters: client writers can be chained to process the bytes written through them. The definition is: + +``` +struct Curl_cwtype { + const char *name; + CURLcode (*do_init)(struct Curl_easy *data, + struct Curl_cwriter *writer); + CURLcode (*do_write)(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes); + void (*do_close)(struct Curl_easy *data, + struct Curl_cwriter *writer); +}; + +struct Curl_cwriter { + const struct Curl_cwtype *cwt; /* type implementation */ + struct Curl_cwriter *next; /* Downstream writer. */ + Curl_cwriter_phase phase; /* phase at which it operates */ +}; +``` + +`Curl_cwriter` is a writer instance with a `next` pointer to form the chain. It has a type `cwt` which provides the implementation. The main callback is `do_write()` that processes the data and calls then the `next` writer. The others are for setup and tear down. + +## Phases and Ordering + +Since client writers may transform the bytes written through them, the order in which the are called is relevant for the outcome. When a writer is created, one property it gets is the `phase` in which it operates. Writer phases are defined like: + +``` +typedef enum { + CURL_CW_RAW, /* raw data written, before any decoding */ + CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */ + CURL_CW_PROTOCOL, /* after transfer, but before content decoding */ + CURL_CW_CONTENT_DECODE, /* remove content-encodings */ + CURL_CW_CLIENT /* data written to client */ +} Curl_cwriter_phase; +``` + +If a writer for phase `PROTOCOL` is added to the chain, it is always added *after* any `RAW` or `TRANSFER_DECODE` and *before* any `CONTENT_DECODE` and `CLIENT` phase writer. If there is already a writer for the same phase present, the new writer is inserted just before that one. + +All transfers have a chain of 3 writers by default. A specific protocol handler may alter that by adding additional writers. The 3 standard writers are (name, phase): + +1. `"raw", CURL_CW_RAW `: if the transfer is verbose, it forwards the body data to the debug function. +1. `"download", CURL_CW_PROTOCOL`: checks that protocol limits are kept and updates progress counters. When a download has a known length, it checks that it is not exceeded and errors otherwise. +1. `"client", CURL_CW_CLIENT`: the main work horse. It invokes the application callbacks or writes to the configured file handles. It chops large writes into smaller parts, as documented for `CURLOPT_WRITEFUNCTION`. If also handles *pausing* of transfers when the application callback returns `CURL_WRITEFUNC_PAUSE`. + +With these writers always in place, libcurl's protocol handlers automatically have these implemented. + +## Enhanced Use + +HTTP is the protocol in curl that makes use of the client writer chain by adding writers to it. When the `libcurl` application set `CURLOPT_ACCEPT_ENCODING` (as `curl` does with `--compressed`), the server is offered an `Accept-Encoding` header with the algorithms supported. The server then may choose to send the response body compressed. For example using `gzip` or `brotli` or even both. + +In the server's response, there then will be a `Content-Encoding` header listing the encoding applied. If supported by `libcurl` it will then decompress the content before writing it out to the client. How does it do that? + +The HTTP protocol will add client writers in phase `CURL_CW_CONTENT_DECODE` on seeing such a header. For each encoding listed, it will add the corresponding writer. The response from the server is then passed through `Curl_client_write()` to the writers that decode it. If several encodings had been applied the writer chain decodes them in the proper order. + +When the server provides a `Content-Length` header, that value applies to the *compressed* content. So length checks on the response bytes must happen *before* it gets decoded. That is why this check happens in phase `CURL_CW_PROTOCOL` which always is ordered before writers in phase `CURL_CW_CONTENT_DECODE`. + +What else? + +Well, HTTP servers may also apply a `Transfer-Encoding` to the body of a response. The most well-known one is `chunked`, but algorithms like `gzip` and friends could also be applied. The difference to content encodings is that decoding needs to happen *before* protocol checks, for example on length, are done. + +That is why transfer decoding writers are added for phase `CURL_CW_TRANSFER_DECODE`. Which makes their operation happen *before* phase `CURL_CW_PROTOCOL` where length may be checked. + +## Summary + +By adding the common behavior of all protocols into `Curl_client_write()` we make sure that they do apply everywhere. Protocol handler have less to worry about. Changes to default behavior can be done without affecting handler implementations. + +Having a writer chain as implementation allows protocol handlers with extra needs, like HTTP, to add to this for special behavior. The common way of writing the actual response data stays the same. + diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 0000000..9c0b376 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,30 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +#add_subdirectory(examples) +if(BUILD_LIBCURL_DOCS) + add_subdirectory(libcurl) +endif() +if(ENABLE_CURL_MANUAL AND BUILD_CURL_EXE) + add_subdirectory(cmdline-opts) +endif() diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..1f71c38 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,32 @@ +Contributor Code of Conduct +=========================== + +As contributors and maintainers of this project, we pledge to respect all +people who contribute through reporting issues, posting feature requests, +updating documentation, submitting pull requests or patches, and other +activities. + +We are committed to making participation in this project a harassment-free +experience for everyone, regardless of level of experience, gender, gender +identity and expression, sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, or religion. + +Examples of unacceptable behavior by participants include the use of sexual +language or imagery, derogatory comments or personal attacks, trolling, public +or private harassment, insults, or other unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct. Project maintainers who do not +follow the Code of Conduct may be removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by opening an issue or contacting one or more of the project +maintainers. + +This Code of Conduct is adapted from the [Contributor +Covenant](https://contributor-covenant.org/), version 1.1.0, available at +[https://contributor-covenant.org/version/1/1/0/](https://contributor-covenant.org/version/1/1/0/) diff --git a/docs/CODE_REVIEW.md b/docs/CODE_REVIEW.md new file mode 100644 index 0000000..0776d30 --- /dev/null +++ b/docs/CODE_REVIEW.md @@ -0,0 +1,168 @@ +# How to do code reviews for curl + +Anyone and everyone is encouraged and welcome to review code submissions in +curl. This is a guide on what to check for and how to perform a successful +code review. + +## All submissions should get reviewed + +All pull requests and patches submitted to the project should be reviewed by +at least one experienced curl maintainer before that code is accepted and +merged. + +## Let the tools and tests take the first rounds + +On initial pull requests, let the tools and tests do their job first and then +start out by helping the submitter understand the test failures and tool +alerts. + +## How to provide feedback to author + +Be nice. Ask questions. Provide examples or suggestions of improvements. +Assume the best intentions. Remember language barriers. + +All first-time contributors can become regulars. Let's help them go there. + +## Is this a change we want? + +If this is not a change that seems to be aligned with the project's path +forward and as such cannot be accepted, inform the author about this sooner +rather than later. Do it gently and explain why and possibly what could be +done to make it more acceptable. + +## API/ABI stability or changed behavior + +Changing the API and the ABI may be fine in a change but it needs to be done +deliberately and carefully. If not, a reviewer must help the author to realize +the mistake. + +curl and libcurl are similarly strict on not modifying existing behavior. API +and ABI stability is not enough, the behavior should also remain intact as far +as possible. + +## Code style + +Most code style nits are detected by checksrc but not all. Only leave remarks +on style deviation once checksrc does not find anymore. + +Minor nits from fresh submitters can also be handled by the maintainer when +merging, in case it seems like the submitter is not clear on what to do. We +want to make the process fun and exciting for new contributors. + +## Encourage consistency + +Make sure new code is written in a similar style as existing code. Naming, +logic, conditions, etc. + +## Are pointers always non-NULL? + +If a function or code rely on pointers being non-NULL, take an extra look if +that seems to be a fair assessment. + +## Asserts + +Conditions that should never be false can be verified with `DEBUGASSERT()` +calls to get caught in tests and debugging easier, while not having an impact +on final or release builds. + +## Memory allocation + +Can the mallocs be avoided? Do not introduce mallocs in any hot paths. If +there are (new) mallocs, can they be combined into fewer calls? + +Are all allocations handled in error paths to avoid leaks and crashes? + +## Thread-safety + +We do not like static variables as they break thread-safety and prevent +functions from being reentrant. + +## Should features be `#ifdef`ed? + +Features and functionality may not be present everywhere and should therefore +be `#ifdef`ed. Additionally, some features should be possible to switch on/off +in the build. + +Write `#ifdef`s to be as little of a "maze" as possible. + +## Does it look portable enough? + +curl runs "everywhere". Does the code take a reasonable stance and enough +precautions to be possible to build and run on most platforms? + +Remember that we live by C89 restrictions. + +## Tests and testability + +New features should be added in conjunction with one or more test cases. +Ideally, functions should also be written so that unit tests can be done to +test individual functions. + +## Documentation + +New features or changes to existing functionality **must** be accompanied by +updated documentation. Submitting that in a separate follow-up pull request is +not OK. A code review must also verify that the submitted documentation update +matches the code submission. + +English is not everyone's first language, be mindful of this and help the +submitter improve the text if it needs a rewrite to read better. + +## Code should not be hard to understand + +Source code should be written to maximize readability and be easy to +understand. + +## Functions should not be large + +A single function should never be large as that makes it hard to follow and +understand all the exit points and state changes. Some existing functions in +curl certainly violate this ground rule but when reviewing new code we should +propose splitting into smaller functions. + +## Duplication is evil + +Anything that looks like duplicated code is a red flag. Anything that seems to +introduce code that we *should* already have or provide needs a closer check. + +## Sensitive data + +When credentials are involved, take an extra look at what happens with this +data. Where it comes from and where it goes. + +## Variable types differ + +`size_t` is not a fixed size. `time_t` can be signed or unsigned and have +different sizes. Relying on variable sizes is a red flag. + +Also remember that endianness and >= 32 bit accesses to unaligned addresses +are problematic areas. + +## Integer overflows + +Be careful about integer overflows. Some variable types can be either 32 bit +or 64 bit. Integer overflows must be detected and acted on *before* they +happen. + +## Dangerous use of functions + +Maybe use of `realloc()` should rather use the dynbuf functions? + +Do not allow new code that grows buffers without using dynbuf. + +Use of C functions that rely on a terminating zero must only be used on data +that really do have a null-terminating zero. + +## Dangerous "data styles" + +Make extra precautions and verify that memory buffers that need a terminating +zero always have exactly that. Buffers *without* a null-terminator must not be +used as input to string functions. + +# Commit messages + +Tightly coupled with a code review is making sure that the commit message is +good. It is the responsibility of the person who merges the code to make sure +that the commit message follows our standard (detailed in the +[CONTRIBUTE](CONTRIBUTE.md) document). This includes making sure the PR +identifies related issues and giving credit to reporters and helpers. diff --git a/docs/CODE_STYLE.md b/docs/CODE_STYLE.md new file mode 100644 index 0000000..e6af360 --- /dev/null +++ b/docs/CODE_STYLE.md @@ -0,0 +1,310 @@ +# curl C code style + +Source code that has a common style is easier to read than code that uses +different styles in different places. It helps making the code feel like one +single code base. Easy-to-read is an important property of code and helps +making it easier to review when new things are added and it helps debugging +code when developers are trying to figure out why things go wrong. A unified +style is more important than individual contributors having their own personal +tastes satisfied. + +Our C code has a few style rules. Most of them are verified and upheld by the +`scripts/checksrc.pl` script. Invoked with `make checksrc` or even by default +by the build system when built after `./configure --enable-debug` has been +used. + +It is normally not a problem for anyone to follow the guidelines, as you just +need to copy the style already used in the source code and there are no +particularly unusual rules in our set of rules. + +We also work hard on writing code that are warning-free on all the major +platforms and in general on as many platforms as possible. Code that obviously +will cause warnings will not be accepted as-is. + +## Naming + +Try using a non-confusing naming scheme for your new functions and variable +names. It does not necessarily have to mean that you should use the same as in +other places of the code, just that the names should be logical, +understandable and be named according to what they are used for. File-local +functions should be made static. We like lower case names. + +See the [INTERNALS](https://curl.se/dev/internals.html#symbols) document on +how we name non-exported library-global symbols. + +## Indenting + +We use only spaces for indentation, never TABs. We use two spaces for each new +open brace. + +```c +if(something_is_true) { + while(second_statement == fine) { + moo(); + } +} +``` + +## Comments + +Since we write C89 code, **//** comments are not allowed. They were not +introduced in the C standard until C99. We use only __/* comments */__. + +```c +/* this is a comment */ +``` + +## Long lines + +Source code in curl may never be wider than 79 columns and there are two +reasons for maintaining this even in the modern era of large and high +resolution screens: + +1. Narrower columns are easier to read than wide ones. There is a reason + newspapers have used columns for decades or centuries. + +2. Narrower columns allow developers to easier show multiple pieces of code + next to each other in different windows. It allows two or three source + code windows next to each other on the same screen - as well as multiple + terminal and debugging windows. + +## Braces + +In if/while/do/for expressions, we write the open brace on the same line as +the keyword and we then set the closing brace on the same indentation level as +the initial keyword. Like this: + +```c +if(age < 40) { + /* clearly a youngster */ +} +``` + +You may omit the braces if they would contain only a one-line statement: + +```c +if(!x) + continue; +``` + +For functions the opening brace should be on a separate line: + +```c +int main(int argc, char **argv) +{ + return 1; +} +``` + +## 'else' on the following line + +When adding an **else** clause to a conditional expression using braces, we +add it on a new line after the closing brace. Like this: + +```c +if(age < 40) { + /* clearly a youngster */ +} +else { + /* probably grumpy */ +} +``` + +## No space before parentheses + +When writing expressions using if/while/do/for, there shall be no space +between the keyword and the open parenthesis. Like this: + +```c +while(1) { + /* loop forever */ +} +``` + +## Use boolean conditions + +Rather than test a conditional value such as a bool against TRUE or FALSE, a +pointer against NULL or != NULL and an int against zero or not zero in +if/while conditions we prefer: + +```c +result = do_something(); +if(!result) { + /* something went wrong */ + return result; +} +``` + +## No assignments in conditions + +To increase readability and reduce complexity of conditionals, we avoid +assigning variables within if/while conditions. We frown upon this style: + +```c +if((ptr = malloc(100)) == NULL) + return NULL; +``` + +and instead we encourage the above version to be spelled out more clearly: + +```c +ptr = malloc(100); +if(!ptr) + return NULL; +``` + +## New block on a new line + +We never write multiple statements on the same source line, even for short +if() conditions. + +```c +if(a) + return TRUE; +else if(b) + return FALSE; +``` + +and NEVER: + +```c +if(a) return TRUE; +else if(b) return FALSE; +``` + +## Space around operators + +Please use spaces on both sides of operators in C expressions. Postfix **(), +[], ->, ., ++, --** and Unary **+, -, !, ~, &** operators excluded they should +have no space. + +Examples: + +```c +bla = func(); +who = name[0]; +age += 1; +true = !false; +size += -2 + 3 * (a + b); +ptr->member = a++; +struct.field = b--; +ptr = &address; +contents = *pointer; +complement = ~bits; +empty = (!*string) ? TRUE : FALSE; +``` + +## No parentheses for return values + +We use the 'return' statement without extra parentheses around the value: + +```c +int works(void) +{ + return TRUE; +} +``` + +## Parentheses for sizeof arguments + +When using the sizeof operator in code, we prefer it to be written with +parentheses around its argument: + +```c +int size = sizeof(int); +``` + +## Column alignment + +Some statements cannot be completed on a single line because the line would be +too long, the statement too hard to read, or due to other style guidelines +above. In such a case the statement will span multiple lines. + +If a continuation line is part of an expression or sub-expression then you +should align on the appropriate column so that it is easy to tell what part of +the statement it is. Operators should not start continuation lines. In other +cases follow the 2-space indent guideline. Here are some examples from +libcurl: + +```c +if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && + (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && + (handle->set.httpreq == HTTPREQ_GET || + handle->set.httpreq == HTTPREQ_HEAD)) + /* did not ask for HTTP/1.0 and a GET or HEAD */ + return TRUE; +``` + +If no parenthesis, use the default indent: + +```c +data->set.http_disable_hostname_check_before_authentication = + (0 != va_arg(param, long)) ? TRUE : FALSE; +``` + +Function invoke with an open parenthesis: + +```c +if(option) { + result = parse_login_details(option, strlen(option), + (userp ? &user : NULL), + (passwdp ? &passwd : NULL), + NULL); +} +``` + +Align with the "current open" parenthesis: + +```c +DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing " + "server response left\n", + (int)clipamount)); +``` + +## Platform dependent code + +Use **#ifdef HAVE_FEATURE** to do conditional code. We avoid checking for +particular operating systems or hardware in the #ifdef lines. The HAVE_FEATURE +shall be generated by the configure script for unix-like systems and they are +hard-coded in the `config-[system].h` files for the others. + +We also encourage use of macros/functions that possibly are empty or defined +to constants when libcurl is built without that feature, to make the code +seamless. Like this example where the **magic()** function works differently +depending on a build-time conditional: + +```c +#ifdef HAVE_MAGIC +void magic(int a) +{ + return a + 2; +} +#else +#define magic(x) 1 +#endif + +int content = magic(3); +``` + +## No typedefed structs + +Use structs by all means, but do not typedef them. Use the `struct name` way +of identifying them: + +```c +struct something { + void *valid; + size_t way_to_write; +}; +struct something instance; +``` + +**Not okay**: + +```c +typedef struct { + void *wrong; + size_t way_to_write; +} something; +something instance; +``` diff --git a/docs/CONNECTION-FILTERS.md b/docs/CONNECTION-FILTERS.md new file mode 100644 index 0000000..a145d42 --- /dev/null +++ b/docs/CONNECTION-FILTERS.md @@ -0,0 +1,242 @@ +# curl connection filters + +Connection filters is a design in the internals of curl, not visible in its +public API. They were added in curl v7.87.0. This document describes the +concepts, its high level implementation and the motivations. + +## Filters + +A "connection filter" is a piece of code that is responsible for handling a +range of operations of curl's connections: reading, writing, waiting on +external events, connecting and closing down - to name the most important +ones. + +The most important feat of connection filters is that they can be stacked on +top of each other (or "chained" if you prefer that metaphor). In the common +scenario that you want to retrieve a `https:` URL with curl, you need 2 basic +things to send the request and get the response: a TCP connection, represented +by a `socket` and a SSL instance en- and decrypt over that socket. You write +your request to the SSL instance, which encrypts and writes that data to the +socket, which then sends the bytes over the network. + +With connection filters, curl's internal setup will look something like this +(cf for connection filter): + +``` +Curl_easy *data connectdata *conn cf-ssl cf-socket ++----------------+ +-----------------+ +-------+ +--------+ +|https://curl.se/|----> | properties |----> | keys |---> | socket |--> OS --> network ++----------------+ +-----------------+ +-------+ +--------+ + + Curl_write(data, buffer) + --> Curl_cfilter_write(data, data->conn, buffer) + ---> conn->filter->write(conn->filter, data, buffer) +``` + +While connection filters all do different things, they look the same from the "outside". The code in `data` and `conn` does not really know **which** filters are installed. `conn` just writes into the first filter, whatever that is. + +Same is true for filters. Each filter has a pointer to the `next` filter. When SSL has encrypted the data, it does not write to a socket, it writes to the next filter. If that is indeed a socket, or a file, or an HTTP/2 connection is of no concern to the SSL filter. + +This allows stacking, as in: + +``` +Direct: + http://localhost/ conn -> cf-socket + https://curl.se/ conn -> cf-ssl -> cf-socket +Via http proxy tunnel: + http://localhost/ conn -> cf-http-proxy -> cf-socket + https://curl.se/ conn -> cf-ssl -> cf-http-proxy -> cf-socket +Via https proxy tunnel: + http://localhost/ conn -> cf-http-proxy -> cf-ssl -> cf-socket + https://curl.se/ conn -> cf-ssl -> cf-http-proxy -> cf-ssl -> cf-socket +Via http proxy tunnel via SOCKS proxy: + http://localhost/ conn -> cf-http-proxy -> cf-socks -> cf-socket +``` + +### Connecting/Closing + +Before `Curl_easy` can send the request, the connection needs to be established. This means that all connection filters have done, whatever they need to do: waiting for the socket to be connected, doing the TLS handshake, performing the HTTP tunnel request, etc. This has to be done in reverse order: the last filter has to do its connect first, then the one above can start, etc. + +Each filter does in principle the following: + +``` +static CURLcode +myfilter_cf_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + CURLcode result; + + if(cf->connected) { /* we and all below are done */ + *done = TRUE; + return CURLE_OK; + } + /* Let the filters below connect */ + result = cf->next->cft->connect(cf->next, data, blocking, done); + if(result || !*done) + return result; /* below errored/not finished yet */ + + /* MYFILTER CONNECT THINGS */ /* below connected, do out thing */ + *done = cf->connected = TRUE; /* done, remember, return */ + return CURLE_OK; +} +``` + +Closing a connection then works similar. The `conn` tells the first filter to close. Contrary to connecting, +the filter does its own things first, before telling the next filter to close. + +### Efficiency + +There are two things curl is concerned about: efficient memory use and fast transfers. + +The memory footprint of a filter is relatively small: + +``` +struct Curl_cfilter { + const struct Curl_cftype *cft; /* the type providing implementation */ + struct Curl_cfilter *next; /* next filter in chain */ + void *ctx; /* filter type specific settings */ + struct connectdata *conn; /* the connection this filter belongs to */ + int sockindex; /* TODO: like to get rid off this */ + BIT(connected); /* != 0 iff this filter is connected */ +}; +``` +The filter type `cft` is a singleton, one static struct for each type of filter. The `ctx` is where a filter will hold its specific data. That varies by filter type. An http-proxy filter will keep the ongoing state of the CONNECT here, but free it after its has been established. The SSL filter will keep the `SSL*` (if OpenSSL is used) here until the connection is closed. So, this varies. + +`conn` is a reference to the connection this filter belongs to, so nothing extra besides the pointer itself. + +Several things, that before were kept in `struct connectdata`, will now go into the `filter->ctx` *when needed*. So, the memory footprint for connections that do *not* use an http proxy, or socks, or https will be lower. + +As to transfer efficiency, writing and reading through a filter comes at near zero cost *if the filter does not transform the data*. An http proxy or socks filter, once it is connected, will just pass the calls through. Those filters implementations will look like this: + +``` +ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + return cf->next->cft->do_send(cf->next, data, buf, len, err); +} +``` +The `recv` implementation is equivalent. + +## Filter Types + +The currently existing filter types (curl 8.5.0) are: + +* `TCP`, `UDP`, `UNIX`: filters that operate on a socket, providing raw I/O. +* `SOCKET-ACCEPT`: special TCP socket that has a socket that has been `accept()`ed in a `listen()` +* `SSL`: filter that applies TLS en-/decryption and handshake. Manages the underlying TLS backend implementation. +* `HTTP-PROXY`, `H1-PROXY`, `H2-PROXY`: the first manages the connection to an + HTTP proxy server and uses the other depending on which ALPN protocol has + been negotiated. +* `SOCKS-PROXY`: filter for the various SOCKS proxy protocol variations +* `HAPROXY`: filter for the protocol of the same name, providing client IP information to a server. +* `HTTP/2`: filter for handling multiplexed transfers over an HTTP/2 connection +* `HTTP/3`: filter for handling multiplexed transfers over an HTTP/3+QUIC connection +* `HAPPY-EYEBALLS`: meta filter that implements IPv4/IPv6 "happy eyeballing". It creates up to 2 sub-filters that race each other for a connection. +* `SETUP`: meta filter that manages the creation of sub-filter chains for a specific transport (e.g. TCP or QUIC). +* `HTTPS-CONNECT`: meta filter that races a TCP+TLS and a QUIC connection against each other to determine if HTTP/1.1, HTTP/2 or HTTP/3 shall be used for a transfer. + +Meta filters are combining other filters for a specific purpose, mostly during connection establishment. Other filters like `TCP`, `UDP` and `UNIX` are only to be found at the end of filter chains. SSL filters provide encryption, of course. Protocol filters change the bytes sent and received. + +## Filter Flags + +Filter types carry flags that inform what they do. These are (for now): + +* `CF_TYPE_IP_CONNECT`: this filter type talks directly to a server. This does not have to be the server the transfer wants to talk to. For example when a proxy server is used. +* `CF_TYPE_SSL`: this filter type provides encryption. +* `CF_TYPE_MULTIPLEX`: this filter type can manage multiple transfers in parallel. + +Filter types can combine these flags. For example, the HTTP/3 filter types have `CF_TYPE_IP_CONNECT`, `CF_TYPE_SSL` and `CF_TYPE_MULTIPLEX` set. + +Flags are useful to extrapolate properties of a connection. To check if a connection is encrypted, libcurl inspect the filter chain in place, top down, for `CF_TYPE_SSL`. If it finds `CF_TYPE_IP_CONNECT` before any `CF_TYPE_SSL`, the connection is not encrypted. + +For example, `conn1` is for a `http:` request using a tunnel through a HTTP/2 `https:` proxy. `conn2` is a `https:` HTTP/2 connection to the same proxy. `conn3` uses HTTP/3 without proxy. The filter chains would look like this (simplified): + +``` +conn1 --> `HTTP-PROXY` --> `H2-PROXY` --> `SSL` --> `TCP` +flags: `IP_CONNECT` `SSL` `IP_CONNECT` + +conn2 --> `HTTP/2` --> `SSL` --> `HTTP-PROXY` --> `H2-PROXY` --> `SSL` --> `TCP` +flags: `SSL` `IP_CONNECT` `SSL` `IP_CONNECT` + +conn3 --> `HTTP/3` +flags: `SSL|IP_CONNECT` +``` + +Inspecting the filter chains, `conn1` is seen as unencrypted, since it contains an `IP_CONNECT` filter before any `SSL`. `conn2` is clearly encrypted as an `SSL` flagged filter is seen first. `conn3` is also encrypted as the `SSL` flag is checked before the presence of `IP_CONNECT`. + +Similar checks can determine if a connection is multiplexed or not. + +## Filter Tracing + +Filters may make use of special trace macros like `CURL_TRC_CF(data, cf, msg, ...)`. With `data` being the transfer and `cf` being the filter instance. These traces are normally not active and their execution is guarded so that they are cheap to ignore. + +Users of `curl` may activate them by adding the name of the filter type to the +`--trace-config` argument. For example, in order to get more detailed tracing +of an HTTP/2 request, invoke curl with: + +``` +> curl -v --trace-config ids,time,http/2 https://curl.se +``` +Which will give you trace output with time information, transfer+connection ids and details from the `HTTP/2` filter. Filter type names in the trace config are case insensitive. You may use `all` to enable tracing for all filter types. When using `libcurl` you may call `curl_global_trace(config_string)` at the start of your application to enable filter details. + +## Meta Filters + +Meta filters is a catch-all name for filter types that do not change the transfer data in any way but provide other important services to curl. In general, it is possible to do all sorts of silly things with them. One of the commonly used, important things is "eyeballing". + +The `HAPPY-EYEBALLS` filter is involved in the connect phase. Its job is to +try the various IPv4 and IPv6 addresses that are known for a server. If only +one address family is known (or configured), it tries the addresses one after +the other with timeouts calculated from the amount of addresses and the +overall connect timeout. + +When more than one address family is to be tried, it splits the address list into IPv4 and IPv6 and makes parallel attempts. The connection filter chain will look like this: + +``` +* create connection for http://curl.se +conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> NULL +* start connect +conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> NULL + - ballerv4 --> TCP[151.101.1.91]:443 + - ballerv6 --> TCP[2a04:4e42:c00::347]:443 +* v6 answers, connected +conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> TCP[2a04:4e42:c00::347]:443 +* transfer +``` + +The modular design of connection filters and that we can plug them into each other is used to control the parallel attempts. When a `TCP` filter does not connect (in time), it is torn down and another one is created for the next address. This keeps the `TCP` filter simple. + +The `HAPPY-EYEBALLS` on the other hand stays focused on its side of the problem. We can use it also to make other type of connection by just giving it another filter type to try and have happy eyeballing for QUIC: + +``` +* create connection for --http3-only https://curl.se +conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL +* start connect +conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL + - ballerv4 --> HTTP/3[151.101.1.91]:443 + - ballerv6 --> HTTP/3[2a04:4e42:c00::347]:443 +* v6 answers, connected +conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> HTTP/3[2a04:4e42:c00::347]:443 +* transfer +``` + +When we plug these two variants together, we get the `HTTPS-CONNECT` filter +type that is used for `--http3` when **both** HTTP/3 and HTTP/2 or HTTP/1.1 +shall be attempted: + +``` +* create connection for --http3 https://curl.se +conn[curl.se] --> HTTPS-CONNECT --> NULL +* start connect +conn[curl.se] --> HTTPS-CONNECT --> NULL + - SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL + - ballerv4 --> HTTP/3[151.101.1.91]:443 + - ballerv6 --> HTTP/3[2a04:4e42:c00::347]:443 + - SETUP[TCP] --> HAPPY-EYEBALLS --> NULL + - ballerv4 --> TCP[151.101.1.91]:443 + - ballerv6 --> TCP[2a04:4e42:c00::347]:443 +* v4 QUIC answers, connected +conn[curl.se] --> HTTPS-CONNECT --> SETUP[QUIC] --> HAPPY-EYEBALLS --> HTTP/3[151.101.1.91]:443 +* transfer +``` + diff --git a/docs/CONTRIBUTE.md b/docs/CONTRIBUTE.md new file mode 100644 index 0000000..29d98cf --- /dev/null +++ b/docs/CONTRIBUTE.md @@ -0,0 +1,316 @@ +# Contributing to the curl project + +This document is intended to offer guidelines on how to best contribute to the +curl project. This concerns new features as well as corrections to existing +flaws or bugs. + +## Join the Community + +Skip over to [https://curl.se/mail/](https://curl.se/mail/) and join +the appropriate mailing list(s). Read up on details before you post +questions. Read this file before you start sending patches. We prefer +questions sent to and discussions being held on the mailing list(s), not sent +to individuals. + +Before posting to one of the curl mailing lists, please read up on the +[mailing list etiquette](https://curl.se/mail/etiquette.html). + +We also hang out on IRC in #curl on libera.chat + +If you are at all interested in the code side of things, consider clicking +'watch' on the [curl repo on GitHub](https://github.com/curl/curl) to be +notified of pull requests and new issues posted there. + +## License and copyright + +When contributing with code, you agree to put your changes and new code under +the same license curl and libcurl is already using unless stated and agreed +otherwise. + +If you add a larger piece of code, you can opt to make that file or set of +files to use a different license as long as they do not enforce any changes to +the rest of the package and they make sense. Such "separate parts" can not be +GPL licensed (as we do not want copyleft to affect users of libcurl) but they +must use "GPL compatible" licenses (as we want to allow users to use libcurl +properly in GPL licensed environments). + +When changing existing source code, you do not alter the copyright of the +original file(s). The copyright will still be owned by the original creator(s) +or those who have been assigned copyright by the original author(s). + +By submitting a patch to the curl project, you are assumed to have the right +to the code and to be allowed by your employer or whatever to hand over that +patch/code to us. We will credit you for your changes as far as possible, to +give credit but also to keep a trace back to who made what changes. Please +always provide us with your full real name when contributing, + +## What To Read + +Source code, the man pages, the [INTERNALS +document](https://curl.se/dev/internals.html), +[TODO](https://curl.se/docs/todo.html), +[KNOWN_BUGS](https://curl.se/docs/knownbugs.html) and the [most recent +changes](https://curl.se/dev/sourceactivity.html) in git. Just lurking on +the [curl-library mailing +list](https://curl.se/mail/list.cgi?list=curl-library) will give you a +lot of insights on what's going on right now. Asking there is a good idea too. + +## Write a good patch + +### Follow code style + +When writing C code, follow the +[CODE_STYLE](https://curl.se/dev/code-style.html) already established in +the project. Consistent style makes code easier to read and mistakes less +likely to happen. Run `make checksrc` before you submit anything, to make sure +you follow the basic style. That script does not verify everything, but if it +complains you know you have work to do. + +### Non-clobbering All Over + +When you write new functionality or fix bugs, it is important that you do not +fiddle all over the source files and functions. Remember that it is likely +that other people have done changes in the same source files as you have and +possibly even in the same functions. If you bring completely new +functionality, try writing it in a new source file. If you fix bugs, try to +fix one bug at a time and send them as separate patches. + +### Write Separate Changes + +It is annoying when you get a huge patch from someone that is said to fix 511 +odd problems, but discussions and opinions do not agree with 510 of them - or +509 of them were already fixed in a different way. Then the person merging +this change needs to extract the single interesting patch from somewhere +within the huge pile of source, and that creates a lot of extra work. + +Preferably, each fix that corrects a problem should be in its own patch/commit +with its own description/commit message stating exactly what they correct so +that all changes can be selectively applied by the maintainer or other +interested parties. + +Also, separate changes enable bisecting much better for tracking problems +and regression in the future. + +### Patch Against Recent Sources + +Please try to get the latest available sources to make your patches against. +It makes the lives of the developers so much easier. The best is if you get +the most up-to-date sources from the git repository, but the latest release +archive is quite OK as well. + +### Documentation + +Writing docs is dead boring and one of the big problems with many open source +projects but someone's gotta do it. It makes things a lot easier if you submit +a small description of your fix or your new features with every contribution +so that it can be swiftly added to the package documentation. + +The documentation is always made in man pages (nroff formatted) or plain +ASCII files. All HTML files on the website and in the release archives are +generated from the nroff/ASCII versions. + +### Test Cases + +Since the introduction of the test suite, we can quickly verify that the main +features are working as they are supposed to. To maintain this situation and +improve it, all new features and functions that are added need to be tested +in the test suite. Every feature that is added should get at least one valid +test case that verifies that it works as documented. If every submitter also +posts a few test cases, it will not end up as a heavy burden on a single person. + +If you do not have test cases or perhaps you have done something that is hard +to write tests for, do explain exactly how you have otherwise tested and +verified your changes. + +## Submit Your Changes + +### How to get your changes into the main sources + +Ideally you file a [pull request on +GitHub](https://github.com/curl/curl/pulls), but you can also send your plain +patch to [the curl-library mailing +list](https://curl.se/mail/list.cgi?list=curl-library). + +If you opt to post a patch on the mailing list, chances are someone will +convert it into a pull request for you, to have the CI jobs verify it proper +before it can be merged. Be prepared that some feedback on the proposed change +might then come on GitHub. + +Your change will be reviewed and discussed and you will be expected to correct +flaws pointed out and update accordingly, or the change risks stalling and +eventually just getting deleted without action. As a submitter of a change, +you are the owner of that change until it has been merged. + +Respond on the list or on GitHub about the change and answer questions and/or +fix nits/flaws. This is important. We will take lack of replies as a sign that +you are not anxious to get your patch accepted and we tend to simply drop such +changes. + +### About pull requests + +With GitHub it is easy to send a [pull +request](https://github.com/curl/curl/pulls) to the curl project to have +changes merged. + +We strongly prefer pull requests to mailed patches, as it makes it a proper +git commit that is easy to merge and they are easy to track and not that easy +to lose in the flood of many emails, like they sometimes do on the mailing +lists. + +Every pull request submitted will automatically be tested in several different +ways. [See the CI document for more +information](https://github.com/curl/curl/blob/master/tests/CI.md). + +Sometimes the tests fail due to a dependency service temporarily being offline +or otherwise unavailable, e.g. package downloads. In this case you can just +try to update your pull requests to rerun the tests later as described below. + +You can update your pull requests by pushing new commits or force-pushing +changes to existing commits. Force-pushing an amended commit without any +actual content changed also allows you to retrigger the tests for that commit. + +When you adjust your pull requests after review, consider squashing the +commits so that we can review the full updated version more easily. + +A pull request sent to the project might get labeled `needs-votes` by a +project maintainer. This label means that in addition to meeting all other +checks and qualifications this pull request must also receive more "votes" of +user support. More signs that people want this to happen. It could be in the +form of messages saying so, or thumbs-up reactions on GitHub. + +### Making quality changes + +Make the patch against as recent source versions as possible. + +If you have followed the tips in this document and your patch still has not +been incorporated or responded to after some weeks, consider resubmitting it +to the list or better yet: change it to a pull request. + +### Commit messages + +A short guide to how to write git commit messages in the curl project. + + ---- start ---- + [area]: [short line describing the main effect] + -- empty line -- + [full description, no wider than 72 columns that describes as much as + possible as to why this change is made, and possibly what things + it fixes and everything else that is related, with unwieldy URLs replaced + with references like [0], [1], etc.] + -- empty line -- + [[0] URL - Reference to a URL in the description, almost like Markdown; + the last numbered reference is followed by an -- empty line -- ] + [Follow-up to {shorthash} - if this fixes or continues a previous commit; + add a Ref: that commit's PR or issue if it's not a small, obvious fix; + followed by an -- empty line -- ] + [Bug: URL to the source of the report or more related discussion; use Fixes + for GitHub issues instead when that is appropriate] + [Approved-by: John Doe - credit someone who approved the PR; if you are + committing this for someone else using --author=... you do not need this + as you are implicitly approving it by committing] + [Authored-by: John Doe - credit the original author of the code; only use + this if you cannot use "git commit --author=..."] + [Signed-off-by: John Doe - we do not use this, but do not bother removing it] + [whatever-else-by: credit all helpers, finders, doers; try to use one of + the following keywords if at all possible, for consistency: + Acked-by:, Assisted-by:, Co-authored-by:, Found-by:, Reported-by:, + Reviewed-by:, Suggested-by:, Tested-by:] + [Ref: #1234 - if this is related to a GitHub issue or PR, possibly one that + has already been closed] + [Ref: URL to more information about the commit; use Bug: instead for + a reference to a bug on another bug tracker] + [Fixes #1234 - if this closes a GitHub issue; GitHub will actually + close the issue once this commit is merged] + [Closes #1234 - if this closes a GitHub PR; GitHub will actually + close the PR once this commit is merged] + ---- stop ---- + +The first line is a succinct description of the change: + + - use the imperative, present tense: "change" not "changed" nor "changes" + - do not capitalize the first letter + - no period (.) at the end + +The `[area]` in the first line can be `http2`, `cookies`, `openssl` or +similar. There is no fixed list to select from but using the same "area" as +other related changes could make sense. + +Do not forget to use commit --author=... if you commit someone else's work, and +make sure that you have your own user and email setup correctly in git before +you commit. + +Add whichever header lines as appropriate, with one line per person if more +than one person was involved. There is no need to credit yourself unless you +are using --author=... which hides your identity. Do not include people's +email addresses in headers to avoid spam, unless they are already public from +a previous commit; saying `{userid} on github` is OK. + +### Write Access to git Repository + +If you are a frequent contributor, you may be given push access to the git +repository and then you will be able to push your changes straight into the git +repo instead of sending changes as pull requests or by mail as patches. + +Just ask if this is what you would want. You will be required to have posted +several high quality patches first, before you can be granted push access. + +### How To Make a Patch with git + +You need to first checkout the repository: + + git clone https://github.com/curl/curl.git + +You then proceed and edit all the files you like and you commit them to your +local repository: + + git commit [file] + +As usual, group your commits so that you commit all changes at once that +constitute a logical change. + +Once you have done all your commits and you are happy with what you see, you +can make patches out of your changes that are suitable for mailing: + + git format-patch remotes/origin/master + +This creates files in your local directory named `NNNN-[name].patch` for each +commit. + +Now send those patches off to the curl-library list. You can of course opt to +do that with the 'git send-email' command. + +### How To Make a Patch without git + +Keep a copy of the unmodified curl sources. Make your changes in a separate +source tree. When you think you have something that you want to offer the +curl community, use GNU diff to generate patches. + +If you have modified a single file, try something like: + + diff -u unmodified-file.c my-changed-one.c > my-fixes.diff + +If you have modified several files, possibly in different directories, you +can use diff recursively: + + diff -ur curl-original-dir curl-modified-sources-dir > my-fixes.diff + +The GNU diff and GNU patch tools exist for virtually all platforms, including +all kinds of Unixes and Windows. + +### Useful resources + - [Webinar on getting code into cURL](https://www.youtube.com/watch?v=QmZ3W1d6LQI) + +## Update copyright and license information + +There is a CI job called **REUSE compliance / check** that will run on every +pull request and commit to verify that the *REUSE state* of all files are +still fine. + +This means that all files need to have their license and copyright information +clearly stated. Ideally by having the standard curl source code header, with +the SPDX-License-Identifier included. If the header does not work, you can use a +smaller header or add the information for a specific file to the `.reuse/dep5` +file. + +You can manually verify the copyright and compliance status by running the +`./scripts/copyright.pl` script in the root of the git repository. diff --git a/docs/CURL-DISABLE.md b/docs/CURL-DISABLE.md new file mode 100644 index 0000000..7978ed2 --- /dev/null +++ b/docs/CURL-DISABLE.md @@ -0,0 +1,168 @@ +# Code defines to disable features and protocols + +## `CURL_DISABLE_ALTSVC` + +Disable support for Alt-Svc: HTTP headers. + +## `CURL_DISABLE_BINDLOCAL` + +Disable support for binding the local end of connections. + +## `CURL_DISABLE_COOKIES` + +Disable support for HTTP cookies. + +## `CURL_DISABLE_BASIC_AUTH` + +Disable support for the Basic authentication methods. + +## `CURL_DISABLE_BEARER_AUTH` + +Disable support for the Bearer authentication methods. + +## `CURL_DISABLE_DIGEST_AUTH` + +Disable support for the Digest authentication methods. + +## `CURL_DISABLE_KERBEROS_AUTH` + +Disable support for the Kerberos authentication methods. + +## `CURL_DISABLE_NEGOTIATE_AUTH` + +Disable support for the negotiate authentication methods. + +## `CURL_DISABLE_AWS` + +Disable **AWS-SIG4** support. + +## `CURL_DISABLE_DICT` + +Disable the DICT protocol + +## `CURL_DISABLE_DOH` + +Disable DNS-over-HTTPS + +## `CURL_DISABLE_FILE` + +Disable the FILE protocol + +## `CURL_DISABLE_FORM_API` + +Disable the form API + +## `CURL_DISABLE_FTP` + +Disable the FTP (and FTPS) protocol + +## `CURL_DISABLE_GETOPTIONS` + +Disable the `curl_easy_options` API calls that lets users get information +about existing options to `curl_easy_setopt`. + +## `CURL_DISABLE_GOPHER` + +Disable the GOPHER protocol. + +## `CURL_DISABLE_HEADERS_API` + +Disable the HTTP header API. + +## `CURL_DISABLE_HSTS` + +Disable the HTTP Strict Transport Security support. + +## `CURL_DISABLE_HTTP` + +Disable the HTTP(S) protocols. Note that this then also disable HTTP proxy +support. + +## `CURL_DISABLE_HTTP_AUTH` + +Disable support for all HTTP authentication methods. + +## `CURL_DISABLE_IMAP` + +Disable the IMAP(S) protocols. + +## `CURL_DISABLE_LDAP` + +Disable the LDAP(S) protocols. + +## `CURL_DISABLE_LDAPS` + +Disable the LDAPS protocol. + +## `CURL_DISABLE_LIBCURL_OPTION` + +Disable the --libcurl option from the curl tool. + +## `CURL_DISABLE_MIME` + +Disable MIME support. + +## `CURL_DISABLE_MQTT` + +Disable MQTT support. + +## `CURL_DISABLE_NETRC` + +Disable the netrc parser. + +## `CURL_DISABLE_NTLM` + +Disable support for NTLM. + +## `CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG` + +Disable the auto load config support in the OpenSSL backend. + +## `CURL_DISABLE_PARSEDATE` + +Disable date parsing + +## `CURL_DISABLE_POP3` + +Disable the POP3 protocol + +## `CURL_DISABLE_PROGRESS_METER` + +Disable the built-in progress meter + +## `CURL_DISABLE_PROXY` + +Disable support for proxies + +## `CURL_DISABLE_RTSP` + +Disable the RTSP protocol. + +## `CURL_DISABLE_SHUFFLE_DNS` + +Disable the shuffle DNS feature + +## `CURL_DISABLE_SMB` + +Disable the SMB(S) protocols + +## `CURL_DISABLE_SMTP` + +Disable the SMTP(S) protocols + +## `CURL_DISABLE_SOCKETPAIR` + +Disable the use of `socketpair()` internally to allow waking up and canceling +`curl_multi_poll()`. + +## `CURL_DISABLE_TELNET` + +Disable the TELNET protocol + +## `CURL_DISABLE_TFTP` + +Disable the TFTP protocol + +## `CURL_DISABLE_VERBOSE_STRINGS` + +Disable verbose strings and error messages. diff --git a/docs/CURLDOWN.md b/docs/CURLDOWN.md new file mode 100644 index 0000000..2e89eed --- /dev/null +++ b/docs/CURLDOWN.md @@ -0,0 +1,125 @@ +# curldown + +A markdown-like syntax for libcurl man pages. + +## Purpose + +A text format for writing libcurl documentation in the shape of man pages. + +Make it easier for users to contribute and write documentation. A format that +is easier on the eye in its source format. + +Make it harder to do syntactical mistakes. + +Use a format that allows creating man pages that end up looking exactly like +the man pages did when we wrote them in nroff format. + +Take advantage of the fact that people these days are accustomed to markdown +by using a markdown-like syntax. + +This allows us to fix issues in the nroff format easier since now we generate +them. For example: escaping minus to prevent them from being turned into +Unicode by man. + +Generate nroff output that looks (next to) *identical* to the previous files, +so that the look, existing test cases, HTML conversions, existing +infrastructure etc remain mostly intact. + +Contains meta-data in a structured way to allow better output (for example the +see also information) and general awareness of what the file is about. + +## File extension + +Since curldown looks similar to markdown, we use `.md` extensions on the +files. + +## Conversion + +Convert **from curldown to nroff** with `cd2nroff`. Generates nroff man pages. + +Convert **from nroff to curldown** with `nroff2cd`. This is only meant to be +used for the initial conversion to curldown and should ideally never be needed +again. + +Convert, check or clean up an existing curldown to nicer, better, cleaner +curldown with **cd2cd**. + +Mass-convert all curldown files to nroff in specified directories with +`cdall`: + + cdall [dir1] [dir2] [dir3] .. + +## Known issues + +The `cd2nroff` tool does not yet handle *italics* or **bold** where the start +and the end markers are used on separate lines. + +The `nroff2cd` tool generates code style quotes for all `.fi` sections since +the nroff format does not carry a distinction. + +# Format + +Each curldown starts with a header with meta-data: + + --- + c: Copyright (C) Daniel Stenberg, , et al. + SPDX-License-Identifier: curl + Title: CURLOPT_AWS_SIGV4 + Section: 3 + Source: libcurl + See-also: + - CURLOPT_HEADEROPT (3) + - CURLOPT_HTTPAUTH (3) + --- + +All curldown files *must* have all the headers present and at least one +`See-also:` entry specified. + +Following the header in the file, is the manual page using markdown-like +syntax: + +~~~ + # NAME + a page - this is a page descriving something + + # SYNOPSIS + ~~~c + #include + + CURLcode curl_easy_setopt(CURL *handle, CURLOPT_AWS_SIGV4, char *param); + ~~~ +~~~ + +Quoted source code should start with `~~~c` and end with `~~~` while regular +quotes can start with `~~~` or just be indented with 4 spaces. + +Headers at top-level `#` get converted to `.SH`. + +`nroff2cd` supports the `##` next level header which gets converted to `.IP`. + +Write bold words or phrases within `**` like: + + This is a **bold** word. + +Write italics like: + + This is *italics*. + +Due to how man pages do not support backticks especially formatted, such +occurrences in the source will instead just use italics in the generated +output: + + This `word` appears in italics. + +When generating the nroff output, the tooling will remove superfluous newlines, +meaning they can be used freely in the source file to make the text more +readable. + +All mentioned curl symbols that have their own man pages, like +`curl_easy_perform(3)` will automatically be rendered using italics in the +output without having to enclose it with asterisks. This helps ensuring that +they get converted to links properly later in the HTML version on the website, +as converted with `roffit`. This makes the curldown text easier to read even +when mentioning many curl symbols. + +This auto-linking works for patterns matching `(lib|)curl[^ ]*(3)`. diff --git a/docs/DEPRECATE.md b/docs/DEPRECATE.md new file mode 100644 index 0000000..fcbd92a --- /dev/null +++ b/docs/DEPRECATE.md @@ -0,0 +1,52 @@ +# Items to be removed from future curl releases + +If any of these deprecated features is a cause for concern for you, please +email the +[curl-library mailing list](https://lists.haxx.se/listinfo/curl-library) +as soon as possible and explain to us why this is a problem for you and +how your use case cannot be satisfied properly using a workaround. + +## NTLM_WB auth + +This NTLM authentication method is powered by a separate tool, +`ntlm_auth`. Barely anyone uses this method. It was always a quirky +implementation (including fork + exec), it has limited portability and we do +not test it in the test suite and CI. + +We keep the native NTLM implementation. + +Due to a mistake, the `NTLM_WB` functionality is missing in builds since 8.4.0 +(October 2023). It needs to be manually patched to work. See [PR +12479](https://github.com/curl/curl/pull/12479). + +curl will remove the support for NTLM_WB auth in April 2024. + +## space-separated `NOPROXY` patterns + +When specifying patterns/domain names for curl that should *not* go through a +proxy, the curl tool features the `--noproxy` command line option and the +library supports the `NO_PROXY` environment variable and the `CURLOPT_NOPROXY` +libcurl option. + +They all set the same list of patterns. This list is documented to be a set of +**comma-separated** names, but can also be provided separated with just +space. The ability to just use spaces for this has never been documented but +some users may still have come to rely on this. + +Several other tools and utilities also parse the `NO_PROXY` environment +variable but do not consider a space to be a valid separator. Using spaces for +separator is probably less portable and might cause more friction than commas +do. Users should use commas for this for greater portability. + +curl will remove the support for space-separated names in July 2024. + +## past removals + + - Pipelining + - axTLS + - PolarSSL + - NPN + - Support for systems without 64 bit data types + - NSS + - gskit + - mingw v1 diff --git a/docs/DYNBUF.md b/docs/DYNBUF.md new file mode 100644 index 0000000..c3a4b76 --- /dev/null +++ b/docs/DYNBUF.md @@ -0,0 +1,128 @@ +# dynbuf + +This is the internal module for creating and handling "dynamic buffers". This +means buffers that can be appended to, dynamically and grow to adapt. + +There will always be a terminating zero put at the end of the dynamic buffer. + +The `struct dynbuf` is used to hold data for each instance of a dynamic +buffer. The members of that struct **MUST NOT** be accessed or modified +without using the dedicated dynbuf API. + +## `Curl_dyn_init` + +```c +void Curl_dyn_init(struct dynbuf *s, size_t toobig); +``` + +This initializes a struct to use for dynbuf and it cannot fail. The `toobig` +value **must** be set to the maximum size we allow this buffer instance to +grow to. The functions below will return `CURLE_OUT_OF_MEMORY` when hitting +this limit. + +## `Curl_dyn_free` + +```c +void Curl_dyn_free(struct dynbuf *s); +``` + +Free the associated memory and clean up. After a free, the `dynbuf` struct can +be reused to start appending new data to. + +## `Curl_dyn_addn` + +```c +CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len); +``` + +Append arbitrary data of a given length to the end of the buffer. + +If this function fails it calls `Curl_dyn_free` on `dynbuf`. + +## `Curl_dyn_add` + +```c +CURLcode Curl_dyn_add(struct dynbuf *s, const char *str); +``` + +Append a C string to the end of the buffer. + +If this function fails it calls `Curl_dyn_free` on `dynbuf`. + +## `Curl_dyn_addf` + +```c +CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...); +``` + +Append a `printf()`-style string to the end of the buffer. + +If this function fails it calls `Curl_dyn_free` on `dynbuf`. + +## `Curl_dyn_vaddf` + +```c +CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap); +``` + +Append a `vprintf()`-style string to the end of the buffer. + +If this function fails it calls `Curl_dyn_free` on `dynbuf`. + +## `Curl_dyn_reset` + +```c +void Curl_dyn_reset(struct dynbuf *s); +``` + +Reset the buffer length, but leave the allocation. + +## `Curl_dyn_tail` + +```c +CURLcode Curl_dyn_tail(struct dynbuf *s, size_t length); +``` + +Keep `length` bytes of the buffer tail (the last `length` bytes of the +buffer). The rest of the buffer is dropped. The specified `length` must not be +larger than the buffer length. To instead keep the leading part, see +`Curl_dyn_setlen()`. + +## `Curl_dyn_ptr` + +```c +char *Curl_dyn_ptr(const struct dynbuf *s); +``` + +Returns a `char *` to the buffer if it has a length, otherwise may return +NULL. Since the buffer may be reallocated, this pointer should not be trusted +or used anymore after the next buffer manipulation call. + +## `Curl_dyn_uptr` + +```c +unsigned char *Curl_dyn_uptr(const struct dynbuf *s); +``` + +Returns an `unsigned char *` to the buffer if it has a length, otherwise may +return NULL. Since the buffer may be reallocated, this pointer should not be +trusted or used anymore after the next buffer manipulation call. + +## `Curl_dyn_len` + +```c +size_t Curl_dyn_len(const struct dynbuf *s); +``` + +Returns the length of the buffer in bytes. Does not include the terminating +zero byte. + +## `Curl_dyn_setlen` + +```c +CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t len); +``` + +Sets the new shorter length of the buffer in number of bytes. Keeps the +leftmost set number of bytes, discards the rest. To instead keep the tail part +of the buffer, see `Curl_dyn_tail()`. diff --git a/docs/EARLY-RELEASE.md b/docs/EARLY-RELEASE.md new file mode 100644 index 0000000..6d5a5e2 --- /dev/null +++ b/docs/EARLY-RELEASE.md @@ -0,0 +1,67 @@ +# How to determine if an early patch release is warranted + +In the curl project we do releases every 8 weeks. Unless we break the cycle +and do an early patch release. + +We do frequent releases partly to always have the next release "not too far +away". + +## Bugfix + +During the release cycle, and especially in the beginning of a new cycle (the +so-called "cool down" period), there are times when a bug is reported and +after it has been subsequently fixed correctly, the question might be asked: +is this bug and associated fix important enough for an early patch release? + +The question can only be properly asked when a fix has been created and landed +in the git master branch. + +## Early release + +An early patch release means that we ship a new, complete and full release +called `major.minor.patch` where the `patch` part is increased by one since +the previous release. A curl release is a curl release. There is no small or +big and we never release just a patch. There is only "release". + +## Questions to ask + + - Is there a security advisory rated high or critical? + - Is there a data corruption bug? + - Did the bug cause an API/ABI breakage? + - Will the problem annoy a significant share of the user population? + +If the answer is yes to one or more of the above, an early release might be +warranted. + +More questions to ask ourselves when doing the assessment if the answers to +the three ones above are all 'no'. + + - Does the bug cause curl to prematurely terminate? + - How common is the affected buggy option/feature/protocol/platform to get + used? + - How large is the estimated impacted user base? + - Does the bug block something crucial for applications or other adoption of + curl "out there" ? + - Does the bug cause problems for curl developers or others on "the curl + team" ? + - Is the bug limited to the curl tool only? That might have a smaller impact + than a bug also present in libcurl. + - Is there a (decent) workaround? + - Is it a regression? Is the bug introduced in this release? + - Can the bug be fixed "easily" by applying a patch? + - Does the bug break the build? Most users do not build curl themselves. + - How long is it until the already scheduled next release? + - Can affected users safely rather revert to a former release until the next + scheduled release? + - Is it a performance regression with no functionality side-effects? If so it + has to be substantial. + +## If an early release is deemed necessary + +Unless done for security or similarly important reasons, an early release +should not be done within a week of the previous release. + +This, to enable us to collect and bundle more fixes into the same release to +make the release more worthwhile for everyone and to allow more time for fixes +to settle and things to get tested. Getting a release in shape and done in +style is work that should not be rushed. diff --git a/docs/EXPERIMENTAL.md b/docs/EXPERIMENTAL.md new file mode 100644 index 0000000..de69401 --- /dev/null +++ b/docs/EXPERIMENTAL.md @@ -0,0 +1,24 @@ +# Experimental + +Some features and functionality in curl and libcurl are considered +**EXPERIMENTAL**. + +Experimental support in curl means: + +1. Experimental features are provided to allow users to try them out and + provide feedback on functionality and API etc before they ship and get + "carved in stone". +2. You must enable the feature when invoking configure as otherwise curl will + not be built with the feature present. +3. We strongly advise against using this feature in production. +4. **We reserve the right to change behavior** of the feature without sticking + 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. + +## Experimental features right now + + - The Hyper HTTP backend + - HTTP/3 support (using the quiche or msh3 backends) + - The rustls backend + - WebSocket diff --git a/docs/FAQ b/docs/FAQ new file mode 100644 index 0000000..1450a1e --- /dev/null +++ b/docs/FAQ @@ -0,0 +1,1561 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + +FAQ + + 1. Philosophy + 1.1 What is cURL? + 1.2 What is libcurl? + 1.3 What is curl not? + 1.4 When will you make curl do XXXX ? + 1.5 Who makes curl? + 1.6 What do you get for making curl? + 1.7 What about CURL from curl.com? + 1.8 I have a problem, who do I mail? + 1.9 Where do I buy commercial support for curl? + 1.10 How many are using curl? + 1.11 Why do you not update ca-bundle.crt + 1.12 I have a problem, who can I chat with? + 1.13 curl's ECCN number? + 1.14 How do I submit my patch? + 1.15 How do I port libcurl to my OS? + + 2. Install Related Problems + 2.1 configure fails when using static libraries + 2.2 Does curl work/build with other SSL libraries? + 2.3 How do I upgrade curl.exe in Windows? + 2.4 Does curl support SOCKS (RFC 1928) ? + + 3. Usage Problems + 3.1 curl: (1) SSL is disabled, https: not supported + 3.2 How do I tell curl to resume a transfer? + 3.3 Why does my posting using -F not work? + 3.4 How do I tell curl to run custom FTP commands? + 3.5 How can I disable the Accept: */* header? + 3.6 Does curl support ASP, XML, XHTML or HTML version Y? + 3.7 Can I use curl to delete/rename a file through FTP? + 3.8 How do I tell curl to follow HTTP redirects? + 3.9 How do I use curl in my favorite programming language? + 3.10 What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP? + 3.11 How do I POST with a different Content-Type? + 3.12 Why do FTP-specific features over HTTP proxy fail? + 3.13 Why do my single/double quotes fail? + 3.14 Does curl support JavaScript or PAC (automated proxy config)? + 3.15 Can I do recursive fetches with curl? + 3.16 What certificates do I need when I use SSL? + 3.17 How do I list the root directory of an FTP server? + 3.18 Can I use curl to send a POST/PUT and not wait for a response? + 3.19 How do I get HTTP from a host using a specific IP address? + 3.20 How to SFTP from my user's home directory? + 3.21 Protocol xxx not supported or disabled in libcurl + 3.22 curl -X gives me HTTP problems + + 4. Running Problems + 4.2 Why do I get problems when I use & or % in the URL? + 4.3 How can I use {, }, [ or ] to specify multiple URLs? + 4.4 Why do I get downloaded data even though the web page does not exist? + 4.5 Why do I get return code XXX from an HTTP server? + 4.5.1 "400 Bad Request" + 4.5.2 "401 Unauthorized" + 4.5.3 "403 Forbidden" + 4.5.4 "404 Not Found" + 4.5.5 "405 Method Not Allowed" + 4.5.6 "301 Moved Permanently" + 4.6 Can you tell me what error code 142 means? + 4.7 How do I keep user names and passwords secret in curl command lines? + 4.8 I found a bug + 4.9 curl cannot authenticate to a server that requires NTLM? + 4.10 My HTTP request using HEAD, PUT or DELETE does not work + 4.11 Why do my HTTP range requests return the full document? + 4.12 Why do I get "certificate verify failed" ? + 4.13 Why is curl -R on Windows one hour off? + 4.14 Redirects work in browser but not with curl + 4.15 FTPS does not work + 4.16 My HTTP POST or PUT requests are slow + 4.17 Non-functional connect timeouts on Windows + 4.18 file:// URLs containing drive letters (Windows, NetWare) + 4.19 Why does not curl return an error when the network cable is unplugged? + 4.20 curl does not return error for HTTP non-200 responses + + 5. libcurl Issues + 5.1 Is libcurl thread-safe? + 5.2 How can I receive all data into a large memory chunk? + 5.3 How do I fetch multiple files with libcurl? + 5.4 Does libcurl do Winsock initialization on win32 systems? + 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ? + 5.6 What about Keep-Alive or persistent connections? + 5.7 Link errors when building libcurl on Windows + 5.8 libcurl.so.X: open failed: No such file or directory + 5.9 How does libcurl resolve host names? + 5.10 How do I prevent libcurl from writing the response to stdout? + 5.11 How do I make libcurl not receive the whole HTTP response? + 5.12 Can I make libcurl fake or hide my real IP address? + 5.13 How do I stop an ongoing transfer? + 5.14 Using C++ non-static functions for callbacks? + 5.15 How do I get an FTP directory listing? + 5.16 I want a different time-out + 5.17 Can I write a server with libcurl? + 5.18 Does libcurl use threads? + + 6. License Issues + 6.1 I have a GPL program, can I use the libcurl library? + 6.2 I have a closed-source program, can I use the libcurl library? + 6.3 I have a BSD licensed program, can I use the libcurl library? + 6.4 I have a program that uses LGPL libraries, can I use libcurl? + 6.5 Can I modify curl/libcurl for my program and keep the changes secret? + 6.6 Can you please change the curl/libcurl license to XXXX? + 6.7 What are my obligations when using libcurl in my commercial apps? + + 7. PHP/CURL Issues + 7.1 What is PHP/CURL? + 7.2 Who wrote PHP/CURL? + 7.3 Can I perform multiple requests using the same handle? + 7.4 Does PHP/CURL have dependencies? + + 8. Development + 8.1 Why does curl use C89? + 8.2 Will curl be rewritten? + +============================================================================== + +1. Philosophy + + 1.1 What is cURL? + + cURL is the name of the project. The name is a play on 'Client for URLs', + originally with URL spelled in uppercase to make it obvious it deals with + URLs. The fact it can also be read as 'see URL' also helped, it works as + an abbreviation for "Client URL Request Library" or why not the recursive + version: "curl URL Request Library". + + The cURL project produces two products: + + libcurl + + A client-side URL transfer library, supporting DICT, FILE, FTP, FTPS, + GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, + RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS + and WSS. + + libcurl supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading, + Kerberos, SPNEGO, HTTP form based upload, proxies, cookies, user+password + authentication, file transfer resume, http proxy tunneling and more. + + libcurl is highly portable, it builds and works identically on numerous + platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HP-UX, + IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, macOS, + Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS, Symbian, OSF, Android, + Minix, IBM TPF and more... + + libcurl is free, thread-safe, IPv6 compatible, feature rich, well + supported and fast. + + curl + + A command line tool for getting or sending data using URL syntax. + + Since curl uses libcurl, curl supports the same wide range of common + Internet protocols that libcurl does. + + We pronounce curl with an initial k sound. It rhymes with words like girl + and earl. This is a short WAV file to help you: + + https://media.merriam-webster.com/soundc11/c/curl0001.wav + + There are numerous sub-projects and related projects that also use the word + curl in the project names in various combinations, but you should take + notice that this FAQ is directed at the command-line tool named curl (and + libcurl the library), and may therefore not be valid for other curl-related + projects. (There is however a small section for the PHP/CURL in this FAQ.) + + 1.2 What is libcurl? + + libcurl is a reliable and portable library for doing Internet data transfers + using one or more of its supported Internet protocols. + + You can use libcurl freely in your application, be it open source, + commercial or closed-source. + + libcurl is most probably the most portable, most powerful and most often + used C-based multi-platform file transfer library on this planet - be it + open source or commercial. + + 1.3 What is curl not? + + curl is not a wget clone. That is a common misconception. Never, during + curl's development, have we intended curl to replace wget or compete on its + market. curl is targeted at single-shot file transfers. + + curl is not a website mirroring program. If you want to use curl to mirror + something: fine, go ahead and write a script that wraps around curl or use + libcurl to make it reality. + + curl is not an FTP site mirroring program. Sure, get and send FTP with curl + but if you want systematic and sequential behavior you should write a + script (or write a new program that interfaces libcurl) and do it. + + curl is not a PHP tool, even though it works perfectly well when used from + or with PHP (when using the PHP/CURL module). + + curl is not a program for a single operating system. curl exists, compiles, + builds and runs under a wide range of operating systems, including all + modern Unixes (and a bunch of older ones too), Windows, Amiga, OS/2, macOS, + QNX etc. + + 1.4 When will you make curl do XXXX ? + + We love suggestions of what to change in order to make curl and libcurl + better. We do however believe in a few rules when it comes to the future of + curl: + + curl -- the command line tool -- is to remain a non-graphical command line + tool. If you want GUIs or fancy scripting capabilities, you should look for + another tool that uses libcurl. + + We do not add things to curl that other small and available tools already do + well at the side. curl's output can be piped into another program or + redirected to another file for the next program to interpret. + + We focus on protocol related issues and improvements. If you want to do more + magic with the supported protocols than curl currently does, chances are + good we will agree. If you want to add more protocols, we may agree. + + If you want someone else to do all the work while you wait for us to + implement it for you, that is not a friendly attitude. We spend a + considerable time already on maintaining and developing curl. In order to + get more out of us, you should consider trading in some of your time and + effort in return. Simply go to the GitHub repository which resides at + https://github.com/curl/curl, fork the project, and create pull requests + with your proposed changes. + + If you write the code, chances are better that it will get into curl faster. + + 1.5 Who makes curl? + + curl and libcurl are not made by any single individual. Daniel Stenberg is + project leader and main developer, but other persons' submissions are + important and crucial. Anyone can contribute and post their changes and + improvements and have them inserted in the main sources (of course on the + condition that developers agree that the fixes are good). + + The full list of all contributors is found in the docs/THANKS file. + + curl is developed by a community, with Daniel at the wheel. + + 1.6 What do you get for making curl? + + Project cURL is entirely free and open. We do this voluntarily, mostly in + our spare time. Companies may pay individual developers to work on curl. + This is not controlled by nor supervised in any way by the curl project. + + We get help from companies. Haxx provides website, bandwidth, mailing lists + etc, GitHub hosts the primary git repository and other services like the bug + tracker at https://github.com/curl/curl. Also again, some companies have + sponsored certain parts of the development in the past and I hope some will + continue to do so in the future. + + If you want to support our project, consider a donation or a banner-program + or even better: by helping us with coding, documenting or testing etc. + + See also: https://curl.se/sponsors.html + + 1.7 What about CURL from curl.com? + + During the summer of 2001, curl.com was busy advertising their client-side + programming language for the web, named CURL. + + We are in no way associated with curl.com or their CURL programming + language. + + Our project name curl has been in effective use since 1998. We were not the + first computer related project to use the name "curl" and do not claim any + rights to the name. + + We recognize that we will be living in parallel with curl.com and wish them + every success. + + 1.8 I have a problem, who do I mail? + + Please do not mail any single individual unless you really need to. Keep + curl-related questions on a suitable mailing list. All available mailing + lists are listed in the MANUAL document and online at + https://curl.se/mail/ + + Keeping curl-related questions and discussions on mailing lists allows + others to join in and help, to share their ideas, to contribute their + suggestions and to spread their wisdom. Keeping discussions on public mailing + lists also allows for others to learn from this (both current and future + users thanks to the web based archives of the mailing lists), thus saving us + from having to repeat ourselves even more. Thanks for respecting this. + + If you have found or simply suspect a security problem in curl or libcurl, + submit all the details at https://hackerone.one/curl. On there we keep the + issue private while we investigate, confirm it, work and validate a fix and + agree on a time schedule for publication etc. That way we produce a fix in a + timely manner before the flaw is announced to the world, reducing the impact + the problem risks having on existing users. + + Security issues can also be taking to the curl security team by emailing + security at curl.se (closed list of receivers, mails are not disclosed). + + 1.9 Where do I buy commercial support for curl? + + curl is fully open source. It means you can hire any skilled engineer to fix + your curl-related problems. + + We list available alternatives on the curl website: + https://curl.se/support.html + + 1.10 How many are using curl? + + It is impossible to tell. + + We do not know how many users that knowingly have installed and use curl. + + We do not know how many users that use curl without knowing that they are in + fact using it. + + We do not know how many users that downloaded or installed curl and then + never use it. + + In 2020, we estimate that curl runs in roughly ten billion installations + world wide. + + 1.11 Why do you not update ca-bundle.crt + + In the cURL project we have decided not to attempt to keep this file updated + (or even present) since deciding what to add to a ca cert bundle is an + undertaking we have not been ready to accept, and the one we can get from + Mozilla is perfectly fine so there is no need to duplicate that work. + + Today, with many services performed over HTTPS, every operating system + should come with a default ca cert bundle that can be deemed somewhat + trustworthy and that collection (if reasonably updated) should be deemed to + be a lot better than a private curl version. + + If you want the most recent collection of ca certs that Mozilla Firefox + uses, we recommend that you extract the collection yourself from Mozilla + Firefox (by running 'make ca-bundle), or by using our online service setup + for this purpose: https://curl.se/docs/caextract.html + + 1.12 I have a problem who, can I chat with? + + There is a bunch of friendly people hanging out in the #curl channel on the + IRC network libera.chat. If you are polite and nice, chances are good that + you can get -- or provide -- help instantly. + + 1.13 curl's ECCN number? + + The US government restricts exports of software that contains or uses + cryptography. When doing so, the Export Control Classification Number (ECCN) + is used to identify the level of export control etc. + + Apache Software Foundation gives a good explanation of ECCNs at + https://www.apache.org/dev/crypto.html + + We believe curl's number might be ECCN 5D002, another possibility is + 5D992. It seems necessary to write them (the authority that administers ECCN + numbers), asking to confirm. + + Comprehensible explanations of the meaning of such numbers and how to obtain + them (resp.) are here + + https://www.bis.doc.gov/licensing/exportingbasics.htm + https://www.bis.doc.gov/licensing/do_i_needaneccn.html + + An incomprehensible description of the two numbers above is here + https://www.bis.doc.gov/index.php/documents/new-encryption/1653-ccl5-pt2-3 + + 1.14 How do I submit my patch? + + We strongly encourage you to submit changes and improvements directly as + "pull requests" on GitHub: https://github.com/curl/curl/pulls + + If you for any reason cannot or will not deal with GitHub, send your patch to + the curl-library mailing list. We are many subscribers there and there are + lots of people who can review patches, comment on them and "receive" them + properly. + + Lots of more details are found in the CONTRIBUTE.md and INTERNALS.md + documents. + + 1.15 How do I port libcurl to my OS? + + Here's a rough step-by-step: + + 1. copy a suitable lib/config-*.h file as a start to lib/config-[youros].h + + 2. edit lib/config-[youros].h to match your OS and setup + + 3. edit lib/curl_setup.h to include config-[youros].h when your OS is + detected by the preprocessor, in the style others already exist + + 4. compile lib/*.c and make them into a library + + +2. Install Related Problems + + 2.1 configure fails when using static libraries + + You may find that configure fails to properly detect the entire dependency + chain of libraries when you provide static versions of the libraries that + configure checks for. + + The reason why static libraries is much harder to deal with is that for them + we do not get any help but the script itself must know or check what more + libraries that are needed (with shared libraries, that dependency "chain" is + handled automatically). This is a error-prone process and one that also + tends to vary over time depending on the release versions of the involved + components and may also differ between operating systems. + + For that reason, configure does few attempts to actually figure this out and + you are instead encouraged to set LIBS and LDFLAGS accordingly when you + invoke configure, and point out the needed libraries and set the necessary + flags yourself. + + 2.2 Does curl work with other SSL libraries? + + curl has been written to use a generic SSL function layer internally, and + that SSL functionality can then be provided by one out of many different SSL + backends. + + curl can be built to use one of the following SSL alternatives: OpenSSL, + libressl, BoringSSL, AWS-LC, GnuTLS, wolfSSL, mbedTLS, Secure Transport + (native iOS/OS X), Schannel (native Windows), BearSSL or Rustls. They all + have their pros and cons, and we try to maintain a comparison of them here: + https://curl.se/docs/ssl-compared.html + + 2.3 How do I upgrade curl.exe in Windows? + + The curl tool that is shipped as an integrated component of Windows 10 and + Windows 11 is managed by Microsoft. If you were to delete the file or + replace it with a newer version downloaded from https://curl.se/windows, + then Windows Update will cease to work on your system. + + There is no way to independently force an upgrade of the curl.exe that is + part of Windows other than through the regular Windows update process. There + is also nothing the curl project itself can do about this, since this is + managed and controlled entirely by Microsoft as owners of the operating + system. + + You can always download and install the latest version of curl for Windows + from https://curl.se/windows into a separate location. + + 2.4 Does curl support SOCKS (RFC 1928) ? + + Yes, SOCKS 4 and 5 are supported. + +3. Usage problems + + 3.1 curl: (1) SSL is disabled, https: not supported + + If you get this output when trying to get anything from an HTTPS server, it + means that the instance of curl/libcurl that you are using was built without + support for this protocol. + + This could have happened if the configure script that was run at build time + could not find all libs and include files curl requires for SSL to work. If + the configure script fails to find them, curl is simply built without SSL + support. + + To get HTTPS support into a curl that was previously built but that reports + that HTTPS is not supported, you should dig through the document and logs + and check out why the configure script does not find the SSL libs and/or + include files. + + Also, check out the other paragraph in this FAQ labeled "configure does not + find OpenSSL even when it is installed". + + 3.2 How do I tell curl to resume a transfer? + + curl supports resumed transfers both ways on both FTP and HTTP. + Try the -C option. + + 3.3 Why does my posting using -F not work? + + You cannot arbitrarily use -F or -d, the choice between -F or -d depends on + the HTTP operation you need curl to do and what the web server that will + receive your post expects. + + If the form you are trying to submit uses the type 'multipart/form-data', + then and only then you must use the -F type. In all the most common cases, + you should use -d which then causes a posting with the type + 'application/x-www-form-urlencoded'. + + This is described in some detail in the MANUAL and TheArtOfHttpScripting + documents, and if you do not understand it the first time, read it again + before you post questions about this to the mailing list. Also, try reading + through the mailing list archives for old postings and questions regarding + this. + + 3.4 How do I tell curl to run custom FTP commands? + + You can tell curl to perform optional commands both before and/or after a + file transfer. Study the -Q/--quote option. + + Since curl is used for file transfers, you do not normally use curl to + perform FTP commands without transferring anything. Therefore you must + always specify a URL to transfer to/from even when doing custom FTP + commands, or use -I which implies the "no body" option sent to libcurl. + + 3.5 How can I disable the Accept: */* header? + + You can change all internally generated headers by adding a replacement with + the -H/--header option. By adding a header with empty contents you safely + disable that one. Use -H "Accept:" to disable that specific header. + + 3.6 Does curl support ASP, XML, XHTML or HTML version Y? + + To curl, all contents are alike. It does not matter how the page was + generated. It may be ASP, PHP, Perl, shell-script, SSI or plain HTML + files. There is no difference to curl and it does not even know what kind of + language that generated the page. + + See also item 3.14 regarding JavaScript. + + 3.7 Can I use curl to delete/rename a file through FTP? + + Yes. You specify custom FTP commands with -Q/--quote. + + One example would be to delete a file after you have downloaded it: + + curl -O ftp://example.com/coolfile -Q '-DELE coolfile' + + or rename a file after upload: + + curl -T infile ftp://example.com/dir/ -Q "-RNFR infile" -Q "-RNTO newname" + + 3.8 How do I tell curl to follow HTTP redirects? + + curl does not follow so-called redirects by default. The Location: header + that informs the client about this is only interpreted if you are using the + -L/--location option. As in: + + curl -L http://example.com + + Not all redirects are HTTP ones, see 4.14 + + 3.9 How do I use curl in my favorite programming language? + + Many programming languages have interfaces/bindings that allow you to use + curl without having to use the command line tool. If you are fluent in such + a language, you may prefer to use one of these interfaces instead. + + Find out more about which languages that support curl directly, and how to + install and use them, in the libcurl section of the curl website: + https://curl.se/libcurl/ + + All the various bindings to libcurl are made by other projects and people, + outside of the cURL project. The cURL project itself only produces libcurl + with its plain C API. If you do not find anywhere else to ask you can ask + about bindings on the curl-library list too, but be prepared that people on + that list may not know anything about bindings. + + In December 2021, there were interfaces available for the following + languages: Ada95, Basic, C, C++, Ch, Cocoa, D, Delphi, Dylan, Eiffel, + Euphoria, Falcon, Ferite, Gambas, glib/GTK+, Go, Guile, Harbour, Haskell, + Java, Julia, Lisp, Lua, Mono, .NET, node.js, Object-Pascal, OCaml, Pascal, + Perl, PHP, PostgreSQL, Python, R, Rexx, Ring, RPG, Ruby, Rust, Scheme, + Scilab, S-Lang, Smalltalk, SP-Forth, SPL, Tcl, Visual Basic, Visual FoxPro, + Q, wxwidgets, XBLite and Xoho. By the time you read this, additional ones + may have appeared. + + 3.10 What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP? + + curl adheres to the HTTP spec, which basically means you can play with *any* + protocol that is built on top of HTTP. Protocols such as SOAP, WEBDAV and + XML-RPC are all such ones. You can use -X to set custom requests and -H to + set custom headers (or replace internally generated ones). + + Using libcurl is of course just as good and you would just use the proper + library options to do the same. + + 3.11 How do I POST with a different Content-Type? + + You can always replace the internally generated headers with -H/--header. + To make a simple HTTP POST with text/xml as content-type, do something like: + + curl -d "datatopost" -H "Content-Type: text/xml" [URL] + + 3.12 Why do FTP-specific features over HTTP proxy fail? + + Because when you use an HTTP proxy, the protocol spoken on the network will + be HTTP, even if you specify an FTP URL. This effectively means that you + normally cannot use FTP-specific features such as FTP upload and FTP quote + etc. + + There is one exception to this rule, and that is if you can "tunnel through" + the given HTTP proxy. Proxy tunneling is enabled with a special option (-p) + and is generally not available as proxy admins usually disable tunneling to + ports other than 443 (which is used for HTTPS access through proxies). + + 3.13 Why do my single/double quotes fail? + + To specify a command line option that includes spaces, you might need to + put the entire option within quotes. Like in: + + curl -d " with spaces " example.com + + or perhaps + + curl -d ' with spaces ' example.com + + Exactly what kind of quotes and how to do this is entirely up to the shell + or command line interpreter that you are using. For most unix shells, you + can more or less pick either single (') or double (") quotes. For + Windows/DOS command prompts you must use double (") quotes, and if the + option string contains inner double quotes you can escape them with a + backslash. + + For Windows powershell the arguments are not always passed on as expected + because curl is not a powershell script. You may or may not be able to use + single quotes. To escape inner double quotes seems to require a + backslash-backtick escape sequence and the outer quotes as double quotes. + + Please study the documentation for your particular environment. Examples in + the curl docs will use a mix of both of these as shown above. You must + adjust them to work in your environment. + + Remember that curl works and runs on more operating systems than most single + individuals have ever tried. + + 3.14 Does curl support JavaScript or PAC (automated proxy config)? + + Many web pages do magic stuff using embedded JavaScript. curl and libcurl + have no built-in support for that, so it will be treated just like any other + contents. + + .pac files are a Netscape invention and are sometimes used by organizations + to allow them to differentiate which proxies to use. The .pac contents is + just a JavaScript program that gets invoked by the browser and that returns + the name of the proxy to connect to. Since curl does not support JavaScript, + it cannot support .pac proxy configuration either. + + Some workarounds usually suggested to overcome this JavaScript dependency: + + Depending on the JavaScript complexity, write up a script that translates it + to another language and execute that. + + Read the JavaScript code and rewrite the same logic in another language. + + Implement a JavaScript interpreter, people have successfully used the + Mozilla JavaScript engine in the past. + + Ask your admins to stop this, for a static proxy setup or similar. + + 3.15 Can I do recursive fetches with curl? + + No. curl itself has no code that performs recursive operations, such as + those performed by wget and similar tools. + + There exists wrapper scripts with that functionality (for example the + curlmirror perl script), and you can write programs based on libcurl to do + it, but the command line tool curl itself cannot. + + 3.16 What certificates do I need when I use SSL? + + There are three different kinds of "certificates" to keep track of when we + talk about using SSL-based protocols (HTTPS or FTPS) using curl or libcurl. + + CLIENT CERTIFICATE + + The server you communicate with may require that you can provide this in + order to prove that you actually are who you claim to be. If the server + does not require this, you do not need a client certificate. + + A client certificate is always used together with a private key, and the + private key has a pass phrase that protects it. + + SERVER CERTIFICATE + + The server you communicate with has a server certificate. You can and should + verify this certificate to make sure that you are truly talking to the real + server and not a server impersonating it. + + CERTIFICATE AUTHORITY CERTIFICATE ("CA cert") + + You often have several CA certs in a CA cert bundle that can be used to + verify a server certificate that was signed by one of the authorities in the + bundle. curl does not come with a CA cert bundle but most curl installs + provide one. You can also override the default. + + The server certificate verification process is made by using a Certificate + Authority certificate ("CA cert") that was used to sign the server + certificate. Server certificate verification is enabled by default in curl + and libcurl and is often the reason for problems as explained in FAQ entry + 4.12 and the SSLCERTS document + (https://curl.se/docs/sslcerts.html). Server certificates that are + "self-signed" or otherwise signed by a CA that you do not have a CA cert + for, cannot be verified. If the verification during a connect fails, you are + refused access. You then need to explicitly disable the verification to + connect to the server. + + 3.17 How do I list the root directory of an FTP server? + + There are two ways. The way defined in the RFC is to use an encoded slash + in the first path part. List the "/tmp" directory like this: + + curl ftp://ftp.example.com/%2ftmp/ + + or the not-quite-kosher-but-more-readable way, by simply starting the path + section of the URL with a slash: + + curl ftp://ftp.example.com//tmp/ + + 3.18 Can I use curl to send a POST/PUT and not wait for a response? + + No. + + You can easily write your own program using libcurl to do such stunts. + + 3.19 How do I get HTTP from a host using a specific IP address? + + For example, you may be trying out a website installation that is not yet in + the DNS. Or you have a site using multiple IP addresses for a given host + name and you want to address a specific one out of the set. + + Set a custom Host: header that identifies the server name you want to reach + but use the target IP address in the URL: + + curl --header "Host: www.example.com" http://127.0.0.1/ + + You can also opt to add faked host name entries to curl with the --resolve + option. That has the added benefit that things like redirects will also work + properly. The above operation would instead be done as: + + curl --resolve www.example.com:80:127.0.0.1 http://www.example.com/ + + 3.20 How to SFTP from my user's home directory? + + Contrary to how FTP works, SFTP and SCP URLs specify the exact directory to + work with. It means that if you do not specify that you want the user's home + directory, you get the actual root directory. + + To specify a file in your user's home directory, you need to use the correct + URL syntax which for SFTP might look similar to: + + curl -O -u user:password sftp://example.com/~/file.txt + + and for SCP it is just a different protocol prefix: + + curl -O -u user:password scp://example.com/~/file.txt + + 3.21 Protocol xxx not supported or disabled in libcurl + + When passing on a URL to curl to use, it may respond that the particular + protocol is not supported or disabled. The particular way this error message + is phrased is because curl does not make a distinction internally of whether + a particular protocol is not supported (i.e. never got any code added that + knows how to speak that protocol) or if it was explicitly disabled. curl can + be built to only support a given set of protocols, and the rest would then + be disabled or not supported. + + Note that this error will also occur if you pass a wrongly spelled protocol + part as in "htpt://example.com" or as in the less evident case if you prefix + the protocol part with a space as in " http://example.com/". + + 3.22 curl -X gives me HTTP problems + + In normal circumstances, -X should hardly ever be used. + + By default you use curl without explicitly saying which request method to + use when the URL identifies an HTTP transfer. If you just pass in a URL like + "curl http://example.com" it will use GET. If you use -d or -F curl will use + POST, -I will cause a HEAD and -T will make it a PUT. + + If for whatever reason you are not happy with these default choices that curl + does for you, you can override those request methods by specifying -X + [WHATEVER]. This way you can for example send a DELETE by doing "curl -X + DELETE [URL]". + + It is thus pointless to do "curl -XGET [URL]" as GET would be used + anyway. In the same vein it is pointless to do "curl -X POST -d data + [URL]"... But you can make a fun and somewhat rare request that sends a + request-body in a GET request with something like "curl -X GET -d data + [URL]" + + Note that -X does not actually change curl's behavior as it only modifies the + actual string sent in the request, but that may of course trigger a + different set of events. + + Accordingly, by using -XPOST on a command line that for example would follow + a 303 redirect, you will effectively prevent curl from behaving + correctly. Be aware. + + +4. Running Problems + + 4.2 Why do I get problems when I use & or % in the URL? + + In general Unix shells, the & symbol is treated specially and when used, it + runs the specified command in the background. To safely send the & as a part + of a URL, you should quote the entire URL by using single (') or double (") + quotes around it. Similar problems can also occur on some shells with other + characters, including ?*!$~(){}<>\|;`. When in doubt, quote the URL. + + An example that would invoke a remote CGI that uses &-symbols could be: + + curl 'http://www.example.com/cgi-bin/query?text=yes&q=curl' + + In Windows, the standard DOS shell treats the percent sign specially and you + need to use TWO percent signs for each single one you want to use in the + URL. + + If you want a literal percent sign to be part of the data you pass in a POST + using -d/--data you must encode it as '%25' (which then also needs the + percent sign doubled on Windows machines). + + 4.3 How can I use {, }, [ or ] to specify multiple URLs? + + Because those letters have a special meaning to the shell, to be used in + a URL specified to curl you must quote them. + + An example that downloads two URLs (sequentially) would be: + + curl '{curl,www}.haxx.se' + + To be able to use those characters as actual parts of the URL (without using + them for the curl URL "globbing" system), use the -g/--globoff option: + + curl -g 'www.example.com/weirdname[].html' + + 4.4 Why do I get downloaded data even though the web page does not exist? + + curl asks remote servers for the page you specify. If the page does not exist + at the server, the HTTP protocol defines how the server should respond and + that means that headers and a "page" will be returned. That is simply how + HTTP works. + + By using the --fail option you can tell curl explicitly to not get any data + if the HTTP return code does not say success. + + 4.5 Why do I get return code XXX from an HTTP server? + + RFC 2616 clearly explains the return codes. This is a short transcript. Go + read the RFC for exact details: + + 4.5.1 "400 Bad Request" + + The request could not be understood by the server due to malformed + syntax. The client SHOULD NOT repeat the request without modifications. + + 4.5.2 "401 Unauthorized" + + The request requires user authentication. + + 4.5.3 "403 Forbidden" + + The server understood the request, but is refusing to fulfill it. + Authorization will not help and the request SHOULD NOT be repeated. + + 4.5.4 "404 Not Found" + + The server has not found anything matching the Request-URI. No indication + is given as to whether the condition is temporary or permanent. + + 4.5.5 "405 Method Not Allowed" + + The method specified in the Request-Line is not allowed for the resource + identified by the Request-URI. The response MUST include an Allow header + containing a list of valid methods for the requested resource. + + 4.5.6 "301 Moved Permanently" + + If you get this return code and an HTML output similar to this: + +

Moved Permanently

The document has moved
here. + + it might be because you requested a directory URL but without the trailing + slash. Try the same operation again _with_ the trailing URL, or use the + -L/--location option to follow the redirection. + + 4.6 Can you tell me what error code 142 means? + + All curl error codes are described at the end of the man page, in the + section called "EXIT CODES". + + Error codes that are larger than the highest documented error code means + that curl has exited due to a crash. This is a serious error, and we + appreciate a detailed bug report from you that describes how we could go + ahead and repeat this. + + 4.7 How do I keep user names and passwords secret in curl command lines? + + This problem has two sides: + + The first part is to avoid having clear-text passwords in the command line + so that they do not appear in 'ps' outputs and similar. That is easily + avoided by using the "-K" option to tell curl to read parameters from a file + or stdin to which you can pass the secret info. curl itself will also + attempt to "hide" the given password by blanking out the option - this + does not work on all platforms. + + To keep the passwords in your account secret from the rest of the world is + not a task that curl addresses. You could of course encrypt them somehow to + at least hide them from being read by human eyes, but that is not what + anyone would call security. + + Also note that regular HTTP (using Basic authentication) and FTP passwords + are sent as cleartext across the network. All it takes for anyone to fetch + them is to listen on the network. Eavesdropping is easy. Use more secure + authentication methods (like Digest, Negotiate or even NTLM) or consider the + SSL-based alternatives HTTPS and FTPS. + + 4.8 I found a bug + + It is not a bug if the behavior is documented. Read the docs first. + Especially check out the KNOWN_BUGS file, it may be a documented bug. + + If it is a problem with a binary you have downloaded or a package for your + particular platform, try contacting the person who built the package/archive + you have. + + If there is a bug, read the BUGS document first. Then report it as described + in there. + + 4.9 curl cannot authenticate to a server that requires NTLM? + + NTLM support requires OpenSSL, GnuTLS, mbedTLS, Secure Transport, or + Microsoft Windows libraries at build-time to provide this functionality. + + 4.10 My HTTP request using HEAD, PUT or DELETE does not work + + Many web servers allow or demand that the administrator configures the + server properly for these requests to work on the web server. + + Some servers seem to support HEAD only on certain kinds of URLs. + + To fully grasp this, try the documentation for the particular server + software you are trying to interact with. This is not anything curl can do + anything about. + + 4.11 Why do my HTTP range requests return the full document? + + Because the range may not be supported by the server, or the server may + choose to ignore it and return the full document anyway. + + 4.12 Why do I get "certificate verify failed" ? + + When you invoke curl and get an error 60 error back it means that curl + could not verify that the server's certificate was good. curl verifies the + certificate using the CA cert bundle and verifying for which names the + certificate has been granted. + + To completely disable the certificate verification, use -k. This does + however enable man-in-the-middle attacks and makes the transfer INSECURE. + We strongly advise against doing this for more than experiments. + + If you get this failure with a CA cert bundle installed and used, the + server's certificate might not be signed by one of the CA's in your CA + store. It might for example be self-signed. You then correct this problem by + obtaining a valid CA cert for the server. Or again, decrease the security by + disabling this check. + + At times, you find that the verification works in your favorite browser but + fails in curl. When this happens, the reason is usually that the server + sends an incomplete cert chain. The server is mandated to send all + "intermediate certificates" but does not. This typically works with browsers + anyway since they A) cache such certs and B) supports AIA which downloads + such missing certificates on demand. This is a server misconfiguration. A + good way to figure out if this is the case it to use the SSL Labs server + test and check the certificate chain: https://www.ssllabs.com/ssltest/ + + Details are also in the SSLCERTS.md document, found online here: + https://curl.se/docs/sslcerts.html + + 4.13 Why is curl -R on Windows one hour off? + + Since curl 7.53.0 this issue should be fixed as long as curl was built with + any modern compiler that allows for a 64-bit curl_off_t type. For older + compilers or prior curl versions it may set a time that appears one hour off. + This happens due to a flaw in how Windows stores and uses file modification + times and it is not easily worked around. For more details read this: + https://www.codeproject.com/Articles/1144/Beating-the-Daylight-Savings-Time-bug-and-getting + + 4.14 Redirects work in browser but not with curl + + curl supports HTTP redirects well (see item 3.8). Browsers generally support + at least two other ways to perform redirects that curl does not: + + Meta tags. You can write an HTML tag that will cause the browser to redirect + to another given URL after a certain time. + + JavaScript. You can write a JavaScript program embedded in an HTML page that + redirects the browser to another given URL. + + There is no way to make curl follow these redirects. You must either + manually figure out what the page is set to do, or write a script that parses + the results and fetches the new URL. + + 4.15 FTPS does not work + + curl supports FTPS (sometimes known as FTP-SSL) both implicit and explicit + mode. + + When a URL is used that starts with FTPS://, curl assumes implicit SSL on + the control connection and will therefore immediately connect and try to + speak SSL. FTPS:// connections default to port 990. + + To use explicit FTPS, you use an FTP:// URL and the --ftp-ssl option (or one + of its related flavors). This is the most common method, and the one + mandated by RFC 4217. This kind of connection will then of course use the + standard FTP port 21 by default. + + 4.16 My HTTP POST or PUT requests are slow + + libcurl makes all POST and PUT requests (except for requests with a small + request body) use the "Expect: 100-continue" header. This header allows the + server to deny the operation early so that libcurl can bail out before having + to send any data. This is useful in authentication cases and others. + + However, many servers do not implement the Expect: stuff properly and if the + server does not respond (positively) within 1 second libcurl will continue + and send off the data anyway. + + You can disable libcurl's use of the Expect: header the same way you disable + any header, using -H / CURLOPT_HTTPHEADER, or by forcing it to use HTTP 1.0. + + 4.17 Non-functional connect timeouts + + In most Windows setups having a timeout longer than 21 seconds make no + difference, as it will only send 3 TCP SYN packets and no more. The second + packet sent three seconds after the first and the third six seconds after + the second. No more than three packets are sent, no matter how long the + timeout is set. + + See option TcpMaxConnectRetransmissions on this page: + https://support.microsoft.com/en-us/kb/175523/en-us + + Also, even on non-Windows systems there may run a firewall or anti-virus + software or similar that accepts the connection but does not actually do + anything else. This will make (lib)curl to consider the connection connected + and thus the connect timeout will not trigger. + + 4.18 file:// URLs containing drive letters (Windows, NetWare) + + When using curl to try to download a local file, one might use a URL + in this format: + + file://D:/blah.txt + + you will find that even if D:\blah.txt does exist, curl returns a 'file + not found' error. + + According to RFC 1738 (https://www.ietf.org/rfc/rfc1738.txt), + file:// URLs must contain a host component, but it is ignored by + most implementations. In the above example, 'D:' is treated as the + host component, and is taken away. Thus, curl tries to open '/blah.txt'. + If your system is installed to drive C:, that will resolve to 'C:\blah.txt', + and if that does not exist you will get the not found error. + + To fix this problem, use file:// URLs with *three* leading slashes: + + file:///D:/blah.txt + + Alternatively, if it makes more sense, specify 'localhost' as the host + component: + + file://localhost/D:/blah.txt + + In either case, curl should now be looking for the correct file. + + 4.19 Why does not curl return an error when the network cable is unplugged? + + Unplugging a cable is not an error situation. The TCP/IP protocol stack + was designed to be fault tolerant, so even though there may be a physical + break somewhere the connection should not be affected, just possibly + delayed. Eventually, the physical break will be fixed or the data will be + re-routed around the physical problem through another path. + + In such cases, the TCP/IP stack is responsible for detecting when the + network connection is irrevocably lost. Since with some protocols it is + perfectly legal for the client to wait indefinitely for data, the stack may + never report a problem, and even when it does, it can take up to 20 minutes + for it to detect an issue. The curl option --keepalive-time enables + keep-alive support in the TCP/IP stack which makes it periodically probe the + connection to make sure it is still available to send data. That should + reliably detect any TCP/IP network failure. + + TCP keep alive will not detect the network going down before the TCP/IP + connection is established (e.g. during a DNS lookup) or using protocols that + do not use TCP. To handle those situations, curl offers a number of timeouts + on its own. --speed-limit/--speed-time will abort if the data transfer rate + falls too low, and --connect-timeout and --max-time can be used to put an + overall timeout on the connection phase or the entire transfer. + + A libcurl-using application running in a known physical environment (e.g. + an embedded device with only a single network connection) may want to act + immediately if its lone network connection goes down. That can be achieved + by having the application monitor the network connection on its own using an + OS-specific mechanism, then signaling libcurl to abort (see also item 5.13). + + 4.20 curl does not return error for HTTP non-200 responses + + Correct. Unless you use -f (--fail). + + When doing HTTP transfers, curl will perform exactly what you are asking it + to do and if successful it will not return an error. You can use curl to + test your web server's "file not found" page (that gets 404 back), you can + use it to check your authentication protected web pages (that gets a 401 + back) and so on. + + The specific HTTP response code does not constitute a problem or error for + curl. It simply sends and delivers HTTP as you asked and if that worked, + everything is fine and dandy. The response code is generally providing more + higher level error information that curl does not care about. The error was + not in the HTTP transfer. + + If you want your command line to treat error codes in the 400 and up range + as errors and thus return a non-zero value and possibly show an error + message, curl has a dedicated option for that: -f (CURLOPT_FAILONERROR in + libcurl speak). + + You can also use the -w option and the variable %{response_code} to extract + the exact response code that was returned in the response. + +5. libcurl Issues + + 5.1 Is libcurl thread-safe? + + Yes. + + We have written the libcurl code specifically adjusted for multi-threaded + programs. libcurl will use thread-safe functions instead of non-safe ones if + your system has such. Note that you must never share the same handle in + multiple threads. + + There may be some exceptions to thread safety depending on how libcurl was + built. Please review the guidelines for thread safety to learn more: + https://curl.se/libcurl/c/threadsafe.html + + 5.2 How can I receive all data into a large memory chunk? + + [ See also the examples/getinmemory.c source ] + + You are in full control of the callback function that gets called every time + there is data received from the remote server. You can make that callback do + whatever you want. You do not have to write the received data to a file. + + One solution to this problem could be to have a pointer to a struct that you + pass to the callback function. You set the pointer using the + CURLOPT_WRITEDATA option. Then that pointer will be passed to the callback + instead of a FILE * to a file: + + /* imaginary struct */ + struct MemoryStruct { + char *memory; + size_t size; + }; + + /* imaginary callback function */ + size_t + WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) + { + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)data; + + mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1); + if (mem->memory) { + memcpy(&(mem->memory[mem->size]), ptr, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + return realsize; + } + + 5.3 How do I fetch multiple files with libcurl? + + libcurl has excellent support for transferring multiple files. You should + just repeatedly set new URLs with curl_easy_setopt() and then transfer it + with curl_easy_perform(). The handle you get from curl_easy_init() is not + only reusable, but you are even encouraged to reuse it if you can, as that + will enable libcurl to use persistent connections. + + 5.4 Does libcurl do Winsock initialization on win32 systems? + + Yes, if told to in the curl_global_init() call. + + 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ? + + Yes, but you cannot open a FILE * and pass the pointer to a DLL and have + that DLL use the FILE * (as the DLL and the client application cannot access + each others' variable memory areas). If you set CURLOPT_WRITEDATA you must + also use CURLOPT_WRITEFUNCTION as well to set a function that writes the + file, even if that simply writes the data to the specified FILE *. + Similarly, if you use CURLOPT_READDATA you must also specify + CURLOPT_READFUNCTION. + + 5.6 What about Keep-Alive or persistent connections? + + curl and libcurl have excellent support for persistent connections when + transferring several files from the same server. curl will attempt to reuse + connections for all URLs specified on the same command line/config file, and + libcurl will reuse connections for all transfers that are made using the + same libcurl handle. + + When you use the easy interface the connection cache is kept within the easy + handle. If you instead use the multi interface, the connection cache will be + kept within the multi handle and will be shared among all the easy handles + that are used within the same multi handle. + + 5.7 Link errors when building libcurl on Windows + + You need to make sure that your project, and all the libraries (both static + and dynamic) that it links against, are compiled/linked against the same run + time library. + + This is determined by the /MD, /ML, /MT (and their corresponding /M?d) + options to the command line compiler. /MD (linking against MSVCRT dll) seems + to be the most commonly used option. + + When building an application that uses the static libcurl library, you must + add -DCURL_STATICLIB to your CFLAGS. Otherwise the linker will look for + dynamic import symbols. If you are using Visual Studio, you need to instead + add CURL_STATICLIB in the "Preprocessor Definitions" section. + + If you get a linker error like "unknown symbol __imp__curl_easy_init ..." you + have linked against the wrong (static) library. If you want to use the + libcurl.dll and import lib, you do not need any extra CFLAGS, but use one of + the import libraries below. These are the libraries produced by the various + lib/Makefile.* files: + + Target: static lib. import lib for libcurl*.dll. + ----------------------------------------------------------- + MinGW: libcurl.a libcurldll.a + MSVC (release): libcurl.lib libcurl_imp.lib + MSVC (debug): libcurld.lib libcurld_imp.lib + Borland: libcurl.lib libcurl_imp.lib + + 5.8 libcurl.so.X: open failed: No such file or directory + + This is an error message you might get when you try to run a program linked + with a shared version of libcurl and your runtime linker (ld.so) could not + find the shared library named libcurl.so.X. (Where X is the number of the + current libcurl ABI, typically 3 or 4). + + You need to make sure that ld.so finds libcurl.so.X. You can do that + multiple ways, and it differs somewhat between different operating systems. + They are usually: + + * Add an option to the linker command line that specify the hard-coded path + the runtime linker should check for the lib (usually -R) + + * Set an environment variable (LD_LIBRARY_PATH for example) where ld.so + should check for libs + + * Adjust the system's config to check for libs in the directory where you have + put the library (like Linux's /etc/ld.so.conf) + + 'man ld.so' and 'man ld' will tell you more details + + 5.9 How does libcurl resolve host names? + + libcurl supports a large number of name resolve functions. One of them is + picked at build-time and will be used unconditionally. Thus, if you want to + change name resolver function you must rebuild libcurl and tell it to use a + different function. + + - The non-IPv6 resolver that can use one of four different host name resolve + calls (depending on what your system supports): + + A - gethostbyname() + B - gethostbyname_r() with 3 arguments + C - gethostbyname_r() with 5 arguments + D - gethostbyname_r() with 6 arguments + + - The IPv6-resolver that uses getaddrinfo() + + - The c-ares based name resolver that uses the c-ares library for resolves. + Using this offers asynchronous name resolves. + + - The threaded resolver (default option on Windows). It uses: + + A - gethostbyname() on plain IPv4 hosts + B - getaddrinfo() on IPv6 enabled hosts + + Also note that libcurl never resolves or reverse-lookups addresses given as + pure numbers, such as 127.0.0.1 or ::1. + + 5.10 How do I prevent libcurl from writing the response to stdout? + + libcurl provides a default built-in write function that writes received data + to stdout. Set the CURLOPT_WRITEFUNCTION to receive the data, or possibly + set CURLOPT_WRITEDATA to a different FILE * handle. + + 5.11 How do I make libcurl not receive the whole HTTP response? + + You make the write callback (or progress callback) return an error and + libcurl will then abort the transfer. + + 5.12 Can I make libcurl fake or hide my real IP address? + + No. libcurl operates on a higher level. Besides, faking IP address would + imply sending IP packets with a made-up source address, and then you normally + get a problem with receiving the packet sent back as they would then not be + routed to you. + + If you use a proxy to access remote sites, the sites will not see your local + IP address but instead the address of the proxy. + + Also note that on many networks NATs or other IP-munging techniques are used + that makes you see and use a different IP address locally than what the + remote server will see you coming from. You may also consider using + https://www.torproject.org/ . + + 5.13 How do I stop an ongoing transfer? + + With the easy interface you make sure to return the correct error code from + one of the callbacks, but none of them are instant. There is no function you + can call from another thread or similar that will stop it immediately. + Instead, you need to make sure that one of the callbacks you use returns an + appropriate value that will stop the transfer. Suitable callbacks that you + can do this with include the progress callback, the read callback and the + write callback. + + If you are using the multi interface, you can also stop a transfer by + removing the particular easy handle from the multi stack at any moment you + think the transfer is done or when you wish to abort the transfer. + + 5.14 Using C++ non-static functions for callbacks? + + libcurl is a C library, it does not know anything about C++ member functions. + + You can overcome this "limitation" with relative ease using a static + member function that is passed a pointer to the class: + + // f is the pointer to your object. + static size_t YourClass::func(void *buffer, size_t sz, size_t n, void *f) + { + // Call non-static member function. + static_cast(f)->nonStaticFunction(); + } + + // This is how you pass pointer to the static function: + curl_easy_setopt(hcurl, CURLOPT_WRITEFUNCTION, YourClass::func); + curl_easy_setopt(hcurl, CURLOPT_WRITEDATA, this); + + 5.15 How do I get an FTP directory listing? + + If you end the FTP URL you request with a slash, libcurl will provide you + with a directory listing of that given directory. You can also set + CURLOPT_CUSTOMREQUEST to alter what exact listing command libcurl would use + to list the files. + + The follow-up question tends to be how is a program supposed to parse the + directory listing. How does it know what's a file and what's a directory and + what's a symlink etc. If the FTP server supports the MLSD command then it + will return data in a machine-readable format that can be parsed for type. + The types are specified by RFC 3659 section 7.5.1. If MLSD is not supported + then you have to work with what you are given. The LIST output format is + entirely at the server's own liking and the NLST output does not reveal any + types and in many cases does not even include all the directory entries. + Also, both LIST and NLST tend to hide unix-style hidden files (those that + start with a dot) by default so you need to do "LIST -a" or similar to see + them. + + Example - List only directories. + ftp.funet.fi supports MLSD and ftp.kernel.org does not: + + curl -s ftp.funet.fi/pub/ -X MLSD | \ + perl -lne 'print if s/(?:^|;)type=dir;[^ ]+ (.+)$/$1/' + + curl -s ftp.kernel.org/pub/linux/kernel/ | \ + perl -lne 'print if s/^d[-rwx]{9}(?: +[^ ]+){7} (.+)$/$1/' + + If you need to parse LIST output in libcurl one such existing + list parser is available at https://cr.yp.to/ftpparse.html Versions of + libcurl since 7.21.0 also provide the ability to specify a wildcard to + download multiple files from one FTP directory. + + 5.16 I want a different time-out + + Sometimes users realize that CURLOPT_TIMEOUT and CURLOPT_CONNECTIMEOUT are + not sufficiently advanced or flexible to cover all the various use cases and + scenarios applications end up with. + + libcurl offers many more ways to time-out operations. A common alternative + is to use the CURLOPT_LOW_SPEED_LIMIT and CURLOPT_LOW_SPEED_TIME options to + specify the lowest possible speed to accept before to consider the transfer + timed out. + + The most flexible way is by writing your own time-out logic and using + CURLOPT_XFERINFOFUNCTION (perhaps in combination with other callbacks) and + use that to figure out exactly when the right condition is met when the + transfer should get stopped. + + 5.17 Can I write a server with libcurl? + + No. libcurl offers no functions or building blocks to build any kind of + Internet protocol server. libcurl is only a client-side library. For server + libraries, you need to continue your search elsewhere but there exist many + good open source ones out there for most protocols you could want a server + for. There are also really good stand-alone servers that have been tested + and proven for many years. There is no need for you to reinvent them. + + 5.18 Does libcurl use threads? + + Put simply: no, libcurl will execute in the same thread you call it in. All + callbacks will be called in the same thread as the one you call libcurl in. + + If you want to avoid your thread to be blocked by the libcurl call, you make + sure you use the non-blocking multi API which will do transfers + asynchronously - still in the same single thread. + + libcurl will potentially internally use threads for name resolving, if it + was built to work like that, but in those cases it will create the child + threads by itself and they will only be used and then killed internally by + libcurl and never exposed to the outside. + +6. License Issues + + curl and libcurl are released under a MIT/X derivative license. The license + is liberal and should not impose a problem for your project. This section is + just a brief summary for the cases we get the most questions. (Parts of this + section was much enhanced by Bjorn Reese.) + + We are not lawyers and this is not legal advice. You should probably consult + one if you want true and accurate legal insights without our prejudice. Note + especially that this section concerns the libcurl license only; compiling in + features of libcurl that depend on other libraries (e.g. OpenSSL) may affect + the licensing obligations of your application. + + 6.1 I have a GPL program, can I use the libcurl library? + + Yes + + Since libcurl may be distributed under the MIT/X derivative license, it can + be used together with GPL in any software. + + 6.2 I have a closed-source program, can I use the libcurl library? + + Yes + + libcurl does not put any restrictions on the program that uses the library. + + 6.3 I have a BSD licensed program, can I use the libcurl library? + + Yes + + libcurl does not put any restrictions on the program that uses the library. + + 6.4 I have a program that uses LGPL libraries, can I use libcurl? + + Yes + + The LGPL license does not clash with other licenses. + + 6.5 Can I modify curl/libcurl for my program and keep the changes secret? + + Yes + + The MIT/X derivative license practically allows you to do almost anything + with the sources, on the condition that the copyright texts in the sources + are left intact. + + 6.6 Can you please change the curl/libcurl license to XXXX? + + No. + + We have carefully picked this license after years of development and + discussions and a large amount of people have contributed with source code + knowing that this is the license we use. This license puts the restrictions + we want on curl/libcurl and it does not spread to other programs or + libraries that use it. It should be possible for everyone to use libcurl or + curl in their projects, no matter what license they already have in use. + + 6.7 What are my obligations when using libcurl in my commercial apps? + + Next to none. All you need to adhere to is the MIT-style license (stated in + the COPYING file) which basically says you have to include the copyright + notice in "all copies" and that you may not use the copyright holder's name + when promoting your software. + + You do not have to release any of your source code. + + You do not have to reveal or make public any changes to the libcurl source + code. + + You do not have to broadcast to the world that you are using libcurl within + your app. + + All we ask is that you disclose "the copyright notice and this permission + notice" somewhere. Most probably like in the documentation or in the section + where other third party dependencies already are mentioned and acknowledged. + + As can be seen here: https://curl.se/docs/companies.html and elsewhere, + more and more companies are discovering the power of libcurl and take + advantage of it even in commercial environments. + + +7. PHP/CURL Issues + + 7.1 What is PHP/CURL? + + The module for PHP that makes it possible for PHP programs to access curl- + functions from within PHP. + + In the cURL project we call this module PHP/CURL to differentiate it from + curl the command line tool and libcurl the library. The PHP team however + does not refer to it like this (for unknown reasons). They call it plain + CURL (often using all caps) or sometimes ext/curl, but both cause much + confusion to users which in turn gives us a higher question load. + + 7.2 Who wrote PHP/CURL? + + PHP/CURL was initially written by Sterling Hughes. + + 7.3 Can I perform multiple requests using the same handle? + + Yes - at least in PHP version 4.3.8 and later (this has been known to not + work in earlier versions, but the exact version when it started to work is + unknown to me). + + After a transfer, you just set new options in the handle and make another + transfer. This will make libcurl reuse the same connection if it can. + + 7.4 Does PHP/CURL have dependencies? + + PHP/CURL is a module that comes with the regular PHP package. It depends on + and uses libcurl, so you need to have libcurl installed properly before + PHP/CURL can be used. + +8. Development + + 8.1 Why does curl use C89? + + As with everything in curl, there is a history and we keep using what we have + used before until someone brings up the subject and argues for and works on + changing it. + + We started out using C89 in the 1990s because that was the only way to write + a truly portable C program and have it run as widely as possible. C89 was for + a long time even necessary to make things work on otherwise considered modern + platforms such as Windows. Today, we do not really know how many users that + still require the use of a C89 compiler. + + We will continue to use C89 for as long as nobody brings up a strong enough + reason for us to change our minds. The core developers of the project do not + feel restricted by this and we are not convinced that going C99 will offer us + enough of a benefit to warrant the risk of cutting off a share of users. + + 8.2 Will curl be rewritten? + + In one go: no. Little by little over time? Maybe. + + Over the years, new languages and clever operating environments come and go. + Every now and then the urge apparently arises to request that we rewrite curl + in another language. + + Some the most important properties in curl are maintaining the API and ABI + for libcurl and keeping the behavior for the command line tool. As long as we + can do that, everything else is up for discussion. To maintain the ABI, we + probably have to maintain a certain amount of code in C, and to remain rock + stable, we will never risk anything by rewriting a lot of things in one go. + That said, we can certainly offer more and more optional backends written in + other languages, as long as those backends can be plugged in at build-time. + Backends can be written in any language, but should probably provide APIs + usable from C to ease integration and transition. diff --git a/docs/FEATURES.md b/docs/FEATURES.md new file mode 100644 index 0000000..4a589e1 --- /dev/null +++ b/docs/FEATURES.md @@ -0,0 +1,219 @@ +# Features -- what curl can do + +## curl tool + + - config file support + - multiple URLs in a single command line + - range "globbing" support: [0-13], {one,two,three} + - multiple file upload on a single command line + - custom maximum transfer rate + - redirect stderr + - parallel transfers + +## libcurl + + - URL RFC 3986 syntax + - custom maximum download time + - custom least download speed acceptable + - custom output result after completion + - guesses protocol from hostname unless specified + - uses .netrc + - progress bar with time statistics while downloading + - "standard" proxy environment variables support + - compiles on win32 (reported builds on 70+ operating systems) + - selectable network interface for outgoing traffic + - IPv6 support on Unix and Windows + - happy eyeballs dual-stack connects + - persistent connections + - SOCKS 4 + 5 support, with or without local name resolving + - supports user name and password in proxy environment variables + - operations through HTTP proxy "tunnel" (using CONNECT) + - replaceable memory functions (malloc, free, realloc, etc) + - asynchronous name resolving (6) + - both a push and a pull style interface + - international domain names (10) + +## HTTP + + - HTTP/0.9 responses are optionally accepted + - HTTP/1.0 + - HTTP/1.1 + - HTTP/2, including multiplexing and server push (5) + - GET + - PUT + - HEAD + - POST + - multipart formpost (RFC 1867-style) + - authentication: Basic, Digest, NTLM (9) and Negotiate (SPNEGO) (3) + to server and proxy + - resume (both GET and PUT) + - follow redirects + - maximum amount of redirects to follow + - custom HTTP request + - cookie get/send fully parsed + - reads/writes the Netscape cookie file format + - custom headers (replace/remove internally generated headers) + - custom user-agent string + - custom referrer string + - range + - proxy authentication + - time conditions + - via HTTP proxy, HTTPS proxy or SOCKS proxy + - retrieve file modification date + - Content-Encoding support for deflate and gzip + - "Transfer-Encoding: chunked" support in uploads + - automatic data compression (11) + +## HTTPS (1) + + - (all the HTTP features) + - HTTP/3 experimental support + - using client certificates + - verify server certificate + - via HTTP proxy, HTTPS proxy or SOCKS proxy + - select desired encryption + - select usage of a specific SSL version + +## FTP + + - download + - authentication + - Kerberos 5 (12) + - active/passive using PORT, EPRT, PASV or EPSV + - single file size information (compare to HTTP HEAD) + - 'type=' URL support + - directory listing + - directory listing names-only + - upload + - upload append + - upload via http-proxy as HTTP PUT + - download resume + - upload resume + - custom ftp commands (before and/or after the transfer) + - simple "range" support + - via HTTP proxy, HTTPS proxy or SOCKS proxy + - all operations can be tunneled through proxy + - customizable to retrieve file modification date + - no directory depth limit + +## FTPS (1) + + - implicit `ftps://` support that use SSL on both connections + - explicit "AUTH TLS" and "AUTH SSL" usage to "upgrade" plain `ftp://` + connection to use SSL for both or one of the connections + +## SCP (8) + + - both password and public key auth + +## SFTP (7) + + - both password and public key auth + - with custom commands sent before/after the transfer + +## TFTP + + - download + - upload + +## TELNET + + - connection negotiation + - custom telnet options + - stdin/stdout I/O + +## LDAP (2) + + - full LDAP URL support + +## DICT + + - extended DICT URL support + +## FILE + + - URL support + - upload + - resume + +## SMB + + - SMBv1 over TCP and SSL + - download + - upload + - authentication with NTLMv1 + +## SMTP + + - authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9), Kerberos 5 + (4) and External. + - send emails + - mail from support + - mail size support + - mail auth support for trusted server-to-server relaying + - multiple recipients + - via http-proxy + +## SMTPS (1) + + - implicit `smtps://` support + - explicit "STARTTLS" usage to "upgrade" plain `smtp://` connections to use SSL + - via http-proxy + +## POP3 + + - authentication: Clear Text, APOP and SASL + - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9), + Kerberos 5 (4) and External. + - list emails + - retrieve emails + - enhanced command support for: CAPA, DELE, TOP, STAT, UIDL and NOOP via + custom requests + - via http-proxy + +## POP3S (1) + + - implicit `pop3s://` support + - explicit `STLS` usage to "upgrade" plain `pop3://` connections to use SSL + - via http-proxy + +## IMAP + + - authentication: Clear Text and SASL + - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9), + Kerberos 5 (4) and External. + - list the folders of a mailbox + - select a mailbox with support for verifying the `UIDVALIDITY` + - fetch emails with support for specifying the UID and SECTION + - upload emails via the append command + - enhanced command support for: EXAMINE, CREATE, DELETE, RENAME, STATUS, + STORE, COPY and UID via custom requests + - via http-proxy + +## IMAPS (1) + + - implicit `imaps://` support + - explicit "STARTTLS" usage to "upgrade" plain `imap://` connections to use SSL + - via http-proxy + +## MQTT + + - Subscribe to and publish topics using URL scheme `mqtt://broker/topic` + +## Footnotes + + 1. requires a TLS library + 2. requires OpenLDAP or WinLDAP + 3. requires a GSS-API implementation (such as Heimdal or MIT Kerberos) or + SSPI (native Windows) + 4. requires a GSS-API implementation, however, only Windows SSPI is + currently supported + 5. requires nghttp2 + 6. requires c-ares + 7. requires libssh2, libssh or wolfSSH + 8. requires libssh2 or libssh + 9. requires OpenSSL, GnuTLS, mbedTLS, Secure Transport or SSPI + (native Windows) + 10. requires libidn2 or Windows + 11. requires libz, brotli and/or zstd + 12. requires a GSS-API implementation (such as Heimdal or MIT Kerberos) diff --git a/docs/GOVERNANCE.md b/docs/GOVERNANCE.md new file mode 100644 index 0000000..0f7029e --- /dev/null +++ b/docs/GOVERNANCE.md @@ -0,0 +1,182 @@ +# Decision making in the curl project + +A rough guide to how we make decisions and who does what. + +## BDFL + +This project was started by and has to some extent been pushed forward over +the years with Daniel Stenberg as the driving force. It matches a standard +BDFL (Benevolent Dictator For Life) style project. + +This setup has been used due to convenience and the fact that it has worked +fine this far. It is not because someone thinks of it as a superior project +leadership model. It will also only continue working as long as Daniel manages +to listen in to what the project and the general user population wants and +expects from us. + +## Legal entity + +There is no legal entity. The curl project is just a bunch of people scattered +around the globe with the common goal to produce source code that creates +great products. We are not part of any umbrella organization and we are not +located in any specific country. We are totally independent. + +The copyrights in the project are owned by the individuals and organizations +that wrote those parts of the code. + +## Decisions + +The curl project is not a democracy, but everyone is entitled to state their +opinion and may argue for their sake within the community. + +All and any changes that have been done or will be done are eligible to bring +up for discussion, to object to or to praise. Ideally, we find consensus for +the appropriate way forward in any given situation or challenge. + +If there is no obvious consensus, a maintainer who's knowledgeable in the +specific area will take an "executive" decision that they think is the right +for the project. + +## Donations + +Donating plain money to curl is best done to curl's [Open Collective +fund](https://opencollective.com/curl). Open Collective is a US based +non-profit organization that holds on to funds for us. This fund is then used +for paying the curl security bug bounties, to reimburse project related +expenses etc. + +Donations to the project can also come in the form of server hosting, providing +services and paying for people to work on curl related code etc. Usually, such +donations are services paid for directly by the sponsors. + +We grade sponsors in a few different levels and if they meet the criteria, +they can be mentioned on the Sponsors page on the curl website. + +## Commercial Support + +The curl project does not do or offer commercial support. It only hosts +mailing lists, runs bug trackers etc to facilitate communication and work. + +However, Daniel works for wolfSSL and we offer commercial curl support there. + +# Key roles + +## User + +Someone who uses or has used curl or libcurl. + +## Contributor + +Someone who has helped the curl project, who has contributed to bring it +forward. Contributing could be to provide advice, debug a problem, file a bug +report, run test infrastructure or writing code etc. + +## Commit author + +Sometimes also called 'committer'. Someone who has authored a commit in the +curl source code repository. Committers are recorded as `Author` in git. + +## Maintainers + +A maintainer in the curl project is an individual who has been given +permissions to push commits to one of the git repositories. + +Maintainers are free to push commits to the repositories at their own will. +Maintainers are however expected to listen to feedback from users and any +change that is non-trivial in size or nature *should* be brought to the +project as a Pull-Request (PR) to allow others to comment/object before merge. + +## Former maintainers + +A maintainer who stops being active in the project will at some point get +their push permissions removed. We do this for security reasons but also to +make sure that we always have the list of maintainers as "the team that push +stuff to curl". + +Getting push permissions removed is not a punishment. Everyone who ever worked +on maintaining curl is considered a hero, for all time hereafter. + +## Security team members + +We have a security team. That is the team of people who are subscribed to the +curl-security mailing list; the receivers of security reports from users and +developers. This list of people will vary over time but should be skilled +developers familiar with the curl project. + +The security team works best when it consists of a small set of active +persons. We invite new members when the team seems to need it, and we also +expect to retire security team members as they "drift off" from the project or +just find themselves unable to perform their duties there. + +## Server admins + +We run a web server, a mailing list and more on the curl project's primary +server. That physical machine is owned and run by Haxx. Daniel is the primary +admin of all things curl related server stuff, but Björn Stenberg and Linus +Feltzing serve as backup admins for when Daniel is gone or unable. + +The primary server is paid for by Haxx. The machine is physically located in a +server bunker in Stockholm Sweden, operated by the company Glesys. + +The website contents are served to the web via Fastly and Daniel is the +primary curl contact with Fastly. + +## BDFL + +That is Daniel. + +# Maintainers + +A curl maintainer is a project volunteer who has the authority and rights to +merge changes into a git repository in the curl project. + +Anyone can aspire to become a curl maintainer. + +### Duties + +There are no mandatory duties. We hope and wish that maintainers consider +reviewing patches and help merging them, especially when the changes are +within the area of personal expertise and experience. + +### Requirements + +- only merge code that meets our quality and style guide requirements. +- *never* merge code without doing a PR first, unless the change is "trivial" +- if in doubt, ask for input/feedback from others + +### Recommendations + +- we require two-factor authentication enabled on your GitHub account to + reduce risk of malicious source code tampering +- consider enabling signed git commits for additional verification of changes + +### Merge advice + +When you are merging patches/pull requests... + +- make sure the commit messages follow our template +- squash patch sets into a few logical commits even if the PR did not, if + necessary +- avoid the "merge" button on GitHub, do it "manually" instead to get full + control and full audit trail (GitHub leaves out you as "Committer:") +- remember to credit the reporter and the helpers. + +## Who are maintainers? + +The [list of maintainers](https://github.com/orgs/curl/people). Be aware that +the level of presence and activity in the project vary greatly between +different individuals and over time. + +### Become a maintainer? + +If you think you can help making the project better by shouldering some +maintaining responsibilities, then please get in touch. + +You will be expected to be familiar with the curl project and its ways of +working. You need to have gotten a few quality patches merged as a proof of +this. + +### Stop being a maintainer + +If you (appear to) not be active in the project anymore, you may be removed as +a maintainer. Thank you for your service. diff --git a/docs/HELP-US.md b/docs/HELP-US.md new file mode 100644 index 0000000..90c9724 --- /dev/null +++ b/docs/HELP-US.md @@ -0,0 +1,89 @@ +# How to get started helping out in the curl project + +We are always in need of more help. If you are new to the project and are +looking for ways to contribute and help out, this document aims to give a few +good starting points. + +You may subscribe to the [curl-library mailing +list](https://lists.haxx.se/listinfo/curl-library) to keep track of the +current discussion topics; or if you are registered on GitHub, you can use the +[Discussions section](https://github.com/curl/curl/discussions) on the main +curl repository. + +## Scratch your own itch + +One of the best ways is to start working on any problems or issues you have +found yourself or perhaps got annoyed at in the past. It can be a spelling +error in an error text or a weirdly phrased section in a man page. Hunt it +down and report the bug. Or make your first pull request with a fix for that. + +## Smaller tasks + +Some projects mark small issues as "beginner friendly", "bite-sized" or +similar. We do not do that in curl since such issues never linger around long +enough. Simple issues get handled fast. + +If you are looking for a smaller or simpler task in the project to help out +with as an entry-point into the project, perhaps because you are a newcomer or +even maybe not a terribly experienced developer, here's our advice: + + - Read through this document to get a grasp on a general approach to use + - Consider adding a test case for something not currently tested (correctly) + - Consider updating or adding documentation + - One way to get started gently in the project, is to participate in an + existing issue/PR and help out by reproducing the issue, review the code in + the PR etc. + +## Help wanted + +In the issue tracker we occasionally mark bugs with [help +wanted](https://github.com/curl/curl/labels/help%20wanted), as a sign that the +bug is acknowledged to exist and that there is nobody known to work on this +issue for the moment. Those are bugs that are fine to "grab" and provide a +pull request for. The complexity level of these will of course vary, so pick +one that piques your interest. + +## Work on known bugs + +Some bugs are known and have not yet received attention and work enough to get +fixed. We collect such known existing flaws in the +[KNOWN_BUGS](https://curl.se/docs/knownbugs.html) page. Many of them link +to the original bug report with some additional details, but some may also +have aged a bit and may require some verification that the bug still exists in +the same way and that what was said about it in the past is still valid. + +## Fix autobuild problems + +On the [autobuilds page](https://curl.se/dev/builds.html) we show a +collection of test results from the automatic curl build and tests that are +performed by volunteers. Fixing compiler warnings and errors shown there is +something we value greatly. Also, if you own or run systems or architectures +that are not already tested in the autobuilds, we also appreciate more +volunteers running builds automatically to help us keep curl portable. + +## TODO items + +Ideas for features and functions that we have considered worthwhile to +implement and provide are kept in the +[TODO](https://curl.se/docs/todo.html) file. Some of the ideas are +rough. Some are well thought out. Some probably are not really suitable +anymore. + +Before you invest a lot of time on a TODO item, do bring it up for discussion +on the mailing list. For discussion on applicability but also for ideas and +brainstorming on specific ways to do the implementation etc. + +## You decide + +You can also come up with a completely new thing you think we should do. Or +not do. Or fix. Or add to the project. You then either bring it to the mailing +list first to see if people will shoot down the idea at once, or you bring a +first draft of the idea as a pull request and take the discussion there around +the specific implementation. Either way is fine. + +## CONTRIBUTE + +We offer [guidelines](https://curl.se/dev/contribute.html) that are +suitable to be familiar with before you decide to contribute to curl. If +you are used to open source development, you will probably not find many +surprises there. diff --git a/docs/HISTORY.md b/docs/HISTORY.md new file mode 100644 index 0000000..d28217c --- /dev/null +++ b/docs/HISTORY.md @@ -0,0 +1,437 @@ +How curl Became Like This +========================= + +Towards the end of 1996, Daniel Stenberg was spending time writing an IRC bot +for an Amiga related channel on EFnet. He then came up with the idea to make +currency-exchange calculations available to Internet Relay Chat (IRC) +users. All the necessary data were published on the Web; he just needed to +automate their retrieval. + +1996 +---- + +On November 11, 1996 the Brazilian developer Rafael Sagula wrote and released +HttpGet version 0.1. + +Daniel extended this existing command-line open-source tool. After a few minor +adjustments, it did just what he needed. The first release with Daniel's +additions was 0.2, released on December 17, 1996. Daniel quickly became the +new maintainer of the project. + +1997 +---- + +HttpGet 0.3 was released in January 1997 and now it accepted HTTP URLs on the +command line. + +HttpGet 1.0 was released on April 8 1997 with brand new HTTP proxy support. + +We soon found and fixed support for getting currencies over GOPHER. Once FTP +download support was added, the name of the project was changed and urlget 2.0 +was released in August 1997. The http-only days were already passed. + +Version 2.2 was released on August 14 1997 and introduced support to build for +and run on Windows and Solaris. + +November 24 1997: Version 3.1 added FTP upload support. + +Version 3.5 added support for HTTP POST. + +1998 +---- + +February 4: urlget 3.10 + +February 9: urlget 3.11 + +March 14: urlget 3.12 added proxy authentication. + +The project slowly grew bigger. With upload capabilities, the name was once +again misleading and a second name change was made. On March 20, 1998 curl 4 +was released. (The version numbering from the previous names was kept.) + +(Unrelated to this project a company called Curl Corporation registered a US +trademark on the name "CURL" on May 18 1998. That company had then already +registered the curl.com domain back in November of the previous year. All this +was revealed to us much later.) + +SSL support was added, powered by the SSLeay library. + +August: first announcement of curl on freshmeat.net. + +October: with the curl 4.9 release and the introduction of cookie support, +curl was no longer released under the GPL license. Now we are at 4000 lines of +code, we switched over to the MPL license to restrict the effects of +"copyleft". + +November: configure script and reported successful compiles on several +major operating systems. The never-quite-understood -F option was added and +curl could now simulate quite a lot of a browser. TELNET support was added. + +Curl 5 was released in December 1998 and introduced the first ever curl man +page. People started making Linux RPM packages out of it. + +1999 +---- + +January: DICT support added. + +OpenSSL took over and SSLeay was abandoned. + +May: first Debian package. + +August: LDAP:// and FILE:// support added. The curl website gets 1300 visits +weekly. Moved site to curl.haxx.nu. + +September: Released curl 6.0. 15000 lines of code. + +December 28: added the project on Sourceforge and started using its services +for managing the project. + +2000 +---- + +Spring: major internal overhaul to provide a suitable library interface. +The first non-beta release was named 7.1 and arrived in August. This offered +the easy interface and turned out to be the beginning of actually getting +other software and programs to be based on and powered by libcurl. Almost +20000 lines of code. + +June: the curl site moves to "curl.haxx.se" + +August, the curl website gets 4000 visits weekly. + +The PHP guys adopted libcurl already the same month, when the first ever third +party libcurl binding showed up. CURL has been a supported module in PHP since +the release of PHP 4.0.2. This would soon get followers. More than 16 +different bindings exist at the time of this writing. + +September: kerberos4 support was added. + +November: started the work on a test suite for curl. It was later re-written +from scratch again. The libcurl major SONAME number was set to 1. + +2001 +---- + +January: Daniel released curl 7.5.2 under a new license again: MIT (or +MPL). The MIT license is extremely liberal and can be combined with GPL +in other projects. This would finally put an end to the "complaints" from +people involved in GPLed projects that previously were prohibited from using +libcurl while it was released under MPL only. (Due to the fact that MPL is +deemed "GPL incompatible".) + +March 22: curl supports HTTP 1.1 starting with the release of 7.7. This +also introduced libcurl's ability to do persistent connections. 24000 lines of +code. The libcurl major SONAME number was bumped to 2 due to this overhaul. +The first experimental ftps:// support was added. + +August: The curl website gets 8000 visits weekly. Curl Corporation contacted +Daniel to discuss "the name issue". After Daniel's reply, they have never +since got back in touch again. + +September: libcurl 7.9 introduces cookie jar and `curl_formadd()`. During the +forthcoming 7.9.x releases, we introduced the multi interface slowly and +without many whistles. + +September 25: curl (7.7.2) is bundled in Mac OS X (10.1) for the first time. It was +already becoming more and more of a standard utility of Linux distributions +and a regular in the BSD ports collections. + +2002 +---- + +June: the curl website gets 13000 visits weekly. curl and libcurl is +35000 lines of code. Reported successful compiles on more than 40 combinations +of CPUs and operating systems. + +To estimate the number of users of the curl tool or libcurl library is next to +impossible. Around 5000 downloaded packages each week from the main site gives +a hint, but the packages are mirrored extensively, bundled with numerous OS +distributions and otherwise retrieved as part of other software. + +October 1: with the release of curl 7.10 it is released under the MIT license +only. + +Starting with 7.10, curl verifies SSL server certificates by default. + +2003 +---- + +January: Started working on the distributed curl tests. The autobuilds. + +February: the curl site averages at 20000 visits weekly. At any given moment, +there is an average of 3 people browsing the website. + +Multiple new authentication schemes are supported: Digest (May), NTLM (June) +and Negotiate (June). + +November: curl 7.10.8 is released. 45000 lines of code. ~55000 unique visitors +to the website. Five official web mirrors. + +December: full-fledged SSL for FTP is supported. + +2004 +---- + +January: curl 7.11.0 introduced large file support. + +June: curl 7.12.0 introduced IDN support. 10 official web mirrors. + +This release bumped the major SONAME to 3 due to the removal of the +`curl_formparse()` function + +August: Curl and libcurl 7.12.1 + + Public curl release number: 82 + Releases counted from the beginning: 109 + Available command line options: 96 + Available curl_easy_setopt() options: 120 + Number of public functions in libcurl: 36 + Amount of public website mirrors: 12 + Number of known libcurl bindings: 26 + +2005 +---- + +April: GnuTLS can now optionally be used for the secure layer when curl is +built. + +April: Added the multi_socket() API + +September: TFTP support was added. + +More than 100,000 unique visitors of the curl website. 25 mirrors. + +December: security vulnerability: libcurl URL Buffer Overflow + +2006 +---- + +January: We dropped support for Gopher. We found bugs in the implementation +that turned out to have been introduced years ago, so with the conclusion that +nobody had found out in all this time we removed it instead of fixing it. + +March: security vulnerability: libcurl TFTP Packet Buffer Overflow + +September: The major SONAME number for libcurl was bumped to 4 due to the +removal of ftp third party transfer support. + +November: Added SCP and SFTP support + +2007 +---- + +February: Added support for the Mozilla NSS library to do the SSL/TLS stuff + +July: security vulnerability: libcurl GnuTLS insufficient cert verification + +2008 +---- + +November: + + Command line options: 128 + curl_easy_setopt() options: 158 + Public functions in libcurl: 58 + Known libcurl bindings: 37 + Contributors: 683 + + 145,000 unique visitors. >100 GB downloaded. + +2009 +---- + +March: security vulnerability: libcurl Arbitrary File Access + +April: added CMake support + +August: security vulnerability: libcurl embedded zero in cert name + +December: Added support for IMAP, POP3 and SMTP + +2010 +---- + +January: Added support for RTSP + +February: security vulnerability: libcurl data callback excessive length + +March: The project switched over to use git (hosted by GitHub) instead of CVS +for source code control + +May: Added support for RTMP + +Added support for PolarSSL to do the SSL/TLS stuff + +August: + + Public curl releases: 117 + Command line options: 138 + curl_easy_setopt() options: 180 + Public functions in libcurl: 58 + Known libcurl bindings: 39 + Contributors: 808 + + Gopher support added (re-added actually, see January 2006) + +2011 +---- + +February: added support for the axTLS backend + +April: added the cyassl backend (later renamed to WolfSSL) + +2012 +---- + + July: Added support for Schannel (native Windows TLS backend) and Darwin SSL + (Native Mac OS X and iOS TLS backend). + + Supports Metalink + + October: SSH-agent support. + +2013 +---- + + February: Cleaned up internals to always uses the "multi" non-blocking + approach internally and only expose the blocking API with a wrapper. + + September: First small steps on supporting HTTP/2 with nghttp2. + + October: Removed krb4 support. + + December: Happy eyeballs. + +2014 +---- + + March: first real release supporting HTTP/2 + + September: Website had 245,000 unique visitors and served 236GB data + + SMB and SMBS support + +2015 +---- + + June: support for multiplexing with HTTP/2 + + August: support for HTTP/2 server push + + December: Public Suffix List + +2016 +---- + + January: the curl tool defaults to HTTP/2 for HTTPS URLs + + December: curl 7.52.0 introduced support for HTTPS-proxy + + First TLS 1.3 support + +2017 +---- + + July: OSS-Fuzz started fuzzing libcurl + + September: Added Multi-SSL support + + The website serves 3100 GB/month + + Public curl releases: 169 + Command line options: 211 + curl_easy_setopt() options: 249 + Public functions in libcurl: 74 + Contributors: 1609 + + October: SSLKEYLOGFILE support, new MIME API + + October: Daniel received the Polhem Prize for his work on curl + + November: brotli + +2018 +---- + + January: new SSH backend powered by libssh + + March: starting with the 1803 release of Windows 10, curl is shipped bundled + with Microsoft's operating system. + + July: curl shows headers using bold type face + + October: added DNS-over-HTTPS (DoH) and the URL API + + MesaLink is a new supported TLS backend + + libcurl now does HTTP/2 (and multiplexing) by default on HTTPS URLs + + curl and libcurl are installed in an estimated 5 *billion* instances + world-wide. + + October 31: Curl and libcurl 7.62.0 + + Public curl releases: 177 + Command line options: 219 + curl_easy_setopt() options: 261 + Public functions in libcurl: 80 + Contributors: 1808 + + December: removed axTLS support + +2019 +---- + + March: added experimental alt-svc support + + August: the first HTTP/3 requests with curl. + + September: 7.66.0 is released and the tool offers parallel downloads + +2020 +---- + + curl and libcurl are installed in an estimated 10 *billion* instances + world-wide. + + January: added BearSSL support + + March: removed support for PolarSSL, added wolfSSH support + + April: experimental MQTT support + + August: zstd support + + November: the website moves to curl.se. The website serves 10TB data monthly. + + December: alt-svc support + +2021 +---- + + February 3: curl 7.75.0 ships with support for Hyper as an HTTP backend + + March 31: curl 7.76.0 ships with support for rustls + + July: HSTS is supported + +2022 +---- + + March: added --json, removed mesalink support + + Public curl releases: 206 + Command line options: 245 + curl_easy_setopt() options: 295 + Public functions in libcurl: 86 + Contributors: 2601 + + The curl.se website serves 16,500 GB/month over 462M requests, the + official docker image has been pulled 4,098,015,431 times. + +2023 +---- + +August: Dropped support for the NSS library diff --git a/docs/HSTS.md b/docs/HSTS.md new file mode 100644 index 0000000..5f0e624 --- /dev/null +++ b/docs/HSTS.md @@ -0,0 +1,42 @@ +# HSTS support + +HTTP Strict-Transport-Security. Added as experimental in curl +7.74.0. Supported "for real" since 7.77.0. + +## Standard + +[HTTP Strict Transport Security](https://datatracker.ietf.org/doc/html/rfc6797) + +## Behavior + +libcurl features an in-memory cache for HSTS hosts, so that subsequent +HTTP-only requests to a hostname present in the cache will get internally +"redirected" to the HTTPS version. + +## `curl_easy_setopt()` options: + + - `CURLOPT_HSTS_CTRL` - enable HSTS for this easy handle + - `CURLOPT_HSTS` - specify filename where to store the HSTS cache on close + (and possibly read from at startup) + +## curl command line options + + - `--hsts [filename]` - enable HSTS, use the file as HSTS cache. If filename + is `""` (no length) then no file will be used, only in-memory cache. + +## HSTS cache file format + +Lines starting with `#` are ignored. + +For each hsts entry: + + [host name] "YYYYMMDD HH:MM:SS" + +The `[host name]` is dot-prefixed if it includes subdomains. + +The time stamp is when the entry expires. + +## Possible future additions + + - `CURLOPT_HSTS_PRELOAD` - provide a set of HSTS host names to load first + - ability to save to something else than a file diff --git a/docs/HTTP-COOKIES.md b/docs/HTTP-COOKIES.md new file mode 100644 index 0000000..a91e824 --- /dev/null +++ b/docs/HTTP-COOKIES.md @@ -0,0 +1,166 @@ +# HTTP Cookies + +## Cookie overview + + Cookies are `name=contents` pairs that an HTTP server tells the client to + hold and then the client sends back those to the server on subsequent + requests to the same domains and paths for which the cookies were set. + + Cookies are either "session cookies" which typically are forgotten when the + session is over which is often translated to equal when browser quits, or + the cookies are not session cookies they have expiration dates after which + the client will throw them away. + + Cookies are set to the client with the Set-Cookie: header and are sent to + servers with the Cookie: header. + + For a long time, the only spec explaining how to use cookies was the + original [Netscape spec from 1994](https://curl.se/rfc/cookie_spec.html). + + In 2011, [RFC 6265](https://www.ietf.org/rfc/rfc6265.txt) was finally + published and details how cookies work within HTTP. In 2016, an update which + added support for prefixes was + [proposed](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-prefixes-00), + and in 2017, another update was + [drafted](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-alone-01) + to deprecate modification of 'secure' cookies from non-secure origins. Both + of these drafts have been incorporated into a proposal to + [replace](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-11) + RFC 6265. Cookie prefixes and secure cookie modification protection has been + implemented by curl. + + curl considers `http://localhost` to be a *secure context*, meaning that it + will allow and use cookies marked with the `secure` keyword even when done + over plain HTTP for this host. curl does this to match how popular browsers + work with secure cookies. + +## Super cookies + + A single cookie can be set for a domain that matches multiple hosts. Like if + set for `example.com` it gets sent to both `aa.example.com` as well as + `bb.example.com`. + + A challenge with this concept is that there are certain domains for which + cookies should not be allowed at all, because they are *Public + Suffixes*. Similarly, a client never accepts cookies set directly for the + top-level domain like for example `.com`. Cookies set for *too broad* + domains are generally referred to as *super cookies*. + + If curl is built with PSL (**Public Suffix List**) support, it detects and + discards cookies that are specified for such suffix domains that should not + be allowed to have cookies. + + if curl is *not* built with PSL support, it has no ability to stop super + cookies. + +## Cookies saved to disk + + Netscape once created a file format for storing cookies on disk so that they + would survive browser restarts. curl adopted that file format to allow + sharing the cookies with browsers, only to see browsers move away from that + format. Modern browsers no longer use it, while curl still does. + + The Netscape cookie file format stores one cookie per physical line in the + file with a bunch of associated meta data, each field separated with + TAB. That file is called the cookie jar in curl terminology. + + When libcurl saves a cookie jar, it creates a file header of its own in + which there is a URL mention that will link to the web version of this + document. + +## Cookie file format + + The cookie file format is text based and stores one cookie per line. Lines + that start with `#` are treated as comments. An exception is lines that + start with `#HttpOnly_`, which is a prefix for cookies that have the + `HttpOnly` attribute set. + + Each line that specifies a single cookie consists of seven text fields + separated with TAB characters. A valid line must end with a newline + character. + +### Fields in the file + + Field number, what type and example data and the meaning of it: + + 0. string `example.com` - the domain name + 1. boolean `FALSE` - include subdomains + 2. string `/foobar/` - path + 3. boolean `TRUE` - send/receive over HTTPS only + 4. number `1462299217` - expires at - seconds since Jan 1st 1970, or 0 + 5. string `person` - name of the cookie + 6. string `daniel` - value of the cookie + +## Cookies with curl the command line tool + + curl has a full cookie "engine" built in. If you just activate it, you can + have curl receive and send cookies exactly as mandated in the specs. + + Command line options: + + `-b, --cookie` + + tell curl a file to read cookies from and start the cookie engine, or if it + is not a file it will pass on the given string. `-b name=var` works and so + does `-b cookiefile`. + + `-j, --junk-session-cookies` + + when used in combination with -b, it will skip all "session cookies" on load + so as to appear to start a new cookie session. + + `-c, --cookie-jar` + + tell curl to start the cookie engine and write cookies to the given file + after the request(s) + +## Cookies with libcurl + + libcurl offers several ways to enable and interface the cookie engine. These + options are the ones provided by the native API. libcurl bindings may offer + access to them using other means. + + `CURLOPT_COOKIE` + + Is used when you want to specify the exact contents of a cookie header to + send to the server. + + `CURLOPT_COOKIEFILE` + + Tell libcurl to activate the cookie engine, and to read the initial set of + cookies from the given file. Read-only. + + `CURLOPT_COOKIEJAR` + + Tell libcurl to activate the cookie engine, and when the easy handle is + closed save all known cookies to the given cookie jar file. Write-only. + + `CURLOPT_COOKIELIST` + + Provide detailed information about a single cookie to add to the internal + storage of cookies. Pass in the cookie as an HTTP header with all the + details set, or pass in a line from a Netscape cookie file. This option can + also be used to flush the cookies etc. + + `CURLOPT_COOKIESESSION` + + Tell libcurl to ignore all cookies it is about to load that are session + cookies. + + `CURLINFO_COOKIELIST` + + Extract cookie information from the internal cookie storage as a linked + list. + +## Cookies with JavaScript + + These days a lot of the web is built up by JavaScript. The web browser loads + complete programs that render the page you see. These JavaScript programs + can also set and access cookies. + + Since curl and libcurl are plain HTTP clients without any knowledge of or + capability to handle JavaScript, such cookies will not be detected or used. + + Often, if you want to mimic what a browser does on such websites, you can + record web browser HTTP traffic when using such a site and then repeat the + cookie operations using curl or libcurl. diff --git a/docs/HTTP2.md b/docs/HTTP2.md new file mode 100644 index 0000000..5b40283 --- /dev/null +++ b/docs/HTTP2.md @@ -0,0 +1,102 @@ +HTTP/2 with curl +================ + +[HTTP/2 Spec](https://www.rfc-editor.org/rfc/rfc7540.txt) +[http2 explained](https://daniel.haxx.se/http2/) + +Build prerequisites +------------------- + - nghttp2 + - OpenSSL, libressl, BoringSSL, GnuTLS, mbedTLS, wolfSSL or Schannel + with a new enough version. + +[nghttp2](https://nghttp2.org/) +------------------------------- + +libcurl uses this 3rd party library for the low level protocol handling +parts. The reason for this is that HTTP/2 is much more complex at that layer +than HTTP/1.1 (which we implement on our own) and that nghttp2 is an already +existing and well functional library. + +We require at least version 1.12.0. + +Over an http:// URL +------------------- + +If `CURLOPT_HTTP_VERSION` is set to `CURL_HTTP_VERSION_2_0`, libcurl will +include an upgrade header in the initial request to the host to allow +upgrading to HTTP/2. + +Possibly we can later introduce an option that will cause libcurl to fail if +not possible to upgrade. Possibly we introduce an option that makes libcurl +use HTTP/2 at once over http:// + +Over an https:// URL +-------------------- + +If `CURLOPT_HTTP_VERSION` is set to `CURL_HTTP_VERSION_2_0`, libcurl will use +ALPN to negotiate which protocol to continue with. Possibly introduce an +option that will cause libcurl to fail if not possible to use HTTP/2. + +`CURL_HTTP_VERSION_2TLS` was added in 7.47.0 as a way to ask libcurl to prefer +HTTP/2 for HTTPS but stick to 1.1 by default for plain old HTTP connections. + +ALPN is the TLS extension that HTTP/2 is expected to use. + +`CURLOPT_SSL_ENABLE_ALPN` is offered to allow applications to explicitly +disable ALPN. + +Multiplexing +------------ + +Starting in 7.43.0, libcurl fully supports HTTP/2 multiplexing, which is the +term for doing multiple independent transfers over the same physical TCP +connection. + +To take advantage of multiplexing, you need to use the multi interface and set +`CURLMOPT_PIPELINING` to `CURLPIPE_MULTIPLEX`. With that bit set, libcurl will +attempt to reuse existing HTTP/2 connections and just add a new stream over +that when doing subsequent parallel requests. + +While libcurl sets up a connection to an HTTP server there is a period during +which it does not know if it can pipeline or do multiplexing and if you add +new transfers in that period, libcurl will default to start new connections +for those transfers. With the new option `CURLOPT_PIPEWAIT` (added in 7.43.0), +you can ask that a transfer should rather wait and see in case there is a +connection for the same host in progress that might end up being possible to +multiplex on. It favors keeping the number of connections low to the cost of +slightly longer time to first byte transferred. + +Applications +------------ + +We hide HTTP/2's binary nature and convert received HTTP/2 traffic to headers +in HTTP 1.1 style. This allows applications to work unmodified. + +curl tool +--------- + +curl offers the `--http2` command line option to enable use of HTTP/2. + +curl offers the `--http2-prior-knowledge` command line option to enable use of +HTTP/2 without HTTP/1.1 Upgrade. + +Since 7.47.0, the curl tool enables HTTP/2 by default for HTTPS connections. + +curl tool limitations +--------------------- + +The command line tool does not support HTTP/2 server push. It supports +multiplexing when the parallel transfer option is used. + +HTTP Alternative Services +------------------------- + +Alt-Svc is an extension with a corresponding frame (ALTSVC) in HTTP/2 that +tells the client about an alternative "route" to the same content for the same +origin server that you get the response from. A browser or long-living client +can use that hint to create a new connection asynchronously. For libcurl, we +may introduce a way to bring such clues to the application and/or let a +subsequent request use the alternate route automatically. + +[Detailed in RFC 7838](https://datatracker.ietf.org/doc/html/rfc7838) diff --git a/docs/HTTP3.md b/docs/HTTP3.md new file mode 100644 index 0000000..851a0c4 --- /dev/null +++ b/docs/HTTP3.md @@ -0,0 +1,415 @@ +# HTTP3 (and QUIC) + +## Resources + +[HTTP/3 Explained](https://http3-explained.haxx.se/en/) - the online free +book describing the protocols involved. + +[quicwg.org](https://quicwg.org/) - home of the official protocol drafts + +## QUIC libraries + +QUIC libraries we are using: + +[ngtcp2](https://github.com/ngtcp2/ngtcp2) + +[quiche](https://github.com/cloudflare/quiche) - **EXPERIMENTAL** + +[OpenSSL 3.2+ QUIC](https://github.com/openssl/openssl) - **EXPERIMENTAL** + +[msh3](https://github.com/nibanks/msh3) (with [msquic](https://github.com/microsoft/msquic)) - **EXPERIMENTAL** + +## Experimental + +HTTP/3 support in curl is considered **EXPERIMENTAL** until further notice +when built to use *quiche* or *msh3*. Only the *ngtcp2* backend is not +experimental. + +Further development and tweaking of the HTTP/3 support in curl will happen in +the master branch using pull-requests, just like ordinary changes. + +To fix before we remove the experimental label: + + - the used QUIC library needs to consider itself non-beta + - it is fine to "leave" individual backends as experimental if necessary + +# ngtcp2 version + +Building curl with ngtcp2 involves 3 components: `ngtcp2` itself, `nghttp3` and a QUIC supporting TLS library. The supported TLS libraries are covered below. + + * `ngtcp2`: v1.2.0 + * `nghttp3`: v1.1.0 + +## Build with quictls + +OpenSSL does not offer the required APIs for building a QUIC client. You need +to use a TLS library that has such APIs and that works with *ngtcp2*. + +Build quictls + + % git clone --depth 1 -b openssl-3.1.4+quic https://github.com/quictls/openssl + % cd openssl + % ./config enable-tls1_3 --prefix= + % make + % make install + +Build nghttp3 + + % cd .. + % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 + % cd nghttp3 + % autoreconf -fi + % ./configure --prefix= --enable-lib-only + % make + % make install + +Build ngtcp2 + + % cd .. + % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2 + % cd ngtcp2 + % autoreconf -fi + % ./configure PKG_CONFIG_PATH=/lib/pkgconfig:/lib/pkgconfig LDFLAGS="-Wl,-rpath,/lib" --prefix= --enable-lib-only + % make + % make install + +Build curl + + % cd .. + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % LDFLAGS="-Wl,-rpath,/lib" ./configure --with-openssl= --with-nghttp3= --with-ngtcp2= + % make + % make install + +For OpenSSL 3.0.0 or later builds on Linux for x86_64 architecture, substitute all occurrences of "/lib" with "/lib64" + +## Build with GnuTLS + +Build GnuTLS + + % git clone --depth 1 https://gitlab.com/gnutls/gnutls.git + % cd gnutls + % ./bootstrap + % ./configure --prefix= + % make + % make install + +Build nghttp3 + + % cd .. + % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 + % cd nghttp3 + % autoreconf -fi + % ./configure --prefix= --enable-lib-only + % make + % make install + +Build ngtcp2 + + % cd .. + % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2 + % cd ngtcp2 + % autoreconf -fi + % ./configure PKG_CONFIG_PATH=/lib/pkgconfig:/lib/pkgconfig LDFLAGS="-Wl,-rpath,/lib" --prefix= --enable-lib-only --with-gnutls + % make + % make install + +Build curl + + % cd .. + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % ./configure --with-gnutls= --with-nghttp3= --with-ngtcp2= + % make + % make install + +## Build with wolfSSL + +Build wolfSSL + + % git clone https://github.com/wolfSSL/wolfssl.git + % cd wolfssl + % autoreconf -fi + % ./configure --prefix= --enable-quic --enable-session-ticket --enable-earlydata --enable-psk --enable-harden --enable-altcertchains + % make + % make install + +Build nghttp3 + + % cd .. + % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 + % cd nghttp3 + % autoreconf -fi + % ./configure --prefix= --enable-lib-only + % make + % make install + +Build ngtcp2 + + % cd .. + % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2 + % cd ngtcp2 + % autoreconf -fi + % ./configure PKG_CONFIG_PATH=/lib/pkgconfig:/lib/pkgconfig LDFLAGS="-Wl,-rpath,/lib" --prefix= --enable-lib-only --with-wolfssl + % make + % make install + +Build curl + + % cd .. + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % ./configure --with-wolfssl= --with-nghttp3= --with-ngtcp2= + % make + % make install + +# quiche version + +quiche support is **EXPERIMENTAL** + +Since the quiche build manages its dependencies, curl can be built against the latest version. You are *probably* able to build against their main branch, but in case of problems, we recommend their latest release tag. + +## build + +Build quiche and BoringSSL: + + % git clone --recursive -b 0.20.0 https://github.com/cloudflare/quiche + % cd quiche + % cargo build --package quiche --release --features ffi,pkg-config-meta,qlog + % mkdir quiche/deps/boringssl/src/lib + % ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/ + +Build curl: + + % cd .. + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-openssl=$PWD/../quiche/quiche/deps/boringssl/src --with-quiche=$PWD/../quiche/target/release + % make + % make install + + If `make install` results in `Permission denied` error, you will need to prepend it with `sudo`. + +# OpenSSL version + +quiche QUIC support is **EXPERIMENTAL** + +Build OpenSSL 3.2.0 + + % cd .. + % git clone -b openssl-3.2.0 https://github.com/openssl/openssl + % cd openssl + % ./config enable-tls1_3 --prefix= --libdir=/lib + % make install + +Build nghttp3 + + % cd .. + % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 + % cd nghttp3 + % autoreconf -fi + % ./configure --prefix= --enable-lib-only + % make + % make install + +Build curl: + + % cd .. + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % ./configure --with-openssl= --with-openssl-quic --with-nghttp3= + % make + % make install + + If `make install` results in `Permission denied` error, you will need to prepend it with `sudo`. + +# msh3 (msquic) version + +**Note**: The msquic HTTP/3 backend is immature and is not properly functional +one as of September 2023. Feel free to help us test it and improve it, but +there is no point in filing bugs about it just yet. + +msh3 support is **EXPERIMENTAL** + +## Build Linux (with quictls fork of OpenSSL) + +Build msh3: + + % git clone -b v0.6.0 --depth 1 --recursive https://github.com/nibanks/msh3 + % cd msh3 && mkdir build && cd build + % cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=RelWithDebInfo .. + % cmake --build . + % cmake --install . + +Build curl: + + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % ./configure LDFLAGS="-Wl,-rpath,/usr/local/lib" --with-msh3=/usr/local --with-openssl + % make + % make install + +Run from `/usr/local/bin/curl`. + +## Build Windows + +Build msh3: + + % git clone -b v0.6.0 --depth 1 --recursive https://github.com/nibanks/msh3 + % cd msh3 && mkdir build && cd build + % cmake -G 'Visual Studio 17 2022' -DCMAKE_BUILD_TYPE=RelWithDebInfo .. + % cmake --build . --config Release + % cmake --install . --config Release + +**Note** - On Windows, Schannel will be used for TLS support by default. If +you with to use (the quictls fork of) OpenSSL, specify the +`-DQUIC_TLS=openssl` option to the generate command above. Also note that +OpenSSL brings with it an additional set of build dependencies not specified +here. + +Build curl (in [Visual Studio Command +prompt](../winbuild/README.md#open-a-command-prompt)): + + % git clone https://github.com/curl/curl + % cd curl/winbuild + % nmake /f Makefile.vc mode=dll WITH_MSH3=dll MSH3_PATH="C:/Program Files/msh3" MACHINE=x64 + +**Note** - If you encounter a build error with `tool_hugehelp.c` being +missing, rename `tool_hugehelp.c.cvs` in the same directory to +`tool_hugehelp.c` and then run `nmake` again. + +Run in the `C:/Program Files/msh3/lib` directory, copy `curl.exe` to that +directory, or copy `msquic.dll` and `msh3.dll` from that directory to the +`curl.exe` directory. For example: + + % C:\Program Files\msh3\lib> F:\curl\builds\libcurl-vc-x64-release-dll-ipv6-sspi-schannel-msh3\bin\curl.exe --http3 https://curl.se/ + +# `--http3` + +Use only HTTP/3: + + curl --http3-only https://example.org:4433/ + +Use HTTP/3 with fallback to HTTP/2 or HTTP/1.1 (see "HTTPS eyeballing" below): + + curl --http3 https://example.org:4433/ + +Upgrade via Alt-Svc: + + curl --alt-svc altsvc.cache https://curl.se/ + +See this [list of public HTTP/3 servers](https://bagder.github.io/HTTP3-test/) + +### HTTPS eyeballing + +With option `--http3` curl will attempt earlier HTTP versions as well should +the connect attempt via HTTP/3 not succeed "fast enough". This strategy is +similar to IPv4/6 happy eyeballing where the alternate address family is used +in parallel after a short delay. + +The IPv4/6 eyeballing has a default of 200ms and you may override that via +`--happy-eyeballs-timeout-ms value`. Since HTTP/3 is still relatively new, we +decided to use this timeout also for the HTTP eyeballing - with a slight +twist. + +The `happy-eyeballs-timeout-ms` value is the **hard** timeout, meaning after +that time expired, a TLS connection is opened in addition to negotiate HTTP/2 +or HTTP/1.1. At half of that value - currently - is the **soft** timeout. The +soft timeout fires, when there has been **no data at all** seen from the +server on the HTTP/3 connection. + +So, without you specifying anything, the hard timeout is 200ms and the soft is 100ms: + + * Ideally, the whole QUIC handshake happens and curl has an HTTP/3 connection + in less than 100ms. + * When QUIC is not supported (or UDP does not work for this network path), no + reply is seen and the HTTP/2 TLS+TCP connection starts 100ms later. + * In the worst case, UDP replies start before 100ms, but drag on. This will + start the TLS+TCP connection after 200ms. + * When the QUIC handshake fails, the TLS+TCP connection is attempted right + away. For example, when the QUIC server presents the wrong certificate. + +The whole transfer only fails, when **both** QUIC and TLS+TCP fail to +handshake or time out. + +Note that all this happens in addition to IP version happy eyeballing. If the +name resolution for the server gives more than one IP address, curl will try +all those until one succeeds - just as with all other protocols. If those IP +addresses contain both IPv6 and IPv4, those attempts will happen, delayed, in +parallel (the actual eyeballing). + +## Known Bugs + +Check out the [list of known HTTP3 bugs](https://curl.se/docs/knownbugs.html#HTTP3). + +# HTTP/3 Test server + +This is not advice on how to run anything in production. This is for +development and experimenting. + +## Prerequisite(s) + +An existing local HTTP/1.1 server that hosts files. Preferably also a few huge +ones. You can easily create huge local files like `truncate -s=8G 8GB` - they +are huge but do not occupy that much space on disk since they are just big +holes. + +In a Debian setup you can install **apache2**. It runs on port 80 and has a +document root in `/var/www/html`. Download the 8GB file from apache with `curl +localhost/8GB -o dev/null` + +In this description we setup and run an HTTP/3 reverse-proxy in front of the +HTTP/1 server. + +## Setup + +You can select either or both of these server solutions. + +### nghttpx + +Get, build and install **quictls**, **nghttp3** and **ngtcp2** as described +above. + +Get, build and install **nghttp2**: + + git clone https://github.com/nghttp2/nghttp2.git + cd nghttp2 + autoreconf -fi + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/daniel/build-quictls/lib/pkgconfig:/home/daniel/build-nghttp3/lib/pkgconfig:/home/daniel/build-ngtcp2/lib/pkgconfig LDFLAGS=-L/home/daniel/build-quictls/lib CFLAGS=-I/home/daniel/build-quictls/include ./configure --enable-maintainer-mode --prefix=/home/daniel/build-nghttp2 --disable-shared --enable-app --enable-http3 --without-jemalloc --without-libxml2 --without-systemd + make && make install + +Run the local h3 server on port 9443, make it proxy all traffic through to +HTTP/1 on localhost port 80. For local toying, we can just use the test cert +that exists in curl's test dir. + + CERT=$CURLSRC/tests/stunnel.pem + $HOME/bin/nghttpx $CERT $CERT --backend=localhost,80 \ + --frontend="localhost,9443;quic" + +### Caddy + +[Install Caddy](https://caddyserver.com/docs/install). For easiest use, the binary +should be either in your PATH or your current directory. + +Create a `Caddyfile` with the following content: +~~~ +localhost:7443 { + respond "Hello, world! you are using {http.request.proto}" +} +~~~ + +Then run Caddy: + + ./caddy start + +Making requests to `https://localhost:7443` should tell you which protocol is being used. + +You can change the hard-coded response to something more useful by replacing `respond` +with `reverse_proxy` or `file_server`, for example: `reverse_proxy localhost:80` diff --git a/docs/HYPER.md b/docs/HYPER.md new file mode 100644 index 0000000..9932c1b --- /dev/null +++ b/docs/HYPER.md @@ -0,0 +1,73 @@ +# Hyper + +Hyper is a separate HTTP library written in Rust. curl can be told to use this +library as a backend to deal with HTTP. + +## Experimental! + +Hyper support in curl is considered **EXPERIMENTAL** until further notice. It +needs to be explicitly enabled at build-time. + +Further development and tweaking of the Hyper backend support in curl will +happen in the master branch using pull-requests, just like ordinary +changes. + +## Hyper version + +The C API for Hyper is brand new and is still under development. + +## build curl with hyper + +Using Rust 1.64.0 or later, build hyper and enable its C API like this: + + % git clone https://github.com/hyperium/hyper + % cd hyper + % RUSTFLAGS="--cfg hyper_unstable_ffi" cargo rustc --features client,http1,http2,ffi --crate-type cdylib + +Also, `--release` can be added for a release (optimized) build. + +Build curl to use hyper's C API: + + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % ./configure LDFLAGS="-Wl,-rpath,/target/debug -Wl,-rpath,/target/release" --with-openssl --with-hyper= + % make + +# using Hyper internally + +Hyper is a low level HTTP transport library. curl itself provides all HTTP +headers and Hyper provides all received headers back to curl. + +Therefore, most of the "header logic" in curl as in responding to and acting +on specific input and output headers are done the same way in curl code. + +The API in Hyper delivers received HTTP headers as (cleaned up) name=value +pairs, making it impossible for curl to know the exact byte representation +over the wire with Hyper. + +## Limitations + +The hyper backend does not support + +- `CURLOPT_IGNORE_CONTENT_LENGTH` +- `--raw` and disabling `CURLOPT_HTTP_TRANSFER_DECODING` +- RTSP +- hyper is much stricter about what HTTP header contents it allows +- leading whitespace in first HTTP/1 response header +- HTTP/0.9 +- HTTP/2 upgrade using HTTP:// URLs. Aka 'h2c' +- HTTP/2 in general. Hyper has support for HTTP/2 but the curl side + needs changes so that a `hyper_clientconn` can last for the duration + of a connection. Probably this means turning the Hyper HTTP/2 backend + into a connection filter. + +## Remaining issues + +This backend is still not feature complete with the native backend. Areas that +still need attention and verification include: + +- multiplexed HTTP/2 +- h2 Upgrade: +- receiving HTTP/1 trailers +- sending HTTP/1 trailers diff --git a/docs/INSTALL b/docs/INSTALL new file mode 100644 index 0000000..ff260b1 --- /dev/null +++ b/docs/INSTALL @@ -0,0 +1,9 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + + How To Compile + +see INSTALL.md diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md new file mode 100644 index 0000000..6dad387 --- /dev/null +++ b/docs/INSTALL-CMAKE.md @@ -0,0 +1,133 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + + How To Compile with CMake + +# Building with CMake + +This document describes how to configure, build and install curl and libcurl +from source code using the CMake build tool. To build with CMake, you will +of course have to first install CMake. The minimum required version of CMake +is specified in the file `CMakeLists.txt` found in the top of the curl +source tree. Once the correct version of CMake is installed you can follow +the instructions below for the platform you are building on. + +CMake builds can be configured either from the command line, or from one of +CMake's GUIs. + +# Current flaws in the curl CMake build + +Missing features in the CMake build: + + - Builds libcurl without large file support + - Does not support all SSL libraries (only OpenSSL, Schannel, Secure + Transport, and mbedTLS, WolfSSL) + - Does not allow different resolver backends (no c-ares build support) + - No RTMP support built + - Does not allow build curl and libcurl debug enabled + - Does not allow a custom CA bundle path + - Does not allow you to disable specific protocols from the build + - Does not find or use krb4 or GSS + - Rebuilds test files too eagerly, but still cannot run the tests + - Does not detect the correct `strerror_r` flavor when cross-compiling + (issue #1123) + +# Configuring + +A CMake configuration of curl is similar to the autotools build of curl. +It consists of the following steps after you have unpacked the source. + +## Using `cmake` + +You can configure for in source tree builds or for a build tree +that is apart from the source tree. + + - Build in the source tree. + + $ cmake -B . + + - Build in a separate directory (parallel to the curl source tree in this + example). The build directory will be created for you. + + $ cmake -B ../curl-build + +### Fallback for CMake before version 3.13 + +CMake before version 3.13 does not support the `-B` option. In that case, +you must create the build directory yourself, `cd` to it and run `cmake` +from there: + + $ mkdir ../curl-build + $ cd ../curl-build + $ cmake ../curl + +If you want to build in the source tree, it is enough to do this: + + $ cmake . + +## Using `ccmake` + +CMake comes with a curses based interface called `ccmake`. To run `ccmake` +on a curl use the instructions for the command line cmake, but substitute +`ccmake` for `cmake`. + +This will bring up a curses interface with instructions on the bottom of the +screen. You can press the "c" key to configure the project, and the "g" key +to generate the project. After the project is generated, you can run make. + +## Using `cmake-gui` + +CMake also comes with a Qt based GUI called `cmake-gui`. To configure with +`cmake-gui`, you run `cmake-gui` and follow these steps: + + 1. Fill in the "Where is the source code" combo box with the path to + the curl source tree. + 2. Fill in the "Where to build the binaries" combo box with the path to + the directory for your build tree, ideally this should not be the same + as the source tree, but a parallel directory called curl-build or + something similar. + 3. Once the source and binary directories are specified, press the + "Configure" button. + 4. Select the native build tool that you want to use. + 5. At this point you can change any of the options presented in the GUI. + Once you have selected all the options you want, click the "Generate" + button. + +# Building + +Build (you have to specify the build directory). + + $ cmake --build ../curl-build + +### Fallback for CMake before version 3.13 + +CMake before version 3.13 does not support the `--build` option. In that +case, you have to `cd` to the build directory and use the building tool that +corresponds to the build files that CMake generated for you. This example +assumes that CMake generates `Makefile`: + + $ cd ../curl-build + $ make + +# Testing + +(The test suite does not yet work with the cmake build) + +# Installing + +Install to default location (you have to specify the build directory). + + $ cmake --install ../curl-build + +### Fallback for CMake before version 3.15 + +CMake before version 3.15 does not support the `--install` option. In that +case, you have to `cd` to the build directory and use the building tool that +corresponds to the build files that CMake generated for you. This example +assumes that CMake generates `Makefile`: + + $ cd ../curl-build + $ make install diff --git a/docs/INSTALL.md b/docs/INSTALL.md new file mode 100644 index 0000000..336d654 --- /dev/null +++ b/docs/INSTALL.md @@ -0,0 +1,576 @@ +# how to install curl and libcurl + +## Installing Binary Packages + +Lots of people download binary distributions of curl and libcurl. This +document does not describe how to install curl or libcurl using such a binary +package. This document describes how to compile, build and install curl and +libcurl from source code. + +## Building using vcpkg + +You can download and install curl and libcurl using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: + + git clone https://github.com/Microsoft/vcpkg.git + cd vcpkg + ./bootstrap-vcpkg.sh + ./vcpkg integrate install + vcpkg install curl[tool] + +The curl port in vcpkg is kept up to date by Microsoft team members and +community contributors. If the version is out of date, please [create an issue +or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + +## Building from git + +If you get your code off a git repository instead of a release tarball, see +the `GIT-INFO` file in the root directory for specific instructions on how to +proceed. + +# Unix + +A normal Unix installation is made in three or four steps (after you have +unpacked the source archive): + + ./configure --with-openssl [--with-gnutls --with-wolfssl] + make + make test (optional) + make install + +(Adjust the configure line accordingly to use the TLS library you want.) + +You probably need to be root when doing the last command. + +Get a full listing of all available configure options by invoking it like: + + ./configure --help + +If you want to install curl in a different file hierarchy than `/usr/local`, +specify that when running configure: + + ./configure --prefix=/path/to/curl/tree + +If you have write permission in that directory, you can do 'make install' +without being root. An example of this would be to make a local install in +your own home directory: + + ./configure --prefix=$HOME + make + make install + +The configure script always tries to find a working SSL library unless +explicitly told not to. If you have OpenSSL installed in the default search +path for your compiler/linker, you do not need to do anything special. If you +have OpenSSL installed in `/usr/local/ssl`, you can run configure like: + + ./configure --with-openssl + +If you have OpenSSL installed somewhere else (for example, `/opt/OpenSSL`) and +you have pkg-config installed, set the pkg-config path first, like this: + + env PKG_CONFIG_PATH=/opt/OpenSSL/lib/pkgconfig ./configure --with-openssl + +Without pkg-config installed, use this: + + ./configure --with-openssl=/opt/OpenSSL + +If you insist on forcing a build without SSL support, you can run configure +like this: + + ./configure --without-ssl + +If you have OpenSSL installed, but with the libraries in one place and the +header files somewhere else, you have to set the `LDFLAGS` and `CPPFLAGS` +environment variables prior to running configure. Something like this should +work: + + CPPFLAGS="-I/path/to/ssl/include" LDFLAGS="-L/path/to/ssl/lib" ./configure + +If you have shared SSL libs installed in a directory where your runtime +linker does not find them (which usually causes configure failures), you can +provide this option to gcc to set a hard-coded path to the runtime linker: + + LDFLAGS=-Wl,-R/usr/local/ssl/lib ./configure --with-openssl + +## Static builds + +To force a static library compile, disable the shared library creation by +running configure like: + + ./configure --disable-shared + +The configure script is primarily done to work with shared/dynamic third party +dependencies. When linking with shared libraries, the dependency "chain" is +handled automatically by the library loader - on all modern systems. + +If you instead link with a static library, you need to provide all the +dependency libraries already at the link command line. + +Figuring out all the dependency libraries for a given library is hard, as it +might involve figuring out the dependencies of the dependencies and they vary +between platforms and change between versions. + +When using static dependencies, the build scripts will mostly assume that you, +the user, will provide all the necessary additional dependency libraries as +additional arguments in the build. With configure, by setting `LIBS` or +`LDFLAGS` on the command line. + +Building statically is not for the faint of heart. + +## Debug + +If you are a curl developer and use gcc, you might want to enable more debug +options with the `--enable-debug` option. + +curl can be built to use a whole range of libraries to provide various useful +services, and configure will try to auto-detect a decent default. If you want +to alter it, you can select how to deal with each individual library. + +## Select TLS backend + +These options are provided to select the TLS backend to use. + + - AmiSSL: `--with-amissl` + - BearSSL: `--with-bearssl` + - GnuTLS: `--with-gnutls`. + - mbedTLS: `--with-mbedtls` + - OpenSSL: `--with-openssl` (also for BoringSSL, AWS-LC, libressl, and quictls) + - rustls: `--with-rustls` + - Schannel: `--with-schannel` + - Secure Transport: `--with-secure-transport` + - wolfSSL: `--with-wolfssl` + +You can build curl with *multiple* TLS backends at your choice, but some TLS +backends cannot be combined: if you build with an OpenSSL fork (or wolfSSL), +you cannot add another OpenSSL fork (or wolfSSL) simply because they have +conflicting identical symbol names. + +When you build with multiple TLS backends, you can select the active one at +runtime when curl starts up. + +## configure finding libs in wrong directory + +When the configure script checks for third-party libraries, it adds those +directories to the `LDFLAGS` variable and then tries linking to see if it +works. When successful, the found directory is kept in the `LDFLAGS` variable +when the script continues to execute and do more tests and possibly check for +more libraries. + +This can make subsequent checks for libraries wrongly detect another +installation in a directory that was previously added to `LDFLAGS` by another +library check. + +# Windows + +Building for Windows XP is required as a minimum. + +## Building Windows DLLs and C runtime (CRT) linkage issues + + As a general rule, building a DLL with static CRT linkage is highly + discouraged, and intermixing CRTs in the same app is something to avoid at + any cost. + + Reading and comprehending Microsoft Knowledge Base articles KB94248 and + KB140584 is a must for any Windows developer. Especially important is full + understanding if you are not going to follow the advice given above. + + - [How To Use the C Runtime](https://support.microsoft.com/help/94248/how-to-use-the-c-run-time) + - [Runtime Library Compiler Options](https://docs.microsoft.com/cpp/build/reference/md-mt-ld-use-run-time-library) + - [Potential Errors Passing CRT Objects Across DLL Boundaries](https://docs.microsoft.com/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries) + +If your app is misbehaving in some strange way, or it is suffering from memory +corruption, before asking for further help, please try first to rebuild every +single library your app uses as well as your app using the debug +multi-threaded dynamic C runtime. + + If you get linkage errors read section 5.7 of the FAQ document. + +## Cygwin + +Almost identical to the Unix installation. Run the configure script in the +curl source tree root with `sh configure`. Make sure you have the `sh` +executable in `/bin/` or you will see the configure fail toward the end. + +Run `make` + +## MS-DOS + +Requires DJGPP in the search path and pointing to the Watt-32 stack via +`WATT_PATH=c:/djgpp/net/watt`. + +Run `make -f Makefile.dist djgpp` in the root curl dir. + +For build configuration options, please see the mingw-w64 section. + +Notes: + + - DJGPP 2.04 beta has a `sscanf()` bug so the URL parsing is not done + properly. Use DJGPP 2.03 until they fix it. + + - Compile Watt-32 (and OpenSSL) with the same version of DJGPP. Otherwise + things go wrong because things like FS-extensions and `errno` values have + been changed between releases. + +## AmigaOS + +Run `make -f Makefile.dist amiga` in the root curl dir. + +For build configuration options, please see the mingw-w64 section. + +## Disabling Specific Protocols in Windows builds + +The configure utility, unfortunately, is not available for the Windows +environment, therefore, you cannot use the various disable-protocol options of +the configure utility on this platform. + +You can use specific defines to disable specific protocols and features. See +[CURL-DISABLE](CURL-DISABLE.md) for the full list. + +If you want to set any of these defines you have the following options: + + - Modify `lib/config-win32.h` + - Modify `lib/curl_setup.h` + - Modify `winbuild/Makefile.vc` + - Modify the "Preprocessor Definitions" in the libcurl project + +Note: The pre-processor settings can be found using the Visual Studio IDE +under "Project -> Properties -> Configuration Properties -> C/C++ -> +Preprocessor". + +## Using BSD-style lwIP instead of Winsock TCP/IP stack in Win32 builds + +In order to compile libcurl and curl using BSD-style lwIP TCP/IP stack it is +necessary to make the definition of the preprocessor symbol `USE_LWIPSOCK` +visible to libcurl and curl compilation processes. To set this definition you +have the following alternatives: + + - Modify `lib/config-win32.h` and `src/config-win32.h` + - Modify `winbuild/Makefile.vc` + - Modify the "Preprocessor Definitions" in the libcurl project + +Note: The pre-processor settings can be found using the Visual Studio IDE +under "Project -> Properties -> Configuration Properties -> C/C++ -> +Preprocessor". + +Once that libcurl has been built with BSD-style lwIP TCP/IP stack support, in +order to use it with your program it is mandatory that your program includes +lwIP header file `` (or another lwIP header that includes this) +before including any libcurl header. Your program does not need the +`USE_LWIPSOCK` preprocessor definition which is for libcurl internals only. + +Compilation has been verified with lwIP 1.4.0. + +This BSD-style lwIP TCP/IP stack support must be considered experimental given +that it has been verified that lwIP 1.4.0 still needs some polish, and libcurl +might yet need some additional adjustment. + +## Important static libcurl usage note + +When building an application that uses the static libcurl library on Windows, +you must add `-DCURL_STATICLIB` to your `CFLAGS`. Otherwise the linker will +look for dynamic import symbols. + +## Legacy Windows and SSL + +Schannel (from Windows SSPI), is the native SSL library in Windows. However, +Schannel in Windows <= XP is unable to connect to servers that +no longer support the legacy handshakes and algorithms used by those +versions. If you will be using curl in one of those earlier versions of +Windows you should choose another SSL backend such as OpenSSL. + +# Apple Platforms (macOS, iOS, tvOS, watchOS, and their simulator counterparts) + +On modern Apple operating systems, curl can be built to use Apple's SSL/TLS +implementation, Secure Transport, instead of OpenSSL. To build with Secure +Transport for SSL/TLS, use the configure option `--with-secure-transport`. + +When Secure Transport is in use, the curl options `--cacert` and `--capath` +and their libcurl equivalents, will be ignored, because Secure Transport uses +the certificates stored in the Keychain to evaluate whether or not to trust +the server. This, of course, includes the root certificates that ship with the +OS. The `--cert` and `--engine` options, and their libcurl equivalents, are +currently unimplemented in curl with Secure Transport. + +In general, a curl build for an Apple `ARCH/SDK/DEPLOYMENT_TARGET` combination +can be taken by providing appropriate values for `ARCH`, `SDK`, `DEPLOYMENT_TARGET` +below and running the commands: + +```bash +# Set these three according to your needs +export ARCH=x86_64 +export SDK=macosx +export DEPLOYMENT_TARGET=10.8 + +export CFLAGS="-arch $ARCH -isysroot $(xcrun -sdk $SDK --show-sdk-path) -m$SDK-version-min=$DEPLOYMENT_TARGET" +./configure --host=$ARCH-apple-darwin --prefix $(pwd)/artifacts --with-secure-transport +make -j8 +make install +``` + +Above will build curl for macOS platform with `x86_64` architecture and `10.8` as deployment target. + +Here is an example for iOS device: + +```bash +export ARCH=arm64 +export SDK=iphoneos +export DEPLOYMENT_TARGET=11.0 + +export CFLAGS="-arch $ARCH -isysroot $(xcrun -sdk $SDK --show-sdk-path) -m$SDK-version-min=$DEPLOYMENT_TARGET" +./configure --host=$ARCH-apple-darwin --prefix $(pwd)/artifacts --with-secure-transport +make -j8 +make install +``` + +Another example for watchOS simulator for macs with Apple Silicon: + +```bash +export ARCH=arm64 +export SDK=watchsimulator +export DEPLOYMENT_TARGET=5.0 + +export CFLAGS="-arch $ARCH -isysroot $(xcrun -sdk $SDK --show-sdk-path) -m$SDK-version-min=$DEPLOYMENT_TARGET" +./configure --host=$ARCH-apple-darwin --prefix $(pwd)/artifacts --with-secure-transport +make -j8 +make install +``` + +In all above, the built libraries and executables can be found in the +`artifacts` folder. + +# Android + +When building curl for Android it is recommended to use a Linux/macOS +environment since using curl's `configure` script is the easiest way to build +curl for Android. Before you can build curl for Android, you need to install +the Android NDK first. This can be done using the SDK Manager that is part of +Android Studio. Once you have installed the Android NDK, you need to figure +out where it has been installed and then set up some environment variables +before launching `configure`. On macOS, those variables could look like this +to compile for `aarch64` and API level 29: + +```bash +export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/25.1.8937393 # Point into your NDK. +export HOST_TAG=darwin-x86_64 # Same tag for Apple Silicon. Other OS values here: https://developer.android.com/ndk/guides/other_build_systems#overview +export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG +export AR=$TOOLCHAIN/bin/llvm-ar +export AS=$TOOLCHAIN/bin/llvm-as +export CC=$TOOLCHAIN/bin/aarch64-linux-android21-clang +export CXX=$TOOLCHAIN/bin/aarch64-linux-android21-clang++ +export LD=$TOOLCHAIN/bin/ld +export RANLIB=$TOOLCHAIN/bin/llvm-ranlib +export STRIP=$TOOLCHAIN/bin/llvm-strip +``` + +When building on Linux or targeting other API levels or architectures, you need +to adjust those variables accordingly. After that you can build curl like this: + + ./configure --host aarch64-linux-android --with-pic --disable-shared + +Note that this will not give you SSL/TLS support. If you need SSL/TLS, you +have to build curl against a SSL/TLS layer, e.g. OpenSSL, because it is +impossible for curl to access Android's native SSL/TLS layer. To build curl +for Android using OpenSSL, follow the OpenSSL build instructions and then +install `libssl.a` and `libcrypto.a` to `$TOOLCHAIN/sysroot/usr/lib` and copy +`include/openssl` to `$TOOLCHAIN/sysroot/usr/include`. Now you can build curl +for Android using OpenSSL like this: + +```bash +LIBS="-lssl -lcrypto -lc++" # For OpenSSL/BoringSSL. In general, you will need to the SSL/TLS layer's transitive dependencies if you are linking statically. +./configure --host aarch64-linux-android --with-pic --disable-shared --with-openssl="$TOOLCHAIN/sysroot/usr" +``` + +# IBM i + +For IBM i (formerly OS/400), you can use curl in two different ways: + +- Natively, running in the **ILE**. The obvious use is being able to call curl + from ILE C or RPG applications. + - You will need to build this from source. See `packages/OS400/README` for + the ILE specific build instructions. +- In the **PASE** environment, which runs AIX programs. curl will be built as + it would be on AIX. + - IBM provides builds of curl in their Yum repository for PASE software. + - To build from source, follow the Unix instructions. + +There are some additional limitations and quirks with curl on this platform; +they affect both environments. + +## Multi-threading notes + +By default, jobs in IBM i will not start with threading enabled. (Exceptions +include interactive PASE sessions started by `QP2TERM` or SSH.) If you use +curl in an environment without threading when options like asynchronous DNS +were enabled, you will get messages like: + +``` +getaddrinfo() thread failed to start +``` + +Do not panic. curl and your program are not broken. You can fix this by: + +- Set the environment variable `QIBM_MULTI_THREADED` to `Y` before starting + your program. This can be done at whatever scope you feel is appropriate. +- Alternatively, start the job with the `ALWMLTTHD` parameter set to `*YES`. + +# Cross compile + +Download and unpack the curl package. + +`cd` to the new directory. (e.g. `cd curl-7.12.3`) + +Set environment variables to point to the cross-compile toolchain and call +configure with any options you need. Be sure and specify the `--host` and +`--build` parameters at configuration time. The following script is an example +of cross-compiling for the IBM 405GP PowerPC processor using the toolchain on +Linux. + +```bash +#! /bin/sh + +export PATH=$PATH:/opt/hardhat/devkit/ppc/405/bin +export CPPFLAGS="-I/opt/hardhat/devkit/ppc/405/target/usr/include" +export AR=ppc_405-ar +export AS=ppc_405-as +export LD=ppc_405-ld +export RANLIB=ppc_405-ranlib +export CC=ppc_405-gcc +export NM=ppc_405-nm + +./configure --target=powerpc-hardhat-linux + --host=powerpc-hardhat-linux + --build=i586-pc-linux-gnu + --prefix=/opt/hardhat/devkit/ppc/405/target/usr/local + --exec-prefix=/usr/local +``` + +You may also need to provide a parameter like `--with-random=/dev/urandom` to +configure as it cannot detect the presence of a random number generating +device for a target system. The `--prefix` parameter specifies where curl +will be installed. If `configure` completes successfully, do `make` and `make +install` as usual. + +In some cases, you may be able to simplify the above commands to as little as: + + ./configure --host=ARCH-OS + +# REDUCING SIZE + +There are a number of configure options that can be used to reduce the size of +libcurl for embedded applications where binary size is an important factor. +First, be sure to set the `CFLAGS` variable when configuring with any relevant +compiler optimization flags to reduce the size of the binary. For gcc, this +would mean at minimum the -Os option, and potentially the `-march=X`, +`-mdynamic-no-pic` and `-flto` options as well, e.g. + + ./configure CFLAGS='-Os' LDFLAGS='-Wl,-Bsymbolic'... + +Note that newer compilers often produce smaller code than older versions +due to improved optimization. + +Be sure to specify as many `--disable-` and `--without-` flags on the +configure command-line as you can to disable all the libcurl features that you +know your application is not going to need. Besides specifying the +`--disable-PROTOCOL` flags for all the types of URLs your application will not +use, here are some other flags that can reduce the size of the library by +disabling support for some feature: + + - `--disable-alt-svc` (HTTP Alt-Svc) + - `--disable-ares` (the C-ARES DNS library) + - `--disable-cookies` (HTTP cookies) + - `--disable-basic-auth` (cryptographic authentication) + - `--disable-bearer-auth` (cryptographic authentication) + - `--disable-digest-auth` (cryptographic authentication) + - `--disable-kerberos-auth` (cryptographic authentication) + - `--disable-negotiate-auth` (cryptographic authentication) + - `--disable-aws` (cryptographic authentication) + - `--disable-dateparse` (date parsing for time conditionals) + - `--disable-dnsshuffle` (internal server load spreading) + - `--disable-doh` (DNS-over-HTTP) + - `--disable-get-easy-options` (lookup easy options at runtime) + - `--disable-hsts` (HTTP Strict Transport Security) + - `--disable-http-auth` (all HTTP authentication) + - `--disable-ipv6` (IPv6) + - `--disable-libcurl-option` (--libcurl C code generation support) + - `--disable-manual` (built-in documentation) + - `--disable-netrc` (.netrc file) + - `--disable-ntlm-wb` (NTLM WinBind) + - `--disable-progress-meter` (graphical progress meter in library) + - `--disable-proxy` (HTTP and SOCKS proxies) + - `--disable-pthreads` (multi-threading) + - `--disable-socketpair` (socketpair for asynchronous name resolving) + - `--disable-threaded-resolver` (threaded name resolver) + - `--disable-tls-srp` (Secure Remote Password authentication for TLS) + - `--disable-unix-sockets` (UNIX sockets) + - `--disable-verbose` (eliminates debugging strings and error code strings) + - `--disable-versioned-symbols` (versioned symbols) + - `--enable-symbol-hiding` (eliminates unneeded symbols in the shared library) + - `--without-brotli` (Brotli on-the-fly decompression) + - `--without-libpsl` (Public Suffix List in cookies) + - `--without-nghttp2` (HTTP/2 using nghttp2) + - `--without-ngtcp2` (HTTP/2 using ngtcp2) + - `--without-zstd` (Zstd on-the-fly decompression) + - `--without-libidn2` (internationalized domain names) + - `--without-librtmp` (RTMP) + - `--without-ssl` (SSL/TLS) + - `--without-zlib` (on-the-fly decompression) + +The GNU compiler and linker have a number of options that can reduce the +size of the libcurl dynamic libraries on some platforms even further. +Specify them by providing appropriate `CFLAGS` and `LDFLAGS` variables on +the configure command-line, e.g. + + CFLAGS="-Os -ffunction-sections -fdata-sections + -fno-unwind-tables -fno-asynchronous-unwind-tables -flto" + LDFLAGS="-Wl,-s -Wl,-Bsymbolic -Wl,--gc-sections" + +Be sure also to strip debugging symbols from your binaries after compiling +using 'strip' (or the appropriate variant if cross-compiling). If space is +really tight, you may be able to remove some unneeded sections of the shared +library using the -R option to objcopy (e.g. the .comment section). + +Using these techniques it is possible to create a basic HTTP-only libcurl +shared library for i386 Linux platforms that is only 133 KiB in size +(as of libcurl version 7.80.0, using gcc 11.2.0). + +You may find that statically linking libcurl to your application will result +in a lower total size than dynamically linking. + +Note that the curl test harness can detect the use of some, but not all, of +the `--disable` statements suggested above. Use will cause tests relying on +those features to fail. The test harness can be manually forced to skip the +relevant tests by specifying certain key words on the `runtests.pl` command +line. Following is a list of appropriate key words for those configure options +that are not automatically detected: + + - `--disable-cookies` !cookies + - `--disable-dateparse` !RETRY-AFTER !`CURLOPT_TIMECONDITION` !`CURLINFO_FILETIME` !`If-Modified-Since` !`curl_getdate` !`-z` + - `--disable-libcurl-option` !`--libcurl` + - `--disable-verbose` !verbose\ logs + +# Ports + +This is a probably incomplete list of known CPU architectures and operating +systems that curl has been compiled for. If you know a system curl compiles +and runs on, that is not listed, please let us know! + +## 101 Operating Systems + + AIX, AmigaOS, Android, ArcoOS, Aros, Atari FreeMiNT, BeOS, Blackberry 10, + Blackberry Tablet OS, Cell OS, CheriBSD, Chrome OS, Cisco IOS, DG/UX, + Dragonfly BSD, DR DOS, eCOS, FreeBSD, FreeDOS, FreeRTOS, Fuchsia, Garmin OS, + Genode, Haiku, HardenedBSD, HP-UX, Hurd, Illumos, Integrity, iOS, ipadOS, IRIX, + Linux, Lua RTOS, Mac OS 9, macOS, Mbed, Meego, Micrium, MINIX, Moblin, MorphOS, + MPE/iX, MS-DOS, NCR MP-RAS, NetBSD, Netware, NextStep, Nintendo Switch, + NonStop OS, NuttX, OpenBSD, OpenStep, Orbis OS, OS/2, OS/400, OS21, Plan 9, + PlayStation Portable, QNX, Qubes OS, ReactOS, Redox, RICS OS, ROS, RTEMS, + Sailfish OS, SCO Unix, Serenity, SINIX-Z, SkyOS, Solaris, Sortix, SunOS, + Syllable OS, Symbian, Tizen, TPF, Tru64, tvOS, ucLinux, Ultrix, UNICOS, + UnixWare, VMS, vxWorks, watchOS, Wear OS, WebOS, Wii system software, Wii U, + Windows, Windows CE, Xbox System, Xenix, Zephyr, z/OS, z/TPF, z/VM, z/VSE + +## 28 CPU Architectures + + Alpha, ARC, ARM, AVR32, C-SKY, CompactRISC, Elbrus, ETRAX, HP-PA, Itanium, + LoongArch, m68k, m88k, MicroBlaze, MIPS, Nios, OpenRISC, POWER, PowerPC, + RISC-V, s390, SH4, SPARC, Tilera, VAX, x86, Xtensa, z/arch diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md new file mode 100644 index 0000000..d7513a8 --- /dev/null +++ b/docs/INTERNALS.md @@ -0,0 +1,56 @@ +# curl internals + +The canonical libcurl internals documentation is now in the [everything +curl](https://everything.curl.dev/internals) book. This file lists supported +versions of libs and build tools. + +## Portability + + We write curl and libcurl to compile with C89 compilers on 32-bit and up + machines. Most of libcurl assumes more or less POSIX compliance but that is + not a requirement. + + We write libcurl to build and work with lots of third party tools, and we + want it to remain functional and buildable with these and later versions + (older versions may still work but is not what we work hard to maintain): + +## Dependencies + + We aim to support these or later versions. + + - OpenSSL 0.9.7 + - GnuTLS 3.1.10 + - zlib 1.1.4 + - libssh2 1.0 + - c-ares 1.16.0 + - libidn2 2.0.0 + - wolfSSL 2.0.0 + - OpenLDAP 2.0 + - MIT Kerberos 1.2.4 + - Heimdal ? + - nghttp2 1.15.0 + - WinSock 2.2 (on Windows 95+ and Windows CE .NET 4.1+) + +## Build tools + + When writing code (mostly for generating stuff included in release tarballs) + we use a few "build tools" and we make sure that we remain functional with + these versions: + + - GNU Libtool 1.4.2 + - GNU Autoconf 2.59 + - GNU Automake 1.7 + - GNU M4 1.4 + - perl 5.6 + - roffit 0.5 + - nroff any version that supports `-man [in] [out]` + - cmake 3.7 + +Library Symbols +=============== + + All symbols used internally in libcurl must use a `Curl_` prefix if they are + used in more than a single file. Single-file symbols must be made static. + Public ("exported") symbols must use a `curl_` prefix. Public API functions + are marked with `CURL_EXTERN` in the public header files so that all others + can be hidden on platforms where this is possible. diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS new file mode 100644 index 0000000..f91ff63 --- /dev/null +++ b/docs/KNOWN_BUGS @@ -0,0 +1,610 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + + Known Bugs + +These are problems and bugs known to exist at the time of this release. Feel +free to join in and help us correct one or more of these. Also be sure to +check the changelog of the current development status, as one or more of these +problems may have been fixed or changed somewhat since this was written. + + 1. HTTP + 1.2 hyper is slow + 1.5 Expect-100 meets 417 + + 2. TLS + 2.3 Unable to use PKCS12 certificate with Secure Transport + 2.4 Secure Transport will not import PKCS#12 client certificates without a password + 2.5 Client cert handling with Issuer DN differs between backends + 2.7 Client cert (MTLS) issues with Schannel + 2.11 Schannel TLS 1.2 handshake bug in old Windows versions + 2.12 FTPS with Schannel times out file list operation + 2.13 CURLOPT_CERTINFO results in CURLE_OUT_OF_MEMORY with Schannel + + 3. Email protocols + 3.1 IMAP SEARCH ALL truncated response + 3.2 No disconnect command + 3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses + 3.4 AUTH PLAIN for SMTP is not working on all servers + 3.5 APOP authentication fails on POP3 + + 4. Command line + + 5. Build and portability issues + 5.1 OS400 port requires deprecated IBM library + 5.2 curl-config --libs contains private details + 5.3 building for old macOS fails with gcc + 5.5 cannot handle Unicode arguments in non-Unicode builds on Windows + 5.6 cygwin: make install installs curl-config.1 twice + 5.9 Utilize Requires.private directives in libcurl.pc + 5.11 configure --with-gssapi with Heimdal is ignored on macOS + 5.12 flaky CI builds + 5.13 long paths are not fully supported on Windows + 5.14 Windows Unicode builds use homedir in current locale + + 6. Authentication + 6.1 NTLM authentication and unicode + 6.2 MIT Kerberos for Windows build + 6.3 NTLM in system context uses wrong name + 6.5 NTLM does not support password with § character + 6.6 libcurl can fail to try alternatives with --proxy-any + 6.7 Do not clear digest for single realm + 6.9 SHA-256 digest not supported in Windows SSPI builds + 6.10 curl never completes Negotiate over HTTP + 6.11 Negotiate on Windows fails + 6.12 cannot use Secure Transport with Crypto Token Kit + 6.13 Negotiate against Hadoop HDFS + + 7. FTP + 7.3 FTP with NOBODY and FAILONERROR + 7.4 FTP with ACCT + 7.11 FTPS upload data loss with TLS 1.3 + 7.12 FTPS directory listing hangs on Windows with Schannel + + 9. SFTP and SCP + 9.1 SFTP does not do CURLOPT_POSTQUOTE correct + 9.2 wolfssh: publickey auth does not work + 9.3 Remote recursive folder creation with SFTP + 9.4 libssh blocking and infinite loop problem + 9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" + + 10. SOCKS + 10.3 FTPS over SOCKS + + 11. Internals + 11.2 error buffer not set if connection to multiple addresses fails + 11.4 HTTP test server 'connection-monitor' problems + 11.5 Connection information when using TCP Fast Open + + 12. LDAP + 12.1 OpenLDAP hangs after returning results + 12.2 LDAP on Windows does authentication wrong? + 12.3 LDAP on Windows does not work + 12.4 LDAPS requests to ActiveDirectory server hang + + 13. TCP/IP + 13.2 Trying local ports fails on Windows + + 15. CMake + 15.1 cmake outputs: no version information available + 15.2 support build with GnuTLS + 15.3 unusable tool_hugehelp.c with MinGW + 15.6 uses -lpthread instead of Threads::Threads + 15.7 generated .pc file contains strange entries + 15.8 libcurl.pc uses absolute library paths + 15.11 ExternalProject_Add does not set CURL_CA_PATH + 15.13 CMake build with MIT Kerberos does not work + + 16. aws-sigv4 + 16.1 aws-sigv4 does not sign requests with * correctly + 16.6 aws-sigv4 does not behave well with AWS VPC Lattice + + 17. HTTP/2 + 17.2 HTTP/2 frames while in the connection pool kill reuse + 17.3 ENHANCE_YOUR_CALM causes infinite retries + + 18. HTTP/3 + 18.1 connection migration does not work + + 19. RTSP + 19.1 Some methods do not support response bodies + +============================================================================== + +1. HTTP + +1.2 hyper is slow + + When curl is built to use hyper for HTTP, it is unnecessary slow. + + https://github.com/curl/curl/issues/11203 + +1.5 Expect-100 meets 417 + + If an upload using Expect: 100-continue receives an HTTP 417 response, it + ought to be automatically resent without the Expect:. A workaround is for + the client application to redo the transfer after disabling Expect:. + https://curl.se/mail/archive-2008-02/0043.html + +2. TLS + +2.3 Unable to use PKCS12 certificate with Secure Transport + + See https://github.com/curl/curl/issues/5403 + +2.4 Secure Transport will not import PKCS#12 client certificates without a password + + libcurl calls SecPKCS12Import with the PKCS#12 client certificate, but that + function rejects certificates that do not have a password. + https://github.com/curl/curl/issues/1308 + +2.5 Client cert handling with Issuer DN differs between backends + + When the specified client certificate does not match any of the + server-specified DNs, the OpenSSL and GnuTLS backends behave differently. + The github discussion may contain a solution. + + See https://github.com/curl/curl/issues/1411 + +2.7 Client cert (MTLS) issues with Schannel + + See https://github.com/curl/curl/issues/3145 + +2.11 Schannel TLS 1.2 handshake bug in old Windows versions + + In old versions of Windows such as 7 and 8.1 the Schannel TLS 1.2 handshake + implementation likely has a bug that can rarely cause the key exchange to + fail, resulting in error SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED. + + https://github.com/curl/curl/issues/5488 + +2.12 FTPS with Schannel times out file list operation + + "Instead of the command completing, it just sits there until the timeout + expires." - the same command line seems to work with other TLS backends and + other operating systems. See https://github.com/curl/curl/issues/5284. + +2.13 CURLOPT_CERTINFO results in CURLE_OUT_OF_MEMORY with Schannel + + https://github.com/curl/curl/issues/8741 + +3. Email protocols + +3.1 IMAP SEARCH ALL truncated response + + IMAP "SEARCH ALL" truncates output on large boxes. "A quick search of the + code reveals that pingpong.c contains some truncation code, at line 408, when + it deems the server response to be too large truncating it to 40 characters" + https://curl.se/bug/view.cgi?id=1366 + +3.2 No disconnect command + + The disconnect commands (LOGOUT and QUIT) may not be sent by IMAP, POP3 and + SMTP if a failure occurs during the authentication phase of a connection. + +3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses + + You have to tell libcurl not to expect a body, when dealing with one line + response commands. Please see the POP3 examples and test cases which show + this for the NOOP and DELE commands. https://curl.se/bug/?i=740 + +3.4 AUTH PLAIN for SMTP is not working on all servers + + Specifying "--login-options AUTH=PLAIN" on the command line does not seem to + work correctly. + + See https://github.com/curl/curl/issues/4080 + +3.5 APOP authentication fails on POP3 + + See https://github.com/curl/curl/issues/10073 + +4. Command line + +5. Build and portability issues + +5.1 OS400 port requires deprecated IBM library + + curl for OS400 requires QADRT to build, which provides ASCII wrappers for + libc/POSIX functions in the ILE, but IBM no longer supports or even offers + this library to download. + + See https://github.com/curl/curl/issues/5176 + +5.2 curl-config --libs contains private details + + "curl-config --libs" will include details set in LDFLAGS when configure is + run that might be needed only for building libcurl. Further, curl-config + --cflags suffers from the same effects with CFLAGS/CPPFLAGS. + +5.3 building for old macOS fails with gcc + + Building curl for certain old macOS versions fails when gcc is used. We + command using clang in those cases. + + See https://github.com/curl/curl/issues/11441 + +5.5 cannot handle Unicode arguments in non-Unicode builds on Windows + + If a URL or filename cannot be encoded using the user's current codepage then + it can only be encoded properly in the Unicode character set. Windows uses + UTF-16 encoding for Unicode and stores it in wide characters, however curl + and libcurl are not equipped for that at the moment except when built with + _UNICODE and UNICODE defined. And, except for Cygwin, Windows cannot use UTF-8 + as a locale. + + https://curl.se/bug/?i=345 + https://curl.se/bug/?i=731 + https://curl.se/bug/?i=3747 + +5.6 cygwin: make install installs curl-config.1 twice + + https://github.com/curl/curl/issues/8839 + +5.9 Utilize Requires.private directives in libcurl.pc + + https://github.com/curl/curl/issues/864 + +5.11 configure --with-gssapi with Heimdal is ignored on macOS + + ... unless you also pass --with-gssapi-libs + + https://github.com/curl/curl/issues/3841 + +5.12 flaky CI builds + + We run many CI builds for each commit and PR on github, and especially a + number of the Windows builds are flaky. This means that we rarely get all CI + builds go green and complete without errors. This is unfortunate as it makes + us sometimes miss actual build problems and it is surprising to newcomers to + the project who (rightfully) do not expect this. + + See https://github.com/curl/curl/issues/6972 + +5.13 long paths are not fully supported on Windows + + curl on Windows cannot access long paths (paths longer than 260 characters). + However, as a workaround, the Windows path prefix \\?\ which disables all path + interpretation may work to allow curl to access the path. For example: + \\?\c:\longpath. + + See https://github.com/curl/curl/issues/8361 + +5.14 Windows Unicode builds use homedir in current locale + + The Windows Unicode builds of curl use the current locale, but expect Unicode + UTF-8 encoded paths for internal use such as open, access and stat. The user's + home directory is retrieved via curl_getenv in the current locale and not as + UTF-8 encoded Unicode. + + See https://github.com/curl/curl/pull/7252 and + https://github.com/curl/curl/pull/7281 + +6. Authentication + +6.1 NTLM authentication and unicode + + NTLM authentication involving unicode user name or password only works + properly if built with UNICODE defined together with the Schannel + backend. The original problem was mentioned in: + https://curl.se/mail/lib-2009-10/0024.html + https://curl.se/bug/view.cgi?id=896 + + The Schannel version verified to work as mentioned in + https://curl.se/mail/lib-2012-07/0073.html + +6.2 MIT Kerberos for Windows build + + libcurl fails to build with MIT Kerberos for Windows (KfW) due to KfW's + library header files exporting symbols/macros that should be kept private to + the KfW library. See ticket #5601 at https://krbdev.mit.edu/rt/ + +6.3 NTLM in system context uses wrong name + + NTLM authentication using SSPI (on Windows) when (lib)curl is running in + "system context" will make it use wrong(?) user name - at least when compared + to what winhttp does. See https://curl.se/bug/view.cgi?id=535 + +6.5 NTLM does not support password with § character + + https://github.com/curl/curl/issues/2120 + +6.6 libcurl can fail to try alternatives with --proxy-any + + When connecting via a proxy using --proxy-any, a failure to establish an + authentication will cause libcurl to abort trying other options if the + failed method has a higher preference than the alternatives. As an example, + --proxy-any against a proxy which advertise Negotiate and NTLM, but which + fails to set up Kerberos authentication will not proceed to try authentication + using NTLM. + + https://github.com/curl/curl/issues/876 + +6.7 Do not clear digest for single realm + + https://github.com/curl/curl/issues/3267 + +6.9 SHA-256 digest not supported in Windows SSPI builds + + Windows builds of curl that have SSPI enabled use the native Windows API calls + to create authentication strings. The call to InitializeSecurityContext fails + with SEC_E_QOP_NOT_SUPPORTED which causes curl to fail with CURLE_AUTH_ERROR. + + Microsoft does not document supported digest algorithms and that SEC_E error + code is not a documented error for InitializeSecurityContext (digest). + + https://github.com/curl/curl/issues/6302 + +6.10 curl never completes Negotiate over HTTP + + Apparently it is not working correctly...? + + See https://github.com/curl/curl/issues/5235 + +6.11 Negotiate on Windows fails + + When using --negotiate (or NTLM) with curl on Windows, SSL/TLS handshake + fails despite having a valid kerberos ticket cached. Works without any issue + in Unix/Linux. + + https://github.com/curl/curl/issues/5881 + +6.12 cannot use Secure Transport with Crypto Token Kit + + https://github.com/curl/curl/issues/7048 + +6.13 Negotiate authentication against Hadoop HDFS + + https://github.com/curl/curl/issues/8264 + +7. FTP + +7.3 FTP with NOBODY and FAILONERROR + + It seems sensible to be able to use CURLOPT_NOBODY and CURLOPT_FAILONERROR + with FTP to detect if a file exists or not, but it is not working: + https://curl.se/mail/lib-2008-07/0295.html + +7.4 FTP with ACCT + + When doing an operation over FTP that requires the ACCT command (but not when + logging in), the operation will fail since libcurl does not detect this and + thus fails to issue the correct command: + https://curl.se/bug/view.cgi?id=635 + +7.11 FTPS upload data loss with TLS 1.3 + + During FTPS upload curl does not attempt to read TLS handshake messages sent + after the initial handshake. OpenSSL servers running TLS 1.3 may send such a + message. When curl closes the upload connection if unread data has been + received (such as a TLS handshake message) then the TCP protocol sends an + RST to the server, which may cause the server to discard or truncate the + upload if it has not read all sent data yet, and then return an error to curl + on the control channel connection. + + Since 7.78.0 this is mostly fixed. curl will do a single read before closing + TLS connections (which causes the TLS library to read handshake messages), + however there is still possibility of an RST if more messages need to be read + or a message arrives after the read but before close (network race condition). + + https://github.com/curl/curl/issues/6149 + +7.12 FTPS directory listing hangs on Windows with Schannel + + https://github.com/curl/curl/issues/9161 + +9. SFTP and SCP + +9.1 SFTP does not do CURLOPT_POSTQUOTE correct + + When libcurl sends CURLOPT_POSTQUOTE commands when connected to a SFTP server + using the multi interface, the commands are not being sent correctly and + instead the connection is "cancelled" (the operation is considered done) + prematurely. There is a half-baked (busy-looping) patch provided in the bug + report but it cannot be accepted as-is. See + https://curl.se/bug/view.cgi?id=748 + +9.2 wolfssh: publickey auth does not work + + When building curl to use the wolfSSH backend for SFTP, the publickey + authentication does not work. This is simply functionality not written for curl + yet, the necessary API for make this work is provided by wolfSSH. + + See https://github.com/curl/curl/issues/4820 + +9.3 Remote recursive folder creation with SFTP + + On this servers, the curl fails to create directories on the remote server + even when the CURLOPT_FTP_CREATE_MISSING_DIRS option is set. + + See https://github.com/curl/curl/issues/5204 + +9.4 libssh blocking and infinite loop problem + + In the SSH_SFTP_INIT state for libssh, the ssh session working mode is set to + blocking mode. If the network is suddenly disconnected during sftp + transmission, curl will be stuck, even if curl is configured with a timeout. + + https://github.com/curl/curl/issues/8632 + +9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" + + Running SCP and SFTP tests on cygwin makes this warning message appear. + + https://github.com/curl/curl/issues/11244 + +10. SOCKS + +10.3 FTPS over SOCKS + + libcurl does not support FTPS over a SOCKS proxy. + + +11. Internals + +11.2 error buffer not set if connection to multiple addresses fails + + If you ask libcurl to resolve a hostname like example.com to IPv6 addresses + only. But you only have IPv4 connectivity. libcurl will correctly fail with + CURLE_COULDNT_CONNECT. But the error buffer set by CURLOPT_ERRORBUFFER + remains empty. Issue: https://github.com/curl/curl/issues/544 + +11.4 HTTP test server 'connection-monitor' problems + + The 'connection-monitor' feature of the sws HTTP test server does not work + properly if some tests are run in unexpected order. Like 1509 and then 1525. + + See https://github.com/curl/curl/issues/868 + +11.5 Connection information when using TCP Fast Open + + CURLINFO_LOCAL_PORT (and possibly a few other) fails when TCP Fast Open is + enabled. + + See https://github.com/curl/curl/issues/1332 and + https://github.com/curl/curl/issues/4296 + +12. LDAP + +12.1 OpenLDAP hangs after returning results + + By configuration defaults, OpenLDAP automatically chase referrals on + secondary socket descriptors. The OpenLDAP backend is asynchronous and thus + should monitor all socket descriptors involved. Currently, these secondary + descriptors are not monitored, causing OpenLDAP library to never receive + data from them. + + As a temporary workaround, disable referrals chasing by configuration. + + The fix is not easy: proper automatic referrals chasing requires a + synchronous bind callback and monitoring an arbitrary number of socket + descriptors for a single easy handle (currently limited to 5). + + Generic LDAP is synchronous: OK. + + See https://github.com/curl/curl/issues/622 and + https://curl.se/mail/lib-2016-01/0101.html + +12.2 LDAP on Windows does authentication wrong? + + https://github.com/curl/curl/issues/3116 + +12.3 LDAP on Windows does not work + + A simple curl command line getting "ldap://ldap.forumsys.com" returns an + error that says "no memory" ! + + https://github.com/curl/curl/issues/4261 + +12.4 LDAPS requests to ActiveDirectory server hang + + https://github.com/curl/curl/issues/9580 + +13. TCP/IP + +13.2 Trying local ports fails on Windows + + This makes '--local-port [range]' to not work since curl cannot properly + detect if a port is already in use, so it will try the first port, use that and + then subsequently fail anyway if that was actually in use. + + https://github.com/curl/curl/issues/8112 + +15. CMake + +15.1 cmake outputs: no version information available + + Something in the SONAME generation seems to be wrong in the cmake build. + + https://github.com/curl/curl/issues/11158 + +15.2 support build with GnuTLS + +15.3 unusable tool_hugehelp.c with MinGW + + see https://github.com/curl/curl/issues/3125 + +15.6 uses -lpthread instead of Threads::Threads + + See https://github.com/curl/curl/issues/6166 + +15.7 generated .pc file contains strange entries + + The Libs.private field of the generated .pc file contains -lgcc -lgcc_s -lc + -lgcc -lgcc_s + + See https://github.com/curl/curl/issues/6167 + +15.8 libcurl.pc uses absolute library paths + + The libcurl.pc file generated by cmake contains things like Libs.private: + /usr/lib64/libssl.so /usr/lib64/libcrypto.so /usr/lib64/libz.so. The + autotools equivalent would say Libs.private: -lssl -lcrypto -lz + + See https://github.com/curl/curl/issues/6169 + +15.11 ExternalProject_Add does not set CURL_CA_PATH + + CURL_CA_BUNDLE and CURL_CA_PATH are not set properly when cmake's + ExternalProject_Add is used to build curl as a dependency. + + See https://github.com/curl/curl/issues/6313 + +15.13 CMake build with MIT Kerberos does not work + + Minimum CMake version was bumped in curl 7.71.0 (#5358) Since CMake 3.2 + try_compile started respecting the CMAKE_EXE_FLAGS. The code dealing with + MIT Kerberos detection sets few variables to potentially weird mix of space, + and ;-separated flags. It had to blow up at some point. All the CMake checks + that involve compilation are doomed from that point, the configured tree + cannot be built. + + https://github.com/curl/curl/issues/6904 + +16. aws-sigv4 + +16.1 aws-sigv4 does not sign requests with * correctly + + https://github.com/curl/curl/issues/7559 + +16.6 aws-sigv4 does not behave well with AWS VPC Lattice + + https://github.com/curl/curl/issues/11007 + +17. HTTP/2 + +17.2 HTTP/2 frames while in the connection pool kill reuse + + If the server sends HTTP/2 frames (like for example an HTTP/2 PING frame) to + curl while the connection is held in curl's connection pool, the socket will + be found readable when considered for reuse and that makes curl think it is + dead and then it will be closed and a new connection gets created instead. + + This is *best* fixed by adding monitoring to connections while they are kept + in the pool so that pings can be responded to appropriately. + +17.3 ENHANCE_YOUR_CALM causes infinite retries + + Infinite retries with 2 parallel requests on one connection receiving GOAWAY + with ENHANCE_YOUR_CALM error code. + + See https://github.com/curl/curl/issues/5119 + +18. HTTP/3 + +18.1 connection migration does not work + + https://github.com/curl/curl/issues/7695 + +19. RTSP + +19.1 Some methods do not support response bodies + + The RTSP implementation is written to assume that a number of RTSP methods + will always get responses without bodies, even though there seems to be no + indication in the RFC that this is always the case. + + https://github.com/curl/curl/issues/12414 diff --git a/docs/MAIL-ETIQUETTE b/docs/MAIL-ETIQUETTE new file mode 100644 index 0000000..2dcf9cb --- /dev/null +++ b/docs/MAIL-ETIQUETTE @@ -0,0 +1,285 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + +MAIL ETIQUETTE + + 1. About the lists + 1.1 Mailing Lists + 1.2 Netiquette + 1.3 Do Not Mail a Single Individual + 1.4 Subscription Required + 1.5 Moderation of new posters + 1.6 Handling trolls and spam + 1.7 How to unsubscribe + 1.8 I posted, now what? + 1.9 Your emails are public + + 2. Sending mail + 2.1 Reply or New Mail + 2.2 Reply to the List + 2.3 Use a Sensible Subject + 2.4 Do Not Top-Post + 2.5 HTML is not for mails + 2.6 Quoting + 2.7 Digest + 2.8 Please Tell Us How You Solved The Problem + +============================================================================== + +1. About the lists + + 1.1 Mailing Lists + + The mailing lists we have are all listed and described at + https://curl.se/mail/ + + Each mailing list is targeted to a specific set of users and subjects, + please use the one or the ones that suit you the most. + + Each mailing list has hundreds up to thousands of readers, meaning that each + mail sent will be received and read by a large number of people. People + from various cultures, regions, religions and continents. + + 1.2 Netiquette + + Netiquette is a common term for how to behave on the Internet. Of course, in + each particular group and subculture there will be differences in what is + acceptable and what is considered good manners. + + This document outlines what we in the curl project consider to be good + etiquette, and primarily this focus on how to behave on and how to use our + mailing lists. + + 1.3 Do Not Mail a Single Individual + + Many people send one question to one person. One person gets many mails, and + there is only one person who can give you a reply. The question may be + something that other people would also like to ask. These other people have + no way to read the reply, but to ask the one person the question. The one + person consequently gets overloaded with mail. + + If you really want to contact an individual and perhaps pay for his or her + services, by all means go ahead, but if it's just another curl question, + take it to a suitable list instead. + + 1.4 Subscription Required + + All curl mailing lists require that you are subscribed to allow a mail to go + through to all the subscribers. + + If you post without being subscribed (or from a different mail address than + the one you are subscribed with), your mail will simply be silently + discarded. You have to subscribe first, then post. + + The reason for this unfortunate and strict subscription policy is of course + to stop spam from pestering the lists. + + 1.5 Moderation of new posters + + Several of the curl mailing lists automatically make all posts from new + subscribers be moderated. This means that after you have subscribed and + sent your first mail to a list, that mail will not be let through to the + list until a mailing list administrator has verified that it is OK and + permits it to get posted. + + Once a first post has been made that proves the sender is actually talking + about curl-related subjects, the moderation "flag" will be switched off and + future posts will go through without being moderated. + + The reason for this moderation policy is that we do suffer from spammers who + actually subscribe and send spam to our lists. + + 1.6 Handling trolls and spam + + Despite our good intentions and hard work to keep spam off the lists and to + maintain a friendly and positive atmosphere, there will be times when spam + and or trolls get through. + + Troll - "someone who posts inflammatory, extraneous, or off-topic messages + in an online community" + + Spam - "use of electronic messaging systems to send unsolicited bulk + messages" + + No matter what, we NEVER EVER respond to trolls or spammers on the list. If + you believe the list admin should do something in particular, contact them + off-list. The subject will be taken care of as much as possible to prevent + repeated offenses, but responding on the list to such messages never leads to + anything good and only puts the light even more on the offender: which was + the entire purpose of it getting sent to the list in the first place. + + Do not feed the trolls. + + 1.7 How to unsubscribe + + You can unsubscribe the same way you subscribed in the first place. You go + to the page for the particular mailing list you are subscribed to and you enter + your email address and password and press the unsubscribe button. + + Also, the instructions to unsubscribe are included in the headers of every + mail that is sent out to all curl related mailing lists and there is a footer + in each mail that links to the "admin" page on which you can unsubscribe and + change other options. + + You NEVER EVER email the mailing list requesting someone else to take you off + the list. + + 1.8 I posted, now what? + + If you are not subscribed with the same email address that you used to send + the email, your post will just be silently discarded. + + If you posted for the first time to the mailing list, you first need to wait + for an administrator to allow your email to go through (moderated). This + normally happens quickly but in case we are asleep, you may have to wait a + few hours. + + Once your email goes through it is sent out to several hundred or even + thousands of recipients. Your email may cover an area that not that many + people know about or are interested in. Or possibly the person who knows + about it is on vacation or under a heavy work load right now. You may have + to wait for a response and you should not expect to get a response at all. + Ideally, you get an answer within a couple of days. + + You do yourself and all of us a service when you include as many details as + possible already in your first email. Mention your operating system and + environment. Tell us which curl version you are using and tell us what you + did, what happened and what you expected would happen. Preferably, show us + what you did with details enough to allow others to help point out the + problem or repeat the steps in their locations. + + Failing to include details will only delay responses and make people respond + and ask for more details and you will have to send a follow-up email that + includes them. + + Expect the responses to primarily help YOU debug the issue, or ask YOU + questions that can lead you or others towards a solution or explanation to + whatever you experience. + + If you are a repeat offender to the guidelines outlined in this document, + chances are that people will ignore you at will and your chances to get + responses in the future will greatly diminish. + + 1.9 Your emails are public + + Your email, its contents and all its headers and the details in those + headers will be received by every subscriber of the mailing list that you + send your email to. + + Your email as sent to a curl mailing list will end up in mail archives, on + the curl website and elsewhere, for others to see and read. Today and in + the future. In addition to the archives, the mail is sent out to thousands + of individuals. There is no way to undo a sent email. + + When sending emails to a curl mailing list, do not include sensitive + information such as user names and passwords; use fake ones, temporary ones + or just remove them completely from the mail. Note that this includes base64 + encoded HTTP Basic auth headers. + + This public nature of the curl mailing lists makes automatically inserted mail + footers about mails being "private" or "only meant for the recipient" or + similar even more silly than usual. Because they are absolutely not private + when sent to a public mailing list. + + +2. Sending mail + + 2.1 Reply or New Mail + + Please do not reply to an existing message as a short-cut to post a message + to the lists. + + Many mail programs and web archivers use information within mails to keep + them together as "threads", as collections of posts that discuss a certain + subject. If you do not intend to reply on the same or similar subject, do not + just hit reply on an existing mail and change the subject, create a new mail. + + 2.2 Reply to the List + + When replying to a message from the list, make sure that you do "group + reply" or "reply to all", and not just reply to the author of the single + mail you reply to. + + We are actively discouraging replying back to the single person by setting + the Reply-To: field in outgoing mails back to the mailing list address, + making it harder for people to mail the author directly, if only by mistake. + + 2.3 Use a Sensible Subject + + Please use a subject of the mail that makes sense and that is related to the + contents of your mail. It makes it a lot easier to find your mail afterwards + and it makes it easier to track mail threads and topics. + + 2.4 Do Not Top-Post + + If you reply to a message, do not use top-posting. Top-posting is when you + write the new text at the top of a mail and you insert the previous quoted + mail conversation below. It forces users to read the mail in a backwards + order to properly understand it. + + This is why top posting is so bad (in top posting order): + + A: Because it messes up the order in which people normally read text. + Q: Why is top-posting such a bad thing? + A: Top-posting. + Q: What is the most annoying thing in email? + + Apart from the screwed up read order (especially when mixed together in a + thread when someone responds using the mandated bottom-posting style), it + also makes it impossible to quote only parts of the original mail. + + When you reply to a mail. You let the mail client insert the previous mail + quoted. Then you put the cursor on the first line of the mail and you move + down through the mail, deleting all parts of the quotes that do not add + context for your comments. When you want to add a comment you do so, inline, + right after the quotes that relate to your comment. Then you continue + downwards again. + + When most of the quotes have been removed and you have added your own words, + you are done. + + 2.5 HTML is not for mails + + Please switch off those HTML encoded messages. You can mail all those funny + mails to your friends. We speak plain text mails. + + 2.6 Quoting + + Quote as little as possible. Just enough to provide the context you cannot + leave out. A lengthy description can be found here: + + https://www.netmeister.org/news/learn2quote.html + + 2.7 Digest + + We allow subscribers to subscribe to the "digest" version of the mailing + lists. A digest is a collection of mails lumped together in one single mail. + + Should you decide to reply to a mail sent out as a digest, there are two + things you MUST consider if you really really cannot subscribe normally + instead: + + Cut off all mails and chatter that is not related to the mail you want to + reply to. + + Change the subject name to something sensible and related to the subject, + preferably even the actual subject of the single mail you wanted to reply to + + 2.8 Please Tell Us How You Solved The Problem + + Many people mail questions to the list, people spend some of their time and + make an effort in providing good answers to these questions. + + If you are the one who asks, please consider responding once more in case + one of the hints was what solved your problems. The guys who write answers + feel good to know that they provided a good answer and that you fixed the + problem. Far too often, the person who asked the question is never heard from + again, and we never get to know if they are gone because the problem was + solved or perhaps because the problem was unsolvable. + + Getting the solution posted also helps other users that experience the same + problem(s). They get to see (possibly in the web archives) that the + suggested fixes actually have helped at least one person. diff --git a/docs/MQTT.md b/docs/MQTT.md new file mode 100644 index 0000000..660ff29 --- /dev/null +++ b/docs/MQTT.md @@ -0,0 +1,27 @@ +# MQTT in curl + +## Usage + +A plain "GET" subscribes to the topic and prints all published messages. +Doing a "POST" publishes the post data to the topic and exits. + +Example subscribe: + + curl mqtt://host.home/bedroom/temp + +Example publish: + + curl -d 75 mqtt://host.home/bedroom/dimmer + +## What does curl deliver as a response to a subscribe + +It outputs two bytes topic length (MSB | LSB), the topic followed by the +payload. + +## Caveats + +Remaining limitations: + - Only QoS level 0 is implemented for publish + - No way to set retain flag for publish + - No TLS (mqtts) support + - Naive EAGAIN handling will not handle split messages diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 0000000..fbe94c4 --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1,128 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +AUTOMAKE_OPTIONS = foreign no-dependencies + +# EXTRA_DIST breaks with $(abs_builddir) so build it using this variable +# but distribute it (using the relative file name) in the next variable +man_MANS = $(abs_builddir)/curl.1 mk-ca-bundle.1 +noinst_man_MANS = curl.1 mk-ca-bundle.1 +dist_man_MANS = curl-config.1 +CURLPAGES = curl-config.md mk-ca-bundle.md + +# Build targets in this file (.) before cmdline-opts to ensure that +# the curl.1 rule below runs first +SUBDIRS = . cmdline-opts libcurl +DIST_SUBDIRS = $(SUBDIRS) examples + +CLEANFILES = $(man_MANS) curl.1 curl-config.1 mk-ca-bundle.1 +nodist_MANS = $(CLEANFILES) + +EXTRA_DIST = \ + $(CURLPAGES) \ + ALTSVC.md \ + BINDINGS.md \ + BUFREF.md \ + BUG-BOUNTY.md \ + BUGS.md \ + CHECKSRC.md \ + CIPHERS.md \ + CMakeLists.txt \ + CODE_OF_CONDUCT.md \ + CODE_REVIEW.md \ + CODE_STYLE.md \ + CLIENT-WRITERS.md \ + CONNECTION-FILTERS.md \ + CONTRIBUTE.md \ + CURL-DISABLE.md \ + CURLDOWN.md \ + DEPRECATE.md \ + DYNBUF.md \ + EARLY-RELEASE.md \ + EXPERIMENTAL.md \ + FAQ \ + FEATURES.md \ + GOVERNANCE.md \ + HELP-US.md \ + HISTORY.md \ + HSTS.md \ + HTTP-COOKIES.md \ + HTTP2.md \ + HTTP3.md \ + HYPER.md \ + INSTALL \ + INSTALL-CMAKE.md \ + INSTALL.md \ + INTERNALS.md \ + KNOWN_BUGS \ + MAIL-ETIQUETTE \ + MQTT.md \ + NEW-PROTOCOL.md \ + options-in-versions \ + PARALLEL-TRANSFERS.md \ + README.md \ + RELEASE-PROCEDURE.md \ + RUSTLS.md \ + ROADMAP.md \ + SECURITY-ADVISORY.md \ + SSL-PROBLEMS.md \ + SSLCERTS.md \ + THANKS \ + TODO \ + TheArtOfHttpScripting.md \ + URL-SYNTAX.md \ + VERSIONS.md \ + VULN-DISCLOSURE-POLICY.md \ + WEBSOCKET.md + +CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ + +CD2 = $(CD2_$(V)) +CD2_0 = @echo " RENDER " $@; +CD2_1 = +CD2_ = $(CD2_0) + +SUFFIXES = .1 .md + +# $(abs_builddir) is to disable VPATH when searching for this file, which +# would otherwise find the copy in $(srcdir) which breaks the $(HUGE) +# rule in src/Makefile.am in out-of-tree builds that references the file in the +# build directory. +# +# First, seed the used copy of curl.1 with the prebuilt copy (in an out-of-tree +# build), then run make recursively to rebuild it only if its dependencies +# have changed. +$(abs_builddir)/curl.1: + if test "$(top_builddir)x" != "$(top_srcdir)x" -a -e "$(srcdir)/curl.1"; then \ + $(INSTALL_DATA) "$(srcdir)/curl.1" $@ \ + && touch -r "$(srcdir)/curl.1" $@; fi + cd cmdline-opts && $(MAKE) + +.md.1: + $(CD2)$(CD2NROFF) + +curl-config.1: curl-config.md + +distclean: + rm -f $(CLEANFILES) diff --git a/docs/Makefile.in b/docs/Makefile.in new file mode 100644 index 0000000..9703691 --- /dev/null +++ b/docs/Makefile.in @@ -0,0 +1,951 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = docs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +depcomp = +am__maybe_remake_depfiles = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man1dir = $(mandir)/man1 +am__installdirs = "$(DESTDIR)$(man1dir)" +MANS = $(dist_man_MANS) $(man_MANS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in INSTALL \ + README.md THANKS TODO +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign no-dependencies + +# EXTRA_DIST breaks with $(abs_builddir) so build it using this variable +# but distribute it (using the relative file name) in the next variable +man_MANS = $(abs_builddir)/curl.1 mk-ca-bundle.1 +noinst_man_MANS = curl.1 mk-ca-bundle.1 +dist_man_MANS = curl-config.1 +CURLPAGES = curl-config.md mk-ca-bundle.md + +# Build targets in this file (.) before cmdline-opts to ensure that +# the curl.1 rule below runs first +SUBDIRS = . cmdline-opts libcurl +DIST_SUBDIRS = $(SUBDIRS) examples +CLEANFILES = $(man_MANS) curl.1 curl-config.1 mk-ca-bundle.1 +nodist_MANS = $(CLEANFILES) +EXTRA_DIST = \ + $(CURLPAGES) \ + ALTSVC.md \ + BINDINGS.md \ + BUFREF.md \ + BUG-BOUNTY.md \ + BUGS.md \ + CHECKSRC.md \ + CIPHERS.md \ + CMakeLists.txt \ + CODE_OF_CONDUCT.md \ + CODE_REVIEW.md \ + CODE_STYLE.md \ + CLIENT-WRITERS.md \ + CONNECTION-FILTERS.md \ + CONTRIBUTE.md \ + CURL-DISABLE.md \ + CURLDOWN.md \ + DEPRECATE.md \ + DYNBUF.md \ + EARLY-RELEASE.md \ + EXPERIMENTAL.md \ + FAQ \ + FEATURES.md \ + GOVERNANCE.md \ + HELP-US.md \ + HISTORY.md \ + HSTS.md \ + HTTP-COOKIES.md \ + HTTP2.md \ + HTTP3.md \ + HYPER.md \ + INSTALL \ + INSTALL-CMAKE.md \ + INSTALL.md \ + INTERNALS.md \ + KNOWN_BUGS \ + MAIL-ETIQUETTE \ + MQTT.md \ + NEW-PROTOCOL.md \ + options-in-versions \ + PARALLEL-TRANSFERS.md \ + README.md \ + RELEASE-PROCEDURE.md \ + RUSTLS.md \ + ROADMAP.md \ + SECURITY-ADVISORY.md \ + SSL-PROBLEMS.md \ + SSLCERTS.md \ + THANKS \ + TODO \ + TheArtOfHttpScripting.md \ + URL-SYNTAX.md \ + VERSIONS.md \ + VULN-DISCLOSURE-POLICY.md \ + WEBSOCKET.md + +CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ +CD2 = $(CD2_$(V)) +CD2_0 = @echo " RENDER " $@; +CD2_1 = +CD2_ = $(CD2_0) +SUFFIXES = .1 .md +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .1 .md +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign docs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(dist_man_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(dist_man_MANS) $(man_MANS)'; \ + test -n "$(man1dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.1[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS) $(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(MANS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: install-man1 + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-man1 install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-man uninstall-man1 + +.PRECIOUS: Makefile + + +# $(abs_builddir) is to disable VPATH when searching for this file, which +# would otherwise find the copy in $(srcdir) which breaks the $(HUGE) +# rule in src/Makefile.am in out-of-tree builds that references the file in the +# build directory. +# +# First, seed the used copy of curl.1 with the prebuilt copy (in an out-of-tree +# build), then run make recursively to rebuild it only if its dependencies +# have changed. +$(abs_builddir)/curl.1: + if test "$(top_builddir)x" != "$(top_srcdir)x" -a -e "$(srcdir)/curl.1"; then \ + $(INSTALL_DATA) "$(srcdir)/curl.1" $@ \ + && touch -r "$(srcdir)/curl.1" $@; fi + cd cmdline-opts && $(MAKE) + +.md.1: + $(CD2)$(CD2NROFF) + +curl-config.1: curl-config.md + +distclean: + rm -f $(CLEANFILES) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/docs/NEW-PROTOCOL.md b/docs/NEW-PROTOCOL.md new file mode 100644 index 0000000..223815b --- /dev/null +++ b/docs/NEW-PROTOCOL.md @@ -0,0 +1,110 @@ +# Adding a new protocol? + +Every once in a while, someone comes up with the idea of adding support for yet +another protocol to curl. After all, curl already supports 25 something +protocols and it is the Internet transfer machine for the world. + +In the curl project we love protocols and we love supporting many protocols +and doing it well. + +How do you proceed to add a new protocol and what are the requirements? + +## No fixed set of requirements + +This document is an attempt to describe things to consider. There is no +checklist of the twenty-seven things you need to cross off. We view the entire +effort as a whole and then judge if it seems to be the right thing - for +now. The more things that look right, fit our patterns and are done in ways +that align with our thinking, the better are the chances that we will agree +that supporting this protocol is a grand idea. + +## Mutual benefit is preferred + +curl is not here for your protocol. Your protocol is not here for curl. The +best cooperation and end result occur when all involved parties mutually see +and agree that supporting this protocol in curl would be good for everyone. +Heck, for the world. + +Consider "selling us" the idea that we need an implementation merged in curl, +to be fairly important. *Why* do we want curl to support this new protocol? + +## Protocol requirements + +### Client-side + +The protocol implementation is for a client's side of a "communication +session". + +### Transfer oriented + +The protocol itself should be focused on *transfers*. Be it uploads or +downloads or both. It should at least be possible to view the transfers as +such, like we can view reading emails over POP3 as a download and sending +emails over SMTP as an upload. + +If you cannot even shoehorn the protocol into a transfer focused view, then +you are up for a tough argument. + +### URL + +There should be a documented URL format. If there is an RFC for it there is no +question about it but the syntax does not have to be a published RFC. It could +be enough if it is already in use by other implementations. + +If you make up the syntax just in order to be able to propose it to curl, then +you are in a bad place. URLs are designed and defined for interoperability. +There should at least be a good chance that other clients and servers can be +implemented supporting the same URL syntax and work the same or similar way. + +URLs work on registered 'schemes'. There is a register of [all officially +recognized +schemes](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml). If +your protocol is not in there, is it really a protocol we want? + +### Wide and public use + +The protocol shall already be used or have an expectation of getting used +widely. Experimental protocols are better off worked on in experiments first, +to prove themselves before they are adopted by curl. + +## Code + +Of course the code needs to be written, provided, licensed agreeably and it +should follow our code guidelines and review comments have to be dealt with. +If the implementation needs third party code, that third party code should not +have noticeably lesser standards than the curl project itself. + +## Tests + +As much of the protocol implementation as possible needs to be verified by +curl test cases. We must have the implementation get tested by CI jobs, +torture tests and more. + +We have experienced many times in the past how new implementations were brought +to curl and immediately once the code had been merged, the originator vanished +from the face of the earth. That is fine, but we need to take the necessary +precautions so when it happens we are still fine. + +Our test infrastructure is powerful enough to test just about every possible +protocol - but it might require a bit of an effort to make it happen. + +## Documentation + +We cannot assume that users are particularly familiar with details and +peculiarities of the protocol. It needs documentation. + +Maybe it even needs some internal documentation so that the developers who +will try to debug something five years from now can figure out functionality a +little easier! + +The protocol specification itself should be freely available without requiring +a non-disclosure agreement or similar. + +## Do not compare + +We are constantly raising the bar and we are constantly improving the +project. A lot of things we did in the past would not be acceptable if done +today. Therefore, you might be tempted to use shortcuts or "hacks" you can +spot other - existing - protocol implementations have used, but there is +nothing to gain from that. The bar has been raised. Former "cheats" will not be +tolerated anymore. diff --git a/docs/PARALLEL-TRANSFERS.md b/docs/PARALLEL-TRANSFERS.md new file mode 100644 index 0000000..03ceb8f --- /dev/null +++ b/docs/PARALLEL-TRANSFERS.md @@ -0,0 +1,50 @@ +# Parallel transfers + +curl 7.66.0 introduced support for doing multiple transfers simultaneously; in +parallel. + +## -Z, --parallel + +When this command line option is used, curl will perform the transfers given +to it at the same time. It will do up to `--parallel-max` concurrent +transfers, with a default value of 50. + +## Progress meter + +The progress meter that is displayed when doing parallel transfers is +completely different than the regular one used for each single transfer. + + It shows: + + o percent download (if known, which means *all* transfers need to have a + known size) + o percent upload (if known, with the same caveat as for download) + o total amount of downloaded data + o total amount of uploaded data + o number of transfers to perform + o number of concurrent transfers being transferred right now + o number of transfers queued up waiting to start + o total time all transfers are expected to take (if sizes are known) + o current time the transfers have spent so far + o estimated time left (if sizes are known) + o current transfer speed (the faster of upload/download speeds measured over + the last few seconds) + +Example: + + DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed + 72 -- 37.9G 0 101 30 23 0:00:55 0:00:34 0:00:22 2752M + +## Behavior differences + +Connections are shared fine between different easy handles, but the +"authentication contexts" are not. For example doing HTTP Digest auth with one +handle for a particular transfer and then continue on with another handle that +reuses the same connection, the second handle cannot send the necessary +Authorization header at once since the context is only kept in the original +easy handle. + +To fix this, the authorization state could be made possible to share with the +share API as well, as a context per origin + path (realm?) basically. + +Visible in test 153, 1412 and more. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..b72d8bc --- /dev/null +++ b/docs/README.md @@ -0,0 +1,12 @@ +![curl logo](https://curl.se/logo/curl-logo.svg) + +# Documentation + +you will find a mix of various documentation in this directory and +subdirectories, using several different formats. Some of them are not ideal +for reading directly in your browser. + +If you would rather see the rendered version of the documentation, check out the +curl website's [documentation section](https://curl.se/docs/) for +general curl stuff or the [libcurl section](https://curl.se/libcurl/) for +libcurl related documentation. diff --git a/docs/RELEASE-PROCEDURE.md b/docs/RELEASE-PROCEDURE.md new file mode 100644 index 0000000..0ce02fb --- /dev/null +++ b/docs/RELEASE-PROCEDURE.md @@ -0,0 +1,117 @@ +curl release procedure - how to do a release +============================================ + +in the source code repo +----------------------- + +- run `./scripts/copyright.pl` and correct possible omissions + +- edit `RELEASE-NOTES` to be accurate + +- update `docs/THANKS` + +- make sure all relevant changes are committed on the master branch + +- tag the git repo in this style: `git tag -a curl-7_34_0`. -a annotates the + tag and we use underscores instead of dots in the version number. Make sure + the tag is GPG signed (using -s). + +- run `./maketgz 7.34.0` to build the release tarballs. It is important that + you run this on a machine with the correct set of autotools etc installed + as this is what then will be shipped and used by most users on \*nix like + systems. + +- push the git commits and the new tag + +- GPG sign the 4 tarballs as `maketgz` suggests + +- upload the 8 resulting files to the primary download directory + +in the curl-www repo +-------------------- + +- edit `Makefile` (version number and date), + +- edit `_newslog.html` (announce the new release) and + +- edit `_changes.html` (insert changes+bugfixes from RELEASE-NOTES) + +- commit all local changes + +- tag the repo with the same name as used for the source repo. + +- make sure all relevant changes are committed and pushed on the master branch + + (the website then updates its contents automatically) + +on GitHub +--------- + +- edit the newly made release tag so that it is listed as the latest release + +inform +------ + +- send an email to curl-users, curl-announce and curl-library. Insert the + RELEASE-NOTES into the mail. + +celebrate +--------- + +- suitable beverage intake is encouraged for the festivities + +curl release scheduling +======================= + +Release Cycle +------------- + +We normally do releases every 8 weeks on Wednesdays. If important problems +arise, we can insert releases outside the schedule or we can move the release +date. + +Each 8 week (56 days) release cycle is divided into three distinct periods: + +- During the first 10 calendar days after a release, we are in "cool down". We + do not merge features but only bug-fixes. If a regression is reported, we + might do a follow-up patch release. + +- During the following 3 weeks (21 days) there is a feature window: we allow + new features and changes to curl and libcurl. If we accept any such changes, + we bump the minor number used for the next release. + +- During the next 25 days we are in feature freeze. We do not merge any + features or changes, and we only focus on fixing bugs and polishing things + to make the pending release a solid one. + +If a future release date happens to end up on a "bad date", like in the middle +of common public holidays or when the lead release manager is unavailable, the +release date can be moved forwards or backwards a full week. This is then +advertised well in advance. + +Critical problems +----------------- + +We can break the release cycle and do a patch release at any point if a +critical enough problem is reported. There is no exact definition of how to +assess such criticality, but if an issue is highly disturbing or has a +security impact on a large enough share of the user population it might +qualify. + +If you think an issue qualifies, bring it to the curl-library mailing list and +push for it. + +Coming dates +------------ + +Based on the description above, here are some planned release dates (at the +time of this writing): + +- October 11, 2023 +- December 6, 2023 +- January 31, 2024 +- March 27, 2024 +- May 22, 2024 +- July 17, 2024 +- September 11, 2024 +- November 6, 2024 diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..4642938 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,24 @@ +# curl the next few years - perhaps + +Roadmap of things Daniel Stenberg wants to work on next. It is intended to +serve as a guideline for others for information, feedback and possible +participation. + +## "Complete" the HTTP/3 support + +curl has experimental support for HTTP/3 since a good while back. There are +some functionality missing and once the final specs are published we want to +eventually remove the "experimental" label from this functionality. + +## HTTPS DNS records + +As a DNS version of alt-svc and also a pre-requisite for ECH (see below). + +See: https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-02 + +## ECH (Encrypted Client Hello - formerly known as ESNI) + + See Daniel's post on [Support of Encrypted + SNI](https://curl.se/mail/lib-2019-03/0000.html) on the mailing list. + + Initial work exists in [PR 4011](https://github.com/curl/curl/pull/4011) diff --git a/docs/RUSTLS.md b/docs/RUSTLS.md new file mode 100644 index 0000000..7a0d806 --- /dev/null +++ b/docs/RUSTLS.md @@ -0,0 +1,26 @@ +# Rustls + +[Rustls is a TLS backend written in Rust](https://docs.rs/rustls/). Curl can +be built to use it as an alternative to OpenSSL or other TLS backends. We use +the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi/). This +version of curl depends on version v0.10.0 of rustls-ffi. + +# Building with rustls + +First, [install Rust](https://rustup.rs/). + +Next, check out, build, and install the appropriate version of rustls-ffi: + + % cargo install cbindgen + % git clone https://github.com/rustls/rustls-ffi -b v0.10.0 + % cd rustls-ffi + % make + % make DESTDIR=${HOME}/rustls-ffi-built/ install + +Now configure and build curl with rustls: + + % git clone https://github.com/curl/curl + % cd curl + % autoreconf -fi + % ./configure --with-rustls=${HOME}/rustls-ffi-built + % make diff --git a/docs/SECURITY-ADVISORY.md b/docs/SECURITY-ADVISORY.md new file mode 100644 index 0000000..6344d22 --- /dev/null +++ b/docs/SECURITY-ADVISORY.md @@ -0,0 +1,129 @@ +# Anatomy of a curl security advisory + +As described in the [Security Process](https://curl.se/dev/secprocess.html) +document, when a security vulnerability has been reported to the project and +confirmed, we author an advisory document for the issue. It should ideally +be written in cooperation with the reporter to make sure all the angles and +details of the problem are gathered and described correctly and succinctly. + +## New document + +A security advisory for curl is created in the `docs/` folder in the +[curl-www](https://github.com/curl/curl-www) repository. It should be named +`$CVEID.md` where `$CVEID` is the full CVE Id that has been registered for the +flaw. Like `CVE-2016-0755`. The `.md` extension of course means that the +document is written using markdown. + +The standard way to go about this is to first write the `VULNERABILITY` +section for the document, so that there is description of the flaw available, +then paste this description into the CVE Id request. + +### `vuln.pm` + +The new issue should be entered at the top of the list in the file `vuln.pm` +in the same directory. It holds a large array with all published curl +vulnerabilities. All fields should be filled in accordingly, separated by a +pipe character (`|`). + +The eleven fields for each CVE in `vuln.pm` are, in order: + + HTML page name, first vulnerable version, last vulnerable version, name of + the issue, CVE Id, announce date (`YYYYMMDD`), report to the project date + (`YYYYMMDD`), CWE, awarded reward amount (USD), area (single word), C-issue + (`-` if not a C issue at all, `OVERFLOW` , `OVERREAD`, `DOUBLE_FREE`, + `USE_AFTER_FREE`, `NULL_MISTAKE`, `UNINIT`) + +### `Makefile` + +The new CVE webpage filename needs to be added in the `Makefile`'s `CVELIST` +macro. + +When the markdown is in place and the `Makefile` and `vuln.pm` are updated, +all other files and metadata for all curl advisories and versions get +generated automatically using those files. + +## Document format + +The easy way is to start with a recent previously published advisory and just +blank out old texts and save it using a new name. Save the subtitles and +general layout. + +Some details and metadata will be extracted from this document so it is +important to stick to the existing format. + +The first list must be the title of the issue. + +### VULNERABILITY + +The first subtitle should be `VULNERABILITY`. That should then include a +through and detailed description of the flaw. Including how it can be +triggered and maybe something about what might happen if triggered or +exploited. + +### INFO + +The next section is `INFO` which adds meta data information about the flaw. It +specifically mentions the official CVE Id for the issue and it must list the +CWE Id, starting on its own line. We write CWE identifiers in advisories with +the full (official) explanation on the right side of a colon. Like this: + +`CWE-305: Authentication Bypass by Primary Weakness` + +### AFFECTED VERSIONS + +The third section first lists what versions that are affected, then adds +clarity by stressing what versions that are *not* affected. A third line adds +information about which specific git commit that introduced the vulnerability. + +The `Introduced-in` commit should be a full URL that displays the commit, but +should work as a stand-alone commit hash if everything up to the last slash is +cut out. + +An example using the correct syntax: + +~~~ +- Affected versions: curl 7.16.1 to and including 7.88.1 +- Not affected versions: curl < 7.16.1 and curl >= 8.0.0 +- Introduced-in: https://github.com/curl/curl/commit/2147284cad +~~~ + +### THE SOLUTION + +This section describes and discusses the fix. The only mandatory information +here is the link to the git commit that fixes the problem. + +The `Fixed-in` value should be a full URL that displays the commit, but should +work as a stand-alone commit hash if everything up to the last slash is cut +out. + +Example: + +`- Fixed-in: https://github.com/curl/curl/commit/af369db4d3833272b8ed` + +### RECOMMENDATIONS + +This section lists the recommended actions for the users in a top to bottom +priority order and should ideally contain three items but no less than two. + +The top two are almost always `upgrade curl to version XXX` and `apply the +patch to your local version`. + +### TIMELINE + +Detail when this report was received in the project. When package distributors +were notified (via the distros mailing list or similar) + +When the advisory and fixed version are released. + +### CREDITS + +Mention the reporter and patch author at least, then everyone else involved +you think deserves a mention. + +If you want to mention more than one name, separate the names with comma +(`,`). + +~~~ +- Reported-by: Full Name +- Patched-by: Full Name +~~~ diff --git a/docs/SSL-PROBLEMS.md b/docs/SSL-PROBLEMS.md new file mode 100644 index 0000000..afe4250 --- /dev/null +++ b/docs/SSL-PROBLEMS.md @@ -0,0 +1,97 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + +# SSL problems + + First, let's establish that we often refer to TLS and SSL interchangeably as + SSL here. The current protocol is called TLS, it was called SSL a long time + ago. + + There are several known reasons why a connection that involves SSL might + fail. This is a document that attempts to detail the most common ones and + how to mitigate them. + +## CA certs + + CA certs are used to digitally verify the server's certificate. You need a + "ca bundle" for this. See lots of more details on this in the `SSLCERTS` + document. + +## CA bundle missing intermediate certificates + + When using said CA bundle to verify a server cert, you will experience + problems if your CA store does not contain the certificates for the + intermediates if the server does not provide them. + + The TLS protocol mandates that the intermediate certificates are sent in the + handshake, but as browsers have ways to survive or work around such + omissions, missing intermediates in TLS handshakes still happen that + browser-users will not notice. + + Browsers work around this problem in two ways: they cache intermediate + certificates from previous transfers and some implement the TLS "AIA" + extension that lets the client explicitly download such certificates on + demand. + +## Protocol version + + Some broken servers fail to support the protocol negotiation properly that + SSL servers are supposed to handle. This may cause the connection to fail + completely. Sometimes you may need to explicitly select a SSL version to use + when connecting to make the connection succeed. + + An additional complication can be that modern SSL libraries sometimes are + built with support for older SSL and TLS versions disabled! + + All versions of SSL and the TLS versions before 1.2 are considered insecure + and should be avoided. Use TLS 1.2 or later. + +## Ciphers + + Clients give servers a list of ciphers to select from. If the list does not + include any ciphers the server wants/can use, the connection handshake + fails. + + curl has recently disabled the user of a whole bunch of seriously insecure + ciphers from its default set (slightly depending on SSL backend in use). + + You may have to explicitly provide an alternative list of ciphers for curl + to use to allow the server to use a weak cipher for you. + + Note that these weak ciphers are identified as flawed. For example, this + includes symmetric ciphers with less than 128 bit keys and RC4. + + Schannel in Windows XP is not able to connect to servers that no longer + support the legacy handshakes and algorithms used by those versions, so we + advise against building curl to use Schannel on really old Windows versions. + + Reference: [Prohibiting RC4 Cipher + Suites](https://datatracker.ietf.org/doc/html/draft-popov-tls-prohibiting-rc4-01) + +## Allow BEAST + + BEAST is the name of a TLS 1.0 attack that surfaced 2011. When adding means + to mitigate this attack, it turned out that some broken servers out there in + the wild did not work properly with the BEAST mitigation in place. + + To make such broken servers work, the --ssl-allow-beast option was + introduced. Exactly as it sounds, it re-introduces the BEAST vulnerability + but on the other hand it allows curl to connect to that kind of strange + servers. + +## Disabling certificate revocation checks + + Some SSL backends may do certificate revocation checks (CRL, OCSP, etc) + depending on the OS or build configuration. The --ssl-no-revoke option was + introduced in 7.44.0 to disable revocation checking but currently is only + supported for Schannel (the native Windows SSL library), with an exception + in the case of Windows' Untrusted Publishers block list which it seems cannot + be bypassed. This option may have broader support to accommodate other SSL + backends in the future. + + References: + + https://curl.se/docs/ssl-compared.html diff --git a/docs/SSLCERTS.md b/docs/SSLCERTS.md new file mode 100644 index 0000000..7087e1e --- /dev/null +++ b/docs/SSLCERTS.md @@ -0,0 +1,155 @@ +SSL Certificate Verification +============================ + +SSL is TLS +---------- + +SSL is the old name. It is called TLS these days. + +Native SSL +---------- + +If libcurl was built with Schannel or Secure Transport support (the native SSL +libraries included in Windows and Mac OS X), then this does not apply to +you. Scroll down for details on how the OS-native engines handle SSL +certificates. If you are not sure, then run "curl -V" and read the results. If +the version string says `Schannel` in it, then it was built with Schannel +support. + +It is about trust +----------------- + +This system is about trust. In your local CA certificate store you have certs +from *trusted* Certificate Authorities that you then can use to verify that +the server certificates you see are valid. They are signed by one of the +certificate authorities you trust. + +Which certificate authorities do you trust? You can decide to trust the same +set of companies your operating system trusts, or the set one of the known +browsers trust. That is basically trust via someone else you trust. You should +just be aware that modern operating systems and browsers are setup to trust +*hundreds* of companies and in recent years several certificate authorities +have been found untrustworthy. + +Certificate Verification +------------------------ + +libcurl performs peer SSL certificate verification by default. This is done +by using a CA certificate store that the SSL library can use to make sure the +peer's server certificate is valid. + +If you communicate with HTTPS, FTPS or other TLS-using servers using +certificates in the CA store, you can be sure that the remote server really is +the one it claims to be. + +If the remote server uses a self-signed certificate, if you do not install a CA +cert store, if the server uses a certificate signed by a CA that is not +included in the store you use or if the remote host is an impostor +impersonating your favorite site, and you want to transfer files from this +server, do one of the following: + + 1. Tell libcurl to *not* verify the peer. With libcurl you disable this with + `curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);` + + With the curl command line tool, you disable this with `-k`/`--insecure`. + + 2. Get a CA certificate that can verify the remote server and use the proper + option to point out this CA cert for verification when connecting. For + libcurl hackers: `curl_easy_setopt(curl, CURLOPT_CAINFO, cacert);` + + With the curl command line tool: `--cacert [file]` + + 3. Add the CA cert for your server to the existing default CA certificate + store. The default CA certificate store can be changed at compile time with + the following configure options: + + `--with-ca-bundle=FILE`: use the specified file as the CA certificate + store. CA certificates need to be concatenated in PEM format into this + file. + + `--with-ca-path=PATH`: use the specified path as CA certificate store. CA + certificates need to be stored as individual PEM files in this directory. + You may need to run c_rehash after adding files there. + + If neither of the two options is specified, configure will try to + auto-detect a setting. It's also possible to explicitly not set any + default store but rely on the built in default the crypto library may + provide instead. You can achieve that by passing both + `--without-ca-bundle` and `--without-ca-path` to the configure script. + + If you use Internet Explorer, this is one way to get extract the CA cert + for a particular server: + + - View the certificate by double-clicking the padlock + - Find out where the CA certificate is kept (Certificate> + Authority Information Access>URL) + - Get a copy of the crt file using curl + - Convert it from crt to PEM using the OpenSSL tool: + `openssl x509 -inform DES -in yourdownloaded.crt -out outcert.pem -text` + - Add the `outcert.pem` to the CA certificate store or use it stand-alone + as described below. + + If you use the `openssl` tool, this is one way to get extract the CA cert + for a particular server: + + - `openssl s_client -showcerts -servername server -connect server:443 > cacert.pem` + - type "quit", followed by the "ENTER" key + - The certificate will have "BEGIN CERTIFICATE" and "END CERTIFICATE" + markers. + - If you want to see the data in the certificate, you can do: `openssl + x509 -inform PEM -in certfile -text -out certdata` where `certfile` is + the cert you extracted from logfile. Look in `certdata`. + - If you want to trust the certificate, you can add it to your CA + certificate store or use it stand-alone as described. Just remember that + the security is no better than the way you obtained the certificate. + + 4. If you are using the curl command line tool and the TLS backend is not + Schannel then you can specify your own CA cert file by setting the + environment variable `CURL_CA_BUNDLE` to the path of your choice. + + If you are using the curl command line tool on Windows, curl will search + for a CA cert file named "curl-ca-bundle.crt" in these directories and in + this order: + 1. application's directory + 2. current working directory + 3. Windows System directory (e.g. C:\windows\system32) + 4. Windows Directory (e.g. C:\windows) + 5. all directories along %PATH% + + 5. Get another CA cert bundle. One option is to extract the one a recent + Firefox browser uses by running 'make ca-bundle' in the curl build tree + root, or possibly download a version that was generated this way for you: + [CA Extract](https://curl.se/docs/caextract.html) + +Neglecting to use one of the above methods when dealing with a server using a +certificate that is not signed by one of the certificates in the installed CA +certificate store, will cause SSL to report an error ("certificate verify +failed") during the handshake and SSL will then refuse further communication +with that server. + +Certificate Verification with Schannel and Secure Transport +----------------------------------------------------------- + +If libcurl was built with Schannel (Microsoft's native TLS engine) or Secure +Transport (Apple's native TLS engine) support, then libcurl will still perform +peer certificate verification, but instead of using a CA cert bundle, it will +use the certificates that are built into the OS. These are the same +certificates that appear in the Internet Options control panel (under Windows) +or Keychain Access application (under OS X). Any custom security rules for +certificates will be honored. + +Schannel will run CRL checks on certificates unless peer verification is +disabled. Secure Transport on iOS will run OCSP checks on certificates unless +peer verification is disabled. Secure Transport on OS X will run either OCSP +or CRL checks on certificates if those features are enabled, and this behavior +can be adjusted in the preferences of Keychain Access. + +HTTPS proxy +----------- + +Since version 7.52.0, curl can do HTTPS to the proxy separately from the +connection to the server. This TLS connection is handled separately from the +server connection so instead of `--insecure` and `--cacert` to control the +certificate verification, you use `--proxy-insecure` and `--proxy-cacert`. +With these options, you make sure that the TLS connection and the trust of the +proxy can be kept totally separate from the TLS connection to the server. diff --git a/docs/THANKS b/docs/THANKS new file mode 100644 index 0000000..eee2ec5 --- /dev/null +++ b/docs/THANKS @@ -0,0 +1,3083 @@ + This project has been alive for many years. Countless people have provided + feedback that have improved curl. Here follows a list of people that have + contributed (a-z order). + + If you have contributed but are missing here, please let us know! + +0xee on github +0xflotus on github +12932 on github +1337vt on github +1ocalhost on github +3dyd on github +3eka on github +8U61ife on github +a1346054 on github +Aaro Koskinen +Aaron Oneal +Aaron Orenstein +Aaron Scarisbrick +aasivov on github +Abhinav Singh +Abram Pousada +accountantM on github +AceCrow on Github +ad0p on github +Adam Averay +Adam Barclay +Adam Brown +Adam Coyne +Adam D. Moss +Adam Langley +Adam Light +Adam Marcionek +Adam Piggott +Adam Rosenfield +Adam Sampson +Adam Tkac +Adnan Khan +adnn on github +Adrian Burcea +Adrian Peniak +Adrian Schuur +Adriano Meirelles +afrind on github +Aftab Alam +ahodesuka on github +ajak in #curl +Ajit Dhumale +Akhil Kedia +Aki Koskinen +Akos Pasztory +Akshay Vernekar +Alain Danteny +Alain Miniussi +Alan Jenkins +Alan Pinstein +Albert Chin-A-Young +Albert Choy +Albin Vass +Alejandro Alvarez Ayllon +Alejandro Colomar +Alejandro R. Sedeño +Aleksandar Milivojevic +Aleksander Mazur +Aleksandr Krotov +Aleksey Tulinov +Ales Mlakar +Ales Novak +Alessandro Ghedini +Alessandro Vesely +Alex aka WindEagle +Alex Baines +Alex Bligh +Alex Bozarth +Alex Chan +Alex Crichton +Alex Fishman +Alex Gaynor +Alex Grebenschikov +Alex Gruz +Alex Kiernan +Alex Klyubin +Alex Konev +Alex Malinovich +Alex Mayorga +Alex McLellan +Alex Neblett +Alex Nichols +Alex Potapenko +Alex Rousskov +Alex Samorukov +Alex Suykov +Alex Vinnik +Alex Xu +Alexander Bartel +Alexander Beedie +Alexander Chuykov +Alexander Dyagilev +Alexander Elgert +Alexander Jaeger +Alexander Kanavin +Alexander Klauer +Alexander Kourakos +Alexander Krasnostavsky +Alexander Lazic +Alexander Pepper +Alexander Peslyak +Alexander Sinditskiy +Alexander Traud +Alexander V. Tikhonov +Alexander Zhuravlev +Alexandre Bury +Alexandre Ferrieux +Alexandre Pion +Alexey Borzov +Alexey Eremikhin +Alexey Larikov +Alexey Melnichuk +Alexey Pesternikov +Alexey Savchuk +Alexey Simak +Alexey Zakhlestin +Alexis Carvalho +Alexis La Goutte +Alexis Vachette +Alfonso Martone +Alfred Gebert +Ali Khodkar +Ali Utku Selen +ALittleDruid on github +Allen Pulsifer +Alois Klink +Alona Rossen +Amaury Denoyelle +amishmm on github +Amit Katyal +Ammar Faizi +Amol Pattekar +Amr Shahin +Anatol Belski +Anatoli Tubman +Anders Bakken +Anders Berg +Anders Gustafsson +Anders Havn +Anders Roxell +Anderson Sasaki +Anderson Toshiyuki Sasaki +Andi Jahja +Andre Guibert de Bruet +Andre Heinecke +Andrea Pappacoda +Andreas Damm +Andreas Falkenhahn +Andreas Farber +Andreas Fischer +Andreas Huebner +Andreas Kostyrka +Andreas Malzahn +Andreas Ntaflos +Andreas Olsson +Andreas Rieke +Andreas Roth +Andreas Schneider +Andreas Schuldei +Andreas Sommer +Andreas Streichardt +Andreas Wurf +Andrei Benea +Andrei Bica +Andrei Cipu +Andrei Karas +Andrei Kurushin +Andrei Neculau +Andrei Rybak +Andrei Sedoi +Andrei Valeriu BICA +Andrei Virtosu +Andrej E Baranov +Andrew Barnert +Andrew Barnes +Andrew Benham +Andrew Biggs +Andrew Bushnell +Andrew de los Reyes +Andrew Francis +Andrew Fuller +Andrew Ishchuk +Andrew Krieger +Andrew Kurushin +Andrew Lambert +Andrew Moise +Andrew Potter +Andrew Robbins +Andrew Wansink +Andrey Alifanov +Andrey Gursky +Andrey Labunets +Andrii Moiseiev +Andrius Merkys +Andrés García +Andy Alt +Andy Cedilnik +Andy Fiddaman +Andy Serpa +Andy Stamp +Andy Tsouladze +Angus Mackay +anio on github +annalee +anon00000000 on github +anshnd on github +Anssi Kolehmainen +Antarpreet Singh +Anthon Pang +Anthony Avina +Anthony Bryan +Anthony G. Basile +Anthony Hu +Anthony Ramine +Anthony Shaw +Antoine Aubert +Antoine Calando +Antoine du Hamel +Antoine Pietri +Antoine Pitrou +Anton Bychkov +Anton Gerasimov +Anton Kalmykov +Anton Malov +Anton Yabchinskiy +Antoni Villalonga +Antonio Larrosa +Antony74 on github +Antti Hätälä +Anubhav Rai +apparentorder on github +April King +arainchik on github +Archangel_SDY on github +Arkadiusz Miskiewicz +Armel Asselin +Arnaud Compan +Arnaud Ebalard +Arnaud Rebillout +Arne Soete +Aron Bergman +Aron Rotteveel +Artak Galoyan +Arthur Murray +Artur Sinila +Arve Knudsen +Arvid Norberg +arvids-kokins-bidstack on github +asavah on github +Ashish Shukla +Ashwin Metpalli +Ask Bjørn Hansen +Askar Safin +AtariDreams on github +Ates Goral +atjg on github +Augustus Saunders +Austin Green +Avery Fay +awesomenode on github +Axel Chong +Axel Morawietz +Axel Tillequin +Ayesh Karunaratne +Ayoub Boudhar +Ayushman Singh Chauhan +b9a1 on github +Bachue Zhou +Baitinq on github +Balaji Parasuram +Balaji S Rao +Balaji Salunke +Balakrishnan Balasubramanian +Balazs Kovacsics +balikalina on Github +Balint Szilakszi +Barry Abrahamson +Barry Pollard +Bart Whiteley +Baruch Siach +Bas Mevissen +Bas van Schaik +Bastian Krause +Bastien Bouclet +Basuke Suzuki +baumanj on github +bdry on github +beckenc on github +Ben +Ben Boeckel +Ben Darnell +Ben Fritz +Ben Greear +Ben Kohler +Ben Madsen +Ben Noordhuis +Ben Van Hof +Ben Voris +Ben Winslow +Benau on github +Benbuck Nason +Benjamin Gerard +Benjamin Gilbert +Benjamin Johnson +Benjamin Kircher +Benjamin Loison +Benjamin Riefenstahl +Benjamin Ritcey +Benjamin Sergeant +Benoit Neil +Benoit Pierre +Benoit Sigoure +Bernard Leak +Bernard Spil +Bernat Mut +Bernd Mueller +Bernhard Iselborn +Bernhard M. Wiedemann +Bernhard Reutner-Fischer +Bernhard Walle +Bert Huijben +Bertrand Demiddelaer +Bertrand Simonnet +beslick5 on github +Bevan Weiss +Bill Doyle +Bill Egert +Bill Hoffman +Bill Middlecamp +Bill Nagel +Bill Pyne +billionai on github +Billyzou0741326 on github +Bin Lan +Bin Meng +Biswapriyo Nath +Bjarni Ingi Gislason +Bjoern Franke +Bjoern Sikora +Bjorn Augustsson +Bjorn Reese +Björn Stenberg +black-desk on github +Blaise Potard +Blake Burkhart +bnfp on github +Bo Anderson +Bob Relyea +Bob Richmond +Bob Schader +bobmitchell1956 on github +Bodo Bergmann +Bogdan Nicula +boilingoden +Boris Kuschel +Boris Okunskiy +Boris Rasin +Boris Verkhovskiy +Brad Burdick +Brad Fitzpatrick +Brad Forschinger +Brad Harder +Brad Hards +Brad King +Brad Spencer +Bradford Bruce +bramus on github +Brandon Casey +Brandon Dong +Brandon Wang +BratSinot on github +Brendan Jurd +Brennan Kinney +Brent Beardsley +Brian Akins +Brian Bergeron +Brian Carpenter +Brian Chaplin +Brian Childs +Brian Chrisman +Brian Dessent +Brian E. Gallew +Brian Green +Brian Inglis +Brian J. Murrell +Brian Lund +Brian Nixon +Brian Prodoehl +Brian R Duffy +Brian Ulm +Brock Noland +Bru Rom +Bruce Mitchener +Bruce Stephens +BrumBrum on hackerone +Bruno Baguette +Bruno de Carvalho +Bruno Grasselli +Bruno Henrique Batista Cruz da Silva +Bruno Thomsen +Bryan Henderson +Bryan Kemp +bsammon on github +bsergean on github +bubbleguuum on github +Bubu on github +buzo-ffm on github +bxac on github +Bylon2 on github +Byrial Jensen +Cajus Pollmeier +Caleb Raitto +Calvin Buckley +calvin2021y on github +Cameron Blomquist +Cameron Cawley +Cameron Kaiser +Cameron MacMinn +Cameron Will +Camille Moncelier +Cao ZhenXiang +Caolan McNamara +Captain Basil +Carie Pointer +Carl Zogheib +Carlo Alberto +Carlo Cannas +Carlo Marcelo Arenas Belón +Carlo Teubner +Carlo Wood +Carlos Henrique Lima Melara +Carlos ORyan +Carsten Lange +Casey Bodley +Casey O'Donnell +Catalin Patulea +causal-agent on github +cbartl on github +cclauss on github +Cering on github +Cesar Eduardo Barros +Chad Monroe +Chandrakant Bagul +Chara White +Charles Cazabon +Charles Kerr +Charles Romestant +Charlie C +Chen Prog +Cherish98 on github +Chester Liu +Chih-Chung Chang +Chih-Hsuan Yen +Chilledheart on github +Chloe Kudryavtsev +Chris "Bob Bob" +Chris Araman +Chris Carlmar +Chris Combes +Chris Conlon +Chris Deidun +Chris Faherty +Chris Flerackers +Chris Gaukroger +Chris Maltby +Chris Mumford +Chris Paulson-Ellis +Chris Roberts +Chris Sauer +Chris Smowton +Chris Talbot +Chris Young +Christian Fillion +Christian Grothoff +Christian Heimes +Christian Hesse +Christian Hägele +Christian Krause +Christian Kurz +Christian Robottom Reis +Christian Schmitz +Christian Stewart +Christian Vogt +Christian Weisgerber +Christoph Krey +Christoph M. Becker +Christoph Reiter +Christophe Demory +Christophe Dervieux +Christophe Legry +Christopher Conroy +Christopher Degawa +Christopher Head +Christopher Palow +Christopher R. Palmer +Christopher Reid +Christopher Sauer +Christopher Stone +Chungtsun Li +Ciprian Badescu +civodul on github +Claes Jakobsson +Clarence Gardner +Claudio Neves +claudiusaiz on github +clbr on github +Clemens Gruber +Cliff Crosland +Clifford Wolf +Clint Clayton +Cloudogu Siebels +Clément Notin +cmfrolick on github +codesniffer13 on github +Cody Jones +Cody Mack +COFFEETALES on github +coinhubs on github +Colby Ranger +Colin Blair +Colin Cross +Colin Hogben +Colin Leroy +Colin O'Dell +Colin Watson +Colm Buckley +Colman Mbuya +Constantine Sapuntzakis +consulion on github +coralw on github +correctmost on github +Cory Benfield +Cory Nelson +Costya Shulyupin +Craig A West +Craig Andrews +Craig Davison +Craig de Stigter +Craig Markwardt +crazydef on github +Cris Bailiff +Cristian Greco +Cristian Morales Vega +Cristian Rodríguez +Curt Bogmine +Cynthia Coan +Cyril B +Cyrill Osterwalder +Cédric Connes +Cédric Deltheil +D. Flinkmann +d4d on hackerone +d912e3 on github +Da-Yoon Chung +daboul on github +Dag Ekengren +Dagobert Michelsen +Daiki Ueno +Dair Grant +Dambaev Alexander +Damian Dixon +Damien Adant +Damien Vielpeau +Damien Walsh +Dan Becker +Dan Cristian +Dan Donahue +Dan Fandrich +Dan Johnson +Dan Kenigsberg +Dan Locks +Dan McNulty +Dan Nelson +Dan Petitt +Dan Torop +Dan Zitter +Daniel at touchtunes +Daniel Bankhead +Daniel Black +Daniel Carpenter +Daniel Cater +Daniel Egger +Daniel Faust +Daniel Gustafsson +Daniel Hallberg +Daniel Hwang +Daniel JeliÅ„ski +Daniel Johnson +Daniel Kahn Gillmor +Daniel Katz +Daniel Krügler +Daniel KureÄka +Daniel Lee Hwang +Daniel Lublin +Daniel Marjamäki +Daniel Melani +Daniel Mentz +Daniel Romero +Daniel Schauenberg +Daniel Seither +Daniel Shahaf +Daniel Silverstone +Daniel Steinberg +Daniel Stenberg +Daniel Theron +Daniel Valenzuela +Daniel Woelfel +Daphne Luong +Dario Nieuwenhuis +Dario Weißer +Darryl House +Darshan Mody +Darío Hereñú +dasimx on github +Dave Cottlehuber +Dave Dribin +Dave Halbakken +Dave Hamilton +Dave May +Dave Reisner +Dave Thompson +Dave Vasilevsky +Davey Shafik +David Bau +David Benjamin +David Binderman +David Blaikie +David Bohman +David Byron +David Carlier +David Cohen +David Cook +David Demelier +David E. Narváez +David Earl +David Eriksson +David Garske +David Goerger +David Houlder +David Hu +David Hull +David J Meyer +David James +David Kalnischkies +David Kierznowski +David Kimdon +David L. +David Lang +David LeBlanc +David Lopes +David Lord +David McCreedy +David McLaughlin +David Odin +David Phillips +David Rosenstrauch +David Ryskalczyk +David Sanderson +David Schweikert +David Shaw +David Strauss +David Suter +David Tarendash +David Thiel +David Walser +David Woodhouse +David Wright +David Yan +Davide Cassioli +Davide Masserut +davidedec on github +dbrowndan on github +dEajL3kA on github +Deal(一线çµ) +dekerser on github +dengjfzh on github +Dengminwen +Denis BaruÄić +Denis Chaplygin +Denis Feklushkin +Denis Goleshchikhin +Denis Laxalde +Denis Ollier +Dennis Clarke +Dennis Felsing +dependabot[bot] +Derek Higgins +Derzsi Dániel +Desmond O. Chang +destman on github +Detlef Schmier +Dheeraj Sangamkar +Didier Brisebourg +Diego Bes +Diego Casorran +Dietmar Hauser +Dilyan Palauzov +Dima Barsky +Dima Pasechnik +Dima Tisnek +Dimitar Boevski +Dimitre Dimitrov +Dimitrios Apostolou +Dimitrios Siganos +Dimitris Sarris +Dinar +Diogo Teles Sant'Anna +Dion Williams +Dirk Eddelbuettel +Dirk Feytons +Dirk Manske +Dirk Rosenkranz +Dirk Wetter +Dirkjan Bussink +Diven Qi +divinity76 on github +Divy Le Ray +dkjjr89 on github +dkwolfe4 on github +Dmitri Shubin +Dmitri Tikhonov +Dmitriy Sergeyev +dmitrmax on github +Dmitry Atamanov +Dmitry Bartsevich +Dmitry Eremin-Solenikov +Dmitry Falko +Dmitry Karpov +Dmitry Kostjuchenko +Dmitry Kurochkin +Dmitry Mikhirev +Dmitry Popov +Dmitry Rechkin +Dmitry S. Baikov +Dmitry Wagin +dnivras on github +Dolbneff A.V +Domen Kožar +Domenico Andreoli +Dominick Meglio +Dominik Hölzl +Dominik Klemba +Dominik Thalhammer +Dominique Leuenberger +Don J Olmstead +Dongliang Mu +Doron Behar +Doug Kaufman +Doug Porter +Douglas Creager +Douglas E. Wegscheid +Douglas Kilpatrick +Douglas Mencken +Douglas R. Horner +Douglas R. Reno +Douglas Steinwand +Dov Murik +dpull on github +Drake Arconis +dtmsecurity on github +Duane Cathey +Duncan Mac-Vicar Prett +Duncan Wilcox +Dustin Boswell +Dustin Howett +Dusty Mabe +Duy Phan Thanh +Dwarakanath Yadavalli +Dylan Anthony +Dylan Ellicott +Dylan Salisbury +Dániel Bakai +eaglegai on github +Early Ehlinger +Earnestly on github +Eason-Yu on github +Ebe Janchivdorj +ebejan on github +Ebenezer Ikonne +Ed Morley +ed0d2b2ce19451f2 +Eddie Lumpkin +Edgaras JanuÅ¡auskas +Edin Kadribasic +Edmond Yu +Edoardo Lolletti +Eduard Bloch +Eduard Strehlau +Edward Kimmel +Edward Rudd +Edward Sheldrake +Edward Thomson +Eelco Dolstra +Eetu Ojanen +eeverettrbx on github +Egon Eckert +Egor Pugin +Ehren Bendler +Eldar Zaitov +elelel on github +elephoenix on github +Eli Schwartz +Elia Tufarolo +Elliot Killick +Elliot Saba +Ellis Pritchard +Elmira A Semenova +Elms +Eloy Degen +elsamuko on github +emanruse on github +Emanuele Bovisio +Emanuele Torre +Emil Engler +Emil Lerner +Emil Romanus +Emil Österlund +Emiliano Ida +Emilio Cobos Ãlvarez +Emilio López +Emmanuel Tychon +Enno Boland +Enrico Scholz +Enrik Berkhan +enWILLYado on github +eppesuig +Eramoto Masaya +Eric Cooper +Eric Curtin +Eric Gallager +Eric Hu +Eric Landes +Eric Lavigne +Eric Lubin +Eric Melville +Eric Mertens +Eric Murphy +Eric Musser +Eric Rautman +Eric Rescorla +Eric Ridge +Eric Rosenquist +Eric S. Raymond +Eric Sauvageau +Eric Thelin +Eric Vergnaud +Eric Vigeant +Eric Wong +Eric Wu +Eric Young +Erick Nuwendam +Erik Jacobsen +Erik Janssen +Erik Johansson +Erik Minekus +Erik Olsson +Erik Stenlund +Ernest Beinrohr +Ernst Sjöstrand +Erwan Legrand +Erwin Authried +Esdras de Morais da Silva +Estanislau Augé-Pujadas +Ethan Glasser Camp +Etienne Simard +Eugene Kotlyarov +Evan Jordan +Evangelos Foutras +Even Rouault +Evert Pot +Evgeny Grin (Karlson2k) +Evgeny Turnaev +eXeC64 on github +Eygene Ryabinkin +Eylem Ugurel +Fabian Fischer +Fabian Frank +Fabian Hiernaux +Fabian Keil +Fabian Ruff +Fabian Yamaguchi +Fabrice Fontaine +Fabrizio Ammollo +Fahim Chandurwala +Faizur Rahman +Faraz Fallahi +Farzin on github +Fata Nugraha +Fawad Mirza +FC Stegerman +fds242 on github +Federico Bianchi +Federico Pellegrin +Fedor Karpelevitch +Fedor Korotkov +FeignClaims on github +Feist Josselin +Felipe Gasper +Felix Hädicke +Felix Kaiser +Felix von Leitner +Felix Yan +Feng Tu +Fernando Muñoz +Filip Lundgren +Filip Salomonsson +finkjsc on github +Firefox OS +Flameborn on github +Flavio Medeiros +Florian Kohnhäuser +Florian Pritz +Florian Schoppmann +Florian Van Heghe +Florian Weimer +Florin Petriuc +Forrest Cahoon +Francisco Moraes +Francisco Munoz +Francisco Olarte +Francisco Sedano +Francois Petitjean +Francois Rivard +Frank Denis +Frank Gevaerts +Frank Hempel +Frank Keeney +Frank McGeough +Frank Meier +Frank Ticheler +Frank Van Uffelen +FrantiÅ¡ek KuÄera +François Charlier +François Michel +François Rigault +Frazer Smith +Fred Machado +Fred New +Fred Noz +Fred Stluka +Frederic Lepied +Frederik B +Frederik Wedel-Heinen +Fredrik Thulin +FuccDucc on github +Fujii Hironori +fullincome on github +fundawang on github +Gabe +Gabriel Corona +Gabriel Kuri +Gabriel Simmer +Gabriel Sjoberg +Gambit Communications +Ganesh Kamath +gaoxingwang on github +Garrett Holmstrom +Garrett Squire +Gary Maxwell +Gaurav Malhotra +Gautam Kachroo +Gautam Mani +Gavin Wong +Gavrie Philipson +Gaz Iqbal +Gaël Portay +gclinch on github +Gealber Morales +Geeknik Labs +Geoff Beier +Georeth Zhou +Georg Horn +Georg Huettenegger +Georg Lippitsch +Georg Wicherski +George Liu +Gerd v. Egidy +Gergely Nagy +Gerhard Herre +Gerome Fournier +Gerrit Bruchhäuser +Gerrit Renker +Ghennadi Procopciuc +Giancarlo Formicuccia +Giaslas Georgios +Gil Weber +Gilad +Gilbert Ramirez Jr. +Gilles Blanc +Gilles Vollant +Giorgos Oikonomou +Gisle Vanem +git-bruh on github +GitYuanQu on github +Giuseppe Attardi +Giuseppe D'Ambrosio +Giuseppe Persico +Gleb Ivanovsky +Glen A Johnson Jr. +Glen Nakamura +Glen Scott +Glenn de boer +Glenn Sheridan +Glenn Strauss +godmar on github +Godwin Stewart +Google Inc. +Gordon Marler +Gorilla Maguila +Goro FUJI +Gou Lingfeng +Graham Campbell +Grant Erickson +Grant Pannell +Greg Hewgill +Greg Morse +Greg Onufer +Greg Pratt +Greg Rowe +Greg Zavertnik +Gregor Jasny +Gregory Jefferis +Gregory Muchka +Gregory Nicholls +Gregory Panakkal +Gregory Szorc +Griffin Downs +Grigory Entin +Grisha Levit +Guenole Bescon +Guido Berhoerster +Guillaume Algis +Guillaume Arluison +guitared on github +Gunamoi Software +Gunter Knauf +guoxinvmware on github +Gustaf Hui +Gustavo Grieco +Guy Poizat +GwanYeong Kim +Gwen Shapira +Gwenole Beauchesne +Gökhan Åžengün +Götz Babin-Ebell +h1zzz on github +H3RSKO on github +Hagai Auro +Haibo Huang +Hakan Sunay Halil +Hamish Mackenzie +hamstergene on github +Han Han +Han Qiao +Hang Kin Lau +Hang Su +Hannah Schierling +Hannes Magnusson +Hanno Böck +Hanno Kranzhoff +Hans Steegers +Hans-Christian Egtvedt +Hans-Christian Noren Egtvedt +Hans-Jurgen May +Hao Wu +Hardeep Singh +Haris Okanovic +Harold Stuart +Harry Mallon +Harry Sarson +Harry Sintonen +Harshal Pradhan +Hauke Duden +Haydar Alaidrus +Hayden Roche +He Qin +Heikki Korpela +Heinrich Ko +Heinrich Schaefer +Helge Klein +Helmut K. C. Tessarek +Helwing Lutz +Hendrik Visage +Henning Schild +Henri Gomez +Henrik Gaßmann +Henrik Holst +Henrik Storner +Henry Ludemann +Henry Roeland +Herve Amblard +HexTheDragon +hgdagon on github +Hide Ishikawa +Hidemoto Nakada +highmtworks on github +Himanshu Gupta +Hind Montassif +Hiroki Kurosawa +Hirotaka Tagawa +Ho-chi Chen +Hoi-Ho Chan +Hongli Lai +Hongyi Zhao +Howard Blaise +Howard Chu +hsiao yi +htasta on github +Hubert Kario +Hugh Macdonald +Hugo van Kemenade +humbleacolyte +Huzaifa Sidhpurwala +huzunhao on github +hydra3333 on github +Hzhijun +iammrtau on github +Ian Blanes +Ian D Allen +Ian Fette +Ian Ford +Ian Gulliver +Ian Lynagh +Ian Spence +Ian Turner +Ian Wilkes +iAroc on github +iconoclasthero +icy17 on github +Ignacio Vazquez-Abrams +Igor Franchuk +Igor Khristophorov +Igor Makarov +Igor Novoseltsev +Igor Polyakov +Igor Todorovski +Ihor Karpenko +ihsinme on github +Iida Yosiaki +Ikko Ashimine +Ilguiz Latypov +Ilja van Sprundel +Illarion Taev +illusory-dream on github +Ilmari Lauhakangas +Ilya Kosarev +imilli on github +Immanuel Gregoire +ImpatientHippo on GitHub +Inca R +infinnovation-dev on github +Ingmar Runge +Ingo Ralf Blum +Ingo Wilken +Inho Oh +IonuÈ›-Francisc Oancea +Irfan Adilovic +Ironbars13 on github +Irving Wolfe +Isaac Boukris +Isaiah Norton +Ishan SinghLevett +Ithubg on github +Ivan Avdeev +Ivan Tsybulin +ivanfywang +IvanoG on github +Ivo Bellin Salarin +iz8mbw on github +J. Bromley +Jack Boos Yu +Jack Zhang +Jackarain on github +JackBoosY on github +Jacky Lam +Jacob Barthelmeh +Jacob Hoffman-Andrews +Jacob Mealey +Jacob Meuser +Jacob Moshenko +Jacob Tolar +Jactry Zeng +Jad Chamcham +Jaime Fullaondo +jakirkham on github +Jakob Hirsch +Jakub Bochenski +Jakub Jelen +Jakub Wilk +Jakub Zakrzewski +James Atwill +James Brown +James Bursa +James Cheng +James Clancy +James Cone +James Dury +James Fuller +James Gallagher +James Griffiths +James Housley +James Keast +James Knight +James Le Cuirot +James Lucas +James MacMillan +James Slaughter +Jamie Lokier +Jamie Newton +Jamie Wilkinson +Jan Alexander Steffens +Jan Chren +Jan Ehrhardt +Jan Engelhardt +Jan Koen Annot +Jan Kunder +Jan Macku +Jan Mazur +Jan Schaumann +Jan Schmidt +Jan Van Boghout +Jan Venekamp +Jan Verbeek +Jan-Piet Mens +JanB on github +janko-js on github +Janne Blomqvist +Janne Johansson +Jared Jennings +Jared Lundell +Jari Aalto +Jari Sundell +jasal82 on github +Jason Baietto +Jason Glasgow +Jason Juang +Jason Lee +Jason Liu +Jason McDonald +Jason S. Priebe +Javier Barroso +Javier Blazquez +Javier G. Sogo +Javier Navarro +Javier Sixto +Jay Austin +Jay Dommaschk +Jay Wu +Jayesh A Shah +Jaz Fresh +JazJas on github +jbgoog on github +Jean Fabrice +Jean Gressmann +Jean Jacques Drouin +Jean-Claude Chauve +Jean-Francois Bertrand +Jean-Francois Durand +Jean-Louis Lemaire +Jean-Marc Ranger +Jean-Noël Rouvignac +Jean-Philippe Barrette-LaPierre +Jean-Philippe Menil +Jeff Connelly +Jeff Hodges +Jeff Johnson +Jeff King +Jeff Lawson +Jeff Luszcz +Jeff Mears +Jeff Phillips +Jeff Pohlmeyer +Jeff Weber +Jeffrey Tolar +Jeffrey Walton +jeffrson on github +Jelle van der Waa +Jenny Heino +Jens Finkhaeuser +Jens Rantil +Jens Schleusener +Jeremie Rapin +Jeremy Falcon +Jeremy Friesner +Jeremy Huddleston +Jeremy Lainé +Jeremy Lin +Jeremy Maitin-Shepard +Jeremy Pearson +Jeremy Tan +Jeremy Thibault +Jeroen Koekkoek +Jeroen Ooms +Jerome Mao +Jerome Muffat-Meridol +Jerome Robert +Jerome St-Louis +Jerome Vouillon +Jerry Krinock +Jerry Wu +Jes Badwal +Jesper Jensen +Jess Lowe +Jesse Chisholm +Jesse Noller +Jesse Tan +jethrogb on github +jhoyla on github +Jie He +Jiehong on github +Jilayne Lovejoy +Jim Beveridge +Jim Drash +Jim Freeman +Jim Fuller +Jim Hollinger +Jim King +Jim Meyering +Jimmy Gaussen +Jiri Dvorak +Jiri Hruska +Jiri Jaburek +Jishan Shaikh +Jiří Malák +jmdavitt on github +jnbr on github +Jocelyn Jaubert +Jochem Broekhoff +Joe Halpin +Joe Malicki +Joe Mason +Joel Chen +Joel Depooter +Joel Jakobsson +Joel Teichroeb +joey-l-us on github +Jofell Gallardo +Johan Anderson +Johan Lantz +Johan Nilsson +Johan van Selst +Johann150 on github +Johannes Bauer +Johannes Ernst +Johannes G. Kristinsson +Johannes Lesr +Johannes Schindelin +John A. Bristor +John Bampton +John Bradshaw +John Butterfield +John Coffey +John Crow +John David Anglin +John DeHelian +John Dennis +John Dunn +John E. Malmberg +John Gardiner Myers +John H. Ayad +John Hascall +John Haugabook +John Hawthorn +John Janssen +John Joseph Bachir +John Kelly +John Kohl +John Lask +John Levon +John Lightsey +John Marino +John Marshall +John McGowan +John P. McCaskey +John Porter +John Schroeder +John Sherrill +John Simpson +John Starks +John Suprock +John V. Chow +John Walker +John Wanghui +John Weismiller +John Wilkinson +John-Mark Bell +Johnny Luong +Jojojov on github +Jon DeVree +Jon Grubbs +Jon Johnson Jr +Jon Nelson +Jon Rumsey +Jon Sargeant +Jon Seymour +Jon Spencer +Jon Torrey +Jon Travis +Jon Turner +Jon Wilkes +Jonas Bülow +Jonas Forsman +Jonas Haag +Jonas Minnberg +Jonas Schnelli +Jonas Vautherin +Jonatan Lander +Jonatan Vela +Jonathan Cardoso Machado +Jonathan Hseu +Jonathan Moerman +Jonathan Nieder +Jonathan Watt +Jonathan Wernberg +Jongki Suwandi +jonny112 on github +Joombalaya on github +Joonas Kuorilehto +Jordan Brown +Jose Alf +Jose Kahan +Josef Wolf +Joseph Chen +Joseph Tharayil +Josh Bialkowski +Josh Brobst +Josh Kapell +Josh McCullough +Josh Soref +joshhe on github +Joshix-1 on github +Joshua Kwan +Joshua Root +Joshua Swink +Josie Huddleston +Josip Medved +Josue Andrade Gomes +José Joaquín Atria +Jozef Kralik +Juan Barreto +Juan Cruz Viotti +Juan F. Codagnone +Juan Ignacio Hervás +Juan RP +Judson Bishop +Juergen Hoetzel +Juergen Wilke +Jukka Pihl +Julian Montes +Julian Noble +Julian Ospald +Julian Romero Nieto +Julian Taylor +Julian Z +Julien Chaffraix +Julien Nabet +Julien Royer +Juliusz Sosinowicz +Jun Tseng +Jun-ichiro itojun Hagino +Jun-ya Kato +jungle-boogie on github +Junho Choi +junsik on github +Jurij Smakov +jurisuk on github +Juro Bystricky +JustAnotherArchivist on github +justchen1369 on github +Justin Clift +Justin Ehlert +Justin Fletcher +Justin Karneges +Justin Maggard +jveazey on github +jvreelanda on github +jvvprasad78 on github +jzinn on github +János Fekete +Jérémy Rabasco +Jérémy Rocher +Jörg Mueller-Tolk +Jörn Hartroth +Jürgen Gmach +K. R. Walker +ka7 on github +Kael1117 on github +Kai Engert +Kai Noda +Kai Pastor +Kai Sommerfeld +Kai-Uwe Rommel +Kalle Vahlman +Kamil Dudka +Kane York +Kang Lin +Kang-Jin Lee +Kantanat Wannapaka +Kareem +Kari Pahula +Karl Chen +Karl Moerder +Karol Pietrzak +Kartatz on Github +Karthikdasari0423 +Karthikdasari0423 on github +Kartik Mahajan +Kaspar Brand +Katie Wang +Katsuhiko YOSHIDA +Kazuho Oku +kchow-FTNT on github +Kees Cook +Kees Dekker +Keitagit-kun on github +Keith MacDonald +Keith McGuigan +Keith Mok +Kelly Kaoudis +Ken Brown +Ken Hirsch +Ken Rastatter +Kenneth Davidson +Kenneth Myhra +Kenny To +Kent Boortz +Kerem Kat +Keshav Krity +Kev Jackson +Kevin Adler +Kevin Baughman +Kevin Burke +Kevin Fisk +Kevin Ji +Kevin Lussier +Kevin R. Bulgrien +Kevin Reed +Kevin Roth +Kevin Ryan +Kevin Smith +Kevin Ushey +Kim Minjoong +Kim Rinnewitz +Kim Vandry +Kimmo Kinnunen +kirbyn17 on hackerone +Kirill Efimov +Kirill Marchuk +Kjell Ericson +Kjetil Jacobsen +Klaus Crusius +Klaus Stein +Klevtsov Vadim +Kobi Gurkan +Koen Dergent +Koichi Shiraishi +kokke on github +Konstantin Isakov +Konstantin Kushnir +KotlinIsland on github +kotoriã®ã­ã“ +kouzhudong on github +Kovalkov Dmitrii +kreshano on github +Kris Kennaway +Krishnendu Majumdar +Krister Johansen +Kristian Gunstone +Kristian Köhntopp +Kristian Mide +Kristiyan Tsaklev +Kristoffer Gleditsch +Kunal Chandarana +Kunal Ekawde +Kurt Fankhauser +Kushal Das +Kvarec Lezki +kwind on github +Kwon-Young Choi +Kyle Abramowitz +Kyle Edwards +Kyle J. McKay +Kyle L. Huff +Kyle Sallee +kyled-dell on github +Kyohei Kadota +Kyselgov E.N +l00p3r on Hackerone +Lachlan O'Dea +Ladar Levison +Lance Ware +Laramie Leavitt +Larry Campbell +Larry Fahnoe +Larry Lin +Larry Stefani +Larry Stone +Lars Buitinck +Lars Francke +Lars Gustafsson +Lars J. Aas +Lars Johannesen +Lars Nilsson +Lars Torben Wilson +Lau +Laurent Bonnans +Laurent Dufresne +Laurent Rabret +Lauri Kasanen +Laurie Clark-Michalek +Lawrence Gripper +Lawrence Matthews +Lawrence Wagerfield +Leah Neukirchen +Lealem Amedie +Leandro Coutinho +Legoff Vincent +Lehel Bernadt +Leif W +Leigh Purdie +Leith Bade +Len Krause +Len Marinaccio +Lenaic Lefever +Lenny Rachitsky +Leo Neat +Leon Breedt +Leon Winter +Leonardo Rosati +Leonardo Taccari +Leszek Kubik +Li Xinwei +Liam Healy +Liam Warfield +LigH-de on github +lijian996 on github +Lijo Antony +lilongyan-huawei on github +Lin Sun +Linas Vepstas +Lindley French +Ling Thio +Linos Giannopoulos +Linus Lewandowski +Linus Nielsen Feltzing +Linus Nordberg +Lior Kaplan +Lisa Xu +Litter White +Liviu Chircu +Liza Alenchery +lizhuang0630 on github +lkordos on github +lllaffer on github +Lloyd Fournier +Lluís Batlle i Rossell +locpyl-tidnyd on github +Loganaden Velvindron +Loic Dachary +LoRd_MuldeR +Loren Kirkby +Lorenzo Miniero +Loïc Yhuel +lRoccoon on github +Luan Cestari +Luca Altea +Luca Boccassi +Luca Niccoli +Lucas Adamski +Lucas Clemente Vella +Lucas Holt +Lucas Pardue +Lucas Servén Marín +Lucas Severo +Lucien Zürcher +Ludek Finstrle +Ludovico Cavedon +Ludwig Nussel +Lukas Ruzicka +Lukas Tribus +Lukasz Czekierda +lukaszgn on github +Luke Amery +Luke Call +Luke Dashjr +Luke Granger-Brown +luminixinc on github +Luo Jinghua +Luong Dinh Dung +Luz Paz +Luật Nguyá»…n +lwthiker on github +Lyman Epp +Lyndon Hill +M.R.T on github +Maciej Domanski +Maciej Karpiuk +Maciej Puzio +Maciej W. Rozycki +madblobfish on github +MaeIsBad on github +Mahmoud Samir Fayed +Maks Naumov +Maksim Arhipov +Maksim Kuzevanov +Maksim Sciepanienka +Maksim Stsepanenka +Maksymilian Arciemowicz +Malik Idrees Hasan Khan +Mamoru Tasaka +Mamta Upadhyay +Mandy Wu +Manfred Schwarb +Manuel Massing +Manuj Bhatia +Marc Aldorasi +Marc Boucher +Marc Deslauriers +Marc Doughty +Marc Hesse +Marc Hörsken +Marc Kleine-Budde +Marc Renault +Marc Schlatter +Marc-Antoine Perennou +marc-groundctl on github +Marcel Hernandez +Marcel Raad +Marcel Roelofs +Marcelo Echeverria +Marcelo Juchem +Marcin Adamski +Marcin Gryszkalis +Marcin Konicki +Marcin Rataj +Marco Deckel +Marco G. Salvagno +Marco Kamner +Marco Maggi +Marcos Diazr +Marcus Hoffmann +Marcus Klein +Marcus Sundberg +Marcus T +Marcus Webster +Margu +Marian Klymov +Marin Hannache +Mario Schroeder +Mark Brand +Mark Butler +Mark Davies +Mark Dodgson +Mark Gaiser +Mark Hamilton +Mark Huang +Mark Incley +Mark Itzcovitz +Mark Karpeles +Mark Lentczner +Mark Nottingham +Mark Roszko +Mark Salisbury +Mark Seuffert +Mark Sinkovics +Mark Snelling +Mark Swaanenburg +Mark Tully +Mark W. Eichin +Mark Wotton +Markus Duft +Markus Elfring +Markus Koetter +Markus Moeller +Markus Oberhumer +Markus Olsson +Markus Sommer +Markus Westerlind +Maros Priputen +Marquis de Muesli +marski on github +Martijn Koster +Martin Ankerl +Martin BaÅ¡ti +Martin C. Martin +Martin D'Aloia +Martin Dorey +Martin Drasar +Martin Dreher +Martin Frodl +Martin Galvan +Martin Gartner +Martin Hager +Martin Halle +Martin Hedenfalk +Martin Howarth +Martin Jansen +Martin Kammerhofer +Martin Kepplinger +Martin Lemke +Martin Schmatz +Martin Skinner +Martin Staael +Martin Storsjö +Martin Strunz +Martin V +Martin Vejnár +Martin Waleczek +Martin Ã…gren +Marty Kuhrt +Maruko +Masaya Suzuki +masbug on github +Massimiliano Fantuzzi +Massimiliano Ziccardi +Massimo Callegari +Master Inspire +MasterInQuestion on github +Mateusz Loskot +Mathew Benson +Mathias Axelsson +Mathias Fuchs +Mathias Gumz +Mathieu Carbonneaux +Mathieu Legare +Matias N. Goldberg +Mats Lidell +Mats Lindestam +Matt Arsenault +Matt Ford +Matt Holt +Matt Jolly +Matt Kraai +Matt McClure +Matt Veenstra +Matt Witherspoon +Matt Wixson +Matteo Baccan +Matteo Bignotti +Matteo Bignottignotti +Matteo Rocco +Matthew Blain +Matthew Clarke +Matthew Hall +Matthew Kerwin +Matthew Thompson +Matthew Whitehead +Matthias Bolte +Matthias Gatto +Matthias Naegler +Mattias Fornander +Matus Uzak +Maurice Barnum +Mauricio Scheffer +Mauro Iorio +Mauro Rappa +Maurício Meneghini Fauth +Max Dymond +Max Katsev +Max Kellermann +Max Khon +Max Mehl +Max Peal +Max Savenkov +Max Zettlmeißl +Maxim Dzhura +Maxim Ivanov +Maxim Perenesenko +Maxim Prohorov +Maxime Larocque +Maxime Legros +mbeifuss on github +mccormickt12 on github +Median Median Stride +mehatzri on github +Mehmet Bozkurt +Mekonikum +Melissa Mears +Melroy van den Berg +Mert YazıcıoÄŸlu +Mettgut Jamalla +Micah Snyder) +Michael Afanasiev +Michael Anti +Michael Baentsch +Michael Benedict +Michael Brehm +Michael Brown +Michael Calmer +Michael Cronenworth +Michael Curtis +Michael Day +Michael Drake +Michael Felt +Michael Forney +Michael Gmelin +Michael Goffioul +Michael Heimpold +Michael Hordijk +Michael Jahn +Michael Jerris +Michael Kalinin +Michael Kaufmann +Michael Kilburn +Michael Kolechkin +Michael Kujawa +Michael König +Michael Lee +Michael Maltese +Michael Mealling +Michael Mueller +Michael Musset +Michael O'Farrell +Michael Olbrich +Michael Osipov +Michael Schmid +Michael Smith +Michael Stapelberg +Michael Steuer +Michael Stillwell +Michael Trebilcock +Michael Vittiglio +Michael Wallner +Michal Bonino +Michal Marek +Michal Rus +Michal Trybus +Michal ÄŒaplygin +MichaÅ‚ Antoniak +MichaÅ‚ Fita +MichaÅ‚ Górny +MichaÅ‚ Janiszewski +MichaÅ‚ Kowalczyk +MichaÅ‚ Petryka +MichaÅ‚ Piechowski +Michel Promonet +Michele Bini +Miguel Angel +Miguel Diaz +migueljcrum on github +Mihai Ionescu +Mikael Johansson +Mikael Sennerholm +Mikalai Ananenka +Mike Bytnar +Mike Crowe +Mike Dobbs +Mike Dowell +Mike Duglas +Mike Frysinger +Mike Gelfand +Mike Giancola +Mike Hasselberg +Mike Henshaw +Mike Hommey +Mike Mio +Mike Norton +Mike Power +Mike Protts +Mike Revi +Mike Tzou +Mikhail Kuznetsov +Miklos Nemeth +MiloÅ¡ Ljumović +Mingliang Zhu +Mingtao Yang +Miroslav Franc +Miroslav Spousta +Mischa Salle +Mitz Wark +mkzero on github +modbw on github +Mohamed Daahir +Mohamed Lrhazi +Mohamed Osama +Mohammad AlSaleh +Mohammad Hasbini +Mohammadreza Hendiani +Mohammed Naser +Mohun Biswas +momala454 on github +Momoka Yamamoto +MonkeybreadSoftware on github +moohoorama on github +Morten Minde Neergaard +Mostyn Bramley-Moore +Moti Avrahami +MrdUkk on github +MrSorcus on github +Muhammad Herdiansyah +Muhammad Hussein Ammari +Muhammed Yavuz Nuzumlalı +Murugan Balraj +musvaage on github +Muz Dima +Myk Taylor +n0name321 on github +Nach M. S. +Nagai H +Nao Yonashiro +naost3rn on github +Natanael Copa +Nate Prewitt +Nathan Coulter +Nathan Moinvaziri +Nathan O'Sullivan +Nathanael Nerode +Nathaniel J. Smith +Nathaniel R. Lewis +Nathaniel Waisbrot +Naveen Chandran +Naveen Noel +Neal McBurnett +Neal Poole +nedres on github +neex on github +Nehal J Wani +neheb on github +Neil Bowers +Neil Dunbar +Neil Kolban +Neil Spring +neutric on github +nevv on HackerOne/curl +Niall McGee +Niall O'Reilly +niallor on github +nian6324 on github +nianxuejie on github +Nic Roets +Nicholas Maniscalco +Nicholas Nethercote +Nick Banks +Nick Coghlan +Nick Draffen +Nick Gimbrone +Nick Humfrey +Nick Miyake +Nick Zitzmann +nick-telia on github +Nicklas Avén +Nico Baggus +Nico Rieck +nico-abram on github +Nicolas Berloquin +Nicolas Croiset +Nicolas François +Nicolas Grekas +Nicolas Guillier +Nicolas Morey-Chaisemartin +Nicolas Noben +Nicolas Sterchele +Nicolás Ojeda Bär +Niels Martignène +Niels van Tongeren +Nikita Schmidt +Nikitinskit Dmitriy +Niklas Angebrand +Niklas Hambüchen +Nikolai Kondrashov +Nikos Mavrogiannopoulos +Nikos Tsipinakis +nimaje on github +niner on github +Ning Dong +Nir Soffer +Niracler Li +Niranjan Hasabnis +Nis Jorgensen +nk +Noam Moshe +nobedee on github +NobodyXu on github +Nobuhiro Ban +Nodak Sodak +nopjmp on github +Norbert Frese +Norbert Kett +Norbert Novotny +norbertmm on github +nosajsnikta on github +NTMan on Github +Nuru on github +Octavio Schroeder +odek86 on github +Ofer +ohyeaah on github +Okhin Vasilij +Ola Mork +Olaf Flebbe +Olaf Hering +Olaf Stüben +Oleg Jukovec +Oleg Pudeyev +Oleguer Llopart +Olen Andoni +olesteban on github +Oli Kingshott +Oliver Chang +Oliver Gondža +Oliver Graute +Oliver Kuckertz +Oliver Roberts +Oliver Schindler +Oliver Urbann +oliverpool on github +Olivier Berger +Olivier Brunel +Omar Ramadan +omau on github +OndÅ™ej KoláÄek +opensignature on github +opensslonzos-github on github +Ophir Lojkine +Orange Tsai +Oren Souroujon +Oren Tirosh +Orgad Shaneh +Ori Avtalion +orycho on github +osabc on github +Osaila on github +Osama Albahrani +Oscar Koeroo +Oscar Norlander +Oskar Liljeblad +Oskar Sigvardsson +Oumph on github +ovidiu-benea on github +Ozan Cansel +P R Schaffner +Pablo Busse +Palo Markovic +pandada8 on github +Paolo Mossino +Paolo Piacentini +Paras Sethia +parazyd on github +Pascal Gaudette +Pascal Terjan +Pasha Kuznetsov +Pasi Karkkainen +Pat Ray +patelvivekv1993 on github +patnyb on github +Patrice Guerin +Patricia Muscalu +Patrick Bihan-Faou +Patrick Dawson +Patrick McManus +Patrick Monnerat +Patrick Rapin +Patrick Schlangen +Patrick Scott +Patrick Smith +Patrick Watson +Patrik Thunstrom +Pau Garcia i Quiles +Paul B. Omta +Paul Donohue +Paul Dreik +Paul Groke +Paul Harrington +Paul Harris +Paul Hoffman +Paul Howarth +Paul Johnson +Paul Joyce +Paul Marks +Paul Marquis +Paul Moore +Paul Nolan +Paul Oliver +Paul Querna +Paul Saab +Paul Seligman +Paul Vixie +Paul Wise +Paulo Roberto Tomasi +Pavel Cenek +Pavel Gushchin +Pavel Kalyugin +Pavel Löbl +Pavel Mayorov +Pavel Orehov +Pavel Pavlov +Pavel Raiskup +Pavel Rochnyak +Pavel Volgarev +Pavol Markovic +Pawel A. Gajda +Pawel Kierski +PaweÅ‚ Kowalski +PaweÅ‚ Wegner +PBudmark on github +Pedro Henrique +Pedro Larroy +Pedro Monreal +Pedro Neves +pendrek at hackerone +Peng Li +Peng-Yu Chen +Per Jensen +Per Lundberg +Per Malmberg +Per Nilsson +Pete Lomax +Peter Bray +Peter Forret +Peter Frühberger +Peter Gal +Peter Goodman +Peter Heuchert +Peter Hjalmarsson +Peter Korsgaard +Peter Körner +Peter Lamare +Peter Lamberg +Peter Laser +Peter O'Gorman +Peter Pentchev +Peter Piekarski +Peter Silva +Peter Simonyi +Peter Su +Peter Sumatra +Peter Sylvester +Peter Todd +Peter Varga +Peter Verhas +Peter Wang +Peter Wu +Peter Wullinger +Peteris Krumins +Petr Bahula +Petr Novak +Petr Pisar +Petr Voytsik +Petr Å tetiar +Phil Blundell +Phil Crump +Phil E. Taylor +Phil Karn +Phil Lisiecki +Phil Pellouchoud +Philip Chan +Philip Craig +Philip Gladstone +Philip Heiduck +Philip Langdale +Philip Prindeville +Philip Sanetra +Philipp Engel +Philipp Klaus Krause +Philipp Waehnert +Philippe Antoine on HackerOne +Philippe Hameau +Philippe Marguinaud +Philippe Raoult +Philippe Vaucher +Pierre +Pierre Brico +Pierre Chapuis +Pierre Joye +Pierre Yager +Pierre Ynard +Pierre-Yves Bigourdan +Pierrick Charron +Piotr Dobrogost +Piotr Komborski +Po-Chuan Hsieh +Pontakorn Prasertsuk +Pontus Lundkvist +Pooyan McSporran +Poul T Lomholt +Pramod Sharma +Prash Dush +Praveen Pvs +Prithvi MK +privetryan on github +Priyanka Shah +ProceduralMan on github +promptfuzz_ on hackerone +Pronyushkin Petr +PrzemysÅ‚aw Tomaszewski +pszemus on github +pszlazak on github +puckipedia on github +Puneet Pawaia +qiandu2006 on github +Quagmire +Quanah Gibson-Mount +Quentin Balland +Quinn Slack +r-a-sattarov on github +R. Dennis Steed +Radek Brich +Radek Zajic +Radoslav Georgiev +Radu Hociung +Radu Simionescu +Rafa Muyo +Rafael Antonio +Rafael Sagula +Rafayel Mkrtchyan +Rafaël Carré +RafaÅ‚ Mikrut +Rainer Canavan +Rainer Jung +Rainer Koenig +Rainer Müller +Raito Bezarius +Rajesh Naganathan +Rajkumar Mandal +Ralf S. Engelschall +Ralph Beckmann +Ralph Langendam +Ralph Mitchell +Ram Krushna Mishra +ramsay-jones on github +Ran Mozes +RanBarLavie on github +Randall S. Becker +Randolf J +Randy Armstrong +Randy McMurchy +Raphael Gozzo +Rasmus Melchior Jacobsen +Raul Onitza-Klugman +Ravi Pratap +Ray Dassen +Ray Pekowski +Ray Satiro +Razvan Cojocaru +rcombs on github +Red Hat Product Security +Reed Loden +Reinhard Max +Reinout van Schouwen +RekGRpth on github +Remco van Hooff +Remi Gacogne +Remo E +Renato Botelho +Renaud Allard +Renaud Chaillat +Renaud Duhaut +Renaud Guillard +Renaud Lehoux +Rene Bernhardt +Rene Rebe +Reuven Wachtfogel +RevaliQaQ on github +Reza Arbab +Rianov Viacheslav +Ricardo Cadime +Ricardo Gomes +Ricardo M. Correia +Ricardo Martins +Rich Burridge +Rich FitzJohn +Rich Gray +Rich Mirch +Rich Rauenzahn +Rich Salz +Rich Turner +Richard Adams +Richard Alcock +Richard Archer +Richard Atterer +Richard Bowker +Richard Bramante +Richard Clayton +Richard Cooper +Richard Gorton +Richard Gray +Richard Hosking +Richard Hsu +Richard Levitte +Richard Marion +Richard Michael +Richard Moore +Richard Prescott +Richard Silverman +Richard van den Berg +Richard W.M. Jones +Richard Whitehouse +Richy Kim +Rici Lake +Rick Deist +Rick Jones +Rick Lane +Rick Richardson +Rick Welykochy +Rickard Hallerbäck +Ricki Hirner +Ricky Leverence +Ricky-Tigg on github +Rider Linden +RiderALT on github +Rikard Falkeborn +rilysh +rl1987 on github +Rob Boeckermann +Rob Cotrone +Rob Crittenden +Rob Davies +Rob de Wit +Rob Jones +Rob Sanders +Rob Stanzel +Rob Ward +RobBotic1 on github +Robby Simpson +Robert A. Monat +Robert B. Harris +Robert Brose +Robert Charles Muir +Robert D. Young +Robert Dunaj +Robert Foreman +Robert Iakobashvili +Robert Kolcun +Robert Linden +Robert Olson +Robert Prag +Robert Ronto +Robert Schumann +Robert Simpson +Robert Southee +Robert Weaver +Robert Wruck +Robin A. Meade +Robin Cornelius +Robin Douine +Robin Johnson +Robin Kay +Robin Marx +Robson Braga Araujo +Rod Widdowson +Rodger Combs +Rodney Simmons +Rodric Glaser +Rodrigo Silva +Roger Leigh +Roger Orr +Roger Young +Roland Blom +Roland Hieber +Roland Krikava +Roland Zimmermann +Rolf Eike Beer +Rolland Dudemaine +Romain Coltel +Romain Fliedel +Romain Geissler +romamik om github +Roman Koifman +Roman Mamedov +Romulo A. Ceccon +Ron Eldor +Ron Parker +Ron Zapp +Ronan Pigott +Ronnie Mose +Rosen Penev +Rosimildo da Silva +Ross Burton +roughtex on github +Roy Bellingan +Roy Li +Roy Shan +Rui LIU +Rui Pinheiro +Rune Kleveland +Ruslan Baratov +Ruslan Gazizov +Rutger Broekhoff +Rutger Hofman +Ruurd Beerstra +RuurdBeerstra on github +rwmjones on github +Ryan Beck-Buysse +Ryan Braud +Ryan Chan +Ryan Mast +Ryan Nelson +Ryan Schmidt +Ryan Scott +Ryan Sleevi +Ryan Winograd +ryancaicse on github +Ryuichi KAWAMATA +rzrymiak on github +Rémy Léone +S. Moonesamy +s0urc3_ on hackerone +Sai Ram Kunala +Salah-Eddin Shaban +Saleem Abdulrasool +SaltyMilk +Salvador Dávila +Salvatore Sorrentino +Sam Deane +Sam Hurst +Sam James +Sam Roth +Sam Schanken +Samanta Navarro +Sampo Kellomaki +Samuel Chiang +Samuel Díaz García +Samuel Henrique +Samuel Listopad +Samuel Marks +Samuel Surtees +Samuel Thibault +Samuel Tranchet +SandakovMM on github +Sander Gates +Sandor Feldi +Sandro Jaeckel +Santhana Todatry +Santino Keupp +Saqib Ali +Sara Golemon +Saran Neti +Sascha Swiercy +Sascha Zengler +Satadru Pramanik +Satana de Sant'Ana +Saul good +Saurav Babu +sayrer on github +SBKarr on github +Scarlett McAllister +Scott Bailey +Scott Barrett +Scott Cantor +Scott Davis +Scott McCreary +sd0 on hackerone +Sean Boudreau +Sean Burford +Sean MacLennan +Sean McArthur +Sean Miller +Sean Molenaar +Sebastiaan van Erk +Sebastian Haglund +Sebastian Mundry +Sebastian Pohlschmidt +Sebastian Rasmussen +Sebastian Sterk +selmelc on hackerone +SendSonS on github +Senthil Raja Velu +Sergei Kuzmin +Sergei Nikulov +Sergey +Sergey Alirzaev +Sergey Bronnikov +Sergey Fionov +Sergey Markelov +Sergey Ogryzkov +Sergey Ryabinin +Sergey Tatarincev +Sergii Kavunenko +Sergii Pylypenko +Sergio Ballestrero +Sergio Barresi +Sergio Borghese +Sergio Durigan Junior +Sergio Mijatovic +Sergio-IME on github +sergio-nsk on github +Serj Kalichev +SerusDev on github +Seshubabu Pasam +Seth Mos +Sevan Janiyan +sfan5 on github +Sgharat on github +Sh Diao +Shachaf Ben-Kiki +ShadowZzj on github +Shailesh Kapse +Shankar Jadhavar +Shao Shuchao +Sharad Gupta +Shard +Sharon Brizinov +Shaun Jackman +Shaun Mirani +Shawn Landden +Shawn Poulson +Sheshadri.V +Shikha Sharma +Shine Fan +Shiraz Kanga +shithappens2016 on github +Shlomi Fish +Shmulik Regev +Shohei Maeda +Siddhartha Prakash Jain +siddharthchhabrap on github +Sidney San Martín +Siegfried Gyuricsko +silveja1 on github +Simon Berger +Simon Chalifoux +Simon Dick +Simon H. +Simon Josefsson +Simon Legner +Simon Liu +Simon Warta +simplerobot on github +Siva Sivaraman +SLDiggie on github +Smackd0wn +Smackd0wn on github +smuellerDD on github +sn on hackerone +sofaboss on github +Sohom Datta +Somnath Kundu +Song Ma +Sonia Subramanian +Spacen Jasset +Spezifant on github +Spiridonoff A.V +Spoon Man +Spork Schivago +ssdbest on github +sspiri on github +sstruchtrup on github +Stadler Stephan +Stan Hu +Stan van de Burgt +Stanislav Ivochkin +Stanislav Zidek +Stanley Wucw +Stathis Kapnidis +Stav Nir +steelman on github +Stefan Agner +Stefan Bühler +Stefan Eissing +Stefan Esser +Stefan Grether +Stefan Huber +Stefan Kanthak +Stefan Karpinski +Stefan Krause +Stefan Neis +Stefan Strogin +Stefan Talpalaru +Stefan Teleman +Stefan Tomanek +Stefan Ulrich +Stefan Yohansson +Stefano Simonelli +Steinar H. Gunderson +steini2000 on github +Stepan Broz +Stepan Efremov +Stephan Bergmann +Stephan Guilloux +Stephan Lagerholm +Stephan Mühlstrasser +Stephan Szabo +Stephane Pellegrino +Stephen Boost +Stephen Brokenshire +Stephen Collyer +Stephen Kick +Stephen M. Coakley +Stephen More +Stephen Toub +Sterling Hughes +Steve Green +Steve H Truong +Steve Havelka +Steve Herrell +Steve Holme +Steve Lhomme +Steve Little +Steve Marx +Steve Oliphant +Steve Roskowski +Steve Walch +Steven Allen +Steven Bazyl +Steven G. Johnson +Steven Gu +Steven M. Schweda +Steven Parkes +Steven Penny +Stewart Gebbie +Stian Soiland-Reyes +Stoned Elipot +stootill on github +Stuart Henderson +Sukanya Hanumanthu +SumatraPeter on github +Sune Ahlgren +Sunny Bean +Sunny Purushe +SuperIlu on github +Sven Anders +Sven Blumenstein +Sven Neuhaus +Sven Wegener +Svyatoslav Mishyn +swalkaus at yahoo.com +sylgal on github +Sylvestre Ledru +Symeon Paraschoudis +Sébastien Helleu +Sébastien Willemijns +T. Bharath +T. Yamada +T200proX7 on github +Tadej Vengust +Tae Hyoung Ahn +Taiyu Len +Taneli Vähäkangas +Tanguy Fautre +Taras Kushnir +tarek112 on github +Tatsuhiko Miyagawa +Tatsuhiro Tsujikawa +tawmoto on github +tbugfinder on github +Ted Lyngmo +Teemu Yli-Elsila +Temprimus +Terri Oda +Terry Wu +thanhchungbtc on github +The Infinnovation team +TheAssassin on github +TheKnarf on github +Theo +Theodore Dubois +therealhirudo on github +Thiago Suchorski +tholin on github +Thomas Bouzerar +Thomas Braun +Thomas Danielsson +Thomas Ferguson +Thomas Gamper +Thomas Glanzmann +Thomas Guillem +Thomas J. Moore +Thomas Klausner +Thomas L. Shinnick +Thomas Lopatic +Thomas M. DuBuisson +Thomas Petazzoni +Thomas Ruecker +Thomas Schwinge +Thomas Taylor +Thomas Tonino +Thomas van Hesteren +Thomas Vegas +Thomas Weißschuh +Thomas1664 on github +Thorsten Klein +Thorsten Schöning +Tiit Pikma +Till Maas +Tim Ansell +Tim Baker +Tim Bartley +Tim Chen +Tim Costello +Tim Harder +Tim Heckman +Tim Hill +Tim Mcdonough +Tim Newsome +Tim Rühsen +Tim Sedlmeyer +Tim Sneddon +Tim Stack +Tim Starling +Tim Tassonis +Tim Verhoeven +Timmy Schierling +Timo Lange +Timo Sirainen +Timotej Lazar +Timothe Litt +Timothy Gu +Timothy Polich +Timur Artikov +Tinus van den Berg +TJ Saunders +Tk Xiong +tlahn on github +tmkk on github +Tobias Blomberg +Tobias Gabriel +Tobias Hieta +Tobias Hintze +Tobias Lindgren +Tobias Markus +Tobias Nießen +Tobias Nygren +Tobias Nyholm +Tobias Rundström +Tobias Schaefer +Tobias Stoeckmann +Toby Peterson +Todd A Ouska +Todd Kaufmann +Todd Kulesza +Todd Short +Todd Vierling +Tom Benoist +Tom Donovan +Tom Eccles +Tom G. Christensen +Tom Grace +Tom Greenslade +Tom Lee +Tom Mattison +Tom Moers +Tom Mueller +Tom Regner +Tom Seddon +Tom Sparrow +Tom van der Woerdt +Tom Wright +Tom Zerucha +Tomas Berger +Tomas Hoger +Tomas Jakobsson +Tomas Mlcoch +Tomas Mraz +Tomas Pospisek +Tomas Szepe +Tomas Tomecek +Tomasz Kojm +Tomasz Lacki +Tommie Gannert +tommink[at]post.pl +Tommy Chiang +Tommy Odom +Tommy Petty +Tommy Tam +Ton Voon +Toni Moreno +Tony Kelman +tonystz on Github +Toon Verwaest +Tor Arntsen +Torben Dannhauer +Torben Dury +Torsten Foertsch +Toshio Kuratomi +Toshiyuki Maezawa +tpaukrt on github +Traian Nicolescu +Trail of Bits +Travis Burtrum +Travis Obenhaus +Trivikram Kamat +Troels Walsted Hansen +Troy Engel +trrui-huawei +Tseng Jun +Tuomas Siipola +Tuomo Rinne +Tupone Alfredo +Turiiya +Tyler Hall +Török Edwin +u20221022 on github +Ulf Härnhammar +Ulf Samuelsson +Ulrich Doehner +Ulrich Telle +Ulrich Zadow +UnicornZhang on Github +updatede on github +UrsusArctos on github +User Sg +ustcqidi on github +Vadim Grinshpun +Valentin David +Valentin Richter +Valentyn Korniienko +Valentín Gutiérrez +Valerii Zapodovnikov +vanillajonathan on github +Varnavas Papaioannou +Vasiliy Faronov +Vasiliy Ulyanov +Vasily Lobaskin +Vasy Okhin +Venkat Akella +Venkataramana Mokkapati +Vicente Garcia +Victor Magierski +Victor Snezhko +Victor Vieux +VictorVG on github +Vijay Panghal +Vikram Saxena +Viktor Szakats +Vilhelm Prytz +Ville Skyttä +Vilmos Nebehaj +Vincas Razma +Vincent Bronner +Vincent Grande +Vincent Le Normand +Vincent Penquerc'h +Vincent Sanders +Vincent Torri +violetlige on github +vitaha85 on github +Vitaly Varyvdin +vl409 on github +Vlad Grachov +Vlad Ureche +Vladimir Grishchenko +Vladimir Kotal +Vladimir Lazarenko +Vladimir Panteleev +Vladimir Varlamov +Vlastimil OvÄáÄík +vlkl-sap on github +vlubart on github +Vojtech Janota +Vojtech Minarik +VojtÄ›ch Král +Volker Schmid +Vsevolod Novikov +vshmuk on hackerone +vvb2060 +vvb2060 on github +Vyron Tsingaras +Vítor Galvão +W. Mark Kubacki +w0x42 on hackerone +Waldek Kozba +Walter J. Mack +wangzhikun +Ward Willats +Warren Menzer +Wayne Haigh +Wei Chong Tan +Wenchao Li +Wenxiang Qian +Werner Koch +Werner Stolz +Wes Hinsley +wesinator on github +Wesley Laxton +Wesley Miaw +Wez Furlong +Wham Bang +Wilfredo Sanchez +Wilhelm von Thiele +Will Dietz +Will Roberts +Willem Hoek +Willem Sparreboom +William A. Rowe Jr +William Ahern +William Desportes +William Tang +wmsch on github +wncboy on github +Wojciech Zwiefka +Wolf Vollprecht +Wouter Van Rooy +Wu Yongzheng +Wu Zheng +Wyatt O'Day +Wyatt OʼDay +x2018 on github +Xavier Bouchoux +XhmikosR on github +XhstormR on github +Xi Ruoyao +Xiang Xiao +Xiangbin Li +xianghongai on github +Xiaoke Wang +Xiaoyin Liu +XmiliaH on github +xnynx on github +xtonik on github +xwxbug on github +Xì Gà +Yaakov Selkowitz +Yadhu Krishna M +Yair Lenga +Yang Tse +Yaobin Wen +Yarram Sunil +Yasuharu Yamada +Yasuhiro Matsumoto +Yechiel Kalmenson +Yedaya Katsman +Yehezkel Horowitz +Yehoshua Hershberg +ygthien on github +Yi Huang +Yifei Kong +Yiming Jing +Yingwei Liu +yiyuaner on github +Ymir1711 on github +Yonggang Luo +Yongkang Huang +Younes El-karama +youngchopin on github +Yousuke Kimoto +Yu Xin +Yukihiro Kawada +Yun SangHo +Yuri Slobodyanyuk +Yurii Rashkovskii +Yuriy Chernyshov +Yuriy Sosov +yushicheng7788 on github +Yusuke Nakamura +Yves Arrouye +Yves Lejeune +YX Hao +z2-2z on github +z2_ on hackerone +Zachary Seguin +Zdenek Pavlas +Zekun Ni +zelinchen on github +zengwei +zengwei2000 +Zenju on github +Zero King +Zespre Schmidt +Zhang Xiuhua +zhanghu on xiaomi +Zhao Yisha +Zhaoyang Wu +zhengqwe on github +Zhibiao Wu +zhihaoy on github +Zhouyihai Ding +ZimCodes on github +zloi-user on github +Zmey Petroff +Zvi Har'El +zzq1015 on github +Ãdler Jonas Gross +Érico Nogueira +Érico Nogueira Rolim +Ä°smail Dönmez +Åukasz Domeradzki +Å tefan Kremeň +Ð‘Ð¾Ñ€Ð¸Ñ Ð’ÐµÑ€Ñ…Ð¾Ð²Ñкий +Коваленко Ðнатолий Викторович +Ðикита Дорохин +ウã•ã‚“ +ä¸ç¡®å®š +加藤éƒä¹‹ +å—å®«é›ªçŠ +左潇峰 +梦终无痕 +ç©ä¸¹å°¼ Dan Jacobson diff --git a/docs/TODO b/docs/TODO new file mode 100644 index 0000000..1629443 --- /dev/null +++ b/docs/TODO @@ -0,0 +1,1408 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + + Things that could be nice to do in the future + + Things to do in project curl. Please tell us what you think, contribute and + send us patches that improve things. + + Be aware that these are things that we could do, or have once been considered + things we could do. If you want to work on any of these areas, please + consider bringing it up for discussions first on the mailing list so that we + all agree it is still a good idea for the project. + + All bugs documented in the KNOWN_BUGS document are subject for fixing. + + 1. libcurl + 1.1 TFO support on Windows + 1.2 Consult %APPDATA% also for .netrc + 1.3 struct lifreq + 1.4 alt-svc sharing + 1.5 get rid of PATH_MAX + 1.6 native IDN support on macOS + 1.8 CURLOPT_RESOLVE for any port number + 1.9 Cache negative name resolves + 1.10 auto-detect proxy + 1.11 minimize dependencies with dynamically loaded modules + 1.12 updated DNS server while running + 1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION + 1.15 Monitor connections in the connection pool + 1.16 Try to URL encode given URL + 1.17 Add support for IRIs + 1.18 try next proxy if one does not work + 1.19 provide timing info for each redirect + 1.20 SRV and URI DNS records + 1.21 netrc caching and sharing + 1.22 CURLINFO_PAUSE_STATE + 1.23 Offer API to flush the connection pool + 1.25 Expose tried IP addresses that failed + 1.28 FD_CLOEXEC + 1.29 WebSocket read callback + 1.30 config file parsing + 1.31 erase secrets from heap/stack after use + 1.32 add asynch getaddrinfo support + 1.33 make DoH inherit more transfer properties + + 2. libcurl - multi interface + 2.1 More non-blocking + 2.2 Better support for same name resolves + 2.3 Non-blocking curl_multi_remove_handle() + 2.4 Split connect and authentication process + 2.5 Edge-triggered sockets should work + 2.6 multi upkeep + 2.7 Virtual external sockets + 2.8 dynamically decide to use socketpair + + 3. Documentation + 3.1 Improve documentation about fork safety + 3.2 Provide cmake config-file + + 4. FTP + 4.1 HOST + 4.2 Alter passive/active on failure and retry + 4.3 Earlier bad letter detection + 4.4 Support CURLOPT_PREQUOTE for dir listings too + 4.5 ASCII support + 4.6 GSSAPI via Windows SSPI + 4.7 STAT for LIST without data connection + 4.8 Passive transfer could try other IP addresses + + 5. HTTP + 5.1 Provide the error body from a CONNECT response + 5.2 Obey Retry-After in redirects + 5.3 Rearrange request header order + 5.4 Allow SAN names in HTTP/2 server push + 5.5 auth= in URLs + 5.6 alt-svc should fallback if alt-svc does not work + 5.7 Require HTTP version X or higher + + 6. TELNET + 6.1 ditch stdin + 6.2 ditch telnet-specific select + 6.3 feature negotiation debug data + 6.4 exit immediately upon connection if stdin is /dev/null + + 7. SMTP + 7.1 Passing NOTIFY option to CURLOPT_MAIL_RCPT + 7.2 Enhanced capability support + 7.3 Add CURLOPT_MAIL_CLIENT option + + 8. POP3 + 8.2 Enhanced capability support + + 9. IMAP + 9.1 Enhanced capability support + + 10. LDAP + 10.1 SASL based authentication mechanisms + 10.2 CURLOPT_SSL_CTX_FUNCTION for LDAPS + 10.3 Paged searches on LDAP server + 10.4 Certificate-Based Authentication + + 11. SMB + 11.1 File listing support + 11.2 Honor file timestamps + 11.3 Use NTLMv2 + 11.4 Create remote directories + + 12. FILE + 12.1 Directory listing for FILE: + + 13. TLS + 13.1 TLS-PSK with OpenSSL + 13.2 Provide mutex locking API + 13.3 Defeat TLS fingerprinting + 13.4 Cache/share OpenSSL contexts + 13.5 Export session ids + 13.6 Provide callback for cert verification + 13.7 Less memory massaging with Schannel + 13.8 Support DANE + 13.9 TLS record padding + 13.10 Support Authority Information Access certificate extension (AIA) + 13.11 Some TLS options are not offered for HTTPS proxies + 13.12 Reduce CA certificate bundle reparsing + 13.13 Make sure we forbid TLS 1.3 post-handshake authentication + 13.14 Support the clienthello extension + + 14. GnuTLS + 14.2 check connection + + 15. Schannel + 15.1 Extend support for client certificate authentication + 15.2 Extend support for the --ciphers option + 15.4 Add option to allow abrupt server closure + + 16. SASL + 16.1 Other authentication mechanisms + 16.2 Add QOP support to GSSAPI authentication + + 17. SSH protocols + 17.1 Multiplexing + 17.2 Handle growing SFTP files + 17.3 Read keys from ~/.ssh/id_ecdsa, id_ed25519 + 17.4 Support CURLOPT_PREQUOTE + 17.5 SSH over HTTPS proxy with more backends + 17.6 SFTP with SCP:// + + 18. Command line tool + 18.1 sync + 18.2 glob posts + 18.4 --proxycommand + 18.5 UTF-8 filenames in Content-Disposition + 18.6 Option to make -Z merge lined based outputs on stdout + 18.8 Consider convenience options for JSON and XML? + 18.9 Choose the name of file in braces for complex URLs + 18.10 improve how curl works in a windows console window + 18.11 Windows: set attribute 'archive' for completed downloads + 18.12 keep running, read instructions from pipe/socket + 18.13 Ratelimit or wait between serial requests + 18.14 --dry-run + 18.15 --retry should resume + 18.16 send only part of --data + 18.17 consider file name from the redirected URL with -O ? + 18.18 retry on network is unreachable + 18.19 expand ~/ in config files + 18.20 host name sections in config files + 18.21 retry on the redirected-to URL + 18.23 Set the modification date on an uploaded file + 18.24 Use multiple parallel transfers for a single download + 18.25 Prevent terminal injection when writing to terminal + 18.26 Custom progress meter update interval + 18.27 -J and -O with %-encoded file names + 18.28 -J with -C - + 18.29 --retry and transfer timeouts + + 19. Build + 19.1 roffit + 19.2 Enable PIE and RELRO by default + 19.3 Do not use GNU libtool on OpenBSD + 19.4 Package curl for Windows in a signed installer + 19.5 make configure use --cache-file more and better + 19.6 build curl with Windows Unicode support + + 20. Test suite + 20.1 SSL tunnel + 20.2 nicer lacking perl message + 20.3 more protocols supported + 20.4 more platforms supported + 20.5 Add support for concurrent connections + 20.6 Use the RFC 6265 test suite + 20.7 Support LD_PRELOAD on macOS + 20.8 Run web-platform-tests URL tests + + 21. MQTT + 21.1 Support rate-limiting + + 22. TFTP + 22.1 TFTP doesn't convert LF to CRLF for mode=netascii + +============================================================================== + +1. libcurl + +1.1 TFO support on Windows + + libcurl supports the CURLOPT_TCP_FASTOPEN option since 7.49.0 for Linux and + Mac OS. Windows supports TCP Fast Open starting with Windows 10, version 1607 + and we should add support for it. + + TCP Fast Open is supported on several platforms but not on Windows. Work on + this was once started but never finished. + + See https://github.com/curl/curl/pull/3378 + +1.2 Consult %APPDATA% also for .netrc + + %APPDATA%\.netrc is not considered when running on Windows. should not it? + + See https://github.com/curl/curl/issues/4016 + +1.3 struct lifreq + + Use 'struct lifreq' and SIOCGLIFADDR instead of 'struct ifreq' and + SIOCGIFADDR on newer Solaris versions as they claim the latter is obsolete. + To support IPv6 interface addresses for network interfaces properly. + +1.4 Better and more sharing + + The share interface could benefit from allowing the alt-svc cache to be + possible to share between easy handles. + + See https://github.com/curl/curl/issues/4476 + + The share interface offers CURL_LOCK_DATA_CONNECT to have multiple easy + handle share a connection cache, but due to how connections are used they are + still not thread-safe when used shared. + + See https://github.com/curl/curl/issues/4915 and lib1541.c + + The share interface offers CURL_LOCK_DATA_HSTS to have multiple easy handle + share a HSTS cache, but this is not thread-safe. + +1.5 get rid of PATH_MAX + + Having code use and rely on PATH_MAX is not nice: + https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html + + Currently the libssh2 SSH based code uses it, but to remove PATH_MAX from + there we need libssh2 to properly tell us when we pass in a too small buffer + and its current API (as of libssh2 1.2.7) does not. + +1.6 native IDN support on macOS + + On recent macOS versions, the getaddrinfo() function itself has built-in IDN + support. By setting the AI_CANONNAME flag, the function will return the + encoded name in the ai_canonname struct field in the returned information. + This could be used by curl on macOS when built without a separate IDN library + and an IDN host name is used in a URL. + + See initial work in https://github.com/curl/curl/pull/5371 + +1.8 CURLOPT_RESOLVE for any port number + + This option allows applications to set a replacement IP address for a given + host + port pair. Consider making support for providing a replacement address + for the host name on all port numbers. + + See https://github.com/curl/curl/issues/1264 + +1.9 Cache negative name resolves + + A name resolve that has failed is likely to fail when made again within a + short period of time. Currently we only cache positive responses. + +1.10 auto-detect proxy + + libcurl could be made to detect the system proxy setup automatically and use + that. On Windows, macOS and Linux desktops for example. + + The pull-request to use libproxy for this was deferred due to doubts on the + reliability of the dependency and how to use it: + https://github.com/curl/curl/pull/977 + + libdetectproxy is a (C++) library for detecting the proxy on Windows + https://github.com/paulharris/libdetectproxy + +1.11 minimize dependencies with dynamically loaded modules + + We can create a system with loadable modules/plug-ins, where these modules + would be the ones that link to 3rd party libs. That would allow us to avoid + having to load ALL dependencies since only the necessary ones for this + app/invoke/used protocols would be necessary to load. See + https://github.com/curl/curl/issues/349 + +1.12 updated DNS server while running + + If /etc/resolv.conf gets updated while a program using libcurl is running, it + is may cause name resolves to fail unless res_init() is called. We should + consider calling res_init() + retry once unconditionally on all name resolve + failures to mitigate against this. Firefox works like that. Note that Windows + does not have res_init() or an alternative. + + https://github.com/curl/curl/issues/2251 + +1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION + + curl will create most sockets via the CURLOPT_OPENSOCKETFUNCTION callback and + close them with the CURLOPT_CLOSESOCKETFUNCTION callback. However, c-ares + does not use those functions and instead opens and closes the sockets + itself. This means that when curl passes the c-ares socket to the + CURLMOPT_SOCKETFUNCTION it is not owned by the application like other sockets. + + See https://github.com/curl/curl/issues/2734 + +1.15 Monitor connections in the connection pool + + libcurl's connection cache or pool holds a number of open connections for the + purpose of possible subsequent connection reuse. It may contain a few up to a + significant amount of connections. Currently, libcurl leaves all connections + as they are and first when a connection is iterated over for matching or + reuse purpose it is verified that it is still alive. + + Those connections may get closed by the server side for idleness or they may + get an HTTP/2 ping from the peer to verify that they are still alive. By + adding monitoring of the connections while in the pool, libcurl can detect + dead connections (and close them) better and earlier, and it can handle + HTTP/2 pings to keep such ones alive even when not actively doing transfers + on them. + +1.16 Try to URL encode given URL + + Given a URL that for example contains spaces, libcurl could have an option + that would try somewhat harder than it does now and convert spaces to %20 and + perhaps URL encoded byte values over 128 etc (basically do what the redirect + following code already does). + + https://github.com/curl/curl/issues/514 + +1.17 Add support for IRIs + + IRIs (RFC 3987) allow localized, non-ascii, names in the URL. To properly + support this, curl/libcurl would need to translate/encode the given input + from the input string encoding into percent encoded output "over the wire". + + To make that work smoothly for curl users even on Windows, curl would + probably need to be able to convert from several input encodings. + +1.18 try next proxy if one does not work + + Allow an application to specify a list of proxies to try, and failing to + connect to the first go on and try the next instead until the list is + exhausted. Browsers support this feature at least when they specify proxies + using PACs. + + https://github.com/curl/curl/issues/896 + +1.19 provide timing info for each redirect + + curl and libcurl provide timing information via a set of different + time-stamps (CURLINFO_*_TIME). When curl is following redirects, those + returned time value are the accumulated sums. An improvement could be to + offer separate timings for each redirect. + + https://github.com/curl/curl/issues/6743 + +1.20 SRV and URI DNS records + + Offer support for resolving SRV and URI DNS records for libcurl to know which + server to connect to for various protocols (including HTTP). + +1.21 netrc caching and sharing + + The netrc file is read and parsed each time a connection is setup, which + means that if a transfer needs multiple connections for authentication or + redirects, the file might be reread (and parsed) multiple times. This makes + it impossible to provide the file as a pipe. + +1.22 CURLINFO_PAUSE_STATE + + Return information about the transfer's current pause state, in both + directions. https://github.com/curl/curl/issues/2588 + +1.23 Offer API to flush the connection pool + + Sometimes applications want to flush all the existing connections kept alive. + An API could allow a forced flush or just a forced loop that would properly + close all connections that have been closed by the server already. + +1.25 Expose tried IP addresses that failed + + When libcurl fails to connect to a host, it could offer the application the + addresses that were used in the attempt. Source + dest IP, source + dest port + and protocol (UDP or TCP) for each failure. Possibly as a callback. Perhaps + also provide "reason". + + https://github.com/curl/curl/issues/2126 + +1.28 FD_CLOEXEC + + It sets the close-on-exec flag for the file descriptor, which causes the file + descriptor to be automatically (and atomically) closed when any of the + exec-family functions succeed. Should probably be set by default? + + https://github.com/curl/curl/issues/2252 + +1.29 WebSocket read callback + + Call the read callback once the connection is established to allow sending + the first message in the connection. + + https://github.com/curl/curl/issues/11402 + +1.30 config file parsing + + Consider providing an API, possibly in a separate companion library, for + parsing a config file like curl's -K/--config option to allow applications to + get the same ability to read curl options from files. + + See https://github.com/curl/curl/issues/3698 + +1.31 erase secrets from heap/stack after use + + Introducing a concept and system to erase secrets from memory after use, it + could help mitigate and lessen the impact of (future) security problems etc. + However: most secrets are passed to libcurl as clear text from the + application and then clearing them within the library adds nothing... + + https://github.com/curl/curl/issues/7268 + +1.32 add asynch getaddrinfo support + + Use getaddrinfo_a() to provide an asynch name resolver backend to libcurl + that does not use threads and does not depend on c-ares. The getaddrinfo_a + function is (probably?) glibc specific but that is a widely used libc among + our users. + + https://github.com/curl/curl/pull/6746 + +1.33 make DoH inherit more transfer properties + + Some options are not inherited because they are not relevant for the DoH SSL + connections, or inheriting the option may result in unexpected behavior. For + example the user's debug function callback is not inherited because it would + be unexpected for internal handles (ie DoH handles) to be passed to that + callback. + + If an option is not inherited then it is not possible to set it separately + for DoH without a DoH-specific option. For example: + CURLOPT_DOH_SSL_VERIFYHOST, CURLOPT_DOH_SSL_VERIFYPEER and + CURLOPT_DOH_SSL_VERIFYSTATUS. + + See https://github.com/curl/curl/issues/6605 + +2. libcurl - multi interface + +2.1 More non-blocking + + Make sure we do not ever loop because of non-blocking sockets returning + EWOULDBLOCK or similar. Blocking cases include: + + - Name resolves on non-windows unless c-ares or the threaded resolver is used. + + - The threaded resolver may block on cleanup: + https://github.com/curl/curl/issues/4852 + + - file:// transfers + + - TELNET transfers + + - GSSAPI authentication for FTP transfers + + - The "DONE" operation (post transfer protocol-specific actions) for the + protocols SFTP, SMTP, FTP. Fixing multi_done() for this is a worthy task. + + - curl_multi_remove_handle for any of the above. See section 2.3. + +2.2 Better support for same name resolves + + If a name resolve has been initiated for name NN and a second easy handle + wants to resolve that name as well, make it wait for the first resolve to end + up in the cache instead of doing a second separate resolve. This is + especially needed when adding many simultaneous handles using the same host + name when the DNS resolver can get flooded. + +2.3 Non-blocking curl_multi_remove_handle() + + The multi interface has a few API calls that assume a blocking behavior, like + add_handle() and remove_handle() which limits what we can do internally. The + multi API need to be moved even more into a single function that "drives" + everything in a non-blocking manner and signals when something is done. A + remove or add would then only ask for the action to get started and then + multi_perform() etc still be called until the add/remove is completed. + +2.4 Split connect and authentication process + + The multi interface treats the authentication process as part of the connect + phase. As such any failures during authentication will not trigger the relevant + QUIT or LOGOFF for protocols such as IMAP, POP3 and SMTP. + +2.5 Edge-triggered sockets should work + + The multi_socket API should work with edge-triggered socket events. One of + the internal actions that need to be improved for this to work perfectly is + the 'maxloops' handling in transfer.c:readwrite_data(). + +2.6 multi upkeep + + In libcurl 7.62.0 we introduced curl_easy_upkeep. It unfortunately only works + on easy handles. We should introduces a version of that for the multi handle, + and also consider doing "upkeep" automatically on connections in the + connection pool when the multi handle is in used. + + See https://github.com/curl/curl/issues/3199 + +2.7 Virtual external sockets + + libcurl performs operations on the given file descriptor that presumes it is + a socket and an application cannot replace them at the moment. Allowing an + application to fully replace those would allow a larger degree of freedom and + flexibility. + + See https://github.com/curl/curl/issues/5835 + +2.8 dynamically decide to use socketpair + + For users who do not use curl_multi_wait() or do not care for + curl_multi_wakeup(), we could introduce a way to make libcurl NOT + create a socketpair in the multi handle. + + See https://github.com/curl/curl/issues/4829 + +3. Documentation + +3.1 Improve documentation about fork safety + + See https://github.com/curl/curl/issues/6968 + +3.2 Provide cmake config-file + + A config-file package is a set of files provided by us to allow applications + to write cmake scripts to find and use libcurl easier. See + https://github.com/curl/curl/issues/885 + +4. FTP + +4.1 HOST + + HOST is a command for a client to tell which host name to use, to offer FTP + servers named-based virtual hosting: + + https://datatracker.ietf.org/doc/html/rfc7151 + +4.2 Alter passive/active on failure and retry + + When trying to connect passively to a server which only supports active + connections, libcurl returns CURLE_FTP_WEIRD_PASV_REPLY and closes the + connection. There could be a way to fallback to an active connection (and + vice versa). https://curl.se/bug/feature.cgi?id=1754793 + +4.3 Earlier bad letter detection + + Make the detection of (bad) %0d and %0a codes in FTP URL parts earlier in the + process to avoid doing a resolve and connect in vain. + +4.4 Support CURLOPT_PREQUOTE for dir listings too + + The lack of support is mostly an oversight and requires the FTP state machine + to get updated to get fixed. + + https://github.com/curl/curl/issues/8602 + +4.5 ASCII support + + FTP ASCII transfers do not follow RFC 959. They do not convert the data + accordingly. + +4.6 GSSAPI via Windows SSPI + + In addition to currently supporting the SASL GSSAPI mechanism (Kerberos V5) + via third-party GSS-API libraries, such as Heimdal or MIT Kerberos, also add + support for GSSAPI authentication via Windows SSPI. + +4.7 STAT for LIST without data connection + + Some FTP servers allow STAT for listing directories instead of using LIST, + and the response is then sent over the control connection instead of as the + otherwise usedw data connection: https://www.nsftools.com/tips/RawFTP.htm#STAT + + This is not detailed in any FTP specification. + +4.8 Passive transfer could try other IP addresses + + When doing FTP operations through a proxy at localhost, the reported spotted + that curl only tried to connect once to the proxy, while it had multiple + addresses and a failed connect on one address should make it try the next. + + After switching to passive mode (EPSV), curl could try all IP addresses for + "localhost". Currently it tries ::1, but it should also try 127.0.0.1. + + See https://github.com/curl/curl/issues/1508 + +5. HTTP + +5.1 Provide the error body from a CONNECT response + + When curl receives a body response from a CONNECT request to a proxy, it will + always just read and ignore it. It would make some users happy if curl + instead optionally would be able to make that responsible available. Via a new + callback? Through some other means? + + See https://github.com/curl/curl/issues/9513 + +5.2 Obey Retry-After in redirects + + The Retry-After is said to dicate "the minimum time that the user agent is + asked to wait before issuing the redirected request" and libcurl does not + obey this. + + See https://github.com/curl/curl/issues/11447 + +5.3 Rearrange request header order + + Server implementers often make an effort to detect browser and to reject + clients it can detect to not match. One of the last details we cannot yet + control in libcurl's HTTP requests, which also can be exploited to detect + that libcurl is in fact used even when it tries to impersonate a browser, is + the order of the request headers. I propose that we introduce a new option in + which you give headers a value, and then when the HTTP request is built it + sorts the headers based on that number. We could then have internally created + headers use a default value so only headers that need to be moved have to be + specified. + +5.4 Allow SAN names in HTTP/2 server push + + curl only allows HTTP/2 push promise if the provided :authority header value + exactly matches the host name given in the URL. It could be extended to allow + any name that would match the Subject Alternative Names in the server's TLS + certificate. + + See https://github.com/curl/curl/pull/3581 + +5.5 auth= in URLs + + Add the ability to specify the preferred authentication mechanism to use by + using ;auth= in the login part of the URL. + + For example: + + http://test:pass;auth=NTLM@example.com would be equivalent to specifying + --user test:pass;auth=NTLM or --user test:pass --ntlm from the command line. + + Additionally this should be implemented for proxy base URLs as well. + +5.6 alt-svc should fallback if alt-svc does not work + + The alt-svc: header provides a set of alternative services for curl to use + instead of the original. If the first attempted one fails, it should try the + next etc and if all alternatives fail go back to the original. + + See https://github.com/curl/curl/issues/4908 + +5.7 Require HTTP version X or higher + + curl and libcurl provide options for trying higher HTTP versions (for example + HTTP/2) but then still allows the server to pick version 1.1. We could + consider adding a way to require a minimum version. + + See https://github.com/curl/curl/issues/7980 + +6. TELNET + +6.1 ditch stdin + + Reading input (to send to the remote server) on stdin is a crappy solution + for library purposes. We need to invent a good way for the application to be + able to provide the data to send. + +6.2 ditch telnet-specific select + + Move the telnet support's network select() loop go away and merge the code + into the main transfer loop. Until this is done, the multi interface will not + work for telnet. + +6.3 feature negotiation debug data + + Add telnet feature negotiation data to the debug callback as header data. + +6.4 exit immediately upon connection if stdin is /dev/null + + If it did, curl could be used to probe if there is an server there listening + on a specific port. That is, the following command would exit immediately + after the connection is established with exit code 0: + + curl -s --connect-timeout 2 telnet://example.com:80 NOTIFY=SUCCESS,FAILURE" ); + + https://github.com/curl/curl/issues/8232 + +7.2 Enhanced capability support + + Add the ability, for an application that uses libcurl, to obtain the list of + capabilities returned from the EHLO command. + +7.3 Add CURLOPT_MAIL_CLIENT option + + Rather than use the URL to specify the mail client string to present in the + HELO and EHLO commands, libcurl should support a new CURLOPT specifically for + specifying this data as the URL is non-standard and to be honest a bit of a + hack ;-) + + Please see the following thread for more information: + https://curl.se/mail/lib-2012-05/0178.html + + +8. POP3 + +8.2 Enhanced capability support + + Add the ability, for an application that uses libcurl, to obtain the list of + capabilities returned from the CAPA command. + +9. IMAP + +9.1 Enhanced capability support + + Add the ability, for an application that uses libcurl, to obtain the list of + capabilities returned from the CAPABILITY command. + +10. LDAP + +10.1 SASL based authentication mechanisms + + Currently the LDAP module only supports ldap_simple_bind_s() in order to bind + to an LDAP server. However, this function sends username and password details + using the simple authentication mechanism (as clear text). However, it should + be possible to use ldap_bind_s() instead specifying the security context + information ourselves. + +10.2 CURLOPT_SSL_CTX_FUNCTION for LDAPS + + CURLOPT_SSL_CTX_FUNCTION works perfectly for HTTPS and email protocols, but + it has no effect for LDAPS connections. + + https://github.com/curl/curl/issues/4108 + +10.3 Paged searches on LDAP server + + https://github.com/curl/curl/issues/4452 + +10.4 Certificate-Based Authentication + + LDAPS not possible with MAC and Windows with Certificate-Based Authentication + + https://github.com/curl/curl/issues/9641 + +11. SMB + +11.1 File listing support + + Add support for listing the contents of a SMB share. The output should + probably be the same as/similar to FTP. + +11.2 Honor file timestamps + + The timestamp of the transferred file should reflect that of the original + file. + +11.3 Use NTLMv2 + + Currently the SMB authentication uses NTLMv1. + +11.4 Create remote directories + + Support for creating remote directories when uploading a file to a directory + that does not exist on the server, just like --ftp-create-dirs. + + +12. FILE + +12.1 Directory listing for FILE: + + Add support for listing the contents of a directory accessed with FILE. The + output should probably be the same as/similar to FTP. + + +13. TLS + +13.1 TLS-PSK with OpenSSL + + Transport Layer Security pre-shared key ciphersuites (TLS-PSK) is a set of + cryptographic protocols that provide secure communication based on pre-shared + keys (PSKs). These pre-shared keys are symmetric keys shared in advance among + the communicating parties. + + https://github.com/curl/curl/issues/5081 + +13.2 Provide mutex locking API + + Provide a libcurl API for setting mutex callbacks in the underlying SSL + library, so that the same application code can use mutex-locking + independently of OpenSSL or GnutTLS being used. + +13.3 Defeat TLS fingerprinting + + By changing the order of TLS extensions provided in the TLS handshake, it is + sometimes possible to circumvent TLS fingerprinting by servers. The TLS + extension order is of course not the only way to fingerprint a client. + + See https://github.com/curl/curl/issues/8119 + +13.4 Cache/share OpenSSL contexts + + "Look at SSL cafile - quick traces look to me like these are done on every + request as well, when they should only be necessary once per SSL context (or + once per handle)". The major improvement we can rather easily do is to make + sure we do not create and kill a new SSL "context" for every request, but + instead make one for every connection and reuse that SSL context in the same + style connections are reused. It will make us use slightly more memory but it + will libcurl do less creations and deletions of SSL contexts. + + Technically, the "caching" is probably best implemented by getting added to + the share interface so that easy handles who want to and can reuse the + context specify that by sharing with the right properties set. + + https://github.com/curl/curl/issues/1110 + +13.5 Export session ids + + Add an interface to libcurl that enables "session IDs" to get + exported/imported. Cris Bailiff said: "OpenSSL has functions which can + serialise the current SSL state to a buffer of your choice, and recover/reset + the state from such a buffer at a later date - this is used by mod_ssl for + apache to implement and SSL session ID cache". + +13.6 Provide callback for cert verification + + OpenSSL supports a callback for customised verification of the peer + certificate, but this does not seem to be exposed in the libcurl APIs. Could + it be? There is so much that could be done if it were. + +13.7 Less memory massaging with Schannel + + The Schannel backend does a lot of custom memory management we would rather + avoid: the repeated alloc + free in sends and the custom memory + realloc + system for encrypted and decrypted data. That should be avoided and reduced + for 1) efficiency and 2) safety. + +13.8 Support DANE + + DNS-Based Authentication of Named Entities (DANE) is a way to provide SSL + keys and certs over DNS using DNSSEC as an alternative to the CA model. + https://www.rfc-editor.org/rfc/rfc6698.txt + + An initial patch was posted by Suresh Krishnaswamy on March 7th 2013 + (https://curl.se/mail/lib-2013-03/0075.html) but it was a too simple + approach. See Daniel's comments: + https://curl.se/mail/lib-2013-03/0103.html . libunbound may be the + correct library to base this development on. + + Björn Stenberg wrote a separate initial take on DANE that was never + completed. + +13.9 TLS record padding + + TLS (1.3) offers optional record padding and OpenSSL provides an API for it. + I could make sense for libcurl to offer this ability to applications to make + traffic patterns harder to figure out by network traffic observers. + + See https://github.com/curl/curl/issues/5398 + +13.10 Support Authority Information Access certificate extension (AIA) + + AIA can provide various things like CRLs but more importantly information + about intermediate CA certificates that can allow validation path to be + fulfilled when the HTTPS server does not itself provide them. + + Since AIA is about downloading certs on demand to complete a TLS handshake, + it is probably a bit tricky to get done right. + + See https://github.com/curl/curl/issues/2793 + +13.11 Some TLS options are not offered for HTTPS proxies + + Some TLS related options to the command line tool and libcurl are only + provided for the server and not for HTTPS proxies. --proxy-tls-max, + --proxy-tlsv1.3, --proxy-curves and a few more.a + + https://github.com/curl/curl/issues/12286 + +13.12 Reduce CA certificate bundle reparsing + + When using the OpenSSL backend, curl will load and reparse the CA bundle at + the creation of the "SSL context" when it sets up a connection to do a TLS + handshake. A more effective way would be to somehow cache the CA bundle to + avoid it having to be repeatedly reloaded and reparsed. + + See https://github.com/curl/curl/issues/9379 + +13.13 Make sure we forbid TLS 1.3 post-handshake authentication + + RFC 8740 explains how using HTTP/2 must forbid the use of TLS 1.3 + post-handshake authentication. We should make sure to live up to that. + + See https://github.com/curl/curl/issues/5396 + +13.14 Support the clienthello extension + + Certain stupid networks and middle boxes have a problem with SSL handshake + packets that are within a certain size range because how that sets some bits + that previously (in older TLS version) were not set. The clienthello + extension adds padding to avoid that size range. + + https://datatracker.ietf.org/doc/html/rfc7685 + https://github.com/curl/curl/issues/2299 + +14. GnuTLS + +14.2 check connection + + Add a way to check if the connection seems to be alive, to correspond to the + SSL_peak() way we use with OpenSSL. + +15. Schannel + +15.1 Extend support for client certificate authentication + + The existing support for the -E/--cert and --key options could be + extended by supplying a custom certificate and key in PEM format, see: + - Getting a Certificate for Schannel + https://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx + +15.2 Extend support for the --ciphers option + + The existing support for the --ciphers option could be extended + by mapping the OpenSSL/GnuTLS cipher suites to the Schannel APIs, see + - Specifying Schannel Ciphers and Cipher Strengths + https://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx + +15.4 Add option to allow abrupt server closure + + libcurl w/schannel will error without a known termination point from the + server (such as length of transfer, or SSL "close notify" alert) to prevent + against a truncation attack. Really old servers may neglect to send any + termination point. An option could be added to ignore such abrupt closures. + + https://github.com/curl/curl/issues/4427 + +16. SASL + +16.1 Other authentication mechanisms + + Add support for other authentication mechanisms such as OLP, + GSS-SPNEGO and others. + +16.2 Add QOP support to GSSAPI authentication + + Currently the GSSAPI authentication only supports the default QOP of auth + (Authentication), whilst Kerberos V5 supports both auth-int (Authentication + with integrity protection) and auth-conf (Authentication with integrity and + privacy protection). + + +17. SSH protocols + +17.1 Multiplexing + + SSH is a perfectly fine multiplexed protocols which would allow libcurl to do + multiple parallel transfers from the same host using the same connection, + much in the same spirit as HTTP/2 does. libcurl however does not take + advantage of that ability but will instead always create a new connection for + new transfers even if an existing connection already exists to the host. + + To fix this, libcurl would have to detect an existing connection and "attach" + the new transfer to the existing one. + +17.2 Handle growing SFTP files + + The SFTP code in libcurl checks the file size *before* a transfer starts and + then proceeds to transfer exactly that amount of data. If the remote file + grows while the transfer is in progress libcurl will not notice and will not + adapt. The OpenSSH SFTP command line tool does and libcurl could also just + attempt to download more to see if there is more to get... + + https://github.com/curl/curl/issues/4344 + +17.3 Read keys from ~/.ssh/id_ecdsa, id_ed25519 + + The libssh2 backend in curl is limited to only reading keys from id_rsa and + id_dsa, which makes it fail connecting to servers that use more modern key + types. + + https://github.com/curl/curl/issues/8586 + +17.4 Support CURLOPT_PREQUOTE + + The two other QUOTE options are supported for SFTP, but this was left out for + unknown reasons. + +17.5 SSH over HTTPS proxy with more backends + + The SSH based protocols SFTP and SCP did not work over HTTPS proxy at + all until PR https://github.com/curl/curl/pull/6021 brought the + functionality with the libssh2 backend. Presumably, this support + can/could be added for the other backends as well. + +17.6 SFTP with SCP:// + + OpenSSH 9 switched their 'scp' tool to speak SFTP under the hood. Going + forward it might be worth having curl or libcurl attempt SFTP if SCP fails to + follow suite. + +18. Command line tool + +18.1 sync + + "curl --sync http://example.com/feed[1-100].rss" or + "curl --sync http://example.net/{index,calendar,history}.html" + + Downloads a range or set of URLs using the remote name, but only if the + remote file is newer than the local file. A Last-Modified HTTP date header + should also be used to set the mod date on the downloaded file. + +18.2 glob posts + + Globbing support for -d and -F, as in 'curl -d "name=foo[0-9]" URL'. + This is easily scripted though. + +18.4 --proxycommand + + Allow the user to make curl run a command and use its stdio to make requests + and not do any network connection by itself. Example: + + curl --proxycommand 'ssh pi@raspberrypi.local -W 10.1.1.75 80' \ + http://some/otherwise/unavailable/service.php + + See https://github.com/curl/curl/issues/4941 + +18.5 UTF-8 filenames in Content-Disposition + + RFC 6266 documents how UTF-8 names can be passed to a client in the + Content-Disposition header, and curl does not support this. + + https://github.com/curl/curl/issues/1888 + +18.6 Option to make -Z merge lined based outputs on stdout + + When a user requests multiple lined based files using -Z and sends them to + stdout, curl will not "merge" and send complete lines fine but may send + partial lines from several sources. + + https://github.com/curl/curl/issues/5175 + +18.8 Consider convenience options for JSON and XML? + + Could we add `--xml` or `--json` to add headers needed to call rest API: + + `--xml` adds -H 'Content-Type: application/xml' -H "Accept: application/xml" and + `--json` adds -H 'Content-Type: application/json' -H "Accept: application/json" + + Setting Content-Type when doing a GET or any other method without a body + would be a bit strange I think - so maybe only add CT for requests with body? + Maybe plain `--xml` and ` --json` are a bit too brief and generic. Maybe + `--http-json` etc? + + See https://github.com/curl/curl/issues/5203 + +18.9 Choose the name of file in braces for complex URLs + + When using braces to download a list of URLs and you use complicated names + in the list of alternatives, it could be handy to allow curl to use other + names when saving. + + Consider a way to offer that. Possibly like + {partURL1:name1,partURL2:name2,partURL3:name3} where the name following the + colon is the output name. + + See https://github.com/curl/curl/issues/221 + +18.10 improve how curl works in a windows console window + + If you pull the scrollbar when transferring with curl in a Windows console + window, the transfer is interrupted and can get disconnected. This can + probably be improved. See https://github.com/curl/curl/issues/322 + +18.11 Windows: set attribute 'archive' for completed downloads + + The archive bit (FILE_ATTRIBUTE_ARCHIVE, 0x20) separates files that shall be + backed up from those that are either not ready or have not changed. + + Downloads in progress are neither ready to be backed up, nor should they be + opened by a different process. Only after a download has been completed it's + sensible to include it in any integer snapshot or backup of the system. + + See https://github.com/curl/curl/issues/3354 + +18.12 keep running, read instructions from pipe/socket + + Provide an option that makes curl not exit after the last URL (or even work + without a given URL), and then make it read instructions passed on a pipe or + over a socket to make further instructions so that a second subsequent curl + invoke can talk to the still running instance and ask for transfers to get + done, and thus maintain its connection pool, DNS cache and more. + +18.13 Ratelimit or wait between serial requests + + Consider a command line option that can make curl do multiple serial requests + slow, potentially with a (random) wait between transfers. There is also a + proposed set of standard HTTP headers to let servers let the client adapt to + its rate limits: + https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/ + + See https://github.com/curl/curl/issues/5406 + +18.14 --dry-run + + A command line option that makes curl show exactly what it would do and send + if it would run for real. + + See https://github.com/curl/curl/issues/5426 + +18.15 --retry should resume + + When --retry is used and curl actually retries transfer, it should use the + already transferred data and do a resumed transfer for the rest (when + possible) so that it does not have to transfer the same data again that was + already transferred before the retry. + + See https://github.com/curl/curl/issues/1084 + +18.16 send only part of --data + + When the user only wants to send a small piece of the data provided with + --data or --data-binary, like when that data is a huge file, consider a way + to specify that curl should only send a piece of that. One suggested syntax + would be: "--data-binary @largefile.zip!1073741823-2147483647". + + See https://github.com/curl/curl/issues/1200 + +18.17 consider file name from the redirected URL with -O ? + + When a user gives a URL and uses -O, and curl follows a redirect to a new + URL, the file name is not extracted and used from the newly redirected-to URL + even if the new URL may have a much more sensible file name. + + This is clearly documented and helps for security since there is no surprise + to users which file name that might get overwritten. But maybe a new option + could allow for this or maybe -J should imply such a treatment as well as -J + already allows for the server to decide what file name to use so it already + provides the "may overwrite any file" risk. + + This is extra tricky if the original URL has no file name part at all since + then the current code path will error out with an error message, and we cannot + *know* already at that point if curl will be redirected to a URL that has a + file name... + + See https://github.com/curl/curl/issues/1241 + +18.18 retry on network is unreachable + + The --retry option retries transfers on "transient failures". We later added + --retry-connrefused to also retry for "connection refused" errors. + + Suggestions have been brought to also allow retry on "network is unreachable" + errors and while totally reasonable, maybe we should consider a way to make + this more configurable than to add a new option for every new error people + want to retry for? + + https://github.com/curl/curl/issues/1603 + +18.19 expand ~/ in config files + + For example .curlrc could benefit from being able to do this. + + See https://github.com/curl/curl/issues/2317 + +18.20 host name sections in config files + + config files would be more powerful if they could set different + configurations depending on used URLs, host name or possibly origin. Then a + default .curlrc could a specific user-agent only when doing requests against + a certain site. + +18.21 retry on the redirected-to URL + + When curl is told to --retry a failed transfer and follows redirects, it + might get an HTTP 429 response from the redirected-to URL and not the + original one, which then could make curl decide to rather retry the transfer + on that URL only instead of the original operation to the original URL. + + Perhaps extra emphasized if the original transfer is a large POST that + redirects to a separate GET, and that GET is what gets the 529 + + See https://github.com/curl/curl/issues/5462 + +18.23 Set the modification date on an uploaded file + + For SFTP and possibly FTP, curl could offer an option to set the + modification time for the uploaded file. + + See https://github.com/curl/curl/issues/5768 + +18.24 Use multiple parallel transfers for a single download + + To enhance transfer speed, downloading a single URL can be split up into + multiple separate range downloads that get combined into a single final + result. + + An ideal implementation would not use a specified number of parallel + transfers, but curl could: + - First start getting the full file as transfer A + - If after N seconds have passed and the transfer is expected to continue for + M seconds or more, add a new transfer (B) that asks for the second half of + A's content (and stop A at the middle). + - If splitting up the work improves the transfer rate, it could then be done + again. Then again, etc up to a limit. + + This way, if transfer B fails (because Range: is not supported) it will let + transfer A remain the single one. N and M could be set to some sensible + defaults. + + See https://github.com/curl/curl/issues/5774 + +18.25 Prevent terminal injection when writing to terminal + + curl could offer an option to make escape sequence either non-functional or + avoid cursor moves or similar to reduce the risk of a user getting tricked by + clever tricks. + + See https://github.com/curl/curl/issues/6150 + +18.26 Custom progress meter update interval + + Users who are for example doing large downloads in CI or remote setups might + want the occasional progress meter update to see that the transfer is + progressing and has not stuck, but they may not appreciate the + many-times-a-second frequency curl can end up doing it with now. + +18.27 -J and -O with %-encoded file names + + -J/--remote-header-name does not decode %-encoded file names. RFC 6266 details + how it should be done. The can of worm is basically that we have no charset + handling in curl and ascii >=128 is a challenge for us. Not to mention that + decoding also means that we need to check for nastiness that is attempted, + like "../" sequences and the like. Probably everything to the left of any + embedded slashes should be cut off. + https://curl.se/bug/view.cgi?id=1294 + + -O also does not decode %-encoded names, and while it has even less + information about the charset involved the process is similar to the -J case. + + Note that we will not add decoding to -O without the user asking for it with + some other means as well, since -O has always been documented to use the name + exactly as specified in the URL. + +18.28 -J with -C - + + When using -J (with -O), automatically resumed downloading together with "-C + -" fails. Without -J the same command line works. This happens because the + resume logic is worked out before the target file name (and thus its + pre-transfer size) has been figured out. This can be improved. + + https://curl.se/bug/view.cgi?id=1169 + +18.29 --retry and transfer timeouts + + If using --retry and the transfer timeouts (possibly due to using -m or + -y/-Y) the next attempt does not resume the transfer properly from what was + downloaded in the previous attempt but will truncate and restart at the + original position where it was at before the previous failed attempt. See + https://curl.se/mail/lib-2008-01/0080.html and Mandriva bug report + https://qa.mandriva.com/show_bug.cgi?id=22565 + + + +19. Build + +19.1 roffit + + Consider extending 'roffit' to produce decent ASCII output, and use that + instead of (g)nroff when building src/tool_hugehelp.c + +19.2 Enable PIE and RELRO by default + + Especially when having programs that execute curl via the command line, PIE + renders the exploitation of memory corruption vulnerabilities a lot more + difficult. This can be attributed to the additional information leaks being + required to conduct a successful attack. RELRO, on the other hand, masks + different binary sections like the GOT as read-only and thus kills a handful + of techniques that come in handy when attackers are able to arbitrarily + overwrite memory. A few tests showed that enabling these features had close + to no impact, neither on the performance nor on the general functionality of + curl. + +19.3 Do not use GNU libtool on OpenBSD + When compiling curl on OpenBSD with "--enable-debug" it will give linking + errors when you use GNU libtool. This can be fixed by using the libtool + provided by OpenBSD itself. However for this the user always needs to invoke + make with "LIBTOOL=/usr/bin/libtool". It would be nice if the script could + have some magic to detect if this system is an OpenBSD host and then use the + OpenBSD libtool instead. + + See https://github.com/curl/curl/issues/5862 + +19.4 Package curl for Windows in a signed installer + + See https://github.com/curl/curl/issues/5424 + +19.5 make configure use --cache-file more and better + + The configure script can be improved to cache more values so that repeated + invokes run much faster. + + See https://github.com/curl/curl/issues/7753 + +19.6 build curl with Windows Unicode support + + The user wants an easier way to tell autotools to build curl with Windows + Unicode support, like ./configure --enable-windows-unicode + + See https://github.com/curl/curl/issues/7229 + +20. Test suite + +20.1 SSL tunnel + + Make our own version of stunnel for simple port forwarding to enable HTTPS + and FTP-SSL tests without the stunnel dependency, and it could allow us to + provide test tools built with either OpenSSL or GnuTLS + +20.2 nicer lacking perl message + + If perl was not found by the configure script, do not attempt to run the tests + but explain something nice why it does not. + +20.3 more protocols supported + + Extend the test suite to include more protocols. The telnet could just do FTP + or http operations (for which we have test servers). + +20.4 more platforms supported + + Make the test suite work on more platforms. OpenBSD and Mac OS. Remove + fork()s and it should become even more portable. + +20.5 Add support for concurrent connections + + Tests 836, 882 and 938 were designed to verify that separate connections are + not used when using different login credentials in protocols that should not + reuse a connection under such circumstances. + + Unfortunately, ftpserver.pl does not appear to support multiple concurrent + connections. The read while() loop seems to loop until it receives a + disconnect from the client, where it then enters the waiting for connections + loop. When the client opens a second connection to the server, the first + connection has not been dropped (unless it has been forced - which we + should not do in these tests) and thus the wait for connections loop is never + entered to receive the second connection. + +20.6 Use the RFC 6265 test suite + + A test suite made for HTTP cookies (RFC 6265) by Adam Barth is available at + https://github.com/abarth/http-state/tree/master/tests + + It'd be really awesome if someone would write a script/setup that would run + curl with that test suite and detect deviances. Ideally, that would even be + incorporated into our regular test suite. + +20.7 Support LD_PRELOAD on macOS + + LD_RELOAD does not work on macOS, but there are tests which require it to run + properly. Look into making the preload support in runtests.pl portable such + that it uses DYLD_INSERT_LIBRARIES on macOS. + +20.8 Run web-platform-tests URL tests + + Run web-platform-tests URL tests and compare results with browsers on wpt.fyi + + It would help us find issues to fix and help us document where our parser + differs from the WHATWG URL spec parsers. + + See https://github.com/curl/curl/issues/4477 + +21. MQTT + +21.1 Support rate-limiting + + The rate-limiting logic is done in the PERFORMING state in multi.c but MQTT + is not (yet) implemented to use that. + +22. TFTP + +22.1 TFTP doesn't convert LF to CRLF for mode=netascii + + RFC 3617 defines that an TFTP transfer can be done using "netascii" + mode. curl does not support extracting that mode from the URL nor does it treat + such transfers specifically. It should probably do LF to CRLF translations + for them. + + See https://github.com/curl/curl/issues/12655 diff --git a/docs/TheArtOfHttpScripting.md b/docs/TheArtOfHttpScripting.md new file mode 100644 index 0000000..8607642 --- /dev/null +++ b/docs/TheArtOfHttpScripting.md @@ -0,0 +1,709 @@ +# The Art Of Scripting HTTP Requests Using Curl + +## Background + + This document assumes that you are familiar with HTML and general networking. + + The increasing amount of applications moving to the web has made "HTTP + Scripting" more frequently requested and wanted. To be able to automatically + extract information from the web, to fake users, to post or upload data to + web servers are all important tasks today. + + Curl is a command line tool for doing all sorts of URL manipulations and + transfers, but this particular document will focus on how to use it when + doing HTTP requests for fun and profit. This documents assumes that you know + how to invoke `curl --help` or `curl --manual` to get basic information about + it. + + Curl is not written to do everything for you. It makes the requests, it gets + the data, it sends data and it retrieves the information. You probably need + to glue everything together using some kind of script language or repeated + manual invokes. + +## The HTTP Protocol + + HTTP is the protocol used to fetch data from web servers. It is a simple + protocol that is built upon TCP/IP. The protocol also allows information to + get sent to the server from the client using a few different methods, as will + be shown here. + + HTTP is plain ASCII text lines being sent by the client to a server to + request a particular action, and then the server replies a few text lines + before the actual requested content is sent to the client. + + The client, curl, sends an HTTP request. The request contains a method (like + GET, POST, HEAD etc), a number of request headers and sometimes a request + body. The HTTP server responds with a status line (indicating if things went + well), response headers and most often also a response body. The "body" part + is the plain data you requested, like the actual HTML or the image etc. + +## See the Protocol + + Using curl's option [`--verbose`](https://curl.se/docs/manpage.html#-v) + (`-v` as a short option) will display what kind of commands curl sends to the + server, as well as a few other informational texts. + + `--verbose` is the single most useful option when it comes to debug or even + understand the curl<->server interaction. + + Sometimes even `--verbose` is not enough. Then + [`--trace`](https://curl.se/docs/manpage.html#-trace) and + [`--trace-ascii`](https://curl.se/docs/manpage.html#--trace-ascii) + offer even more details as they show **everything** curl sends and + receives. Use it like this: + + curl --trace-ascii debugdump.txt http://www.example.com/ + +## See the Timing + + Many times you may wonder what exactly is taking all the time, or you just + want to know the amount of milliseconds between two points in a transfer. For + those, and other similar situations, the + [`--trace-time`](https://curl.se/docs/manpage.html#--trace-time) option + is what you need. It will prepend the time to each trace output line: + + curl --trace-ascii d.txt --trace-time http://example.com/ + +## See which Transfer + + When doing parallel transfers, it is relevant to see which transfer is + doing what. When response headers are received (and logged) you need to + know which transfer these are for. + [`--trace-ids`](https://curl.se/docs/manpage.html#--trace-ids) option + is what you need. It will prepend the transfer and connection identifier + to each trace output line: + + curl --trace-ascii d.txt --trace-ids http://example.com/ + +## See the Response + + By default curl sends the response to stdout. You need to redirect it + somewhere to avoid that, most often that is done with `-o` or `-O`. + +# URL + +## Spec + + The Uniform Resource Locator format is how you specify the address of a + particular resource on the Internet. You know these, you have seen URLs like + https://curl.se or https://example.com a million times. RFC 3986 is the + canonical spec. The formal name is not URL, it is **URI**. + +## Host + + The hostname is usually resolved using DNS or your /etc/hosts file to an IP + address and that is what curl will communicate with. Alternatively you specify + the IP address directly in the URL instead of a name. + + For development and other trying out situations, you can point to a different + IP address for a hostname than what would otherwise be used, by using curl's + [`--resolve`](https://curl.se/docs/manpage.html#--resolve) option: + + curl --resolve www.example.org:80:127.0.0.1 http://www.example.org/ + +## Port number + + Each protocol curl supports operates on a default port number, be it over TCP + or in some cases UDP. Normally you do not have to take that into + consideration, but at times you run test servers on other ports or + similar. Then you can specify the port number in the URL with a colon and a + number immediately following the hostname. Like when doing HTTP to port + 1234: + + curl http://www.example.org:1234/ + + The port number you specify in the URL is the number that the server uses to + offer its services. Sometimes you may use a proxy, and then you may + need to specify that proxy's port number separately from what curl needs to + connect to the server. Like when using an HTTP proxy on port 4321: + + curl --proxy http://proxy.example.org:4321 http://remote.example.org/ + +## User name and password + + Some services are setup to require HTTP authentication and then you need to + provide name and password which is then transferred to the remote site in + various ways depending on the exact authentication protocol used. + + You can opt to either insert the user and password in the URL or you can + provide them separately: + + curl http://user:password@example.org/ + + or + + curl -u user:password http://example.org/ + + You need to pay attention that this kind of HTTP authentication is not what + is usually done and requested by user-oriented websites these days. They tend + to use forms and cookies instead. + +## Path part + + The path part is just sent off to the server to request that it sends back + the associated response. The path is what is to the right side of the slash + that follows the hostname and possibly port number. + +# Fetch a page + +## GET + + The simplest and most common request/operation made using HTTP is to GET a + URL. The URL could itself refer to a webpage, an image or a file. The client + issues a GET request to the server and receives the document it asked for. + If you issue the command line + + curl https://curl.se + + you get a webpage returned in your terminal window. The entire HTML document + that that URL holds. + + All HTTP replies contain a set of response headers that are normally hidden, + use curl's [`--include`](https://curl.se/docs/manpage.html#-i) (`-i`) + option to display them as well as the rest of the document. + +## HEAD + + You can ask the remote server for ONLY the headers by using the + [`--head`](https://curl.se/docs/manpage.html#-I) (`-I`) option which + will make curl issue a HEAD request. In some special cases servers deny the + HEAD method while others still work, which is a particular kind of annoyance. + + The HEAD method is defined and made so that the server returns the headers + exactly the way it would do for a GET, but without a body. It means that you + may see a `Content-Length:` in the response headers, but there must not be an + actual body in the HEAD response. + +## Multiple URLs in a single command line + + A single curl command line may involve one or many URLs. The most common case + is probably to just use one, but you can specify any amount of URLs. Yes + any. No limits. You will then get requests repeated over and over for all the + given URLs. + + Example, send two GET requests: + + curl http://url1.example.com http://url2.example.com + + If you use [`--data`](https://curl.se/docs/manpage.html#-d) to POST to + the URL, using multiple URLs means that you send that same POST to all the + given URLs. + + Example, send two POSTs: + + curl --data name=curl http://url1.example.com http://url2.example.com + + +## Multiple HTTP methods in a single command line + + Sometimes you need to operate on several URLs in a single command line and do + different HTTP methods on each. For this, you will enjoy the + [`--next`](https://curl.se/docs/manpage.html#-:) option. It is basically + a separator that separates a bunch of options from the next. All the URLs + before `--next` will get the same method and will get all the POST data + merged into one. + + When curl reaches the `--next` on the command line, it will sort of reset the + method and the POST data and allow a new set. + + Perhaps this is best shown with a few examples. To send first a HEAD and then + a GET: + + curl -I http://example.com --next http://example.com + + To first send a POST and then a GET: + + curl -d score=10 http://example.com/post.cgi --next http://example.com/results.html + +# HTML forms + +## Forms explained + + Forms are the general way a website can present an HTML page with fields for + the user to enter data in, and then press some kind of 'OK' or 'Submit' + button to get that data sent to the server. The server then typically uses + the posted data to decide how to act. Like using the entered words to search + in a database, or to add the info in a bug tracking system, display the + entered address on a map or using the info as a login-prompt verifying that + the user is allowed to see what it is about to see. + + Of course there has to be some kind of program on the server end to receive + the data you send. You cannot just invent something out of the air. + +## GET + + A GET-form uses the method GET, as specified in HTML like: + +```html +
+ + +
+``` + + In your favorite browser, this form will appear with a text box to fill in + and a press-button labeled "OK". If you fill in '1905' and press the OK + button, your browser will then create a new URL to get for you. The URL will + get `junk.cgi?birthyear=1905&press=OK` appended to the path part of the + previous URL. + + If the original form was seen on the page `www.example.com/when/birth.html`, + the second page you will get will become + `www.example.com/when/junk.cgi?birthyear=1905&press=OK`. + + Most search engines work this way. + + To make curl do the GET form post for you, just enter the expected created + URL: + + curl "http://www.example.com/when/junk.cgi?birthyear=1905&press=OK" + +## POST + + The GET method makes all input field names get displayed in the URL field of + your browser. That is generally a good thing when you want to be able to + bookmark that page with your given data, but it is an obvious disadvantage if + you entered secret information in one of the fields or if there are a large + amount of fields creating a long and unreadable URL. + + The HTTP protocol then offers the POST method. This way the client sends the + data separated from the URL and thus you will not see any of it in the URL + address field. + + The form would look similar to the previous one: + +```html +
+ + +
+``` + + And to use curl to post this form with the same data filled in as before, we + could do it like: + + curl --data "birthyear=1905&press=%20OK%20" http://www.example.com/when/junk.cgi + + This kind of POST will use the Content-Type + `application/x-www-form-urlencoded` and is the most widely used POST kind. + + The data you send to the server MUST already be properly encoded, curl will + not do that for you. For example, if you want the data to contain a space, + you need to replace that space with `%20`, etc. Failing to comply with this will + most likely cause your data to be received wrongly and messed up. + + Recent curl versions can in fact url-encode POST data for you, like this: + + curl --data-urlencode "name=I am Daniel" http://www.example.com + + If you repeat `--data` several times on the command line, curl will + concatenate all the given data pieces - and put a `&` symbol between each + data segment. + +## File Upload POST + + Back in late 1995 they defined an additional way to post data over HTTP. It + is documented in the RFC 1867, why this method sometimes is referred to as + RFC 1867-posting. + + This method is mainly designed to better support file uploads. A form that + allows a user to upload a file could be written like this in HTML: + +
+ + +
+ + This clearly shows that the Content-Type about to be sent is + `multipart/form-data`. + + To post to a form like this with curl, you enter a command line like: + + curl --form upload=@localfilename --form press=OK [URL] + +## Hidden Fields + + A common way for HTML based applications to pass state information between + pages is to add hidden fields to the forms. Hidden fields are already filled + in, they are not displayed to the user and they get passed along just as all + the other fields. + + A similar example form with one visible field, one hidden field and one + submit button could look like: + +```html +
+ + + +
+``` + + To POST this with curl, you will not have to think about if the fields are + hidden or not. To curl they are all the same: + + curl --data "birthyear=1905&press=OK&person=daniel" [URL] + +## Figure Out What A POST Looks Like + + When you are about to fill in a form and send it to a server by using curl + instead of a browser, you are of course interested in sending a POST exactly + the way your browser does. + + An easy way to get to see this, is to save the HTML page with the form on + your local disk, modify the 'method' to a GET, and press the submit button + (you could also change the action URL if you want to). + + You will then clearly see the data get appended to the URL, separated with a + `?`-letter as GET forms are supposed to. + +# HTTP upload + +## PUT + + Perhaps the best way to upload data to an HTTP server is to use PUT. Then + again, this of course requires that someone put a program or script on the + server end that knows how to receive an HTTP PUT stream. + + Put a file to an HTTP server with curl: + + curl --upload-file uploadfile http://www.example.com/receive.cgi + +# HTTP Authentication + +## Basic Authentication + + HTTP Authentication is the ability to tell the server your username and + password so that it can verify that you are allowed to do the request you are + doing. The Basic authentication used in HTTP (which is the type curl uses by + default) is **plain text** based, which means it sends username and password + only slightly obfuscated, but still fully readable by anyone that sniffs on + the network between you and the remote server. + + To tell curl to use a user and password for authentication: + + curl --user name:password http://www.example.com + +## Other Authentication + + The site might require a different authentication method (check the headers + returned by the server), and then + [`--ntlm`](https://curl.se/docs/manpage.html#--ntlm), + [`--digest`](https://curl.se/docs/manpage.html#--digest), + [`--negotiate`](https://curl.se/docs/manpage.html#--negotiate) or even + [`--anyauth`](https://curl.se/docs/manpage.html#--anyauth) might be + options that suit you. + +## Proxy Authentication + + Sometimes your HTTP access is only available through the use of an HTTP + proxy. This seems to be especially common at various companies. An HTTP proxy + may require its own user and password to allow the client to get through to + the Internet. To specify those with curl, run something like: + + curl --proxy-user proxyuser:proxypassword curl.se + + If your proxy requires the authentication to be done using the NTLM method, + use [`--proxy-ntlm`](https://curl.se/docs/manpage.html#--proxy-ntlm), if + it requires Digest use + [`--proxy-digest`](https://curl.se/docs/manpage.html#--proxy-digest). + + If you use any one of these user+password options but leave out the password + part, curl will prompt for the password interactively. + +## Hiding credentials + + Do note that when a program is run, its parameters might be possible to see + when listing the running processes of the system. Thus, other users may be + able to watch your passwords if you pass them as plain command line + options. There are ways to circumvent this. + + It is worth noting that while this is how HTTP Authentication works, many + websites will not use this concept when they provide logins etc. See the Web + Login chapter further below for more details on that. + +# More HTTP Headers + +## Referer + + An HTTP request may include a 'referer' field (yes it is misspelled), which + can be used to tell from which URL the client got to this particular + resource. Some programs/scripts check the referer field of requests to verify + that this was not arriving from an external site or an unknown page. While + this is a stupid way to check something so easily forged, many scripts still + do it. Using curl, you can put anything you want in the referer-field and + thus more easily be able to fool the server into serving your request. + + Use curl to set the referer field with: + + curl --referer http://www.example.come http://www.example.com + +## User Agent + + Similar to the referer field, all HTTP requests may set the User-Agent + field. It names what user agent (client) that is being used. Many + applications use this information to decide how to display pages. Silly web + programmers try to make different pages for users of different browsers to + make them look the best possible for their particular browsers. They usually + also do different kinds of JavaScript etc. + + At times, you will see that getting a page with curl will not return the same + page that you see when getting the page with your browser. Then you know it + is time to set the User Agent field to fool the server into thinking you are + one of those browsers. + + To make curl look like Internet Explorer 5 on a Windows 2000 box: + + curl --user-agent "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" [URL] + + Or why not look like you are using Netscape 4.73 on an old Linux box: + + curl --user-agent "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" [URL] + +## Redirects + +## Location header + + When a resource is requested from a server, the reply from the server may + include a hint about where the browser should go next to find this page, or a + new page keeping newly generated output. The header that tells the browser to + redirect is `Location:`. + + Curl does not follow `Location:` headers by default, but will simply display + such pages in the same manner it displays all HTTP replies. It does however + feature an option that will make it attempt to follow the `Location:` + pointers. + + To tell curl to follow a Location: + + curl --location http://www.example.com + + If you use curl to POST to a site that immediately redirects you to another + page, you can safely use + [`--location`](https://curl.se/docs/manpage.html#-L) (`-L`) and + `--data`/`--form` together. Curl will only use POST in the first request, and + then revert to GET in the following operations. + +## Other redirects + + Browsers typically support at least two other ways of redirects that curl + does not: first the html may contain a meta refresh tag that asks the browser + to load a specific URL after a set number of seconds, or it may use + JavaScript to do it. + +# Cookies + +## Cookie Basics + + The way the web browsers do "client side state control" is by using + cookies. Cookies are just names with associated contents. The cookies are + sent to the client by the server. The server tells the client for what path + and hostname it wants the cookie sent back, and it also sends an expiration + date and a few more properties. + + When a client communicates with a server with a name and path as previously + specified in a received cookie, the client sends back the cookies and their + contents to the server, unless of course they are expired. + + Many applications and servers use this method to connect a series of requests + into a single logical session. To be able to use curl in such occasions, we + must be able to record and send back cookies the way the web application + expects them. The same way browsers deal with them. + +## Cookie options + + The simplest way to send a few cookies to the server when getting a page with + curl is to add them on the command line like: + + curl --cookie "name=Daniel" http://www.example.com + + Cookies are sent as common HTTP headers. This is practical as it allows curl + to record cookies simply by recording headers. Record cookies with curl by + using the [`--dump-header`](https://curl.se/docs/manpage.html#-D) (`-D`) + option like: + + curl --dump-header headers_and_cookies http://www.example.com + + (Take note that the + [`--cookie-jar`](https://curl.se/docs/manpage.html#-c) option described + below is a better way to store cookies.) + + Curl has a full blown cookie parsing engine built-in that comes in use if you + want to reconnect to a server and use cookies that were stored from a + previous connection (or hand-crafted manually to fool the server into + believing you had a previous connection). To use previously stored cookies, + you run curl like: + + curl --cookie stored_cookies_in_file http://www.example.com + + Curl's "cookie engine" gets enabled when you use the + [`--cookie`](https://curl.se/docs/manpage.html#-b) option. If you only + want curl to understand received cookies, use `--cookie` with a file that + does not exist. Example, if you want to let curl understand cookies from a + page and follow a location (and thus possibly send back cookies it received), + you can invoke it like: + + curl --cookie nada --location http://www.example.com + + Curl has the ability to read and write cookie files that use the same file + format that Netscape and Mozilla once used. It is a convenient way to share + cookies between scripts or invokes. The `--cookie` (`-b`) switch + automatically detects if a given file is such a cookie file and parses it, + and by using the `--cookie-jar` (`-c`) option you will make curl write a new + cookie file at the end of an operation: + + curl --cookie cookies.txt --cookie-jar newcookies.txt \ + http://www.example.com + +# HTTPS + +## HTTPS is HTTP secure + + There are a few ways to do secure HTTP transfers. By far the most common + protocol for doing this is what is generally known as HTTPS, HTTP over + SSL. SSL encrypts all the data that is sent and received over the network and + thus makes it harder for attackers to spy on sensitive information. + + SSL (or TLS as the current version of the standard is called) offers a set of + advanced features to do secure transfers over HTTP. + + Curl supports encrypted fetches when built to use a TLS library and it can be + built to use one out of a fairly large set of libraries - `curl -V` will show + which one your curl was built to use (if any!). To get a page from an HTTPS + server, simply run curl like: + + curl https://secure.example.com + +## Certificates + + In the HTTPS world, you use certificates to validate that you are the one + you claim to be, as an addition to normal passwords. Curl supports client- + side certificates. All certificates are locked with a pass phrase, which you + need to enter before the certificate can be used by curl. The pass phrase + can be specified on the command line or if not, entered interactively when + curl queries for it. Use a certificate with curl on an HTTPS server like: + + curl --cert mycert.pem https://secure.example.com + + curl also tries to verify that the server is who it claims to be, by + verifying the server's certificate against a locally stored CA cert + bundle. Failing the verification will cause curl to deny the connection. You + must then use [`--insecure`](https://curl.se/docs/manpage.html#-k) + (`-k`) in case you want to tell curl to ignore that the server cannot be + verified. + + More about server certificate verification and ca cert bundles can be read in + the [`SSLCERTS` document](https://curl.se/docs/sslcerts.html). + + At times you may end up with your own CA cert store and then you can tell + curl to use that to verify the server's certificate: + + curl --cacert ca-bundle.pem https://example.com/ + +# Custom Request Elements + +## Modify method and headers + + Doing fancy stuff, you may need to add or change elements of a single curl + request. + + For example, you can change the POST method to `PROPFIND` and send the data + as `Content-Type: text/xml` (instead of the default `Content-Type`) like + this: + + curl --data "" --header "Content-Type: text/xml" \ + --request PROPFIND example.com + + You can delete a default header by providing one without content. Like you + can ruin the request by chopping off the `Host:` header: + + curl --header "Host:" http://www.example.com + + You can add headers the same way. Your server may want a `Destination:` + header, and you can add it: + + curl --header "Destination: http://nowhere" http://example.com + +## More on changed methods + + It should be noted that curl selects which methods to use on its own + depending on what action to ask for. `-d` will do POST, `-I` will do HEAD and + so on. If you use the [`--request`](https://curl.se/docs/manpage.html#-X) / + `-X` option you can change the method keyword curl selects, but you will not + modify curl's behavior. This means that if you for example use -d "data" to + do a POST, you can modify the method to a `PROPFIND` with `-X` and curl will + still think it sends a POST. You can change the normal GET to a POST method + by simply adding `-X POST` in a command line like: + + curl -X POST http://example.org/ + + curl will however still act as if it sent a GET so it will not send any + request body etc. + +# Web Login + +## Some login tricks + + While not strictly just HTTP related, it still causes a lot of people + problems so here's the executive run-down of how the vast majority of all + login forms work and how to login to them using curl. + + It can also be noted that to do this properly in an automated fashion, you + will most certainly need to script things and do multiple curl invokes etc. + + First, servers mostly use cookies to track the logged-in status of the + client, so you will need to capture the cookies you receive in the + responses. Then, many sites also set a special cookie on the login page (to + make sure you got there through their login page) so you should make a habit + of first getting the login-form page to capture the cookies set there. + + Some web-based login systems feature various amounts of JavaScript, and + sometimes they use such code to set or modify cookie contents. Possibly they + do that to prevent programmed logins, like this manual describes how to... + Anyway, if reading the code is not enough to let you repeat the behavior + manually, capturing the HTTP requests done by your browsers and analyzing the + sent cookies is usually a working method to work out how to shortcut the + JavaScript need. + + In the actual `
` tag for the login, lots of sites fill-in + random/session or otherwise secretly generated hidden tags and you may need + to first capture the HTML code for the login form and extract all the hidden + fields to be able to do a proper login POST. Remember that the contents need + to be URL encoded when sent in a normal POST. + +# Debug + +## Some debug tricks + + Many times when you run curl on a site, you will notice that the site does not + seem to respond the same way to your curl requests as it does to your + browser's. + + Then you need to start making your curl requests more similar to your + browser's requests: + + - Use the `--trace-ascii` option to store fully detailed logs of the requests + for easier analyzing and better understanding + + - Make sure you check for and use cookies when needed (both reading with + `--cookie` and writing with `--cookie-jar`) + + - Set user-agent (with [`-A`](https://curl.se/docs/manpage.html#-A)) to + one like a recent popular browser does + + - Set referer (with [`-E`](https://curl.se/docs/manpage.html#-E)) like + it is set by the browser + + - If you use POST, make sure you send all the fields and in the same order as + the browser does it. + +## Check what the browsers do + + A good helper to make sure you do this right, is the web browsers' developers + tools that let you view all headers you send and receive (even when using + HTTPS). + + A more raw approach is to capture the HTTP traffic on the network with tools + such as Wireshark or tcpdump and check what headers that were sent and + received by the browser. (HTTPS forces you to use `SSLKEYLOGFILE` to do + that.) diff --git a/docs/URL-SYNTAX.md b/docs/URL-SYNTAX.md new file mode 100644 index 0000000..011a32c --- /dev/null +++ b/docs/URL-SYNTAX.md @@ -0,0 +1,391 @@ +# URL syntax and their use in curl + +## Specifications + +The official "URL syntax" is primarily defined in these two different +specifications: + + - [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) (although URL is called + "URI" in there) + - [The WHATWG URL Specification](https://url.spec.whatwg.org/) + +RFC 3986 is the earlier one, and curl has always tried to adhere to that one +(since it shipped in January 2005). + +The WHATWG URL spec was written later, is incompatible with the RFC 3986 and +changes over time. + +## Variations + +URL parsers as implemented in browsers, libraries and tools usually opt to +support one of the mentioned specifications. Bugs, differences in +interpretations and the moving nature of the WHATWG spec does however make it +unlikely that multiple parsers treat URLs the same way. + +## Security + +Due to the inherent differences between URL parser implementations, it is +considered a security risk to mix different implementations and assume the +same behavior! + +For example, if you use one parser to check if a URL uses a good hostname or +the correct auth field, and then pass on that same URL to a *second* parser, +there will always be a risk it treats the same URL differently. There is no +right and wrong in URL land, only differences of opinions. + +libcurl offers a separate API to its URL parser for this reason, among others. + +Applications may at times find it convenient to allow users to specify URLs +for various purposes and that string would then end up fed to curl. Getting a +URL from an external untrusted party and using it with curl brings several +security concerns: + +1. If you have an application that runs as or in a server application, getting + an unfiltered URL can trick your application to access a local resource + instead of a remote resource. Protecting yourself against localhost accesses + is hard when accepting user provided URLs. + +2. Such custom URLs can access other ports than you planned as port numbers + are part of the regular URL format. The combination of a local host and a + custom port number can allow external users to play tricks with your local + services. + +3. Such a URL might use other schemes than you thought of or planned for. + +## "RFC 3986 plus" + +curl recognizes a URL syntax that we call "RFC 3986 plus". It is grounded on +the well established RFC 3986 to make sure previously written command lines and +curl using scripts will remain working. + +curl's URL parser allows a few deviations from the spec in order to +inter-operate better with URLs that appear in the wild. + +### spaces + +A URL provided to curl cannot contain spaces. They need to be provided URL +encoded to be accepted in a URL by curl. + +An exception to this rule: `Location:` response headers that indicate to a +client where a resource has been redirected to, sometimes contain spaces. This +is a violation of RFC 3986 but is fine in the WHATWG spec. curl handles these +by re-encoding them to `%20`. + +### non-ASCII + +Byte values in a provided URL that are outside of the printable ASCII range +are percent-encoded by curl. + +### multiple slashes + +An absolute URL always starts with a "scheme" followed by a colon. For all the +schemes curl supports, the colon must be followed by two slashes according to +RFC 3986 but not according to the WHATWG spec - which allows one to infinity +amount. + +curl allows one, two or three slashes after the colon to still be considered a +valid URL. + +### "scheme-less" + +curl supports "URLs" that do not start with a scheme. This is not supported by +any of the specifications. This is a shortcut to entering URLs that was +supported by browsers early on and has been mimicked by curl. + +Based on what the hostname starts with, curl will "guess" what protocol to +use: + + - `ftp.` means FTP + - `dict.` means DICT + - `ldap.` means LDAP + - `imap.` means IMAP + - `smtp.` means SMTP + - `pop3.` means POP3 + - all other means HTTP + +### globbing letters + +The curl command line tool supports "globbing" of URLs. It means that you can +create ranges and lists using `[N-M]` and `{one,two,three}` sequences. The +letters used for this (`[]{}`) are reserved in RFC 3986 and can therefore not +legitimately be part of such a URL. + +They are however not reserved or special in the WHATWG specification, so +globbing can mess up such URLs. Globbing can be turned off for such occasions +(using `--globoff`). + +# URL syntax details + +A URL may consist of the following components - many of them are optional: + + [scheme][divider][userinfo][hostname][port number][path][query][fragment] + +Each component is separated from the following component with a divider +character or string. + +For example, this could look like: + + http://user:password@www.example.com:80/index.html?foo=bar#top + +## Scheme + +The scheme specifies the protocol to use. A curl build can support a few or +many different schemes. You can limit what schemes curl should accept. + +curl supports the following schemes on URLs specified to transfer. They are +matched case insensitively: + +`dict`, `file`, `ftp`, `ftps`, `gopher`, `gophers`, `http`, `https`, `imap`, +`imaps`, `ldap`, `ldaps`, `mqtt`, `pop3`, `pop3s`, `rtmp`, `rtmpe`, `rtmps`, +`rtmpt`, `rtmpte`, `rtmpts`, `rtsp`, `smb`, `smbs`, `smtp`, `smtps`, `telnet`, +`tftp` + +When the URL is specified to identify a proxy, curl recognizes the following +schemes: + +`http`, `https`, `socks4`, `socks4a`, `socks5`, `socks5h`, `socks` + +## Userinfo + +The userinfo field can be used to set user name and password for +authentication purposes in this transfer. The use of this field is discouraged +since it often means passing around the password in plain text and is thus a +security risk. + +URLs for IMAP, POP3 and SMTP also support *login options* as part of the +userinfo field. They are provided as a semicolon after the password and then +the options. + +## Hostname + +The hostname part of the URL contains the address of the server that you want +to connect to. This can be the fully qualified domain name of the server, the +local network name of the machine on your network or the IP address of the +server or machine represented by either an IPv4 or IPv6 address (within +brackets). For example: + + http://www.example.com/ + + http://hostname/ + + http://192.168.0.1/ + + http://[2001:1890:1112:1::20]/ + +### "localhost" + +Starting in curl 7.77.0, curl uses loopback IP addresses for the name +`localhost`: `127.0.0.1` and `::1`. It does not resolve the name using the +resolver functions. + +This is done to make sure the host accessed is truly the localhost - the local +machine. + +### IDNA + +If curl was built with International Domain Name (IDN) support, it can also +handle host names using non-ASCII characters. + +When built with libidn2, curl uses the IDNA 2008 standard. This is equivalent +to the WHATWG URL spec, but differs from certain browsers that use IDNA 2003 +Transitional Processing. The two standards have a huge overlap but differ +slightly, perhaps most famously in how they deal with the German "double s" +(`ß`). + +When winidn is used, curl uses IDNA 2003 Transitional Processing, like the rest +of Windows. + +## Port number + +If there is a colon after the hostname, that should be followed by the port +number to use. 1 - 65535. curl also supports a blank port number field - but +only if the URL starts with a scheme. + +If the port number is not specified in the URL, curl will used a default port +based on the provide scheme: + +DICT 2628, FTP 21, FTPS 990, GOPHER 70, GOPHERS 70, HTTP 80, HTTPS 443, +IMAP 132, IMAPS 993, LDAP 369, LDAPS 636, MQTT 1883, POP3 110, POP3S 995, +RTMP 1935, RTMPS 443, RTMPT 80, RTSP 554, SCP 22, SFTP 22, SMB 445, SMBS 445, +SMTP 25, SMTPS 465, TELNET 23, TFTP 69 + +# Scheme specific behaviors + +## FTP + +The path part of an FTP request specifies the file to retrieve and from which +directory. If the file part is omitted then libcurl downloads the directory +listing for the directory specified. If the directory is omitted then the +directory listing for the root / home directory will be returned. + +FTP servers typically put the user in its "home directory" after login, which +then differs between users. To explicitly specify the root directory of an FTP +server, start the path with double slash `//` or `/%2f` (2F is the hexadecimal +value of the ascii code for the slash). + +## FILE + +When a `FILE://` URL is accessed on Windows systems, it can be crafted in a +way so that Windows attempts to connect to a (remote) machine when curl wants +to read or write such a path. + +curl only allows the hostname part of a FILE URL to be one out of these three +alternatives: `localhost`, `127.0.0.1` or blank ("", zero characters). +Anything else will make curl fail to parse the URL. + +### Windows-specific FILE details + +curl accepts that the FILE URL's path starts with a "drive letter". That is a +single letter `a` to `z` followed by a colon or a pipe character (`|`). + +The Windows operating system itself will convert some file accesses to perform +network accesses over SMB/CIFS, through several different file path patterns. +This way, a `file://` URL passed to curl *might* be converted into a network +access inadvertently and unknowingly to curl. This is a Windows feature curl +cannot control or disable. + +## IMAP + +The path part of an IMAP request not only specifies the mailbox to list or +select, but can also be used to check the `UIDVALIDITY` of the mailbox, to +specify the `UID`, `SECTION` and `PARTIAL` octets of the message to fetch and +to specify what messages to search for. + +A top level folder list: + + imap://user:password@mail.example.com + +A folder list on the user's inbox: + + imap://user:password@mail.example.com/INBOX + +Select the user's inbox and fetch message with `uid = 1`: + + imap://user:password@mail.example.com/INBOX/;UID=1 + +Select the user's inbox and fetch the first message in the mail box: + + imap://user:password@mail.example.com/INBOX/;MAILINDEX=1 + +Select the user's inbox, check the `UIDVALIDITY` of the mailbox is 50 and +fetch message 2 if it is: + + imap://user:password@mail.example.com/INBOX;UIDVALIDITY=50/;UID=2 + +Select the user's inbox and fetch the text portion of message 3: + + imap://user:password@mail.example.com/INBOX/;UID=3/;SECTION=TEXT + +Select the user's inbox and fetch the first 1024 octets of message 4: + + imap://user:password@mail.example.com/INBOX/;UID=4/;PARTIAL=0.1024 + +Select the user's inbox and check for NEW messages: + + imap://user:password@mail.example.com/INBOX?NEW + +Select the user's inbox and search for messages containing "shadows" in the +subject line: + + imap://user:password@mail.example.com/INBOX?SUBJECT%20shadows + +Searching via the query part of the URL `?` is a search request for the +results to be returned as message sequence numbers (`MAILINDEX`). It is +possible to make a search request for results to be returned as unique ID +numbers (`UID`) by using a custom curl request via `-X`. `UID` numbers are +unique per session (and multiple sessions when `UIDVALIDITY` is the same). For +example, if you are searching for `"foo bar"` in header+body (`TEXT`) and you +want the matching `MAILINDEX` numbers returned then you could search via URL: + + imap://user:password@mail.example.com/INBOX?TEXT%20%22foo%20bar%22 + +If you want matching `UID` numbers you have to use a custom request: + + imap://user:password@mail.example.com/INBOX -X "UID SEARCH TEXT \"foo bar\"" + +For more information about IMAP commands please see RFC 9051. For more +information about the individual components of an IMAP URL please see RFC 5092. + +* Note old curl versions would `FETCH` by message sequence number when `UID` +was specified in the URL. That was a bug fixed in 7.62.0, which added +`MAILINDEX` to `FETCH` by mail sequence number. + +## LDAP + +The path part of a LDAP request can be used to specify the: Distinguished +Name, Attributes, Scope, Filter and Extension for a LDAP search. Each field is +separated by a question mark and when that field is not required an empty +string with the question mark separator should be included. + +Search for the `DN` as `My Organization`: + + ldap://ldap.example.com/o=My%20Organization + +the same search but will only return `postalAddress` attributes: + + ldap://ldap.example.com/o=My%20Organization?postalAddress + +Search for an empty `DN` and request information about the +`rootDomainNamingContext` attribute for an Active Directory server: + + ldap://ldap.example.com/?rootDomainNamingContext + +For more information about the individual components of a LDAP URL please +see [RFC 4516](https://datatracker.ietf.org/doc/html/rfc4516). + +## POP3 + +The path part of a POP3 request specifies the message ID to retrieve. If the +ID is not specified then a list of waiting messages is returned instead. + +## SCP + +The path part of an SCP URL specifies the path and file to retrieve or +upload. The file is taken as an absolute path from the root directory on the +server. + +To specify a path relative to the user's home directory on the server, prepend +`~/` to the path portion. + +## SFTP + +The path part of an SFTP URL specifies the file to retrieve or upload. If the +path ends with a slash (`/`) then a directory listing is returned instead of a +file. If the path is omitted entirely then the directory listing for the root +/ home directory will be returned. + +## SMB +The path part of a SMB request specifies the file to retrieve and from what +share and directory or the share to upload to and as such, may not be omitted. +If the user name is embedded in the URL then it must contain the domain name +and as such, the backslash must be URL encoded as %2f. + +When uploading to SMB, the size of the file needs to be known ahead of time, +meaning that you can upload a file passed to curl over a pipe like stdin. + +curl supports SMB version 1 (only) + +## SMTP + +The path part of a SMTP request specifies the hostname to present during +communication with the mail server. If the path is omitted, then libcurl will +attempt to resolve the local computer's hostname. However, this may not +return the fully qualified domain name that is required by some mail servers +and specifying this path allows you to set an alternative name, such as your +machine's fully qualified domain name, which you might have obtained from an +external function such as gethostname or getaddrinfo. + +The default smtp port is 25. Some servers use port 587 as an alternative. + +## RTMP + +There is no official URL spec for RTMP so libcurl uses the URL syntax supported +by the underlying librtmp library. It has a syntax where it wants a +traditional URL, followed by a space and a series of space-separated +`name=value` pairs. + +While space is not typically a "legal" letter, libcurl accepts them. When a +user wants to pass in a `#` (hash) character it will be treated as a fragment +and get cut off by libcurl if provided literally. You will instead have to +escape it by providing it as backslash and its ASCII value in hexadecimal: +`\23`. diff --git a/docs/VERSIONS.md b/docs/VERSIONS.md new file mode 100644 index 0000000..0ec9cd5 --- /dev/null +++ b/docs/VERSIONS.md @@ -0,0 +1,57 @@ +Version Numbers and Releases +============================ + + Curl is not only curl. Curl is also libcurl. They are actually individually + versioned, but they usually follow each other closely. + + The version numbering is always built up using the same system: + + X.Y.Z + + - X is main version number + - Y is release number + - Z is patch number + +## Bumping numbers + + One of these numbers will get bumped in each new release. The numbers to the + right of a bumped number will be reset to zero. + + The main version number will get bumped when *really* big, world colliding + changes are made. The release number is bumped when changes are performed or + things/features are added. The patch number is bumped when the changes are + mere bugfixes. + + It means that after release 1.2.3, we can release 2.0.0 if something really + big has been made, 1.3.0 if not that big changes were made or 1.2.4 if only + bugs were fixed. + + Bumping, as in increasing the number with 1, is unconditionally only + affecting one of the numbers (except the ones to the right of it, that may be + set to zero). 1 becomes 2, 3 becomes 4, 9 becomes 10, 88 becomes 89 and 99 + becomes 100. So, after 1.2.9 comes 1.2.10. After 3.99.3, 3.100.0 might come. + + All original curl source release archives are named according to the libcurl + version (not according to the curl client version that, as said before, might + differ). + + As a service to any application that might want to support new libcurl + features while still being able to build with older versions, all releases + have the libcurl version stored in the `curl/curlver.h` file using a static + numbering scheme that can be used for comparison. The version number is + defined as: + +```c +#define LIBCURL_VERSION_NUM 0xXXYYZZ +``` + + Where `XX`, `YY` and `ZZ` are the main version, release and patch numbers in + hexadecimal. All three number fields are always represented using two digits + (eight bits each). 1.2 would appear as "0x010200" while version 9.11.7 + appears as `0x090b07`. + + This 6-digit hexadecimal number is always a greater number in a more recent + release. It makes comparisons with greater than and less than work. + + This number is also available as three separate defines: + `LIBCURL_VERSION_MAJOR`, `LIBCURL_VERSION_MINOR` and `LIBCURL_VERSION_PATCH`. diff --git a/docs/VULN-DISCLOSURE-POLICY.md b/docs/VULN-DISCLOSURE-POLICY.md new file mode 100644 index 0000000..a008663 --- /dev/null +++ b/docs/VULN-DISCLOSURE-POLICY.md @@ -0,0 +1,293 @@ +# curl vulnerability disclosure policy + +This document describes how security vulnerabilities are handled in the curl +project. + +## Publishing Information + +All known and public curl or libcurl related vulnerabilities are listed on +[the curl website security page](https://curl.se/docs/security.html). + +Security vulnerabilities **should not** be entered in the project's public bug +tracker. + +## Vulnerability Handling + +The typical process for handling a new security vulnerability is as follows. + +No information should be made public about a vulnerability until it is +formally announced at the end of this process. That means, for example, that a +bug tracker entry must NOT be created to track the issue since that will make +the issue public and it should not be discussed on any of the project's public +mailing lists. Messages associated with any commits should not make any +reference to the security nature of the commit if done prior to the public +announcement. + +- The person discovering the issue, the reporter, reports the vulnerability on + [HackerOne](https://hackerone.com/curl). Issues filed there reach a handful + of selected and trusted people. + +- Messages that do not relate to the reporting or managing of an undisclosed + security vulnerability in curl or libcurl are ignored and no further action + is required. + +- A person in the security team responds to the original report to acknowledge + that a human has seen the report. + +- The security team investigates the report and either rejects it or accepts + it. See below for examples of problems that are not considered + vulnerabilities. + +- If the report is rejected, the team writes to the reporter to explain why. + +- If the report is accepted, the team writes to the reporter to let them + know it is accepted and that they are working on a fix. + +- The security team discusses the problem, works out a fix, considers the + impact of the problem and suggests a release schedule. This discussion + should involve the reporter as much as possible. + +- The release of the information should be "as soon as possible" and is most + often synchronized with an upcoming release that contains the fix. If the + reporter, or anyone else involved, thinks the next planned release is too + far away, then a separate earlier release should be considered. + +- Write a security advisory draft about the problem that explains what the + problem is, its impact, which versions it affects, solutions or workarounds, + when the release is out and make sure to credit all contributors properly. + Figure out the CWE (Common Weakness Enumeration) number for the flaw. See + [SECURITY-ADVISORY](https://curl.se/dev/advisory.html) for help on creating + the advisory. + +- Request a CVE number from HackerOne + +- Update the "security advisory" with the CVE number. + +- The security team commits the fix in a private branch. The commit message + should ideally contain the CVE number. If the severity level of the issue is + set to Low or Medium, the fix is allowed to get merged into the master + repository via a normal PR - but without mentioning it being a security + vulnerability. + +- The monetary reward part of the bug-bounty is managed by the Internet Bug + Bounty team and the reporter is asked to request the reward from them after + the issue has been completely handled and published by curl. + +- No more than 10 days before release, inform + [distros@openwall](https://oss-security.openwall.org/wiki/mailing-lists/distros) + to prepare them about the upcoming public security vulnerability + announcement - attach the advisory draft for information with CVE and + current patch. 'distros' does not accept an embargo longer than 14 days and + they do not care for Windows-specific flaws. + +- No more than 48 hours before the release, the private branch is merged into + the master branch and pushed. Once pushed, the information is accessible to + the public and the actual release should follow suit immediately afterwards. + The time between the push and the release is used for final tests and + reviews. + +- The project team creates a release that includes the fix. + +- The project team announces the release and the vulnerability to the world in + the same manner we always announce releases. It gets sent to the + curl-announce, curl-library and curl-users mailing lists. + +- The security webpage on the website should get the new vulnerability + mentioned. + +## security (at curl dot se) + +This is a private mailing list for discussions on and about curl security +issues. + +Who is on this list? There are a couple of criteria you must meet, and then we +might ask you to join the list or you can ask to join it. It really is not a +formal process. We basically only require that you have a long-term presence +in the curl project and you have shown an understanding for the project and +its way of working. You must have been around for a good while and you should +have no plans of vanishing in the near future. + +We do not make the list of participants public mostly because it tends to vary +somewhat over time and a list somewhere will only risk getting outdated. + +## Publishing Security Advisories + +1. Write up the security advisory, using markdown syntax. Use the same + subtitles as last time to maintain consistency. + +2. Name the advisory file after the allocated CVE id. + +3. Add a line on the top of the array in `curl-www/docs/vuln.pm`. + +4. Put the new advisory markdown file in the `curl-www/docs/` directory. Add it + to the git repository. + +5. Run `make` in your local web checkout and verify that things look fine. + +6. On security advisory release day, push the changes on the curl-www + repository's remote master branch. + +## HackerOne + +Request the issue to be disclosed. If there are sensitive details present in +the report and discussion, those should be redacted from the disclosure. The +default policy is to disclose as much as possible as soon as the vulnerability +has been published. + +## Bug Bounty + +See [BUG-BOUNTY](https://curl.se/docs/bugbounty.html) for details on the +bug bounty program. + +# Severity levels + +The curl project's security team rates security problems using four severity +levels depending how serious we consider the problem to be. We use **Low**, +**Medium**, **High** and **Critical**. We refrain from using numerical scoring +of vulnerabilities. + +When deciding severity level on a particular issue, we take all the factors +into account: attack vector, attack complexity, required privileges, necessary +build configuration, protocols involved, platform specifics and also what +effects a possible exploit or trigger of the issue can lead do, including +confidentiality, integrity or availability problems. + +## Low + +This is a security problem that is truly hard or unlikely to exploit or +trigger. Due to timing, platform requirements or the fact that options or +protocols involved are rare etc. [Past +example](https://curl.se/docs/CVE-2022-43552.html) + +## Medium + +This is a security problem that is less hard than **Low** to exploit or +trigger. Less strict timing, wider platforms availability or involving more +widely used options or protocols. A problem that usually needs something else +to also happen to become serious. [Past +example](https://curl.se/docs/CVE-2022-32206.html) + +## High + +This issue in itself a serious problem with real world impact. Flaws that can +easily compromise the confidentiality, integrity or availability of resources. +Exploiting or triggering this problem is not hard. [Past +example](https://curl.se/docs/CVE-2019-3822.html) + +## Critical + +Easily exploitable by a remote unauthenticated attacker and lead to system +compromise (arbitrary code execution) without requiring user interaction, with +a common configuration on a popular platform. This issue has few restrictions +and requirements and can be exploited easily using most curl configurations. +[Past example](https://curl.se/docs/CVE-2000-0973.html) + +# Not security issues + +This is an incomplete list of issues that are not considered vulnerabilities. + +## Small memory leaks + +We do not consider a small memory leak a security problem; even if the amount +of allocated memory grows by a small amount every now and then. Long-living +applications and services already need to have counter-measures and deal with +growing memory usage, be it leaks or just increased use. A small memory or +resource leak is then expected to *not* cause a security problem. + +Of course there can be a discussion if a leak is small or not. A large leak +can be considered a security problem due to the DOS risk. If leaked memory +contains sensitive data it might also qualify as a security problem. + +## Never-ending transfers + +We do not consider flaws that cause a transfer to never end to be a security +problem. There are already several benign and likely reasons for transfers to +stall and never end, so applications that cannot deal with never-ending +transfers already need to have counter-measures established. + +If the problem avoids the regular counter-measures when it causes a never- +ending transfer, it might be a security problem. + +## Not practically possible + +If the flaw or vulnerability cannot practically get executed on existing +hardware it is not a security problem. + +## API misuse + +If a reported issue only triggers by an application using the API in a way +that is not documented to work or even documented to not work, it is probably +not going to be considered a security problem. We only guarantee secure and +proper functionality when the APIs are used as expected and documented. + +There can be a discussion about what the documentation actually means and how +to interpret the text, which might end up with us still agreeing that it is a +security problem. + +## Local attackers already present + +When an issue can only be attacked or misused by an attacker present on the +local system or network, the bar is raised. If a local user wrongfully has +elevated rights on your system enough to attack curl, they can probably +already do much worse harm and the problem is not really in curl. + +## Experiments + +Vulnerabilities in features which are off by default (in the build) and +documented as experimental, are not eligible for a reward and we do not +consider them security problems. + +## URL inconsistencies + +URL parser inconsistencies between browsers and curl are expected and are not +considered security vulnerabilities. The WHATWG URL Specification and RFC +3986+ (the plus meaning that it is an extended version) [are not completely +interoperable](https://github.com/bagder/docs/blob/master/URL-interop.md). + +Obvious parser bugs can still be vulnerabilities of course. + +## Visible command line arguments + +The curl command blanks the contents of a number of command line arguments to +prevent them from appearing in process listings. It does not blank all +arguments even if some of them that are not blanked might contain sensitive +data. We consider this functionality a best-effort and omissions are not +security vulnerabilities. + + - not all systems allow the arguments to be blanked in the first place + - since curl blanks the argument itself they will be readable for a short + moment no matter what + - virtually every argument can contain sensitive data, depending on use + - blanking all arguments would make it impractical for users to differentiate + curl command lines in process listings + +## Busy-loops + +Busy-loops that consume 100% CPU time but eventually end (perhaps due to a set +timeout value or otherwise) are not considered security problems. Applications +are supposed to already handle situations when the transfer loop legitimately +consumes 100% CPU time, so while a prolonged such busy-loop is a nasty bug, we +do not consider it a security problem. + +## Saving files + +curl cannot protect against attacks where an attacker has write access to the +same directory where curl is directed to save files. + +## Tricking a user to run a command line + +A creative, misleading or funny looking command line is not a security +problem. The curl command line tool takes options and URLs on the command line +and if an attacker can trick the user to run a specifically crafted curl +command line, all bets are off. Such an attacker can just as well have the +user run a much worse command that can do something fatal (like +`sudo rm -rf /`). + +## Terminal output and escape sequences + +Content that is transferred from a server and gets displayed in a terminal by +curl may contain escape sequences or use other tricks to fool the user. This +is curl working as designed and is not a curl security problem. Escape +sequences, moving cursor, changing color etc, is also frequently used for +good. To reduce the risk of getting fooled, save files and browse them after +download using a display method that minimizes risks. diff --git a/docs/WEBSOCKET.md b/docs/WEBSOCKET.md new file mode 100644 index 0000000..c3967b8 --- /dev/null +++ b/docs/WEBSOCKET.md @@ -0,0 +1,135 @@ + + +# WebSocket in curl + +## URL + +WebSocket communication with libcurl is done by setting up a transfer to a URL +using the `ws://` or `wss://` URL schemes. The latter one being the secure +version done over HTTPS. + +When using `wss://` to do WebSocket over HTTPS, the standard TLS and HTTPS +options will be acknowledged for the CA, verification of server certificate +etc. + +WebSocket communication is done by upgrading a connection from either HTTP or +HTTPS. When given a WebSocket URL to work with, libcurl considers it a +transfer failure if the upgrade procedure fails. This means that a plain HTTP +200 response code is considered an error for this work. + +## API + +The WebSocket API is described in the individual man pages for the new API. + +WebSocket with libcurl can be done two ways. + +1. Get the WebSocket frames from the server sent to the write callback. You + can then respond with `curl_ws_send()` from within the callback (or outside + of it). + +2. Set `CURLOPT_CONNECT_ONLY` to 2L (new for WebSocket), which makes libcurl + do an HTTP GET + `Upgrade:` request plus response in the + `curl_easy_perform()` call before it returns and then you can use + `curl_ws_recv()` and `curl_ws_send()` to receive and send WebSocket frames + from and to the server. + +The new options to `curl_easy_setopt()`: + + `CURLOPT_WS_OPTIONS` - to control specific behavior. `CURLWS_RAW_MODE` makes + libcurl provide all WebSocket traffic raw in the callback. + +The new function calls: + + `curl_ws_recv()` - receive a WebSocket frame + + `curl_ws_send()` - send a WebSocket frame + + `curl_ws_meta()` - return WebSocket metadata within a write callback + +## Max frame size + +The current implementation only supports frame sizes up to a max (64K right +now). This is because the API delivers full frames and it then cannot manage +the full 2^63 bytes size. + +If we decide we need to support (much) larger frames than 64K, we need to +adjust the API accordingly to be able to deliver partial frames in both +directions. + +## Errors + +If the given WebSocket URL (using `ws://` or `wss://`) fails to get upgraded +via a 101 response code and instead gets another response code back from the +HTTP server - the transfer will return `CURLE_HTTP_RETURNED_ERROR` for that +transfer. Note then that even 2xx response codes are then considered error +since it failed to provide a WebSocket transfer. + +## Test suite + +I looked for an existing small WebSocket server implementation with maximum +flexibility to dissect and cram into the test suite but I ended up deciding +that extending the existing test suite server sws to deal with WebSocket +might be the better way. + +- This server is already integrated and working in the test suite + +- We want maximum control and ability to generate broken protocol and negative + tests as well. A dumber and simpler TCP server could then be easier to + massage into this than a "proper" WebSocket server. + +## Command line tool WebSocket + +The plan is to make curl do WebSocket similar to telnet/nc. That part of the +work has not been started. + +Ideas: + + - Read stdin and send off as messages. Consider newline as end of fragment. + (default to text? offer option to set binary) + - Respond to PINGs automatically + - Issue PINGs at some default interval (option to switch off/change interval?) + - Allow `-d` to specify (initial) data to send (should the format allow for + multiple separate frames?) + - Exit after N messages received, where N can be zero. + +## Future work + +- Verify the Sec-WebSocket-Accept response. It requires a sha-1 function. +- Verify Sec-WebSocket-Extensions and Sec-WebSocket-Protocol in the response +- Make WebSocket work with hyper +- Consider a `curl_ws_poll()` +- Make sure WebSocket code paths are fuzzed +- Add client-side PING interval +- Provide option to disable PING-PONG automation +- Support compression (`CURLWS_COMPRESS`) + +## Why not libWebSocket + +libWebSocket is said to be a solid, fast and efficient WebSocket library with +a vast amount of users. My plan was originally to build upon it to skip having +to implement the low level parts of WebSocket myself. + +Here are the reasons why I have decided to move forward with WebSocket in +curl **without using libWebSocket**: + +- doxygen generated docs only makes them hard to navigate. No tutorial, no + clearly written explanatory pages for specific functions. + +- seems (too) tightly integrated with a specific TLS library, while we want to + support WebSocket with whatever TLS library libcurl was already made to + work with. + +- seems (too) tightly integrated with event libraries + +- the references to threads and thread-pools in code and APIs indicate too + much logic for our purposes + +- "bloated" - it is a *huge* library that is actually more lines of code than + libcurl itself + +- WebSocket is a fairly simple protocol on the network/framing layer so + making a homegrown handling of it should be fine diff --git a/docs/cmdline-opts/CMakeLists.txt b/docs/cmdline-opts/CMakeLists.txt new file mode 100644 index 0000000..ee158df --- /dev/null +++ b/docs/cmdline-opts/CMakeLists.txt @@ -0,0 +1,37 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +set(MANPAGE "${CURL_BINARY_DIR}/docs/curl.1") + +# Load DPAGES and OTHERPAGES from shared file +transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") + +add_custom_command(OUTPUT "${MANPAGE}" + COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && "${PERL_EXECUTABLE}" "./gen.pl" mainpage ${DPAGES} > "${MANPAGE}" + VERBATIM +) +add_custom_target(generate-curl.1 ALL DEPENDS "${MANPAGE}") +if(NOT CURL_DISABLE_INSTALL) + install(FILES "${MANPAGE}" DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +endif() diff --git a/docs/cmdline-opts/MANPAGE.md b/docs/cmdline-opts/MANPAGE.md new file mode 100644 index 0000000..951cbe8 --- /dev/null +++ b/docs/cmdline-opts/MANPAGE.md @@ -0,0 +1,110 @@ + + +# curl man page generator + +This is the curl man page generator. It generates a single nroff man page +output from the set of sources files in this directory. + +The `mainpage.idx` file lists all files that are rendered in that order to +produce the output. The magic `%options` keyword inserts all command line +options documented. + +The `%options` documentation is created with one source file for each +supported command line option. + +The documentation file format is described below. It is meant to look similar +to markdown which is why it uses `.md` file extensions. + +## Option files + +Each command line option is described in a file named `.d`, where +option name is written without any prefixing dashes. Like the file name for +the `-v, --verbose` option is named `verbose.d`. + +Each file has a set of meta-data in the top of the file, followed by a body of +text. + +The documentation files that do not document options have no meta-data part. + +A line that starts with ``. + +### Meta-data + + --- (start of meta-data) + Added: (version number in which this was added) + Arg: (the argument the option takes) + c: (copyright line) + Example: + - (an example command line, without "curl" and can use `$URL`) + - (another example) + Experimental: yes (if so) + Help: (short text for the --help output for this option) + Long: (long form name, without dashes) + Magic: (description of "magic" options) + Multi: single/append/boolean/mutex/custom (if used more than once) + Mutexed: (space separated list of options this overrides, no dashes) + Protocols: (space separated list for which protocols this option works) + Requires: (space separated list of features this requires, no dashes) + Scope: global (if the option is global) + See-also: + - (a related option, no dashes) + - (another related option, no dashes) + Short: (single letter, without dash) + SPDX-License-Identifier: curl + Tags: (space separated list) + --- (end of meta-data) + +### Body + +The body of the description. Only refer to options with their long form option +version, like `--verbose`. The output generator replaces such option with the +correct markup that shows both short and long version. + +Text written within `*asterisks*` is shown using italics. Text within two +`**asterisks**` is shown using bold. + +Text that is prefixed with a space is treated like an "example" and gets +output in monospace. + +Within the body, describe a list of items like this: + + ## item 1 + description + + ## item 2 + second description + +The list is automatically terminated at end of file, or you can do it +explicitly with an empty "header": + + ## + +### Headers + +The `#` header can be used by non-option files and it produces produces a +`.SH` output. + +If the `#` header is used for a command line option file, that header is +simply ignored in the generated output. It can still serve a purpose in the +source file as it helps the user identify what option the file is for. + +### Variables + +There are three different "variables" that can be used when creating the +output. They need to be written within backticks in the source file (to escape +getting spellchecked by CI jobs): `%DATE`, `%VERSION` and `%GLOBALS`. + +## Generate + +`./gen.pl mainpage` + +This command outputs a single huge nroff file, meant to become `curl.1`. The +full curl man page. + +`./gen.pl listhelp` + +Generates a full `curl --help` output for all known command line options. diff --git a/docs/cmdline-opts/Makefile.am b/docs/cmdline-opts/Makefile.am new file mode 100644 index 0000000..e9b35ac --- /dev/null +++ b/docs/cmdline-opts/Makefile.am @@ -0,0 +1,44 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +AUTOMAKE_OPTIONS = foreign no-dependencies + +MANPAGE = $(top_builddir)/docs/curl.1 + +include Makefile.inc + +EXTRA_DIST = $(DPAGES) MANPAGE.md gen.pl $(SUPPORT) CMakeLists.txt mainpage.idx + +GEN = $(GN_$(V)) +GN_0 = @echo " GENERATE" $@; +GN_1 = +GN_ = $(GN_0) + +all: $(MANPAGE) + +$(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc gen.pl + $(GEN)(rm -f $(MANPAGE) && cd $(srcdir) && @PERL@ ./gen.pl mainpage $(DPAGES) > $(builddir)/manpage.tmp && mv $(builddir)/manpage.tmp $(MANPAGE)) + +listhelp: + ./gen.pl listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c diff --git a/docs/cmdline-opts/Makefile.in b/docs/cmdline-opts/Makefile.in new file mode 100644 index 0000000..507f191 --- /dev/null +++ b/docs/cmdline-opts/Makefile.in @@ -0,0 +1,916 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# Shared between Makefile.am and CMakeLists.txt +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = docs/cmdline-opts +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +depcomp = +am__maybe_remake_depfiles = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign no-dependencies +MANPAGE = $(top_builddir)/docs/curl.1 +SUPPORT = \ + _AUTHORS.md \ + _BUGS.md \ + _DESCRIPTION.md \ + _ENVIRONMENT.md \ + _EXITCODES.md \ + _FILES.md \ + _GLOBBING.md \ + _NAME.md \ + _OPTIONS.md \ + _OUTPUT.md \ + _PROGRESS.md \ + _PROTOCOLS.md \ + _PROXYPREFIX.md \ + _SEEALSO.md \ + _SYNOPSIS.md \ + _URL.md \ + _VARIABLES.md \ + _VERSION.md \ + _WWW.md + +DPAGES = \ + abstract-unix-socket.md \ + alt-svc.md \ + anyauth.md \ + append.md \ + aws-sigv4.md \ + basic.md \ + ca-native.md \ + cacert.md \ + capath.md \ + cert-status.md \ + cert-type.md \ + cert.md \ + ciphers.md \ + compressed-ssh.md \ + compressed.md \ + config.md \ + connect-timeout.md \ + connect-to.md \ + continue-at.md \ + cookie-jar.md \ + cookie.md \ + create-dirs.md \ + create-file-mode.md \ + crlf.md \ + crlfile.md \ + curves.md \ + data-ascii.md \ + data-binary.md \ + data-raw.md \ + data-urlencode.md \ + data.md \ + delegation.md \ + digest.md \ + disable-eprt.md \ + disable-epsv.md \ + disable.md \ + disallow-username-in-url.md \ + dns-interface.md \ + dns-ipv4-addr.md \ + dns-ipv6-addr.md \ + dns-servers.md \ + doh-cert-status.md \ + doh-insecure.md \ + doh-url.md \ + dump-header.md \ + egd-file.md \ + engine.md \ + etag-compare.md \ + etag-save.md \ + expect100-timeout.md \ + fail-early.md \ + fail-with-body.md \ + fail.md \ + false-start.md \ + form-escape.md \ + form-string.md \ + form.md \ + ftp-account.md \ + ftp-alternative-to-user.md \ + ftp-create-dirs.md \ + ftp-method.md \ + ftp-pasv.md \ + ftp-port.md \ + ftp-pret.md \ + ftp-skip-pasv-ip.md \ + ftp-ssl-ccc-mode.md \ + ftp-ssl-ccc.md \ + ftp-ssl-control.md \ + get.md \ + globoff.md \ + happy-eyeballs-timeout-ms.md \ + haproxy-protocol.md \ + haproxy-clientip.md \ + head.md \ + header.md \ + help.md \ + hostpubmd5.md \ + hostpubsha256.md \ + hsts.md \ + http0.9.md \ + http1.0.md \ + http1.1.md \ + http2-prior-knowledge.md \ + http2.md \ + http3.md \ + http3-only.md \ + ignore-content-length.md \ + include.md \ + insecure.md \ + interface.md \ + ipfs-gateway.md \ + ipv4.md \ + ipv6.md \ + json.md \ + junk-session-cookies.md \ + keepalive-time.md \ + key-type.md \ + key.md \ + krb.md \ + libcurl.md \ + limit-rate.md \ + list-only.md \ + local-port.md \ + location-trusted.md \ + location.md \ + login-options.md \ + mail-auth.md \ + mail-from.md \ + mail-rcpt-allowfails.md \ + mail-rcpt.md \ + manual.md \ + max-filesize.md \ + max-redirs.md \ + max-time.md \ + metalink.md \ + negotiate.md \ + netrc-file.md \ + netrc-optional.md \ + netrc.md \ + next.md \ + no-alpn.md \ + no-buffer.md \ + no-clobber.md \ + no-keepalive.md \ + no-npn.md \ + no-progress-meter.md \ + no-sessionid.md \ + noproxy.md \ + ntlm-wb.md \ + ntlm.md \ + oauth2-bearer.md \ + output-dir.md \ + output.md \ + parallel-immediate.md \ + parallel-max.md \ + parallel.md \ + pass.md \ + path-as-is.md \ + pinnedpubkey.md \ + post301.md \ + post302.md \ + post303.md \ + preproxy.md \ + progress-bar.md \ + proto-default.md \ + proto-redir.md \ + proto.md \ + proxy-anyauth.md \ + proxy-basic.md \ + proxy-ca-native.md \ + proxy-cacert.md \ + proxy-capath.md \ + proxy-cert-type.md \ + proxy-cert.md \ + proxy-ciphers.md \ + proxy-crlfile.md \ + proxy-digest.md \ + proxy-header.md \ + proxy-http2.md \ + proxy-insecure.md \ + proxy-key-type.md \ + proxy-key.md \ + proxy-negotiate.md \ + proxy-ntlm.md \ + proxy-pass.md \ + proxy-pinnedpubkey.md \ + proxy-service-name.md \ + proxy-ssl-allow-beast.md \ + proxy-ssl-auto-client-cert.md \ + proxy-tls13-ciphers.md \ + proxy-tlsauthtype.md \ + proxy-tlspassword.md \ + proxy-tlsuser.md \ + proxy-tlsv1.md \ + proxy-user.md \ + proxy.md \ + proxy1.0.md \ + proxytunnel.md \ + pubkey.md \ + quote.md \ + random-file.md \ + range.md \ + rate.md \ + raw.md \ + referer.md \ + remote-header-name.md \ + remote-name-all.md \ + remote-name.md \ + remote-time.md \ + remove-on-error.md \ + request-target.md \ + request.md \ + resolve.md \ + retry-all-errors.md \ + retry-connrefused.md \ + retry-delay.md \ + retry-max-time.md \ + retry.md \ + sasl-authzid.md \ + sasl-ir.md \ + service-name.md \ + show-error.md \ + silent.md \ + socks4.md \ + socks4a.md \ + socks5-basic.md \ + socks5-gssapi-nec.md \ + socks5-gssapi-service.md \ + socks5-gssapi.md \ + socks5-hostname.md \ + socks5.md \ + speed-limit.md \ + speed-time.md \ + ssl-allow-beast.md \ + ssl-auto-client-cert.md \ + ssl-no-revoke.md \ + ssl-reqd.md \ + ssl-revoke-best-effort.md \ + ssl.md \ + sslv2.md \ + sslv3.md \ + stderr.md \ + styled-output.md \ + suppress-connect-headers.md \ + tcp-fastopen.md \ + tcp-nodelay.md \ + telnet-option.md \ + tftp-blksize.md \ + tftp-no-options.md \ + time-cond.md \ + tls-max.md \ + tls13-ciphers.md \ + tlsauthtype.md \ + tlspassword.md \ + tlsuser.md \ + tlsv1.0.md \ + tlsv1.1.md \ + tlsv1.2.md \ + tlsv1.3.md \ + tlsv1.md \ + tr-encoding.md \ + trace-ascii.md \ + trace-config.md \ + trace-ids.md \ + trace-time.md \ + trace.md \ + unix-socket.md \ + upload-file.md \ + url.md \ + url-query.md \ + use-ascii.md \ + user-agent.md \ + user.md \ + variable.md \ + verbose.md \ + version.md \ + write-out.md \ + xattr.md + +EXTRA_DIST = $(DPAGES) MANPAGE.md gen.pl $(SUPPORT) CMakeLists.txt mainpage.idx +GEN = $(GN_$(V)) +GN_0 = @echo " GENERATE" $@; +GN_1 = +GN_ = $(GN_0) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.inc $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/cmdline-opts/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign docs/cmdline-opts/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/Makefile.inc $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +all: $(MANPAGE) + +$(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc gen.pl + $(GEN)(rm -f $(MANPAGE) && cd $(srcdir) && @PERL@ ./gen.pl mainpage $(DPAGES) > $(builddir)/manpage.tmp && mv $(builddir)/manpage.tmp $(MANPAGE)) + +listhelp: + ./gen.pl listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc new file mode 100644 index 0000000..428cc3b --- /dev/null +++ b/docs/cmdline-opts/Makefile.inc @@ -0,0 +1,305 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# Shared between Makefile.am and CMakeLists.txt + +SUPPORT = \ + _AUTHORS.md \ + _BUGS.md \ + _DESCRIPTION.md \ + _ENVIRONMENT.md \ + _EXITCODES.md \ + _FILES.md \ + _GLOBBING.md \ + _NAME.md \ + _OPTIONS.md \ + _OUTPUT.md \ + _PROGRESS.md \ + _PROTOCOLS.md \ + _PROXYPREFIX.md \ + _SEEALSO.md \ + _SYNOPSIS.md \ + _URL.md \ + _VARIABLES.md \ + _VERSION.md \ + _WWW.md + +DPAGES = \ + abstract-unix-socket.md \ + alt-svc.md \ + anyauth.md \ + append.md \ + aws-sigv4.md \ + basic.md \ + ca-native.md \ + cacert.md \ + capath.md \ + cert-status.md \ + cert-type.md \ + cert.md \ + ciphers.md \ + compressed-ssh.md \ + compressed.md \ + config.md \ + connect-timeout.md \ + connect-to.md \ + continue-at.md \ + cookie-jar.md \ + cookie.md \ + create-dirs.md \ + create-file-mode.md \ + crlf.md \ + crlfile.md \ + curves.md \ + data-ascii.md \ + data-binary.md \ + data-raw.md \ + data-urlencode.md \ + data.md \ + delegation.md \ + digest.md \ + disable-eprt.md \ + disable-epsv.md \ + disable.md \ + disallow-username-in-url.md \ + dns-interface.md \ + dns-ipv4-addr.md \ + dns-ipv6-addr.md \ + dns-servers.md \ + doh-cert-status.md \ + doh-insecure.md \ + doh-url.md \ + dump-header.md \ + egd-file.md \ + engine.md \ + etag-compare.md \ + etag-save.md \ + expect100-timeout.md \ + fail-early.md \ + fail-with-body.md \ + fail.md \ + false-start.md \ + form-escape.md \ + form-string.md \ + form.md \ + ftp-account.md \ + ftp-alternative-to-user.md \ + ftp-create-dirs.md \ + ftp-method.md \ + ftp-pasv.md \ + ftp-port.md \ + ftp-pret.md \ + ftp-skip-pasv-ip.md \ + ftp-ssl-ccc-mode.md \ + ftp-ssl-ccc.md \ + ftp-ssl-control.md \ + get.md \ + globoff.md \ + happy-eyeballs-timeout-ms.md \ + haproxy-protocol.md \ + haproxy-clientip.md \ + head.md \ + header.md \ + help.md \ + hostpubmd5.md \ + hostpubsha256.md \ + hsts.md \ + http0.9.md \ + http1.0.md \ + http1.1.md \ + http2-prior-knowledge.md \ + http2.md \ + http3.md \ + http3-only.md \ + ignore-content-length.md \ + include.md \ + insecure.md \ + interface.md \ + ipfs-gateway.md \ + ipv4.md \ + ipv6.md \ + json.md \ + junk-session-cookies.md \ + keepalive-time.md \ + key-type.md \ + key.md \ + krb.md \ + libcurl.md \ + limit-rate.md \ + list-only.md \ + local-port.md \ + location-trusted.md \ + location.md \ + login-options.md \ + mail-auth.md \ + mail-from.md \ + mail-rcpt-allowfails.md \ + mail-rcpt.md \ + manual.md \ + max-filesize.md \ + max-redirs.md \ + max-time.md \ + metalink.md \ + negotiate.md \ + netrc-file.md \ + netrc-optional.md \ + netrc.md \ + next.md \ + no-alpn.md \ + no-buffer.md \ + no-clobber.md \ + no-keepalive.md \ + no-npn.md \ + no-progress-meter.md \ + no-sessionid.md \ + noproxy.md \ + ntlm-wb.md \ + ntlm.md \ + oauth2-bearer.md \ + output-dir.md \ + output.md \ + parallel-immediate.md \ + parallel-max.md \ + parallel.md \ + pass.md \ + path-as-is.md \ + pinnedpubkey.md \ + post301.md \ + post302.md \ + post303.md \ + preproxy.md \ + progress-bar.md \ + proto-default.md \ + proto-redir.md \ + proto.md \ + proxy-anyauth.md \ + proxy-basic.md \ + proxy-ca-native.md \ + proxy-cacert.md \ + proxy-capath.md \ + proxy-cert-type.md \ + proxy-cert.md \ + proxy-ciphers.md \ + proxy-crlfile.md \ + proxy-digest.md \ + proxy-header.md \ + proxy-http2.md \ + proxy-insecure.md \ + proxy-key-type.md \ + proxy-key.md \ + proxy-negotiate.md \ + proxy-ntlm.md \ + proxy-pass.md \ + proxy-pinnedpubkey.md \ + proxy-service-name.md \ + proxy-ssl-allow-beast.md \ + proxy-ssl-auto-client-cert.md \ + proxy-tls13-ciphers.md \ + proxy-tlsauthtype.md \ + proxy-tlspassword.md \ + proxy-tlsuser.md \ + proxy-tlsv1.md \ + proxy-user.md \ + proxy.md \ + proxy1.0.md \ + proxytunnel.md \ + pubkey.md \ + quote.md \ + random-file.md \ + range.md \ + rate.md \ + raw.md \ + referer.md \ + remote-header-name.md \ + remote-name-all.md \ + remote-name.md \ + remote-time.md \ + remove-on-error.md \ + request-target.md \ + request.md \ + resolve.md \ + retry-all-errors.md \ + retry-connrefused.md \ + retry-delay.md \ + retry-max-time.md \ + retry.md \ + sasl-authzid.md \ + sasl-ir.md \ + service-name.md \ + show-error.md \ + silent.md \ + socks4.md \ + socks4a.md \ + socks5-basic.md \ + socks5-gssapi-nec.md \ + socks5-gssapi-service.md \ + socks5-gssapi.md \ + socks5-hostname.md \ + socks5.md \ + speed-limit.md \ + speed-time.md \ + ssl-allow-beast.md \ + ssl-auto-client-cert.md \ + ssl-no-revoke.md \ + ssl-reqd.md \ + ssl-revoke-best-effort.md \ + ssl.md \ + sslv2.md \ + sslv3.md \ + stderr.md \ + styled-output.md \ + suppress-connect-headers.md \ + tcp-fastopen.md \ + tcp-nodelay.md \ + telnet-option.md \ + tftp-blksize.md \ + tftp-no-options.md \ + time-cond.md \ + tls-max.md \ + tls13-ciphers.md \ + tlsauthtype.md \ + tlspassword.md \ + tlsuser.md \ + tlsv1.0.md \ + tlsv1.1.md \ + tlsv1.2.md \ + tlsv1.3.md \ + tlsv1.md \ + tr-encoding.md \ + trace-ascii.md \ + trace-config.md \ + trace-ids.md \ + trace-time.md \ + trace.md \ + unix-socket.md \ + upload-file.md \ + url.md \ + url-query.md \ + use-ascii.md \ + user-agent.md \ + user.md \ + variable.md \ + verbose.md \ + version.md \ + write-out.md \ + xattr.md diff --git a/docs/cmdline-opts/_AUTHORS.md b/docs/cmdline-opts/_AUTHORS.md new file mode 100644 index 0000000..0c9bfb9 --- /dev/null +++ b/docs/cmdline-opts/_AUTHORS.md @@ -0,0 +1,5 @@ + + +# AUTHORS +Daniel Stenberg is the main author, but the whole list of contributors is +found in the separate THANKS file. diff --git a/docs/cmdline-opts/_BUGS.md b/docs/cmdline-opts/_BUGS.md new file mode 100644 index 0000000..45630d4 --- /dev/null +++ b/docs/cmdline-opts/_BUGS.md @@ -0,0 +1,5 @@ + + +# BUGS +If you experience any problems with curl, submit an issue in the project's bug +tracker on GitHub: https://github.com/curl/curl/issues diff --git a/docs/cmdline-opts/_DESCRIPTION.md b/docs/cmdline-opts/_DESCRIPTION.md new file mode 100644 index 0000000..3e06c1b --- /dev/null +++ b/docs/cmdline-opts/_DESCRIPTION.md @@ -0,0 +1,11 @@ + + +# DESCRIPTION + +**curl** is a tool for transferring data from or to a server using URLs. It +supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, +IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, +SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. + +curl is powered by libcurl for all transfer-related features. See +*libcurl(3)* for details. diff --git a/docs/cmdline-opts/_ENVIRONMENT.md b/docs/cmdline-opts/_ENVIRONMENT.md new file mode 100644 index 0000000..cf30d47 --- /dev/null +++ b/docs/cmdline-opts/_ENVIRONMENT.md @@ -0,0 +1,114 @@ + + +# ENVIRONMENT +The environment variables can be specified in lower case or upper case. The +lower case version has precedence. `http_proxy` is an exception as it is only +available in lower case. + +Using an environment variable to set the proxy has the same effect as using +the --proxy option. + +## `http_proxy` [protocol://][:port] +Sets the proxy server to use for HTTP. + +## `HTTPS_PROXY` [protocol://][:port] +Sets the proxy server to use for HTTPS. + +## `[url-protocol]_PROXY` [protocol://][:port] +Sets the proxy server to use for [url-protocol], where the protocol is a +protocol that curl supports and as specified in a URL. FTP, FTPS, POP3, IMAP, +SMTP, LDAP, etc. + +## `ALL_PROXY` [protocol://][:port] +Sets the proxy server to use if no protocol-specific proxy is set. + +## `NO_PROXY` +list of host names that should not go through any proxy. If set to an asterisk +'*' only, it matches all hosts. Each name in this list is matched as either +a domain name which contains the hostname, or the hostname itself. + +This environment variable disables use of the proxy even when specified with +the --proxy option. That is + + NO_PROXY=direct.example.com curl -x http://proxy.example.com + http://direct.example.com + +accesses the target URL directly, and + + NO_PROXY=direct.example.com curl -x http://proxy.example.com + http://somewhere.example.com + +accesses the target URL through the proxy. + +The list of host names can also be include numerical IP addresses, and IPv6 +versions should then be given without enclosing brackets. + +IP addresses can be specified using CIDR notation: an appended slash and +number specifies the number of "network bits" out of the address to use in the +comparison (added in 7.86.0). For example "192.168.0.0/16" would match all +addresses starting with "192.168". + +## `APPDATA` +On Windows, this variable is used when trying to find the home directory. If +the primary home variable are all unset. + +## `COLUMNS` +If set, the specified number of characters is used as the terminal width when +the alternative progress-bar is shown. If not set, curl tries to figure it out +using other ways. + +## `CURL_CA_BUNDLE` +If set, it is used as the --cacert value. This environment variable is ignored +if Schannel is used as the TLS backend. + +## `CURL_HOME` +If set, is the first variable curl checks when trying to find its home +directory. If not set, it continues to check *XDG_CONFIG_HOME* + +## `CURL_SSL_BACKEND` +If curl was built with support for "MultiSSL", meaning that it has built-in +support for more than one TLS backend, this environment variable can be set to +the case insensitive name of the particular backend to use when curl is +invoked. Setting a name that is not a built-in alternative makes curl stay +with the default. + +SSL backend names (case-insensitive): **bearssl**, **gnutls**, **mbedtls**, +**openssl**, **rustls**, **schannel**, **secure-transport**, **wolfssl** + +## `HOME` +If set, this is used to find the home directory when that is needed. Like when +looking for the default .curlrc. *CURL_HOME* and *XDG_CONFIG_HOME* +have preference. + +## `QLOGDIR` +If curl was built with HTTP/3 support, setting this environment variable to a +local directory makes curl produce **qlogs** in that directory, using file +names named after the destination connection id (in hex). Do note that these +files can become rather large. Works with the ngtcp2 and quiche QUIC backends. + +## `SHELL` +Used on VMS when trying to detect if using a **DCL** or a **unix** shell. + +## `SSL_CERT_DIR` +If set, it is used as the --capath value. This environment variable is ignored +if Schannel is used as the TLS backend. + +## `SSL_CERT_FILE` +If set, it is used as the --cacert value. This environment variable is ignored +if Schannel is used as the TLS backend. + +## `SSLKEYLOGFILE` +If you set this environment variable to a file name, curl stores TLS secrets +from its connections in that file when invoked to enable you to analyze the +TLS traffic in real time using network analyzing tools such as Wireshark. This +works with the following TLS backends: OpenSSL, libressl, BoringSSL, GnuTLS +and wolfSSL. + +## `USERPROFILE` +On Windows, this variable is used when trying to find the home directory. If +the other, primary, variable are all unset. If set, curl uses the path +**"$USERPROFILE\Application Data"**. + +## `XDG_CONFIG_HOME` +If *CURL_HOME* is not set, this variable is checked when looking for a +default .curlrc file. diff --git a/docs/cmdline-opts/_EXITCODES.md b/docs/cmdline-opts/_EXITCODES.md new file mode 100644 index 0000000..ac7ab5c --- /dev/null +++ b/docs/cmdline-opts/_EXITCODES.md @@ -0,0 +1,201 @@ + + +# EXIT CODES +There are a bunch of different error codes and their corresponding error +messages that may appear under error conditions. At the time of this writing, +the exit codes are: +## 0 +Success. The operation completed successfully according to the instructions. +## 1 +Unsupported protocol. This build of curl has no support for this protocol. +## 2 +Failed to initialize. +## 3 +URL malformed. The syntax was not correct. +## 4 +A feature or option that was needed to perform the desired request was not +enabled or was explicitly disabled at build-time. To make curl able to do +this, you probably need another build of libcurl. +## 5 +Could not resolve proxy. The given proxy host could not be resolved. +## 6 +Could not resolve host. The given remote host could not be resolved. +## 7 +Failed to connect to host. +## 8 +Weird server reply. The server sent data curl could not parse. +## 9 +FTP access denied. The server denied login or denied access to the particular +resource or directory you wanted to reach. Most often you tried to change to a +directory that does not exist on the server. +## 10 +FTP accept failed. While waiting for the server to connect back when an active +FTP session is used, an error code was sent over the control connection or +similar. +## 11 +FTP weird PASS reply. Curl could not parse the reply sent to the PASS request. +## 12 +During an active FTP session while waiting for the server to connect back to +curl, the timeout expired. +## 13 +FTP weird PASV reply, Curl could not parse the reply sent to the PASV request. +## 14 +FTP weird 227 format. Curl could not parse the 227-line the server sent. +## 15 +FTP cannot use host. Could not resolve the host IP we got in the 227-line. +## 16 +HTTP/2 error. A problem was detected in the HTTP2 framing layer. This is +somewhat generic and can be one out of several problems, see the error message +for details. +## 17 +FTP could not set binary. Could not change transfer method to binary. +## 18 +Partial file. Only a part of the file was transferred. +## 19 +FTP could not download/access the given file, the RETR (or similar) command +failed. +## 21 +FTP quote error. A quote command returned error from the server. +## 22 +HTTP page not retrieved. The requested URL was not found or returned another +error with the HTTP error code being 400 or above. This return code only +appears if --fail is used. +## 23 +Write error. Curl could not write data to a local filesystem or similar. +## 25 +Failed starting the upload. For FTP, the server typically denied the STOR +command. +## 26 +Read error. Various reading problems. +## 27 +Out of memory. A memory allocation request failed. +## 28 +Operation timeout. The specified time-out period was reached according to the +conditions. +## 30 +FTP PORT failed. The PORT command failed. Not all FTP servers support the PORT +command, try doing a transfer using PASV instead. +## 31 +FTP could not use REST. The REST command failed. This command is used for +resumed FTP transfers. +## 33 +HTTP range error. The range "command" did not work. +## 34 +HTTP post error. Internal post-request generation error. +## 35 +SSL connect error. The SSL handshaking failed. +## 36 +Bad download resume. Could not continue an earlier aborted download. +## 37 +FILE could not read file. Failed to open the file. Permissions? +## 38 +LDAP cannot bind. LDAP bind operation failed. +## 39 +LDAP search failed. +## 41 +Function not found. A required LDAP function was not found. +## 42 +Aborted by callback. An application told curl to abort the operation. +## 43 +Internal error. A function was called with a bad parameter. +## 45 +Interface error. A specified outgoing interface could not be used. +## 47 +Too many redirects. When following redirects, curl hit the maximum amount. +## 48 +Unknown option specified to libcurl. This indicates that you passed a weird +option to curl that was passed on to libcurl and rejected. Read up in the +manual! +## 49 +Malformed telnet option. +## 52 +The server did not reply anything, which here is considered an error. +## 53 +SSL crypto engine not found. +## 54 +Cannot set SSL crypto engine as default. +## 55 +Failed sending network data. +## 56 +Failure in receiving network data. +## 58 +Problem with the local certificate. +## 59 +Could not use specified SSL cipher. +## 60 +Peer certificate cannot be authenticated with known CA certificates. +## 61 +Unrecognized transfer encoding. +## 63 +Maximum file size exceeded. +## 64 +Requested FTP SSL level failed. +## 65 +Sending the data requires a rewind that failed. +## 66 +Failed to initialize SSL Engine. +## 67 +The user name, password, or similar was not accepted and curl failed to log in. +## 68 +File not found on TFTP server. +## 69 +Permission problem on TFTP server. +## 70 +Out of disk space on TFTP server. +## 71 +Illegal TFTP operation. +## 72 +Unknown TFTP transfer ID. +## 73 +File already exists (TFTP). +## 74 +No such user (TFTP). +## 77 +Problem reading the SSL CA cert (path? access rights?). +## 78 +The resource referenced in the URL does not exist. +## 79 +An unspecified error occurred during the SSH session. +## 80 +Failed to shut down the SSL connection. +## 82 +Could not load CRL file, missing or wrong format (added in 7.19.0). +## 83 +Issuer check failed (added in 7.19.0). +## 84 +The FTP PRET command failed. +## 85 +Mismatch of RTSP CSeq numbers. +## 86 +Mismatch of RTSP Session Identifiers. +## 87 +Unable to parse FTP file list. +## 88 +FTP chunk callback reported error. +## 89 +No connection available, the session is queued. +## 90 +SSL public key does not matched pinned public key. +## 91 +Invalid SSL certificate status. +## 92 +Stream error in HTTP/2 framing layer. +## 93 +An API function was called from inside a callback. +## 94 +An authentication function returned an error. +## 95 +A problem was detected in the HTTP/3 layer. This is somewhat generic and can +be one out of several problems, see the error message for details. +## 96 +QUIC connection error. This error may be caused by an SSL library error. QUIC +is the protocol used for HTTP/3 transfers. +## 97 +Proxy handshake error. +## 98 +A client-side certificate is required to complete the TLS handshake. +## 99 +Poll or select returned fatal error. +## XX +More error codes might appear here in future releases. The existing ones are +meant to never change. diff --git a/docs/cmdline-opts/_FILES.md b/docs/cmdline-opts/_FILES.md new file mode 100644 index 0000000..8c5d3fa --- /dev/null +++ b/docs/cmdline-opts/_FILES.md @@ -0,0 +1,6 @@ + + +# FILES +*~/.curlrc* + +Default config file, see --config for details. diff --git a/docs/cmdline-opts/_GLOBBING.md b/docs/cmdline-opts/_GLOBBING.md new file mode 100644 index 0000000..282356c --- /dev/null +++ b/docs/cmdline-opts/_GLOBBING.md @@ -0,0 +1,40 @@ + + +# GLOBBING +You can specify multiple URLs or parts of URLs by writing lists within braces +or ranges within brackets. We call this "globbing". + +Provide a list with three different names like this: + + "http://site.{one,two,three}.com" + +Do sequences of alphanumeric series by using [] as in: + + "ftp://ftp.example.com/file[1-100].txt" + +With leading zeroes: + + "ftp://ftp.example.com/file[001-100].txt" + +With letters through the alphabet: + + "ftp://ftp.example.com/file[a-z].txt" + +Nested sequences are not supported, but you can use several ones next to each +other: + + "http://example.com/archive[1996-1999]/vol[1-4]/part{a,b,c}.html" + +You can specify a step counter for the ranges to get every Nth number or +letter: + + "http://example.com/file[1-100:10].txt" + + "http://example.com/file[a-z:2].txt" + +When using [] or {} sequences when invoked from a command line prompt, you +probably have to put the full URL within double quotes to avoid the shell from +interfering with it. This also goes for other characters treated special, like +for example '&', '?' and '*'. + +Switch off globbing with --globoff. diff --git a/docs/cmdline-opts/_NAME.md b/docs/cmdline-opts/_NAME.md new file mode 100644 index 0000000..b0d8916 --- /dev/null +++ b/docs/cmdline-opts/_NAME.md @@ -0,0 +1,4 @@ + + +# NAME +curl - transfer a URL diff --git a/docs/cmdline-opts/_OPTIONS.md b/docs/cmdline-opts/_OPTIONS.md new file mode 100644 index 0000000..1b25566 --- /dev/null +++ b/docs/cmdline-opts/_OPTIONS.md @@ -0,0 +1,26 @@ + + +# OPTIONS +Options start with one or two dashes. Many of the options require an +additional value next to them. If provided text does not start with a dash, it +is presumed to be and treated as a URL. + +The short "single-dash" form of the options, -d for example, may be used with +or without a space between it and its value, although a space is a recommended +separator. The long "double-dash" form, --data for example, requires a space +between it and its value. + +Short version options that do not need any additional values can be used +immediately next to each other, like for example you can specify all the +options *-O*, *-L* and *-v* at once as *-OLv*. + +In general, all boolean options are enabled with --**option** and yet again +disabled with --**no-**option. That is, you use the same option name but +prefix it with "no-". However, in this list we mostly only list and show the +*--option* version of them. + +When --next is used, it resets the parser state and you start again with a +clean option state, except for the options that are "global". Global options +retain their values and meaning even after --next. + +The following options are global: `%GLOBALS`. diff --git a/docs/cmdline-opts/_OUTPUT.md b/docs/cmdline-opts/_OUTPUT.md new file mode 100644 index 0000000..32a5457 --- /dev/null +++ b/docs/cmdline-opts/_OUTPUT.md @@ -0,0 +1,11 @@ + + +# OUTPUT +If not told otherwise, curl writes the received data to stdout. It can be +instructed to instead save that data into a local file, using the --output or +--remote-name options. If curl is given multiple URLs to transfer on the +command line, it similarly needs multiple options for where to save them. + +curl does not parse or otherwise "understand" the content it gets or writes as +output. It does no encoding or decoding, unless explicitly asked to with +dedicated command line options. diff --git a/docs/cmdline-opts/_PROGRESS.md b/docs/cmdline-opts/_PROGRESS.md new file mode 100644 index 0000000..80e36f1 --- /dev/null +++ b/docs/cmdline-opts/_PROGRESS.md @@ -0,0 +1,25 @@ + + +# "PROGRESS METER" + +curl normally displays a progress meter during operations, indicating the +amount of transferred data, transfer speeds and estimated time left, etc. The +progress meter displays the transfer rate in bytes per second. The suffixes +(k, M, G, T, P) are 1024 based. For example 1k is 1024 bytes. 1M is 1048576 +bytes. + +curl displays this data to the terminal by default, so if you invoke curl to +do an operation and it is about to write data to the terminal, it *disables* +the progress meter as otherwise it would mess up the output mixing progress +meter and response data. + +If you want a progress meter for HTTP POST or PUT requests, you need to +redirect the response output to a file, using shell redirect (>), --output or +similar. + +This does not apply to FTP upload as that operation does not spit out any +response data to the terminal. + +If you prefer a progress "bar" instead of the regular meter, --progress-bar is +your friend. You can also disable the progress meter completely with the +--silent option. diff --git a/docs/cmdline-opts/_PROTOCOLS.md b/docs/cmdline-opts/_PROTOCOLS.md new file mode 100644 index 0000000..b834f9a --- /dev/null +++ b/docs/cmdline-opts/_PROTOCOLS.md @@ -0,0 +1,51 @@ + + +# PROTOCOLS +curl supports numerous protocols, or put in URL terms: schemes. Your +particular build may not support them all. +## DICT +Lets you lookup words using online dictionaries. +## FILE +Read or write local files. curl does not support accessing file:// URL +remotely, but when running on Microsoft Windows using the native UNC approach +works. +## FTP(S) +curl supports the File Transfer Protocol with a lot of tweaks and levers. With +or without using TLS. +## GOPHER(S) +Retrieve files. +## HTTP(S) +curl supports HTTP with numerous options and variations. It can speak HTTP +version 0.9, 1.0, 1.1, 2 and 3 depending on build options and the correct +command line options. +## IMAP(S) +Using the mail reading protocol, curl can "download" emails for you. With or +without using TLS. +## LDAP(S) +curl can do directory lookups for you, with or without TLS. +## MQTT +curl supports MQTT version 3. Downloading over MQTT equals "subscribe" to a +topic while uploading/posting equals "publish" on a topic. MQTT over TLS is +not supported (yet). +## POP3(S) +Downloading from a pop3 server means getting a mail. With or without using +TLS. +## RTMP(S) +The **Realtime Messaging Protocol** is primarily used to serve streaming media +and curl can download it. +## RTSP +curl supports RTSP 1.0 downloads. +## SCP +curl supports SSH version 2 scp transfers. +## SFTP +curl supports SFTP (draft 5) done over SSH version 2. +## SMB(S) +curl supports SMB version 1 for upload and download. +## SMTP(S) +Uploading contents to an SMTP server means sending an email. With or without +TLS. +## TELNET +Telling curl to fetch a telnet URL starts an interactive session where it +sends what it reads on stdin and outputs what the server sends it. +## TFTP +curl can do TFTP downloads and uploads. diff --git a/docs/cmdline-opts/_PROXYPREFIX.md b/docs/cmdline-opts/_PROXYPREFIX.md new file mode 100644 index 0000000..297b56c --- /dev/null +++ b/docs/cmdline-opts/_PROXYPREFIX.md @@ -0,0 +1,22 @@ + + +# PROXY PROTOCOL PREFIXES +The proxy string may be specified with a protocol:// prefix to specify +alternative proxy protocols. (Added in 7.21.7) + +If no protocol is specified in the proxy string or if the string does not +match a supported one, the proxy is treated as an HTTP proxy. + +The supported proxy protocol prefixes are as follows: +## http:// +Makes it use it as an HTTP proxy. The default if no scheme prefix is used. +## https:// +Makes it treated as an **HTTPS** proxy. +## socks4:// +Makes it the equivalent of --socks4 +## socks4a:// +Makes it the equivalent of --socks4a +## socks5:// +Makes it the equivalent of --socks5 +## socks5h:// +Makes it the equivalent of --socks5-hostname diff --git a/docs/cmdline-opts/_SEEALSO.md b/docs/cmdline-opts/_SEEALSO.md new file mode 100644 index 0000000..f4d0b55 --- /dev/null +++ b/docs/cmdline-opts/_SEEALSO.md @@ -0,0 +1,5 @@ + + +# SEE ALSO + +**ftp (1)**, **wget (1)** diff --git a/docs/cmdline-opts/_SYNOPSIS.md b/docs/cmdline-opts/_SYNOPSIS.md new file mode 100644 index 0000000..3815877 --- /dev/null +++ b/docs/cmdline-opts/_SYNOPSIS.md @@ -0,0 +1,5 @@ + + +# SYNOPSIS + +**curl [options / URLs]** diff --git a/docs/cmdline-opts/_URL.md b/docs/cmdline-opts/_URL.md new file mode 100644 index 0000000..0084ec6 --- /dev/null +++ b/docs/cmdline-opts/_URL.md @@ -0,0 +1,28 @@ + + +# URL +The URL syntax is protocol-dependent. You find a detailed description in +RFC 3986. + +If you provide a URL without a leading **protocol://** scheme, curl guesses +what protocol you want. It then defaults to HTTP but assumes others based on +often-used host name prefixes. For example, for host names starting with +"ftp." curl assumes you want FTP. + +You can specify any amount of URLs on the command line. They are fetched in a +sequential manner in the specified order unless you use --parallel. You can +specify command line options and URLs mixed and in any order on the command +line. + +curl attempts to reuse connections when doing multiple transfers, so that +getting many files from the same server do not use multiple connects and setup +handshakes. This improves speed. Connection reuse can only be done for URLs +specified for a single command line invocation and cannot be performed between +separate curl runs. + +Provide an IPv6 zone id in the URL with an escaped percentage sign. Like in + + "http://[fe80::3%25eth0]/" + +Everything provided on the command line that is not a command line option or +its argument, curl assumes is a URL and treats it as such. diff --git a/docs/cmdline-opts/_VARIABLES.md b/docs/cmdline-opts/_VARIABLES.md new file mode 100644 index 0000000..3e17bfd --- /dev/null +++ b/docs/cmdline-opts/_VARIABLES.md @@ -0,0 +1,44 @@ + + +# VARIABLES +curl supports command line variables (added in 8.3.0). Set variables with +--variable name=content or --variable name@file (where "file" can be stdin if +set to a single dash (-)). + +Variable contents can be expanded in option parameters using "{{name}}" (without +the quotes) if the option name is prefixed with "--expand-". This gets the +contents of the variable "name" inserted, or a blank if the name does not +exist as a variable. Insert "{{" verbatim in the string by prefixing it with a +backslash, like "\{{". + +You an access and expand environment variables by first importing them. You +can select to either require the environment variable to be set or you can +provide a default value in case it is not already set. Plain --variable %name +imports the variable called 'name' but exits with an error if that environment +variable is not already set. To provide a default value if it is not set, use +--variable %name=content or --variable %name@content. + +Example. Get the USER environment variable into the URL, fail if USER is not +set: + + --variable '%USER' + --expand-url = "https://example.com/api/{{USER}}/method" + +When expanding variables, curl supports a set of functions that can make the +variable contents more convenient to use. It can trim leading and trailing +white space with *trim*, it can output the contents as a JSON quoted string +with *json*, URL encode the string with *url* or base64 encode it with +*b64*. You apply function to a variable expansion, add them colon separated to +the right side of the variable. Variable content holding null bytes that are +not encoded when expanded cause error. + +Example: get the contents of a file called $HOME/.secret into a variable +called "fix". Make sure that the content is trimmed and percent-encoded sent +as POST data: + + --variable %HOME + --expand-variable fix@{{HOME}}/.secret + --expand-data "{{fix:trim:url}}" + https://example.com/ + +Command line variables and expansions were added in in 8.3.0. diff --git a/docs/cmdline-opts/_VERSION.md b/docs/cmdline-opts/_VERSION.md new file mode 100644 index 0000000..4c759f1 --- /dev/null +++ b/docs/cmdline-opts/_VERSION.md @@ -0,0 +1,15 @@ + + +# VERSION + +This man page describes curl %VERSION. If you use a later version, chances are +this man page does not fully document it. If you use an earlier version, this +document tries to include version information about which specific version +that introduced changes. + +You can always learn which the latest curl version is by running + + curl https://curl.se/info + +The online version of this man page is always showing the latest incarnation: +https://curl.se/docs/manpage.html diff --git a/docs/cmdline-opts/_WWW.md b/docs/cmdline-opts/_WWW.md new file mode 100644 index 0000000..35d9466 --- /dev/null +++ b/docs/cmdline-opts/_WWW.md @@ -0,0 +1,4 @@ + + +# WWW +https://curl.se diff --git a/docs/cmdline-opts/abstract-unix-socket.md b/docs/cmdline-opts/abstract-unix-socket.md new file mode 100644 index 0000000..27bc8ca --- /dev/null +++ b/docs/cmdline-opts/abstract-unix-socket.md @@ -0,0 +1,21 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: abstract-unix-socket +Arg: +Help: Connect via abstract Unix domain socket +Added: 7.53.0 +Protocols: HTTP +Category: connection +Multi: single +See-also: + - unix-socket +Example: + - --abstract-unix-socket socketpath $URL +--- + +# `--abstract-unix-socket` + +Connect through an abstract Unix domain socket, instead of using the network. +Note: netstat shows the path of an abstract socket prefixed with '@', however +the argument should not have this leading character. diff --git a/docs/cmdline-opts/alt-svc.md b/docs/cmdline-opts/alt-svc.md new file mode 100644 index 0000000..0a0f17d --- /dev/null +++ b/docs/cmdline-opts/alt-svc.md @@ -0,0 +1,28 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: alt-svc +Arg: +Protocols: HTTPS +Help: Enable alt-svc with this cache file +Added: 7.64.1 +Category: http +Multi: append +See-also: + - resolve + - connect-to +Example: + - --alt-svc svc.txt $URL +--- + +# `--alt-svc` + +This option enables the alt-svc parser in curl. If the file name points to an +existing alt-svc cache file, that gets used. After a completed transfer, the +cache is saved to the file name again if it has been modified. + +Specify a "" file name (zero length) to avoid loading/saving and make curl +just handle the cache in memory. + +If this option is used several times, curl loads contents from all the +files but the last one is used for saving. diff --git a/docs/cmdline-opts/anyauth.md b/docs/cmdline-opts/anyauth.md new file mode 100644 index 0000000..150e069 --- /dev/null +++ b/docs/cmdline-opts/anyauth.md @@ -0,0 +1,30 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: anyauth +Help: Pick any authentication method +Protocols: HTTP +Category: http proxy auth +Added: 7.10.6 +Multi: mutex +See-also: + - proxy-anyauth + - basic + - digest +Example: + - --anyauth --user me:pwd $URL +--- + +# `--anyauth` + +Tells curl to figure out authentication method by itself, and use the most +secure one the remote site claims to support. This is done by first doing a +request and checking the response-headers, thus possibly inducing an extra +network round-trip. This is used instead of setting a specific authentication +method, which you can do with --basic, --digest, --ntlm, and --negotiate. + +Using --anyauth is not recommended if you do uploads from stdin, since it may +require data to be sent twice and then the client must be able to rewind. If +the need should arise when uploading from stdin, the upload operation fails. + +Used together with --user. diff --git a/docs/cmdline-opts/append.md b/docs/cmdline-opts/append.md new file mode 100644 index 0000000..3d0030d --- /dev/null +++ b/docs/cmdline-opts/append.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Short: a +Long: append +Help: Append to target file when uploading +Protocols: FTP SFTP +Category: ftp sftp +Added: 4.8 +Multi: boolean +See-also: + - range + - continue-at +Example: + - --upload-file local --append ftp://example.com/ +--- + +# `--append` + +When used in an upload, this option makes curl append to the target file +instead of overwriting it. If the remote file does not exist, it is +created. Note that this flag is ignored by some SFTP servers (including +OpenSSH). diff --git a/docs/cmdline-opts/aws-sigv4.md b/docs/cmdline-opts/aws-sigv4.md new file mode 100644 index 0000000..1b39092 --- /dev/null +++ b/docs/cmdline-opts/aws-sigv4.md @@ -0,0 +1,30 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: aws-sigv4 +Protocols: HTTP +Arg: +Help: Use AWS V4 signature authentication +Category: auth http +Added: 7.75.0 +Multi: single +See-also: + - basic + - user +Example: + - --aws-sigv4 "aws:amz:us-east-2:es" --user "key:secret" $URL +--- + +# `--aws-sigv4` + +Use AWS V4 signature authentication in the transfer. + +The provider argument is a string that is used by the algorithm when creating +outgoing authentication headers. + +The region argument is a string that points to a geographic area of +a resources collection (region-code) when the region name is omitted from +the endpoint. + +The service argument is a string that points to a function provided by a cloud +(service-code) when the service name is omitted from the endpoint. diff --git a/docs/cmdline-opts/basic.md b/docs/cmdline-opts/basic.md new file mode 100644 index 0000000..34b0191 --- /dev/null +++ b/docs/cmdline-opts/basic.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: basic +Help: Use HTTP Basic Authentication +Protocols: HTTP +Category: auth +Added: 7.10.6 +Multi: mutex +See-also: + - proxy-basic +Example: + - -u name:password --basic $URL +--- + +# `--basic` + +Tells curl to use HTTP Basic authentication with the remote host. This is the +default and this option is usually pointless, unless you use it to override a +previously set option that sets a different authentication method (such as +--ntlm, --digest, or --negotiate). + +Used together with --user. diff --git a/docs/cmdline-opts/ca-native.md b/docs/cmdline-opts/ca-native.md new file mode 100644 index 0000000..d0b4bfa --- /dev/null +++ b/docs/cmdline-opts/ca-native.md @@ -0,0 +1,28 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ca-native +Help: Use CA certificates from the native OS +Protocols: TLS +Category: tls +Added: 8.2.0 +Multi: boolean +See-also: + - cacert + - capath + - insecure +Example: + - --ca-native $URL +--- + +# `--ca-native` + +Tells curl to use the CA store from the native operating system to verify the +peer. By default, curl otherwise uses a CA store provided in a single file or +directory, but when using this option it interfaces the operating system's +own vault. + +This option works for curl on Windows when built to use OpenSSL, wolfSSL +(added in 8.3.0) or GnuTLS (added in 8.5.0). When curl on Windows is built to +use Schannel, this feature is implied and curl then only uses the native CA +store. diff --git a/docs/cmdline-opts/cacert.md b/docs/cmdline-opts/cacert.md new file mode 100644 index 0000000..7b1b217 --- /dev/null +++ b/docs/cmdline-opts/cacert.md @@ -0,0 +1,42 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: cacert +Arg: +Help: CA certificate to verify peer against +Protocols: TLS +Category: tls +Added: 7.5 +Multi: single +See-also: + - capath + - insecure +Example: + - --cacert CA-file.txt $URL +--- + +# `--cacert` + +Tells curl to use the specified certificate file to verify the peer. The file +may contain multiple CA certificates. The certificate(s) must be in PEM +format. Normally curl is built to use a default file for this, so this option +is typically used to alter that default file. + +curl recognizes the environment variable named 'CURL_CA_BUNDLE' if it is set +and the TLS backend is not Schannel, and uses the given path as a path to a CA +cert bundle. This option overrides that variable. + +The windows version of curl automatically looks for a CA certs file named +'curl-ca-bundle.crt', either in the same directory as curl.exe, or in the +Current Working Directory, or in any folder along your PATH. + +(iOS and macOS only) If curl is built against Secure Transport, then this +option is supported for backward compatibility with other SSL engines, but it +should not be set. If the option is not set, then curl uses the certificates +in the system and user Keychain to verify the peer, which is the preferred +method of verifying the peer's certificate chain. + +(Schannel only) This option is supported for Schannel in Windows 7 or later +(added in 7.60.0). This option is supported for backward compatibility with +other SSL engines; instead it is recommended to use Windows' store of root +certificates (the default for Schannel). diff --git a/docs/cmdline-opts/capath.md b/docs/cmdline-opts/capath.md new file mode 100644 index 0000000..ecd28df --- /dev/null +++ b/docs/cmdline-opts/capath.md @@ -0,0 +1,28 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: capath +Arg: +Help: CA directory to verify peer against +Protocols: TLS +Category: tls +Added: 7.9.8 +Multi: single +See-also: + - cacert + - insecure +Example: + - --capath /local/directory $URL +--- + +# `--capath` + +Tells curl to use the specified certificate directory to verify the +peer. Multiple paths can be provided by separating them with ":" (e.g. +"path1:path2:path3"). The certificates must be in PEM format, and if curl is +built against OpenSSL, the directory must have been processed using the +c_rehash utility supplied with OpenSSL. Using --capath can allow +OpenSSL-powered curl to make SSL-connections much more efficiently than using +--cacert if the --cacert file contains many CA certificates. + +If this option is set, the default capath value is ignored. diff --git a/docs/cmdline-opts/cert-status.md b/docs/cmdline-opts/cert-status.md new file mode 100644 index 0000000..bfbd3af --- /dev/null +++ b/docs/cmdline-opts/cert-status.md @@ -0,0 +1,25 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: cert-status +Protocols: TLS +Added: 7.41.0 +Help: Verify the status of the server cert via OCSP-staple +Category: tls +Multi: boolean +See-also: + - pinnedpubkey +Example: + - --cert-status $URL +--- + +# `--cert-status` + +Tells curl to verify the status of the server certificate by using the +Certificate Status Request (aka. OCSP stapling) TLS extension. + +If this option is enabled and the server sends an invalid (e.g. expired) +response, if the response suggests that the server certificate has been +revoked, or no response at all is received, the verification fails. + +This is currently only implemented in the OpenSSL and GnuTLS backends. diff --git a/docs/cmdline-opts/cert-type.md b/docs/cmdline-opts/cert-type.md new file mode 100644 index 0000000..a0030a5 --- /dev/null +++ b/docs/cmdline-opts/cert-type.md @@ -0,0 +1,26 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: cert-type +Protocols: TLS +Arg: +Help: Certificate type (DER/PEM/ENG/P12) +Category: tls +Added: 7.9.3 +Multi: single +See-also: + - cert + - key + - key-type +Example: + - --cert-type PEM --cert file $URL +--- + +# `--cert-type` + +Tells curl what type the provided client certificate is using. PEM, DER, ENG +and P12 are recognized types. + +The default type depends on the TLS backend and is usually PEM, however for +Secure Transport and Schannel it is P12. If --cert is a pkcs11: URI then ENG is +the default type. diff --git a/docs/cmdline-opts/cert.md b/docs/cmdline-opts/cert.md new file mode 100644 index 0000000..6df5d0e --- /dev/null +++ b/docs/cmdline-opts/cert.md @@ -0,0 +1,56 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Short: E +Long: cert +Arg: +Help: Client certificate file and password +Protocols: TLS +Category: tls +Added: 5.0 +Multi: single +See-also: + - cert-type + - key + - key-type +Example: + - --cert certfile --key keyfile $URL +--- + +# `--cert` + +Tells curl to use the specified client certificate file when getting a file +with HTTPS, FTPS or another SSL-based protocol. The certificate must be in +PKCS#12 format if using Secure Transport, or PEM format if using any other +engine. If the optional password is not specified, it is queried for on +the terminal. Note that this option assumes a certificate file that is the +private key and the client certificate concatenated. See --cert and --key to +specify them independently. + +In the portion of the argument, you must escape the character +":" as "\:" so that it is not recognized as the password delimiter. Similarly, +you must escape the double quote character as \" so that it is not recognized +as an escape character. + +If curl is built against OpenSSL library, and the engine pkcs11 is available, +then a PKCS#11 URI (RFC 7512) can be used to specify a certificate located in +a PKCS#11 device. A string beginning with "pkcs11:" is interpreted as a +PKCS#11 URI. If a PKCS#11 URI is provided, then the --engine option is set as +"pkcs11" if none was provided and the --cert-type option is set as "ENG" if +none was provided. + +(iOS and macOS only) If curl is built against Secure Transport, then the +certificate string can either be the name of a certificate/private key in the +system or user keychain, or the path to a PKCS#12-encoded certificate and +private key. If you want to use a file from the current directory, please +precede it with "./" prefix, in order to avoid confusion with a nickname. + +(Schannel only) Client certificates must be specified by a path expression to +a certificate store. (Loading *PFX* is not supported; you can import it to a +store first). You can use "\\" to +refer to a certificate in the system certificates store, for example, +*"CurrentUser\MY\934a7ac6f8a5d579285a74fa61e19f23ddfe8d7a"*. Thumbprint is +usually a SHA-1 hex string which you can see in certificate details. Following +store locations are supported: *CurrentUser*, *LocalMachine*, +*CurrentService*, *Services*, *CurrentUserGroupPolicy*, +*LocalMachineGroupPolicy* and *LocalMachineEnterprise*. diff --git a/docs/cmdline-opts/ciphers.md b/docs/cmdline-opts/ciphers.md new file mode 100644 index 0000000..9d7e0c6 --- /dev/null +++ b/docs/cmdline-opts/ciphers.md @@ -0,0 +1,24 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ciphers +Arg: +Help: SSL ciphers to use +Protocols: TLS +Category: tls +Added: 7.9 +Multi: single +See-also: + - tlsv1.3 + - tls13-ciphers + - proxy-ciphers +Example: + - --ciphers ECDHE-ECDSA-AES256-CCM8 $URL +--- + +# `--ciphers` + +Specifies which ciphers to use in the connection. The list of ciphers must +specify valid ciphers. Read up on SSL cipher list details on this URL: + +https://curl.se/docs/ssl-ciphers.html diff --git a/docs/cmdline-opts/compressed-ssh.md b/docs/cmdline-opts/compressed-ssh.md new file mode 100644 index 0000000..c52e5a7 --- /dev/null +++ b/docs/cmdline-opts/compressed-ssh.md @@ -0,0 +1,19 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: compressed-ssh +Help: Enable SSH compression +Protocols: SCP SFTP +Added: 7.56.0 +Category: scp ssh +Multi: boolean +See-also: + - compressed +Example: + - --compressed-ssh sftp://example.com/ +--- + +# `--compressed-ssh` + +Enables built-in SSH compression. +This is a request, not an order; the server may or may not do it. diff --git a/docs/cmdline-opts/compressed.md b/docs/cmdline-opts/compressed.md new file mode 100644 index 0000000..35bbab8 --- /dev/null +++ b/docs/cmdline-opts/compressed.md @@ -0,0 +1,27 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: compressed +Help: Request compressed response +Protocols: HTTP +Category: http +Added: 7.10 +Multi: boolean +See-also: + - compressed-ssh +Example: + - --compressed $URL +--- + +# `--compressed` + +Request a compressed response using one of the algorithms curl supports, and +automatically decompress the content. + +Response headers are not modified when saved, so if they are "interpreted" +separately again at a later point they might appear to be saying that the +content is (still) compressed; while in fact it has already been decompressed. + +If this option is used and the server sends an unsupported encoding, curl +reports an error. This is a request, not an order; the server may or may not +deliver data compressed. diff --git a/docs/cmdline-opts/config.md b/docs/cmdline-opts/config.md new file mode 100644 index 0000000..2f393e2 --- /dev/null +++ b/docs/cmdline-opts/config.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: config +Arg: +Help: Read config from a file +Short: K +Category: curl +Added: 4.10 +Multi: append +See-also: + - disable +Example: + - --config file.txt $URL +--- + +# `--config` + +Specify a text file to read curl arguments from. The command line arguments +found in the text file are used as if they were provided on the command +line. + +Options and their parameters must be specified on the same line in the file, +separated by whitespace, colon, or the equals sign. Long option names can +optionally be given in the config file without the initial double dashes and +if so, the colon or equals characters can be used as separators. If the option +is specified with one or two dashes, there can be no colon or equals character +between the option and its parameter. + +If the parameter contains whitespace or starts with a colon (:) or equals sign +(=), it must be specified enclosed within double quotes ("). Within double +quotes the following escape sequences are available: \\, \", \t, \n, \r and +\v. A backslash preceding any other letter is ignored. + +If the first non-blank column of a config line is a '#' character, that line +is treated as a comment. + +Only write one option per physical line in the config file. A single line is +required to be no more than 10 megabytes (since 8.2.0). + +Specify the filename to --config as '-' to make curl read the file from stdin. + +Note that to be able to specify a URL in the config file, you need to specify +it using the --url option, and not by simply writing the URL on its own +line. So, it could look similar to this: + + url = "https://curl.se/docs/" + + # --- Example file --- + # this is a comment + url = "example.com" + output = "curlhere.html" + user-agent = "superagent/1.0" + + # and fetch another URL too + url = "example.com/docs/manpage.html" + -O + referer = "http://nowhereatall.example.com/" + # --- End of example file --- + +When curl is invoked, it (unless --disable is used) checks for a default +config file and uses it if found, even when --config is used. The default +config file is checked for in the following places in this order: + +1) **"$CURL_HOME/.curlrc"** + +2) **"$XDG_CONFIG_HOME/curlrc"** (Added in 7.73.0) + +3) **"$HOME/.curlrc"** + +4) Windows: **"%USERPROFILE%\.curlrc"** + +5) Windows: **"%APPDATA%\.curlrc"** + +6) Windows: **"%USERPROFILE%\Application Data\.curlrc"** + +7) Non-Windows: use getpwuid to find the home directory + +8) On Windows, if it finds no *.curlrc* file in the sequence described above, it +checks for one in the same dir the curl executable is placed. + +On Windows two filenames are checked per location: *.curlrc* and *_curlrc*, +preferring the former. Older versions on Windows checked for *_curlrc* only. diff --git a/docs/cmdline-opts/connect-timeout.md b/docs/cmdline-opts/connect-timeout.md new file mode 100644 index 0000000..f7281b0 --- /dev/null +++ b/docs/cmdline-opts/connect-timeout.md @@ -0,0 +1,28 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: connect-timeout +Arg: +Help: Maximum time allowed for connection +Category: connection +Added: 7.7 +Multi: single +See-also: + - max-time +Example: + - --connect-timeout 20 $URL + - --connect-timeout 3.14 $URL +--- + +# `--connect-timeout` + +Maximum time in seconds that you allow curl's connection to take. This only +limits the connection phase, so if curl connects within the given period it +continues - if not it exits. + +This option accepts decimal values (added in 7.32.0). The decimal value needs +to be provided using a dot (.) as decimal separator - not the local version +even if it might be using another separator. + +The connection phase is considered complete when the DNS lookup and requested +TCP, TLS or QUIC handshakes are done. diff --git a/docs/cmdline-opts/connect-to.md b/docs/cmdline-opts/connect-to.md new file mode 100644 index 0000000..7cd0aa8 --- /dev/null +++ b/docs/cmdline-opts/connect-to.md @@ -0,0 +1,30 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: connect-to +Arg: +Help: Connect to host +Added: 7.49.0 +Category: connection +Multi: append +See-also: + - resolve + - header +Example: + - --connect-to example.com:443:example.net:8443 $URL +--- + +# `--connect-to` + +For a request to the given `HOST1:PORT1` pair, connect to `HOST2:PORT2` +instead. This option is suitable to direct requests at a specific server, +e.g. at a specific cluster node in a cluster of servers. This option is only +used to establish the network connection. It does NOT affect the hostname/port +that is used for TLS/SSL (e.g. SNI, certificate verification) or for the +application protocols. `HOST1` and `PORT1` may be the empty string, meaning +"any host/port". `HOST2` and `PORT2` may also be the empty string, meaning +"use the request's original host/port". + +A hostname specified to this option is compared as a string, so it needs to +match the name used in request URL. It can be either numerical such as +`127.0.0.1` or the full host name such as `example.org`. diff --git a/docs/cmdline-opts/continue-at.md b/docs/cmdline-opts/continue-at.md new file mode 100644 index 0000000..67a79fd --- /dev/null +++ b/docs/cmdline-opts/continue-at.md @@ -0,0 +1,26 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Short: C +Long: continue-at +Arg: +Help: Resumed transfer offset +Category: connection +Added: 4.8 +Multi: single +See-also: + - range +Example: + - -C - $URL + - -C 400 $URL +--- + +# `--continue-at` + +Continue/Resume a previous file transfer at the given offset. The given offset +is the exact number of bytes that are skipped, counting from the beginning +of the source file before it is transferred to the destination. If used with +uploads, the FTP server command SIZE is not used by curl. + +Use "-C -" to tell curl to automatically find out where/how to resume the +transfer. It then uses the given output/input files to figure that out. diff --git a/docs/cmdline-opts/cookie-jar.md b/docs/cmdline-opts/cookie-jar.md new file mode 100644 index 0000000..5453152 --- /dev/null +++ b/docs/cmdline-opts/cookie-jar.md @@ -0,0 +1,37 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Short: c +Long: cookie-jar +Arg: +Protocols: HTTP +Help: Write cookies to after operation +Category: http +Added: 7.9 +Multi: single +See-also: + - cookie +Example: + - -c store-here.txt $URL + - -c store-here.txt -b read-these $URL +--- + +# `--cookie-jar` + +Specify to which file you want curl to write all cookies after a completed +operation. Curl writes all cookies from its in-memory cookie storage to the +given file at the end of operations. If no cookies are known, no data is +written. The file is created using the Netscape cookie file format. If you set +the file name to a single dash, "-", the cookies are written to stdout. + +The file specified with --cookie-jar is only used for output. No cookies are +read from the file. To read cookies, use the --cookie option. Both options +can specify the same file. + +This command line option activates the cookie engine that makes curl record +and use cookies. The --cookie option also activates it. + +If the cookie jar cannot be created or written to, the whole curl operation +does not fail or even report an error clearly. Using --verbose gets a warning +displayed, but that is the only visible feedback you get about this possibly +lethal situation. diff --git a/docs/cmdline-opts/cookie.md b/docs/cmdline-opts/cookie.md new file mode 100644 index 0000000..d0a6d35 --- /dev/null +++ b/docs/cmdline-opts/cookie.md @@ -0,0 +1,58 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Short: b +Long: cookie +Arg: +Protocols: HTTP +Help: Send cookies from string/file +Category: http +Added: 4.9 +Multi: append +See-also: + - cookie-jar + - junk-session-cookies +Example: + - -b "" $URL + - -b cookiefile $URL + - -b cookiefile -c cookiefile $URL +--- + +# `--cookie` + +Pass the data to the HTTP server in the Cookie header. It is supposedly the +data previously received from the server in a "Set-Cookie:" line. The data +should be in the format "NAME1=VALUE1; NAME2=VALUE2". This makes curl use the +cookie header with this content explicitly in all outgoing request(s). If +multiple requests are done due to authentication, followed redirects or +similar, they all get this cookie passed on. + +If no '=' symbol is used in the argument, it is instead treated as a filename +to read previously stored cookie from. This option also activates the cookie +engine which makes curl record incoming cookies, which may be handy if you are +using this in combination with the --location option or do multiple URL +transfers on the same invoke. + +If the file name is exactly a minus ("-"), curl instead reads the contents from +stdin. If the file name is an empty string ("") and is the only cookie input, +curl will activate the cookie engine without any cookies. + +The file format of the file to read cookies from should be plain HTTP headers +(Set-Cookie style) or the Netscape/Mozilla cookie file format. + +The file specified with --cookie is only used as input. No cookies are written +to the file. To store cookies, use the --cookie-jar option. + +If you use the Set-Cookie file format and do not specify a domain then the +cookie is not sent since the domain never matches. To address this, set a +domain in Set-Cookie line (doing that includes subdomains) or preferably: use +the Netscape format. + +Users often want to both read cookies from a file and write updated cookies +back to a file, so using both --cookie and --cookie-jar in the same command +line is common. + +If curl is built with PSL (**Public Suffix List**) support, it detects and +discards cookies that are specified for such suffix domains that should not be +allowed to have cookies. If curl is *not* built with PSL support, it has no +ability to stop super cookies. diff --git a/docs/cmdline-opts/create-dirs.md b/docs/cmdline-opts/create-dirs.md new file mode 100644 index 0000000..de48807 --- /dev/null +++ b/docs/cmdline-opts/create-dirs.md @@ -0,0 +1,26 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: create-dirs +Help: Create necessary local directory hierarchy +Category: curl +Added: 7.10.3 +Multi: boolean +See-also: + - ftp-create-dirs + - output-dir +Example: + - --create-dirs --output local/dir/file $URL +--- + +# `--create-dirs` + +When used in conjunction with the --output option, curl creates the necessary +local directory hierarchy as needed. This option creates the directories +mentioned with the --output option combined with the path possibly set with +--output-dir. If the combined output file name uses no directory, or if the +directories it mentions already exist, no directories are created. + +Created directories are made with mode 0750 on unix style file systems. + +To create remote directories when using FTP or SFTP, try --ftp-create-dirs. diff --git a/docs/cmdline-opts/create-file-mode.md b/docs/cmdline-opts/create-file-mode.md new file mode 100644 index 0000000..c6467d1 --- /dev/null +++ b/docs/cmdline-opts/create-file-mode.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: create-file-mode +Arg: +Help: File mode for created files +Protocols: SFTP SCP FILE +Category: sftp scp file upload +Added: 7.75.0 +Multi: single +See-also: + - ftp-create-dirs +Example: + - --create-file-mode 0777 -T localfile sftp://example.com/new +--- + +# `--create-file-mode` + +When curl is used to create files remotely using one of the supported +protocols, this option allows the user to set which 'mode' to set on the file +at creation time, instead of the default 0644. + +This option takes an octal number as argument. diff --git a/docs/cmdline-opts/crlf.md b/docs/cmdline-opts/crlf.md new file mode 100644 index 0000000..81a14ef --- /dev/null +++ b/docs/cmdline-opts/crlf.md @@ -0,0 +1,21 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: crlf +Help: Convert LF to CRLF in upload +Protocols: FTP SMTP +Category: ftp smtp +Added: 5.7 +Multi: boolean +See-also: + - use-ascii +Example: + - --crlf -T file ftp://example.com/ +--- + +# `--crlf` + +Convert line feeds to carriage return plus line feeds in upload. Useful for +**MVS (OS/390)**. + +(SMTP added in 7.40.0) diff --git a/docs/cmdline-opts/crlfile.md b/docs/cmdline-opts/crlfile.md new file mode 100644 index 0000000..16bd7b3 --- /dev/null +++ b/docs/cmdline-opts/crlfile.md @@ -0,0 +1,21 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: crlfile +Arg: +Protocols: TLS +Help: Use this CRL list +Added: 7.19.7 +Category: tls +Multi: single +See-also: + - cacert + - capath +Example: + - --crlfile rejects.txt $URL +--- + +# `--crlfile` + +Provide a file using PEM format with a Certificate Revocation List that may +specify peer certificates that are to be considered revoked. diff --git a/docs/cmdline-opts/curves.md b/docs/cmdline-opts/curves.md new file mode 100644 index 0000000..99f1ad4 --- /dev/null +++ b/docs/cmdline-opts/curves.md @@ -0,0 +1,28 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: curves +Arg: +Help: (EC) TLS key exchange algorithm(s) to request +Protocols: TLS +Added: 7.73.0 +Category: tls +Multi: single +See-also: + - ciphers +Example: + - --curves X25519 $URL +--- + +# `--curves` + +Tells curl to request specific curves to use during SSL session establishment +according to RFC 8422, 5.1. Multiple algorithms can be provided by separating +them with `:` (e.g. `X25519:P-521`). The parameter is available identically in +the OpenSSL `s_client` and `s_server` utilities. + +--curves allows a OpenSSL powered curl to make SSL-connections with exactly +the (EC) curve requested by the client, avoiding nontransparent client/server +negotiations. + +If this option is set, the default curves list built into OpenSSL are ignored. diff --git a/docs/cmdline-opts/data-ascii.md b/docs/cmdline-opts/data-ascii.md new file mode 100644 index 0000000..124dee1 --- /dev/null +++ b/docs/cmdline-opts/data-ascii.md @@ -0,0 +1,21 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: data-ascii +Arg: +Help: HTTP POST ASCII data +Protocols: HTTP +Category: http post upload +Added: 7.2 +Multi: append +See-also: + - data-binary + - data-raw + - data-urlencode +Example: + - --data-ascii @file $URL +--- + +# `--data-ascii` + +This is just an alias for --data. diff --git a/docs/cmdline-opts/data-binary.md b/docs/cmdline-opts/data-binary.md new file mode 100644 index 0000000..3d563fb --- /dev/null +++ b/docs/cmdline-opts/data-binary.md @@ -0,0 +1,31 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: data-binary +Arg: +Help: HTTP POST binary data +Protocols: HTTP +Category: http post upload +Added: 7.2 +Multi: append +See-also: + - data-ascii +Example: + - --data-binary @filename $URL +--- + +# `--data-binary` + +This posts data exactly as specified with no extra processing whatsoever. + +If you start the data with the letter @, the rest should be a filename. Data +is posted in a similar manner as --data does, except that newlines and +carriage returns are preserved and conversions are never done. + +Like --data the default content-type sent to the server is +application/x-www-form-urlencoded. If you want the data to be treated as +arbitrary binary data by the server then set the content-type to octet-stream: +-H "Content-Type: application/octet-stream". + +If this option is used several times, the ones following the first append +data as described in --data. diff --git a/docs/cmdline-opts/data-raw.md b/docs/cmdline-opts/data-raw.md new file mode 100644 index 0000000..2cb4693 --- /dev/null +++ b/docs/cmdline-opts/data-raw.md @@ -0,0 +1,21 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: data-raw +Arg: +Protocols: HTTP +Help: HTTP POST data, '@' allowed +Added: 7.43.0 +Category: http post upload +Multi: append +See-also: + - data +Example: + - --data-raw "hello" $URL + - --data-raw "@at@at@" $URL +--- + +# `--data-raw` + +This posts data similarly to --data but without the special +interpretation of the @ character. diff --git a/docs/cmdline-opts/data-urlencode.md b/docs/cmdline-opts/data-urlencode.md new file mode 100644 index 0000000..4d3f298 --- /dev/null +++ b/docs/cmdline-opts/data-urlencode.md @@ -0,0 +1,51 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: data-urlencode +Arg: +Help: HTTP POST data URL encoded +Protocols: HTTP +Added: 7.18.0 +Category: http post upload +Multi: append +See-also: + - data + - data-raw +Example: + - --data-urlencode name=val $URL + - --data-urlencode =encodethis $URL + - --data-urlencode name@file $URL + - --data-urlencode @fileonly $URL +--- + +# `--data-urlencode` + +This posts data, similar to the other --data options with the exception +that this performs URL-encoding. + +To be CGI-compliant, the part should begin with a *name* followed +by a separator and a content specification. The part can be passed to +curl using one of the following syntaxes: + +## content +This makes curl URL-encode the content and pass that on. Just be careful +so that the content does not contain any = or @ symbols, as that makes +the syntax match one of the other cases below! + +## =content +This makes curl URL-encode the content and pass that on. The preceding = +symbol is not included in the data. + +## name=content +This makes curl URL-encode the content part and pass that on. Note that +the name part is expected to be URL-encoded already. + +## @filename +This makes curl load data from the given file (including any newlines), +URL-encode that data and pass it on in the POST. + +## name@filename +This makes curl load data from the given file (including any newlines), +URL-encode that data and pass it on in the POST. The name part gets an equal +sign appended, resulting in *name=urlencoded-file-content*. Note that the +name is expected to be URL-encoded already. diff --git a/docs/cmdline-opts/data.md b/docs/cmdline-opts/data.md new file mode 100644 index 0000000..fb3b848 --- /dev/null +++ b/docs/cmdline-opts/data.md @@ -0,0 +1,49 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: data +Short: d +Arg: +Help: HTTP POST data +Protocols: HTTP MQTT +Mutexed: form head upload-file +Category: important http post upload +Added: 4.0 +Multi: append +See-also: + - data-binary + - data-urlencode + - data-raw +Example: + - -d "name=curl" $URL + - -d "name=curl" -d "tool=cmdline" $URL + - -d @filename $URL +--- + +# `--data` + +Sends the specified data in a POST request to the HTTP server, in the same way +that a browser does when a user has filled in an HTML form and presses the +submit button. This makes curl pass the data to the server using the +content-type application/x-www-form-urlencoded. Compare to --form. + +--data-raw is almost the same but does not have a special interpretation of +the @ character. To post data purely binary, you should instead use the +--data-binary option. To URL-encode the value of a form field you may use +--data-urlencode. + +If any of these options is used more than once on the same command line, the +data pieces specified are merged with a separating &-symbol. Thus, using +'-d name=daniel -d skill=lousy' would generate a post chunk that looks like +'name=daniel&skill=lousy'. + +If you start the data with the letter @, the rest should be a file name to +read the data from, or - if you want curl to read the data from stdin. Posting +data from a file named 'foobar' would thus be done with --data @foobar. When +--data is told to read from a file like that, carriage returns and newlines +are stripped out. If you do not want the @ character to have a special +interpretation use --data-raw instead. + +The data for this option is passed on to the server exactly as provided on the +command line. curl does not convert, change or improve it. It is up to the +user to provide the data in the correct form. diff --git a/docs/cmdline-opts/delegation.md b/docs/cmdline-opts/delegation.md new file mode 100644 index 0000000..3d6cff8 --- /dev/null +++ b/docs/cmdline-opts/delegation.md @@ -0,0 +1,31 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: delegation +Arg: +Help: GSS-API delegation permission +Protocols: GSS/kerberos +Category: auth +Added: 7.22.0 +Multi: single +See-also: + - insecure + - ssl +Example: + - --delegation "none" $URL +--- + +# `--delegation` + +Set LEVEL to tell the server what it is allowed to delegate when it +comes to user credentials. + +## none +Do not allow any delegation. + +## policy +Delegates if and only if the OK-AS-DELEGATE flag is set in the Kerberos +service ticket, which is a matter of realm policy. + +## always +Unconditionally allow the server to delegate. diff --git a/docs/cmdline-opts/digest.md b/docs/cmdline-opts/digest.md new file mode 100644 index 0000000..f05c01f --- /dev/null +++ b/docs/cmdline-opts/digest.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: digest +Help: Use HTTP Digest Authentication +Protocols: HTTP +Mutexed: basic ntlm negotiate +Category: proxy auth http +Added: 7.10.6 +Multi: boolean +See-also: + - user + - proxy-digest + - anyauth +Example: + - -u name:password --digest $URL +--- + +# `--digest` + +Enables HTTP Digest authentication. This is an authentication scheme that +prevents the password from being sent over the wire in clear text. Use this in +combination with the normal --user option to set user name and password. diff --git a/docs/cmdline-opts/disable-eprt.md b/docs/cmdline-opts/disable-eprt.md new file mode 100644 index 0000000..80ae056 --- /dev/null +++ b/docs/cmdline-opts/disable-eprt.md @@ -0,0 +1,32 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: disable-eprt +Help: Inhibit using EPRT or LPRT +Protocols: FTP +Category: ftp +Added: 7.10.5 +Multi: boolean +See-also: + - disable-epsv + - ftp-port +Example: + - --disable-eprt ftp://example.com/ +--- + +# `--disable-eprt` + +Tell curl to disable the use of the EPRT and LPRT commands when doing active +FTP transfers. Curl normally first attempts to use EPRT before using PORT, but +with this option, it uses PORT right away. EPRT is an extension to the +original FTP protocol, and does not work on all servers, but enables more +functionality in a better way than the traditional PORT command. + +--eprt can be used to explicitly enable EPRT again and --no-eprt is an alias +for --disable-eprt. + +If the server is accessed using IPv6, this option has no effect as EPRT is +necessary then. + +Disabling EPRT only changes the active behavior. If you want to switch to +passive mode you need to not use --ftp-port or force it with --ftp-pasv. diff --git a/docs/cmdline-opts/disable-epsv.md b/docs/cmdline-opts/disable-epsv.md new file mode 100644 index 0000000..f4a8de8 --- /dev/null +++ b/docs/cmdline-opts/disable-epsv.md @@ -0,0 +1,30 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: disable-epsv +Help: Inhibit using EPSV +Protocols: FTP +Category: ftp +Added: 7.9.2 +Multi: boolean +See-also: + - disable-eprt + - ftp-port +Example: + - --disable-epsv ftp://example.com/ +--- + +# `--disable-epsv` + +Tell curl to disable the use of the EPSV command when doing passive FTP +transfers. Curl normally first attempts to use EPSV before PASV, but with this +option, it does not try EPSV. + +--epsv can be used to explicitly enable EPSV again and --no-epsv is an alias +for --disable-epsv. + +If the server is an IPv6 host, this option has no effect as EPSV is necessary +then. + +Disabling EPSV only changes the passive behavior. If you want to switch to +active mode you need to use --ftp-port. diff --git a/docs/cmdline-opts/disable.md b/docs/cmdline-opts/disable.md new file mode 100644 index 0000000..e22a2bb --- /dev/null +++ b/docs/cmdline-opts/disable.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: disable +Short: q +Help: Disable .curlrc +Category: curl +Added: 5.0 +Multi: boolean +See-also: + - config +Example: + - -q $URL +--- + +# `--disable` + +If used as the **first** parameter on the command line, the *curlrc* config +file is not read or used. See the --config for details on the default config +file search path. + +Prior to 7.50.0 curl supported the short option name *q* but not the long +option name *disable*. diff --git a/docs/cmdline-opts/disallow-username-in-url.md b/docs/cmdline-opts/disallow-username-in-url.md new file mode 100644 index 0000000..faa4d88 --- /dev/null +++ b/docs/cmdline-opts/disallow-username-in-url.md @@ -0,0 +1,18 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: disallow-username-in-url +Help: Disallow username in URL +Added: 7.61.0 +Category: curl +Multi: boolean +See-also: + - proto +Example: + - --disallow-username-in-url $URL +--- + +# `--disallow-username-in-url` + +This tells curl to exit if passed a URL containing a username. This is probably +most useful when the URL is being provided at runtime or similar. diff --git a/docs/cmdline-opts/dns-interface.md b/docs/cmdline-opts/dns-interface.md new file mode 100644 index 0000000..afc5573 --- /dev/null +++ b/docs/cmdline-opts/dns-interface.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: dns-interface +Arg: +Help: Interface to use for DNS requests +Protocols: DNS +Added: 7.33.0 +Requires: c-ares +Category: dns +Multi: single +See-also: + - dns-ipv4-addr + - dns-ipv6-addr +Example: + - --dns-interface eth0 $URL +--- + +# `--dns-interface` + +Tell curl to send outgoing DNS requests through . This option is a +counterpart to --interface (which does not affect DNS). The supplied string +must be an interface name (not an address). diff --git a/docs/cmdline-opts/dns-ipv4-addr.md b/docs/cmdline-opts/dns-ipv4-addr.md new file mode 100644 index 0000000..ff4163b --- /dev/null +++ b/docs/cmdline-opts/dns-ipv4-addr.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: dns-ipv4-addr +Arg:
+Help: IPv4 address to use for DNS requests +Protocols: DNS +Added: 7.33.0 +Requires: c-ares +Category: dns +Multi: single +See-also: + - dns-interface + - dns-ipv6-addr +Example: + - --dns-ipv4-addr 10.1.2.3 $URL +--- + +# `--dns-ipv4-addr` + +Tell curl to bind to a specific IP address when making IPv4 DNS requests, so +that the DNS requests originate from this address. The argument should be a +single IPv4 address. diff --git a/docs/cmdline-opts/dns-ipv6-addr.md b/docs/cmdline-opts/dns-ipv6-addr.md new file mode 100644 index 0000000..7d4d1c1 --- /dev/null +++ b/docs/cmdline-opts/dns-ipv6-addr.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: dns-ipv6-addr +Arg:
+Help: IPv6 address to use for DNS requests +Protocols: DNS +Added: 7.33.0 +Requires: c-ares +Category: dns +Multi: single +See-also: + - dns-interface + - dns-ipv4-addr +Example: + - --dns-ipv6-addr 2a04:4e42::561 $URL +--- + +# `--dns-ipv6-addr` + +Tell curl to bind to a specific IP address when making IPv6 DNS requests, so +that the DNS requests originate from this address. The argument should be a +single IPv6 address. diff --git a/docs/cmdline-opts/dns-servers.md b/docs/cmdline-opts/dns-servers.md new file mode 100644 index 0000000..3eab666 --- /dev/null +++ b/docs/cmdline-opts/dns-servers.md @@ -0,0 +1,24 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: dns-servers +Arg: +Help: DNS server addrs to use +Protocols: DNS +Requires: c-ares +Added: 7.33.0 +Category: dns +Multi: single +See-also: + - dns-interface + - dns-ipv4-addr +Example: + - --dns-servers 192.168.0.1,192.168.0.2 $URL +--- + +# `--dns-servers` + +Set the list of DNS servers to be used instead of the system default. +The list of IP addresses should be separated with commas. Port numbers +may also optionally be given as *:* after each IP +address. diff --git a/docs/cmdline-opts/doh-cert-status.md b/docs/cmdline-opts/doh-cert-status.md new file mode 100644 index 0000000..efa9da7 --- /dev/null +++ b/docs/cmdline-opts/doh-cert-status.md @@ -0,0 +1,17 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: doh-cert-status +Help: Verify the status of the DoH server cert via OCSP-staple +Added: 7.76.0 +Category: dns tls +Multi: boolean +See-also: + - doh-insecure +Example: + - --doh-cert-status --doh-url https://doh.example $URL +--- + +# `--doh-cert-status` + +Same as --cert-status but used for DoH (DNS-over-HTTPS). diff --git a/docs/cmdline-opts/doh-insecure.md b/docs/cmdline-opts/doh-insecure.md new file mode 100644 index 0000000..684428d --- /dev/null +++ b/docs/cmdline-opts/doh-insecure.md @@ -0,0 +1,17 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: doh-insecure +Help: Allow insecure DoH server connections +Added: 7.76.0 +Category: dns tls +Multi: boolean +See-also: + - doh-url +Example: + - --doh-insecure --doh-url https://doh.example $URL +--- + +# `--doh-insecure` + +Same as --insecure but used for DoH (DNS-over-HTTPS). diff --git a/docs/cmdline-opts/doh-url.md b/docs/cmdline-opts/doh-url.md new file mode 100644 index 0000000..d12bf51 --- /dev/null +++ b/docs/cmdline-opts/doh-url.md @@ -0,0 +1,27 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: doh-url +Arg: +Help: Resolve host names over DoH +Added: 7.62.0 +Category: dns +Multi: single +See-also: + - doh-insecure +Example: + - --doh-url https://doh.example $URL +--- + +# `--doh-url` + +Specifies which DNS-over-HTTPS (DoH) server to use to resolve hostnames, +instead of using the default name resolver mechanism. The URL must be HTTPS. + +Some SSL options that you set for your transfer also applies to DoH since the +name lookups take place over SSL. However, the certificate verification +settings are not inherited but are controlled separately via --doh-insecure +and --doh-cert-status. + +This option is unset if an empty string "" is used as the URL. +(Added in 7.85.0) diff --git a/docs/cmdline-opts/dump-header.md b/docs/cmdline-opts/dump-header.md new file mode 100644 index 0000000..42d3e85 --- /dev/null +++ b/docs/cmdline-opts/dump-header.md @@ -0,0 +1,27 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: dump-header +Short: D +Arg: +Help: Write the received headers to +Protocols: HTTP FTP +Category: http ftp +Added: 5.7 +Multi: single +See-also: + - output +Example: + - --dump-header store.txt $URL +--- + +# `--dump-header` + +Write the received protocol headers to the specified file. If no headers are +received, the use of this option creates an empty file. + +When used in FTP, the FTP server response lines are considered being "headers" +and thus are saved there. + +Having multiple transfers in one set of operations (i.e. the URLs in one +--next clause), appends them to the same file, separated by a blank line. diff --git a/docs/cmdline-opts/egd-file.md b/docs/cmdline-opts/egd-file.md new file mode 100644 index 0000000..b68b7d4 --- /dev/null +++ b/docs/cmdline-opts/egd-file.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: egd-file +Arg: +Help: EGD socket path for random data +Protocols: TLS +Category: tls +Added: 7.7 +Multi: single +See-also: + - random-file +Example: + - --egd-file /random/here $URL +--- + +# `--egd-file` + +Deprecated option (added in 7.84.0). Prior to that it only had an effect on +curl if built to use old versions of OpenSSL. + +Specify the path name to the Entropy Gathering Daemon socket. The socket is +used to seed the random engine for SSL connections. diff --git a/docs/cmdline-opts/engine.md b/docs/cmdline-opts/engine.md new file mode 100644 index 0000000..5111900 --- /dev/null +++ b/docs/cmdline-opts/engine.md @@ -0,0 +1,22 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: engine +Arg: +Help: Crypto engine to use +Protocols: TLS +Category: tls +Added: 7.9.3 +Multi: single +See-also: + - ciphers + - curves +Example: + - --engine flavor $URL +--- + +# `--engine` + +Select the OpenSSL crypto engine to use for cipher operations. Use --engine +list to print a list of build-time supported engines. Note that not all (and +possibly none) of the engines may be available at runtime. diff --git a/docs/cmdline-opts/etag-compare.md b/docs/cmdline-opts/etag-compare.md new file mode 100644 index 0000000..11c1d0e --- /dev/null +++ b/docs/cmdline-opts/etag-compare.md @@ -0,0 +1,30 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: etag-compare +Arg: +Help: Pass an ETag from a file as a custom header +Protocols: HTTP +Added: 7.68.0 +Category: http +Multi: single +See-also: + - etag-save + - time-cond +Example: + - --etag-compare etag.txt $URL +--- + +# `--etag-compare` + +This option makes a conditional HTTP request for the specific ETag read +from the given file by sending a custom If-None-Match header using the +stored ETag. + +For correct results, make sure that the specified file contains only a +single line with the desired ETag. An empty file is parsed as an empty +ETag. + +Use the option --etag-save to first save the ETag from a response, and +then use this option to compare against the saved ETag in a subsequent +request. diff --git a/docs/cmdline-opts/etag-save.md b/docs/cmdline-opts/etag-save.md new file mode 100644 index 0000000..f6fb14a --- /dev/null +++ b/docs/cmdline-opts/etag-save.md @@ -0,0 +1,22 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: etag-save +Arg: +Help: Parse ETag from a request and save it to a file +Protocols: HTTP +Added: 7.68.0 +Category: http +Multi: single +See-also: + - etag-compare +Example: + - --etag-save storetag.txt $URL +--- + +# `--etag-save` + +This option saves an HTTP ETag to the specified file. An ETag is a +caching related header, usually returned in a response. + +If no ETag is sent by the server, an empty file is created. diff --git a/docs/cmdline-opts/expect100-timeout.md b/docs/cmdline-opts/expect100-timeout.md new file mode 100644 index 0000000..9554568 --- /dev/null +++ b/docs/cmdline-opts/expect100-timeout.md @@ -0,0 +1,25 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: expect100-timeout +Arg: +Help: How long to wait for 100-continue +Protocols: HTTP +Added: 7.47.0 +Category: http +Multi: single +See-also: + - connect-timeout +Example: + - --expect100-timeout 2.5 -T file $URL +--- + +# `--expect100-timeout` + +Maximum time in seconds that you allow curl to wait for a 100-continue +response when curl emits an Expects: 100-continue header in its request. By +default curl waits one second. This option accepts decimal values! When +curl stops waiting, it continues as if the response has been received. + +The decimal value needs to provided using a dot (.) as decimal separator - not +the local version even if it might be using another separator. diff --git a/docs/cmdline-opts/fail-early.md b/docs/cmdline-opts/fail-early.md new file mode 100644 index 0000000..b68160c --- /dev/null +++ b/docs/cmdline-opts/fail-early.md @@ -0,0 +1,32 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: fail-early +Help: Fail on first transfer error, do not continue +Added: 7.52.0 +Category: curl +Multi: boolean +Scope: global +See-also: + - fail + - fail-with-body +Example: + - --fail-early $URL https://two.example +--- + +# `--fail-early` + +Fail and exit on the first detected transfer error. + +When curl is used to do multiple transfers on the command line, it attempts to +operate on each given URL, one by one. By default, it ignores errors if there +are more URLs given and the last URL's success determines the error code curl +returns. So early failures are "hidden" by subsequent successful transfers. + +Using this option, curl instead returns an error on the first transfer that +fails, independent of the amount of URLs that are given on the command +line. This way, no transfer failures go undetected by scripts and similar. + +This option does not imply --fail, which causes transfers to fail due to the +server's HTTP status code. You can combine the two options, however note --fail +is not global and is therefore contained by --next. diff --git a/docs/cmdline-opts/fail-with-body.md b/docs/cmdline-opts/fail-with-body.md new file mode 100644 index 0000000..e340cb0 --- /dev/null +++ b/docs/cmdline-opts/fail-with-body.md @@ -0,0 +1,27 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: fail-with-body +Protocols: HTTP +Help: Fail on HTTP errors but save the body +Category: http output +Added: 7.76.0 +Mutexed: fail +Multi: boolean +See-also: + - fail + - fail-early +Example: + - --fail-with-body $URL +--- + +# `--fail-with-body` + +Return an error on server errors where the HTTP response code is 400 or +greater). In normal cases when an HTTP server fails to deliver a document, it +returns an HTML document stating so (which often also describes why and +more). This flag allows curl to output and save that content but also to +return error 22. + +This is an alternative option to --fail which makes curl fail for the same +circumstances but without saving the content. diff --git a/docs/cmdline-opts/fail.md b/docs/cmdline-opts/fail.md new file mode 100644 index 0000000..b8de4eb --- /dev/null +++ b/docs/cmdline-opts/fail.md @@ -0,0 +1,29 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: fail +Short: f +Protocols: HTTP +Help: Fail fast with no output on HTTP errors +Category: important http +Mutexed: fail-with-body +Added: 4.0 +Multi: boolean +See-also: + - fail-with-body + - fail-early +Example: + - --fail $URL +--- + +# `--fail` + +Fail fast with no output at all on server errors. This is useful to enable +scripts and users to better deal with failed attempts. In normal cases when an +HTTP server fails to deliver a document, it returns an HTML document stating +so (which often also describes why and more). This flag prevents curl from +outputting that and return error 22. + +This method is not fail-safe and there are occasions where non-successful +response codes slip through, especially when authentication is involved +(response codes 401 and 407). diff --git a/docs/cmdline-opts/false-start.md b/docs/cmdline-opts/false-start.md new file mode 100644 index 0000000..d2697da --- /dev/null +++ b/docs/cmdline-opts/false-start.md @@ -0,0 +1,24 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: false-start +Help: Enable TLS False Start +Protocols: TLS +Added: 7.42.0 +Category: tls +Multi: boolean +See-also: + - tcp-fastopen +Example: + - --false-start $URL +--- + +# `--false-start` + +Tells curl to use false start during the TLS handshake. False start is a mode +where a TLS client starts sending application data before verifying the +server's Finished message, thus saving a round trip when performing a full +handshake. + +This is currently only implemented in the Secure Transport (on iOS 7.0 or +later, or OS X 10.9 or later) backend. diff --git a/docs/cmdline-opts/form-escape.md b/docs/cmdline-opts/form-escape.md new file mode 100644 index 0000000..62973f1 --- /dev/null +++ b/docs/cmdline-opts/form-escape.md @@ -0,0 +1,19 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: form-escape +Help: Escape multipart form field/file names using backslash +Protocols: HTTP +Added: 7.81.0 +Category: http upload +Multi: single +See-also: + - form +Example: + - --form-escape -F 'field\name=curl' -F 'file=@load"this' $URL +--- + +# `--form-escape` + +Tells curl to pass on names of multipart form fields and files using +backslash-escaping instead of percent-encoding. diff --git a/docs/cmdline-opts/form-string.md b/docs/cmdline-opts/form-string.md new file mode 100644 index 0000000..d26c471 --- /dev/null +++ b/docs/cmdline-opts/form-string.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: form-string +Help: Specify multipart MIME data +Protocols: HTTP SMTP IMAP +Arg: +Category: http upload +Added: 7.13.2 +Multi: append +See-also: + - form +Example: + - --form-string "data" $URL +--- + +# `--form-string` + +Similar to --form except that the value string for the named parameter is used +literally. Leading '@' and '<' characters, and the ';type=' string in +the value have no special meaning. Use this in preference to --form if +there is any possibility that the string value may accidentally trigger the +'@' or '<' features of --form. diff --git a/docs/cmdline-opts/form.md b/docs/cmdline-opts/form.md new file mode 100644 index 0000000..0ba5521 --- /dev/null +++ b/docs/cmdline-opts/form.md @@ -0,0 +1,142 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: form +Short: F +Arg: +Help: Specify multipart MIME data +Protocols: HTTP SMTP IMAP +Mutexed: data head upload-file +Category: http upload +Added: 5.0 +Multi: append +See-also: + - data + - form-string + - form-escape +Example: + - --form "name=curl" --form "file=@loadthis" $URL +--- + +# `--form` + +For HTTP protocol family, this lets curl emulate a filled-in form in which a +user has pressed the submit button. This causes curl to POST data using the +Content-Type multipart/form-data according to RFC 2388. + +For SMTP and IMAP protocols, this is the means to compose a multipart mail +message to transmit. + +This enables uploading of binary files etc. To force the 'content' part to be +a file, prefix the file name with an @ sign. To just get the content part from +a file, prefix the file name with the symbol <. The difference between @ and < +is then that @ makes a file get attached in the post as a file upload, while +the < makes a text field and just get the contents for that text field from a +file. + +Tell curl to read content from stdin instead of a file by using - as +filename. This goes for both @ and < constructs. When stdin is used, the +contents is buffered in memory first by curl to determine its size and allow a +possible resend. Defining a part's data from a named non-regular file (such as +a named pipe or similar) is not subject to buffering and is instead read at +transmission time; since the full size is unknown before the transfer starts, +such data is sent as chunks by HTTP and rejected by IMAP. + +Example: send an image to an HTTP server, where 'profile' is the name of the +form-field to which the file **portrait.jpg** is the input: + + curl -F profile=@portrait.jpg https://example.com/upload.cgi + +Example: send your name and shoe size in two text fields to the server: + + curl -F name=John -F shoesize=11 https://example.com/ + +Example: send your essay in a text field to the server. Send it as a plain +text field, but get the contents for it from a local file: + + curl -F "story=HTML message;type=text/html' \ + -F '=)' -F '=@textfile.txt' ... smtp://example.com + +Data can be encoded for transfer using encoder=. Available encodings are +*binary* and *8bit* that do nothing else than adding the corresponding +Content-Transfer-Encoding header, *7bit* that only rejects 8-bit characters +with a transfer error, *quoted-printable* and *base64* that encodes data +according to the corresponding schemes, limiting lines length to 76 +characters. + +Example: send multipart mail with a quoted-printable text message and a +base64 attached file: + + curl -F '=text message;encoder=quoted-printable' \ + -F '=@localfile;encoder=base64' ... smtp://example.com + +See further examples and details in the MANUAL. diff --git a/docs/cmdline-opts/ftp-account.md b/docs/cmdline-opts/ftp-account.md new file mode 100644 index 0000000..2f33639 --- /dev/null +++ b/docs/cmdline-opts/ftp-account.md @@ -0,0 +1,20 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-account +Arg: +Help: Account data string +Protocols: FTP +Added: 7.13.0 +Category: ftp auth +Multi: single +See-also: + - user +Example: + - --ftp-account "mr.robot" ftp://example.com/ +--- + +# `--ftp-account` + +When an FTP server asks for "account data" after user name and password has +been provided, this data is sent off using the ACCT command. diff --git a/docs/cmdline-opts/ftp-alternative-to-user.md b/docs/cmdline-opts/ftp-alternative-to-user.md new file mode 100644 index 0000000..9bd3686 --- /dev/null +++ b/docs/cmdline-opts/ftp-alternative-to-user.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-alternative-to-user +Arg: +Help: String to replace USER [name] +Protocols: FTP +Added: 7.15.5 +Category: ftp +Multi: single +See-also: + - ftp-account + - user +Example: + - --ftp-alternative-to-user "U53r" ftp://example.com +--- + +# `--ftp-alternative-to-user` + +If authenticating with the USER and PASS commands fails, send this command. +When connecting to Tumbleweed's Secure Transport server over FTPS using a +client certificate, using "SITE AUTH" tells the server to retrieve the +username from the certificate. diff --git a/docs/cmdline-opts/ftp-create-dirs.md b/docs/cmdline-opts/ftp-create-dirs.md new file mode 100644 index 0000000..5151e33 --- /dev/null +++ b/docs/cmdline-opts/ftp-create-dirs.md @@ -0,0 +1,20 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-create-dirs +Protocols: FTP SFTP +Help: Create the remote dirs if not present +Category: ftp sftp curl +Added: 7.10.7 +Multi: boolean +See-also: + - create-dirs +Example: + - --ftp-create-dirs -T file ftp://example.com/remote/path/file +--- + +# `--ftp-create-dirs` + +When an FTP or SFTP URL/operation uses a path that does not currently exist on +the server, the standard behavior of curl is to fail. Using this option, curl +instead attempts to create missing directories. diff --git a/docs/cmdline-opts/ftp-method.md b/docs/cmdline-opts/ftp-method.md new file mode 100644 index 0000000..e4e3468 --- /dev/null +++ b/docs/cmdline-opts/ftp-method.md @@ -0,0 +1,36 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-method +Arg: +Help: Control CWD usage +Protocols: FTP +Added: 7.15.1 +Category: ftp +Multi: single +See-also: + - list-only +Example: + - --ftp-method multicwd ftp://example.com/dir1/dir2/file + - --ftp-method nocwd ftp://example.com/dir1/dir2/file + - --ftp-method singlecwd ftp://example.com/dir1/dir2/file +--- + +# `--ftp-method` + +Control what method curl should use to reach a file on an FTP(S) +server. The method argument should be one of the following alternatives: + +## multicwd +curl does a single CWD operation for each path part in the given URL. For deep +hierarchies this means many commands. This is how RFC 1738 says it should +be done. This is the default but the slowest behavior. + +## nocwd +curl does no CWD at all. curl does SIZE, RETR, STOR etc and give a full +path to the server for all these commands. This is the fastest behavior. + +## singlecwd +curl does one CWD with the full target directory and then operates on the file +"normally" (like in the multicwd case). This is somewhat more standards +compliant than 'nocwd' but without the full penalty of 'multicwd'. diff --git a/docs/cmdline-opts/ftp-pasv.md b/docs/cmdline-opts/ftp-pasv.md new file mode 100644 index 0000000..265a8e4 --- /dev/null +++ b/docs/cmdline-opts/ftp-pasv.md @@ -0,0 +1,26 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-pasv +Help: Use PASV/EPSV instead of PORT +Protocols: FTP +Added: 7.11.0 +Category: ftp +Multi: boolean +See-also: + - disable-epsv +Example: + - --ftp-pasv ftp://example.com/ +--- + +# `--ftp-pasv` + +Use passive mode for the data connection. Passive is the internal default +behavior, but using this option can be used to override a previous --ftp-port +option. + +Reversing an enforced passive really is not doable but you must then instead +enforce the correct --ftp-port again. + +Passive mode means that curl tries the EPSV command first and then PASV, +unless --disable-epsv is used. diff --git a/docs/cmdline-opts/ftp-port.md b/docs/cmdline-opts/ftp-port.md new file mode 100644 index 0000000..e9ec591 --- /dev/null +++ b/docs/cmdline-opts/ftp-port.md @@ -0,0 +1,51 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-port +Arg:
+Help: Use PORT instead of PASV +Short: P +Protocols: FTP +Category: ftp +Added: 4.0 +Multi: single +See-also: + - ftp-pasv + - disable-eprt +Example: + - -P - ftp:/example.com + - -P eth0 ftp:/example.com + - -P 192.168.0.2 ftp:/example.com +--- + +# `--ftp-port` + +Reverses the default initiator/listener roles when connecting with FTP. This +option makes curl use active mode. curl then tells the server to connect back +to the client's specified address and port, while passive mode asks the server +to setup an IP address and port for it to connect to.
should be one +of: + +## interface +e.g. **eth0** to specify which interface's IP address you want to use (Unix only) + +## IP address +e.g. **192.168.10.1** to specify the exact IP address + +## host name +e.g. **my.host.domain** to specify the machine + +## - +make curl pick the same IP address that is already used for the control +connection. This is the recommended choice. + +## + +Disable the use of PORT with --ftp-pasv. Disable the attempt to use the EPRT +command instead of PORT by using --disable-eprt. EPRT is really PORT++. + +You can also append ":[start]-[end]" to the right of the address, to tell +curl what TCP port range to use. That means you specify a port range, from a +lower to a higher number. A single number works as well, but do note that it +increases the risk of failure since the port may not be available. +(Added in 7.19.5) diff --git a/docs/cmdline-opts/ftp-pret.md b/docs/cmdline-opts/ftp-pret.md new file mode 100644 index 0000000..accbc22 --- /dev/null +++ b/docs/cmdline-opts/ftp-pret.md @@ -0,0 +1,21 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-pret +Help: Send PRET before PASV +Protocols: FTP +Added: 7.20.0 +Category: ftp +Multi: boolean +See-also: + - ftp-port + - ftp-pasv +Example: + - --ftp-pret ftp://example.com/ +--- + +# `--ftp-pret` + +Tell curl to send a PRET command before PASV (and EPSV). Certain FTP servers, +mainly drftpd, require this non-standard command for directory listings as +well as up and downloads in PASV mode. diff --git a/docs/cmdline-opts/ftp-skip-pasv-ip.md b/docs/cmdline-opts/ftp-skip-pasv-ip.md new file mode 100644 index 0000000..ef94b34 --- /dev/null +++ b/docs/cmdline-opts/ftp-skip-pasv-ip.md @@ -0,0 +1,24 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-skip-pasv-ip +Help: Skip the IP address for PASV +Protocols: FTP +Added: 7.14.2 +Category: ftp +Multi: boolean +See-also: + - ftp-pasv +Example: + - --ftp-skip-pasv-ip ftp://example.com/ +--- + +# `--ftp-skip-pasv-ip` + +Tell curl to not use the IP address the server suggests in its response to +curl's PASV command when curl connects the data connection. Instead curl +reuses the same IP address it already uses for the control connection. + +This option is enabled by default (added in 7.74.0). + +This option has no effect if PORT, EPRT or EPSV is used instead of PASV. diff --git a/docs/cmdline-opts/ftp-ssl-ccc-mode.md b/docs/cmdline-opts/ftp-ssl-ccc-mode.md new file mode 100644 index 0000000..5f428dc --- /dev/null +++ b/docs/cmdline-opts/ftp-ssl-ccc-mode.md @@ -0,0 +1,22 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-ssl-ccc-mode +Arg: +Help: Set CCC mode +Protocols: FTP +Added: 7.16.2 +Category: ftp tls +Multi: boolean +See-also: + - ftp-ssl-ccc +Example: + - --ftp-ssl-ccc-mode active --ftp-ssl-ccc ftps://example.com/ +--- + +# `--ftp-ssl-ccc-mode` + +Sets the CCC mode. The passive mode does not initiate the shutdown, but +instead waits for the server to do it, and does not reply to the shutdown from +the server. The active mode initiates the shutdown and waits for a reply from +the server. diff --git a/docs/cmdline-opts/ftp-ssl-ccc.md b/docs/cmdline-opts/ftp-ssl-ccc.md new file mode 100644 index 0000000..d477606 --- /dev/null +++ b/docs/cmdline-opts/ftp-ssl-ccc.md @@ -0,0 +1,22 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-ssl-ccc +Help: Send CCC after authenticating +Protocols: FTP +Added: 7.16.1 +Category: ftp tls +Multi: boolean +See-also: + - ssl + - ftp-ssl-ccc-mode +Example: + - --ftp-ssl-ccc ftps://example.com/ +--- + +# `--ftp-ssl-ccc` + +Use CCC (Clear Command Channel) Shuts down the SSL/TLS layer after +authenticating. The rest of the control channel communication is be +unencrypted. This allows NAT routers to follow the FTP transaction. The +default mode is passive. diff --git a/docs/cmdline-opts/ftp-ssl-control.md b/docs/cmdline-opts/ftp-ssl-control.md new file mode 100644 index 0000000..ace1ab2 --- /dev/null +++ b/docs/cmdline-opts/ftp-ssl-control.md @@ -0,0 +1,20 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: ftp-ssl-control +Help: Require SSL/TLS for FTP login, clear for transfer +Protocols: FTP +Added: 7.16.0 +Category: ftp tls +Multi: boolean +See-also: + - ssl +Example: + - --ftp-ssl-control ftp://example.com +--- + +# `--ftp-ssl-control` + +Require SSL/TLS for the FTP login, clear for transfer. Allows secure +authentication, but non-encrypted data transfers for efficiency. Fails the +transfer if the server does not support SSL/TLS. diff --git a/docs/cmdline-opts/gen.pl b/docs/cmdline-opts/gen.pl new file mode 100755 index 0000000..f4dcce8 --- /dev/null +++ b/docs/cmdline-opts/gen.pl @@ -0,0 +1,965 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +=begin comment + +This script generates the manpage. + +Example: gen.pl [files] > curl.1 + +Dev notes: + +We open *input* files in :crlf translation (a no-op on many platforms) in +case we have CRLF line endings in Windows but a perl that defaults to LF. +Unfortunately it seems some perls like msysgit cannot handle a global input-only +:crlf so it has to be specified on each file open for text input. + +=end comment +=cut + +my %optshort; +my %optlong; +my %helplong; +my %arglong; +my %redirlong; +my %protolong; +my %catlong; + +use POSIX qw(strftime); +my @ts; +if (defined($ENV{SOURCE_DATE_EPOCH})) { + @ts = localtime($ENV{SOURCE_DATE_EPOCH}); +} else { + @ts = localtime; +} +my $date = strftime "%B %d %Y", @ts; +my $year = strftime "%Y", @ts; +my $version = "unknown"; +my $globals; + +open(INC, "<../../include/curl/curlver.h"); +while() { + if($_ =~ /^#define LIBCURL_VERSION \"([0-9.]*)/) { + $version = $1; + last; + } +} +close(INC); + +# get the long name version, return the man page string +sub manpageify { + my ($k)=@_; + my $l; + my $klong = $k; + # quote "bare" minuses in the long name + $klong =~ s/-/\\-/g; + if($optlong{$k} ne "") { + # both short + long + $l = "\\fI-".$optlong{$k}.", \\-\\-$klong\\fP"; + } + else { + # only long + $l = "\\fI\\-\\-$klong\\fP"; + } + return $l; +} + +sub printdesc { + my @desc = @_; + my $exam = 0; + for my $d (@desc) { + print $d; + } +} + +sub seealso { + my($standalone, $data)=@_; + if($standalone) { + return sprintf + ".SH \"SEE ALSO\"\n$data\n"; + } + else { + return "See also $data. "; + } +} + +sub overrides { + my ($standalone, $data)=@_; + if($standalone) { + return ".SH \"OVERRIDES\"\n$data\n"; + } + else { + return $data; + } +} + +sub protocols { + my ($standalone, $data)=@_; + if($standalone) { + return ".SH \"PROTOCOLS\"\n$data\n"; + } + else { + return "($data) "; + } +} + +sub too_old { + my ($version)=@_; + my $a = 999999; + if($version =~ /^(\d+)\.(\d+)\.(\d+)/) { + $a = $1 * 1000 + $2 * 10 + $3; + } + elsif($version =~ /^(\d+)\.(\d+)/) { + $a = $1 * 1000 + $2 * 10; + } + if($a < 7500) { + # we consider everything before 7.50.0 to be too old to mention + # specific changes for + return 1; + } + return 0; +} + +sub added { + my ($standalone, $data)=@_; + if(too_old($data)) { + # do not mention ancient additions + return ""; + } + if($standalone) { + return ".SH \"ADDED\"\nAdded in curl version $data\n"; + } + else { + return "Added in $data. "; + } +} + +sub render { + my ($fh, $f, $line) = @_; + my @desc; + my $tablemode = 0; + my $header = 0; + # if $top is TRUE, it means a top-level page and not a command line option + my $top = ($line == 1); + my $quote; + $start = 0; + + while(<$fh>) { + my $d = $_; + $line++; + if($d =~ /^\.(SH|BR|IP|B)/) { + print STDERR "$f:$line:1:ERROR: nroff instruction in input: \".$1\"\n"; + return 4; + } + if(/^ * + +# libcurl examples + +This directory is for libcurl programming examples. They are meant to show +some simple steps on how you can build your own application to take full +advantage of libcurl. + +If you end up with other small but still useful example sources, please mail +them for submission in future packages and on the website. + +## Building + +The `Makefile.example` is an example Makefile that could be used to build +these examples. Just edit the file according to your system and requirements +first. + +Most examples should build fine using a command line like this: + + `curl-config --cc --cflags --libs` -o example example.c + +Some compilers do not like having the arguments in this order but instead +want you do reorganize them like: + + `curl-config --cc` -o example example.c `curl-config --cflags --libs` + +**Please** do not use the `curl.se` site as a test target for your libcurl +applications/experiments. Even if some of the examples use that site as a URL +at some places, it does not mean that the URLs work or that we expect you to +actually torture our website with your tests. Thanks. + +## Examples + +Each example source code file is designed to be and work stand-alone and +rather self-explanatory. The examples may at times lack the level of error +checks you need in a real world, but that is then only for the sake of +readability: to make the code smaller and easier to follow. diff --git a/docs/examples/address-scope.c b/docs/examples/address-scope.c new file mode 100644 index 0000000..dc305a0 --- /dev/null +++ b/docs/examples/address-scope.c @@ -0,0 +1,62 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP GET to an IPv6 address with specific scope + * + */ +#include +#include + +#ifndef _WIN32 +#include +#endif + +int main(void) +{ +#ifndef _WIN32 + /* Windows users need to find how to use if_nametoindex() */ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + long my_scope_id; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + my_scope_id = if_nametoindex("eth0"); + curl_easy_setopt(curl, CURLOPT_ADDRESS_SCOPE, my_scope_id); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } +#endif + return 0; +} diff --git a/docs/examples/altsvc.c b/docs/examples/altsvc.c new file mode 100644 index 0000000..28e9794 --- /dev/null +++ b/docs/examples/altsvc.c @@ -0,0 +1,58 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP with Alt-Svc support + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* cache the alternatives in this file */ + curl_easy_setopt(curl, CURLOPT_ALTSVC, "altsvc.txt"); + + /* restrict which HTTP versions to use alternatives */ + curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, (long) + CURLALTSVC_H1|CURLALTSVC_H2|CURLALTSVC_H3); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/anyauthput.c b/docs/examples/anyauthput.c new file mode 100644 index 0000000..156e8d1 --- /dev/null +++ b/docs/examples/anyauthput.c @@ -0,0 +1,155 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP PUT upload with authentication using "any" method. libcurl picks the + * one the server supports/wants. + * + */ +#include +#include +#include +#include + +#include + +#ifdef _WIN32 +# define FILENO(fp) _fileno(fp) +#else +# define FILENO(fp) fileno(fp) +#endif + +#if LIBCURL_VERSION_NUM < 0x070c03 +#error "upgrade your libcurl to no less than 7.12.3" +#endif + +/* + * This example shows an HTTP PUT operation with authentication using "any" + * type. It PUTs a file given as a command line argument to the URL also given + * on the command line. + * + * Since libcurl 7.12.3, using "any" auth and POST/PUT requires a set seek + * function. + * + * This example also uses its own read callback. + */ + +/* seek callback function */ +static int my_seek(void *userp, curl_off_t offset, int origin) +{ + FILE *fp = (FILE *) userp; + + if(-1 == fseek(fp, (long) offset, origin)) + /* could not seek */ + return CURL_SEEKFUNC_CANTSEEK; + + return CURL_SEEKFUNC_OK; /* success! */ +} + +/* read callback function, fread() look alike */ +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t nread; + + nread = fread(ptr, size, nmemb, stream); + + if(nread > 0) { + fprintf(stderr, "*** We read %lu bytes from file\n", (unsigned long)nread); + } + + return nread; +} + +int main(int argc, char **argv) +{ + CURL *curl; + CURLcode res; + FILE *fp; + struct stat file_info; + + char *file; + char *url; + + if(argc < 3) + return 1; + + file = argv[1]; + url = argv[2]; + + /* get the file size of the local file */ + fp = fopen(file, "rb"); + fstat(FILENO(fp), &file_info); + + /* In windows, this will init the winsock stuff */ + curl_global_init(CURL_GLOBAL_ALL); + + /* get a curl handle */ + curl = curl_easy_init(); + if(curl) { + /* we want to use our own read function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + + /* which file to upload */ + curl_easy_setopt(curl, CURLOPT_READDATA, (void *) fp); + + /* set the seek function */ + curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek); + + /* pass the file descriptor to the seek callback as well */ + curl_easy_setopt(curl, CURLOPT_SEEKDATA, (void *) fp); + + /* enable "uploading" (which means PUT when doing HTTP) */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* specify target URL, and note that this URL should also include a file + name, not only a directory (as you can do with GTP uploads) */ + curl_easy_setopt(curl, CURLOPT_URL, url); + + /* and give the size of the upload, this supports large file sizes + on systems that have general support for it */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)file_info.st_size); + + /* tell libcurl we can use "any" auth, which lets the lib pick one, but it + also costs one extra round-trip and possibly sending of all the PUT + data twice!!! */ + curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY); + + /* set user name and password for the authentication */ + curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password"); + + /* Now run off and do what you have been told! */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + fclose(fp); /* close the local file */ + + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/cacertinmem.c b/docs/examples/cacertinmem.c new file mode 100644 index 0000000..647b495 --- /dev/null +++ b/docs/examples/cacertinmem.c @@ -0,0 +1,183 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * CA cert in memory with OpenSSL to get an HTTPS page. + * + */ + +#include +#include +#include +#include + +static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) +{ + fwrite(ptr, size, nmemb, (FILE *)stream); + return (nmemb*size); +} + +static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) +{ + CURLcode rv = CURLE_ABORTED_BY_CALLBACK; + + /** This example uses two (fake) certificates **/ + static const char mypem[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE\n" + "AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw\n" + "CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ\n" + "BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND\n" + "VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb\n" + "qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY\n" + "HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo\n" + "G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA\n" + "0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH\n" + "k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47\n" + "JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m\n" + "AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD\n" + "vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms\n" + "tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH\n" + "7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h\n" + "I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA\n" + "h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF\n" + "d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H\n" + "pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7\n" + "-----END CERTIFICATE-----\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE\n" + "AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x\n" + "CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW\n" + "MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF\n" + "RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC\n" + "AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7\n" + "09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7\n" + "XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P\n" + "gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe\n" + "I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i\n" + "5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi\n" + "ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn\n" + "MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ\n" + "o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6\n" + "zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN\n" + "GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt\n" + "r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK\n" + "Z05phkOTOPu220+DkdRgfks+KzgHVZhepA==\n" + "-----END CERTIFICATE-----\n"; + + BIO *cbio = BIO_new_mem_buf(mypem, sizeof(mypem)); + X509_STORE *cts = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); + int i; + STACK_OF(X509_INFO) *inf; + (void)curl; + (void)parm; + + if(!cts || !cbio) { + return rv; + } + + inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL); + + if(!inf) { + BIO_free(cbio); + return rv; + } + + for(i = 0; i < sk_X509_INFO_num(inf); i++) { + X509_INFO *itmp = sk_X509_INFO_value(inf, i); + if(itmp->x509) { + X509_STORE_add_cert(cts, itmp->x509); + } + if(itmp->crl) { + X509_STORE_add_crl(cts, itmp->crl); + } + } + + sk_X509_INFO_pop_free(inf, X509_INFO_free); + BIO_free(cbio); + + rv = CURLE_OK; + return rv; +} + +int main(void) +{ + CURL *ch; + CURLcode rv; + + curl_global_init(CURL_GLOBAL_ALL); + ch = curl_easy_init(); + curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(ch, CURLOPT_HEADER, 0L); + curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, stdout); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, stderr); + curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); + + /* Turn off the default CA locations, otherwise libcurl will load CA + * certificates from the locations that were detected/specified at + * build-time + */ + curl_easy_setopt(ch, CURLOPT_CAINFO, NULL); + curl_easy_setopt(ch, CURLOPT_CAPATH, NULL); + + /* first try: retrieve page without ca certificates -> should fail + * unless libcurl was built --with-ca-fallback enabled at build-time + */ + rv = curl_easy_perform(ch); + if(rv == CURLE_OK) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + /* use a fresh connection (optional) + * this option seriously impacts performance of multiple transfers but + * it is necessary order to demonstrate this example. recall that the + * ssl ctx callback is only called _before_ an SSL connection is + * established, therefore it will not affect existing verified SSL + * connections already in the connection cache associated with this + * handle. normally you would set the ssl ctx function before making + * any transfers, and not use this option. + */ + curl_easy_setopt(ch, CURLOPT_FRESH_CONNECT, 1L); + + /* second try: retrieve page using cacerts' certificate -> will succeed + * load the certificate by installing a function doing the necessary + * "modifications" to the SSL CONTEXT just before link init + */ + curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); + rv = curl_easy_perform(ch); + if(rv == CURLE_OK) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + curl_easy_cleanup(ch); + curl_global_cleanup(); + return rv; +} diff --git a/docs/examples/certinfo.c b/docs/examples/certinfo.c new file mode 100644 index 0000000..795be6c --- /dev/null +++ b/docs/examples/certinfo.c @@ -0,0 +1,87 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Extract lots of TLS certificate info. + * + */ +#include + +#include + +static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) +{ + (void)stream; + (void)ptr; + return size * nmemb; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, wrfu); + + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); + + res = curl_easy_perform(curl); + + if(!res) { + struct curl_certinfo *certinfo; + + res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &certinfo); + + if(!res && certinfo) { + int i; + + printf("%d certs!\n", certinfo->num_of_certs); + + for(i = 0; i < certinfo->num_of_certs; i++) { + struct curl_slist *slist; + + for(slist = certinfo->certinfo[i]; slist; slist = slist->next) + printf("%s\n", slist->data); + + } + } + + } + + curl_easy_cleanup(curl); + } + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/chkspeed.c b/docs/examples/chkspeed.c new file mode 100644 index 0000000..a8d9566 --- /dev/null +++ b/docs/examples/chkspeed.c @@ -0,0 +1,224 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Show transfer timing info after download completes. + * + */ +/* Example source code to show how the callback function can be used to + * download data into a chunk of memory instead of storing it in a file. + * After successful download we use curl_easy_getinfo() calls to get the + * amount of downloaded bytes, the time used for the whole download, and + * the average download speed. + * On Linux you can create the download test files with: + * dd if=/dev/urandom of=file_1M.bin bs=1M count=1 + * + */ + +#include +#include +#include + +#include + +#define URL_BASE "http://speedtest.your.domain/" +#define URL_1M URL_BASE "file_1M.bin" +#define URL_2M URL_BASE "file_2M.bin" +#define URL_5M URL_BASE "file_5M.bin" +#define URL_10M URL_BASE "file_10M.bin" +#define URL_20M URL_BASE "file_20M.bin" +#define URL_50M URL_BASE "file_50M.bin" +#define URL_100M URL_BASE "file_100M.bin" + +#define CHKSPEED_VERSION "1.0" + +static size_t WriteCallback(void *ptr, size_t size, size_t nmemb, void *data) +{ + /* we are not interested in the downloaded bytes itself, + so we only return the size we would have saved ... */ + (void)ptr; /* unused */ + (void)data; /* unused */ + return (size_t)(size * nmemb); +} + +int main(int argc, char *argv[]) +{ + CURL *curl_handle; + CURLcode res; + int prtall = 0, prtsep = 0, prttime = 0; + const char *url = URL_1M; + char *appname = argv[0]; + + if(argc > 1) { + /* parse input parameters */ + for(argc--, argv++; *argv; argc--, argv++) { + if(argv[0][0] == '-') { + switch(argv[0][1]) { + case 'h': + case 'H': + fprintf(stderr, + "\rUsage: %s [-m=1|2|5|10|20|50|100] [-t] [-x] [url]\n", + appname); + exit(1); + case 'v': + case 'V': + fprintf(stderr, "\r%s %s - %s\n", + appname, CHKSPEED_VERSION, curl_version()); + exit(1); + case 'a': + case 'A': + prtall = 1; + break; + case 'x': + case 'X': + prtsep = 1; + break; + case 't': + case 'T': + prttime = 1; + break; + case 'm': + case 'M': + if(argv[0][2] == '=') { + long m = strtol((*argv) + 3, NULL, 10); + switch(m) { + case 1: + url = URL_1M; + break; + case 2: + url = URL_2M; + break; + case 5: + url = URL_5M; + break; + case 10: + url = URL_10M; + break; + case 20: + url = URL_20M; + break; + case 50: + url = URL_50M; + break; + case 100: + url = URL_100M; + break; + default: + fprintf(stderr, "\r%s: invalid parameter %s\n", + appname, *argv + 3); + return 1; + } + break; + } + fprintf(stderr, "\r%s: invalid or unknown option %s\n", + appname, *argv); + return 1; + default: + fprintf(stderr, "\r%s: invalid or unknown option %s\n", + appname, *argv); + return 1; + } + } + else { + url = *argv; + } + } + } + + /* print separator line */ + if(prtsep) { + printf("-------------------------------------------------\n"); + } + /* print localtime */ + if(prttime) { + time_t t = time(NULL); + printf("Localtime: %s", ctime(&t)); + } + + /* init libcurl */ + curl_global_init(CURL_GLOBAL_ALL); + + /* init the curl session */ + curl_handle = curl_easy_init(); + + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, url); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteCallback); + + /* some servers do not like requests that are made without a user-agent + field, so we provide one */ + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, + "libcurl-speedchecker/" CHKSPEED_VERSION); + + /* get it! */ + res = curl_easy_perform(curl_handle); + + if(CURLE_OK == res) { + curl_off_t val; + + /* check for bytes downloaded */ + res = curl_easy_getinfo(curl_handle, CURLINFO_SIZE_DOWNLOAD_T, &val); + if((CURLE_OK == res) && (val>0)) + printf("Data downloaded: %lu bytes.\n", (unsigned long)val); + + /* check for total download time */ + res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME_T, &val); + if((CURLE_OK == res) && (val>0)) + printf("Total download time: %lu.%06lu sec.\n", + (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); + + /* check for average download speed */ + res = curl_easy_getinfo(curl_handle, CURLINFO_SPEED_DOWNLOAD_T, &val); + if((CURLE_OK == res) && (val>0)) + printf("Average download speed: %lu kbyte/sec.\n", + (unsigned long)(val / 1024)); + + if(prtall) { + /* check for name resolution time */ + res = curl_easy_getinfo(curl_handle, CURLINFO_NAMELOOKUP_TIME_T, &val); + if((CURLE_OK == res) && (val>0)) + printf("Name lookup time: %lu.%06lu sec.\n", + (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); + + /* check for connect time */ + res = curl_easy_getinfo(curl_handle, CURLINFO_CONNECT_TIME_T, &val); + if((CURLE_OK == res) && (val>0)) + printf("Connect time: %lu.%06lu sec.\n", + (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); + } + } + else { + fprintf(stderr, "Error while fetching '%s' : %s\n", + url, curl_easy_strerror(res)); + } + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + /* we are done with libcurl, so clean it up */ + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/connect-to.c b/docs/examples/connect-to.c new file mode 100644 index 0000000..fcdd2cc --- /dev/null +++ b/docs/examples/connect-to.c @@ -0,0 +1,70 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use CURLOPT_CONNECT_TO to connect to "wrong" host name + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + /* + Each single string should be written using the format + HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT where HOST is the host of the + request, PORT is the port of the request, CONNECT-TO-HOST is the host name + to connect to, and CONNECT-TO-PORT is the port to connect to. + */ + /* instead of curl.se:443, it will resolve and use example.com:443 but in + other aspects work as if it still is curl.se */ + struct curl_slist *host = curl_slist_append(NULL, + "curl.se:443:example.com:443"); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CONNECT_TO, host); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + + /* since this connects to the wrong host, checking the host name in the + server certificate will fail, so unless we disable the check libcurl + returns CURLE_PEER_FAILED_VERIFICATION */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + + /* Letting the wrong host name in the certificate be okay, the transfer + goes through but will (most likely) cause a 404 or similar because it + sends an unknown name in the Host: header field */ + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + curl_slist_free_all(host); + + return (int)res; +} diff --git a/docs/examples/cookie_interface.c b/docs/examples/cookie_interface.c new file mode 100644 index 0000000..1200498 --- /dev/null +++ b/docs/examples/cookie_interface.c @@ -0,0 +1,142 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Import and export cookies with COOKIELIST. + * + */ + +#include +#include +#include +#include +#include + +#include + +static void +print_cookies(CURL *curl) +{ + CURLcode res; + struct curl_slist *cookies; + struct curl_slist *nc; + int i; + + printf("Cookies, curl knows:\n"); + res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies); + if(res != CURLE_OK) { + fprintf(stderr, "Curl curl_easy_getinfo failed: %s\n", + curl_easy_strerror(res)); + exit(1); + } + nc = cookies; + i = 1; + while(nc) { + printf("[%d]: %s\n", i, nc->data); + nc = nc->next; + i++; + } + if(i == 1) { + printf("(none)\n"); + } + curl_slist_free_all(cookies); +} + +int +main(void) +{ + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if(curl) { + char nline[512]; + + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* start cookie engine */ + res = curl_easy_perform(curl); + if(res != CURLE_OK) { + fprintf(stderr, "Curl perform failed: %s\n", curl_easy_strerror(res)); + return 1; + } + + print_cookies(curl); + + printf("Erasing curl's knowledge of cookies!\n"); + curl_easy_setopt(curl, CURLOPT_COOKIELIST, "ALL"); + + print_cookies(curl); + + printf("-----------------------------------------------\n" + "Setting a cookie \"PREF\" via cookie interface:\n"); +#ifdef _WIN32 +#define snprintf _snprintf +#endif + /* Netscape format cookie */ + snprintf(nline, sizeof(nline), "%s\t%s\t%s\t%s\t%.0f\t%s\t%s", + ".example.com", "TRUE", "/", "FALSE", + difftime(time(NULL) + 31337, (time_t)0), + "PREF", "hello example, i like you!"); + res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline); + if(res != CURLE_OK) { + fprintf(stderr, "Curl curl_easy_setopt failed: %s\n", + curl_easy_strerror(res)); + return 1; + } + + /* HTTP-header style cookie. If you use the Set-Cookie format and do not + specify a domain then the cookie is sent for any domain and will not be + modified, likely not what you intended. Starting in 7.43.0 any-domain + cookies will not be exported either. For more information refer to the + CURLOPT_COOKIELIST documentation. + */ + snprintf(nline, sizeof(nline), + "Set-Cookie: OLD_PREF=3d141414bf4209321; " + "expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.example.com"); + res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline); + if(res != CURLE_OK) { + fprintf(stderr, "Curl curl_easy_setopt failed: %s\n", + curl_easy_strerror(res)); + return 1; + } + + print_cookies(curl); + + res = curl_easy_perform(curl); + if(res != CURLE_OK) { + fprintf(stderr, "Curl perform failed: %s\n", curl_easy_strerror(res)); + return 1; + } + + curl_easy_cleanup(curl); + } + else { + fprintf(stderr, "Curl init failed!\n"); + return 1; + } + + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/crawler.c b/docs/examples/crawler.c new file mode 100644 index 0000000..2ff4ae7 --- /dev/null +++ b/docs/examples/crawler.c @@ -0,0 +1,237 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Jeroen Ooms + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * To compile: + * gcc crawler.c $(pkg-config --cflags --libs libxml-2.0 libcurl) + * + */ +/* + * Web crawler based on curl and libxml2 to stress-test curl with + * hundreds of concurrent connections to various servers. + * + */ + +/* Parameters */ +int max_con = 200; +int max_total = 20000; +int max_requests = 500; +int max_link_per_page = 5; +int follow_relative_links = 0; +char *start_page = "https://www.reuters.com"; + +#include +#include +#include +#include +#include +#include +#include +#include + +int pending_interrupt = 0; +void sighandler(int dummy) +{ + pending_interrupt = 1; +} + +/* resizable buffer */ +typedef struct { + char *buf; + size_t size; +} memory; + +size_t grow_buffer(void *contents, size_t sz, size_t nmemb, void *ctx) +{ + size_t realsize = sz * nmemb; + memory *mem = (memory*) ctx; + char *ptr = realloc(mem->buf, mem->size + realsize); + if(!ptr) { + /* out of memory */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + mem->buf = ptr; + memcpy(&(mem->buf[mem->size]), contents, realsize); + mem->size += realsize; + return realsize; +} + +CURL *make_handle(char *url) +{ + CURL *handle = curl_easy_init(); + + /* Important: use HTTP2 over HTTPS */ + curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); + curl_easy_setopt(handle, CURLOPT_URL, url); + + /* buffer body */ + memory *mem = malloc(sizeof(memory)); + mem->size = 0; + mem->buf = malloc(1); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, grow_buffer); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, mem); + curl_easy_setopt(handle, CURLOPT_PRIVATE, mem); + + /* For completeness */ + curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, ""); + curl_easy_setopt(handle, CURLOPT_TIMEOUT, 5L); + curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L); + /* only allow redirects to HTTP and HTTPS URLs */ + curl_easy_setopt(handle, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"); + curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L); + curl_easy_setopt(handle, CURLOPT_MAXREDIRS, 10L); + /* each transfer needs to be done within 20 seconds! */ + curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, 20000L); + /* connect fast or fail */ + curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT_MS, 2000L); + /* skip files larger than a gigabyte */ + curl_easy_setopt(handle, CURLOPT_MAXFILESIZE_LARGE, + (curl_off_t)1024*1024*1024); + curl_easy_setopt(handle, CURLOPT_COOKIEFILE, ""); + curl_easy_setopt(handle, CURLOPT_FILETIME, 1L); + curl_easy_setopt(handle, CURLOPT_USERAGENT, "mini crawler"); + curl_easy_setopt(handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_easy_setopt(handle, CURLOPT_UNRESTRICTED_AUTH, 1L); + curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + curl_easy_setopt(handle, CURLOPT_EXPECT_100_TIMEOUT_MS, 0L); + return handle; +} + +/* HREF finder implemented in libxml2 but could be any HTML parser */ +size_t follow_links(CURLM *multi_handle, memory *mem, char *url) +{ + int opts = HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | \ + HTML_PARSE_NOWARNING | HTML_PARSE_NONET; + htmlDocPtr doc = htmlReadMemory(mem->buf, mem->size, url, NULL, opts); + if(!doc) + return 0; + xmlChar *xpath = (xmlChar*) "//a/@href"; + xmlXPathContextPtr context = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context); + xmlXPathFreeContext(context); + if(!result) + return 0; + xmlNodeSetPtr nodeset = result->nodesetval; + if(xmlXPathNodeSetIsEmpty(nodeset)) { + xmlXPathFreeObject(result); + return 0; + } + size_t count = 0; + int i; + for(i = 0; i < nodeset->nodeNr; i++) { + double r = rand(); + int x = r * nodeset->nodeNr / RAND_MAX; + const xmlNode *node = nodeset->nodeTab[x]->xmlChildrenNode; + xmlChar *href = xmlNodeListGetString(doc, node, 1); + if(follow_relative_links) { + xmlChar *orig = href; + href = xmlBuildURI(href, (xmlChar *) url); + xmlFree(orig); + } + char *link = (char *) href; + if(!link || strlen(link) < 20) + continue; + if(!strncmp(link, "http://", 7) || !strncmp(link, "https://", 8)) { + curl_multi_add_handle(multi_handle, make_handle(link)); + if(count++ == max_link_per_page) + break; + } + xmlFree(link); + } + xmlXPathFreeObject(result); + return count; +} + +int is_html(char *ctype) +{ + return ctype != NULL && strlen(ctype) > 10 && strstr(ctype, "text/html"); +} + +int main(void) +{ + signal(SIGINT, sighandler); + LIBXML_TEST_VERSION; + curl_global_init(CURL_GLOBAL_DEFAULT); + CURLM *multi_handle = curl_multi_init(); + curl_multi_setopt(multi_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, max_con); + curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 6L); + + /* enables http/2 if available */ +#ifdef CURLPIPE_MULTIPLEX + curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); +#endif + + /* sets html start page */ + curl_multi_add_handle(multi_handle, make_handle(start_page)); + + int msgs_left; + int pending = 0; + int complete = 0; + int still_running = 1; + while(still_running && !pending_interrupt) { + int numfds; + curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds); + curl_multi_perform(multi_handle, &still_running); + + /* See how the transfers went */ + CURLMsg *m = NULL; + while((m = curl_multi_info_read(multi_handle, &msgs_left))) { + if(m->msg == CURLMSG_DONE) { + CURL *handle = m->easy_handle; + char *url; + memory *mem; + curl_easy_getinfo(handle, CURLINFO_PRIVATE, &mem); + curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url); + if(m->data.result == CURLE_OK) { + long res_status; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &res_status); + if(res_status == 200) { + char *ctype; + curl_easy_getinfo(handle, CURLINFO_CONTENT_TYPE, &ctype); + printf("[%d] HTTP 200 (%s): %s\n", complete, ctype, url); + if(is_html(ctype) && mem->size > 100) { + if(pending < max_requests && (complete + pending) < max_total) { + pending += follow_links(multi_handle, mem, url); + still_running = 1; + } + } + } + else { + printf("[%d] HTTP %d: %s\n", complete, (int) res_status, url); + } + } + else { + printf("[%d] Connection failure: %s\n", complete, url); + } + curl_multi_remove_handle(multi_handle, handle); + curl_easy_cleanup(handle); + free(mem->buf); + free(mem); + complete++; + pending--; + } + } + } + curl_multi_cleanup(multi_handle); + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/debug.c b/docs/examples/debug.c new file mode 100644 index 0000000..68d9303 --- /dev/null +++ b/docs/examples/debug.c @@ -0,0 +1,155 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Show how CURLOPT_DEBUGFUNCTION can be used. + * + */ +#include +#include + +struct data { + char trace_ascii; /* 1 or 0 */ +}; + +static +void dump(const char *text, + FILE *stream, unsigned char *ptr, size_t size, + char nohex) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s, %10.10lu bytes (0x%8.8lx)\n", + text, (unsigned long)size, (unsigned long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + struct data *config = (struct data *)userp; + const char *text; + (void)handle; /* prevent compiler warning */ + + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + return 0; + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + default: /* in case a new one is introduced to shock us */ + return 0; + } + + dump(text, stderr, (unsigned char *)data, size, config->trace_ascii); + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + struct data config; + + config.trace_ascii = 1; /* enable ascii tracing */ + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &config); + + /* the DEBUGFUNCTION has no effect until we enable VERBOSE */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/default-scheme.c b/docs/examples/default-scheme.c new file mode 100644 index 0000000..525dcc3 --- /dev/null +++ b/docs/examples/default-scheme.c @@ -0,0 +1,57 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Change default scheme when none is provided in the URL + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "example.com"); + + /* Change the default protocol (scheme) for schemeless URLs from plain + "http" to use a secure one instead. */ + curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/ephiperfifo.c b/docs/examples/ephiperfifo.c new file mode 100644 index 0000000..0ce68de --- /dev/null +++ b/docs/examples/ephiperfifo.c @@ -0,0 +1,547 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * multi socket API usage with epoll and timerfd + * + */ +/* Example application source code using the multi socket interface to + * download many files at once. + * + * This example features the same basic functionality as hiperfifo.c does, + * but this uses epoll and timerfd instead of libevent. + * + * Written by Jeff Pohlmeyer, converted to use epoll by Josh Bialkowski + +Requires a linux system with epoll + +When running, the program creates the named pipe "hiper.fifo" + +Whenever there is input into the fifo, the program reads the input as a list +of URL's and creates some new easy handles to fetch each URL via the +curl_multi "hiper" API. + + +Thus, you can try a single URL: + % echo http://www.yahoo.com > hiper.fifo + +Or a whole bunch of them: + % cat my-url-list > hiper.fifo + +The fifo buffer is handled almost instantly, so you can even add more URL's +while the previous requests are still being downloaded. + +Note: + For the sake of simplicity, URL length is limited to 1023 char's ! + +This is purely a demo app, all retrieved data is simply discarded by the write +callback. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */ + + +/* Global information, common to all connections */ +typedef struct _GlobalInfo +{ + int epfd; /* epoll filedescriptor */ + int tfd; /* timer filedescriptor */ + int fifofd; /* fifo filedescriptor */ + CURLM *multi; + int still_running; + FILE *input; +} GlobalInfo; + + +/* Information associated with a specific easy handle */ +typedef struct _ConnInfo +{ + CURL *easy; + char *url; + GlobalInfo *global; + char error[CURL_ERROR_SIZE]; +} ConnInfo; + + +/* Information associated with a specific socket */ +typedef struct _SockInfo +{ + curl_socket_t sockfd; + CURL *easy; + int action; + long timeout; + GlobalInfo *global; +} SockInfo; + +#define mycase(code) \ + case code: s = __STRING(code) + +/* Die if we get a bad CURLMcode somewhere */ +static void mcode_or_die(const char *where, CURLMcode code) +{ + if(CURLM_OK != code) { + const char *s; + switch(code) { + mycase(CURLM_BAD_HANDLE); break; + mycase(CURLM_BAD_EASY_HANDLE); break; + mycase(CURLM_OUT_OF_MEMORY); break; + mycase(CURLM_INTERNAL_ERROR); break; + mycase(CURLM_UNKNOWN_OPTION); break; + mycase(CURLM_LAST); break; + default: s = "CURLM_unknown"; break; + mycase(CURLM_BAD_SOCKET); + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + /* ignore this error */ + return; + } + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + exit(code); + } +} + +static void timer_cb(GlobalInfo* g, int revents); + +/* Update the timer after curl_multi library does it's thing. Curl will + * inform us through this callback what it wants the new timeout to be, + * after it does some work. */ +static int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g) +{ + struct itimerspec its; + + fprintf(MSG_OUT, "multi_timer_cb: Setting timeout to %ld ms\n", timeout_ms); + + if(timeout_ms > 0) { + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = timeout_ms / 1000; + its.it_value.tv_nsec = (timeout_ms % 1000) * 1000 * 1000; + } + else if(timeout_ms == 0) { + /* libcurl wants us to timeout now, however setting both fields of + * new_value.it_value to zero disarms the timer. The closest we can + * do is to schedule the timer to fire in 1 ns. */ + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 1; + } + else { + memset(&its, 0, sizeof(struct itimerspec)); + } + + timerfd_settime(g->tfd, /* flags= */0, &its, NULL); + return 0; +} + + +/* Check for completed transfers, and remove their easy handles */ +static void check_multi_info(GlobalInfo *g) +{ + char *eff_url; + CURLMsg *msg; + int msgs_left; + ConnInfo *conn; + CURL *easy; + CURLcode res; + + fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running); + while((msg = curl_multi_info_read(g->multi, &msgs_left))) { + if(msg->msg == CURLMSG_DONE) { + easy = msg->easy_handle; + res = msg->data.result; + curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn); + curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url); + fprintf(MSG_OUT, "DONE: %s => (%d) %s\n", eff_url, res, conn->error); + curl_multi_remove_handle(g->multi, easy); + free(conn->url); + curl_easy_cleanup(easy); + free(conn); + } + } +} + +/* Called by libevent when we get action on a multi socket filedescriptor */ +static void event_cb(GlobalInfo *g, int fd, int revents) +{ + CURLMcode rc; + struct itimerspec its; + + int action = ((revents & EPOLLIN) ? CURL_CSELECT_IN : 0) | + ((revents & EPOLLOUT) ? CURL_CSELECT_OUT : 0); + + rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running); + mcode_or_die("event_cb: curl_multi_socket_action", rc); + + check_multi_info(g); + if(g->still_running <= 0) { + fprintf(MSG_OUT, "last transfer done, kill timeout\n"); + memset(&its, 0, sizeof(struct itimerspec)); + timerfd_settime(g->tfd, 0, &its, NULL); + } +} + +/* Called by main loop when our timeout expires */ +static void timer_cb(GlobalInfo* g, int revents) +{ + CURLMcode rc; + uint64_t count = 0; + ssize_t err = 0; + + err = read(g->tfd, &count, sizeof(uint64_t)); + if(err == -1) { + /* Note that we may call the timer callback even if the timerfd is not + * readable. It's possible that there are multiple events stored in the + * epoll buffer (i.e. the timer may have fired multiple times). The + * event count is cleared after the first call so future events in the + * epoll buffer will fail to read from the timer. */ + if(errno == EAGAIN) { + fprintf(MSG_OUT, "EAGAIN on tfd %d\n", g->tfd); + return; + } + } + if(err != sizeof(uint64_t)) { + fprintf(stderr, "read(tfd) == %ld", err); + perror("read(tfd)"); + } + + rc = curl_multi_socket_action(g->multi, + CURL_SOCKET_TIMEOUT, 0, &g->still_running); + mcode_or_die("timer_cb: curl_multi_socket_action", rc); + check_multi_info(g); +} + + + +/* Clean up the SockInfo structure */ +static void remsock(SockInfo *f, GlobalInfo* g) +{ + if(f) { + if(f->sockfd) { + if(epoll_ctl(g->epfd, EPOLL_CTL_DEL, f->sockfd, NULL)) + fprintf(stderr, "EPOLL_CTL_DEL failed for fd: %d : %s\n", + f->sockfd, strerror(errno)); + } + free(f); + } +} + + + +/* Assign information to a SockInfo structure */ +static void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act, + GlobalInfo *g) +{ + struct epoll_event ev; + int kind = ((act & CURL_POLL_IN) ? EPOLLIN : 0) | + ((act & CURL_POLL_OUT) ? EPOLLOUT : 0); + + if(f->sockfd) { + if(epoll_ctl(g->epfd, EPOLL_CTL_DEL, f->sockfd, NULL)) + fprintf(stderr, "EPOLL_CTL_DEL failed for fd: %d : %s\n", + f->sockfd, strerror(errno)); + } + + f->sockfd = s; + f->action = act; + f->easy = e; + + ev.events = kind; + ev.data.fd = s; + if(epoll_ctl(g->epfd, EPOLL_CTL_ADD, s, &ev)) + fprintf(stderr, "EPOLL_CTL_ADD failed for fd: %d : %s\n", + s, strerror(errno)); +} + + + +/* Initialize a new SockInfo structure */ +static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g) +{ + SockInfo *fdp = (SockInfo*)calloc(1, sizeof(SockInfo)); + + fdp->global = g; + setsock(fdp, s, easy, action, g); + curl_multi_assign(g->multi, s, fdp); +} + +/* CURLMOPT_SOCKETFUNCTION */ +static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) +{ + GlobalInfo *g = (GlobalInfo*) cbp; + SockInfo *fdp = (SockInfo*) sockp; + const char *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) { + fprintf(MSG_OUT, "\n"); + remsock(fdp, g); + } + else { + if(!fdp) { + fprintf(MSG_OUT, "Adding data: %s\n", whatstr[what]); + addsock(s, e, what, g); + } + else { + fprintf(MSG_OUT, + "Changing action from %s to %s\n", + whatstr[fdp->action], whatstr[what]); + setsock(fdp, s, e, what, g); + } + } + return 0; +} + + + +/* CURLOPT_WRITEFUNCTION */ +static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) +{ + (void)ptr; + (void)data; + return size * nmemb; +} + + +/* CURLOPT_PROGRESSFUNCTION */ +static int prog_cb(void *p, double dltotal, double dlnow, double ult, + double uln) +{ + ConnInfo *conn = (ConnInfo *)p; + (void)ult; + (void)uln; + + fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal); + return 0; +} + + +/* Create a new easy handle, and add it to the global curl_multi */ +static void new_conn(char *url, GlobalInfo *g) +{ + ConnInfo *conn; + CURLMcode rc; + + conn = (ConnInfo*)calloc(1, sizeof(ConnInfo)); + conn->error[0]='\0'; + + conn->easy = curl_easy_init(); + if(!conn->easy) { + fprintf(MSG_OUT, "curl_easy_init() failed, exiting!\n"); + exit(2); + } + conn->global = g; + conn->url = strdup(url); + curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url); + curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error); + curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn); + curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_TIME, 3L); + curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_LIMIT, 10L); + fprintf(MSG_OUT, + "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url); + rc = curl_multi_add_handle(g->multi, conn->easy); + mcode_or_die("new_conn: curl_multi_add_handle", rc); + + /* note that the add_handle() will set a time-out to trigger soon so that + the necessary socket_action() call will be called by this app */ +} + +/* This gets called whenever data is received from the fifo */ +static void fifo_cb(GlobalInfo* g, int revents) +{ + char s[1024]; + long int rv = 0; + int n = 0; + + do { + s[0]='\0'; + rv = fscanf(g->input, "%1023s%n", s, &n); + s[n]='\0'; + if(n && s[0]) { + new_conn(s, g); /* if we read a URL, go get it! */ + } + else + break; + } while(rv != EOF); +} + +/* Create a named pipe and tell libevent to monitor it */ +static const char *fifo = "hiper.fifo"; +static int init_fifo(GlobalInfo *g) +{ + struct stat st; + curl_socket_t sockfd; + struct epoll_event epev; + + fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo); + if(lstat (fifo, &st) == 0) { + if((st.st_mode & S_IFMT) == S_IFREG) { + errno = EEXIST; + perror("lstat"); + exit(1); + } + } + unlink(fifo); + if(mkfifo (fifo, 0600) == -1) { + perror("mkfifo"); + exit(1); + } + sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0); + if(sockfd == -1) { + perror("open"); + exit(1); + } + + g->fifofd = sockfd; + g->input = fdopen(sockfd, "r"); + + epev.events = EPOLLIN; + epev.data.fd = sockfd; + epoll_ctl(g->epfd, EPOLL_CTL_ADD, sockfd, &epev); + + fprintf(MSG_OUT, "Now, pipe some URL's into > %s\n", fifo); + return 0; +} + +static void clean_fifo(GlobalInfo *g) +{ + epoll_ctl(g->epfd, EPOLL_CTL_DEL, g->fifofd, NULL); + fclose(g->input); + unlink(fifo); +} + + +int g_should_exit_ = 0; + +void sigint_handler(int signo) +{ + g_should_exit_ = 1; +} + +int main(int argc, char **argv) +{ + GlobalInfo g; + struct itimerspec its; + struct epoll_event ev; + struct epoll_event events[10]; + (void)argc; + (void)argv; + + g_should_exit_ = 0; + signal(SIGINT, sigint_handler); + + memset(&g, 0, sizeof(GlobalInfo)); + g.epfd = epoll_create1(EPOLL_CLOEXEC); + if(g.epfd == -1) { + perror("epoll_create1 failed"); + exit(1); + } + + g.tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if(g.tfd == -1) { + perror("timerfd_create failed"); + exit(1); + } + + memset(&its, 0, sizeof(struct itimerspec)); + its.it_interval.tv_sec = 0; + its.it_value.tv_sec = 1; + timerfd_settime(g.tfd, 0, &its, NULL); + + ev.events = EPOLLIN; + ev.data.fd = g.tfd; + epoll_ctl(g.epfd, EPOLL_CTL_ADD, g.tfd, &ev); + + init_fifo(&g); + g.multi = curl_multi_init(); + + /* setup the generic multi interface options we want */ + curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g); + curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb); + curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g); + + /* we do not call any curl_multi_socket*() function yet as we have no handles + added! */ + + fprintf(MSG_OUT, "Entering wait loop\n"); + fflush(MSG_OUT); + while(!g_should_exit_) { + int idx; + int err = epoll_wait(g.epfd, events, + sizeof(events)/sizeof(struct epoll_event), 10000); + if(err == -1) { + if(errno == EINTR) { + fprintf(MSG_OUT, "note: wait interrupted\n"); + continue; + } + else { + perror("epoll_wait"); + exit(1); + } + } + + for(idx = 0; idx < err; ++idx) { + if(events[idx].data.fd == g.fifofd) { + fifo_cb(&g, events[idx].events); + } + else if(events[idx].data.fd == g.tfd) { + timer_cb(&g, events[idx].events); + } + else { + event_cb(&g, events[idx].data.fd, events[idx].events); + } + } + } + + fprintf(MSG_OUT, "Exiting normally.\n"); + fflush(MSG_OUT); + + curl_multi_cleanup(g.multi); + clean_fifo(&g); + return 0; +} diff --git a/docs/examples/evhiperfifo.c b/docs/examples/evhiperfifo.c new file mode 100644 index 0000000..17bff2b --- /dev/null +++ b/docs/examples/evhiperfifo.c @@ -0,0 +1,450 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * multi socket interface together with libev + * + */ +/* Example application source code using the multi socket interface to + * download many files at once. + * + * This example features the same basic functionality as hiperfifo.c does, + * but this uses libev instead of libevent. + * + * Written by Jeff Pohlmeyer, converted to use libev by Markus Koetter + +Requires libev and a (POSIX?) system that has mkfifo(). + +This is an adaptation of libcurl's "hipev.c" and libevent's "event-test.c" +sample programs. + +When running, the program creates the named pipe "hiper.fifo" + +Whenever there is input into the fifo, the program reads the input as a list +of URL's and creates some new easy handles to fetch each URL via the +curl_multi "hiper" API. + + +Thus, you can try a single URL: + % echo http://www.yahoo.com > hiper.fifo + +Or a whole bunch of them: + % cat my-url-list > hiper.fifo + +The fifo buffer is handled almost instantly, so you can even add more URL's +while the previous requests are still being downloaded. + +Note: + For the sake of simplicity, URL length is limited to 1023 char's ! + +This is purely a demo app, all retrieved data is simply discarded by the write +callback. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DPRINT(x...) printf(x) + +#define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */ + + +/* Global information, common to all connections */ +typedef struct _GlobalInfo +{ + struct ev_loop *loop; + struct ev_io fifo_event; + struct ev_timer timer_event; + CURLM *multi; + int still_running; + FILE *input; +} GlobalInfo; + + +/* Information associated with a specific easy handle */ +typedef struct _ConnInfo +{ + CURL *easy; + char *url; + GlobalInfo *global; + char error[CURL_ERROR_SIZE]; +} ConnInfo; + + +/* Information associated with a specific socket */ +typedef struct _SockInfo +{ + curl_socket_t sockfd; + CURL *easy; + int action; + long timeout; + struct ev_io ev; + int evset; + GlobalInfo *global; +} SockInfo; + +static void timer_cb(EV_P_ struct ev_timer *w, int revents); + +/* Update the event timer after curl_multi library calls */ +static int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g) +{ + DPRINT("%s %li\n", __PRETTY_FUNCTION__, timeout_ms); + ev_timer_stop(g->loop, &g->timer_event); + if(timeout_ms >= 0) { + /* -1 means delete, other values are timeout times in milliseconds */ + double t = timeout_ms / 1000; + ev_timer_init(&g->timer_event, timer_cb, t, 0.); + ev_timer_start(g->loop, &g->timer_event); + } + return 0; +} + +/* Die if we get a bad CURLMcode somewhere */ +static void mcode_or_die(const char *where, CURLMcode code) +{ + if(CURLM_OK != code) { + const char *s; + switch(code) { + case CURLM_BAD_HANDLE: + s = "CURLM_BAD_HANDLE"; + break; + case CURLM_BAD_EASY_HANDLE: + s = "CURLM_BAD_EASY_HANDLE"; + break; + case CURLM_OUT_OF_MEMORY: + s = "CURLM_OUT_OF_MEMORY"; + break; + case CURLM_INTERNAL_ERROR: + s = "CURLM_INTERNAL_ERROR"; + break; + case CURLM_UNKNOWN_OPTION: + s = "CURLM_UNKNOWN_OPTION"; + break; + case CURLM_LAST: + s = "CURLM_LAST"; + break; + default: + s = "CURLM_unknown"; + break; + case CURLM_BAD_SOCKET: + s = "CURLM_BAD_SOCKET"; + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + /* ignore this error */ + return; + } + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + exit(code); + } +} + + + +/* Check for completed transfers, and remove their easy handles */ +static void check_multi_info(GlobalInfo *g) +{ + char *eff_url; + CURLMsg *msg; + int msgs_left; + ConnInfo *conn; + CURL *easy; + CURLcode res; + + fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running); + while((msg = curl_multi_info_read(g->multi, &msgs_left))) { + if(msg->msg == CURLMSG_DONE) { + easy = msg->easy_handle; + res = msg->data.result; + curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn); + curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url); + fprintf(MSG_OUT, "DONE: %s => (%d) %s\n", eff_url, res, conn->error); + curl_multi_remove_handle(g->multi, easy); + free(conn->url); + curl_easy_cleanup(easy); + free(conn); + } + } +} + + + +/* Called by libevent when we get action on a multi socket */ +static void event_cb(EV_P_ struct ev_io *w, int revents) +{ + DPRINT("%s w %p revents %i\n", __PRETTY_FUNCTION__, w, revents); + GlobalInfo *g = (GlobalInfo*) w->data; + CURLMcode rc; + + int action = ((revents & EV_READ) ? CURL_POLL_IN : 0) | + ((revents & EV_WRITE) ? CURL_POLL_OUT : 0); + rc = curl_multi_socket_action(g->multi, w->fd, action, &g->still_running); + mcode_or_die("event_cb: curl_multi_socket_action", rc); + check_multi_info(g); + if(g->still_running <= 0) { + fprintf(MSG_OUT, "last transfer done, kill timeout\n"); + ev_timer_stop(g->loop, &g->timer_event); + } +} + +/* Called by libevent when our timeout expires */ +static void timer_cb(EV_P_ struct ev_timer *w, int revents) +{ + DPRINT("%s w %p revents %i\n", __PRETTY_FUNCTION__, w, revents); + + GlobalInfo *g = (GlobalInfo *)w->data; + CURLMcode rc; + + rc = curl_multi_socket_action(g->multi, CURL_SOCKET_TIMEOUT, 0, + &g->still_running); + mcode_or_die("timer_cb: curl_multi_socket_action", rc); + check_multi_info(g); +} + +/* Clean up the SockInfo structure */ +static void remsock(SockInfo *f, GlobalInfo *g) +{ + printf("%s \n", __PRETTY_FUNCTION__); + if(f) { + if(f->evset) + ev_io_stop(g->loop, &f->ev); + free(f); + } +} + + + +/* Assign information to a SockInfo structure */ +static void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act, + GlobalInfo *g) +{ + printf("%s \n", __PRETTY_FUNCTION__); + + int kind = ((act & CURL_POLL_IN) ? EV_READ : 0) | + ((act & CURL_POLL_OUT) ? EV_WRITE : 0); + + f->sockfd = s; + f->action = act; + f->easy = e; + if(f->evset) + ev_io_stop(g->loop, &f->ev); + ev_io_init(&f->ev, event_cb, f->sockfd, kind); + f->ev.data = g; + f->evset = 1; + ev_io_start(g->loop, &f->ev); +} + + + +/* Initialize a new SockInfo structure */ +static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g) +{ + SockInfo *fdp = calloc(1, sizeof(SockInfo)); + + fdp->global = g; + setsock(fdp, s, easy, action, g); + curl_multi_assign(g->multi, s, fdp); +} + +/* CURLMOPT_SOCKETFUNCTION */ +static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) +{ + DPRINT("%s e %p s %i what %i cbp %p sockp %p\n", + __PRETTY_FUNCTION__, e, s, what, cbp, sockp); + + GlobalInfo *g = (GlobalInfo*) cbp; + SockInfo *fdp = (SockInfo*) sockp; + const char *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) { + fprintf(MSG_OUT, "\n"); + remsock(fdp, g); + } + else { + if(!fdp) { + fprintf(MSG_OUT, "Adding data: %s\n", whatstr[what]); + addsock(s, e, what, g); + } + else { + fprintf(MSG_OUT, + "Changing action from %s to %s\n", + whatstr[fdp->action], whatstr[what]); + setsock(fdp, s, e, what, g); + } + } + return 0; +} + + +/* CURLOPT_WRITEFUNCTION */ +static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) +{ + size_t realsize = size * nmemb; + ConnInfo *conn = (ConnInfo*) data; + (void)ptr; + (void)conn; + return realsize; +} + + +/* CURLOPT_PROGRESSFUNCTION */ +static int prog_cb(void *p, double dltotal, double dlnow, double ult, + double uln) +{ + ConnInfo *conn = (ConnInfo *)p; + (void)ult; + (void)uln; + + fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal); + return 0; +} + + +/* Create a new easy handle, and add it to the global curl_multi */ +static void new_conn(char *url, GlobalInfo *g) +{ + ConnInfo *conn; + CURLMcode rc; + + conn = calloc(1, sizeof(ConnInfo)); + conn->error[0]='\0'; + + conn->easy = curl_easy_init(); + if(!conn->easy) { + fprintf(MSG_OUT, "curl_easy_init() failed, exiting!\n"); + exit(2); + } + conn->global = g; + conn->url = strdup(url); + curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url); + curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error); + curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn); + curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_TIME, 3L); + curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_LIMIT, 10L); + + fprintf(MSG_OUT, + "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url); + rc = curl_multi_add_handle(g->multi, conn->easy); + mcode_or_die("new_conn: curl_multi_add_handle", rc); + + /* note that the add_handle() will set a time-out to trigger soon so that + the necessary socket_action() call will be called by this app */ +} + +/* This gets called whenever data is received from the fifo */ +static void fifo_cb(EV_P_ struct ev_io *w, int revents) +{ + char s[1024]; + long int rv = 0; + int n = 0; + GlobalInfo *g = (GlobalInfo *)w->data; + + do { + s[0]='\0'; + rv = fscanf(g->input, "%1023s%n", s, &n); + s[n]='\0'; + if(n && s[0]) { + new_conn(s, g); /* if we read a URL, go get it! */ + } + else + break; + } while(rv != EOF); +} + +/* Create a named pipe and tell libevent to monitor it */ +static int init_fifo(GlobalInfo *g) +{ + struct stat st; + static const char *fifo = "hiper.fifo"; + curl_socket_t sockfd; + + fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo); + if(lstat (fifo, &st) == 0) { + if((st.st_mode & S_IFMT) == S_IFREG) { + errno = EEXIST; + perror("lstat"); + exit(1); + } + } + unlink(fifo); + if(mkfifo (fifo, 0600) == -1) { + perror("mkfifo"); + exit(1); + } + sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0); + if(sockfd == -1) { + perror("open"); + exit(1); + } + g->input = fdopen(sockfd, "r"); + + fprintf(MSG_OUT, "Now, pipe some URL's into > %s\n", fifo); + ev_io_init(&g->fifo_event, fifo_cb, sockfd, EV_READ); + ev_io_start(g->loop, &g->fifo_event); + return (0); +} + +int main(int argc, char **argv) +{ + GlobalInfo g; + (void)argc; + (void)argv; + + memset(&g, 0, sizeof(GlobalInfo)); + g.loop = ev_default_loop(0); + + init_fifo(&g); + g.multi = curl_multi_init(); + + ev_timer_init(&g.timer_event, timer_cb, 0., 0.); + g.timer_event.data = &g; + g.fifo_event.data = &g; + curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g); + curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb); + curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g); + + /* we do not call any curl_multi_socket*() function yet as we have no handles + added! */ + + ev_loop(g.loop, 0); + curl_multi_cleanup(g.multi); + return 0; +} diff --git a/docs/examples/externalsocket.c b/docs/examples/externalsocket.c new file mode 100644 index 0000000..9c34373 --- /dev/null +++ b/docs/examples/externalsocket.c @@ -0,0 +1,173 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Pass in a custom socket for libcurl to use. + * + */ +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#define close closesocket +#else +#include /* socket types */ +#include /* socket definitions */ +#include +#include /* inet (3) functions */ +#include /* misc. Unix functions */ +#endif + +#include + +/* The IP address and port number to connect to */ +#define IPADDR "127.0.0.1" +#define PORTNUM 80 + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); + return written; +} + +static int closecb(void *clientp, curl_socket_t item) +{ + (void)clientp; + printf("libcurl wants to close %d now\n", (int)item); + return 0; +} + +static curl_socket_t opensocket(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address) +{ + curl_socket_t sockfd; + (void)purpose; + (void)address; + sockfd = *(curl_socket_t *)clientp; + /* the actual externally set socket is passed in via the OPENSOCKETDATA + option */ + return sockfd; +} + +static int sockopt_callback(void *clientp, curl_socket_t curlfd, + curlsocktype purpose) +{ + (void)clientp; + (void)curlfd; + (void)purpose; + /* This return code was added in libcurl 7.21.5 */ + return CURL_SOCKOPT_ALREADY_CONNECTED; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + struct sockaddr_in servaddr; /* socket address structure */ + curl_socket_t sockfd; + +#ifdef _WIN32 + WSADATA wsaData; + int initwsa = WSAStartup(MAKEWORD(2, 2), &wsaData); + if(initwsa) { + printf("WSAStartup failed: %d\n", initwsa); + return 1; + } +#endif + + curl = curl_easy_init(); + if(curl) { + /* + * Note that libcurl will internally think that you connect to the host + * and port that you specify in the URL option. + */ + curl_easy_setopt(curl, CURLOPT_URL, "http://99.99.99.99:9999"); + + /* Create the socket "manually" */ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if(sockfd == CURL_SOCKET_BAD) { + printf("Error creating listening socket.\n"); + return 3; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(PORTNUM); + + servaddr.sin_addr.s_addr = inet_addr(IPADDR); + if(INADDR_NONE == servaddr.sin_addr.s_addr) { + close(sockfd); + return 2; + } + + if(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == + -1) { + close(sockfd); + printf("client error: connect: %s\n", strerror(errno)); + return 1; + } + + /* no progress meter please */ + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + + /* send all data to this function */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + + /* call this function to get a socket */ + curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket); + curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sockfd); + + /* call this function to close sockets */ + curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closecb); + curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &sockfd); + + /* call this function to set options for the socket */ + curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + + close(sockfd); + + if(res) { + printf("libcurl error: %d\n", res); + return 4; + } + } + +#ifdef _WIN32 + WSACleanup(); +#endif + return 0; +} diff --git a/docs/examples/fileupload.c b/docs/examples/fileupload.c new file mode 100644 index 0000000..9e3bd84 --- /dev/null +++ b/docs/examples/fileupload.c @@ -0,0 +1,89 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Upload to a file:// URL + * + */ +#include +#include +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + struct stat file_info; + curl_off_t speed_upload, total_time; + FILE *fd; + + fd = fopen("debugit", "rb"); /* open file to upload */ + if(!fd) + return 1; /* cannot continue */ + + /* to get the file size */ + if(fstat(fileno(fd), &file_info) != 0) + return 1; /* cannot continue */ + + curl = curl_easy_init(); + if(curl) { + /* upload to this place */ + curl_easy_setopt(curl, CURLOPT_URL, + "file:///home/dast/src/curl/debug/new"); + + /* tell it to "upload" to the URL */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* set where to read from (on Windows you need to use READFUNCTION too) */ + curl_easy_setopt(curl, CURLOPT_READDATA, fd); + + /* and give the size of the upload (optional) */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)file_info.st_size); + + /* enable verbose for easier tracing */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + else { + /* now extract transfer info */ + curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD_T, &speed_upload); + curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &total_time); + + fprintf(stderr, "Speed: %lu bytes/sec during %lu.%06lu seconds\n", + (unsigned long)speed_upload, + (unsigned long)(total_time / 1000000), + (unsigned long)(total_time % 1000000)); + } + /* always cleanup */ + curl_easy_cleanup(curl); + } + fclose(fd); + return 0; +} diff --git a/docs/examples/ftp-wildcard.c b/docs/examples/ftp-wildcard.c new file mode 100644 index 0000000..f805432 --- /dev/null +++ b/docs/examples/ftp-wildcard.c @@ -0,0 +1,152 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * FTP wildcard pattern matching + * + */ +#include +#include + +struct callback_data { + FILE *output; +}; + +static long file_is_coming(struct curl_fileinfo *finfo, + struct callback_data *data, + int remains); + +static long file_is_downloaded(struct callback_data *data); + +static size_t write_it(char *buff, size_t size, size_t nmemb, + void *cb_data); + +int main(int argc, char **argv) +{ + /* curl easy handle */ + CURL *handle; + + /* help data */ + struct callback_data data = { 0 }; + + /* global initialization */ + int rc = curl_global_init(CURL_GLOBAL_ALL); + if(rc) + return rc; + + /* initialization of easy handle */ + handle = curl_easy_init(); + if(!handle) { + curl_global_cleanup(); + return CURLE_OUT_OF_MEMORY; + } + + /* turn on wildcard matching */ + curl_easy_setopt(handle, CURLOPT_WILDCARDMATCH, 1L); + + /* callback is called before download of concrete file started */ + curl_easy_setopt(handle, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming); + + /* callback is called after data from the file have been transferred */ + curl_easy_setopt(handle, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded); + + /* this callback will write contents into files */ + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_it); + + /* put transfer data into callbacks */ + curl_easy_setopt(handle, CURLOPT_CHUNK_DATA, &data); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data); + + /* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); */ + + /* set a URL containing wildcard pattern (only in the last part) */ + if(argc == 2) + curl_easy_setopt(handle, CURLOPT_URL, argv[1]); + else + curl_easy_setopt(handle, CURLOPT_URL, "ftp://example.com/test/*"); + + /* and start transfer! */ + rc = curl_easy_perform(handle); + + curl_easy_cleanup(handle); + curl_global_cleanup(); + return rc; +} + +static long file_is_coming(struct curl_fileinfo *finfo, + struct callback_data *data, + int remains) +{ + printf("%3d %40s %10luB ", remains, finfo->filename, + (unsigned long)finfo->size); + + switch(finfo->filetype) { + case CURLFILETYPE_DIRECTORY: + printf(" DIR\n"); + break; + case CURLFILETYPE_FILE: + printf("FILE "); + break; + default: + printf("OTHER\n"); + break; + } + + if(finfo->filetype == CURLFILETYPE_FILE) { + /* do not transfer files >= 50B */ + if(finfo->size > 50) { + printf("SKIPPED\n"); + return CURL_CHUNK_BGN_FUNC_SKIP; + } + + data->output = fopen(finfo->filename, "wb"); + if(!data->output) { + return CURL_CHUNK_BGN_FUNC_FAIL; + } + } + + return CURL_CHUNK_BGN_FUNC_OK; +} + +static long file_is_downloaded(struct callback_data *data) +{ + if(data->output) { + printf("DOWNLOADED\n"); + fclose(data->output); + data->output = 0x0; + } + return CURL_CHUNK_END_FUNC_OK; +} + +static size_t write_it(char *buff, size_t size, size_t nmemb, + void *cb_data) +{ + struct callback_data *data = cb_data; + size_t written = 0; + if(data->output) + written = fwrite(buff, size, nmemb, data->output); + else + /* listing output */ + written = fwrite(buff, size, nmemb, stdout); + return written; +} diff --git a/docs/examples/ftpget.c b/docs/examples/ftpget.c new file mode 100644 index 0000000..95369c1 --- /dev/null +++ b/docs/examples/ftpget.c @@ -0,0 +1,94 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include + +#include + +/* + * Get a single file from an FTP server. + * + */ + +struct FtpFile { + const char *filename; + FILE *stream; +}; + +static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) +{ + struct FtpFile *out = (struct FtpFile *)stream; + if(!out->stream) { + /* open file for writing */ + out->stream = fopen(out->filename, "wb"); + if(!out->stream) + return 0; /* failure, cannot open file to write */ + } + return fwrite(buffer, size, nmemb, out->stream); +} + + +int main(void) +{ + CURL *curl; + CURLcode res; + struct FtpFile ftpfile = { + "curl.tar.gz", /* name to store the file as if successful */ + NULL + }; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + /* + * You better replace the URL with one that works! + */ + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://ftp.example.com/curl/curl-7.9.2.tar.gz"); + /* Define our callback to get called when there is data to be written */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); + /* Set a pointer to our struct to pass to the callback */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); + + /* Switch on full protocol/debug output */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + + if(CURLE_OK != res) { + /* we failed */ + fprintf(stderr, "curl told us %d\n", res); + } + } + + if(ftpfile.stream) + fclose(ftpfile.stream); /* close the local file */ + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/ftpgetinfo.c b/docs/examples/ftpgetinfo.c new file mode 100644 index 0000000..be24fa7 --- /dev/null +++ b/docs/examples/ftpgetinfo.c @@ -0,0 +1,93 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include +#include + +#include + +/* + * Checks a single file's size and mtime from an FTP server. + * + */ + +static size_t throw_away(void *ptr, size_t size, size_t nmemb, void *data) +{ + (void)ptr; + (void)data; + /* we are not interested in the headers itself, + so we only return the size we would have saved ... */ + return (size_t)(size * nmemb); +} + +int main(void) +{ + char ftpurl[] = "ftp://ftp.example.com/gnu/binutils/binutils-2.19.1.tar.bz2"; + CURL *curl; + CURLcode res; + long filetime = -1; + curl_off_t filesize = 0; + const char *filename = strrchr(ftpurl, '/') + 1; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, ftpurl); + /* No download if the file */ + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + /* Ask for filetime */ + curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, throw_away); + curl_easy_setopt(curl, CURLOPT_HEADER, 0L); + /* Switch on full protocol/debug output */ + /* curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); */ + + res = curl_easy_perform(curl); + + if(CURLE_OK == res) { + /* https://curl.se/libcurl/c/curl_easy_getinfo.html */ + res = curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); + if((CURLE_OK == res) && (filetime >= 0)) { + time_t file_time = (time_t)filetime; + printf("filetime %s: %s", filename, ctime(&file_time)); + } + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, + &filesize); + if((CURLE_OK == res) && (filesize>0)) + printf("filesize %s: %" CURL_FORMAT_CURL_OFF_T " bytes\n", + filename, filesize); + } + else { + /* we failed */ + fprintf(stderr, "curl told us %d\n", res); + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/ftpgetresp.c b/docs/examples/ftpgetresp.c new file mode 100644 index 0000000..238885d --- /dev/null +++ b/docs/examples/ftpgetresp.c @@ -0,0 +1,79 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include + +#include + +/* + * Similar to ftpget.c but also stores the received response-lines + * in a separate file using our own callback! + * + */ +static size_t +write_response(void *ptr, size_t size, size_t nmemb, void *data) +{ + FILE *writehere = (FILE *)data; + return fwrite(ptr, size, nmemb, writehere); +} + +#define FTPBODY "ftp-list" +#define FTPHEADERS "ftp-responses" + +int main(void) +{ + CURL *curl; + CURLcode res; + FILE *ftpfile; + FILE *respfile; + + /* local file name to store the file as */ + ftpfile = fopen(FTPBODY, "wb"); /* b is binary, needed on win32 */ + + /* local file name to store the FTP server's response lines in */ + respfile = fopen(FTPHEADERS, "wb"); /* b is binary, needed on win32 */ + + curl = curl_easy_init(); + if(curl) { + /* Get a file listing from sunet */ + curl_easy_setopt(curl, CURLOPT_URL, "ftp://ftp.example.com/"); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, ftpfile); + /* If you intend to use this on windows with a libcurl DLL, you must use + CURLOPT_WRITEFUNCTION as well */ + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_response); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, respfile); + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + fclose(ftpfile); /* close the local file */ + fclose(respfile); /* close the response file */ + + return 0; +} diff --git a/docs/examples/ftpsget.c b/docs/examples/ftpsget.c new file mode 100644 index 0000000..dfe80b9 --- /dev/null +++ b/docs/examples/ftpsget.c @@ -0,0 +1,101 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +#include + +/* + * Get a single file from an FTPS server. + * + */ + +struct FtpFile { + const char *filename; + FILE *stream; +}; + +static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, + void *stream) +{ + struct FtpFile *out = (struct FtpFile *)stream; + if(!out->stream) { + /* open file for writing */ + out->stream = fopen(out->filename, "wb"); + if(!out->stream) + return 0; /* failure, cannot open file to write */ + } + return fwrite(buffer, size, nmemb, out->stream); +} + + +int main(void) +{ + CURL *curl; + CURLcode res; + struct FtpFile ftpfile = { + "yourfile.bin", /* name to store the file as if successful */ + NULL + }; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + /* + * You better replace the URL with one that works! Note that we use an + * FTP:// URL with standard explicit FTPS. You can also do FTPS:// URLs if + * you want to do the rarer kind of transfers: implicit. + */ + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://user@server/home/user/file.txt"); + /* Define our callback to get called when there is data to be written */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); + /* Set a pointer to our struct to pass to the callback */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); + + /* We activate SSL and we require it for both control and data */ + curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); + + /* Switch on full protocol/debug output */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + + if(CURLE_OK != res) { + /* we failed */ + fprintf(stderr, "curl told us %d\n", res); + } + } + + if(ftpfile.stream) + fclose(ftpfile.stream); /* close the local file */ + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/ftpupload.c b/docs/examples/ftpupload.c new file mode 100644 index 0000000..92bb0b8 --- /dev/null +++ b/docs/examples/ftpupload.c @@ -0,0 +1,142 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +/* + * Performs an FTP upload and renames the file just after a successful + * transfer. + * + */ + +#define LOCAL_FILE "/tmp/uploadthis.txt" +#define UPLOAD_FILE_AS "while-uploading.txt" +#define REMOTE_URL "ftp://example.com/" UPLOAD_FILE_AS +#define RENAME_FILE_TO "renamed-and-fine.txt" + +/* NOTE: if you want this example to work on Windows with libcurl as a + DLL, you MUST also provide a read callback with CURLOPT_READFUNCTION. + Failing to do so will give you a crash since a DLL may not use the + variable's memory when passed in to it from an app like this. */ +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) +{ + unsigned long nread; + /* in real-world cases, this would probably get this data differently + as this fread() stuff is exactly what the library already would do + by default internally */ + size_t retcode = fread(ptr, size, nmemb, stream); + + if(retcode > 0) { + nread = (unsigned long)retcode; + fprintf(stderr, "*** We read %lu bytes from file\n", nread); + } + + return retcode; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + FILE *hd_src; + struct stat file_info; + unsigned long fsize; + + struct curl_slist *headerlist = NULL; + static const char buf_1 [] = "RNFR " UPLOAD_FILE_AS; + static const char buf_2 [] = "RNTO " RENAME_FILE_TO; + + /* get the file size of the local file */ + if(stat(LOCAL_FILE, &file_info)) { + printf("Couldn't open '%s': %s\n", LOCAL_FILE, strerror(errno)); + return 1; + } + fsize = (unsigned long)file_info.st_size; + + printf("Local file size: %lu bytes.\n", fsize); + + /* get a FILE * of the same file */ + hd_src = fopen(LOCAL_FILE, "rb"); + + /* In windows, this will init the winsock stuff */ + curl_global_init(CURL_GLOBAL_ALL); + + /* get a curl handle */ + curl = curl_easy_init(); + if(curl) { + /* build a list of commands to pass to libcurl */ + headerlist = curl_slist_append(headerlist, buf_1); + headerlist = curl_slist_append(headerlist, buf_2); + + /* we want to use our own read function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + + /* enable uploading */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* specify target */ + curl_easy_setopt(curl, CURLOPT_URL, REMOTE_URL); + + /* pass in that last of FTP commands to run after the transfer */ + curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist); + + /* now specify which file to upload */ + curl_easy_setopt(curl, CURLOPT_READDATA, hd_src); + + /* Set the size of the file to upload (optional). If you give a *_LARGE + option you MUST make sure that the type of the passed-in argument is a + curl_off_t. If you use CURLOPT_INFILESIZE (without _LARGE) you must + make sure that to pass in a type 'long' argument. */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)fsize); + + /* Now run off and do what you have been told! */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* clean up the FTP commands list */ + curl_slist_free_all(headerlist); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + fclose(hd_src); /* close the local file */ + + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/ftpuploadfrommem.c b/docs/examples/ftpuploadfrommem.c new file mode 100644 index 0000000..9613cca --- /dev/null +++ b/docs/examples/ftpuploadfrommem.c @@ -0,0 +1,126 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * FTP upload a file from memory + * + */ +#include +#include +#include + +static const char data[]= + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + "Nam rhoncus odio id venenatis volutpat. Vestibulum dapibus " + "bibendum ullamcorper. Maecenas finibus elit augue, vel " + "condimentum odio maximus nec. In hac habitasse platea dictumst. " + "Vestibulum vel dolor et turpis rutrum finibus ac at nulla. " + "Vivamus nec neque ac elit blandit pretium vitae maximus ipsum. " + "Quisque sodales magna vel erat auctor, sed pellentesque nisi " + "rhoncus. Donec vehicula maximus pretium. Aliquam eu tincidunt " + "lorem."; + +struct WriteThis { + const char *readptr; + size_t sizeleft; +}; + +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct WriteThis *upload = (struct WriteThis *)userp; + size_t max = size*nmemb; + + if(max < 1) + return 0; + + if(upload->sizeleft) { + size_t copylen = max; + if(copylen > upload->sizeleft) + copylen = upload->sizeleft; + memcpy(ptr, upload->readptr, copylen); + upload->readptr += copylen; + upload->sizeleft -= copylen; + return copylen; + } + + return 0; /* no more data left to deliver */ +} + +int main(void) +{ + CURL *curl; + CURLcode res; + + struct WriteThis upload; + + upload.readptr = data; + upload.sizeleft = strlen(data); + + /* In windows, this will init the winsock stuff */ + res = curl_global_init(CURL_GLOBAL_DEFAULT); + /* Check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed: %s\n", + curl_easy_strerror(res)); + return 1; + } + + /* get a curl handle */ + curl = curl_easy_init(); + if(curl) { + /* First set the URL, the target file */ + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/path/to/upload/file"); + + /* User and password for the FTP login */ + curl_easy_setopt(curl, CURLOPT_USERPWD, "login:secret"); + + /* Now specify we want to UPLOAD data */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* we want to use our own read function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + + /* pointer to pass to our read function */ + curl_easy_setopt(curl, CURLOPT_READDATA, &upload); + + /* get verbose debug output please */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Set the expected upload size. */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)upload.sizeleft); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/ftpuploadresume.c b/docs/examples/ftpuploadresume.c new file mode 100644 index 0000000..42d31a2 --- /dev/null +++ b/docs/examples/ftpuploadresume.c @@ -0,0 +1,167 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Upload to FTP, resuming failed transfers. Active mode. + * + */ + +#include +#include +#include + +/* parse headers for Content-Length */ +static size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, + void *stream) +{ + int r; + long len = 0; + + r = sscanf(ptr, "Content-Length: %ld\n", &len); + if(r) + *((long *) stream) = len; + + return size * nmemb; +} + +/* discard downloaded data */ +static size_t discardfunc(void *ptr, size_t size, size_t nmemb, void *stream) +{ + (void)ptr; + (void)stream; + return size * nmemb; +} + +/* read data to upload */ +static size_t readfunc(char *ptr, size_t size, size_t nmemb, void *stream) +{ + FILE *f = stream; + size_t n; + + if(ferror(f)) + return CURL_READFUNC_ABORT; + + n = fread(ptr, size, nmemb, f) * size; + + return n; +} + + +static int upload(CURL *curlhandle, const char *remotepath, + const char *localpath, long timeout, long tries) +{ + FILE *f; + long uploaded_len = 0; + CURLcode r = CURLE_GOT_NOTHING; + int c; + + f = fopen(localpath, "rb"); + if(!f) { + perror(NULL); + return 0; + } + + curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L); + + curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath); + + if(timeout) + curl_easy_setopt(curlhandle, CURLOPT_SERVER_RESPONSE_TIMEOUT, timeout); + + curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc); + curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &uploaded_len); + + curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, discardfunc); + + curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc); + curl_easy_setopt(curlhandle, CURLOPT_READDATA, f); + + /* enable active mode */ + curl_easy_setopt(curlhandle, CURLOPT_FTPPORT, "-"); + + /* allow the server no more than 7 seconds to connect back */ + curl_easy_setopt(curlhandle, CURLOPT_ACCEPTTIMEOUT_MS, 7000L); + + curl_easy_setopt(curlhandle, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L); + + curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L); + + for(c = 0; (r != CURLE_OK) && (c < tries); c++) { + /* are we resuming? */ + if(c) { /* yes */ + /* determine the length of the file already written */ + + /* + * With NOBODY and NOHEADER, libcurl will issue a SIZE + * command, but the only way to retrieve the result is + * to parse the returned Content-Length header. Thus, + * getcontentlengthfunc(). We need discardfunc() above + * because HEADER will dump the headers to stdout + * without it. + */ + curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 1L); + curl_easy_setopt(curlhandle, CURLOPT_HEADER, 1L); + + r = curl_easy_perform(curlhandle); + if(r != CURLE_OK) + continue; + + curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curlhandle, CURLOPT_HEADER, 0L); + + fseek(f, uploaded_len, SEEK_SET); + + curl_easy_setopt(curlhandle, CURLOPT_APPEND, 1L); + } + else { /* no */ + curl_easy_setopt(curlhandle, CURLOPT_APPEND, 0L); + } + + r = curl_easy_perform(curlhandle); + } + + fclose(f); + + if(r == CURLE_OK) + return 1; + else { + fprintf(stderr, "%s\n", curl_easy_strerror(r)); + return 0; + } +} + +int main(void) +{ + CURL *curlhandle = NULL; + + curl_global_init(CURL_GLOBAL_ALL); + curlhandle = curl_easy_init(); + + upload(curlhandle, "ftp://user:pass@example.com/path/file", "C:\\file", + 0, 3); + + curl_easy_cleanup(curlhandle); + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/getinfo.c b/docs/examples/getinfo.c new file mode 100644 index 0000000..9c178c2 --- /dev/null +++ b/docs/examples/getinfo.c @@ -0,0 +1,54 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use getinfo to get content-type after completed transfer. + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); + res = curl_easy_perform(curl); + + if(CURLE_OK == res) { + char *ct; + /* ask for the content-type */ + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct); + + if((CURLE_OK == res) && ct) + printf("We received Content-Type: %s\n", ct); + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/getinmemory.c b/docs/examples/getinmemory.c new file mode 100644 index 0000000..8ec8414 --- /dev/null +++ b/docs/examples/getinmemory.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Shows how the write callback function can be used to download data into a + * chunk of memory instead of storing it in a file. + * + */ + +#include +#include +#include + +#include + +struct MemoryStruct { + char *memory; + size_t size; +}; + +static size_t +WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)userp; + + char *ptr = realloc(mem->memory, mem->size + realsize + 1); + if(!ptr) { + /* out of memory! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +int main(void) +{ + CURL *curl_handle; + CURLcode res; + + struct MemoryStruct chunk; + + chunk.memory = malloc(1); /* will be grown as needed by the realloc above */ + chunk.size = 0; /* no data at this point */ + + curl_global_init(CURL_GLOBAL_ALL); + + /* init the curl session */ + curl_handle = curl_easy_init(); + + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.example.com/"); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + + /* some servers do not like requests that are made without a user-agent + field, so we provide one */ + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + /* get it! */ + res = curl_easy_perform(curl_handle); + + /* check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + else { + /* + * Now, our chunk.memory points to a memory block that is chunk.size + * bytes big and contains the remote file. + * + * Do something nice with it! + */ + + printf("%lu bytes retrieved\n", (unsigned long)chunk.size); + } + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + free(chunk.memory); + + /* we are done with libcurl, so clean it up */ + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/getredirect.c b/docs/examples/getredirect.c new file mode 100644 index 0000000..9163c9b --- /dev/null +++ b/docs/examples/getredirect.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Show how to extract Location: header and URL to redirect to. + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + char *location; + long response_code; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* example.com is redirected, figure out the redirection! */ + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + else { + res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + if((res == CURLE_OK) && + ((response_code / 100) != 3)) { + /* a redirect implies a 3xx response code */ + fprintf(stderr, "Not a redirect.\n"); + } + else { + res = curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &location); + + if((res == CURLE_OK) && location) { + /* This is the new absolute URL that you could redirect to, even if + * the Location: response header may have been a relative URL. */ + printf("Redirected to: %s\n", location); + } + } + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/getreferrer.c b/docs/examples/getreferrer.c new file mode 100644 index 0000000..6073f9f --- /dev/null +++ b/docs/examples/getreferrer.c @@ -0,0 +1,59 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Show how to extract referrer header. + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + + curl = curl_easy_init(); + if(curl) { + CURLcode res; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_REFERER, "https://example.org/referrer"); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + else { + char *hdr; + res = curl_easy_getinfo(curl, CURLINFO_REFERER, &hdr); + if((res == CURLE_OK) && hdr) + printf("Referrer header: %s\n", hdr); + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/ghiper.c b/docs/examples/ghiper.c new file mode 100644 index 0000000..5a4f4a7 --- /dev/null +++ b/docs/examples/ghiper.c @@ -0,0 +1,438 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * multi socket API usage together with with glib2 + * + */ +/* Example application source code using the multi socket interface to + * download many files at once. + * + * Written by Jeff Pohlmeyer + + Requires glib-2.x and a (POSIX?) system that has mkfifo(). + + This is an adaptation of libcurl's "hipev.c" and libevent's "event-test.c" + sample programs, adapted to use glib's g_io_channel in place of libevent. + + When running, the program creates the named pipe "hiper.fifo" + + Whenever there is input into the fifo, the program reads the input as a list + of URL's and creates some new easy handles to fetch each URL via the + curl_multi "hiper" API. + + + Thus, you can try a single URL: + % echo http://www.yahoo.com > hiper.fifo + + Or a whole bunch of them: + % cat my-url-list > hiper.fifo + + The fifo buffer is handled almost instantly, so you can even add more URL's + while the previous requests are still being downloaded. + + This is purely a demo app, all retrieved data is simply discarded by the write + callback. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSG_OUT g_print /* Change to "g_error" to write to stderr */ +#define SHOW_VERBOSE 0 /* Set to non-zero for libcurl messages */ +#define SHOW_PROGRESS 0 /* Set to non-zero to enable progress callback */ + +/* Global information, common to all connections */ +typedef struct _GlobalInfo { + CURLM *multi; + guint timer_event; + int still_running; +} GlobalInfo; + +/* Information associated with a specific easy handle */ +typedef struct _ConnInfo { + CURL *easy; + char *url; + GlobalInfo *global; + char error[CURL_ERROR_SIZE]; +} ConnInfo; + +/* Information associated with a specific socket */ +typedef struct _SockInfo { + curl_socket_t sockfd; + CURL *easy; + int action; + long timeout; + GIOChannel *ch; + guint ev; + GlobalInfo *global; +} SockInfo; + +/* Die if we get a bad CURLMcode somewhere */ +static void mcode_or_die(const char *where, CURLMcode code) +{ + if(CURLM_OK != code) { + const char *s; + switch(code) { + case CURLM_BAD_HANDLE: s = "CURLM_BAD_HANDLE"; break; + case CURLM_BAD_EASY_HANDLE: s = "CURLM_BAD_EASY_HANDLE"; break; + case CURLM_OUT_OF_MEMORY: s = "CURLM_OUT_OF_MEMORY"; break; + case CURLM_INTERNAL_ERROR: s = "CURLM_INTERNAL_ERROR"; break; + case CURLM_BAD_SOCKET: s = "CURLM_BAD_SOCKET"; break; + case CURLM_UNKNOWN_OPTION: s = "CURLM_UNKNOWN_OPTION"; break; + case CURLM_LAST: s = "CURLM_LAST"; break; + default: s = "CURLM_unknown"; + } + MSG_OUT("ERROR: %s returns %s\n", where, s); + exit(code); + } +} + +/* Check for completed transfers, and remove their easy handles */ +static void check_multi_info(GlobalInfo *g) +{ + char *eff_url; + CURLMsg *msg; + int msgs_left; + ConnInfo *conn; + CURL *easy; + CURLcode res; + + MSG_OUT("REMAINING: %d\n", g->still_running); + while((msg = curl_multi_info_read(g->multi, &msgs_left))) { + if(msg->msg == CURLMSG_DONE) { + easy = msg->easy_handle; + res = msg->data.result; + curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn); + curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url); + MSG_OUT("DONE: %s => (%d) %s\n", eff_url, res, conn->error); + curl_multi_remove_handle(g->multi, easy); + free(conn->url); + curl_easy_cleanup(easy); + free(conn); + } + } +} + +/* Called by glib when our timeout expires */ +static gboolean timer_cb(gpointer data) +{ + GlobalInfo *g = (GlobalInfo *)data; + CURLMcode rc; + + rc = curl_multi_socket_action(g->multi, + CURL_SOCKET_TIMEOUT, 0, &g->still_running); + mcode_or_die("timer_cb: curl_multi_socket_action", rc); + check_multi_info(g); + return FALSE; +} + +/* Update the event timer after curl_multi library calls */ +static int update_timeout_cb(CURLM *multi, long timeout_ms, void *userp) +{ + struct timeval timeout; + GlobalInfo *g = (GlobalInfo *)userp; + timeout.tv_sec = timeout_ms/1000; + timeout.tv_usec = (timeout_ms%1000)*1000; + + MSG_OUT("*** update_timeout_cb %ld => %ld:%ld ***\n", + timeout_ms, timeout.tv_sec, timeout.tv_usec); + + /* + * if timeout_ms is -1, just delete the timer + * + * For other values of timeout_ms, this should set or *update* the timer to + * the new value + */ + if(timeout_ms >= 0) + g->timer_event = g_timeout_add(timeout_ms, timer_cb, g); + return 0; +} + +/* Called by glib when we get action on a multi socket */ +static gboolean event_cb(GIOChannel *ch, GIOCondition condition, gpointer data) +{ + GlobalInfo *g = (GlobalInfo*) data; + CURLMcode rc; + int fd = g_io_channel_unix_get_fd(ch); + + int action = + ((condition & G_IO_IN) ? CURL_CSELECT_IN : 0) | + ((condition & G_IO_OUT) ? CURL_CSELECT_OUT : 0); + + rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running); + mcode_or_die("event_cb: curl_multi_socket_action", rc); + + check_multi_info(g); + if(g->still_running) { + return TRUE; + } + else { + MSG_OUT("last transfer done, kill timeout\n"); + if(g->timer_event) { + g_source_remove(g->timer_event); + } + return FALSE; + } +} + +/* Clean up the SockInfo structure */ +static void remsock(SockInfo *f) +{ + if(!f) { + return; + } + if(f->ev) { + g_source_remove(f->ev); + } + g_free(f); +} + +/* Assign information to a SockInfo structure */ +static void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act, + GlobalInfo *g) +{ + GIOCondition kind = + ((act & CURL_POLL_IN) ? G_IO_IN : 0) | + ((act & CURL_POLL_OUT) ? G_IO_OUT : 0); + + f->sockfd = s; + f->action = act; + f->easy = e; + if(f->ev) { + g_source_remove(f->ev); + } + f->ev = g_io_add_watch(f->ch, kind, event_cb, g); +} + +/* Initialize a new SockInfo structure */ +static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g) +{ + SockInfo *fdp = g_malloc0(sizeof(SockInfo)); + + fdp->global = g; + fdp->ch = g_io_channel_unix_new(s); + setsock(fdp, s, easy, action, g); + curl_multi_assign(g->multi, s, fdp); +} + +/* CURLMOPT_SOCKETFUNCTION */ +static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) +{ + GlobalInfo *g = (GlobalInfo*) cbp; + SockInfo *fdp = (SockInfo*) sockp; + static const char *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) { + MSG_OUT("\n"); + remsock(fdp); + } + else { + if(!fdp) { + MSG_OUT("Adding data: %s%s\n", + (what & CURL_POLL_IN) ? "READ" : "", + (what & CURL_POLL_OUT) ? "WRITE" : ""); + addsock(s, e, what, g); + } + else { + MSG_OUT( + "Changing action from %d to %d\n", fdp->action, what); + setsock(fdp, s, e, what, g); + } + } + return 0; +} + +/* CURLOPT_WRITEFUNCTION */ +static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) +{ + size_t realsize = size * nmemb; + ConnInfo *conn = (ConnInfo*) data; + (void)ptr; + (void)conn; + return realsize; +} + +/* CURLOPT_PROGRESSFUNCTION */ +static int prog_cb(void *p, double dltotal, double dlnow, double ult, + double uln) +{ + ConnInfo *conn = (ConnInfo *)p; + MSG_OUT("Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal); + return 0; +} + +/* Create a new easy handle, and add it to the global curl_multi */ +static void new_conn(char *url, GlobalInfo *g) +{ + ConnInfo *conn; + CURLMcode rc; + + conn = g_malloc0(sizeof(ConnInfo)); + conn->error[0]='\0'; + conn->easy = curl_easy_init(); + if(!conn->easy) { + MSG_OUT("curl_easy_init() failed, exiting!\n"); + exit(2); + } + conn->global = g; + conn->url = g_strdup(url); + curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url); + curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, &conn); + curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, (long)SHOW_VERBOSE); + curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error); + curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn); + curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, SHOW_PROGRESS?0L:1L); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(conn->easy, CURLOPT_CONNECTTIMEOUT, 30L); + curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_LIMIT, 1L); + curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_TIME, 30L); + + MSG_OUT("Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url); + rc = curl_multi_add_handle(g->multi, conn->easy); + mcode_or_die("new_conn: curl_multi_add_handle", rc); + + /* note that the add_handle() will set a time-out to trigger soon so that + the necessary socket_action() call will be called by this app */ +} + +/* This gets called by glib whenever data is received from the fifo */ +static gboolean fifo_cb(GIOChannel *ch, GIOCondition condition, gpointer data) +{ +#define BUF_SIZE 1024 + gsize len, tp; + gchar *buf, *tmp, *all = NULL; + GIOStatus rv; + + do { + GError *err = NULL; + rv = g_io_channel_read_line(ch, &buf, &len, &tp, &err); + if(buf) { + if(tp) { + buf[tp]='\0'; + } + new_conn(buf, (GlobalInfo*)data); + g_free(buf); + } + else { + buf = g_malloc(BUF_SIZE + 1); + while(TRUE) { + buf[BUF_SIZE]='\0'; + g_io_channel_read_chars(ch, buf, BUF_SIZE, &len, &err); + if(len) { + buf[len]='\0'; + if(all) { + tmp = all; + all = g_strdup_printf("%s%s", tmp, buf); + g_free(tmp); + } + else { + all = g_strdup(buf); + } + } + else { + break; + } + } + if(all) { + new_conn(all, (GlobalInfo*)data); + g_free(all); + } + g_free(buf); + } + if(err) { + g_error("fifo_cb: %s", err->message); + g_free(err); + break; + } + } while((len) && (rv == G_IO_STATUS_NORMAL)); + return TRUE; +} + +int init_fifo(void) +{ + struct stat st; + const char *fifo = "hiper.fifo"; + int socket; + + if(lstat (fifo, &st) == 0) { + if((st.st_mode & S_IFMT) == S_IFREG) { + errno = EEXIST; + perror("lstat"); + exit(1); + } + } + + unlink(fifo); + if(mkfifo (fifo, 0600) == -1) { + perror("mkfifo"); + exit(1); + } + + socket = open(fifo, O_RDWR | O_NONBLOCK, 0); + + if(socket == -1) { + perror("open"); + exit(1); + } + MSG_OUT("Now, pipe some URL's into > %s\n", fifo); + + return socket; +} + +int main(int argc, char **argv) +{ + GlobalInfo *g; + GMainLoop*gmain; + int fd; + GIOChannel* ch; + g = g_malloc0(sizeof(GlobalInfo)); + + fd = init_fifo(); + ch = g_io_channel_unix_new(fd); + g_io_add_watch(ch, G_IO_IN, fifo_cb, g); + gmain = g_main_loop_new(NULL, FALSE); + g->multi = curl_multi_init(); + curl_multi_setopt(g->multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(g->multi, CURLMOPT_SOCKETDATA, g); + curl_multi_setopt(g->multi, CURLMOPT_TIMERFUNCTION, update_timeout_cb); + curl_multi_setopt(g->multi, CURLMOPT_TIMERDATA, g); + + /* we do not call any curl_multi_socket*() function yet as we have no handles + added! */ + + g_main_loop_run(gmain); + curl_multi_cleanup(g->multi); + return 0; +} diff --git a/docs/examples/headerapi.c b/docs/examples/headerapi.c new file mode 100644 index 0000000..4df6cbd --- /dev/null +++ b/docs/examples/headerapi.c @@ -0,0 +1,81 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Extract headers post transfer with the header API + * + */ +#include +#include + +static size_t write_cb(char *data, size_t n, size_t l, void *userp) +{ + /* take care of the data here, ignored in this example */ + (void)data; + (void)userp; + return n*l; +} + +int main(void) +{ + CURL *curl; + + curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_header *header; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + /* this example just ignores the content */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + if(CURLHE_OK == curl_easy_header(curl, "Content-Type", 0, CURLH_HEADER, + -1, &header)) + printf("Got content-type: %s\n", header->value); + + printf("All server headers:\n"); + { + struct curl_header *h; + struct curl_header *prev = NULL; + do { + h = curl_easy_nextheader(curl, CURLH_HEADER, -1, prev); + if(h) + printf(" %s: %s (%u)\n", h->name, h->value, (int)h->amount); + prev = h; + } while(h); + + } + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/hiperfifo.c b/docs/examples/hiperfifo.c new file mode 100644 index 0000000..9fba341 --- /dev/null +++ b/docs/examples/hiperfifo.c @@ -0,0 +1,464 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * multi socket API usage with libevent 2 + * + */ +/* Example application source code using the multi socket interface to + download many files at once. + +Written by Jeff Pohlmeyer + +Requires libevent version 2 and a (POSIX?) system that has mkfifo(). + +This is an adaptation of libcurl's "hipev.c" and libevent's "event-test.c" +sample programs. + +When running, the program creates the named pipe "hiper.fifo" + +Whenever there is input into the fifo, the program reads the input as a list +of URL's and creates some new easy handles to fetch each URL via the +curl_multi "hiper" API. + + +Thus, you can try a single URL: + % echo http://www.yahoo.com > hiper.fifo + +Or a whole bunch of them: + % cat my-url-list > hiper.fifo + +The fifo buffer is handled almost instantly, so you can even add more URL's +while the previous requests are still being downloaded. + +Note: + For the sake of simplicity, URL length is limited to 1023 char's ! + +This is purely a demo app, all retrieved data is simply discarded by the write +callback. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */ + + +/* Global information, common to all connections */ +typedef struct _GlobalInfo +{ + struct event_base *evbase; + struct event fifo_event; + struct event timer_event; + CURLM *multi; + int still_running; + FILE *input; + int stopped; +} GlobalInfo; + + +/* Information associated with a specific easy handle */ +typedef struct _ConnInfo +{ + CURL *easy; + char *url; + GlobalInfo *global; + char error[CURL_ERROR_SIZE]; +} ConnInfo; + + +/* Information associated with a specific socket */ +typedef struct _SockInfo +{ + curl_socket_t sockfd; + CURL *easy; + int action; + long timeout; + struct event ev; + GlobalInfo *global; +} SockInfo; + +#define mycase(code) \ + case code: s = __STRING(code) + +/* Die if we get a bad CURLMcode somewhere */ +static void mcode_or_die(const char *where, CURLMcode code) +{ + if(CURLM_OK != code) { + const char *s; + switch(code) { + mycase(CURLM_BAD_HANDLE); break; + mycase(CURLM_BAD_EASY_HANDLE); break; + mycase(CURLM_OUT_OF_MEMORY); break; + mycase(CURLM_INTERNAL_ERROR); break; + mycase(CURLM_UNKNOWN_OPTION); break; + mycase(CURLM_LAST); break; + default: s = "CURLM_unknown"; break; + mycase(CURLM_BAD_SOCKET); + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + /* ignore this error */ + return; + } + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + exit(code); + } +} + + +/* Update the event timer after curl_multi library calls */ +static int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g) +{ + struct timeval timeout; + (void)multi; + + timeout.tv_sec = timeout_ms/1000; + timeout.tv_usec = (timeout_ms%1000)*1000; + fprintf(MSG_OUT, "multi_timer_cb: Setting timeout to %ld ms\n", timeout_ms); + + /* + * if timeout_ms is -1, just delete the timer + * + * For all other values of timeout_ms, this should set or *update* the timer + * to the new value + */ + if(timeout_ms == -1) + evtimer_del(&g->timer_event); + else /* includes timeout zero */ + evtimer_add(&g->timer_event, &timeout); + return 0; +} + + +/* Check for completed transfers, and remove their easy handles */ +static void check_multi_info(GlobalInfo *g) +{ + char *eff_url; + CURLMsg *msg; + int msgs_left; + ConnInfo *conn; + CURL *easy; + CURLcode res; + + fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running); + while((msg = curl_multi_info_read(g->multi, &msgs_left))) { + if(msg->msg == CURLMSG_DONE) { + easy = msg->easy_handle; + res = msg->data.result; + curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn); + curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url); + fprintf(MSG_OUT, "DONE: %s => (%d) %s\n", eff_url, res, conn->error); + curl_multi_remove_handle(g->multi, easy); + free(conn->url); + curl_easy_cleanup(easy); + free(conn); + } + } + if(g->still_running == 0 && g->stopped) + event_base_loopbreak(g->evbase); +} + + + +/* Called by libevent when we get action on a multi socket */ +static void event_cb(int fd, short kind, void *userp) +{ + GlobalInfo *g = (GlobalInfo*) userp; + CURLMcode rc; + + int action = + ((kind & EV_READ) ? CURL_CSELECT_IN : 0) | + ((kind & EV_WRITE) ? CURL_CSELECT_OUT : 0); + + rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running); + mcode_or_die("event_cb: curl_multi_socket_action", rc); + + check_multi_info(g); + if(g->still_running <= 0) { + fprintf(MSG_OUT, "last transfer done, kill timeout\n"); + if(evtimer_pending(&g->timer_event, NULL)) { + evtimer_del(&g->timer_event); + } + } +} + + + +/* Called by libevent when our timeout expires */ +static void timer_cb(int fd, short kind, void *userp) +{ + GlobalInfo *g = (GlobalInfo *)userp; + CURLMcode rc; + (void)fd; + (void)kind; + + rc = curl_multi_socket_action(g->multi, + CURL_SOCKET_TIMEOUT, 0, &g->still_running); + mcode_or_die("timer_cb: curl_multi_socket_action", rc); + check_multi_info(g); +} + + + +/* Clean up the SockInfo structure */ +static void remsock(SockInfo *f) +{ + if(f) { + if(event_initialized(&f->ev)) { + event_del(&f->ev); + } + free(f); + } +} + + + +/* Assign information to a SockInfo structure */ +static void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act, + GlobalInfo *g) +{ + int kind = + ((act & CURL_POLL_IN) ? EV_READ : 0) | + ((act & CURL_POLL_OUT) ? EV_WRITE : 0) | EV_PERSIST; + + f->sockfd = s; + f->action = act; + f->easy = e; + if(event_initialized(&f->ev)) { + event_del(&f->ev); + } + event_assign(&f->ev, g->evbase, f->sockfd, kind, event_cb, g); + event_add(&f->ev, NULL); +} + + + +/* Initialize a new SockInfo structure */ +static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g) +{ + SockInfo *fdp = calloc(1, sizeof(SockInfo)); + + fdp->global = g; + setsock(fdp, s, easy, action, g); + curl_multi_assign(g->multi, s, fdp); +} + +/* CURLMOPT_SOCKETFUNCTION */ +static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) +{ + GlobalInfo *g = (GlobalInfo*) cbp; + SockInfo *fdp = (SockInfo*) sockp; + const char *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) { + fprintf(MSG_OUT, "\n"); + remsock(fdp); + } + else { + if(!fdp) { + fprintf(MSG_OUT, "Adding data: %s\n", whatstr[what]); + addsock(s, e, what, g); + } + else { + fprintf(MSG_OUT, + "Changing action from %s to %s\n", + whatstr[fdp->action], whatstr[what]); + setsock(fdp, s, e, what, g); + } + } + return 0; +} + + + +/* CURLOPT_WRITEFUNCTION */ +static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) +{ + (void)ptr; + (void)data; + return size * nmemb; +} + + +/* CURLOPT_PROGRESSFUNCTION */ +static int prog_cb(void *p, double dltotal, double dlnow, double ult, + double uln) +{ + ConnInfo *conn = (ConnInfo *)p; + (void)ult; + (void)uln; + + fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal); + return 0; +} + + +/* Create a new easy handle, and add it to the global curl_multi */ +static void new_conn(char *url, GlobalInfo *g) +{ + ConnInfo *conn; + CURLMcode rc; + + conn = calloc(1, sizeof(ConnInfo)); + conn->error[0]='\0'; + + conn->easy = curl_easy_init(); + if(!conn->easy) { + fprintf(MSG_OUT, "curl_easy_init() failed, exiting!\n"); + exit(2); + } + conn->global = g; + conn->url = strdup(url); + curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url); + curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error); + curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn); + curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L); + fprintf(MSG_OUT, + "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url); + rc = curl_multi_add_handle(g->multi, conn->easy); + mcode_or_die("new_conn: curl_multi_add_handle", rc); + + /* note that the add_handle() will set a time-out to trigger soon so that + the necessary socket_action() call will be called by this app */ +} + +/* This gets called whenever data is received from the fifo */ +static void fifo_cb(int fd, short event, void *arg) +{ + char s[1024]; + long int rv = 0; + int n = 0; + GlobalInfo *g = (GlobalInfo *)arg; + (void)fd; + (void)event; + + do { + s[0]='\0'; + rv = fscanf(g->input, "%1023s%n", s, &n); + s[n]='\0'; + if(n && s[0]) { + if(!strcmp(s, "stop")) { + g->stopped = 1; + if(g->still_running == 0) + event_base_loopbreak(g->evbase); + } + else + new_conn(s, arg); /* if we read a URL, go get it! */ + } + else + break; + } while(rv != EOF); +} + +/* Create a named pipe and tell libevent to monitor it */ +static const char *fifo = "hiper.fifo"; +static int init_fifo(GlobalInfo *g) +{ + struct stat st; + curl_socket_t sockfd; + + fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo); + if(lstat (fifo, &st) == 0) { + if((st.st_mode & S_IFMT) == S_IFREG) { + errno = EEXIST; + perror("lstat"); + exit(1); + } + } + unlink(fifo); + if(mkfifo (fifo, 0600) == -1) { + perror("mkfifo"); + exit(1); + } + sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0); + if(sockfd == -1) { + perror("open"); + exit(1); + } + g->input = fdopen(sockfd, "r"); + + fprintf(MSG_OUT, "Now, pipe some URL's into > %s\n", fifo); + event_assign(&g->fifo_event, g->evbase, sockfd, EV_READ|EV_PERSIST, + fifo_cb, g); + event_add(&g->fifo_event, NULL); + return (0); +} + +static void clean_fifo(GlobalInfo *g) +{ + event_del(&g->fifo_event); + fclose(g->input); + unlink(fifo); +} + +int main(int argc, char **argv) +{ + GlobalInfo g; + (void)argc; + (void)argv; + + memset(&g, 0, sizeof(GlobalInfo)); + g.evbase = event_base_new(); + init_fifo(&g); + g.multi = curl_multi_init(); + evtimer_assign(&g.timer_event, g.evbase, timer_cb, &g); + + /* setup the generic multi interface options we want */ + curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g); + curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb); + curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g); + + /* we do not call any curl_multi_socket*() function yet as we have no handles + added! */ + + event_base_dispatch(g.evbase); + + /* this, of course, will not get called since only way to stop this program + is via ctrl-C, but it is here to show how cleanup /would/ be done. */ + clean_fifo(&g); + event_del(&g.timer_event); + event_base_free(g.evbase); + curl_multi_cleanup(g.multi); + return 0; +} diff --git a/docs/examples/href_extractor.c b/docs/examples/href_extractor.c new file mode 100644 index 0000000..5c92b0c --- /dev/null +++ b/docs/examples/href_extractor.c @@ -0,0 +1,88 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Uses the "Streaming HTML parser" to extract the href pieces in a streaming + * manner from a downloaded HTML. + * + */ +/* + * The HTML parser is found at https://github.com/arjunc77/htmlstreamparser + */ + +#include +#include +#include + + +static size_t write_callback(void *buffer, size_t size, size_t nmemb, + void *hsp) +{ + size_t realsize = size * nmemb, p; + for(p = 0; p < realsize; p++) { + html_parser_char_parse(hsp, ((char *)buffer)[p]); + if(html_parser_cmp_tag(hsp, "a", 1)) + if(html_parser_cmp_attr(hsp, "href", 4)) + if(html_parser_is_in(hsp, HTML_VALUE_ENDED)) { + html_parser_val(hsp)[html_parser_val_length(hsp)] = '\0'; + printf("%s\n", html_parser_val(hsp)); + } + } + return realsize; +} + +int main(int argc, char *argv[]) +{ + char tag[1], attr[4], val[128]; + CURL *curl; + HTMLSTREAMPARSER *hsp; + + if(argc != 2) { + printf("Usage: %s URL\n", argv[0]); + return EXIT_FAILURE; + } + + curl = curl_easy_init(); + + hsp = html_parser_init(); + + html_parser_set_tag_to_lower(hsp, 1); + html_parser_set_attr_to_lower(hsp, 1); + html_parser_set_tag_buffer(hsp, tag, sizeof(tag)); + html_parser_set_attr_buffer(hsp, attr, sizeof(attr)); + html_parser_set_val_buffer(hsp, val, sizeof(val)-1); + + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, hsp); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + curl_easy_perform(curl); + + curl_easy_cleanup(curl); + + html_parser_cleanup(hsp); + + return EXIT_SUCCESS; +} diff --git a/docs/examples/hsts-preload.c b/docs/examples/hsts-preload.c new file mode 100644 index 0000000..ee42535 --- /dev/null +++ b/docs/examples/hsts-preload.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Preload domains to HSTS + * + */ +#include +#include +#include + +struct entry { + const char *name; + const char *exp; +}; + +static const struct entry preload_hosts[] = { + { "example.com", "20370320 01:02:03" }, + { "curl.se", "20370320 03:02:01" }, + { NULL, NULL } /* end of list marker */ +}; + +struct state { + int index; +}; + +/* "read" is from the point of the library, it wants data from us. One domain + entry per invoke. */ +static CURLSTScode hstsread(CURL *easy, struct curl_hstsentry *e, + void *userp) +{ + const char *host; + const char *expire; + struct state *s = (struct state *)userp; + (void)easy; + host = preload_hosts[s->index].name; + expire = preload_hosts[s->index++].exp; + + if(host && (strlen(host) < e->namelen)) { + strcpy(e->name, host); + e->includeSubDomains = 0; + strcpy(e->expire, expire); + fprintf(stderr, "HSTS preload '%s' until '%s'\n", host, expire); + } + else + return CURLSTS_DONE; + return CURLSTS_OK; +} + +static CURLSTScode hstswrite(CURL *easy, struct curl_hstsentry *e, + struct curl_index *i, void *userp) +{ + (void)easy; + (void)userp; /* we have no custom input */ + printf("[%u/%u] %s %s\n", (unsigned int)i->index, (unsigned int)i->total, + e->name, e->expire); + return CURLSTS_OK; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + struct state st = {0}; + + /* enable HSTS for this handle */ + curl_easy_setopt(curl, CURLOPT_HSTS_CTRL, (long)CURLHSTS_ENABLE); + + /* function to call at first to populate the cache before the transfer */ + curl_easy_setopt(curl, CURLOPT_HSTSREADFUNCTION, hstsread); + curl_easy_setopt(curl, CURLOPT_HSTSREADDATA, &st); + + /* function to call after transfer to store the new state of the HSTS + cache */ + curl_easy_setopt(curl, CURLOPT_HSTSWRITEFUNCTION, hstswrite); + curl_easy_setopt(curl, CURLOPT_HSTSWRITEDATA, NULL); + + /* use the domain with HTTP but due to the preload, it should do the + transfer using HTTPS */ + curl_easy_setopt(curl, CURLOPT_URL, "http://curl.se"); + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/htmltidy.c b/docs/examples/htmltidy.c new file mode 100644 index 0000000..cc6f63e --- /dev/null +++ b/docs/examples/htmltidy.c @@ -0,0 +1,130 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Download a document and use libtidy to parse the HTML. + * + */ +/* + * LibTidy => https://www.html-tidy.org/ + */ + +#include +#include +#include +#include + +/* curl write callback, to fill tidy's input buffer... */ +uint write_cb(char *in, uint size, uint nmemb, TidyBuffer *out) +{ + uint r; + r = size * nmemb; + tidyBufAppend(out, in, r); + return r; +} + +/* Traverse the document tree */ +void dumpNode(TidyDoc doc, TidyNode tnod, int indent) +{ + TidyNode child; + for(child = tidyGetChild(tnod); child; child = tidyGetNext(child) ) { + ctmbstr name = tidyNodeGetName(child); + if(name) { + /* if it has a name, then it's an HTML tag ... */ + TidyAttr attr; + printf("%*.*s%s ", indent, indent, "<", name); + /* walk the attribute list */ + for(attr = tidyAttrFirst(child); attr; attr = tidyAttrNext(attr) ) { + printf("%s", tidyAttrName(attr)); + tidyAttrValue(attr)?printf("=\"%s\" ", + tidyAttrValue(attr)):printf(" "); + } + printf(">\n"); + } + else { + /* if it does not have a name, then it's probably text, cdata, etc... */ + TidyBuffer buf; + tidyBufInit(&buf); + tidyNodeGetText(doc, child, &buf); + printf("%*.*s\n", indent, indent, buf.bp?(char *)buf.bp:""); + tidyBufFree(&buf); + } + dumpNode(doc, child, indent + 4); /* recursive */ + } +} + + +int main(int argc, char **argv) +{ + if(argc == 2) { + CURL *curl; + char curl_errbuf[CURL_ERROR_SIZE]; + TidyDoc tdoc; + TidyBuffer docbuf = {0}; + TidyBuffer tidy_errbuf = {0}; + int err; + + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); + + tdoc = tidyCreate(); + tidyOptSetBool(tdoc, TidyForceOutput, yes); /* try harder */ + tidyOptSetInt(tdoc, TidyWrapLen, 4096); + tidySetErrorBuffer(tdoc, &tidy_errbuf); + tidyBufInit(&docbuf); + + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &docbuf); + err = curl_easy_perform(curl); + if(!err) { + err = tidyParseBuffer(tdoc, &docbuf); /* parse the input */ + if(err >= 0) { + err = tidyCleanAndRepair(tdoc); /* fix any problems */ + if(err >= 0) { + err = tidyRunDiagnostics(tdoc); /* load tidy error buffer */ + if(err >= 0) { + dumpNode(tdoc, tidyGetRoot(tdoc), 0); /* walk the tree */ + fprintf(stderr, "%s\n", tidy_errbuf.bp); /* show errors */ + } + } + } + } + else + fprintf(stderr, "%s\n", curl_errbuf); + + /* clean-up */ + curl_easy_cleanup(curl); + tidyBufFree(&docbuf); + tidyBufFree(&tidy_errbuf); + tidyRelease(tdoc); + return err; + + } + else + printf("usage: %s \n", argv[0]); + + return 0; +} diff --git a/docs/examples/htmltitle.cpp b/docs/examples/htmltitle.cpp new file mode 100644 index 0000000..ee3e023 --- /dev/null +++ b/docs/examples/htmltitle.cpp @@ -0,0 +1,296 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Get a web page, extract the title with libxml. + * + + Written by Lars Nilsson + + GNU C++ compile command line suggestion (edit paths accordingly): + + g++ -Wall -I/opt/curl/include -I/opt/libxml/include/libxml2 htmltitle.cpp \ + -o htmltitle -L/opt/curl/lib -L/opt/libxml/lib -lcurl -lxml2 +*/ +#include +#include +#include +#include +#include +#include + +// +// Case-insensitive string comparison +// + +#ifdef _MSC_VER +#define COMPARE(a, b) (!_stricmp((a), (b))) +#else +#define COMPARE(a, b) (!strcasecmp((a), (b))) +#endif + +// +// libxml callback context structure +// + +struct Context +{ + Context(): addTitle(false) { } + + bool addTitle; + std::string title; +}; + +// +// libcurl variables for error strings and returned data + +static char errorBuffer[CURL_ERROR_SIZE]; +static std::string buffer; + +// +// libcurl write callback function +// + +static int writer(char *data, size_t size, size_t nmemb, + std::string *writerData) +{ + if(writerData == NULL) + return 0; + + writerData->append(data, size*nmemb); + + return size * nmemb; +} + +// +// libcurl connection initialization +// + +static bool init(CURL *&conn, char *url) +{ + CURLcode code; + + conn = curl_easy_init(); + + if(conn == NULL) { + fprintf(stderr, "Failed to create CURL connection\n"); + exit(EXIT_FAILURE); + } + + code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, errorBuffer); + if(code != CURLE_OK) { + fprintf(stderr, "Failed to set error buffer [%d]\n", code); + return false; + } + + code = curl_easy_setopt(conn, CURLOPT_URL, url); + if(code != CURLE_OK) { + fprintf(stderr, "Failed to set URL [%s]\n", errorBuffer); + return false; + } + + code = curl_easy_setopt(conn, CURLOPT_FOLLOWLOCATION, 1L); + if(code != CURLE_OK) { + fprintf(stderr, "Failed to set redirect option [%s]\n", errorBuffer); + return false; + } + + code = curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writer); + if(code != CURLE_OK) { + fprintf(stderr, "Failed to set writer [%s]\n", errorBuffer); + return false; + } + + code = curl_easy_setopt(conn, CURLOPT_WRITEDATA, &buffer); + if(code != CURLE_OK) { + fprintf(stderr, "Failed to set write data [%s]\n", errorBuffer); + return false; + } + + return true; +} + +// +// libxml start element callback function +// + +static void StartElement(void *voidContext, + const xmlChar *name, + const xmlChar **attributes) +{ + Context *context = static_cast(voidContext); + + if(COMPARE(reinterpret_cast(name), "TITLE")) { + context->title = ""; + context->addTitle = true; + } + (void) attributes; +} + +// +// libxml end element callback function +// + +static void EndElement(void *voidContext, + const xmlChar *name) +{ + Context *context = static_cast(voidContext); + + if(COMPARE(reinterpret_cast(name), "TITLE")) + context->addTitle = false; +} + +// +// Text handling helper function +// + +static void handleCharacters(Context *context, + const xmlChar *chars, + int length) +{ + if(context->addTitle) + context->title.append(reinterpret_cast(chars), length); +} + +// +// libxml PCDATA callback function +// + +static void Characters(void *voidContext, + const xmlChar *chars, + int length) +{ + Context *context = static_cast(voidContext); + + handleCharacters(context, chars, length); +} + +// +// libxml CDATA callback function +// + +static void cdata(void *voidContext, + const xmlChar *chars, + int length) +{ + Context *context = static_cast(voidContext); + + handleCharacters(context, chars, length); +} + +// +// libxml SAX callback structure +// + +static htmlSAXHandler saxHandler = +{ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + StartElement, + EndElement, + NULL, + Characters, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + cdata, + NULL +}; + +// +// Parse given (assumed to be) HTML text and return the title +// + +static void parseHtml(const std::string &html, + std::string &title) +{ + htmlParserCtxtPtr ctxt; + Context context; + + ctxt = htmlCreatePushParserCtxt(&saxHandler, &context, "", 0, "", + XML_CHAR_ENCODING_NONE); + + htmlParseChunk(ctxt, html.c_str(), html.size(), 0); + htmlParseChunk(ctxt, "", 0, 1); + + htmlFreeParserCtxt(ctxt); + + title = context.title; +} + +int main(int argc, char *argv[]) +{ + CURL *conn = NULL; + CURLcode code; + std::string title; + + // Ensure one argument is given + + if(argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + curl_global_init(CURL_GLOBAL_DEFAULT); + + // Initialize CURL connection + + if(!init(conn, argv[1])) { + fprintf(stderr, "Connection initialization failed\n"); + exit(EXIT_FAILURE); + } + + // Retrieve content for the URL + + code = curl_easy_perform(conn); + curl_easy_cleanup(conn); + + if(code != CURLE_OK) { + fprintf(stderr, "Failed to get '%s' [%s]\n", argv[1], errorBuffer); + exit(EXIT_FAILURE); + } + + // Parse the (assumed) HTML code + parseHtml(buffer, title); + + // Display the extracted title + printf("Title: %s\n", title.c_str()); + + return EXIT_SUCCESS; +} diff --git a/docs/examples/http-options.c b/docs/examples/http-options.c new file mode 100644 index 0000000..964e0ef --- /dev/null +++ b/docs/examples/http-options.c @@ -0,0 +1,59 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Issue an HTTP 'OPTIONS *' request + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS"); + + /* issue an OPTIONS * request (no leading slash) */ + curl_easy_setopt(curl, CURLOPT_REQUEST_TARGET, "*"); + + /* if this operation fails, allow risking a memory leak and do quick exit + from libcurl as this will exit() anyway */ + curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/http-post.c b/docs/examples/http-post.c new file mode 100644 index 0000000..2cacefe --- /dev/null +++ b/docs/examples/http-post.c @@ -0,0 +1,61 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * simple HTTP POST using the easy interface + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + /* In windows, this will init the winsock stuff */ + curl_global_init(CURL_GLOBAL_ALL); + + /* get a curl handle */ + curl = curl_easy_init(); + if(curl) { + /* First set the URL that is about to receive our POST. This URL can + just as well be an https:// URL if that is what should receive the + data. */ + curl_easy_setopt(curl, CURLOPT_URL, "http://postit.example.com/moo.cgi"); + /* Now specify the POST data */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl"); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/http2-download.c b/docs/examples/http2-download.c new file mode 100644 index 0000000..5da7ed6 --- /dev/null +++ b/docs/examples/http2-download.c @@ -0,0 +1,234 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Multiplexed HTTP/2 downloads over a single connection + * + */ +#include +#include +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include +#include + +#ifndef CURLPIPE_MULTIPLEX +/* This little trick will just make sure that we do not enable pipelining for + libcurls old enough to not have this symbol. It is _not_ defined to zero in + a recent libcurl header. */ +#define CURLPIPE_MULTIPLEX 0 +#endif + +struct transfer { + CURL *easy; + unsigned int num; + FILE *out; +}; + +#define NUM_HANDLES 1000 + +static +void dump(const char *text, unsigned int num, unsigned char *ptr, size_t size, + char nohex) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stderr, "%u %s, %lu bytes (0x%lx)\n", + num, text, (unsigned long)size, (unsigned long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stderr); /* newline */ + } +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + const char *text; + struct transfer *t = (struct transfer *)userp; + unsigned int num = t->num; + (void)handle; /* prevent compiler warning */ + + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "== %u Info: %s", num, data); + return 0; + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + default: /* in case a new one is introduced to shock us */ + return 0; + } + + dump(text, num, (unsigned char *)data, size, 1); + return 0; +} + +static void setup(struct transfer *t, int num) +{ + char filename[128]; + CURL *hnd; + + hnd = t->easy = curl_easy_init(); + + curl_msnprintf(filename, 128, "dl-%d", num); + + t->out = fopen(filename, "wb"); + if(!t->out) { + fprintf(stderr, "error: could not open file %s for writing: %s\n", + filename, strerror(errno)); + exit(1); + } + + /* write to this file */ + curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t->out); + + /* set the same URL */ + curl_easy_setopt(hnd, CURLOPT_URL, "https://localhost:8443/index.html"); + + /* please be verbose */ + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(hnd, CURLOPT_DEBUGDATA, t); + + /* enlarge the receive buffer for potentially higher transfer speeds */ + curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 100000L); + + /* HTTP/2 please */ + curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + +#if (CURLPIPE_MULTIPLEX > 0) + /* wait for pipe connection to confirm */ + curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); +#endif +} + +/* + * Download many transfers over HTTP/2, using the same connection! + */ +int main(int argc, char **argv) +{ + struct transfer trans[NUM_HANDLES]; + CURLM *multi_handle; + int i; + int still_running = 0; /* keep number of running handles */ + int num_transfers; + if(argc > 1) { + /* if given a number, do that many transfers */ + num_transfers = atoi(argv[1]); + if((num_transfers < 1) || (num_transfers > NUM_HANDLES)) + num_transfers = 3; /* a suitable low default */ + } + else + num_transfers = 3; /* suitable default */ + + /* init a multi stack */ + multi_handle = curl_multi_init(); + + for(i = 0; i < num_transfers; i++) { + setup(&trans[i], i); + + /* add the individual transfer */ + curl_multi_add_handle(multi_handle, trans[i].easy); + } + + curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) + break; + } while(still_running); + + for(i = 0; i < num_transfers; i++) { + curl_multi_remove_handle(multi_handle, trans[i].easy); + curl_easy_cleanup(trans[i].easy); + } + + curl_multi_cleanup(multi_handle); + + return 0; +} diff --git a/docs/examples/http2-pushinmemory.c b/docs/examples/http2-pushinmemory.c new file mode 100644 index 0000000..74c64e0 --- /dev/null +++ b/docs/examples/http2-pushinmemory.c @@ -0,0 +1,190 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP/2 server push. Receive all data in memory. + * + */ +#include +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include + +struct Memory { + char *memory; + size_t size; +}; + +static size_t +write_cb(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct Memory *mem = (struct Memory *)userp; + char *ptr = realloc(mem->memory, mem->size + realsize + 1); + if(!ptr) { + /* out of memory! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +#define MAX_FILES 10 +static struct Memory files[MAX_FILES]; +static int pushindex = 1; + +static void init_memory(struct Memory *chunk) +{ + chunk->memory = malloc(1); /* grown as needed with realloc */ + chunk->size = 0; /* no data at this point */ +} + +static void setup(CURL *hnd) +{ + /* set the same URL */ + curl_easy_setopt(hnd, CURLOPT_URL, "https://localhost:8443/index.html"); + + /* HTTP/2 please */ + curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + + /* we use a self-signed test server, skip verification during debugging */ + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); + + /* write data to a struct */ + curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, write_cb); + init_memory(&files[0]); + curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &files[0]); + + /* wait for pipe connection to confirm */ + curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); +} + +/* called when there is an incoming push */ +static int server_push_callback(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp) +{ + char *headp; + int *transfers = (int *)userp; + (void)parent; /* we have no use for this */ + (void)num_headers; /* unused */ + + if(pushindex == MAX_FILES) + /* cannot fit anymore */ + return CURL_PUSH_DENY; + + /* write to this buffer */ + init_memory(&files[pushindex]); + curl_easy_setopt(easy, CURLOPT_WRITEDATA, &files[pushindex]); + pushindex++; + + headp = curl_pushheader_byname(headers, ":path"); + if(headp) + fprintf(stderr, "* Pushed :path '%s'\n", headp /* skip :path + colon */); + + (*transfers)++; /* one more */ + return CURL_PUSH_OK; +} + + +/* + * Download a file over HTTP/2, take care of server push. + */ +int main(void) +{ + CURL *easy; + CURLM *multi; + int still_running; /* keep number of running handles */ + int transfers = 1; /* we start with one */ + int i; + struct CURLMsg *m; + + /* init a multi stack */ + multi = curl_multi_init(); + + easy = curl_easy_init(); + + /* set options */ + setup(easy); + + /* add the easy transfer */ + curl_multi_add_handle(multi, easy); + + curl_multi_setopt(multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, server_push_callback); + curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &transfers); + + while(transfers) { + int rc; + CURLMcode mcode = curl_multi_perform(multi, &still_running); + if(mcode) + break; + + mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc); + if(mcode) + break; + + + /* + * When doing server push, libcurl itself created and added one or more + * easy handles but *we* need to clean them up when they are done. + */ + do { + int msgq = 0; + m = curl_multi_info_read(multi, &msgq); + if(m && (m->msg == CURLMSG_DONE)) { + CURL *e = m->easy_handle; + transfers--; + curl_multi_remove_handle(multi, e); + curl_easy_cleanup(e); + } + } while(m); + + } + + + curl_multi_cleanup(multi); + + /* 'pushindex' is now the number of received transfers */ + for(i = 0; i < pushindex; i++) { + /* do something fun with the data, and then free it when done */ + free(files[i].memory); + } + + return 0; +} diff --git a/docs/examples/http2-serverpush.c b/docs/examples/http2-serverpush.c new file mode 100644 index 0000000..e830aa9 --- /dev/null +++ b/docs/examples/http2-serverpush.c @@ -0,0 +1,276 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP/2 server push + * + */ +#include +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include + +#ifndef CURLPIPE_MULTIPLEX +#error "too old libcurl, cannot do HTTP/2 server push!" +#endif + +static +void dump(const char *text, unsigned char *ptr, size_t size, + char nohex) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stderr, "%s, %lu bytes (0x%lx)\n", + text, (unsigned long)size, (unsigned long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stderr); /* newline */ + } +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + const char *text; + (void)handle; /* prevent compiler warning */ + (void)userp; + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + return 0; + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + default: /* in case a new one is introduced to shock us */ + return 0; + } + + dump(text, (unsigned char *)data, size, 1); + return 0; +} + +#define OUTPUTFILE "dl" + +static int setup(CURL *hnd, const char *url) +{ + FILE *out = fopen(OUTPUTFILE, "wb"); + if(!out) + /* failed */ + return 1; + + /* write to this file */ + curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out); + + /* set the same URL */ + curl_easy_setopt(hnd, CURLOPT_URL, url); + + /* please be verbose */ + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); + + /* HTTP/2 please */ + curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + + /* we use a self-signed test server, skip verification during debugging */ + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); + +#if (CURLPIPE_MULTIPLEX > 0) + /* wait for pipe connection to confirm */ + curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); +#endif + return 0; /* all is good */ +} + +/* called when there is an incoming push */ +static int server_push_callback(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp) +{ + char *headp; + size_t i; + int *transfers = (int *)userp; + char filename[128]; + FILE *out; + static unsigned int count = 0; + + (void)parent; /* we have no use for this */ + + snprintf(filename, 128, "push%u", count++); + + /* here's a new stream, save it in a new file for each new push */ + out = fopen(filename, "wb"); + if(!out) { + /* if we cannot save it, deny it */ + fprintf(stderr, "Failed to create output file for push\n"); + return CURL_PUSH_DENY; + } + + /* write to this file */ + curl_easy_setopt(easy, CURLOPT_WRITEDATA, out); + + fprintf(stderr, "**** push callback approves stream %u, got %lu headers!\n", + count, (unsigned long)num_headers); + + for(i = 0; imsg == CURLMSG_DONE)) { + CURL *e = m->easy_handle; + transfers--; + curl_multi_remove_handle(multi_handle, e); + curl_easy_cleanup(e); + } + } while(m); + + } while(transfers); /* as long as we have transfers going */ + + curl_multi_cleanup(multi_handle); + + + return 0; +} diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c new file mode 100644 index 0000000..dd63b8c --- /dev/null +++ b/docs/examples/http2-upload.c @@ -0,0 +1,303 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Multiplexed HTTP/2 uploads over a single connection + * + */ +#include +#include +#include +#include +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include +#include + +#ifndef CURLPIPE_MULTIPLEX +/* This little trick will just make sure that we do not enable pipelining for + libcurls old enough to not have this symbol. It is _not_ defined to zero in + a recent libcurl header. */ +#define CURLPIPE_MULTIPLEX 0 +#endif + +#define NUM_HANDLES 1000 + +struct input { + FILE *in; + size_t bytes_read; /* count up */ + CURL *hnd; + int num; +}; + +static +void dump(const char *text, int num, unsigned char *ptr, size_t size, + char nohex) +{ + size_t i; + size_t c; + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stderr, "%d %s, %lu bytes (0x%lx)\n", + num, text, (unsigned long)size, (unsigned long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stderr); /* newline */ + } +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + char timebuf[60]; + const char *text; + struct input *i = (struct input *)userp; + int num = i->num; + static time_t epoch_offset; + static int known_offset; + struct timeval tv; + time_t secs; + struct tm *now; + (void)handle; /* prevent compiler warning */ + + gettimeofday(&tv, NULL); + if(!known_offset) { + epoch_offset = time(NULL) - tv.tv_sec; + known_offset = 1; + } + secs = epoch_offset + tv.tv_sec; + now = localtime(&secs); /* not thread safe but we do not care */ + curl_msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld", + now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); + + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "%s [%d] Info: %s", timebuf, num, data); + return 0; + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + default: /* in case a new one is introduced to shock us */ + return 0; + } + + dump(text, num, (unsigned char *)data, size, 1); + return 0; +} + +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct input *i = userp; + size_t retcode = fread(ptr, size, nmemb, i->in); + i->bytes_read += retcode; + return retcode; +} + +static void setup(struct input *i, int num, const char *upload) +{ + FILE *out; + char url[256]; + char filename[128]; + struct stat file_info; + curl_off_t uploadsize; + CURL *hnd; + + hnd = i->hnd = curl_easy_init(); + i->num = num; + curl_msnprintf(filename, 128, "dl-%d", num); + out = fopen(filename, "wb"); + if(!out) { + fprintf(stderr, "error: could not open file %s for writing: %s\n", upload, + strerror(errno)); + exit(1); + } + + curl_msnprintf(url, 256, "https://localhost:8443/upload-%d", num); + + /* get the file size of the local file */ + if(stat(upload, &file_info)) { + fprintf(stderr, "error: could not stat file %s: %s\n", upload, + strerror(errno)); + exit(1); + } + + uploadsize = file_info.st_size; + + i->in = fopen(upload, "rb"); + if(!i->in) { + fprintf(stderr, "error: could not open file %s for reading: %s\n", upload, + strerror(errno)); + exit(1); + } + + /* write to this file */ + curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out); + + /* we want to use our own read function */ + curl_easy_setopt(hnd, CURLOPT_READFUNCTION, read_callback); + /* read from this file */ + curl_easy_setopt(hnd, CURLOPT_READDATA, i); + /* provide the size of the upload */ + curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, uploadsize); + + /* send in the URL to store the upload as */ + curl_easy_setopt(hnd, CURLOPT_URL, url); + + /* upload please */ + curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L); + + /* please be verbose */ + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(hnd, CURLOPT_DEBUGDATA, i); + + /* HTTP/2 please */ + curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + + /* we use a self-signed test server, skip verification during debugging */ + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); + +#if (CURLPIPE_MULTIPLEX > 0) + /* wait for pipe connection to confirm */ + curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); +#endif +} + +/* + * Upload all files over HTTP/2, using the same physical connection! + */ +int main(int argc, char **argv) +{ + struct input trans[NUM_HANDLES]; + CURLM *multi_handle; + int i; + int still_running = 0; /* keep number of running handles */ + const char *filename = "index.html"; + int num_transfers; + + if(argc > 1) { + /* if given a number, do that many transfers */ + num_transfers = atoi(argv[1]); + + if(!num_transfers || (num_transfers > NUM_HANDLES)) + num_transfers = 3; /* a suitable low default */ + + if(argc > 2) + /* if given a file name, upload this! */ + filename = argv[2]; + } + else + num_transfers = 3; + + /* init a multi stack */ + multi_handle = curl_multi_init(); + + for(i = 0; i, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Checks if HTTP/3 support is present in libcurl. + * + */ +#include +#include + +int main(void) +{ + curl_version_info_data *ver; + + curl_global_init(CURL_GLOBAL_ALL); + + ver = curl_version_info(CURLVERSION_NOW); + if(ver->features & CURL_VERSION_HTTP2) + printf("HTTP/2 support is present\n"); + + if(ver->features & CURL_VERSION_HTTP3) + printf("HTTP/3 support is present\n"); + + if(ver->features & CURL_VERSION_ALTSVC) + printf("Alt-svc support is present\n"); + + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/http3.c b/docs/examples/http3.c new file mode 100644 index 0000000..900e119 --- /dev/null +++ b/docs/examples/http3.c @@ -0,0 +1,55 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Very simple HTTP/3 GET + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Use HTTP/3 but fallback to earlier HTTP if necessary */ + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, + (long)CURL_HTTP_VERSION_3); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/httpcustomheader.c b/docs/examples/httpcustomheader.c new file mode 100644 index 0000000..a388167 --- /dev/null +++ b/docs/examples/httpcustomheader.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP request with custom modified, removed and added headers + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + struct curl_slist *chunk = NULL; + + /* Remove a header curl would otherwise add by itself */ + chunk = curl_slist_append(chunk, "Accept:"); + + /* Add a custom header */ + chunk = curl_slist_append(chunk, "Another: yes"); + + /* Modify a header curl otherwise adds differently */ + chunk = curl_slist_append(chunk, "Host: example.com"); + + /* Add a header with "blank" contents to the right of the colon. Note that + we are then using a semicolon in the string we pass to curl! */ + chunk = curl_slist_append(chunk, "X-silly-header;"); + + /* set our custom set of headers */ + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + + curl_easy_setopt(curl, CURLOPT_URL, "localhost"); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + + /* free the custom headers */ + curl_slist_free_all(chunk); + } + return 0; +} diff --git a/docs/examples/httpput-postfields.c b/docs/examples/httpput-postfields.c new file mode 100644 index 0000000..98d7c3d --- /dev/null +++ b/docs/examples/httpput-postfields.c @@ -0,0 +1,105 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP PUT using CURLOPT_POSTFIELDS + * + */ +#include +#include +#include +#include + +static const char olivertwist[]= + "Among other public buildings in a certain town, which for many reasons " + "it will be prudent to refrain from mentioning, and to which I will assign " + "no fictitious name, there is one anciently common to most towns, great or " + "small: to wit, a workhouse; and in this workhouse was born; on a day and " + "date which I need not trouble myself to repeat, inasmuch as it can be of " + "no possible consequence to the reader, in this stage of the business at " + "all events; the item of mortality whose name is prefixed"; + +/* ... to the head of this chapter. String cut off to stick within the C90 + 509 byte limit. */ + +/* + * This example shows an HTTP PUT operation that sends a fixed buffer with + * CURLOPT_POSTFIELDS to the URL given as an argument. + */ + +int main(int argc, char **argv) +{ + CURL *curl; + CURLcode res; + char *url; + + if(argc < 2) + return 1; + + url = argv[1]; + + /* In windows, this will init the winsock stuff */ + curl_global_init(CURL_GLOBAL_ALL); + + /* get a curl handle */ + curl = curl_easy_init(); + if(curl) { + struct curl_slist *headers = NULL; + + /* default type with postfields is application/x-www-form-urlencoded, + change it if you want */ + headers = curl_slist_append(headers, "Content-Type: literature/classic"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + /* pass on content in request body. When CURLOPT_POSTFIELDSIZE is not used, + curl does strlen to get the size. */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, olivertwist); + + /* override the POST implied by CURLOPT_POSTFIELDS + * + * Warning: CURLOPT_CUSTOMREQUEST is problematic, especially if you want + * to follow redirects. Be aware. + */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); + + /* specify target URL, and note that this URL should include a file + name, not only a directory */ + curl_easy_setopt(curl, CURLOPT_URL, url); + + /* Now run off and do what you have been told! */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + + /* free headers */ + curl_slist_free_all(headers); + } + + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/httpput.c b/docs/examples/httpput.c new file mode 100644 index 0000000..b9a6c87 --- /dev/null +++ b/docs/examples/httpput.c @@ -0,0 +1,123 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP PUT with easy interface and read callback + * + */ +#include +#include +#include +#include + +/* + * This example shows an HTTP PUT operation. PUTs a file given as a command + * line argument to the URL also given on the command line. + * + * This example also uses its own read callback. + * + * Here's an article on how to setup a PUT handler for Apache: + * http://www.apacheweek.com/features/put + */ + +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t retcode; + unsigned long nread; + + /* in real-world cases, this would probably get this data differently + as this fread() stuff is exactly what the library already would do + by default internally */ + retcode = fread(ptr, size, nmemb, stream); + + if(retcode > 0) { + nread = (unsigned long)retcode; + fprintf(stderr, "*** We read %lu bytes from file\n", nread); + } + + return retcode; +} + +int main(int argc, char **argv) +{ + CURL *curl; + CURLcode res; + FILE * hd_src; + struct stat file_info; + + char *file; + char *url; + + if(argc < 3) + return 1; + + file = argv[1]; + url = argv[2]; + + /* get the file size of the local file */ + stat(file, &file_info); + + /* get a FILE * of the same file, could also be made with + fdopen() from the previous descriptor, but hey this is just + an example! */ + hd_src = fopen(file, "rb"); + + /* In windows, this will init the winsock stuff */ + curl_global_init(CURL_GLOBAL_ALL); + + /* get a curl handle */ + curl = curl_easy_init(); + if(curl) { + /* we want to use our own read function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + + /* enable uploading (implies PUT over HTTP) */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* specify target URL, and note that this URL should include a file + name, not only a directory */ + curl_easy_setopt(curl, CURLOPT_URL, url); + + /* now specify which file to upload */ + curl_easy_setopt(curl, CURLOPT_READDATA, hd_src); + + /* provide the size of the upload, we typecast the value to curl_off_t + since we must be sure to use the correct data size */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)file_info.st_size); + + /* Now run off and do what you have been told! */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + fclose(hd_src); /* close the local file */ + + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/https.c b/docs/examples/https.c new file mode 100644 index 0000000..2a34e37 --- /dev/null +++ b/docs/examples/https.c @@ -0,0 +1,83 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Simple HTTPS GET + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who is not using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you are connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + /* cache the CA cert bundle in memory for a week */ + curl_easy_setopt(curl, CURLOPT_CA_CACHE_TIMEOUT, 604800L); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/imap-append.c b/docs/examples/imap-append.c new file mode 100644 index 0000000..33566bb --- /dev/null +++ b/docs/examples/imap-append.c @@ -0,0 +1,130 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Send email with IMAP + * + */ + +#include +#include +#include + +/* This is a simple example showing how to send mail using libcurl's IMAP + * capabilities. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +#define FROM "" +#define TO "" +#define CC "" + +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" + "Cc: " CC "(Another example User)\r\n" + "Message-ID: " + "\r\n" + "Subject: IMAP example message\r\n" + "\r\n" /* empty line to divide headers from body, see RFC 5322 */ + "The body of the message starts here.\r\n" + "\r\n" + "It could be a lot of lines, could be MIME encoded, whatever.\r\n" + "Check RFC 5322.\r\n"; + +struct upload_status { + size_t bytes_read; +}; + +static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + size_t room = size * nmemb; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = &payload_text[upload_ctx->bytes_read]; + + if(*data) { + size_t len = strlen(data); + if(room < len) + len = room; + memcpy(ptr, data, len); + upload_ctx->bytes_read += len; + + return len; + } + + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + size_t filesize; + long infilesize = LONG_MAX; + struct upload_status upload_ctx = { 0 }; + + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will create a new message in folder "Sent". */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/Sent"); + + /* In this case, we are using a callback function to specify the data. You + * could just use the CURLOPT_READDATA option to specify a FILE pointer to + * read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + filesize = strlen(payload_text); + if(filesize <= LONG_MAX) + infilesize = (long)filesize; + curl_easy_setopt(curl, CURLOPT_INFILESIZE, infilesize); + + /* Perform the append */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-authzid.c b/docs/examples/imap-authzid.c new file mode 100644 index 0000000..af07320 --- /dev/null +++ b/docs/examples/imap-authzid.c @@ -0,0 +1,73 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Retrieve emails from a shared IMAP mailbox + * + */ + +#include +#include + +/* This is a simple example showing how to fetch mail using libcurl's IMAP + * capabilities. + * + * Note that this example requires libcurl 7.66.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set the username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* Set the authorization identity (identity to act as) */ + curl_easy_setopt(curl, CURLOPT_SASL_AUTHZID, "shared-mailbox"); + + /* Force PLAIN authentication */ + curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, "AUTH=PLAIN"); + + /* This will fetch message 1 from the user's inbox */ + curl_easy_setopt(curl, CURLOPT_URL, + "imap://imap.example.com/INBOX/;UID=1"); + + /* Perform the fetch */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-copy.c b/docs/examples/imap-copy.c new file mode 100644 index 0000000..0920f09 --- /dev/null +++ b/docs/examples/imap-copy.c @@ -0,0 +1,73 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Copy an email from one IMAP folder to another + * + */ + +#include +#include + +/* This is a simple example showing how to copy a mail from one mailbox folder + * to another using libcurl's IMAP capabilities. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is source mailbox folder to select */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX"); + + /* Set the COPY command specifying the message ID and destination folder */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "COPY 1 FOLDER"); + + /* Note that to perform a move operation you will need to perform the copy, + * then mark the original mail as Deleted and EXPUNGE or CLOSE. Please see + * imap-store.c for more information on deleting messages. */ + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-create.c b/docs/examples/imap-create.c new file mode 100644 index 0000000..6a9b565 --- /dev/null +++ b/docs/examples/imap-create.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Create a new IMAP folder + * + */ + +#include +#include + +/* This is a simple example showing how to create a new mailbox folder using + * libcurl's IMAP capabilities. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com"); + + /* Set the CREATE command specifying the new folder name */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "CREATE FOLDER"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-delete.c b/docs/examples/imap-delete.c new file mode 100644 index 0000000..e43ab2e --- /dev/null +++ b/docs/examples/imap-delete.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Delete an IMAP folder + * + */ + +#include +#include + +/* This is a simple example showing how to delete an existing mailbox folder + * using libcurl's IMAP capabilities. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com"); + + /* Set the DELETE command specifying the existing folder */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE FOLDER"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-examine.c b/docs/examples/imap-examine.c new file mode 100644 index 0000000..34217bf --- /dev/null +++ b/docs/examples/imap-examine.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Obtain information about an IMAP folder + * + */ + +#include +#include + +/* This is a simple example showing how to obtain information about a mailbox + * folder using libcurl's IMAP capabilities via the EXAMINE command. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com"); + + /* Set the EXAMINE command specifying the mailbox folder */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "EXAMINE OUTBOX"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-fetch.c b/docs/examples/imap-fetch.c new file mode 100644 index 0000000..3361d7c --- /dev/null +++ b/docs/examples/imap-fetch.c @@ -0,0 +1,67 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Retrieve IMAP emails + * + */ + +#include +#include + +/* This is a simple example showing how to fetch mail using libcurl's IMAP + * capabilities. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will fetch message 1 from the user's inbox */ + curl_easy_setopt(curl, CURLOPT_URL, + "imap://imap.example.com/INBOX/;UID=1"); + + /* Perform the fetch */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-list.c b/docs/examples/imap-list.c new file mode 100644 index 0000000..2f3780f --- /dev/null +++ b/docs/examples/imap-list.c @@ -0,0 +1,68 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * List the folders within an IMAP mailbox + * + */ + +#include +#include + +/* This is a simple example showing how to list the folders within an IMAP + * mailbox. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will list the folders within the user's mailbox. If you want to + * list the folders within a specific folder, for example the inbox, then + * specify the folder as a path in the URL such as /INBOX */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com"); + + /* Perform the list */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-lsub.c b/docs/examples/imap-lsub.c new file mode 100644 index 0000000..cf45a5f --- /dev/null +++ b/docs/examples/imap-lsub.c @@ -0,0 +1,70 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * List the subscribed IMAP folders + * + */ + +#include +#include + +/* This is a simple example showing how to list the subscribed folders within + * an IMAP mailbox. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com"); + + /* Set the LSUB command. Note the syntax is similar to that of a LIST + command. */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "LSUB \"\" *"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-multi.c b/docs/examples/imap-multi.c new file mode 100644 index 0000000..6a5f4b0 --- /dev/null +++ b/docs/examples/imap-multi.c @@ -0,0 +1,83 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Get IMAP email with the multi interface + * + */ + +#include +#include +#include + +/* This is a simple example showing how to fetch mail using libcurl's IMAP + * capabilities. It builds on the imap-fetch.c example to demonstrate how to + * use libcurl's multi interface. + */ + +int main(void) +{ + CURL *curl; + CURLM *mcurl; + int still_running = 1; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(!curl) + return 1; + + mcurl = curl_multi_init(); + if(!mcurl) + return 2; + + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will fetch message 1 from the user's inbox */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX/;UID=1"); + + /* Tell the multi stack about our easy handle */ + curl_multi_add_handle(mcurl, curl); + + do { + CURLMcode mc = curl_multi_perform(mcurl, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); + + if(mc) + break; + } while(still_running); + + /* Always cleanup */ + curl_multi_remove_handle(mcurl, curl); + curl_multi_cleanup(mcurl); + curl_easy_cleanup(curl); + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/imap-noop.c b/docs/examples/imap-noop.c new file mode 100644 index 0000000..9e5a3da --- /dev/null +++ b/docs/examples/imap-noop.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Perform an IMAP noop + * + */ + +#include +#include + +/* This is a simple example showing how to perform a noop using libcurl's IMAP + * capabilities. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com"); + + /* Set the NOOP command */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "NOOP"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-search.c b/docs/examples/imap-search.c new file mode 100644 index 0000000..141b06f --- /dev/null +++ b/docs/examples/imap-search.c @@ -0,0 +1,73 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Search for new IMAP emails + * + */ + +#include +#include + +/* This is a simple example showing how to search for new messages using + * libcurl's IMAP capabilities. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is mailbox folder to select */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX"); + + /* Set the SEARCH command specifying what we want to search for. Note that + * this can contain a message sequence set and a number of search criteria + * keywords including flags such as ANSWERED, DELETED, DRAFT, FLAGGED, NEW, + * RECENT and SEEN. For more information about the search criteria please + * see RFC-3501 section 6.4.4. */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "SEARCH NEW"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-ssl.c b/docs/examples/imap-ssl.c new file mode 100644 index 0000000..e920720 --- /dev/null +++ b/docs/examples/imap-ssl.c @@ -0,0 +1,94 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * IMAP with implicit SSL + * + */ + +#include +#include + +/* This is a simple example showing how to fetch mail using libcurl's IMAP + * capabilities. It builds on the imap-fetch.c example adding transport + * security to protect the authentication details from being snooped. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will fetch message 1 from the user's inbox. Note the use of + * imaps:// rather than imap:// to request a SSL based connection. */ + curl_easy_setopt(curl, CURLOPT_URL, + "imaps://imap.example.com/INBOX/;UID=1"); + + /* If you want to connect to a site who is not using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. */ +#ifdef SKIP_PEER_VERIFICATION + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif + + /* If the site you are connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. */ +#ifdef SKIP_HOSTNAME_VERIFICATION + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + /* Since the traffic will be encrypted, it is useful to turn on debug + * information within libcurl to see what is happening during the + * transfer */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Perform the fetch */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-store.c b/docs/examples/imap-store.c new file mode 100644 index 0000000..d04a607 --- /dev/null +++ b/docs/examples/imap-store.c @@ -0,0 +1,84 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Modify the properties of an email over IMAP + * + */ + +#include +#include + +/* This is a simple example showing how to modify an existing mail using + * libcurl's IMAP capabilities with the STORE command. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is the mailbox folder to select */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX"); + + /* Set the STORE command with the Deleted flag for message 1. Note that + * you can use the STORE command to set other flags such as Seen, Answered, + * Flagged, Draft and Recent. */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "STORE 1 +Flags \\Deleted"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + else { + /* Set the EXPUNGE command, although you can use the CLOSE command if you + * do not want to know the result of the STORE */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "EXPUNGE"); + + /* Perform the second custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/imap-tls.c b/docs/examples/imap-tls.c new file mode 100644 index 0000000..d98f5ef --- /dev/null +++ b/docs/examples/imap-tls.c @@ -0,0 +1,94 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * IMAP using TLS + * + */ + +#include +#include + +/* This is a simple example showing how to fetch mail using libcurl's IMAP + * capabilities. It builds on the imap-fetch.c example adding transport + * security to protect the authentication details from being snooped. + * + * Note that this example requires libcurl 7.30.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will fetch message 1 from the user's inbox */ + curl_easy_setopt(curl, CURLOPT_URL, + "imap://imap.example.com/INBOX/;UID=1"); + + /* In this example, we will start with a plain text connection, and upgrade + * to Transport Layer Security (TLS) using the STARTTLS command. Be careful + * of using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer + * will continue anyway - see the security discussion in the libcurl + * tutorial for more details. */ + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + + /* If your server does not have a valid certificate, then you can disable + * part of the Transport Layer Security protection by setting the + * CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false). + * curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + * curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + * + * That is, in general, a bad idea. It is still better than sending your + * authentication details in plain text though. Instead, you should get + * the issuer certificate (or the host certificate if the certificate is + * self-signed) and add it to the set of certificates that are known to + * libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See docs/SSLCERTS + * for more information. */ + curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem"); + + /* Since the traffic will be encrypted, it is useful to turn on debug + * information within libcurl to see what is happening during the + * transfer */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Perform the fetch */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/interface.c b/docs/examples/interface.c new file mode 100644 index 0000000..f1a2016 --- /dev/null +++ b/docs/examples/interface.c @@ -0,0 +1,52 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use CURLOPT_INTERFACE to bind the outgoing socket to an interface + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* The interface needs to be a local existing interface over which you can + connect to the host in the URL. It can also specify an IP address, but + that address needs to be assigned one of the local network + interfaces. */ + curl_easy_setopt(curl, CURLOPT_INTERFACE, "enp3s0"); + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/ipv6.c b/docs/examples/ipv6.c new file mode 100644 index 0000000..1b69870 --- /dev/null +++ b/docs/examples/ipv6.c @@ -0,0 +1,48 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTPS GET using IPv6 only + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); + + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/keepalive.c b/docs/examples/keepalive.c new file mode 100644 index 0000000..1c876bb --- /dev/null +++ b/docs/examples/keepalive.c @@ -0,0 +1,55 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use the TCP keep-alive options + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* enable TCP keep-alive for this transfer */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); + + /* keep-alive idle time to 120 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L); + + /* interval time between keep-alive probes: 60 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); + + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/localport.c b/docs/examples/localport.c new file mode 100644 index 0000000..56e0b62 --- /dev/null +++ b/docs/examples/localport.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use CURLOPT_LOCALPORT to control local port number + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Try to use a local port number between 20000-20009 */ + curl_easy_setopt(curl, CURLOPT_LOCALPORT, 20000L); + /* 10 means number of attempts, which starts with the number set in + CURLOPT_LOCALPORT. The lowe value set, the smaller the change it will + work. */ + curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, 10L); + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/maxconnects.c b/docs/examples/maxconnects.c new file mode 100644 index 0000000..84fefd7 --- /dev/null +++ b/docs/examples/maxconnects.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) James Fuller, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Set maximum number of persistent connections to 1. + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + const char *urls[] = { "https://example.com", + "https://curl.se", + "https://www.example/", + NULL /* end of list */ + }; + int i = 0; + + /* Change the maximum number of persistent connection */ + curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 1L); + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* loop over the URLs */ + while(urls[i]) { + curl_easy_setopt(curl, CURLOPT_URL, urls[i]); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + i++; + } + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/multi-app.c b/docs/examples/multi-app.c new file mode 100644 index 0000000..3dbc464 --- /dev/null +++ b/docs/examples/multi-app.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * A basic application source code using the multi interface doing two + * transfers in parallel. + * + */ + +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include + +/* + * Download an HTTP file and upload an FTP file simultaneously. + */ + +#define HANDLECOUNT 2 /* Number of simultaneous transfers */ +#define HTTP_HANDLE 0 /* Index for the HTTP transfer */ +#define FTP_HANDLE 1 /* Index for the FTP transfer */ + +int main(void) +{ + CURL *handles[HANDLECOUNT]; + CURLM *multi_handle; + + int still_running = 1; /* keep number of running handles */ + int i; + + CURLMsg *msg; /* for picking up messages with the transfer status */ + int msgs_left; /* how many messages are left */ + + /* Allocate one CURL handle per transfer */ + for(i = 0; imsg == CURLMSG_DONE) { + int idx; + + /* Find out which handle this message is about */ + for(idx = 0; idxeasy_handle == handles[idx]); + if(found) + break; + } + + switch(idx) { + case HTTP_HANDLE: + printf("HTTP transfer completed with status %d\n", msg->data.result); + break; + case FTP_HANDLE: + printf("FTP transfer completed with status %d\n", msg->data.result); + break; + } + } + } + + /* remove the transfers and cleanup the handles */ + for(i = 0; i, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * multi interface and debug callback + * + */ + +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include + +#define TRUE 1 + +static void dump(const char *text, FILE *stream, unsigned char *ptr, + size_t size, char nohex) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s, %10.10lu bytes (0x%8.8lx)\n", + text, (unsigned long)size, (unsigned long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} + +static +int my_trace(CURL *handle, curl_infotype type, + unsigned char *data, size_t size, + void *userp) +{ + const char *text; + + (void)userp; + (void)handle; /* prevent compiler warning */ + + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + return 0; + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + default: /* in case a new one is introduced to shock us */ + return 0; + } + + dump(text, stderr, data, size, TRUE); + return 0; +} + +/* + * Simply download an HTTP file. + */ +int main(void) +{ + CURL *http_handle; + CURLM *multi_handle; + + int still_running = 0; /* keep number of running handles */ + + http_handle = curl_easy_init(); + + /* set the options (I left out a few, you will get the point anyway) */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); + + curl_easy_setopt(http_handle, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1L); + + /* init a multi stack */ + multi_handle = curl_multi_init(); + + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); + + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) + break; + + } while(still_running); + + curl_multi_cleanup(multi_handle); + + curl_easy_cleanup(http_handle); + + return 0; +} diff --git a/docs/examples/multi-double.c b/docs/examples/multi-double.c new file mode 100644 index 0000000..62295a9 --- /dev/null +++ b/docs/examples/multi-double.c @@ -0,0 +1,97 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * multi interface code doing two parallel HTTP transfers + * + */ +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include + +/* + * Simply download two HTTP files! + */ +int main(void) +{ + CURL *http_handle; + CURL *http_handle2; + CURLM *multi_handle; + + int still_running = 1; /* keep number of running handles */ + + http_handle = curl_easy_init(); + http_handle2 = curl_easy_init(); + + /* set options */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); + + /* set options */ + curl_easy_setopt(http_handle2, CURLOPT_URL, "http://localhost/"); + + /* init a multi stack */ + multi_handle = curl_multi_init(); + + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); + curl_multi_add_handle(multi_handle, http_handle2); + + while(still_running) { + CURLMsg *msg; + int queued; + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) + break; + + do { + msg = curl_multi_info_read(multi_handle, &queued); + if(msg) { + if(msg->msg == CURLMSG_DONE) { + /* a transfer ended */ + fprintf(stderr, "Transfer completed\n"); + } + } + } while(msg); + } + + curl_multi_remove_handle(multi_handle, http_handle); + curl_multi_remove_handle(multi_handle, http_handle2); + + curl_multi_cleanup(multi_handle); + + curl_easy_cleanup(http_handle); + curl_easy_cleanup(http_handle2); + + return 0; +} diff --git a/docs/examples/multi-event.c b/docs/examples/multi-event.c new file mode 100644 index 0000000..5a24bb2 --- /dev/null +++ b/docs/examples/multi-event.c @@ -0,0 +1,242 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * multi_socket API using libevent + * + */ + +#include +#include +#include +#include + +struct event_base *base; +CURLM *curl_handle; +struct event *timeout; + +typedef struct curl_context_s { + struct event *event; + curl_socket_t sockfd; +} curl_context_t; + +static void curl_perform(int fd, short event, void *arg); + +static curl_context_t *create_curl_context(curl_socket_t sockfd) +{ + curl_context_t *context; + + context = (curl_context_t *) malloc(sizeof(*context)); + + context->sockfd = sockfd; + + context->event = event_new(base, sockfd, 0, curl_perform, context); + + return context; +} + +static void destroy_curl_context(curl_context_t *context) +{ + event_del(context->event); + event_free(context->event); + free(context); +} + +static void add_download(const char *url, int num) +{ + char filename[50]; + FILE *file; + CURL *handle; + + snprintf(filename, 50, "%d.download", num); + + file = fopen(filename, "wb"); + if(!file) { + fprintf(stderr, "Error opening %s\n", filename); + return; + } + + handle = curl_easy_init(); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); + curl_easy_setopt(handle, CURLOPT_PRIVATE, file); + curl_easy_setopt(handle, CURLOPT_URL, url); + curl_multi_add_handle(curl_handle, handle); + fprintf(stderr, "Added download %s -> %s\n", url, filename); +} + +static void check_multi_info(void) +{ + char *done_url; + CURLMsg *message; + int pending; + CURL *easy_handle; + FILE *file; + + while((message = curl_multi_info_read(curl_handle, &pending))) { + switch(message->msg) { + case CURLMSG_DONE: + /* Do not use message data after calling curl_multi_remove_handle() and + curl_easy_cleanup(). As per curl_multi_info_read() docs: + "WARNING: The data the returned pointer points to will not survive + calling curl_multi_cleanup, curl_multi_remove_handle or + curl_easy_cleanup." */ + easy_handle = message->easy_handle; + + curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url); + curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &file); + printf("%s DONE\n", done_url); + + curl_multi_remove_handle(curl_handle, easy_handle); + curl_easy_cleanup(easy_handle); + if(file) { + fclose(file); + } + break; + + default: + fprintf(stderr, "CURLMSG default\n"); + break; + } + } +} + +static void curl_perform(int fd, short event, void *arg) +{ + int running_handles; + int flags = 0; + curl_context_t *context; + + if(event & EV_READ) + flags |= CURL_CSELECT_IN; + if(event & EV_WRITE) + flags |= CURL_CSELECT_OUT; + + context = (curl_context_t *) arg; + + curl_multi_socket_action(curl_handle, context->sockfd, flags, + &running_handles); + + check_multi_info(); +} + +static void on_timeout(evutil_socket_t fd, short events, void *arg) +{ + int running_handles; + curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, + &running_handles); + check_multi_info(); +} + +static int start_timeout(CURLM *multi, long timeout_ms, void *userp) +{ + if(timeout_ms < 0) { + evtimer_del(timeout); + } + else { + if(timeout_ms == 0) + timeout_ms = 1; /* 0 means directly call socket_action, but we will do it + in a bit */ + struct timeval tv; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + evtimer_del(timeout); + evtimer_add(timeout, &tv); + } + return 0; +} + +static int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, + void *socketp) +{ + curl_context_t *curl_context; + int events = 0; + + switch(action) { + case CURL_POLL_IN: + case CURL_POLL_OUT: + case CURL_POLL_INOUT: + curl_context = socketp ? + (curl_context_t *) socketp : create_curl_context(s); + + curl_multi_assign(curl_handle, s, (void *) curl_context); + + if(action != CURL_POLL_IN) + events |= EV_WRITE; + if(action != CURL_POLL_OUT) + events |= EV_READ; + + events |= EV_PERSIST; + + event_del(curl_context->event); + event_assign(curl_context->event, base, curl_context->sockfd, events, + curl_perform, curl_context); + event_add(curl_context->event, NULL); + + break; + case CURL_POLL_REMOVE: + if(socketp) { + event_del(((curl_context_t*) socketp)->event); + destroy_curl_context((curl_context_t*) socketp); + curl_multi_assign(curl_handle, s, NULL); + } + break; + default: + abort(); + } + + return 0; +} + +int main(int argc, char **argv) +{ + if(argc <= 1) + return 0; + + if(curl_global_init(CURL_GLOBAL_ALL)) { + fprintf(stderr, "Could not init curl\n"); + return 1; + } + + base = event_base_new(); + timeout = evtimer_new(base, on_timeout, NULL); + + curl_handle = curl_multi_init(); + curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); + curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); + + while(argc-- > 1) { + add_download(argv[argc], argc); + } + + event_base_dispatch(base); + + curl_multi_cleanup(curl_handle); + event_free(timeout); + event_base_free(base); + + libevent_global_shutdown(); + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/multi-formadd.c b/docs/examples/multi-formadd.c new file mode 100644 index 0000000..801b61e --- /dev/null +++ b/docs/examples/multi-formadd.c @@ -0,0 +1,115 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * using the multi interface to do a multipart formpost without blocking + * + */ + +/* + * Warning: this example uses the deprecated form api. See "multi-post.c" + * for a similar example using the mime api. + */ + +#include +#include +#include + +#include + +int main(void) +{ + CURL *curl; + + CURLM *multi_handle; + int still_running = 0; + + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + struct curl_slist *headerlist = NULL; + static const char buf[] = "Expect:"; + + /* Fill in the file upload field. This makes libcurl load data from + the given file name when curl_easy_perform() is called. */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "sendfile", + CURLFORM_FILE, "multi-formadd.c", + CURLFORM_END); + + /* Fill in the filename field */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "filename", + CURLFORM_COPYCONTENTS, "multi-formadd.c", + CURLFORM_END); + + /* Fill in the submit field too, even if this is rarely needed */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "submit", + CURLFORM_COPYCONTENTS, "send", + CURLFORM_END); + + curl = curl_easy_init(); + multi_handle = curl_multi_init(); + + /* initialize custom header list (stating that Expect: 100-continue is not + wanted */ + headerlist = curl_slist_append(headerlist, buf); + if(curl && multi_handle) { + + /* what URL that receives this POST */ + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/upload.cgi"); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + + curl_multi_add_handle(multi_handle, curl); + + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) + break; + + } while(still_running); + + curl_multi_cleanup(multi_handle); + + /* always cleanup */ + curl_easy_cleanup(curl); + + /* then cleanup the formpost chain */ + curl_formfree(formpost); + + /* free slist */ + curl_slist_free_all(headerlist); + } + return 0; +} diff --git a/docs/examples/multi-legacy.c b/docs/examples/multi-legacy.c new file mode 100644 index 0000000..f36139f --- /dev/null +++ b/docs/examples/multi-legacy.c @@ -0,0 +1,179 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * A basic application source code using the multi interface doing two + * transfers in parallel without curl_multi_wait/poll. + * + */ + +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include + +/* + * Download an HTTP file and upload an FTP file simultaneously. + */ + +#define HANDLECOUNT 2 /* Number of simultaneous transfers */ +#define HTTP_HANDLE 0 /* Index for the HTTP transfer */ +#define FTP_HANDLE 1 /* Index for the FTP transfer */ + +int main(void) +{ + CURL *handles[HANDLECOUNT]; + CURLM *multi_handle; + + int still_running = 0; /* keep number of running handles */ + int i; + + CURLMsg *msg; /* for picking up messages with the transfer status */ + int msgs_left; /* how many messages are left */ + + /* Allocate one CURL handle per transfer */ + for(i = 0; i= 0) { + timeout.tv_sec = curl_timeo / 1000; + if(timeout.tv_sec > 1) + timeout.tv_sec = 1; + else + timeout.tv_usec = (int)(curl_timeo % 1000) * 1000; + } + + /* get file descriptors from the transfers */ + mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); + + if(mc != CURLM_OK) { + fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); + break; + } + + /* On success the value of maxfd is guaranteed to be >= -1. We call + select(maxfd + 1, ...); specially in case of (maxfd == -1) there are + no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- + to sleep 100ms, which is the minimum suggested value in the + curl_multi_fdset() doc. */ + + if(maxfd == -1) { +#ifdef _WIN32 + Sleep(100); + rc = 0; +#else + /* Portable sleep for platforms other than Windows. */ + struct timeval wait = { 0, 100 * 1000 }; /* 100ms */ + rc = select(0, NULL, NULL, NULL, &wait); +#endif + } + else { + /* Note that on some platforms 'timeout' may be modified by select(). + If you need access to the original value save a copy beforehand. */ + rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); + } + + switch(rc) { + case -1: + /* select error */ + break; + case 0: /* timeout */ + default: /* action */ + curl_multi_perform(multi_handle, &still_running); + break; + } + } + + /* See how the transfers went */ + while((msg = curl_multi_info_read(multi_handle, &msgs_left))) { + if(msg->msg == CURLMSG_DONE) { + int idx; + + /* Find out which handle this message is about */ + for(idx = 0; idxeasy_handle == handles[idx]); + if(found) + break; + } + + switch(idx) { + case HTTP_HANDLE: + printf("HTTP transfer completed with status %d\n", msg->data.result); + break; + case FTP_HANDLE: + printf("FTP transfer completed with status %d\n", msg->data.result); + break; + } + } + } + + curl_multi_cleanup(multi_handle); + + /* Free the CURL handles */ + for(i = 0; i, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * using the multi interface to do a multipart formpost without blocking + * + */ + +#include +#include +#include + +#include + +int main(void) +{ + CURL *curl; + + CURLM *multi_handle; + int still_running = 0; + + curl_mime *form = NULL; + curl_mimepart *field = NULL; + struct curl_slist *headerlist = NULL; + static const char buf[] = "Expect:"; + + curl = curl_easy_init(); + multi_handle = curl_multi_init(); + + if(curl && multi_handle) { + /* Create the form */ + form = curl_mime_init(curl); + + /* Fill in the file upload field */ + field = curl_mime_addpart(form); + curl_mime_name(field, "sendfile"); + curl_mime_filedata(field, "multi-post.c"); + + /* Fill in the filename field */ + field = curl_mime_addpart(form); + curl_mime_name(field, "filename"); + curl_mime_data(field, "multi-post.c", CURL_ZERO_TERMINATED); + + /* Fill in the submit field too, even if this is rarely needed */ + field = curl_mime_addpart(form); + curl_mime_name(field, "submit"); + curl_mime_data(field, "send", CURL_ZERO_TERMINATED); + + /* initialize custom header list (stating that Expect: 100-continue is not + wanted */ + headerlist = curl_slist_append(headerlist, buf); + + /* what URL that receives this POST */ + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/upload.cgi"); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + curl_easy_setopt(curl, CURLOPT_MIMEPOST, form); + + curl_multi_add_handle(multi_handle, curl); + + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) + break; + } while(still_running); + + curl_multi_cleanup(multi_handle); + + /* always cleanup */ + curl_easy_cleanup(curl); + + /* then cleanup the form */ + curl_mime_free(form); + + /* free slist */ + curl_slist_free_all(headerlist); + } + return 0; +} diff --git a/docs/examples/multi-single.c b/docs/examples/multi-single.c new file mode 100644 index 0000000..c593362 --- /dev/null +++ b/docs/examples/multi-single.c @@ -0,0 +1,84 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * using the multi interface to do a single download + * + */ + +#include +#include + +/* somewhat unix-specific */ +#include +#include + +/* curl stuff */ +#include + +/* + * Simply download an HTTP file. + */ +int main(void) +{ + CURL *http_handle; + CURLM *multi_handle; + int still_running = 1; /* keep number of running handles */ + + curl_global_init(CURL_GLOBAL_DEFAULT); + + http_handle = curl_easy_init(); + + /* set the options (I left out a few, you will get the point anyway) */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); + + /* init a multi stack */ + multi_handle = curl_multi_init(); + + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); + + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + + if(!mc) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) { + fprintf(stderr, "curl_multi_poll() failed, code %d.\n", (int)mc); + break; + } + + } while(still_running); + + curl_multi_remove_handle(multi_handle, http_handle); + + curl_easy_cleanup(http_handle); + + curl_multi_cleanup(multi_handle); + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c new file mode 100644 index 0000000..6581b9f --- /dev/null +++ b/docs/examples/multi-uv.c @@ -0,0 +1,237 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * multi_socket API using libuv + * + */ +/* Example application using the multi socket interface to download multiple + files in parallel, powered by libuv. + + Requires libuv and (of course) libcurl. + + See https://nikhilm.github.io/uvbook/ for more information on libuv. +*/ + +#include +#include +#include +#include + +uv_loop_t *loop; +CURLM *curl_handle; +uv_timer_t timeout; + +typedef struct curl_context_s { + uv_poll_t poll_handle; + curl_socket_t sockfd; +} curl_context_t; + +static curl_context_t *create_curl_context(curl_socket_t sockfd) +{ + curl_context_t *context; + + context = (curl_context_t *) malloc(sizeof(*context)); + + context->sockfd = sockfd; + + uv_poll_init_socket(loop, &context->poll_handle, sockfd); + context->poll_handle.data = context; + + return context; +} + +static void curl_close_cb(uv_handle_t *handle) +{ + curl_context_t *context = (curl_context_t *) handle->data; + free(context); +} + +static void destroy_curl_context(curl_context_t *context) +{ + uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb); +} + +static void add_download(const char *url, int num) +{ + char filename[50]; + FILE *file; + CURL *handle; + + snprintf(filename, 50, "%d.download", num); + + file = fopen(filename, "wb"); + if(!file) { + fprintf(stderr, "Error opening %s\n", filename); + return; + } + + handle = curl_easy_init(); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); + curl_easy_setopt(handle, CURLOPT_PRIVATE, file); + curl_easy_setopt(handle, CURLOPT_URL, url); + curl_multi_add_handle(curl_handle, handle); + fprintf(stderr, "Added download %s -> %s\n", url, filename); +} + +static void check_multi_info(void) +{ + char *done_url; + CURLMsg *message; + int pending; + CURL *easy_handle; + FILE *file; + + while((message = curl_multi_info_read(curl_handle, &pending))) { + switch(message->msg) { + case CURLMSG_DONE: + /* Do not use message data after calling curl_multi_remove_handle() and + curl_easy_cleanup(). As per curl_multi_info_read() docs: + "WARNING: The data the returned pointer points to will not survive + calling curl_multi_cleanup, curl_multi_remove_handle or + curl_easy_cleanup." */ + easy_handle = message->easy_handle; + + curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url); + curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &file); + printf("%s DONE\n", done_url); + + curl_multi_remove_handle(curl_handle, easy_handle); + curl_easy_cleanup(easy_handle); + if(file) { + fclose(file); + } + break; + + default: + fprintf(stderr, "CURLMSG default\n"); + break; + } + } +} + +static void curl_perform(uv_poll_t *req, int status, int events) +{ + int running_handles; + int flags = 0; + curl_context_t *context; + + if(events & UV_READABLE) + flags |= CURL_CSELECT_IN; + if(events & UV_WRITABLE) + flags |= CURL_CSELECT_OUT; + + context = (curl_context_t *) req->data; + + curl_multi_socket_action(curl_handle, context->sockfd, flags, + &running_handles); + + check_multi_info(); +} + +static void on_timeout(uv_timer_t *req) +{ + int running_handles; + curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, + &running_handles); + check_multi_info(); +} + +static int start_timeout(CURLM *multi, long timeout_ms, void *userp) +{ + if(timeout_ms < 0) { + uv_timer_stop(&timeout); + } + else { + if(timeout_ms == 0) + timeout_ms = 1; /* 0 means directly call socket_action, but we will do it + in a bit */ + uv_timer_start(&timeout, on_timeout, timeout_ms, 0); + } + return 0; +} + +static int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, + void *socketp) +{ + curl_context_t *curl_context; + int events = 0; + + switch(action) { + case CURL_POLL_IN: + case CURL_POLL_OUT: + case CURL_POLL_INOUT: + curl_context = socketp ? + (curl_context_t *) socketp : create_curl_context(s); + + curl_multi_assign(curl_handle, s, (void *) curl_context); + + if(action != CURL_POLL_IN) + events |= UV_WRITABLE; + if(action != CURL_POLL_OUT) + events |= UV_READABLE; + + uv_poll_start(&curl_context->poll_handle, events, curl_perform); + break; + case CURL_POLL_REMOVE: + if(socketp) { + uv_poll_stop(&((curl_context_t*)socketp)->poll_handle); + destroy_curl_context((curl_context_t*) socketp); + curl_multi_assign(curl_handle, s, NULL); + } + break; + default: + abort(); + } + + return 0; +} + +int main(int argc, char **argv) +{ + loop = uv_default_loop(); + + if(argc <= 1) + return 0; + + if(curl_global_init(CURL_GLOBAL_ALL)) { + fprintf(stderr, "Could not init curl\n"); + return 1; + } + + uv_timer_init(loop, &timeout); + + curl_handle = curl_multi_init(); + curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); + curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); + + while(argc-- > 1) { + add_download(argv[argc], argc); + } + + uv_run(loop, UV_RUN_DEFAULT); + curl_multi_cleanup(curl_handle); + + return 0; +} diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c new file mode 100644 index 0000000..cc4ce7c --- /dev/null +++ b/docs/examples/multithread.c @@ -0,0 +1,96 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * A multi-threaded program using pthreads to fetch several files at once + * + */ + +#include +#include +#include + +#define NUMT 4 + +/* + List of URLs to fetch. + + If you intend to use a SSL-based protocol here you might need to setup TLS + library mutex callbacks as described here: + + https://curl.se/libcurl/c/threadsafe.html + +*/ +const char * const urls[NUMT]= { + "https://curl.se/", + "ftp://example.com/", + "https://example.net/", + "www.example" +}; + +static void *pull_one_url(void *url) +{ + CURL *curl; + + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_perform(curl); /* ignores error */ + curl_easy_cleanup(curl); + + return NULL; +} + + +/* + int pthread_create(pthread_t *new_thread_ID, + const pthread_attr_t *attr, + void * (*start_func)(void *), void *arg); +*/ + +int main(int argc, char **argv) +{ + pthread_t tid[NUMT]; + int i; + + /* Must initialize libcurl before any threads are started */ + curl_global_init(CURL_GLOBAL_ALL); + + for(i = 0; i< NUMT; i++) { + int error = pthread_create(&tid[i], + NULL, /* default attributes please */ + pull_one_url, + (void *)urls[i]); + if(0 != error) + fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); + else + fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]); + } + + /* now wait for all threads to terminate */ + for(i = 0; i< NUMT; i++) { + pthread_join(tid[i], NULL); + fprintf(stderr, "Thread %d terminated\n", i); + } + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/netrc.c b/docs/examples/netrc.c new file mode 100644 index 0000000..42e1b63 --- /dev/null +++ b/docs/examples/netrc.c @@ -0,0 +1,49 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use credentials from .netrc + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); + curl_easy_setopt(curl, CURLOPT_NETRC_FILE, + "/home/daniel/s3cr3ts.txt"); + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/parseurl.c b/docs/examples/parseurl.c new file mode 100644 index 0000000..688336f --- /dev/null +++ b/docs/examples/parseurl.c @@ -0,0 +1,80 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Basic URL API use. + * + */ +#include +#include + +#if !CURL_AT_LEAST_VERSION(7, 62, 0) +#error "this example requires curl 7.62.0 or later" +#endif + +int main(void) +{ + CURLU *h; + CURLUcode uc; + char *host; + char *path; + + h = curl_url(); /* get a handle to work with */ + if(!h) + return 1; + + /* parse a full URL */ + uc = curl_url_set(h, CURLUPART_URL, "http://example.com/path/index.html", 0); + if(uc) + goto fail; + + /* extract host name from the parsed URL */ + uc = curl_url_get(h, CURLUPART_HOST, &host, 0); + if(!uc) { + printf("Host name: %s\n", host); + curl_free(host); + } + + /* extract the path from the parsed URL */ + uc = curl_url_get(h, CURLUPART_PATH, &path, 0); + if(!uc) { + printf("Path: %s\n", path); + curl_free(path); + } + + /* redirect with a relative URL */ + uc = curl_url_set(h, CURLUPART_URL, "../another/second.html", 0); + if(uc) + goto fail; + + /* extract the new, updated path */ + uc = curl_url_get(h, CURLUPART_PATH, &path, 0); + if(!uc) { + printf("Path: %s\n", path); + curl_free(path); + } + +fail: + curl_url_cleanup(h); /* free url handle */ + return 0; +} diff --git a/docs/examples/persistent.c b/docs/examples/persistent.c new file mode 100644 index 0000000..51bd8c3 --- /dev/null +++ b/docs/examples/persistent.c @@ -0,0 +1,70 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * reusing handles to do HTTP persistent connections + * + */ +#include +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_HEADER, 1L); + + /* get the first document */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* get another document from the same server using the same + connection */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/docs/"); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + return 0; +} diff --git a/docs/examples/pop3-authzid.c b/docs/examples/pop3-authzid.c new file mode 100644 index 0000000..a948e95 --- /dev/null +++ b/docs/examples/pop3-authzid.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Retrieve emails from a shared POP3 mailbox + * + */ + +#include +#include + +/* This is a simple example showing how to retrieve mail using libcurl's POP3 + * capabilities. + * + * Note that this example requires libcurl 7.66.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set the username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* Set the authorization identity (identity to act as) */ + curl_easy_setopt(curl, CURLOPT_SASL_AUTHZID, "shared-mailbox"); + + /* Force PLAIN authentication */ + curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, "AUTH=PLAIN"); + + /* This will retrieve message 1 from the user's mailbox */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com/1"); + + /* Perform the retr */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-dele.c b/docs/examples/pop3-dele.c new file mode 100644 index 0000000..fe3795c --- /dev/null +++ b/docs/examples/pop3-dele.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Delete POP3 emails + * + */ + +#include +#include + +/* This is a simple example showing how to delete an existing mail using + * libcurl's POP3 capabilities. + * + * Note that this example requires libcurl 7.26.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* You can specify the message either in the URL or DELE command */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com/1"); + + /* Set the DELE command */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELE"); + + /* Do not perform a transfer as DELE returns no data */ + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-list.c b/docs/examples/pop3-list.c new file mode 100644 index 0000000..2e8b3ba --- /dev/null +++ b/docs/examples/pop3-list.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * List the contents of a POP3 mailbox + * + */ + +#include +#include + +/* This is a simple example using libcurl's POP3 capabilities to list the + * contents of a mailbox. + * + * Note that this example requires libcurl 7.20.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will list every message of the given mailbox */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com"); + + /* Perform the list */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-multi.c b/docs/examples/pop3-multi.c new file mode 100644 index 0000000..b4fad19 --- /dev/null +++ b/docs/examples/pop3-multi.c @@ -0,0 +1,84 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Get POP3 email using the multi interface + * + */ + +#include +#include +#include + +/* This is a simple example showing how to retrieve mail using libcurl's POP3 + * capabilities. It builds on the pop3-retr.c example to demonstrate how to use + * libcurl's multi interface. + */ + +int main(void) +{ + CURL *curl; + CURLM *mcurl; + int still_running = 1; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(!curl) + return 1; + + mcurl = curl_multi_init(); + if(!mcurl) + return 2; + + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will retrieve message 1 from the user's mailbox */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com/1"); + + /* Tell the multi stack about our easy handle */ + curl_multi_add_handle(mcurl, curl); + + do { + CURLMcode mc = curl_multi_perform(mcurl, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); + + if(mc) + break; + + } while(still_running); + + /* Always cleanup */ + curl_multi_remove_handle(mcurl, curl); + curl_multi_cleanup(mcurl); + curl_easy_cleanup(curl); + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/pop3-noop.c b/docs/examples/pop3-noop.c new file mode 100644 index 0000000..16181d2 --- /dev/null +++ b/docs/examples/pop3-noop.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Perform a POP3 noop + * + */ + +#include +#include + +/* This is a simple example showing how to perform a noop using libcurl's POP3 + * capabilities. + * + * Note that this example requires libcurl 7.26.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com"); + + /* Set the NOOP command */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "NOOP"); + + /* Do not perform a transfer as NOOP returns no data */ + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-retr.c b/docs/examples/pop3-retr.c new file mode 100644 index 0000000..4940e07 --- /dev/null +++ b/docs/examples/pop3-retr.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Retrieve POP3 email + * + */ + +#include +#include + +/* This is a simple example showing how to retrieve mail using libcurl's POP3 + * capabilities. + * + * Note that this example requires libcurl 7.20.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will retrieve message 1 from the user's mailbox */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com/1"); + + /* Perform the retr */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-ssl.c b/docs/examples/pop3-ssl.c new file mode 100644 index 0000000..e72cf6f --- /dev/null +++ b/docs/examples/pop3-ssl.c @@ -0,0 +1,93 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Get POP3 email using implicit SSL + * + */ + +#include +#include + +/* This is a simple example showing how to retrieve mail using libcurl's POP3 + * capabilities. It builds on the pop3-retr.c example adding transport + * security to protect the authentication details from being snooped. + * + * Note that this example requires libcurl 7.20.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will retrieve message 1 from the user's mailbox. Note the use of + * pop3s:// rather than pop3:// to request a SSL based connection. */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3s://pop.example.com/1"); + + /* If you want to connect to a site who is not using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. */ +#ifdef SKIP_PEER_VERIFICATION + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif + + /* If the site you are connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. */ +#ifdef SKIP_HOSTNAME_VERIFICATION + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + /* Since the traffic will be encrypted, it is useful to turn on debug + * information within libcurl to see what is happening during the + * transfer */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Perform the retr */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-stat.c b/docs/examples/pop3-stat.c new file mode 100644 index 0000000..419859b --- /dev/null +++ b/docs/examples/pop3-stat.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Obtain POP3 message statistics + * + */ + +#include +#include + +/* This is a simple example showing how to obtain message statistics using + * libcurl's POP3 capabilities. + * + * Note that this example requires libcurl 7.26.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com"); + + /* Set the STAT command */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "STAT"); + + /* Do not perform a transfer as the data is in the response */ + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-tls.c b/docs/examples/pop3-tls.c new file mode 100644 index 0000000..04e6e3b --- /dev/null +++ b/docs/examples/pop3-tls.c @@ -0,0 +1,93 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * POP3 using TLS + * + */ + +#include +#include + +/* This is a simple example showing how to retrieve mail using libcurl's POP3 + * capabilities. It builds on the pop3-retr.c example adding transport + * security to protect the authentication details from being snooped. + * + * Note that this example requires libcurl 7.20.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This will retrieve message 1 from the user's mailbox */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com/1"); + + /* In this example, we will start with a plain text connection, and upgrade + * to Transport Layer Security (TLS) using the STLS command. Be careful of + * using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer + * will continue anyway - see the security discussion in the libcurl + * tutorial for more details. */ + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + + /* If your server does not have a valid certificate, then you can disable + * part of the Transport Layer Security protection by setting the + * CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false). + * curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + * curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + * + * That is, in general, a bad idea. It is still better than sending your + * authentication details in plain text though. Instead, you should get + * the issuer certificate (or the host certificate if the certificate is + * self-signed) and add it to the set of certificates that are known to + * libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See docs/SSLCERTS + * for more information. */ + curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem"); + + /* Since the traffic will be encrypted, it is useful to turn on debug + * information within libcurl to see what is happening during the + * transfer */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Perform the retr */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-top.c b/docs/examples/pop3-top.c new file mode 100644 index 0000000..7ceba88 --- /dev/null +++ b/docs/examples/pop3-top.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * POP3 example showing how to retrieve only the headers of an email + * + */ + +#include +#include + +/* This is a simple example showing how to retrieve only the headers of a mail + * using libcurl's POP3 capabilities. + * + * Note that this example requires libcurl 7.26.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com"); + + /* Set the TOP command for message 1 to only include the headers */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "TOP 1 0"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/pop3-uidl.c b/docs/examples/pop3-uidl.c new file mode 100644 index 0000000..496e5b0 --- /dev/null +++ b/docs/examples/pop3-uidl.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * List the contents of a POP3 mailbox by unique ID + * + */ + +#include +#include + +/* This is a simple example using libcurl's POP3 capabilities to list the + * contents of a mailbox by unique ID. + * + * Note that this example requires libcurl 7.26.0 or above. + */ + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is just the server URL */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com"); + + /* Set the UIDL command */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "UIDL"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/post-callback.c b/docs/examples/post-callback.c new file mode 100644 index 0000000..a802c35 --- /dev/null +++ b/docs/examples/post-callback.c @@ -0,0 +1,156 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Issue an HTTP POST and provide the data through the read callback. + * + */ +#include +#include +#include + +/* silly test data to POST */ +static const char data[]="Lorem ipsum dolor sit amet, consectetur adipiscing " + "elit. Sed vel urna neque. Ut quis leo metus. Quisque eleifend, ex at " + "laoreet rhoncus, odio ipsum semper metus, at tempus ante urna in mauris. " + "Suspendisse ornare tempor venenatis. Ut dui neque, pellentesque a varius " + "eget, mattis vitae ligula. Fusce ut pharetra est. Ut ullamcorper mi ac " + "sollicitudin semper. Praesent sit amet tellus varius, posuere nulla non, " + "rhoncus ipsum."; + +struct WriteThis { + const char *readptr; + size_t sizeleft; +}; + +static size_t read_callback(char *dest, size_t size, size_t nmemb, void *userp) +{ + struct WriteThis *wt = (struct WriteThis *)userp; + size_t buffer_size = size*nmemb; + + if(wt->sizeleft) { + /* copy as much as possible from the source to the destination */ + size_t copy_this_much = wt->sizeleft; + if(copy_this_much > buffer_size) + copy_this_much = buffer_size; + memcpy(dest, wt->readptr, copy_this_much); + + wt->readptr += copy_this_much; + wt->sizeleft -= copy_this_much; + return copy_this_much; /* we copied this many bytes */ + } + + return 0; /* no more data left to deliver */ +} + +int main(void) +{ + CURL *curl; + CURLcode res; + + struct WriteThis wt; + + wt.readptr = data; + wt.sizeleft = strlen(data); + + /* In windows, this will init the winsock stuff */ + res = curl_global_init(CURL_GLOBAL_DEFAULT); + /* Check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed: %s\n", + curl_easy_strerror(res)); + return 1; + } + + /* get a curl handle */ + curl = curl_easy_init(); + if(curl) { + /* First set the URL that is about to receive our POST. */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/index.cgi"); + + /* Now specify we want to POST data */ + curl_easy_setopt(curl, CURLOPT_POST, 1L); + + /* we want to use our own read function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + + /* pointer to pass to our read function */ + curl_easy_setopt(curl, CURLOPT_READDATA, &wt); + + /* get verbose debug output please */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* + If you use POST to an HTTP 1.1 server, you can send data without knowing + the size before starting the POST if you use chunked encoding. You + enable this by adding a header like "Transfer-Encoding: chunked" with + CURLOPT_HTTPHEADER. With HTTP 1.0 or without chunked transfer, you must + specify the size in the request. + */ +#ifdef USE_CHUNKED + { + struct curl_slist *chunk = NULL; + + chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked"); + res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + /* use curl_slist_free_all() after the *perform() call to free this + list again */ + } +#else + /* Set the expected POST size. If you want to POST large amounts of data, + consider CURLOPT_POSTFIELDSIZE_LARGE */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)wt.sizeleft); +#endif + +#ifdef DISABLE_EXPECT + /* + Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" + header. You can disable this header with CURLOPT_HTTPHEADER as usual. + NOTE: if you want chunked transfer too, you need to combine these two + since you can only set one list of headers with CURLOPT_HTTPHEADER. */ + + /* A less good option would be to enforce HTTP 1.0, but that might also + have other implications. */ + { + struct curl_slist *chunk = NULL; + + chunk = curl_slist_append(chunk, "Expect:"); + res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + /* use curl_slist_free_all() after the *perform() call to free this + list again */ + } +#endif + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/postinmemory.c b/docs/examples/postinmemory.c new file mode 100644 index 0000000..1610ad5 --- /dev/null +++ b/docs/examples/postinmemory.c @@ -0,0 +1,114 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Make an HTTP POST with data from memory and receive response in memory. + * + */ +#include +#include +#include +#include + +struct MemoryStruct { + char *memory; + size_t size; +}; + +static size_t +WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)userp; + + char *ptr = realloc(mem->memory, mem->size + realsize + 1); + if(!ptr) { + /* out of memory! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + struct MemoryStruct chunk; + static const char *postthis = "Field=1&Field=2&Field=3"; + + chunk.memory = malloc(1); /* will be grown as needed by realloc above */ + chunk.size = 0; /* no data at this point */ + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.org/"); + + /* send all data to this function */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); + + /* some servers do not like requests that are made without a user-agent + field, so we provide one */ + curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis); + + /* if we do not provide POSTFIELDSIZE, libcurl will strlen() by + itself */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis)); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + else { + /* + * Now, our chunk.memory points to a memory block that is chunk.size + * bytes big and contains the remote file. + * + * Do something nice with it! + */ + printf("%s\n",chunk.memory); + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + free(chunk.memory); + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/postit2-formadd.c b/docs/examples/postit2-formadd.c new file mode 100644 index 0000000..27761fc --- /dev/null +++ b/docs/examples/postit2-formadd.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP Multipart formpost with file upload and two additional parts. + * + */ + +/* + * Example code that uploads a file name 'foo' to a remote script that accepts + * "HTML form based" (as described in RFC 1738) uploads using HTTP POST. + * + * Warning: this example uses the deprecated form api. See "postit2.c" + * for a similar example using the mime api. + * + * The imaginary form we will fill in looks like: + * + * + * Enter file: + * Enter file name: + * + * + */ + +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + CURL *curl; + CURLcode res; + + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + struct curl_slist *headerlist = NULL; + static const char buf[] = "Expect:"; + + curl_global_init(CURL_GLOBAL_ALL); + + /* Fill in the file upload field */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "sendfile", + CURLFORM_FILE, "postit2-formadd.c", + CURLFORM_END); + + /* Fill in the filename field */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "filename", + CURLFORM_COPYCONTENTS, "postit2-formadd.c", + CURLFORM_END); + + + /* Fill in the submit field too, even if this is rarely needed */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "submit", + CURLFORM_COPYCONTENTS, "send", + CURLFORM_END); + + curl = curl_easy_init(); + /* initialize custom header list (stating that Expect: 100-continue is not + wanted */ + headerlist = curl_slist_append(headerlist, buf); + if(curl) { + /* what URL that receives this POST */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/examplepost.cgi"); + if((argc == 2) && (!strcmp(argv[1], "noexpectheader"))) + /* only disable 100-continue header if explicitly requested */ + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + + /* then cleanup the formpost chain */ + curl_formfree(formpost); + /* free slist */ + curl_slist_free_all(headerlist); + } + return 0; +} diff --git a/docs/examples/postit2.c b/docs/examples/postit2.c new file mode 100644 index 0000000..a1fb12b --- /dev/null +++ b/docs/examples/postit2.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * HTTP Multipart formpost with file upload and two additional parts. + * + */ +/* Example code that uploads a file name 'foo' to a remote script that accepts + * "HTML form based" (as described in RFC 1738) uploads using HTTP POST. + * + * The imaginary form we will fill in looks like: + * + *
+ * Enter file: + * Enter file name: + * + *
+ * + */ + +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + CURL *curl; + CURLcode res; + + curl_mime *form = NULL; + curl_mimepart *field = NULL; + struct curl_slist *headerlist = NULL; + static const char buf[] = "Expect:"; + + curl_global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if(curl) { + /* Create the form */ + form = curl_mime_init(curl); + + /* Fill in the file upload field */ + field = curl_mime_addpart(form); + curl_mime_name(field, "sendfile"); + curl_mime_filedata(field, "postit2.c"); + + /* Fill in the filename field */ + field = curl_mime_addpart(form); + curl_mime_name(field, "filename"); + curl_mime_data(field, "postit2.c", CURL_ZERO_TERMINATED); + + /* Fill in the submit field too, even if this is rarely needed */ + field = curl_mime_addpart(form); + curl_mime_name(field, "submit"); + curl_mime_data(field, "send", CURL_ZERO_TERMINATED); + + /* initialize custom header list (stating that Expect: 100-continue is not + wanted */ + headerlist = curl_slist_append(headerlist, buf); + /* what URL that receives this POST */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/examplepost.cgi"); + if((argc == 2) && (!strcmp(argv[1], "noexpectheader"))) + /* only disable 100-continue header if explicitly requested */ + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + curl_easy_setopt(curl, CURLOPT_MIMEPOST, form); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + + /* then cleanup the form */ + curl_mime_free(form); + /* free slist */ + curl_slist_free_all(headerlist); + } + return 0; +} diff --git a/docs/examples/progressfunc.c b/docs/examples/progressfunc.c new file mode 100644 index 0000000..e164f03 --- /dev/null +++ b/docs/examples/progressfunc.c @@ -0,0 +1,97 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use the progress callbacks, old and/or new one depending on available + * libcurl version. + * + */ +#include +#include + +#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 3000000 +#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES 6000 + +struct myprogress { + curl_off_t lastruntime; /* type depends on version, see above */ + CURL *curl; +}; + +/* this is how the CURLOPT_XFERINFOFUNCTION callback works */ +static int xferinfo(void *p, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + struct myprogress *myp = (struct myprogress *)p; + CURL *curl = myp->curl; + curl_off_t curtime = 0; + + curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &curtime); + + /* under certain circumstances it may be desirable for certain functionality + to only run every N seconds, in order to do this the transaction time can + be used */ + if((curtime - myp->lastruntime) >= MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL) { + myp->lastruntime = curtime; + fprintf(stderr, "TOTAL TIME: %lu.%06lu\r\n", + (unsigned long)(curtime / 1000000), + (unsigned long)(curtime % 1000000)); + } + + fprintf(stderr, "UP: %lu of %lu DOWN: %lu of %lu\r\n", + (unsigned long)ulnow, (unsigned long)ultotal, + (unsigned long)dlnow, (unsigned long)dltotal); + + if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES) + return 1; + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + struct myprogress prog; + + curl = curl_easy_init(); + if(curl) { + prog.lastruntime = 0; + prog.curl = curl; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo); + /* pass the struct pointer into the xferinfo function */ + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog); + + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + res = curl_easy_perform(curl); + + if(res != CURLE_OK) + fprintf(stderr, "%s\n", curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return (int)res; +} diff --git a/docs/examples/protofeats.c b/docs/examples/protofeats.c new file mode 100644 index 0000000..3e76221 --- /dev/null +++ b/docs/examples/protofeats.c @@ -0,0 +1,52 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Outputs all protocols and features supported + * + */ +#include +#include + +#if !CURL_AT_LEAST_VERSION(7,87,0) +#error "too old libcurl" +#endif + +int main(void) +{ + curl_version_info_data *ver; + const char *const *ptr; + + curl_global_init(CURL_GLOBAL_ALL); + + ver = curl_version_info(CURLVERSION_NOW); + printf("Protocols:\n"); + for(ptr = ver->protocols; *ptr; ++ptr) + printf(" %s\n", *ptr); + printf("Features:\n"); + for(ptr = ver->feature_names; *ptr; ++ptr) + printf(" %s\n", *ptr); + + curl_global_cleanup(); + return 0; +} diff --git a/docs/examples/range.c b/docs/examples/range.c new file mode 100644 index 0000000..1a93f36 --- /dev/null +++ b/docs/examples/range.c @@ -0,0 +1,45 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * GET a range only of a HTTP resource + * + */ +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + curl_easy_setopt(curl, CURLOPT_RANGE, "200-999"); + + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/resolve.c b/docs/examples/resolve.c new file mode 100644 index 0000000..a16f459 --- /dev/null +++ b/docs/examples/resolve.c @@ -0,0 +1,58 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use CURLOPT_RESOLVE to feed custom IP addresses for given host name + port + * number combinations. + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + /* Each single name resolve string should be written using the format + HOST:PORT:ADDRESS where HOST is the name libcurl will try to resolve, + PORT is the port number of the service where libcurl wants to connect to + the HOST and ADDRESS is the numerical IP address + */ + struct curl_slist *host = curl_slist_append(NULL, + "example.com:443:127.0.0.1"); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_RESOLVE, host); + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + curl_slist_free_all(host); + + return (int)res; +} diff --git a/docs/examples/rtsp-options.c b/docs/examples/rtsp-options.c new file mode 100644 index 0000000..e4a6230 --- /dev/null +++ b/docs/examples/rtsp-options.c @@ -0,0 +1,55 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Very simple RTSP request sending OPTIONS. + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); + + curl_easy_setopt(curl, CURLOPT_RTSP_SESSION_ID, "12345"); + + curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/sendrecv.c b/docs/examples/sendrecv.c new file mode 100644 index 0000000..eabe0c2 --- /dev/null +++ b/docs/examples/sendrecv.c @@ -0,0 +1,173 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Demonstrate curl_easy_send() and curl_easy_recv() usage. + * + */ + +#include +#include +#include + +/* Auxiliary function that waits on the socket. */ +static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms) +{ + struct timeval tv; + fd_set infd, outfd, errfd; + int res; + + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (int)(timeout_ms % 1000) * 1000; + + FD_ZERO(&infd); + FD_ZERO(&outfd); + FD_ZERO(&errfd); + +/* Avoid this warning with pre-2020 Cygwin/MSYS releases: + * warning: conversion to 'long unsigned int' from 'curl_socket_t' {aka 'int'} + * may change the sign of the result [-Wsign-conversion] + */ +#if defined(__GNUC__) && defined(__CYGWIN__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + FD_SET(sockfd, &errfd); /* always check for error */ + + if(for_recv) { + FD_SET(sockfd, &infd); + } + else { + FD_SET(sockfd, &outfd); + } +#if defined(__GNUC__) && defined(__CYGWIN__) +#pragma GCC diagnostic pop +#endif + + /* select() returns the number of signalled sockets or -1 */ + res = select((int)sockfd + 1, &infd, &outfd, &errfd, &tv); + return res; +} + +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); + + /* A general note of caution here: if you are using curl_easy_recv() or + curl_easy_send() to implement HTTP or _any_ other protocol libcurl + supports "natively", you are doing it wrong and you should stop. + + This example uses HTTP only to show how to use this API, it does not + suggest that writing an application doing this is sensible. + */ + + curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_socket_t sockfd; + size_t nsent_total = 0; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* Do not do the transfer - only connect to host */ + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); + res = curl_easy_perform(curl); + + if(res != CURLE_OK) { + printf("Error: %s\n", curl_easy_strerror(res)); + return 1; + } + + /* Extract the socket from the curl handle - we will need it for + waiting. */ + res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd); + + if(res != CURLE_OK) { + printf("Error: %s\n", curl_easy_strerror(res)); + return 1; + } + + printf("Sending request.\n"); + + do { + /* Warning: This example program may loop indefinitely. + * A production-quality program must define a timeout and exit this loop + * as soon as the timeout has expired. */ + size_t nsent; + do { + nsent = 0; + res = curl_easy_send(curl, request + nsent_total, + request_len - nsent_total, &nsent); + nsent_total += nsent; + + if(res == CURLE_AGAIN && !wait_on_socket(sockfd, 0, 60000L)) { + printf("Error: timeout.\n"); + return 1; + } + } while(res == CURLE_AGAIN); + + if(res != CURLE_OK) { + printf("Error: %s\n", curl_easy_strerror(res)); + return 1; + } + + printf("Sent %lu bytes.\n", (unsigned long)nsent); + + } while(nsent_total < request_len); + + printf("Reading response.\n"); + + for(;;) { + /* Warning: This example program may loop indefinitely (see above). */ + char buf[1024]; + size_t nread; + do { + nread = 0; + res = curl_easy_recv(curl, buf, sizeof(buf), &nread); + + if(res == CURLE_AGAIN && !wait_on_socket(sockfd, 1, 60000L)) { + printf("Error: timeout.\n"); + return 1; + } + } while(res == CURLE_AGAIN); + + if(res != CURLE_OK) { + printf("Error: %s\n", curl_easy_strerror(res)); + break; + } + + if(nread == 0) { + /* end of the response */ + break; + } + + printf("Received %lu bytes.\n", (unsigned long)nread); + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/sepheaders.c b/docs/examples/sepheaders.c new file mode 100644 index 0000000..0d090ed --- /dev/null +++ b/docs/examples/sepheaders.c @@ -0,0 +1,96 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Simple HTTP GET that stores the headers in a separate file + * + */ +#include +#include +#include + +#include + +static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); + return written; +} + +int main(void) +{ + CURL *curl_handle; + static const char *headerfilename = "head.out"; + FILE *headerfile; + static const char *bodyfilename = "body.out"; + FILE *bodyfile; + + curl_global_init(CURL_GLOBAL_ALL); + + /* init the curl session */ + curl_handle = curl_easy_init(); + + /* set URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, "https://example.com"); + + /* no progress meter please */ + curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); + + /* open the header file */ + headerfile = fopen(headerfilename, "wb"); + if(!headerfile) { + curl_easy_cleanup(curl_handle); + return -1; + } + + /* open the body file */ + bodyfile = fopen(bodyfilename, "wb"); + if(!bodyfile) { + curl_easy_cleanup(curl_handle); + fclose(headerfile); + return -1; + } + + /* we want the headers be written to this file handle */ + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, headerfile); + + /* we want the body be written to this file handle instead of stdout */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bodyfile); + + /* get it! */ + curl_easy_perform(curl_handle); + + /* close the header file */ + fclose(headerfile); + + /* close the body file */ + fclose(bodyfile); + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + return 0; +} diff --git a/docs/examples/sessioninfo.c b/docs/examples/sessioninfo.c new file mode 100644 index 0000000..befb8f3 --- /dev/null +++ b/docs/examples/sessioninfo.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Uses the CURLINFO_TLS_SESSION data. + * + */ + +/* Note that this example currently requires curl to be linked against + GnuTLS (and this program must also be linked against -lgnutls). */ + +#include + +#include +#include +#include + +static CURL *curl; + +static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) +{ + const struct curl_tlssessioninfo *info; + unsigned int cert_list_size; + const gnutls_datum_t *chainp; + CURLcode res; + + (void)stream; + (void)ptr; + + res = curl_easy_getinfo(curl, CURLINFO_TLS_SESSION, &info); + + if(!res) { + switch(info->backend) { + case CURLSSLBACKEND_GNUTLS: + /* info->internals is now the gnutls_session_t */ + chainp = gnutls_certificate_get_peers(info->internals, &cert_list_size); + if((chainp) && (cert_list_size)) { + unsigned int i; + + for(i = 0; i < cert_list_size; i++) { + gnutls_x509_crt_t cert; + gnutls_datum_t dn; + + if(GNUTLS_E_SUCCESS == gnutls_x509_crt_init(&cert)) { + if(GNUTLS_E_SUCCESS == + gnutls_x509_crt_import(cert, &chainp[i], GNUTLS_X509_FMT_DER)) { + if(GNUTLS_E_SUCCESS == + gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &dn)) { + fprintf(stderr, "Certificate #%u: %.*s", i, dn.size, dn.data); + + gnutls_free(dn.data); + } + } + + gnutls_x509_crt_deinit(cert); + } + } + } + break; + case CURLSSLBACKEND_NONE: + default: + break; + } + } + + return size * nmemb; +} + +int main(void) +{ + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, wrfu); + + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); + + (void) curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/sftpget.c b/docs/examples/sftpget.c new file mode 100644 index 0000000..992d607 --- /dev/null +++ b/docs/examples/sftpget.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Gets a file using an SFTP URL. + * + */ + +#include + +#include + +/* define this to switch off the use of ssh-agent in this program */ +#undef DISABLE_SSH_AGENT + +/* + * This is an example showing how to get a single file from an SFTP server. + * It delays the actual destination file creation until the first write + * callback so that it will not create an empty file in case the remote file + * does not exist or something else fails. + */ + +struct FtpFile { + const char *filename; + FILE *stream; +}; + +static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, + void *stream) +{ + struct FtpFile *out = (struct FtpFile *)stream; + if(!out->stream) { + /* open file for writing */ + out->stream = fopen(out->filename, "wb"); + if(!out->stream) + return 0; /* failure, cannot open file to write */ + } + return fwrite(buffer, size, nmemb, out->stream); +} + + +int main(void) +{ + CURL *curl; + CURLcode res; + struct FtpFile ftpfile = { + "yourfile.bin", /* name to store the file as if successful */ + NULL + }; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + /* + * You better replace the URL with one that works! + */ + curl_easy_setopt(curl, CURLOPT_URL, + "sftp://user@server/home/user/file.txt"); + /* Define our callback to get called when there is data to be written */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); + /* Set a pointer to our struct to pass to the callback */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); + +#ifndef DISABLE_SSH_AGENT + /* We activate ssh agent. For this to work you need + to have ssh-agent running (type set | grep SSH_AGENT to check) or + pageant on Windows (there is an icon in systray if so) */ + curl_easy_setopt(curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_AGENT); +#endif + + /* Switch on full protocol/debug output */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + + if(CURLE_OK != res) { + /* we failed */ + fprintf(stderr, "curl told us %d\n", res); + } + } + + if(ftpfile.stream) + fclose(ftpfile.stream); /* close the local file */ + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/sftpuploadresume.c b/docs/examples/sftpuploadresume.c new file mode 100644 index 0000000..aabe5c3 --- /dev/null +++ b/docs/examples/sftpuploadresume.c @@ -0,0 +1,137 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Upload to SFTP, resuming a previously aborted transfer. + * + */ + +#include +#include +#include + +/* read data to upload */ +static size_t readfunc(char *ptr, size_t size, size_t nmemb, void *stream) +{ + FILE *f = (FILE *)stream; + size_t n; + + if(ferror(f)) + return CURL_READFUNC_ABORT; + + n = fread(ptr, size, nmemb, f) * size; + + return n; +} + +/* + * sftpGetRemoteFileSize returns the remote file size in byte; -1 on error + */ +static curl_off_t sftpGetRemoteFileSize(const char *i_remoteFile) +{ + CURLcode result = CURLE_GOT_NOTHING; + curl_off_t remoteFileSizeByte = -1; + CURL *curlHandlePtr = curl_easy_init(); + + curl_easy_setopt(curlHandlePtr, CURLOPT_VERBOSE, 1L); + + curl_easy_setopt(curlHandlePtr, CURLOPT_URL, i_remoteFile); + curl_easy_setopt(curlHandlePtr, CURLOPT_NOPROGRESS, 1); + curl_easy_setopt(curlHandlePtr, CURLOPT_NOBODY, 1); + curl_easy_setopt(curlHandlePtr, CURLOPT_HEADER, 1); + curl_easy_setopt(curlHandlePtr, CURLOPT_FILETIME, 1); + + result = curl_easy_perform(curlHandlePtr); + if(CURLE_OK == result) { + result = curl_easy_getinfo(curlHandlePtr, + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, + &remoteFileSizeByte); + if(result) + return -1; + printf("filesize: %lu\n", (unsigned long)remoteFileSizeByte); + } + curl_easy_cleanup(curlHandlePtr); + + return remoteFileSizeByte; +} + + +static int sftpResumeUpload(CURL *curlhandle, const char *remotepath, + const char *localpath) +{ + FILE *f = NULL; + CURLcode result = CURLE_GOT_NOTHING; + + curl_off_t remoteFileSizeByte = sftpGetRemoteFileSize(remotepath); + if(-1 == remoteFileSizeByte) { + printf("Error reading the remote file size: unable to resume upload\n"); + return -1; + } + + f = fopen(localpath, "rb"); + if(!f) { + perror(NULL); + return 0; + } + + curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath); + curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc); + curl_easy_setopt(curlhandle, CURLOPT_READDATA, f); + +#ifdef _WIN32 + _fseeki64(f, remoteFileSizeByte, SEEK_SET); +#else + fseek(f, (long)remoteFileSizeByte, SEEK_SET); +#endif + curl_easy_setopt(curlhandle, CURLOPT_APPEND, 1L); + result = curl_easy_perform(curlhandle); + + fclose(f); + + if(result == CURLE_OK) + return 1; + else { + fprintf(stderr, "%s\n", curl_easy_strerror(result)); + return 0; + } +} + +int main(void) +{ + const char *remote = "sftp://user:pass@example.com/path/filename"; + const char *filename = "filename"; + CURL *curlhandle = NULL; + + curl_global_init(CURL_GLOBAL_ALL); + curlhandle = curl_easy_init(); + + if(!sftpResumeUpload(curlhandle, remote, filename)) { + printf("resumed upload using curl %s failed\n", curl_version()); + } + + curl_easy_cleanup(curlhandle); + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/shared-connection-cache.c b/docs/examples/shared-connection-cache.c new file mode 100644 index 0000000..26bfb1a --- /dev/null +++ b/docs/examples/shared-connection-cache.c @@ -0,0 +1,87 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Connection cache shared between easy handles with the share interface + * + */ +#include +#include + +static void my_lock(CURL *handle, curl_lock_data data, + curl_lock_access laccess, void *useptr) +{ + (void)handle; + (void)data; + (void)laccess; + (void)useptr; + fprintf(stderr, "-> Mutex lock\n"); +} + +static void my_unlock(CURL *handle, curl_lock_data data, void *useptr) +{ + (void)handle; + (void)data; + (void)useptr; + fprintf(stderr, "<- Mutex unlock\n"); +} + +int main(void) +{ + CURLSH *share; + int i; + + share = curl_share_init(); + curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); + + curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock); + curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock); + + /* Loop the transfer and cleanup the handle properly every lap. This will + still reuse connections since the pool is in the shared object! */ + + for(i = 0; i < 3; i++) { + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + + curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); + + /* use the share object */ + curl_easy_setopt(curl, CURLOPT_SHARE, share); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + } + + curl_share_cleanup(share); + return 0; +} diff --git a/docs/examples/simple.c b/docs/examples/simple.c new file mode 100644 index 0000000..8579b0b --- /dev/null +++ b/docs/examples/simple.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Very simple HTTP GET + * + */ +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/simplepost.c b/docs/examples/simplepost.c new file mode 100644 index 0000000..89435af --- /dev/null +++ b/docs/examples/simplepost.c @@ -0,0 +1,59 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Very simple HTTP POST + * + */ +#include +#include +#include + +int main(void) +{ + CURL *curl; + CURLcode res; + + static const char *postthis = "moo mooo moo moo"; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis); + + /* if we do not provide POSTFIELDSIZE, libcurl will strlen() by + itself */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis)); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/simplessl.c b/docs/examples/simplessl.c new file mode 100644 index 0000000..9d933ce --- /dev/null +++ b/docs/examples/simplessl.c @@ -0,0 +1,143 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Shows HTTPS usage with client certs and optional ssl engine use. + * + */ +#include + +#include + +/* some requirements for this to work: + 1. set pCertFile to the file with the client certificate + 2. if the key is passphrase protected, set pPassphrase to the + passphrase you use + 3. if you are using a crypto engine: + 3.1. set a #define USE_ENGINE + 3.2. set pEngine to the name of the crypto engine you use + 3.3. set pKeyName to the key identifier you want to use + 4. if you do not use a crypto engine: + 4.1. set pKeyName to the file name of your client key + 4.2. if the format of the key file is DER, set pKeyType to "DER" + + !! verify of the server certificate is not implemented here !! + + **** This example only works with libcurl 7.9.3 and later! **** + +*/ + +int main(void) +{ + CURL *curl; + CURLcode res; + FILE *headerfile; + const char *pPassphrase = NULL; + + static const char *pCertFile = "testcert.pem"; + static const char *pCACertFile = "cacert.pem"; + static const char *pHeaderFile = "dumpit"; + + const char *pKeyName; + const char *pKeyType; + + const char *pEngine; + +#ifdef USE_ENGINE + pKeyName = "rsa_test"; + pKeyType = "ENG"; + pEngine = "chil"; /* for nChiper HSM... */ +#else + pKeyName = "testkey.pem"; + pKeyType = "PEM"; + pEngine = NULL; +#endif + + headerfile = fopen(pHeaderFile, "wb"); + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(curl) { + /* what call to write: */ + curl_easy_setopt(curl, CURLOPT_URL, "HTTPS://your.favourite.ssl.site"); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, headerfile); + + do { /* dummy loop, just to break out from */ + if(pEngine) { + /* use crypto engine */ + if(curl_easy_setopt(curl, CURLOPT_SSLENGINE, pEngine) != CURLE_OK) { + /* load the crypto engine */ + fprintf(stderr, "cannot set crypto engine\n"); + break; + } + if(curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK) { + /* set the crypto engine as default */ + /* only needed for the first time you load + a engine in a curl object... */ + fprintf(stderr, "cannot set crypto engine as default\n"); + break; + } + } + /* cert is stored PEM coded in file... */ + /* since PEM is default, we needn't set it for PEM */ + curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); + + /* set the cert for client authentication */ + curl_easy_setopt(curl, CURLOPT_SSLCERT, pCertFile); + + /* sorry, for engine we must set the passphrase + (if the key has one...) */ + if(pPassphrase) + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, pPassphrase); + + /* if we use a key stored in a crypto engine, + we must set the key type to "ENG" */ + curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, pKeyType); + + /* set the private key (file or ID in engine) */ + curl_easy_setopt(curl, CURLOPT_SSLKEY, pKeyName); + + /* set the file with the certs validating the server */ + curl_easy_setopt(curl, CURLOPT_CAINFO, pCACertFile); + + /* disconnect if we cannot validate server's cert */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* we are done... */ + } while(0); + /* always cleanup */ + curl_easy_cleanup(curl); + } + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/smooth-gtk-thread.c b/docs/examples/smooth-gtk-thread.c new file mode 100644 index 0000000..906660f --- /dev/null +++ b/docs/examples/smooth-gtk-thread.c @@ -0,0 +1,218 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * A multi threaded application that uses a progress bar to show + * status. It uses Gtk+ to make a smooth pulse. + * + */ +/* + * Written by Jud Bishop after studying the other examples provided with + * libcurl. + * + * To compile (on a single line): + * gcc -ggdb `pkg-config --cflags --libs gtk+-2.0` -lcurl -lssl -lcrypto + * -lgthread-2.0 -dl smooth-gtk-thread.c -o smooth-gtk-thread + */ + +#include +#include +#include +#include +#include + +#include + +#define NUMT 4 + +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +int j = 0; +gint num_urls = 9; /* Just make sure this is less than urls[]*/ +const char * const urls[]= { + "90022", + "90023", + "90024", + "90025", + "90026", + "90027", + "90028", + "90029", + "90030" +}; + +size_t write_file(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + return fwrite(ptr, size, nmemb, stream); +} + +static void run_one(gchar *http, int j) +{ + FILE *outfile = fopen(urls[j], "wb"); + CURL *curl; + + curl = curl_easy_init(); + if(curl) { + printf("j = %d\n", j); + + /* Set the URL and transfer type */ + curl_easy_setopt(curl, CURLOPT_URL, http); + + /* Write to the file */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file); + curl_easy_perform(curl); + + fclose(outfile); + curl_easy_cleanup(curl); + } +} + +void *pull_one_url(void *NaN) +{ + /* protect the reading and increasing of 'j' with a mutex */ + pthread_mutex_lock(&lock); + while(j < num_urls) { + int i = j; + j++; + pthread_mutex_unlock(&lock); + http = g_strdup_printf("https://example.com/%s", urls[i]); + if(http) { + run_one(http, i); + g_free(http); + } + pthread_mutex_lock(&lock); + } + pthread_mutex_unlock(&lock); + return NULL; +} + + +gboolean pulse_bar(gpointer data) +{ + gdk_threads_enter(); + gtk_progress_bar_pulse(GTK_PROGRESS_BAR (data)); + gdk_threads_leave(); + + /* Return true so the function will be called again; + * returning false removes this timeout function. + */ + return TRUE; +} + +void *create_thread(void *progress_bar) +{ + pthread_t tid[NUMT]; + int i; + + /* Make sure I do not create more threads than urls. */ + for(i = 0; i < NUMT && i < num_urls ; i++) { + int error = pthread_create(&tid[i], + NULL, /* default attributes please */ + pull_one_url, + NULL); + if(0 != error) + fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); + else + fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]); + } + + /* Wait for all threads to terminate. */ + for(i = 0; i < NUMT && i < num_urls; i++) { + pthread_join(tid[i], NULL); + fprintf(stderr, "Thread %d terminated\n", i); + } + + /* This stops the pulsing if you have it turned on in the progress bar + section */ + g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(progress_bar), + "pulse_id"))); + + /* This destroys the progress bar */ + gtk_widget_destroy(progress_bar); + + /* [Un]Comment this out to kill the program rather than pushing close. */ + /* gtk_main_quit(); */ + + + return NULL; + +} + +static gboolean cb_delete(GtkWidget *window, gpointer data) +{ + gtk_main_quit(); + return FALSE; +} + +int main(int argc, char **argv) +{ + GtkWidget *top_window, *outside_frame, *inside_frame, *progress_bar; + + /* Must initialize libcurl before any threads are started */ + curl_global_init(CURL_GLOBAL_ALL); + + /* Init thread */ + g_thread_init(NULL); + gdk_threads_init(); + gdk_threads_enter(); + + gtk_init(&argc, &argv); + + /* Base window */ + top_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + /* Frame */ + outside_frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(outside_frame), GTK_SHADOW_OUT); + gtk_container_add(GTK_CONTAINER(top_window), outside_frame); + + /* Frame */ + inside_frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(inside_frame), GTK_SHADOW_IN); + gtk_container_set_border_width(GTK_CONTAINER(inside_frame), 5); + gtk_container_add(GTK_CONTAINER(outside_frame), inside_frame); + + /* Progress bar */ + progress_bar = gtk_progress_bar_new(); + gtk_progress_bar_pulse(GTK_PROGRESS_BAR (progress_bar)); + /* Make uniform pulsing */ + gint pulse_ref = g_timeout_add(300, pulse_bar, progress_bar); + g_object_set_data(G_OBJECT(progress_bar), "pulse_id", + GINT_TO_POINTER(pulse_ref)); + gtk_container_add(GTK_CONTAINER(inside_frame), progress_bar); + + gtk_widget_show_all(top_window); + printf("gtk_widget_show_all\n"); + + g_signal_connect(G_OBJECT (top_window), "delete-event", + G_CALLBACK(cb_delete), NULL); + + if(!g_thread_create(&create_thread, progress_bar, FALSE, NULL) != 0) + g_warning("cannot create the thread"); + + gtk_main(); + gdk_threads_leave(); + printf("gdk_threads_leave\n"); + + return 0; +} diff --git a/docs/examples/smtp-authzid.c b/docs/examples/smtp-authzid.c new file mode 100644 index 0000000..dc24d7f --- /dev/null +++ b/docs/examples/smtp-authzid.c @@ -0,0 +1,162 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Send email on behalf of another user with SMTP + * + */ + +#include +#include +#include + +/* + * This is a simple example show how to send an email using libcurl's SMTP + * capabilities. + * + * Note that this example requires libcurl 7.66.0 or above. + */ + +/* The libcurl options want plain addresses, the viewable headers in the mail + * can get a full name as well. + */ +#define FROM_ADDR "" +#define SENDER_ADDR "" +#define TO_ADDR "" + +#define FROM_MAIL "Ursel " FROM_ADDR +#define SENDER_MAIL "Kurt " SENDER_ADDR +#define TO_MAIL "A Receiver " TO_ADDR + +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" + "Sender: " SENDER_MAIL "\r\n" + "Message-ID: \r\n" + "Subject: SMTP example message\r\n" + "\r\n" /* empty line to divide headers from body, see RFC 5322 */ + "The body of the message starts here.\r\n" + "\r\n" + "It could be a lot of lines, could be MIME encoded, whatever.\r\n" + "Check RFC 5322.\r\n"; + +struct upload_status { + size_t bytes_read; +}; + +static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + size_t room = size * nmemb; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = &payload_text[upload_ctx->bytes_read]; + + if(data) { + size_t len = strlen(data); + if(room < len) + len = room; + memcpy(ptr, data, len); + upload_ctx->bytes_read += len; + + return len; + } + + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + + curl = curl_easy_init(); + if(curl) { + /* This is the URL for your mailserver. In this example we connect to the + smtp-submission port as we require an authenticated connection. */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com:587"); + + /* Set the username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "kurt"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "xipj3plmq"); + + /* Set the authorization identity (identity to act as) */ + curl_easy_setopt(curl, CURLOPT_SASL_AUTHZID, "ursel"); + + /* Force PLAIN authentication */ + curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, "AUTH=PLAIN"); + + /* Note that this option is not strictly required, omitting it will result + * in libcurl sending the MAIL FROM command with empty sender data. All + * autoresponses should have an empty reverse-path, and should be directed + * to the address in the reverse-path which triggered them. Otherwise, + * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more + * details. + */ + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_ADDR); + + /* Add a recipient, in this particular case it corresponds to the + * To: addressee in the header. */ + recipients = curl_slist_append(recipients, TO_ADDR); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* We are using a callback function to specify the payload (the headers and + * body of the message). You could just use the CURLOPT_READDATA option to + * specify a FILE pointer to read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* Send the message */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* curl will not send the QUIT command until you call cleanup, so you + * should be able to reuse this connection for additional messages + * (setting CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and + * calling curl_easy_perform() again. It may not be a good idea to keep + * the connection open for a long time though (more than a few minutes may + * result in the server timing out the connection), and you do want to + * clean up in the end. + */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/smtp-expn.c b/docs/examples/smtp-expn.c new file mode 100644 index 0000000..e61b6b4 --- /dev/null +++ b/docs/examples/smtp-expn.c @@ -0,0 +1,81 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Expand an SMTP email mailing list + * + */ + +#include +#include +#include + +/* This is a simple example showing how to expand an email mailing list. + * + * Notes: + * + * 1) This example requires libcurl 7.34.0 or above. + * 2) Not all email servers support this command. + */ + +int main(void) +{ + CURL *curl; + CURLcode res; + struct curl_slist *recipients = NULL; + + curl = curl_easy_init(); + if(curl) { + /* This is the URL for your mailserver */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); + + /* Note that the CURLOPT_MAIL_RCPT takes a list, not a char array */ + recipients = curl_slist_append(recipients, "Friends"); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* Set the EXPN command */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "EXPN"); + + /* Perform the custom request */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* curl will not send the QUIT command until you call cleanup, so you + * should be able to reuse this connection for additional requests. It may + * not be a good idea to keep the connection open for a long time though + * (more than a few minutes may result in the server timing out the + * connection) and you do want to clean up in the end. + */ + curl_easy_cleanup(curl); + } + + return 0; +} diff --git a/docs/examples/smtp-mail.c b/docs/examples/smtp-mail.c new file mode 100644 index 0000000..7427878 --- /dev/null +++ b/docs/examples/smtp-mail.c @@ -0,0 +1,150 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Send email with SMTP + * + */ + +#include +#include +#include + +/* + * For an SMTP example using the multi interface please see smtp-multi.c. + */ + +/* The libcurl options want plain addresses, the viewable headers in the mail + * can get a full name as well. + */ +#define FROM_ADDR "" +#define TO_ADDR "" +#define CC_ADDR "" + +#define FROM_MAIL "Sender Person " FROM_ADDR +#define TO_MAIL "A Receiver " TO_ADDR +#define CC_MAIL "John CC Smith " CC_ADDR + +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" + "Cc: " CC_MAIL "\r\n" + "Message-ID: \r\n" + "Subject: SMTP example message\r\n" + "\r\n" /* empty line to divide headers from body, see RFC 5322 */ + "The body of the message starts here.\r\n" + "\r\n" + "It could be a lot of lines, could be MIME encoded, whatever.\r\n" + "Check RFC 5322.\r\n"; + +struct upload_status { + size_t bytes_read; +}; + +static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + size_t room = size * nmemb; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = &payload_text[upload_ctx->bytes_read]; + + if(data) { + size_t len = strlen(data); + if(room < len) + len = room; + memcpy(ptr, data, len); + upload_ctx->bytes_read += len; + + return len; + } + + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + + curl = curl_easy_init(); + if(curl) { + /* This is the URL for your mailserver */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); + + /* Note that this option is not strictly required, omitting it will result + * in libcurl sending the MAIL FROM command with empty sender data. All + * autoresponses should have an empty reverse-path, and should be directed + * to the address in the reverse-path which triggered them. Otherwise, + * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more + * details. + */ + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_ADDR); + + /* Add two recipients, in this particular case they correspond to the + * To: and Cc: addressees in the header, but they could be any kind of + * recipient. */ + recipients = curl_slist_append(recipients, TO_ADDR); + recipients = curl_slist_append(recipients, CC_ADDR); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* We are using a callback function to specify the payload (the headers and + * body of the message). You could just use the CURLOPT_READDATA option to + * specify a FILE pointer to read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* Send the message */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* curl will not send the QUIT command until you call cleanup, so you + * should be able to reuse this connection for additional messages + * (setting CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and + * calling curl_easy_perform() again. It may not be a good idea to keep + * the connection open for a long time though (more than a few minutes may + * result in the server timing out the connection), and you do want to + * clean up in the end. + */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/smtp-mime.c b/docs/examples/smtp-mime.c new file mode 100644 index 0000000..36703a1 --- /dev/null +++ b/docs/examples/smtp-mime.c @@ -0,0 +1,168 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Send SMTP mime emails + * + */ + +#include +#include +#include + +/* This is a simple example showing how to send mime mail using libcurl's SMTP + * capabilities. For an example of using the multi interface please see + * smtp-multi.c. + * + * Note that this example requires libcurl 7.56.0 or above. + */ + +#define FROM "" +#define TO "" +#define CC "" + +static const char *headers_text[] = { + "Date: Tue, 22 Aug 2017 14:08:43 +0100", + "To: " TO, + "From: " FROM " (Example User)", + "Cc: " CC " (Another example User)", + "Message-ID: ", + "Subject: example sending a MIME-formatted message", + NULL +}; + +static const char inline_text[] = + "This is the inline text message of the email.\r\n" + "\r\n" + " It could be a lot of lines that would be displayed in an email\r\n" + "viewer that is not able to handle HTML.\r\n"; + +static const char inline_html[] = + "\r\n" + "

This is the inline HTML message of the email.

" + "
\r\n" + "

It could be a lot of HTML data that would be displayed by " + "email viewers able to handle HTML.

" + "\r\n"; + + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + curl = curl_easy_init(); + if(curl) { + struct curl_slist *headers = NULL; + struct curl_slist *recipients = NULL; + struct curl_slist *slist = NULL; + curl_mime *mime; + curl_mime *alt; + curl_mimepart *part; + const char **cpp; + + /* This is the URL for your mailserver */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); + + /* Note that this option is not strictly required, omitting it will result + * in libcurl sending the MAIL FROM command with empty sender data. All + * autoresponses should have an empty reverse-path, and should be directed + * to the address in the reverse-path which triggered them. Otherwise, + * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more + * details. + */ + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM); + + /* Add two recipients, in this particular case they correspond to the + * To: and Cc: addressees in the header, but they could be any kind of + * recipient. */ + recipients = curl_slist_append(recipients, TO); + recipients = curl_slist_append(recipients, CC); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* allow one of the recipients to fail and still consider it okay */ + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT_ALLOWFAILS, 1L); + + /* Build and set the message header list. */ + for(cpp = headers_text; *cpp; cpp++) + headers = curl_slist_append(headers, *cpp); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + /* Build the mime message. */ + mime = curl_mime_init(curl); + + /* The inline part is an alternative proposing the html and the text + versions of the email. */ + alt = curl_mime_init(curl); + + /* HTML message. */ + part = curl_mime_addpart(alt); + curl_mime_data(part, inline_html, CURL_ZERO_TERMINATED); + curl_mime_type(part, "text/html"); + + /* Text message. */ + part = curl_mime_addpart(alt); + curl_mime_data(part, inline_text, CURL_ZERO_TERMINATED); + + /* Create the inline part. */ + part = curl_mime_addpart(mime); + curl_mime_subparts(part, alt); + curl_mime_type(part, "multipart/alternative"); + slist = curl_slist_append(NULL, "Content-Disposition: inline"); + curl_mime_headers(part, slist, 1); + + /* Add the current source program as an attachment. */ + part = curl_mime_addpart(mime); + curl_mime_filedata(part, "smtp-mime.c"); + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); + + /* Send the message */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Free lists. */ + curl_slist_free_all(recipients); + curl_slist_free_all(headers); + + /* curl will not send the QUIT command until you call cleanup, so you + * should be able to reuse this connection for additional messages + * (setting CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and + * calling curl_easy_perform() again. It may not be a good idea to keep + * the connection open for a long time though (more than a few minutes may + * result in the server timing out the connection), and you do want to + * clean up in the end. + */ + curl_easy_cleanup(curl); + + /* Free multipart message. */ + curl_mime_free(mime); + } + + return (int)res; +} diff --git a/docs/examples/smtp-multi.c b/docs/examples/smtp-multi.c new file mode 100644 index 0000000..e5bc401 --- /dev/null +++ b/docs/examples/smtp-multi.c @@ -0,0 +1,153 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Send SMTP email with the multi interface + * + */ + +#include +#include + +/* This is an example showing how to send mail using libcurl's SMTP + * capabilities. It builds on the smtp-mail.c example to demonstrate how to use + * libcurl's multi interface. + */ + +#define FROM_MAIL "" +#define TO_MAIL "" +#define CC_MAIL "" + +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" + "Cc: " CC_MAIL "\r\n" + "Message-ID: \r\n" + "Subject: SMTP example message\r\n" + "\r\n" /* empty line to divide headers from body, see RFC 5322 */ + "The body of the message starts here.\r\n" + "\r\n" + "It could be a lot of lines, could be MIME encoded, whatever.\r\n" + "Check RFC 5322.\r\n"; + +struct upload_status { + size_t bytes_read; +}; + +static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + size_t room = size * nmemb; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = &payload_text[upload_ctx->bytes_read]; + + if(data) { + size_t len = strlen(data); + if(room < len) + len = room; + memcpy(ptr, data, len); + upload_ctx->bytes_read += len; + + return len; + } + + return 0; +} + +int main(void) +{ + CURL *curl; + CURLM *mcurl; + int still_running = 1; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + + curl_global_init(CURL_GLOBAL_DEFAULT); + + curl = curl_easy_init(); + if(!curl) + return 1; + + mcurl = curl_multi_init(); + if(!mcurl) + return 2; + + /* This is the URL for your mailserver */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); + + /* Note that this option is not strictly required, omitting it will result in + * libcurl sending the MAIL FROM command with empty sender data. All + * autoresponses should have an empty reverse-path, and should be directed + * to the address in the reverse-path which triggered them. Otherwise, they + * could cause an endless loop. See RFC 5321 Section 4.5.5 for more details. + */ + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_MAIL); + + /* Add two recipients, in this particular case they correspond to the + * To: and Cc: addressees in the header, but they could be any kind of + * recipient. */ + recipients = curl_slist_append(recipients, TO_MAIL); + recipients = curl_slist_append(recipients, CC_MAIL); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* We are using a callback function to specify the payload (the headers and + * body of the message). You could just use the CURLOPT_READDATA option to + * specify a FILE pointer to read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* Tell the multi stack about our easy handle */ + curl_multi_add_handle(mcurl, curl); + + do { + CURLMcode mc = curl_multi_perform(mcurl, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); + + if(mc) + break; + + } while(still_running); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* Always cleanup */ + curl_multi_remove_handle(mcurl, curl); + curl_multi_cleanup(mcurl); + curl_easy_cleanup(curl); + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/smtp-ssl.c b/docs/examples/smtp-ssl.c new file mode 100644 index 0000000..8970840 --- /dev/null +++ b/docs/examples/smtp-ssl.c @@ -0,0 +1,170 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Send SMTP email using implicit SSL + * + */ + +#include +#include +#include + +/* This is a simple example showing how to send mail using libcurl's SMTP + * capabilities. It builds on the smtp-mail.c example to add authentication + * and, more importantly, transport security to protect the authentication + * details from being snooped. + * + * Note that this example requires libcurl 7.20.0 or above. + */ + +#define FROM_MAIL "" +#define TO_MAIL "" +#define CC_MAIL "" + +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" + "Cc: " CC_MAIL "\r\n" + "Message-ID: \r\n" + "Subject: SMTP example message\r\n" + "\r\n" /* empty line to divide headers from body, see RFC 5322 */ + "The body of the message starts here.\r\n" + "\r\n" + "It could be a lot of lines, could be MIME encoded, whatever.\r\n" + "Check RFC 5322.\r\n"; + +struct upload_status { + size_t bytes_read; +}; + +static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + size_t room = size * nmemb; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = &payload_text[upload_ctx->bytes_read]; + + if(data) { + size_t len = strlen(data); + if(room < len) + len = room; + memcpy(ptr, data, len); + upload_ctx->bytes_read += len; + + return len; + } + + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is the URL for your mailserver. Note the use of smtps:// rather + * than smtp:// to request a SSL based connection. */ + curl_easy_setopt(curl, CURLOPT_URL, "smtps://mainserver.example.net"); + + /* If you want to connect to a site who is not using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. */ +#ifdef SKIP_PEER_VERIFICATION + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif + + /* If the site you are connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. */ +#ifdef SKIP_HOSTNAME_VERIFICATION + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + /* Note that this option is not strictly required, omitting it will result + * in libcurl sending the MAIL FROM command with empty sender data. All + * autoresponses should have an empty reverse-path, and should be directed + * to the address in the reverse-path which triggered them. Otherwise, + * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more + * details. + */ + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_MAIL); + + /* Add two recipients, in this particular case they correspond to the + * To: and Cc: addressees in the header, but they could be any kind of + * recipient. */ + recipients = curl_slist_append(recipients, TO_MAIL); + recipients = curl_slist_append(recipients, CC_MAIL); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* We are using a callback function to specify the payload (the headers and + * body of the message). You could just use the CURLOPT_READDATA option to + * specify a FILE pointer to read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* Since the traffic will be encrypted, it is useful to turn on debug + * information within libcurl to see what is happening during the + * transfer */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Send the message */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/smtp-tls.c b/docs/examples/smtp-tls.c new file mode 100644 index 0000000..83aab69 --- /dev/null +++ b/docs/examples/smtp-tls.c @@ -0,0 +1,173 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Send SMTP email using implicit TLS + * + */ + +#include +#include +#include + +/* This is a simple example showing how to send mail using libcurl's SMTP + * capabilities. It builds on the smtp-mail.c example to add authentication + * and, more importantly, transport security to protect the authentication + * details from being snooped. + * + * Note that this example requires libcurl 7.20.0 or above. + */ + +#define FROM_MAIL "" +#define TO_MAIL "" +#define CC_MAIL "" + +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" + "Cc: " CC_MAIL "\r\n" + "Message-ID: \r\n" + "Subject: SMTP example message\r\n" + "\r\n" /* empty line to divide headers from body, see RFC 5322 */ + "The body of the message starts here.\r\n" + "\r\n" + "It could be a lot of lines, could be MIME encoded, whatever.\r\n" + "Check RFC 5322.\r\n"; + +struct upload_status { + size_t bytes_read; +}; + +static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + size_t room = size * nmemb; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = &payload_text[upload_ctx->bytes_read]; + + if(data) { + size_t len = strlen(data); + if(room < len) + len = room; + memcpy(ptr, data, len); + upload_ctx->bytes_read += len; + + return len; + } + + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + + curl = curl_easy_init(); + if(curl) { + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + + /* This is the URL for your mailserver. Note the use of port 587 here, + * instead of the normal SMTP port (25). Port 587 is commonly used for + * secure mail submission (see RFC 4403), but you should use whatever + * matches your server configuration. */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mainserver.example.net:587"); + + /* In this example, we will start with a plain text connection, and upgrade + * to Transport Layer Security (TLS) using the STARTTLS command. Be careful + * of using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer + * will continue anyway - see the security discussion in the libcurl + * tutorial for more details. */ + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + + /* If your server does not have a valid certificate, then you can disable + * part of the Transport Layer Security protection by setting the + * CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false). + * curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + * curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + * That is, in general, a bad idea. It is still better than sending your + * authentication details in plain text though. Instead, you should get + * the issuer certificate (or the host certificate if the certificate is + * self-signed) and add it to the set of certificates that are known to + * libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See docs/SSLCERTS + * for more information. */ + curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem"); + + /* Note that this option is not strictly required, omitting it will result + * in libcurl sending the MAIL FROM command with empty sender data. All + * autoresponses should have an empty reverse-path, and should be directed + * to the address in the reverse-path which triggered them. Otherwise, + * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more + * details. + */ + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_MAIL); + + /* Add two recipients, in this particular case they correspond to the + * To: and Cc: addressees in the header, but they could be any kind of + * recipient. */ + recipients = curl_slist_append(recipients, TO_MAIL); + recipients = curl_slist_append(recipients, CC_MAIL); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* We are using a callback function to specify the payload (the headers and + * body of the message). You could just use the CURLOPT_READDATA option to + * specify a FILE pointer to read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* Since the traffic will be encrypted, it is useful to turn on debug + * information within libcurl to see what is happening during the + * transfer. + */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Send the message */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* Always cleanup */ + curl_easy_cleanup(curl); + } + + return (int)res; +} diff --git a/docs/examples/smtp-vrfy.c b/docs/examples/smtp-vrfy.c new file mode 100644 index 0000000..70da41b --- /dev/null +++ b/docs/examples/smtp-vrfy.c @@ -0,0 +1,81 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Verify an SMTP email address + * + */ + +#include +#include +#include + +/* This is a simple example showing how to verify an email address from an + * SMTP server. + * + * Notes: + * + * 1) This example requires libcurl 7.34.0 or above. + * 2) Not all email servers support this command and even if your email server + * does support it, it may respond with a 252 response code even though the + * address does not exist. + */ + +int main(void) +{ + CURL *curl; + CURLcode res; + struct curl_slist *recipients = NULL; + + curl = curl_easy_init(); + if(curl) { + /* This is the URL for your mailserver */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); + + /* Note that the CURLOPT_MAIL_RCPT takes a list, not a char array */ + recipients = curl_slist_append(recipients, ""); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* Perform the VRFY */ + res = curl_easy_perform(curl); + + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* curl will not send the QUIT command until you call cleanup, so you + * should be able to reuse this connection for additional requests. It may + * not be a good idea to keep the connection open for a long time though + * (more than a few minutes may result in the server timing out the + * connection) and you do want to clean up in the end. + */ + curl_easy_cleanup(curl); + } + + return 0; +} diff --git a/docs/examples/sslbackend.c b/docs/examples/sslbackend.c new file mode 100644 index 0000000..fd2b575 --- /dev/null +++ b/docs/examples/sslbackend.c @@ -0,0 +1,79 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Shows HTTPS usage with client certs and optional ssl engine use. + * + */ +#include +#include +#include +#include +#include + +#include + +/* + * An SSL-enabled libcurl is required for this sample to work (at least one + * SSL backend has to be configured). + * + * **** This example only works with libcurl 7.56.0 and later! **** +*/ + +int main(int argc, char **argv) +{ + const char *name = argc > 1 ? argv[1] : "openssl"; + CURLsslset result; + + if(!strcmp("list", name)) { + const curl_ssl_backend **list; + int i; + + result = curl_global_sslset(CURLSSLBACKEND_NONE, NULL, &list); + assert(result == CURLSSLSET_UNKNOWN_BACKEND); + + for(i = 0; list[i]; i++) + printf("SSL backend #%d: '%s' (ID: %d)\n", + i, list[i]->name, list[i]->id); + + return 0; + } + else if(isdigit((int)(unsigned char)*name)) { + int id = atoi(name); + + result = curl_global_sslset((curl_sslbackend)id, NULL, NULL); + } + else + result = curl_global_sslset(CURLSSLBACKEND_NONE, name, NULL); + + if(result == CURLSSLSET_UNKNOWN_BACKEND) { + fprintf(stderr, "Unknown SSL backend id: %s\n", name); + return 1; + } + + assert(result == CURLSSLSET_OK); + + printf("Version with SSL backend '%s':\n\n\t%s\n", name, curl_version()); + + return 0; +} diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c new file mode 100644 index 0000000..2d7d523 --- /dev/null +++ b/docs/examples/synctime.c @@ -0,0 +1,377 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Set your system time from a remote HTTP server's Date: header. + * + */ +/* This example code only builds as-is on Windows. + * + * While Unix/Linux user, you do not need this software. + * You can achieve the same result as synctime using curl, awk and date. + * Set proxy as according to your network, but beware of proxy Cache-Control. + * + * To set your system clock, root access is required. + * # date -s "`curl -sI https://nist.time.gov/timezone.cgi?UTC/s/0 \ + * | awk -F': ' '/Date: / {print $2}'`" + * + * To view remote webserver date and time. + * $ curl -sI https://nist.time.gov/timezone.cgi?UTC/s/0 \ + * | awk -F': ' '/Date: / {print $2}' + * + * Synchronising your computer clock via Internet time server usually relies + * on DAYTIME, TIME, or NTP protocols. These protocols provide good accurate + * time synchronization but it does not work well through a + * firewall/proxy. Some adjustment has to be made to the firewall/proxy for + * these protocols to work properly. + * + * There is an indirect method. Since most webserver provide server time in + * their HTTP header, therefore you could synchronise your computer clock + * using HTTP protocol which has no problem with firewall/proxy. + * + * For this software to work, you should take note of these items. + * 1. Your firewall/proxy must allow your computer to surf internet. + * 2. Webserver system time must in sync with the NTP time server, + * or at least provide an accurate time keeping. + * 3. Webserver HTTP header does not provide the milliseconds units, + * so there is no way to get an accurate time. + * 4. This software could only provide an accuracy of +- a few seconds, + * as Round-Trip delay time is not taken into consideration. + * Compensation of network, firewall/proxy delay cannot be simply divide + * the Round-Trip delay time by half. + * 5. Win32 SetSystemTime() API will set your computer clock according to + * GMT/UTC time. Therefore your computer timezone must be properly set. + * 6. Webserver data should not be cached by the proxy server. Some + * webserver provide Cache-Control to prevent caching. + * + * References: + * https://web.archive.org/web/20100228012139/ \ + * tf.nist.gov/timefreq/service/its.htm + * https://web.archive.org/web/20100409024302/ \ + * tf.nist.gov/timefreq/service/firewall.htm + * + * Usage: + * This software will synchronise your computer clock only when you issue + * it with --synctime. By default, it only display the webserver's clock. + * + * Written by: Frank (contributed to libcurl) + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL THE AUTHOR OF THIS SOFTWARE BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + */ + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + + +#define MAX_STRING 256 +#define MAX_STRING1 MAX_STRING + 1 + +#define SYNCTIME_UA "synctime/1.0" + +typedef struct +{ + char http_proxy[MAX_STRING1]; + char proxy_user[MAX_STRING1]; + char timeserver[MAX_STRING1]; +} conf_t; + +const char DefaultTimeServer[3][MAX_STRING1] = +{ + "https://nist.time.gov/", + "https://www.google.com/" +}; + +const char *DayStr[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +const char *MthStr[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +int ShowAllHeader; +int AutoSyncTime; +SYSTEMTIME SYSTime; +SYSTEMTIME LOCALTime; + +#define HTTP_COMMAND_HEAD 0 +#define HTTP_COMMAND_GET 1 + + +size_t SyncTime_CURL_WriteOutput(void *ptr, size_t size, size_t nmemb, + void *stream) +{ + fwrite(ptr, size, nmemb, stream); + return (nmemb*size); +} + +size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, + void *stream) +{ + char TmpStr1[26], TmpStr2[26]; + + (void)stream; + + if(ShowAllHeader == 1) + fprintf(stderr, "%s", (char *)(ptr)); + + if(strncmp((char *)(ptr), "Date:", 5) == 0) { + if(ShowAllHeader == 0) + fprintf(stderr, "HTTP Server. %s", (char *)(ptr)); + + if(AutoSyncTime == 1) { + *TmpStr1 = 0; + *TmpStr2 = 0; + if(strlen((char *)(ptr)) > 50) /* Can prevent buffer overflow to + TmpStr1 & 2? */ + AutoSyncTime = 0; + else { + int RetVal = sscanf((char *)(ptr), "Date: %25s %hu %s %hu %hu:%hu:%hu", + TmpStr1, &SYSTime.wDay, TmpStr2, &SYSTime.wYear, + &SYSTime.wHour, &SYSTime.wMinute, + &SYSTime.wSecond); + + if(RetVal == 7) { + int i; + SYSTime.wMilliseconds = 500; /* adjust to midpoint, 0.5 sec */ + for(i = 0; i<12; i++) { + if(strcmp(MthStr[i], TmpStr2) == 0) { + SYSTime.wMonth = i + 1; + break; + } + } + AutoSyncTime = 3; /* Computer clock will be adjusted */ + } + else { + AutoSyncTime = 0; /* Error in sscanf() fields conversion */ + } + } + } + } + + if(strncmp((char *)(ptr), "X-Cache: HIT", 12) == 0) { + fprintf(stderr, "ERROR: HTTP Server data is cached." + " Server Date is no longer valid.\n"); + AutoSyncTime = 0; + } + return (nmemb*size); +} + +void SyncTime_CURL_Init(CURL *curl, char *proxy_port, + char *proxy_user_password) +{ + if(strlen(proxy_port) > 0) + curl_easy_setopt(curl, CURLOPT_PROXY, proxy_port); + + if(strlen(proxy_user_password) > 0) + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user_password); + +#ifdef SYNCTIME_UA + curl_easy_setopt(curl, CURLOPT_USERAGENT, SYNCTIME_UA); +#endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, SyncTime_CURL_WriteOutput); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, SyncTime_CURL_WriteHeader); +} + +int SyncTime_CURL_Fetch(CURL *curl, char *URL_Str, char *OutFileName, + int HttpGetBody) +{ + FILE *outfile; + CURLcode res; + + outfile = NULL; + if(HttpGetBody == HTTP_COMMAND_HEAD) + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + else { + outfile = fopen(OutFileName, "wb"); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile); + } + + curl_easy_setopt(curl, CURLOPT_URL, URL_Str); + res = curl_easy_perform(curl); + if(outfile) + fclose(outfile); + return res; /* (CURLE_OK) */ +} + +void showUsage(void) +{ + fprintf(stderr, "SYNCTIME: Synchronising computer clock with time server" + " using HTTP protocol.\n"); + fprintf(stderr, "Usage : SYNCTIME [Option]\n"); + fprintf(stderr, "Options :\n"); + fprintf(stderr, " --server=WEBSERVER Use this time server instead" + " of default.\n"); + fprintf(stderr, " --showall Show all HTTP header.\n"); + fprintf(stderr, " --synctime Synchronising computer clock" + " with time server.\n"); + fprintf(stderr, " --proxy-user=USER[:PASS] Set proxy username and" + " password.\n"); + fprintf(stderr, " --proxy=HOST[:PORT] Use HTTP proxy on given" + " port.\n"); + fprintf(stderr, " --help Print this help.\n"); + fprintf(stderr, "\n"); + return; +} + +int conf_init(conf_t *conf) +{ + int i; + + *conf->http_proxy = 0; + for(i = 0; iproxy_user[i] = 0; /* Clean up password from memory */ + *conf->timeserver = 0; + return 1; +} + +int main(int argc, char *argv[]) +{ + CURL *curl; + conf_t conf[1]; + int RetValue; + + ShowAllHeader = 0; /* Do not show HTTP Header */ + AutoSyncTime = 0; /* Do not synchronise computer clock */ + RetValue = 0; /* Successful Exit */ + conf_init(conf); + + if(argc > 1) { + int OptionIndex = 0; + while(OptionIndex < argc) { + if(strncmp(argv[OptionIndex], "--server=", 9) == 0) + snprintf(conf->timeserver, MAX_STRING, "%s", &argv[OptionIndex][9]); + + if(strcmp(argv[OptionIndex], "--showall") == 0) + ShowAllHeader = 1; + + if(strcmp(argv[OptionIndex], "--synctime") == 0) + AutoSyncTime = 1; + + if(strncmp(argv[OptionIndex], "--proxy-user=", 13) == 0) + snprintf(conf->proxy_user, MAX_STRING, "%s", &argv[OptionIndex][13]); + + if(strncmp(argv[OptionIndex], "--proxy=", 8) == 0) + snprintf(conf->http_proxy, MAX_STRING, "%s", &argv[OptionIndex][8]); + + if((strcmp(argv[OptionIndex], "--help") == 0) || + (strcmp(argv[OptionIndex], "/?") == 0)) { + showUsage(); + return 0; + } + OptionIndex++; + } + } + + if(*conf->timeserver == 0) /* Use default server for time information */ + snprintf(conf->timeserver, MAX_STRING, "%s", DefaultTimeServer[0]); + + /* Init CURL before usage */ + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if(curl) { + struct tm *lt; + struct tm *gmt; + time_t tt; + time_t tt_local; + time_t tt_gmt; + double tzonediffFloat; + int tzonediffWord; + char timeBuf[61]; + char tzoneBuf[16]; + + SyncTime_CURL_Init(curl, conf->http_proxy, conf->proxy_user); + + /* Calculating time diff between GMT and localtime */ + tt = time(0); + lt = localtime(&tt); + tt_local = mktime(lt); + gmt = gmtime(&tt); + tt_gmt = mktime(gmt); + tzonediffFloat = difftime(tt_local, tt_gmt); + tzonediffWord = (int)(tzonediffFloat/3600.0); + + if((double)(tzonediffWord * 3600) == tzonediffFloat) + snprintf(tzoneBuf, 15, "%+03d'00'", tzonediffWord); + else + snprintf(tzoneBuf, 15, "%+03d'30'", tzonediffWord); + + /* Get current system time and local time */ + GetSystemTime(&SYSTime); + GetLocalTime(&LOCALTime); + snprintf(timeBuf, 60, "%s, %02d %s %04d %02d:%02d:%02d.%03d, ", + DayStr[LOCALTime.wDayOfWeek], LOCALTime.wDay, + MthStr[LOCALTime.wMonth-1], LOCALTime.wYear, + LOCALTime.wHour, LOCALTime.wMinute, LOCALTime.wSecond, + LOCALTime.wMilliseconds); + + fprintf(stderr, "Fetch: %s\n\n", conf->timeserver); + fprintf(stderr, "Before HTTP. Date: %s%s\n\n", timeBuf, tzoneBuf); + + /* HTTP HEAD command to the Webserver */ + SyncTime_CURL_Fetch(curl, conf->timeserver, "index.htm", + HTTP_COMMAND_HEAD); + + GetLocalTime(&LOCALTime); + snprintf(timeBuf, 60, "%s, %02d %s %04d %02d:%02d:%02d.%03d, ", + DayStr[LOCALTime.wDayOfWeek], LOCALTime.wDay, + MthStr[LOCALTime.wMonth-1], LOCALTime.wYear, + LOCALTime.wHour, LOCALTime.wMinute, LOCALTime.wSecond, + LOCALTime.wMilliseconds); + fprintf(stderr, "\nAfter HTTP. Date: %s%s\n", timeBuf, tzoneBuf); + + if(AutoSyncTime == 3) { + /* Synchronising computer clock */ + if(!SetSystemTime(&SYSTime)) { /* Set system time */ + fprintf(stderr, "ERROR: Unable to set system time.\n"); + RetValue = 1; + } + else { + /* Successfully re-adjusted computer clock */ + GetLocalTime(&LOCALTime); + snprintf(timeBuf, 60, "%s, %02d %s %04d %02d:%02d:%02d.%03d, ", + DayStr[LOCALTime.wDayOfWeek], LOCALTime.wDay, + MthStr[LOCALTime.wMonth-1], LOCALTime.wYear, + LOCALTime.wHour, LOCALTime.wMinute, LOCALTime.wSecond, + LOCALTime.wMilliseconds); + fprintf(stderr, "\nNew System's Date: %s%s\n", timeBuf, tzoneBuf); + } + } + + /* Cleanup before exit */ + conf_init(conf); + curl_easy_cleanup(curl); + } + return RetValue; +} diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c new file mode 100644 index 0000000..f58e447 --- /dev/null +++ b/docs/examples/threaded-ssl.c @@ -0,0 +1,168 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Show the required mutex callback setups for GnuTLS and OpenSSL when using + * libcurl multi-threaded. + * + */ +/* A multi-threaded example that uses pthreads and fetches 4 remote files at + * once over HTTPS. The lock callbacks and stuff assume OpenSSL <1.1 or GnuTLS + * (libgcrypt) so far. + * + * OpenSSL docs for this: + * https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_num_locks.html + * gcrypt docs for this: + * https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html + */ + +#define USE_OPENSSL /* or USE_GNUTLS accordingly */ + +#include +#include +#include + +#define NUMT 4 + +/* we have this global to let the callback get easy access to it */ +static pthread_mutex_t *lockarray; + +#ifdef USE_OPENSSL +#include +static void lock_callback(int mode, int type, char *file, int line) +{ + (void)file; + (void)line; + if(mode & CRYPTO_LOCK) { + pthread_mutex_lock(&(lockarray[type])); + } + else { + pthread_mutex_unlock(&(lockarray[type])); + } +} + +static unsigned long thread_id(void) +{ + unsigned long ret; + + ret = (unsigned long)pthread_self(); + return ret; +} + +static void init_locks(void) +{ + int i; + + lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * + sizeof(pthread_mutex_t)); + for(i = 0; i +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +void init_locks(void) +{ + gcry_control(GCRYCTL_SET_THREAD_CBS); +} + +#define kill_locks() +#endif + +/* List of URLs to fetch.*/ +const char * const urls[]= { + "https://www.example.com/", + "https://www2.example.com/", + "https://www3.example.com/", + "https://www4.example.com/", +}; + +static void *pull_one_url(void *url) +{ + CURL *curl; + + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, url); + /* this example does not verify the server's certificate, which means we + might be downloading stuff from an impostor */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_perform(curl); /* ignores error */ + curl_easy_cleanup(curl); + + return NULL; +} + +int main(int argc, char **argv) +{ + pthread_t tid[NUMT]; + int i; + (void)argc; /* we do not use any arguments in this example */ + (void)argv; + + /* Must initialize libcurl before any threads are started */ + curl_global_init(CURL_GLOBAL_ALL); + + init_locks(); + + for(i = 0; i< NUMT; i++) { + int error = pthread_create(&tid[i], + NULL, /* default attributes please */ + pull_one_url, + (void *)urls[i]); + if(0 != error) + fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); + else + fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]); + } + + /* now wait for all threads to terminate */ + for(i = 0; i< NUMT; i++) { + pthread_join(tid[i], NULL); + fprintf(stderr, "Thread %d terminated\n", i); + } + + kill_locks(); + + return 0; +} diff --git a/docs/examples/unixsocket.c b/docs/examples/unixsocket.c new file mode 100644 index 0000000..53c5fd2 --- /dev/null +++ b/docs/examples/unixsocket.c @@ -0,0 +1,67 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Access HTTP server over unix domain socket + * + */ +#include +#include + +#ifdef USE_ABSTRACT +/* + * The abstract socket namespace is a nonportable Linux extension. The name + * has no connection with filesystem pathnames. + */ +#define ABSTRACT "http-unix-domain" +#else +#define PATH "/tmp/http-unix-domain" +#endif + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); + +#ifdef USE_ABSTRACT + curl_easy_setopt(curl, CURLOPT_ABSTRACT_UNIX_SOCKET, ABSTRACT); +#else + curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, PATH); +#endif + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/url2file.c b/docs/examples/url2file.c new file mode 100644 index 0000000..f95d574 --- /dev/null +++ b/docs/examples/url2file.c @@ -0,0 +1,88 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Download a given URL into a local file named page.out. + * + */ +#include +#include +#include + +#include + +static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); + return written; +} + +int main(int argc, char *argv[]) +{ + CURL *curl_handle; + static const char *pagefilename = "page.out"; + FILE *pagefile; + + if(argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + curl_global_init(CURL_GLOBAL_ALL); + + /* init the curl session */ + curl_handle = curl_easy_init(); + + /* set URL to get here */ + curl_easy_setopt(curl_handle, CURLOPT_URL, argv[1]); + + /* Switch on full protocol/debug output while testing */ + curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); + + /* disable progress meter, set to 0L to enable it */ + curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); + + /* open the file */ + pagefile = fopen(pagefilename, "wb"); + if(pagefile) { + + /* write the page body to this file handle */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile); + + /* get it! */ + curl_easy_perform(curl_handle); + + /* close the header file */ + fclose(pagefile); + } + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + curl_global_cleanup(); + + return 0; +} diff --git a/docs/examples/urlapi.c b/docs/examples/urlapi.c new file mode 100644 index 0000000..2ed78eb --- /dev/null +++ b/docs/examples/urlapi.c @@ -0,0 +1,77 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Set working URL with CURLU *. + * + */ +#include +#include + +#if !CURL_AT_LEAST_VERSION(7, 80, 0) +#error "this example requires curl 7.80.0 or later" +#endif + +int main(void) +{ + CURL *curl; + CURLcode res; + + CURLU *urlp; + CURLUcode uc; + + /* get a curl handle */ + curl = curl_easy_init(); + + /* init Curl URL */ + urlp = curl_url(); + uc = curl_url_set(urlp, CURLUPART_URL, + "http://example.com/path/index.html", 0); + + if(uc) { + fprintf(stderr, "curl_url_set() failed: %s", curl_url_strerror(uc)); + goto cleanup; + } + + if(curl) { + /* set urlp to use as working URL */ + curl_easy_setopt(curl, CURLOPT_CURLU, urlp); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* only allow HTTP, TFTP and SFTP */ + curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,tftp,sftp"); + + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + goto cleanup; + } + +cleanup: + curl_url_cleanup(urlp); + curl_easy_cleanup(curl); + return 0; +} diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c new file mode 100644 index 0000000..12a2b79 --- /dev/null +++ b/docs/examples/usercertinmem.c @@ -0,0 +1,228 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Use an in-memory user certificate and RSA key and retrieve an https page. + * + */ +/* Written by Ishan SinghLevett, based on Theo Borm's cacertinmem.c. + * Note that to maintain simplicity this example does not use a CA certificate + * for peer verification. However, some form of peer verification + * must be used in real circumstances when a secure connection is required. + */ + +#include +#include +#include +#include +#include + +static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) +{ + fwrite(ptr, size, nmemb, stream); + return (nmemb*size); +} + +static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) +{ + X509 *cert = NULL; + BIO *bio = NULL; + BIO *kbio = NULL; + RSA *rsa = NULL; + int ret; + + const char *mypem = /* www.cacert.org */ + "-----BEGIN CERTIFICATE-----\n"\ + "MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n"\ + "IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n"\ + "IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n"\ + "Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n"\ + "BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi\n"\ + "MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ\n"\ + "ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\n"\ + "CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ\n"\ + "8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6\n"\ + "zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y\n"\ + "fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7\n"\ + "w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc\n"\ + "G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k\n"\ + "epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q\n"\ + "laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ\n"\ + "QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU\n"\ + "fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826\n"\ + "YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w\n"\ + "ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY\n"\ + "gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe\n"\ + "MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0\n"\ + "IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy\n"\ + "dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw\n"\ + "czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0\n"\ + "dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl\n"\ + "aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC\n"\ + "AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg\n"\ + "b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB\n"\ + "ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc\n"\ + "nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg\n"\ + "18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c\n"\ + "gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl\n"\ + "Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY\n"\ + "sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T\n"\ + "SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF\n"\ + "CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum\n"\ + "GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n"\ + "zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n"\ + "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n"\ + "-----END CERTIFICATE-----\n"; + +/* replace the XXX with the actual RSA key */ + const char *mykey = + "-----BEGIN RSA PRIVATE KEY-----\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ + "-----END RSA PRIVATE KEY-----\n"; + + (void)curl; /* avoid warnings */ + (void)parm; /* avoid warnings */ + + /* get a BIO */ + bio = BIO_new_mem_buf((char *)mypem, -1); + + if(!bio) { + printf("BIO_new_mem_buf failed\n"); + } + + /* use it to read the PEM formatted certificate from memory into an X509 + * structure that SSL can use + */ + cert = PEM_read_bio_X509(bio, NULL, 0, NULL); + if(!cert) { + printf("PEM_read_bio_X509 failed...\n"); + } + + /* tell SSL to use the X509 certificate */ + ret = SSL_CTX_use_certificate((SSL_CTX*)sslctx, cert); + if(ret != 1) { + printf("Use certificate failed\n"); + } + + /* create a bio for the RSA key */ + kbio = BIO_new_mem_buf((char *)mykey, -1); + if(!kbio) { + printf("BIO_new_mem_buf failed\n"); + } + + /* read the key bio into an RSA object */ + rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL); + if(!rsa) { + printf("Failed to create key bio\n"); + } + + /* tell SSL to use the RSA key from memory */ + ret = SSL_CTX_use_RSAPrivateKey((SSL_CTX*)sslctx, rsa); + if(ret != 1) { + printf("Use Key failed\n"); + } + + /* free resources that have been allocated by openssl functions */ + if(bio) + BIO_free(bio); + + if(kbio) + BIO_free(kbio); + + if(rsa) + RSA_free(rsa); + + if(cert) + X509_free(cert); + + /* all set to go */ + return CURLE_OK; +} + +int main(void) +{ + CURL *ch; + CURLcode rv; + + curl_global_init(CURL_GLOBAL_ALL); + ch = curl_easy_init(); + curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(ch, CURLOPT_HEADER, 0L); + curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, stdout); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, stderr); + curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + + /* both VERIFYPEER and VERIFYHOST are set to 0 in this case because there is + no CA certificate */ + + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); + curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM"); + + /* first try: retrieve page without user certificate and key -> will fail + */ + rv = curl_easy_perform(ch); + if(rv == CURLE_OK) { + printf("*** transfer succeeded ***\n"); + } + else { + printf("*** transfer failed ***\n"); + } + + /* second try: retrieve page using user certificate and key -> will succeed + * load the certificate and key by installing a function doing the necessary + * "modifications" to the SSL CONTEXT just before link init + */ + curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); + rv = curl_easy_perform(ch); + if(rv == CURLE_OK) { + printf("*** transfer succeeded ***\n"); + } + else { + printf("*** transfer failed ***\n"); + } + + curl_easy_cleanup(ch); + curl_global_cleanup(); + return rv; +} diff --git a/docs/examples/version-check.pl b/docs/examples/version-check.pl new file mode 100755 index 0000000..932d154 --- /dev/null +++ b/docs/examples/version-check.pl @@ -0,0 +1,105 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# This script accepts a source file as input on the command line. +# +# It first loads the 'symbols-in-versions' document and stores a lookup +# table for all known symbols for which version they were introduced. +# +# It then scans the given source file to dig up all symbols starting with CURL. +# Finally, it sorts the internal list of found symbols (using the version +# number as sort key) and then it outputs the most recent version number and +# the symbols from that version that are used. +# +# Usage: +# +# version-check.pl [source file] +# + +open(S, "<../libcurl/symbols-in-versions") || die; + +my %doc; +my %rem; +while() { + if(/(^CURL[^ \n]*) *(.*)/) { + my ($sym, $rest)=($1, $2); + my @a=split(/ +/, $rest); + + $doc{$sym}=$a[0]; # when it was introduced + + if($a[2]) { + # this symbol is documented to have been present the last time + # in this release + $rem{$sym}=$a[2]; + } + } + +} + +close(S); + +sub age { + my ($ver)=@_; + + my @s=split(/\./, $ver); + return $s[0]*10000+$s[1]*100+$s[2]; +} + +my %used; +open(C, "<$ARGV[0]") || die; + +while() { + if(/\W(CURL[_A-Z0-9v]+)\W/) { + #print "$1\n"; + $used{$1}++; + } +} + +close(C); + +sub sortversions { + my $r = age($doc{$a}) <=> age($doc{$b}); + if(!$r) { + $r = $a cmp $b; + } + return $r; +} + +my @recent = reverse sort sortversions keys %used; + +# the most recent symbol +my $newsym = $recent[0]; +# the most recent version +my $newver = $doc{$newsym}; + +print "The scanned source uses these symbols introduced in $newver:\n"; + +for my $w (@recent) { + if($doc{$w} eq $newver) { + printf " $w\n"; + next; + } + last; +} diff --git a/docs/examples/websocket-cb.c b/docs/examples/websocket-cb.c new file mode 100644 index 0000000..7adbf44 --- /dev/null +++ b/docs/examples/websocket-cb.c @@ -0,0 +1,68 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * WebSocket download-only using write callback + * + */ +#include +#include + +static size_t writecb(char *b, size_t size, size_t nitems, void *p) +{ + CURL *easy = p; + size_t i; + const struct curl_ws_frame *frame = curl_ws_meta(easy); + fprintf(stderr, "Type: %s\n", frame->flags & CURLWS_BINARY ? + "binary" : "text"); + fprintf(stderr, "Bytes: %u", (unsigned int)(nitems * size)); + for(i = 0; i < nitems; i++) + fprintf(stderr, "%02x ", (unsigned char)b[i]); + return nitems; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "wss://example.com"); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb); + /* pass the easy handle to the callback */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/websocket.c b/docs/examples/websocket.c new file mode 100644 index 0000000..dbcd044 --- /dev/null +++ b/docs/examples/websocket.c @@ -0,0 +1,131 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * WebSocket using CONNECT_ONLY + * + */ +#include +#include +#include +#include + +static int ping(CURL *curl, const char *send_payload) +{ + size_t sent; + CURLcode result = + curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0, + CURLWS_PING); + return (int)result; +} + +static int recv_pong(CURL *curl, const char *expected_payload) +{ + size_t rlen; + const struct curl_ws_frame *meta; + char buffer[256]; + CURLcode result = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta); + if(!result) { + if(meta->flags & CURLWS_PONG) { + int same = 0; + fprintf(stderr, "ws: got PONG back\n"); + if(rlen == strlen(expected_payload)) { + if(!memcmp(expected_payload, buffer, rlen)) { + fprintf(stderr, "ws: got the same payload back\n"); + same = 1; + } + } + if(!same) + fprintf(stderr, "ws: did NOT get the same payload back\n"); + } + else { + fprintf(stderr, "recv_pong: got %u bytes rflags %x\n", (int)rlen, + meta->flags); + } + } + fprintf(stderr, "ws: curl_ws_recv returned %u, received %u\n", + (unsigned int)result, (unsigned int)rlen); + return (int)result; +} + +static int recv_any(CURL *curl) +{ + size_t rlen; + const struct curl_ws_frame *meta; + char buffer[256]; + CURLcode result = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta); + if(result) + return result; + + return 0; +} + +/* close the connection */ +static void websocket_close(CURL *curl) +{ + size_t sent; + (void)curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE); +} + +static void websocket(CURL *curl) +{ + int i = 0; + do { + recv_any(curl); + if(ping(curl, "foobar")) + return; + if(recv_pong(curl, "foobar")) { + return; + } + sleep(2); + } while(i++ < 10); + websocket_close(curl); +} + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "wss://example.com"); + + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + else { + /* connected and ready */ + websocket(curl); + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} diff --git a/docs/examples/xmlstream.c b/docs/examples/xmlstream.c new file mode 100644 index 0000000..76a8e48 --- /dev/null +++ b/docs/examples/xmlstream.c @@ -0,0 +1,168 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * Stream-parse a document using the streaming Expat parser. + * + */ +/* Written by David Strauss + * + * Expat => https://libexpat.github.io/ + * + * gcc -Wall -I/usr/local/include xmlstream.c -lcurl -lexpat -o xmlstream + * + */ + +#include +#include +#include +#include + +#include +#include + +struct MemoryStruct { + char *memory; + size_t size; +}; + +struct ParserStruct { + int ok; + size_t tags; + size_t depth; + struct MemoryStruct characters; +}; + +static void startElement(void *userData, const XML_Char *name, + const XML_Char **atts) +{ + struct ParserStruct *state = (struct ParserStruct *) userData; + state->tags++; + state->depth++; + + /* Get a clean slate for reading in character data. */ + free(state->characters.memory); + state->characters.memory = NULL; + state->characters.size = 0; +} + +static void characterDataHandler(void *userData, const XML_Char *s, int len) +{ + struct ParserStruct *state = (struct ParserStruct *) userData; + struct MemoryStruct *mem = &state->characters; + + char *ptr = realloc(mem->memory, mem->size + len + 1); + if(!ptr) { + /* Out of memory. */ + fprintf(stderr, "Not enough memory (realloc returned NULL).\n"); + state->ok = 0; + return; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), s, len); + mem->size += len; + mem->memory[mem->size] = 0; +} + +static void endElement(void *userData, const XML_Char *name) +{ + struct ParserStruct *state = (struct ParserStruct *) userData; + state->depth--; + + printf("%5lu %10lu %s\n", state->depth, state->characters.size, name); +} + +static size_t parseStreamCallback(void *contents, size_t length, size_t nmemb, + void *userp) +{ + XML_Parser parser = (XML_Parser) userp; + size_t real_size = length * nmemb; + struct ParserStruct *state = (struct ParserStruct *) XML_GetUserData(parser); + + /* Only parse if we are not already in a failure state. */ + if(state->ok && XML_Parse(parser, contents, real_size, 0) == 0) { + int error_code = XML_GetErrorCode(parser); + fprintf(stderr, "Parsing response buffer of length %lu failed" + " with error code %d (%s).\n", + real_size, error_code, XML_ErrorString(error_code)); + state->ok = 0; + } + + return real_size; +} + +int main(void) +{ + CURL *curl_handle; + CURLcode res; + XML_Parser parser; + struct ParserStruct state; + + /* Initialize the state structure for parsing. */ + memset(&state, 0, sizeof(struct ParserStruct)); + state.ok = 1; + + /* Initialize a namespace-aware parser. */ + parser = XML_ParserCreateNS(NULL, '\0'); + XML_SetUserData(parser, &state); + XML_SetElementHandler(parser, startElement, endElement); + XML_SetCharacterDataHandler(parser, characterDataHandler); + + /* Initialize a libcurl handle. */ + curl_global_init(CURL_GLOBAL_DEFAULT); + curl_handle = curl_easy_init(); + curl_easy_setopt(curl_handle, CURLOPT_URL, + "https://www.w3schools.com/xml/simple.xml"); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, parseStreamCallback); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)parser); + + printf("Depth Characters Closing Tag\n"); + + /* Perform the request and any follow-up parsing. */ + res = curl_easy_perform(curl_handle); + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + else if(state.ok) { + /* Expat requires one final call to finalize parsing. */ + if(XML_Parse(parser, NULL, 0, 1) == 0) { + int error_code = XML_GetErrorCode(parser); + fprintf(stderr, "Finalizing parsing failed with error code %d (%s).\n", + error_code, XML_ErrorString(error_code)); + } + else { + printf(" --------------\n"); + printf(" %lu tags total\n", state.tags); + } + } + + /* Clean up. */ + free(state.characters.memory); + XML_ParserFree(parser); + curl_easy_cleanup(curl_handle); + curl_global_cleanup(); + + return 0; +} diff --git a/docs/libcurl/ABI.md b/docs/libcurl/ABI.md new file mode 100644 index 0000000..408ea10 --- /dev/null +++ b/docs/libcurl/ABI.md @@ -0,0 +1,68 @@ + + +ABI - Application Binary Interface +================================== + + "ABI" describes the low-level interface between an application program and a + library. Calling conventions, function arguments, return values, struct + sizes/defines and more. + + [Wikipedia has a longer description](https://en.wikipedia.org/wiki/Application_binary_interface) + +## Upgrades + + A libcurl upgrade does not break the ABI or change established and documented + behavior. Your application can remain using libcurl just as before, only with + fewer bugs and possibly with added new features. + +## Version Numbers + + In libcurl land, you cannot tell by the libcurl version number if that + libcurl is binary compatible or not with another libcurl version. As a rule, + we do not break the ABI so you can *always* upgrade to a later version without + any loss or change in functionality. + +## SONAME Bumps + + Whenever there are changes done to the library that will cause an ABI + breakage, that may require your application to get attention or possibly be + changed to adhere to new things, we will bump the SONAME. Then the library + will get a different output name and thus can in fact be installed in + parallel with an older installed lib (on most systems). Thus, old + applications built against the previous ABI version will remain working and + using the older lib, while newer applications build and use the newer one. + + During the first seven years of libcurl releases, there have only been four + ABI breakages. + + We are determined to bump the SONAME as rarely as possible. Ideally, we never + do it again. + +## Downgrades + + Going to an older libcurl version from one you are currently using can be a + tricky thing. Mostly we add features and options to newer libcurls as that + will not break ABI or hamper existing applications. This has the implication + that going backwards may get you in a situation where you pick a libcurl that + does not support the options your application needs. Or possibly you even + downgrade so far so you cross an ABI break border and thus a different + SONAME, and then your application may need to adapt to the modified ABI. + +## History + + The previous major library SONAME number bumps (breaking backwards + compatibility) happened the following times: + + 0 - libcurl 7.1, August 2000 + + 1 - libcurl 7.5 December 2000 + + 2 - libcurl 7.7 March 2001 + + 3 - libcurl 7.12.0 June 2004 + + 4 - libcurl 7.16.0 October 2006 diff --git a/docs/libcurl/CMakeLists.txt b/docs/libcurl/CMakeLists.txt new file mode 100644 index 0000000..6f0aa64 --- /dev/null +++ b/docs/libcurl/CMakeLists.txt @@ -0,0 +1,69 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# Load man_MANS from shared file +transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") + +function(add_manual_pages _listname) + unset(_rofffiles) + unset(_mdfiles) + foreach(_file IN LISTS ${_listname}) + list(APPEND _rofffiles "${CMAKE_CURRENT_BINARY_DIR}/${_file}") + if(_file STREQUAL "libcurl-symbols.3") + # Special case, an auto-generated file. + string(REPLACE ".3" ".md" _mdfile "${CMAKE_CURRENT_BINARY_DIR}/${_file}") + else() + string(REPLACE ".3" ".md" _mdfile "${_file}") + endif() + list(APPEND _mdfiles "${_mdfile}") + endforeach() + + add_custom_command(OUTPUT ${_rofffiles} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${PROJECT_SOURCE_DIR}/scripts/cd2nroff -k -d "${CMAKE_CURRENT_BINARY_DIR}" ${_mdfiles} + DEPENDS ${_mdfiles} + VERBATIM + ) + +endfunction() + +add_custom_command(OUTPUT libcurl-symbols.md + COMMAND + "${PERL_EXECUTABLE}" + "${CMAKE_CURRENT_SOURCE_DIR}/mksymbolsmanpage.pl" < + "${CMAKE_CURRENT_SOURCE_DIR}/symbols-in-versions" > libcurl-symbols.md + DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/symbols-in-versions" + "${CMAKE_CURRENT_SOURCE_DIR}/mksymbolsmanpage.pl" + VERBATIM +) + +add_manual_pages(man_MANS) +add_custom_target(man ALL DEPENDS ${man_MANS}) +if(NOT CURL_DISABLE_INSTALL) + install(FILES "$" + DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) +endif() + +add_subdirectory(opts) diff --git a/docs/libcurl/Makefile.am b/docs/libcurl/Makefile.am new file mode 100644 index 0000000..17b2bc8 --- /dev/null +++ b/docs/libcurl/Makefile.am @@ -0,0 +1,54 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +AUTOMAKE_OPTIONS = foreign no-dependencies + +SUBDIRS = opts + +include Makefile.inc + +CURLPAGES = $(man_MANS:.3=.md) + +m4macrodir = $(datadir)/aclocal +dist_m4macro_DATA = libcurl.m4 + +CLEANFILES = $(man_MANS) libcurl-symbols.md +nodist_MANS = $(man_MANS) + +EXTRA_DIST = $(CURLPAGES) ABI.md symbols-in-versions symbols.pl \ + mksymbolsmanpage.pl CMakeLists.txt + +CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ +CD2 = $(CD2_$(V)) +CD2_0 = @echo " RENDER " $@; +CD2_1 = +CD2_ = $(CD2_0) + +SUFFIXES = .3 .md + +libcurl-symbols.md: $(srcdir)/symbols-in-versions $(srcdir)/mksymbolsmanpage.pl + $(CD2)perl $(srcdir)/mksymbolsmanpage.pl < $(srcdir)/symbols-in-versions > $@ + +.md.3: + $(CD2)$(CD2NROFF) diff --git a/docs/libcurl/Makefile.in b/docs/libcurl/Makefile.in new file mode 100644 index 0000000..f1f8eaa --- /dev/null +++ b/docs/libcurl/Makefile.in @@ -0,0 +1,1026 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# Shared between Makefile.am and CMakeLists.txt + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = docs/libcurl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_m4macro_DATA) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +depcomp = +am__maybe_remake_depfiles = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man3dir = $(mandir)/man3 +am__installdirs = "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(m4macrodir)" +MANS = $(man_MANS) +DATA = $(dist_m4macro_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign no-dependencies +SUBDIRS = opts +man_MANS = \ + curl_easy_cleanup.3 \ + curl_easy_duphandle.3 \ + curl_easy_escape.3 \ + curl_easy_getinfo.3 \ + curl_easy_header.3 \ + curl_easy_init.3 \ + curl_easy_nextheader.3 \ + curl_easy_option_by_id.3 \ + curl_easy_option_by_name.3 \ + curl_easy_option_next.3 \ + curl_easy_pause.3 \ + curl_easy_perform.3 \ + curl_easy_recv.3 \ + curl_easy_reset.3 \ + curl_easy_send.3 \ + curl_easy_setopt.3 \ + curl_easy_strerror.3 \ + curl_easy_unescape.3 \ + curl_easy_upkeep.3 \ + curl_escape.3 \ + curl_formadd.3 \ + curl_formfree.3 \ + curl_formget.3 \ + curl_free.3 \ + curl_getdate.3 \ + curl_getenv.3 \ + curl_global_cleanup.3 \ + curl_global_init.3 \ + curl_global_init_mem.3 \ + curl_global_trace.3 \ + curl_global_sslset.3 \ + curl_mime_addpart.3 \ + curl_mime_data.3 \ + curl_mime_data_cb.3 \ + curl_mime_encoder.3 \ + curl_mime_filedata.3 \ + curl_mime_filename.3 \ + curl_mime_free.3 \ + curl_mime_headers.3 \ + curl_mime_init.3 \ + curl_mime_name.3 \ + curl_mime_subparts.3 \ + curl_mime_type.3 \ + curl_mprintf.3 \ + curl_multi_add_handle.3 \ + curl_multi_assign.3 \ + curl_multi_cleanup.3 \ + curl_multi_fdset.3 \ + curl_multi_get_handles.3 \ + curl_multi_info_read.3 \ + curl_multi_init.3 \ + curl_multi_perform.3 \ + curl_multi_poll.3 \ + curl_multi_remove_handle.3 \ + curl_multi_setopt.3 \ + curl_multi_socket.3 \ + curl_multi_socket_action.3 \ + curl_multi_socket_all.3 \ + curl_multi_strerror.3 \ + curl_multi_timeout.3 \ + curl_multi_wakeup.3 \ + curl_multi_wait.3 \ + curl_pushheader_bynum.3 \ + curl_pushheader_byname.3 \ + curl_share_cleanup.3 \ + curl_share_init.3 \ + curl_share_setopt.3 \ + curl_share_strerror.3 \ + curl_slist_append.3 \ + curl_slist_free_all.3 \ + curl_strequal.3 \ + curl_strnequal.3 \ + curl_unescape.3 \ + curl_url.3 \ + curl_url_cleanup.3 \ + curl_url_dup.3 \ + curl_url_get.3 \ + curl_url_set.3 \ + curl_url_strerror.3 \ + curl_version.3 \ + curl_version_info.3 \ + curl_ws_meta.3 \ + curl_ws_recv.3 \ + curl_ws_send.3 \ + libcurl-easy.3 \ + libcurl-env.3 \ + libcurl-env-dbg.3 \ + libcurl-errors.3 \ + libcurl-multi.3 \ + libcurl-security.3 \ + libcurl-share.3 \ + libcurl-symbols.3 \ + libcurl-thread.3 \ + libcurl-tutorial.3 \ + libcurl-url.3 \ + libcurl-ws.3 \ + libcurl.3 + +CURLPAGES = $(man_MANS:.3=.md) +m4macrodir = $(datadir)/aclocal +dist_m4macro_DATA = libcurl.m4 +CLEANFILES = $(man_MANS) libcurl-symbols.md +nodist_MANS = $(man_MANS) +EXTRA_DIST = $(CURLPAGES) ABI.md symbols-in-versions symbols.pl \ + mksymbolsmanpage.pl CMakeLists.txt + +CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ +CD2 = $(CD2_$(V)) +CD2_0 = @echo " RENDER " $@; +CD2_1 = +CD2_ = $(CD2_0) +SUFFIXES = .3 .md +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .3 .md +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.inc $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/libcurl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign docs/libcurl/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/Makefile.inc $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man3: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man3dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.3[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ + done; } + +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man3dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.3[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) +install-dist_m4macroDATA: $(dist_m4macro_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_m4macro_DATA)'; test -n "$(m4macrodir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(m4macrodir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(m4macrodir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(m4macrodir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(m4macrodir)" || exit $$?; \ + done + +uninstall-dist_m4macroDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_m4macro_DATA)'; test -n "$(m4macrodir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(m4macrodir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(MANS) $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(m4macrodir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-dist_m4macroDATA install-man + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: install-man3 + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-dist_m4macroDATA uninstall-man + +uninstall-man: uninstall-man3 + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_m4macroDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-man3 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-dist_m4macroDATA uninstall-man uninstall-man3 + +.PRECIOUS: Makefile + + +libcurl-symbols.md: $(srcdir)/symbols-in-versions $(srcdir)/mksymbolsmanpage.pl + $(CD2)perl $(srcdir)/mksymbolsmanpage.pl < $(srcdir)/symbols-in-versions > $@ + +.md.3: + $(CD2)$(CD2NROFF) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/docs/libcurl/Makefile.inc b/docs/libcurl/Makefile.inc new file mode 100644 index 0000000..336b419 --- /dev/null +++ b/docs/libcurl/Makefile.inc @@ -0,0 +1,124 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# Shared between Makefile.am and CMakeLists.txt + +man_MANS = \ + curl_easy_cleanup.3 \ + curl_easy_duphandle.3 \ + curl_easy_escape.3 \ + curl_easy_getinfo.3 \ + curl_easy_header.3 \ + curl_easy_init.3 \ + curl_easy_nextheader.3 \ + curl_easy_option_by_id.3 \ + curl_easy_option_by_name.3 \ + curl_easy_option_next.3 \ + curl_easy_pause.3 \ + curl_easy_perform.3 \ + curl_easy_recv.3 \ + curl_easy_reset.3 \ + curl_easy_send.3 \ + curl_easy_setopt.3 \ + curl_easy_strerror.3 \ + curl_easy_unescape.3 \ + curl_easy_upkeep.3 \ + curl_escape.3 \ + curl_formadd.3 \ + curl_formfree.3 \ + curl_formget.3 \ + curl_free.3 \ + curl_getdate.3 \ + curl_getenv.3 \ + curl_global_cleanup.3 \ + curl_global_init.3 \ + curl_global_init_mem.3 \ + curl_global_trace.3 \ + curl_global_sslset.3 \ + curl_mime_addpart.3 \ + curl_mime_data.3 \ + curl_mime_data_cb.3 \ + curl_mime_encoder.3 \ + curl_mime_filedata.3 \ + curl_mime_filename.3 \ + curl_mime_free.3 \ + curl_mime_headers.3 \ + curl_mime_init.3 \ + curl_mime_name.3 \ + curl_mime_subparts.3 \ + curl_mime_type.3 \ + curl_mprintf.3 \ + curl_multi_add_handle.3 \ + curl_multi_assign.3 \ + curl_multi_cleanup.3 \ + curl_multi_fdset.3 \ + curl_multi_get_handles.3 \ + curl_multi_info_read.3 \ + curl_multi_init.3 \ + curl_multi_perform.3 \ + curl_multi_poll.3 \ + curl_multi_remove_handle.3 \ + curl_multi_setopt.3 \ + curl_multi_socket.3 \ + curl_multi_socket_action.3 \ + curl_multi_socket_all.3 \ + curl_multi_strerror.3 \ + curl_multi_timeout.3 \ + curl_multi_wakeup.3 \ + curl_multi_wait.3 \ + curl_pushheader_bynum.3 \ + curl_pushheader_byname.3 \ + curl_share_cleanup.3 \ + curl_share_init.3 \ + curl_share_setopt.3 \ + curl_share_strerror.3 \ + curl_slist_append.3 \ + curl_slist_free_all.3 \ + curl_strequal.3 \ + curl_strnequal.3 \ + curl_unescape.3 \ + curl_url.3 \ + curl_url_cleanup.3 \ + curl_url_dup.3 \ + curl_url_get.3 \ + curl_url_set.3 \ + curl_url_strerror.3 \ + curl_version.3 \ + curl_version_info.3 \ + curl_ws_meta.3 \ + curl_ws_recv.3 \ + curl_ws_send.3 \ + libcurl-easy.3 \ + libcurl-env.3 \ + libcurl-env-dbg.3 \ + libcurl-errors.3 \ + libcurl-multi.3 \ + libcurl-security.3 \ + libcurl-share.3 \ + libcurl-symbols.3 \ + libcurl-thread.3 \ + libcurl-tutorial.3 \ + libcurl-url.3 \ + libcurl-ws.3 \ + libcurl.3 diff --git a/docs/libcurl/curl_easy_cleanup.md b/docs/libcurl/curl_easy_cleanup.md new file mode 100644 index 0000000..bdbc058 --- /dev/null +++ b/docs/libcurl/curl_easy_cleanup.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_cleanup +Section: 3 +Source: libcurl +See-also: + - curl_easy_duphandle (3) + - curl_easy_init (3) + - curl_easy_reset (3) + - curl_multi_cleanup (3) + - curl_multi_remove_handle (3) +--- + +# NAME + +curl_easy_cleanup - End a libcurl easy handle + +# SYNOPSIS + +~~~c +#include + +void curl_easy_cleanup(CURL *handle); +~~~ + +# DESCRIPTION + +This function is the opposite of curl_easy_init(3). It closes down and frees +all resources previously associated with this easy handle. + +This call closes all connections this handle has used and possibly has kept +open until now unless the easy handle was attached to a multi handle while +doing the transfers. Do not call this function if you intend to transfer more +files, reusing handles is a key to good performance with libcurl. + +Occasionally you may get your progress callback or header callback called from +within curl_easy_cleanup(3) (if previously set for the handle using +curl_easy_setopt(3)). Like if libcurl decides to shut down the connection and +the protocol is of a kind that requires a command/response sequence before +disconnect. Examples of such protocols are FTP, POP3 and IMAP. + +Any use of the easy **handle** after this function has been called and have +returned, is illegal. + +To close an easy handle that has been used with the multi interface, make sure +to first call curl_multi_remove_handle(3) to remove it from the multi handle +before it is closed. + +Passing in a NULL pointer in *handle* makes this function return immediately +with no action. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res) + printf("error: %s\n", curl_easy_strerror(res)); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.1 + +# RETURN VALUE + +None diff --git a/docs/libcurl/curl_easy_duphandle.md b/docs/libcurl/curl_easy_duphandle.md new file mode 100644 index 0000000..d7c5b03 --- /dev/null +++ b/docs/libcurl/curl_easy_duphandle.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_duphandle +Section: 3 +Source: libcurl +See-also: + - curl_easy_cleanup (3) + - curl_easy_init (3) + - curl_easy_reset (3) + - curl_global_init (3) +--- + +# NAME + +curl_easy_duphandle - Clone a libcurl session handle + +# SYNOPSIS + +~~~c +#include + +CURL *curl_easy_duphandle(CURL *handle); +~~~ + +# DESCRIPTION + +This function returns a new curl handle, a duplicate, using all the options +previously set in the input curl *handle*. Both handles can subsequently be +used independently and they must both be freed with curl_easy_cleanup(3). + +Any options that the input handle has been told to point to (as opposed to +copy) with previous calls to curl_easy_setopt(3), are pointed to by the new +handle as well. You must therefore make sure to keep the data around until +both handles have been cleaned up. + +The new handle does **not** inherit any state information, no connections, no +SSL sessions and no cookies. It also does not inherit any share object states +or options (created as if CURLOPT_SHARE(3) was set to NULL). + +If the source handle has HSTS or alt-svc enabled, the duplicate gets data read +data from the main filename to populate the cache. + +In multi-threaded programs, this function must be called in a synchronous way, +the input handle may not be in use when cloned. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + CURL *nother; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + nother = curl_easy_duphandle(curl); + res = curl_easy_perform(nother); + curl_easy_cleanup(nother); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9 + +# RETURN VALUE + +If this function returns NULL, something went wrong and no valid handle was +returned. diff --git a/docs/libcurl/curl_easy_escape.md b/docs/libcurl/curl_easy_escape.md new file mode 100644 index 0000000..655dbb4 --- /dev/null +++ b/docs/libcurl/curl_easy_escape.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_escape +Section: 3 +Source: libcurl +See-also: + - curl_easy_unescape (3) + - curl_free (3) +--- + +# NAME + +curl_easy_escape - URL encodes the given string + +# SYNOPSIS + +~~~c +#include + +char *curl_easy_escape(CURL *curl, const char *string, int length); +~~~ + +# DESCRIPTION + +This function converts the given input *string* to a URL encoded string +and returns that as a new allocated string. All input characters that are not +a-z, A-Z, 0-9, '-', '.', '_' or '~' are converted to their "URL escaped" +version (**%NN** where **NN** is a two-digit hexadecimal number). + +If *length* is set to 0 (zero), curl_easy_escape(3) uses strlen() on +the input *string* to find out the size. This function does not accept +input strings longer than **CURL_MAX_INPUT_LENGTH** (8 MB). + +Since 7.82.0, the **curl** parameter is ignored. Prior to that there was +per-handle character conversion support for some old operating systems such as +TPF, but it was otherwise ignored. + +You must curl_free(3) the returned string when you are done with it. + +# ENCODING + +libcurl is typically not aware of, nor does it care about, character +encodings. curl_easy_escape(3) encodes the data byte-by-byte into the +URL encoded version without knowledge or care for what particular character +encoding the application or the receiving server may assume that the data +uses. + +The caller of curl_easy_escape(3) must make sure that the data passed in +to the function is encoded correctly. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + char *output = curl_easy_escape(curl, "data to convert", 15); + if(output) { + printf("Encoded: %s\n", output); + curl_free(output); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.4 and replaces the old curl_escape(3) function. + +# RETURN VALUE + +A pointer to a null-terminated string or NULL if it failed. diff --git a/docs/libcurl/curl_easy_getinfo.md b/docs/libcurl/curl_easy_getinfo.md new file mode 100644 index 0000000..3b98ea4 --- /dev/null +++ b/docs/libcurl/curl_easy_getinfo.md @@ -0,0 +1,483 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_getinfo +Section: 3 +Source: libcurl +See-also: + - curl_easy_setopt (3) +--- + +# NAME + +curl_easy_getinfo - extract information from a curl handle + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); +~~~ + +# DESCRIPTION + +Get the *info* kept in the *curl* handle. The third argument **MUST** be +pointing to the specific type of the used option which is documented in each +man page of the *info* option. The data is stored accordingly and can be +relied upon only if this function returns CURLE_OK. Use this function after a +performed transfer if you want to get transfer related data. + +You should not free the memory returned by this function unless it is +explicitly mentioned below. + +# AVAILABLE INFORMATION + +The following information can be extracted: + +## CURLINFO_EFFECTIVE_METHOD + +Last used HTTP method. See CURLINFO_EFFECTIVE_METHOD(3) + +## CURLINFO_EFFECTIVE_URL + +Last used URL. See CURLINFO_EFFECTIVE_URL(3) + +## CURLINFO_RESPONSE_CODE + +Last received response code. See CURLINFO_RESPONSE_CODE(3) + +## CURLINFO_REFERER + +Referrer header. See CURLINFO_REFERER(3) + +## CURLINFO_HTTP_CONNECTCODE + +Last proxy CONNECT response code. See CURLINFO_HTTP_CONNECTCODE(3) + +## CURLINFO_HTTP_VERSION + +The http version used in the connection. See CURLINFO_HTTP_VERSION(3) + +## CURLINFO_FILETIME + +Remote time of the retrieved document. See CURLINFO_FILETIME(3) + +## CURLINFO_FILETIME_T + +Remote time of the retrieved document. See CURLINFO_FILETIME_T(3) + +## CURLINFO_TOTAL_TIME + +Total time of previous transfer. See CURLINFO_TOTAL_TIME(3) + +## CURLINFO_TOTAL_TIME_T + +Total time of previous transfer. See CURLINFO_TOTAL_TIME_T(3) + +## CURLINFO_NAMELOOKUP_TIME + +Time from start until name resolving completed. See +CURLINFO_NAMELOOKUP_TIME(3) + +## CURLINFO_NAMELOOKUP_TIME_T + +Time from start until name resolving completed. See +CURLINFO_NAMELOOKUP_TIME_T(3) + +## CURLINFO_CONNECT_TIME + +Time from start until remote host or proxy completed. +See CURLINFO_CONNECT_TIME(3) + +## CURLINFO_CONNECT_TIME_T + +Time from start until remote host or proxy completed. +See CURLINFO_CONNECT_TIME_T(3) + +## CURLINFO_APPCONNECT_TIME + +Time from start until SSL/SSH handshake completed. +See CURLINFO_APPCONNECT_TIME(3) + +## CURLINFO_APPCONNECT_TIME_T + +Time from start until SSL/SSH handshake completed. +See CURLINFO_APPCONNECT_TIME_T(3) + +## CURLINFO_PRETRANSFER_TIME + +Time from start until just before the transfer begins. +See CURLINFO_PRETRANSFER_TIME(3) + +## CURLINFO_PRETRANSFER_TIME_T + +Time from start until just before the transfer begins. +See CURLINFO_PRETRANSFER_TIME_T(3) + +## CURLINFO_QUEUE_TIME_T + +Time during which this transfer was held in a waiting queue. +See CURLINFO_QUEUE_TIME_T(3) + +## CURLINFO_STARTTRANSFER_TIME + +Time from start until just when the first byte is received. +See CURLINFO_STARTTRANSFER_TIME(3) + +## CURLINFO_STARTTRANSFER_TIME_T + +Time from start until just when the first byte is received. +See CURLINFO_STARTTRANSFER_TIME_T(3) + +## CURLINFO_REDIRECT_TIME + +Time taken for all redirect steps before the final transfer. +See CURLINFO_REDIRECT_TIME(3) + +## CURLINFO_REDIRECT_TIME_T + +Time taken for all redirect steps before the final transfer. +See CURLINFO_REDIRECT_TIME_T(3) + +## CURLINFO_REDIRECT_COUNT + +Total number of redirects that were followed. +See CURLINFO_REDIRECT_COUNT(3) + +## CURLINFO_REDIRECT_URL + +URL a redirect would take you to, had you enabled redirects. +See CURLINFO_REDIRECT_URL(3) + +## CURLINFO_SIZE_UPLOAD + +(Deprecated) Number of bytes uploaded. +See CURLINFO_SIZE_UPLOAD(3) + +## CURLINFO_SIZE_UPLOAD_T + +Number of bytes uploaded. +See CURLINFO_SIZE_UPLOAD_T(3) + +## CURLINFO_SIZE_DOWNLOAD + +(Deprecated) Number of bytes downloaded. +See CURLINFO_SIZE_DOWNLOAD(3) + +## CURLINFO_SIZE_DOWNLOAD_T + +Number of bytes downloaded. +See CURLINFO_SIZE_DOWNLOAD_T(3) + +## CURLINFO_SPEED_DOWNLOAD + +(Deprecated) Average download speed. +See CURLINFO_SPEED_DOWNLOAD(3) + +## CURLINFO_SPEED_DOWNLOAD_T + +Average download speed. +See CURLINFO_SPEED_DOWNLOAD_T(3) + +## CURLINFO_SPEED_UPLOAD + +(Deprecated) Average upload speed. +See CURLINFO_SPEED_UPLOAD(3) + +## CURLINFO_SPEED_UPLOAD_T + +Average upload speed. +See CURLINFO_SPEED_UPLOAD_T(3) + +## CURLINFO_HEADER_SIZE + +Number of bytes of all headers received. +See CURLINFO_HEADER_SIZE(3) + +## CURLINFO_REQUEST_SIZE + +Number of bytes sent in the issued HTTP requests. +See CURLINFO_REQUEST_SIZE(3) + +## CURLINFO_SSL_VERIFYRESULT + +Certificate verification result. +See CURLINFO_SSL_VERIFYRESULT(3) + +## CURLINFO_PROXY_ERROR + +Detailed proxy error. +See CURLINFO_PROXY_ERROR(3) + +## CURLINFO_PROXY_SSL_VERIFYRESULT + +Proxy certificate verification result. +See CURLINFO_PROXY_SSL_VERIFYRESULT(3) + +## CURLINFO_SSL_ENGINES + +A list of OpenSSL crypto engines. +See CURLINFO_SSL_ENGINES(3) + +## CURLINFO_CONTENT_LENGTH_DOWNLOAD + +(Deprecated) Content length from the Content-Length header. +See CURLINFO_CONTENT_LENGTH_DOWNLOAD(3) + +## CURLINFO_CONTENT_LENGTH_DOWNLOAD_T + +Content length from the Content-Length header. +See CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) + +## CURLINFO_CONTENT_LENGTH_UPLOAD + +(Deprecated) Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD(3) + +## CURLINFO_CONTENT_LENGTH_UPLOAD_T + +Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD_T(3) + +## CURLINFO_CONTENT_TYPE + +Content type from the Content-Type header. +See CURLINFO_CONTENT_TYPE(3) + +## CURLINFO_RETRY_AFTER + +The value from the Retry-After header. +See CURLINFO_RETRY_AFTER(3) + +## CURLINFO_PRIVATE + +User's private data pointer. +See CURLINFO_PRIVATE(3) + +## CURLINFO_HTTPAUTH_AVAIL + +Available HTTP authentication methods. +See CURLINFO_HTTPAUTH_AVAIL(3) + +## CURLINFO_PROXYAUTH_AVAIL + +Available HTTP proxy authentication methods. +See CURLINFO_PROXYAUTH_AVAIL(3) + +## CURLINFO_OS_ERRNO + +The errno from the last failure to connect. +See CURLINFO_OS_ERRNO(3) + +## CURLINFO_NUM_CONNECTS + +Number of new successful connections used for previous transfer. +See CURLINFO_NUM_CONNECTS(3) + +## CURLINFO_PRIMARY_IP + +Destination IP address of the last connection. +See CURLINFO_PRIMARY_IP(3) + +## CURLINFO_PRIMARY_PORT + +Destination port of the last connection. +See CURLINFO_PRIMARY_PORT(3) + +## CURLINFO_LOCAL_IP + +Source IP address of the last connection. +See CURLINFO_LOCAL_IP(3) + +## CURLINFO_LOCAL_PORT + +Source port number of the last connection. +See CURLINFO_LOCAL_PORT(3) + +## CURLINFO_COOKIELIST + +List of all known cookies. +See CURLINFO_COOKIELIST(3) + +## CURLINFO_LASTSOCKET + +(Deprecated) Last socket used. +See CURLINFO_LASTSOCKET(3) + +## CURLINFO_ACTIVESOCKET + +The session's active socket. +See CURLINFO_ACTIVESOCKET(3) + +## CURLINFO_FTP_ENTRY_PATH + +The entry path after logging in to an FTP server. +See CURLINFO_FTP_ENTRY_PATH(3) + +## CURLINFO_CAPATH + +Get the default value for CURLOPT_CAPATH(3). +See CURLINFO_CAPATH(3) + +## CURLINFO_CAINFO + +Get the default value for CURLOPT_CAINFO(3). +See CURLINFO_CAINFO(3) + +## CURLINFO_CERTINFO + +Certificate chain. +See CURLINFO_CERTINFO(3) + +## CURLINFO_TLS_SSL_PTR + +TLS session info that can be used for further processing. +See CURLINFO_TLS_SSL_PTR(3) + +## CURLINFO_TLS_SESSION + +TLS session info that can be used for further processing. See +CURLINFO_TLS_SESSION(3). Deprecated option, use +CURLINFO_TLS_SSL_PTR(3) instead! + +## CURLINFO_CONDITION_UNMET + +Whether or not a time conditional was met or 304 HTTP response. +See CURLINFO_CONDITION_UNMET(3) + +## CURLINFO_RTSP_SESSION_ID + +RTSP session ID. +See CURLINFO_RTSP_SESSION_ID(3) + +## CURLINFO_RTSP_CLIENT_CSEQ + +The RTSP client CSeq that is expected next. +See CURLINFO_RTSP_CLIENT_CSEQ(3) + +## CURLINFO_RTSP_SERVER_CSEQ + +The RTSP server CSeq that is expected next. +See CURLINFO_RTSP_SERVER_CSEQ(3) + +## CURLINFO_RTSP_CSEQ_RECV + +RTSP CSeq last received. +See CURLINFO_RTSP_CSEQ_RECV(3) + +## CURLINFO_PROTOCOL + +(Deprecated) The protocol used for the connection. (Added in 7.52.0) +See CURLINFO_PROTOCOL(3) + +## CURLINFO_SCHEME + +The scheme used for the connection. (Added in 7.52.0) +See CURLINFO_SCHEME(3) + +## CURLINFO_CONN_ID + +The ID of the last connection used by the transfer. (Added in 8.2.0) +See CURLINFO_CONN_ID(3) + +## CURLINFO_XFER_ID + +The ID of the transfer. (Added in 8.2.0) +See CURLINFO_XFER_ID(3) + +# TIMES + +An overview of the time values available from curl_easy_getinfo(3) + +~~~ +curl_easy_perform() + | + |--QUEUE_TIME + |--|--NAMELOOKUP + |--|--|--CONNECT + |--|--|--|--APPCONNECT + |--|--|--|--|--PRETRANSFER + |--|--|--|--|--|--STARTTRANSFER + |--|--|--|--|--|--|--TOTAL + |--|--|--|--|--|--|--REDIRECT +~~~ + +## QUEUE_TIME + +CURLINFO_QUEUE_TIME_T(3). The time during which the transfer was held in a +waiting queue before it could start for real. (Added in 8.6.0) + +## NAMELOOKUP + +CURLINFO_NAMELOOKUP_TIME(3) and CURLINFO_NAMELOOKUP_TIME_T(3). The time it +took from the start until the name resolving was completed. + +## CONNECT + +CURLINFO_CONNECT_TIME(3) and CURLINFO_CONNECT_TIME_T(3). The time it took from +the start until the connect to the remote host (or proxy) was completed. + +## APPCONNECT + +CURLINFO_APPCONNECT_TIME(3) and CURLINFO_APPCONNECT_TIME_T(3). The time it +took from the start until the SSL connect/handshake with the remote host was +completed. (Added in 7.19.0) The latter is the integer version (measuring +microseconds). (Added in 7.60.0) + +## PRETRANSFER + +CURLINFO_PRETRANSFER_TIME(3) and CURLINFO_PRETRANSFER_TIME_T(3). The time it +took from the start until the file transfer is just about to begin. This +includes all pre-transfer commands and negotiations that are specific to the +particular protocol(s) involved. + +## STARTTRANSFER + +CURLINFO_STARTTRANSFER_TIME(3) and CURLINFO_STARTTRANSFER_TIME_T(3). The time +it took from the start until the first byte is received by libcurl. + +## TOTAL + +CURLINFO_TOTAL_TIME(3) and CURLINFO_TOTAL_TIME_T(3). Total time +of the previous request. + +## REDIRECT + +CURLINFO_REDIRECT_TIME(3) and CURLINFO_REDIRECT_TIME_T(3). The time it took +for all redirection steps include name lookup, connect, pretransfer and +transfer before final transaction was started. So, this is zero if no +redirection took place. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); + res = curl_easy_perform(curl); + + if(CURLE_OK == res) { + char *ct; + /* ask for the content-type */ + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct); + + if((CURLE_OK == res) && ct) + printf("We received Content-Type: %s\n", ct); + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1 + +# RETURN VALUE + +If the operation was successful, CURLE_OK is returned. Otherwise an +appropriate error code is returned. diff --git a/docs/libcurl/curl_easy_header.md b/docs/libcurl/curl_easy_header.md new file mode 100644 index 0000000..9c2d76c --- /dev/null +++ b/docs/libcurl/curl_easy_header.md @@ -0,0 +1,160 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_header +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONTENT_TYPE (3) + - CURLOPT_HEADERFUNCTION (3) + - curl_easy_nextheader (3) + - curl_easy_perform (3) + - libcurl-errors (3) +--- + +# NAME + +curl_easy_header - get an HTTP header + +# SYNOPSIS + +~~~c +#include + +CURLHcode curl_easy_header(CURL *easy, + const char *name, + size_t index, + unsigned int origin, + int request, + struct curl_header **hout); +~~~ + +# DESCRIPTION + +curl_easy_header(3) returns a pointer to a "curl_header" struct in **hout** +with data for the HTTP response header *name*. The case insensitive +null-terminated header name should be specified without colon. + +*index* 0 means asking for the first instance of the header. If the returned +header struct has **amount** set larger than 1, it means there are more +instances of the same header name available to get. Asking for a too big index +makes **CURLHE_BADINDEX** get returned. + +The *origin* argument is for specifying which headers to receive, as a single +HTTP transfer might provide headers from several different places and they may +then have different importance to the user and headers using the same name +might be used. The *origin* is a bitmask for what header sources you want. See +the descriptions below. + +The *request* argument tells libcurl from which request you want headers +from. A single transfer might consist of a series of HTTP requests and this +argument lets you specify which particular individual request you want the +headers from. 0 being the first request and then the number increases for +further redirects or when multi-state authentication is used. Passing in -1 is +a shortcut to "the last" request in the series, independently of the actual +amount of requests used. + +libcurl stores and provides the actually used "correct" headers. If for +example two headers with the same name arrive and the latter overrides the +former, then only the latter is provided. If the first header survives the +second, then only the first one is provided. An application using this API +does not have to bother about multiple headers used wrongly. + +The memory for the returned struct is associated with the easy handle and +subsequent calls to curl_easy_header(3) clobber the struct used in the +previous calls for the same easy handle. Applications need to copy the data if +it wants to keep it around. The memory used for the struct gets freed with +calling curl_easy_cleanup(3) of the easy handle. + +The first line in an HTTP response is called the status line. It is not +considered a header by this function. Headers are the "name: value" lines +following the status. + +This function can be used before (all) headers have been received and is fine +to call from within libcurl callbacks. It returns the state of the headers at +the time it is called. + +# The header struct + +~~~c +struct curl_header { + char *name; + char *value; + size_t amount; + size_t index; + unsigned int origin; + void *anchor; +}; +~~~ + +The data **name** field points to, is the same as the requested name, but +might have a different case. + +The data **value** field points to, comes exactly as delivered over the +network but with leading and trailing whitespace and newlines stripped +off. The `value` data is null-terminated. For legacy HTTP/1 "folded headers", +this API provides the full single value in an unfolded manner with a single +whitespace between the lines. + +**amount** is how many headers using this name that exist, within the origin +and request scope asked for. + +**index** is the zero based entry number of this particular header, which in +case this header was used more than once in the requested scope can be larger +than 0 but is always less than **amount**. + +The **origin** field in the "curl_header" struct has one of the origin bits +set, indicating where from the header originates. At the time of this writing, +there are 5 bits with defined use. The undocumented 27 remaining bits are +reserved for future use and must not be assumed to have any particular value. + +**anchor** is a private handle used by libcurl internals. Do not modify. + +# ORIGINS + +## CURLH_HEADER + +The header arrived as a header from the server. + +## CURLH_TRAILER + +The header arrived as a trailer. A header that arrives after the body. + +## CURLH_CONNECT + +The header arrived in a CONNECT response. A CONNECT request is being done to +setup a transfer "through" an HTTP(S) proxy. + +## CURLH_1XX + +The header arrived in an HTTP 1xx response. A 1xx response is an "intermediate" +response that might happen before the "real" response. + +## CURLH_PSEUDO + +The header is an HTTP/2 or HTTP/3 pseudo header + +# EXAMPLE + +~~~c +int main(void) +{ + struct curl_header *type; + CURL *curl = curl_easy_init(); + if(curl) { + CURLHcode h; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_perform(curl); + h = curl_easy_header(curl, "Content-Type", 0, CURLH_HEADER, -1, &type); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.83.0. Officially supported since 7.84.0. + +# RETURN VALUE + +This function returns a CURLHcode indicating success or error. diff --git a/docs/libcurl/curl_easy_init.md b/docs/libcurl/curl_easy_init.md new file mode 100644 index 0000000..a746554 --- /dev/null +++ b/docs/libcurl/curl_easy_init.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_init +Section: 3 +Source: libcurl +See-also: + - curl_easy_cleanup (3) + - curl_easy_duphandle (3) + - curl_easy_perform (3) + - curl_easy_reset (3) + - curl_global_init (3) + - curl_multi_init (3) +--- + +# NAME + +curl_easy_init - Start a libcurl easy session + +# SYNOPSIS + +~~~c +#include + +CURL *curl_easy_init(); +~~~ + +# DESCRIPTION + +This function allocates and returns a CURL easy handle. Such a handle is used +as input to other functions in the easy interface. This call must have a +corresponding call to curl_easy_cleanup(3) when the operation is complete. + +The easy handle is used to hold and control a single network transfer. It is +encouraged to reuse easy handles for repeated transfers. + +An alternative way to get a new easy handle is to duplicate an already +existing one with curl_easy_duphandle(3), which has the upside that it gets +all the options that were set in the source handle set in the new copy as +well. + +If you did not already call curl_global_init(3) before calling this function, +curl_easy_init(3) does it automatically. This may be lethal in multi-threaded +cases, if curl_global_init(3) is not thread-safe in your system, and it may +then result in resource problems because there is no corresponding cleanup. + +You are strongly advised to not allow this automatic behavior, by calling +curl_global_init(3) yourself properly. See the description in libcurl(3) of +global environment requirements for details of how to use this function. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +If this function returns NULL, something went wrong and you cannot use the +other curl functions. diff --git a/docs/libcurl/curl_easy_nextheader.md b/docs/libcurl/curl_easy_nextheader.md new file mode 100644 index 0000000..7c7e151 --- /dev/null +++ b/docs/libcurl/curl_easy_nextheader.md @@ -0,0 +1,100 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_nextheader +Section: 3 +Source: libcurl +See-also: + - curl_easy_header (3) + - curl_easy_perform (3) +--- + +# NAME + +curl_easy_nextheader - get the next HTTP header + +# SYNOPSIS + +~~~c +#include + +struct curl_header *curl_easy_nextheader(CURL *easy, + unsigned int origin, + int request, + struct curl_header *prev); +~~~ + +# DESCRIPTION + +This function lets an application iterate over all previously received HTTP +headers. + +The *origin* argument is for specifying which headers to receive, as a single +HTTP transfer might provide headers from several different places and they may +then have different importance to the user and headers using the same name +might be used. The *origin* is a bitmask for what header sources you want. See +the curl_easy_header(3) man page for the origin descriptions. + +The *request* argument tells libcurl from which request you want headers +from. A single transfer might consist of a series of HTTP requests and this +argument lets you specify which particular individual request you want the +headers from. 0 being the first request and then the number increases for +further redirects or when multi-state authentication is used. Passing in -1 is +a shortcut to "the last" request in the series, independently of the actual +amount of requests used. + +It is suggested that you pass in the same **origin** and **request** when +iterating over a range of headers as changing the value mid-loop might give +you unexpected results. + +If *prev* is NULL, this function returns a pointer to the first header stored +within the given scope (origin + request). + +If *prev* is a pointer to a previously returned header struct, +curl_easy_nextheader(3) returns a pointer the next header stored within the +given scope. This way, an application can iterate over all available headers. + +The memory for the struct this points to, is owned and managed by libcurl and +is associated with the easy handle. Applications must copy the data if they +want it to survive subsequent API calls or the life-time of the easy handle. + +# EXAMPLE + +~~~c +int main(void) +{ + struct curl_header *prev = NULL; + struct curl_header *h; + + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_perform(curl); + + /* extract the normal headers from the first request */ + while((h = curl_easy_nextheader(curl, CURLH_HEADER, 0, prev))) { + printf("%s: %s\n", h->name, h->value); + prev = h; + } + + /* extract the normal headers + 1xx + trailers from the last request */ + unsigned int origin = CURLH_HEADER| CURLH_1XX | CURLH_TRAILER; + while((h = curl_easy_nextheader(curl, origin, -1, prev))) { + printf("%s: %s\n", h->name, h->value); + prev = h; + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.83.0. Officially supported since 7.84.0. + +# RETURN VALUE + +This function returns the next header, or NULL when there are no more +(matching) headers or an error occurred. + +If this function returns NULL when *prev* was set to NULL, then there are no +headers available within the scope to return. diff --git a/docs/libcurl/curl_easy_option_by_id.md b/docs/libcurl/curl_easy_option_by_id.md new file mode 100644 index 0000000..b1d6d42 --- /dev/null +++ b/docs/libcurl/curl_easy_option_by_id.md @@ -0,0 +1,54 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_option_by_id +Section: 3 +Source: libcurl +See-also: + - curl_easy_option_by_name (3) + - curl_easy_option_next (3) + - curl_easy_setopt (3) +--- + +# NAME + +curl_easy_option_by_id - find an easy setopt option by id + +# SYNOPSIS + +~~~c +#include + +const struct curl_easyoption *curl_easy_option_by_id(CURLoption id); +~~~ + +# DESCRIPTION + +Given a *CURLoption* **id**, this function returns a pointer to the +*curl_easyoption* struct, holding information about the +curl_easy_setopt(3) option using that id. The option id is the CURLOPT_ +prefix ones provided in the standard curl/curl.h header file. This function +returns the non-alias version of the cases where there is an alias function as +well. + +If libcurl has no option with the given id, this function returns NULL. + +# EXAMPLE + +~~~c +int main(void) +{ + const struct curl_easyoption *opt = curl_easy_option_by_id(CURLOPT_URL); + if(opt) { + printf("This option wants type %x\n", opt->type); + } +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.73.0 + +# RETURN VALUE + +A pointer to the *curl_easyoption* struct for the option or NULL. diff --git a/docs/libcurl/curl_easy_option_by_name.md b/docs/libcurl/curl_easy_option_by_name.md new file mode 100644 index 0000000..86ccbd4 --- /dev/null +++ b/docs/libcurl/curl_easy_option_by_name.md @@ -0,0 +1,53 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_option_by_name +Section: 3 +Source: libcurl +See-also: + - curl_easy_option_by_id (3) + - curl_easy_option_next (3) + - curl_easy_setopt (3) +--- + +# NAME + +curl_easy_option_by_name - find an easy setopt option by name + +# SYNOPSIS + +~~~c +#include + +const struct curl_easyoption *curl_easy_option_by_name(const char *name); +~~~ + +# DESCRIPTION + +Given a **name**, this function returns a pointer to the +*curl_easyoption* struct, holding information about the +curl_easy_setopt(3) option using that name. The name should be specified +without the "CURLOPT_" prefix and the name comparison is made case +insensitive. + +If libcurl has no option with the given name, this function returns NULL. + +# EXAMPLE + +~~~c +int main(void) +{ + const struct curl_easyoption *opt = curl_easy_option_by_name("URL"); + if(opt) { + printf("This option wants CURLoption %x\n", (int)opt->id); + } +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.73.0 + +# RETURN VALUE + +A pointer to the *curl_easyoption* struct for the option or NULL. diff --git a/docs/libcurl/curl_easy_option_next.md b/docs/libcurl/curl_easy_option_next.md new file mode 100644 index 0000000..f5da17c --- /dev/null +++ b/docs/libcurl/curl_easy_option_next.md @@ -0,0 +1,89 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_option_next +Section: 3 +Source: libcurl +See-also: + - curl_easy_option_by_id (3) + - curl_easy_option_by_name (3) + - curl_easy_setopt (3) +--- + +# NAME + +curl_easy_option_next - iterate over easy setopt options + +# SYNOPSIS + +~~~c +#include + +const struct curl_easyoption * +curl_easy_option_next(const struct curl_easyoption *prev); +~~~ + +# DESCRIPTION + +This function returns a pointer to the first or the next *curl_easyoption* +struct, providing an ability to iterate over all known options for +curl_easy_setopt(3) in this instance of libcurl. + +Pass a **NULL** argument as **prev** to get the first option returned, or +pass in the current option to get the next one returned. If there is no more +option to return, curl_easy_option_next(3) returns NULL. + +The options returned by this functions are the ones known to this libcurl and +information about what argument type they want. + +If the **CURLOT_FLAG_ALIAS** bit is set in the flags field, it means the +name is provided for backwards compatibility as an alias. + +# struct + +~~~c +typedef enum { + CURLOT_LONG, /* long (a range of values) */ + CURLOT_VALUES, /* (a defined set or bitmask) */ + CURLOT_OFF_T, /* curl_off_t (a range of values) */ + CURLOT_OBJECT, /* pointer (void *) */ + CURLOT_STRING, /* (char * to null-terminated buffer) */ + CURLOT_SLIST, /* (struct curl_slist *) */ + CURLOT_CBPTR, /* (void * passed as-is to a callback) */ + CURLOT_BLOB, /* blob (struct curl_blob *) */ + CURLOT_FUNCTION /* function pointer */ +} curl_easytype; + +/* The CURLOPTTYPE_* id ranges can still be used to figure out what type/size + to use for curl_easy_setopt() for the given id */ +struct curl_easyoption { + const char *name; + CURLoption id; + curl_easytype type; + unsigned int flags; +}; +~~~ + +# EXAMPLE + +~~~c +int main(void) +{ + /* iterate over all available options */ + const struct curl_easyoption *opt; + opt = curl_easy_option_next(NULL); + while(opt) { + printf("Name: %s\n", opt->name); + opt = curl_easy_option_next(opt); + } +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.73.0 + +# RETURN VALUE + +A pointer to the *curl_easyoption* struct for the next option or NULL if +no more options. diff --git a/docs/libcurl/curl_easy_pause.md b/docs/libcurl/curl_easy_pause.md new file mode 100644 index 0000000..03e6b91 --- /dev/null +++ b/docs/libcurl/curl_easy_pause.md @@ -0,0 +1,140 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_pause +Section: 3 +Source: libcurl +See-also: + - curl_easy_cleanup (3) + - curl_easy_reset (3) +--- + +# NAME + +curl_easy_pause - pause and unpause a connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_pause(CURL *handle, int bitmask ); +~~~ + +# DESCRIPTION + +Using this function, you can explicitly mark a running connection to get +paused, and you can unpause a connection that was previously paused. Unlike +most other libcurl functions, curl_easy_pause(3) can be used from within +callbacks. + +A connection can be paused by using this function or by letting the read or +the write callbacks return the proper magic return code +(*CURL_READFUNC_PAUSE* and *CURL_WRITEFUNC_PAUSE*). A write callback +that returns pause signals to the library that it could not take care of any +data at all, and that data is then delivered again to the callback when the +transfer is unpaused. + +While it may feel tempting, take care and notice that you cannot call this +function from another thread. To unpause, you may for example call it from the +progress callback (CURLOPT_PROGRESSFUNCTION(3)). + +When this function is called to unpause receiving, the write callback might +get called before this function returns to deliver cached content. When +libcurl delivers such cached data to the write callback, it is delivered as +fast as possible, which may overstep the boundary set in +CURLOPT_MAX_RECV_SPEED_LARGE(3) etc. + +The **handle** argument identifies the transfer you want to pause or +unpause. + +A paused transfer is excluded from low speed cancels via the +CURLOPT_LOW_SPEED_LIMIT(3) option and unpausing a transfer resets the +time period required for the low speed limit to be met. + +The **bitmask** argument is a set of bits that sets the new state of the +connection. The following bits can be used: + +## CURLPAUSE_RECV + +Pause receiving data. There is no data received on this connection until this +function is called again without this bit set. Thus, the write callback +(CURLOPT_WRITEFUNCTION(3)) is not called. + +## CURLPAUSE_SEND + +Pause sending data. There is no data sent on this connection until this +function is called again without this bit set. Thus, the read callback +(CURLOPT_READFUNCTION(3)) is not called. + +## CURLPAUSE_ALL + +Convenience define that pauses both directions. + +## CURLPAUSE_CONT + +Convenience define that unpauses both directions. + +# LIMITATIONS + +The pausing of transfers does not work with protocols that work without +network connectivity, like FILE://. Trying to pause such a transfer, in any +direction, might cause problems or error. + +# MULTIPLEXED + +When a connection is used multiplexed, like for HTTP/2, and one of the +transfers over the connection is paused and the others continue flowing, +libcurl might end up buffering contents for the paused transfer. It has to do +this because it needs to drain the socket for the other transfers and the +already announced window size for the paused transfer allows the server to +continue sending data up to that window size amount. By default, libcurl +announces a 32 megabyte window size, which thus can make libcurl end up +buffering 32 megabyte of data for a paused stream. + +When such a paused stream is unpaused again, any buffered data is delivered +first. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* pause a transfer in both directions */ + curl_easy_pause(curl, CURL_READFUNC_PAUSE | CURL_WRITEFUNC_PAUSE); + + } +} +~~~ + +# MEMORY USE + +When pausing a download transfer by returning the magic return code from a +write callback, the read data is already in libcurl's internal buffers so it +has to keep it in an allocated buffer until the receiving is again unpaused +using this function. + +If the downloaded data is compressed and is asked to get uncompressed +automatically on download, libcurl continues to uncompress the entire +downloaded chunk and it caches the data uncompressed. This has the side- +effect that if you download something that is compressed a lot, it can result +in a large data amount needing to be allocated to save the data during the +pause. Consider not using paused receiving if you allow libcurl to uncompress +data automatically. + +If the download is done with HTTP/2 or HTTP/3, there is up to a stream window +size worth of data that curl cannot stop but instead needs to cache while the +transfer is paused. This means that if a window size of 64 MB is used, libcurl +might end up having to cache 64 MB of data. + +# AVAILABILITY + +Added in 7.18.0. + +# RETURN VALUE + +CURLE_OK (zero) means that the option was set properly, and a non-zero return +code means something wrong occurred after the new state was set. See the +libcurl-errors(3) man page for the full list with descriptions. diff --git a/docs/libcurl/curl_easy_perform.md b/docs/libcurl/curl_easy_perform.md new file mode 100644 index 0000000..ff65a82 --- /dev/null +++ b/docs/libcurl/curl_easy_perform.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_perform +Section: 3 +Source: libcurl +See-also: + - curl_easy_init (3) + - curl_easy_setopt (3) + - curl_multi_add_handle (3) + - curl_multi_perform (3) + - libcurl-errors (3) +--- + +# NAME + +curl_easy_perform - perform a blocking file transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_perform(CURL *easy_handle); +~~~ + +# DESCRIPTION + +curl_easy_perform(3) performs a network transfer in a blocking manner and +returns when done, or earlier if it fails. For non-blocking behavior, see +curl_multi_perform(3). + +Invoke this function after curl_easy_init(3) and all the curl_easy_setopt(3) +calls are made, and it performs the transfer as described in the options. It +must be called with the same **easy_handle** as input as the curl_easy_init(3) +call returned. + +You can do any amount of calls to curl_easy_perform(3) while using the same +**easy_handle**. If you intend to transfer more than one file, you are even +encouraged to do so. libcurl attempts to reuse existing connections for the +following transfers, thus making the operations faster, less CPU intense and +using less network resources. You probably want to use curl_easy_setopt(3) +between the invokes to set options for the following curl_easy_perform(3) +call. + +You must never call this function simultaneously from two places using the +same **easy_handle**. Let the function return first before invoking it another +time. If you want parallel transfers, you must use several curl easy_handles. + +A network transfer moves data to a peer or from a peer. An application tells +libcurl how to receive data by setting the CURLOPT_WRITEFUNCTION(3) and +CURLOPT_WRITEDATA(3) options. To tell libcurl what data to send, there are a +few more alternatives but two common ones are CURLOPT_READFUNCTION(3) and +CURLOPT_POSTFIELDS(3). + +While the **easy_handle** is added to a multi handle, it cannot be used by +curl_easy_perform(3). + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +CURLE_OK (0) means everything was OK, non-zero means an error occurred as +** defines - see libcurl-errors(3). If the CURLOPT_ERRORBUFFER(3) +was set with curl_easy_setopt(3) there is a readable error message stored in +the error buffer when non-zero is returned. diff --git a/docs/libcurl/curl_easy_recv.md b/docs/libcurl/curl_easy_recv.md new file mode 100644 index 0000000..df210f7 --- /dev/null +++ b/docs/libcurl/curl_easy_recv.md @@ -0,0 +1,103 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_recv +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_perform (3) + - curl_easy_send (3) + - curl_easy_setopt (3) +--- + +# NAME + +curl_easy_recv - receives raw data on an "easy" connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n); +~~~ + +# DESCRIPTION + +This function receives raw data from the established connection. You may use +it together with curl_easy_send(3) to implement custom protocols using +libcurl. This functionality can be particularly useful if you use proxies +and/or SSL encryption: libcurl takes care of proxy negotiation and connection +setup. + +**buffer** is a pointer to your buffer memory that gets populated by the +received data. **buflen** is the maximum amount of data you can get in that +buffer. The variable **n** points to receives the number of received bytes. + +To establish the connection, set CURLOPT_CONNECT_ONLY(3) option before +calling curl_easy_perform(3) or curl_multi_perform(3). Note that +curl_easy_recv(3) does not work on connections that were created without +this option. + +The call returns **CURLE_AGAIN** if there is no data to read - the socket is +used in non-blocking mode internally. When **CURLE_AGAIN** is returned, use +your operating system facilities like *select(2)* to wait for data. The +socket may be obtained using curl_easy_getinfo(3) with +CURLINFO_ACTIVESOCKET(3). + +Wait on the socket only if curl_easy_recv(3) returns **CURLE_AGAIN**. +The reason for this is libcurl or the SSL library may internally cache some +data, therefore you should call curl_easy_recv(3) until all data is +read which would include any cached data. + +Furthermore if you wait on the socket and it tells you there is data to read, +curl_easy_recv(3) may return **CURLE_AGAIN** if the only data that was +read was for internal SSL processing, and no other data is available. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* Do not do the transfer - only connect to host */ + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); + res = curl_easy_perform(curl); + + if(res == CURLE_OK) { + char buf[256]; + size_t nread; + long sockfd; + + /* Extract the socket from the curl handle - we need it for waiting. */ + res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd); + + /* read data */ + res = curl_easy_recv(curl, buf, sizeof(buf), &nread); + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.18.2. + +# RETURN VALUE + +On success, returns **CURLE_OK**, stores the received data into +**buffer**, and the number of bytes it actually read into ***n**. + +On failure, returns the appropriate error code. + +The function may return **CURLE_AGAIN**. In this case, use your operating +system facilities to wait until data can be read, and retry. + +Reading exactly 0 bytes indicates a closed connection. + +If there is no socket available to use from the previous transfer, this function +returns **CURLE_UNSUPPORTED_PROTOCOL**. diff --git a/docs/libcurl/curl_easy_reset.md b/docs/libcurl/curl_easy_reset.md new file mode 100644 index 0000000..c2aea6e --- /dev/null +++ b/docs/libcurl/curl_easy_reset.md @@ -0,0 +1,56 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_reset +Section: 3 +Source: libcurl +See-also: + - curl_easy_cleanup (3) + - curl_easy_duphandle (3) + - curl_easy_init (3) + - curl_easy_setopt (3) +--- + +# NAME + +curl_easy_reset - reset all options of a libcurl session handle + +# SYNOPSIS + +~~~c +#include + +void curl_easy_reset(CURL *handle); +~~~ + +# DESCRIPTION + +Re-initializes all options previously set on a specified CURL handle to the +default values. This puts back the handle to the same state as it was in when +it was just created with curl_easy_init(3). + +It does not change the following information kept in the handle: live +connections, the Session ID cache, the DNS cache, the cookies, the shares or +the alt-svc cache. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + + /* ... the handle is used and options are set ... */ + curl_easy_reset(curl); + } +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.12.1 + +# RETURN VALUE + +Nothing diff --git a/docs/libcurl/curl_easy_send.md b/docs/libcurl/curl_easy_send.md new file mode 100644 index 0000000..725b05c --- /dev/null +++ b/docs/libcurl/curl_easy_send.md @@ -0,0 +1,95 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_send +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_perform (3) + - curl_easy_recv (3) + - curl_easy_setopt (3) +--- + +# NAME + +curl_easy_send - sends raw data over an "easy" connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); +~~~ + +# DESCRIPTION + +This function sends arbitrary data over the established connection. You may +use it together with curl_easy_recv(3) to implement custom protocols +using libcurl. This functionality can be particularly useful if you use +proxies and/or SSL encryption: libcurl takes care of proxy negotiation and +connection setup. + +**buffer** is a pointer to the data of length **buflen** that you want +sent. The variable **n** points to receives the number of sent bytes. + +To establish the connection, set CURLOPT_CONNECT_ONLY(3) option before +calling curl_easy_perform(3) or curl_multi_perform(3). Note that +curl_easy_send(3) does not work on connections that were created without +this option. + +The call returns **CURLE_AGAIN** if it is not possible to send data right now +- the socket is used in non-blocking mode internally. When **CURLE_AGAIN** +is returned, use your operating system facilities like *select(2)* to wait +until the socket is writable. The socket may be obtained using +curl_easy_getinfo(3) with CURLINFO_ACTIVESOCKET(3). + +Furthermore if you wait on the socket and it tells you it is writable, +curl_easy_send(3) may return **CURLE_AGAIN** if the only data that was sent +was for internal SSL processing, and no other data could be sent. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* Do not do the transfer - only connect to host */ + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); + res = curl_easy_perform(curl); + + if(res == CURLE_OK) { + long sockfd; + size_t sent; + /* Extract the socket from the curl handle - we need it for waiting. */ + res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd); + + /* send data */ + res = curl_easy_send(curl, "hello", 5, &sent); + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.18.2. + +# RETURN VALUE + +On success, returns **CURLE_OK** and stores the number of bytes actually +sent into ***n**. Note that this may be less than the amount you wanted to +send. + +On failure, returns the appropriate error code. + +This function may return **CURLE_AGAIN**. In this case, use your operating +system facilities to wait until the socket is writable, and retry. + +If there is no socket available to use from the previous transfer, this function +returns **CURLE_UNSUPPORTED_PROTOCOL**. diff --git a/docs/libcurl/curl_easy_setopt.md b/docs/libcurl/curl_easy_setopt.md new file mode 100644 index 0000000..5724b09 --- /dev/null +++ b/docs/libcurl/curl_easy_setopt.md @@ -0,0 +1,1381 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_setopt +Section: 3 +Source: libcurl +See-also: + - curl_easy_cleanup (3) + - curl_easy_getinfo (3) + - curl_easy_init (3) + - curl_easy_option_by_id (3) + - curl_easy_option_by_name (3) + - curl_easy_option_next (3) + - curl_easy_reset (3) + - curl_multi_setopt (3) +--- + +# NAME + +curl_easy_setopt - set options for a curl easy handle + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter); +~~~ + +# DESCRIPTION + +curl_easy_setopt(3) is used to tell libcurl how to behave. By setting the +appropriate options, the application can change libcurl's behavior. All +options are set with an *option* followed by a *parameter*. That parameter can +be a **long**, a **function pointer**, an **object pointer** or a +**curl_off_t**, depending on what the specific option expects. Read this +manual carefully as bad input values may cause libcurl to behave badly! You +can only set one option in each function call. A typical application uses many +curl_easy_setopt(3) calls in the setup phase. + +Options set with this function call are valid for all forthcoming transfers +performed using this *handle*. The options are not in any way reset between +transfers, so if you want subsequent transfers with different options, you +must change them between the transfers. You can optionally reset all options +back to internal default with curl_easy_reset(3). + +Strings passed to libcurl as 'char *' arguments, are copied by the library; +the string storage associated to the pointer argument may be discarded or +reused after curl_easy_setopt(3) returns. The only exception to this rule is +really CURLOPT_POSTFIELDS(3), but the alternative that copies the string +CURLOPT_COPYPOSTFIELDS(3) has some usage characteristics you need to read up +on. This function does not accept input strings longer than +**CURL_MAX_INPUT_LENGTH** (8 MB). + +The order in which the options are set does not matter. + +Before version 7.17.0, strings were not copied. Instead the user was forced +keep them available until libcurl no longer needed them. + +The *handle* is the return code from a curl_easy_init(3) or +curl_easy_duphandle(3) call. + +# BEHAVIOR OPTIONS + +## CURLOPT_VERBOSE + +Display verbose information. See CURLOPT_VERBOSE(3) + +## CURLOPT_HEADER + +Include the header in the body output. See CURLOPT_HEADER(3) + +## CURLOPT_NOPROGRESS + +Shut off the progress meter. See CURLOPT_NOPROGRESS(3) + +## CURLOPT_NOSIGNAL + +Do not install signal handlers. See CURLOPT_NOSIGNAL(3) + +## CURLOPT_WILDCARDMATCH + +Transfer multiple files according to a filename pattern. See +CURLOPT_WILDCARDMATCH(3) + +# CALLBACK OPTIONS + +## CURLOPT_WRITEFUNCTION + +Callback for writing data. See CURLOPT_WRITEFUNCTION(3) + +## CURLOPT_WRITEDATA + +Data pointer to pass to the write callback. See CURLOPT_WRITEDATA(3) + +## CURLOPT_READFUNCTION + +Callback for reading data. See CURLOPT_READFUNCTION(3) + +## CURLOPT_READDATA + +Data pointer to pass to the read callback. See CURLOPT_READDATA(3) + +## CURLOPT_IOCTLFUNCTION + +**Deprecated option** Callback for I/O operations. +See CURLOPT_IOCTLFUNCTION(3) + +## CURLOPT_IOCTLDATA + +**Deprecated option** Data pointer to pass to the I/O callback. +See CURLOPT_IOCTLDATA(3) + +## CURLOPT_SEEKFUNCTION + +Callback for seek operations. See CURLOPT_SEEKFUNCTION(3) + +## CURLOPT_SEEKDATA + +Data pointer to pass to the seek callback. See CURLOPT_SEEKDATA(3) + +## CURLOPT_SOCKOPTFUNCTION + +Callback for sockopt operations. See CURLOPT_SOCKOPTFUNCTION(3) + +## CURLOPT_SOCKOPTDATA + +Data pointer to pass to the sockopt callback. See CURLOPT_SOCKOPTDATA(3) + +## CURLOPT_OPENSOCKETFUNCTION + +Callback for socket creation. See CURLOPT_OPENSOCKETFUNCTION(3) + +## CURLOPT_OPENSOCKETDATA + +Data pointer to pass to the open socket callback. See CURLOPT_OPENSOCKETDATA(3) + +## CURLOPT_CLOSESOCKETFUNCTION + +Callback for closing socket. See CURLOPT_CLOSESOCKETFUNCTION(3) + +## CURLOPT_CLOSESOCKETDATA + +Data pointer to pass to the close socket callback. See CURLOPT_CLOSESOCKETDATA(3) + +## CURLOPT_PROGRESSFUNCTION + +**OBSOLETE** callback for progress meter. +See CURLOPT_PROGRESSFUNCTION(3) + +## CURLOPT_PROGRESSDATA + +Data pointer to pass to the progress meter callback. See CURLOPT_PROGRESSDATA(3) + +## CURLOPT_XFERINFOFUNCTION + +Callback for progress meter. See CURLOPT_XFERINFOFUNCTION(3) + +## CURLOPT_XFERINFODATA + +Data pointer to pass to the progress meter callback. See CURLOPT_XFERINFODATA(3) + +## CURLOPT_HEADERFUNCTION + +Callback for writing received headers. See CURLOPT_HEADERFUNCTION(3) + +## CURLOPT_HEADERDATA + +Data pointer to pass to the header callback. See CURLOPT_HEADERDATA(3) + +## CURLOPT_DEBUGFUNCTION + +Callback for debug information. See CURLOPT_DEBUGFUNCTION(3) + +## CURLOPT_DEBUGDATA + +Data pointer to pass to the debug callback. See CURLOPT_DEBUGDATA(3) + +## CURLOPT_SSL_CTX_FUNCTION + +Callback for SSL context logic. See CURLOPT_SSL_CTX_FUNCTION(3) + +## CURLOPT_SSL_CTX_DATA + +Data pointer to pass to the SSL context callback. See CURLOPT_SSL_CTX_DATA(3) + +## CURLOPT_CONV_TO_NETWORK_FUNCTION + +**OBSOLETE** Callback for code base conversion. +See CURLOPT_CONV_TO_NETWORK_FUNCTION(3) + +## CURLOPT_CONV_FROM_NETWORK_FUNCTION + +**OBSOLETE** Callback for code base conversion. +See CURLOPT_CONV_FROM_NETWORK_FUNCTION(3) + +## CURLOPT_CONV_FROM_UTF8_FUNCTION + +**OBSOLETE** Callback for code base conversion. +See CURLOPT_CONV_FROM_UTF8_FUNCTION(3) + +## CURLOPT_INTERLEAVEFUNCTION + +Callback for RTSP interleaved data. See CURLOPT_INTERLEAVEFUNCTION(3) + +## CURLOPT_INTERLEAVEDATA + +Data pointer to pass to the RTSP interleave callback. See CURLOPT_INTERLEAVEDATA(3) + +## CURLOPT_CHUNK_BGN_FUNCTION + +Callback for wildcard download start of chunk. See CURLOPT_CHUNK_BGN_FUNCTION(3) + +## CURLOPT_CHUNK_END_FUNCTION + +Callback for wildcard download end of chunk. See CURLOPT_CHUNK_END_FUNCTION(3) + +## CURLOPT_CHUNK_DATA + +Data pointer to pass to the chunk callbacks. See CURLOPT_CHUNK_DATA(3) + +## CURLOPT_FNMATCH_FUNCTION + +Callback for wildcard matching. See CURLOPT_FNMATCH_FUNCTION(3) + +## CURLOPT_FNMATCH_DATA + +Data pointer to pass to the wildcard matching callback. See CURLOPT_FNMATCH_DATA(3) + +## CURLOPT_SUPPRESS_CONNECT_HEADERS + +Suppress proxy CONNECT response headers from user callbacks. See +CURLOPT_SUPPRESS_CONNECT_HEADERS(3) + +## CURLOPT_RESOLVER_START_FUNCTION + +Callback to be called before a new resolve request is started. See +CURLOPT_RESOLVER_START_FUNCTION(3) + +## CURLOPT_RESOLVER_START_DATA + +Data pointer to pass to resolver start callback. See CURLOPT_RESOLVER_START_DATA(3) + +## CURLOPT_PREREQFUNCTION + +Callback to be called after a connection is established but before a request +is made on that connection. See CURLOPT_PREREQFUNCTION(3) + +## CURLOPT_PREREQDATA + +Data pointer to pass to the CURLOPT_PREREQFUNCTION callback. See +CURLOPT_PREREQDATA(3) + +# ERROR OPTIONS + +## CURLOPT_ERRORBUFFER + +Error message buffer. See CURLOPT_ERRORBUFFER(3) + +## CURLOPT_STDERR + +stderr replacement stream. See CURLOPT_STDERR(3) + +## CURLOPT_FAILONERROR + +Fail on HTTP 4xx errors. CURLOPT_FAILONERROR(3) + +## CURLOPT_KEEP_SENDING_ON_ERROR + +Keep sending on HTTP >= 300 errors. CURLOPT_KEEP_SENDING_ON_ERROR(3) + +# NETWORK OPTIONS + +## CURLOPT_URL + +URL to work on. See CURLOPT_URL(3) + +## CURLOPT_PATH_AS_IS + +Disable squashing /../ and /./ sequences in the path. See CURLOPT_PATH_AS_IS(3) + +## CURLOPT_PROTOCOLS + +**Deprecated option** Allowed protocols. See CURLOPT_PROTOCOLS(3) + +## CURLOPT_PROTOCOLS_STR + +Allowed protocols. See CURLOPT_PROTOCOLS_STR(3) + +## CURLOPT_REDIR_PROTOCOLS + +**Deprecated option** Protocols to allow redirects to. See +CURLOPT_REDIR_PROTOCOLS(3) + +## CURLOPT_REDIR_PROTOCOLS_STR + +Protocols to allow redirects to. See CURLOPT_REDIR_PROTOCOLS_STR(3) + +## CURLOPT_DEFAULT_PROTOCOL + +Default protocol. See CURLOPT_DEFAULT_PROTOCOL(3) + +## CURLOPT_PROXY + +Proxy to use. See CURLOPT_PROXY(3) + +## CURLOPT_PRE_PROXY + +Socks proxy to use. See CURLOPT_PRE_PROXY(3) + +## CURLOPT_PROXYPORT + +Proxy port to use. See CURLOPT_PROXYPORT(3) + +## CURLOPT_PROXYTYPE + +Proxy type. See CURLOPT_PROXYTYPE(3) + +## CURLOPT_NOPROXY + +Filter out hosts from proxy use. CURLOPT_NOPROXY(3) + +## CURLOPT_HTTPPROXYTUNNEL + +Tunnel through the HTTP proxy. CURLOPT_HTTPPROXYTUNNEL(3) + +## CURLOPT_CONNECT_TO + +Connect to a specific host and port. See CURLOPT_CONNECT_TO(3) + +## CURLOPT_SOCKS5_AUTH + +Socks5 authentication methods. See CURLOPT_SOCKS5_AUTH(3) + +## CURLOPT_SOCKS5_GSSAPI_SERVICE + +**Deprecated option** Socks5 GSSAPI service name. +See CURLOPT_SOCKS5_GSSAPI_SERVICE(3) + +## CURLOPT_SOCKS5_GSSAPI_NEC + +Socks5 GSSAPI NEC mode. See CURLOPT_SOCKS5_GSSAPI_NEC(3) + +## CURLOPT_PROXY_SERVICE_NAME + +Proxy authentication service name. CURLOPT_PROXY_SERVICE_NAME(3) + +## CURLOPT_HAPROXYPROTOCOL + +Send an HAProxy PROXY protocol v1 header. See CURLOPT_HAPROXYPROTOCOL(3) + +## CURLOPT_HAPROXY_CLIENT_IP + +Spoof the client IP in an HAProxy PROXY protocol v1 header. See +CURLOPT_HAPROXY_CLIENT_IP(3) + +## CURLOPT_SERVICE_NAME + +Authentication service name. CURLOPT_SERVICE_NAME(3) + +## CURLOPT_INTERFACE + +Bind connection locally to this. See CURLOPT_INTERFACE(3) + +## CURLOPT_LOCALPORT + +Bind connection locally to this port. See CURLOPT_LOCALPORT(3) + +## CURLOPT_LOCALPORTRANGE + +Bind connection locally to port range. See CURLOPT_LOCALPORTRANGE(3) + +## CURLOPT_DNS_CACHE_TIMEOUT + +Timeout for DNS cache. See CURLOPT_DNS_CACHE_TIMEOUT(3) + +## CURLOPT_DNS_USE_GLOBAL_CACHE + +**OBSOLETE** Enable global DNS cache. +See CURLOPT_DNS_USE_GLOBAL_CACHE(3) + +## CURLOPT_DOH_URL + +Use this DoH server for name resolves. See CURLOPT_DOH_URL(3) + +## CURLOPT_BUFFERSIZE + +Ask for alternate buffer size. See CURLOPT_BUFFERSIZE(3) + +## CURLOPT_PORT + +Port number to connect to. See CURLOPT_PORT(3) + +## CURLOPT_TCP_FASTOPEN + +Enable TCP Fast Open. See CURLOPT_TCP_FASTOPEN(3) + +## CURLOPT_TCP_NODELAY + +Disable the Nagle algorithm. See CURLOPT_TCP_NODELAY(3) + +## CURLOPT_ADDRESS_SCOPE + +IPv6 scope for local addresses. See CURLOPT_ADDRESS_SCOPE(3) + +## CURLOPT_TCP_KEEPALIVE + +Enable TCP keep-alive. See CURLOPT_TCP_KEEPALIVE(3) + +## CURLOPT_TCP_KEEPIDLE + +Idle time before sending keep-alive. See CURLOPT_TCP_KEEPIDLE(3) + +## CURLOPT_TCP_KEEPINTVL + +Interval between keep-alive probes. See CURLOPT_TCP_KEEPINTVL(3) + +## CURLOPT_UNIX_SOCKET_PATH + +Path to a Unix domain socket. See CURLOPT_UNIX_SOCKET_PATH(3) + +## CURLOPT_ABSTRACT_UNIX_SOCKET + +Path to an abstract Unix domain socket. See CURLOPT_ABSTRACT_UNIX_SOCKET(3) + +# NAMES and PASSWORDS OPTIONS (Authentication) + +## CURLOPT_NETRC + +Enable .netrc parsing. See CURLOPT_NETRC(3) + +## CURLOPT_NETRC_FILE + +.netrc filename. See CURLOPT_NETRC_FILE(3) + +## CURLOPT_USERPWD + +User name and password. See CURLOPT_USERPWD(3) + +## CURLOPT_PROXYUSERPWD + +Proxy user name and password. See CURLOPT_PROXYUSERPWD(3) + +## CURLOPT_USERNAME + +User name. See CURLOPT_USERNAME(3) + +## CURLOPT_PASSWORD + +Password. See CURLOPT_PASSWORD(3) + +## CURLOPT_LOGIN_OPTIONS + +Login options. See CURLOPT_LOGIN_OPTIONS(3) + +## CURLOPT_PROXYUSERNAME + +Proxy user name. See CURLOPT_PROXYUSERNAME(3) + +## CURLOPT_PROXYPASSWORD + +Proxy password. See CURLOPT_PROXYPASSWORD(3) + +## CURLOPT_HTTPAUTH + +HTTP server authentication methods. See CURLOPT_HTTPAUTH(3) + +## CURLOPT_TLSAUTH_USERNAME + +TLS authentication user name. See CURLOPT_TLSAUTH_USERNAME(3) + +## CURLOPT_PROXY_TLSAUTH_USERNAME + +Proxy TLS authentication user name. See CURLOPT_PROXY_TLSAUTH_USERNAME(3) + +## CURLOPT_TLSAUTH_PASSWORD + +TLS authentication password. See CURLOPT_TLSAUTH_PASSWORD(3) + +## CURLOPT_PROXY_TLSAUTH_PASSWORD + +Proxy TLS authentication password. See CURLOPT_PROXY_TLSAUTH_PASSWORD(3) + +## CURLOPT_TLSAUTH_TYPE + +TLS authentication methods. See CURLOPT_TLSAUTH_TYPE(3) + +## CURLOPT_PROXY_TLSAUTH_TYPE + +Proxy TLS authentication methods. See CURLOPT_PROXY_TLSAUTH_TYPE(3) + +## CURLOPT_PROXYAUTH + +HTTP proxy authentication methods. See CURLOPT_PROXYAUTH(3) + +## CURLOPT_SASL_AUTHZID + +SASL authorization identity (identity to act as). See CURLOPT_SASL_AUTHZID(3) + +## CURLOPT_SASL_IR + +Enable SASL initial response. See CURLOPT_SASL_IR(3) + +## CURLOPT_XOAUTH2_BEARER + +OAuth2 bearer token. See CURLOPT_XOAUTH2_BEARER(3) + +## CURLOPT_DISALLOW_USERNAME_IN_URL + +Do not allow username in URL. See CURLOPT_DISALLOW_USERNAME_IN_URL(3) + +# HTTP OPTIONS + +## CURLOPT_AUTOREFERER + +Automatically set Referer: header. See CURLOPT_AUTOREFERER(3) + +## CURLOPT_ACCEPT_ENCODING + +Accept-Encoding and automatic decompressing data. See CURLOPT_ACCEPT_ENCODING(3) + +## CURLOPT_TRANSFER_ENCODING + +Request Transfer-Encoding. See CURLOPT_TRANSFER_ENCODING(3) + +## CURLOPT_FOLLOWLOCATION + +Follow HTTP redirects. See CURLOPT_FOLLOWLOCATION(3) + +## CURLOPT_UNRESTRICTED_AUTH + +Do not restrict authentication to original host. CURLOPT_UNRESTRICTED_AUTH(3) + +## CURLOPT_MAXREDIRS + +Maximum number of redirects to follow. See CURLOPT_MAXREDIRS(3) + +## CURLOPT_POSTREDIR + +How to act on redirects after POST. See CURLOPT_POSTREDIR(3) + +## CURLOPT_PUT + +**Deprecated option** Issue an HTTP PUT request. See CURLOPT_PUT(3) + +## CURLOPT_POST + +Issue an HTTP POST request. See CURLOPT_POST(3) + +## CURLOPT_POSTFIELDS + +Send a POST with this data. See CURLOPT_POSTFIELDS(3) + +## CURLOPT_POSTFIELDSIZE + +The POST data is this big. See CURLOPT_POSTFIELDSIZE(3) + +## CURLOPT_POSTFIELDSIZE_LARGE + +The POST data is this big. See CURLOPT_POSTFIELDSIZE_LARGE(3) + +## CURLOPT_COPYPOSTFIELDS + +Send a POST with this data - and copy it. See CURLOPT_COPYPOSTFIELDS(3) + +## CURLOPT_HTTPPOST + +**Deprecated option** Multipart formpost HTTP POST. +See CURLOPT_HTTPPOST(3) + +## CURLOPT_REFERER + +Referer: header. See CURLOPT_REFERER(3) + +## CURLOPT_USERAGENT + +User-Agent: header. See CURLOPT_USERAGENT(3) + +## CURLOPT_HTTPHEADER + +Custom HTTP headers. See CURLOPT_HTTPHEADER(3) + +## CURLOPT_HEADEROPT + +Control custom headers. See CURLOPT_HEADEROPT(3) + +## CURLOPT_PROXYHEADER + +Custom HTTP headers sent to proxy. See CURLOPT_PROXYHEADER(3) + +## CURLOPT_HTTP200ALIASES + +Alternative versions of 200 OK. See CURLOPT_HTTP200ALIASES(3) + +## CURLOPT_COOKIE + +Cookie(s) to send. See CURLOPT_COOKIE(3) + +## CURLOPT_COOKIEFILE + +File to read cookies from. See CURLOPT_COOKIEFILE(3) + +## CURLOPT_COOKIEJAR + +File to write cookies to. See CURLOPT_COOKIEJAR(3) + +## CURLOPT_COOKIESESSION + +Start a new cookie session. See CURLOPT_COOKIESESSION(3) + +## CURLOPT_COOKIELIST + +Add or control cookies. See CURLOPT_COOKIELIST(3) + +## CURLOPT_ALTSVC + +Specify the Alt-Svc: cache filename. See CURLOPT_ALTSVC(3) + +## CURLOPT_ALTSVC_CTRL + +Enable and configure Alt-Svc: treatment. See CURLOPT_ALTSVC_CTRL(3) + +## CURLOPT_HSTS + +Set HSTS cache file. See CURLOPT_HSTS(3) + +## CURLOPT_HSTS_CTRL + +Enable HSTS. See CURLOPT_HSTS_CTRL(3) + +## CURLOPT_HSTSREADFUNCTION + +Set HSTS read callback. See CURLOPT_HSTSREADFUNCTION(3) + +## CURLOPT_HSTSREADDATA + +Pass pointer to the HSTS read callback. See CURLOPT_HSTSREADDATA(3) + +## CURLOPT_HSTSWRITEFUNCTION + +Set HSTS write callback. See CURLOPT_HSTSWRITEFUNCTION(3) + +## CURLOPT_HSTSWRITEDATA + +Pass pointer to the HSTS write callback. See CURLOPT_HSTSWRITEDATA(3) + +## CURLOPT_HTTPGET + +Do an HTTP GET request. See CURLOPT_HTTPGET(3) + +## CURLOPT_REQUEST_TARGET + +Set the request target. CURLOPT_REQUEST_TARGET(3) + +## CURLOPT_HTTP_VERSION + +HTTP version to use. CURLOPT_HTTP_VERSION(3) + +## CURLOPT_HTTP09_ALLOWED + +Allow HTTP/0.9 responses. CURLOPT_HTTP09_ALLOWED(3) + +## CURLOPT_IGNORE_CONTENT_LENGTH + +Ignore Content-Length. See CURLOPT_IGNORE_CONTENT_LENGTH(3) + +## CURLOPT_HTTP_CONTENT_DECODING + +Disable Content decoding. See CURLOPT_HTTP_CONTENT_DECODING(3) + +## CURLOPT_HTTP_TRANSFER_DECODING + +Disable Transfer decoding. See CURLOPT_HTTP_TRANSFER_DECODING(3) + +## CURLOPT_EXPECT_100_TIMEOUT_MS + +100-continue timeout. See CURLOPT_EXPECT_100_TIMEOUT_MS(3) + +## CURLOPT_TRAILERFUNCTION + +Set callback for sending trailing headers. See +CURLOPT_TRAILERFUNCTION(3) + +## CURLOPT_TRAILERDATA + +Custom pointer passed to the trailing headers callback. See +CURLOPT_TRAILERDATA(3) + +## CURLOPT_PIPEWAIT + +Wait on connection to pipeline on it. See CURLOPT_PIPEWAIT(3) + +## CURLOPT_STREAM_DEPENDS + +This HTTP/2 stream depends on another. See CURLOPT_STREAM_DEPENDS(3) + +## CURLOPT_STREAM_DEPENDS_E + +This HTTP/2 stream depends on another exclusively. See +CURLOPT_STREAM_DEPENDS_E(3) + +## CURLOPT_STREAM_WEIGHT + +Set this HTTP/2 stream's weight. See CURLOPT_STREAM_WEIGHT(3) + +# SMTP OPTIONS + +## CURLOPT_MAIL_FROM + +Address of the sender. See CURLOPT_MAIL_FROM(3) + +## CURLOPT_MAIL_RCPT + +Address of the recipients. See CURLOPT_MAIL_RCPT(3) + +## CURLOPT_MAIL_AUTH + +Authentication address. See CURLOPT_MAIL_AUTH(3) + +## CURLOPT_MAIL_RCPT_ALLOWFAILS + +Allow RCPT TO command to fail for some recipients. See +CURLOPT_MAIL_RCPT_ALLOWFAILS(3) + +# TFTP OPTIONS + +## CURLOPT_TFTP_BLKSIZE + +TFTP block size. See CURLOPT_TFTP_BLKSIZE(3) + +## CURLOPT_TFTP_NO_OPTIONS + +Do not send TFTP options requests. See CURLOPT_TFTP_NO_OPTIONS(3) + +# FTP OPTIONS + +## CURLOPT_FTPPORT + +Use active FTP. See CURLOPT_FTPPORT(3) + +## CURLOPT_QUOTE + +Commands to run before transfer. See CURLOPT_QUOTE(3) + +## CURLOPT_POSTQUOTE + +Commands to run after transfer. See CURLOPT_POSTQUOTE(3) + +## CURLOPT_PREQUOTE + +Commands to run just before transfer. See CURLOPT_PREQUOTE(3) + +## CURLOPT_APPEND + +Append to remote file. See CURLOPT_APPEND(3) + +## CURLOPT_FTP_USE_EPRT + +Use EPRT. See CURLOPT_FTP_USE_EPRT(3) + +## CURLOPT_FTP_USE_EPSV + +Use EPSV. See CURLOPT_FTP_USE_EPSV(3) + +## CURLOPT_FTP_USE_PRET + +Use PRET. See CURLOPT_FTP_USE_PRET(3) + +## CURLOPT_FTP_CREATE_MISSING_DIRS + +Create missing directories on the remote server. See CURLOPT_FTP_CREATE_MISSING_DIRS(3) + +## CURLOPT_SERVER_RESPONSE_TIMEOUT + +Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT(3) + +## CURLOPT_SERVER_RESPONSE_TIMEOUT_MS + +Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3) + +## CURLOPT_FTP_ALTERNATIVE_TO_USER + +Alternative to USER. See CURLOPT_FTP_ALTERNATIVE_TO_USER(3) + +## CURLOPT_FTP_SKIP_PASV_IP + +Ignore the IP address in the PASV response. See CURLOPT_FTP_SKIP_PASV_IP(3) + +## CURLOPT_FTPSSLAUTH + +Control how to do TLS. See CURLOPT_FTPSSLAUTH(3) + +## CURLOPT_FTP_SSL_CCC + +Back to non-TLS again after authentication. See CURLOPT_FTP_SSL_CCC(3) + +## CURLOPT_FTP_ACCOUNT + +Send ACCT command. See CURLOPT_FTP_ACCOUNT(3) + +## CURLOPT_FTP_FILEMETHOD + +Specify how to reach files. See CURLOPT_FTP_FILEMETHOD(3) + +# RTSP OPTIONS + +## CURLOPT_RTSP_REQUEST + +RTSP request. See CURLOPT_RTSP_REQUEST(3) + +## CURLOPT_RTSP_SESSION_ID + +RTSP session-id. See CURLOPT_RTSP_SESSION_ID(3) + +## CURLOPT_RTSP_STREAM_URI + +RTSP stream URI. See CURLOPT_RTSP_STREAM_URI(3) + +## CURLOPT_RTSP_TRANSPORT + +RTSP Transport: header. See CURLOPT_RTSP_TRANSPORT(3) + +## CURLOPT_RTSP_CLIENT_CSEQ + +Client CSEQ number. See CURLOPT_RTSP_CLIENT_CSEQ(3) + +## CURLOPT_RTSP_SERVER_CSEQ + +CSEQ number for RTSP Server->Client request. See CURLOPT_RTSP_SERVER_CSEQ(3) + +## CURLOPT_AWS_SIGV4 + +AWS HTTP V4 Signature. See CURLOPT_AWS_SIGV4(3) + +# PROTOCOL OPTIONS + +## CURLOPT_TRANSFERTEXT + +Use text transfer. See CURLOPT_TRANSFERTEXT(3) + +## CURLOPT_PROXY_TRANSFER_MODE + +Add transfer mode to URL over proxy. See CURLOPT_PROXY_TRANSFER_MODE(3) + +## CURLOPT_CRLF + +Convert newlines. See CURLOPT_CRLF(3) + +## CURLOPT_RANGE + +Range requests. See CURLOPT_RANGE(3) + +## CURLOPT_RESUME_FROM + +Resume a transfer. See CURLOPT_RESUME_FROM(3) + +## CURLOPT_RESUME_FROM_LARGE + +Resume a transfer. See CURLOPT_RESUME_FROM_LARGE(3) + +## CURLOPT_CURLU + +Set URL to work on with a URL handle. See CURLOPT_CURLU(3) + +## CURLOPT_CUSTOMREQUEST + +Custom request/method. See CURLOPT_CUSTOMREQUEST(3) + +## CURLOPT_FILETIME + +Request file modification date and time. See CURLOPT_FILETIME(3) + +## CURLOPT_DIRLISTONLY + +List only. See CURLOPT_DIRLISTONLY(3) + +## CURLOPT_NOBODY + +Do not get the body contents. See CURLOPT_NOBODY(3) + +## CURLOPT_INFILESIZE + +Size of file to send. CURLOPT_INFILESIZE(3) + +## CURLOPT_INFILESIZE_LARGE + +Size of file to send. CURLOPT_INFILESIZE_LARGE(3) + +## CURLOPT_UPLOAD + +Upload data. See CURLOPT_UPLOAD(3) + +## CURLOPT_UPLOAD_BUFFERSIZE + +Set upload buffer size. See CURLOPT_UPLOAD_BUFFERSIZE(3) + +## CURLOPT_MIMEPOST + +Post/send MIME data. See CURLOPT_MIMEPOST(3) + +## CURLOPT_MIME_OPTIONS + +Set MIME option flags. See CURLOPT_MIME_OPTIONS(3) + +## CURLOPT_MAXFILESIZE + +Maximum file size to get. See CURLOPT_MAXFILESIZE(3) + +## CURLOPT_MAXFILESIZE_LARGE + +Maximum file size to get. See CURLOPT_MAXFILESIZE_LARGE(3) + +## CURLOPT_TIMECONDITION + +Make a time conditional request. See CURLOPT_TIMECONDITION(3) + +## CURLOPT_TIMEVALUE + +Time value for the time conditional request. See CURLOPT_TIMEVALUE(3) + +## CURLOPT_TIMEVALUE_LARGE + +Time value for the time conditional request. See CURLOPT_TIMEVALUE_LARGE(3) + +# CONNECTION OPTIONS + +## CURLOPT_TIMEOUT + +Timeout for the entire request. See CURLOPT_TIMEOUT(3) + +## CURLOPT_TIMEOUT_MS + +Millisecond timeout for the entire request. See CURLOPT_TIMEOUT_MS(3) + +## CURLOPT_LOW_SPEED_LIMIT + +Low speed limit to abort transfer. See CURLOPT_LOW_SPEED_LIMIT(3) + +## CURLOPT_LOW_SPEED_TIME + +Time to be below the speed to trigger low speed abort. See CURLOPT_LOW_SPEED_TIME(3) + +## CURLOPT_MAX_SEND_SPEED_LARGE + +Cap the upload speed to this. See CURLOPT_MAX_SEND_SPEED_LARGE(3) + +## CURLOPT_MAX_RECV_SPEED_LARGE + +Cap the download speed to this. See CURLOPT_MAX_RECV_SPEED_LARGE(3) + +## CURLOPT_MAXCONNECTS + +Maximum number of connections in the connection pool. See CURLOPT_MAXCONNECTS(3) + +## CURLOPT_FRESH_CONNECT + +Use a new connection. CURLOPT_FRESH_CONNECT(3) + +## CURLOPT_FORBID_REUSE + +Prevent subsequent connections from reusing this. See CURLOPT_FORBID_REUSE(3) + +## CURLOPT_MAXAGE_CONN + +Limit the age (idle time) of connections for reuse. See CURLOPT_MAXAGE_CONN(3) + +## CURLOPT_MAXLIFETIME_CONN + +Limit the age (since creation) of connections for reuse. See +CURLOPT_MAXLIFETIME_CONN(3) + +## CURLOPT_CONNECTTIMEOUT + +Timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT(3) + +## CURLOPT_CONNECTTIMEOUT_MS + +Millisecond timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT_MS(3) + +## CURLOPT_IPRESOLVE + +IP version to use. See CURLOPT_IPRESOLVE(3) + +## CURLOPT_CONNECT_ONLY + +Only connect, nothing else. See CURLOPT_CONNECT_ONLY(3) + +## CURLOPT_USE_SSL + +Use TLS/SSL. See CURLOPT_USE_SSL(3) + +## CURLOPT_RESOLVE + +Provide fixed/fake name resolves. See CURLOPT_RESOLVE(3) + +## CURLOPT_DNS_INTERFACE + +Bind name resolves to this interface. See CURLOPT_DNS_INTERFACE(3) + +## CURLOPT_DNS_LOCAL_IP4 + +Bind name resolves to this IP4 address. See CURLOPT_DNS_LOCAL_IP4(3) + +## CURLOPT_DNS_LOCAL_IP6 + +Bind name resolves to this IP6 address. See CURLOPT_DNS_LOCAL_IP6(3) + +## CURLOPT_DNS_SERVERS + +Preferred DNS servers. See CURLOPT_DNS_SERVERS(3) + +## CURLOPT_DNS_SHUFFLE_ADDRESSES + +Shuffle addresses before use. See CURLOPT_DNS_SHUFFLE_ADDRESSES(3) + +## CURLOPT_ACCEPTTIMEOUT_MS + +Timeout for waiting for the server's connect back to be accepted. See +CURLOPT_ACCEPTTIMEOUT_MS(3) + +## CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS + +Timeout for happy eyeballs. See CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3) + +## CURLOPT_UPKEEP_INTERVAL_MS + +Sets the interval at which connection upkeep are performed. See +CURLOPT_UPKEEP_INTERVAL_MS(3) + +# SSL and SECURITY OPTIONS + +## CURLOPT_SSLCERT + +Client cert. See CURLOPT_SSLCERT(3) + +## CURLOPT_SSLCERT_BLOB + +Client cert memory buffer. See CURLOPT_SSLCERT_BLOB(3) + +## CURLOPT_PROXY_SSLCERT + +Proxy client cert. See CURLOPT_PROXY_SSLCERT(3) + +## CURLOPT_PROXY_SSLCERT_BLOB + +Proxy client cert memory buffer. See CURLOPT_PROXY_SSLCERT_BLOB(3) + +## CURLOPT_SSLCERTTYPE + +Client cert type. See CURLOPT_SSLCERTTYPE(3) + +## CURLOPT_PROXY_SSLCERTTYPE + +Proxy client cert type. See CURLOPT_PROXY_SSLCERTTYPE(3) + +## CURLOPT_SSLKEY + +Client key. See CURLOPT_SSLKEY(3) + +## CURLOPT_SSLKEY_BLOB + +Client key memory buffer. See CURLOPT_SSLKEY_BLOB(3) + +## CURLOPT_PROXY_SSLKEY + +Proxy client key. See CURLOPT_PROXY_SSLKEY(3) + +## CURLOPT_PROXY_SSLKEY_BLOB + +Proxy client key. See CURLOPT_PROXY_SSLKEY_BLOB(3) + +## CURLOPT_SSLKEYTYPE + +Client key type. See CURLOPT_SSLKEYTYPE(3) + +## CURLOPT_PROXY_SSLKEYTYPE + +Proxy client key type. See CURLOPT_PROXY_SSLKEYTYPE(3) + +## CURLOPT_KEYPASSWD + +Client key password. See CURLOPT_KEYPASSWD(3) + +## CURLOPT_PROXY_KEYPASSWD + +Proxy client key password. See CURLOPT_PROXY_KEYPASSWD(3) + +## CURLOPT_SSL_EC_CURVES + +Set key exchange curves. See CURLOPT_SSL_EC_CURVES(3) + +## CURLOPT_SSL_ENABLE_ALPN + +Enable use of ALPN. See CURLOPT_SSL_ENABLE_ALPN(3) + +## CURLOPT_SSL_ENABLE_NPN + +**OBSOLETE** Enable use of NPN. See CURLOPT_SSL_ENABLE_NPN(3) + +## CURLOPT_SSLENGINE + +Use identifier with SSL engine. See CURLOPT_SSLENGINE(3) + +## CURLOPT_SSLENGINE_DEFAULT + +Default SSL engine. See CURLOPT_SSLENGINE_DEFAULT(3) + +## CURLOPT_SSL_FALSESTART + +Enable TLS False Start. See CURLOPT_SSL_FALSESTART(3) + +## CURLOPT_SSLVERSION + +SSL version to use. See CURLOPT_SSLVERSION(3) + +## CURLOPT_PROXY_SSLVERSION + +Proxy SSL version to use. See CURLOPT_PROXY_SSLVERSION(3) + +## CURLOPT_SSL_VERIFYHOST + +Verify the hostname in the SSL certificate. See CURLOPT_SSL_VERIFYHOST(3) + +## CURLOPT_DOH_SSL_VERIFYHOST + +Verify the hostname in the DoH (DNS-over-HTTPS) SSL certificate. See +CURLOPT_DOH_SSL_VERIFYHOST(3) + +## CURLOPT_PROXY_SSL_VERIFYHOST + +Verify the hostname in the proxy SSL certificate. See +CURLOPT_PROXY_SSL_VERIFYHOST(3) + +## CURLOPT_SSL_VERIFYPEER + +Verify the SSL certificate. See CURLOPT_SSL_VERIFYPEER(3) + +## CURLOPT_DOH_SSL_VERIFYPEER + +Verify the DoH (DNS-over-HTTPS) SSL certificate. See +CURLOPT_DOH_SSL_VERIFYPEER(3) + +## CURLOPT_PROXY_SSL_VERIFYPEER + +Verify the proxy SSL certificate. See CURLOPT_PROXY_SSL_VERIFYPEER(3) + +## CURLOPT_SSL_VERIFYSTATUS + +Verify the SSL certificate's status. See CURLOPT_SSL_VERIFYSTATUS(3) + +## CURLOPT_DOH_SSL_VERIFYSTATUS + +Verify the DoH (DNS-over-HTTPS) SSL certificate's status. See +CURLOPT_DOH_SSL_VERIFYSTATUS(3) + +## CURLOPT_CAINFO + +CA cert bundle. See CURLOPT_CAINFO(3) + +## CURLOPT_CAINFO_BLOB + +CA cert bundle memory buffer. See CURLOPT_CAINFO_BLOB(3) + +## CURLOPT_PROXY_CAINFO + +Proxy CA cert bundle. See CURLOPT_PROXY_CAINFO(3) + +## CURLOPT_PROXY_CAINFO_BLOB + +Proxy CA cert bundle memory buffer. See CURLOPT_PROXY_CAINFO_BLOB(3) + +## CURLOPT_ISSUERCERT + +Issuer certificate. See CURLOPT_ISSUERCERT(3) + +## CURLOPT_ISSUERCERT_BLOB + +Issuer certificate memory buffer. See CURLOPT_ISSUERCERT_BLOB(3) + +## CURLOPT_PROXY_ISSUERCERT + +Proxy issuer certificate. See CURLOPT_PROXY_ISSUERCERT(3) + +## CURLOPT_PROXY_ISSUERCERT_BLOB + +Proxy issuer certificate memory buffer. See CURLOPT_PROXY_ISSUERCERT_BLOB(3) + +## CURLOPT_CAPATH + +Path to CA cert bundle. See CURLOPT_CAPATH(3) + +## CURLOPT_PROXY_CAPATH + +Path to proxy CA cert bundle. See CURLOPT_PROXY_CAPATH(3) + +## CURLOPT_CRLFILE + +Certificate Revocation List. See CURLOPT_CRLFILE(3) + +## CURLOPT_PROXY_CRLFILE + +Proxy Certificate Revocation List. See CURLOPT_PROXY_CRLFILE(3) + +## CURLOPT_CA_CACHE_TIMEOUT + +Timeout for CA cache. See CURLOPT_CA_CACHE_TIMEOUT(3) + +## CURLOPT_CERTINFO + +Extract certificate info. See CURLOPT_CERTINFO(3) + +## CURLOPT_PINNEDPUBLICKEY + +Set pinned SSL public key . See CURLOPT_PINNEDPUBLICKEY(3) + +## CURLOPT_PROXY_PINNEDPUBLICKEY + +Set the proxy's pinned SSL public key. See +CURLOPT_PROXY_PINNEDPUBLICKEY(3) + +## CURLOPT_RANDOM_FILE + +**OBSOLETE** Provide source for entropy random data. +See CURLOPT_RANDOM_FILE(3) + +## CURLOPT_EGDSOCKET + +**OBSOLETE** Identify EGD socket for entropy. See CURLOPT_EGDSOCKET(3) + +## CURLOPT_SSL_CIPHER_LIST + +Ciphers to use. See CURLOPT_SSL_CIPHER_LIST(3) + +## CURLOPT_PROXY_SSL_CIPHER_LIST + +Proxy ciphers to use. See CURLOPT_PROXY_SSL_CIPHER_LIST(3) + +## CURLOPT_TLS13_CIPHERS + +TLS 1.3 cipher suites to use. See CURLOPT_TLS13_CIPHERS(3) + +## CURLOPT_PROXY_TLS13_CIPHERS + +Proxy TLS 1.3 cipher suites to use. See CURLOPT_PROXY_TLS13_CIPHERS(3) + +## CURLOPT_SSL_SESSIONID_CACHE + +Disable SSL session-id cache. See CURLOPT_SSL_SESSIONID_CACHE(3) + +## CURLOPT_SSL_OPTIONS + +Control SSL behavior. See CURLOPT_SSL_OPTIONS(3) + +## CURLOPT_PROXY_SSL_OPTIONS + +Control proxy SSL behavior. See CURLOPT_PROXY_SSL_OPTIONS(3) + +## CURLOPT_KRBLEVEL + +Kerberos security level. See CURLOPT_KRBLEVEL(3) + +## CURLOPT_GSSAPI_DELEGATION + +Disable GSS-API delegation. See CURLOPT_GSSAPI_DELEGATION(3) + +# SSH OPTIONS + +## CURLOPT_SSH_AUTH_TYPES + +SSH authentication types. See CURLOPT_SSH_AUTH_TYPES(3) + +## CURLOPT_SSH_COMPRESSION + +Enable SSH compression. See CURLOPT_SSH_COMPRESSION(3) + +## CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 + +MD5 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3) + +## CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 + +SHA256 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3) + +## CURLOPT_SSH_PUBLIC_KEYFILE + +Filename of the public key. See CURLOPT_SSH_PUBLIC_KEYFILE(3) + +## CURLOPT_SSH_PRIVATE_KEYFILE + +Filename of the private key. See CURLOPT_SSH_PRIVATE_KEYFILE(3) + +## CURLOPT_SSH_KNOWNHOSTS + +Filename with known hosts. See CURLOPT_SSH_KNOWNHOSTS(3) + +## CURLOPT_SSH_KEYFUNCTION + +Callback for known hosts handling. See CURLOPT_SSH_KEYFUNCTION(3) + +## CURLOPT_SSH_KEYDATA + +Custom pointer to pass to ssh key callback. See CURLOPT_SSH_KEYDATA(3) + +## CURLOPT_SSH_HOSTKEYFUNCTION + +Callback for checking host key handling. See CURLOPT_SSH_HOSTKEYFUNCTION(3) + +## CURLOPT_SSH_HOSTKEYDATA + +Custom pointer to pass to ssh host key callback. See CURLOPT_SSH_HOSTKEYDATA(3) + +# WEBSOCKET + +## CURLOPT_WS_OPTIONS + +Set WebSocket options. See CURLOPT_WS_OPTIONS(3) + +# OTHER OPTIONS + +## CURLOPT_PRIVATE + +Private pointer to store. See CURLOPT_PRIVATE(3) + +## CURLOPT_SHARE + +Share object to use. See CURLOPT_SHARE(3) + +## CURLOPT_NEW_FILE_PERMS + +Mode for creating new remote files. See CURLOPT_NEW_FILE_PERMS(3) + +## CURLOPT_NEW_DIRECTORY_PERMS + +Mode for creating new remote directories. See CURLOPT_NEW_DIRECTORY_PERMS(3) + +## CURLOPT_QUICK_EXIT + +To be set by toplevel tools like "curl" to skip lengthy cleanups when they are +about to call exit() anyway. See CURLOPT_QUICK_EXIT(3) + +# TELNET OPTIONS + +## CURLOPT_TELNETOPTIONS + +TELNET options. See CURLOPT_TELNETOPTIONS(3) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +*CURLE_OK* (zero) means that the option was set properly, non-zero means an +error occurred as ** defines. See the libcurl-errors(3) man page +for the full list with descriptions. + +Strings passed on to libcurl must be shorter than 8000000 bytes, otherwise +curl_easy_setopt(3) returns **CURLE_BAD_FUNCTION_ARGUMENT** (added in 7.65.0). + +**CURLE_BAD_FUNCTION_ARGUMENT** is returned when the argument to an option is +invalid, like perhaps out of range. + +If you try to set an option that libcurl does not know about, perhaps because +the library is too old to support it or the option was removed in a recent +version, this function returns *CURLE_UNKNOWN_OPTION*. If support for the +option was disabled at compile-time, it returns *CURLE_NOT_BUILT_IN*. diff --git a/docs/libcurl/curl_easy_strerror.md b/docs/libcurl/curl_easy_strerror.md new file mode 100644 index 0000000..218601a --- /dev/null +++ b/docs/libcurl/curl_easy_strerror.md @@ -0,0 +1,59 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_strerror +Section: 3 +Source: libcurl +See-also: + - curl_multi_strerror (3) + - curl_share_strerror (3) + - curl_url_strerror (3) + - libcurl-errors (3) +--- + +# NAME + +curl_easy_strerror - return string describing error code + +# SYNOPSIS + +~~~c +#include + +const char *curl_easy_strerror(CURLcode errornum); +~~~ + +# DESCRIPTION + +The curl_easy_strerror(3) function returns a string describing the +CURLcode error code passed in the argument *errornum*. + +Typically applications also appreciate CURLOPT_ERRORBUFFER(3) for more +specific error descriptions generated at runtime. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + /* set options */ + /* Perform the entire transfer */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.12.0 + +# RETURN VALUE + +A pointer to a null-terminated string. diff --git a/docs/libcurl/curl_easy_unescape.md b/docs/libcurl/curl_easy_unescape.md new file mode 100644 index 0000000..4f9262b --- /dev/null +++ b/docs/libcurl/curl_easy_unescape.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_unescape +Section: 3 +Source: libcurl +See-also: + - curl_easy_escape (3) + - curl_free (3) +--- + +# NAME + +curl_easy_unescape - URL decodes the given string + +# SYNOPSIS + +~~~c +#include + +char *curl_easy_unescape(CURL *curl, const char *input, + int inlength, int *outlength); +~~~ + +# DESCRIPTION + +This function converts the URL encoded string **input** to a "plain string" +and returns that in an allocated memory area. All input characters that are URL +encoded (%XX where XX is a two-digit hexadecimal number) are converted to their +binary versions. + +If the **length** argument is set to 0 (zero), curl_easy_unescape(3) +uses strlen() on **input** to find out the size. + +If **outlength** is non-NULL, the function writes the length of the returned +string in the integer it points to. This allows proper handling even for +strings containing %00. Since this is a pointer to an *int* type, it can +only return a value up to *INT_MAX* so no longer string can be returned in +this parameter. + +Since 7.82.0, the **curl** parameter is ignored. Prior to that there was +per-handle character conversion support for some old operating systems such as +TPF, but it was otherwise ignored. + +You must curl_free(3) the returned string when you are done with it. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + int decodelen; + char *decoded = curl_easy_unescape(curl, "%63%75%72%6c", 12, &decodelen); + if(decoded) { + /* do not assume printf() works on the decoded data! */ + printf("Decoded: "); + /* ... */ + curl_free(decoded); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.4 and replaces the old curl_unescape(3) function. + +# RETURN VALUE + +A pointer to a null-terminated string or NULL if it failed. diff --git a/docs/libcurl/curl_easy_upkeep.md b/docs/libcurl/curl_easy_upkeep.md new file mode 100644 index 0000000..2ad89d3 --- /dev/null +++ b/docs/libcurl/curl_easy_upkeep.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_easy_upkeep +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TCP_KEEPALIVE (3) + - CURLOPT_TCP_KEEPIDLE (3) +--- + +# NAME + +curl_easy_upkeep - Perform any connection upkeep checks. + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_upkeep(CURL *handle); +~~~ + +# DESCRIPTION + +Some protocols have "connection upkeep" mechanisms. These mechanisms usually +send some traffic on existing connections in order to keep them alive; this +can prevent connections from being closed due to overzealous firewalls, for +example. + +Currently the only protocol with a connection upkeep mechanism is HTTP/2: when +the connection upkeep interval is exceeded and curl_easy_upkeep(3) +is called, an HTTP/2 PING frame is sent on the connection. + +This function must be explicitly called in order to perform the upkeep work. +The connection upkeep interval is set with +CURLOPT_UPKEEP_INTERVAL_MS(3). + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* Make a connection to an HTTP/2 server. */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the interval to 30000ms / 30s */ + curl_easy_setopt(curl, CURLOPT_UPKEEP_INTERVAL_MS, 30000L); + + curl_easy_perform(curl); + + /* Perform more work here. */ + + /* While the connection is being held open, curl_easy_upkeep() can be + called. If curl_easy_upkeep() is called and the time since the last + upkeep exceeds the interval, then an HTTP/2 PING is sent. */ + curl_easy_upkeep(curl); + + /* Perform more work here. */ + + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.62.0. + +# RETURN VALUE + +On success, returns **CURLE_OK**. + +On failure, returns the appropriate error code. diff --git a/docs/libcurl/curl_escape.md b/docs/libcurl/curl_escape.md new file mode 100644 index 0000000..e5e7e92 --- /dev/null +++ b/docs/libcurl/curl_escape.md @@ -0,0 +1,58 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_escape +Section: 3 +Source: libcurl +See-also: + - curl_free (3) + - curl_unescape (3) +--- + +# NAME + +curl_escape - URL encodes the given string + +# SYNOPSIS + +~~~c +#include + +char *curl_escape(const char *string, int length); +~~~ + +# DESCRIPTION + +Obsolete function. Use curl_easy_escape(3) instead! + +This function converts the given input **string** to a URL encoded string +and return that as a new allocated string. All input characters that are not +a-z, A-Z or 0-9 are converted to their "URL escaped" version (**%NN** where +**NN** is a two-digit hexadecimal number). + +If the **length** argument is set to 0, curl_escape(3) uses strlen() +on **string** to find out the size. + +You must curl_free(3) the returned string when you are done with it. + +# EXAMPLE + +~~~c +int main(void) +{ + char *output = curl_escape("data to convert", 15); + if(output) { + printf("Encoded: %s\n", output); + curl_free(output); + } +} +~~~ + +# AVAILABILITY + +Since 7.15.4, curl_easy_escape(3) should be used. This function might be +removed in a future release. + +# RETURN VALUE + +A pointer to a null-terminated string or NULL if it failed. diff --git a/docs/libcurl/curl_formadd.md b/docs/libcurl/curl_formadd.md new file mode 100644 index 0000000..3793df8 --- /dev/null +++ b/docs/libcurl/curl_formadd.md @@ -0,0 +1,313 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_formadd +Section: 3 +Source: libcurl +See-also: + - curl_easy_setopt (3) + - curl_formfree (3) + - curl_mime_init (3) +--- + +# NAME + +curl_formadd - add a section to a multipart form POST + +# SYNOPSIS + +~~~c +#include + +CURLFORMcode curl_formadd(struct curl_httppost **firstitem, + struct curl_httppost **lastitem, ...); +~~~ + +# DESCRIPTION + +**This function is deprecated.** Use curl_mime_init(3) instead. + +curl_formadd() is used to append sections when building a multipart form +post. Append one section at a time until you have added all the sections you +want included and then you pass the *firstitem* pointer as parameter to +CURLOPT_HTTPPOST(3). *lastitem* is set after each curl_formadd(3) call and +on repeated invokes it should be left as set to allow repeated invokes to find +the end of the list faster. + +After the *lastitem* pointer follow the real arguments. + +The pointers *firstitem* and *lastitem* should both be pointing to +NULL in the first call to this function. All list-data is allocated by the +function itself. You must call curl_formfree(3) on the *firstitem* +after the form post has been done to free the resources. + +Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. +You can disable this header with CURLOPT_HTTPHEADER(3) as usual. + +First, there are some basics you need to understand about multipart form +posts. Each part consists of at least a NAME and a CONTENTS part. If the part +is made for file upload, there are also a stored CONTENT-TYPE and a FILENAME. +Below, we discuss what options you use to set these properties in the parts +you want to add to your post. + +The options listed first are for making normal parts. The options from +*CURLFORM_FILE* through *CURLFORM_BUFFERLENGTH* are for file upload +parts. + +# OPTIONS + +## CURLFORM_COPYNAME + +followed by a string which provides the *name* of this part. libcurl +copies the string so your application does not need to keep it around after +this function call. If the name is not null-terminated, you must set its +length with **CURLFORM_NAMELENGTH**. The *name* is not allowed to +contain zero-valued bytes. The copied data is freed by curl_formfree(3). + +## CURLFORM_PTRNAME + +followed by a string which provides the *name* of this part. libcurl uses the +pointer and refer to the data in your application, so you must make sure it +remains until curl no longer needs it. If the name is not null-terminated, you +must set its length with **CURLFORM_NAMELENGTH**. The *name* is not allowed to +contain zero-valued bytes. + +## CURLFORM_COPYCONTENTS + +followed by a pointer to the contents of this part, the actual data to send +away. libcurl copies the provided data, so your application does not need to +keep it around after this function call. If the data is not null terminated, +or if you would like it to contain zero bytes, you must set the length of the +name with **CURLFORM_CONTENTSLENGTH**. The copied data is freed by +curl_formfree(3). + +## CURLFORM_PTRCONTENTS + +followed by a pointer to the contents of this part, the actual data to send +away. libcurl uses the pointer and refer to the data in your application, so +you must make sure it remains until curl no longer needs it. If the data is +not null-terminated, or if you would like it to contain zero bytes, you must +set its length with **CURLFORM_CONTENTSLENGTH**. + +## CURLFORM_CONTENTLEN + +followed by a curl_off_t value giving the length of the contents. Note that +for *CURLFORM_STREAM* contents, this option is mandatory. + +If you pass a 0 (zero) for this option, libcurl calls strlen() on the contents +to figure out the size. If you really want to send a zero byte content then +you must make sure strlen() on the data pointer returns zero. + +(Option added in 7.46.0) + +## CURLFORM_CONTENTSLENGTH + +(This option is deprecated. Use *CURLFORM_CONTENTLEN* instead!) + +followed by a long giving the length of the contents. Note that for +*CURLFORM_STREAM* contents, this option is mandatory. + +If you pass a 0 (zero) for this option, libcurl calls strlen() on the contents +to figure out the size. If you really want to send a zero byte content then +you must make sure strlen() on the data pointer returns zero. + +## CURLFORM_FILECONTENT + +followed by a filename, causes that file to be read and its contents used +as data in this part. This part does *not* automatically become a file +upload part simply because its data was read from a file. + +The specified file needs to kept around until the associated transfer is done. + +## CURLFORM_FILE + +followed by a filename, makes this part a file upload part. It sets the +*filename* field to the basename of the provided filename, it reads the +contents of the file and passes them as data and sets the content-type if the +given file match one of the internally known file extensions. For +**CURLFORM_FILE** the user may send one or more files in one part by +providing multiple **CURLFORM_FILE** arguments each followed by the filename +(and each *CURLFORM_FILE* is allowed to have a +*CURLFORM_CONTENTTYPE*). + +The given upload file has to exist in its full in the file system already when +the upload starts, as libcurl needs to read the correct file size beforehand. + +The specified file needs to kept around until the associated transfer is done. + +## CURLFORM_CONTENTTYPE + +is used in combination with *CURLFORM_FILE*. Followed by a pointer to a +string which provides the content-type for this part, possibly instead of an +internally chosen one. + +## CURLFORM_FILENAME + +is used in combination with *CURLFORM_FILE*. Followed by a pointer to a +string, it tells libcurl to use the given string as the *filename* in the file +upload part instead of the actual filename. + +## CURLFORM_BUFFER + +is used for custom file upload parts without use of *CURLFORM_FILE*. It +tells libcurl that the file contents are already present in a buffer. The +parameter is a string which provides the *filename* field in the content +header. + +## CURLFORM_BUFFERPTR + +is used in combination with *CURLFORM_BUFFER*. The parameter is a pointer +to the buffer to be uploaded. This buffer must not be freed until after +curl_easy_cleanup(3) is called. You must also use +*CURLFORM_BUFFERLENGTH* to set the number of bytes in the buffer. + +## CURLFORM_BUFFERLENGTH + +is used in combination with *CURLFORM_BUFFER*. The parameter is a +long which gives the length of the buffer. + +## CURLFORM_STREAM + +Tells libcurl to use the CURLOPT_READFUNCTION(3) callback to get +data. The parameter you pass to *CURLFORM_STREAM* is the pointer passed on +to the read callback's fourth argument. If you want the part to look like a +file upload one, set the *CURLFORM_FILENAME* parameter as well. Note that +when using *CURLFORM_STREAM*, *CURLFORM_CONTENTSLENGTH* must also be +set with the total expected length of the part unless the formpost is sent +chunked encoded. (Option added in libcurl 7.18.2) + +## CURLFORM_ARRAY + +Another possibility to send options to curl_formadd() is the +**CURLFORM_ARRAY** option, that passes a struct curl_forms array pointer as +its value. Each curl_forms structure element has a *CURLformoption* and a +char pointer. The final element in the array must be a CURLFORM_END. All +available options can be used in an array, except the CURLFORM_ARRAY option +itself. The last argument in such an array must always be **CURLFORM_END**. + +## CURLFORM_CONTENTHEADER + +specifies extra headers for the form POST section. This takes a curl_slist +prepared in the usual way using **curl_slist_append** and appends the list +of headers to those libcurl automatically generates. The list must exist while +the POST occurs, if you free it before the post completes you may experience +problems. + +When you have passed the *struct curl_httppost* pointer to +curl_easy_setopt(3) (using the CURLOPT_HTTPPOST(3) option), you +must not free the list until after you have called curl_easy_cleanup(3) +for the curl handle. + +See example below. + +# EXAMPLE + +~~~c +#include /* for strlen */ + +static const char record[]="data in a buffer"; + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct curl_httppost *post = NULL; + struct curl_httppost *last = NULL; + char namebuffer[] = "name buffer"; + long namelength = strlen(namebuffer); + char buffer[] = "test buffer"; + char htmlbuffer[] = "test buffer"; + long htmlbufferlength = strlen(htmlbuffer); + struct curl_forms forms[3]; + char file1[] = "my-face.jpg"; + char file2[] = "your-face.jpg"; + /* add null character into htmlbuffer, to demonstrate that + transfers of buffers containing null characters actually work + */ + htmlbuffer[8] = '\0'; + + /* Add simple name/content section */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "name", + CURLFORM_COPYCONTENTS, "content", CURLFORM_END); + + /* Add simple name/content/contenttype section */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "htmlcode", + CURLFORM_COPYCONTENTS, "", + CURLFORM_CONTENTTYPE, "text/html", CURLFORM_END); + + /* Add name/ptrcontent section */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "name_for_ptrcontent", + CURLFORM_PTRCONTENTS, buffer, CURLFORM_END); + + /* Add ptrname/ptrcontent section */ + curl_formadd(&post, &last, CURLFORM_PTRNAME, namebuffer, + CURLFORM_PTRCONTENTS, buffer, CURLFORM_NAMELENGTH, + namelength, CURLFORM_END); + + /* Add name/ptrcontent/contenttype section */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "html_code_with_hole", + CURLFORM_PTRCONTENTS, htmlbuffer, + CURLFORM_CONTENTSLENGTH, htmlbufferlength, + CURLFORM_CONTENTTYPE, "text/html", CURLFORM_END); + + /* Add simple file section */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "picture", + CURLFORM_FILE, "my-face.jpg", CURLFORM_END); + + /* Add file/contenttype section */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "picture", + CURLFORM_FILE, "my-face.jpg", + CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END); + + /* Add two file section */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "pictures", + CURLFORM_FILE, "my-face.jpg", + CURLFORM_FILE, "your-face.jpg", CURLFORM_END); + + /* Add two file section using CURLFORM_ARRAY */ + forms[0].option = CURLFORM_FILE; + forms[0].value = file1; + forms[1].option = CURLFORM_FILE; + forms[1].value = file2; + forms[2].option = CURLFORM_END; + + /* Add a buffer to upload */ + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "name", + CURLFORM_BUFFER, "data", + CURLFORM_BUFFERPTR, record, + CURLFORM_BUFFERLENGTH, sizeof(record), + CURLFORM_END); + + /* no option needed for the end marker */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "pictures", + CURLFORM_ARRAY, forms, CURLFORM_END); + /* Add the content of a file as a normal post text value */ + curl_formadd(&post, &last, CURLFORM_COPYNAME, "filecontent", + CURLFORM_FILECONTENT, ".bashrc", CURLFORM_END); + /* Set the form info */ + curl_easy_setopt(curl, CURLOPT_HTTPPOST, post); + + curl_easy_perform(curl); + + curl_easy_cleanup(curl); + + curl_formfree(post); + } +} +~~~ + +# AVAILABILITY + +Deprecated in 7.56.0. Before this release, field names were allowed to +contain zero-valued bytes. The pseudo-filename "-" to read stdin is +discouraged although still supported, but data is not read before being +actually sent: the effective data size can then not be automatically +determined, resulting in a chunked encoding transfer. Backslashes and +double quotes in field and file names are now escaped before transmission. + +# RETURN VALUE + +0 means everything was OK, non-zero means an error occurred corresponding +to a CURL_FORMADD_* constant defined in +** diff --git a/docs/libcurl/curl_formfree.md b/docs/libcurl/curl_formfree.md new file mode 100644 index 0000000..d2f90c0 --- /dev/null +++ b/docs/libcurl/curl_formfree.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_formfree +Section: 3 +Source: libcurl +See-also: + - curl_formadd (3) + - curl_mime_free (3) + - curl_mime_init (3) +--- + +# NAME + +curl_formfree - free a previously build multipart form post chain + +# SYNOPSIS + +~~~c +#include + +void curl_formfree(struct curl_httppost *form); +~~~ + +# DESCRIPTION + +This function is deprecated. Do not use. See curl_mime_init(3) instead! + +curl_formfree() is used to clean up data previously built/appended with +curl_formadd(3). This must be called when the data has been used, which +typically means after curl_easy_perform(3) has been called. + +The pointer to free is the same pointer you passed to the +CURLOPT_HTTPPOST(3) option, which is the *firstitem* pointer from +the curl_formadd(3) invoke(s). + +**form** is the pointer as returned from a previous call to +curl_formadd(3) and may be NULL. + +Passing in a NULL pointer in *form* makes this function return immediately +with no action. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct curl_httppost *formpost; + struct curl_httppost *lastptr; + + /* Fill in a file upload field */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "file", + CURLFORM_FILE, "nice-image.jpg", + CURLFORM_END); + + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + + curl_easy_perform(curl); + + /* then cleanup the formpost chain */ + curl_formfree(formpost); + } +} +~~~ + +# AVAILABILITY + +Deprecated in 7.56.0. + +# RETURN VALUE + +None diff --git a/docs/libcurl/curl_formget.md b/docs/libcurl/curl_formget.md new file mode 100644 index 0000000..7130ee9 --- /dev/null +++ b/docs/libcurl/curl_formget.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_formget +Section: 3 +Source: libcurl +See-also: + - curl_formadd (3) + - curl_mime_init (3) +--- + +# NAME + +curl_formget - serialize a previously built multipart form POST chain + +# SYNOPSIS + +~~~c +#include + +int curl_formget(struct curl_httppost * form, void *userp, + curl_formget_callback append); +~~~ + +# DESCRIPTION + +curl_formget() serializes data previously built with curl_formadd(3). It +accepts a void pointer as second argument named *userp* which is passed as +the first argument to the curl_formget_callback function. + +~~~c + typedef size_t (*curl_formget_callback)(void *userp, const char *buf, + size_t len);" +~~~ + +The curl_formget_callback is invoked for each part of the HTTP POST chain. The +character buffer passed to the callback must not be freed. The callback should +return the buffer length passed to it on success. + +If the **CURLFORM_STREAM** option is used in the formpost, it prevents +curl_formget(3) from working until you have performed the actual HTTP +request. This, because first then does libcurl known which actual read +callback to use! + +# EXAMPLE + +~~~c +size_t print_httppost_callback(void *arg, const char *buf, size_t len) +{ + fwrite(buf, len, 1, stdout); + (*(size_t *) arg) += len; + return len; +} + +size_t print_httppost(struct curl_httppost *post) +{ + size_t total_size = 0; + if(curl_formget(post, &total_size, print_httppost_callback)) { + return (size_t) -1; + } + return total_size; +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.15.5. The form API is deprecated in +libcurl 7.56.0. + +# RETURN VALUE + +0 means everything was OK, non-zero means an error occurred diff --git a/docs/libcurl/curl_free.md b/docs/libcurl/curl_free.md new file mode 100644 index 0000000..6963940 --- /dev/null +++ b/docs/libcurl/curl_free.md @@ -0,0 +1,52 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_free +Section: 3 +Source: libcurl +See-also: + - curl_easy_escape (3) + - curl_easy_unescape (3) +--- + +# NAME + +curl_free - reclaim memory that has been obtained through a libcurl call + +# SYNOPSIS + +~~~c +#include + +void curl_free(void *ptr); +~~~ + +# DESCRIPTION + +curl_free reclaims memory that has been obtained through a libcurl call. Use +curl_free(3) instead of free() to avoid anomalies that can result from +differences in memory management between your application and libcurl. + +Passing in a NULL pointer in *ptr* makes this function return immediately +with no action. + +# EXAMPLE + +~~~c +int main(void) +{ + char *width = curl_getenv("COLUMNS"); + if(width) { + /* it was set! */ + curl_free(width); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +None diff --git a/docs/libcurl/curl_getdate.md b/docs/libcurl/curl_getdate.md new file mode 100644 index 0000000..e4fbf03 --- /dev/null +++ b/docs/libcurl/curl_getdate.md @@ -0,0 +1,128 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_getdate +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TIMECONDITION (3) + - CURLOPT_TIMEVALUE (3) + - curl_easy_escape (3) + - curl_easy_unescape (3) +--- + +# NAME + +curl_getdate - Convert a date string to number of seconds + +# SYNOPSIS + +~~~c +#include + +time_t curl_getdate(const char *datestring, const time_t *now); +~~~ + +# DESCRIPTION + +curl_getdate(3) returns the number of seconds since the Epoch, January +1st 1970 00:00:00 in the UTC time zone, for the date and time that the +*datestring* parameter specifies. The *now* parameter is not used, +pass a NULL there. + +This function works with valid dates and does not always detect and reject +wrong dates, such as February 30. + +# PARSING DATES AND TIMES + +A "date" is a string containing several items separated by whitespace. The +order of the items is immaterial. A date string may contain many flavors of +items: + +## calendar date items + +Can be specified several ways. Month names can only be three-letter English +abbreviations, numbers can be zero-prefixed and the year may use 2 or 4 +digits. Examples: 06 Nov 1994, 06-Nov-94 and Nov-94 6. + +## time of the day items + +This string specifies the time on a given day. You must specify it with 6 +digits with two colons: HH:MM:SS. If there is no time given in a provided date +string, 00:00:00 is assumed. Example: 18:19:21. + +## time zone items + +Specifies international time zone. There are a few acronyms supported, but in +general you should instead use the specific relative time compared to +UTC. Supported formats include: -1200, MST, +0100. + +## day of the week items + +Specifies a day of the week. Days of the week may be spelled out in full +(using English): `Sunday', `Monday', etc or they may be abbreviated to their +first three letters. This is usually not info that adds anything. + +## pure numbers + +If a decimal number of the form YYYYMMDD appears, then YYYY is read as the +year, MM as the month number and DD as the day of the month, for the specified +calendar date. + +# EXAMPLE + +~~~c +int main(void) +{ + time_t t; + t = curl_getdate("Sun, 06 Nov 1994 08:49:37 GMT", NULL); + t = curl_getdate("Sunday, 06-Nov-94 08:49:37 GMT", NULL); + t = curl_getdate("Sun Nov 6 08:49:37 1994", NULL); + t = curl_getdate("06 Nov 1994 08:49:37 GMT", NULL); + t = curl_getdate("06-Nov-94 08:49:37 GMT", NULL); + t = curl_getdate("Nov 6 08:49:37 1994", NULL); + t = curl_getdate("06 Nov 1994 08:49:37", NULL); + t = curl_getdate("06-Nov-94 08:49:37", NULL); + t = curl_getdate("1994 Nov 6 08:49:37", NULL); + t = curl_getdate("GMT 08:49:37 06-Nov-94 Sunday", NULL); + t = curl_getdate("94 6 Nov 08:49:37", NULL); + t = curl_getdate("1994 Nov 6", NULL); + t = curl_getdate("06-Nov-94", NULL); + t = curl_getdate("Sun Nov 6 94", NULL); + t = curl_getdate("1994.Nov.6", NULL); + t = curl_getdate("Sun/Nov/6/94/GMT", NULL); + t = curl_getdate("Sun, 06 Nov 1994 08:49:37 CET", NULL); + t = curl_getdate("06 Nov 1994 08:49:37 EST", NULL); + t = curl_getdate("Sun, 12 Sep 2004 15:05:58 -0700", NULL); + t = curl_getdate("Sat, 11 Sep 2004 21:32:11 +0200", NULL); + t = curl_getdate("20040912 15:05:58 -0700", NULL); + t = curl_getdate("20040911 +0200", NULL); +} +~~~ + +# STANDARDS + +This parser handles date formats specified in RFC 822 (including the update in +RFC 1123) using time zone name or time zone delta and RFC 850 (obsoleted by +RFC 1036) and ANSI C's *asctime()* format. + +These formats are the only ones RFC 7231 says HTTP applications may use. + +# AVAILABILITY + +Always + +# RETURN VALUE + +This function returns -1 when it fails to parse the date string. Otherwise it +returns the number of seconds as described. + +On systems with a signed 32 bit time_t: if the year is larger than 2037 or +less than 1903, this function returns -1. + +On systems with an unsigned 32 bit time_t: if the year is larger than 2106 or +less than 1970, this function returns -1. + +On systems with 64 bit time_t: if the year is less than 1583, this function +returns -1. (The Gregorian calendar was first introduced 1582 so no "real" +dates in this way of doing dates existed before then.) diff --git a/docs/libcurl/curl_getenv.md b/docs/libcurl/curl_getenv.md new file mode 100644 index 0000000..dbf326d --- /dev/null +++ b/docs/libcurl/curl_getenv.md @@ -0,0 +1,57 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_getenv +Section: 3 +Source: libcurl +See-also: + - getenv (3C) +--- + +# NAME + +curl_getenv - return value for environment name + +# SYNOPSIS + +~~~c +#include + +char *curl_getenv(const char *name); +~~~ + +# DESCRIPTION + +curl_getenv() is a portable wrapper for the getenv() function, meant to +emulate its behavior and provide an identical interface for all operating +systems libcurl builds on (including win32). + +You must curl_free(3) the returned string when you are done with it. + +# EXAMPLE + +~~~c +int main(void) +{ + char *width = curl_getenv("COLUMNS"); + if(width) { + /* it was set! */ + curl_free(width); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +A pointer to a null-terminated string or NULL if it failed to find the +specified name. + +# NOTE + +Under unix operating systems, there is no point in returning an allocated +memory, although other systems does not work properly if this is not done. The +unix implementation thus suffers slightly from the drawbacks of other systems. diff --git a/docs/libcurl/curl_global_cleanup.md b/docs/libcurl/curl_global_cleanup.md new file mode 100644 index 0000000..5502e71 --- /dev/null +++ b/docs/libcurl/curl_global_cleanup.md @@ -0,0 +1,74 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_global_cleanup +Section: 3 +Source: libcurl +See-also: + - curl_global_init (3) + - libcurl (3) + - libcurl-thread (3) +--- + +# NAME + +curl_global_cleanup - global libcurl cleanup + +# SYNOPSIS + +~~~c +#include + +void curl_global_cleanup(void); +~~~ + +# DESCRIPTION + +This function releases resources acquired by curl_global_init(3). + +You should call curl_global_cleanup(3) once for each call you make to +curl_global_init(3), after you are done using libcurl. + +This function is thread-safe since libcurl 7.84.0 if +curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). + +If this is not thread-safe, you must not call this function when any other +thread in the program (i.e. a thread sharing the same memory) is running. +This does not just mean no other thread that is using libcurl. Because +curl_global_cleanup(3) calls functions of other libraries that are +similarly thread unsafe, it could conflict with any other thread that uses +these other libraries. + +See the description in libcurl(3) of global environment requirements for +details of how to use this function. + +# CAUTION + +curl_global_cleanup(3) does not block waiting for any libcurl-created +threads to terminate (such as threads used for name resolving). If a module +containing libcurl is dynamically unloaded while libcurl-created threads are +still running then your program may crash or other corruption may occur. We +recommend you do not run libcurl from any module that may be unloaded +dynamically. This behavior may be addressed in the future. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_global_init(CURL_GLOBAL_DEFAULT); + + /* use libcurl, then before exiting... */ + + curl_global_cleanup(); +} +~~~ + +# AVAILABILITY + +Added in 7.8 + +# RETURN VALUE + +None diff --git a/docs/libcurl/curl_global_init.md b/docs/libcurl/curl_global_init.md new file mode 100644 index 0000000..5c00e86 --- /dev/null +++ b/docs/libcurl/curl_global_init.md @@ -0,0 +1,131 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_global_init +Section: 3 +Source: libcurl +See-also: + - curl_easy_init (3) + - curl_global_cleanup (3) + - curl_global_init_mem (3) + - curl_global_sslset (3) + - curl_global_trace (3) + - libcurl (3) +--- + +# NAME + +curl_global_init - Global libcurl initialization + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_global_init(long flags); +~~~ + +# DESCRIPTION + +This function sets up the program environment that libcurl needs. Think of it +as an extension of the library loader. + +This function must be called at least once within a program (a program is all +the code that shares a memory space) before the program calls any other +function in libcurl. The environment it sets up is constant for the life of +the program and is the same for every program, so multiple calls have the same +effect as one call. + +The flags option is a bit pattern that tells libcurl exactly what features to +init, as described below. Set the desired bits by ORing the values together. +In normal operation, you must specify CURL_GLOBAL_ALL. Do not use any other +value unless you are familiar with it and mean to control internal operations +of libcurl. + +This function is thread-safe since libcurl 7.84.0 if +curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). + +If this is not thread-safe, you must not call this function when any other +thread in the program (i.e. a thread sharing the same memory) is running. +This does not just mean no other thread that is using libcurl. Because +curl_global_init(3) calls functions of other libraries that are +similarly thread unsafe, it could conflict with any other thread that uses +these other libraries. + +If you are initializing libcurl from a Windows DLL you should not initialize +it from *DllMain* or a static initializer because Windows holds the loader +lock during that time and it could cause a deadlock. + +See the description in libcurl(3) of global environment requirements for +details of how to use this function. + +# FLAGS + +## CURL_GLOBAL_ALL + +Initialize everything possible. This sets all known bits except +**CURL_GLOBAL_ACK_EINTR**. + +## CURL_GLOBAL_SSL + +(This flag's presence or absence serves no meaning since 7.57.0. The +description below is for older libcurl versions.) + +Initialize SSL. + +The implication here is that if this bit is not set, the initialization of the +SSL layer needs to be done by the application or at least outside of +libcurl. The exact procedure how to do SSL initialization depends on the TLS +backend libcurl uses. + +Doing TLS based transfers without having the TLS layer initialized may lead to +unexpected behaviors. + +## CURL_GLOBAL_WIN32 + +Initialize the Win32 socket libraries. + +The implication here is that if this bit is not set, the initialization of +winsock has to be done by the application or you risk getting undefined +behaviors. This option exists for when the initialization is handled outside +of libcurl so there is no need for libcurl to do it again. + +## CURL_GLOBAL_NOTHING + +Initialize nothing extra. This sets no bit. + +## CURL_GLOBAL_DEFAULT + +A sensible default. It initializes both SSL and Win32. Right now, this equals +the functionality of the **CURL_GLOBAL_ALL** mask. + +## CURL_GLOBAL_ACK_EINTR + +This bit has no point since 7.69.0 but its behavior is instead the default. + +Before 7.69.0: when this flag is set, curl acknowledges EINTR condition when +connecting or when waiting for data. Otherwise, curl waits until full timeout +elapses. (Added in 7.30.0) + +# EXAMPLE + +~~~c +int main(void) +{ + curl_global_init(CURL_GLOBAL_DEFAULT); + + /* use libcurl, then before exiting... */ + + curl_global_cleanup(); +} +~~~ + +# AVAILABILITY + +Added in 7.8 + +# RETURN VALUE + +If this function returns non-zero, something went wrong and you cannot use the +other curl functions. diff --git a/docs/libcurl/curl_global_init_mem.md b/docs/libcurl/curl_global_init_mem.md new file mode 100644 index 0000000..3bf468f --- /dev/null +++ b/docs/libcurl/curl_global_init_mem.md @@ -0,0 +1,95 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_global_init_mem +Section: 3 +Source: libcurl +See-also: + - curl_global_cleanup (3) + - curl_global_init (3) +--- + +# NAME + +curl_global_init_mem - Global libcurl initialization with memory callbacks + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); +~~~ + +# DESCRIPTION + +This function works exactly as curl_global_init(3) with one addition: it +allows the application to set callbacks to replace the otherwise used internal +memory functions. + +If you are using libcurl from multiple threads or libcurl was built with the +threaded resolver option then the callback functions must be thread safe. The +threaded resolver is a common build option to enable (and in some cases the +default) so we strongly urge you to make your callback functions thread safe. + +All callback arguments must be set to valid function pointers. The +prototypes for the given callbacks must match these: + +## void *malloc_callback(size_t size); + +To replace malloc() + +## void free_callback(void *ptr); + +To replace free() + +## void *realloc_callback(void *ptr, size_t size); + +To replace realloc() + +## char *strdup_callback(const char *str); + +To replace strdup() + +## void *calloc_callback(size_t nmemb, size_t size); + +To replace calloc() + +This function is otherwise the same as curl_global_init(3), please refer +to that man page for documentation. + +# CAUTION + +Manipulating these gives considerable powers to the application to severely +screw things up for libcurl. Take care! + +# EXAMPLE + +~~~c +extern void *malloc_cb(size_t); +extern void free_cb(void *); +extern void *realloc_cb(void *, size_t); +extern char *strdup_cb(const char *); +extern void *calloc_cb(size_t, size_t); + +int main(void) +{ + curl_global_init_mem(CURL_GLOBAL_DEFAULT, malloc_cb, + free_cb, realloc_cb, + strdup_cb, calloc_cb); +} +~~~ + +# AVAILABILITY + +Added in 7.12.0 + +# RETURN VALUE + +CURLE_OK (0) means everything was OK, non-zero means an error occurred as +** defines - see libcurl-errors(3). diff --git a/docs/libcurl/curl_global_sslset.md b/docs/libcurl/curl_global_sslset.md new file mode 100644 index 0000000..6f50867 --- /dev/null +++ b/docs/libcurl/curl_global_sslset.md @@ -0,0 +1,138 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_global_sslset +Section: 3 +Source: libcurl +See-also: + - curl_global_init (3) + - libcurl (3) +--- + +# NAME + +curl_global_sslset - Select SSL backend to use with libcurl + +# SYNOPSIS + +~~~c +#include + +CURLsslset curl_global_sslset(curl_sslbackend id, + const char *name, + const curl_ssl_backend ***avail); +~~~ + +# DESCRIPTION + +This function configures at runtime which SSL backend to use with +libcurl. This function can only be used to select an SSL backend once, and it +must be called **before** curl_global_init(3). + +The backend can be identified by the *id* +(e.g. **CURLSSLBACKEND_OPENSSL**). The backend can also be specified via the +*name* parameter for a case insensitive match (passing +**CURLSSLBACKEND_NONE** as *id*). If both *id* and *name* are +specified, the *name* is ignored. + +If neither *id* nor *name* are specified, the function fails with +**CURLSSLSET_UNKNOWN_BACKEND** and set the *avail* pointer to the +NULL-terminated list of available backends. The available backends are those +that this particular build of libcurl supports. + +Since libcurl 7.60.0, the *avail* pointer is always set to the list of +alternatives if non-NULL. + +Upon success, the function returns **CURLSSLSET_OK**. + +If the specified SSL backend is not available, the function returns +**CURLSSLSET_UNKNOWN_BACKEND** and sets the *avail* pointer to a +NULL-terminated list of available SSL backends. In this case, you may call the +function again to try to select a different backend. + +The SSL backend can be set only once. If it has already been set, a subsequent +attempt to change it results in a **CURLSSLSET_TOO_LATE** getting returned. + +This function is thread-safe since libcurl 7.84.0 if +curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). + +If this is not thread-safe, you must not call this function when any other +thread in the program (i.e. a thread sharing the same memory) is running. +This does not just mean no other thread that is using libcurl. + +# OpenSSL + +The name "OpenSSL" is used for all versions of OpenSSL and its associated +forks/flavors in this function. OpenSSL, BoringSSL, libressl, quictls and +AmiSSL are all supported by libcurl, but in the eyes of +curl_global_sslset(3) they are all just "OpenSSL". They all mostly +provide the same API. + +curl_version_info(3) can return more specific info about the exact +OpenSSL flavor and version number is use. + +# struct + +~~~c +typedef struct { + curl_sslbackend id; + const char *name; +} curl_ssl_backend; + +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, /* or one of its forks */ + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_GSKIT = 5, /* deprecated */ + CURLSSLBACKEND_POLARSSL = 6, /* deprecated */ + CURLSSLBACKEND_WOLFSSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_SECURETRANSPORT = 9, + CURLSSLBACKEND_AXTLS = 10, /* deprecated */ + CURLSSLBACKEND_MBEDTLS = 11, + CURLSSLBACKEND_MESALINK = 12, /* deprecated */ + CURLSSLBACKEND_BEARSSL = 13, + CURLSSLBACKEND_RUSTLS = 14 +} curl_sslbackend; +~~~ + +# EXAMPLE + +~~~c +int main(void) +{ + int i; + /* choose a specific backend */ + curl_global_sslset(CURLSSLBACKEND_WOLFSSL, NULL, NULL); + + /* list the available ones */ + const curl_ssl_backend **list; + curl_global_sslset(CURLSSLBACKEND_NONE, NULL, &list); + + for(i = 0; list[i]; i++) + printf("SSL backend #%d: '%s' (ID: %d)\n", + i, list[i]->name, list[i]->id); +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.56.0. Before this version, there was no +support for choosing SSL backends at runtime. + +# RETURN VALUE + +If this function returns *CURLSSLSET_OK*, the backend was successfully +selected. + +If the chosen backend is unknown (or support for the chosen backend has not +been compiled into libcurl), the function returns +*CURLSSLSET_UNKNOWN_BACKEND*. + +If the backend had been configured previously, or if curl_global_init(3) +has already been called, the function returns *CURLSSLSET_TOO_LATE*. + +If this libcurl was built completely without SSL support, with no backends at +all, this function returns *CURLSSLSET_NO_BACKENDS*. diff --git a/docs/libcurl/curl_global_trace.md b/docs/libcurl/curl_global_trace.md new file mode 100644 index 0000000..c916835 --- /dev/null +++ b/docs/libcurl/curl_global_trace.md @@ -0,0 +1,124 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_global_trace +Section: 3 +Source: libcurl +See-also: + - curl_global_init (3) + - libcurl (3) +--- + +# NAME + +curl_global_trace - Global libcurl logging configuration + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_global_trace(const char *config); +~~~ + +# DESCRIPTION + +This function configures the logging behavior, allowing to make some +parts of curl more verbose or silent than others. + +This function may be called during the initialization phase of a program. It +does not have to be. It can be called several times even, possibly overwriting +settings of previous calls. + +Calling this function after transfers have been started is undefined. On +some platforms/architectures it might take effect, on others not. + +This function is thread-safe since libcurl 8.3.0 if +curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). + +If this is not thread-safe, you must not call this function when any other +thread in the program (i.e. a thread sharing the same memory) is running. +This does not just mean no other thread that is using libcurl. Because +curl_global_init(3) may call functions of other libraries that are +similarly thread unsafe, it could conflict with any other thread that uses +these other libraries. + +If you are initializing libcurl from a Windows DLL you should not initialize +it from *DllMain* or a static initializer because Windows holds the loader +lock during that time and it could cause a deadlock. + +The *config* string is a list of comma-separated component names. Names +are case-insensitive and unknown names are ignored. The special name "all" +applies to all components. Names may be prefixed with '+' or '-' to enable +or disable detailed logging for a component. + +The list of component names is not part of curl's public API. Names may be +added or disappear in future versions of libcurl. Since unknown names are +silently ignored, outdated log configurations does not cause errors when +upgrading libcurl. Given that, some names can be expected to be fairly stable +and are listed below for easy reference. + +Note that log configuration applies only to transfers where debug logging +is enabled. See CURLOPT_VERBOSE(3) or CURLOPT_DEBUGFUNCTION(3) +on how to control that. + +# TRACE COMPONENTS + +## tcp + +Tracing of TCP socket handling: connect, reads, writes. + +## ssl + +Tracing of SSL/TLS operations, whichever SSL backend is used in your build. + +## http/2 + +Details about HTTP/2 handling: frames, events, I/O, etc. + +## http/3 + +Details about HTTP/3 handling: connect, frames, events, I/O etc. + +## http-proxy + +Involved when transfers are tunneled through an HTTP proxy. "h1-proxy" or +"h2-proxy" are also involved, depending on the HTTP version negotiated with +the proxy. + +In order to find out all components involved in a transfer, run it with "all" +configured. You can then see all names involved in your libcurl version in the +trace. + +# EXAMPLE + +~~~c +int main(void) +{ + /* log details of HTTP/2 and SSL handling */ + curl_global_trace("http/2,ssl"); + + /* log all details, except SSL handling */ + curl_global_trace("all,-ssl"); +} +~~~ + +Below is a trace sample where "http/2" was configured. The trace output +of an enabled component appears at the beginning in brackets. +~~~ +* [HTTP/2] [h2sid=1] cf_send(len=96) submit https://example.com/ +... +* [HTTP/2] [h2sid=1] FRAME[HEADERS] +* [HTTP/2] [h2sid=1] 249 header bytes +... +~~~ + +# AVAILABILITY + +Added in 8.3 + +# RETURN VALUE + +If this function returns non-zero, something went wrong and the configuration +may not have any effects or may only been applied partially. diff --git a/docs/libcurl/curl_mime_addpart.md b/docs/libcurl/curl_mime_addpart.md new file mode 100644 index 0000000..f641abb --- /dev/null +++ b/docs/libcurl/curl_mime_addpart.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_addpart +Section: 3 +Source: libcurl +See-also: + - curl_mime_data (3) + - curl_mime_data_cb (3) + - curl_mime_encoder (3) + - curl_mime_filedata (3) + - curl_mime_filename (3) + - curl_mime_headers (3) + - curl_mime_init (3) + - curl_mime_name (3) + - curl_mime_subparts (3) + - curl_mime_type (3) +--- + +# NAME + +curl_mime_addpart - append a new empty part to a mime structure + +# SYNOPSIS + +~~~c +#include + +curl_mimepart *curl_mime_addpart(curl_mime *mime); +~~~ + +# DESCRIPTION + +curl_mime_addpart(3) creates and appends a new empty part to the given +mime structure and returns a handle to it. The returned part handle can +subsequently be populated using functions from the mime API. + +*mime* is the handle of the mime structure in which the new part must be +appended. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_mime *mime; + curl_mimepart *part; + + CURL *curl = curl_easy_init(); + if(curl) { + /* create a mime handle */ + mime = curl_mime_init(curl); + + /* add a part */ + part = curl_mime_addpart(mime); + + /* continue and set name + data to the part */ + curl_mime_data(part, "This is the field data", CURL_ZERO_TERMINATED); + curl_mime_name(part, "data"); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +A mime part structure handle, or NULL upon failure. diff --git a/docs/libcurl/curl_mime_data.md b/docs/libcurl/curl_mime_data.md new file mode 100644 index 0000000..15a1d27 --- /dev/null +++ b/docs/libcurl/curl_mime_data.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_data +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_data_cb (3) + - curl_mime_name (3) + - curl_mime_type (3) +--- + +# NAME + +curl_mime_data - set a mime part's body data from memory + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_data(curl_mimepart *part, const char *data, + size_t datasize); +~~~ + +# DESCRIPTION + +curl_mime_data(3) sets a mime part's body content from memory data. + +*part* is the mime part to assign contents to, created with +curl_mime_addpart(3). + +*data* points to the data that gets copied by this function. The storage +may safely be reused after the call. + +*datasize* is the number of bytes *data* points to. It can be set to +*CURL_ZERO_TERMINATED* to indicate *data* is a null-terminated +character string. + +Setting a part's contents multiple times is valid: only the value set by the +last call is retained. It is possible to unassign part's contents by setting +*data* to NULL. + +Setting large data is memory consuming: one might consider using +curl_mime_data_cb(3) in such a case. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_mime *mime; + curl_mimepart *part; + + CURL *curl = curl_easy_init(); + if(curl) { + /* create a mime handle */ + mime = curl_mime_init(curl); + + /* add a part */ + part = curl_mime_addpart(mime); + + /* add data to the part */ + curl_mime_data(part, "raw contents to send", CURL_ZERO_TERMINATED); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mime_data_cb.md b/docs/libcurl/curl_mime_data_cb.md new file mode 100644 index 0000000..bd3c77a --- /dev/null +++ b/docs/libcurl/curl_mime_data_cb.md @@ -0,0 +1,168 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_data_cb +Section: 3 +Source: libcurl +See-also: + - curl_easy_duphandle (3) + - curl_mime_addpart (3) + - curl_mime_data (3) + - curl_mime_name (3) +--- + +# NAME + +curl_mime_data_cb - set a callback-based data source for a mime part's body + +# SYNOPSIS + +~~~c +#include + +size_t readfunc(char *buffer, size_t size, size_t nitems, void *arg); + +int seekfunc(void *arg, curl_off_t offset, int origin); + +void freefunc(void *arg); + +CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, void *arg); +~~~ + +# DESCRIPTION + +curl_mime_data_cb(3) sets the data source of a mime part's body content +from a data read callback function. + +*part* is the part's to assign contents to. + +*readfunc* is a pointer to a data read callback function, with a signature +as shown by the above prototype. It may not be set to NULL. + +*seekfunc* is a pointer to a seek callback function, with a signature as +shown by the above prototype. This function is used when resending data (i.e.: +after a redirect); this pointer may be set to NULL, in which case a resend +might not be not possible. + +*freefunc* is a pointer to a user resource freeing callback function, with +a signature as shown by the above prototype. If no resource is to be freed, it +may safely be set to NULL. This function is called upon mime structure +freeing. + +*arg* is a user defined argument to callback functions. + +The read callback function gets called by libcurl as soon as it needs to +read data in order to send it to the peer - like if you ask it to upload or +post data to the server. The data area pointed at by the pointer *buffer* +should be filled up with at most *size* multiplied with *nitems* number +of bytes by your function. + +Your read function must then return the actual number of bytes that it stored +in that memory area. Returning 0 signals end-of-file to the library and cause +it to stop the current transfer. + +If you stop the current transfer by returning 0 "pre-maturely" (i.e. before +the server expected it, like when you have said you intend to upload N bytes +and yet you upload less than N bytes), you may experience that the server +"hangs" waiting for the rest of the data that does not come. + +The read callback may return *CURL_READFUNC_ABORT* to stop the current +operation immediately, resulting in a *CURLE_ABORTED_BY_CALLBACK* error +code from the transfer. + +The callback can return *CURL_READFUNC_PAUSE* to cause reading from this +connection to pause. See curl_easy_pause(3) for further details. + +The seek function gets called by libcurl to rewind input stream data or to +seek to a certain position. The function shall work like fseek(3) or lseek(3) +and it gets SEEK_SET, SEEK_CUR or SEEK_END as argument for *origin*, +although libcurl currently only passes SEEK_SET. + +The callback function must return *CURL_SEEKFUNC_OK* on success, +*CURL_SEEKFUNC_FAIL* to cause the upload operation to fail or +*CURL_SEEKFUNC_CANTSEEK* to indicate that while the seek failed, libcurl +is free to work around the problem if possible. The latter can sometimes be +done by instead reading from the input or similar. + +Care must be taken if the part is bound to a curl easy handle that is later +duplicated: the *arg* pointer argument is also duplicated, resulting in +the pointed item to be shared between the original and the copied handle. In +particular, special attention should be given to the *freefunc* procedure +code since it then gets called twice with the same argument. + +# EXAMPLE + +Sending a huge data string causes the same amount of memory to be allocated: +to avoid overhead resources consumption, one might want to use a callback +source to avoid data duplication. In this case, original data must be retained +until after the transfer terminates. +~~~c +#include /* for memcpy */ +char hugedata[512000]; + +struct ctl { + char *buffer; + curl_off_t size; + curl_off_t position; +}; + +size_t read_callback(char *buffer, size_t size, size_t nitems, void *arg) +{ + struct ctl *p = (struct ctl *) arg; + curl_off_t sz = p->size - p->position; + + nitems *= size; + if(sz > nitems) + sz = nitems; + if(sz) + memcpy(buffer, p->buffer + p->position, sz); + p->position += sz; + return sz; +} + +int seek_callback(void *arg, curl_off_t offset, int origin) +{ + struct ctl *p = (struct ctl *) arg; + + switch(origin) { + case SEEK_END: + offset += p->size; + break; + case SEEK_CUR: + offset += p->position; + break; + } + + if(offset < 0) + return CURL_SEEKFUNC_FAIL; + p->position = offset; + return CURL_SEEKFUNC_OK; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_mime *mime = curl_mime_init(curl); + curl_mimepart *part = curl_mime_addpart(mime); + struct ctl hugectl; + + hugectl.buffer = hugedata; + hugectl.size = sizeof(hugedata); + hugectl.position = 0; + curl_mime_data_cb(part, hugectl.size, read_callback, seek_callback, NULL, + &hugectl); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mime_encoder.md b/docs/libcurl/curl_mime_encoder.md new file mode 100644 index 0000000..85dc3ac --- /dev/null +++ b/docs/libcurl/curl_mime_encoder.md @@ -0,0 +1,100 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_encoder +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_headers (3) + - curl_mime_subparts (3) +--- + +# NAME + +curl_mime_encoder - set a mime part's encoder and content transfer encoding + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding); +~~~ + +# DESCRIPTION + +curl_mime_encoder() requests a mime part's content to be encoded before being +transmitted. + +*part* is the part's handle to assign an encoder. +*encoding* is a pointer to a null-terminated encoding scheme. It may be +set to NULL to disable an encoder previously attached to the part. The encoding +scheme storage may safely be reused after this function returns. + +Setting a part's encoder multiple times is valid: only the value set by the +last call is retained. + +Upon multipart rendering, the part's content is encoded according to the +pertaining scheme and a corresponding *"Content-Transfer-Encoding"* header +is added to the part. + +Supported encoding schemes are: + +"*binary*": the data is left unchanged, the header is added. + +"*8bit*": header added, no data change. + +"*7bit*": the data is unchanged, but is each byte is checked +to be a 7-bit value; if not, a read error occurs. + +"*base64*": Data is converted to base64 encoding, then split in +CRLF-terminated lines of at most 76 characters. + +"*quoted-printable*": data is encoded in quoted printable lines of +at most 76 characters. Since the resulting size of the final data cannot be +determined prior to reading the original data, it is left as unknown, causing +chunked transfer in HTTP. For the same reason, this encoder may not be used +with IMAP. This encoder targets text data that is mostly ASCII and should +not be used with other types of data. + +If the original data is already encoded in such a scheme, a custom +*Content-Transfer-Encoding* header should be added with +curl_mime_headers(3) instead of setting a part encoder. + +Encoding should not be applied to multiparts, thus the use of this function on +a part with content set with curl_mime_subparts(3) is strongly +discouraged. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_mime *mime; + curl_mimepart *part; + + CURL *curl = curl_easy_init(); + if(curl) { + /* create a mime handle */ + mime = curl_mime_init(curl); + + /* add a part */ + part = curl_mime_addpart(mime); + + /* send a file */ + curl_mime_filedata(part, "image.png"); + + /* encode file data in base64 for transfer */ + curl_mime_encoder(part, "base64"); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mime_filedata.md b/docs/libcurl/curl_mime_filedata.md new file mode 100644 index 0000000..0770412 --- /dev/null +++ b/docs/libcurl/curl_mime_filedata.md @@ -0,0 +1,88 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_filedata +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_data (3) + - curl_mime_filename (3) + - curl_mime_name (3) +--- + +# NAME + +curl_mime_filedata - set a mime part's body data from a file contents + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_filedata(curl_mimepart *part, + const char *filename); +~~~ + +# DESCRIPTION + +curl_mime_filedata(3) sets a mime part's body content from the named +file's contents. This is an alternative to curl_mime_data(3) for setting +data to a mime part. + +*part* is the part's to assign contents to. + +*filename* points to the null-terminated file's path name. The pointer can +be NULL to detach the previous part contents settings. Filename storage can +be safely be reused after this call. + +As a side effect, the part's remote filename is set to the base name of the +given *filename* if it is a valid named file. This can be undone or +overridden by a subsequent call to curl_mime_filename(3). + +The contents of the file is read during the file transfer in a streaming +manner to allow huge files to get transferred without using much memory. It +therefore requires that the file is kept intact during the entire request. + +If the file size cannot be determined before actually reading it (such as for +a character device or named pipe), the whole mime structure containing the +part is transferred using chunks by HTTP but is rejected by IMAP. + +Setting a part's contents multiple times is valid: only the value set by the +last call is retained. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_mime *mime; + curl_mimepart *part; + + CURL *curl = curl_easy_init(); + if(curl) { + /* create a mime handle */ + mime = curl_mime_init(curl); + + /* add a part */ + part = curl_mime_addpart(mime); + + /* send data from this file */ + curl_mime_filedata(part, "image.png"); + + /* set name */ + curl_mime_name(part, "data"); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. CURLE_READ_ERROR is only an +indication that the file is not yet readable: it can be safely ignored at +this time, but the file must be made readable before the pertaining +easy handle is performed. diff --git a/docs/libcurl/curl_mime_filename.md b/docs/libcurl/curl_mime_filename.md new file mode 100644 index 0000000..4fb6b0d --- /dev/null +++ b/docs/libcurl/curl_mime_filename.md @@ -0,0 +1,79 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_filename +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_data (3) + - curl_mime_filedata (3) +--- + +# NAME + +curl_mime_filename - set a mime part's remote file name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_filename(curl_mimepart *part, + const char *filename); +~~~ + +# DESCRIPTION + +curl_mime_filename(3) sets a mime part's remote filename. When remote +filename is set, content data is processed as a file, whatever is the part's +content source. A part's remote filename is transmitted to the server in the +associated Content-Disposition generated header. + +*part* is the part's handle to assign the remote filename to. + +*filename* points to the null-terminated filename string; it may be set +to NULL to remove a previously attached remote filename. + +The remote filename string is copied into the part, thus the associated +storage may safely be released or reused after call. Setting a part's file +name multiple times is valid: only the value set by the last call is retained. + +# EXAMPLE + +~~~c + +static char imagebuf[]="imagedata"; + +int main(void) +{ + curl_mime *mime; + curl_mimepart *part; + + CURL *curl = curl_easy_init(); + if(curl) { + /* create a mime handle */ + mime = curl_mime_init(curl); + + /* add a part */ + part = curl_mime_addpart(mime); + + /* send image data from memory */ + curl_mime_data(part, imagebuf, sizeof(imagebuf)); + + /* set a file name to make it look like a file upload */ + curl_mime_filename(part, "image.png"); + + /* set name */ + curl_mime_name(part, "data"); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mime_free.md b/docs/libcurl/curl_mime_free.md new file mode 100644 index 0000000..5aa5b6a --- /dev/null +++ b/docs/libcurl/curl_mime_free.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_free +Section: 3 +Source: libcurl +See-also: + - curl_free (3) + - curl_mime_init (3) +--- + +# NAME + +curl_mime_free - free a previously built mime structure + +# SYNOPSIS + +~~~c +#include + +void curl_mime_free(curl_mime *mime); +~~~ + +# DESCRIPTION + +curl_mime_free(3) is used to clean up data previously built/appended +with curl_mime_addpart(3) and other mime-handling functions. This must +be called when the data has been used, which typically means after +curl_easy_perform(3) has been called. + +The handle to free is the one you passed to the CURLOPT_MIMEPOST(3) +option: attached sub part mime structures must not be explicitly freed as they +are by the top structure freeing. + +**mime** is the handle as returned from a previous call to +curl_mime_init(3) and may be NULL. + +Passing in a NULL pointer in *mime* makes this function return immediately +with no action. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* Build the mime message. */ + curl_mime *mime = curl_mime_init(curl); + + /* send off the transfer */ + + /* Free multipart message. */ + curl_mime_free(mime); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +None diff --git a/docs/libcurl/curl_mime_headers.md b/docs/libcurl/curl_mime_headers.md new file mode 100644 index 0000000..4f6421a --- /dev/null +++ b/docs/libcurl/curl_mime_headers.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_headers +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_name (3) +--- + +# NAME + +curl_mime_headers - set a mime part's custom headers + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, int take_ownership); +~~~ + +# DESCRIPTION + +curl_mime_headers(3) sets a mime part's custom headers. + +*part* is the part's handle to assign the custom headers list to. + +*headers* is the head of a list of custom headers; it may be set to NULL +to remove a previously attached custom header list. + +*take_ownership*: when non-zero, causes the list to be freed upon +replacement or mime structure deletion; in this case the list must not be +freed explicitly. + +Setting a part's custom headers list multiple times is valid: only the value +set by the last call is retained. + +# EXAMPLE + +~~~c +int main(void) +{ + struct curl_slist *headers = NULL; + CURL *easy = curl_easy_init(); + curl_mime *mime; + curl_mimepart *part; + + headers = curl_slist_append(headers, "Custom-Header: mooo"); + + mime = curl_mime_init(easy); + part = curl_mime_addpart(mime); + + /* use these headers in the part, takes ownership */ + curl_mime_headers(part, headers, 1); + + /* pass on this data */ + curl_mime_data(part, "12345679", CURL_ZERO_TERMINATED); + + /* set name */ + curl_mime_name(part, "numbers"); + + /* Post and send it. */ + curl_easy_setopt(easy, CURLOPT_MIMEPOST, mime); + curl_easy_setopt(easy, CURLOPT_URL, "https://example.com"); + curl_easy_perform(easy); +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mime_init.md b/docs/libcurl/curl_mime_init.md new file mode 100644 index 0000000..0811bb3 --- /dev/null +++ b/docs/libcurl/curl_mime_init.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_init +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MIMEPOST (3) + - curl_mime_addpart (3) + - curl_mime_free (3) + - curl_mime_subparts (3) +--- + +# NAME + +curl_mime_init - create a mime handle + +# SYNOPSIS + +~~~c +#include + +curl_mime *curl_mime_init(CURL *easy_handle); +~~~ + +# DESCRIPTION + +curl_mime_init(3) creates a handle to a new empty mime structure. +This mime structure can be subsequently filled using the mime API, then +attached to some easy handle using option CURLOPT_MIMEPOST(3) within +a curl_easy_setopt(3) call or added as a multipart in another mime +handle's part using curl_mime_subparts(3). + +*easy_handle* is used for part separator randomization and error +reporting. Since 7.87.0, it does not need to be the final target handle. + +Using a mime handle is the recommended way to post an HTTP form, format and +send a multi-part email with SMTP or upload such an email to an IMAP server. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *easy = curl_easy_init(); + curl_mime *mime; + curl_mimepart *part; + + /* Build an HTTP form with a single field named "data", */ + mime = curl_mime_init(easy); + part = curl_mime_addpart(mime); + curl_mime_data(part, "This is the field data", CURL_ZERO_TERMINATED); + curl_mime_name(part, "data"); + + /* Post and send it. */ + curl_easy_setopt(easy, CURLOPT_MIMEPOST, mime); + curl_easy_setopt(easy, CURLOPT_URL, "https://example.com"); + curl_easy_perform(easy); + + /* Clean-up. */ + curl_easy_cleanup(easy); + curl_mime_free(mime); +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +A mime struct handle, or NULL upon failure. diff --git a/docs/libcurl/curl_mime_name.md b/docs/libcurl/curl_mime_name.md new file mode 100644 index 0000000..bd25033 --- /dev/null +++ b/docs/libcurl/curl_mime_name.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_name +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_data (3) + - curl_mime_type (3) +--- + +# NAME + +curl_mime_name - set a mime part's name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_name(curl_mimepart *part, const char *name); +~~~ + +# DESCRIPTION + +curl_mime_name(3) sets a mime part's name. This is the way HTTP form +fields are named. + +*part* is the part's handle to assign a name to. + +*name* points to the null-terminated name string. + +The name string is copied into the part, thus the associated storage may +safely be released or reused after call. Setting a part's name multiple times +is valid: only the value set by the last call is retained. It is possible to +reset the name of a part by setting *name* to NULL. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_mime *mime; + curl_mimepart *part; + + CURL *curl = curl_easy_init(); + if(curl) { + /* create a mime handle */ + mime = curl_mime_init(curl); + + /* add a part */ + part = curl_mime_addpart(mime); + + /* give the part a name */ + curl_mime_name(part, "shoe_size"); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mime_subparts.md b/docs/libcurl/curl_mime_subparts.md new file mode 100644 index 0000000..4136a1b --- /dev/null +++ b/docs/libcurl/curl_mime_subparts.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_subparts +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_init (3) +--- + +# NAME + +curl_mime_subparts - set sub-parts of a multipart mime part + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts); +~~~ + +# DESCRIPTION + +curl_mime_subparts(3) sets a multipart mime part's content from a mime +structure. + +*part* is a handle to the multipart part. + +*subparts* is a mime structure handle holding the sub-parts. After +curl_mime_subparts(3) succeeds, the mime structure handle belongs to the +multipart part and must not be freed explicitly. It may however be updated by +subsequent calls to mime API functions. + +Setting a part's contents multiple times is valid: only the value set by the +last call is retained. It is possible to unassign previous part's contents by +setting *subparts* to NULL. + +# EXAMPLE + +~~~c + +static char *inline_html = "example"; +static char *inline_text = "once upon the time"; + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct curl_slist *slist; + + /* The inline part is an alternative proposing the html and the text + versions of the email. */ + curl_mime *alt = curl_mime_init(curl); + curl_mimepart *part; + + /* HTML message. */ + part = curl_mime_addpart(alt); + curl_mime_data(part, inline_html, CURL_ZERO_TERMINATED); + curl_mime_type(part, "text/html"); + + /* Text message. */ + part = curl_mime_addpart(alt); + curl_mime_data(part, inline_text, CURL_ZERO_TERMINATED); + + /* Create the inline part. */ + part = curl_mime_addpart(alt); + curl_mime_subparts(part, alt); + curl_mime_type(part, "multipart/alternative"); + slist = curl_slist_append(NULL, "Content-Disposition: inline"); + curl_mime_headers(part, slist, 1); + } +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mime_type.md b/docs/libcurl/curl_mime_type.md new file mode 100644 index 0000000..3970ad8 --- /dev/null +++ b/docs/libcurl/curl_mime_type.md @@ -0,0 +1,86 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_mime_type +Section: 3 +Source: libcurl +See-also: + - curl_mime_addpart (3) + - curl_mime_data (3) + - curl_mime_name (3) +--- + +# NAME + +curl_mime_type - set a mime part's content type + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); +~~~ + +# DESCRIPTION + +curl_mime_type(3) sets a mime part's content type. + +*part* is the part's handle to assign the content type to. + +*mimetype* points to the null-terminated file mime type string; it may be +set to NULL to remove a previously attached mime type. + +The mime type string is copied into the part, thus the associated storage may +safely be released or reused after call. Setting a part's type multiple times +is valid: only the value set by the last call is retained. + +In the absence of a mime type and if needed by the protocol specifications, +a default mime type is determined by the context: + +- If set as a custom header, use this value. + +- application/form-data for an HTTP form post. + +- If a remote filename is set, the mime type is taken from the file name +extension, or application/octet-stream by default. + +- For a multipart part, multipart/mixed. + +- text/plain in other cases. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_mime *mime; + curl_mimepart *part; + + CURL *curl = curl_easy_init(); + if(curl) { + /* create a mime handle */ + mime = curl_mime_init(curl); + + /* add a part */ + part = curl_mime_addpart(mime); + + /* get data from this file */ + curl_mime_filedata(part, "image.png"); + + /* content-type for this part */ + curl_mime_type(part, "image/png"); + + /* set name */ + curl_mime_name(part, "image"); +} +} +~~~ + +# AVAILABILITY + +As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. + +# RETURN VALUE + +CURLE_OK or a CURL error code upon failure. diff --git a/docs/libcurl/curl_mprintf.md b/docs/libcurl/curl_mprintf.md new file mode 100644 index 0000000..5aca9e3 --- /dev/null +++ b/docs/libcurl/curl_mprintf.md @@ -0,0 +1,288 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_printf +Section: 3 +Source: libcurl +See-also: + - fprintf (3) + - printf (3) + - sprintf (3) + - vprintf (3) +--- + +# NAME + +curl_maprintf, curl_mfprintf, curl_mprintf, curl_msnprintf, curl_msprintf +curl_mvaprintf, curl_mvfprintf, curl_mvprintf, curl_mvsnprintf, +curl_mvsprintf - formatted output conversion + +# SYNOPSIS + +~~~c +#include + +int curl_mprintf(const char *format, ...); +int curl_mfprintf(FILE *fd, const char *format, ...); +int curl_msprintf(char *buffer, const char *format, ...); +int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...); +int curl_mvprintf(const char *format, va_list args); +int curl_mvfprintf(FILE *fd, const char *format, va_list args); +int curl_mvsprintf(char *buffer, const char *format, va_list args); +int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, + va_list args); +char *curl_maprintf(const char *format , ...); +char *curl_mvaprintf(const char *format, va_list args); +~~~ + +# DESCRIPTION + +These functions produce output according to the format string and given +arguments. They are mostly clones of the well-known C-style functions but +there are slight differences in behavior. + +We discourage users from using any of these functions in new applications. + +Functions in the curl_mprintf() family produce output according to a format as +described below. The functions **curl_mprintf()** and **curl_mvprintf()** +write output to stdout, the standard output stream; **curl_mfprintf()** and +**curl_mvfprintf()** write output to the given output stream; +**curl_msprintf()**, **curl_msnprintf()**, **curl_mvsprintf()**, and +**curl_mvsnprintf()** write to the character string **buffer**. + +The functions **curl_msnprintf()** and **curl_mvsnprintf()** write at most +*maxlength* bytes (including the terminating null byte ('0')) to +*buffer*. + +The functions **curl_mvprintf()**, **curl_mvfprintf()**, +**curl_mvsprintf()**, **curl_mvsnprintf()** are equivalent to the +functions **curl_mprintf()**, **curl_mfprintf()**, **curl_msprintf()**, +**curl_msnprintf()**, respectively, except that they are called with a +*va_list* instead of a variable number of arguments. These functions do +not call the *va_end* macro. Because they invoke the *va_arg* macro, +the value of *ap* is undefined after the call. + +The functions **curl_maprintf()** and **curl_mvaprintf()** return the +output string as pointer to a newly allocated memory area. The returned string +must be curl_free(3)ed by the receiver. + +All of these functions write the output under the control of a format string +that specifies how subsequent arguments are converted for output. + +# FORMAT STRING + +The format string is composed of zero or more directives: ordinary characters +(not %), which are copied unchanged to the output stream; and conversion +specifications, each of which results in fetching zero or more subsequent +arguments. Each conversion specification is introduced by the character %, and +ends with a conversion specifier. In between there may be (in this order) zero +or more *flags*, an optional minimum *field width*, an optional +*precision* and an optional *length modifier*. + +# The $ modifier + +The arguments must correspond properly with the conversion specifier. By +default, the arguments are used in the order given, where each '*' (see Field +width and Precision below) and each conversion specifier asks for the next +argument (and it is an error if insufficiently many arguments are given). One +can also specify explicitly which argument is taken, at each place where an +argument is required, by writing "%m$" instead of '%' and "*m$" instead +of '*', where the decimal integer m denotes the position in the argument list +of the desired argument, indexed starting from 1. Thus, +~~~c + curl_mprintf("%*d", width, num); +~~~ +and +~~~c + curl_mprintf("%2$*1$d", width, num); +~~~ +are equivalent. The second style allows repeated references to the same +argument. + +If the style using '$' is used, it must be used throughout for all conversions +taking an argument and all width and precision arguments, but it may be mixed +with "%%" formats, which do not consume an argument. There may be no gaps in +the numbers of arguments specified using '$'; for example, if arguments 1 and +3 are specified, argument 2 must also be specified somewhere in the format +string. + +# Flag characters + +The character % is followed by zero or more of the following flags: + +## # + +The value should be converted to its "alternate form". + +## 0 + +The value should be zero padded. + +## - + +The converted value is to be left adjusted on the field boundary. (The default +is right justification.) The converted value is padded on the right with +blanks, rather than on the left with blanks or zeros. A '-' overrides a &'0' +if both are given. + +## (space) + +(a space: ' ') A blank should be left before a positive number (or empty +string) produced by a signed conversion. + +## + + +A sign (+ or -) should always be placed before a number produced by a signed +conversion. By default, a sign is used only for negative numbers. A '+' +overrides a space if both are used. + +# Field width + +An optional decimal digit string (with nonzero first digit) specifying a +minimum field width. If the converted value has fewer characters than the +field width, it gets padded with spaces on the left (or right, if the +left-adjustment flag has been given). Instead of a decimal digit string one +may write "*" or "*m$" (for some decimal integer m) to specify that the field +width is given in the next argument, or in the *m-th* argument, +respectively, which must be of type int. A negative field width is taken as +a '-' flag followed by a positive field width. In no case does a nonexistent +or small field width cause truncation of a field; if the result of a +conversion is wider than the field width, the field is expanded to contain the +conversion result. + +# Precision + +An optional precision in the form of a period ('.') followed by an optional +decimal digit string. Instead of a decimal digit string one may write "*" or +"*m$" (for some decimal integer m) to specify that the precision is given in +the next argument, or in the *m-th* argument, respectively, which must be of +type int. If the precision is given as just '.', the precision is taken to be +zero. A negative precision is taken as if the precision were omitted. This +gives the minimum number of digits to appear for **d**, **i**, **o**, +**u**, **x**, and **X** conversions, the number of digits to appear +after the radix character for **a**, **A**, **e**, **E**, **f**, and +**F** conversions, the maximum number of significant digits for **g** and +**G** conversions, or the maximum number of characters to be printed from a +string for **s** and **S** conversions. + +# Length modifier + +## h + +A following integer conversion corresponds to a *short* or *unsigned short* +argument. + +## l + +(ell) A following integer conversion corresponds to a *long* or +*unsigned long* argument, or a following n conversion corresponds to a +pointer to a long argument + +## ll + +(ell-ell). A following integer conversion corresponds to a *long long* or +*unsigned long long* argument, or a following n conversion corresponds to +a pointer to a long long argument. + +## q + +A synonym for **ll**. + +## L + +A following a, A, e, E, f, F, g, or G conversion corresponds to a long double +argument. + +## z + +A following integer conversion corresponds to a *size_t* or *ssize_t* +argument. + +# Conversion specifiers + +A character that specifies the type of conversion to be applied. The +conversion specifiers and their meanings are: + +## d, i + +The int argument is converted to signed decimal notation. The precision, if +any, gives the minimum number of digits that must appear; if the converted +value requires fewer digits, it is padded on the left with zeros. The default +precision is 1. When 0 is printed with an explicit precision 0, the output is +empty. + +## o, u, x, X + +The unsigned int argument is converted to unsigned octal (o), unsigned decimal +(u), or unsigned hexadecimal (**x** and **X**) notation. The letters +*abcdef* are used for **x** conversions; the letters *ABCDEF* are +used for **X** conversions. The precision, if any, gives the minimum number +of digits that must appear; if the converted value requires fewer digits, it +is padded on the left with zeros. The default precision is 1. When 0 is +printed with an explicit precision 0, the output is empty. + +## e, E + +The double argument is rounded and output in the style **"[-]d.ddde±dd"** + +## f, F + +The double argument is rounded and output to decimal notation in the style +**"[-]ddd.ddd"**. + +## g, G + +The double argument is converted in style f or e. + +## c + +The int argument is converted to an unsigned char, and the resulting character +is written. + +## s + +The *const char ** argument is expected to be a pointer to an array of +character type (pointer to a string). Characters from the array are written up +to (but not including) a terminating null byte. If a precision is specified, +no more than the number specified are written. If a precision is given, no +null byte need be present; if the precision is not specified, or is greater +than the size of the array, the array must contain a terminating null byte. + +## p + +The *void ** pointer argument is printed in hexadecimal. + +## n + +The number of characters written so far is stored into the integer pointed to +by the corresponding argument. + +## % + +A '%' symbol is written. No argument is converted. + +# EXAMPLE + +~~~c +const char *name = "John"; + +int main(void) +{ + curl_mprintf("My name is %s\n", name); + curl_mprintf("Pi is almost %f\n", (double)25.0/8); +} +~~~ + +# AVAILABILITY + +These functions might be removed from the public libcurl API in the future. Do +not use them in new programs or projects. + +# RETURN VALUE + +The **curl_maprintf** and **curl_mvaprintf** functions return a pointer to +a newly allocated string, or NULL if it failed. + +All other functions return the number of characters actually printed +(excluding the null byte used to end output to strings). Note that this +sometimes differ from how the POSIX versions of these functions work. diff --git a/docs/libcurl/curl_multi_add_handle.md b/docs/libcurl/curl_multi_add_handle.md new file mode 100644 index 0000000..3d6ba81 --- /dev/null +++ b/docs/libcurl/curl_multi_add_handle.md @@ -0,0 +1,88 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_add_handle +Section: 3 +Source: libcurl +See-also: + - curl_multi_cleanup (3) + - curl_multi_get_handles (3) + - curl_multi_init (3) + - curl_multi_setopt (3) + - curl_multi_socket_action (3) +--- + +# NAME + +curl_multi_add_handle - add an easy handle to a multi session + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle); +~~~ + +# DESCRIPTION + +Adds the *easy handle* to the *multi_handle*. + +While an easy handle is added to a multi stack, you cannot and you must not +use curl_easy_perform(3) on that handle. After having removed the easy +handle from the multi stack again, it is perfectly fine to use it with the +easy interface again. + +If the easy handle is not set to use a shared (CURLOPT_SHARE(3)) cache, +it is made to use a DNS cache that is shared between all easy handles within +the multi handle when curl_multi_add_handle(3) is called. + +When an easy interface is added to a multi handle, it is set to use a shared +connection cache owned by the multi handle. Removing and adding new easy +handles does not affect the pool of connections or the ability to do +connection reuse. + +If you have CURLMOPT_TIMERFUNCTION(3) set in the multi handle (as you +should if you are working event-based with curl_multi_socket_action(3) +and friends), that callback is called from within this function to ask for an +updated timer so that your main event loop gets the activity on this handle to +get started. + +The easy handle remains added to the multi handle until you remove it again +with curl_multi_remove_handle(3) - even when a transfer with that +specific easy handle is completed. + +You should remove the easy handle from the multi stack before you terminate +first the easy handle and then the multi handle: + +1 - curl_multi_remove_handle(3) + +2 - curl_easy_cleanup(3) + +3 - curl_multi_cleanup(3) + +# EXAMPLE + +~~~c +int main(void) +{ + /* init a multi stack */ + CURLM *multi = curl_multi_init(); + + /* create two easy handles */ + CURL *http_handle = curl_easy_init(); + CURL *http_handle2 = curl_easy_init(); + + /* add individual transfers */ + curl_multi_add_handle(multi, http_handle); + curl_multi_add_handle(multi, http_handle2); +} +~~~ + +# AVAILABILITY + +Added in 7.9.6 + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. diff --git a/docs/libcurl/curl_multi_assign.md b/docs/libcurl/curl_multi_assign.md new file mode 100644 index 0000000..3f01349 --- /dev/null +++ b/docs/libcurl/curl_multi_assign.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_assign +Section: 3 +Source: libcurl +See-also: + - curl_multi_setopt (3) + - curl_multi_socket_action (3) +--- + +# NAME + +curl_multi_assign - set data to associate with an internal socket + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, + void *sockptr); +~~~ + +# DESCRIPTION + +This function creates an association in the multi handle between the given +socket and a private pointer of the application. This is designed for +curl_multi_socket_action(3) uses. + +When set, the *sockptr* pointer is passed to all future socket callbacks +for the specific *sockfd* socket. + +If the given *sockfd* is not already in use by libcurl, this function +returns an error. + +libcurl only keeps one single pointer associated with a socket, so calling +this function several times for the same socket makes the last set pointer get +used. + +The idea here being that this association (socket to private pointer) is +something that just about every application that uses this API needs and then +libcurl can just as well do it since it already has the necessary +functionality. + +It is acceptable to call this function from your multi callback functions. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *multi = curl_multi_init(); + void *ourstructp; /* pointer to our data */ + curl_socket_t fd; /* file descriptor to associate our data with */ + + /* make our struct pointer associated with socket fd */ + CURLMcode mc = curl_multi_assign(multi, fd, ourstructp); + if(mc) + printf("error: %s\n", curl_multi_strerror(mc)); +} +~~~ + +# AVAILABILITY + +Added in 7.15.5 + +# RETURN VALUE + +The standard CURLMcode for multi interface error codes. + +# TYPICAL USAGE + +In a typical application you allocate a struct or at least use some kind of +semi-dynamic data for each socket that we must wait for action on when using +the curl_multi_socket_action(3) approach. + +When our socket-callback gets called by libcurl and we get to know about yet +another socket to wait for, we can use curl_multi_assign(3) to point out +the particular data so that when we get updates about this same socket again, +we do not have to find the struct associated with this socket by ourselves. diff --git a/docs/libcurl/curl_multi_cleanup.md b/docs/libcurl/curl_multi_cleanup.md new file mode 100644 index 0000000..9aa64a8 --- /dev/null +++ b/docs/libcurl/curl_multi_cleanup.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_cleanup +Section: 3 +Source: libcurl +See-also: + - curl_easy_cleanup (3) + - curl_easy_init (3) + - curl_multi_get_handles (3) + - curl_multi_init (3) +--- + +# NAME + +curl_multi_cleanup - close down a multi session + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_cleanup(CURLM *multi_handle); +~~~ + +# DESCRIPTION + +Cleans up and removes a whole multi stack. It does not free or touch any +individual easy handles in any way - they still need to be closed +individually, using the usual curl_easy_cleanup(3) way. The order of +cleaning up should be: + +1 - curl_multi_remove_handle(3) before any easy handles are cleaned up + +2 - curl_easy_cleanup(3) can now be called independently since the easy +handle is no longer connected to the multi handle + +3 - curl_multi_cleanup(3) should be called when all easy handles are +removed + +Passing in a NULL pointer in *multi_handle* makes this function return +CURLM_BAD_HANDLE immediately with no other action. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *multi = curl_multi_init(); + + /* when the multi transfer is done ... */ + + /* remove all easy handles, then: */ + curl_multi_cleanup(multi); +} +~~~ + +# AVAILABILITY + +Added in 7.9.6 + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. On success, +CURLM_OK is returned. diff --git a/docs/libcurl/curl_multi_fdset.md b/docs/libcurl/curl_multi_fdset.md new file mode 100644 index 0000000..37d5959 --- /dev/null +++ b/docs/libcurl/curl_multi_fdset.md @@ -0,0 +1,119 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_fdset +Section: 3 +Source: libcurl +See-also: + - curl_multi_cleanup (3) + - curl_multi_init (3) + - curl_multi_perform (3) + - curl_multi_timeout (3) + - curl_multi_wait (3) + - select (2) +--- + +# NAME + +curl_multi_fdset - extracts file descriptor information from a multi handle + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); +~~~ + +# DESCRIPTION + +This function extracts file descriptor information from a given multi_handle. +libcurl returns its *fd_set* sets. The application can use these to +select() on, but be sure to *FD_ZERO* them before calling this function as +curl_multi_fdset(3) only adds its own descriptors, it does not zero or +otherwise remove any others. The curl_multi_perform(3) function should +be called as soon as one of them is ready to be read from or written to. + +The *read_fd_set* argument should point to an object of type **fd_set** +that on returns specifies the file descriptors to be checked for being ready +to read. + +The *write_fd_set* argument should point to an object of type **fd_set** +that on return specifies the file descriptors to be checked for being ready to +write. + +The *exc_fd_set* argument should point to an object of type **fd_set** +that on return specifies the file descriptors to be checked for error +conditions. + +If no file descriptors are set by libcurl, *max_fd* contain -1 when this +function returns. Otherwise it contains the highest descriptor number libcurl +set. When libcurl returns -1 in *max_fd*, it is because libcurl currently +does something that is not possible for your application to monitor with a +socket and unfortunately you can then not know exactly when the current action +is completed using select(). You then need to wait a while before you proceed +and call curl_multi_perform(3) anyway. How long to wait? Unless +curl_multi_timeout(3) gives you a lower number, we suggest 100 +milliseconds or so, but you may want to test it out in your own particular +conditions to find a suitable value. + +When doing select(), you should use curl_multi_timeout(3) to figure out +how long to wait for action. Call curl_multi_perform(3) even if no +activity has been seen on the **fd_sets** after the timeout expires as +otherwise internal retries and timeouts may not work as you would think and +want. + +If one of the sockets used by libcurl happens to be larger than what can be +set in an **fd_set**, which on POSIX systems means that the file descriptor +is larger than **FD_SETSIZE**, then libcurl tries to not set it. Setting a +too large file descriptor in an **fd_set** implies an out of bounds write +which can cause crashes, or worse. The effect of NOT storing it might possibly +save you from the crash, but makes your program NOT wait for sockets it should +wait for... + +# EXAMPLE + +~~~c +int main(void) +{ + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd; + int rc; + CURLMcode mc; + struct timeval timeout = {1, 0}; + + CURLM *multi = curl_multi_init(); + + do { + + /* call curl_multi_perform() */ + + /* get file descriptors from the transfers */ + mc = curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); + + if(mc != CURLM_OK) { + fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); + break; + } + + /* wait for activity on one of the sockets */ + rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); + + } while(!mc); +} +~~~ + +# AVAILABILITY + +Added in 7.9.6 + +# RETURN VALUE + +**CURLMcode** type, general libcurl multi interface error code. See +libcurl-errors(3) diff --git a/docs/libcurl/curl_multi_get_handles.md b/docs/libcurl/curl_multi_get_handles.md new file mode 100644 index 0000000..0a7ff67 --- /dev/null +++ b/docs/libcurl/curl_multi_get_handles.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_get_handles +Section: 3 +Source: libcurl +See-also: + - curl_multi_add_handle (3) + - curl_multi_cleanup (3) + - curl_multi_init (3) + - curl_multi_remove_handle (3) +--- + +# NAME + +curl_multi_get_handles - returns all added easy handles + +# SYNOPSIS + +~~~c +#include + +CURL **curl_multi_get_handles(CURLM *multi_handle); +~~~ + +# DESCRIPTION + +Returns an array with pointers to all added easy handles. The end of the list +is marked with a NULL pointer. + +Even if there is not a single easy handle added, this still returns an array +but with only a single NULL pointer entry. + +The returned array contains all the handles that are present at the time of +the call. As soon as a handle has been removed from or a handle has been added +to the multi handle after the handle array was returned, the two data points +are out of sync. + +The order of the easy handles within the array is not guaranteed. + +The returned array must be freed with a call to curl_free(3) after use. + +# EXAMPLE + +~~~c +int main(void) +{ + /* init a multi stack */ + CURLM *multi = curl_multi_init(); + CURL *curl = curl_easy_init(); + + if(curl) { + /* add the transfer */ + curl_multi_add_handle(multi, curl); + + /* extract all added handles */ + CURL **list = curl_multi_get_handles(multi); + + if(list) { + int i; + /* remove all added handles */ + for(i = 0; list[i]; i++) { + curl_multi_remove_handle(multi, list[i]); + } + curl_free(list); + } + } +} +~~~ + +# AVAILABILITY + +Added in 8.4.0 + +# RETURN VALUE + +Returns NULL on failure. Otherwise it returns a pointer to an allocated array. diff --git a/docs/libcurl/curl_multi_info_read.md b/docs/libcurl/curl_multi_info_read.md new file mode 100644 index 0000000..23d515d --- /dev/null +++ b/docs/libcurl/curl_multi_info_read.md @@ -0,0 +1,102 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_info_read +Section: 3 +Source: libcurl +See-also: + - curl_multi_cleanup (3) + - curl_multi_init (3) + - curl_multi_perform (3) +--- + +# NAME + +curl_multi_info_read - read multi stack information + +# SYNOPSIS + +~~~c +#include + +CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue); +~~~ + +# DESCRIPTION + +Ask the multi handle if there are any messages from the individual +transfers. Messages may include information such as an error code from the +transfer or just the fact that a transfer is completed. More details on these +should be written down as well. + +Repeated calls to this function returns a new struct each time, until a NULL +is returned as a signal that there is no more to get at this point. The +integer pointed to with *msgs_in_queue* contains the number of remaining +messages after this function was called. + +When you fetch a message using this function, it is removed from the internal +queue so calling this function again does not return the same message +again. It instead returns new messages at each new invoke until the queue is +emptied. + +**WARNING:** The data the returned pointer points to does not survive +calling curl_multi_cleanup(3), curl_multi_remove_handle(3) or +curl_easy_cleanup(3). + +The *CURLMsg* struct is simple and only contains basic information. If +more involved information is wanted, the particular "easy handle" is present +in that struct and can be used in subsequent regular +curl_easy_getinfo(3) calls (or similar): + +~~~c + struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; + }; +~~~ +When **msg** is *CURLMSG_DONE*, the message identifies a transfer that +is done, and then **result** contains the return code for the easy handle +that just completed. + +At this point, there are no other **msg** types defined. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *multi = curl_multi_init(); + CURL *curl = curl_easy_init(); + if(curl) { + struct CURLMsg *m; + + /* call curl_multi_perform or curl_multi_socket_action first, then loop + through and check if there are any transfers that have completed */ + + do { + int msgq = 0; + m = curl_multi_info_read(multi, &msgq); + if(m && (m->msg == CURLMSG_DONE)) { + CURL *e = m->easy_handle; + /* m->data.result holds the error code for the transfer */ + curl_multi_remove_handle(multi, e); + curl_easy_cleanup(e); + } + } while(m); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9.6 + +# RETURN VALUE + +A pointer to a filled-in struct, or NULL if it failed or ran out of +structs. It also writes the number of messages left in the queue (after this +read) in the integer the second argument points to. diff --git a/docs/libcurl/curl_multi_init.md b/docs/libcurl/curl_multi_init.md new file mode 100644 index 0000000..0e91b57 --- /dev/null +++ b/docs/libcurl/curl_multi_init.md @@ -0,0 +1,57 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_init +Section: 3 +Source: libcurl +See-also: + - curl_easy_init (3) + - curl_global_init (3) + - curl_multi_add_handle (3) + - curl_multi_cleanup (3) + - curl_multi_get_handles (3) +--- + +# NAME + +curl_multi_init - create a multi handle + +# SYNOPSIS + +~~~c +#include + +CURLM *curl_multi_init(); +~~~ + +# DESCRIPTION + +This function returns a pointer to a *CURLM* handle to be used as input to +all the other multi-functions, sometimes referred to as a multi handle in some +places in the documentation. This init call MUST have a corresponding call to +curl_multi_cleanup(3) when the operation is complete. + +# EXAMPLE + +~~~c +int main(void) +{ + /* init a multi stack */ + CURLM *multi = curl_multi_init(); + CURL *curl = curl_easy_init(); + CURL *curl2 = curl_easy_init(); + + /* add individual transfers */ + curl_multi_add_handle(multi, curl); + curl_multi_add_handle(multi, curl2); +} +~~~ + +# AVAILABILITY + +Added in 7.9.6 + +# RETURN VALUE + +If this function returns NULL, something went wrong and you cannot use the +other curl functions. diff --git a/docs/libcurl/curl_multi_perform.md b/docs/libcurl/curl_multi_perform.md new file mode 100644 index 0000000..ecad22e --- /dev/null +++ b/docs/libcurl/curl_multi_perform.md @@ -0,0 +1,107 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_perform +Section: 3 +Source: libcurl +See-also: + - curl_multi_add_handle (3) + - curl_multi_cleanup (3) + - curl_multi_fdset (3) + - curl_multi_info_read (3) + - curl_multi_init (3) + - curl_multi_wait (3) + - libcurl-errors (3) +--- + +# NAME + +curl_multi_perform - reads/writes available data from easy handles + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles); +~~~ + +# DESCRIPTION + +This function performs transfers on all the added handles that need attention +in a non-blocking fashion. The easy handles have previously been added to the +multi handle with curl_multi_add_handle(3). + +When an application has found out there is data available for the multi_handle +or a timeout has elapsed, the application should call this function to +read/write whatever there is to read or write right now etc. +curl_multi_perform(3) returns as soon as the reads/writes are done. This +function does not require that there actually is any data available for +reading or that data can be written, it can be called just in case. It stores +the number of handles that still transfer data in the second argument's +integer-pointer. + +If the amount of *running_handles* is changed from the previous call (or +is less than the amount of easy handles you have added to the multi handle), +you know that there is one or more transfers less "running". You can then call +curl_multi_info_read(3) to get information about each individual +completed transfer, and that returned info includes CURLcode and more. If an +added handle fails quickly, it may never be counted as a running_handle. You +could use curl_multi_info_read(3) to track actual status of the added +handles in that case. + +When *running_handles* is set to zero (0) on the return of this function, +there is no longer any transfers in progress. + +When this function returns error, the state of all transfers are uncertain and +they cannot be continued. curl_multi_perform(3) should not be called +again on the same multi handle after an error has been returned, unless first +removing all the handles and adding new ones. + +# EXAMPLE + +~~~c +int main(void) +{ + int still_running; + CURL *multi = curl_multi_init(); + CURL *curl = curl_easy_init(); + if(curl) { + curl_multi_add_handle(multi, curl); + do { + CURLMcode mc = curl_multi_perform(multi, &still_running); + + if(!mc && still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi, NULL, 0, 1000, NULL); + + if(mc) { + fprintf(stderr, "curl_multi_poll() failed, code %d.\n", (int)mc); + break; + } + + /* if there are still transfers, loop! */ + } while(still_running); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9.6 + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. + +This function returns errors regarding the whole multi stack. Problems on +individual transfers may have occurred even when this function returns +*CURLM_OK*. Use curl_multi_info_read(3) to figure out how individual +transfers did. + +# TYPICAL USAGE + +Most applications use curl_multi_poll(3) to make libcurl wait for +activity on any of the ongoing transfers. As soon as one or more file +descriptor has activity or the function times out, the application calls +curl_multi_perform(3). diff --git a/docs/libcurl/curl_multi_poll.md b/docs/libcurl/curl_multi_poll.md new file mode 100644 index 0000000..b239f28 --- /dev/null +++ b/docs/libcurl/curl_multi_poll.md @@ -0,0 +1,128 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_poll +Section: 3 +Source: libcurl +See-also: + - curl_multi_fdset (3) + - curl_multi_perform (3) + - curl_multi_wait (3) + - curl_multi_wakeup (3) +--- + +# NAME + +curl_multi_poll - polls on all easy handles in a multi handle + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_poll(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *numfds); +~~~ + +# DESCRIPTION + +curl_multi_poll(3) polls all file descriptors used by the curl easy +handles contained in the given multi handle set. It blocks until activity is +detected on at least one of the handles or *timeout_ms* has passed. +Alternatively, if the multi handle has a pending internal timeout that has a +shorter expiry time than *timeout_ms*, that shorter time is used instead +to make sure timeout accuracy is reasonably kept. + +The calling application may pass additional curl_waitfd structures which are +similar to *poll(2)*'s *pollfd* structure to be waited on in the same +call. + +On completion, if *numfds* is non-NULL, it gets populated with the total +number of file descriptors on which interesting events occurred. This number +can include both libcurl internal descriptors as well as descriptors provided +in *extra_fds*. + +The curl_multi_wakeup(3) function can be used from another thread to +wake up this function and return faster. This is one of the details +that makes this function different than curl_multi_wait(3) which cannot +be woken up this way. + +If no extra file descriptors are provided and libcurl has no file descriptor +to offer to wait for, this function instead waits during *timeout_ms* +milliseconds (or shorter if an internal timer indicates so). This is the other +detail that makes this function different than curl_multi_wait(3). + +This function is encouraged to be used instead of select(3) when using the +multi interface to allow applications to easier circumvent the common problem +with 1024 maximum file descriptors. + +# curl_waitfd + +~~~c +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; +}; +~~~ + +## CURL_WAIT_POLLIN + +Bit flag to curl_waitfd.events indicating the socket should poll on read +events such as new data received. + +## CURL_WAIT_POLLPRI + +Bit flag to curl_waitfd.events indicating the socket should poll on high +priority read events such as out of band data. + +## CURL_WAIT_POLLOUT + +Bit flag to curl_waitfd.events indicating the socket should poll on write +events such as the socket being clear to write without blocking. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *easy_handle; + CURLM *multi_handle; + int still_running = 0; + + /* add the individual easy handle */ + curl_multi_add_handle(multi_handle, easy_handle); + + do { + CURLMcode mc; + int numfds; + + mc = curl_multi_perform(multi_handle, &still_running); + + if(mc == CURLM_OK) { + /* wait for activity or timeout */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, &numfds); + } + + if(mc != CURLM_OK) { + fprintf(stderr, "curl_multi failed, code %d.\n", mc); + break; + } + + } while(still_running); + + curl_multi_remove_handle(multi_handle, easy_handle); +} +~~~ + +# AVAILABILITY + +Added in 7.66.0. + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. See +libcurl-errors(3) diff --git a/docs/libcurl/curl_multi_remove_handle.md b/docs/libcurl/curl_multi_remove_handle.md new file mode 100644 index 0000000..bb8ee1c --- /dev/null +++ b/docs/libcurl/curl_multi_remove_handle.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_remove_handle +Section: 3 +Source: libcurl +See-also: + - curl_multi_add_handle (3) + - curl_multi_cleanup (3) + - curl_multi_init (3) +--- + +# NAME + +curl_multi_remove_handle - remove an easy handle from a multi session + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *easy_handle); +~~~ + +# DESCRIPTION + +Removes a given *easy_handle* from the *multi_handle*. This makes the +specified easy handle be removed from this multi handle's control. + +When the easy handle has been removed from a multi stack, it is again +perfectly legal to invoke curl_easy_perform(3) on this easy handle. + +Removing an easy handle while being in use is perfectly legal and effectively +halts the transfer in progress involving that easy handle. All other easy +handles and transfers remain unaffected. + +It is fine to remove a handle at any time during a transfer, just not from +within any libcurl callback function. + +Removing an easy handle from the multi handle before the corresponding +transfer is complete might cause libcurl to close the connection - if the +state of it and the internal protocol handler deem it necessary. Otherwise +libcurl keeps the connection alive in the connection pool associated with the +multi handle, ready to get reused for a future transfer using this multi +handle. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *multi = curl_multi_init(); + int queued = 0; + + /* when an easy handle has completed, remove it */ + CURLMsg *msg = curl_multi_info_read(multi, &queued); + if(msg) { + if(msg->msg == CURLMSG_DONE) { + /* a transfer ended */ + fprintf(stderr, "Transfer completed\n"); + curl_multi_remove_handle(multi, msg->easy_handle); + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.9.6 + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. diff --git a/docs/libcurl/curl_multi_setopt.md b/docs/libcurl/curl_multi_setopt.md new file mode 100644 index 0000000..c0c8a3e --- /dev/null +++ b/docs/libcurl/curl_multi_setopt.md @@ -0,0 +1,125 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_setopt +Section: 3 +Source: libcurl +See-also: + - curl_multi_cleanup (3) + - curl_multi_info_read (3) + - curl_multi_init (3) + - curl_multi_socket (3) +--- + +# NAME + +curl_multi_setopt - set options for a curl multi handle + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *multi_handle, CURLMoption option, parameter); +~~~ + +# DESCRIPTION + +curl_multi_setopt(3) is used to tell a libcurl multi handle how to +behave. By using the appropriate options to curl_multi_setopt(3), you +can change libcurl's behavior when using that multi handle. All options are +set with the *option* followed by the *parameter*. That parameter can +be a **long**, a **function pointer**, an **object pointer** or a +**curl_off_t** type, depending on what the specific option expects. Read +this manual carefully as bad input values may cause libcurl to behave +badly. You can only set one option in each function call. + +# OPTIONS + +## CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE + +See CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3) + +## CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE + +See CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3) + +## CURLMOPT_MAX_HOST_CONNECTIONS + +See CURLMOPT_MAX_HOST_CONNECTIONS(3) + +## CURLMOPT_MAX_PIPELINE_LENGTH + +See CURLMOPT_MAX_PIPELINE_LENGTH(3) + +## CURLMOPT_MAX_TOTAL_CONNECTIONS + +See CURLMOPT_MAX_TOTAL_CONNECTIONS(3) + +## CURLMOPT_MAXCONNECTS + +See CURLMOPT_MAXCONNECTS(3) + +## CURLMOPT_PIPELINING + +See CURLMOPT_PIPELINING(3) + +## CURLMOPT_PIPELINING_SITE_BL + +See CURLMOPT_PIPELINING_SITE_BL(3) + +## CURLMOPT_PIPELINING_SERVER_BL + +See CURLMOPT_PIPELINING_SERVER_BL(3) + +## CURLMOPT_PUSHFUNCTION + +See CURLMOPT_PUSHFUNCTION(3) + +## CURLMOPT_PUSHDATA + +See CURLMOPT_PUSHDATA(3) + +## CURLMOPT_SOCKETFUNCTION + +See CURLMOPT_SOCKETFUNCTION(3) + +## CURLMOPT_SOCKETDATA + +See CURLMOPT_SOCKETDATA(3) + +## CURLMOPT_TIMERFUNCTION + +See CURLMOPT_TIMERFUNCTION(3) + +## CURLMOPT_TIMERDATA + +See CURLMOPT_TIMERDATA(3) + +## CURLMOPT_MAX_CONCURRENT_STREAMS + +See CURLMOPT_MAX_CONCURRENT_STREAMS(3) + +# EXAMPLE + +~~~c + +#define MAX_PARALLEL 45 + +int main(void) +{ + CURLM *multi; + /* Limit the amount of simultaneous connections curl should allow: */ + curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)MAX_PARALLEL); +} +~~~ + +# AVAILABILITY + +Added in 7.15.4 + +# RETURN VALUE + +The standard CURLMcode for multi interface error codes. Note that it returns a +CURLM_UNKNOWN_OPTION if you try setting an option that this version of libcurl +does not know of. diff --git a/docs/libcurl/curl_multi_socket.md b/docs/libcurl/curl_multi_socket.md new file mode 100644 index 0000000..ff465c3 --- /dev/null +++ b/docs/libcurl/curl_multi_socket.md @@ -0,0 +1,95 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_socket +Section: 3 +Source: libcurl +See-also: + - curl_multi_cleanup (3) + - curl_multi_fdset (3) + - curl_multi_info_read (3) + - curl_multi_init (3) + - the hiperfifo.c example +--- + +# NAME + +curl_multi_socket - reads/writes available data + +# SYNOPSIS + +~~~c +#include +CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t sockfd, + int *running_handles); + +CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); +~~~ + +# DESCRIPTION + +These functions are deprecated. Do not use. See +curl_multi_socket_action(3) instead. + +At return, the integer **running_handles** points to contains the number of +still running easy handles within the multi handle. When this number reaches +zero, all transfers are complete/done. Note that when you call +curl_multi_socket_action(3) on a specific socket and the counter +decreases by one, it DOES NOT necessarily mean that this exact socket/transfer +is the one that completed. Use curl_multi_info_read(3) to figure out +which easy handle that completed. + +The curl_multi_socket_action(3) functions inform the application about +updates in the socket (file descriptor) status by doing none, one, or multiple +calls to the socket callback function set with the +CURLMOPT_SOCKETFUNCTION(3) option to curl_multi_setopt(3). They +update the status with changes since the previous time the callback was +called. + +Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option +with curl_multi_setopt(3). Your application then gets called with +information on how long to wait for socket actions at most before doing the +timeout action: call the curl_multi_socket_action(3) function with the +**sockfd** argument set to CURL_SOCKET_TIMEOUT. You can also use the +curl_multi_timeout(3) function to poll the value at any given time, but +for an event-based system using the callback is far better than relying on +polling the timeout value. + +Usage of curl_multi_socket(3) is deprecated, whereas the function is +equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to +0. + +Force libcurl to (re-)check all its internal sockets and transfers instead of +just a single one by calling curl_multi_socket_all(3). Note that there +should not be any reason to use this function. + +# EXAMPLE + +~~~c +int main(void) +{ + /* the event-library gets told when there activity on the socket 'fd', + which we translate to a call to curl_multi_socket_action() */ + int running; + int rc; + int fd; + CURLM *multi; + rc = curl_multi_socket(multi, fd, &running); +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.15.4, and is deemed stable since +7.16.0. + +curl_multi_socket(3) is deprecated, use +curl_multi_socket_action(3) instead! + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. + +The return code is for the whole multi stack. Problems still might have +occurred on individual transfers even when one of these functions return OK. diff --git a/docs/libcurl/curl_multi_socket_action.md b/docs/libcurl/curl_multi_socket_action.md new file mode 100644 index 0000000..8af17c8 --- /dev/null +++ b/docs/libcurl/curl_multi_socket_action.md @@ -0,0 +1,120 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_socket_action +Section: 3 +Source: libcurl +See-also: + - curl_multi_cleanup (3) + - curl_multi_fdset (3) + - curl_multi_info_read (3) + - curl_multi_init (3) + - the hiperfifo.c example +--- + +# NAME + +curl_multi_socket_action - reads/writes available data given an action + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t sockfd, + int ev_bitmask, + int *running_handles); +~~~ + +# DESCRIPTION + +When the application has detected action on a socket handled by libcurl, it +should call curl_multi_socket_action(3) with the **sockfd** argument +set to the socket with the action. When the events on a socket are known, they +can be passed as an events bitmask **ev_bitmask** by first setting +**ev_bitmask** to 0, and then adding using bitwise OR (|) any combination of +events to be chosen from CURL_CSELECT_IN, CURL_CSELECT_OUT or +CURL_CSELECT_ERR. When the events on a socket are unknown, pass 0 instead, and +libcurl tests the descriptor internally. It is also permissible to pass +CURL_SOCKET_TIMEOUT to the **sockfd** parameter in order to initiate the +whole process or when a timeout occurs. + +At return, **running_handles** points to the number of running easy handles +within the multi handle. When this number reaches zero, all transfers are +complete/done. When you call curl_multi_socket_action(3) on a specific +socket and the counter decreases by one, it DOES NOT necessarily mean that +this exact socket/transfer is the one that completed. Use +curl_multi_info_read(3) to figure out which easy handle that completed. + +The curl_multi_socket_action(3) function informs the application about +updates in the socket (file descriptor) status by doing none, one, or multiple +calls to the socket callback function set with the +CURLMOPT_SOCKETFUNCTION(3) option to curl_multi_setopt(3). They +update the status with changes since the previous time the callback was +called. + +Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option +with curl_multi_setopt(3). Your application then gets called with +information on how long to wait for socket actions at most before doing the +timeout action: call the curl_multi_socket_action(3) function with the +**sockfd** argument set to CURL_SOCKET_TIMEOUT. You can also use the +curl_multi_timeout(3) function to poll the value at any given time, but +for an event-based system using the callback is far better than relying on +polling the timeout value. + +When this function returns error, the state of all transfers are uncertain and +they cannot be continued. curl_multi_socket_action(3) should not be +called again on the same multi handle after an error has been returned, unless +first removing all the handles and adding new ones. + +# TYPICAL USAGE + +1. Create a multi handle + +2. Set the socket callback with CURLMOPT_SOCKETFUNCTION(3) + +3. Set the timeout callback with CURLMOPT_TIMERFUNCTION(3), to get to +know what timeout value to use when waiting for socket activities. + +4. Add easy handles with curl_multi_add_handle() + +5. Provide some means to manage the sockets libcurl is using, so you can check +them for activity. This can be done through your application code, or by way +of an external library such as libevent or glib. + +6. Call curl_multi_socket_action(..., CURL_SOCKET_TIMEOUT, 0, ...) +to kickstart everything. To get one or more callbacks called. + +7. Wait for activity on any of libcurl's sockets, use the timeout value your +callback has been told. + +8, When activity is detected, call curl_multi_socket_action() for the +socket(s) that got action. If no activity is detected and the timeout expires, +call curl_multi_socket_action(3) with *CURL_SOCKET_TIMEOUT*. + +# EXAMPLE + +~~~c +int main(void) +{ + /* the event-library gets told when there activity on the socket 'fd', + which we translate to a call to curl_multi_socket_action() */ + int running; + CURLM *multi; /* the stack we work with */ + int fd; /* the descriptor that had action */ + int bitmask; /* what activity that happened */ + CURLMcode mc = curl_multi_socket_action(multi, fd, bitmask, &running); + if(mc) + printf("error: %s\n", curl_multi_strerror(mc)); +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.15.4, and is deemed stable since 7.16.0. + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. See +libcurl-errors(3) diff --git a/docs/libcurl/curl_multi_socket_all.md b/docs/libcurl/curl_multi_socket_all.md new file mode 100644 index 0000000..ff465c3 --- /dev/null +++ b/docs/libcurl/curl_multi_socket_all.md @@ -0,0 +1,95 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_socket +Section: 3 +Source: libcurl +See-also: + - curl_multi_cleanup (3) + - curl_multi_fdset (3) + - curl_multi_info_read (3) + - curl_multi_init (3) + - the hiperfifo.c example +--- + +# NAME + +curl_multi_socket - reads/writes available data + +# SYNOPSIS + +~~~c +#include +CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t sockfd, + int *running_handles); + +CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); +~~~ + +# DESCRIPTION + +These functions are deprecated. Do not use. See +curl_multi_socket_action(3) instead. + +At return, the integer **running_handles** points to contains the number of +still running easy handles within the multi handle. When this number reaches +zero, all transfers are complete/done. Note that when you call +curl_multi_socket_action(3) on a specific socket and the counter +decreases by one, it DOES NOT necessarily mean that this exact socket/transfer +is the one that completed. Use curl_multi_info_read(3) to figure out +which easy handle that completed. + +The curl_multi_socket_action(3) functions inform the application about +updates in the socket (file descriptor) status by doing none, one, or multiple +calls to the socket callback function set with the +CURLMOPT_SOCKETFUNCTION(3) option to curl_multi_setopt(3). They +update the status with changes since the previous time the callback was +called. + +Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option +with curl_multi_setopt(3). Your application then gets called with +information on how long to wait for socket actions at most before doing the +timeout action: call the curl_multi_socket_action(3) function with the +**sockfd** argument set to CURL_SOCKET_TIMEOUT. You can also use the +curl_multi_timeout(3) function to poll the value at any given time, but +for an event-based system using the callback is far better than relying on +polling the timeout value. + +Usage of curl_multi_socket(3) is deprecated, whereas the function is +equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to +0. + +Force libcurl to (re-)check all its internal sockets and transfers instead of +just a single one by calling curl_multi_socket_all(3). Note that there +should not be any reason to use this function. + +# EXAMPLE + +~~~c +int main(void) +{ + /* the event-library gets told when there activity on the socket 'fd', + which we translate to a call to curl_multi_socket_action() */ + int running; + int rc; + int fd; + CURLM *multi; + rc = curl_multi_socket(multi, fd, &running); +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.15.4, and is deemed stable since +7.16.0. + +curl_multi_socket(3) is deprecated, use +curl_multi_socket_action(3) instead! + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. + +The return code is for the whole multi stack. Problems still might have +occurred on individual transfers even when one of these functions return OK. diff --git a/docs/libcurl/curl_multi_strerror.md b/docs/libcurl/curl_multi_strerror.md new file mode 100644 index 0000000..5429e0e --- /dev/null +++ b/docs/libcurl/curl_multi_strerror.md @@ -0,0 +1,51 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_strerror +Section: 3 +Source: libcurl +See-also: + - curl_easy_strerror (3) + - curl_share_strerror (3) + - curl_url_strerror (3) + - libcurl-errors (3) +--- + +# NAME + +curl_multi_strerror - return string describing error code + +# SYNOPSIS + +~~~c +#include + +const char *curl_multi_strerror(CURLMcode errornum); +~~~ + +# DESCRIPTION + +This function returns a string describing the *CURLMcode* error code +passed in the argument *errornum*. + +# EXAMPLE + +~~~c +int main(void) +{ + int still_running; + CURLM *multi = curl_multi_init(); + + CURLMcode mc = curl_multi_perform(multi, &still_running); + if(mc) + printf("error: %s\n", curl_multi_strerror(mc)); +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.12.0 + +# RETURN VALUE + +A pointer to a null-terminated string. diff --git a/docs/libcurl/curl_multi_timeout.md b/docs/libcurl/curl_multi_timeout.md new file mode 100644 index 0000000..83bad38 --- /dev/null +++ b/docs/libcurl/curl_multi_timeout.md @@ -0,0 +1,89 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_timeout +Section: 3 +Source: libcurl +See-also: + - curl_multi_fdset (3) + - curl_multi_info_read (3) + - curl_multi_setopt (3) + - curl_multi_socket (3) +--- + +# NAME + +curl_multi_timeout - how long to wait for action before proceeding + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_timeout(CURLM *multi_handle, long *timeout); +~~~ + +# DESCRIPTION + +An application using the libcurl multi interface should call +curl_multi_timeout(3) to figure out how long it should wait for socket +actions - at most - before proceeding. + +Proceeding means either doing the socket-style timeout action: call the +curl_multi_socket_action(3) function with the **sockfd** argument set +to CURL_SOCKET_TIMEOUT, or call curl_multi_perform(3) if you are using +the simpler and older multi interface approach. + +The timeout value returned in the long **timeout** points to, is in number +of milliseconds at this moment. If 0, it means you should proceed immediately +without waiting for anything. If it returns -1, there is no timeout at all set. + +An application that uses the *multi_socket* API should not use this function. +It should instead use the CURLMOPT_TIMERFUNCTION(3) option for proper and +desired behavior. + +Note: if libcurl returns a -1 timeout here, it just means that libcurl +currently has no stored timeout value. You must not wait too long (more than a +few seconds perhaps) before you call curl_multi_perform(3) again. + +# EXAMPLE + +~~~c +int main(void) +{ + struct timeval timeout; + long timeo; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd; + CURLM *multi = curl_multi_init(); + + curl_multi_timeout(multi, &timeo); + if(timeo < 0) + /* no set timeout, use a default */ + timeo = 980; + + timeout.tv_sec = timeo / 1000; + timeout.tv_usec = (timeo % 1000) * 1000; + + /* wait for activities no longer than the set timeout */ + select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); +} +~~~ + +# TYPICAL USAGE + +Call curl_multi_timeout(3), then wait for action on the sockets. Figure +out which sockets to wait for by calling curl_multi_fdset(3). + +When there is activity or timeout, call curl_multi_perform(3) and then +loop - until all transfers are complete. + +# AVAILABILITY + +This function was added in libcurl 7.15.4. + +# RETURN VALUE + +The standard CURLMcode for multi interface error codes. diff --git a/docs/libcurl/curl_multi_wait.md b/docs/libcurl/curl_multi_wait.md new file mode 100644 index 0000000..094ace3 --- /dev/null +++ b/docs/libcurl/curl_multi_wait.md @@ -0,0 +1,121 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_wait +Section: 3 +Source: libcurl +See-also: + - curl_multi_fdset (3) + - curl_multi_perform (3) + - curl_multi_poll (3) +--- + +# NAME + +curl_multi_wait - polls on all easy handles in a multi handle + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *numfds); +~~~ + +# DESCRIPTION + +curl_multi_wait(3) polls all file descriptors used by the curl easy +handles contained in the given multi handle set. It blocks until activity is +detected on at least one of the handles or *timeout_ms* has passed. +Alternatively, if the multi handle has a pending internal timeout that has a +shorter expiry time than *timeout_ms*, that shorter time is be used +instead to make sure timeout accuracy is reasonably kept. + +The calling application may pass additional *curl_waitfd* structures which +are similar to *poll(2)*'s *pollfd* structure to be waited on in the +same call. + +On completion, if *numfds* is non-NULL, it gets populated with the total +number of file descriptors on which interesting events occurred. This number +can include both libcurl internal descriptors as well as descriptors provided +in *extra_fds*. + +If no extra file descriptors are provided and libcurl has no file descriptor +to offer to wait for, this function returns immediately. (Consider using +curl_multi_poll(3) to avoid this behavior.) + +This function is encouraged to be used instead of select(3) when using the +multi interface to allow applications to easier circumvent the common problem +with 1024 maximum file descriptors. + +# curl_waitfd + +~~~c +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; +}; +~~~ + +## CURL_WAIT_POLLIN + +Bit flag to *curl_waitfd.events* indicating the socket should poll on read +events such as new data received. + +## CURL_WAIT_POLLPRI + +Bit flag to *curl_waitfd.events* indicating the socket should poll on high +priority read events such as out of band data. + +## CURL_WAIT_POLLOUT + +Bit flag to *curl_waitfd.events* indicating the socket should poll on +write events such as the socket being clear to write without blocking. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *easy; + CURLM *multi = curl_multi_init(); + int still_running; + + /* add the individual easy handle */ + curl_multi_add_handle(multi, easy); + + do { + CURLMcode mc; + int numfds; + + mc = curl_multi_perform(multi, &still_running); + + if(mc == CURLM_OK) { + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_wait(multi, NULL, 0, 1000, &numfds); + } + + if(mc != CURLM_OK) { + fprintf(stderr, "curl_multi failed, code %d.\n", mc); + break; + } + + } while(still_running); + + curl_multi_remove_handle(multi, easy); +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.28.0. + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. See +libcurl-errors(3) diff --git a/docs/libcurl/curl_multi_wakeup.md b/docs/libcurl/curl_multi_wakeup.md new file mode 100644 index 0000000..f6200c4 --- /dev/null +++ b/docs/libcurl/curl_multi_wakeup.md @@ -0,0 +1,91 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_wakeup +Section: 3 +Source: libcurl +See-also: + - curl_multi_poll (3) + - curl_multi_wait (3) +--- + +# NAME + +curl_multi_wakeup - wakes up a sleeping curl_multi_poll call + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_wakeup(CURLM *multi_handle); +~~~ + +# DESCRIPTION + +This function can be called from any thread and it wakes up a sleeping +curl_multi_poll(3) call that is currently (or is about to be) waiting +for activity or a timeout. + +If the function is called when there is no curl_multi_poll(3) call, it +causes the next call to return immediately. + +Calling this function only guarantees to wake up the current (or the next if +there is no current) curl_multi_poll(3) call, which means it is possible +that multiple calls to this function wake up the same waiting operation. + +This function has no effect on curl_multi_wait(3) calls. + +# EXAMPLE + +~~~c +extern int time_to_die(void); +extern int set_something_to_signal_thread_1_to_exit(void); +extern int decide_to_stop_thread1(); + +int main(void) +{ + CURL *easy; + CURLM *multi; + int still_running; + + /* add the individual easy handle */ + curl_multi_add_handle(multi, easy); + + /* this is thread 1 */ + do { + CURLMcode mc; + int numfds; + + mc = curl_multi_perform(multi, &still_running); + + if(mc == CURLM_OK) { + /* wait for activity, timeout or wakeup */ + mc = curl_multi_poll(multi, NULL, 0, 10000, &numfds); + } + + if(time_to_die()) + return 1; + + } while(still_running); + + curl_multi_remove_handle(multi, easy); + + /* this is thread 2 */ + + if(decide_to_stop_thread1()) { + + set_something_to_signal_thread_1_to_exit(); + + curl_multi_wakeup(multi); + } +} +~~~ + +# AVAILABILITY + +Added in 7.68.0 + +# RETURN VALUE + +CURLMcode type, general libcurl multi interface error code. diff --git a/docs/libcurl/curl_pushheader_byname.md b/docs/libcurl/curl_pushheader_byname.md new file mode 100644 index 0000000..ecb031f --- /dev/null +++ b/docs/libcurl/curl_pushheader_byname.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_pushheader_byname +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PUSHFUNCTION (3) + - curl_pushheader_bynum (3) +--- + +# NAME + +curl_pushheader_byname - get a push header by name + +# SYNOPSIS + +~~~c +#include + +char *curl_pushheader_byname(struct curl_pushheaders *h, const char *name); +~~~ + +# DESCRIPTION + +This is a function that is only functional within a +CURLMOPT_PUSHFUNCTION(3) callback. It makes no sense to try to use it +elsewhere and it has no function then. + +It returns the value for the given header field name (or NULL) for the +incoming server push request. This is a shortcut so that the application does +not have to loop through all headers to find the one it is interested in. The +data this function points to is freed when this callback returns. If more than +one header field use the same name, this returns only the first one. + +# EXAMPLE + +~~~c +#include /* for strncmp */ + +static int push_cb(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *clientp) +{ + char *headp; + int *transfers = (int *)clientp; + FILE *out; + headp = curl_pushheader_byname(headers, ":path"); + if(headp && !strncmp(headp, "/push-", 6)) { + fprintf(stderr, "The PATH is %s\n", headp); + + /* save the push here */ + out = fopen("pushed-stream", "wb"); + + /* write to this file */ + curl_easy_setopt(easy, CURLOPT_WRITEDATA, out); + + (*transfers)++; /* one more */ + + return CURL_PUSH_OK; + } + return CURL_PUSH_DENY; +} + +int main(void) +{ + int counter; + CURLM *multi = curl_multi_init(); + curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_cb); + curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter); +} +~~~ + +# AVAILABILITY + +Added in 7.44.0 + +# RETURN VALUE + +Returns a pointer to the header field content or NULL. diff --git a/docs/libcurl/curl_pushheader_bynum.md b/docs/libcurl/curl_pushheader_bynum.md new file mode 100644 index 0000000..537f06b --- /dev/null +++ b/docs/libcurl/curl_pushheader_bynum.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_pushheader_bynum +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PUSHFUNCTION (3) + - curl_pushheader_byname (3) +--- + +# NAME + +curl_pushheader_bynum - get a push header by index + +# SYNOPSIS + +~~~c +#include + +char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num); +~~~ + +# DESCRIPTION + +This is a function that is only functional within a +CURLMOPT_PUSHFUNCTION(3) callback. It makes no sense to try to use it +elsewhere and it has no function then. + +It returns the value for the header field at the given index **num**, for +the incoming server push request or NULL. The data pointed to is freed by +libcurl when this callback returns. The returned pointer points to a +"name:value" string that gets freed when this callback returns. + +# EXAMPLE + +~~~c +/* output all the incoming push request headers */ +static int push_cb(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *clientp) +{ + int i = 0; + char *field; + do { + field = curl_pushheader_bynum(headers, i); + if(field) + fprintf(stderr, "Push header: %s\n", field); + i++; + } while(field); + return CURL_PUSH_OK; /* permission granted */ +} + +int main(void) +{ + CURLM *multi = curl_multi_init(); + curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_cb); +} +~~~ + +# AVAILABILITY + +Added in 7.44.0 + +# RETURN VALUE + +Returns a pointer to the header field content or NULL. diff --git a/docs/libcurl/curl_share_cleanup.md b/docs/libcurl/curl_share_cleanup.md new file mode 100644 index 0000000..59126a1 --- /dev/null +++ b/docs/libcurl/curl_share_cleanup.md @@ -0,0 +1,54 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_share_cleanup +Section: 3 +Source: libcurl +See-also: + - curl_share_init (3) + - curl_share_setopt (3) +--- + +# NAME + +curl_share_cleanup - Clean up a shared object + +# SYNOPSIS + +~~~c +#include + +CURLSHcode curl_share_cleanup(CURLSH *share_handle); +~~~ + +# DESCRIPTION + +This function deletes a shared object. The share handle cannot be used anymore +when this function has been called. + +Passing in a NULL pointer in *share_handle* makes this function return +immediately with no action. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); + /* use the share, then ... */ + curl_share_cleanup(share); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +CURLSHE_OK (zero) means that the option was set properly, non-zero means an +error occurred as ** defines. See the libcurl-errors(3) +man page for the full list with descriptions. If an error occurs, then the +share object is not deleted. diff --git a/docs/libcurl/curl_share_init.md b/docs/libcurl/curl_share_init.md new file mode 100644 index 0000000..5537107 --- /dev/null +++ b/docs/libcurl/curl_share_init.md @@ -0,0 +1,56 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_share_init +Section: 3 +Source: libcurl +See-also: + - curl_share_cleanup (3) + - curl_share_setopt (3) +--- + +# NAME + +curl_share_init - Create a shared object + +# SYNOPSIS + +~~~c +#include + +CURLSH *curl_share_init(); +~~~ + +# DESCRIPTION + +This function returns a pointer to a *CURLSH* handle to be used as input +to all the other share-functions, sometimes referred to as a share handle in +some places in the documentation. This init call MUST have a corresponding +call to curl_share_cleanup(3) when all operations using the share are +complete. + +This *share handle* is what you pass to curl using the +CURLOPT_SHARE(3) option with curl_easy_setopt(3), to make that +specific curl handle use the data in this share. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +If this function returns NULL, something went wrong (out of memory, etc.) +and therefore the share object was not created. diff --git a/docs/libcurl/curl_share_setopt.md b/docs/libcurl/curl_share_setopt.md new file mode 100644 index 0000000..5ab9550 --- /dev/null +++ b/docs/libcurl/curl_share_setopt.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_share_setopt +Section: 3 +Source: libcurl +See-also: + - curl_share_cleanup (3) + - curl_share_init (3) +--- + +# NAME + +curl_share_setopt - Set options for a shared object + +# SYNOPSIS + +~~~c +#include + +CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option, parameter); +~~~ + +# DESCRIPTION + +Set the *option* to *parameter* for the given *share*. + +# OPTIONS + +## CURLSHOPT_LOCKFUNC + +See CURLSHOPT_LOCKFUNC(3). + +## CURLSHOPT_UNLOCKFUNC + +See CURLSHOPT_UNLOCKFUNC(3). + +## CURLSHOPT_SHARE + +See CURLSHOPT_SHARE(3). + +## CURLSHOPT_UNSHARE + +See CURLSHOPT_UNSHARE(3). + +## CURLSHOPT_USERDATA + +See CURLSHOPT_USERDATA(3). + +# EXAMPLE + +~~~c +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +CURLSHE_OK (zero) means that the option was set properly, non-zero means an +error occurred as ** defines. See the libcurl-errors(3) +man page for the full list with descriptions. diff --git a/docs/libcurl/curl_share_strerror.md b/docs/libcurl/curl_share_strerror.md new file mode 100644 index 0000000..130d43b --- /dev/null +++ b/docs/libcurl/curl_share_strerror.md @@ -0,0 +1,50 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_share_strerror +Section: 3 +Source: libcurl +See-also: + - curl_easy_strerror (3) + - curl_multi_strerror (3) + - curl_url_strerror (3) + - libcurl-errors (3) +--- + +# NAME + +curl_share_strerror - return string describing error code + +# SYNOPSIS + +~~~c +#include + +const char *curl_share_strerror(CURLSHcode errornum); +~~~ + +# DESCRIPTION + +The curl_share_strerror(3) function returns a string describing the +*CURLSHcode* error code passed in the argument *errornum*. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +This function was added in libcurl 7.12.0 + +# RETURN VALUE + +A pointer to a null-terminated string. diff --git a/docs/libcurl/curl_slist_append.md b/docs/libcurl/curl_slist_append.md new file mode 100644 index 0000000..9773fd4 --- /dev/null +++ b/docs/libcurl/curl_slist_append.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_slist_append +Section: 3 +Source: libcurl +See-also: + - curl_slist_free_all (3) +--- + +# NAME + +curl_slist_append - add a string to an slist + +# SYNOPSIS + +~~~c +#include + +struct curl_slist *curl_slist_append(struct curl_slist *list, + const char *string); +~~~ + +# DESCRIPTION + +curl_slist_append(3) appends a string to a linked list of strings. The +existing **list** should be passed as the first argument and the new list is +returned from this function. Pass in NULL in the **list** argument to create +a new list. The specified **string** has been appended when this function +returns. curl_slist_append(3) copies the string. + +The list should be freed again (after usage) with +curl_slist_free_all(3). + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *handle; + struct curl_slist *slist = NULL; + struct curl_slist *temp = NULL; + + slist = curl_slist_append(slist, "pragma:"); + + if(!slist) + return -1; + + temp = curl_slist_append(slist, "Accept:"); + + if(!temp) { + curl_slist_free_all(slist); + return -1; + } + + slist = temp; + + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, slist); + + curl_easy_perform(handle); + + curl_slist_free_all(slist); /* free the list again */ +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +A null pointer is returned if anything went wrong, otherwise the new list +pointer is returned. To avoid overwriting an existing non-empty list on +failure, the new list should be returned to a temporary variable which can +be tested for NULL before updating the original list pointer. diff --git a/docs/libcurl/curl_slist_free_all.md b/docs/libcurl/curl_slist_free_all.md new file mode 100644 index 0000000..928f306 --- /dev/null +++ b/docs/libcurl/curl_slist_free_all.md @@ -0,0 +1,58 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_slist_free_all +Section: 3 +Source: libcurl +See-also: + - curl_slist_append (3) +--- + +# NAME + +curl_slist_free_all - free an entire curl_slist list + +# SYNOPSIS + +~~~c +#include + +void curl_slist_free_all(struct curl_slist *list); +~~~ + +# DESCRIPTION + +curl_slist_free_all() removes all traces of a previously built curl_slist +linked list. + +Passing in a NULL pointer in *list* makes this function return immediately +with no action. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *handle; + struct curl_slist *slist = NULL; + + slist = curl_slist_append(slist, "X-libcurl: coolness"); + + if(!slist) + return -1; + + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, slist); + + curl_easy_perform(handle); + + curl_slist_free_all(slist); /* free the list again */ +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Nothing. diff --git a/docs/libcurl/curl_strequal.md b/docs/libcurl/curl_strequal.md new file mode 100644 index 0000000..518faee --- /dev/null +++ b/docs/libcurl/curl_strequal.md @@ -0,0 +1,57 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_strequal +Section: 3 +Source: libcurl +See-also: + - strcasecmp (3) + - strcmp (3) +--- + +# NAME + +curl_strequal, curl_strnequal - case insensitive string comparisons + +# SYNOPSIS + +~~~c +#include + +int curl_strequal(const char *str1, const char *str2); +int curl_strnequal(const char *str1, const char *str2, size_t length); +~~~ + +# DESCRIPTION + +The curl_strequal(3) function compares the two strings *str1* and +*str2*, ignoring the case of the characters. It returns a non-zero (TRUE) +integer if the strings are identical. + +The **curl_strnequal()** function is similar, except it only compares the +first *length* characters of *str1*. + +These functions are provided by libcurl to enable applications to compare +strings in a truly portable manner. There are no standard portable case +insensitive string comparison functions. These two work on all platforms. + +# EXAMPLE + +~~~c +int main(int argc, char **argv) +{ + const char *name = "compare"; + if(curl_strequal(name, argv[1])) + printf("Name and input matches\n"); + if(curl_strnequal(name, argv[1], 5)) + printf("Name and input matches in the 5 first bytes\n"); +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Non-zero if the strings are identical. Zero if they are not. diff --git a/docs/libcurl/curl_strnequal.md b/docs/libcurl/curl_strnequal.md new file mode 100644 index 0000000..518faee --- /dev/null +++ b/docs/libcurl/curl_strnequal.md @@ -0,0 +1,57 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_strequal +Section: 3 +Source: libcurl +See-also: + - strcasecmp (3) + - strcmp (3) +--- + +# NAME + +curl_strequal, curl_strnequal - case insensitive string comparisons + +# SYNOPSIS + +~~~c +#include + +int curl_strequal(const char *str1, const char *str2); +int curl_strnequal(const char *str1, const char *str2, size_t length); +~~~ + +# DESCRIPTION + +The curl_strequal(3) function compares the two strings *str1* and +*str2*, ignoring the case of the characters. It returns a non-zero (TRUE) +integer if the strings are identical. + +The **curl_strnequal()** function is similar, except it only compares the +first *length* characters of *str1*. + +These functions are provided by libcurl to enable applications to compare +strings in a truly portable manner. There are no standard portable case +insensitive string comparison functions. These two work on all platforms. + +# EXAMPLE + +~~~c +int main(int argc, char **argv) +{ + const char *name = "compare"; + if(curl_strequal(name, argv[1])) + printf("Name and input matches\n"); + if(curl_strnequal(name, argv[1], 5)) + printf("Name and input matches in the 5 first bytes\n"); +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Non-zero if the strings are identical. Zero if they are not. diff --git a/docs/libcurl/curl_unescape.md b/docs/libcurl/curl_unescape.md new file mode 100644 index 0000000..8ae9f50 --- /dev/null +++ b/docs/libcurl/curl_unescape.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_unescape +Section: 3 +Source: libcurl +See-also: + - RFC 2396 + - curl_easy_escape (3) + - curl_easy_unescape (3) + - curl_free (3) +--- + +# NAME + +curl_unescape - URL decodes the given string + +# SYNOPSIS + +~~~c +#include + +char *curl_unescape(const char *input, int length); +~~~ + +# DESCRIPTION + +Obsolete function. Use curl_easy_unescape(3) instead. + +This function converts the URL encoded string **input** to a "plain string" +and return that as a new allocated string. All input characters that are URL +encoded (%XX where XX is a two-digit hexadecimal number) are converted to +their plain text versions. + +If the **length** argument is set to 0, curl_unescape(3) calls +strlen() on **input** to find out the size. + +You must curl_free(3) the returned string when you are done with it. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + char *decoded = curl_unescape("%63%75%72%6c", 12); + if(decoded) { + /* do not assume printf() works on the decoded data */ + printf("Decoded: "); + /* ... */ + curl_free(decoded); + } + } +} +~~~ + +# AVAILABILITY + +Since 7.15.4, curl_easy_unescape(3) should be used. This function might +be removed in a future release. + +# RETURN VALUE + +A pointer to a null-terminated string or NULL if it failed. diff --git a/docs/libcurl/curl_url.md b/docs/libcurl/curl_url.md new file mode 100644 index 0000000..f71fb35 --- /dev/null +++ b/docs/libcurl/curl_url.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_url +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CURLU (3) + - curl_url_cleanup (3) + - curl_url_dup (3) + - curl_url_get (3) + - curl_url_set (3) + - curl_url_strerror (3) +--- + +# NAME + +curl_url - returns a new URL handle + +# SYNOPSIS + +~~~c +#include + +CURLU *curl_url(); +~~~ + +# DESCRIPTION + +This function allocates a URL object and returns a *CURLU* handle for it, +to be used as input to all other URL API functions. + +This is a handle to a URL object that holds or can hold URL components for a +single URL. When the object is first created, there is of course no components +stored. They are then set in the object with the curl_url_set(3) +function. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLUcode rc; + CURLU *url = curl_url(); + rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0); + if(!rc) { + char *scheme; + rc = curl_url_get(url, CURLUPART_SCHEME, &scheme, 0); + if(!rc) { + printf("the scheme is %s\n", scheme); + curl_free(scheme); + } + curl_url_cleanup(url); + } +} +~~~ + +# AVAILABILITY + +Added in 7.62.0 + +# RETURN VALUE + +Returns a **CURLU *** if successful, or NULL if out of memory. diff --git a/docs/libcurl/curl_url_cleanup.md b/docs/libcurl/curl_url_cleanup.md new file mode 100644 index 0000000..d0f85b6 --- /dev/null +++ b/docs/libcurl/curl_url_cleanup.md @@ -0,0 +1,51 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_url_cleanup +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CURLU (3) + - curl_url (3) + - curl_url_dup (3) + - curl_url_get (3) + - curl_url_set (3) +--- + +# NAME + +curl_url_cleanup - free the URL handle + +# SYNOPSIS + +~~~c +#include + +void curl_url_cleanup(CURLU *handle); +~~~ + +# DESCRIPTION + +Frees all the resources associated with the given *CURLU* handle! + +Passing in a NULL pointer in *handle* makes this function return +immediately with no action. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLU *url = curl_url(); + curl_url_set(url, CURLUPART_URL, "https://example.com", 0); + curl_url_cleanup(url); +} +~~~ + +# AVAILABILITY + +Added in 7.62.0 + +# RETURN VALUE + +none diff --git a/docs/libcurl/curl_url_dup.md b/docs/libcurl/curl_url_dup.md new file mode 100644 index 0000000..ea590ce --- /dev/null +++ b/docs/libcurl/curl_url_dup.md @@ -0,0 +1,56 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_url_dup +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CURLU (3) + - curl_url (3) + - curl_url_cleanup (3) + - curl_url_get (3) + - curl_url_set (3) +--- + +# NAME + +curl_url_dup - duplicate a URL handle + +# SYNOPSIS + +~~~c +#include + +CURLU *curl_url_dup(const CURLU *inhandle); +~~~ + +# DESCRIPTION + +Duplicates the URL object the input *CURLU* *inhandle* identifies and +returns a pointer to the copy as a new *CURLU* handle. The new handle also +needs to be freed with curl_url_cleanup(3). + +# EXAMPLE + +~~~c +int main(void) +{ + CURLUcode rc; + CURLU *url = curl_url(); + CURLU *url2; + rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0); + if(!rc) { + url2 = curl_url_dup(url); /* clone it! */ + curl_url_cleanup(url2); + } + curl_url_cleanup(url); +} +~~~ + +# AVAILABILITY + +Added in 7.62.0 + +# RETURN VALUE + +Returns a new handle or NULL if out of memory. diff --git a/docs/libcurl/curl_url_get.md b/docs/libcurl/curl_url_get.md new file mode 100644 index 0000000..2ea4218 --- /dev/null +++ b/docs/libcurl/curl_url_get.md @@ -0,0 +1,210 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_url_get +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CURLU (3) + - curl_url (3) + - curl_url_cleanup (3) + - curl_url_dup (3) + - curl_url_set (3) + - curl_url_strerror (3) +--- + +# NAME + +curl_url_get - extract a part from a URL + +# SYNOPSIS + +~~~c +#include + +CURLUcode curl_url_get(const CURLU *url, + CURLUPart part, + char **content, + unsigned int flags); +~~~ + +# DESCRIPTION + +Given a *url* handle of a URL object, this function extracts an individual +piece or the full URL from it. + +The *part* argument specifies which part to extract (see list below) and +*content* points to a 'char *' to get updated to point to a newly +allocated string with the contents. + +The *flags* argument is a bitmask with individual features. + +The returned content pointer must be freed with curl_free(3) after use. + +# FLAGS + +The flags argument is zero, one or more bits set in a bitmask. + +## CURLU_DEFAULT_PORT + +If the handle has no port stored, this option makes curl_url_get(3) +return the default port for the used scheme. + +## CURLU_DEFAULT_SCHEME + +If the handle has no scheme stored, this option makes curl_url_get(3) +return the default scheme instead of error. + +## CURLU_NO_DEFAULT_PORT + +Instructs curl_url_get(3) to not return a port number if it matches the +default port for the scheme. + +## CURLU_URLDECODE + +Asks curl_url_get(3) to URL decode the contents before returning it. It +does not decode the scheme, the port number or the full URL. + +The query component also gets plus-to-space conversion as a bonus when this +bit is set. + +Note that this URL decoding is charset unaware and you get a zero terminated +string back with data that could be intended for a particular encoding. + +If there are byte values lower than 32 in the decoded string, the get +operation returns an error instead. + +## CURLU_URLENCODE + +If set, curl_url_get(3) URL encodes the hostname part when a full URL +is retrieved. If not set (default), libcurl returns the URL with the host name +"raw" to support IDN names to appear as-is. IDN host names are typically using +non-ASCII bytes that otherwise gets percent-encoded. + +Note that even when not asking for URL encoding, the '%' (byte 37) is URL +encoded to make sure the hostname remains valid. + +## CURLU_PUNYCODE + +If set and *CURLU_URLENCODE* is not set, and asked to retrieve the +**CURLUPART_HOST** or **CURLUPART_URL** parts, libcurl returns the host +name in its punycode version if it contains any non-ASCII octets (and is an +IDN name). + +If libcurl is built without IDN capabilities, using this bit makes +curl_url_get(3) return *CURLUE_LACKS_IDN* if the hostname contains +anything outside the ASCII range. + +(Added in curl 7.88.0) + +## CURLU_PUNY2IDN + +If set and asked to retrieve the **CURLUPART_HOST** or **CURLUPART_URL** +parts, libcurl returns the hostname in its IDN (International Domain Name) +UTF-8 version if it otherwise is a punycode version. If the punycode name +cannot be converted to IDN correctly, libcurl returns +*CURLUE_BAD_HOSTNAME*. + +If libcurl is built without IDN capabilities, using this bit makes +curl_url_get(3) return *CURLUE_LACKS_IDN* if the hostname is using +punycode. + +(Added in curl 8.3.0) + +# PARTS + +## CURLUPART_URL + +When asked to return the full URL, curl_url_get(3) returns a normalized +and possibly cleaned up version using all available URL parts. + +We advise using the *CURLU_PUNYCODE* option to get the URL as "normalized" +as possible since IDN allows host names to be written in many different ways +that still end up the same punycode version. + +## CURLUPART_SCHEME + +Scheme cannot be URL decoded on get. + +## CURLUPART_USER + +## CURLUPART_PASSWORD + +## CURLUPART_OPTIONS + +The options field is an optional field that might follow the password in the +userinfo part. It is only recognized/used when parsing URLs for the following +schemes: pop3, smtp and imap. The URL API still allows users to set and get +this field independently of scheme when not parsing full URLs. + +## CURLUPART_HOST + +The hostname. If it is an IPv6 numeric address, the zone id is not part of it +but is provided separately in *CURLUPART_ZONEID*. IPv6 numerical addresses +are returned within brackets ([]). + +IPv6 names are normalized when set, which should make them as short as +possible while maintaining correct syntax. + +## CURLUPART_ZONEID + +If the hostname is a numeric IPv6 address, this field might also be set. + +## CURLUPART_PORT + +A port cannot be URL decoded on get. This number is returned in a string just +like all other parts. That string is guaranteed to hold a valid port number in +ASCII using base 10. + +## CURLUPART_PATH + +The *part* is always at least a slash ('/') even if no path was supplied +in the URL. A URL path always starts with a slash. + +## CURLUPART_QUERY + +The initial question mark that denotes the beginning of the query part is a +delimiter only. It is not part of the query contents. + +A not-present query returns *part* set to NULL. +A zero-length query returns *part* as a zero-length string. + +The query part gets pluses converted to space when asked to URL decode on get +with the CURLU_URLDECODE bit. + +## CURLUPART_FRAGMENT + +The initial hash sign that denotes the beginning of the fragment is a +delimiter only. It is not part of the fragment contents. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLUcode rc; + CURLU *url = curl_url(); + rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0); + if(!rc) { + char *scheme; + rc = curl_url_get(url, CURLUPART_SCHEME, &scheme, 0); + if(!rc) { + printf("the scheme is %s\n", scheme); + curl_free(scheme); + } + curl_url_cleanup(url); + } +} +~~~ + +# AVAILABILITY + +Added in 7.62.0. CURLUPART_ZONEID was added in 7.65.0. + +# RETURN VALUE + +Returns a CURLUcode error value, which is CURLUE_OK (0) if everything went +fine. See the libcurl-errors(3) man page for the full list with +descriptions. + +If this function returns an error, no URL part is returned. diff --git a/docs/libcurl/curl_url_set.md b/docs/libcurl/curl_url_set.md new file mode 100644 index 0000000..fe2f7ff --- /dev/null +++ b/docs/libcurl/curl_url_set.md @@ -0,0 +1,247 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_url_set +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CURLU (3) + - curl_url (3) + - curl_url_cleanup (3) + - curl_url_dup (3) + - curl_url_get (3) + - curl_url_strerror (3) +--- + +# NAME + +curl_url_set - set a URL part + +# SYNOPSIS + +~~~c +#include + +CURLUcode curl_url_set(CURLU *url, + CURLUPart part, + const char *content, + unsigned int flags); +~~~ + +# DESCRIPTION + +The *url* handle to work on, passed in as the first argument, must be a +handle previously created by curl_url(3) or curl_url_dup(3). + +This function sets or updates individual URL components, or parts, held by the +URL object the handle identifies. + +The *part* argument should identify the particular URL part (see list +below) to set or change, with *content* pointing to a null-terminated +string with the new contents for that URL part. The contents should be in the +form and encoding they would use in a URL: URL encoded. + +When setting part in the URL object that was previously already set, it +replaces the data that was previously stored for that part with the new +*content*. + +The caller does not have to keep *content* around after a successful call +as this function copies the content. + +Setting a part to a NULL pointer removes that part's contents from the +*CURLU* handle. + +By default, this API only accepts URLs using schemes for protocols that are +supported built-in. To make libcurl parse URLs generically even for schemes it +does not know about, the **CURLU_NON_SUPPORT_SCHEME** flags bit must be +set. Otherwise, this function returns *CURLUE_UNSUPPORTED_SCHEME* for URL +schemes it does not recognize. + +This function has an 8 MB maximum length limit for all provided input strings. +In the real world, excessively long fields in URLs cause problems even if this +API accepts them. + +When setting or updating contents of individual URL parts, this API might +accept data that would not be otherwise possible to set in the string when it +gets populated as a result of a full URL parse. Beware. If done so, extracting +a full URL later on from such components might render an invalid URL. + +The *flags* argument is a bitmask with independent features. + +# PARTS + +## CURLUPART_URL + +Allows the full URL of the handle to be replaced. If the handle already is +populated with a URL, the new URL can be relative to the previous. + +When successfully setting a new URL, relative or absolute, the handle contents +is replaced with the components of the newly set URL. + +Pass a pointer to a null-terminated string to the *url* parameter. The +string must point to a correctly formatted "RFC 3986+" URL or be a NULL +pointer. + +Unless *CURLU_NO_AUTHORITY* is set, a blank hostname is not allowed in +the URL. + +## CURLUPART_SCHEME + +Scheme cannot be URL decoded on set. libcurl only accepts setting schemes up +to 40 bytes long. + +## CURLUPART_USER + +## CURLUPART_PASSWORD + +## CURLUPART_OPTIONS + +The options field is an optional field that might follow the password in the +userinfo part. It is only recognized/used when parsing URLs for the following +schemes: pop3, smtp and imap. This function however allows users to +independently set this field. + +## CURLUPART_HOST + +The hostname. If it is International Domain Name (IDN) the string must then be +encoded as your locale says or UTF-8 (when WinIDN is used). If it is a +bracketed IPv6 numeric address it may contain a zone id (or you can use +*CURLUPART_ZONEID*). + +Unless *CURLU_NO_AUTHORITY* is set, a blank hostname is not allowed to set. + +## CURLUPART_ZONEID + +If the hostname is a numeric IPv6 address, this field can also be set. + +## CURLUPART_PORT + +The port number cannot be URL encoded on set. The given port number is +provided as a string and the decimal number in it must be between 0 and +65535. Anything else returns an error. + +## CURLUPART_PATH + +If a path is set in the URL without a leading slash, a slash is prepended +automatically. + +## CURLUPART_QUERY + +The query part gets spaces converted to pluses when asked to URL encode on set +with the *CURLU_URLENCODE* bit. + +If used together with the *CURLU_APPENDQUERY* bit, the provided part is +appended on the end of the existing query. + +The question mark in the URL is not part of the actual query contents. + +## CURLUPART_FRAGMENT + +The hash sign in the URL is not part of the actual fragment contents. + +# FLAGS + +The flags argument is zero, one or more bits set in a bitmask. + +## CURLU_APPENDQUERY + +Can be used when setting the *CURLUPART_QUERY* component. The provided new +part is then appended at the end of the existing query - and if the previous +part did not end with an ampersand (&), an ampersand gets inserted before the +new appended part. + +When *CURLU_APPENDQUERY* is used together with *CURLU_URLENCODE*, the +first '=' symbol is not URL encoded. + +## CURLU_NON_SUPPORT_SCHEME + +If set, allows curl_url_set(3) to set a non-supported scheme. + +## CURLU_URLENCODE + +When set, curl_url_set(3) URL encodes the part on entry, except for +scheme, port and URL. + +When setting the path component with URL encoding enabled, the slash character +is be skipped. + +The query part gets space-to-plus conversion before the URL conversion. + +This URL encoding is charset unaware and converts the input in a byte-by-byte +manner. + +## CURLU_DEFAULT_SCHEME + +If set, allows the URL to be set without a scheme and then sets that to the +default scheme: HTTPS. Overrides the *CURLU_GUESS_SCHEME* option if both +are set. + +## CURLU_GUESS_SCHEME + +If set, allows the URL to be set without a scheme and it instead "guesses" +which scheme that was intended based on the hostname. If the outermost +subdomain name matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that scheme is +used, otherwise it picks HTTP. Conflicts with the *CURLU_DEFAULT_SCHEME* +option which takes precedence if both are set. + +## CURLU_NO_AUTHORITY + +If set, skips authority checks. The RFC allows individual schemes to omit the +host part (normally the only mandatory part of the authority), but libcurl +cannot know whether this is permitted for custom schemes. Specifying the flag +permits empty authority sections, similar to how file scheme is handled. + +## CURLU_PATH_AS_IS + +When set for **CURLUPART_URL**, this skips the normalization of the +path. That is the procedure where libcurl otherwise removes sequences of +dot-slash and dot-dot etc. The same option used for transfers is called +CURLOPT_PATH_AS_IS(3). + +## CURLU_ALLOW_SPACE + +If set, the URL parser allows space (ASCII 32) where possible. The URL syntax +does normally not allow spaces anywhere, but they should be encoded as %20 +or '+'. When spaces are allowed, they are still not allowed in the scheme. +When space is used and allowed in a URL, it is stored as-is unless +*CURLU_URLENCODE* is also set, which then makes libcurl URL encode the +space before stored. This affects how the URL is constructed when +curl_url_get(3) is subsequently used to extract the full URL or +individual parts. (Added in 7.78.0) + +## CURLU_DISALLOW_USER + +If set, the URL parser does not accept embedded credentials for the +**CURLUPART_URL**, and instead returns **CURLUE_USER_NOT_ALLOWED** for +such URLs. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLUcode rc; + CURLU *url = curl_url(); + rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0); + if(!rc) { + /* change it to an FTP URL */ + rc = curl_url_set(url, CURLUPART_SCHEME, "ftp", 0); + } + curl_url_cleanup(url); +} +~~~ + +# AVAILABILITY + +Added in 7.62.0. CURLUPART_ZONEID was added in 7.65.0. + +# RETURN VALUE + +Returns a *CURLUcode* error value, which is CURLUE_OK (0) if everything +went fine. See the libcurl-errors(3) man page for the full list with +descriptions. + +The input string passed to curl_url_set(3) must be shorter than eight +million bytes. Otherwise this function returns **CURLUE_MALFORMED_INPUT**. + +If this function returns an error, no URL part is set. diff --git a/docs/libcurl/curl_url_strerror.md b/docs/libcurl/curl_url_strerror.md new file mode 100644 index 0000000..26562aa --- /dev/null +++ b/docs/libcurl/curl_url_strerror.md @@ -0,0 +1,53 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_url_strerror +Section: 3 +Source: libcurl +See-also: + - curl_easy_strerror (3) + - curl_multi_strerror (3) + - curl_share_strerror (3) + - curl_url_get (3) + - curl_url_set (3) + - libcurl-errors (3) +--- + +# NAME + +curl_url_strerror - return string describing error code + +# SYNOPSIS + +~~~c +#include + +const char *curl_url_strerror(CURLUcode errornum); +~~~ + +# DESCRIPTION + +This function returns a string describing the CURLUcode error code passed in +the argument *errornum*. + +# EXAMPLE + +~~~c +int main(void) +{ + CURLUcode rc; + CURLU *url = curl_url(); + rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0); + if(rc) + printf("URL error: %s\n", curl_url_strerror(rc)); + curl_url_cleanup(url); +} +~~~ + +# AVAILABILITY + +Added in 7.80.0 + +# RETURN VALUE + +A pointer to a null-terminated string. diff --git a/docs/libcurl/curl_version.md b/docs/libcurl/curl_version.md new file mode 100644 index 0000000..3a3cb35 --- /dev/null +++ b/docs/libcurl/curl_version.md @@ -0,0 +1,46 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_version +Section: 3 +Source: libcurl +See-also: + - curl_version_info (3) +--- + +# NAME + +curl_version - returns the libcurl version string + +# SYNOPSIS + +~~~c +#include + +char *curl_version(); +~~~ + +# DESCRIPTION + +Returns a human readable string with the version number of libcurl and some of +its important components (like OpenSSL version). + +We recommend using curl_version_info(3) instead! + +# EXAMPLE + +~~~c +int main(void) +{ + printf("libcurl version %s\n", curl_version()); +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +A pointer to a null-terminated string. The string resides in a statically +allocated buffer and must not be freed by the caller. diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md new file mode 100644 index 0000000..9fc764e --- /dev/null +++ b/docs/libcurl/curl_version_info.md @@ -0,0 +1,381 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_version_info +Section: 3 +Source: libcurl +See-also: + - curl_version (3) +--- + +# NAME + +curl_version_info - returns runtime libcurl version info + +# SYNOPSIS + +~~~c +#include + +curl_version_info_data *curl_version_info(CURLversion age); +~~~ + +# DESCRIPTION + +Returns a pointer to a filled in static struct with information about various +features in the running version of libcurl. *age* should be set to the +version of this functionality by the time you write your program. This way, +libcurl always returns a proper struct that your program understands, while +programs in the future might get a different struct. **CURLVERSION_NOW** is +the most recent one for the library you have installed: +~~~c + data = curl_version_info(CURLVERSION_NOW); +~~~ +Applications should use this information to judge if things are possible to do +or not, instead of using compile-time checks, as dynamic/DLL libraries can be +changed independent of applications. + +This function can alter the returned static data as long as +curl_global_init(3) has not been called. It is therefore not thread-safe +before libcurl initialization occurs. + +The curl_version_info_data struct looks like this + +~~~c +typedef struct { + CURLversion age; /* see description below */ + + const char *version; /* human readable string */ + unsigned int version_num; /* numeric representation */ + const char *host; /* human readable string */ + int features; /* bitmask, see below */ + char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used, always zero */ + const char *libz_version; /* human readable string */ + const char *const *protocols; /* protocols */ + + /* when 'age' is CURLVERSION_SECOND or higher, the members below exist */ + const char *ares; /* human readable string */ + int ares_num; /* number */ + + /* when 'age' is CURLVERSION_THIRD or higher, the members below exist */ + const char *libidn; /* human readable string */ + + /* when 'age' is CURLVERSION_FOURTH or higher (>= 7.16.1), the members + below exist */ + int iconv_ver_num; /* '_libiconv_version' if iconv support enabled */ + + const char *libssh_version; /* human readable string */ + + /* when 'age' is CURLVERSION_FIFTH or higher (>= 7.57.0), the members + below exist */ + unsigned int brotli_ver_num; /* Numeric Brotli version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *brotli_version; /* human readable string. */ + + /* when 'age' is CURLVERSION_SIXTH or higher (>= 7.66.0), the members + below exist */ + unsigned int nghttp2_ver_num; /* Numeric nghttp2 version + (MAJOR << 16) | (MINOR << 8) | PATCH */ + const char *nghttp2_version; /* human readable string. */ + + const char *quic_version; /* human readable quic (+ HTTP/3) library + + version or NULL */ + + /* when 'age' is CURLVERSION_SEVENTH or higher (>= 7.70.0), the members + below exist */ + const char *cainfo; /* the built-in default CURLOPT_CAINFO, might + be NULL */ + const char *capath; /* the built-in default CURLOPT_CAPATH, might + be NULL */ + /* when 'age' is CURLVERSION_EIGHTH or higher (>= 7.71.0), the members + below exist */ + unsigned int zstd_ver_num; /* Numeric Zstd version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *zstd_version; /* human readable string. */ + /* when 'age' is CURLVERSION_NINTH or higher (>= 7.75.0), the members + below exist */ + const char *hyper_version; /* human readable string. */ + /* when 'age' is CURLVERSION_TENTH or higher (>= 7.77.0), the members + below exist */ + const char *gsasl_version; /* human readable string. */ + /* when 'age' is CURLVERSION_ELEVENTH or higher (>= 7.87.0), the members + below exist */ + const char *const *feature_names; /* Feature names. */ +} curl_version_info_data; +~~~ + +*age* describes what the age of this struct is. The number depends on how +new the libcurl you are using is. You are however guaranteed to get a struct +that you have a matching struct for in the header, as you tell libcurl your +"age" with the input argument. + +*version* is just an ascii string for the libcurl version. + +*version_num* is a 24 bit number created like this: <8 bits major number> +| <8 bits minor number> | <8 bits patch number>. Version 7.9.8 is therefore +returned as 0x070908. + +*host* is an ascii string showing what host information that this libcurl +was built for. As discovered by a configure script or set by the build +environment. + +*features* is a bit mask representing available features. It can have none, +one or more bits set. The use of this field is deprecated: use +*feature_names* instead. The feature names description below lists the +associated bits. + +*feature_names* is a pointer to an array of string pointers, containing the +names of the features that libcurl supports. The array is terminated by a NULL +entry. See the list of features names below. + +*ssl_version* is an ASCII string for the TLS library name + version used. If +libcurl has no SSL support, this is NULL. For example "Schannel", "Secure +Transport" or "OpenSSL/1.1.0g". + +*ssl_version_num* is always 0. + +*libz_version* is an ASCII string (there is no numerical version). If +libcurl has no libz support, this is NULL. + +*protocols* is a pointer to an array of char * pointers, containing the +names protocols that libcurl supports (using lowercase letters). The protocol +names are the same as would be used in URLs. The array is terminated by a NULL +entry. + +# FEATURES + +## alt-svc + +*features* mask bit: CURL_VERSION_ALTSVC + +HTTP Alt-Svc parsing and the associated options (Added in 7.64.1) + +## AsynchDNS + +*features* mask bit: CURL_VERSION_ASYNCHDNS + +libcurl was built with support for asynchronous name lookups, which allows +more exact timeouts (even on Windows) and less blocking when using the multi +interface. (added in 7.10.7) + +## brotli + +*features* mask bit: CURL_VERSION_BROTLI + +supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0) + +## Debug + +*features* mask bit: CURL_VERSION_DEBUG + +libcurl was built with debug capabilities (added in 7.10.6) + +## gsasl + +*features* mask bit: CURL_VERSION_GSASL + +libcurl was built with libgsasl and thus with some extra SCRAM-SHA +authentication methods. (added in 7.76.0) + +## GSS-API + +*features* mask bit: CURL_VERSION_GSSAPI + +libcurl was built with support for GSS-API. This makes libcurl use provided +functions for Kerberos and SPNEGO authentication. It also allows libcurl +to use the current user credentials without the app having to pass them on. +(Added in 7.38.0) + +## HSTS + +*features* mask bit: CURL_VERSION_HSTS + +libcurl was built with support for HSTS (HTTP Strict Transport Security) +(Added in 7.74.0) + +## HTTP2 + +*features* mask bit: CURL_VERSION_HTTP2 + +libcurl was built with support for HTTP2. +(Added in 7.33.0) + +## HTTP3 + +*features* mask bit: CURL_VERSION_HTTP3 + +HTTP/3 and QUIC support are built-in (Added in 7.66.0) + +## HTTPS-proxy + +*features* mask bit: CURL_VERSION_HTTPS_PROXY + +libcurl was built with support for HTTPS-proxy. +(Added in 7.52.0) + +## IDN + +*features* mask bit: CURL_VERSION_IDN + +libcurl was built with support for IDNA, domain names with international +letters. (Added in 7.12.0) + +## IPv6 + +*features* mask bit: CURL_VERSION_IPV6 + +supports IPv6 + +## Kerberos + +*features* mask bit: CURL_VERSION_KERBEROS5 + +supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and +SOCKSv5 proxy. (Added in 7.40.0) + +## Largefile + +*features* mask bit: CURL_VERSION_LARGEFILE + +libcurl was built with support for large files. (Added in 7.11.1) + +## libz + +*features* mask bit: CURL_VERSION_LIBZ + +supports HTTP deflate using libz (Added in 7.10) + +## MultiSSL + +*features* mask bit: CURL_VERSION_MULTI_SSL + +libcurl was built with multiple SSL backends. For details, see +curl_global_sslset(3). +(Added in 7.56.0) + +## NTLM + +*features* mask bit: CURL_VERSION_NTLM + +supports HTTP NTLM (added in 7.10.6) + +## NTLM_WB + +*features* mask bit: CURL_VERSION_NTLM_WB + +libcurl was built with support for NTLM delegation to a winbind helper. +(Added in 7.22.0) + +## PSL + +*features* mask bit: CURL_VERSION_PSL + +libcurl was built with support for Mozilla's Public Suffix List. This makes +libcurl ignore cookies with a domain that is on the list. +(Added in 7.47.0) + +## SPNEGO + +*features* mask bit: CURL_VERSION_SPNEGO + +libcurl was built with support for SPNEGO authentication (Simple and Protected +GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8) + +## SSL + +*features* mask bit: CURL_VERSION_SSL + +supports SSL (HTTPS/FTPS) (Added in 7.10) + +## SSPI + +*features* mask bit: CURL_VERSION_SSPI + +libcurl was built with support for SSPI. This is only available on Windows and +makes libcurl use Windows-provided functions for Kerberos, NTLM, SPNEGO and +Digest authentication. It also allows libcurl to use the current user +credentials without the app having to pass them on. (Added in 7.13.2) + +## threadsafe + +*features* mask bit: CURL_VERSION_THREADSAFE + +libcurl was built with thread-safety support (Atomic or SRWLOCK) to protect +curl initialization. (Added in 7.84.0) See libcurl-thread(3) + +## TLS-SRP + +*features* mask bit: CURL_VERSION_TLSAUTH_SRP + +libcurl was built with support for TLS-SRP (in one or more of the built-in TLS +backends). (Added in 7.21.4) + +## TrackMemory + +*features* mask bit: CURL_VERSION_CURLDEBUG + +libcurl was built with memory tracking debug capabilities. This is mainly of +interest for libcurl hackers. (added in 7.19.6) + +## Unicode + +*features* mask bit: CURL_VERSION_UNICODE + +libcurl was built with Unicode support on Windows. This makes non-ASCII +characters work in filenames and options passed to libcurl. (Added in 7.72.0) + +## UnixSockets + +*features* mask bit: CURL_VERSION_UNIX_SOCKETS + +libcurl was built with support for Unix domain sockets. +(Added in 7.40.0) + +## zstd + +*features* mask bit: CURL_VERSION_ZSTD + +supports HTTP zstd content encoding using zstd library (Added in 7.72.0) + +## no name + +*features* mask bit: CURL_VERSION_CONV + +libcurl was built with support for character conversions, as provided by the +CURLOPT_CONV_* callbacks. Always 0 since 7.82.0. (Added in 7.15.4, +deprecated.) + +## no name + +*features* mask bit: CURL_VERSION_GSSNEGOTIATE + +supports HTTP GSS-Negotiate (added in 7.10.6, deprecated in 7.38.0) + +## no name + +*features* mask bit: CURL_VERSION_KERBEROS4 + +supports Kerberos V4 (when using FTP). Legacy bit. Deprecated since 7.33.0. + +# EXAMPLE + +~~~c +int main(void) +{ + curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW); + printf("libcurl version %u.%u.%u\n", + (ver->version_num >> 16) & 0xff, + (ver->version_num >> 8) & 0xff, + ver->version_num & 0xff); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +A pointer to a curl_version_info_data struct. +curl_version(3) diff --git a/docs/libcurl/curl_ws_meta.md b/docs/libcurl/curl_ws_meta.md new file mode 100644 index 0000000..531791a --- /dev/null +++ b/docs/libcurl/curl_ws_meta.md @@ -0,0 +1,143 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_ws_meta +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_setopt (3) + - curl_ws_recv (3) + - curl_ws_send (3) + - libcurl-ws (3) +--- + +# NAME + +curl_ws_meta - meta data WebSocket information + +# SYNOPSIS + +~~~c +#include + +const struct curl_ws_frame *curl_ws_meta(CURL *curl); +~~~ + +# DESCRIPTION + +This function call is EXPERIMENTAL. + +When the write callback (CURLOPT_WRITEFUNCTION(3)) is invoked on +received WebSocket traffic, curl_ws_meta(3) can be called from within +the callback to provide additional information about the current frame. + +This function only works from within the callback, and only when receiving +WebSocket data. + +This function requires an easy handle as input argument for libcurl to know +what transfer the question is about, but as there is no such pointer provided +to the callback by libcurl itself, applications that want to use +curl_ws_meta(3) need to pass it on to the callback on its own. + +# struct curl_ws_frame + +~~~c +struct curl_ws_frame { + int age; + int flags; + curl_off_t offset; + curl_off_t bytesleft; +}; +~~~ + +## age + +This field specify the age of this struct. It is always zero for now. + +## flags + +This is a bitmask with individual bits set that describes the WebSocket +data. See the list below. + +## offset + +When this frame is a continuation of fragment data already delivered, this is +the offset into the final fragment where this piece belongs. + +## bytesleft + +If this is not a complete fragment, the *bytesleft* field informs about +how many additional bytes are expected to arrive before this fragment is +complete. + +# FLAGS + +## CURLWS_TEXT + +The buffer contains text data. Note that this makes a difference to WebSocket +but libcurl itself does not make any verification of the content or +precautions that you actually receive valid UTF-8 content. + +## CURLWS_BINARY + +This is binary data. + +## CURLWS_CONT + +This is not the final fragment of the message, it implies that there is +another fragment coming as part of the same message. + +## CURLWS_CLOSE + +This transfer is now closed. + +## CURLWS_PING + +This as an incoming ping message, that expects a pong response. + +# EXAMPLE + +~~~c + +/* we pass a pointer to this struct to the callback */ +struct customdata { + CURL *easy; + void *ptr; +}; + +static size_t writecb(unsigned char *buffer, + size_t size, size_t nitems, void *p) +{ + struct customdata *c = (struct customdata *)p; + const struct curl_ws_frame *m = curl_ws_meta(c->easy); + + printf("flags: %x\n", m->flags); +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct customdata custom; + custom.easy = curl; + custom.ptr = NULL; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &custom); + + curl_easy_perform(curl); + + } +} +~~~ + +# AVAILABILITY + +Added in 7.86.0. + +# RETURN VALUE + +This function returns a pointer to a *curl_ws_frame* struct with read-only +information that is valid for this specific callback invocation. If it cannot +return this information, or if the function is called in the wrong context, it +returns NULL. diff --git a/docs/libcurl/curl_ws_recv.md b/docs/libcurl/curl_ws_recv.md new file mode 100644 index 0000000..d801edd --- /dev/null +++ b/docs/libcurl/curl_ws_recv.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_ws_recv +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_perform (3) + - curl_easy_setopt (3) + - curl_ws_send (3) + - libcurl-ws (3) +--- + +# NAME + +curl_ws_recv - receive WebSocket data + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, + size_t *recv, const struct curl_ws_frame **meta); +~~~ + +# DESCRIPTION + +This function call is EXPERIMENTAL. + +Retrieves as much as possible of a received WebSocket data fragment into the +**buffer**, but not more than **buflen** bytes. *recv* is set to the +number of bytes actually stored. + +If there is more fragment data to deliver than what fits in the provided +*buffer*, libcurl returns a full buffer and the application needs to call +this function again to continue draining the buffer. + +The *meta* pointer gets set to point to a *const struct curl_ws_frame* +that contains information about the received data. See the +curl_ws_meta(3) for details on that struct. + +# EXAMPLE + +~~~c +int main(void) +{ + size_t rlen; + const struct curl_ws_frame *meta; + char buffer[256]; + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta); + if(res) + printf("error: %s\n", curl_easy_strerror(res)); + } +} +~~~ + +# AVAILABILITY + +Added in 7.86.0. + +# RETURN VALUE + +Returns **CURLE_OK** if everything is okay, and a non-zero number for +errors. Returns **CURLE_GOT_NOTHING** if the associated connection is +closed. + +Instead of blocking, the function returns **CURLE_AGAIN**. The correct +behavior is then to wait for the socket to signal readability before calling +this function again. diff --git a/docs/libcurl/curl_ws_send.md b/docs/libcurl/curl_ws_send.md new file mode 100644 index 0000000..a5a056c --- /dev/null +++ b/docs/libcurl/curl_ws_send.md @@ -0,0 +1,120 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_ws_send +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_perform (3) + - curl_easy_setopt (3) + - curl_ws_recv (3) + - libcurl-ws (3) +--- + +# NAME + +curl_ws_send - send WebSocket data + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_ws_send(CURL *curl, const void *buffer, size_t buflen, + size_t *sent, curl_off_t fragsize, + unsigned int flags); +~~~ + +# DESCRIPTION + +This function call is EXPERIMENTAL. + +Send the specific message fragment over an established WebSocket +connection. The *buffer* holds the data to send and it is *buflen* +number of payload bytes in that memory area. + +*sent* is returned as the number of payload bytes actually sent. + +To send a (huge) fragment using multiple calls with partial content per +invoke, set the *CURLWS_OFFSET* bit and the *fragsize* argument as the +total expected size for the first part, then set the *CURLWS_OFFSET* with +a zero *fragsize* for the following parts. + +If not sending a partial fragment or if this is raw mode, *fragsize* +should be set to zero. + +If **CURLWS_RAW_MODE** is enabled in CURLOPT_WS_OPTIONS(3), the +**flags** argument should be set to 0. + +To send a message consisting of multiple frames, set the *CURLWS_CONT* bit +in all frames except the final one. + +# FLAGS + +## CURLWS_TEXT + +The buffer contains text data. Note that this makes a difference to WebSocket +but libcurl itself does not make any verification of the content or +precautions that you actually send valid UTF-8 content. + +## CURLWS_BINARY + +This is binary data. + +## CURLWS_CONT + +This is not the final fragment of the message, which implies that there is +another fragment coming as part of the same message where this bit is not set. + +## CURLWS_CLOSE + +Close this transfer. + +## CURLWS_PING + +This is a ping. + +## CURLWS_PONG + +This is a pong. + +## CURLWS_OFFSET + +The provided data is only a partial fragment and there is more coming in a +following call to *curl_ws_send()*. When sending only a piece of the +fragment like this, the *fragsize* must be provided with the total +expected fragment size in the first call and it needs to be zero in subsequent +calls. + +# EXAMPLE + +~~~c +#include /* for strlen */ + +const char *send_payload = "magic"; + +int main(void) +{ + size_t sent; + CURLcode res; + CURL *curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, "wss://example.com/"); + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); + curl_easy_perform(curl); + res = curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0, + CURLWS_PING); + curl_easy_cleanup(curl); + return (int)res; +} +~~~ + +# AVAILABILITY + +Added in 7.86.0. + +# RETURN VALUE + +*CURLE_OK* (zero) means that the data was sent properly, non-zero means an +error occurred as ** defines. See the libcurl-errors(3) +man page for the full list with descriptions. diff --git a/docs/libcurl/libcurl-easy.md b/docs/libcurl/libcurl-easy.md new file mode 100644 index 0000000..f456c97 --- /dev/null +++ b/docs/libcurl/libcurl-easy.md @@ -0,0 +1,52 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl +Section: 3 +Source: libcurl +See-also: + - curl_easy_cleanup (3) + - curl_easy_init (3) + - curl_easy_setopt (3) + - libcurl (3) + - libcurl-errors (3) + - libcurl-multi (3) +--- + +# NAME + +libcurl-easy - easy interface overview + +# DESCRIPTION + +When using libcurl's "easy" interface you init your session and get a handle +(often referred to as an "easy handle"), which you use as input to the easy +interface functions you use. Use curl_easy_init(3) to get the handle. + +You continue by setting all the options you want in the upcoming transfer, the +most important among them is the URL itself (you cannot transfer anything +without a specified URL as you may have figured out yourself). You might want +to set some callbacks as well that are called from the library when data is +available etc. curl_easy_setopt(3) is used for all this. + +CURLOPT_URL(3) is the only option you really must set, as otherwise +there can be no transfer. Another commonly used option is +CURLOPT_VERBOSE(3) that helps you see what libcurl is doing under the +hood, which is useful when debugging for example. The +curl_easy_setopt(3) man page has a full index of the almost 300 +available options. + +If you at any point would like to blank all previously set options for a +single easy handle, you can call curl_easy_reset(3) and you can also +make a clone of an easy handle (with all its set options) using +curl_easy_duphandle(3). + +When all is setup, you tell libcurl to perform the transfer using +curl_easy_perform(3). It performs the entire transfer operation and does +not return until it is done (successfully or not). + +After the transfer has been made, you can set new options and make another +transfer, or if you are done, cleanup the session by calling +curl_easy_cleanup(3). If you want persistent connections, you do not +cleanup immediately, but instead run ahead and perform other transfers using +the same easy handle. diff --git a/docs/libcurl/libcurl-env-dbg.md b/docs/libcurl/libcurl-env-dbg.md new file mode 100644 index 0000000..21b763b --- /dev/null +++ b/docs/libcurl/libcurl-env-dbg.md @@ -0,0 +1,118 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-env-dbg +Section: 3 +Source: libcurl +See-also: + - libcurl-env (3) +--- + +# NAME + +libcurl-env-dbg - environment variables libcurl DEBUGBUILD understands + +# DESCRIPTION + +This is a set of variables only recognized and used if libcurl was built +"debug enabled", which should never be true for a library used in production. +These variables are intended for internal use only, subject to change and have +many effects on the behavior of libcurl. Refer to the source code to determine +how exactly they are being used. + +## CURL_ALTSVC_HTTP + +Bypass the AltSvc HTTPS protocol restriction if this variable exists. + +## CURL_DBG_SOCK_RBLOCK + +The percentage of recv() calls that should be answered with a EAGAIN at random. +For TCP/UNIX sockets. + +## CURL_DBG_SOCK_RMAX + +The maximum data that shall be received from the network in one recv() call. +For TCP/UNIX sockets. This is applied to every recv. + +Example: **CURL_DBG_SOCK_RMAX=400** means recv buffer size is limited to a +maximum of 400 bytes. + +## CURL_DBG_SOCK_WBLOCK + +The percentage of send() calls that should be answered with a EAGAIN at random. +For TCP/UNIX sockets. + +## CURL_DBG_SOCK_WPARTIAL + +The percentage of data that shall be written to the network. For TCP/UNIX +sockets. This is applied to every send. + +Example: **CURL_DBG_SOCK_WPARTIAL=80** means a send with 1000 bytes would +only send 800. + +## CURL_DBG_QUIC_WBLOCK + +The percentage of send() calls that should be answered with EAGAIN at random. +QUIC only. + +## CURL_DEBUG + +Trace logging behavior as an alternative to calling curl_global_trace(3). + +Example: **CURL_DEBUG=http/2** means trace details about HTTP/2 handling. + +## CURL_DEBUG_SIZE + +Fake the size returned by CURLINFO_HEADER_SIZE and CURLINFO_REQUEST_SIZE. + +## CURL_GETHOSTNAME + +Fake the local machine's unqualified hostname for NTLM and SMTP. + +## CURL_HSTS_HTTP + +Bypass the HSTS HTTPS protocol restriction if this variable exists. + +## CURL_FORCETIME + +A time of 0 is used for AWS signatures and NTLM if this variable exists. + +## CURL_ENTROPY + +A fixed faked value to use instead of a proper random number so that functions +in libcurl that are otherwise getting random outputs can be tested for what +they generate. + +## CURL_SMALLREQSEND + +An alternative size of HTTP data to be sent at a time only if smaller than the +current. + +## CURL_SMALLSENDS + +An alternative size of socket data to be sent at a time only if smaller than +the current. + +## CURL_TIME + +Fake unix timestamp to use for AltSvc, HSTS and CURLINFO variables that are +time related. + +This variable can also be used to fake the data returned by some CURLINFO +variables that are not time-related (such as CURLINFO_LOCAL_PORT), and in that +case the value is not a timestamp. + +## CURL_TRACE + +LDAP tracing is enabled if this variable exists and its value is 1 or greater. + +OpenLDAP tracing is separate. Refer to CURL_OPENLDAP_TRACE. + +## CURL_NTLM_WB_FILE + +Debug-version of the *ntlm-wb* executable. + +## CURL_OPENLDAP_TRACE + +OpenLDAP tracing is enabled if this variable exists and its value is 1 or +greater. There is a number of debug levels, refer to *openldap.c* comments. diff --git a/docs/libcurl/libcurl-env.md b/docs/libcurl/libcurl-env.md new file mode 100644 index 0000000..bd3e29c --- /dev/null +++ b/docs/libcurl/libcurl-env.md @@ -0,0 +1,99 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-env +Section: 3 +Source: libcurl +See-also: + - libcurl-env-dbg (3) +--- + +# NAME + +libcurl-env - environment variables libcurl understands + +# DESCRIPTION + +libcurl reads and understands a set of environment variables that if set +controls and changes behaviors. This is the full list of variables to set and +description of what they do. Also note that curl, the command line tool, +supports a set of additional environment variables independently of this. + +## [scheme]_proxy + +When libcurl is given a URL to use in a transfer, it first extracts the scheme +part from the URL and checks if there is a given proxy set for that in its +corresponding environment variable. A URL like https://example.com makes +libcurl use the **http_proxy** variable, while a URL like ftp://example.com +uses the **ftp_proxy** variable. + +These proxy variables are also checked for in their uppercase versions, except +the **http_proxy** one which is only used lowercase. Note also that some +systems actually have a case insensitive handling of environment variables and +then of course **HTTP_PROXY** still works. + +An exception exists for the WebSocket **ws** and **wss** URL schemes, +where libcurl first checks **ws_proxy** or **wss_proxy** but if they are +not set, it will fall back and try the http and https versions instead if set. + +## ALL_PROXY + +This is a setting to set proxy for all URLs, independently of what scheme is +being used. Note that the scheme specific variables overrides this one if set. + +## CURL_SSL_BACKEND + +When libcurl is built to support multiple SSL backends, it selects a specific +backend at first use. If no selection is done by the program using libcurl, +this variable's selection is used. Setting a name that is not a built-in +alternative makes libcurl stay with the default. + +SSL backend names (case-insensitive): BearSSL, GnuTLS, mbedTLS, +nss, OpenSSL, rustls, Schannel, Secure-Transport, wolfSSL + +## HOME + +When the netrc feature is used (CURLOPT_NETRC(3)), this variable is +checked as the primary way to find the "current" home directory in which +the .netrc file is likely to exist. + +## USERPROFILE + +When the netrc feature is used (CURLOPT_NETRC(3)), this variable is +checked as the secondary way to find the "current" home directory (on Windows +only) in which the .netrc file is likely to exist. + +## LOGNAME + +User name to use when invoking the *ntlm-wb* tool, if *NTLMUSER* was +not set. + +## NO_PROXY + +This has the same functionality as the CURLOPT_NOPROXY(3) option: it +gives libcurl a comma-separated list of hostname patterns for which libcurl +should not use a proxy. + +## NTLMUSER + +User name to use when invoking the *ntlm-wb* tool. + +## SSLKEYLOGFILE + +When set and libcurl runs with a SSL backend that supports this feature, +libcurl saves SSL secrets into the given filename. Using those SSL secrets, +other tools (such as Wireshark) can decrypt the SSL communication and +analyze/view the traffic. + +These secrets and this file might be sensitive. Users are advised to take +precautions so that they are not stolen or otherwise inadvertently revealed. + +## USER + +User name to use when invoking the *ntlm-wb* tool, if *NTLMUSER* and +*LOGNAME* were not set. + +# Debug Variables + +Debug variables are intended for internal use and are documented in +libcurl-env-dbg(3). diff --git a/docs/libcurl/libcurl-errors.md b/docs/libcurl/libcurl-errors.md new file mode 100644 index 0000000..2a7c8bf --- /dev/null +++ b/docs/libcurl/libcurl-errors.md @@ -0,0 +1,757 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-errors +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_ERRORBUFFER (3) + - CURLOPT_VERBOSE (3) + - curl_easy_strerror (3) + - curl_multi_strerror (3) + - curl_share_strerror (3) + - curl_url_strerror (3) +--- + +# NAME + +libcurl-errors - error codes in libcurl + +# DESCRIPTION + +This man page includes most, if not all, available error codes in libcurl. +Why they occur and possibly what you can do to fix the problem are also included. + +# CURLcode + +Almost all "easy" interface functions return a CURLcode error code. No matter +what, using the curl_easy_setopt(3) option CURLOPT_ERRORBUFFER(3) +is a good idea as it gives you a human readable error string that may offer +more details about the cause of the error than just the error code. +curl_easy_strerror(3) can be called to get an error string from a given +CURLcode number. + +CURLcode is one of the following: + +## CURLE_OK (0) + +All fine. Proceed as usual. + +## CURLE_UNSUPPORTED_PROTOCOL (1) + +The URL you passed to libcurl used a protocol that this libcurl does not +support. The support might be a compile-time option that you did not use, it +can be a misspelled protocol string or just a protocol libcurl has no code +for. + +## CURLE_FAILED_INIT (2) + +Early initialization code failed. This is likely to be an internal error or +problem, or a resource problem where something fundamental could not get done +at init time. + +## CURLE_URL_MALFORMAT (3) + +The URL was not properly formatted. + +## CURLE_NOT_BUILT_IN (4) + +A requested feature, protocol or option was not found built-in in this libcurl +due to a build-time decision. This means that a feature or option was not +enabled or explicitly disabled when libcurl was built and in order to get it +to function you have to get a rebuilt libcurl. + +## CURLE_COULDNT_RESOLVE_PROXY (5) + +Could not resolve proxy. The given proxy host could not be resolved. + +## CURLE_COULDNT_RESOLVE_HOST (6) + +Could not resolve host. The given remote host was not resolved. + +## CURLE_COULDNT_CONNECT (7) + +Failed to connect() to host or proxy. + +## CURLE_WEIRD_SERVER_REPLY (8) + +The server sent data libcurl could not parse. This error code was known as +*CURLE_FTP_WEIRD_SERVER_REPLY* before 7.51.0. + +## CURLE_REMOTE_ACCESS_DENIED (9) + +We were denied access to the resource given in the URL. For FTP, this occurs +while trying to change to the remote directory. + +## CURLE_FTP_ACCEPT_FAILED (10) + +While waiting for the server to connect back when an active FTP session is +used, an error code was sent over the control connection or similar. + +## CURLE_FTP_WEIRD_PASS_REPLY (11) + +After having sent the FTP password to the server, libcurl expects a proper +reply. This error code indicates that an unexpected code was returned. + +## CURLE_FTP_ACCEPT_TIMEOUT (12) + +During an active FTP session while waiting for the server to connect, the +CURLOPT_ACCEPTTIMEOUT_MS(3) (or the internal default) timeout expired. + +## CURLE_FTP_WEIRD_PASV_REPLY (13) + +libcurl failed to get a sensible result back from the server as a response to +either a PASV or a EPSV command. The server is flawed. + +## CURLE_FTP_WEIRD_227_FORMAT (14) + +FTP servers return a 227-line as a response to a PASV command. If libcurl +fails to parse that line, this return code is passed back. + +## CURLE_FTP_CANT_GET_HOST (15) + +An internal failure to lookup the host used for the new connection. + +## CURLE_HTTP2 (16) + +A problem was detected in the HTTP2 framing layer. This is somewhat generic +and can be one out of several problems, see the error buffer for details. + +## CURLE_FTP_COULDNT_SET_TYPE (17) + +Received an error when trying to set the transfer mode to binary or ASCII. + +## CURLE_PARTIAL_FILE (18) + +A file transfer was shorter or larger than expected. This happens when the +server first reports an expected transfer size, and then delivers data that +does not match the previously given size. + +## CURLE_FTP_COULDNT_RETR_FILE (19) + +This was either a weird reply to a 'RETR' command or a zero byte transfer +complete. + +## Obsolete error (20) + +Not used in modern versions. + +## CURLE_QUOTE_ERROR (21) + +When sending custom "QUOTE" commands to the remote server, one of the commands +returned an error code that was 400 or higher (for FTP) or otherwise +indicated unsuccessful completion of the command. + +## CURLE_HTTP_RETURNED_ERROR (22) + +This is returned if CURLOPT_FAILONERROR(3) is set TRUE and the HTTP +server returns an error code that is >= 400. + +## CURLE_WRITE_ERROR (23) + +An error occurred when writing received data to a local file, or an error was +returned to libcurl from a write callback. + +## Obsolete error (24) + +Not used in modern versions. + +## CURLE_UPLOAD_FAILED (25) + +Failed starting the upload. For FTP, the server typically denied the STOR +command. The error buffer usually contains the server's explanation for this. + +## CURLE_READ_ERROR (26) + +There was a problem reading a local file or an error returned by the read +callback. + +## CURLE_OUT_OF_MEMORY (27) + +A memory allocation request failed. This is serious badness and +things are severely screwed up if this ever occurs. + +## CURLE_OPERATION_TIMEDOUT (28) + +Operation timeout. The specified time-out period was reached according to the +conditions. + +## Obsolete error (29) + +Not used in modern versions. + +## CURLE_FTP_PORT_FAILED (30) + +The FTP PORT command returned error. This mostly happens when you have not +specified a good enough address for libcurl to use. See +CURLOPT_FTPPORT(3). + +## CURLE_FTP_COULDNT_USE_REST (31) + +The FTP REST command returned error. This should never happen if the server is +sane. + +## Obsolete error (32) + +Not used in modern versions. + +## CURLE_RANGE_ERROR (33) + +The server does not support or accept range requests. + +## CURLE_HTTP_POST_ERROR (34) + +This is an odd error that mainly occurs due to internal confusion. + +## CURLE_SSL_CONNECT_ERROR (35) + +A problem occurred somewhere in the SSL/TLS handshake. You really want the +error buffer and read the message there as it pinpoints the problem slightly +more. Could be certificates (file formats, paths, permissions), passwords, and +others. + +## CURLE_BAD_DOWNLOAD_RESUME (36) + +The download could not be resumed because the specified offset was out of the +file boundary. + +## CURLE_FILE_COULDNT_READ_FILE (37) + +A file given with FILE:// could not be opened. Most likely because the file +path does not identify an existing file. Did you check file permissions? + +## CURLE_LDAP_CANNOT_BIND (38) + +LDAP cannot bind. LDAP bind operation failed. + +## CURLE_LDAP_SEARCH_FAILED (39) + +LDAP search failed. + +## Obsolete error (40) + +Not used in modern versions. + +## CURLE_FUNCTION_NOT_FOUND (41) + +Function not found. A required zlib function was not found. + +## CURLE_ABORTED_BY_CALLBACK (42) + +Aborted by callback. A callback returned "abort" to libcurl. + +## CURLE_BAD_FUNCTION_ARGUMENT (43) + +A function was called with a bad parameter. + +## Obsolete error (44) + +Not used in modern versions. + +## CURLE_INTERFACE_FAILED (45) + +Interface error. A specified outgoing interface could not be used. Set which +interface to use for outgoing connections' source IP address with +CURLOPT_INTERFACE(3). + +## Obsolete error (46) + +Not used in modern versions. + +## CURLE_TOO_MANY_REDIRECTS (47) + +Too many redirects. When following redirects, libcurl hit the maximum amount. +Set your limit with CURLOPT_MAXREDIRS(3). + +## CURLE_UNKNOWN_OPTION (48) + +An option passed to libcurl is not recognized/known. Refer to the appropriate +documentation. This is most likely a problem in the program that uses +libcurl. The error buffer might contain more specific information about which +exact option it concerns. + +## CURLE_SETOPT_OPTION_SYNTAX (49) + +An option passed in to a setopt was wrongly formatted. See error message for +details about what option. + +## Obsolete errors (50-51) + +Not used in modern versions. + +## CURLE_GOT_NOTHING (52) + +Nothing was returned from the server, and under the circumstances, getting +nothing is considered an error. + +## CURLE_SSL_ENGINE_NOTFOUND (53) + +The specified crypto engine was not found. + +## CURLE_SSL_ENGINE_SETFAILED (54) + +Failed setting the selected SSL crypto engine as default. + +## CURLE_SEND_ERROR (55) + +Failed sending network data. + +## CURLE_RECV_ERROR (56) + +Failure with receiving network data. + +## Obsolete error (57) + +Not used in modern versions. + +## CURLE_SSL_CERTPROBLEM (58) + +problem with the local client certificate. + +## CURLE_SSL_CIPHER (59) + +Could not use specified cipher. + +## CURLE_PEER_FAILED_VERIFICATION (60) + +The remote server's SSL certificate or SSH fingerprint was deemed not OK. +This error code has been unified with CURLE_SSL_CACERT since 7.62.0. Its +previous value was 51. + +## CURLE_BAD_CONTENT_ENCODING (61) + +Unrecognized transfer encoding. + +## Obsolete error (62) + +Not used in modern versions. + +## CURLE_FILESIZE_EXCEEDED (63) + +Maximum file size exceeded. + +## CURLE_USE_SSL_FAILED (64) + +Requested FTP SSL level failed. + +## CURLE_SEND_FAIL_REWIND (65) + +When doing a send operation curl had to rewind the data to retransmit, but the +rewinding operation failed. + +## CURLE_SSL_ENGINE_INITFAILED (66) + +Initiating the SSL Engine failed. + +## CURLE_LOGIN_DENIED (67) + +The remote server denied curl to login (Added in 7.13.1) + +## CURLE_TFTP_NOTFOUND (68) + +File not found on TFTP server. + +## CURLE_TFTP_PERM (69) + +Permission problem on TFTP server. + +## CURLE_REMOTE_DISK_FULL (70) + +Out of disk space on the server. + +## CURLE_TFTP_ILLEGAL (71) + +Illegal TFTP operation. + +## CURLE_TFTP_UNKNOWNID (72) + +Unknown TFTP transfer ID. + +## CURLE_REMOTE_FILE_EXISTS (73) + +File already exists and is not overwritten. + +## CURLE_TFTP_NOSUCHUSER (74) + +This error should never be returned by a properly functioning TFTP server. + +## Obsolete error (75-76) + +Not used in modern versions. + +## CURLE_SSL_CACERT_BADFILE (77) + +Problem with reading the SSL CA cert (path? access rights?) + +## CURLE_REMOTE_FILE_NOT_FOUND (78) + +The resource referenced in the URL does not exist. + +## CURLE_SSH (79) + +An unspecified error occurred during the SSH session. + +## CURLE_SSL_SHUTDOWN_FAILED (80) + +Failed to shut down the SSL connection. + +## CURLE_AGAIN (81) + +Socket is not ready for send/recv. Wait until it is ready and try again. This +return code is only returned from curl_easy_recv(3) and curl_easy_send(3) +(Added in 7.18.2) + +## CURLE_SSL_CRL_BADFILE (82) + +Failed to load CRL file (Added in 7.19.0) + +## CURLE_SSL_ISSUER_ERROR (83) + +Issuer check failed (Added in 7.19.0) + +## CURLE_FTP_PRET_FAILED (84) + +The FTP server does not understand the PRET command at all or does not support +the given argument. Be careful when using CURLOPT_CUSTOMREQUEST(3), a +custom LIST command is sent with the PRET command before PASV as well. (Added +in 7.20.0) + +## CURLE_RTSP_CSEQ_ERROR (85) + +Mismatch of RTSP CSeq numbers. + +## CURLE_RTSP_SESSION_ERROR (86) + +Mismatch of RTSP Session Identifiers. + +## CURLE_FTP_BAD_FILE_LIST (87) + +Unable to parse FTP file list (during FTP wildcard downloading). + +## CURLE_CHUNK_FAILED (88) + +Chunk callback reported error. + +## CURLE_NO_CONNECTION_AVAILABLE (89) + +(For internal use only, is never returned by libcurl) No connection available, +the session is queued. (added in 7.30.0) + +## CURLE_SSL_PINNEDPUBKEYNOTMATCH (90) + +Failed to match the pinned key specified with CURLOPT_PINNEDPUBLICKEY(3). + +## CURLE_SSL_INVALIDCERTSTATUS (91) + +Status returned failure when asked with CURLOPT_SSL_VERIFYSTATUS(3). + +## CURLE_HTTP2_STREAM (92) + +Stream error in the HTTP/2 framing layer. + +## CURLE_RECURSIVE_API_CALL (93) + +An API function was called from inside a callback. + +## CURLE_AUTH_ERROR (94) + +An authentication function returned an error. + +## CURLE_HTTP3 (95) + +A problem was detected in the HTTP/3 layer. This is somewhat generic and can +be one out of several problems, see the error buffer for details. + +## CURLE_QUIC_CONNECT_ERROR (96) + +QUIC connection error. This error may be caused by an SSL library error. QUIC +is the protocol used for HTTP/3 transfers. + +## CURLE_PROXY (97) + +Proxy handshake error. CURLINFO_PROXY_ERROR(3) provides extra details on +the specific problem. + +## CURLE_SSL_CLIENTCERT (98) + +SSL Client Certificate required. + +## CURLE_UNRECOVERABLE_POLL (99) + +An internal call to poll() or select() returned error that is not recoverable. + +## CURLE_TOO_LARGE (100) + +A value or data field grew larger than allowed. + +# CURLMcode + +This is the generic return code used by functions in the libcurl multi +interface. Also consider curl_multi_strerror(3). + +## CURLM_CALL_MULTI_PERFORM (-1) + +This is not really an error. It means you should call +curl_multi_perform(3) again without doing select() or similar in +between. Before version 7.20.0 (released on February 9 2010) this could be returned by +curl_multi_perform(3), but in later versions this return code is never +used. + +## CURLM_OK (0) + +Things are fine. + +## CURLM_BAD_HANDLE (1) + +The passed-in handle is not a valid *CURLM* handle. + +## CURLM_BAD_EASY_HANDLE (2) + +An easy handle was not good/valid. It could mean that it is not an easy handle +at all, or possibly that the handle already is in use by this or another multi +handle. + +## CURLM_OUT_OF_MEMORY (3) + +You are doomed. + +## CURLM_INTERNAL_ERROR (4) + +This can only be returned if libcurl bugs. Please report it to us! + +## CURLM_BAD_SOCKET (5) + +The passed-in socket is not a valid one that libcurl already knows about. +(Added in 7.15.4) + +## CURLM_UNKNOWN_OPTION (6) + +curl_multi_setopt() with unsupported option +(Added in 7.15.4) + +## CURLM_ADDED_ALREADY (7) + +An easy handle already added to a multi handle was attempted to get added a +second time. (Added in 7.32.1) + +## CURLM_RECURSIVE_API_CALL (8) + +An API function was called from inside a callback. + +## CURLM_WAKEUP_FAILURE (9) + +Wake up is unavailable or failed. + +## CURLM_BAD_FUNCTION_ARGUMENT (10) + +A function was called with a bad parameter. + +## CURLM_ABORTED_BY_CALLBACK (11) + +A multi handle callback returned error. + +## CURLM_UNRECOVERABLE_POLL (12) + +An internal call to poll() or select() returned error that is not recoverable. + +# CURLSHcode + +The "share" interface returns a **CURLSHcode** to indicate when an error has +occurred. Also consider curl_share_strerror(3). + +## CURLSHE_OK (0) + +All fine. Proceed as usual. + +## CURLSHE_BAD_OPTION (1) + +An invalid option was passed to the function. + +## CURLSHE_IN_USE (2) + +The share object is currently in use. + +## CURLSHE_INVALID (3) + +An invalid share object was passed to the function. + +## CURLSHE_NOMEM (4) + +Not enough memory was available. +(Added in 7.12.0) + +## CURLSHE_NOT_BUILT_IN (5) + +The requested sharing could not be done because the library you use do not have +that particular feature enabled. (Added in 7.23.0) + +# CURLUcode + +The URL interface returns a *CURLUcode* to indicate when an error has +occurred. Also consider curl_url_strerror(3). + +## CURLUE_OK (0) + +All fine. Proceed as usual. + +## CURLUE_BAD_HANDLE (1) + +An invalid URL handle was passed as argument. + +## CURLUE_BAD_PARTPOINTER (2) + +An invalid 'part' argument was passed as argument. + +## CURLUE_MALFORMED_INPUT (3) + +A malformed input was passed to a URL API function. + +## CURLUE_BAD_PORT_NUMBER (4) + +The port number was not a decimal number between 0 and 65535. + +## CURLUE_UNSUPPORTED_SCHEME (5) + +This libcurl build does not support the given URL scheme. + +## CURLUE_URLDECODE (6) + +URL decode error, most likely because of rubbish in the input. + +## CURLUE_OUT_OF_MEMORY (7) + +A memory function failed. + +## CURLUE_USER_NOT_ALLOWED (8) + +Credentials was passed in the URL when prohibited. + +## CURLUE_UNKNOWN_PART (9) + +An unknown part ID was passed to a URL API function. + +## CURLUE_NO_SCHEME (10) + +There is no scheme part in the URL. + +## CURLUE_NO_USER (11) + +There is no user part in the URL. + +## CURLUE_NO_PASSWORD (12) + +There is no password part in the URL. + +## CURLUE_NO_OPTIONS (13) + +There is no options part in the URL. + +## CURLUE_NO_HOST (14) + +There is no host part in the URL. + +## CURLUE_NO_PORT (15) + +There is no port part in the URL. + +## CURLUE_NO_QUERY (16) + +There is no query part in the URL. + +## CURLUE_NO_FRAGMENT (17) + +There is no fragment part in the URL. + +## CURLUE_NO_ZONEID (18) + +There is no zone id set in the URL. + +## CURLUE_BAD_FILE_URL (19) + +The file:// URL is invalid. + +## CURLUE_BAD_FRAGMENT (20) + +The fragment part of the URL contained bad or invalid characters. + +## CURLUE_BAD_HOSTNAME (21) + +The hostname contained bad or invalid characters. + +## CURLUE_BAD_IPV6 (22) + +The IPv6 address hostname contained bad or invalid characters. + +## CURLUE_BAD_LOGIN (23) + +The login part of the URL contained bad or invalid characters. + +## CURLUE_BAD_PASSWORD (24) + +The password part of the URL contained bad or invalid characters. + +## CURLUE_BAD_PATH (25) + +The path part of the URL contained bad or invalid characters. + +## CURLUE_BAD_QUERY (26) + +The query part of the URL contained bad or invalid characters. + +## CURLUE_BAD_SCHEME (27) + +The scheme part of the URL contained bad or invalid characters. + +## CURLUE_BAD_SLASHES (28) + +The URL contained an invalid number of slashes. + +## CURLUE_BAD_USER (29) + +The user part of the URL contained bad or invalid characters. + +## CURLUE_LACKS_IDN (30) + +libcurl lacks IDN support. + +## CURLUE_TOO_LARGE (31) + +A value or data field is larger than allowed. + +# CURLHcode + +The header interface returns a *CURLHcode* to indicate when an error has +occurred. + +## CURLHE_OK (0) + +All fine. Proceed as usual. + +## CURLHE_BADINDEX (1) + +There is no header with the requested index. + +## CURLHE_MISSING (2) + +No such header exists. + +## CURLHE_NOHEADERS (3) + +No headers at all have been recorded. + +## CURLHE_NOREQUEST (4) + +There was no such request number. + +## CURLHE_OUT_OF_MEMORY (5) + +Out of resources + +## CURLHE_BAD_ARGUMENT (6) + +One or more of the given arguments are bad. + +## CURLHE_NOT_BUILT_IN (7) + +HTTP support or the header API has been disabled in the build. diff --git a/docs/libcurl/libcurl-multi.md b/docs/libcurl/libcurl-multi.md new file mode 100644 index 0000000..3acd13e --- /dev/null +++ b/docs/libcurl/libcurl-multi.md @@ -0,0 +1,178 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-multi +Section: 3 +Source: libcurl +See-also: + - libcurl (3) + - libcurl-easy (3) + - libcurl-errors (3) +--- + +# NAME + +libcurl-multi - how to use the multi interface + +# DESCRIPTION + +This is an overview on how to use the libcurl multi interface in your C +programs. There are specific man pages for each function mentioned in +here. There is also the libcurl-tutorial(3) man page for a complete +tutorial to programming with libcurl and the libcurl-easy(3) man page +for an overview of the libcurl easy interface. + +All functions in the multi interface are prefixed with curl_multi. + +# OBJECTIVES + +The multi interface offers several abilities that the easy interface does not. +They are mainly: + +1. Enable a "pull" interface. The application that uses libcurl decides where +and when to ask libcurl to get/send data. + +2. Enable multiple simultaneous transfers in the same thread without making it +complicated for the application. + +3. Enable the application to wait for action on its own file descriptors and +curl's file descriptors simultaneously. + +4. Enable event-based handling and scaling transfers up to and beyond +thousands of parallel connections. + +# ONE MULTI HANDLE MANY EASY HANDLES + +To use the multi interface, you must first create a 'multi handle' with +curl_multi_init(3). This handle is then used as input to all further +curl_multi_* functions. + +With a multi handle and the multi interface you can do several simultaneous +transfers in parallel. Each single transfer is built up around an easy +handle. You create all the easy handles you need, and setup the appropriate +options for each easy handle using curl_easy_setopt(3). + +There are two flavors of the multi interface, the select() oriented one and +the event based one we call multi_socket. You benefit from reading through the +description of both versions to fully understand how they work and +differentiate. We start out with the select() oriented version. + +When an easy handle is setup and ready for transfer, then instead of using +curl_easy_perform(3) like when using the easy interface for transfers, +you should add the easy handle to the multi handle with +curl_multi_add_handle(3). You can add more easy handles to a multi +handle at any point, even if other transfers are already running. + +Should you change your mind, the easy handle is again removed from the multi +stack using curl_multi_remove_handle(3). Once removed from the multi +handle, you can again use other easy interface functions like +curl_easy_perform(3) on the handle or whatever you think is +necessary. You can remove handles at any point during transfers. + +Adding the easy handle to the multi handle does not start the transfer. +Remember that one of the main ideas with this interface is to let your +application drive. You drive the transfers by invoking +curl_multi_perform(3). libcurl then transfers data if there is anything +available to transfer. It uses the callbacks and everything else you have +setup in the individual easy handles. It transfers data on all current +transfers in the multi stack that are ready to transfer anything. It may be +all, it may be none. When there is nothing more to do for now, it returns back +to the calling application. + +Your application extracts info from libcurl about when it would like to get +invoked to transfer data or do other work. The most convenient way is to use +curl_multi_poll(3) that helps you wait until the application should call +libcurl again. The older API to accomplish the same thing is +curl_multi_fdset(3) that extracts *fd_sets* from libcurl to use in +select() or poll() calls in order to get to know when the transfers in the +multi stack might need attention. Both these APIs allow for your program to +wait for input on your own private file descriptors at the same time. +curl_multi_timeout(3) also helps you with providing a suitable timeout +period for your select() calls. + +curl_multi_perform(3) stores the number of still running transfers in +one of its input arguments, and by reading that you can figure out when all +the transfers in the multi handles are done. 'done' does not mean +successful. One or more of the transfers may have failed. + +To get information about completed transfers, to figure out success or not and +similar, curl_multi_info_read(3) should be called. It can return a +message about a current or previous transfer. Repeated invokes of the function +get more messages until the message queue is empty. The information you +receive there includes an easy handle pointer which you may use to identify +which easy handle the information regards. + +When a single transfer is completed, the easy handle is still left added to +the multi stack. You need to first remove the easy handle with +curl_multi_remove_handle(3) and then close it with +curl_easy_cleanup(3), or possibly set new options to it and add it again +with curl_multi_add_handle(3) to start another transfer. + +When all transfers in the multi stack are done, close the multi handle with +curl_multi_cleanup(3). Be careful and please note that you **MUST** +invoke separate curl_easy_cleanup(3) calls for every single easy handle +to clean them up properly. + +If you want to reuse an easy handle that was added to the multi handle for +transfer, you must first remove it from the multi stack and then re-add it +again (possibly after having altered some options at your own choice). + +# MULTI_SOCKET + +curl_multi_socket_action(3) function offers a way for applications to +not only avoid being forced to use select(), but it also offers a much more +high-performance API that makes a significant difference for applications +using large numbers of simultaneous connections. + +curl_multi_socket_action(3) is then used instead of +curl_multi_perform(3). + +When using this API, you add easy handles to the multi handle just as with the +normal multi interface. Then you also set two callbacks with the +CURLMOPT_SOCKETFUNCTION(3) and CURLMOPT_TIMERFUNCTION(3) options +to curl_multi_setopt(3). They are two callback functions that libcurl +calls with information about what sockets to wait for, and for what activity, +and what the current timeout time is - if that expires libcurl should be +notified. + +The multi_socket API is designed to inform your application about which +sockets libcurl is currently using and for what activities (read and/or write) +on those sockets your application is expected to wait for. + +Your application must make sure to receive all sockets informed about in the +CURLMOPT_SOCKETFUNCTION(3) callback and make sure it reacts on the given +activity on them. When a socket has the given activity, you call +curl_multi_socket_action(3) specifying which socket and action there +are. + +The CURLMOPT_TIMERFUNCTION(3) callback is called to set a timeout. When +that timeout expires, your application should call the +curl_multi_socket_action(3) function saying it was due to a timeout. + +This API is typically used with an event-driven underlying functionality (like +libevent, libev, kqueue, epoll or similar) with which the application +"subscribes" on socket changes. This allows applications and libcurl to much +better scale upward and beyond thousands of simultaneous transfers without +losing performance. + +When you have added your initial set of handles, you call +curl_multi_socket_action(3) with CURL_SOCKET_TIMEOUT set in the +*sockfd* argument, and you get callbacks invoked that set you up and you +then continue to call curl_multi_socket_action(3) accordingly when you +get activity on the sockets you have been asked to wait on, or if the timeout +timer expires. + +You can poll curl_multi_info_read(3) to see if any transfer has +completed, as it then has a message saying so. + +# BLOCKING + +A few areas in the code are still using blocking code, even when used from the +multi interface. While we certainly want and intend for these to get fixed in +the future, you should be aware of the following current restrictions: + +~~~c + - Name resolves unless the c-ares or threaded-resolver backends are used + - file:// transfers + - TELNET transfers +~~~ diff --git a/docs/libcurl/libcurl-security.md b/docs/libcurl/libcurl-security.md new file mode 100644 index 0000000..09d63f4 --- /dev/null +++ b/docs/libcurl/libcurl-security.md @@ -0,0 +1,487 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-security +Section: 3 +Source: libcurl +See-also: + - libcurl-thread (3) +--- + +# NAME + +libcurl-security - security considerations when using libcurl + +# Security + +The libcurl project takes security seriously. The library is written with +caution and precautions are taken to mitigate many kinds of risks encountered +while operating with potentially malicious servers on the Internet. It is a +powerful library, however, which allows application writers to make trade-offs +between ease of writing and exposure to potential risky operations. If used +the right way, you can use libcurl to transfer data pretty safely. + +Many applications are used in closed networks where users and servers can +(possibly) be trusted, but many others are used on arbitrary servers and are +fed input from potentially untrusted users. Following is a discussion about +some risks in the ways in which applications commonly use libcurl and +potential mitigations of those risks. It is not comprehensive, but shows +classes of attacks that robust applications should consider. The Common +Weakness Enumeration project at https://cwe.mitre.org/ is a good reference for +many of these and similar types of weaknesses of which application writers +should be aware. + +# Command Lines + +If you use a command line tool (such as curl) that uses libcurl, and you give +options to the tool on the command line those options can get read by other +users of your system when they use *ps* or other tools to list currently +running processes. + +To avoid these problems, never feed sensitive things to programs using command +line options. Write them to a protected file and use the -K option to avoid +this. + +# .netrc + +.netrc is a pretty handy file/feature that allows you to login quickly and +automatically to frequently visited sites. The file contains passwords in +clear text and is a real security risk. In some cases, your .netrc is also +stored in a home directory that is NFS mounted or used on another network +based file system, so the clear text password flies through your network every +time anyone reads that file. + +For applications that enable .netrc use, a user who manage to set the right +URL might then be possible to pass on passwords. + +To avoid these problems, do not use .netrc files and never store passwords in +plain text anywhere. + +# Clear Text Passwords + +Many of the protocols libcurl supports send name and password unencrypted as +clear text (HTTP Basic authentication, FTP, TELNET etc). It is easy for anyone +on your network or a network nearby yours to just fire up a network analyzer +tool and eavesdrop on your passwords. Do not let the fact that HTTP Basic uses +base64 encoded passwords fool you. They may not look readable at a first +glance, but they are easily "deciphered" by anyone within seconds. + +To avoid this problem, use an authentication mechanism or other protocol that +does not let snoopers see your password: Digest, CRAM-MD5, Kerberos, SPNEGO or +NTLM authentication. Or even better: use authenticated protocols that protect +the entire connection and everything sent over it. + +# Unauthenticated Connections + +Protocols that do not have any form of cryptographic authentication cannot +with any certainty know that they communicate with the right remote server. + +If your application is using a fixed scheme or fixed hostname, it is not safe +as long as the connection is unauthenticated. There can be a man-in-the-middle +or in fact the whole server might have been replaced by an evil actor. + +Unauthenticated protocols are unsafe. The data that comes back to curl may +have been injected by an attacker. The data that curl sends might be modified +before it reaches the intended server. If it even reaches the intended server +at all. + +Remedies: + +## Restrict operations to authenticated transfers + +Use authenticated protocols protected with HTTPS or SSH. + +## Make sure the server's certificate etc is verified + +Never ever switch off certificate verification. + +# Redirects + +The CURLOPT_FOLLOWLOCATION(3) option automatically follows HTTP +redirects sent by a remote server. These redirects can refer to any kind of +URL, not just HTTP. libcurl restricts the protocols allowed to be used in +redirects for security reasons: only HTTP, HTTPS, FTP and FTPS are +enabled by default. Applications may opt to restrict that set further. + +A redirect to a file: URL would cause the libcurl to read (or write) arbitrary +files from the local filesystem. If the application returns the data back to +the user (as would happen in some kinds of CGI scripts), an attacker could +leverage this to read otherwise forbidden data (e.g. +**file://localhost/etc/passwd**). + +If authentication credentials are stored in the ~/.netrc file, or Kerberos is +in use, any other URL type (not just file:) that requires authentication is +also at risk. A redirect such as **ftp://some-internal-server/private-file** would +then return data even when the server is password protected. + +In the same way, if an unencrypted SSH private key has been configured for the +user running the libcurl application, SCP: or SFTP: URLs could access password +or private-key protected resources, +e.g. **sftp://user@some-internal-server/etc/passwd** + +The CURLOPT_REDIR_PROTOCOLS(3) and CURLOPT_NETRC(3) options can be +used to mitigate against this kind of attack. + +A redirect can also specify a location available only on the machine running +libcurl, including servers hidden behind a firewall from the attacker. +E.g. **http://127.0.0.1/** or **http://intranet/delete-stuff.cgi?delete=all** or +**tftp://bootp-server/pc-config-data** + +Applications can mitigate against this by disabling +CURLOPT_FOLLOWLOCATION(3) and handling redirects itself, sanitizing URLs +as necessary. Alternately, an app could leave CURLOPT_FOLLOWLOCATION(3) +enabled but set CURLOPT_REDIR_PROTOCOLS(3) and install a +CURLOPT_OPENSOCKETFUNCTION(3) or CURLOPT_PREREQFUNCTION(3) callback +function in which addresses are sanitized before use. + +# CRLF in Headers + +For all options in libcurl which specify headers, including but not limited to +CURLOPT_HTTPHEADER(3), CURLOPT_PROXYHEADER(3), +CURLOPT_COOKIE(3), CURLOPT_USERAGENT(3), CURLOPT_REFERER(3) +and CURLOPT_RANGE(3), libcurl sends the headers as-is and does not apply +any special sanitation or normalization to them. + +If you allow untrusted user input into these options without sanitizing CRLF +sequences in them, someone malicious may be able to modify the request in a +way you did not intend such as injecting new headers. + +# Local Resources + +A user who can control the DNS server of a domain being passed in within a URL +can change the address of the host to a local, private address which a +server-side libcurl-using application could then use. E.g. the innocuous URL +**http://fuzzybunnies.example.com/** could actually resolve to the IP +address of a server behind a firewall, such as 127.0.0.1 or +10.1.2.3. Applications can mitigate against this by setting a +CURLOPT_OPENSOCKETFUNCTION(3) or CURLOPT_PREREQFUNCTION(3) and +checking the address before a connection. + +All the malicious scenarios regarding redirected URLs apply just as well to +non-redirected URLs, if the user is allowed to specify an arbitrary URL that +could point to a private resource. For example, a web app providing a +translation service might happily translate **file://localhost/etc/passwd** +and display the result. Applications can mitigate against this with the +CURLOPT_PROTOCOLS(3) option as well as by similar mitigation techniques +for redirections. + +A malicious FTP server could in response to the PASV command return an IP +address and port number for a server local to the app running libcurl but +behind a firewall. Applications can mitigate against this by using the +CURLOPT_FTP_SKIP_PASV_IP(3) option or CURLOPT_FTPPORT(3). + +Local servers sometimes assume local access comes from friends and trusted +users. An application that expects https://example.com/file_to_read that and +instead gets http://192.168.0.1/my_router_config might print a file that would +otherwise be protected by the firewall. + +Allowing your application to connect to local hosts, be it the same machine +that runs the application or a machine on the same local network, might be +possible to exploit by an attacker who then perhaps can "port-scan" the +particular hosts - depending on how the application and servers acts. + +# IPv4 Addresses + +Some users might be tempted to filter access to local resources or similar +based on numerical IPv4 addresses used in URLs. This is a bad and error-prone +idea because of the many different ways a numerical IPv4 address can be +specified and libcurl accepts: one to four dot-separated fields using one of +or a mix of decimal, octal or hexadecimal encoding. + +# IPv6 Addresses + +libcurl handles IPv6 addresses transparently and just as easily as IPv4 +addresses. That means that a sanitizing function that filters out addresses +like 127.0.0.1 is not sufficient - the equivalent IPv6 addresses **::1**, +**::**, **0:00::0:1**, **::127.0.0.1** and **::ffff:7f00:1** supplied +somehow by an attacker would all bypass a naive filter and could allow access +to undesired local resources. IPv6 also has special address blocks like +link-local and site-local that generally should not be accessed by a +server-side libcurl-using application. A poorly configured firewall installed +in a data center, organization or server may also be configured to limit IPv4 +connections but leave IPv6 connections wide open. In some cases, setting +CURLOPT_IPRESOLVE(3) to CURL_IPRESOLVE_V4 can be used to limit resolved +addresses to IPv4 only and bypass these issues. + +# Uploads + +When uploading, a redirect can cause a local (or remote) file to be +overwritten. Applications must not allow any unsanitized URL to be passed in +for uploads. Also, CURLOPT_FOLLOWLOCATION(3) should not be used on +uploads. Instead, the applications should consider handling redirects itself, +sanitizing each URL first. + +# Authentication + +Use of CURLOPT_UNRESTRICTED_AUTH(3) could cause authentication +information to be sent to an unknown second server. Applications can mitigate +against this by disabling CURLOPT_FOLLOWLOCATION(3) and handling +redirects itself, sanitizing where necessary. + +Use of the CURLAUTH_ANY option to CURLOPT_HTTPAUTH(3) could result in +user name and password being sent in clear text to an HTTP server. Instead, +use CURLAUTH_ANYSAFE which ensures that the password is encrypted over the +network, or else fail the request. + +Use of the CURLUSESSL_TRY option to CURLOPT_USE_SSL(3) could result in +user name and password being sent in clear text to an FTP server. Instead, +use CURLUSESSL_CONTROL to ensure that an encrypted connection is used or else +fail the request. + +# Cookies + +If cookies are enabled and cached, then a user could craft a URL which +performs some malicious action to a site whose authentication is already +stored in a cookie. E.g. +**http://mail.example.com/delete-stuff.cgi?delete=all** Applications can +mitigate against this by disabling cookies or clearing them between requests. + +# Dangerous SCP URLs + +SCP URLs can contain raw commands within the scp: URL, which is a side effect +of how the SCP protocol is designed. E.g. +~~~ + scp://user:pass@host/a;date >/tmp/test; +~~~ +Applications must not allow unsanitized SCP: URLs to be passed in for +downloads. + +# file:// + +By default curl and libcurl support file:// URLs. Such a URL is always an +access, or attempted access, to a local resource. If your application wants to +avoid that, keep control of what URLs to use and/or prevent curl/libcurl from +using the protocol. + +By default, libcurl prohibits redirects to file:// URLs. + +# Warning: file:// on Windows + +The Windows operating system tries automatically, and without any way for +applications to disable it, to establish a connection to another host over the +network and access it (over SMB or other protocols), if only the correct file +path is accessed. + +When first realizing this, the curl team tried to filter out such attempts in +order to protect applications for inadvertent probes of for example internal +networks etc. This resulted in CVE-2019-15601 and the associated security fix. + +However, we have since been made aware of the fact that the previous fix was far +from adequate as there are several other ways to accomplish more or less the +same thing: accessing a remote host over the network instead of the local file +system. + +The conclusion we have come to is that this is a weakness or feature in the +Windows operating system itself, that we as an application cannot safely +protect users against. It would just be a whack-a-mole race we do not want to +participate in. There are too many ways to do it and there is no knob we can +use to turn off the practice. + +If you use curl or libcurl on Windows (any version), disable the use of the +FILE protocol in curl or be prepared that accesses to a range of "magic paths" +potentially make your system access other hosts on your network. curl cannot +protect you against this. + +# What if the user can set the URL + +Applications may find it tempting to let users set the URL that it can work +on. That is probably fine, but opens up for mischief and trickery that you as +an application author may want to address or take precautions against. + +If your curl-using script allow a custom URL do you also, perhaps +unintentionally, allow the user to pass other options to the curl command line +if creative use of special characters are applied? + +If the user can set the URL, the user can also specify the scheme part to +other protocols that you did not intend for users to use and perhaps did not +consider. curl supports over 20 different URL schemes. "http://" might be what +you thought, "ftp://" or "imap://" might be what the user gives your +application. Also, cross-protocol operations might be done by using a +particular scheme in the URL but point to a server doing a different protocol +on a non-standard port. + +Remedies: + +## Use --proto + +curl command lines can use *--proto* to limit what URL schemes it accepts + +## Use CURLOPT_PROTOCOLS + +libcurl programs can use CURLOPT_PROTOCOLS(3) to limit what URL schemes it accepts + +## consider not allowing the user to set the full URL + +Maybe just let the user provide data for parts of it? Or maybe filter input to +only allow specific choices? + +# RFC 3986 vs WHATWG URL + +curl supports URLs mostly according to how they are defined in RFC 3986, and +has done so since the beginning. + +Web browsers mostly adhere to the WHATWG URL Specification. + +This deviance makes some URLs copied between browsers (or returned over HTTP +for redirection) and curl not work the same way. It can also cause problems if +an application parses URLs differently from libcurl and makes different +assumptions about a link. This can mislead users into getting the wrong thing, +connecting to the wrong host or otherwise not working identically. + +Within an application, this can be mitigated by always using the +curl_url(3) API to parse URLs, ensuring that they are parsed the same way +as within libcurl itself. + +# FTP uses two connections + +When performing an FTP transfer, two TCP connections are used: one for setting +up the transfer and one for the actual data. + +FTP is not only unauthenticated, but the setting up of the second transfer is +also a weak spot. The second connection to use for data, is either setup with +the PORT/EPRT command that makes the server connect back to the client on the +given IP+PORT, or with PASV/EPSV that makes the server setup a port to listen +to and tells the client to connect to a given IP+PORT. + +Again, unauthenticated means that the connection might be meddled with by a +man-in-the-middle or that there is a malicious server pretending to be the +right one. + +A malicious FTP server can respond to PASV commands with the IP+PORT of a +totally different machine. Perhaps even a third party host, and when there are +many clients trying to connect to that third party, it could create a +Distributed Denial-Of-Service attack out of it. If the client makes an upload +operation, it can make the client send the data to another site. If the +attacker can affect what data the client uploads, it can be made to work as a +HTTP request and then the client could be made to issue HTTP requests to third +party hosts. + +An attacker that manages to control curl's command line options can tell curl +to send an FTP PORT command to ask the server to connect to a third party host +instead of back to curl. + +The fact that FTP uses two connections makes it vulnerable in a way that is +hard to avoid. + +# Denial of Service + +A malicious server could cause libcurl to effectively hang by sending data +slowly, or even no data at all but just keeping the TCP connection open. This +could effectively result in a denial-of-service attack. The +CURLOPT_TIMEOUT(3) and/or CURLOPT_LOW_SPEED_LIMIT(3) options can +be used to mitigate against this. + +A malicious server could cause libcurl to download an infinite amount of data, +potentially causing all of memory or disk to be filled. Setting the +CURLOPT_MAXFILESIZE_LARGE(3) option is not sufficient to guard against +this. Instead, applications should monitor the amount of data received within +the write or progress callback and abort once the limit is reached. + +A malicious HTTP server could cause an infinite redirection loop, causing a +denial-of-service. This can be mitigated by using the +CURLOPT_MAXREDIRS(3) option. + +# Arbitrary Headers + +User-supplied data must be sanitized when used in options like +CURLOPT_USERAGENT(3), CURLOPT_HTTPHEADER(3), +CURLOPT_POSTFIELDS(3) and others that are used to generate structured +data. Characters like embedded carriage returns or ampersands could allow the +user to create additional headers or fields that could cause malicious +transactions. + +# Server-supplied Names + +A server can supply data which the application may, in some cases, use as a +filename. The curl command-line tool does this with *--remote-header-name*, +using the Content-disposition: header to generate a filename. An application +could also use CURLINFO_EFFECTIVE_URL(3) to generate a filename from a +server-supplied redirect URL. Special care must be taken to sanitize such +names to avoid the possibility of a malicious server supplying one like +**"/etc/passwd"**, **"autoexec.bat"**, **"prn:"** or even **".bashrc"**. + +# Server Certificates + +A secure application should never use the CURLOPT_SSL_VERIFYPEER(3) +option to disable certificate validation. There are numerous attacks that are +enabled by applications that fail to properly validate server TLS/SSL +certificates, thus enabling a malicious server to spoof a legitimate +one. HTTPS without validated certificates is potentially as insecure as a +plain HTTP connection. + +# Showing What You Do + +Relatedly, be aware that in situations when you have problems with libcurl and +ask someone for help, everything you reveal in order to get best possible help +might also impose certain security related risks. Host names, user names, +paths, operating system specifics, etc. (not to mention passwords of course) +may in fact be used by intruders to gain additional information of a potential +target. + +Be sure to limit access to application logs if they could hold private or +security-related data. Besides the obvious candidates like user names and +passwords, things like URLs, cookies or even file names could also hold +sensitive data. + +To avoid this problem, you must of course use your common sense. Often, you +can just edit out the sensitive data or just search/replace your true +information with faked data. + +# setuid applications using libcurl + +libcurl-using applications that set the 'setuid' bit to run with elevated or +modified rights also implicitly give that extra power to libcurl and this +should only be done after careful considerations. + +Giving setuid powers to the application means that libcurl can save files using +those new rights (if for example the `SSLKEYLOGFILE` environment variable is +set). Also: if the application wants these powers to read or manage secrets +that the user is otherwise not able to view (like credentials for a login +etc), it should be noted that libcurl still might understand proxy environment +variables that allow the user to redirect libcurl operations to use a proxy +controlled by the user. + +# File descriptors, fork and NTLM + +An application that uses libcurl and invokes *fork()* gets all file +descriptors duplicated in the child process, including the ones libcurl +created. + +libcurl itself uses *fork()* and *execl()* if told to use the +**CURLAUTH_NTLM_WB** authentication method which then invokes the helper +command in a child process with file descriptors duplicated. Make sure that +only the trusted and reliable helper program is invoked! + +# Secrets in memory + +When applications pass user names, passwords or other sensitive data to +libcurl to be used for upcoming transfers, those secrets are kept around as-is +in memory. In many cases they are stored in the heap for as long as the handle +itself for which the options are set. + +If an attacker can access the heap, like maybe by reading swap space or via a +core dump file, such data might be accessible. + +Further, when eventually closing a handle and the secrets are no longer +needed, libcurl does not explicitly clear memory before freeing it, so +credentials may be left in freed data. + +# Saving files + +libcurl cannot protect against attacks where an attacker has write access to +the same directory where libcurl is directed to save files. + +# Cookies + +If libcurl is built with PSL (**Public Suffix List**) support, it detects and +discards cookies that are specified for such suffix domains that should not be +allowed to have cookies. + +if libcurl is *not* built with PSL support, it has no ability to stop super +cookies. + +# Report Security Problems + +Should you detect or just suspect a security problem in libcurl or curl, +contact the project curl security team immediately. See +https://curl.se/dev/secprocess.html for details. diff --git a/docs/libcurl/libcurl-share.md b/docs/libcurl/libcurl-share.md new file mode 100644 index 0000000..e244b97 --- /dev/null +++ b/docs/libcurl/libcurl-share.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-share +Section: 3 +Source: libcurl +See-also: + - curl_share_cleanup (3) + - curl_share_init (3) + - curl_share_setopt (3) + - libcurl-easy (3) + - libcurl-errors (3) + - libcurl-multi (3) +--- + +# NAME + +libcurl-share - how to use the share interface + +# DESCRIPTION + +This is an overview on how to use the libcurl share interface in your C +programs. There are specific man pages for each function mentioned in +here. + +All functions in the share interface are prefixed with curl_share. + +# OBJECTIVES + +The share interface was added to enable sharing of data between curl handles. + +# ONE SET OF DATA - MANY TRANSFERS + +You can have multiple easy handles share data between them. Have them update +and use the **same** cookie database, DNS cache, TLS session cache and/or +connection cache! This way, each single transfer takes advantage from data +updates made by the other transfer(s). + +# SHARE OBJECT + +You create a shared object with curl_share_init(3). It returns a handle +for a newly created one. + +You tell the shared object what data you want it to share by using +curl_share_setopt(3). + +Since you can use this share from multiple threads, and libcurl has no +internal thread synchronization, you must provide mutex callbacks if you are +using this multi-threaded. You set lock and unlock functions with +curl_share_setopt(3) too. + +Then, you make an easy handle to use this share, you set the +CURLOPT_SHARE(3) option with curl_easy_setopt(3), and pass in +share handle. You can make any number of easy handles share the same share +handle. + +To make an easy handle stop using that particular share, you set +CURLOPT_SHARE(3) to NULL for that easy handle. To make a handle stop +sharing a particular data, you can CURLSHOPT_UNSHARE(3) it. + +When you are done using the share, make sure that no easy handle is still using +it, and call curl_share_cleanup(3) on the handle. diff --git a/docs/libcurl/libcurl-symbols.md b/docs/libcurl/libcurl-symbols.md new file mode 100644 index 0000000..f5ca349 --- /dev/null +++ b/docs/libcurl/libcurl-symbols.md @@ -0,0 +1,3405 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-symbols +Section: 3 +Source: libcurl +See-also: + - libcurl (3) + - libcurl-easy (3) + - libcurl-multi (3) + - libcurl-security (3) + - libcurl-thread (3) +--- +# libcurl symbols + +This man page details version information for public symbols provided in the +libcurl header files. This lists the first version in which the symbol was +introduced and for some symbols two additional information pieces: + +The first version in which the symbol is marked "deprecated" - meaning that +since that version no new code should be written to use the symbol as it is +marked for getting removed in a future. + +The last version that featured the specific symbol. Using the symbol in source +code will make it no longer compile error-free after that specified version. + +This man page is automatically generated from the symbols-in-versions file. + +## CURL_AT_LEAST_VERSION +Introduced in 7.43.0. + +## CURL_BLOB_COPY +Introduced in 7.71.0. + +## CURL_BLOB_NOCOPY +Introduced in 7.71.0. + +## CURL_CHUNK_BGN_FUNC_FAIL +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURL_CHUNK_BGN_FUNC_OK +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURL_CHUNK_BGN_FUNC_SKIP +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURL_CHUNK_END_FUNC_FAIL +Introduced in 7.21.0. See CURLOPT_CHUNK_END_FUNCTION(3). + +## CURL_CHUNK_END_FUNC_OK +Introduced in 7.21.0. See CURLOPT_CHUNK_END_FUNCTION(3). + +## CURL_CSELECT_ERR +Introduced in 7.16.3. See curl_multi_socket_action(3). + +## CURL_CSELECT_IN +Introduced in 7.16.3. See curl_multi_socket_action(3). + +## CURL_CSELECT_OUT +Introduced in 7.16.3. See curl_multi_socket_action(3). + +## CURL_DEPRECATED +Introduced in 7.87.0. + +## CURL_DID_MEMORY_FUNC_TYPEDEFS +Introduced in 7.49.0. + +## CURL_EASY_NONE +Introduced in 7.14.0. Last used in 7.15.4. + +## CURL_EASY_TIMEOUT +Introduced in 7.14.0. Last used in 7.15.4. + +## CURL_ERROR_SIZE +Introduced in 7.1. + +## CURL_FNMATCHFUNC_FAIL +Introduced in 7.21.0. See CURLOPT_FNMATCH_FUNCTION(3). + +## CURL_FNMATCHFUNC_MATCH +Introduced in 7.21.0. See CURLOPT_FNMATCH_FUNCTION(3). + +## CURL_FNMATCHFUNC_NOMATCH +Introduced in 7.21.0. See CURLOPT_FNMATCH_FUNCTION(3). + +## CURL_FORMADD_DISABLED +Introduced in 7.12.1. Deprecated since 7.56.0. + +## CURL_FORMADD_ILLEGAL_ARRAY +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURL_FORMADD_INCOMPLETE +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURL_FORMADD_MEMORY +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURL_FORMADD_NULL +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURL_FORMADD_OK +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURL_FORMADD_OPTION_TWICE +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURL_FORMADD_UNKNOWN_OPTION +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURL_GLOBAL_ACK_EINTR +Introduced in 7.30.0. See curl_global_init(3). + +## CURL_GLOBAL_ALL +Introduced in 7.8. See curl_global_init(3). + +## CURL_GLOBAL_DEFAULT +Introduced in 7.8. See curl_global_init(3). + +## CURL_GLOBAL_NOTHING +Introduced in 7.8. See curl_global_init(3). + +## CURL_GLOBAL_SSL +Introduced in 7.8. See curl_global_init(3). + +## CURL_GLOBAL_WIN32 +Introduced in 7.8.1. See curl_global_init(3). + +## CURL_HET_DEFAULT +Introduced in 7.59.0. See CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3). + +## CURL_HTTP_VERSION_1_0 +Introduced in 7.9.1. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_1_1 +Introduced in 7.9.1. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_2 +Introduced in 7.43.0. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_2_0 +Introduced in 7.33.0. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE +Introduced in 7.49.0. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_2TLS +Introduced in 7.47.0. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_3 +Introduced in 7.66.0. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_3ONLY +Introduced in 7.88.0. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTP_VERSION_NONE +Introduced in 7.9.1. See CURLOPT_HTTP_VERSION(3). + +## CURL_HTTPPOST_BUFFER +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_HTTPPOST_CALLBACK +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_HTTPPOST_FILENAME +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_HTTPPOST_LARGE +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_HTTPPOST_PTRBUFFER +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_HTTPPOST_PTRCONTENTS +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_HTTPPOST_PTRNAME +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_HTTPPOST_READFILE +Introduced in 7.46.0. See curl_formadd(3). + +## CURL_IGNORE_DEPRECATION +Introduced in 7.87.0. + +## CURL_IPRESOLVE_V4 +Introduced in 7.10.8. See CURLOPT_IPRESOLVE(3). + +## CURL_IPRESOLVE_V6 +Introduced in 7.10.8. See CURLOPT_IPRESOLVE(3). + +## CURL_IPRESOLVE_WHATEVER +Introduced in 7.10.8. See CURLOPT_IPRESOLVE(3). + +## CURL_ISOCPP +Introduced in 7.10.2. + +## CURL_LOCK_ACCESS_NONE +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_ACCESS_SHARED +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_ACCESS_SINGLE +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_CONNECT +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_COOKIE +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_DNS +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_HSTS +Introduced in 7.88.0. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_NONE +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_PSL +Introduced in 7.61.0. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_SHARE +Introduced in 7.10.4. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_SSL_SESSION +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURL_LOCK_TYPE_CONNECT +Introduced in 7.10. Last used in 7.10.2. + +## CURL_LOCK_TYPE_COOKIE +Introduced in 7.10. Last used in 7.10.2. + +## CURL_LOCK_TYPE_DNS +Introduced in 7.10. Last used in 7.10.2. + +## CURL_LOCK_TYPE_NONE +Introduced in 7.10. Last used in 7.10.2. + +## CURL_LOCK_TYPE_SSL_SESSION +Introduced in 7.10. Last used in 7.10.2. + +## CURL_MAX_HTTP_HEADER +Introduced in 7.19.7. + +## CURL_MAX_READ_SIZE +Introduced in 7.53.0. + +## CURL_MAX_WRITE_SIZE +Introduced in 7.9.7. + +## CURL_NETRC_IGNORED +Introduced in 7.9.8. + +## CURL_NETRC_OPTIONAL +Introduced in 7.9.8. + +## CURL_NETRC_REQUIRED +Introduced in 7.9.8. + +## CURL_POLL_IN +Introduced in 7.14.0. See CURLMOPT_SOCKETFUNCTION(3). + +## CURL_POLL_INOUT +Introduced in 7.14.0. See CURLMOPT_SOCKETFUNCTION(3). + +## CURL_POLL_NONE +Introduced in 7.14.0. See CURLMOPT_SOCKETFUNCTION(3). + +## CURL_POLL_OUT +Introduced in 7.14.0. See CURLMOPT_SOCKETFUNCTION(3). + +## CURL_POLL_REMOVE +Introduced in 7.14.0. See CURLMOPT_SOCKETFUNCTION(3). + +## CURL_PREREQFUNC_ABORT +Introduced in 7.79.0. + +## CURL_PREREQFUNC_OK +Introduced in 7.79.0. + +## CURL_PROGRESS_BAR +Introduced in 7.1.1. Last used in 7.4.1. + +## CURL_PROGRESS_STATS +Introduced in 7.1.1. Last used in 7.4.1. + +## CURL_PROGRESSFUNC_CONTINUE +Introduced in 7.68.0. + +## CURL_PULL_SYS_POLL_H +Introduced in 7.56.0. + +## CURL_PUSH_DENY +Introduced in 7.44.0. + +## CURL_PUSH_ERROROUT +Introduced in 7.72.0. + +## CURL_PUSH_OK +Introduced in 7.44.0. + +## CURL_READFUNC_ABORT +Introduced in 7.12.1. + +## CURL_READFUNC_PAUSE +Introduced in 7.18.0. + +## CURL_REDIR_GET_ALL +Introduced in 7.19.1. + +## CURL_REDIR_POST_301 +Introduced in 7.19.1. See CURLOPT_POSTREDIR(3). + +## CURL_REDIR_POST_302 +Introduced in 7.19.1. See CURLOPT_POSTREDIR(3). + +## CURL_REDIR_POST_303 +Introduced in 7.25.1. See CURLOPT_POSTREDIR(3). + +## CURL_REDIR_POST_ALL +Introduced in 7.19.1. See CURLOPT_POSTREDIR(3). + +## CURL_RTSPREQ_ANNOUNCE +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_DESCRIBE +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_GET_PARAMETER +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_NONE +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_OPTIONS +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_PAUSE +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_PLAY +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_RECEIVE +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_RECORD +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_SET_PARAMETER +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_SETUP +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_RTSPREQ_TEARDOWN +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURL_SEEKFUNC_CANTSEEK +Introduced in 7.19.5. See CURLOPT_SEEKFUNCTION(3). + +## CURL_SEEKFUNC_FAIL +Introduced in 7.19.5. See CURLOPT_SEEKFUNCTION(3). + +## CURL_SEEKFUNC_OK +Introduced in 7.19.5. See CURLOPT_SEEKFUNCTION(3). + +## CURL_SOCKET_BAD +Introduced in 7.14.0. + +## CURL_SOCKET_TIMEOUT +Introduced in 7.14.0. + +## CURL_SOCKOPT_ALREADY_CONNECTED +Introduced in 7.21.5. + +## CURL_SOCKOPT_ERROR +Introduced in 7.21.5. + +## CURL_SOCKOPT_OK +Introduced in 7.21.5. + +## CURL_SSLVERSION_DEFAULT +Introduced in 7.9.2. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_MAX_DEFAULT +Introduced in 7.54.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_MAX_NONE +Introduced in 7.54.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_MAX_TLSv1_0 +Introduced in 7.54.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_MAX_TLSv1_1 +Introduced in 7.54.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_MAX_TLSv1_2 +Introduced in 7.54.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_MAX_TLSv1_3 +Introduced in 7.54.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_SSLv2 +Introduced in 7.9.2. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_SSLv3 +Introduced in 7.9.2. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_TLSv1 +Introduced in 7.9.2. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_TLSv1_0 +Introduced in 7.34.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_TLSv1_1 +Introduced in 7.34.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_TLSv1_2 +Introduced in 7.34.0. See CURLOPT_SSLVERSION(3). + +## CURL_SSLVERSION_TLSv1_3 +Introduced in 7.52.0. See CURLOPT_SSLVERSION(3). + +## CURL_STRICTER +Introduced in 7.50.2. + +## CURL_TIMECOND_IFMODSINCE +Introduced in 7.9.7. See CURLOPT_TIMECONDITION(3). + +## CURL_TIMECOND_IFUNMODSINCE +Introduced in 7.9.7. See CURLOPT_TIMECONDITION(3). + +## CURL_TIMECOND_LASTMOD +Introduced in 7.9.7. See CURLOPT_TIMECONDITION(3). + +## CURL_TIMECOND_NONE +Introduced in 7.9.7. See CURLOPT_TIMECONDITION(3). + +## CURL_TLSAUTH_NONE +Introduced in 7.21.4. + +## CURL_TLSAUTH_SRP +Introduced in 7.21.4. + +## CURL_TRAILERFUNC_ABORT +Introduced in 7.64.0. See CURLOPT_TRAILERFUNCTION(3). + +## CURL_TRAILERFUNC_OK +Introduced in 7.64.0. See CURLOPT_TRAILERFUNCTION(3). + +## CURL_UPKEEP_INTERVAL_DEFAULT +Introduced in 7.62.0. + +## CURL_VERSION_ALTSVC +Introduced in 7.64.1. See curl_version_info(3). + +## CURL_VERSION_ASYNCHDNS +Introduced in 7.10.7. See curl_version_info(3). + +## CURL_VERSION_BITS +Introduced in 7.43.0. See curl_version_info(3). + +## CURL_VERSION_BROTLI +Introduced in 7.57.0. See curl_version_info(3). + +## CURL_VERSION_CONV +Introduced in 7.15.4. See curl_version_info(3). + +## CURL_VERSION_CURLDEBUG +Introduced in 7.19.6. See curl_version_info(3). + +## CURL_VERSION_DEBUG +Introduced in 7.10.6. See curl_version_info(3). + +## CURL_VERSION_GSASL +Introduced in 7.76.0. See curl_version_info(3). + +## CURL_VERSION_GSSAPI +Introduced in 7.38.0. See curl_version_info(3). + +## CURL_VERSION_GSSNEGOTIATE +Introduced in 7.10.6. Deprecated since 7.38.0. + +## CURL_VERSION_HSTS +Introduced in 7.74.0. See curl_version_info(3). + +## CURL_VERSION_HTTP2 +Introduced in 7.33.0. See curl_version_info(3). + +## CURL_VERSION_HTTP3 +Introduced in 7.66.0. See curl_version_info(3). + +## CURL_VERSION_HTTPS_PROXY +Introduced in 7.52.0. See curl_version_info(3). + +## CURL_VERSION_IDN +Introduced in 7.12.0. See curl_version_info(3). + +## CURL_VERSION_IPV6 +Introduced in 7.10. See curl_version_info(3). + +## CURL_VERSION_KERBEROS4 +Introduced in 7.10. Deprecated since 7.33.0. + +## CURL_VERSION_KERBEROS5 +Introduced in 7.40.0. See curl_version_info(3). + +## CURL_VERSION_LARGEFILE +Introduced in 7.11.1. See curl_version_info(3). + +## CURL_VERSION_LIBZ +Introduced in 7.10. See curl_version_info(3). + +## CURL_VERSION_MULTI_SSL +Introduced in 7.56.0. See curl_version_info(3). + +## CURL_VERSION_NTLM +Introduced in 7.10.6. See curl_version_info(3). + +## CURL_VERSION_NTLM_WB +Introduced in 7.22.0. See curl_version_info(3). + +## CURL_VERSION_PSL +Introduced in 7.47.0. See curl_version_info(3). + +## CURL_VERSION_SPNEGO +Introduced in 7.10.8. See curl_version_info(3). + +## CURL_VERSION_SSL +Introduced in 7.10. See curl_version_info(3). + +## CURL_VERSION_SSPI +Introduced in 7.13.2. See curl_version_info(3). + +## CURL_VERSION_THREADSAFE +Introduced in 7.84.0. See curl_version_info(3). + +## CURL_VERSION_TLSAUTH_SRP +Introduced in 7.21.4. See curl_version_info(3). + +## CURL_VERSION_UNICODE +Introduced in 7.72.0. See curl_version_info(3). + +## CURL_VERSION_UNIX_SOCKETS +Introduced in 7.40.0. See curl_version_info(3). + +## CURL_VERSION_ZSTD +Introduced in 7.72.0. See curl_version_info(3). + +## CURL_WAIT_POLLIN +Introduced in 7.28.0. + +## CURL_WAIT_POLLOUT +Introduced in 7.28.0. + +## CURL_WAIT_POLLPRI +Introduced in 7.28.0. + +## CURL_WIN32 +Introduced in 7.69.0. Last used in 8.5.0. + +## CURL_WRITEFUNC_ERROR +Introduced in 7.87.0. + +## CURL_WRITEFUNC_PAUSE +Introduced in 7.18.0. + +## CURL_ZERO_TERMINATED +Introduced in 7.56.0. + +## CURLALTSVC_H1 +Introduced in 7.64.1. See CURLOPT_ALTSVC_CTRL(3). + +## CURLALTSVC_H2 +Introduced in 7.64.1. See CURLOPT_ALTSVC_CTRL(3). + +## CURLALTSVC_H3 +Introduced in 7.64.1. See CURLOPT_ALTSVC_CTRL(3). + +## CURLALTSVC_READONLYFILE +Introduced in 7.64.1. See CURLOPT_ALTSVC_CTRL(3). + +## CURLAUTH_ANY +Introduced in 7.10.6. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_ANYSAFE +Introduced in 7.10.6. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_AWS_SIGV4 +Introduced in 7.75.0. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_BASIC +Introduced in 7.10.6. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_BEARER +Introduced in 7.61.0. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_DIGEST +Introduced in 7.10.6. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_DIGEST_IE +Introduced in 7.19.3. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_GSSAPI +Introduced in 7.55.0. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_GSSNEGOTIATE +Introduced in 7.10.6. Deprecated since 7.38.0. + +## CURLAUTH_NEGOTIATE +Introduced in 7.38.0. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_NONE +Introduced in 7.10.6. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_NTLM +Introduced in 7.10.6. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_NTLM_WB +Introduced in 7.22.0. See CURLOPT_HTTPAUTH(3). + +## CURLAUTH_ONLY +Introduced in 7.21.3. See CURLOPT_HTTPAUTH(3). + +## CURLCLOSEPOLICY_CALLBACK +Introduced in 7.7. Deprecated since 7.16.1. + +## CURLCLOSEPOLICY_LEAST_RECENTLY_USED +Introduced in 7.7. Deprecated since 7.16.1. + +## CURLCLOSEPOLICY_LEAST_TRAFFIC +Introduced in 7.7. Deprecated since 7.16.1. + +## CURLCLOSEPOLICY_NONE +Introduced in 7.7. Deprecated since 7.16.1. + +## CURLCLOSEPOLICY_OLDEST +Introduced in 7.7. Deprecated since 7.16.1. + +## CURLCLOSEPOLICY_SLOWEST +Introduced in 7.7. Deprecated since 7.16.1. + +## CURLE_ABORTED_BY_CALLBACK +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_AGAIN +Introduced in 7.18.2. See libcurl-errors(3). + +## CURLE_ALREADY_COMPLETE +Introduced in 7.7.2. Deprecated since 7.8. + +## CURLE_AUTH_ERROR +Introduced in 7.66.0. See libcurl-errors(3). + +## CURLE_BAD_CALLING_ORDER +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_BAD_CONTENT_ENCODING +Introduced in 7.10. See libcurl-errors(3). + +## CURLE_BAD_DOWNLOAD_RESUME +Introduced in 7.10. See libcurl-errors(3). + +## CURLE_BAD_FUNCTION_ARGUMENT +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_BAD_PASSWORD_ENTERED +Introduced in 7.4.2. Deprecated since 7.17.0. + +## CURLE_CHUNK_FAILED +Introduced in 7.21.0. See libcurl-errors(3). + +## CURLE_CONV_FAILED +Introduced in 7.15.4. Deprecated since 7.82.0. + +## CURLE_CONV_REQD +Introduced in 7.15.4. Deprecated since 7.82.0. + +## CURLE_COULDNT_CONNECT +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_COULDNT_RESOLVE_HOST +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_COULDNT_RESOLVE_PROXY +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FAILED_INIT +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FILE_COULDNT_READ_FILE +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FILESIZE_EXCEEDED +Introduced in 7.10.8. See libcurl-errors(3). + +## CURLE_FTP_ACCEPT_FAILED +Introduced in 7.24.0. See libcurl-errors(3). + +## CURLE_FTP_ACCEPT_TIMEOUT +Introduced in 7.24.0. See libcurl-errors(3). + +## CURLE_FTP_ACCESS_DENIED +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_BAD_DOWNLOAD_RESUME +Introduced in 7.1. Deprecated since 7.1. + +## CURLE_FTP_BAD_FILE_LIST +Introduced in 7.21.0. See libcurl-errors(3). + +## CURLE_FTP_CANT_GET_HOST +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FTP_CANT_RECONNECT +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_COULDNT_GET_SIZE +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_COULDNT_RETR_FILE +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FTP_COULDNT_SET_ASCII +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_COULDNT_SET_BINARY +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_COULDNT_SET_TYPE +Introduced in 7.17.0. See libcurl-errors(3). + +## CURLE_FTP_COULDNT_STOR_FILE +Introduced in 7.1. Deprecated since 7.16.3. + +## CURLE_FTP_COULDNT_USE_REST +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FTP_PARTIAL_FILE +Introduced in 7.1. Deprecated since 7.1. + +## CURLE_FTP_PORT_FAILED +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FTP_PRET_FAILED +Introduced in 7.20.0. See libcurl-errors(3). + +## CURLE_FTP_QUOTE_ERROR +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_SSL_FAILED +Introduced in 7.11.0. Deprecated since 7.17.0. + +## CURLE_FTP_USER_PASSWORD_INCORRECT +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_WEIRD_227_FORMAT +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FTP_WEIRD_PASS_REPLY +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FTP_WEIRD_PASV_REPLY +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_FTP_WEIRD_SERVER_REPLY +Introduced in 7.1. Deprecated since 7.51.0. + +## CURLE_FTP_WEIRD_USER_REPLY +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FTP_WRITE_ERROR +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_FUNCTION_NOT_FOUND +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_GOT_NOTHING +Introduced in 7.9.1. See libcurl-errors(3). + +## CURLE_HTTP2 +Introduced in 7.38.0. See libcurl-errors(3). + +## CURLE_HTTP2_STREAM +Introduced in 7.49.0. See libcurl-errors(3). + +## CURLE_HTTP3 +Introduced in 7.68.0. See libcurl-errors(3). + +## CURLE_HTTP_NOT_FOUND +Introduced in 7.1. Deprecated since 7.10.3. + +## CURLE_HTTP_PORT_FAILED +Introduced in 7.3. Deprecated since 7.12.0. + +## CURLE_HTTP_POST_ERROR +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_HTTP_RANGE_ERROR +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_HTTP_RETURNED_ERROR +Introduced in 7.10.3. See libcurl-errors(3). + +## CURLE_INTERFACE_FAILED +Introduced in 7.12.0. See libcurl-errors(3). + +## CURLE_LDAP_CANNOT_BIND +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_LDAP_INVALID_URL +Introduced in 7.10.8. Deprecated since 7.82.0. + +## CURLE_LDAP_SEARCH_FAILED +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_LIBRARY_NOT_FOUND +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_LOGIN_DENIED +Introduced in 7.13.1. See libcurl-errors(3). + +## CURLE_MALFORMAT_USER +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_NO_CONNECTION_AVAILABLE +Introduced in 7.30.0. See libcurl-errors(3). + +## CURLE_NOT_BUILT_IN +Introduced in 7.21.5. See libcurl-errors(3). + +## CURLE_OK +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_OPERATION_TIMEDOUT +Introduced in 7.10.2. See libcurl-errors(3). + +## CURLE_OPERATION_TIMEOUTED +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_OUT_OF_MEMORY +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_PARTIAL_FILE +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_PEER_FAILED_VERIFICATION +Introduced in 7.17.1. See libcurl-errors(3). + +## CURLE_PROXY +Introduced in 7.73.0. See libcurl-errors(3). + +## CURLE_QUIC_CONNECT_ERROR +Introduced in 7.69.0. See libcurl-errors(3). + +## CURLE_QUOTE_ERROR +Introduced in 7.17.0. See libcurl-errors(3). + +## CURLE_RANGE_ERROR +Introduced in 7.17.0. See libcurl-errors(3). + +## CURLE_READ_ERROR +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_RECURSIVE_API_CALL +Introduced in 7.59.0. See libcurl-errors(3). + +## CURLE_RECV_ERROR +Introduced in 7.10. See libcurl-errors(3). + +## CURLE_REMOTE_ACCESS_DENIED +Introduced in 7.17.0. See libcurl-errors(3). + +## CURLE_REMOTE_DISK_FULL +Introduced in 7.17.0. See libcurl-errors(3). + +## CURLE_REMOTE_FILE_EXISTS +Introduced in 7.17.0. See libcurl-errors(3). + +## CURLE_REMOTE_FILE_NOT_FOUND +Introduced in 7.16.1. See libcurl-errors(3). + +## CURLE_RTSP_CSEQ_ERROR +Introduced in 7.20.0. See libcurl-errors(3). + +## CURLE_RTSP_SESSION_ERROR +Introduced in 7.20.0. See libcurl-errors(3). + +## CURLE_SEND_ERROR +Introduced in 7.10. See libcurl-errors(3). + +## CURLE_SEND_FAIL_REWIND +Introduced in 7.12.3. See libcurl-errors(3). + +## CURLE_SETOPT_OPTION_SYNTAX +Introduced in 7.78.0. See libcurl-errors(3). + +## CURLE_SHARE_IN_USE +Introduced in 7.9.6. Deprecated since 7.17.0. + +## CURLE_SSH +Introduced in 7.16.1. See libcurl-errors(3). + +## CURLE_SSL_CACERT +Introduced in 7.10. Deprecated since 7.62.0. + +## CURLE_SSL_CACERT_BADFILE +Introduced in 7.16.0. See libcurl-errors(3). + +## CURLE_SSL_CERTPROBLEM +Introduced in 7.10. See libcurl-errors(3). + +## CURLE_SSL_CIPHER +Introduced in 7.10. See libcurl-errors(3). + +## CURLE_SSL_CLIENTCERT +Introduced in 7.77.0. See libcurl-errors(3). + +## CURLE_SSL_CONNECT_ERROR +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_SSL_CRL_BADFILE +Introduced in 7.19.0. See libcurl-errors(3). + +## CURLE_SSL_ENGINE_INITFAILED +Introduced in 7.12.3. See libcurl-errors(3). + +## CURLE_SSL_ENGINE_NOTFOUND +Introduced in 7.9.3. See libcurl-errors(3). + +## CURLE_SSL_ENGINE_SETFAILED +Introduced in 7.9.3. See libcurl-errors(3). + +## CURLE_SSL_INVALIDCERTSTATUS +Introduced in 7.41.0. See libcurl-errors(3). + +## CURLE_SSL_ISSUER_ERROR +Introduced in 7.19.0. See libcurl-errors(3). + +## CURLE_SSL_PEER_CERTIFICATE +Introduced in 7.8. Deprecated since 7.17.1. + +## CURLE_SSL_PINNEDPUBKEYNOTMATCH +Introduced in 7.39.0. See libcurl-errors(3). + +## CURLE_SSL_SHUTDOWN_FAILED +Introduced in 7.16.1. See libcurl-errors(3). + +## CURLE_TELNET_OPTION_SYNTAX +Introduced in 7.7. See libcurl-errors(3). + +## CURLE_TFTP_DISKFULL +Introduced in 7.15.0. Deprecated since 7.17.0. + +## CURLE_TFTP_EXISTS +Introduced in 7.15.0. Deprecated since 7.17.0. + +## CURLE_TFTP_ILLEGAL +Introduced in 7.15.0. See libcurl-errors(3). + +## CURLE_TFTP_NOSUCHUSER +Introduced in 7.15.0. See libcurl-errors(3). + +## CURLE_TFTP_NOTFOUND +Introduced in 7.15.0. See libcurl-errors(3). + +## CURLE_TFTP_PERM +Introduced in 7.15.0. See libcurl-errors(3). + +## CURLE_TFTP_UNKNOWNID +Introduced in 7.15.0. See libcurl-errors(3). + +## CURLE_TOO_LARGE +Introduced in 8.6.0. See libcurl-errors(3). + +## CURLE_TOO_MANY_REDIRECTS +Introduced in 7.5. See libcurl-errors(3). + +## CURLE_UNKNOWN_OPTION +Introduced in 7.21.5. See libcurl-errors(3). + +## CURLE_UNKNOWN_TELNET_OPTION +Introduced in 7.7. Deprecated since 7.21.5. + +## CURLE_UNRECOVERABLE_POLL +Introduced in 7.84.0. See libcurl-errors(3). + +## CURLE_UNSUPPORTED_PROTOCOL +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_UPLOAD_FAILED +Introduced in 7.16.3. See libcurl-errors(3). + +## CURLE_URL_MALFORMAT +Introduced in 7.1. See libcurl-errors(3). + +## CURLE_URL_MALFORMAT_USER +Introduced in 7.1. Deprecated since 7.17.0. + +## CURLE_USE_SSL_FAILED +Introduced in 7.17.0. See libcurl-errors(3). + +## CURLE_WEIRD_SERVER_REPLY +Introduced in 7.51.0. See libcurl-errors(3). + +## CURLE_WRITE_ERROR +Introduced in 7.1. See libcurl-errors(3). + +## CURLFILETYPE_DEVICE_BLOCK +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_DEVICE_CHAR +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_DIRECTORY +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_DOOR +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_FILE +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_NAMEDPIPE +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_SOCKET +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_SYMLINK +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFILETYPE_UNKNOWN +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_FILENAME +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_FILETYPE +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_GID +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_HLINKCOUNT +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_PERM +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_SIZE +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_TIME +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFINFOFLAG_KNOWN_UID +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLFORM_ARRAY +Introduced in 7.9.1. Deprecated since 7.56.0. + +## CURLFORM_ARRAY_END +Introduced in 7.9.1. Deprecated since 7.9.5. + +## CURLFORM_ARRAY_START +Introduced in 7.9.1. Deprecated since 7.9.5. + +## CURLFORM_BUFFER +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURLFORM_BUFFERLENGTH +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURLFORM_BUFFERPTR +Introduced in 7.9.8. Deprecated since 7.56.0. + +## CURLFORM_CONTENTHEADER +Introduced in 7.9.3. Deprecated since 7.56.0. + +## CURLFORM_CONTENTLEN +Introduced in 7.46.0. Deprecated since 7.56.0. + +## CURLFORM_CONTENTSLENGTH +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_CONTENTTYPE +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_COPYCONTENTS +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_COPYNAME +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_END +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_FILE +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_FILECONTENT +Introduced in 7.9.1. Deprecated since 7.56.0. + +## CURLFORM_FILENAME +Introduced in 7.9.6. Deprecated since 7.56.0. + +## CURLFORM_NAMELENGTH +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_NOTHING +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_PTRCONTENTS +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_PTRNAME +Introduced in 7.9. Deprecated since 7.56.0. + +## CURLFORM_STREAM +Introduced in 7.18.2. Deprecated since 7.56.0. + +## CURLFTP_CREATE_DIR +Introduced in 7.19.4. See CURLOPT_FTP_CREATE_MISSING_DIRS(3). + +## CURLFTP_CREATE_DIR_NONE +Introduced in 7.19.4. See CURLOPT_FTP_CREATE_MISSING_DIRS(3). + +## CURLFTP_CREATE_DIR_RETRY +Introduced in 7.19.4. See CURLOPT_FTP_CREATE_MISSING_DIRS(3). + +## CURLFTPAUTH_DEFAULT +Introduced in 7.12.2. See CURLOPT_FTPSSLAUTH(3). + +## CURLFTPAUTH_SSL +Introduced in 7.12.2. See CURLOPT_FTPSSLAUTH(3). + +## CURLFTPAUTH_TLS +Introduced in 7.12.2. See CURLOPT_FTPSSLAUTH(3). + +## CURLFTPMETHOD_DEFAULT +Introduced in 7.15.3. See CURLOPT_FTP_FILEMETHOD(3). + +## CURLFTPMETHOD_MULTICWD +Introduced in 7.15.3. See CURLOPT_FTP_FILEMETHOD(3). + +## CURLFTPMETHOD_NOCWD +Introduced in 7.15.3. See CURLOPT_FTP_FILEMETHOD(3). + +## CURLFTPMETHOD_SINGLECWD +Introduced in 7.15.3. See CURLOPT_FTP_FILEMETHOD(3). + +## CURLFTPSSL_ALL +Introduced in 7.11.0. Deprecated since 7.17.0. + +## CURLFTPSSL_CCC_ACTIVE +Introduced in 7.16.2. See CURLOPT_USE_SSL(3). + +## CURLFTPSSL_CCC_NONE +Introduced in 7.16.2. See CURLOPT_USE_SSL(3). + +## CURLFTPSSL_CCC_PASSIVE +Introduced in 7.16.1. See CURLOPT_USE_SSL(3). + +## CURLFTPSSL_CONTROL +Introduced in 7.11.0. Deprecated since 7.17.0. + +## CURLFTPSSL_NONE +Introduced in 7.11.0. Deprecated since 7.17.0. + +## CURLFTPSSL_TRY +Introduced in 7.11.0. Deprecated since 7.17.0. + +## CURLGSSAPI_DELEGATION_FLAG +Introduced in 7.22.0. See CURLOPT_GSSAPI_DELEGATION(3). + +## CURLGSSAPI_DELEGATION_NONE +Introduced in 7.22.0. See CURLOPT_GSSAPI_DELEGATION(3). + +## CURLGSSAPI_DELEGATION_POLICY_FLAG +Introduced in 7.22.0. See CURLOPT_GSSAPI_DELEGATION(3). + +## CURLH_1XX +Introduced in 7.83.0. See curl_easy_header(3). + +## CURLH_CONNECT +Introduced in 7.83.0. See curl_easy_header(3). + +## CURLH_HEADER +Introduced in 7.83.0. See curl_easy_header(3). + +## CURLH_PSEUDO +Introduced in 7.83.0. See curl_easy_header(3). + +## CURLH_TRAILER +Introduced in 7.83.0. See curl_easy_header(3). + +## CURLHE_BAD_ARGUMENT +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHE_BADINDEX +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHE_MISSING +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHE_NOHEADERS +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHE_NOREQUEST +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHE_NOT_BUILT_IN +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHE_OK +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHE_OUT_OF_MEMORY +Introduced in 7.83.0. See libcurl-errors(3). + +## CURLHEADER_SEPARATE +Introduced in 7.37.0. See CURLOPT_HEADEROPT(3). + +## CURLHEADER_UNIFIED +Introduced in 7.37.0. See CURLOPT_HEADEROPT(3). + +## CURLHSTS_ENABLE +Introduced in 7.74.0. See CURLOPT_HSTS_CTRL(3). + +## CURLHSTS_READONLYFILE +Introduced in 7.74.0. See CURLOPT_HSTS_CTRL(3). + +## CURLINFO_ACTIVESOCKET +Introduced in 7.45.0. + +## CURLINFO_APPCONNECT_TIME +Introduced in 7.19.0. + +## CURLINFO_APPCONNECT_TIME_T +Introduced in 7.61.0. + +## CURLINFO_CAINFO +Introduced in 7.84.0. + +## CURLINFO_CAPATH +Introduced in 7.84.0. + +## CURLINFO_CERTINFO +Introduced in 7.19.1. + +## CURLINFO_CONDITION_UNMET +Introduced in 7.19.4. + +## CURLINFO_CONN_ID +Introduced in 8.2.0. + +## CURLINFO_CONNECT_TIME +Introduced in 7.4.1. + +## CURLINFO_CONNECT_TIME_T +Introduced in 7.61.0. + +## CURLINFO_CONTENT_LENGTH_DOWNLOAD +Introduced in 7.6.1. Deprecated since 7.55.0. + +## CURLINFO_CONTENT_LENGTH_DOWNLOAD_T +Introduced in 7.55.0. + +## CURLINFO_CONTENT_LENGTH_UPLOAD +Introduced in 7.6.1. Deprecated since 7.55.0. + +## CURLINFO_CONTENT_LENGTH_UPLOAD_T +Introduced in 7.55.0. + +## CURLINFO_CONTENT_TYPE +Introduced in 7.9.4. + +## CURLINFO_COOKIELIST +Introduced in 7.14.1. + +## CURLINFO_DATA_IN +Introduced in 7.9.6. See CURLOPT_DEBUGFUNCTION(3). + +## CURLINFO_DATA_OUT +Introduced in 7.9.6. See CURLOPT_DEBUGFUNCTION(3). + +## CURLINFO_DOUBLE +Introduced in 7.4.1. + +## CURLINFO_EFFECTIVE_METHOD +Introduced in 7.72.0. + +## CURLINFO_EFFECTIVE_URL +Introduced in 7.4. + +## CURLINFO_END +Introduced in 7.9.6. + +## CURLINFO_FILETIME +Introduced in 7.5. + +## CURLINFO_FILETIME_T +Introduced in 7.59.0. + +## CURLINFO_FTP_ENTRY_PATH +Introduced in 7.15.4. + +## CURLINFO_HEADER_IN +Introduced in 7.9.6. See CURLOPT_DEBUGFUNCTION(3). + +## CURLINFO_HEADER_OUT +Introduced in 7.9.6. See CURLOPT_DEBUGFUNCTION(3). + +## CURLINFO_HEADER_SIZE +Introduced in 7.4.1. + +## CURLINFO_HTTP_CODE +Introduced in 7.4.1. Deprecated since 7.10.8. + +## CURLINFO_HTTP_CONNECTCODE +Introduced in 7.10.7. + +## CURLINFO_HTTP_VERSION +Introduced in 7.50.0. + +## CURLINFO_HTTPAUTH_AVAIL +Introduced in 7.10.8. + +## CURLINFO_LASTONE +Introduced in 7.4.1. + +## CURLINFO_LASTSOCKET +Introduced in 7.15.2. Deprecated since 7.45.0. + +## CURLINFO_LOCAL_IP +Introduced in 7.21.0. + +## CURLINFO_LOCAL_PORT +Introduced in 7.21.0. + +## CURLINFO_LONG +Introduced in 7.4.1. + +## CURLINFO_MASK +Introduced in 7.4.1. + +## CURLINFO_NAMELOOKUP_TIME +Introduced in 7.4.1. + +## CURLINFO_NAMELOOKUP_TIME_T +Introduced in 7.61.0. + +## CURLINFO_NONE +Introduced in 7.4.1. + +## CURLINFO_NUM_CONNECTS +Introduced in 7.12.3. + +## CURLINFO_OFF_T +Introduced in 7.55.0. + +## CURLINFO_OS_ERRNO +Introduced in 7.12.2. + +## CURLINFO_PRETRANSFER_TIME +Introduced in 7.4.1. + +## CURLINFO_PRETRANSFER_TIME_T +Introduced in 7.61.0. + +## CURLINFO_PRIMARY_IP +Introduced in 7.19.0. + +## CURLINFO_PRIMARY_PORT +Introduced in 7.21.0. + +## CURLINFO_PRIVATE +Introduced in 7.10.3. + +## CURLINFO_PROTOCOL +Introduced in 7.52.0. Deprecated since 7.85.0. + +## CURLINFO_PROXY_ERROR +Introduced in 7.73.0. + +## CURLINFO_PROXY_SSL_VERIFYRESULT +Introduced in 7.52.0. + +## CURLINFO_PROXYAUTH_AVAIL +Introduced in 7.10.8. + +## CURLINFO_PTR +Introduced in 7.54.1. + +## CURLINFO_QUEUE_TIME_T +Introduced in 8.6.0. + +## CURLINFO_REDIRECT_COUNT +Introduced in 7.9.7. + +## CURLINFO_REDIRECT_TIME +Introduced in 7.9.7. + +## CURLINFO_REDIRECT_TIME_T +Introduced in 7.61.0. + +## CURLINFO_REDIRECT_URL +Introduced in 7.18.2. + +## CURLINFO_REFERER +Introduced in 7.76.0. + +## CURLINFO_REQUEST_SIZE +Introduced in 7.4.1. + +## CURLINFO_RESPONSE_CODE +Introduced in 7.10.8. + +## CURLINFO_RETRY_AFTER +Introduced in 7.66.0. + +## CURLINFO_RTSP_CLIENT_CSEQ +Introduced in 7.20.0. + +## CURLINFO_RTSP_CSEQ_RECV +Introduced in 7.20.0. + +## CURLINFO_RTSP_SERVER_CSEQ +Introduced in 7.20.0. + +## CURLINFO_RTSP_SESSION_ID +Introduced in 7.20.0. + +## CURLINFO_SCHEME +Introduced in 7.52.0. + +## CURLINFO_SIZE_DOWNLOAD +Introduced in 7.4.1. Deprecated since 7.55.0. + +## CURLINFO_SIZE_DOWNLOAD_T +Introduced in 7.55.0. + +## CURLINFO_SIZE_UPLOAD +Introduced in 7.4.1. Deprecated since 7.55.0. + +## CURLINFO_SIZE_UPLOAD_T +Introduced in 7.55.0. + +## CURLINFO_SLIST +Introduced in 7.12.3. + +## CURLINFO_SOCKET +Introduced in 7.45.0. + +## CURLINFO_SPEED_DOWNLOAD +Introduced in 7.4.1. Deprecated since 7.55.0. + +## CURLINFO_SPEED_DOWNLOAD_T +Introduced in 7.55.0. + +## CURLINFO_SPEED_UPLOAD +Introduced in 7.4.1. Deprecated since 7.55.0. + +## CURLINFO_SPEED_UPLOAD_T +Introduced in 7.55.0. + +## CURLINFO_SSL_DATA_IN +Introduced in 7.12.1. See CURLOPT_DEBUGFUNCTION(3). + +## CURLINFO_SSL_DATA_OUT +Introduced in 7.12.1. See CURLOPT_DEBUGFUNCTION(3). + +## CURLINFO_SSL_ENGINES +Introduced in 7.12.3. + +## CURLINFO_SSL_VERIFYRESULT +Introduced in 7.5. + +## CURLINFO_STARTTRANSFER_TIME +Introduced in 7.9.2. + +## CURLINFO_STARTTRANSFER_TIME_T +Introduced in 7.61.0. + +## CURLINFO_STRING +Introduced in 7.4.1. + +## CURLINFO_TEXT +Introduced in 7.9.6. See CURLOPT_DEBUGFUNCTION(3). + +## CURLINFO_TLS_SESSION +Introduced in 7.34.0. Deprecated since 7.48.0. + +## CURLINFO_TLS_SSL_PTR +Introduced in 7.48.0. + +## CURLINFO_TOTAL_TIME +Introduced in 7.4.1. + +## CURLINFO_TOTAL_TIME_T +Introduced in 7.61.0. + +## CURLINFO_TYPEMASK +Introduced in 7.4.1. + +## CURLINFO_XFER_ID +Introduced in 8.2.0. + +## CURLIOCMD_NOP +Introduced in 7.12.3. See CURLOPT_IOCTLFUNCTION(3). + +## CURLIOCMD_RESTARTREAD +Introduced in 7.12.3. See CURLOPT_IOCTLFUNCTION(3). + +## CURLIOE_FAILRESTART +Introduced in 7.12.3. See CURLOPT_IOCTLFUNCTION(3). + +## CURLIOE_OK +Introduced in 7.12.3. See CURLOPT_IOCTLFUNCTION(3). + +## CURLIOE_UNKNOWNCMD +Introduced in 7.12.3. See CURLOPT_IOCTLFUNCTION(3). + +## CURLKHMATCH_MISMATCH +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHMATCH_MISSING +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHMATCH_OK +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHSTAT_DEFER +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHSTAT_FINE +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHSTAT_FINE_ADD_TO_FILE +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHSTAT_FINE_REPLACE +Introduced in 7.73.0. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHSTAT_REJECT +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHTYPE_DSS +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHTYPE_ECDSA +Introduced in 7.58.0. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHTYPE_ED25519 +Introduced in 7.58.0. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHTYPE_RSA +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHTYPE_RSA1 +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLKHTYPE_UNKNOWN +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLM_ABORTED_BY_CALLBACK +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLM_ADDED_ALREADY +Introduced in 7.32.1. See libcurl-errors(3). + +## CURLM_BAD_EASY_HANDLE +Introduced in 7.9.6. See libcurl-errors(3). + +## CURLM_BAD_FUNCTION_ARGUMENT +Introduced in 7.69.0. See libcurl-errors(3). + +## CURLM_BAD_HANDLE +Introduced in 7.9.6. See libcurl-errors(3). + +## CURLM_BAD_SOCKET +Introduced in 7.15.4. See libcurl-errors(3). + +## CURLM_CALL_MULTI_PERFORM +Introduced in 7.9.6. See libcurl-errors(3). + +## CURLM_CALL_MULTI_SOCKET +Introduced in 7.15.5. See libcurl-errors(3). + +## CURLM_INTERNAL_ERROR +Introduced in 7.9.6. See libcurl-errors(3). + +## CURLM_OK +Introduced in 7.9.6. See libcurl-errors(3). + +## CURLM_OUT_OF_MEMORY +Introduced in 7.9.6. See libcurl-errors(3). + +## CURLM_RECURSIVE_API_CALL +Introduced in 7.59.0. See libcurl-errors(3). + +## CURLM_UNKNOWN_OPTION +Introduced in 7.15.4. See libcurl-errors(3). + +## CURLM_UNRECOVERABLE_POLL +Introduced in 7.84.0. See libcurl-errors(3). + +## CURLM_WAKEUP_FAILURE +Introduced in 7.68.0. See libcurl-errors(3). + +## CURLMIMEOPT_FORMESCAPE +Introduced in 7.81.0. See CURLOPT_MIME_OPTIONS(3). + +## CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE +Introduced in 7.30.0. See CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3). + +## CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE +Introduced in 7.30.0. See CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3). + +## CURLMOPT_MAX_CONCURRENT_STREAMS +Introduced in 7.67.0. See CURLMOPT_MAX_CONCURRENT_STREAMS(3). + +## CURLMOPT_MAX_HOST_CONNECTIONS +Introduced in 7.30.0. See CURLMOPT_MAX_HOST_CONNECTIONS(3). + +## CURLMOPT_MAX_PIPELINE_LENGTH +Introduced in 7.30.0. See CURLMOPT_MAX_PIPELINE_LENGTH(3). + +## CURLMOPT_MAX_TOTAL_CONNECTIONS +Introduced in 7.30.0. See CURLMOPT_MAX_TOTAL_CONNECTIONS(3). + +## CURLMOPT_MAXCONNECTS +Introduced in 7.16.3. See CURLMOPT_MAXCONNECTS(3). + +## CURLMOPT_PIPELINING +Introduced in 7.16.0. See CURLMOPT_PIPELINING(3). + +## CURLMOPT_PIPELINING_SERVER_BL +Introduced in 7.30.0. See CURLMOPT_PIPELINING_SERVER_BL(3). + +## CURLMOPT_PIPELINING_SITE_BL +Introduced in 7.30.0. See CURLMOPT_PIPELINING_SITE_BL(3). + +## CURLMOPT_PUSHDATA +Introduced in 7.44.0. See CURLMOPT_PUSHDATA(3). + +## CURLMOPT_PUSHFUNCTION +Introduced in 7.44.0. See CURLMOPT_PUSHFUNCTION(3). + +## CURLMOPT_SOCKETDATA +Introduced in 7.15.4. See CURLMOPT_SOCKETDATA(3). + +## CURLMOPT_SOCKETFUNCTION +Introduced in 7.15.4. See CURLMOPT_SOCKETFUNCTION(3). + +## CURLMOPT_TIMERDATA +Introduced in 7.16.0. See CURLMOPT_TIMERDATA(3). + +## CURLMOPT_TIMERFUNCTION +Introduced in 7.16.0. See CURLMOPT_TIMERFUNCTION(3). + +## CURLMSG_DONE +Introduced in 7.9.6. See curl_multi_info_read(3). + +## CURLMSG_NONE +Introduced in 7.9.6. See curl_multi_info_read(3). + +## CURLOPT +Introduced in 7.69.0. + +## CURLOPT_ABSTRACT_UNIX_SOCKET +Introduced in 7.53.0. See CURLOPT_ABSTRACT_UNIX_SOCKET(3). + +## CURLOPT_ACCEPT_ENCODING +Introduced in 7.21.6. See CURLOPT_ACCEPT_ENCODING(3). + +## CURLOPT_ACCEPTTIMEOUT_MS +Introduced in 7.24.0. See CURLOPT_ACCEPTTIMEOUT_MS(3). + +## CURLOPT_ADDRESS_SCOPE +Introduced in 7.19.0. See CURLOPT_ADDRESS_SCOPE(3). + +## CURLOPT_ALTSVC +Introduced in 7.64.1. See CURLOPT_ALTSVC(3). + +## CURLOPT_ALTSVC_CTRL +Introduced in 7.64.1. See CURLOPT_ALTSVC_CTRL(3). + +## CURLOPT_APPEND +Introduced in 7.17.0. See CURLOPT_APPEND(3). + +## CURLOPT_AUTOREFERER +Introduced in 7.1. See CURLOPT_AUTOREFERER(3). + +## CURLOPT_AWS_SIGV4 +Introduced in 7.75.0. See CURLOPT_AWS_SIGV4(3). + +## CURLOPT_BUFFERSIZE +Introduced in 7.10. See CURLOPT_BUFFERSIZE(3). + +## CURLOPT_CAINFO +Introduced in 7.4.2. See CURLOPT_CAINFO(3). + +## CURLOPT_CAINFO_BLOB +Introduced in 7.77.0. See CURLOPT_CAINFO_BLOB(3). + +## CURLOPT_CAPATH +Introduced in 7.9.8. See CURLOPT_CAPATH(3). + +## CURLOPT_CA_CACHE_TIMEOUT +Introduced in 7.87.0. See CURLOPT_CA_CACHE_TIMEOUT(3). + +## CURLOPT_CERTINFO +Introduced in 7.19.1. See CURLOPT_CERTINFO(3). + +## CURLOPT_CHUNK_BGN_FUNCTION +Introduced in 7.21.0. See CURLOPT_CHUNK_BGN_FUNCTION(3). + +## CURLOPT_CHUNK_DATA +Introduced in 7.21.0. See CURLOPT_CHUNK_DATA(3). + +## CURLOPT_CHUNK_END_FUNCTION +Introduced in 7.21.0. See CURLOPT_CHUNK_END_FUNCTION(3). + +## CURLOPT_CLOSEFUNCTION +Introduced in 7.7. Deprecated since 7.11.1. + +## CURLOPT_CLOSEPOLICY +Introduced in 7.7. Deprecated since 7.16.1. + +## CURLOPT_CLOSESOCKETDATA +Introduced in 7.21.7. See CURLOPT_CLOSESOCKETDATA(3). + +## CURLOPT_CLOSESOCKETFUNCTION +Introduced in 7.21.7. See CURLOPT_CLOSESOCKETFUNCTION(3). + +## CURLOPT_CONNECT_ONLY +Introduced in 7.15.2. See CURLOPT_CONNECT_ONLY(3). + +## CURLOPT_CONNECT_TO +Introduced in 7.49.0. See CURLOPT_CONNECT_TO(3). + +## CURLOPT_CONNECTTIMEOUT +Introduced in 7.7. See CURLOPT_CONNECTTIMEOUT(3). + +## CURLOPT_CONNECTTIMEOUT_MS +Introduced in 7.16.2. See CURLOPT_CONNECTTIMEOUT_MS(3). + +## CURLOPT_CONV_FROM_NETWORK_FUNCTION +Introduced in 7.15.4. Deprecated since 7.82.0. + +## CURLOPT_CONV_FROM_UTF8_FUNCTION +Introduced in 7.15.4. Deprecated since 7.82.0. + +## CURLOPT_CONV_TO_NETWORK_FUNCTION +Introduced in 7.15.4. Deprecated since 7.82.0. + +## CURLOPT_COOKIE +Introduced in 7.1. See CURLOPT_COOKIE(3). + +## CURLOPT_COOKIEFILE +Introduced in 7.1. See CURLOPT_COOKIEFILE(3). + +## CURLOPT_COOKIEJAR +Introduced in 7.9. See CURLOPT_COOKIEJAR(3). + +## CURLOPT_COOKIELIST +Introduced in 7.14.1. See CURLOPT_COOKIELIST(3). + +## CURLOPT_COOKIESESSION +Introduced in 7.9.7. See CURLOPT_COOKIESESSION(3). + +## CURLOPT_COPYPOSTFIELDS +Introduced in 7.17.1. See CURLOPT_COPYPOSTFIELDS(3). + +## CURLOPT_CRLF +Introduced in 7.1. See CURLOPT_CRLF(3). + +## CURLOPT_CRLFILE +Introduced in 7.19.0. See CURLOPT_CRLFILE(3). + +## CURLOPT_CURLU +Introduced in 7.63.0. See CURLOPT_CURLU(3). + +## CURLOPT_CUSTOMREQUEST +Introduced in 7.1. See CURLOPT_CUSTOMREQUEST(3). + +## CURLOPT_DEBUGDATA +Introduced in 7.9.6. See CURLOPT_DEBUGDATA(3). + +## CURLOPT_DEBUGFUNCTION +Introduced in 7.9.6. See CURLOPT_DEBUGFUNCTION(3). + +## CURLOPT_DEFAULT_PROTOCOL +Introduced in 7.45.0. See CURLOPT_DEFAULT_PROTOCOL(3). + +## CURLOPT_DIRLISTONLY +Introduced in 7.17.0. See CURLOPT_DIRLISTONLY(3). + +## CURLOPT_DISALLOW_USERNAME_IN_URL +Introduced in 7.61.0. See CURLOPT_DISALLOW_USERNAME_IN_URL(3). + +## CURLOPT_DNS_CACHE_TIMEOUT +Introduced in 7.9.3. See CURLOPT_DNS_CACHE_TIMEOUT(3). + +## CURLOPT_DNS_INTERFACE +Introduced in 7.33.0. See CURLOPT_DNS_INTERFACE(3). + +## CURLOPT_DNS_LOCAL_IP4 +Introduced in 7.33.0. See CURLOPT_DNS_LOCAL_IP4(3). + +## CURLOPT_DNS_LOCAL_IP6 +Introduced in 7.33.0. See CURLOPT_DNS_LOCAL_IP6(3). + +## CURLOPT_DNS_SERVERS +Introduced in 7.24.0. See CURLOPT_DNS_SERVERS(3). + +## CURLOPT_DNS_SHUFFLE_ADDRESSES +Introduced in 7.60.0. See CURLOPT_DNS_SHUFFLE_ADDRESSES(3). + +## CURLOPT_DNS_USE_GLOBAL_CACHE +Introduced in 7.9.3. Deprecated since 7.11.1. + +## CURLOPT_DOH_SSL_VERIFYHOST +Introduced in 7.76.0. See CURLOPT_DOH_SSL_VERIFYHOST(3). + +## CURLOPT_DOH_SSL_VERIFYPEER +Introduced in 7.76.0. See CURLOPT_DOH_SSL_VERIFYPEER(3). + +## CURLOPT_DOH_SSL_VERIFYSTATUS +Introduced in 7.76.0. See CURLOPT_DOH_SSL_VERIFYSTATUS(3). + +## CURLOPT_DOH_URL +Introduced in 7.62.0. See CURLOPT_DOH_URL(3). + +## CURLOPT_EGDSOCKET +Introduced in 7.7. Deprecated since 7.84.0. + +## CURLOPT_ENCODING +Introduced in 7.10. Deprecated since 7.21.6. + +## CURLOPT_ERRORBUFFER +Introduced in 7.1. See CURLOPT_ERRORBUFFER(3). + +## CURLOPT_EXPECT_100_TIMEOUT_MS +Introduced in 7.36.0. See CURLOPT_EXPECT_100_TIMEOUT_MS(3). + +## CURLOPT_FAILONERROR +Introduced in 7.1. See CURLOPT_FAILONERROR(3). + +## CURLOPT_FILE +Introduced in 7.1. Deprecated since 7.9.7. + +## CURLOPT_FILETIME +Introduced in 7.5. See CURLOPT_FILETIME(3). + +## CURLOPT_FNMATCH_DATA +Introduced in 7.21.0. See CURLOPT_FNMATCH_DATA(3). + +## CURLOPT_FNMATCH_FUNCTION +Introduced in 7.21.0. See CURLOPT_FNMATCH_FUNCTION(3). + +## CURLOPT_FOLLOWLOCATION +Introduced in 7.1. See CURLOPT_FOLLOWLOCATION(3). + +## CURLOPT_FORBID_REUSE +Introduced in 7.7. See CURLOPT_FORBID_REUSE(3). + +## CURLOPT_FRESH_CONNECT +Introduced in 7.7. See CURLOPT_FRESH_CONNECT(3). + +## CURLOPT_FTP_ACCOUNT +Introduced in 7.13.0. See CURLOPT_FTP_ACCOUNT(3). + +## CURLOPT_FTP_ALTERNATIVE_TO_USER +Introduced in 7.15.5. See CURLOPT_FTP_ALTERNATIVE_TO_USER(3). + +## CURLOPT_FTP_CREATE_MISSING_DIRS +Introduced in 7.10.7. See CURLOPT_FTP_CREATE_MISSING_DIRS(3). + +## CURLOPT_FTP_FILEMETHOD +Introduced in 7.15.1. See CURLOPT_FTP_FILEMETHOD(3). + +## CURLOPT_FTP_RESPONSE_TIMEOUT +Introduced in 7.10.8. Deprecated since 7.85.0. + +## CURLOPT_FTP_SKIP_PASV_IP +Introduced in 7.15.0. See CURLOPT_FTP_SKIP_PASV_IP(3). + +## CURLOPT_FTP_SSL +Introduced in 7.11.0. Deprecated since 7.16.4. + +## CURLOPT_FTP_SSL_CCC +Introduced in 7.16.1. See CURLOPT_FTP_SSL_CCC(3). + +## CURLOPT_FTP_USE_EPRT +Introduced in 7.10.5. See CURLOPT_FTP_USE_EPRT(3). + +## CURLOPT_FTP_USE_EPSV +Introduced in 7.9.2. See CURLOPT_FTP_USE_EPSV(3). + +## CURLOPT_FTP_USE_PRET +Introduced in 7.20.0. See CURLOPT_FTP_USE_PRET(3). + +## CURLOPT_FTPAPPEND +Introduced in 7.1. Deprecated since 7.16.4. + +## CURLOPT_FTPASCII +Introduced in 7.1. Deprecated since 7.11.1. + +## CURLOPT_FTPLISTONLY +Introduced in 7.1. Deprecated since 7.16.4. + +## CURLOPT_FTPPORT +Introduced in 7.1. See CURLOPT_FTPPORT(3). + +## CURLOPT_FTPSSLAUTH +Introduced in 7.12.2. See CURLOPT_FTPSSLAUTH(3). + +## CURLOPT_GSSAPI_DELEGATION +Introduced in 7.22.0. See CURLOPT_GSSAPI_DELEGATION(3). + +## CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS +Introduced in 7.59.0. See CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3). + +## CURLOPT_HAPROXYPROTOCOL +Introduced in 7.60.0. See CURLOPT_HAPROXYPROTOCOL(3). + +## CURLOPT_HAPROXY_CLIENT_IP +Introduced in 8.2.0. See CURLOPT_HAPROXY_CLIENT_IP(3). + +## CURLOPT_HEADER +Introduced in 7.1. See CURLOPT_HEADER(3). + +## CURLOPT_HEADERDATA +Introduced in 7.10. See CURLOPT_HEADERDATA(3). + +## CURLOPT_HEADERFUNCTION +Introduced in 7.7.2. See CURLOPT_HEADERFUNCTION(3). + +## CURLOPT_HEADEROPT +Introduced in 7.37.0. See CURLOPT_HEADEROPT(3). + +## CURLOPT_HSTS +Introduced in 7.74.0. See CURLOPT_HSTS(3). + +## CURLOPT_HSTS_CTRL +Introduced in 7.74.0. See CURLOPT_HSTS_CTRL(3). + +## CURLOPT_HSTSREADDATA +Introduced in 7.74.0. See CURLOPT_HSTSREADDATA(3). + +## CURLOPT_HSTSREADFUNCTION +Introduced in 7.74.0. See CURLOPT_HSTSREADFUNCTION(3). + +## CURLOPT_HSTSWRITEDATA +Introduced in 7.74.0. See CURLOPT_HSTSWRITEDATA(3). + +## CURLOPT_HSTSWRITEFUNCTION +Introduced in 7.74.0. See CURLOPT_HSTSWRITEFUNCTION(3). + +## CURLOPT_HTTP09_ALLOWED +Introduced in 7.64.0. See CURLOPT_HTTP09_ALLOWED(3). + +## CURLOPT_HTTP200ALIASES +Introduced in 7.10.3. See CURLOPT_HTTP200ALIASES(3). + +## CURLOPT_HTTP_CONTENT_DECODING +Introduced in 7.16.2. See CURLOPT_HTTP_CONTENT_DECODING(3). + +## CURLOPT_HTTP_TRANSFER_DECODING +Introduced in 7.16.2. See CURLOPT_HTTP_TRANSFER_DECODING(3). + +## CURLOPT_HTTP_VERSION +Introduced in 7.9.1. See CURLOPT_HTTP_VERSION(3). + +## CURLOPT_HTTPAUTH +Introduced in 7.10.6. See CURLOPT_HTTPAUTH(3). + +## CURLOPT_HTTPGET +Introduced in 7.8.1. See CURLOPT_HTTPGET(3). + +## CURLOPT_HTTPHEADER +Introduced in 7.1. See CURLOPT_HTTPHEADER(3). + +## CURLOPT_HTTPPOST +Introduced in 7.1. Deprecated since 7.56.0. + +## CURLOPT_HTTPPROXYTUNNEL +Introduced in 7.3. See CURLOPT_HTTPPROXYTUNNEL(3). + +## CURLOPT_HTTPREQUEST +Introduced in 7.1. Last used in 7.15.5. + +## CURLOPT_IGNORE_CONTENT_LENGTH +Introduced in 7.14.1. See CURLOPT_IGNORE_CONTENT_LENGTH(3). + +## CURLOPT_INFILE +Introduced in 7.1. Deprecated since 7.9.7. + +## CURLOPT_INFILESIZE +Introduced in 7.1. See CURLOPT_INFILESIZE(3). + +## CURLOPT_INFILESIZE_LARGE +Introduced in 7.11.0. See CURLOPT_INFILESIZE_LARGE(3). + +## CURLOPT_INTERFACE +Introduced in 7.3. See CURLOPT_INTERFACE(3). + +## CURLOPT_INTERLEAVEDATA +Introduced in 7.20.0. See CURLOPT_INTERLEAVEDATA(3). + +## CURLOPT_INTERLEAVEFUNCTION +Introduced in 7.20.0. See CURLOPT_INTERLEAVEFUNCTION(3). + +## CURLOPT_IOCTLDATA +Introduced in 7.12.3. Deprecated since 7.18.0. + +## CURLOPT_IOCTLFUNCTION +Introduced in 7.12.3. Deprecated since 7.18.0. + +## CURLOPT_IPRESOLVE +Introduced in 7.10.8. See CURLOPT_IPRESOLVE(3). + +## CURLOPT_ISSUERCERT +Introduced in 7.19.0. See CURLOPT_ISSUERCERT(3). + +## CURLOPT_ISSUERCERT_BLOB +Introduced in 7.71.0. See CURLOPT_ISSUERCERT_BLOB(3). + +## CURLOPT_KEEP_SENDING_ON_ERROR +Introduced in 7.51.0. See CURLOPT_KEEP_SENDING_ON_ERROR(3). + +## CURLOPT_KEYPASSWD +Introduced in 7.17.0. See CURLOPT_KEYPASSWD(3). + +## CURLOPT_KRB4LEVEL +Introduced in 7.3. Deprecated since 7.17.0. + +## CURLOPT_KRBLEVEL +Introduced in 7.16.4. See CURLOPT_KRBLEVEL(3). + +## CURLOPT_LOCALPORT +Introduced in 7.15.2. See CURLOPT_LOCALPORT(3). + +## CURLOPT_LOCALPORTRANGE +Introduced in 7.15.2. See CURLOPT_LOCALPORTRANGE(3). + +## CURLOPT_LOGIN_OPTIONS +Introduced in 7.34.0. See CURLOPT_LOGIN_OPTIONS(3). + +## CURLOPT_LOW_SPEED_LIMIT +Introduced in 7.1. See CURLOPT_LOW_SPEED_LIMIT(3). + +## CURLOPT_LOW_SPEED_TIME +Introduced in 7.1. See CURLOPT_LOW_SPEED_TIME(3). + +## CURLOPT_MAIL_AUTH +Introduced in 7.25.0. See CURLOPT_MAIL_AUTH(3). + +## CURLOPT_MAIL_FROM +Introduced in 7.20.0. See CURLOPT_MAIL_FROM(3). + +## CURLOPT_MAIL_RCPT +Introduced in 7.20.0. See CURLOPT_MAIL_RCPT(3). + +## CURLOPT_MAIL_RCPT_ALLLOWFAILS +Introduced in 7.69.0. Deprecated since 8.2.0. + +## CURLOPT_MAIL_RCPT_ALLOWFAILS +Introduced in 8.2.0. See CURLOPT_MAIL_RCPT_ALLOWFAILS(3). + +## CURLOPT_QUICK_EXIT +Introduced in 7.87.0. See CURLOPT_QUICK_EXIT(3). + +## CURLOPT_MAX_RECV_SPEED_LARGE +Introduced in 7.15.5. See CURLOPT_MAX_RECV_SPEED_LARGE(3). + +## CURLOPT_MAX_SEND_SPEED_LARGE +Introduced in 7.15.5. See CURLOPT_MAX_SEND_SPEED_LARGE(3). + +## CURLOPT_MAXAGE_CONN +Introduced in 7.65.0. See CURLOPT_MAXAGE_CONN(3). + +## CURLOPT_MAXCONNECTS +Introduced in 7.7. See CURLOPT_MAXCONNECTS(3). + +## CURLOPT_MAXFILESIZE +Introduced in 7.10.8. See CURLOPT_MAXFILESIZE(3). + +## CURLOPT_MAXFILESIZE_LARGE +Introduced in 7.11.0. See CURLOPT_MAXFILESIZE_LARGE(3). + +## CURLOPT_MAXLIFETIME_CONN +Introduced in 7.80.0. See CURLOPT_MAXLIFETIME_CONN(3). + +## CURLOPT_MAXREDIRS +Introduced in 7.5. See CURLOPT_MAXREDIRS(3). + +## CURLOPT_MIME_OPTIONS +Introduced in 7.81.0. See CURLOPT_MIME_OPTIONS(3). + +## CURLOPT_MIMEPOST +Introduced in 7.56.0. See CURLOPT_MIMEPOST(3). + +## CURLOPT_MUTE +Introduced in 7.1. Deprecated since 7.8. + +## CURLOPT_NETRC +Introduced in 7.1. See CURLOPT_NETRC(3). + +## CURLOPT_NETRC_FILE +Introduced in 7.11.0. See CURLOPT_NETRC_FILE(3). + +## CURLOPT_NEW_DIRECTORY_PERMS +Introduced in 7.16.4. See CURLOPT_NEW_DIRECTORY_PERMS(3). + +## CURLOPT_NEW_FILE_PERMS +Introduced in 7.16.4. See CURLOPT_NEW_FILE_PERMS(3). + +## CURLOPT_NOBODY +Introduced in 7.1. See CURLOPT_NOBODY(3). + +## CURLOPT_NOPROGRESS +Introduced in 7.1. See CURLOPT_NOPROGRESS(3). + +## CURLOPT_NOPROXY +Introduced in 7.19.4. See CURLOPT_NOPROXY(3). + +## CURLOPT_NOSIGNAL +Introduced in 7.10. See CURLOPT_NOSIGNAL(3). + +## CURLOPT_NOTHING +Introduced in 7.1.1. Deprecated since 7.11.1. + +## CURLOPT_OPENSOCKETDATA +Introduced in 7.17.1. See CURLOPT_OPENSOCKETDATA(3). + +## CURLOPT_OPENSOCKETFUNCTION +Introduced in 7.17.1. See CURLOPT_OPENSOCKETFUNCTION(3). + +## CURLOPT_PASSWDDATA +Introduced in 7.4.2. Deprecated since 7.11.1. + +## CURLOPT_PASSWDFUNCTION +Introduced in 7.4.2. Deprecated since 7.11.1. + +## CURLOPT_PASSWORD +Introduced in 7.19.1. See CURLOPT_PASSWORD(3). + +## CURLOPT_PASV_HOST +Introduced in 7.12.1. Deprecated since 7.16.0. + +## CURLOPT_PATH_AS_IS +Introduced in 7.42.0. See CURLOPT_PATH_AS_IS(3). + +## CURLOPT_PINNEDPUBLICKEY +Introduced in 7.39.0. See CURLOPT_PINNEDPUBLICKEY(3). + +## CURLOPT_PIPEWAIT +Introduced in 7.43.0. See CURLOPT_PIPEWAIT(3). + +## CURLOPT_PORT +Introduced in 7.1. See CURLOPT_PORT(3). + +## CURLOPT_POST +Introduced in 7.1. See CURLOPT_POST(3). + +## CURLOPT_POST301 +Introduced in 7.17.1. Deprecated since 7.19.1. + +## CURLOPT_POSTFIELDS +Introduced in 7.1. See CURLOPT_POSTFIELDS(3). + +## CURLOPT_POSTFIELDSIZE +Introduced in 7.2. See CURLOPT_POSTFIELDSIZE(3). + +## CURLOPT_POSTFIELDSIZE_LARGE +Introduced in 7.11.1. See CURLOPT_POSTFIELDSIZE_LARGE(3). + +## CURLOPT_POSTQUOTE +Introduced in 7.1. See CURLOPT_POSTQUOTE(3). + +## CURLOPT_POSTREDIR +Introduced in 7.19.1. See CURLOPT_POSTREDIR(3). + +## CURLOPT_PRE_PROXY +Introduced in 7.52.0. See CURLOPT_PRE_PROXY(3). + +## CURLOPT_PREQUOTE +Introduced in 7.9.5. See CURLOPT_PREQUOTE(3). + +## CURLOPT_PREREQDATA +Introduced in 7.80.0. See CURLOPT_PREREQDATA(3). + +## CURLOPT_PREREQFUNCTION +Introduced in 7.80.0. See CURLOPT_PREREQFUNCTION(3). + +## CURLOPT_PRIVATE +Introduced in 7.10.3. See CURLOPT_PRIVATE(3). + +## CURLOPT_PROGRESSDATA +Introduced in 7.1. See CURLOPT_PROGRESSDATA(3). + +## CURLOPT_PROGRESSFUNCTION +Introduced in 7.1. Deprecated since 7.32.0. + +## CURLOPT_PROTOCOLS +Introduced in 7.19.4. Deprecated since 7.85.0. + +## CURLOPT_PROTOCOLS_STR +Introduced in 7.85.0. See CURLOPT_PROTOCOLS_STR(3). + +## CURLOPT_PROXY +Introduced in 7.1. See CURLOPT_PROXY(3). + +## CURLOPT_PROXY_CAINFO +Introduced in 7.52.0. See CURLOPT_PROXY_CAINFO(3). + +## CURLOPT_PROXY_CAINFO_BLOB +Introduced in 7.77.0. See CURLOPT_PROXY_CAINFO_BLOB(3). + +## CURLOPT_PROXY_CAPATH +Introduced in 7.52.0. See CURLOPT_PROXY_CAPATH(3). + +## CURLOPT_PROXY_CRLFILE +Introduced in 7.52.0. See CURLOPT_PROXY_CRLFILE(3). + +## CURLOPT_PROXY_ISSUERCERT +Introduced in 7.71.0. See CURLOPT_PROXY_ISSUERCERT(3). + +## CURLOPT_PROXY_ISSUERCERT_BLOB +Introduced in 7.71.0. See CURLOPT_PROXY_ISSUERCERT_BLOB(3). + +## CURLOPT_PROXY_KEYPASSWD +Introduced in 7.52.0. See CURLOPT_PROXY_KEYPASSWD(3). + +## CURLOPT_PROXY_PINNEDPUBLICKEY +Introduced in 7.52.0. See CURLOPT_PROXY_PINNEDPUBLICKEY(3). + +## CURLOPT_PROXY_SERVICE_NAME +Introduced in 7.43.0. See CURLOPT_PROXY_SERVICE_NAME(3). + +## CURLOPT_PROXY_SSL_CIPHER_LIST +Introduced in 7.52.0. See CURLOPT_PROXY_SSL_CIPHER_LIST(3). + +## CURLOPT_PROXY_SSL_OPTIONS +Introduced in 7.52.0. See CURLOPT_PROXY_SSL_OPTIONS(3). + +## CURLOPT_PROXY_SSL_VERIFYHOST +Introduced in 7.52.0. See CURLOPT_PROXY_SSL_VERIFYHOST(3). + +## CURLOPT_PROXY_SSL_VERIFYPEER +Introduced in 7.52.0. See CURLOPT_PROXY_SSL_VERIFYPEER(3). + +## CURLOPT_PROXY_SSLCERT +Introduced in 7.52.0. See CURLOPT_PROXY_SSLCERT(3). + +## CURLOPT_PROXY_SSLCERT_BLOB +Introduced in 7.71.0. See CURLOPT_PROXY_SSLCERT_BLOB(3). + +## CURLOPT_PROXY_SSLCERTTYPE +Introduced in 7.52.0. See CURLOPT_PROXY_SSLCERTTYPE(3). + +## CURLOPT_PROXY_SSLKEY +Introduced in 7.52.0. See CURLOPT_PROXY_SSLKEY(3). + +## CURLOPT_PROXY_SSLKEY_BLOB +Introduced in 7.71.0. See CURLOPT_PROXY_SSLKEY_BLOB(3). + +## CURLOPT_PROXY_SSLKEYTYPE +Introduced in 7.52.0. See CURLOPT_PROXY_SSLKEYTYPE(3). + +## CURLOPT_PROXY_SSLVERSION +Introduced in 7.52.0. See CURLOPT_PROXY_SSLVERSION(3). + +## CURLOPT_PROXY_TLS13_CIPHERS +Introduced in 7.61.0. See CURLOPT_PROXY_TLS13_CIPHERS(3). + +## CURLOPT_PROXY_TLSAUTH_PASSWORD +Introduced in 7.52.0. See CURLOPT_PROXY_TLSAUTH_PASSWORD(3). + +## CURLOPT_PROXY_TLSAUTH_TYPE +Introduced in 7.52.0. See CURLOPT_PROXY_TLSAUTH_TYPE(3). + +## CURLOPT_PROXY_TLSAUTH_USERNAME +Introduced in 7.52.0. See CURLOPT_PROXY_TLSAUTH_USERNAME(3). + +## CURLOPT_PROXY_TRANSFER_MODE +Introduced in 7.18.0. See CURLOPT_PROXY_TRANSFER_MODE(3). + +## CURLOPT_PROXYAUTH +Introduced in 7.10.7. See CURLOPT_PROXYAUTH(3). + +## CURLOPT_PROXYHEADER +Introduced in 7.37.0. See CURLOPT_PROXYHEADER(3). + +## CURLOPT_PROXYPASSWORD +Introduced in 7.19.1. See CURLOPT_PROXYPASSWORD(3). + +## CURLOPT_PROXYPORT +Introduced in 7.1. See CURLOPT_PROXYPORT(3). + +## CURLOPT_PROXYTYPE +Introduced in 7.10. See CURLOPT_PROXYTYPE(3). + +## CURLOPT_PROXYUSERNAME +Introduced in 7.19.1. See CURLOPT_PROXYUSERNAME(3). + +## CURLOPT_PROXYUSERPWD +Introduced in 7.1. See CURLOPT_PROXYUSERPWD(3). + +## CURLOPT_PUT +Introduced in 7.1. Deprecated since 7.12.1. + +## CURLOPT_QUOTE +Introduced in 7.1. See CURLOPT_QUOTE(3). + +## CURLOPT_RANDOM_FILE +Introduced in 7.7. Deprecated since 7.84.0. + +## CURLOPT_RANGE +Introduced in 7.1. See CURLOPT_RANGE(3). + +## CURLOPT_READDATA +Introduced in 7.9.7. See CURLOPT_READDATA(3). + +## CURLOPT_READFUNCTION +Introduced in 7.1. See CURLOPT_READFUNCTION(3). + +## CURLOPT_REDIR_PROTOCOLS +Introduced in 7.19.4. Deprecated since 7.85.0. + +## CURLOPT_REDIR_PROTOCOLS_STR +Introduced in 7.85.0. See CURLOPT_REDIR_PROTOCOLS_STR(3). + +## CURLOPT_REFERER +Introduced in 7.1. See CURLOPT_REFERER(3). + +## CURLOPT_REQUEST_TARGET +Introduced in 7.55.0. See CURLOPT_REQUEST_TARGET(3). + +## CURLOPT_RESOLVE +Introduced in 7.21.3. See CURLOPT_RESOLVE(3). + +## CURLOPT_RESOLVER_START_DATA +Introduced in 7.59.0. See CURLOPT_RESOLVER_START_DATA(3). + +## CURLOPT_RESOLVER_START_FUNCTION +Introduced in 7.59.0. See CURLOPT_RESOLVER_START_FUNCTION(3). + +## CURLOPT_RESUME_FROM +Introduced in 7.1. See CURLOPT_RESUME_FROM(3). + +## CURLOPT_RESUME_FROM_LARGE +Introduced in 7.11.0. See CURLOPT_RESUME_FROM_LARGE(3). + +## CURLOPT_RTSP_CLIENT_CSEQ +Introduced in 7.20.0. See CURLOPT_RTSP_CLIENT_CSEQ(3). + +## CURLOPT_RTSP_REQUEST +Introduced in 7.20.0. See CURLOPT_RTSP_REQUEST(3). + +## CURLOPT_RTSP_SERVER_CSEQ +Introduced in 7.20.0. See CURLOPT_RTSP_SERVER_CSEQ(3). + +## CURLOPT_RTSP_SESSION_ID +Introduced in 7.20.0. See CURLOPT_RTSP_SESSION_ID(3). + +## CURLOPT_RTSP_STREAM_URI +Introduced in 7.20.0. See CURLOPT_RTSP_STREAM_URI(3). + +## CURLOPT_RTSP_TRANSPORT +Introduced in 7.20.0. See CURLOPT_RTSP_TRANSPORT(3). + +## CURLOPT_RTSPHEADER +Introduced in 7.20.0. See CURLOPT_HTTPHEADER. + +## CURLOPT_SASL_AUTHZID +Introduced in 7.66.0. See CURLOPT_SASL_AUTHZID(3). + +## CURLOPT_SASL_IR +Introduced in 7.31.0. See CURLOPT_SASL_IR(3). + +## CURLOPT_SEEKDATA +Introduced in 7.18.0. See CURLOPT_SEEKDATA(3). + +## CURLOPT_SEEKFUNCTION +Introduced in 7.18.0. See CURLOPT_SEEKFUNCTION(3). + +## CURLOPT_SERVER_RESPONSE_TIMEOUT +Introduced in 7.20.0. See CURLOPT_SERVER_RESPONSE_TIMEOUT(3). + +## CURLOPT_SERVER_RESPONSE_TIMEOUT_MS +Introduced in 8.6.0. See CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3). + +## CURLOPT_SERVICE_NAME +Introduced in 7.43.0. See CURLOPT_SERVICE_NAME(3). + +## CURLOPT_SHARE +Introduced in 7.10. See CURLOPT_SHARE(3). + +## CURLOPT_SOCKOPTDATA +Introduced in 7.16.0. See CURLOPT_SOCKOPTDATA(3). + +## CURLOPT_SOCKOPTFUNCTION +Introduced in 7.16.0. See CURLOPT_SOCKOPTFUNCTION(3). + +## CURLOPT_SOCKS5_AUTH +Introduced in 7.55.0. See CURLOPT_SOCKS5_AUTH(3). + +## CURLOPT_SOCKS5_GSSAPI_NEC +Introduced in 7.19.4. See CURLOPT_SOCKS5_GSSAPI_NEC(3). + +## CURLOPT_SOCKS5_GSSAPI_SERVICE +Introduced in 7.19.4. Deprecated since 7.49.0. + +## CURLOPT_SOURCE_HOST +Introduced in 7.12.1. Last used in 7.15.5. + +## CURLOPT_SOURCE_PATH +Introduced in 7.12.1. Last used in 7.15.5. + +## CURLOPT_SOURCE_PORT +Introduced in 7.12.1. Last used in 7.15.5. + +## CURLOPT_SOURCE_POSTQUOTE +Introduced in 7.12.1. Last used in 7.15.5. + +## CURLOPT_SOURCE_PREQUOTE +Introduced in 7.12.1. Last used in 7.15.5. + +## CURLOPT_SOURCE_QUOTE +Introduced in 7.13.0. Last used in 7.15.5. + +## CURLOPT_SOURCE_URL +Introduced in 7.13.0. Last used in 7.15.5. + +## CURLOPT_SOURCE_USERPWD +Introduced in 7.12.1. Last used in 7.15.5. + +## CURLOPT_SSH_AUTH_TYPES +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLOPT_SSH_COMPRESSION +Introduced in 7.56.0. See CURLOPT_SSH_COMPRESSION(3). + +## CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 +Introduced in 7.17.1. See CURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3). + +## CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 +Introduced in 7.80.0. See CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3). + +## CURLOPT_SSH_HOSTKEYDATA +Introduced in 7.84.0. See CURLOPT_SSH_HOSTKEYDATA(3). + +## CURLOPT_SSH_HOSTKEYFUNCTION +Introduced in 7.84.0. See CURLOPT_SSH_HOSTKEYFUNCTION(3). + +## CURLOPT_SSH_KEYDATA +Introduced in 7.19.6. See CURLOPT_SSH_KEYDATA(3). + +## CURLOPT_SSH_KEYFUNCTION +Introduced in 7.19.6. See CURLOPT_SSH_KEYFUNCTION(3). + +## CURLOPT_SSH_KNOWNHOSTS +Introduced in 7.19.6. See CURLOPT_SSH_KNOWNHOSTS(3). + +## CURLOPT_SSH_PRIVATE_KEYFILE +Introduced in 7.16.1. See CURLOPT_SSH_PRIVATE_KEYFILE(3). + +## CURLOPT_SSH_PUBLIC_KEYFILE +Introduced in 7.16.1. See CURLOPT_SSH_PUBLIC_KEYFILE(3). + +## CURLOPT_SSL_CIPHER_LIST +Introduced in 7.9. See CURLOPT_SSL_CIPHER_LIST(3). + +## CURLOPT_SSL_CTX_DATA +Introduced in 7.10.6. See CURLOPT_SSL_CTX_DATA(3). + +## CURLOPT_SSL_CTX_FUNCTION +Introduced in 7.10.6. See CURLOPT_SSL_CTX_FUNCTION(3). + +## CURLOPT_SSL_EC_CURVES +Introduced in 7.73.0. See CURLOPT_SSL_EC_CURVES(3). + +## CURLOPT_SSL_ENABLE_ALPN +Introduced in 7.36.0. See CURLOPT_SSL_ENABLE_ALPN(3). + +## CURLOPT_SSL_ENABLE_NPN +Introduced in 7.36.0. Deprecated since 7.86.0. + +## CURLOPT_SSL_FALSESTART +Introduced in 7.42.0. See CURLOPT_SSL_FALSESTART(3). + +## CURLOPT_SSL_OPTIONS +Introduced in 7.25.0. See CURLOPT_SSL_OPTIONS(3). + +## CURLOPT_SSL_SESSIONID_CACHE +Introduced in 7.16.0. See CURLOPT_SSL_SESSIONID_CACHE(3). + +## CURLOPT_SSL_VERIFYHOST +Introduced in 7.8.1. See CURLOPT_SSL_VERIFYHOST(3). + +## CURLOPT_SSL_VERIFYPEER +Introduced in 7.4.2. See CURLOPT_SSL_VERIFYPEER(3). + +## CURLOPT_SSL_VERIFYSTATUS +Introduced in 7.41.0. See CURLOPT_SSL_VERIFYSTATUS(3). + +## CURLOPT_SSLCERT +Introduced in 7.1. See CURLOPT_SSLCERT(3). + +## CURLOPT_SSLCERT_BLOB +Introduced in 7.71.0. See CURLOPT_SSLCERT_BLOB(3). + +## CURLOPT_SSLCERTPASSWD +Introduced in 7.1.1. Deprecated since 7.17.0. + +## CURLOPT_SSLCERTTYPE +Introduced in 7.9.3. See CURLOPT_SSLCERTTYPE(3). + +## CURLOPT_SSLENGINE +Introduced in 7.9.3. See CURLOPT_SSLENGINE(3). + +## CURLOPT_SSLENGINE_DEFAULT +Introduced in 7.9.3. See CURLOPT_SSLENGINE_DEFAULT(3). + +## CURLOPT_SSLKEY +Introduced in 7.9.3. See CURLOPT_SSLKEY(3). + +## CURLOPT_SSLKEY_BLOB +Introduced in 7.71.0. See CURLOPT_SSLKEY_BLOB(3). + +## CURLOPT_SSLKEYPASSWD +Introduced in 7.9.3. Deprecated since 7.17.0. + +## CURLOPT_SSLKEYTYPE +Introduced in 7.9.3. See CURLOPT_SSLKEYTYPE(3). + +## CURLOPT_SSLVERSION +Introduced in 7.1. See CURLOPT_SSLVERSION(3). + +## CURLOPT_STDERR +Introduced in 7.1. See CURLOPT_STDERR(3). + +## CURLOPT_STREAM_DEPENDS +Introduced in 7.46.0. See CURLOPT_STREAM_DEPENDS(3). + +## CURLOPT_STREAM_DEPENDS_E +Introduced in 7.46.0. See CURLOPT_STREAM_DEPENDS_E(3). + +## CURLOPT_STREAM_WEIGHT +Introduced in 7.46.0. See CURLOPT_STREAM_WEIGHT(3). + +## CURLOPT_SUPPRESS_CONNECT_HEADERS +Introduced in 7.54.0. See CURLOPT_SUPPRESS_CONNECT_HEADERS(3). + +## CURLOPT_TCP_FASTOPEN +Introduced in 7.49.0. See CURLOPT_TCP_FASTOPEN(3). + +## CURLOPT_TCP_KEEPALIVE +Introduced in 7.25.0. See CURLOPT_TCP_KEEPALIVE(3). + +## CURLOPT_TCP_KEEPIDLE +Introduced in 7.25.0. See CURLOPT_TCP_KEEPIDLE(3). + +## CURLOPT_TCP_KEEPINTVL +Introduced in 7.25.0. See CURLOPT_TCP_KEEPINTVL(3). + +## CURLOPT_TCP_NODELAY +Introduced in 7.11.2. See CURLOPT_TCP_NODELAY(3). + +## CURLOPT_TELNETOPTIONS +Introduced in 7.7. See CURLOPT_TELNETOPTIONS(3). + +## CURLOPT_TFTP_BLKSIZE +Introduced in 7.19.4. See CURLOPT_TFTP_BLKSIZE(3). + +## CURLOPT_TFTP_NO_OPTIONS +Introduced in 7.48.0. See CURLOPT_TFTP_NO_OPTIONS(3). + +## CURLOPT_TIMECONDITION +Introduced in 7.1. See CURLOPT_TIMECONDITION(3). + +## CURLOPT_TIMEOUT +Introduced in 7.1. See CURLOPT_TIMEOUT(3). + +## CURLOPT_TIMEOUT_MS +Introduced in 7.16.2. See CURLOPT_TIMEOUT_MS(3). + +## CURLOPT_TIMEVALUE +Introduced in 7.1. See CURLOPT_TIMEVALUE(3). + +## CURLOPT_TIMEVALUE_LARGE +Introduced in 7.59.0. See CURLOPT_TIMEVALUE_LARGE(3). + +## CURLOPT_TLS13_CIPHERS +Introduced in 7.61.0. See CURLOPT_TLS13_CIPHERS(3). + +## CURLOPT_TLSAUTH_PASSWORD +Introduced in 7.21.4. See CURLOPT_TLSAUTH_PASSWORD(3). + +## CURLOPT_TLSAUTH_TYPE +Introduced in 7.21.4. See CURLOPT_TLSAUTH_TYPE(3). + +## CURLOPT_TLSAUTH_USERNAME +Introduced in 7.21.4. See CURLOPT_TLSAUTH_USERNAME(3). + +## CURLOPT_TRAILERDATA +Introduced in 7.64.0. See CURLOPT_TRAILERDATA(3). + +## CURLOPT_TRAILERFUNCTION +Introduced in 7.64.0. See CURLOPT_TRAILERFUNCTION(3). + +## CURLOPT_TRANSFER_ENCODING +Introduced in 7.21.6. See CURLOPT_TRANSFER_ENCODING(3). + +## CURLOPT_TRANSFERTEXT +Introduced in 7.1.1. See CURLOPT_TRANSFERTEXT(3). + +## CURLOPT_UNIX_SOCKET_PATH +Introduced in 7.40.0. See CURLOPT_UNIX_SOCKET_PATH(3). + +## CURLOPT_UNRESTRICTED_AUTH +Introduced in 7.10.4. See CURLOPT_UNRESTRICTED_AUTH(3). + +## CURLOPT_UPKEEP_INTERVAL_MS +Introduced in 7.62.0. See CURLOPT_UPKEEP_INTERVAL_MS(3). + +## CURLOPT_UPLOAD +Introduced in 7.1. See CURLOPT_UPLOAD(3). + +## CURLOPT_UPLOAD_BUFFERSIZE +Introduced in 7.62.0. See CURLOPT_UPLOAD_BUFFERSIZE(3). + +## CURLOPT_URL +Introduced in 7.1. See CURLOPT_URL(3). + +## CURLOPT_USE_SSL +Introduced in 7.17.0. See CURLOPT_USE_SSL(3). + +## CURLOPT_USERAGENT +Introduced in 7.1. See CURLOPT_USERAGENT(3). + +## CURLOPT_USERNAME +Introduced in 7.19.1. See CURLOPT_USERNAME(3). + +## CURLOPT_USERPWD +Introduced in 7.1. See CURLOPT_USERPWD(3). + +## CURLOPT_VERBOSE +Introduced in 7.1. See CURLOPT_VERBOSE(3). + +## CURLOPT_WILDCARDMATCH +Introduced in 7.21.0. See CURLOPT_WILDCARDMATCH(3). + +## CURLOPT_WRITEDATA +Introduced in 7.9.7. See CURLOPT_WRITEDATA(3). + +## CURLOPT_WRITEFUNCTION +Introduced in 7.1. See CURLOPT_WRITEFUNCTION(3). + +## CURLOPT_WRITEHEADER +Introduced in 7.1. See CURLOPT_HEADERDATA. + +## CURLOPT_WRITEINFO +Introduced in 7.1. + +## CURLOPT_WS_OPTIONS +Introduced in 7.86.0. See CURLOPT_WS_OPTIONS(3). + +## CURLOPT_XFERINFODATA +Introduced in 7.32.0. See CURLOPT_XFERINFODATA(3). + +## CURLOPT_XFERINFOFUNCTION +Introduced in 7.32.0. See CURLOPT_XFERINFOFUNCTION(3). + +## CURLOPT_XOAUTH2_BEARER +Introduced in 7.33.0. See CURLOPT_XOAUTH2_BEARER(3). + +## CURLOPTDEPRECATED +Introduced in 7.87.0. + +## CURLOPTTYPE_BLOB +Introduced in 7.71.0. + +## CURLOPTTYPE_CBPOINT +Introduced in 7.73.0. + +## CURLOPTTYPE_FUNCTIONPOINT +Introduced in 7.1. + +## CURLOPTTYPE_LONG +Introduced in 7.1. + +## CURLOPTTYPE_OBJECTPOINT +Introduced in 7.1. + +## CURLOPTTYPE_OFF_T +Introduced in 7.11.0. + +## CURLOPTTYPE_SLISTPOINT +Introduced in 7.65.2. + +## CURLOPTTYPE_STRINGPOINT +Introduced in 7.46.0. + +## CURLOPTTYPE_VALUES +Introduced in 7.73.0. + +## CURLOT_BLOB +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_CBPTR +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_FLAG_ALIAS +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_FUNCTION +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_LONG +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_OBJECT +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_OFF_T +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_SLIST +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_STRING +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLOT_VALUES +Introduced in 7.73.0. See curl_easy_option_next(3). + +## CURLPAUSE_ALL +Introduced in 7.18.0. See curl_easy_pause(3). + +## CURLPAUSE_CONT +Introduced in 7.18.0. See curl_easy_pause(3). + +## CURLPAUSE_RECV +Introduced in 7.18.0. See curl_easy_pause(3). + +## CURLPAUSE_RECV_CONT +Introduced in 7.18.0. See curl_easy_pause(3). + +## CURLPAUSE_SEND +Introduced in 7.18.0. See curl_easy_pause(3). + +## CURLPAUSE_SEND_CONT +Introduced in 7.18.0. See curl_easy_pause(3). + +## CURLPIPE_HTTP1 +Introduced in 7.43.0. See CURLMOPT_PIPELINING(3). + +## CURLPIPE_MULTIPLEX +Introduced in 7.43.0. See CURLMOPT_PIPELINING(3). + +## CURLPIPE_NOTHING +Introduced in 7.43.0. See CURLMOPT_PIPELINING(3). + +## CURLPROTO_ALL +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_DICT +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_FILE +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_FTP +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_FTPS +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_GOPHER +Introduced in 7.21.2. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_GOPHERS +Introduced in 7.75.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_HTTP +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_HTTPS +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_IMAP +Introduced in 7.20.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_IMAPS +Introduced in 7.20.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_LDAP +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_LDAPS +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_MQTT +Introduced in 7.71.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_POP3 +Introduced in 7.20.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_POP3S +Introduced in 7.20.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_RTMP +Introduced in 7.21.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_RTMPE +Introduced in 7.21.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_RTMPS +Introduced in 7.21.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_RTMPT +Introduced in 7.21.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_RTMPTE +Introduced in 7.21.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_RTMPTS +Introduced in 7.21.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_RTSP +Introduced in 7.20.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_SCP +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_SFTP +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_SMB +Introduced in 7.40.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_SMBS +Introduced in 7.40.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_SMTP +Introduced in 7.20.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_SMTPS +Introduced in 7.20.0. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_TELNET +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROTO_TFTP +Introduced in 7.19.4. See CURLINFO_PROTOCOL(3). + +## CURLPROXY_HTTP +Introduced in 7.10. See CURLOPT_PROXYTYPE(3). + +## CURLPROXY_HTTP_1_0 +Introduced in 7.19.4. See CURLOPT_PROXYTYPE(3). + +## CURLPROXY_HTTPS +Introduced in 7.52.0. See CURLOPT_PROXYTYPE(3). + +## CURLPROXY_HTTPS2 +Introduced in 8.1.0. See CURLOPT_PROXYTYPE(3). + +## CURLPROXY_SOCKS4 +Introduced in 7.10. See CURLOPT_PROXYTYPE(3). + +## CURLPROXY_SOCKS4A +Introduced in 7.18.0. See CURLOPT_PROXYTYPE(3). + +## CURLPROXY_SOCKS5 +Introduced in 7.10. See CURLOPT_PROXYTYPE(3). + +## CURLPROXY_SOCKS5_HOSTNAME +Introduced in 7.18.0. See CURLOPT_PROXYTYPE(3). + +## CURLPX_BAD_ADDRESS_TYPE +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_BAD_VERSION +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_CLOSED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_GSSAPI +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_GSSAPI_PERMSG +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_GSSAPI_PROTECTION +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_IDENTD +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_IDENTD_DIFFER +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_LONG_HOSTNAME +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_LONG_PASSWD +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_LONG_USER +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_NO_AUTH +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_OK +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_RECV_ADDRESS +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_RECV_AUTH +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_RECV_CONNECT +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_RECV_REQACK +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_COMMAND_NOT_SUPPORTED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_CONNECTION_REFUSED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_GENERAL_SERVER_FAILURE +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_HOST_UNREACHABLE +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_NETWORK_UNREACHABLE +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_NOT_ALLOWED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_TTL_EXPIRED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REPLY_UNASSIGNED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_REQUEST_FAILED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_RESOLVE_HOST +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_SEND_AUTH +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_SEND_CONNECT +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_SEND_REQUEST +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_UNKNOWN_FAIL +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_UNKNOWN_MODE +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLPX_USER_REJECTED +Introduced in 7.73.0. See CURLINFO_PROXY_ERROR(3). + +## CURLSHE_BAD_OPTION +Introduced in 7.10.3. See libcurl-errors(3). + +## CURLSHE_IN_USE +Introduced in 7.10.3. See libcurl-errors(3). + +## CURLSHE_INVALID +Introduced in 7.10.3. See libcurl-errors(3). + +## CURLSHE_NOMEM +Introduced in 7.12.0. See libcurl-errors(3). + +## CURLSHE_NOT_BUILT_IN +Introduced in 7.23.0. See libcurl-errors(3). + +## CURLSHE_OK +Introduced in 7.10.3. See libcurl-errors(3). + +## CURLSHOPT_LOCKFUNC +Introduced in 7.10.3. See CURLSHOPT_LOCKFUNC(3). + +## CURLSHOPT_NONE +Introduced in 7.10.3. See curl_share_setopt(3). + +## CURLSHOPT_SHARE +Introduced in 7.10.3. See CURLSHOPT_SHARE(3). + +## CURLSHOPT_UNLOCKFUNC +Introduced in 7.10.3. See CURLSHOPT_UNLOCKFUNC(3). + +## CURLSHOPT_UNSHARE +Introduced in 7.10.3. See CURLSHOPT_UNSHARE(3). + +## CURLSHOPT_USERDATA +Introduced in 7.10.3. See CURLSHOPT_USERDATA(3). + +## CURLSOCKTYPE_ACCEPT +Introduced in 7.28.0. See CURLOPT_SOCKOPTFUNCTION(3). + +## CURLSOCKTYPE_IPCXN +Introduced in 7.16.0. See CURLOPT_SOCKOPTFUNCTION(3). + +## CURLSSH_AUTH_AGENT +Introduced in 7.28.0. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_ANY +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_DEFAULT +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_GSSAPI +Introduced in 7.58.0. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_HOST +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_KEYBOARD +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_NONE +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_PASSWORD +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSH_AUTH_PUBLICKEY +Introduced in 7.16.1. See CURLOPT_SSH_AUTH_TYPES(3). + +## CURLSSLBACKEND_AWSLC +Introduced in 8.1.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_AXTLS +Introduced in 7.38.0. Deprecated since 7.61.0. + +## CURLSSLBACKEND_BEARSSL +Introduced in 7.68.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_BORINGSSL +Introduced in 7.49.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_CYASSL +Introduced in 7.34.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_DARWINSSL +Introduced in 7.34.0. Deprecated since 7.64.1. + +## CURLSSLBACKEND_GNUTLS +Introduced in 7.34.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_GSKIT +Introduced in 7.34.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_LIBRESSL +Introduced in 7.49.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_MBEDTLS +Introduced in 7.46.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_MESALINK +Introduced in 7.62.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_NONE +Introduced in 7.34.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_NSS +Introduced in 7.34.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_OPENSSL +Introduced in 7.34.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_POLARSSL +Introduced in 7.34.0. Deprecated since 7.69.0. + +## CURLSSLBACKEND_QSOSSL +Introduced in 7.34.0. Last used in 7.38.0. + +## CURLSSLBACKEND_RUSTLS +Introduced in 7.76.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_SCHANNEL +Introduced in 7.34.0. See curl_global_sslset(3). + +## CURLSSLBACKEND_SECURETRANSPORT +Introduced in 7.64.1. See curl_global_sslset(3). + +## CURLSSLBACKEND_WOLFSSL +Introduced in 7.49.0. See curl_global_sslset(3). + +## CURLSSLOPT_ALLOW_BEAST +Introduced in 7.25.0. See CURLOPT_SSL_OPTIONS(3). + +## CURLSSLOPT_AUTO_CLIENT_CERT +Introduced in 7.77.0. See CURLOPT_SSL_OPTIONS(3). + +## CURLSSLOPT_NATIVE_CA +Introduced in 7.71.0. See CURLOPT_SSL_OPTIONS(3). + +## CURLSSLOPT_NO_PARTIALCHAIN +Introduced in 7.68.0. See CURLOPT_SSL_OPTIONS(3). + +## CURLSSLOPT_NO_REVOKE +Introduced in 7.44.0. See CURLOPT_SSL_OPTIONS(3). + +## CURLSSLOPT_REVOKE_BEST_EFFORT +Introduced in 7.70.0. See CURLOPT_SSL_OPTIONS(3). + +## CURLSSLSET_NO_BACKENDS +Introduced in 7.56.0. See curl_global_sslset(3). + +## CURLSSLSET_OK +Introduced in 7.56.0. See curl_global_sslset(3). + +## CURLSSLSET_TOO_LATE +Introduced in 7.56.0. See curl_global_sslset(3). + +## CURLSSLSET_UNKNOWN_BACKEND +Introduced in 7.56.0. See curl_global_sslset(3). + +## CURLSTS_DONE +Introduced in 7.74.0. See CURLOPT_HSTSREADFUNCTION(3). + +## CURLSTS_FAIL +Introduced in 7.74.0. See CURLOPT_HSTSREADFUNCTION(3). + +## CURLSTS_OK +Introduced in 7.74.0. See CURLOPT_HSTSREADFUNCTION(3). + +## CURLU_ALLOW_SPACE +Introduced in 7.78.0. See curl_url_get(3). + +## CURLU_APPENDQUERY +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_DEFAULT_PORT +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_DEFAULT_SCHEME +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_DISALLOW_USER +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_GUESS_SCHEME +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_NO_AUTHORITY +Introduced in 7.67.0. See curl_url_get(3). + +## CURLU_NO_DEFAULT_PORT +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_NON_SUPPORT_SCHEME +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_PATH_AS_IS +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_PUNY2IDN +Introduced in 8.3.0. See curl_url_get(3). + +## CURLU_PUNYCODE +Introduced in 7.88.0. See curl_url_get(3). + +## CURLU_URLDECODE +Introduced in 7.62.0. See curl_url_get(3). + +## CURLU_URLENCODE +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUE_BAD_FILE_URL +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_FRAGMENT +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_HANDLE +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_BAD_HOSTNAME +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_IPV6 +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_LOGIN +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_PARTPOINTER +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_BAD_PASSWORD +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_PATH +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_PORT_NUMBER +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_BAD_QUERY +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_SCHEME +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_SLASHES +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_BAD_USER +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_LACKS_IDN +Introduced in 7.88.0. See libcurl-errors(3). + +## CURLUE_MALFORMED_INPUT +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_FRAGMENT +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_HOST +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_OPTIONS +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_PASSWORD +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_PORT +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_QUERY +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_SCHEME +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_USER +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_NO_ZONEID +Introduced in 7.81.0. See libcurl-errors(3). + +## CURLUE_OK +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_OUT_OF_MEMORY +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_TOO_LARGE +Introduced in 8.6.0. See libcurl-errors(3). + +## CURLUE_UNKNOWN_PART +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_UNSUPPORTED_SCHEME +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_URLDECODE +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUE_USER_NOT_ALLOWED +Introduced in 7.62.0. See libcurl-errors(3). + +## CURLUPART_FRAGMENT +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_HOST +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_OPTIONS +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_PASSWORD +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_PATH +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_PORT +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_QUERY +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_SCHEME +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_URL +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_USER +Introduced in 7.62.0. See curl_url_get(3). + +## CURLUPART_ZONEID +Introduced in 7.65.0. See curl_url_get(3). + +## CURLUSESSL_ALL +Introduced in 7.17.0. See CURLOPT_USE_SSL(3). + +## CURLUSESSL_CONTROL +Introduced in 7.17.0. See CURLOPT_USE_SSL(3). + +## CURLUSESSL_NONE +Introduced in 7.17.0. See CURLOPT_USE_SSL(3). + +## CURLUSESSL_TRY +Introduced in 7.17.0. See CURLOPT_USE_SSL(3). + +## CURLVERSION_EIGHTH +Introduced in 7.72.0. See curl_version_info(3). + +## CURLVERSION_ELEVENTH +Introduced in 7.87.0. See curl_version_info(3). + +## CURLVERSION_FIFTH +Introduced in 7.57.0. See curl_version_info(3). + +## CURLVERSION_FIRST +Introduced in 7.10. See curl_version_info(3). + +## CURLVERSION_FOURTH +Introduced in 7.16.1. See curl_version_info(3). + +## CURLVERSION_NINTH +Introduced in 7.75.0. See curl_version_info(3). + +## CURLVERSION_NOW +Introduced in 7.10. See curl_version_info(3). + +## CURLVERSION_SECOND +Introduced in 7.11.1. See curl_version_info(3). + +## CURLVERSION_SEVENTH +Introduced in 7.70.0. See curl_version_info(3). + +## CURLVERSION_SIXTH +Introduced in 7.66.0. See curl_version_info(3). + +## CURLVERSION_TENTH +Introduced in 7.77.0. See curl_version_info(3). + +## CURLVERSION_THIRD +Introduced in 7.12.0. See curl_version_info(3). + +## CURLWARNING +Introduced in 7.66.0. + +## CURLWS_BINARY +Introduced in 7.86.0. See curl_ws_send(3). + +## CURLWS_CLOSE +Introduced in 7.86.0. See curl_ws_send(3). + +## CURLWS_CONT +Introduced in 7.86.0. See curl_ws_send(3). + +## CURLWS_OFFSET +Introduced in 7.86.0. See curl_ws_send(3). + +## CURLWS_PING +Introduced in 7.86.0. See curl_ws_send(3). + +## CURLWS_PONG +Introduced in 7.86.0. See curl_ws_send(3). + +## CURLWS_RAW_MODE +Introduced in 7.86.0. See curl_ws_send(3). + +## CURLWS_TEXT +Introduced in 7.86.0. See curl_ws_send(3). diff --git a/docs/libcurl/libcurl-thread.md b/docs/libcurl/libcurl-thread.md new file mode 100644 index 0000000..b3e9ecf --- /dev/null +++ b/docs/libcurl/libcurl-thread.md @@ -0,0 +1,99 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-thread +Section: 3 +Source: libcurl +See-also: + - libcurl-security (3) +--- + +# NAME + +libcurl-thread - libcurl thread safety + +# Multi-threading with libcurl + +libcurl is thread safe but has no internal thread synchronization. You may have +to provide your own locking should you meet any of the thread safety exceptions +below. + +# Handles + +You must **never** share the same handle in multiple threads. You can pass the +handles around among threads, but you must never use a single handle from more +than one thread at any given time. + +# Shared objects + +You can share certain data between multiple handles by using the share +interface but you must provide your own locking and set +curl_share_setopt(3) CURLSHOPT_LOCKFUNC and CURLSHOPT_UNLOCKFUNC. + +Note that some items are specifically documented as not thread-safe in the +share API (the connection pool and HSTS cache for example). + +# TLS + +All current TLS libraries libcurl supports are thread-safe. OpenSSL 1.1.0+ can +be safely used in multi-threaded applications provided that support for the +underlying OS threading API is built-in. For older versions of OpenSSL, the +user must set mutex callbacks. + +# Signals + +Signals are used for timing out name resolves (during DNS lookup) - when built +without using either the c-ares or threaded resolver backends. On systems that +have a signal concept. + +When using multiple threads you should set the CURLOPT_NOSIGNAL(3) +option to 1L for all handles. Everything works fine except that timeouts +cannot be honored during DNS lookups - which you can work around by building +libcurl with c-ares or threaded-resolver support. c-ares is a library that +provides asynchronous name resolves. On some platforms, libcurl simply cannot +function properly multi-threaded unless the CURLOPT_NOSIGNAL(3) option +is set. + +When CURLOPT_NOSIGNAL(3) is set to 1L, your application needs to deal +with the risk of a SIGPIPE (that at least the OpenSSL backend can +trigger). Note that setting CURLOPT_NOSIGNAL(3) to 0L does not work in a +threaded situation as there is a race condition where libcurl risks restoring +the former signal handler while another thread should still ignore it. + +# Name resolving + +The **gethostbyname** or **getaddrinfo** and other name resolving system +calls used by libcurl are provided by your operating system and must be thread +safe. It is important that libcurl can find and use thread safe versions of +these and other system calls, as otherwise it cannot function fully thread +safe. Some operating systems are known to have faulty thread +implementations. We have previously received problem reports on *BSD (at least +in the past, they may be working fine these days). Some operating systems that +are known to have solid and working thread support are Linux, Solaris and +Windows. + +# curl_global_* functions + +These functions are thread-safe since libcurl 7.84.0 if +curl_version_info(3) has the **CURL_VERSION_THREADSAFE** feature bit +set (most platforms). + +If these functions are not thread-safe and you are using libcurl with multiple +threads it is especially important that before use you call +curl_global_init(3) or curl_global_init_mem(3) to explicitly +initialize the library and its dependents, rather than rely on the "lazy" +fail-safe initialization that takes place the first time +curl_easy_init(3) is called. For an in-depth explanation refer to +libcurl(3) section **GLOBAL CONSTANTS**. + +# Memory functions + +These functions, provided either by your operating system or your own +replacements, must be thread safe. You can use curl_global_init_mem(3) +to set your own replacement memory functions. + +# Non-safe functions + +CURLOPT_DNS_USE_GLOBAL_CACHE(3) is not thread-safe. + +curl_version_info(3) is not thread-safe before libcurl initialization. diff --git a/docs/libcurl/libcurl-tutorial.md b/docs/libcurl/libcurl-tutorial.md new file mode 100644 index 0000000..2bf5f05 --- /dev/null +++ b/docs/libcurl/libcurl-tutorial.md @@ -0,0 +1,1451 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl-tutorial +Section: 3 +Source: libcurl +See-also: + - libcurl-easy (3) + - libcurl-errors (3) + - libcurl-multi (3) + - libcurl-url (3) +--- + +# NAME + +libcurl-tutorial - libcurl programming tutorial + +# Objective + +This document attempts to describe the general principles and some basic +approaches to consider when programming with libcurl. The text focuses on the +C interface but should apply fairly well on other language bindings as well as +they usually follow the C API pretty closely. + +This document refers to 'the user' as the person writing the source code that +uses libcurl. That would probably be you or someone in your position. What is +generally referred to as 'the program' is the collected source code that you +write that is using libcurl for transfers. The program is outside libcurl and +libcurl is outside of the program. + +To get more details on all options and functions described herein, please +refer to their respective man pages. + +# Building + +There are many different ways to build C programs. This chapter assumes a Unix +style build process. If you use a different build system, you can still read +this to get general information that may apply to your environment as well. + +## Compiling the Program + +Your compiler needs to know where the libcurl headers are located. Therefore +you must set your compiler's include path to point to the directory where you +installed them. The 'curl-config'[3] tool can be used to get this information: +~~~c + $ curl-config --cflags +~~~ + +## Linking the Program with libcurl + +When having compiled the program, you need to link your object files to create +a single executable. For that to succeed, you need to link with libcurl and +possibly also with other libraries that libcurl itself depends on. Like the +OpenSSL libraries, but even some standard OS libraries may be needed on the +command line. To figure out which flags to use, once again the 'curl-config' +tool comes to the rescue: +~~~c + $ curl-config --libs +~~~ + +## SSL or Not + +libcurl can be built and customized in many ways. One of the things that +varies from different libraries and builds is the support for SSL-based +transfers, like HTTPS and FTPS. If a supported SSL library was detected +properly at build-time, libcurl is built with SSL support. To figure out if an +installed libcurl has been built with SSL support enabled, use *curl-config* +like this: + +~~~c + $ curl-config --feature +~~~ + +If SSL is supported, the keyword *SSL* is written to stdout, possibly together +with a other features that could be either on or off on for different +libcurls. + +See also the "Features libcurl Provides" further down. + +## autoconf macro + +When you write your configure script to detect libcurl and setup variables +accordingly, we offer a macro that probably does everything you need in this +area. See docs/libcurl/libcurl.m4 file - it includes docs on how to use it. + +# Portable Code in a Portable World + +The people behind libcurl have put a considerable effort to make libcurl work +on a large amount of different operating systems and environments. + +You program libcurl the same way on all platforms that libcurl runs on. There +are only a few minor details that differ. If you just make sure to write your +code portable enough, you can create a portable program. libcurl should not +stop you from that. + +# Global Preparation + +The program must initialize some of the libcurl functionality globally. That +means it should be done exactly once, no matter how many times you intend to +use the library. Once for your program's entire life time. This is done using +~~~c + curl_global_init() +~~~ +and it takes one parameter which is a bit pattern that tells libcurl what to +initialize. Using *CURL_GLOBAL_ALL* makes it initialize all known internal +sub modules, and might be a good default option. The current two bits that are +specified are: + +## CURL_GLOBAL_WIN32 + +which only does anything on Windows machines. When used on a Windows machine, +it makes libcurl initialize the win32 socket stuff. Without having that +initialized properly, your program cannot use sockets properly. You should +only do this once for each application, so if your program already does this +or of another library in use does it, you should not tell libcurl to do this +as well. + +## CURL_GLOBAL_SSL + +which only does anything on libcurls compiled and built SSL-enabled. On these +systems, this makes libcurl initialize the SSL library properly for this +application. This only needs to be done once for each application so if your +program or another library already does this, this bit should not be needed. + +libcurl has a default protection mechanism that detects if +curl_global_init(3) has not been called by the time +curl_easy_perform(3) is called and if that is the case, libcurl runs the +function itself with a guessed bit pattern. Please note that depending solely +on this is not considered nice nor good. + +When the program no longer uses libcurl, it should call +curl_global_cleanup(3), which is the opposite of the init call. It +performs the reversed operations to cleanup the resources the +curl_global_init(3) call initialized. + +Repeated calls to curl_global_init(3) and curl_global_cleanup(3) +should be avoided. They should only be called once each. + +# Features libcurl Provides + +It is considered best-practice to determine libcurl features at runtime rather +than at build-time (if possible of course). By calling +curl_version_info(3) and checking out the details of the returned +struct, your program can figure out exactly what the currently running libcurl +supports. + +# Two Interfaces + +libcurl first introduced the so called easy interface. All operations in the +easy interface are prefixed with 'curl_easy'. The easy interface lets you do +single transfers with a synchronous and blocking function call. + +libcurl also offers another interface that allows multiple simultaneous +transfers in a single thread, the so called multi interface. More about that +interface is detailed in a separate chapter further down. You still need to +understand the easy interface first, so please continue reading for better +understanding. + +# Handle the Easy libcurl + +To use the easy interface, you must first create yourself an easy handle. You +need one handle for each easy session you want to perform. Basically, you +should use one handle for every thread you plan to use for transferring. You +must never share the same handle in multiple threads. + +Get an easy handle with +~~~c + handle = curl_easy_init(); +~~~ +It returns an easy handle. Using that you proceed to the next step: setting +up your preferred actions. A handle is just a logic entity for the upcoming +transfer or series of transfers. + +You set properties and options for this handle using +curl_easy_setopt(3). They control how the subsequent transfer or +transfers using this handle are made. Options remain set in the handle until +set again to something different. They are sticky. Multiple requests using the +same handle use the same options. + +If you at any point would like to blank all previously set options for a +single easy handle, you can call curl_easy_reset(3) and you can also +make a clone of an easy handle (with all its set options) using +curl_easy_duphandle(3). + +Many of the options you set in libcurl are "strings", pointers to data +terminated with a zero byte. When you set strings with +curl_easy_setopt(3), libcurl makes its own copy so that they do not need +to be kept around in your application after being set[4]. + +One of the most basic properties to set in the handle is the URL. You set your +preferred URL to transfer with CURLOPT_URL(3) in a manner similar to: + +~~~c + curl_easy_setopt(handle, CURLOPT_URL, "http://domain.com/"); +~~~ + +Let's assume for a while that you want to receive data as the URL identifies a +remote resource you want to get here. Since you write a sort of application +that needs this transfer, I assume that you would like to get the data passed +to you directly instead of simply getting it passed to stdout. So, you write +your own function that matches this prototype: +~~~c + size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp); +~~~ +You tell libcurl to pass all data to this function by issuing a function +similar to this: +~~~c + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data); +~~~ +You can control what data your callback function gets in the fourth argument +by setting another property: +~~~c + curl_easy_setopt(handle, CURLOPT_WRITEDATA, &internal_struct); +~~~ +Using that property, you can easily pass local data between your application +and the function that gets invoked by libcurl. libcurl itself does not touch +the data you pass with CURLOPT_WRITEDATA(3). + +libcurl offers its own default internal callback that takes care of the data +if you do not set the callback with CURLOPT_WRITEFUNCTION(3). It simply +outputs the received data to stdout. You can have the default callback write +the data to a different file handle by passing a 'FILE *' to a file opened for +writing with the CURLOPT_WRITEDATA(3) option. + +Now, we need to take a step back and take a deep breath. Here is one of those +rare platform-dependent nitpicks. Did you spot it? On some platforms[2], +libcurl is not able to operate on file handles opened by the +program. Therefore, if you use the default callback and pass in an open file +handle with CURLOPT_WRITEDATA(3), libcurl crashes. You should avoid this +to make your program run fine virtually everywhere. + +(CURLOPT_WRITEDATA(3) was formerly known as *CURLOPT_FILE*. Both names still +work and do the same thing). + +If you are using libcurl as a win32 DLL, you MUST use the +CURLOPT_WRITEFUNCTION(3) if you set CURLOPT_WRITEDATA(3) - or experience +crashes. + +There are of course many more options you can set, and we get back to a few of +them later. Let's instead continue to the actual transfer: + +~~~c + success = curl_easy_perform(handle); +~~~ + +curl_easy_perform(3) connects to the remote site, does the necessary commands +and performs the transfer. Whenever it receives data, it calls the callback +function we previously set. The function may get one byte at a time, or it may +get many kilobytes at once. libcurl delivers as much as possible as often as +possible. Your callback function should return the number of bytes it "took +care of". If that is not the same amount of bytes that was passed to it, +libcurl aborts the operation and returns with an error code. + +When the transfer is complete, the function returns a return code that informs +you if it succeeded in its mission or not. If a return code is not enough for +you, you can use the CURLOPT_ERRORBUFFER(3) to point libcurl to a buffer of +yours where it stores a human readable error message as well. + +If you then want to transfer another file, the handle is ready to be used +again. It is even preferred and encouraged that you reuse an existing handle +if you intend to make another transfer. libcurl then attempts to reuse a +previous connection. + +For some protocols, downloading a file can involve a complicated process of +logging in, setting the transfer mode, changing the current directory and +finally transferring the file data. libcurl takes care of all that +complication for you. Given simply the URL to a file, libcurl takes care of +all the details needed to get the file moved from one machine to another. + +# Multi-threading Issues + +libcurl is thread safe but there are a few exceptions. Refer to +libcurl-thread(3) for more information. + +# When It does not Work + +There are times when the transfer fails for some reason. You might have set +the wrong libcurl option or misunderstood what the libcurl option actually +does, or the remote server might return non-standard replies that confuse the +library which then confuses your program. + +There is one golden rule when these things occur: set the +CURLOPT_VERBOSE(3) option to 1. it causes the library to spew out the +entire protocol details it sends, some internal info and some received +protocol data as well (especially when using FTP). If you are using HTTP, +adding the headers in the received output to study is also a clever way to get +a better understanding why the server behaves the way it does. Include headers +in the normal body output with CURLOPT_HEADER(3) set 1. + +Of course, there are bugs left. We need to know about them to be able to fix +them, so we are quite dependent on your bug reports. When you do report +suspected bugs in libcurl, please include as many details as you possibly can: +a protocol dump that CURLOPT_VERBOSE(3) produces, library version, as +much as possible of your code that uses libcurl, operating system name and +version, compiler name and version etc. + +If CURLOPT_VERBOSE(3) is not enough, you increase the level of debug +data your application receive by using the CURLOPT_DEBUGFUNCTION(3). + +Getting some in-depth knowledge about the protocols involved is never wrong, +and if you are trying to do funny things, you might understand libcurl and how +to use it better if you study the appropriate RFC documents at least briefly. + +# Upload Data to a Remote Site + +libcurl tries to keep a protocol independent approach to most transfers, thus +uploading to a remote FTP site is similar to uploading data to an HTTP server +with a PUT request. + +Of course, first you either create an easy handle or you reuse one existing +one. Then you set the URL to operate on just like before. This is the remote +URL, that we now upload. + +Since we write an application, we most likely want libcurl to get the upload +data by asking us for it. To make it do that, we set the read callback and the +custom pointer libcurl passes to our read callback. The read callback should +have a prototype similar to: +~~~c + size_t function(char *bufptr, size_t size, size_t nitems, void *userp); +~~~ +Where *bufptr* is the pointer to a buffer we fill in with data to upload +and *size*nitems* is the size of the buffer and therefore also the maximum +amount of data we can return to libcurl in this call. The *userp* pointer +is the custom pointer we set to point to a struct of ours to pass private data +between the application and the callback. +~~~c + curl_easy_setopt(handle, CURLOPT_READFUNCTION, read_function); + + curl_easy_setopt(handle, CURLOPT_READDATA, &filedata); +~~~ +Tell libcurl that we want to upload: +~~~c + curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L); +~~~ +A few protocols do not behave properly when uploads are done without any prior +knowledge of the expected file size. So, set the upload file size using the +CURLOPT_INFILESIZE_LARGE(3) for all known file sizes like this[1]: + +~~~c + /* in this example, file_size must be an curl_off_t variable */ + curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, file_size); +~~~ + +When you call curl_easy_perform(3) this time, it performs all the +necessary operations and when it has invoked the upload it calls your supplied +callback to get the data to upload. The program should return as much data as +possible in every invoke, as that is likely to make the upload perform as fast +as possible. The callback should return the number of bytes it wrote in the +buffer. Returning 0 signals the end of the upload. + +# Passwords + +Many protocols use or even require that user name and password are provided +to be able to download or upload the data of your choice. libcurl offers +several ways to specify them. + +Most protocols support that you specify the name and password in the URL +itself. libcurl detects this and use them accordingly. This is written like +this: +~~~c + protocol://user:password@example.com/path/ +~~~ +If you need any odd letters in your user name or password, you should enter +them URL encoded, as %XX where XX is a two-digit hexadecimal number. + +libcurl also provides options to set various passwords. The user name and +password as shown embedded in the URL can instead get set with the +CURLOPT_USERPWD(3) option. The argument passed to libcurl should be a +char * to a string in the format "user:password". In a manner like this: + +~~~c + curl_easy_setopt(handle, CURLOPT_USERPWD, "myname:thesecret"); +~~~ + +Another case where name and password might be needed at times, is for those +users who need to authenticate themselves to a proxy they use. libcurl offers +another option for this, the CURLOPT_PROXYUSERPWD(3). It is used quite similar +to the CURLOPT_USERPWD(3) option like this: + +~~~c + curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, "myname:thesecret"); +~~~ + +There is a long time Unix "standard" way of storing FTP user names and +passwords, namely in the $HOME/.netrc file (on Windows, libcurl also checks +the *%USERPROFILE% environment* variable if *%HOME%* is unset, and tries +"_netrc" as name). The file should be made private so that only the user may +read it (see also the "Security Considerations" chapter), as it might contain +the password in plain text. libcurl has the ability to use this file to figure +out what set of user name and password to use for a particular host. As an +extension to the normal functionality, libcurl also supports this file for +non-FTP protocols such as HTTP. To make curl use this file, use the +CURLOPT_NETRC(3) option: + +~~~c + curl_easy_setopt(handle, CURLOPT_NETRC, 1L); +~~~ + +A basic example of how such a .netrc file may look like: + +~~~c + machine myhost.mydomain.com + login userlogin + password secretword +~~~ + +All these examples have been cases where the password has been optional, or +at least you could leave it out and have libcurl attempt to do its job +without it. There are times when the password is not optional, like when +you are using an SSL private key for secure transfers. + +To pass the known private key password to libcurl: +~~~c + curl_easy_setopt(handle, CURLOPT_KEYPASSWD, "keypassword"); +~~~ + +# HTTP Authentication + +The previous chapter showed how to set user name and password for getting URLs +that require authentication. When using the HTTP protocol, there are many +different ways a client can provide those credentials to the server and you +can control which way libcurl uses them. The default HTTP authentication +method is called 'Basic', which is sending the name and password in clear-text +in the HTTP request, base64-encoded. This is insecure. + +At the time of this writing, libcurl can be built to use: Basic, Digest, NTLM, +Negotiate (SPNEGO). You can tell libcurl which one to use with +CURLOPT_HTTPAUTH(3) as in: + +~~~c + curl_easy_setopt(handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + +~~~ + +When you send authentication to a proxy, you can also set authentication type +the same way but instead with CURLOPT_PROXYAUTH(3): + +~~~c + curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); +~~~ + +Both these options allow you to set multiple types (by ORing them together), +to make libcurl pick the most secure one out of the types the server/proxy +claims to support. This method does however add a round-trip since libcurl +must first ask the server what it supports: + +~~~c + curl_easy_setopt(handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC); +~~~ + +For convenience, you can use the *CURLAUTH_ANY* define (instead of a list with +specific types) which allows libcurl to use whatever method it wants. + +When asking for multiple types, libcurl picks the available one it considers +"best" in its own internal order of preference. + +# HTTP POSTing + +We get many questions regarding how to issue HTTP POSTs with libcurl the +proper way. This chapter thus includes examples using both different versions +of HTTP POST that libcurl supports. + +The first version is the simple POST, the most common version, that most HTML +pages using the
tag uses. We provide a pointer to the data and tell +libcurl to post it all to the remote site: + +~~~c + char *data="name=daniel&project=curl"; + curl_easy_setopt(handle, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(handle, CURLOPT_URL, "http://posthere.com/"); + + curl_easy_perform(handle); /* post away! */ +~~~ + +Simple enough, huh? Since you set the POST options with the +CURLOPT_POSTFIELDS(3), this automatically switches the handle to use +POST in the upcoming request. + +What if you want to post binary data that also requires you to set the +Content-Type: header of the post? Well, binary posts prevent libcurl from being +able to do strlen() on the data to figure out the size, so therefore we must +tell libcurl the size of the post data. Setting headers in libcurl requests are +done in a generic way, by building a list of our own headers and then passing +that list to libcurl. + +~~~c + struct curl_slist *headers=NULL; + headers = curl_slist_append(headers, "Content-Type: text/xml"); + + /* post binary data */ + curl_easy_setopt(handle, CURLOPT_POSTFIELDS, binaryptr); + + /* set the size of the postfields data */ + curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, 23L); + + /* pass our list of custom made headers */ + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); + + curl_easy_perform(handle); /* post away! */ + + curl_slist_free_all(headers); /* free the header list */ +~~~ + +While the simple examples above cover the majority of all cases where HTTP +POST operations are required, they do not do multi-part formposts. Multi-part +formposts were introduced as a better way to post (possibly large) binary data +and were first documented in the RFC 1867 (updated in RFC 2388). They are +called multi-part because they are built by a chain of parts, each part being +a single unit of data. Each part has its own name and contents. You can in +fact create and post a multi-part formpost with the regular libcurl POST +support described above, but that would require that you build a formpost +yourself and provide to libcurl. + +To make that easier, libcurl provides a MIME API consisting in several +functions: using those, you can create and fill a multi-part form. Function +curl_mime_init(3) creates a multi-part body; you can then append new parts +to a multi-part body using curl_mime_addpart(3). + +There are three possible data sources for a part: memory using +curl_mime_data(3), file using curl_mime_filedata(3) and user-defined data +read callback using curl_mime_data_cb(3). curl_mime_name(3) sets a part's +(i.e.: form field) name, while curl_mime_filename(3) fills in the remote +filename. With curl_mime_type(3), you can tell the MIME type of a part, +curl_mime_headers(3) allows defining the part's headers. When a multi-part +body is no longer needed, you can destroy it using curl_mime_free(3). + +The following example sets two simple text parts with plain textual contents, +and then a file with binary contents and uploads the whole thing. + +~~~c + curl_mime *multipart = curl_mime_init(handle); + curl_mimepart *part = curl_mime_addpart(multipart); + curl_mime_name(part, "name"); + curl_mime_data(part, "daniel", CURL_ZERO_TERMINATED); + part = curl_mime_addpart(multipart); + curl_mime_name(part, "project"); + curl_mime_data(part, "curl", CURL_ZERO_TERMINATED); + part = curl_mime_addpart(multipart); + curl_mime_name(part, "logotype-image"); + curl_mime_filedata(part, "curl.png"); + + /* Set the form info */ + curl_easy_setopt(handle, CURLOPT_MIMEPOST, multipart); + + curl_easy_perform(handle); /* post away! */ + + /* free the post data again */ + curl_mime_free(multipart); +~~~ + +To post multiple files for a single form field, you must supply each file in +a separate part, all with the same field name. Although function +curl_mime_subparts(3) implements nested multi-parts, this way of +multiple files posting is deprecated by RFC 7578, chapter 4.3. + +To set the data source from an already opened FILE pointer, use: + +~~~c + curl_mime_data_cb(part, filesize, (curl_read_callback) fread, + (curl_seek_callback) fseek, NULL, filepointer); +~~~ + +A deprecated curl_formadd(3) function is still supported in libcurl. +It should however not be used anymore for new designs and programs using it +ought to be converted to the MIME API. It is however described here as an +aid to conversion. + +Using *curl_formadd*, you add parts to the form. When you are done adding +parts, you post the whole form. + +The MIME API example above is expressed as follows using this function: + +~~~c + struct curl_httppost *post=NULL; + struct curl_httppost *last=NULL; + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "name", + CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END); + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "project", + CURLFORM_COPYCONTENTS, "curl", CURLFORM_END); + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "logotype-image", + CURLFORM_FILECONTENT, "curl.png", CURLFORM_END); + + /* Set the form info */ + curl_easy_setopt(handle, CURLOPT_HTTPPOST, post); + + curl_easy_perform(handle); /* post away! */ + + /* free the post data again */ + curl_formfree(post); +~~~ + +Multipart formposts are chains of parts using MIME-style separators and +headers. It means that each one of these separate parts get a few headers set +that describe the individual content-type, size etc. To enable your +application to handicraft this formpost even more, libcurl allows you to +supply your own set of custom headers to such an individual form part. You can +of course supply headers to as many parts as you like, but this little example +shows how you set headers to one specific part when you add that to the post +handle: + +~~~c + struct curl_slist *headers=NULL; + headers = curl_slist_append(headers, "Content-Type: text/xml"); + + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "logotype-image", + CURLFORM_FILECONTENT, "curl.xml", + CURLFORM_CONTENTHEADER, headers, + CURLFORM_END); + + curl_easy_perform(handle); /* post away! */ + + curl_formfree(post); /* free post */ + curl_slist_free_all(headers); /* free custom header list */ +~~~ + +Since all options on an easy handle are "sticky", they remain the same until +changed even if you do call curl_easy_perform(3), you may need to tell +curl to go back to a plain GET request if you intend to do one as your next +request. You force an easy handle to go back to GET by using the +CURLOPT_HTTPGET(3) option: +~~~c + curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); +~~~ +Just setting CURLOPT_POSTFIELDS(3) to "" or NULL does *not* stop libcurl +from doing a POST. It just makes it POST without any data to send! + +# Converting from deprecated form API to MIME API + +Four rules have to be respected in building the multi-part: + +- The easy handle must be created before building the multi-part. + +- The multi-part is always created by a call to curl_mime_init(handle). + +- Each part is created by a call to curl_mime_addpart(multipart). + +- When complete, the multi-part must be bound to the easy handle using +CURLOPT_MIMEPOST(3) instead of CURLOPT_HTTPPOST(3). + +Here are some example of *curl_formadd* calls to MIME API sequences: + +~~~c + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "id", + CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END); + CURLFORM_CONTENTHEADER, headers, + CURLFORM_END); +~~~ +becomes: +~~~c + part = curl_mime_addpart(multipart); + curl_mime_name(part, "id"); + curl_mime_data(part, "daniel", CURL_ZERO_TERMINATED); + curl_mime_headers(part, headers, FALSE); +~~~ + +Setting the last curl_mime_headers(3) argument to TRUE would have caused +the headers to be automatically released upon destroyed the multi-part, thus +saving a clean-up call to curl_slist_free_all(3). + +~~~c + curl_formadd(&post, &last, + CURLFORM_PTRNAME, "logotype-image", + CURLFORM_FILECONTENT, "-", + CURLFORM_END); +~~~ +becomes: +~~~c + part = curl_mime_addpart(multipart); + curl_mime_name(part, "logotype-image"); + curl_mime_data_cb(part, (curl_off_t) -1, fread, fseek, NULL, stdin); +~~~ + +curl_mime_name(3) always copies the field name. The special file name +"-" is not supported by curl_mime_filename(3): to read an open file, use +a callback source using fread(). The transfer is be chunk-encoded since the +data size is unknown. + +~~~c + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "datafile[]", + CURLFORM_FILE, "file1", + CURLFORM_FILE, "file2", + CURLFORM_END); +~~~ +becomes: +~~~c + part = curl_mime_addpart(multipart); + curl_mime_name(part, "datafile[]"); + curl_mime_filedata(part, "file1"); + part = curl_mime_addpart(multipart); + curl_mime_name(part, "datafile[]"); + curl_mime_filedata(part, "file2"); +~~~ + +The deprecated multipart/mixed implementation of multiple files field is +translated to two distinct parts with the same name. + +~~~c + curl_easy_setopt(handle, CURLOPT_READFUNCTION, myreadfunc); + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "stream", + CURLFORM_STREAM, arg, + CURLFORM_CONTENTLEN, (curl_off_t) datasize, + CURLFORM_FILENAME, "archive.zip", + CURLFORM_CONTENTTYPE, "application/zip", + CURLFORM_END); +~~~ +becomes: +~~~c + part = curl_mime_addpart(multipart); + curl_mime_name(part, "stream"); + curl_mime_data_cb(part, (curl_off_t) datasize, + myreadfunc, NULL, NULL, arg); + curl_mime_filename(part, "archive.zip"); + curl_mime_type(part, "application/zip"); +~~~ + +CURLOPT_READFUNCTION(3) callback is not used: it is replace by directly +setting the part source data from the callback read function. + +~~~c + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "memfile", + CURLFORM_BUFFER, "memfile.bin", + CURLFORM_BUFFERPTR, databuffer, + CURLFORM_BUFFERLENGTH, (long) sizeof databuffer, + CURLFORM_END); +~~~ +becomes: +~~~c + part = curl_mime_addpart(multipart); + curl_mime_name(part, "memfile"); + curl_mime_data(part, databuffer, (curl_off_t) sizeof databuffer); + curl_mime_filename(part, "memfile.bin"); +~~~ + +curl_mime_data(3) always copies the initial data: data buffer is thus +free for immediate reuse. + +~~~c + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "message", + CURLFORM_FILECONTENT, "msg.txt", + CURLFORM_END); +~~~ +becomes: +~~~c + part = curl_mime_addpart(multipart); + curl_mime_name(part, "message"); + curl_mime_filedata(part, "msg.txt"); + curl_mime_filename(part, NULL); +~~~ + +Use of curl_mime_filedata(3) sets the remote filename as a side effect: it is +therefore necessary to clear it for *CURLFORM_FILECONTENT* emulation. + +# Showing Progress + +For historical and traditional reasons, libcurl has a built-in progress meter +that can be switched on and then makes it present a progress meter in your +terminal. + +Switch on the progress meter by, oddly enough, setting +CURLOPT_NOPROGRESS(3) to zero. This option is set to 1 by default. + +For most applications however, the built-in progress meter is useless and what +instead is interesting is the ability to specify a progress callback. The +function pointer you pass to libcurl is then called on irregular intervals +with information about the current transfer. + +Set the progress callback by using CURLOPT_PROGRESSFUNCTION(3). Pass a pointer +to a function that matches this prototype: + +~~~c + int progress_callback(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); +~~~ + +If any of the input arguments is unknown, a 0 is provided. The first argument, +the 'clientp' is the pointer you pass to libcurl with +CURLOPT_PROGRESSDATA(3). libcurl does not touch it. + +# libcurl with C++ + +There is basically only one thing to keep in mind when using C++ instead of C +when interfacing libcurl: + +The callbacks CANNOT be non-static class member functions + +Example C++ code: + +~~~c +class AClass { + static size_t write_data(void *ptr, size_t size, size_t nmemb, + void *ourpointer) + { + /* do what you want with the data */ + } + } +~~~ + +# Proxies + +What "proxy" means according to Merriam-Webster: "a person authorized to act +for another" but also "the agency, function, or office of a deputy who acts as +a substitute for another". + +Proxies are exceedingly common these days. Companies often only offer Internet +access to employees through their proxies. Network clients or user-agents ask +the proxy for documents, the proxy does the actual request and then it returns +them. + +libcurl supports SOCKS and HTTP proxies. When a given URL is wanted, libcurl +asks the proxy for it instead of trying to connect to the actual remote host +identified in the URL. + +If you are using a SOCKS proxy, you may find that libcurl does not quite support +all operations through it. + +For HTTP proxies: the fact that the proxy is an HTTP proxy puts certain +restrictions on what can actually happen. A requested URL that might not be a +HTTP URL is passed to the HTTP proxy to deliver back to libcurl. This happens +transparently, and an application may not need to know. I say "may", because +at times it is important to understand that all operations over an HTTP proxy +use the HTTP protocol. For example, you cannot invoke your own custom FTP +commands or even proper FTP directory listings. + +## Proxy Options + +To tell libcurl to use a proxy at a given port number: +~~~c + curl_easy_setopt(handle, CURLOPT_PROXY, "proxy-host.com:8080"); +~~~ +Some proxies require user authentication before allowing a request, and you +pass that information similar to this: +~~~c + curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, "user:password"); +~~~ +If you want to, you can specify the hostname only in the +CURLOPT_PROXY(3) option, and set the port number separately with +CURLOPT_PROXYPORT(3). + +Tell libcurl what kind of proxy it is with CURLOPT_PROXYTYPE(3) (if not, +it defaults to assuming an HTTP proxy): +~~~c + curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); +~~~ + +## Environment Variables + +libcurl automatically checks and uses a set of environment variables to know +what proxies to use for certain protocols. The names of the variables are +following an old tradition and are built up as "[protocol]_proxy" (note the +lower casing). Which makes the variable 'http_proxy' checked for a name of a +proxy to use when the input URL is HTTP. Following the same rule, the variable +named 'ftp_proxy' is checked for FTP URLs. Again, the proxies are always HTTP +proxies, the different names of the variables simply allows different HTTP +proxies to be used. + +The proxy environment variable contents should be in the format +"[protocol://][user:password@]machine[:port]". Where the protocol:// part +specifies which type of proxy it is, and the optional port number specifies on +which port the proxy operates. If not specified, the internal default port +number is used and that is most likely not the one you would like it to be. + +There are two special environment variables. 'all_proxy' is what sets proxy +for any URL in case the protocol specific variable was not set, and 'no_proxy' +defines a list of hosts that should not use a proxy even though a variable may +say so. If 'no_proxy' is a plain asterisk ("*") it matches all hosts. + +To explicitly disable libcurl's checking for and using the proxy environment +variables, set the proxy name to "" - an empty string - with +CURLOPT_PROXY(3). + +## SSL and Proxies + +SSL is for secure point-to-point connections. This involves strong encryption +and similar things, which effectively makes it impossible for a proxy to +operate as a "man in between" which the proxy's task is, as previously +discussed. Instead, the only way to have SSL work over an HTTP proxy is to ask +the proxy to tunnel everything through without being able to check or fiddle +with the traffic. + +Opening an SSL connection over an HTTP proxy is therefore a matter of asking the +proxy for a straight connection to the target host on a specified port. This +is made with the HTTP request CONNECT. ("please dear proxy, connect me to that +remote host"). + +Because of the nature of this operation, where the proxy has no idea what kind +of data that is passed in and out through this tunnel, this breaks some of the +few advantages that come from using a proxy, such as caching. Many +organizations prevent this kind of tunneling to other destination port numbers +than 443 (which is the default HTTPS port number). + +## Tunneling Through Proxy + +As explained above, tunneling is required for SSL to work and often even +restricted to the operation intended for SSL; HTTPS. + +This is however not the only time proxy-tunneling might offer benefits to +you or your application. + +As tunneling opens a direct connection from your application to the remote +machine, it suddenly also re-introduces the ability to do non-HTTP +operations over an HTTP proxy. You can in fact use things such as FTP +upload or FTP custom commands this way. + +Again, this is often prevented by the administrators of proxies and is +rarely allowed. + +Tell libcurl to use proxy tunneling like this: +~~~c + curl_easy_setopt(handle, CURLOPT_HTTPPROXYTUNNEL, 1L); +~~~ +In fact, there might even be times when you want to do plain HTTP operations +using a tunnel like this, as it then enables you to operate on the remote +server instead of asking the proxy to do so. libcurl does not stand in the way +for such innovative actions either! + +## Proxy Auto-Config + +Netscape first came up with this. It is basically a webpage (usually using a +.pac extension) with a JavaScript that when executed by the browser with the +requested URL as input, returns information to the browser on how to connect +to the URL. The returned information might be "DIRECT" (which means no proxy +should be used), "PROXY host:port" (to tell the browser where the proxy for +this particular URL is) or "SOCKS host:port" (to direct the browser to a SOCKS +proxy). + +libcurl has no means to interpret or evaluate JavaScript and thus it does not +support this. If you get yourself in a position where you face this nasty +invention, the following advice have been mentioned and used in the past: + +- Depending on the JavaScript complexity, write up a script that translates it +to another language and execute that. + +- Read the JavaScript code and rewrite the same logic in another language. + +- Implement a JavaScript interpreter; people have successfully used the +Mozilla JavaScript engine in the past. + +- Ask your admins to stop this, for a static proxy setup or similar. + +# Persistence Is The Way to Happiness + +Re-cycling the same easy handle several times when doing multiple requests is +the way to go. + +After each single curl_easy_perform(3) operation, libcurl keeps the +connection alive and open. A subsequent request using the same easy handle to +the same host might just be able to use the already open connection! This +reduces network impact a lot. + +Even if the connection is dropped, all connections involving SSL to the same +host again, benefit from libcurl's session ID cache that drastically reduces +re-connection time. + +FTP connections that are kept alive save a lot of time, as the command- +response round-trips are skipped, and also you do not risk getting blocked +without permission to login again like on many FTP servers only allowing N +persons to be logged in at the same time. + +libcurl caches DNS name resolving results, to make lookups of a previously +looked up name a lot faster. + +Other interesting details that improve performance for subsequent requests +may also be added in the future. + +Each easy handle attempts to keep the last few connections alive for a while +in case they are to be used again. You can set the size of this "cache" with +the CURLOPT_MAXCONNECTS(3) option. Default is 5. There is rarely any +point in changing this value, and if you think of changing this it is often +just a matter of thinking again. + +To force your upcoming request to not use an already existing connection, you +can do that by setting CURLOPT_FRESH_CONNECT(3) to 1. In a similar +spirit, you can also forbid the upcoming request to be "lying" around and +possibly get reused after the request by setting +CURLOPT_FORBID_REUSE(3) to 1. + +# HTTP Headers Used by libcurl + +When you use libcurl to do HTTP requests, it passes along a series of headers +automatically. It might be good for you to know and understand these. You can +replace or remove them by using the CURLOPT_HTTPHEADER(3) option. + +## Host + +This header is required by HTTP 1.1 and even many 1.0 servers and should be +the name of the server we want to talk to. This includes the port number if +anything but default. + +## Accept + +"*/*" + +## Expect + +When doing POST requests, libcurl sets this header to "100-continue" to ask +the server for an "OK" message before it proceeds with sending the data part +of the post. If the posted data amount is deemed "small", libcurl does not use +this header. + +# Customizing Operations + +There is an ongoing development today where more and more protocols are built +upon HTTP for transport. This has obvious benefits as HTTP is a tested and +reliable protocol that is widely deployed and has excellent proxy-support. + +When you use one of these protocols, and even when doing other kinds of +programming you may need to change the traditional HTTP (or FTP or...) +manners. You may need to change words, headers or various data. + +libcurl is your friend here too. + +## CUSTOMREQUEST + +If just changing the actual HTTP request keyword is what you want, like when +GET, HEAD or POST is not good enough for you, CURLOPT_CUSTOMREQUEST(3) +is there for you. It is simple to use: +~~~c +curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "MYOWNREQUEST"); +~~~ +When using the custom request, you change the request keyword of the actual +request you are performing. Thus, by default you make a GET request but you +can also make a POST operation (as described before) and then replace the POST +keyword if you want to. You are the boss. + +## Modify Headers + +HTTP-like protocols pass a series of headers to the server when doing the +request, and you are free to pass any amount of extra headers that you +think fit. Adding headers is this easy: + +~~~c +struct curl_slist *headers=NULL; /* init to NULL is important */ + +headers = curl_slist_append(headers, "Hey-server-hey: how are you?"); +headers = curl_slist_append(headers, "X-silly-content: yes"); + +/* pass our list of custom made headers */ +curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); + +curl_easy_perform(handle); /* transfer http */ + +curl_slist_free_all(headers); /* free the header list */ +~~~ + +... and if you think some of the internally generated headers, such as Accept: +or Host: do not contain the data you want them to contain, you can replace +them by simply setting them too: + +~~~c +headers = curl_slist_append(headers, "Accept: Agent-007"); +headers = curl_slist_append(headers, "Host: munged.host.line"); +~~~ + +## Delete Headers + +If you replace an existing header with one with no contents, you prevent the +header from being sent. For instance, if you want to completely prevent the +"Accept:" header from being sent, you can disable it with code similar to +this: + + headers = curl_slist_append(headers, "Accept:"); + +Both replacing and canceling internal headers should be done with careful +consideration and you should be aware that you may violate the HTTP protocol +when doing so. + +## Enforcing chunked transfer-encoding + +By making sure a request uses the custom header "Transfer-Encoding: chunked" +when doing a non-GET HTTP operation, libcurl switches over to "chunked" +upload, even though the size of the data to upload might be known. By default, +libcurl usually switches over to chunked upload automatically if the upload +data size is unknown. + +## HTTP Version + +All HTTP requests includes the version number to tell the server which version +we support. libcurl speaks HTTP 1.1 by default. Some old servers do not like +getting 1.1-requests and when dealing with stubborn old things like that, you +can tell libcurl to use 1.0 instead by doing something like this: + + curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + +## FTP Custom Commands + +Not all protocols are HTTP-like, and thus the above may not help you when +you want to make, for example, your FTP transfers to behave differently. + +Sending custom commands to an FTP server means that you need to send the +commands exactly as the FTP server expects them (RFC 959 is a good guide +here), and you can only use commands that work on the control-connection +alone. All kinds of commands that require data interchange and thus need a +data-connection must be left to libcurl's own judgment. Also be aware that +libcurl does its best to change directory to the target directory before doing +any transfer, so if you change directory (with CWD or similar) you might +confuse libcurl and then it might not attempt to transfer the file in the +correct remote directory. + +A little example that deletes a given file before an operation: + +~~~c + headers = curl_slist_append(headers, "DELE file-to-remove"); + + /* pass the list of custom commands to the handle */ + curl_easy_setopt(handle, CURLOPT_QUOTE, headers); + + curl_easy_perform(handle); /* transfer ftp data! */ + + curl_slist_free_all(headers); /* free the header list */ +~~~ + +If you would instead want this operation (or chain of operations) to happen +_after_ the data transfer took place the option to curl_easy_setopt(3) +would instead be called CURLOPT_POSTQUOTE(3) and used the exact same +way. + +The custom FTP commands are issued to the server in the same order they are +added to the list, and if a command gets an error code returned back from the +server, no more commands are issued and libcurl bails out with an error code +(CURLE_QUOTE_ERROR). Note that if you use CURLOPT_QUOTE(3) to send +commands before a transfer, no transfer actually takes place when a quote +command has failed. + +If you set the CURLOPT_HEADER(3) to 1, you tell libcurl to get +information about the target file and output "headers" about it. The headers +are in "HTTP-style", looking like they do in HTTP. + +The option to enable headers or to run custom FTP commands may be useful to +combine with CURLOPT_NOBODY(3). If this option is set, no actual file +content transfer is performed. + +## FTP Custom CUSTOMREQUEST + +If you do want to list the contents of an FTP directory using your own defined +FTP command, CURLOPT_CUSTOMREQUEST(3) does just that. "NLST" is the +default one for listing directories but you are free to pass in your idea of a +good alternative. + +# Cookies Without Chocolate Chips + +In the HTTP sense, a cookie is a name with an associated value. A server sends +the name and value to the client, and expects it to get sent back on every +subsequent request to the server that matches the particular conditions +set. The conditions include that the domain name and path match and that the +cookie has not become too old. + +In real-world cases, servers send new cookies to replace existing ones to +update them. Server use cookies to "track" users and to keep "sessions". + +Cookies are sent from server to clients with the header Set-Cookie: and +they are sent from clients to servers with the Cookie: header. + +To just send whatever cookie you want to a server, you can use +CURLOPT_COOKIE(3) to set a cookie string like this: +~~~c + curl_easy_setopt(handle, CURLOPT_COOKIE, "name1=var1; name2=var2;"); +~~~ +In many cases, that is not enough. You might want to dynamically save +whatever cookies the remote server passes to you, and make sure those cookies +are then used accordingly on later requests. + +One way to do this, is to save all headers you receive in a plain file and +when you make a request, you tell libcurl to read the previous headers to +figure out which cookies to use. Set the header file to read cookies from with +CURLOPT_COOKIEFILE(3). + +The CURLOPT_COOKIEFILE(3) option also automatically enables the cookie +parser in libcurl. Until the cookie parser is enabled, libcurl does not parse +or understand incoming cookies and they are just be ignored. However, when the +parser is enabled the cookies are understood and the cookies are kept in +memory and used properly in subsequent requests when the same handle is +used. Many times this is enough, and you may not have to save the cookies to +disk at all. Note that the file you specify to CURLOPT_COOKIEFILE(3) +does not have to exist to enable the parser, so a common way to just enable +the parser and not read any cookies is to use the name of a file you know does +not exist. + +If you would rather use existing cookies that you have previously received +with your Netscape or Mozilla browsers, you can make libcurl use that cookie +file as input. The CURLOPT_COOKIEFILE(3) is used for that too, as +libcurl automatically finds out what kind of file it is and acts accordingly. + +Perhaps the most advanced cookie operation libcurl offers, is saving the +entire internal cookie state back into a Netscape/Mozilla formatted cookie +file. We call that the cookie-jar. When you set a filename with +CURLOPT_COOKIEJAR(3), that filename is created and all received cookies get +stored in it when curl_easy_cleanup(3) is called. This enables cookies to get +passed on properly between multiple handles without any information getting +lost. + +# FTP Peculiarities We Need + +FTP transfers use a second TCP/IP connection for the data transfer. This is +usually a fact you can forget and ignore but at times this detail comes back +to haunt you. libcurl offers several different ways to customize how the +second connection is being made. + +libcurl can either connect to the server a second time or tell the server to +connect back to it. The first option is the default and it is also what works +best for all the people behind firewalls, NATs or IP-masquerading setups. +libcurl then tells the server to open up a new port and wait for a second +connection. This is by default attempted with EPSV first, and if that does not +work it tries PASV instead. (EPSV is an extension to the original FTP spec +and does not exist nor work on all FTP servers.) + +You can prevent libcurl from first trying the EPSV command by setting +CURLOPT_FTP_USE_EPSV(3) to zero. + +In some cases, you want to have the server connect back to you for the second +connection. This might be when the server is perhaps behind a firewall or +something and only allows connections on a single port. libcurl then informs +the remote server which IP address and port number to connect to. This is made +with the CURLOPT_FTPPORT(3) option. If you set it to "-", libcurl uses your +system's "default IP address". If you want to use a particular IP, you can set +the full IP address, a hostname to resolve to an IP address or even a local +network interface name that libcurl gets the IP address from. + +When doing the "PORT" approach, libcurl attempts to use the EPRT and the LPRT +before trying PORT, as they work with more protocols. You can disable this +behavior by setting CURLOPT_FTP_USE_EPRT(3) to zero. + +# MIME API revisited for SMTP and IMAP + +In addition to support HTTP multi-part form fields, the MIME API can be used +to build structured email messages and send them via SMTP or append such +messages to IMAP directories. + +A structured email message may contain several parts: some are displayed +inline by the MUA, some are attachments. Parts can also be structured as +multi-part, for example to include another email message or to offer several +text formats alternatives. This can be nested to any level. + +To build such a message, you prepare the nth-level multi-part and then include +it as a source to the parent multi-part using function +curl_mime_subparts(3). Once it has been +bound to its parent multi-part, a nth-level multi-part belongs to it and +should not be freed explicitly. + +Email messages data is not supposed to be non-ascii and line length is +limited: fortunately, some transfer encodings are defined by the standards to +support the transmission of such incompatible data. Function +curl_mime_encoder(3) tells a part that its source data must be encoded +before being sent. It also generates the corresponding header for that part. +If the part data you want to send is already encoded in such a scheme, do not +use this function (this would over-encode it), but explicitly set the +corresponding part header. + +Upon sending such a message, libcurl prepends it with the header list +set with CURLOPT_HTTPHEADER(3), as zero level mime part headers. + +Here is an example building an email message with an inline plain/html text +alternative and a file attachment encoded in base64: + +~~~c + curl_mime *message = curl_mime_init(handle); + + /* The inline part is an alternative proposing the html and the text + versions of the email. */ + curl_mime *alt = curl_mime_init(handle); + + /* HTML message. */ + curl_mimepart *part = curl_mime_addpart(alt); + curl_mime_data(part, "

This is HTML

", + CURL_ZERO_TERMINATED); + curl_mime_type(part, "text/html"); + + /* Text message. */ + part = curl_mime_addpart(alt); + curl_mime_data(part, "This is plain text message", + CURL_ZERO_TERMINATED); + + /* Create the inline part. */ + part = curl_mime_addpart(message); + curl_mime_subparts(part, alt); + curl_mime_type(part, "multipart/alternative"); + struct curl_slist *headers = curl_slist_append(NULL, + "Content-Disposition: inline"); + curl_mime_headers(part, headers, TRUE); + + /* Add the attachment. */ + part = curl_mime_addpart(message); + curl_mime_filedata(part, "manual.pdf"); + curl_mime_encoder(part, "base64"); + + /* Build the mail headers. */ + headers = curl_slist_append(NULL, "From: me@example.com"); + headers = curl_slist_append(headers, "To: you@example.com"); + + /* Set these into the easy handle. */ + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(handle, CURLOPT_MIMEPOST, mime); +~~~ + +It should be noted that appending a message to an IMAP directory requires +the message size to be known prior upload. It is therefore not possible to +include parts with unknown data size in this context. + +# Headers Equal Fun + +Some protocols provide "headers", meta-data separated from the normal +data. These headers are by default not included in the normal data stream, but +you can make them appear in the data stream by setting CURLOPT_HEADER(3) +to 1. + +What might be even more useful, is libcurl's ability to separate the headers +from the data and thus make the callbacks differ. You can for example set a +different pointer to pass to the ordinary write callback by setting +CURLOPT_HEADERDATA(3). + +Or, you can set an entirely separate function to receive the headers, by using +CURLOPT_HEADERFUNCTION(3). + +The headers are passed to the callback function one by one, and you can +depend on that fact. It makes it easier for you to add custom header parsers +etc. + +"Headers" for FTP transfers equal all the FTP server responses. They are not +actually true headers, but in this case we pretend they are! ;-) + +# Post Transfer Information + +See curl_easy_getinfo(3). + +# The multi Interface + +The easy interface as described in detail in this document is a synchronous +interface that transfers one file at a time and does not return until it is +done. + +The multi interface, on the other hand, allows your program to transfer +multiple files in both directions at the same time, without forcing you to use +multiple threads. The name might make it seem that the multi interface is for +multi-threaded programs, but the truth is almost the reverse. The multi +interface allows a single-threaded application to perform the same kinds of +multiple, simultaneous transfers that multi-threaded programs can perform. It +allows many of the benefits of multi-threaded transfers without the complexity +of managing and synchronizing many threads. + +To complicate matters somewhat more, there are even two versions of the multi +interface. The event based one, also called multi_socket and the "normal one" +designed for using with select(). See the libcurl-multi.3 man page for details +on the multi_socket event based API, this description here is for the select() +oriented one. + +To use this interface, you are better off if you first understand the basics +of how to use the easy interface. The multi interface is simply a way to make +multiple transfers at the same time by adding up multiple easy handles into +a "multi stack". + +You create the easy handles you want, one for each concurrent transfer, and +you set all the options just like you learned above, and then you create a +multi handle with curl_multi_init(3) and add all those easy handles to +that multi handle with curl_multi_add_handle(3). + +When you have added the handles you have for the moment (you can still add new +ones at any time), you start the transfers by calling +curl_multi_perform(3). + +curl_multi_perform(3) is asynchronous. It only performs what can be done +now and then return control to your program. It is designed to never +block. You need to keep calling the function until all transfers are +completed. + +The best usage of this interface is when you do a select() on all possible +file descriptors or sockets to know when to call libcurl again. This also +makes it easy for you to wait and respond to actions on your own application's +sockets/handles. You figure out what to select() for by using +curl_multi_fdset(3), that fills in a set of *fd_set* variables for +you with the particular file descriptors libcurl uses for the moment. + +When you then call select(), it returns when one of the file handles signal +action and you then call curl_multi_perform(3) to allow libcurl to do +what it wants to do. Take note that libcurl does also feature some time-out +code so we advise you to never use long timeouts on select() before you call +curl_multi_perform(3) again. curl_multi_timeout(3) is provided to +help you get a suitable timeout period. + +Another precaution you should use: always call curl_multi_fdset(3) +immediately before the select() call since the current set of file descriptors +may change in any curl function invoke. + +If you want to stop the transfer of one of the easy handles in the stack, you +can use curl_multi_remove_handle(3) to remove individual easy +handles. Remember that easy handles should be curl_easy_cleanup(3)ed. + +When a transfer within the multi stack has finished, the counter of running +transfers (as filled in by curl_multi_perform(3)) decreases. When the +number reaches zero, all transfers are done. + +curl_multi_info_read(3) can be used to get information about completed +transfers. It then returns the CURLcode for each easy transfer, to allow you +to figure out success on each individual transfer. + +# SSL, Certificates and Other Tricks + + [ seeding, passwords, keys, certificates, ENGINE, ca certs ] + +# Sharing Data Between Easy Handles + +You can share some data between easy handles when the easy interface is used, +and some data is share automatically when you use the multi interface. + +When you add easy handles to a multi handle, these easy handles automatically +share a lot of the data that otherwise would be kept on a per-easy handle +basis when the easy interface is used. + +The DNS cache is shared between handles within a multi handle, making +subsequent name resolving faster, and the connection pool that is kept to +better allow persistent connections and connection reuse is also shared. If +you are using the easy interface, you can still share these between specific +easy handles by using the share interface, see libcurl-share(3). + +Some things are never shared automatically, not within multi handles, like for +example cookies so the only way to share that is with the share interface. + +# Footnotes + +## [1] + +libcurl 7.10.3 and later have the ability to switch over to chunked +Transfer-Encoding in cases where HTTP uploads are done with data of an unknown +size. + +## [2] + +This happens on Windows machines when libcurl is built and used as a +DLL. However, you can still do this on Windows if you link with a static +library. + +## [3] + +The curl-config tool is generated at build-time (on Unix-like systems) and +should be installed with the 'make install' or similar instruction that +installs the library, header files, man pages etc. + +## [4] + +This behavior was different in versions before 7.17.0, where strings had to +remain valid past the end of the curl_easy_setopt(3) call. diff --git a/docs/libcurl/libcurl-url.md b/docs/libcurl/libcurl-url.md new file mode 100644 index 0000000..a294800 --- /dev/null +++ b/docs/libcurl/libcurl-url.md @@ -0,0 +1,162 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl +Section: 3 +Source: libcurl +See-also: + - CURLOPT_URL (3) + - curl_url (3) + - curl_url_cleanup (3) + - curl_url_dup (3) + - curl_url_get (3) + - curl_url_set (3) + - curl_url_strerror (3) +--- + +# NAME + +libcurl-url - URL interface overview + +# DESCRIPTION + +The URL interface provides functions for parsing and generating URLs. + +# INCLUDE + +You still only include in your code. + +# CREATE + +Create a handle that holds URL info and resources with curl_url(3): +~~~c + CURLU *h = curl_url(); +~~~ + +# CLEANUP + +When done with it, clean it up with curl_url_cleanup(3) +~~~c + curl_url_cleanup(h); +~~~ + +# DUPLICATE + +When you need a copy of a handle, just duplicate it with curl_url_dup(3): +~~~c + CURLU *nh = curl_url_dup(h); +~~~ + +# PARSING + +By setting a URL to the handle with curl_url_set(3), the URL is parsed +and stored in the handle. If the URL is not syntactically correct it returns +an error instead. +~~~c + rc = curl_url_set(h, CURLUPART_URL, + "https://example.com:449/foo/bar?name=moo", 0); +~~~ + +The zero in the fourth argument is a bitmask for changing specific features. + +If successful, this stores the URL in its individual parts within the handle. + +# REDIRECT + +When a handle already contains info about a URL, setting a relative URL makes +it "redirect" to that. +~~~c + rc = curl_url_set(h, CURLUPART_URL, "../test?another", 0); +~~~ + +# GET URL + +The **CURLU** handle represents a URL and you can easily extract that with +curl_url_get(3): +~~~c + char *url; + rc = curl_url_get(h, CURLUPART_URL, &url, 0); + curl_free(url); +~~~ +The zero in the fourth argument is a bitmask for changing specific features. + +# GET PARTS + +When a URL has been parsed or parts have been set, you can extract those +pieces from the handle at any time. + +~~~c + rc = curl_url_get(h, CURLUPART_FRAGMENT, &fragment, 0); + rc = curl_url_get(h, CURLUPART_HOST, &host, 0); + rc = curl_url_get(h, CURLUPART_PASSWORD, &password, 0); + rc = curl_url_get(h, CURLUPART_PATH, &path, 0); + rc = curl_url_get(h, CURLUPART_PORT, &port, 0); + rc = curl_url_get(h, CURLUPART_QUERY, &query, 0); + rc = curl_url_get(h, CURLUPART_SCHEME, &scheme, 0); + rc = curl_url_get(h, CURLUPART_USER, &user, 0); + rc = curl_url_get(h, CURLUPART_ZONEID, &zoneid, 0); +~~~ + +Extracted parts are not URL decoded unless the user also asks for it with the +*CURLU_URLDECODE* flag set in the fourth bitmask argument. + +Remember to free the returned string with curl_free(3) when you are done +with it! + +# SET PARTS + +A user set individual URL parts, either after having parsed a full URL or +instead of parsing such. + +~~~c + rc = curl_url_set(urlp, CURLUPART_FRAGMENT, "anchor", 0); + rc = curl_url_set(urlp, CURLUPART_HOST, "www.example.com", 0); + rc = curl_url_set(urlp, CURLUPART_PASSWORD, "doe", 0); + rc = curl_url_set(urlp, CURLUPART_PATH, "/index.html", 0); + rc = curl_url_set(urlp, CURLUPART_PORT, "443", 0); + rc = curl_url_set(urlp, CURLUPART_QUERY, "name=john", 0); + rc = curl_url_set(urlp, CURLUPART_SCHEME, "https", 0); + rc = curl_url_set(urlp, CURLUPART_USER, "john", 0); + rc = curl_url_set(urlp, CURLUPART_ZONEID, "eth0", 0); +~~~ + +Set parts are not URL encoded unless the user asks for it with the +*CURLU_URLENCODE* flag. + +# CURLU_APPENDQUERY + +An application can append a string to the right end of the query part with the +*CURLU_APPENDQUERY* flag to curl_url_set(3). + +Imagine a handle that holds the URL "https://example.com/?shoes=2". An +application can then add the string "hat=1" to the query part like this: + +~~~c + rc = curl_url_set(urlp, CURLUPART_QUERY, "hat=1", CURLU_APPENDQUERY); +~~~ + +It notices the lack of an ampersand (&) separator and injects one, and the +handle's full URL then equals "https://example.com/?shoes=2&hat=1". + +The appended string can of course also get URL encoded on add, and if asked to +URL encode, the encoding process skips the '=' character. For example, append +"candy=N&N" to what we already have, and URL encode it to deal with the +ampersand in the data: + +~~~c + rc = curl_url_set(urlp, CURLUPART_QUERY, "candy=N&N", + CURLU_APPENDQUERY | CURLU_URLENCODE); +~~~ + +Now the URL looks like + +~~~c + https://example.com/?shoes=2&hat=1&candy=N%26N +~~~ + +# AVAILABILITY + +The URL API was introduced in libcurl 7.62.0. + +A URL with a literal IPv6 address can be parsed even when IPv6 support is not +enabled. diff --git a/docs/libcurl/libcurl-ws.md b/docs/libcurl/libcurl-ws.md new file mode 100644 index 0000000..40f7c03 --- /dev/null +++ b/docs/libcurl/libcurl-ws.md @@ -0,0 +1,123 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECT_ONLY (3) + - CURLOPT_WRITEFUNCTION (3) + - CURLOPT_WS_OPTIONS (3) + - curl_easy_init (3) + - curl_ws_meta (3) + - curl_ws_recv (3) + - curl_ws_send (3) +--- + +# NAME + +libcurl-ws - WebSocket interface overview + +# DESCRIPTION + +The WebSocket interface provides functions for receiving and sending WebSocket +data. + +# INCLUDE + +You still only include in your code. + +# SETUP + +WebSocket is also often known as *WebSockets*, in plural. It is done by +upgrading a regular HTTP(S) GET request to a WebSocket connection. + +WebSocket is a TCP-like message-based communication protocol done over HTTP, +specified in RFC 6455. + +To initiate a WebSocket session with libcurl, setup an easy handle to use a +URL with a "WS://" or "WSS://" scheme. "WS" is for cleartext communication +over HTTP and "WSS" is for doing WebSocket securely over HTTPS. + +A WebSocket request is done as an HTTP/1 GET request with an "Upgrade +WebSocket" request header field. When the upgrade is accepted by the server, +it responds with a 101 Switching and then the client can speak WebSocket with +the server. The communication can happen in both directions at the same time. + +# MESSAGES + +WebSocket communication is message based. That means that both ends send and +receive entire messages, not streams like TCP. A WebSocket message is sent +over the wire in one or more frames. Each frame in a message can have a size +up to 2^63 bytes. + +libcurl delivers WebSocket data as frame fragments. It might send a whole +frame, but it might also deliver them in pieces depending on size and network +patterns. It makes sure to provide the API user about the exact specifics +about the fragment: type, offset, size and how much data there is pending to +arrive for the same frame. + +A message has an unknown size until the last frame header for the message has +been received since only frames have set sizes. + +# Raw mode + +libcurl can be told to speak WebSocket in "raw mode" by setting the +**CURLWS_RAW_MODE** bit to the CURLOPT_WS_OPTIONS(3) option. + +Raw WebSocket means that libcurl passes on the data from the network without +parsing it leaving that entirely to the application. This mode assumes that +the user of this knows WebSocket and can parse and figure out the data all by +itself. + +This mode is intended for applications that already have a WebSocket +parser/engine that want to switch over to use libcurl for enabling WebSocket, +and keep parts of the existing software architecture. + +# PING + +WebSocket is designed to allow long-lived sessions and in order to keep the +connections alive, both ends can send PING messages for the other end to +respond with a PONG. + +libcurl automatically responds to server PING messages with a PONG. It does +not send any PING messages automatically. + +# MODELS + +Because of the many different ways WebSocket can be used, which is much more +flexible than limited to plain downloads or uploads, libcurl offers two +different API models to use it: + +1. Using a write callback with CURLOPT_WRITEFUNCTION(3) much like other +downloads for when the traffic is download oriented. + +2. Using CURLOPT_CONNECT_ONLY(3) and use the WebSocket recv/send +functions. + +# Callback model + +When a write callback is set and a WebSocket transfer is performed, the +callback is called to deliver all WebSocket data that arrives. + +The callback can then call curl_ws_meta(3) to learn about the details of +the incoming data fragment. + +# CONNECT_ONLY model + +By setting CURLOPT_CONNECT_ONLY(3) to **2L**, the transfer only +establishes and setups the WebSocket communication and then returns control +back to the application. + +Once such a setup has been successfully performed, the application can proceed +and use curl_ws_recv(3) and curl_ws_send(3) freely to exchange +WebSocket messages with the server. + +# AVAILABILITY + +The WebSocket API was introduced as experimental in 7.86.0 and is still +experimental today. + +It is only built-in if explicitly opted in at build time. We discourage use of +the WebSocket API in production because of its experimental state. We might +change API, ABI and behavior before this "goes live". diff --git a/docs/libcurl/libcurl.m4 b/docs/libcurl/libcurl.m4 new file mode 100644 index 0000000..e4a518b --- /dev/null +++ b/docs/libcurl/libcurl.m4 @@ -0,0 +1,274 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) David Shaw +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], +# [ACTION-IF-YES], [ACTION-IF-NO]) +# ---------------------------------------------------------- +# David Shaw May-09-2006 +# +# Checks for libcurl. DEFAULT-ACTION is the string yes or no to +# specify whether to default to --with-libcurl or --without-libcurl. +# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the +# minimum version of libcurl to accept. Pass the version as a regular +# version number like 7.10.1. If not supplied, any version is +# accepted. ACTION-IF-YES is a list of shell commands to run if +# libcurl was successfully found and passed the various tests. +# ACTION-IF-NO is a list of shell commands that are run otherwise. +# Note that using --without-libcurl does run ACTION-IF-NO. +# +# This macro #defines HAVE_LIBCURL if a working libcurl setup is +# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary +# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are +# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy +# where yyy are the various protocols supported by libcurl. Both xxx +# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of +# the macro for the complete list of possible defines. Shell +# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also +# defined to 'yes' for those features and protocols that were found. +# Note that xxx and yyy keep the same capitalization as in the +# curl-config list (e.g. it's "HTTP" and not "http"). +# +# Users may override the detected values by doing something like: +# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure +# +# For the sake of sanity, this macro assumes that any libcurl that is found is +# after version 7.7.2, the first version that included the curl-config script. +# Note that it is important for people packaging binary versions of libcurl to +# include this script! Without curl-config, we can only guess what protocols +# are available, or use curl_version_info to figure it out at runtime. + +AC_DEFUN([LIBCURL_CHECK_CONFIG], +[ + AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL]) + AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4]) + AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6]) + AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz]) + AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS]) + AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN]) + AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) + AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) + + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET]) + AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) + AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) + + AC_ARG_WITH(libcurl, + AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), + [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) + + if test "$_libcurl_with" != "no" ; then + + AC_PROG_AWK + + _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" + + _libcurl_try_link=yes + + if test -d "$_libcurl_with" ; then + LIBCURL_CPPFLAGS="-I$withval/include" + _libcurl_ldflags="-L$withval/lib" + AC_PATH_PROG([_libcurl_config],[curl-config],[], + ["$withval/bin"]) + else + AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) + fi + + if test x$_libcurl_config != "x" ; then + AC_CACHE_CHECK([for the version of libcurl], + [libcurl_cv_lib_curl_version], + [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`]) + + _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` + _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse` + + if test $_libcurl_wanted -gt 0 ; then + AC_CACHE_CHECK([for libcurl >= version $2], + [libcurl_cv_lib_version_ok], + [ + if test $_libcurl_version -ge $_libcurl_wanted ; then + libcurl_cv_lib_version_ok=yes + else + libcurl_cv_lib_version_ok=no + fi + ]) + fi + + if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then + if test x"$LIBCURL_CPPFLAGS" = "x" ; then + LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` + fi + if test x"$LIBCURL" = "x" ; then + LIBCURL=`$_libcurl_config --libs` + + # This is so silly, but Apple actually has a bug in their + # curl-config script. Fixed in Tiger, but there are still + # lots of Panther installs around. + case "${host}" in + powerpc-apple-darwin7*) + LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` + ;; + esac + fi + + # All curl-config scripts support --feature + _libcurl_features=`$_libcurl_config --feature` + + # Is it modern enough to have --protocols? (7.12.4) + if test $_libcurl_version -ge 461828 ; then + _libcurl_protocols=`$_libcurl_config --protocols` + fi + else + _libcurl_try_link=no + fi + + unset _libcurl_wanted + fi + + if test $_libcurl_try_link = yes ; then + + # we did not find curl-config, so let's see if the user-supplied + # link line (or failing that, "-lcurl") is enough. + LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} + + AC_CACHE_CHECK([whether libcurl is usable], + [libcurl_cv_lib_curl_usable], + [ + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBCURL $LIBS" + + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ +/* Try and use a few common options to force a failure if we are + missing symbols or cannot link. */ +int x; +curl_easy_setopt(NULL,CURLOPT_URL,NULL); +x=CURL_ERROR_SIZE; +x=CURLOPT_WRITEFUNCTION; +x=CURLOPT_WRITEDATA; +x=CURLOPT_ERRORBUFFER; +x=CURLOPT_STDERR; +x=CURLOPT_VERBOSE; +if (x) {;} +]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + ]) + + if test $libcurl_cv_lib_curl_usable = yes ; then + + # Does curl_free() exist in this version of libcurl? + # If not, fake it with free() + + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBS $LIBCURL" + + AC_CHECK_DECL([curl_free],[], + [AC_DEFINE([curl_free],[free], + [Define curl_free() as free() if our version of curl lacks curl_free.])], + [[#include ]]) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + + AC_DEFINE(HAVE_LIBCURL,1, + [Define to 1 if you have a functional curl library.]) + AC_SUBST(LIBCURL_CPPFLAGS) + AC_SUBST(LIBCURL) + + for _libcurl_feature in $_libcurl_features ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) + eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes + done + + if test "x$_libcurl_protocols" = "x" ; then + + # We do not have --protocols, so just assume that all + # protocols are available + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" + + if test x$libcurl_feature_SSL = xyes ; then + _libcurl_protocols="$_libcurl_protocols HTTPS" + + # FTPS was not standards-compliant until version + # 7.11.0 (0x070b00 == 461568) + if test $_libcurl_version -ge 461568; then + _libcurl_protocols="$_libcurl_protocols FTPS" + fi + fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi + fi + + for _libcurl_protocol in $_libcurl_protocols ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1]) + eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes + done + else + unset LIBCURL + unset LIBCURL_CPPFLAGS + fi + fi + + unset _libcurl_try_link + unset _libcurl_version_parse + unset _libcurl_config + unset _libcurl_feature + unset _libcurl_features + unset _libcurl_protocol + unset _libcurl_protocols + unset _libcurl_version + unset _libcurl_ldflags + fi + + if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then + # This is the IF-NO path + ifelse([$4],,:,[$4]) + else + # This is the IF-YES path + ifelse([$3],,:,[$3]) + fi + + unset _libcurl_with +]) diff --git a/docs/libcurl/libcurl.md b/docs/libcurl/libcurl.md new file mode 100644 index 0000000..1f7c97e --- /dev/null +++ b/docs/libcurl/libcurl.md @@ -0,0 +1,247 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: libcurl +Section: 3 +Source: libcurl +See-also: + - libcurl-easy (3) + - libcurl-multi (3) + - libcurl-security (3) + - libcurl-thread (3) +--- + +# NAME + +libcurl - client-side URL transfers + +# DESCRIPTION + +This is a short overview on how to use libcurl in your C programs. There are +specific man pages for each function mentioned in here. See +libcurl-easy(3), libcurl-multi(3), libcurl-share(3), +libcurl-url(3), libcurl-ws(3) and libcurl-tutorial(3) for +in-depth understanding on how to program with libcurl. + +There are many bindings available that bring libcurl access to your favorite +language. Look elsewhere for documentation on those. + +# TRANSFERS + +To transfer files, you create an "easy handle" using curl_easy_init(3) +for a single individual transfer (in either direction). You then set your +desired set of options in that handle with curl_easy_setopt(3). Options +you set with curl_easy_setopt(3) stick. They are then used for every +repeated use of this handle until you either change the option, or you reset +them all with curl_easy_reset(3). + +To actually transfer data you have the option of using the "easy" interface, +or the "multi" interface. + +The easy interface is a synchronous interface with which you call +curl_easy_perform(3) and let it perform the transfer. When it is +completed, the function returns and you can continue. More details are found in +the libcurl-easy(3) man page. + +The multi interface on the other hand is an asynchronous interface, that you +call and that performs only a little piece of the transfer on each invoke. It +is perfect if you want to do things while the transfer is in progress, or +similar. The multi interface allows you to select() on libcurl action, and +even to easily download multiple files simultaneously using a single +thread. See further details in the libcurl-multi(3) man page. + +# SUPPORT INTERFACES + +There is also a series of other helpful functions and interface families to +use, including these: + +## curl_version_info() + +gets detailed libcurl (and other used libraries) version info. See +curl_version_info(3) + +## curl_getdate() + +converts a date string to time_t. See curl_getdate(3) + +## curl_easy_getinfo() + +get information about a performed transfer. See curl_easy_getinfo(3) + +## curl_mime_addpart() + +helps building an HTTP form POST. See curl_mime_addpart(3) + +## curl_slist_append() + +builds a linked list. See curl_slist_append(3) + +## Sharing data between transfers + +You can have multiple easy handles share certain data, even if they are used +in different threads. This magic is setup using the share interface, as +described in the libcurl-share(3) man page. + +## URL Parsing + +URL parsing and manipulations. See libcurl-url(3) + +## WebSocket communication + +See libcurl-ws(3) + +# LINKING WITH LIBCURL + +On unix-like machines, there is a tool named curl-config that gets installed +with the rest of the curl stuff when 'make install' is performed. + +curl-config is added to make it easier for applications to link with libcurl +and developers to learn about libcurl and how to use it. + +Run 'curl-config --libs' to get the (additional) linker options you need to +link with the particular version of libcurl you have installed. See the +*curl-config(1)* man page for further details. + +Unix-like operating system that ship libcurl as part of their distributions +often do not provide the curl-config tool, but simply install the library and +headers in the common path for this purpose. + +Many Linux and similar systems use pkg-config to provide build and link +options about libraries and libcurl supports that as well. + +# LIBCURL SYMBOL NAMES + +All public functions in the libcurl interface are prefixed with 'curl_' (with +a lowercase c). You can find other functions in the library source code, but +other prefixes indicate that the functions are private and may change without +further notice in the next release. + +Only use documented functions and functionality! + +# PORTABILITY + +libcurl works +**exactly** +the same, on any of the platforms it compiles and builds on. + +# THREADS + +libcurl is thread safe but there are a few exceptions. Refer to +libcurl-thread(3) for more information. + +# PERSISTENT CONNECTIONS + +Persistent connections means that libcurl can reuse the same connection for +several transfers, if the conditions are right. + +libcurl always attempts to use persistent connections. Whenever you use +curl_easy_perform(3) or curl_multi_perform(3) etc, libcurl +attempts to use an existing connection to do the transfer, and if none exists +it opens a new one that is subject for reuse on a possible following call to +curl_easy_perform(3) or curl_multi_perform(3). + +To allow libcurl to take full advantage of persistent connections, you should +do as many of your file transfers as possible using the same handle. + +If you use the easy interface, and you call curl_easy_cleanup(3), all +the possibly open connections held by libcurl are closed and forgotten. + +When you have created a multi handle and are using the multi interface, the +connection pool is instead kept in the multi handle so closing and creating +new easy handles to do transfers do not affect them. Instead all added easy +handles can take advantage of the single shared pool. + +# GLOBAL CONSTANTS + +There are a variety of constants that libcurl uses, mainly through its +internal use of other libraries, which are too complicated for the +library loader to set up. Therefore, a program must call a library +function after the program is loaded and running to finish setting up +the library code. For example, when libcurl is built for SSL +capability via the GNU TLS library, there is an elaborate tree inside +that library that describes the SSL protocol. + +curl_global_init(3) is the function that you must call. This may +allocate resources (e.g. the memory for the GNU TLS tree mentioned above), so +the companion function curl_global_cleanup(3) releases them. + +If libcurl was compiled with support for multiple SSL backends, the function +curl_global_sslset(3) can be called before curl_global_init(3) +to select the active SSL backend. + +The global constant functions are thread-safe since libcurl 7.84.0 if +curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). Read libcurl-thread(3) for thread safety guidelines. + +If the global constant functions are *not thread safe*, then you must +not call them when any other thread in the program is running. It +is not good enough that no other thread is using libcurl at the time, +because these functions internally call similar functions of other +libraries, and those functions are similarly thread-unsafe. You cannot +generally know what these libraries are, or whether other threads are +using them. + +If the global constant functions are *not thread safe*, then the basic rule +for constructing a program that uses libcurl is this: Call +curl_global_init(3), with a *CURL_GLOBAL_ALL* argument, immediately +after the program starts, while it is still only one thread and before it uses +libcurl at all. Call curl_global_cleanup(3) immediately before the +program exits, when the program is again only one thread and after its last +use of libcurl. + +It is not actually required that the functions be called at the beginning +and end of the program -- that is just usually the easiest way to do it. + +You can call both of these multiple times, as long as all calls meet +these requirements and the number of calls to each is the same. + +The global constant situation merits special consideration when the code you +are writing to use libcurl is not the main program, but rather a modular piece +of a program, e.g. another library. As a module, your code does not know about +other parts of the program -- it does not know whether they use libcurl or +not. Its code does not necessarily run at the start and end of the whole +program. + +A module like this must have global constant functions of its own, just like +curl_global_init(3) and curl_global_cleanup(3). The module thus +has control at the beginning and end of the program and has a place to call +the libcurl functions. If multiple modules in the program use libcurl, they +all separately call the libcurl functions, and that is OK because only the +first curl_global_init(3) and the last curl_global_cleanup(3) in a +program change anything. (libcurl uses a reference count in static memory). + +In a C++ module, it is common to deal with the global constant situation by +defining a special class that represents the global constant environment of +the module. A program always has exactly one object of the class, in static +storage. That way, the program automatically calls the constructor of the +object as the program starts up and the destructor as it terminates. As the +author of this libcurl-using module, you can make the constructor call +curl_global_init(3) and the destructor call curl_global_cleanup(3) +and satisfy libcurl's requirements without your user having to think about it. +(Caveat: If you are initializing libcurl from a Windows DLL you should not +initialize it from *DllMain* or a static initializer because Windows holds +the loader lock during that time and it could cause a deadlock.) + +curl_global_init(3) has an argument that tells what particular parts of +the global constant environment to set up. In order to successfully use any +value except *CURL_GLOBAL_ALL* (which says to set up the whole thing), you +must have specific knowledge of internal workings of libcurl and all other +parts of the program of which it is part. + +A special part of the global constant environment is the identity of the +memory allocator. curl_global_init(3) selects the system default memory +allocator, but you can use curl_global_init_mem(3) to supply one of your +own. However, there is no way to use curl_global_init_mem(3) in a +modular program -- all modules in the program that might use libcurl would +have to agree on one allocator. + +There is a failsafe in libcurl that makes it usable in simple situations +without you having to worry about the global constant environment at all: +curl_easy_init(3) sets up the environment itself if it has not been done +yet. The resources it acquires to do so get released by the operating system +automatically when the program exits. + +This failsafe feature exists mainly for backward compatibility because there +was a time when the global functions did not exist. Because it is sufficient +only in the simplest of programs, it is not recommended for any program to +rely on it. diff --git a/docs/libcurl/mksymbolsmanpage.pl b/docs/libcurl/mksymbolsmanpage.pl new file mode 100755 index 0000000..d7b9a77 --- /dev/null +++ b/docs/libcurl/mksymbolsmanpage.pl @@ -0,0 +1,311 @@ +#!/usr/bin/env perl +# *************************************************************************** +# * _ _ ____ _ +# * Project ___| | | | _ \| | +# * / __| | | | |_) | | +# * | (__| |_| | _ <| |___ +# * \___|\___/|_| \_\_____| +# * +# * Copyright (C) Daniel Stenberg, , et al. +# * +# * This software is licensed as described in the file COPYING, which +# * you should have received as part of this distribution. The terms +# * are also available at https://curl.se/docs/copyright.html. +# * +# * You may opt to use, copy, modify, merge, publish, distribute and/or sell +# * copies of the Software, and permit persons to whom the Software is +# * furnished to do so, under the terms of the COPYING file. +# * +# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# * KIND, either express or implied. +# * +# * SPDX-License-Identifier: curl +# * +# *************************************************************************** + +use POSIX qw(strftime); +my @ts; +if (defined($ENV{SOURCE_DATE_EPOCH})) { + @ts = localtime($ENV{SOURCE_DATE_EPOCH}); +} else { + @ts = localtime; +} +my $date = strftime "%b %e, %Y", @ts; +my $year = strftime "%Y", @ts; + +print <
, et al. +SPDX-License-Identifier: curl +Title: libcurl-symbols +Section: 3 +Source: libcurl +See-also: + - libcurl (3) + - libcurl-easy (3) + - libcurl-multi (3) + - libcurl-security (3) + - libcurl-thread (3) +--- +# libcurl symbols + +This man page details version information for public symbols provided in the +libcurl header files. This lists the first version in which the symbol was +introduced and for some symbols two additional information pieces: + +The first version in which the symbol is marked "deprecated" - meaning that +since that version no new code should be written to use the symbol as it is +marked for getting removed in a future. + +The last version that featured the specific symbol. Using the symbol in source +code will make it no longer compile error-free after that specified version. + +This man page is automatically generated from the symbols-in-versions file. +HEADER + ; + +sub nameref { + my ($n)=@_; + if($n =~ /^CURLOPT_/) { + if($n eq "CURLOPT_RTSPHEADER") { + $n = "CURLOPT_HTTPHEADER"; + } + elsif($n eq "CURLOPT_WRITEHEADER") { + $n = "CURLOPT_HEADERDATA"; + } + elsif($n eq "CURLOPT_WRITEINFO") { + ; # now obsolete + } + else { + return "$n(3)"; + } + } + elsif($n =~ /^CURLMOPT_/) { + return "$n(3)"; + } + elsif($n =~ /^CURLINFO_/) { + my %infotypes = ( + 'CURLINFO_TEXT' => 1, + 'CURLINFO_HEADER_IN' => 1, + 'CURLINFO_HEADER_OUT' => 1, + 'CURLINFO_DATA_IN' => 1, + 'CURLINFO_DATA_OUT' => 1, + 'CURLINFO_SSL_DATA_IN' => 1, + 'CURLINFO_SSL_DATA_OUT' => 1, + ); + if($infotypes{$n}) { + return "CURLOPT_DEBUGFUNCTION(3)"; + } + } + elsif($n =~ /^CURLALTSVC_/) { + return "CURLOPT_ALTSVC_CTRL(3)"; + } + elsif($n =~ /^CURLAUTH_/) { + return "CURLOPT_HTTPAUTH(3)"; + } + elsif($n =~ /^CURLFORM_/) { + return "curl_formadd(3)"; + } + elsif($n =~ /^CURLKH/) { + return "CURLOPT_SSH_KEYFUNCTION(3)"; + } + elsif($n =~ /^CURLE_/) { + return "libcurl-errors(3)"; + } + elsif($n =~ /^CURLM_/) { + return "libcurl-errors(3)"; + } + elsif($n =~ /^CURLUE_/) { + return "libcurl-errors(3)"; + } + elsif($n =~ /^CURLHE_/) { + return "libcurl-errors(3)"; + } + elsif($n =~ /^CURLSHE_/) { + return "libcurl-errors(3)"; + } + elsif($n =~ /^CURLPROTO_/) { + return "CURLINFO_PROTOCOL(3)"; + } + elsif($n =~ /^CURLPX_/) { + return "CURLINFO_PROXY_ERROR(3)"; + } + elsif($n =~ /^CURLPROXY_/) { + return "CURLOPT_PROXYTYPE(3)"; + } + elsif($n =~ /^CURLSSLBACKEND_/) { + return "curl_global_sslset(3)"; + } + elsif($n =~ /^CURLSSLOPT_/) { + return "CURLOPT_SSL_OPTIONS(3)"; + } + elsif($n =~ /^CURLSSLSET_/) { + return "curl_global_sslset(3)"; + } + elsif($n =~ /^CURLUPART_/) { + return "curl_url_get(3)"; + } + elsif($n =~ /^CURLU_/) { + return "curl_url_get(3)"; + } + elsif($n =~ /^CURLVERSION_/) { + return "curl_version_info(3)"; + } + elsif($n =~ /^CURLSHOPT_/) { + if($n eq "CURLSHOPT_NONE") { + $n = "curl_share_setopt"; + } + return "$n(3)"; + } + elsif($n =~ /^CURLWS_/) { + return "curl_ws_send(3)"; + } + elsif($n =~ /^CURL_FORMADD_/) { + return "curl_formadd(3)"; + } + elsif($n =~ /^CURL_HTTPPOST_/) { + return "curl_formadd(3)"; + } + elsif($n =~ /^CURL_GLOBAL_/) { + return "curl_global_init(3)"; + } + elsif($n =~ /^CURL_HTTP_VERSION_/) { + return "CURLOPT_HTTP_VERSION(3)"; + } + elsif($n =~ /^CURL_LOCK_/) { + return "CURLSHOPT_SHARE(3)"; + } + elsif($n =~ /^CURL_SSLVERSION_/) { + return "CURLOPT_SSLVERSION(3)"; + } + elsif($n =~ /^CURL_VERSION_/) { + return "curl_version_info(3)"; + } + elsif($n =~ /^CURL_RTSPREQ_/) { + return "CURLOPT_RTSP_REQUEST(3)"; + } + elsif($n =~ /^CURLH_/) { + return "curl_easy_header(3)"; + } + elsif($n =~ /^CURL_TRAILERFUNC_/) { + return "CURLOPT_TRAILERFUNCTION(3)"; + } + elsif($n =~ /^CURLOT_/) { + return "curl_easy_option_next(3)"; + } + elsif($n =~ /^CURLFINFOFLAG_/) { + return "CURLOPT_CHUNK_BGN_FUNCTION(3)"; + } + elsif($n =~ /^CURLFILETYPE_/) { + return "CURLOPT_CHUNK_BGN_FUNCTION(3)"; + } + elsif($n =~ /^CURL_CHUNK_BGN_FUNC_/) { + return "CURLOPT_CHUNK_BGN_FUNCTION(3)"; + } + elsif($n =~ /^CURL_CHUNK_END_FUNC_/) { + return "CURLOPT_CHUNK_END_FUNCTION(3)"; + } + elsif($n =~ /^CURLSSH_AUTH_/) { + return "CURLOPT_SSH_AUTH_TYPES(3)"; + } + elsif($n =~ /^CURL_POLL_/) { + return "CURLMOPT_SOCKETFUNCTION(3)"; + } + elsif($n =~ /^CURLMSG_/) { + return "curl_multi_info_read(3)"; + } + elsif($n =~ /^CURLFTPAUTH_/) { + return "CURLOPT_FTPSSLAUTH(3)"; + } + elsif($n =~ /^CURLFTPMETHOD_/) { + return "CURLOPT_FTP_FILEMETHOD(3)"; + } + elsif($n =~ /^CURLFTPSSL_/) { + return "CURLOPT_USE_SSL(3)"; + } + elsif($n =~ /^CURLFTP_CREATE_/) { + return "CURLOPT_FTP_CREATE_MISSING_DIRS(3)"; + } + elsif($n =~ /^CURLGSSAPI_DELEGATION_/) { + return "CURLOPT_GSSAPI_DELEGATION(3)"; + } + elsif($n =~ /^CURLHEADER_/) { + return "CURLOPT_HEADEROPT(3)"; + } + elsif($n =~ /^CURLHSTS_/) { + return "CURLOPT_HSTS_CTRL(3)"; + } + elsif($n =~ /^CURLIOCMD_/) { + return "CURLOPT_IOCTLFUNCTION(3)"; + } + elsif($n =~ /^CURLIOE_/) { + return "CURLOPT_IOCTLFUNCTION(3)"; + } + elsif($n =~ /^CURLMIMEOPT_/) { + return "CURLOPT_MIME_OPTIONS(3)"; + } + elsif($n =~ /^CURLPAUSE_/) { + return "curl_easy_pause(3)"; + } + elsif($n =~ /^CURLPIPE_/) { + return "CURLMOPT_PIPELINING(3)"; + } + elsif($n =~ /^CURLSOCKTYPE_/) { + return "CURLOPT_SOCKOPTFUNCTION(3)"; + } + elsif($n =~ /^CURLSTS_/) { + return "CURLOPT_HSTSREADFUNCTION(3)"; + } + elsif($n =~ /^CURLUSESSL_/) { + return "CURLOPT_USE_SSL(3)"; + } + elsif($n =~ /^CURL_CSELECT_/) { + return "curl_multi_socket_action(3)"; + } + elsif($n =~ /^CURL_FNMATCHFUNC_/) { + return "CURLOPT_FNMATCH_FUNCTION(3)"; + } + elsif($n =~ /^CURL_HET_/) { + return "CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3)"; + } + elsif($n =~ /^CURL_IPRESOLVE_/) { + return "CURLOPT_IPRESOLVE(3)"; + } + elsif($n =~ /^CURL_SEEKFUNC_/) { + return "CURLOPT_SEEKFUNCTION(3)"; + } + elsif($n =~ /^CURL_TIMECOND_/) { + return "CURLOPT_TIMECONDITION(3)"; + } + elsif($n =~ /^CURL_REDIR_POST_/) { + return "CURLOPT_POSTREDIR(3)"; + } +} + +while() { + if($_ =~ /^(CURL[A-Z0-9_.]*) *(.*)/i) { + my ($symbol, $rest)=($1,$2); + my ($intro, $dep, $rem); + if($rest =~ s/^([0-9.]*) *//) { + $intro = $1; + } + if($rest =~ s/^([0-9.]*) *//) { + $dep = $1; + } + if($rest =~ s/^- *([0-9.]*)//) { + $rem = $1; + } + print "\n## $symbol\nIntroduced in $intro."; + if($dep) { + print " Deprecated since $dep."; + } + if($rem) { + print " Last used in $rem."; + } + my $see = $rem || $dep ? "" : nameref($symbol); + if($see) { + print " See $see."; + } + print "\n"; + } +} diff --git a/docs/libcurl/opts/CMakeLists.txt b/docs/libcurl/opts/CMakeLists.txt new file mode 100644 index 0000000..82844a2 --- /dev/null +++ b/docs/libcurl/opts/CMakeLists.txt @@ -0,0 +1,34 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# Load man_MANS from shared file +transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") + +add_manual_pages(man_MANS) +add_custom_target(opts-man DEPENDS ${man_MANS}) +add_dependencies(man opts-man) +if(NOT CURL_DISABLE_INSTALL) + install(FILES "$" + DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) +endif() diff --git a/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md b/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md new file mode 100644 index 0000000..7e106ed --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_ACTIVESOCKET +Section: 3 +Source: libcurl +See-also: + - CURLINFO_LASTSOCKET (3) + - CURLOPT_CONNECT_ONLY (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_ACTIVESOCKET - get the active socket + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_ACTIVESOCKET, + curl_socket_t *socket); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_socket_t to receive the most recently active socket +used for the transfer connection by this curl session. If the socket is no +longer valid, *CURL_SOCKET_BAD* is returned. When you are finished working +with the socket, you must call curl_easy_cleanup(3) as usual on the easy +handle and let libcurl close the socket and cleanup other resources associated +with the handle. This option returns the active socket only after the transfer +is complete, and is typically used in combination with +CURLOPT_CONNECT_ONLY(3), which skips the transfer phase. + +CURLINFO_ACTIVESOCKET(3) was added as a replacement for +CURLINFO_LASTSOCKET(3) since that one is not working on all platforms. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_socket_t sockfd; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Do not do the transfer - only connect to host */ + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); + res = curl_easy_perform(curl); + + /* Extract the socket from the curl handle */ + res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd); + + if(res != CURLE_OK) { + printf("Error: %s\n", curl_easy_strerror(res)); + return 1; + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.45.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md new file mode 100644 index 0000000..17fb465 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_APPCONNECT_TIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_APPCONNECT_TIME_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_APPCONNECT_TIME - get the time until the SSL/SSH handshake is completed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_APPCONNECT_TIME, + double *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the time, in seconds, it took from the +start until the SSL/SSH connect/handshake to the remote host was completed. +This time is most often close to the CURLINFO_PRETRANSFER_TIME(3) time, +except for cases such as HTTP pipelining where the pretransfer time can be +delayed due to waits in line for the pipeline and more. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + double connect; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &connect); + if(CURLE_OK == res) { + printf("Time: %.1f", connect); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md new file mode 100644 index 0000000..cc4f2b8 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_APPCONNECT_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_APPCONNECT_TIME (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_APPCONNECT_TIME_T - time until the SSL/SSH handshake completed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_APPCONNECT_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the time, in microseconds, it took +from the start until the SSL/SSH connect/handshake to the remote host was +completed. This time is most often close to the +CURLINFO_PRETRANSFER_TIME_T(3) time, except for cases such as HTTP +pipelining where the pretransfer time can be delayed due to waits in line for +the pipeline and more. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t connect; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME_T, &connect); + if(CURLE_OK == res) { + printf("Time: %" CURL_FORMAT_CURL_OFF_T ".%06ld", connect / 1000000, + (long)(connect % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CAINFO.md b/docs/libcurl/opts/CURLINFO_CAINFO.md new file mode 100644 index 0000000..44b2539 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CAINFO.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CAINFO +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CAPATH (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CAINFO - get the default built-in CA certificate path + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CAINFO, char **path); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the pointer to a null-terminated +string holding the default built-in path used for the CURLOPT_CAINFO(3) +option unless set by the user. + +Note that in a situation where libcurl has been built to support multiple TLS +libraries, this option might return a string even if the specific TLS library +currently set to be used does not support CURLOPT_CAINFO(3). + +This is a path identifying a single file containing CA certificates. + +The **path** pointer is set to NULL if there is no default path. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + char *cainfo = NULL; + curl_easy_getinfo(curl, CURLINFO_CAINFO, &cainfo); + if(cainfo) { + printf("default ca info path: %s\n", cainfo); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.84.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CAPATH.md b/docs/libcurl/opts/CURLINFO_CAPATH.md new file mode 100644 index 0000000..46499e7 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CAPATH.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CAPATH +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CAINFO (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CAPATH - get the default built-in CA path string + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CAPATH, char **path); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the pointer to a null-terminated +string holding the default built-in path used for the CURLOPT_CAPATH(3) +option unless set by the user. + +Note that in a situation where libcurl has been built to support multiple TLS +libraries, this option might return a string even if the specific TLS library +currently set to be used does not support CURLOPT_CAPATH(3). + +This is a path identifying a directory. + +The **path** pointer is set to NULL if there is no default path. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + char *capath = NULL; + curl_easy_getinfo(curl, CURLINFO_CAPATH, &capath); + if(capath) { + printf("default ca path: %s\n", capath); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.84.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CERTINFO.md b/docs/libcurl/opts/CURLINFO_CERTINFO.md new file mode 100644 index 0000000..d9cbc93 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CERTINFO.md @@ -0,0 +1,101 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CERTINFO +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CAPATH (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CERTINFO - get the TLS certificate chain + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CERTINFO, + struct curl_certinfo **chainp); +~~~ + +# DESCRIPTION + +Pass a pointer to a *struct curl_certinfo ** and it is set to point to a +struct that holds info about the server's certificate chain, assuming you had +CURLOPT_CERTINFO(3) enabled when the request was made. + +~~~c +struct curl_certinfo { + int num_of_certs; + struct curl_slist **certinfo; +}; +~~~ + +The *certinfo* struct member is an array of linked lists of certificate +information. The *num_of_certs* struct member is the number of certificates +which is the number of elements in the array. Each certificate's list has +items with textual information in the format "name:content" such as +"Subject:Foo", "Issuer:Bar", etc. The items in each list varies depending on +the SSL backend and the certificate. + +# PROTOCOLS + +All TLS-based + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); + + /* connect to any HTTPS site, trusted or not */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + + curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); + + res = curl_easy_perform(curl); + + if(!res) { + int i; + struct curl_certinfo *ci; + res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &ci); + + if(!res) { + printf("%d certs!\n", ci->num_of_certs); + + for(i = 0; i < ci->num_of_certs; i++) { + struct curl_slist *slist; + + for(slist = ci->certinfo[i]; slist; slist = slist->next) + printf("%s\n", slist->data); + } + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +See also the *certinfo.c* example. + +# AVAILABILITY + +This option is only working in libcurl built with OpenSSL, GnuTLS, Schannel or +Secure Transport. GnuTLS support added in 7.42.0. Schannel support added in +7.50.0. Secure Transport support added in 7.79.0. + +Added in 7.19.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md b/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md new file mode 100644 index 0000000..aca04f1 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONDITION_UNMET +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TIMECONDITION (3) + - CURLOPT_TIMEVALUE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONDITION_UNMET - get info on unmet time conditional or 304 HTTP response. + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONDITION_UNMET, + long *unmet); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the number 1 if the condition provided in +the previous request did not match (see CURLOPT_TIMECONDITION(3)). Alas, +if this returns a 1 you know that the reason you did not get data in return is +because it did not fulfill the condition. The long this argument points to +gets a zero stored if the condition instead was met. This can also return 1 if +the server responded with a 304 HTTP status code, for example after sending a +custom "If-Match-*" header. + +# PROTOCOLS + +HTTP and some + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* January 1, 2020 is 1577833200 */ + curl_easy_setopt(curl, CURLOPT_TIMEVALUE, 1577833200L); + + /* If-Modified-Since the above time stamp */ + curl_easy_setopt(curl, CURLOPT_TIMECONDITION, + (long)CURL_TIMECOND_IFMODSINCE); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + /* check the time condition */ + long unmet; + res = curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &unmet); + if(!res) { + printf("The time condition was %sfulfilled\n", unmet?"NOT":""); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md b/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md new file mode 100644 index 0000000..1fde766 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONNECT_TIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONNECT_TIME_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONNECT_TIME - get the time until connect + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONNECT_TIME, double *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the total time in seconds from the start +until the connection to the remote host (or proxy) was completed. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + double connect; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &connect); + if(CURLE_OK == res) { + printf("Time: %.1f", connect); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md b/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md new file mode 100644 index 0000000..cd72cdd --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONNECT_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONNECT_TIME (3) + - CURLOPT_CONNECTTIMEOUT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONNECT_TIME_T - get the time until connect + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONNECT_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the total time in microseconds from +the start until the connection to the remote host (or proxy) was completed. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t connect; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME_T, &connect); + if(CURLE_OK == res) { + printf("Time: %" CURL_FORMAT_CURL_OFF_T ".%06ld", connect / 1000000, + (long)(connect % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONN_ID.md b/docs/libcurl/opts/CURLINFO_CONN_ID.md new file mode 100644 index 0000000..d4791b4 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONN_ID.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONN_ID +Section: 3 +Source: libcurl +See-also: + - CURLINFO_XFER_ID (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONN_ID - get the ID of the last connection used by the handle + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONN_ID, + curl_off_t *conn_id); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the connection identifier last +used by the handle. Stores -1 if there was no connection used. + +The connection id is unique among all connections using the same +connection cache. This is implicitly the case for all connections in the +same multi handle. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + curl_off_t conn_id; + res = curl_easy_getinfo(curl, CURLINFO_CONN_ID, &conn_id); + if(!res) { + printf("Connection used: %" CURL_FORMAT_CURL_OFF_T "\n", conn_id); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 8.2.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md new file mode 100644 index 0000000..1e01419 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONTENT_LENGTH_DOWNLOAD +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONTENT_LENGTH_UPLOAD (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONTENT_LENGTH_DOWNLOAD - get content-length of download + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, + double *content_length); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the content-length of the download. This +is the value read from the Content-Length: field. Since 7.19.4, this returns +-1 if the size is not known. + +CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) is a newer replacement that returns a more +sensible variable type. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + /* check the size */ + double cl; + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl); + if(!res) { + printf("Size: %.0f\n", cl); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.6.1. Deprecated since 7.55.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md new file mode 100644 index 0000000..15016c8 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONTENT_LENGTH_DOWNLOAD_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONTENT_LENGTH_DOWNLOAD_T - get content-length of download + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, + curl_off_t *content_length); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the content-length of the +download. This is the value read from the Content-Length: field. Stores -1 if +the size is not known. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + /* check the size */ + curl_off_t cl; + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl); + if(!res) { + printf("Download size: %" CURL_FORMAT_CURL_OFF_T "\n", cl); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md new file mode 100644 index 0000000..c90e19e --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONTENT_LENGTH_UPLOAD +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONTENT_LENGTH_UPLOAD - get the specified size of the upload + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_UPLOAD, + double *content_length); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the specified size of the upload. Since +7.19.4, this returns -1 if the size is not known. + +CURLINFO_CONTENT_LENGTH_UPLOAD_T(3) is a newer replacement that returns a +more sensible variable type. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the upload */ + res = curl_easy_perform(curl); + + if(!res) { + /* check the size */ + double cl; + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &cl); + if(!res) { + printf("Size: %.0f\n", cl); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.6.1. Deprecated since 7.55.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md new file mode 100644 index 0000000..319a334 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONTENT_LENGTH_UPLOAD_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONTENT_LENGTH_UPLOAD_T - get the specified size of the upload + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_UPLOAD_T, + curl_off_t *content_length); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the specified size of the +upload. Stores -1 if the size is not known. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the upload */ + res = curl_easy_perform(curl); + + if(!res) { + /* check the size */ + curl_off_t cl; + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_UPLOAD_T, &cl); + if(!res) { + printf("Upload size: %" CURL_FORMAT_CURL_OFF_T "\n", cl); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md new file mode 100644 index 0000000..b874572 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_CONTENT_TYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERFUNCTION (3) + - curl_easy_getinfo (3) + - curl_easy_header (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_CONTENT_TYPE - get Content-Type + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_TYPE, char **ct); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the content-type of the downloaded +object. This is the value read from the Content-Type: field. If you get NULL, +it means that the server did not send a valid Content-Type header or that the +protocol used does not support this. + +The **ct** pointer is set to NULL or pointing to private memory. You MUST +NOT free it - it gets freed when you call curl_easy_cleanup(3) on the +corresponding CURL handle. + +The modern way to get this header from a response is to instead use the +curl_easy_header(3) function. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + res = curl_easy_perform(curl); + + if(!res) { + /* extract the content-type */ + char *ct = NULL; + res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct); + if(!res && ct) { + printf("Content-Type: %s\n", ct); + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_COOKIELIST.md b/docs/libcurl/opts/CURLINFO_COOKIELIST.md new file mode 100644 index 0000000..60ac0f0 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_COOKIELIST.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_COOKIELIST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_COOKIELIST (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_COOKIELIST - get all known cookies + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_COOKIELIST, + struct curl_slist **cookies); +~~~ + +# DESCRIPTION + +Pass a pointer to a 'struct curl_slist *' to receive a linked-list of all +cookies curl knows (expired ones, too). Do not forget to call +curl_slist_free_all(3) on the list after it has been used. If there are no +cookies (cookies for the handle have not been enabled or simply none have been +received) the 'struct curl_slist *' is made a NULL pointer. + +Since 7.43.0 cookies that were imported in the Set-Cookie format without a +domain name are not exported by this option. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* enable the cookie engine */ + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); + + res = curl_easy_perform(curl); + + if(!res) { + /* extract all known cookies */ + struct curl_slist *cookies = NULL; + res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies); + if(!res && cookies) { + /* a linked list of cookies in cookie file format */ + struct curl_slist *each = cookies; + while(each) { + printf("%s\n", each->data); + each = each->next; + } + /* we must free these cookies when we are done */ + curl_slist_free_all(cookies); + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.14.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md new file mode 100644 index 0000000..da2e2a0 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_EFFECTIVE_METHOD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CUSTOMREQUEST (3) + - CURLOPT_FOLLOWLOCATION (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_EFFECTIVE_METHOD - get the last used HTTP method + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_EFFECTIVE_METHOD, + char **methodp); +~~~ + +# DESCRIPTION + +Pass in a pointer to a char pointer and get the last used effective HTTP +method. + +In cases when you have asked libcurl to follow redirects, the method may not be +the same method the first request would use. + +The **methodp** pointer is NULL or points to private memory. You MUST NOT +free - it gets freed when you call curl_easy_cleanup(3) on the +corresponding CURL handle. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "data"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + char *method = NULL; + curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_METHOD, &method); + if(method) + printf("Redirected to method: %s\n", method); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.72.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md new file mode 100644 index 0000000..268ff2c --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_EFFECTIVE_URL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FOLLOWLOCATION (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_EFFECTIVE_URL - get the last used URL + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_EFFECTIVE_URL, char **urlp); +~~~ + +# DESCRIPTION + +Pass in a pointer to a char pointer and get the last used effective URL. + +In cases when you have asked libcurl to follow redirects, it may not be the same +value you set with CURLOPT_URL(3). + +The **urlp** pointer is NULL or points to private memory. You MUST NOT free +- it gets freed when you call curl_easy_cleanup(3) on the corresponding +CURL handle. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + char *url = NULL; + curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); + if(url) + printf("Redirect to: %s\n", url); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_FILETIME.md b/docs/libcurl/opts/CURLINFO_FILETIME.md new file mode 100644 index 0000000..77ef534 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_FILETIME.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_FILETIME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FILETIME (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_FILETIME - get the remote time of the retrieved document + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FILETIME, long *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the remote time of the retrieved document +in number of seconds since January 1 1970 in the GMT/UTC time zone. If you get +-1, it can be because of many reasons (it might be unknown, the server might +hide it or the server does not support the command that tells document time +etc) and the time of the document is unknown. + +You must tell libcurl to collect this information before the transfer is made, +by using the CURLOPT_FILETIME(3) option to curl_easy_setopt(3) or +you this unconditionally gets a -1 back. + +Consider using CURLINFO_FILETIME_T(3) to be able to extract dates beyond +the year 2038 on systems using 32 bit longs (Windows). + +# PROTOCOLS + +HTTP(S), FTP(S), SFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* Ask for filetime */ + curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + long filetime = 0; + res = curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); + if((CURLE_OK == res) && (filetime >= 0)) { + time_t file_time = (time_t)filetime; + printf("filetime: %s", ctime(&file_time)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.5 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_FILETIME_T.md b/docs/libcurl/opts/CURLINFO_FILETIME_T.md new file mode 100644 index 0000000..62c5f3c --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_FILETIME_T.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_FILETIME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FILETIME (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_FILETIME_T - get the remote time of the retrieved document + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FILETIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the remote time of the retrieved +document in number of seconds since January 1 1970 in the GMT/UTC time +zone. If you get -1, it can be because of many reasons (it might be unknown, +the server might hide it or the server does not support the command that tells +document time etc) and the time of the document is unknown. + +You must ask libcurl to collect this information before the transfer is made, +by using the CURLOPT_FILETIME(3) option to curl_easy_setopt(3) or +you unconditionally get a -1 back. + +This option is an alternative to CURLINFO_FILETIME(3) to allow systems +with 32 bit long variables to extract dates outside of the 32bit timestamp +range. + +# PROTOCOLS + +HTTP(S), FTP(S), SFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* Ask for filetime */ + curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + curl_off_t filetime; + res = curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime); + if((CURLE_OK == res) && (filetime >= 0)) { + time_t file_time = (time_t)filetime; + printf("filetime: %s", ctime(&file_time)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.59.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md new file mode 100644 index 0000000..344e1f1 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_FTP_ENTRY_PATH +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_FTP_ENTRY_PATH - get entry path in FTP server + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FTP_ENTRY_PATH, char **path); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive a pointer to a string holding the +path of the entry path. That is the initial path libcurl ended up in when +logging on to the remote FTP server. This stores a NULL as pointer if +something is wrong. + +The **path** pointer is NULL or points to private memory. You MUST NOT free +- it gets freed when you call curl_easy_cleanup(3) on the corresponding +CURL handle. + +# PROTOCOLS + +FTP(S) and SFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com"); + + res = curl_easy_perform(curl); + + if(!res) { + /* extract the entry path */ + char *ep = NULL; + res = curl_easy_getinfo(curl, CURLINFO_FTP_ENTRY_PATH, &ep); + if(!res && ep) { + printf("Entry path was: %s\n", ep); + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.4. Works for SFTP since 7.21.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md b/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md new file mode 100644 index 0000000..67ccfc2 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_HEADER_SIZE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REQUEST_SIZE (3) + - CURLINFO_SIZE_DOWNLOAD (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_HEADER_SIZE - get size of retrieved headers + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HEADER_SIZE, long *sizep); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the total size of all the headers +received. Measured in number of bytes. + +The total includes the size of any received headers suppressed by +CURLOPT_SUPPRESS_CONNECT_HEADERS(3). + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long size; + res = curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &size); + if(!res) + printf("Header size: %ld bytes\n", size); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md b/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md new file mode 100644 index 0000000..574e0a5 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_HTTPAUTH_AVAIL +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PROXYAUTH_AVAIL (3) + - CURLOPT_HTTPAUTH (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_HTTPAUTH_AVAIL - get available HTTP authentication methods + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTPAUTH_AVAIL, long *authp); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive a bitmask indicating the authentication +method(s) available according to the previous response. The meaning of the +bits is explained in the CURLOPT_HTTPAUTH(3) option for +curl_easy_setopt(3). + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + res = curl_easy_perform(curl); + + if(!res) { + /* extract the available authentication types */ + long auth; + res = curl_easy_getinfo(curl, CURLINFO_HTTPAUTH_AVAIL, &auth); + if(!res) { + if(!auth) + printf("No auth available, perhaps no 401?\n"); + else { + printf("%s%s%s%s\n", + auth & CURLAUTH_BASIC ? "Basic ":"", + auth & CURLAUTH_DIGEST ? "Digest ":"", + auth & CURLAUTH_NEGOTIATE ? "Negotiate ":"", + auth % CURLAUTH_NTLM ? "NTLM ":""); + } + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added RFC 2617 in 7.10.8 +Added RFC 7616 in 7.57.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md b/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md new file mode 100644 index 0000000..ee3f0f6 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_HTTP_CONNECTCODE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RESPONSE_CODE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_HTTP_CONNECTCODE - get the CONNECT response code + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTP_CONNECTCODE, long *p); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the last received HTTP proxy response code +to a CONNECT request. The returned value is zero if no such response code was +available. + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* typically CONNECT is used to do HTTPS over HTTP proxies */ + curl_easy_setopt(curl, CURLOPT_PROXY, "http://127.0.0.1"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long code; + res = curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE, &code); + if(!res && code) + printf("The CONNECT response code: %03ld\n", code); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.7 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md b/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md new file mode 100644 index 0000000..994d771 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_HTTP_VERSION +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RESPONSE_CODE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_HTTP_VERSION - get the http version used in the connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTP_VERSION, long *p); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the version used in the last http +connection done using this handle. The returned value is +CURL_HTTP_VERSION_1_0, CURL_HTTP_VERSION_1_1, CURL_HTTP_VERSION_2_0, +CURL_HTTP_VERSION_3 or 0 if the version cannot be determined. + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long http_version; + curl_easy_getinfo(curl, CURLINFO_HTTP_VERSION, &http_version); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.50.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_LASTSOCKET.md b/docs/libcurl/opts/CURLINFO_LASTSOCKET.md new file mode 100644 index 0000000..b1619eb --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_LASTSOCKET.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_LASTSOCKET +Section: 3 +Source: libcurl +See-also: + - CURLINFO_ACTIVESOCKET (3) + - CURLOPT_CONNECT_ONLY (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_LASTSOCKET - get the last socket used + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_LASTSOCKET, long *socket); +~~~ + +# DESCRIPTION + +Deprecated since 7.45.0. Use CURLINFO_ACTIVESOCKET(3) instead. + +Pass a pointer to a long to receive the last socket used by this curl +session. If the socket is no longer valid, -1 is returned. When you finish +working with the socket, you must call curl_easy_cleanup(3) as usual and +let libcurl close the socket and cleanup other resources associated with the +handle. This is typically used in combination with +CURLOPT_CONNECT_ONLY(3). + +NOTE: this API is deprecated since it is not working on win64 where the SOCKET +type is 64 bits large while its 'long' is 32 bits. Use the +CURLINFO_ACTIVESOCKET(3) instead, if possible. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + long sockfd; /* does not work on win64! */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Do not do the transfer - only connect to host */ + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); + res = curl_easy_perform(curl); + + /* Extract the socket from the curl handle */ + res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockfd); + + if(res != CURLE_OK) { + printf("Error: %s\n", curl_easy_strerror(res)); + return 1; + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_LOCAL_IP.md b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md new file mode 100644 index 0000000..e70d0cf --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_LOCAL_IP +Section: 3 +Source: libcurl +See-also: + - CURLINFO_LOCAL_PORT (3) + - CURLINFO_PRIMARY_IP (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_LOCAL_IP - get local IP address of last connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_LOCAL_IP, char **ip); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the pointer to a null-terminated +string holding the IP address of the local end of most recent connection done +with this **curl** handle. This string may be IPv6 when that is +enabled. Note that you get a pointer to a memory area that is reused at next +request so you need to copy the string if you want to keep the information. + +The **ip** pointer is NULL or points to private memory. You MUST NOT free - +it gets freed when you call curl_easy_cleanup(3) on the corresponding +CURL handle. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + char *ip; + CURLcode res; + CURL *curl = curl_easy_init(); + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the transfer */ + res = curl_easy_perform(curl); + /* Check for errors */ + if((res == CURLE_OK) && + !curl_easy_getinfo(curl, CURLINFO_LOCAL_IP, &ip) && ip) { + printf("Local IP: %s\n", ip); + } + + /* always cleanup */ + curl_easy_cleanup(curl); +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md b/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md new file mode 100644 index 0000000..055fc2e --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_LOCAL_PORT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_LOCAL_IP (3) + - CURLINFO_PRIMARY_PORT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_LOCAL_PORT - get the latest local port number + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_LOCAL_PORT, long *portp); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the local port number of the most recent +connection done with this **curl** handle. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + + if(CURLE_OK == res) { + long port; + res = curl_easy_getinfo(curl, CURLINFO_LOCAL_PORT, &port); + + if(CURLE_OK == res) { + printf("We used local port: %ld\n", port); + } + } + curl_easy_cleanup(curl); + } + return 0; +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md new file mode 100644 index 0000000..8cf425e --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_NAMELOOKUP_TIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_NAMELOOKUP_TIME_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_NAMELOOKUP_TIME - get the name lookup time + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_NAMELOOKUP_TIME, + double *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the total time in seconds from the start +until the name resolving was completed. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + double namelookup; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &namelookup); + if(CURLE_OK == res) { + printf("Time: %.1f", namelookup); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md new file mode 100644 index 0000000..a3fd4dd --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_NAMELOOKUP_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_NAMELOOKUP_TIME (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_NAMELOOKUP_TIME_T - get the name lookup time in microseconds + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_NAMELOOKUP_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the total time in microseconds +from the start until the name resolving was completed. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t namelookup; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME_T, &namelookup); + if(CURLE_OK == res) { + printf("Time: %" CURL_FORMAT_CURL_OFF_T ".%06ld", namelookup / 1000000, + (long)(namelookup % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md b/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md new file mode 100644 index 0000000..5127a0a --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_NUM_CONNECTS +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_NUM_CONNECTS - get number of created connections + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_NUM_CONNECTS, long *nump); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive how many new connections libcurl had to +create to achieve the previous transfer (only the successful connects are +counted). Combined with CURLINFO_REDIRECT_COUNT(3) you are able to know how +many times libcurl successfully reused existing connection(s) or not. See the +connection options of curl_easy_setopt(3) to see how libcurl tries to make +persistent connections to save time. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long connects; + res = curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &connects); + if(res) + printf("It needed %ld connects\n", connects); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.12.3 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_OS_ERRNO.md b/docs/libcurl/opts/CURLINFO_OS_ERRNO.md new file mode 100644 index 0000000..3fb69b4 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_OS_ERRNO.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_OS_ERRNO +Section: 3 +Source: libcurl +See-also: + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_OS_ERRNO - get errno number from last connect failure + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_OS_ERRNO, long *errnop); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the errno variable from a connect failure. +Note that the value is only set on failure, it is not reset upon a successful +operation. The number is OS and system specific. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res != CURLE_OK) { + long error; + res = curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &error); + if(res && error) { + printf("Errno: %ld\n", error); + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.12.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md new file mode 100644 index 0000000..8eda23a --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PRETRANSFER_TIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONNECT_TIME_T (3) + - CURLINFO_PRETRANSFER_TIME_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PRETRANSFER_TIME - get the time until the file transfer start + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRETRANSFER_TIME, + double *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the time, in seconds, it took from the +start until the file transfer is just about to begin. + +This time-stamp includes all pre-transfer commands and negotiations that are +specific to the particular protocol(s) involved. It includes the sending of +the protocol-specific instructions that trigger a transfer. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + double pretransfer; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &pretransfer); + if(CURLE_OK == res) { + printf("Time: %.1f", pretransfer); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md new file mode 100644 index 0000000..50c515f --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PRETRANSFER_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONNECT_TIME (3) + - CURLINFO_PRETRANSFER_TIME_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PRETRANSFER_TIME_T - get the time until the file transfer start + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRETRANSFER_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the time, in microseconds, it took +from the start until the file transfer is just about to begin. + +This time-stamp includes all pre-transfer commands and negotiations that are +specific to the particular protocol(s) involved. It includes the sending of +the protocol-specific instructions that trigger a transfer. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t pretransfer; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME_T, &pretransfer); + if(CURLE_OK == res) { + printf("Time: %" CURL_FORMAT_CURL_OFF_T ".%06ld\n", + pretransfer / 1000000, + (long)(pretransfer % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md new file mode 100644 index 0000000..115113f --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PRIMARY_IP +Section: 3 +Source: libcurl +See-also: + - CURLINFO_LOCAL_IP (3) + - CURLINFO_LOCAL_PORT (3) + - CURLINFO_PRIMARY_PORT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PRIMARY_IP - get IP address of last connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRIMARY_IP, char **ip); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the pointer to a null-terminated +string holding the IP address of the most recent connection done with this +**curl** handle. This string may be IPv6 when that is enabled. Note that you +get a pointer to a memory area that is reused at next request so you need to +copy the string if you want to keep the information. + +The **ip** pointer is NULL or points to private memory. You MUST NOT free - +it gets freed when you call curl_easy_cleanup(3) on the corresponding +CURL handle. + +# PROTOCOLS + +All network based ones + +# EXAMPLE + +~~~c +int main(void) +{ + char *ip; + CURLcode res; + CURL *curl = curl_easy_init(); + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the transfer */ + res = curl_easy_perform(curl); + /* Check for errors */ + if((res == CURLE_OK) && + !curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ip) && ip) { + printf("IP: %s\n", ip); + } + + /* always cleanup */ + curl_easy_cleanup(curl); +} +~~~ + +# AVAILABILITY + +Added in 7.19.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md b/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md new file mode 100644 index 0000000..3d90b64 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PRIMARY_PORT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_LOCAL_PORT (3) + - CURLINFO_PRIMARY_IP (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PRIMARY_PORT - get the latest destination port number + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRIMARY_PORT, long *portp); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the destination port of the most recent +connection done with this **curl** handle. + +This is the destination port of the actual TCP or UDP connection libcurl used. +If a proxy was used for the most recent transfer, this is the port number of +the proxy, if no proxy was used it is the port number of the most recently +accessed URL. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long port; + res = curl_easy_getinfo(curl, CURLINFO_PRIMARY_PORT, &port); + if(!res) + printf("Connected to remote port: %ld\n", port); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PRIVATE.md b/docs/libcurl/opts/CURLINFO_PRIVATE.md new file mode 100644 index 0000000..127049f --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PRIVATE.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PRIVATE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PRIVATE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PRIVATE - get the private pointer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRIVATE, char **private); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the pointer to the private data +associated with the curl handle (set with the CURLOPT_PRIVATE(3)). +Please note that for internal reasons, the value is returned as a char +pointer, although effectively being a 'void *'. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + void *pointer = (void *)0x2345454; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* set the private pointer */ + curl_easy_setopt(curl, CURLOPT_PRIVATE, pointer); + res = curl_easy_perform(curl); + + /* extract the private pointer again */ + res = curl_easy_getinfo(curl, CURLINFO_PRIVATE, &pointer); + + if(res) + printf("error: %s\n", curl_easy_strerror(res)); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.3 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PROTOCOL.md b/docs/libcurl/opts/CURLINFO_PROTOCOL.md new file mode 100644 index 0000000..9dfb297 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PROTOCOL.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PROTOCOL +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RESPONSE_CODE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PROTOCOL - get the protocol used in the connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROTOCOL, long *p); +~~~ + +# DESCRIPTION + +This option is deprecated. We strongly recommend using +CURLINFO_SCHEME(3) instead, because this option cannot return all +possible protocols! + +Pass a pointer to a long to receive the version used in the last http +connection. The returned value is set to one of the CURLPROTO_* values: + +~~~c +CURLPROTO_DICT, CURLPROTO_FILE, CURLPROTO_FTP, CURLPROTO_FTPS, +CURLPROTO_GOPHER, CURLPROTO_HTTP, CURLPROTO_HTTPS, CURLPROTO_IMAP, +CURLPROTO_IMAPS, CURLPROTO_LDAP, CURLPROTO_LDAPS, CURLPROTO_POP3, +CURLPROTO_POP3S, CURLPROTO_RTMP, CURLPROTO_RTMPE, CURLPROTO_RTMPS, +CURLPROTO_RTMPT, CURLPROTO_RTMPTE, CURLPROTO_RTMPTS, CURLPROTO_RTSP, +CURLPROTO_SCP, CURLPROTO_SFTP, CURLPROTO_SMB, CURLPROTO_SMBS, CURLPROTO_SMTP, +CURLPROTO_SMTPS, CURLPROTO_TELNET, CURLPROTO_TFTP, CURLPROTO_MQTT +~~~ + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long protocol; + curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0. Deprecated since 7.85.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md b/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md new file mode 100644 index 0000000..0e9dbdc --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PROXYAUTH_AVAIL +Section: 3 +Source: libcurl +See-also: + - CURLINFO_HTTPAUTH_AVAIL (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PROXYAUTH_AVAIL - get available HTTP proxy authentication methods + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXYAUTH_AVAIL, + long *authp); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive a bitmask indicating the authentication +method(s) available according to the previous response. The meaning of the +bits is explained in the CURLOPT_PROXYAUTH(3) option for +curl_easy_setopt(3). + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://127.0.0.1:80"); + + res = curl_easy_perform(curl); + + if(!res) { + /* extract the available proxy authentication types */ + long auth; + res = curl_easy_getinfo(curl, CURLINFO_PROXYAUTH_AVAIL, &auth); + if(!res) { + if(!auth) + printf("No proxy auth available, perhaps no 407?\n"); + else { + printf("%s%s%s%s\n", + auth & CURLAUTH_BASIC ? "Basic ":"", + auth & CURLAUTH_DIGEST ? "Digest ":"", + auth & CURLAUTH_NEGOTIATE ? "Negotiate ":"", + auth % CURLAUTH_NTLM ? "NTLM ":""); + } + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added RFC 2617 in 7.10.8 +Added RFC 7616 in 7.57.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md b/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md new file mode 100644 index 0000000..01113c7 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md @@ -0,0 +1,105 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PROXY_ERROR +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RESPONSE_CODE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) + - libcurl-errors (3) +--- + +# NAME + +CURLINFO_PROXY_ERROR - get the detailed (SOCKS) proxy error + +# SYNOPSIS + +~~~c +#include + +typedef enum { + CURLPX_OK, + CURLPX_BAD_ADDRESS_TYPE, + CURLPX_BAD_VERSION, + CURLPX_CLOSED, + CURLPX_GSSAPI, + CURLPX_GSSAPI_PERMSG, + CURLPX_GSSAPI_PROTECTION, + CURLPX_IDENTD, + CURLPX_IDENTD_DIFFER, + CURLPX_LONG_HOSTNAME, + CURLPX_LONG_PASSWD, + CURLPX_LONG_USER, + CURLPX_NO_AUTH, + CURLPX_RECV_ADDRESS, + CURLPX_RECV_AUTH, + CURLPX_RECV_CONNECT, + CURLPX_RECV_REQACK, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_UNASSIGNED, + CURLPX_REQUEST_FAILED, + CURLPX_RESOLVE_HOST, + CURLPX_SEND_AUTH, + CURLPX_SEND_CONNECT, + CURLPX_SEND_REQUEST, + CURLPX_UNKNOWN_FAIL, + CURLPX_UNKNOWN_MODE, + CURLPX_USER_REJECTED, + CURLPX_LAST /* never use */ +} CURLproxycode; + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXY_ERROR, long *detail); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive a detailed error code when the most recent +transfer returned a **CURLE_PROXY** error. That error code matches the +**CURLproxycode** set. + +The error code is zero (**CURLPX_OK**) if no response code was available. + +# PROTOCOLS + +All that can be done over SOCKS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://127.0.0.1"); + res = curl_easy_perform(curl); + if(res == CURLE_PROXY) { + long proxycode; + res = curl_easy_getinfo(curl, CURLINFO_PROXY_ERROR, &proxycode); + if(!res && proxycode) + printf("The detailed proxy error: %ld\n", proxycode); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.73.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md b/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md new file mode 100644 index 0000000..d97f5e7 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_PROXY_SSL_VERIFYRESULT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SSL_VERIFYRESULT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_PROXY_SSL_VERIFYRESULT - get the result of the proxy certificate verification + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXY_SSL_VERIFYRESULT, + long *result); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the result of the certificate verification +that was requested (using the CURLOPT_PROXY_SSL_VERIFYPEER(3) +option. This is only used for HTTPS proxies. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + long verifyresult; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy:443"); + res = curl_easy_perform(curl); + if(res) + printf("error: %s\n", curl_easy_strerror(res)); + curl_easy_getinfo(curl, CURLINFO_PROXY_SSL_VERIFYRESULT, &verifyresult); + printf("The peer verification said %s\n", verifyresult? + "fine" : "bad"); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md b/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md new file mode 100644 index 0000000..00454e7 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_QUEUE_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_STARTTRANSFER_TIME_T (3) + - CURLOPT_TIMEOUT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_QUEUE_TIME_T - time this transfer was queued + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_QUEUE_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the time, in microseconds, this +transfer was held in a waiting queue before it started "for real". A transfer +might be put in a queue if after getting started, it cannot create a new +connection etc due to set conditions and limits imposed by the application. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t queue; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_QUEUE_TIME_T, &queue); + if(CURLE_OK == res) { + printf("Queued: %" CURL_FORMAT_CURL_OFF_T ".%06ld us", queue / 1000000, + (long)(queue % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 8.6.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md b/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md new file mode 100644 index 0000000..aa75bdb --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_REDIRECT_COUNT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_URL (3) + - CURLOPT_FOLLOWLOCATION (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_REDIRECT_COUNT - get the number of redirects + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_COUNT, + long *countp); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the total number of redirections that were +actually followed. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long redirects; + curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redirects); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9.7 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md new file mode 100644 index 0000000..26d9af2 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_REDIRECT_TIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_COUNT (3) + - CURLINFO_REDIRECT_TIME_T (3) + - CURLINFO_REDIRECT_URL (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_REDIRECT_TIME - get the time for all redirection steps + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_TIME, + double *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the total time, in seconds, it took for +all redirection steps include name lookup, connect, pretransfer and transfer +before final transaction was started. CURLINFO_REDIRECT_TIME(3) contains +the complete execution time for multiple redirections. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + double redirect; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, &redirect); + if(CURLE_OK == res) { + printf("Time: %.1f", redirect); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9.7 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md new file mode 100644 index 0000000..f4ee710 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_REDIRECT_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_COUNT (3) + - CURLINFO_REDIRECT_TIME (3) + - CURLINFO_REDIRECT_URL (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_REDIRECT_TIME_T - get the time for all redirection steps + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the total time, in microseconds, it +took for all redirection steps include name lookup, connect, pretransfer and +transfer before final transaction was started. +CURLINFO_REDIRECT_TIME_T(3) holds the complete execution time for +multiple redirections. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t redirect; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME_T, &redirect); + if(CURLE_OK == res) { + printf("Time: %" CURL_FORMAT_CURL_OFF_T ".%06ld", redirect / 1000000, + (long)(redirect % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md b/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md new file mode 100644 index 0000000..8d7fc5c --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_REDIRECT_URL +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_COUNT (3) + - CURLINFO_REDIRECT_TIME_T (3) + - CURLOPT_FOLLOWLOCATION (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_REDIRECT_URL - get the URL a redirect would go to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_URL, char **urlp); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the URL a redirect *would* +take you to if you would enable CURLOPT_FOLLOWLOCATION(3). This can come +handy if you think using the built-in libcurl redirect logic is not good enough +for you but you would still prefer to avoid implementing all the magic of +figuring out the new URL. + +This URL is also set if the CURLOPT_MAXREDIRS(3) limit prevented a +redirect to happen (since 7.54.1). + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + char *url = NULL; + curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &url); + if(url) + printf("Redirect to: %s\n", url); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.18.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_REFERER.md b/docs/libcurl/opts/CURLINFO_REFERER.md new file mode 100644 index 0000000..fabc652 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_REFERER.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_REFERER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_REFERER (3) + - curl_easy_getinfo (3) + - curl_easy_header (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_REFERER - get the used referrer request header + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REFERER, char **hdrp); +~~~ + +# DESCRIPTION + +Pass in a pointer to a char pointer and get the referrer header used in the +most recent request. + +The **hdrp** pointer is NULL or points to private memory you MUST NOT free - +it gets freed when you call curl_easy_cleanup(3) on the corresponding +CURL handle. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_REFERER, "https://example.org/referrer"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + char *hdr = NULL; + curl_easy_getinfo(curl, CURLINFO_REFERER, &hdr); + if(hdr) + printf("Referrer header: %s\n", hdr); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.76.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md b/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md new file mode 100644 index 0000000..444f4ec --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md @@ -0,0 +1,63 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_REQUEST_SIZE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_HEADER_SIZE (3) + - CURLINFO_SIZE_DOWNLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_REQUEST_SIZE - get size of sent request + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REQUEST_SIZE, long *sizep); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the total size of the issued +requests. This is so far only for HTTP requests. Note that this may be more +than one request if CURLOPT_FOLLOWLOCATION(3) is enabled. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long req; + res = curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &req); + if(!res) + printf("Request size: %ld bytes\n", req); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md b/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md new file mode 100644 index 0000000..43cf837 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_RESPONSE_CODE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_HTTP_CONNECTCODE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_RESPONSE_CODE - get the last response code + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RESPONSE_CODE, long *codep); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the last received HTTP, FTP, SMTP or LDAP +(OpenLDAP only) response code. This option was previously known as +CURLINFO_HTTP_CODE in libcurl 7.10.7 and earlier. The stored value is zero if +no server response code has been received. + +Note that a proxy's CONNECT response should be read with +CURLINFO_HTTP_CONNECTCODE(3) and not this. + +# PROTOCOLS + +HTTP, FTP, SMTP and LDAP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.8. CURLINFO_HTTP_CODE was added in 7.4.1. +Support for SMTP responses added in 7.25.0, for OpenLDAP in 7.81.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md b/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md new file mode 100644 index 0000000..adc1200 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_RETRY_AFTER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERFUNCTION (3) + - CURLOPT_STDERR (3) + - curl_easy_header (3) +--- + +# NAME + +CURLINFO_RETRY_AFTER - returns the Retry-After retry delay + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RETRY_AFTER, + curl_off_t *retry); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t variable to receive the number of seconds the +HTTP server suggests the client should wait until the next request is +issued. The information from the "Retry-After:" header. + +While the HTTP header might contain a fixed date string, the +CURLINFO_RETRY_AFTER(3) always returns the number of seconds to wait - +or zero if there was no header or the header could not be parsed. + +# DEFAULT + +Returns zero delay if there was no header. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + curl_off_t wait = 0; + curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &wait); + if(wait) + printf("Wait for %" CURL_FORMAT_CURL_OFF_T " seconds\n", wait); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.66.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md b/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md new file mode 100644 index 0000000..8b515b4 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_RTSP_CLIENT_CSEQ +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RTSP_CSEQ_RECV (3) + - CURLINFO_RTSP_SERVER_CSEQ (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_RTSP_CLIENT_CSEQ - get the next RTSP client CSeq + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_CLIENT_CSEQ, + long *cseq); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the next CSeq that is expected to be used +by the application. + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long cseq; + curl_easy_getinfo(curl, CURLINFO_RTSP_CLIENT_CSEQ, &cseq); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md b/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md new file mode 100644 index 0000000..9eb813a --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_RTSP_CSEQ_RECV +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RTSP_SERVER_CSEQ (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_RTSP_CSEQ_RECV - get the recently received CSeq + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_CSEQ_RECV, long *cseq); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the most recently received CSeq from the +server. If your application encounters a *CURLE_RTSP_CSEQ_ERROR* then you +may wish to troubleshoot and/or fix the CSeq mismatch by peeking at this +value. + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long cseq; + curl_easy_getinfo(curl, CURLINFO_RTSP_CSEQ_RECV, &cseq); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md b/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md new file mode 100644 index 0000000..7826f8a --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_RTSP_SERVER_CSEQ +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RTSP_CSEQ_RECV (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_RTSP_SERVER_CSEQ - get the next RTSP server CSeq + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_SERVER_CSEQ, + long *cseq); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the next CSeq that is expected to be used +by the application. + +Listening for server initiated requests is not implemented! + +Applications wishing to resume an RTSP session on another connection should +retrieve this info before closing the active connection. + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + long cseq; + curl_easy_getinfo(curl, CURLINFO_RTSP_SERVER_CSEQ, &cseq); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md new file mode 100644 index 0000000..402a122 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_RTSP_SESSION_ID +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RTSP_CSEQ_RECV (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_RTSP_SESSION_ID - get RTSP session ID + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_SESSION_ID, char **id); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive a pointer to a string holding the +most recent RTSP Session ID. + +Applications wishing to resume an RTSP session on another connection should +retrieve this info before closing the active connection. + +The **id** pointer is NULL or points to private memory. You MUST NOT free - +it gets freed when you call curl_easy_cleanup(3) on the corresponding +CURL handle. + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + char *id; + curl_easy_getinfo(curl, CURLINFO_RTSP_SESSION_ID, &id); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SCHEME.md b/docs/libcurl/opts/CURLINFO_SCHEME.md new file mode 100644 index 0000000..db567fc --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SCHEME.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SCHEME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_EFFECTIVE_URL (3) + - CURLINFO_PROTOCOL (3) + - CURLINFO_RESPONSE_CODE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SCHEME - get the URL scheme (sometimes called protocol) used in the connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SCHEME, char **scheme); +~~~ + +# DESCRIPTION + +Pass a pointer to a char pointer to receive the pointer to a null-terminated +string holding the URL scheme used for the most recent connection done with +this CURL **handle**. + +The **scheme** pointer is NULL or points to private memory. You MUST NOT +free - it gets freed when you call curl_easy_cleanup(3) on the +corresponding CURL handle. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res == CURLE_OK) { + char *scheme = NULL; + curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme); + if(scheme) + printf("scheme: %s\n", scheme); /* scheme: HTTP */ + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md new file mode 100644 index 0000000..ff19908 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SIZE_DOWNLOAD +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SIZE_DOWNLOAD_T (3) + - CURLINFO_SIZE_UPLOAD_T (3) + - CURLOPT_MAXFILESIZE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SIZE_DOWNLOAD - get the number of downloaded bytes + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_DOWNLOAD, double *dlp); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the total amount of bytes that were +downloaded. The amount is only for the latest transfer and gets reset again +for each new transfer. This counts actual payload data, what's also commonly +called body. All meta and header data is excluded and not included in this +number. + +CURLINFO_SIZE_DOWNLOAD_T(3) is a newer replacement that returns a more +sensible variable type. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + /* check the size */ + double dl; + res = curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &dl); + if(!res) { + printf("Downloaded %.0f bytes\n", dl); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1. Deprecated since 7.55.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md new file mode 100644 index 0000000..f5468db --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SIZE_DOWNLOAD_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SIZE_DOWNLOAD (3) + - CURLINFO_SIZE_UPLOAD_T (3) + - CURLOPT_MAXFILESIZE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SIZE_DOWNLOAD_T - get the number of downloaded bytes + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_DOWNLOAD_T, + curl_off_t *dlp); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the total amount of bytes that +were downloaded. The amount is only for the latest transfer and gets reset +again for each new transfer. This counts actual payload data, what's also +commonly called body. All meta and header data is excluded from this amount. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + /* check the size */ + curl_off_t dl; + res = curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD_T, &dl); + if(!res) { + printf("Downloaded %" CURL_FORMAT_CURL_OFF_T " bytes\n", dl); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md new file mode 100644 index 0000000..175fe71 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SIZE_UPLOAD +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SIZE_DOWNLOAD_T (3) + - CURLINFO_SIZE_UPLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SIZE_UPLOAD - get the number of uploaded bytes + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_UPLOAD, + double *uploadp); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the total amount of bytes that were +uploaded. + +CURLINFO_SIZE_UPLOAD_T(3) is a newer replacement that returns a more +sensible variable type. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + double ul; + res = curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &ul); + if(!res) { + printf("Uploaded %.0f bytes\n", ul); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1. Deprecated since 7.55.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md new file mode 100644 index 0000000..29874f9 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SIZE_UPLOAD_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SIZE_DOWNLOAD_T (3) + - CURLINFO_SIZE_UPLOAD (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SIZE_UPLOAD_T - get the number of uploaded bytes + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_UPLOAD_T, + curl_off_t *uploadp); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the total amount of bytes that +were uploaded. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + curl_off_t ul; + res = curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD_T, &ul); + if(!res) { + printf("Uploaded %" CURL_FORMAT_CURL_OFF_T " bytes\n", ul); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md new file mode 100644 index 0000000..fe07669 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SPEED_DOWNLOAD +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SIZE_UPLOAD_T (3) + - CURLINFO_SPEED_UPLOAD (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SPEED_DOWNLOAD - get download speed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_DOWNLOAD, + double *speed); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the average download speed that curl +measured for the complete download. Measured in bytes/second. + +CURLINFO_SPEED_DOWNLOAD_T(3) is a newer replacement that returns a more +sensible variable type. + +# PROTOCOLS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + double speed; + res = curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD, &speed); + if(!res) { + printf("Download speed %.0f bytes/sec\n", speed); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1. Deprecated since 7.55.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md new file mode 100644 index 0000000..c8bc2f8 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SPEED_DOWNLOAD_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SIZE_UPLOAD_T (3) + - CURLINFO_SPEED_UPLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SPEED_DOWNLOAD_T - get download speed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_DOWNLOAD_T, + curl_off_t *speed); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the average download speed +that curl measured for the complete download. Measured in bytes/second. + +# PROTOCOLS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + curl_off_t speed; + res = curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD_T, &speed); + if(!res) { + printf("Download speed %" CURL_FORMAT_CURL_OFF_T " bytes/sec\n", + speed); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md new file mode 100644 index 0000000..11ce929 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SPEED_UPLOAD +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SPEED_DOWNLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SPEED_UPLOAD - get upload speed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_UPLOAD, double *speed); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the average upload speed that curl +measured for the complete upload. Measured in bytes/second. + +CURLINFO_SPEED_UPLOAD_T(3) is a newer replacement that returns a more +sensible variable type. + +# PROTOCOLS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + double speed; + res = curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed); + if(!res) { + printf("Upload speed %.0f bytes/sec\n", speed); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1. Deprecated since 7.55.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md new file mode 100644 index 0000000..178e9a5 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md @@ -0,0 +1,63 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SPEED_UPLOAD_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SPEED_DOWNLOAD_T (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SPEED_UPLOAD_T - get upload speed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_UPLOAD_T, + curl_off_t *speed); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the average upload speed that +curl measured for the complete upload. Measured in bytes/second. + +# PROTOCOLS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + curl_off_t speed; + res = curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD_T, &speed); + if(!res) { + printf("Upload speed %" CURL_FORMAT_CURL_OFF_T " bytes/sec\n", speed); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md b/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md new file mode 100644 index 0000000..9dbb0a1 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SSL_ENGINES +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSLENGINE (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SSL_ENGINES - get an slist of OpenSSL crypto-engines + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SSL_ENGINES, + struct curl_slist **engine_list); +~~~ + +# DESCRIPTION + +Pass the address of a 'struct curl_slist *' to receive a linked-list of +OpenSSL crypto-engines supported. Note that engines are normally implemented +in separate dynamic libraries. Hence not all the returned engines may be +available at runtime. **NOTE:** you must call curl_slist_free_all(3) +on the list pointer once you are done with it, as libcurl does not free this +data for you. + +# PROTOCOLS + +All TLS based ones. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_slist *engines; + res = curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines); + if((res == CURLE_OK) && engines) { + /* we have a list, free it when done using it */ + curl_slist_free_all(engines); + } + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.12.3. Available in OpenSSL builds with "engine" support. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md b/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md new file mode 100644 index 0000000..fdc38f0 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_SSL_VERIFYRESULT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PROXY_SSL_VERIFYRESULT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_SSL_VERIFYRESULT - get the result of the certificate verification + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SSL_VERIFYRESULT, + long *result); +~~~ + +# DESCRIPTION + +Pass a pointer to a long to receive the result of the server SSL certificate +verification that was requested (using the CURLOPT_SSL_VERIFYPEER(3) +option). + +0 is a positive result. Non-zero is an error. + +# PROTOCOLS + +All using TLS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + long verifyresult; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res) + printf("error: %s\n", curl_easy_strerror(res)); + curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, &verifyresult); + printf("The peer verification said %s\n", verifyresult? + "BAAAD":"fine"); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.5. Only set by the OpenSSL/libressl/boringssl and GnuTLS backends. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md new file mode 100644 index 0000000..d7c1f08 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_STARTTRANSFER_TIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_STARTTRANSFER_TIME_T (3) + - CURLOPT_TIMEOUT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_STARTTRANSFER_TIME - get the time until the first byte is received + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_STARTTRANSFER_TIME, + double *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the time, in seconds, it took from the +start until the first byte is received by libcurl. This includes +CURLINFO_PRETRANSFER_TIME(3) and also the time the server needs to +calculate the result. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + double start; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &start); + if(CURLE_OK == res) { + printf("Time: %.1f", start); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md new file mode 100644 index 0000000..481c7f5 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_STARTTRANSFER_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_STARTTRANSFER_TIME (3) + - CURLOPT_TIMEOUT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_STARTTRANSFER_TIME_T - get the time until the first byte is received + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_STARTTRANSFER_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the time, in microseconds, +it took from the +start until the first byte is received by libcurl. This includes +CURLINFO_PRETRANSFER_TIME_T(3) and also the time the server needs to +calculate the result. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t start; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME_T, &start); + if(CURLE_OK == res) { + printf("Time: %" CURL_FORMAT_CURL_OFF_T ".%06ld", start / 1000000, + (long)(start % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_TLS_SESSION.md b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md new file mode 100644 index 0000000..98cc2d6 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_TLS_SESSION +Section: 3 +Source: libcurl +See-also: + - CURLINFO_TLS_SSL_PTR (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_TLS_SESSION - get TLS session info + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_TLS_SESSION, + struct curl_tlssessioninfo **session); +~~~ + +# DESCRIPTION + +**This option has been superseded** by CURLINFO_TLS_SSL_PTR(3) which +was added in 7.48.0. The only reason you would use this option instead is if +you could be using a version of libcurl earlier than 7.48.0. + +This option is exactly the same as CURLINFO_TLS_SSL_PTR(3) except in the +case of OpenSSL. If the session *backend* is CURLSSLBACKEND_OPENSSL the +session *internals* pointer varies depending on the option: + +CURLINFO_TLS_SESSION(3) OpenSSL session *internals* is **SSL_CTX ***. + +CURLINFO_TLS_SSL_PTR(3) OpenSSL session *internals* is **SSL ***. + +You can obtain an **SSL_CTX** pointer from an SSL pointer using OpenSSL +function *SSL_get_SSL_CTX(3)*. Therefore unless you need compatibility +with older versions of libcurl use CURLINFO_TLS_SSL_PTR(3). Refer to +that document for more information. + +# PROTOCOLS + +All TLS-based + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_tlssessioninfo *tls; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(res) + printf("error: %s\n", curl_easy_strerror(res)); + curl_easy_getinfo(curl, CURLINFO_TLS_SESSION, &tls); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.34.0. Deprecated since 7.48.0 and supported OpenSSL, GnuTLS, and +NSS only up until this version was released. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md b/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md new file mode 100644 index 0000000..4fc246a --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md @@ -0,0 +1,174 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_TLS_SSL_PTR +Section: 3 +Source: libcurl +See-also: + - CURLINFO_TLS_SESSION (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_TLS_SESSION, CURLINFO_TLS_SSL_PTR - get TLS session info + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_TLS_SSL_PTR, + struct curl_tlssessioninfo **session); + +/* if you need compatibility with libcurl < 7.48.0 use + CURLINFO_TLS_SESSION instead: */ + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_TLS_SESSION, + struct curl_tlssessioninfo **session); +~~~ + +# DESCRIPTION + +Pass a pointer to a *struct curl_tlssessioninfo **. The pointer is initialized +to refer to a *struct curl_tlssessioninfo ** that contains an enum indicating +the SSL library used for the handshake and a pointer to the respective +internal TLS session structure of this underlying SSL library. + +This option may be useful for example to extract certificate information in a +format convenient for further processing, such as manual validation. Refer to +the **LIMITATIONS** section. + +~~~c +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; +~~~ + +The *backend* struct member is one of the defines in the CURLSSLBACKEND_* +series: CURLSSLBACKEND_NONE (when built without TLS support), +CURLSSLBACKEND_WOLFSSL, CURLSSLBACKEND_SECURETRANSPORT, CURLSSLBACKEND_GNUTLS, +CURLSSLBACKEND_MBEDTLS, CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL, +CURLSSLBACKEND_SCHANNEL or CURLSSLBACKEND_MESALINK. (Note that the OpenSSL +forks are all reported as just OpenSSL here.) + +The *internals* struct member points to a TLS library specific pointer for +the active ("in use") SSL connection, with the following underlying types: + +## GnuTLS + +**gnutls_session_t** + +## NSS + +**PRFileDesc *** + +## OpenSSL + +CURLINFO_TLS_SESSION(3): **SSL_CTX *** + +CURLINFO_TLS_SSL_PTR(3): **SSL *** +Since 7.48.0 the *internals* member can point to these other SSL backends +as well: + +## mbedTLS + +**mbedTLS_ssl_context *** + +## Secure Channel + +**CtxtHandle *** + +## Secure Transport + +**SSLContext *** + +## wolfSSL + +**SSL *** + +If the *internals* pointer is NULL then either the SSL backend is not +supported, an SSL session has not yet been established or the connection is no +longer associated with the easy handle (e.g. curl_easy_perform(3) has +returned). + +# LIMITATIONS + +This option has some limitations that could make it unsafe when it comes to +the manual verification of certificates. + +This option only retrieves the first in-use SSL session pointer for your easy +handle, however your easy handle may have more than one in-use SSL session if +using FTP over SSL. That is because the FTP protocol has a control channel and +a data channel and one or both may be over SSL. Currently there is no way to +retrieve a second in-use SSL session associated with an easy handle. + +This option has not been thoroughly tested with clear text protocols that can +be upgraded/downgraded to/from SSL: FTP, SMTP, POP3, IMAP when used with +CURLOPT_USE_SSL(3). Though you can to retrieve the SSL pointer, it is possible +that before you can do that, data (including auth) may have already been sent +over a connection after it was upgraded. + +Renegotiation. If unsafe renegotiation or renegotiation in a way that the +certificate is allowed to change is allowed by your SSL library this may occur +and the certificate may change, and data may continue to be sent or received +after renegotiation but before you are able to get the (possibly) changed SSL +pointer, with the (possibly) changed certificate information. + +Instead of using this option to poll for certificate changes use +CURLOPT_SSL_CTX_FUNCTION(3) to set a verification callback, if supported. +That is safer and does not suffer from any of the problems above. + +How are you using this option? Are you affected by any of these limitations? +Please let us know by making a comment at +https://github.com/curl/curl/issues/685 + +# PROTOCOLS + +All TLS-based + +# EXAMPLE + +~~~c +#include +#include + +CURL *curl; +static size_t wf(void *ptr, size_t size, size_t nmemb, void *stream) +{ + const struct curl_tlssessioninfo *info = NULL; + CURLcode res = curl_easy_getinfo(curl, CURLINFO_TLS_SSL_PTR, &info); + if(info && !res) { + if(CURLSSLBACKEND_OPENSSL == info->backend) { + printf("OpenSSL ver. %s\n", SSL_get_version((SSL*)info->internals)); + } + } + return size * nmemb; +} + +int main(int argc, char **argv) +{ + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, wf); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } + return res; +} +~~~ + +# AVAILABILITY + +Added in 7.48.0. + +This option supersedes CURLINFO_TLS_SESSION(3) which was added in 7.34.0. +This option is exactly the same as that option except in the case of OpenSSL. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md b/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md new file mode 100644 index 0000000..c6af169 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_TOTAL_TIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_TOTAL_TIME_T (3) + - CURLOPT_TIMEOUT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_TOTAL_TIME - get total time of previous transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_TOTAL_TIME, double *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a double to receive the total time in seconds for the +previous transfer, including name resolving, TCP connect etc. The double +represents the time in seconds, including fractions. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + double total; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total); + if(CURLE_OK == res) { + printf("Time: %.1f", total); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.4.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md b/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md new file mode 100644 index 0000000..488d5d3 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_TOTAL_TIME_T +Section: 3 +Source: libcurl +See-also: + - CURLINFO_TOTAL_TIME (3) + - CURLOPT_TIMEOUT (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_TOTAL_TIME_T - get total time of previous transfer in microseconds + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_TOTAL_TIME_T, + curl_off_t *timep); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_off_t to receive the total time in microseconds +for the previous transfer, including name resolving, TCP connect etc. +The curl_off_t represents the time in microseconds. + +When a redirect is followed, the time from each request is added together. + +See also the TIMES overview in the curl_easy_getinfo(3) man page. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_off_t total; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + res = curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &total); + if(CURLE_OK == res) { + printf("Time: %" CURL_FORMAT_CURL_OFF_T ".%06ld", total / 1000000, + (long)(total % 1000000)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLINFO_XFER_ID.md b/docs/libcurl/opts/CURLINFO_XFER_ID.md new file mode 100644 index 0000000..b32a46b --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_XFER_ID.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLINFO_XFER_ID +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONN_ID (3) + - curl_easy_getinfo (3) + - curl_easy_setopt (3) +--- + +# NAME + +CURLINFO_XFER_ID - get the ID of a transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_XFER_ID, + curl_off_t *xfer_id); +~~~ + +# DESCRIPTION + +Pass a pointer to a *curl_off_t* to receive the identifier of the +current/last transfer done with the handle. Stores -1 if no transfer +has been started yet for the handle. + +The transfer id is unique among all transfers performed using the same +connection cache. This is implicitly the case for all transfers in the +same multi handle. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Perform the request */ + res = curl_easy_perform(curl); + + if(!res) { + curl_off_t xfer_id; + res = curl_easy_getinfo(curl, CURLINFO_XFER_ID, &xfer_id); + if(!res) { + printf("Transfer ID: %" CURL_FORMAT_CURL_OFF_T "\n", xfer_id); + } + } + } +} +~~~ + +# AVAILABILITY + +Added in 8.2.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md b/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md new file mode 100644 index 0000000..127f4dd --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE (3) + - CURLMOPT_MAX_PIPELINE_LENGTH (3) + - CURLMOPT_PIPELINING (3) +--- + +# NAME + +CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE - chunk length threshold for pipelining + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, + long size); +~~~ + +# DESCRIPTION + +No function since pipelining was removed in 7.62.0. + +Pass a long with a **size** in bytes. If a transfer in a pipeline is +currently processing a chunked (Transfer-encoding: chunked) request with a +current chunk length larger than CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3), +that pipeline is not considered for additional requests, even if it is shorter +than CURLMOPT_MAX_PIPELINE_LENGTH(3). + +# DEFAULT + +The default value is 0, which means that the penalization is inactive. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + long maxchunk = 10000; + curl_multi_setopt(m, CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, maxchunk); +} +~~~ + +# AVAILABILITY + +Added in 7.30.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md b/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md new file mode 100644 index 0000000..d3e7aba --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md @@ -0,0 +1,60 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE (3) + - CURLMOPT_PIPELINING (3) +--- + +# NAME + +CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE - size threshold for pipelining penalty + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, + long size); +~~~ + +# DESCRIPTION + +No function since pipelining was removed in 7.62.0. + +Pass a long with a **size** in bytes. If a transfer in a pipeline is +currently processing a request with a Content-Length larger than this +CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3), that pipeline is not considered +for additional requests, even if it is shorter than +CURLMOPT_MAX_PIPELINE_LENGTH(3). + +# DEFAULT + +The default value is 0, which means that the size penalization is inactive. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + long maxlength = 10000; + curl_multi_setopt(m, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, maxlength); +} +~~~ + +# AVAILABILITY + +Added in 7.30.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md b/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md new file mode 100644 index 0000000..9a5457f --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_MAXCONNECTS +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_MAX_HOST_CONNECTIONS (3) + - CURLOPT_MAXCONNECTS (3) +--- + +# NAME + +CURLMOPT_MAXCONNECTS - size of connection cache + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAXCONNECTS, long max); +~~~ + +# DESCRIPTION + +Pass a long indicating the **max**. The set number is used as the maximum +amount of simultaneously open connections that libcurl may keep in its +connection cache after completed use. By default libcurl enlarges the size for +each added easy handle to make it fit 4 times the number of added easy +handles. + +By setting this option, you can prevent the cache size from growing beyond the +limit set by you. + +When the cache is full, curl closes the oldest one in the cache to prevent the +number of open connections from increasing. + +This option is for the multi handle's use only, when using the easy interface +you should instead use the CURLOPT_MAXCONNECTS(3) option. + +See CURLMOPT_MAX_TOTAL_CONNECTIONS(3) for limiting the number of active +connections. + +# DEFAULT + +See DESCRIPTION + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + /* only keep 10 connections in the cache */ + curl_multi_setopt(m, CURLMOPT_MAXCONNECTS, 10L); +} +~~~ + +# AVAILABILITY + +Added in 7.16.3 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md b/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md new file mode 100644 index 0000000..2471994 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md @@ -0,0 +1,59 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_MAX_CONCURRENT_STREAMS +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_MAXCONNECTS (3) + - CURLOPT_MAXCONNECTS (3) +--- + +# NAME + +CURLMOPT_MAX_CONCURRENT_STREAMS - max concurrent streams for http2 + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAX_CONCURRENT_STREAMS, + long max); +~~~ + +# DESCRIPTION + +Pass a long indicating the **max**. The set number is used as the maximum +number of concurrent streams libcurl should support on connections done using +HTTP/2 or HTTP/3. + +Valid values range from 1 to 2147483647 (2^31 - 1) and defaults to 100. The +value passed here would be honored based on other system resources properties. + +# DEFAULT + +100 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + /* max concurrent streams 200 */ + curl_multi_setopt(m, CURLMOPT_MAX_CONCURRENT_STREAMS, 200L); +} +~~~ + +# AVAILABILITY + +Added in 7.67.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md b/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md new file mode 100644 index 0000000..75c4768 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_MAX_HOST_CONNECTIONS +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_MAXCONNECTS (3) + - CURLMOPT_MAX_TOTAL_CONNECTIONS (3) +--- + +# NAME + +CURLMOPT_MAX_HOST_CONNECTIONS - max number of connections to a single host + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAX_HOST_CONNECTIONS, + long max); +~~~ + +# DESCRIPTION + +Pass a long to indicate **max**. The set number is used as the maximum amount +of simultaneously open connections to a single host (a host being the same as +a hostname + port number pair). For each new session to a host, libcurl might +open a new connection up to the limit set by +CURLMOPT_MAX_HOST_CONNECTIONS(3). When the limit is reached, new sessions are +kept pending until a connection becomes available. + +The default **max** value is 0, unlimited. This set limit is also used for +proxy connections, and then the proxy is considered to be the host for which +this limit counts. + +When more transfers are added to the multi handle than what can be performed +due to the set limit, they are queued up waiting for their chance. When that +happens, the CURLOPT_TIMEOUT_MS(3) timeout is inclusive of the waiting +time, meaning that if you set a too narrow timeout in such a case the transfer +might never even start before it times out. + +Even in the queued up situation, the CURLOPT_CONNECTTIMEOUT_MS(3) +timeout is however treated as a per-connect timeout. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + /* do no more than 2 connections per host */ + curl_multi_setopt(m, CURLMOPT_MAX_HOST_CONNECTIONS, 2L); +} +~~~ + +# AVAILABILITY + +Added in 7.30.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md b/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md new file mode 100644 index 0000000..bad638e --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_MAX_PIPELINE_LENGTH +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_MAX_HOST_CONNECTIONS (3) + - CURLMOPT_PIPELINING (3) +--- + +# NAME + +CURLMOPT_MAX_PIPELINE_LENGTH - maximum number of requests in a pipeline + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAX_PIPELINE_LENGTH, + long max); +~~~ + +# DESCRIPTION + +No function since pipelining was removed in 7.62.0. + +Pass a long. The set **max** number is used as the maximum amount of +outstanding requests in an HTTP/1.1 pipeline. This option is only used for +HTTP/1.1 pipelining, not for HTTP/2 multiplexing. + +When this limit is reached, libcurl creates another connection to the same +host (see CURLMOPT_MAX_HOST_CONNECTIONS(3)), or queue the request until one + of the pipelines to the host is ready to accept a request. Thus, the total +number of requests in-flight is CURLMOPT_MAX_HOST_CONNECTIONS(3) * +CURLMOPT_MAX_PIPELINE_LENGTH(3). + +# DEFAULT + +5 + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + /* set a more conservative pipe length */ + curl_multi_setopt(m, CURLMOPT_MAX_PIPELINE_LENGTH, 3L); +} +~~~ + +# AVAILABILITY + +Added in 7.30.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md b/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md new file mode 100644 index 0000000..859bb2a --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_MAX_TOTAL_CONNECTIONS +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_MAXCONNECTS (3) + - CURLMOPT_MAX_HOST_CONNECTIONS (3) +--- + +# NAME + +CURLMOPT_MAX_TOTAL_CONNECTIONS - max simultaneously open connections + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, + long amount); +~~~ + +# DESCRIPTION + +Pass a long for the **amount**. The set number is used as the maximum number +of simultaneously open connections in total using this multi handle. For each +new session, libcurl might open a new connection up to the limit set by +CURLMOPT_MAX_TOTAL_CONNECTIONS(3). When the limit is reached, new +sessions are held pending until there are available connections. If +CURLMOPT_PIPELINING(3) is enabled, libcurl can try multiplexing if the +host is capable of it. + +When more transfers are added to the multi handle than what can be performed +due to the set limit, they get queued up waiting for their chance. When that +happens, the CURLOPT_TIMEOUT_MS(3) timeout is counted inclusive of the +waiting time, meaning that if you set a too narrow timeout in such a case the +transfer might never even start before it times out. + +Even in the queued up situation, the CURLOPT_CONNECTTIMEOUT_MS(3) +timeout is however treated as a per-connect timeout. + +# DEFAULT + +The default value is 0, which means that there is no limit. It is then simply +controlled by the number of easy handles added. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + /* never do more than 15 connections */ + curl_multi_setopt(m, CURLMOPT_MAX_TOTAL_CONNECTIONS, 15L); +} +~~~ + +# AVAILABILITY + +Added in 7.30.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_PIPELINING.md b/docs/libcurl/opts/CURLMOPT_PIPELINING.md new file mode 100644 index 0000000..3df71b5 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_PIPELINING.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_PIPELINING +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE (3) + - CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE (3) + - CURLMOPT_MAXCONNECTS (3) + - CURLMOPT_MAX_HOST_CONNECTIONS (3) + - CURLMOPT_MAX_PIPELINE_LENGTH (3) + - CURLMOPT_PIPELINING_SITE_BL (3) +--- + +# NAME + +CURLMOPT_PIPELINING - enable HTTP pipelining and multiplexing + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING, long bitmask); +~~~ + +# DESCRIPTION + +Pass in the correct value in the **bitmask** parameter to instruct libcurl +to enable multiplexing for this multi handle. + +With multiplexing enabled, libcurl attempts to do multiple transfers over the +same connection when doing parallel transfers to the same hosts. + +## CURLPIPE_NOTHING (0) + +Default, which means doing no attempts at multiplexing. + +## CURLPIPE_HTTP1 (1) + +This bit is deprecated and has no effect since version 7.62.0. + +## CURLPIPE_MULTIPLEX (2) + +If this bit is set, libcurl tries to multiplex the new transfer over an +existing connection if possible. This requires HTTP/2 or HTTP/3. + +# DEFAULT + +Since 7.62.0, **CURLPIPE_MULTIPLEX** is enabled by default. + +Before that, default was **CURLPIPE_NOTHING**. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURLM *m = curl_multi_init(); + /* try HTTP/2 multiplexing */ + curl_multi_setopt(m, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); +} +~~~ + +# AVAILABILITY + +Added in 7.16.0. Multiplex support bit added in 7.43.0. HTTP/1 Pipelining +support was disabled in 7.62.0. + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md b/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md new file mode 100644 index 0000000..2267008 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_PIPELINING_SERVER_BL +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PIPELINING (3) + - CURLMOPT_PIPELINING_SITE_BL (3) +--- + +# NAME + +CURLMOPT_PIPELINING_SERVER_BL - pipelining server block list + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING_SERVER_BL, + char **servers); +~~~ + +# DESCRIPTION + +No function since pipelining was removed in 7.62.0. + +Pass a **servers** array of char *, ending with a NULL entry. This is a list +of server types prefixes (in the Server: HTTP header) that are blocked from +pipelining, i.e server types that are known to not support HTTP +pipelining. The array is copied by libcurl. + +Note that the comparison matches if the Server: header begins with the string +in the block list, i.e "Server: Ninja 1.2.3" and "Server: Ninja 1.4.0" can +both be blocked by having "Ninja" in the list. + +Pass a NULL pointer to clear the block list. + +# DEFAULT + +The default value is NULL, which means that there is no block list. + +# PROTOCOLS + +# EXAMPLE + +~~~c +static char *server_block_list[] = +{ + "Microsoft-IIS/6.0", + "nginx/0.8.54", + NULL +}; +int main(void) +{ + CURLM *m = curl_multi_init(); + curl_multi_setopt(m, CURLMOPT_PIPELINING_SERVER_BL, server_block_list); +} +~~~ + +# AVAILABILITY + +Added in 7.30.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md b/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md new file mode 100644 index 0000000..a212c4f --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_PIPELINING_SITE_BL +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PIPELINING (3) + - CURLMOPT_PIPELINING_SERVER_BL (3) +--- + +# NAME + +CURLMOPT_PIPELINING_SITE_BL - pipelining host block list + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING_SITE_BL, + char **hosts); +~~~ + +# DESCRIPTION + +No function since pipelining was removed in 7.62.0. + +Pass a **hosts** array of char *, ending with a NULL entry. This is a list +of sites that are blocked from pipelining, i.e sites that are known to not +support HTTP pipelining. The array is copied by libcurl. + +Pass a NULL pointer to clear the block list. + +# DEFAULT + +The default value is NULL, which means that there is no block list. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +static char *site_block_list[] = +{ + "www.haxx.se", + "www.example.com:1234", + NULL +}; + +int main(void) +{ + CURLM *m = curl_multi_init(); + curl_multi_setopt(m, CURLMOPT_PIPELINING_SITE_BL, site_block_list); +} +~~~ + +# AVAILABILITY + +Added in 7.30.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_PUSHDATA.md b/docs/libcurl/opts/CURLMOPT_PUSHDATA.md new file mode 100644 index 0000000..23e8785 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_PUSHDATA.md @@ -0,0 +1,87 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_PUSHDATA +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PIPELINING (3) + - CURLMOPT_PUSHFUNCTION (3) + - CURLOPT_PIPEWAIT (3) + - RFC 7540 +--- + +# NAME + +CURLMOPT_PUSHDATA - pointer to pass to push callback + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PUSHDATA, void *pointer); +~~~ + +# DESCRIPTION + +Set a *pointer* to pass as the last argument to the +CURLMOPT_PUSHFUNCTION(3) callback. The pointer is not touched or used by +libcurl itself, only passed on to the callback function. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +#include + +/* only allow pushes for file names starting with "push-" */ +int push_callback(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *clientp) +{ + char *headp; + int *transfers = (int *)clientp; + FILE *out; + headp = curl_pushheader_byname(headers, ":path"); + if(headp && !strncmp(headp, "/push-", 6)) { + fprintf(stderr, "The PATH is %s\n", headp); + + /* save the push here */ + out = fopen("pushed-stream", "wb"); + + /* write to this file */ + curl_easy_setopt(easy, CURLOPT_WRITEDATA, out); + + (*transfers)++; /* one more */ + + return CURL_PUSH_OK; + } + return CURL_PUSH_DENY; +} + +int main(void) +{ + int counter; + CURLM *multi = curl_multi_init(); + curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_callback); + curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter); +} +~~~ + +# AVAILABILITY + +Added in 7.44.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md new file mode 100644 index 0000000..903ac06 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md @@ -0,0 +1,148 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_PUSHFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PIPELINING (3) + - CURLMOPT_PUSHDATA (3) + - CURLOPT_PIPEWAIT (3) + - RFC 7540 +--- + +# NAME + +CURLMOPT_PUSHFUNCTION - callback that approves or denies server pushes + +# SYNOPSIS + +~~~c +#include + +int curl_push_callback(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *clientp); + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PUSHFUNCTION, + curl_push_callback func); +~~~ + +# DESCRIPTION + +This callback gets called when a new HTTP/2 stream is being pushed by the +server (using the PUSH_PROMISE frame). If no push callback is set, all offered +pushes are denied automatically. + +# CALLBACK DESCRIPTION + +The callback gets its arguments like this: + +*parent* is the handle of the stream on which this push arrives. The new +handle has been duplicated from the parent, meaning that it has gotten all its +options inherited. It is then up to the application to alter any options if +desired. + +*easy* is a newly created handle that represents this upcoming transfer. + +*num_headers* is the number of name+value pairs that was received and can +be accessed + +*headers* is a handle used to access push headers using the accessor +functions described below. This only accesses and provides the PUSH_PROMISE +headers, the normal response headers are provided in the header callback as +usual. + +*clientp* is the pointer set with CURLMOPT_PUSHDATA(3) + +If the callback returns CURL_PUSH_OK, the new easy handle is added to the +multi handle, the callback must not do that by itself. + +The callback can access PUSH_PROMISE headers with two accessor +functions. These functions can only be used from within this callback and they +can only access the PUSH_PROMISE headers: curl_pushheader_byname(3) and +curl_pushheader_bynum(3). The normal response headers are passed to the +header callback for pushed streams just as for normal streams. + +The header fields can also be accessed with curl_easy_header(3), +introduced in later libcurl versions. + +# CALLBACK RETURN VALUE + +## CURL_PUSH_OK (0) + +The application has accepted the stream and it can now start receiving data, +the ownership of the CURL handle has been taken over by the application. + +## CURL_PUSH_DENY (1) + +The callback denies the stream and no data reaches the application, the easy +handle is destroyed by libcurl. + +## CURL_PUSH_ERROROUT (2) + +Returning this code rejects the pushed stream and returns an error back on the +parent stream making it get closed with an error. (Added in 7.72.0) + +## * + +All other return codes are reserved for future use. + +# DEFAULT + +NULL, no callback + +# PROTOCOLS + +HTTP(S) (HTTP/2 only) + +# EXAMPLE + +~~~c +#include + +/* only allow pushes for file names starting with "push-" */ +int push_callback(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *clientp) +{ + char *headp; + int *transfers = (int *)clientp; + FILE *out; + headp = curl_pushheader_byname(headers, ":path"); + if(headp && !strncmp(headp, "/push-", 6)) { + fprintf(stderr, "The PATH is %s\n", headp); + + /* save the push here */ + out = fopen("pushed-stream", "wb"); + + /* write to this file */ + curl_easy_setopt(easy, CURLOPT_WRITEDATA, out); + + (*transfers)++; /* one more */ + + return CURL_PUSH_OK; + } + return CURL_PUSH_DENY; +} + +int main(void) +{ + int counter; + CURLM *multi = curl_multi_init(); + curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_callback); + curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter); +} +~~~ + +# AVAILABILITY + +Added in 7.44.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md b/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md new file mode 100644 index 0000000..f4de8c3 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_SOCKETDATA +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_SOCKETFUNCTION (3) + - CURLMOPT_TIMERFUNCTION (3) + - curl_multi_socket_action (3) +--- + +# NAME + +CURLMOPT_SOCKETDATA - custom pointer passed to the socket callback + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_SOCKETDATA, void *pointer); +~~~ + +# DESCRIPTION + +A data *pointer* to pass to the socket callback set with the +CURLMOPT_SOCKETFUNCTION(3) option. + +This pointer is not touched by libcurl but is only passed in as the socket +callbacks's **clientp** argument. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct priv { + void *ours; +}; + +static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) +{ + struct priv *p = sockp; + printf("my ptr: %p\n", p->ours); + + if(what == CURL_POLL_REMOVE) { + /* remove the socket from our collection */ + } + if(what & CURL_POLL_IN) { + /* wait for read on this socket */ + } + if(what & CURL_POLL_OUT) { + /* wait for write on this socket */ + } + + return 0; +} + +int main(void) +{ + struct priv setup; + CURLM *multi = curl_multi_init(); + /* ... use socket callback and custom pointer */ + curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, &setup); +} +~~~ + +# AVAILABILITY + +Added in 7.15.4 + +# RETURN VALUE + +Returns CURLM_OK. diff --git a/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md b/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md new file mode 100644 index 0000000..5b34db5 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md @@ -0,0 +1,135 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_SOCKETFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_SOCKETDATA (3) + - CURLMOPT_TIMERFUNCTION (3) + - curl_multi_socket_action (3) +--- + +# NAME + +CURLMOPT_SOCKETFUNCTION - callback informed about what to wait for + +# SYNOPSIS + +~~~c +#include + +int socket_callback(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* describes the socket */ + void *clientp, /* private callback pointer */ + void *socketp); /* private socket pointer */ + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_SOCKETFUNCTION, socket_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +When the curl_multi_socket_action(3) function is called, it uses this +callback to inform the application about updates in the socket (file +descriptor) status by doing none, one, or multiple calls to the +**socket_callback**. The callback function gets status updates with changes +since the previous time the callback was called. If the given callback pointer +is set to NULL, no callback is called. + +libcurl then expects the application to monitor the sockets for the specific +activities and tell libcurl again when something happens on one of them. Tell +libcurl by calling curl_multi_socket_action(3). + +# CALLBACK ARGUMENTS + +*easy* identifies the specific transfer for which this update is related. + +*s* is the specific socket this function invocation concerns. If the +**what** argument is not CURL_POLL_REMOVE then it holds information about +what activity on this socket the application is supposed to +monitor. Subsequent calls to this callback might update the **what** bits +for a socket that is already monitored. + +The socket callback should return 0 on success, and -1 on error. If this +callback returns error, **all** transfers currently in progress in this +multi handle are aborted and made to fail. + +**clientp** is set with CURLMOPT_SOCKETDATA(3). + +**socketp** is set with curl_multi_assign(3) or NULL. + +The **what** parameter informs the callback on the status of the given +socket. It can hold one of these values: + +## CURL_POLL_IN + +Wait for incoming data. For the socket to become readable. + +## CURL_POLL_OUT + +Wait for outgoing data. For the socket to become writable. + +## CURL_POLL_INOUT + +Wait for incoming and outgoing data. For the socket to become readable or +writable. + +## CURL_POLL_REMOVE + +The specified socket/file descriptor is no longer used by libcurl for any +active transfer. It might soon be added again. + +# DEFAULT + +NULL (no callback) + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct priv { + void *ours; +}; + +static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) +{ + struct priv *p = sockp; + printf("our ptr: %p\n", p->ours); + + if(what == CURL_POLL_REMOVE) { + /* remove the socket from our collection */ + } + if(what & CURL_POLL_IN) { + /* wait for read on this socket */ + } + if(what & CURL_POLL_OUT) { + /* wait for write on this socket */ + } + + return 0; +} + +int main(void) +{ + struct priv setup; + CURLM *multi = curl_multi_init(); + /* ... use socket callback and custom pointer */ + curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, &setup); +} +~~~ + +# AVAILABILITY + +Added in 7.15.4 + +# RETURN VALUE + +Returns CURLM_OK. diff --git a/docs/libcurl/opts/CURLMOPT_TIMERDATA.md b/docs/libcurl/opts/CURLMOPT_TIMERDATA.md new file mode 100644 index 0000000..13bbd92 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_TIMERDATA.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_TIMERDATA +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_SOCKETFUNCTION (3) + - CURLMOPT_TIMERFUNCTION (3) +--- + +# NAME + +CURLMOPT_TIMERDATA - custom pointer to pass to timer callback + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_TIMERDATA, void *pointer); +~~~ + +# DESCRIPTION + +A data **pointer** to pass to the timer callback set with the +CURLMOPT_TIMERFUNCTION(3) option. + +This pointer is not touched by libcurl but is only be passed in to the timer +callbacks's **clientp** argument. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static int timerfunc(CURLM *multi, long timeout_ms, void *clientp) +{ + struct priv *mydata = clientp; + printf("our ptr: %p\n", mydata->custom); + + if(timeout_ms) { + /* this is the new single timeout to wait for */ + } + else { + /* delete the timeout, nothing to wait for now */ + } +} + +int main(void) +{ + struct priv mydata; + CURLM *multi = curl_multi_init(); + curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timerfunc); + curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &mydata); +} +~~~ + +# AVAILABILITY + +Added in 7.16.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md b/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md new file mode 100644 index 0000000..83a8fe7 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md @@ -0,0 +1,103 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_TIMERFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_SOCKETFUNCTION (3) + - CURLMOPT_TIMERDATA (3) +--- + +# NAME + +CURLMOPT_TIMERFUNCTION - callback to receive timeout values + +# SYNOPSIS + +~~~c +#include + +int timer_callback(CURLM *multi, /* multi handle */ + long timeout_ms, /* timeout in number of ms */ + void *clientp); /* private callback pointer */ + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_TIMERFUNCTION, timer_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +Certain features, such as timeouts and retries, require you to call libcurl +even when there is no activity on the file descriptors. + +Your callback function **timer_callback** should install a non-repeating +timer with an expire time of **timeout_ms** milliseconds. When that timer +fires, call either curl_multi_socket_action(3) or +curl_multi_perform(3), depending on which interface you use. + +A **timeout_ms** value of -1 passed to this callback means you should delete +the timer. All other values are valid expire times in number of milliseconds. + +The **timer_callback** is called when the timeout expire time is changed. + +The **clientp** pointer is set with CURLMOPT_TIMERDATA(3). + +The timer callback should return 0 on success, and -1 on error. If this +callback returns error, **all** transfers currently in progress in this +multi handle are aborted and made to fail. + +This callback can be used instead of, or in addition to, +curl_multi_timeout(3). + +**WARNING:** do not call libcurl directly from within the callback itself +when the **timeout_ms** value is zero, since it risks triggering an +unpleasant recursive behavior that immediately calls another call to the +callback with a zero timeout... + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static int timerfunc(CURLM *multi, long timeout_ms, void *clientp) +{ + struct priv *mydata = clientp; + printf("our ptr: %p\n", mydata->custom); + + if(timeout_ms) { + /* this is the new single timeout to wait for */ + } + else { + /* delete the timeout, nothing to wait for now */ + } +} + +int main(void) +{ + struct priv mydata; + CURLM *multi = curl_multi_init(); + curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timerfunc); + curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &mydata); +} +~~~ + +# AVAILABILITY + +Added in 7.16.0 + +# RETURN VALUE + +Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md b/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md new file mode 100644 index 0000000..33d2b7b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ABSTRACT_UNIX_SOCKET +Section: 3 +Source: libcurl +See-also: + - CURLOPT_UNIX_SOCKET_PATH (3) + - unix (7) +--- + +# NAME + +CURLOPT_ABSTRACT_UNIX_SOCKET - abstract Unix domain socket + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ABSTRACT_UNIX_SOCKET, + char *path); +~~~ + +# DESCRIPTION + +Enables the use of an abstract Unix domain socket instead of establishing a +TCP connection to a host. The parameter should be a char * to a +null-terminated string holding the path of the socket. The path is set to +*path* prefixed by a NULL byte. This is the convention for abstract +sockets, however it should be stressed that the path passed to this function +should not contain a leading NULL byte. + +On non-supporting platforms, the abstract address is interpreted as an empty +string and fails gracefully, generating a runtime error. + +This option shares the same semantics as CURLOPT_UNIX_SOCKET_PATH(3) in +which documentation more details can be found. Internally, these two options +share the same storage and therefore only one of them can be set per handle. + +# DEFAULT + +Default is NULL. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_ABSTRACT_UNIX_SOCKET, "/tmp/foo.sock"); + curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/"); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.53.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md new file mode 100644 index 0000000..77615d8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ACCEPTTIMEOUT_MS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT_MS (3) + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_ACCEPTTIMEOUT_MS - timeout waiting for FTP server to connect back + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ACCEPTTIMEOUT_MS, long ms); +~~~ + +# DESCRIPTION + +Pass a long telling libcurl the maximum number of milliseconds to wait for a +server to connect back to libcurl when an active FTP connection is used. + +# DEFAULT + +60000 milliseconds + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/path/file"); + + /* wait no more than 5 seconds for FTP server responses */ + curl_easy_setopt(curl, CURLOPT_ACCEPTTIMEOUT_MS, 5000L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.24.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md b/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md new file mode 100644 index 0000000..9bba40d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md @@ -0,0 +1,110 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ACCEPT_ENCODING +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPHEADER (3) + - CURLOPT_HTTP_CONTENT_DECODING (3) + - CURLOPT_TRANSFER_ENCODING (3) +--- + +# NAME + +CURLOPT_ACCEPT_ENCODING - automatic decompression of HTTP downloads + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ACCEPT_ENCODING, char *enc); +~~~ + +# DESCRIPTION + +Pass a char pointer argument specifying what encoding you would like. + +Sets the contents of the Accept-Encoding: header sent in an HTTP request, and +enables decoding of a response when a Content-Encoding: header is received. + +libcurl potentially supports several different compressed encodings depending +on what support that has been built-in. + +To aid applications not having to bother about what specific algorithms this +particular libcurl build supports, libcurl allows a zero-length string to be +set ("") to ask for an Accept-Encoding: header to be used that contains all +built-in supported encodings. + +Alternatively, you can specify exactly the encoding or list of encodings you +want in the response. The following encodings are supported: *identity*, +meaning non-compressed, *deflate* which requests the server to compress +its response using the zlib algorithm, *gzip* which requests the gzip +algorithm, (since curl 7.57.0) *br* which is brotli and (since curl +7.72.0) *zstd* which is zstd. Provide them in the string as a +comma-separated list of accepted encodings, like: **"br, gzip, deflate"**. + +Set CURLOPT_ACCEPT_ENCODING(3) to NULL to explicitly disable it, which +makes libcurl not send an Accept-Encoding: header and not decompress received +contents automatically. + +You can also opt to just include the Accept-Encoding: header in your request +with CURLOPT_HTTPHEADER(3) but then there is no automatic decompressing +when receiving data. + +This is a request, not an order; the server may or may not do it. This option +must be set (to any non-NULL value) or else any unsolicited encoding done by +the server is ignored. + +Servers might respond with Content-Encoding even without getting a +Accept-Encoding: in the request. Servers might respond with a different +Content-Encoding than what was asked for in the request. + +The Content-Length: servers send for a compressed response is supposed to +indicate the length of the compressed content so when auto decoding is enabled +it may not match the sum of bytes reported by the write callbacks (although, +sending the length of the non-compressed content is a common server mistake). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* enable all supported built-in compressions */ + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +This option was called CURLOPT_ENCODING before 7.21.6 + +The specific libcurl you are using must have been built with zlib to be able to +decompress gzip and deflate responses, with the brotli library to +decompress brotli responses and with the zstd library to decompress zstd +responses. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md b/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md new file mode 100644 index 0000000..78526bd --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md @@ -0,0 +1,63 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ADDRESS_SCOPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_ADDRESS_SCOPE - scope id for IPv6 addresses + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ADDRESS_SCOPE, long scope); +~~~ + +# DESCRIPTION + +Pass a long specifying the scope id value to use when connecting to IPv6 addresses. + +# DEFAULT + +0 + +# PROTOCOLS + +All, when using IPv6 + +# EXAMPLE + +~~~c +#include /* for if_nametoindex() */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + long my_scope_id; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + my_scope_id = if_nametoindex("eth0"); + curl_easy_setopt(curl, CURLOPT_ADDRESS_SCOPE, my_scope_id); + ret = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value. diff --git a/docs/libcurl/opts/CURLOPT_ALTSVC.md b/docs/libcurl/opts/CURLOPT_ALTSVC.md new file mode 100644 index 0000000..6f64084 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ALTSVC.md @@ -0,0 +1,111 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ALTSVC +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ALTSVC_CTRL (3) + - CURLOPT_CONNECT_TO (3) + - CURLOPT_COOKIEFILE (3) + - CURLOPT_RESOLVE (3) +--- + +# NAME + +CURLOPT_ALTSVC - alt-svc cache file name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ALTSVC, char *filename); +~~~ + +# DESCRIPTION + +Pass in a pointer to a *filename* to instruct libcurl to use that file as +the Alt-Svc cache to read existing cache contents from and possibly also write +it back to after a transfer, unless **CURLALTSVC_READONLYFILE** is set in +CURLOPT_ALTSVC_CTRL(3). + +Specify a blank filename ("") to make libcurl not load from a file at all. + +# DEFAULT + +NULL. The alt-svc cache is not read nor written to file. + +# PROTOCOLS + +HTTPS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, CURLALTSVC_H1); + curl_easy_setopt(curl, CURLOPT_ALTSVC, "altsvc-cache.txt"); + curl_easy_perform(curl); + } +} +~~~ + +# FILE FORMAT + +A text based file with one line per alt-svc entry and each line consists of +nine space-separated fields. + +An example line could look like + + h2 www.example.com 8443 h3 second.example.com 443 "20190808 06:18:37" 1 0 + +The fields of that line are: + +## h2 + +ALPN id for the source origin + +## www.example.comp + +Hostname for the source origin + +## 8443 + +Port number for the source origin + +## h3 + +ALPN id for the destination host + +## second.example.com + +Hostname for the destination host + +## 443 + +Port number for the destination host + +## 2019* + +Expiration date and time of this entry within double quotes. The date format +is "YYYYMMDD HH:MM:SS" and the time zone is GMT. + +## 1 + +Boolean (1 or 0) if "persist" was set for this entry + +## 0 + +Integer priority value (not currently used) + +# AVAILABILITY + +Added in 7.64.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md b/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md new file mode 100644 index 0000000..538fc80 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md @@ -0,0 +1,97 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ALTSVC_CTRL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ALTSVC (3) + - CURLOPT_CONNECT_TO (3) + - CURLOPT_RESOLVE (3) +--- + +# NAME + +CURLOPT_ALTSVC_CTRL - control alt-svc behavior + +# SYNOPSIS + +~~~c +#include + +#define CURLALTSVC_READONLYFILE (1<<2) +#define CURLALTSVC_H1 (1<<3) +#define CURLALTSVC_H2 (1<<4) +#define CURLALTSVC_H3 (1<<5) + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ALTSVC_CTRL, long bitmask); +~~~ + +# DESCRIPTION + +Populate the long *bitmask* with the correct set of features to instruct +libcurl how to handle Alt-Svc for the transfers using this handle. + +libcurl only accepts Alt-Svc headers over a secure transport, meaning +HTTPS. It also only completes a request to an alternative origin if that +origin is properly hosted over HTTPS. These requirements are there to make +sure both the source and the destination are legitimate. + +Alternative services are only used when setting up new connections. If there +exists an existing connection to the host in the connection pool, then that is +preferred. + +Setting any bit enables the alt-svc engine. + +## CURLALTSVC_READONLYFILE + +Do not write the alt-svc cache back to the file specified with +CURLOPT_ALTSVC(3) even if it gets updated. By default a file specified +with that option is read and written to as deemed necessary. + +## CURLALTSVC_H1 + +Accept alternative services offered over HTTP/1.1. + +## CURLALTSVC_H2 + +Accept alternative services offered over HTTP/2. This is only used if libcurl +was also built to actually support HTTP/2, otherwise this bit is ignored. + +## CURLALTSVC_H3 + +Accept alternative services offered over HTTP/3. This is only used if libcurl +was also built to actually support HTTP/3, otherwise this bit is ignored. + +# DEFAULT + +Alt-Svc handling is disabled by default. If CURLOPT_ALTSVC(3) is set, +CURLOPT_ALTSVC_CTRL(3) has a default value corresponding to +CURLALTSVC_H1 | CURLALTSVC_H2 | CURLALTSVC_H3 - the HTTP/2 and HTTP/3 bits are +only set if libcurl was built with support for those versions. + +# PROTOCOLS + +HTTPS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, (long)CURLALTSVC_H1); + curl_easy_setopt(curl, CURLOPT_ALTSVC, "altsvc-cache.txt"); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.64.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_APPEND.md b/docs/libcurl/opts/CURLOPT_APPEND.md new file mode 100644 index 0000000..d507c38 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_APPEND.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_APPEND +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DIRLISTONLY (3) + - CURLOPT_RESUME_FROM (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_APPEND - append to the remote file + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_APPEND, long append); +~~~ + +# DESCRIPTION + +A long parameter set to 1 tells the library to append to the remote file +instead of overwrite it. This is only useful when uploading to an FTP site. + +# DEFAULT + +0 (disabled) + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/to/newfile"); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(curl, CURLOPT_APPEND, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +This option was known as CURLOPT_FTPAPPEND up to 7.16.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_AUTOREFERER.md b/docs/libcurl/opts/CURLOPT_AUTOREFERER.md new file mode 100644 index 0000000..d201a71 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_AUTOREFERER.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_AUTOREFERER +Section: 3 +Source: libcurl +See-also: + - CURLINFO_EFFECTIVE_URL (3) + - CURLINFO_REDIRECT_URL (3) + - CURLINFO_REFERER (3) + - CURLOPT_FOLLOWLOCATION (3) + - CURLOPT_REFERER (3) +--- + +# NAME + +CURLOPT_AUTOREFERER - automatically update the referer header + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_AUTOREFERER, long autorefer); +~~~ + +# DESCRIPTION + +Pass a long parameter set to 1 to enable this. When enabled, libcurl +automatically sets the Referer: header field in HTTP requests to the full URL +when it follows a Location: redirect to a new destination. + +The automatic referer is set to the full previous URL even when redirects are +done cross-origin or following redirects to insecure protocols. This is +considered a minor privacy leak by some. + +With CURLINFO_REFERER(3), applications can extract the actually used +referer header after the transfer. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* follow redirects */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + /* set Referer: automatically when following redirects */ + curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md b/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md new file mode 100644 index 0000000..e19741a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md @@ -0,0 +1,118 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_AWS_SIGV4 +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADEROPT (3) + - CURLOPT_HTTPAUTH (3) + - CURLOPT_HTTPHEADER (3) + - CURLOPT_PROXYAUTH (3) +--- + +# NAME + +CURLOPT_AWS_SIGV4 - V4 signature + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_AWS_SIGV4, char *param); +~~~ + +# DESCRIPTION + +Provides AWS V4 signature authentication on HTTP(S) header. + +Pass a char pointer that is the collection of specific arguments are used for +creating outgoing authentication headers. The format of the *param* option +is: + +## provider1[:provider2[:region[:service]]] + +## provider1, provider2 + +The providers arguments are used for generating some authentication parameters +such as "Algorithm", "date", "request type" and "signed headers". + +## region + +The argument is a geographic area of a resources collection. +It is extracted from the hostname specified in the URL if omitted. + +## service + +The argument is a function provided by a cloud. It is extracted from the +hostname specified in the URL if omitted. + +NOTE: This call set CURLOPT_HTTPAUTH(3) to CURLAUTH_AWS_SIGV4. +Calling CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same +as calling this with **"aws:amz"** in parameter. + +Example with "Test:Try", when curl uses the algorithm, it generates +**"TEST-HMAC-SHA256"** for "Algorithm", **"x-try-date"** and +**"X-Try-Date"** for "date", **"test4_request"** for "request type", +**"SignedHeaders=content-type;host;x-try-date"** for "signed headers" + +If you use just "test", instead of "test:try", test is used for every +generated string. + +# DEFAULT + +By default, the value of this parameter is NULL. +Calling CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same +as calling this with **"aws:amz"** in parameter. + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, + "https://service.region.example.com/uri"); + curl_easy_setopt(curl, CURLOPT_AWS_SIGV4, "provider1:provider2"); + + /* service and region can also be set in CURLOPT_AWS_SIGV4 */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/uri"); + curl_easy_setopt(curl, CURLOPT_AWS_SIGV4, + "provider1:provider2:region:service"); + + curl_easy_setopt(curl, CURLOPT_USERPWD, "MY_ACCESS_KEY:MY_SECRET_KEY"); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.75.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. + +# NOTES + +This option overrides the other auth types you might have set in +CURLOPT_HTTPAUTH(3) which should be highlighted as this makes this auth +method special. This method cannot be combined with other auth types. + +A sha256 checksum of the request payload is used as input to the signature +calculation. For POST requests, this is a checksum of the provided +CURLOPT_POSTFIELDS(3). Otherwise, it is the checksum of an empty buffer. For +requests like PUT, you can provide your own checksum in an HTTP header named +**x-provider2-content-sha256**. + +For **aws:s3**, a **x-amz-content-sha256** header is added to every request +if not already present. For s3 requests with unknown payload, this header takes +the special value "UNSIGNED-PAYLOAD". diff --git a/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md b/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md new file mode 100644 index 0000000..1faebee --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md @@ -0,0 +1,79 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_BUFFERSIZE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAXFILESIZE (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) + - CURLOPT_UPLOAD_BUFFERSIZE (3) + - CURLOPT_WRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_BUFFERSIZE - receive buffer size + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_BUFFERSIZE, long size); +~~~ + +# DESCRIPTION + +Pass a long specifying your preferred *size* (in bytes) for the receive buffer +in libcurl. The main point of this would be that the write callback gets +called more often and with smaller chunks. Secondly, for some protocols, there +is a benefit of having a larger buffer for performance. + +This is just treated as a request, not an order. You cannot be guaranteed to +actually get the given size. + +This buffer size is by default *CURL_MAX_WRITE_SIZE* (16kB). The maximum +buffer size allowed to be set is *CURL_MAX_READ_SIZE* (10MB). The minimum +buffer size allowed to be set is 1024. + +DO NOT set this option on a handle that is currently used for an active +transfer as that may lead to unintended consequences. + +The maximum size was 512kB until 7.88.0. + +# DEFAULT + +CURL_MAX_WRITE_SIZE (16kB) + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/foo.bin"); + + /* ask libcurl to allocate a larger receive buffer */ + curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 120000L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10. Growing the buffer was added in 7.53.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CAINFO.md b/docs/libcurl/opts/CURLOPT_CAINFO.md new file mode 100644 index 0000000..c46073f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CAINFO.md @@ -0,0 +1,87 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CAINFO +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CAINFO (3) + - CURLOPT_CAINFO_BLOB (3) + - CURLOPT_CAPATH (3) + - CURLOPT_CA_CACHE_TIMEOUT (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_CAINFO - path to Certificate Authority (CA) bundle + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CAINFO, char *path); +~~~ + +# DESCRIPTION + +Pass a char pointer to a null-terminated string naming a file holding one or +more certificates to verify the peer with. + +If CURLOPT_SSL_VERIFYPEER(3) is zero and you avoid verifying the +server's certificate, CURLOPT_CAINFO(3) need not even indicate an +accessible file. + +This option is by default set to the system path where libcurl's CA +certificate bundle is assumed to be stored, as established at build time. + +(iOS and macOS) When curl uses Secure Transport this option is supported. If +the option is not set, then curl uses the certificates in the system and user +Keychain to verify the peer. + +(Schannel) This option is supported for Schannel in Windows 7 or later but we +recommend not using it until Windows 8 since it works better starting then. +If the option is not set, then curl uses the certificates in the Windows' +store of root certificates (the default for Schannel). + +The application does not have to keep the string around after setting this +option. + +The default value for this can be figured out with CURLINFO_CAINFO(3). + +# DEFAULT + +Built-in system specific. When curl is built with Secure Transport or +Schannel, this option is not set by default. + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/certs/cabundle.pem"); + curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +For the SSL engines that do not support certificate files the +CURLOPT_CAINFO(3) option is ignored. Schannel support added in libcurl +7.60. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md new file mode 100644 index 0000000..be30446 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md @@ -0,0 +1,84 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CAINFO_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_CAPATH (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_CAINFO_BLOB - Certificate Authority (CA) bundle in PEM format + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CAINFO_BLOB, + struct curl_blob *stblob); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_blob structure, which contains information (pointer +and size) about a memory block with binary data of PEM encoded content holding +one or more certificates to verify the HTTPS server with. + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +If CURLOPT_SSL_VERIFYPEER(3) is zero and you avoid verifying the +server's certificate, CURLOPT_CAINFO_BLOB(3) is not needed. + +This option overrides CURLOPT_CAINFO(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +#include + +int main(void) +{ + char *strpem; /* strpem must point to a PEM string */ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + blob.data = strpem; + blob.len = strlen(strpem); + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.77.0. + +This option is supported by the BearSSL (since 7.79.0), mbedTLS (since +7.81.0), rustls (since 7.82.0), wolfSSL (since 8.2.0), OpenSSL, Secure +Transport and Schannel backends. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_CAPATH.md b/docs/libcurl/opts/CURLOPT_CAPATH.md new file mode 100644 index 0000000..ff1362f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CAPATH.md @@ -0,0 +1,79 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CAPATH +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CAPATH (3) + - CURLOPT_CAINFO (3) + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_CAPATH - directory holding CA certificates + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CAPATH, char *capath); +~~~ + +# DESCRIPTION + +Pass a char pointer to a null-terminated string naming a directory holding +multiple CA certificates to verify the peer with. If libcurl is built against +OpenSSL, the certificate directory must be prepared using the OpenSSL c_rehash +utility. This makes sense only when used in combination with the +CURLOPT_SSL_VERIFYPEER(3) option. + +The CURLOPT_CAPATH(3) function apparently does not work in Windows due +to some limitation in OpenSSL. + +The application does not have to keep the string around after setting this +option. + +The default value for this can be figured out with CURLINFO_CAPATH(3). + +# DEFAULT + +A default path detected at build time. + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_CAPATH, "/etc/cert-dir"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option is supported by the OpenSSL, GnuTLS and mbedTLS (since 7.56.0) +backends. + +# RETURN VALUE + +CURLE_OK if supported; or an error such as: + +CURLE_NOT_BUILT_IN - Not supported by the SSL backend + +CURLE_UNKNOWN_OPTION + +CURLE_OUT_OF_MEMORY diff --git a/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md new file mode 100644 index 0000000..ef52f97 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CA_CACHE_TIMEOUT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_CAINFO_BLOB (3) + - CURLOPT_CAPATH (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_CA_CACHE_TIMEOUT - life-time for cached certificate stores + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CA_CACHE_TIMEOUT, long age); +~~~ + +# DESCRIPTION + +Pass a long, this sets the timeout in seconds. This tells libcurl the maximum +time any cached certificate store it has in memory may be kept and reused for +new connections. Once the timeout has expired, a subsequent fetch requiring a +certificate has to reload it. + +Building a certificate store from a CURLOPT_CAINFO(3) file is a slow +operation so curl may cache the generated certificate store internally to speed +up future connections. + +Set to zero to completely disable caching, or set to -1 to retain the cached +store remain forever. By default, libcurl caches this info for 24 hours. + +# DEFAULT + +86400 (24 hours) + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* only reuse certificate stores for a short time */ + curl_easy_setopt(curl, CURLOPT_CA_CACHE_TIMEOUT, 60L); + + res = curl_easy_perform(curl); + + /* in this second request, the cache is not used if more than + sixty seconds passed since the previous connection */ + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option was added in curl 7.87.0. + +This option is supported by OpenSSL and its forks (since 7.87.0) and Schannel +(since 8.5.0). + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_CERTINFO.md b/docs/libcurl/opts/CURLOPT_CERTINFO.md new file mode 100644 index 0000000..a69e1e9 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CERTINFO.md @@ -0,0 +1,90 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CERTINFO +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CAINFO (3) + - CURLINFO_CAPATH (3) + - CURLINFO_CERTINFO (3) + - CURLOPT_CAINFO (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_CERTINFO - request SSL certificate information + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CERTINFO, long certinfo); +~~~ + +# DESCRIPTION + +Pass a long set to 1 to enable libcurl's certificate chain info gatherer. With +this enabled, libcurl extracts lots of information and data about the +certificates in the certificate chain used in the SSL connection. This data +may then be retrieved after a transfer using curl_easy_getinfo(3) and +its option CURLINFO_CERTINFO(3). + +# DEFAULT + +0 + +# PROTOCOLS + +All TLS-based + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); + + /* connect to any HTTPS site, trusted or not */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + + curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); + + res = curl_easy_perform(curl); + + if(!res) { + struct curl_certinfo *ci; + res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &ci); + + if(!res) { + int i; + printf("%d certs!\n", ci->num_of_certs); + + for(i = 0; i < ci->num_of_certs; i++) { + struct curl_slist *slist; + + for(slist = ci->certinfo[i]; slist; slist = slist->next) + printf("%s\n", slist->data); + } + } + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option is supported by the OpenSSL, GnuTLS, Schannel and Secure +Transport backends. Schannel support added in 7.50.0. Secure Transport support +added in 7.79.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md new file mode 100644 index 0000000..a208c9b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md @@ -0,0 +1,152 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CHUNK_BGN_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CHUNK_END_FUNCTION (3) + - CURLOPT_WILDCARDMATCH (3) +--- + +# NAME + +CURLOPT_CHUNK_BGN_FUNCTION - callback before a transfer with FTP wildcard match + +# SYNOPSIS + +~~~c +#include + +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; /* always zero! */ + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +long chunk_bgn_callback(const void *transfer_info, void *ptr, + int remains); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CHUNK_BGN_FUNCTION, + chunk_bgn_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl before a part of the stream is +going to be transferred (if the transfer supports chunks). + +The *transfer_info* pointer points to a **curl_fileinfo** struct with +details about the file that is about to get transferred. + +This callback makes sense only when using the CURLOPT_WILDCARDMATCH(3) +option for now. + +The target of transfer_info parameter is a "feature depended" structure. For +the FTP wildcard download, the target is **curl_fileinfo** structure (see +*curl/curl.h*). The parameter *ptr* is a pointer given by +CURLOPT_CHUNK_DATA(3). The parameter remains contains number of chunks +remaining per the transfer. If the feature is not available, the parameter has +zero value. + +Return *CURL_CHUNK_BGN_FUNC_OK* if everything is fine, +*CURL_CHUNK_BGN_FUNC_SKIP* if you want to skip the concrete chunk or +*CURL_CHUNK_BGN_FUNC_FAIL* to tell libcurl to stop if some error occurred. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +#include + +struct callback_data { + FILE *output; +}; + +static long file_is_coming(struct curl_fileinfo *finfo, + void *ptr, + int remains) +{ + struct callback_data *data = ptr; + printf("%3d %40s %10luB ", remains, finfo->filename, + (unsigned long)finfo->size); + + switch(finfo->filetype) { + case CURLFILETYPE_DIRECTORY: + printf(" DIR\n"); + break; + case CURLFILETYPE_FILE: + printf("FILE "); + break; + default: + printf("OTHER\n"); + break; + } + + if(finfo->filetype == CURLFILETYPE_FILE) { + /* do not transfer files >= 50B */ + if(finfo->size > 50) { + printf("SKIPPED\n"); + return CURL_CHUNK_BGN_FUNC_SKIP; + } + + data->output = fopen(finfo->filename, "wb"); + if(!data->output) { + return CURL_CHUNK_BGN_FUNC_FAIL; + } + } + + return CURL_CHUNK_BGN_FUNC_OK; +} + +int main() +{ + /* data for callback */ + struct callback_data callback_info; + + CURL *curl = curl_easy_init(); + + /* callback is called before download of concrete file started */ + curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming); + curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info); +} +~~~ + +# AVAILABILITY + +This was added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md b/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md new file mode 100644 index 0000000..3640ec8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md @@ -0,0 +1,102 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CHUNK_DATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CHUNK_BGN_FUNCTION (3) + - CURLOPT_WILDCARDMATCH (3) +--- + +# NAME + +CURLOPT_CHUNK_DATA - pointer passed to the FTP chunk callbacks + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CHUNK_DATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* that is untouched by libcurl and passed as the ptr +argument to the CURLOPT_CHUNK_BGN_FUNCTION(3) and +CURLOPT_CHUNK_END_FUNCTION(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +#include + +struct callback_data { + FILE *output; +}; + +static long file_is_coming(struct curl_fileinfo *finfo, + void *ptr, + int remains) +{ + struct callback_data *data = ptr; + printf("%3d %40s %10luB ", remains, finfo->filename, + (unsigned long)finfo->size); + + switch(finfo->filetype) { + case CURLFILETYPE_DIRECTORY: + printf(" DIR\n"); + break; + case CURLFILETYPE_FILE: + printf("FILE "); + break; + default: + printf("OTHER\n"); + break; + } + + if(finfo->filetype == CURLFILETYPE_FILE) { + /* do not transfer files >= 50B */ + if(finfo->size > 50) { + printf("SKIPPED\n"); + return CURL_CHUNK_BGN_FUNC_SKIP; + } + + data->output = fopen(finfo->filename, "wb"); + if(!data->output) { + return CURL_CHUNK_BGN_FUNC_FAIL; + } + } + + return CURL_CHUNK_BGN_FUNC_OK; +} + +int main() +{ + /* data for callback */ + struct callback_data callback_info; + + CURL *curl = curl_easy_init(); + + /* callback is called before download of concrete file started */ + curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming); + curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info); +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md new file mode 100644 index 0000000..2d67afe --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CHUNK_END_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CHUNK_BGN_FUNCTION (3) + - CURLOPT_WILDCARDMATCH (3) +--- + +# NAME + +CURLOPT_CHUNK_END_FUNCTION - callback after a transfer with FTP wildcard match + +# SYNOPSIS + +~~~c +#include + +long chunk_end_callback(void *ptr); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CHUNK_END_FUNCTION, + chunk_end_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This function gets called by libcurl as soon as a part of the stream has been +transferred (or skipped). + +Return *CURL_CHUNK_END_FUNC_OK* if everything is fine or +**CURL_CHUNK_END_FUNC_FAIL** to tell the lib to stop if some error occurred. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +#include + +struct callback_data { + FILE *output; +}; + +static long file_is_downloaded(struct callback_data *data) +{ + if(data->output) { + fclose(data->output); + data->output = 0x0; + } + return CURL_CHUNK_END_FUNC_OK; +} + +int main() +{ + /* data for callback */ + struct callback_data callback_info; + + CURL *curl = curl_easy_init(); + + curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded); + curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info); +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md b/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md new file mode 100644 index 0000000..2dd7477 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CLOSESOCKETDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CLOSESOCKETFUNCTION (3) + - CURLOPT_OPENSOCKETFUNCTION (3) +--- + +# NAME + +CURLOPT_CLOSESOCKETDATA - pointer passed to the socket close callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CLOSESOCKETDATA, + void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* that remains untouched by libcurl and passed as the first +argument in the closesocket callback set with +CURLOPT_CLOSESOCKETFUNCTION(3). + +# DEFAULT + +The default value of this parameter is NULL. + +# PROTOCOLS + +All except file: + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static int closesocket(void *clientp, curl_socket_t item) +{ + struct priv *my = clientp; + printf("our ptr: %p\n", my->custom); + + printf("libcurl wants to close %d now\n", (int)item); + return 0; +} + +int main(void) +{ + struct priv myown; + CURL *curl = curl_easy_init(); + + /* call this function to close sockets */ + curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closesocket); + curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &myown); + + curl_easy_perform(curl); + curl_easy_cleanup(curl); +} +~~~ + +# AVAILABILITY + +Added in 7.21.7 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md b/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md new file mode 100644 index 0000000..e93e28c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md @@ -0,0 +1,86 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CLOSESOCKETFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CLOSESOCKETDATA (3) + - CURLOPT_OPENSOCKETFUNCTION (3) +--- + +# NAME + +CURLOPT_CLOSESOCKETFUNCTION - callback to socket close replacement + +# SYNOPSIS + +~~~c +#include + +int closesocket_callback(void *clientp, curl_socket_t item); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CLOSESOCKETFUNCTION, + closesocket_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl instead of the *close(3)* or +*closesocket(3)* call when sockets are closed (not for any other file +descriptors). This is pretty much the reverse to the +CURLOPT_OPENSOCKETFUNCTION(3) option. Return 0 to signal success and 1 +if there was an error. + +The *clientp* pointer is set with +CURLOPT_CLOSESOCKETDATA(3). *item* is the socket libcurl wants to be +closed. + +# DEFAULT + +By default libcurl uses the standard socket close function. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static int closesocket(void *clientp, curl_socket_t item) +{ + struct priv *my = clientp; + printf("our ptr: %p\n", my->custom); + + printf("libcurl wants to close %d now\n", (int)item); + return 0; +} + +int main(void) +{ + struct priv myown; + CURL *curl = curl_easy_init(); + + /* call this function to close sockets */ + curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closesocket); + curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &myown); + + curl_easy_perform(curl); + curl_easy_cleanup(curl); +} +~~~ + +# AVAILABILITY + +Added in 7.21.7 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md new file mode 100644 index 0000000..07513fd --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md @@ -0,0 +1,89 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CONNECTTIMEOUT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT_MS (3) + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_CONNECTTIMEOUT - timeout for the connect phase + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT, long timeout); +~~~ + +# DESCRIPTION + +Pass a long. It should contain the maximum time in seconds that you allow the +connection phase to the server to take. This timeout only limits the +connection phase, it has no impact once it has connected. Set to zero to +switch to the default built-in connection timeout - 300 seconds. See also the +CURLOPT_TIMEOUT(3) option. + +CURLOPT_CONNECTTIMEOUT_MS(3) is the same function but set in milliseconds. + +If both CURLOPT_CONNECTTIMEOUT(3) and CURLOPT_CONNECTTIMEOUT_MS(3) +are set, the value set last is used. + +The "connection phase" is considered complete when the requested TCP, TLS or +QUIC handshakes are done. + +The connection timeout set with CURLOPT_CONNECTTIMEOUT(3) is included in +the general all-covering CURLOPT_TIMEOUT(3). + +With CURLOPT_CONNECTTIMEOUT(3) set to 3 and CURLOPT_TIMEOUT(3) set +to 5, the operation can never last longer than 5 seconds, and the connection +phase cannot last longer than 3 seconds. + +With CURLOPT_CONNECTTIMEOUT(3) set to 4 and CURLOPT_TIMEOUT(3) set +to 2, the operation can never last longer than 2 seconds. Including the +connection phase. + +This option may cause libcurl to use the SIGALRM signal to timeout system +calls on builds not using asynch DNS. In unix-like systems, this might cause +signals to be used unless CURLOPT_NOSIGNAL(3) is set. + +# DEFAULT + +300 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* complete connection within 10 seconds */ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK. Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative +value or a value that when converted to milliseconds is too large. diff --git a/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md new file mode 100644 index 0000000..b8508e7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CONNECTTIMEOUT_MS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT (3) + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_CONNECTTIMEOUT_MS - timeout for the connect phase + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT_MS, + long timeout); +~~~ + +# DESCRIPTION + +Pass a long. It should contain the maximum time in milliseconds that you allow +the connection phase to the server to take. + +See CURLOPT_CONNECTTIMEOUT(3) for details. + +# DEFAULT + +300000 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* complete connection within 10000 milliseconds */ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 10000L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md b/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md new file mode 100644 index 0000000..3312936 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CONNECT_ONLY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPPROXYTUNNEL (3) + - CURLOPT_VERBOSE (3) + - curl_easy_recv (3) + - curl_easy_send (3) +--- + +# NAME + +CURLOPT_CONNECT_ONLY - stop when connected to target server + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECT_ONLY, long only); +~~~ + +# DESCRIPTION + +Pass a long. If the parameter equals 1, it tells the library to perform all +the required proxy authentication and connection setup, but no data transfer, +and then return. + +The option can be used to simply test a connection to a server, but is more +useful when used with the CURLINFO_ACTIVESOCKET(3) option to +curl_easy_getinfo(3) as the library can set up the connection and then +the application can obtain the most recently used socket for special data +transfers. + +Since 7.86.0, this option can be set to '2' and if HTTP or WebSocket are used, +libcurl performs the request and reads all response headers before handing +over control to the application. + +Transfers marked connect only do not reuse any existing connections and +connections marked connect only are not allowed to get reused. + +If the connect only transfer is done using the multi interface, the particular +easy handle must remain added to the multi handle for as long as the +application wants to use it. Once it has been removed with +curl_multi_remove_handle(3), curl_easy_send(3) and +curl_easy_recv(3) do not function. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP, SMTP, POP3 and IMAP. For WS and WSS starting in 7.86.0. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); + ret = curl_easy_perform(curl); + if(ret == CURLE_OK) { + /* only connected! */ + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CONNECT_TO.md b/docs/libcurl/opts/CURLOPT_CONNECT_TO.md new file mode 100644 index 0000000..8aea3ff --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CONNECT_TO.md @@ -0,0 +1,114 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CONNECT_TO +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FOLLOWLOCATION (3) + - CURLOPT_HTTPPROXYTUNNEL (3) + - CURLOPT_RESOLVE (3) + - CURLOPT_URL (3) +--- + +# NAME + +CURLOPT_CONNECT_TO - connect to another host and port instead + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECT_TO, + struct curl_slist *connect_to); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of strings with "connect to" information to +use for establishing network connections with this handle. The linked list +should be a fully valid list of **struct curl_slist** structs properly filled +in. Use curl_slist_append(3) to create the list and curl_slist_free_all(3) to +clean up an entire list. + +Each single string should be written using the format +HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT where HOST is the host of the +request, PORT is the port of the request, CONNECT-TO-HOST is the hostname to +connect to, and CONNECT-TO-PORT is the port to connect to. + +The first string that matches the request's host and port is used. + +Dotted numerical IP addresses are supported for HOST and CONNECT-TO-HOST. +A numerical IPv6 address must be written within [brackets]. + +Any of the four values may be empty. When the HOST or PORT is empty, the host +or port always match (the request's host or port is ignored). When +CONNECT-TO-HOST or CONNECT-TO-PORT is empty, the "connect to" feature is +disabled for the host or port, and the request's host or port are used to +establish the network connection. + +This option is suitable to direct the request at a specific server, e.g. at a +specific cluster node in a cluster of servers. + +The "connect to" host and port are only used to establish the network +connection. They do NOT affect the host and port that are used for TLS/SSL +(e.g. SNI, certificate verification) or for the application protocols. + +In contrast to CURLOPT_RESOLVE(3), the option CURLOPT_CONNECT_TO(3) does not +pre-populate the DNS cache and therefore it does not affect future transfers +of other easy handles that have been added to the same multi handle. + +The "connect to" host and port are ignored if they are equal to the host and +the port in the request URL, because connecting to the host and the port in +the request URL is the default behavior. + +If an HTTP proxy is used for a request having a special "connect to" host or +port, and the "connect to" host or port differs from the request's host and +port, the HTTP proxy is automatically switched to tunnel mode for this +specific request. This is necessary because it is not possible to connect to a +specific host or port in normal (non-tunnel) mode. + +When this option is passed to curl_easy_setopt(3), libcurl does not copy the +list so you **must** keep it around until you no longer use this *handle* for +a transfer before you call curl_slist_free_all(3) on the list. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl; + struct curl_slist *connect_to = NULL; + connect_to = curl_slist_append(NULL, "example.com::server1.example.com:"); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CONNECT_TO, connect_to); + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + curl_slist_free_all(connect_to); +} +~~~ + +# AVAILABILITY + +Added in 7.49.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md new file mode 100644 index 0000000..7460a1e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md @@ -0,0 +1,114 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CONV_FROM_NETWORK_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONV_FROM_UTF8_FUNCTION (3) + - CURLOPT_CONV_TO_NETWORK_FUNCTION (3) +--- + +# NAME + +CURLOPT_CONV_FROM_NETWORK_FUNCTION - convert data from network to host encoding + +# SYNOPSIS + +~~~c +#include + +CURLcode conv_callback(char *ptr, size_t length); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONV_FROM_NETWORK_FUNCTION, + conv_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +Applies to non-ASCII platforms. curl_version_info(3) returns the +**CURL_VERSION_CONV** feature bit set if this option is provided. + +The data to be converted is in a buffer pointed to by the *ptr* parameter. +The amount of data to convert is indicated by the *length* parameter. The +converted data overlays the input data in the buffer pointed to by the ptr +parameter. *CURLE_OK* must be returned upon successful conversion. A +CURLcode return value defined by curl.h, such as *CURLE_CONV_FAILED*, +should be returned if an error was encountered. + +CURLOPT_CONV_FROM_NETWORK_FUNCTION(3) converts to host encoding from the +network encoding. It is used when commands or ASCII data are received over the +network. + +If you set a callback pointer to NULL, or do not set it at all, the built-in +libcurl iconv functions are used. If HAVE_ICONV was not defined when libcurl +was built, and no callback has been established, the conversion returns the +**CURLE_CONV_REQD** error code. + +If **HAVE_ICONV** is defined, **CURL_ICONV_CODESET_OF_HOST** must also be +defined. For example: + +~~~c +#define CURL_ICONV_CODESET_OF_HOST "IBM-1047" +~~~ + +The iconv code in libcurl defaults the network and UTF8 codeset names as +follows: + +~~~ +#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" + +#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" +~~~ + +You need to override these definitions if they are different on your system. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP, SMTP, IMAP, POP3 + +# EXAMPLE + +~~~c +static CURLcode my_conv_from_ascii_to_ebcdic(char *buffer, size_t length) +{ + int rc = 0; + + /* in-place convert 'buffer' from ASCII to EBCDIC */ + + if(rc == 0) { + /* success */ + return CURLE_OK; + } + else { + return CURLE_CONV_FAILED; + } +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + + /* use platform-specific functions for codeset conversions */ + curl_easy_setopt(curl, CURLOPT_CONV_FROM_NETWORK_FUNCTION, + my_conv_from_ascii_to_ebcdic); +} +~~~ + +# AVAILABILITY + +Not available and deprecated since 7.82.0. + +Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was +built. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md new file mode 100644 index 0000000..1f7d704 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md @@ -0,0 +1,107 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CONV_FROM_UTF8_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3) + - CURLOPT_CONV_TO_NETWORK_FUNCTION (3) +--- + +# NAME + +CURLOPT_CONV_FROM_UTF8_FUNCTION - convert data from UTF8 to host encoding + +# SYNOPSIS + +~~~c +#include + +CURLcode conv_callback(char *ptr, size_t length); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONV_FROM_UTF8_FUNCTION, + conv_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +Applies to non-ASCII platforms. curl_version_info(3) returns the +CURL_VERSION_CONV feature bit set if this option is provided. + +The data to be converted is in a buffer pointed to by the *ptr* parameter. +The amount of data to convert is indicated by the *length* parameter. The +converted data overlays the input data in the buffer pointed to by the ptr +parameter. *CURLE_OK* must be returned upon successful conversion. A +CURLcode return value defined by curl.h, such as *CURLE_CONV_FAILED*, +should be returned if an error was encountered. + +CURLOPT_CONV_FROM_UTF8_FUNCTION(3) converts to host encoding from UTF8 +encoding. It is required only for SSL processing. + +If you set a callback pointer to NULL, or do not set it at all, the built-in +libcurl iconv functions are used. If HAVE_ICONV was not defined when libcurl +was built, and no callback has been established, the conversion returns the +CURLE_CONV_REQD error code. + +If HAVE_ICONV is defined, CURL_ICONV_CODESET_OF_HOST must also be defined. +For example: +~~~c + #define CURL_ICONV_CODESET_OF_HOST "IBM-1047" +~~~ + +The iconv code in libcurl defaults the network and UTF8 codeset names as +follows: +~~~c +#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" + +#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" +~~~ + +You need to override these definitions if they are different on your system. + +# DEFAULT + +NULL + +# PROTOCOLS + +TLS-based protocols. + +# EXAMPLE + +~~~c +static CURLcode my_conv_from_utf8_to_ebcdic(char *buffer, size_t length) +{ + int rc = 0; + /* in-place convert 'buffer' from UTF-8 to EBCDIC */ + if(rc == 0) { + /* success */ + return CURLE_OK; + } + else { + return CURLE_CONV_FAILED; + } +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_CONV_FROM_UTF8_FUNCTION, + my_conv_from_utf8_to_ebcdic); +} +~~~ + +# AVAILABILITY + +Not available and deprecated since 7.82.0. + +Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was +built. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md new file mode 100644 index 0000000..13d9da8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md @@ -0,0 +1,110 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CONV_TO_NETWORK_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3) + - CURLOPT_CONV_FROM_UTF8_FUNCTION (3) +--- + +# NAME + +CURLOPT_CONV_TO_NETWORK_FUNCTION - convert data to network from host encoding + +# SYNOPSIS + +~~~c +#include + +CURLcode conv_callback(char *ptr, size_t length); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONV_TO_NETWORK_FUNCTION, + conv_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +Applies to non-ASCII platforms. curl_version_info(3) returns the +CURL_VERSION_CONV feature bit set if this option is provided. + +The data to be converted is in a buffer pointed to by the *ptr* parameter. +The amount of data to convert is indicated by the *length* parameter. The +converted data overlays the input data in the buffer pointed to by the ptr +parameter. *CURLE_OK* must be returned upon successful conversion. A CURLcode +return value defined by curl.h, such as *CURLE_CONV_FAILED*, should be +returned if an error was encountered. + +CURLOPT_CONV_TO_NETWORK_FUNCTION(3) converts from host encoding to the +network encoding. It is used when commands or ASCII data are sent over the +network. + +If you set a callback pointer to NULL, or do not set it at all, the built-in +libcurl iconv functions are used. If HAVE_ICONV was not defined when libcurl +was built, and no callback has been established, the conversion returns the +CURLE_CONV_REQD error code. + +If HAVE_ICONV is defined, CURL_ICONV_CODESET_OF_HOST must also be defined. +For example: +~~~c +define CURL_ICONV_CODESET_OF_HOST "IBM-1047" +~~~ + +The iconv code in libcurl defaults the network and UTF8 codeset names as +follows: + +~~~c +#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" + +#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" +~~~ + +You need to override these definitions if they are different on your system. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP, SMTP, IMAP, POP3 + +# EXAMPLE + +~~~c +static CURLcode my_conv_from_ebcdic_to_ascii(char *buffer, size_t length) +{ + int rc = 0; + /* in-place convert 'buffer' from EBCDIC to ASCII */ + if(rc == 0) { + /* success */ + return CURLE_OK; + } + else { + return CURLE_CONV_FAILED; + } +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + + curl_easy_setopt(curl, CURLOPT_CONV_TO_NETWORK_FUNCTION, + my_conv_from_ebcdic_to_ascii); +} +~~~ + +# AVAILABILITY + +Not available and deprecated since 7.82.0. + +Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was +built. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_COOKIE.md b/docs/libcurl/opts/CURLOPT_COOKIE.md new file mode 100644 index 0000000..4e2955d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_COOKIE.md @@ -0,0 +1,97 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_COOKIE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_COOKIELIST (3) + - CURLOPT_COOKIEFILE (3) + - CURLOPT_COOKIEJAR (3) + - CURLOPT_COOKIELIST (3) + - CURLOPT_HTTPHEADER (3) +--- + +# NAME + +CURLOPT_COOKIE - HTTP Cookie header + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COOKIE, char *cookie); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. It is used to set one +or more cookies in the HTTP request. The format of the string should be +NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie +should contain. + +To set multiple cookies, set them all using a single option concatenated like +this: "name1=content1; name2=content2;" etc. + +This option sets the cookie header explicitly in the outgoing request(s). If +multiple requests are done due to authentication, followed redirections or +similar, they all get this cookie passed on. + +The cookies set by this option are separate from the internal cookie storage +held by the cookie engine and they are not be modified by it. If you enable +the cookie engine and either you have imported a cookie of the same name +(e.g. 'foo') or the server has set one, it has no effect on the cookies you +set here. A request to the server sends both the 'foo' held by the cookie +engine and the 'foo' held by this option. To set a cookie that is instead held +by the cookie engine and can be modified by the server use +CURLOPT_COOKIELIST(3). + +Using this option multiple times makes the last set string override the +previous ones. + +This option does not enable the cookie engine. Use CURLOPT_COOKIEFILE(3) +or CURLOPT_COOKIEJAR(3) to enable parsing and sending cookies +automatically. + +The application does not have to keep the string around after setting this +option. + +If libcurl is built with PSL (*Public Suffix List*) support, it detects and +discards cookies that are specified for such suffix domains that should not be +allowed to have cookies. If libcurl is *not* built with PSL support, it has no +ability to stop super cookies. PSL support is identified by the +**CURL_VERSION_PSL** feature bit returned by curl_version_info(3). + +# DEFAULT + +NULL, no cookies + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_COOKIE, "tool=curl; fun=yes;"); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +If HTTP is enabled + +# RETURN VALUE + +Returns CURLE_OK if HTTP is enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_COOKIEFILE.md b/docs/libcurl/opts/CURLOPT_COOKIEFILE.md new file mode 100644 index 0000000..87dce1b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_COOKIEFILE.md @@ -0,0 +1,103 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_COOKIEFILE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_COOKIE (3) + - CURLOPT_COOKIEJAR (3) + - CURLOPT_COOKIESESSION (3) +--- + +# NAME + +CURLOPT_COOKIEFILE - filename to read cookies from + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COOKIEFILE, char *filename); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. It should point to +the filename of your file holding cookie data to read. The cookie data can be +in either the old Netscape / Mozilla cookie data format or just regular HTTP +headers (Set-Cookie style) dumped to a file. + +It also enables the cookie engine, making libcurl parse and send cookies on +subsequent requests with this handle. + +By passing the empty string ("") to this option, you enable the cookie engine +without reading any initial cookies. If you tell libcurl the filename is "-" +(just a single minus sign), libcurl instead reads from stdin. + +This option only **reads** cookies. To make libcurl write cookies to file, +see CURLOPT_COOKIEJAR(3). + +If you read cookies from a plain HTTP headers file and it does not specify a +domain in the Set-Cookie line, then the cookie is not sent since the cookie +domain cannot match the target URL's. To address this, set a domain in +Set-Cookie line (doing that includes subdomains) or preferably: use the +Netscape format. + +If you use this option multiple times, you add more files to read cookies +from. + +The application does not have to keep the string around after setting this +option. + +Setting this option to NULL (since 7.77.0) explicitly disables the cookie +engine and clears the list of files to read cookies from. + +# SECURITY + +This document previously mentioned how specifying a non-existing file can also +enable the cookie engine. While true, we strongly advise against using that +method as it is too hard to be sure that files that stay that way in the long +run. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* get cookies from an existing file */ + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookies.txt"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# Cookie file format + +The cookie file format and general cookie concepts in curl are described +online here: https://curl.se/docs/http-cookies.html + +# AVAILABILITY + +As long as HTTP is supported + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_COOKIEJAR.md b/docs/libcurl/opts/CURLOPT_COOKIEJAR.md new file mode 100644 index 0000000..ec0d273 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_COOKIEJAR.md @@ -0,0 +1,86 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_COOKIEJAR +Section: 3 +Source: libcurl +See-also: + - CURLOPT_COOKIE (3) + - CURLOPT_COOKIEFILE (3) + - CURLOPT_COOKIELIST (3) +--- + +# NAME + +CURLOPT_COOKIEJAR - filename to store cookies to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COOKIEJAR, char *filename); +~~~ + +# DESCRIPTION + +Pass a *filename* as a char *, null-terminated. This makes libcurl write +all internally known cookies to the specified file when +curl_easy_cleanup(3) is called. If no cookies are kept in memory at that +time, no file is created. Specify "-" as filename to instead have the cookies +written to stdout. Using this option also enables cookies for this session, so +if you for example follow a redirect it makes matching cookies get sent +accordingly. + +Note that libcurl does not read any cookies from the cookie jar specified with +this option. To read cookies from a file, use CURLOPT_COOKIEFILE(3). + +If the cookie jar file cannot be created or written to (when the +curl_easy_cleanup(3) is called), libcurl does not and cannot report an +error for this. Using CURLOPT_VERBOSE(3) or +CURLOPT_DEBUGFUNCTION(3) displays a warning, but that is the only +visible feedback you get about this possibly lethal situation. + +Cookies are imported in the Set-Cookie format without a domain name are not +exported by this option. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* export cookies to this file when closing the handle */ + curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "/tmp/cookies.txt"); + + res = curl_easy_perform(curl); + + /* close the handle, write the cookies! */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_COOKIELIST.md b/docs/libcurl/opts/CURLOPT_COOKIELIST.md new file mode 100644 index 0000000..4c17bd4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_COOKIELIST.md @@ -0,0 +1,136 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_COOKIELIST +Section: 3 +Source: libcurl +See-also: + - CURLINFO_COOKIELIST (3) + - CURLOPT_COOKIE (3) + - CURLOPT_COOKIEFILE (3) + - CURLOPT_COOKIEJAR (3) +--- + +# NAME + +CURLOPT_COOKIELIST - add to or manipulate cookies held in memory + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COOKIELIST, + char *cookie); +~~~ + +# DESCRIPTION + +Pass a char pointer to a *cookie* string. + +Such a cookie can be either a single line in Netscape / Mozilla format or just +regular HTTP-style header (Set-Cookie: ...) format. This option also enables +the cookie engine. This adds that single cookie to the internal cookie store. + +We strongly advice against loading cookies from an HTTP header file, as that +is an inferior data exchange format. + +Exercise caution if you are using this option and multiple transfers may +occur. If you use the Set-Cookie format and the string does not specify a +domain, then the cookie is sent for any domain (even after redirects are +followed) and cannot be modified by a server-set cookie. If a server sets a +cookie of the same name (or maybe you have imported one) then both are sent on +future transfers to that server, likely not what you intended. To address +these issues set a domain in Set-Cookie (doing that includes subdomains) or +much better: use the Netscape file format. + +Additionally, there are commands available that perform actions if you pass in +these exact strings: + +## ALL + +erases all cookies held in memory + +## SESS + +erases all session cookies held in memory + +## FLUSH + +writes all known cookies to the file specified by CURLOPT_COOKIEJAR(3) + +## RELOAD + +loads all cookies from the files specified by CURLOPT_COOKIEFILE(3) + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +/* an inline import of a cookie in Netscape format. */ + +#define SEP "\t" /* Tab separates the fields */ + +int main(void) +{ + char *my_cookie = + "example.com" /* Hostname */ + SEP "FALSE" /* Include subdomains */ + SEP "/" /* Path */ + SEP "FALSE" /* Secure */ + SEP "0" /* Expiry in epoch time format. 0 == Session */ + SEP "foo" /* Name */ + SEP "bar"; /* Value */ + + CURL *curl = curl_easy_init(); + if(curl) { + /* my_cookie is imported immediately via CURLOPT_COOKIELIST. */ + curl_easy_setopt(curl, CURLOPT_COOKIELIST, my_cookie); + + /* The list of cookies in cookies.txt are not be imported until right + before a transfer is performed. Cookies in the list that have the same + hostname, path and name as in my_cookie are skipped. That is because + libcurl has already imported my_cookie and it's considered a "live" + cookie. A live cookie is not replaced by one read from a file. + */ + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookies.txt"); /* import */ + + /* Cookies are exported after curl_easy_cleanup is called. The server + may have added, deleted or modified cookies by then. The cookies that + were skipped on import are not exported. + */ + curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt"); /* export */ + + curl_easy_perform(curl); /* cookies imported from cookies.txt */ + + curl_easy_cleanup(curl); /* cookies exported to cookies.txt */ + } +} +~~~ + +# Cookie file format + +The cookie file format and general cookie concepts in curl are described +online here: https://curl.se/docs/http-cookies.html + +# AVAILABILITY + +**ALL** was added in 7.14.1 + +**SESS** was added in 7.15.4 + +**FLUSH** was added in 7.17.1 + +**RELOAD** was added in 7.39.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_COOKIESESSION.md b/docs/libcurl/opts/CURLOPT_COOKIESESSION.md new file mode 100644 index 0000000..6f49f02 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_COOKIESESSION.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_COOKIESESSION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_COOKIE (3) + - CURLOPT_COOKIEFILE (3) + - CURLOPT_COOKIEJAR (3) +--- + +# NAME + +CURLOPT_COOKIESESSION - start a new cookie session + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COOKIESESSION, long init); +~~~ + +# DESCRIPTION + +Pass a long set to 1 to mark this as a new cookie "session". It forces libcurl +to ignore all cookies it is about to load that are "session cookies" from the +previous session. By default, libcurl always loads all cookies, independent if +they are session cookies or not. Session cookies are cookies without expiry +date and they are meant to be alive and existing for this "session" only. + +A "session" is usually defined in browser land for as long as you have your +browser up, more or less. libcurl needs the application to use this option to +tell it when a new session starts, otherwise it assumes everything is still in +the same session. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* new "session", do not load session cookies */ + curl_easy_setopt(curl, CURLOPT_COOKIESESSION, 1L); + + /* get the (non session) cookies from this file */ + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookies.txt"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md b/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md new file mode 100644 index 0000000..911e081 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_COPYPOSTFIELDS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MIMEPOST (3) + - CURLOPT_POSTFIELDS (3) + - CURLOPT_POSTFIELDSIZE (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_COPYPOSTFIELDS - have libcurl copy data to POST + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COPYPOSTFIELDS, char *data); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be the full *data* to post in a +HTTP POST operation. It behaves as the CURLOPT_POSTFIELDS(3) option, but the +original data is instead copied by the library, allowing the application to +overwrite the original data after setting this option. + +Because data are copied, care must be taken when using this option in +conjunction with CURLOPT_POSTFIELDSIZE(3) or +CURLOPT_POSTFIELDSIZE_LARGE(3): If the size has not been set prior to +CURLOPT_COPYPOSTFIELDS(3), the data is assumed to be a null-terminated +string; else the stored size informs the library about the byte count to +copy. In any case, the size must not be changed after +CURLOPT_COPYPOSTFIELDS(3), unless another CURLOPT_POSTFIELDS(3) or +CURLOPT_COPYPOSTFIELDS(3) option is issued. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + char local_buffer[1024]="data to send"; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* size of the data to copy from the buffer and send in the request */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 12L); + + /* send data from the local stack */ + curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, local_buffer); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.17.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_CRLF.md b/docs/libcurl/opts/CURLOPT_CRLF.md new file mode 100644 index 0000000..1766c33 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CRLF.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CRLF +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3) + - CURLOPT_CONV_TO_NETWORK_FUNCTION (3) +--- + +# NAME + +CURLOPT_CRLF - CRLF conversion + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CRLF, long conv); +~~~ + +# DESCRIPTION + +Pass a long. If the value is set to 1 (one), libcurl converts Unix newlines to +CRLF newlines on transfers. Disable this option again by setting the value to +0 (zero). + +This is a legacy option of questionable use. + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/"); + curl_easy_setopt(curl, CURLOPT_CRLF, 1L); + ret = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +SMTP since 7.40.0, other protocols since they were introduced + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_CRLFILE.md b/docs/libcurl/opts/CURLOPT_CRLFILE.md new file mode 100644 index 0000000..b800f8c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CRLFILE.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CRLFILE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_CRLFILE (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_CRLFILE - Certificate Revocation List file + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CRLFILE, char *file); +~~~ + +# DESCRIPTION + +Pass a char pointer to a null-terminated string naming a *file* with the +concatenation of CRL (in PEM format) to use in the certificate validation that +occurs during the SSL exchange. + +When curl is built to use GnuTLS, there is no way to influence the use of CRL +passed to help in the verification process. + +When libcurl is built with OpenSSL support, X509_V_FLAG_CRL_CHECK and +X509_V_FLAG_CRL_CHECK_ALL are both set, requiring CRL check against all the +elements of the certificate chain if a CRL file is passed. Also note that +CURLOPT_CRLFILE(3) implies **CURLSSLOPT_NO_PARTIALCHAIN** (see +CURLOPT_SSL_OPTIONS(3)) since curl 7.71.0 due to an OpenSSL bug. + +This option makes sense only when used in combination with the +CURLOPT_SSL_VERIFYPEER(3) option. + +A specific error code (*CURLE_SSL_CRL_BADFILE*) is defined with the option. It +is returned when the SSL exchange fails because the CRL file cannot be +loaded. A failure in certificate verification due to a revocation information +found in the CRL does not trigger this specific error. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_CRLFILE, "/etc/certs/crl.pem"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_CURLU.md b/docs/libcurl/opts/CURLOPT_CURLU.md new file mode 100644 index 0000000..a3eeb5c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CURLU.md @@ -0,0 +1,79 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CURLU +Section: 3 +Source: libcurl +See-also: + - CURLOPT_URL (3) + - curl_url (3) + - curl_url_cleanup (3) + - curl_url_dup (3) + - curl_url_get (3) + - curl_url_set (3) + - curl_url_strerror (3) +--- + +# NAME + +CURLOPT_CURLU - URL in URL handle format + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CURLU, CURLU *pointer); +~~~ + +# DESCRIPTION + +Pass in a pointer to the *URL* handle to work with. The parameter should be a +*CURLU pointer*. Setting CURLOPT_CURLU(3) explicitly overrides +CURLOPT_URL(3). + +CURLOPT_URL(3) or CURLOPT_CURLU(3) **must** be set before a +transfer is started. + +libcurl uses this handle and its contents read-only and does not change its +contents. An application can update the contents of the URL handle after a +transfer is done and if the same handle is used in a subsequent request the +updated contents is used. + +# DEFAULT + +The default value of this parameter is NULL. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + CURLU *urlp = curl_url(); + if(curl) { + CURLcode res; + CURLUcode ret; + ret = curl_url_set(urlp, CURLUPART_URL, "https://example.com", 0); + + curl_easy_setopt(curl, CURLOPT_CURLU, urlp); + + res = curl_easy_perform(curl); + + curl_url_cleanup(urlp); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.63.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md b/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md new file mode 100644 index 0000000..c4d4ec2 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md @@ -0,0 +1,130 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_CUSTOMREQUEST +Section: 3 +Source: libcurl +See-also: + - CURLINFO_EFFECTIVE_METHOD (3) + - CURLOPT_HTTPHEADER (3) + - CURLOPT_NOBODY (3) + - CURLOPT_REQUEST_TARGET (3) +--- + +# NAME + +CURLOPT_CUSTOMREQUEST - custom request method + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CUSTOMREQUEST, char *method); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. + +When changing the request *method* by setting CURLOPT_CUSTOMREQUEST(3), you +do not actually change how libcurl behaves or acts: you only change the actual +string sent in the request. + +libcurl passes on the verbatim string in its request without any filter or +other safe guards. That includes white space and control characters. + +Restore to the internal default by setting this to NULL. + +This option can be used to specify the request: + +## HTTP + +Instead of GET or HEAD when performing HTTP based requests. This is +particularly useful, for example, for performing an HTTP DELETE request. + +For example: + +When you tell libcurl to do a HEAD request, but then specify a GET though a +custom request libcurl still acts as if it sent a HEAD. To switch to a proper +HEAD use CURLOPT_NOBODY(3), to switch to a proper POST use +CURLOPT_POST(3) or CURLOPT_POSTFIELDS(3) and to switch to a proper +GET use CURLOPT_HTTPGET(3). + +Many people have wrongly used this option to replace the entire request with +their own, including multiple headers and POST contents. While that might work +in many cases, it might cause libcurl to send invalid requests and it could +possibly confuse the remote server badly. Use CURLOPT_POST(3) and +CURLOPT_POSTFIELDS(3) to set POST data. Use CURLOPT_HTTPHEADER(3) +to replace or extend the set of headers sent by libcurl. Use +CURLOPT_HTTP_VERSION(3) to change HTTP version. + +## FTP + +Instead of LIST and NLST when performing FTP directory listings. + +## IMAP + +Instead of LIST when issuing IMAP based requests. + +## POP3 + +Instead of LIST and RETR when issuing POP3 based requests. + +For example: + +When you tell libcurl to use a custom request it behaves like a LIST or RETR +command was sent where it expects data to be returned by the server. As such +CURLOPT_NOBODY(3) should be used when specifying commands such as +**DELE** and **NOOP** for example. + +## SMTP + +Instead of a **HELP** or **VRFY** when issuing SMTP based requests. + +For example: + +Normally a multi line response is returned which can be used, in conjunction +with CURLOPT_MAIL_RCPT(3), to specify an EXPN request. If the +CURLOPT_NOBODY(3) option is specified then the request can be used to +issue **NOOP** and **RSET** commands. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP, FTP, IMAP, POP3 and SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* DELETE the given path */ + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +IMAP is supported since 7.30.0, POP3 since 7.26.0 and SMTP since 7.34.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_DEBUGDATA.md b/docs/libcurl/opts/CURLOPT_DEBUGDATA.md new file mode 100644 index 0000000..cac58d9 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DEBUGDATA.md @@ -0,0 +1,86 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DEBUGDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_DEBUGDATA - pointer passed to the debug callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DEBUGDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* to whatever you want passed in to your +CURLOPT_DEBUGFUNCTION(3) in the last void * argument. This pointer is +not used by libcurl, it is only passed to the callback. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct data { + void *custom; +}; + +static int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *clientp) +{ + struct data *mine = clientp; + printf("our ptr: %p\n", mine->custom); + + /* output debug info */ +} + +int main(void) +{ + CURL *curl; + CURLcode res; + struct data my_tracedata; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); + + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &my_tracedata); + + /* the DEBUGFUNCTION has no effect until we enable VERBOSE */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md b/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md new file mode 100644 index 0000000..1acf963 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md @@ -0,0 +1,216 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DEBUGFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONN_ID (3) + - CURLINFO_XFER_ID (3) + - CURLOPT_DEBUGDATA (3) + - CURLOPT_VERBOSE (3) + - curl_global_trace (3) +--- + +# NAME + +CURLOPT_DEBUGFUNCTION - debug callback + +# SYNOPSIS + +~~~c +#include + +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +int debug_callback(CURL *handle, + curl_infotype type, + char *data, + size_t size, + void *clientp); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DEBUGFUNCTION, + debug_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +CURLOPT_DEBUGFUNCTION(3) replaces the standard debug function used when +CURLOPT_VERBOSE(3) is in effect. This callback receives debug +information, as specified in the *type* argument. This function must +return 0. The *data* pointed to by the char * passed to this function is +not null-terminated, but is exactly of the *size* as told by the +*size* argument. + +The *clientp* argument is the pointer set with CURLOPT_DEBUGDATA(3). + +Available **curl_infotype** values: + +## CURLINFO_TEXT + +The data is informational text. + +## CURLINFO_HEADER_IN + +The data is header (or header-like) data received from the peer. + +## CURLINFO_HEADER_OUT + +The data is header (or header-like) data sent to the peer. + +## CURLINFO_DATA_IN + +The data is the unprocessed protocol data received from the peer. Even if the +data is encoded or compressed, it is not not provided decoded nor decompressed +to this callback. If you need the data in decoded and decompressed form, use +CURLOPT_WRITEFUNCTION(3). + +## CURLINFO_DATA_OUT + +The data is protocol data sent to the peer. + +## CURLINFO_SSL_DATA_OUT + +The data is SSL/TLS (binary) data sent to the peer. + +## CURLINFO_SSL_DATA_IN + +The data is SSL/TLS (binary) data received from the peer. + +WARNING: This callback may be called with the curl *handle* set to an +internal handle. (Added in 8.4.0) + +If you need to distinguish your curl *handle* from internal handles then +set CURLOPT_PRIVATE(3) on your handle. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +static +void dump(const char *text, + FILE *stream, unsigned char *ptr, size_t size) +{ + size_t i; + size_t c; + unsigned int width = 0x10; + + fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", + text, (long)size, (long)size); + + for(i = 0; i < size; i += width) { + fprintf(stream, "%4.4lx: ", (long)i); + + /* show hex to the left */ + for(c = 0; c < width; c++) { + if(i + c < size) + fprintf(stream, "%02x ", ptr[i + c]); + else + fputs(" ", stream); + } + + /* show data on the right */ + for(c = 0; (c < width) && (i + c < size); c++) { + char x = (ptr[i + c] >= 0x20 && ptr[i + c] < 0x80) ? ptr[i + c] : '.'; + fputc(x, stream); + } + + fputc('\n', stream); /* newline */ + } +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *clientp) +{ + const char *text; + (void)handle; /* prevent compiler warning */ + (void)clientp; + + switch(type) { + case CURLINFO_TEXT: + fputs("== Info: ", stderr); + fwrite(data, size, 1, stderr); + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + } + + dump(text, stderr, (unsigned char *)data, size); + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); + + /* the DEBUGFUNCTION has no effect until we enable VERBOSE */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return 0; +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md b/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md new file mode 100644 index 0000000..88468f7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md @@ -0,0 +1,89 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DEFAULT_PROTOCOL +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PROTOCOL (3) + - CURLINFO_SCHEME (3) + - CURLOPT_URL (3) +--- + +# NAME + +CURLOPT_DEFAULT_PROTOCOL - default protocol to use if the URL is missing a +scheme name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DEFAULT_PROTOCOL, + char *protocol); +~~~ + +# DESCRIPTION + +This option tells libcurl to use *protocol* if the URL is missing a scheme +name. + +Use one of these protocol (scheme) names: + +dict, file, ftp, ftps, gopher, http, https, imap, imaps, ldap, ldaps, pop3, +pop3s, rtsp, scp, sftp, smb, smbs, smtp, smtps, telnet, tftp + +An unknown or unsupported protocol causes error +*CURLE_UNSUPPORTED_PROTOCOL* when libcurl parses a URL without a +scheme. Parsing happens when curl_easy_perform(3) or +curl_multi_perform(3) is called. The protocol set supported by libcurl +vary depending on how it was built. Use curl_version_info(3) if you need +a list of protocol names supported by the build of libcurl that you are using. + +This option does not change the default proxy protocol (http). + +Without this option libcurl would make a guess based on the host, see +CURLOPT_URL(3) for details. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL (make a guess based on the host) + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* set a URL without a scheme */ + curl_easy_setopt(curl, CURLOPT_URL, "example.com"); + + /* set the default protocol (scheme) for schemeless URLs */ + curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.45.0 + +# RETURN VALUE + +CURLE_OK if the option is supported. + +CURLE_OUT_OF_MEMORY if there was insufficient heap space. + +CURLE_UNKNOWN_OPTION if the option is not supported. diff --git a/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md b/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md new file mode 100644 index 0000000..2963562 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DIRLISTONLY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CUSTOMREQUEST (3) + - CURLOPT_WILDCARDMATCH (3) +--- + +# NAME + +CURLOPT_DIRLISTONLY - ask for names only in a directory listing + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DIRLISTONLY, long listonly); +~~~ + +# DESCRIPTION + +For FTP and SFTP based URLs a parameter set to 1 tells the library to list the +names of files in a directory, rather than performing a full directory listing +that would normally include file sizes, dates etc. + +For POP3 a parameter of 1 tells the library to list the email message or +messages on the POP3 server. This can be used to change the default behavior +of libcurl, when combined with a URL that contains a message ID, to perform a +"scan listing" which can then be used to determine the size of an email. + +Note: For FTP this causes a NLST command to be sent to the FTP server. Beware +that some FTP servers list only files in their response to NLST; they might +not include subdirectories and symbolic links. + +Setting this option to 1 also implies a directory listing even if the URL +does not end with a slash, which otherwise is necessary. + +Do not use this option if you also use CURLOPT_WILDCARDMATCH(3) as it +effectively breaks that feature. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +FTP, SFTP and POP3 + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/"); + + /* list only */ + curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option was known as CURLOPT_FTPLISTONLY up to 7.16.4. POP3 is supported +since 7.21.5. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md b/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md new file mode 100644 index 0000000..ddaaace --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DISALLOW_USERNAME_IN_URL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROTOCOLS (3) + - CURLOPT_URL (3) + - curl_url_set (3) + - libcurl-security (3) +--- + +# NAME + +CURLOPT_DISALLOW_USERNAME_IN_URL - disallow specifying username in the URL + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DISALLOW_USERNAME_IN_URL, + long disallow); +~~~ + +# DESCRIPTION + +A long parameter set to 1 tells the library to not allow URLs that include a +username. + +This is the equivalent to the *CURLU_DISALLOW_USER* flag for the +curl_url_set(3) function. + +# DEFAULT + +0 (disabled) - user names are allowed by default. + +# PROTOCOLS + +Several + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. + +curl_easy_perform(3) returns CURLE_LOGIN_DENIED if this option is +enabled and a URL containing a username is specified. diff --git a/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md new file mode 100644 index 0000000..0199f52 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md @@ -0,0 +1,90 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DNS_CACHE_TIMEOUT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT_MS (3) + - CURLOPT_DNS_SERVERS (3) + - CURLOPT_DNS_USE_GLOBAL_CACHE (3) + - CURLOPT_MAXAGE_CONN (3) + - CURLOPT_RESOLVE (3) +--- + +# NAME + +CURLOPT_DNS_CACHE_TIMEOUT - life-time for DNS cache entries + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_CACHE_TIMEOUT, long age); +~~~ + +# DESCRIPTION + +Pass a long, this sets the timeout in seconds. Name resolve results are kept +in memory and used for this number of seconds. Set to zero to completely +disable caching, or set to -1 to make the cached entries remain forever. By +default, libcurl caches this info for 60 seconds. + +We recommend users not to tamper with this option unless strictly necessary. +If you do, be careful of using large values that can make the cache size grow +significantly if many different host names are used within that timeout +period. + +The name resolve functions of various libc implementations do not re-read name +server information unless explicitly told so (for example, by calling +*res_init(3)*). This may cause libcurl to keep using the older server even +if DHCP has updated the server info, and this may look like a DNS cache issue +to the casual libcurl-app user. + +DNS entries have a "TTL" property but libcurl does not use that. This DNS +cache timeout is entirely speculative that a name resolves to the same address +for a small amount of time into the future. + +Since version 8.1.0, libcurl prunes entries from the DNS cache if it exceeds +30,000 entries no matter which timeout value is used. + +# DEFAULT + +60 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* only reuse addresses for a short time */ + curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 2L); + + res = curl_easy_perform(curl); + + /* in this second request, the cache is not be used if more than + two seconds have passed since the previous name resolve */ + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md b/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md new file mode 100644 index 0000000..070bdc5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DNS_INTERFACE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_LOCAL_IP4 (3) + - CURLOPT_DNS_LOCAL_IP6 (3) + - CURLOPT_DNS_SERVERS (3) + - CURLOPT_INTERFACE (3) +--- + +# NAME + +CURLOPT_DNS_INTERFACE - interface to speak DNS over + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_INTERFACE, char *ifname); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter. Set the name of the network interface that +the DNS resolver should bind to. This must be an interface name (not an +address). Set this option to NULL to use the default setting (do not bind to a +specific interface). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All protocols except file:// - protocols that resolve host names. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_DNS_INTERFACE, "eth0"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.33.0. This option also requires that libcurl was built with a +resolver backend that supports this operation. The c-ares backend is the only +such one. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, +or CURLE_NOT_BUILT_IN if support was disabled at compile-time. diff --git a/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md new file mode 100644 index 0000000..69af83b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DNS_LOCAL_IP4 +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_INTERFACE (3) + - CURLOPT_DNS_LOCAL_IP6 (3) + - CURLOPT_DNS_SERVERS (3) +--- + +# NAME + +CURLOPT_DNS_LOCAL_IP4 - IPv4 address to bind DNS resolves to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_LOCAL_IP4, char *address); +~~~ + +# DESCRIPTION + +Set the local IPv4 *address* that the resolver should bind to. The argument +should be of type char * and contain a single numerical IPv4 address as a +string. Set this option to NULL to use the default setting (do not bind to a +specific IP address). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_DNS_LOCAL_IP4, "192.168.0.14"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option requires that libcurl was built with a resolver backend that +supports this operation. The c-ares backend is the only such one. + +Added in 7.33.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, +CURLE_NOT_BUILT_IN if support was disabled at compile-time, or +CURLE_BAD_FUNCTION_ARGUMENT when given a bad address. diff --git a/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md new file mode 100644 index 0000000..fb04ee8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DNS_LOCAL_IP6 +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_INTERFACE (3) + - CURLOPT_DNS_LOCAL_IP4 (3) + - CURLOPT_DNS_SERVERS (3) +--- + +# NAME + +CURLOPT_DNS_LOCAL_IP6 - IPv6 address to bind DNS resolves to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_LOCAL_IP6, char *address); +~~~ + +# DESCRIPTION + +Set the local IPv6 *address* that the resolver should bind to. The argument +should be of type char * and contain a single IPv6 address as a string. Set +this option to NULL to use the default setting (do not bind to a specific IP +address). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_DNS_LOCAL_IP6, "fe80::a9ff:fe46:b619"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option requires that libcurl was built with a resolver backend that +supports this operation. The c-ares backend is the only such one. + +Added in 7.33.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, +CURLE_NOT_BUILT_IN if support was disabled at compile-time, or +CURLE_BAD_FUNCTION_ARGUMENT when given a bad address. diff --git a/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md b/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md new file mode 100644 index 0000000..998257c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DNS_SERVERS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_CACHE_TIMEOUT (3) + - CURLOPT_DNS_LOCAL_IP4 (3) + - CURLOPT_DNS_LOCAL_IP6 (3) +--- + +# NAME + +CURLOPT_DNS_SERVERS - DNS servers to use + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_SERVERS, char *servers); +~~~ + +# DESCRIPTION + +Pass a char pointer that is the list of DNS servers to be used instead of the +system default. The format of the dns servers option is: + +host[:port][,host[:port]]... + +For example: + +192.168.1.100,192.168.1.101,3.4.5.6 + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL - use system default + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, + "192.168.1.100:53,192.168.1.101"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option requires that libcurl was built with a resolver backend that +supports this operation. The c-ares backend is the only such one. + +Added in 7.24.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, +CURLE_NOT_BUILT_IN if support was disabled at compile-time, +CURLE_BAD_FUNCTION_ARGUMENT when given an invalid server list, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md b/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md new file mode 100644 index 0000000..f15abc9 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DNS_SHUFFLE_ADDRESSES +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_CACHE_TIMEOUT (3) + - CURLOPT_IPRESOLVE (3) +--- + +# NAME + +CURLOPT_DNS_SHUFFLE_ADDRESSES - shuffle IP addresses for hostname + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_SHUFFLE_ADDRESSES, long onoff); +~~~ + +# DESCRIPTION + +Pass a long set to 1 to enable this option. + +When a name is resolved and more than one IP address is returned, this +function shuffles the order of all returned addresses so that they are used in +a random order. This is similar to the ordering behavior of the legacy +gethostbyname function which is no longer used on most platforms. + +Addresses are not reshuffled if name resolution is completed using the DNS +cache. CURLOPT_DNS_CACHE_TIMEOUT(3) can be used together with this +option to reduce DNS cache timeout or disable caching entirely if frequent +reshuffling is needed. + +Since the addresses returned are randomly reordered, the order is not in +accordance with RFC 3484 or any other deterministic order that may be +generated by the system's name resolution implementation. This may have +performance impacts and may cause IPv4 to be used before IPv6 or vice versa. + +# DEFAULT + +0 (disabled) + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_DNS_SHUFFLE_ADDRESSES, 1L); + + curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.60.0 + +# RETURN VALUE + +CURLE_OK or an error such as CURLE_UNKNOWN_OPTION. diff --git a/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md b/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md new file mode 100644 index 0000000..dfbc229 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DNS_USE_GLOBAL_CACHE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_CACHE_TIMEOUT (3) + - CURLOPT_SHARE (3) +--- + +# NAME + +CURLOPT_DNS_USE_GLOBAL_CACHE - global DNS cache + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_USE_GLOBAL_CACHE, + long enable); +~~~ + +# DESCRIPTION + +Has no function since 7.62.0. Do not use! + +Pass a long. If the *enable* value is 1, it tells curl to use a global DNS +cache that survives between easy handle creations and deletions. This is not +thread-safe and this uses a global variable. + +See CURLOPT_SHARE(3) and curl_share_init(3) for the correct way to +share DNS cache between transfers. + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* switch off the use of a global, thread unsafe, cache */ + curl_easy_setopt(curl, CURLOPT_DNS_USE_GLOBAL_CACHE, 0L); + ret = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} + +~~~ + +# AVAILABILITY + +Deprecated since 7.11.1. Function removed in 7.62.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md new file mode 100644 index 0000000..051e6be --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md @@ -0,0 +1,90 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DOH_SSL_VERIFYHOST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DOH_SSL_VERIFYPEER (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_DOH_SSL_VERIFYHOST - verify the hostname in the DoH SSL certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DOH_SSL_VERIFYHOST, + long verify); +~~~ + +# DESCRIPTION + +Pass a long set to 2L as asking curl to *verify* the DoH (DNS-over-HTTPS) +server's certificate name fields against the hostname. + +This option is the DoH equivalent of CURLOPT_SSL_VERIFYHOST(3) and +only affects requests to the DoH server. + +When CURLOPT_DOH_SSL_VERIFYHOST(3) is 2, the SSL certificate provided by +the DoH server must indicate that the server name is the same as the server +name to which you meant to connect to, or the connection fails. + +Curl considers the DoH server the intended one when the Common Name field or a +Subject Alternate Name field in the certificate matches the hostname in the +DoH URL to which you told Curl to connect. + +When the *verify* value is set to 1L it is treated the same as 2L. However +for consistency with the other *VERIFYHOST* options we suggest use 2 and +not 1. + +When the *verify* value is set to 0L, the connection succeeds regardless of +the names used in the certificate. Use that ability with caution! + +See also CURLOPT_DOH_SSL_VERIFYPEER(3) to verify the digital signature +of the DoH server certificate. + +# DEFAULT + +2 + +# PROTOCOLS + +DoH + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_DOH_URL, + "https://cloudflare-dns.com/dns-query"); + + /* Disable host name verification of the DoH server */ + curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.76.0 + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md new file mode 100644 index 0000000..e2a5a5e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md @@ -0,0 +1,102 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DOH_SSL_VERIFYPEER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_CAPATH (3) + - CURLOPT_DOH_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_DOH_SSL_VERIFYPEER - verify the DoH SSL certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DOH_SSL_VERIFYPEER, + long verify); +~~~ + +# DESCRIPTION + +Pass a long as parameter set to 1L to enable or 0L to disable. + +This option tells curl to verify the authenticity of the DoH (DNS-over-HTTPS) +server's certificate. A value of 1 means curl verifies; 0 (zero) means it +does not. + +This option is the DoH equivalent of CURLOPT_SSL_VERIFYPEER(3) and +only affects requests to the DoH server. + +When negotiating a TLS or SSL connection, the server sends a certificate +indicating its identity. Curl verifies whether the certificate is authentic, +i.e. that you can trust that the server is who the certificate says it is. +This trust is based on a chain of digital signatures, rooted in certification +authority (CA) certificates you supply. curl uses a default bundle of CA +certificates (the path for that is determined at build time) and you can +specify alternate certificates with the CURLOPT_CAINFO(3) option or the +CURLOPT_CAPATH(3) option. + +When CURLOPT_DOH_SSL_VERIFYPEER(3) is enabled, and the verification fails to +prove that the certificate is authentic, the connection fails. When the option +is zero, the peer certificate verification succeeds regardless. + +Authenticating the certificate is not enough to be sure about the server. You +typically also want to ensure that the server is the server you mean to be +talking to. Use CURLOPT_DOH_SSL_VERIFYHOST(3) for that. The check that the +hostname in the certificate is valid for the hostname you are connecting to +is done independently of the CURLOPT_DOH_SSL_VERIFYPEER(3) option. + +WARNING: disabling verification of the certificate allows bad guys to +man-in-the-middle the communication without you knowing it. Disabling +verification makes the communication insecure. Just having encryption on a +transfer is not enough as you cannot be sure that you are communicating with +the correct end-point. + +# DEFAULT + +1 + +# PROTOCOLS + +DoH + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_DOH_URL, + "https://cloudflare-dns.com/dns-query"); + + /* Disable certificate verification of the DoH server */ + curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.76.0 + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md new file mode 100644 index 0000000..1948998 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DOH_SSL_VERIFYSTATUS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DOH_SSL_VERIFYHOST (3) + - CURLOPT_DOH_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYSTATUS (3) +--- + +# NAME + +CURLOPT_DOH_SSL_VERIFYSTATUS - verify the DoH SSL certificate's status + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DOH_SSL_VERIFYSTATUS, + long verify); +~~~ + +# DESCRIPTION + +Pass a long as parameter set to 1 to enable or 0 to disable. + +This option determines whether libcurl verifies the status of the DoH +(DNS-over-HTTPS) server cert using the "Certificate Status Request" TLS +extension (aka. OCSP stapling). + +This option is the DoH equivalent of CURLOPT_SSL_VERIFYSTATUS(3) and +only affects requests to the DoH server. + +If this option is enabled and the server does not support the TLS extension, +the verification fails. + +# DEFAULT + +0 + +# PROTOCOLS + +DoH + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_DOH_URL, + "https://cloudflare-dns.com/dns-query"); + + /* Ask for OCSP stapling when verifying the DoH server */ + curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.76.0. This option is currently only supported by the OpenSSL, and +GnuTLS TLS backends. + +# RETURN VALUE + +Returns CURLE_OK if OCSP stapling is supported by the SSL backend, otherwise +returns CURLE_NOT_BUILT_IN. diff --git a/docs/libcurl/opts/CURLOPT_DOH_URL.md b/docs/libcurl/opts/CURLOPT_DOH_URL.md new file mode 100644 index 0000000..a2e46b4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_DOH_URL.md @@ -0,0 +1,96 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_DOH_URL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_CACHE_TIMEOUT (3) + - CURLOPT_RESOLVE (3) + - CURLOPT_VERBOSE (3) +--- + +# NAME + +CURLOPT_DOH_URL - provide the DNS-over-HTTPS URL + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DOH_URL, char *URL); +~~~ + +# DESCRIPTION + +Pass in a pointer to a *URL* for the DoH server to use for name resolving. The +parameter should be a char pointer to a null-terminated string which must be a +valid and correct HTTPS URL. + +libcurl does not validate the syntax or use this variable until the transfer +is issued. Even if you set a crazy value here, curl_easy_setopt(3) still +returns *CURLE_OK*. + +curl sends POST requests to the given DNS-over-HTTPS URL. + +To find the DoH server itself, which might be specified using a name, libcurl +uses the default name lookup function. You can bootstrap that by providing the +address for the DoH server with CURLOPT_RESOLVE(3). + +Disable DoH use again by setting this option to NULL. + +# INHERIT OPTIONS + +DoH lookups use SSL and some SSL settings from your transfer are inherited, +like CURLOPT_SSL_CTX_FUNCTION(3). + +The hostname and peer certificate verification settings are not inherited but +can be controlled separately via CURLOPT_DOH_SSL_VERIFYHOST(3) and +CURLOPT_DOH_SSL_VERIFYPEER(3). + +A set CURLOPT_OPENSOCKETFUNCTION(3) callback is not inherited. + +# KNOWN BUGS + +Even when DoH is set to be used with this option, there are still some name +resolves that are performed without it, using the default name resolver +mechanism. This includes name resolves done for CURLOPT_INTERFACE(3), +CURLOPT_FTPPORT(3), a proxy type set to **CURLPROXY_SOCKS4** or +**CURLPROXY_SOCKS5** and probably some more. + +# DEFAULT + +NULL - there is no default DoH URL. If this option is not set, libcurl uses +the default name resolver. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_DOH_URL, "https://dns.example.com"); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.62.0 + +# RETURN VALUE + +Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient +heap space. + +Note that curl_easy_setopt(3) does immediately parse the given string so +when given a bad DoH URL, libcurl might not detect the problem until it later +tries to resolve a name with it. diff --git a/docs/libcurl/opts/CURLOPT_EGDSOCKET.md b/docs/libcurl/opts/CURLOPT_EGDSOCKET.md new file mode 100644 index 0000000..a472f5e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_EGDSOCKET.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_EGDSOCKET +Section: 3 +Source: libcurl +See-also: + - CURLOPT_RANDOM_FILE (3) +--- + +# NAME + +CURLOPT_EGDSOCKET - EGD socket path + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_EGDSOCKET, char *path); +~~~ + +# DESCRIPTION + +Deprecated option. It serves no purpose anymore. + +Pass a char pointer to the null-terminated path name to the Entropy Gathering +Daemon socket. It is used to seed the random engine for TLS. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_EGDSOCKET, "/var/egd.socket"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If built with TLS enabled. Only the OpenSSL backend uses this, and only with +OpenSSL versions before 1.1.0. + +This option was deprecated in 7.84.0. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md b/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md new file mode 100644 index 0000000..ed5d361 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md @@ -0,0 +1,101 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ERRORBUFFER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_VERBOSE (3) + - curl_easy_strerror (3) + - curl_multi_strerror (3) + - curl_share_strerror (3) + - curl_url_strerror (3) +--- + +# NAME + +CURLOPT_ERRORBUFFER - error buffer for error messages + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ERRORBUFFER, char *buf); +~~~ + +# DESCRIPTION + +Pass a char pointer to a buffer that libcurl may use to store human readable +error messages on failures or problems. This may be more helpful than just the +return code from curl_easy_perform(3) and related functions. The buffer must +be at least **CURL_ERROR_SIZE** bytes big. + +You must keep the associated buffer available until libcurl no longer needs +it. Failing to do so might cause odd behavior or even crashes. libcurl might +need it until you call curl_easy_cleanup(3) or you set the same option +again to use a different pointer. + +Do not rely on the contents of the buffer unless an error code was returned. +Since 7.60.0 libcurl initializes the contents of the error buffer to an empty +string before performing the transfer. For earlier versions if an error code +was returned but there was no error detail then the buffer was untouched. + +Consider CURLOPT_VERBOSE(3) and CURLOPT_DEBUGFUNCTION(3) to better +debug and trace why errors happen. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +#include /* for strlen() */ +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + char errbuf[CURL_ERROR_SIZE]; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* provide a buffer to store errors in */ + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); + + /* set the error buffer as empty before performing a request */ + errbuf[0] = 0; + + /* perform the request */ + res = curl_easy_perform(curl); + + /* if the request did not complete correctly, show the error + information. if no detailed error information was written to errbuf + show the more generic information from curl_easy_strerror instead. + */ + if(res != CURLE_OK) { + size_t len = strlen(errbuf); + fprintf(stderr, "\nlibcurl: (%d) ", res); + if(len) + fprintf(stderr, "%s%s", errbuf, + ((errbuf[len - 1] != '\n') ? "\n" : "")); + else + fprintf(stderr, "%s\n", curl_easy_strerror(res)); + } + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md new file mode 100644 index 0000000..9458cfc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_EXPECT_100_TIMEOUT_MS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPPOST (3) + - CURLOPT_POST (3) +--- + +# NAME + +CURLOPT_EXPECT_100_TIMEOUT_MS - timeout for Expect: 100-continue response + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_EXPECT_100_TIMEOUT_MS, + long milliseconds); +~~~ + +# DESCRIPTION + +Pass a long to tell libcurl the number of *milliseconds* to wait for a +server response with the HTTP status 100 (Continue), 417 (Expectation Failed) +or similar after sending an HTTP request containing an Expect: 100-continue +header. If this times out before a response is received, the request body is +sent anyway. + +# DEFAULT + +1000 milliseconds + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* wait 3 seconds for 100-continue */ + curl_easy_setopt(curl, CURLOPT_EXPECT_100_TIMEOUT_MS, 3000L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.36.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FAILONERROR.md b/docs/libcurl/opts/CURLOPT_FAILONERROR.md new file mode 100644 index 0000000..7ea5ced --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FAILONERROR.md @@ -0,0 +1,74 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FAILONERROR +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RESPONSE_CODE (3) + - CURLOPT_HTTP200ALIASES (3) + - CURLOPT_KEEP_SENDING_ON_ERROR (3) +--- + +# NAME + +CURLOPT_FAILONERROR - request failure on HTTP response >= 400 + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FAILONERROR, long fail); +~~~ + +# DESCRIPTION + +A long parameter set to 1 tells the library to fail the request if the HTTP +code returned is equal to or larger than 400. The default action would be to +return the page normally, ignoring that code. + +This method is not fail-safe and there are occasions where non-successful +response codes slip through, especially when authentication is involved +(response codes 401 and 407). + +You might get some amounts of headers transferred before this situation is +detected, like when a "100-continue" is received as a response to a POST/PUT +and a 401 or 407 is received immediately afterwards. + +When this option is used and an error is detected, it causes the connection to +get closed and *CURLE_HTTP_RETURNED_ERROR* is returned. + +# DEFAULT + +0, do not fail on error + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + ret = curl_easy_perform(curl); + if(ret == CURLE_HTTP_RETURNED_ERROR) { + /* an HTTP response error problem */ + } + } +} +~~~ + +# AVAILABILITY + +Along with HTTP. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FILETIME.md b/docs/libcurl/opts/CURLOPT_FILETIME.md new file mode 100644 index 0000000..0134491 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FILETIME.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FILETIME +Section: 3 +Source: libcurl +See-also: + - CURLINFO_FILETIME (3) + - curl_easy_getinfo (3) +--- + +# NAME + +CURLOPT_FILETIME - get the modification time of the remote resource + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FILETIME, long gettime); +~~~ + +# DESCRIPTION + +Pass a long. If it is 1, libcurl attempts to get the modification time of the +remote document in this operation. This requires that the remote server sends +the time or replies to a time querying command. The curl_easy_getinfo(3) +function with the CURLINFO_FILETIME(3) argument can be used after a +transfer to extract the received time (if any). + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP(S), FTP(S), SFTP, FILE, SMB(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/path.html"); + /* Ask for filetime */ + curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); + res = curl_easy_perform(curl); + if(CURLE_OK == res) { + long filetime; + res = curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); + if((CURLE_OK == res) && (filetime >= 0)) { + time_t file_time = (time_t)filetime; + printf("filetime: %s", ctime(&file_time)); + } + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always, for SFTP since 7.49.0 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md b/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md new file mode 100644 index 0000000..48b6072 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FNMATCH_DATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FNMATCH_FUNCTION (3) + - CURLOPT_WILDCARDMATCH (3) +--- + +# NAME + +CURLOPT_FNMATCH_DATA - pointer passed to the fnmatch callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FNMATCH_DATA, + void *pointer); +~~~ + +# DESCRIPTION + +Pass a pointer that is untouched by libcurl and passed as the ptr argument to +the CURLOPT_FNMATCH_FUNCTION(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +extern int string_match(const char *s1, const char *s2); + +struct local_stuff { + void *custom; +}; + +static int my_fnmatch(void *clientp, + const char *pattern, const char *string) +{ + struct local_stuff *my = clientp; + printf("my ptr: %p\n", my->custom); + + if(string_match(pattern, string)) + return CURL_FNMATCHFUNC_MATCH; + else + return CURL_FNMATCHFUNC_NOMATCH; +} + +int main(void) +{ + struct local_stuff local_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "ftp://ftp.example.com/file*"); + curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L); + curl_easy_setopt(curl, CURLOPT_FNMATCH_FUNCTION, my_fnmatch); + curl_easy_setopt(curl, CURLOPT_FNMATCH_DATA, &local_data); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md b/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md new file mode 100644 index 0000000..8ed13bf --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md @@ -0,0 +1,88 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FNMATCH_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_FNMATCH_DATA (3) + - CURLOPT_WILDCARDMATCH (3) +--- + +# NAME + +CURLOPT_FNMATCH_FUNCTION - wildcard match callback + +# SYNOPSIS + +~~~c +#include + +int fnmatch_callback(void *ptr, + const char *pattern, + const char *string); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FNMATCH_FUNCTION, + fnmatch_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback is used for wildcard matching. + +Return *CURL_FNMATCHFUNC_MATCH* if pattern matches the string, +*CURL_FNMATCHFUNC_NOMATCH* if not or *CURL_FNMATCHFUNC_FAIL* if an +error occurred. + +# DEFAULT + +NULL == an internal function for wildcard matching. + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +extern int string_match(const char *s1, const char *s2); + +struct local_stuff { + void *custom; +}; +static int my_fnmatch(void *clientp, + const char *pattern, const char *string) +{ + struct local_stuff *data = clientp; + printf("my pointer: %p\n", data->custom); + if(string_match(pattern, string)) + return CURL_FNMATCHFUNC_MATCH; + else + return CURL_FNMATCHFUNC_NOMATCH; +} + +int main(void) +{ + struct local_stuff local_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "ftp://ftp.example.com/file*"); + curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L); + curl_easy_setopt(curl, CURLOPT_FNMATCH_FUNCTION, my_fnmatch); + curl_easy_setopt(curl, CURLOPT_FNMATCH_DATA, &local_data); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md b/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md new file mode 100644 index 0000000..9309dff --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md @@ -0,0 +1,93 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FOLLOWLOCATION +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_COUNT (3) + - CURLINFO_REDIRECT_URL (3) + - CURLOPT_POSTREDIR (3) + - CURLOPT_PROTOCOLS (3) + - CURLOPT_REDIR_PROTOCOLS (3) +--- + +# NAME + +CURLOPT_FOLLOWLOCATION - follow HTTP 3xx redirects + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FOLLOWLOCATION, long enable); +~~~ + +# DESCRIPTION + +A long parameter set to 1 tells the library to follow any Location: header +redirects that an HTTP server sends in a 30x response. The Location: header +can specify a relative or an absolute URL to follow. + +libcurl issues another request for the new URL and follows subsequent new +Location: redirects all the way until no more such headers are returned or the +maximum limit is reached. CURLOPT_MAXREDIRS(3) is used to limit the +number of redirects libcurl follows. + +libcurl restricts what protocols it automatically follow redirects to. The +accepted target protocols are set with CURLOPT_REDIR_PROTOCOLS(3). By +default libcurl allows HTTP, HTTPS, FTP and FTPS on redirects. + +When following a redirect, the specific 30x response code also dictates which +request method libcurl uses in the subsequent request: For 301, 302 and 303 +responses libcurl switches method from POST to GET unless +CURLOPT_POSTREDIR(3) instructs libcurl otherwise. All other redirect +response codes make libcurl use the same method again. + +For users who think the existing location following is too naive, too simple +or just lacks features, it is easy to instead implement your own redirect +follow logic with the use of curl_easy_getinfo(3)'s +CURLINFO_REDIRECT_URL(3) option instead of using +CURLOPT_FOLLOWLOCATION(3). + +# NOTE + +Since libcurl changes method or not based on the specific HTTP response code, +setting CURLOPT_CUSTOMREQUEST(3) while following redirects may change +what libcurl would otherwise do and if not that carefully may even make it +misbehave since CURLOPT_CUSTOMREQUEST(3) overrides the method libcurl +would otherwise select internally. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md b/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md new file mode 100644 index 0000000..0e8a206 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FORBID_REUSE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FRESH_CONNECT (3) + - CURLOPT_MAXCONNECTS (3) + - CURLOPT_MAXLIFETIME_CONN (3) +--- + +# NAME + +CURLOPT_FORBID_REUSE - make connection get closed at once after use + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FORBID_REUSE, long close); +~~~ + +# DESCRIPTION + +Pass a long. Set *close* to 1 to make libcurl explicitly close the +connection when done with the transfer. Normally, libcurl keeps all +connections alive when done with one transfer in case a succeeding one follows +that can reuse them. This option should be used with caution and only if you +understand what it does as it can seriously impact performance. + +Set to 0 to have libcurl keep the connection open for possible later reuse +(default behavior). + +# DEFAULT + +0 + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L); + curl_easy_perform(curl); + + /* this second transfer may not reuse the same connection */ + curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md b/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md new file mode 100644 index 0000000..ccb8527 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FRESH_CONNECT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FORBID_REUSE (3) + - CURLOPT_MAXAGE_CONN (3) + - CURLOPT_MAXLIFETIME_CONN (3) +--- + +# NAME + +CURLOPT_FRESH_CONNECT - force a new connection to be used + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FRESH_CONNECT, long fresh); +~~~ + +# DESCRIPTION + +Pass a long. Set to 1 to make the next transfer use a new (fresh) connection +by force instead of trying to reuse an existing one. This option should be +used with caution and only if you understand what it does as it may impact +performance negatively. + +Related functionality is CURLOPT_FORBID_REUSE(3) which makes sure the +connection is closed after use so that it cannot be reused. + +Set *fresh* to 0 to have libcurl attempt reusing an existing connection +(default behavior). + +# DEFAULT + +0 + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L); + /* this transfer must use a new connection, not reuse an existing */ + curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_FTPPORT.md b/docs/libcurl/opts/CURLOPT_FTPPORT.md new file mode 100644 index 0000000..8e8710b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTPPORT.md @@ -0,0 +1,99 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTPPORT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTP_USE_EPRT (3) + - CURLOPT_FTP_USE_EPSV (3) +--- + +# NAME + +CURLOPT_FTPPORT - make FTP transfer active + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTPPORT, char *spec); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. It specifies that the +FTP transfer should be made actively and the given string is used to get the +IP address to use for the FTP PORT instruction. + +The PORT instruction tells the remote server to do a TCP connect to our +specified IP address. The string may be a plain IP address, a hostname, a +network interface name (under Unix) or just a '-' symbol to let the library +use your system's default IP address. Default FTP operations are passive, and +does not use the PORT command. + +The address can be followed by a ':' to specify a port, optionally followed by +a '-' to specify a port range. If the port specified is 0, the operating +system picks a free port. If a range is provided and all ports in the range +are not available, libcurl reports CURLE_FTP_PORT_FAILED for the +handle. Invalid port/range settings are ignored. IPv6 addresses followed by a +port or port range have to be in brackets. IPv6 addresses without port/range +specifier can be in brackets. + +Examples with specified ports: + +~~~c + eth0:0 + 192.168.1.2:32000-33000 + curl.se:32123 + [::1]:1234-4567 +~~~ + +We strongly advise against specifying the address with a name, as it causes +libcurl to do a blocking name resolve call to retrieve the IP address. That +name resolve operation does **not** use DNS-over-HTTPS even if +CURLOPT_DOH_URL(3) is set. + +Using anything else than "-" for this option should typically only be done if +you have special knowledge and confirmation that it works. + +You disable PORT again and go back to using the passive version by setting +this option to NULL. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/old-server/file.txt"); + curl_easy_setopt(curl, CURLOPT_FTPPORT, "-"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Port range support was added in 7.19.5 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md b/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md new file mode 100644 index 0000000..a6ddf2f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTPSSLAUTH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTP_SSL_CCC (3) + - CURLOPT_USE_SSL (3) +--- + +# NAME + +CURLOPT_FTPSSLAUTH - order in which to attempt TLS vs SSL + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTPSSLAUTH, long order); +~~~ + +# DESCRIPTION + +Pass a long using one of the values from below, to alter how libcurl issues +"AUTH TLS" or "AUTH SSL" when FTP over SSL is activated. This is only +interesting if CURLOPT_USE_SSL(3) is also set. + +Possible *order* values: + +## CURLFTPAUTH_DEFAULT + +Allow libcurl to decide. + +## CURLFTPAUTH_SSL + +Try "AUTH SSL" first, and only if that fails try "AUTH TLS". + +## CURLFTPAUTH_TLS + +Try "AUTH TLS" first, and only if that fails try "AUTH SSL". + +# DEFAULT + +CURLFTPAUTH_DEFAULT + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt"); + curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); + /* funny server, ask for SSL before TLS */ + curl_easy_setopt(curl, CURLOPT_FTPSSLAUTH, (long)CURLFTPAUTH_SSL); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.12.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md b/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md new file mode 100644 index 0000000..f894195 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_ACCOUNT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PASSWORD (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_FTP_ACCOUNT - account info for FTP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_ACCOUNT, char *account); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string (or NULL to disable). When an FTP +server asks for "account data" after user name and password has been provided, +this data is sent off using the ACCT command. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin"); + + curl_easy_setopt(curl, CURLOPT_FTP_ACCOUNT, "human-resources"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.13.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md b/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md new file mode 100644 index 0000000..70f451d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_ALTERNATIVE_TO_USER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTP_ACCOUNT (3) + - CURLOPT_FTP_SKIP_PASV_IP (3) + - CURLOPT_SERVER_RESPONSE_TIMEOUT (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_FTP_ALTERNATIVE_TO_USER - command to use instead of USER with FTP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_ALTERNATIVE_TO_USER, + char *cmd); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, pointing to a string which is used to +authenticate if the usual FTP "USER user" and "PASS password" negotiation +fails. This is currently only known to be required when connecting to +Tumbleweed's Secure Transport FTPS server using client certificates for +authentication. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, "two users"); + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.5 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md b/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md new file mode 100644 index 0000000..07b6f68 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md @@ -0,0 +1,88 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_CREATE_MISSING_DIRS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTP_FILEMETHOD (3) + - CURLOPT_FTP_USE_EPSV (3) +--- + +# NAME + +CURLOPT_FTP_CREATE_MISSING_DIRS - create missing directories for FTP and SFTP + +# SYNOPSIS + +~~~c +#include + +typedef enum { + CURLFTP_CREATE_DIR_NONE, + CURLFTP_CREATE_DIR, + CURLFTP_CREATE_DIR_RETRY +} curl_ftpcreatedir; + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_CREATE_MISSING_DIRS, + long create); +~~~ + +# DESCRIPTION + +Pass a long telling libcurl to *create* the dir. If the value is +*CURLFTP_CREATE_DIR* (1), libcurl may create any remote directory that it +fails to "move" into. + +For FTP requests, that means a CWD command fails. CWD being the command that +changes working directory. + +For SFTP requests, libcurl may create the remote directory if it cannot obtain +a handle to the target-location. The creation fails if a file of the same name +as the directory to create already exists or lack of permissions prevents +creation. + +Setting *create* to *CURLFTP_CREATE_DIR_RETRY* (2), tells libcurl to +retry the CWD command again if the subsequent **MKD** command fails. This is +especially useful if you are doing many simultaneous connections against the +same server and they all have this option enabled, as then CWD may first fail +but then another connection does **MKD** before this connection and thus +**MKD** fails but trying CWD works! + +# DEFAULT + +CURLFTP_CREATE_DIR_NONE (0) + +# PROTOCOLS + +FTP and SFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/non-existing/new.txt"); + curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, + (long)CURLFTP_CREATE_DIR_RETRY); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.7. SFTP support added in 7.16.3. The retry option was added in +7.19.4. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if the +create value is not. diff --git a/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md b/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md new file mode 100644 index 0000000..34b55d6 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md @@ -0,0 +1,86 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_FILEMETHOD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DIRLISTONLY (3) + - CURLOPT_FTP_SKIP_PASV_IP (3) +--- + +# NAME + +CURLOPT_FTP_FILEMETHOD - select directory traversing method for FTP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_FILEMETHOD, + long method); +~~~ + +# DESCRIPTION + +Pass a long telling libcurl which *method* to use to reach a file on a +FTP(S) server. + +This option exists because some server implementations are not compliant to +what the standards say should work. + +The argument should be one of the following alternatives: + +## CURLFTPMETHOD_MULTICWD + +libcurl does a single CWD operation for each path part in the given URL. For +deep hierarchies this means many commands. This is how RFC 1738 says it should +be done. This is the default but the slowest behavior. + +## CURLFTPMETHOD_NOCWD + +libcurl makes no CWD at all. libcurl does SIZE, RETR, STOR etc and gives a +full path to the server for all these commands. This is the fastest behavior +since it skips having to change directories. + +## CURLFTPMETHOD_SINGLECWD + +libcurl does one CWD with the full target directory and then operates on the +file &"normally" (like in the multicwd case). This is somewhat more standards +compliant than 'nocwd' but without the full penalty of 'multicwd'. + +# DEFAULT + +CURLFTPMETHOD_MULTICWD + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/1/2/3/4/new.txt"); + curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, + (long)CURLFTPMETHOD_SINGLECWD); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md new file mode 100644 index 0000000..bea622a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_SKIP_PASV_IP +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTPPORT (3) + - CURLOPT_FTP_USE_EPRT (3) +--- + +# NAME + +CURLOPT_FTP_SKIP_PASV_IP - ignore the IP address in the PASV response + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_SKIP_PASV_IP, long skip); +~~~ + +# DESCRIPTION + +Pass a long. If *skip* is set to 1, it instructs libcurl to not use the IP +address the server suggests in its 227-response to libcurl's PASV command when +libcurl connects the data connection. Instead libcurl reuses the same IP +address it already uses for the control connection. It still uses the port +number from the 227-response. + +This option allows libcurl to work around broken server installations or funny +network setups that due to NATs, firewalls or incompetence report the wrong IP +address. Setting this option also reduces the risk for various sorts of client +abuse by malicious servers. + +This option has no effect if PORT, EPRT or EPSV is used instead of PASV. + +# DEFAULT + +1 since 7.74.0, was 0 before then. + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt"); + + /* please ignore the IP in the PASV response */ + curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, 1L); + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.14.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md b/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md new file mode 100644 index 0000000..71947c3 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_SSL_CCC +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTPSSLAUTH (3) + - CURLOPT_PROTOCOLS_STR (3) + - CURLOPT_USE_SSL (3) +--- + +# NAME + +CURLOPT_FTP_SSL_CCC - switch off SSL again with FTP after auth + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_SSL_CCC, + long how); +~~~ + +# DESCRIPTION + +If enabled, this option makes libcurl use CCC (Clear Command Channel). It +shuts down the SSL/TLS layer after authenticating. The rest of the control +channel communication remains unencrypted. This allows NAT routers to follow +the FTP transaction. Pass a long using one of the values below + +## CURLFTPSSL_CCC_NONE + +do not attempt to use CCC. + +## CURLFTPSSL_CCC_PASSIVE + +Do not initiate the shutdown, but wait for the server to do it. Do not send a +reply. + +## CURLFTPSSL_CCC_ACTIVE + +Initiate the shutdown and wait for a reply. + +# DEFAULT + +CURLFTPSSL_CCC_NONE + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt"); + curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL); + /* go back to clear-text FTP after authenticating */ + curl_easy_setopt(curl, CURLOPT_FTP_SSL_CCC, (long)CURLFTPSSL_CCC_ACTIVE); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md b/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md new file mode 100644 index 0000000..644f51a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_USE_EPRT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTPPORT (3) + - CURLOPT_FTP_USE_EPSV (3) +--- + +# NAME + +CURLOPT_FTP_USE_EPRT - use EPRT for FTP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_USE_EPRT, long enabled); +~~~ + +# DESCRIPTION + +Pass a long. If the value is 1, it tells curl to use the EPRT command when +doing active FTP downloads (which is enabled by +CURLOPT_FTPPORT(3)). Using EPRT means that libcurl first attempts to use +EPRT before using PORT, but if you pass zero to this option, it avoids using +EPRT, only plain PORT. + +The EPRT command is a slightly newer addition to the FTP protocol than PORT +and is the preferred command to use since it enables IPv6 to be used. Old FTP +servers might not support it, which is why libcurl has a fallback mechanism. +Sometimes that fallback is not enough and then this option might come handy. + +If the server is an IPv6 host, this option has no effect as EPRT is necessary +then. + +# DEFAULT + +# PROTOCOLS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt"); + + /* contact us back, aka "active" FTP */ + curl_easy_setopt(curl, CURLOPT_FTPPORT, "-"); + + /* FTP the way the neanderthals did it */ + curl_easy_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.5 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md b/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md new file mode 100644 index 0000000..985ca8b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_USE_EPSV +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTPPORT (3) + - CURLOPT_FTP_USE_EPRT (3) +--- + +# NAME + +CURLOPT_FTP_USE_EPSV - use EPSV for FTP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_USE_EPSV, long epsv); +~~~ + +# DESCRIPTION + +Pass *epsv* as a long. If the value is 1, it tells curl to use the EPSV +command when doing passive FTP downloads (which it does by default). Using +EPSV means that libcurl first attempts to use the EPSV command before using +PASV. If you pass zero to this option, it does not use EPSV, only plain PASV. + +The EPSV command is a slightly newer addition to the FTP protocol than PASV +and is the preferred command to use since it enables IPv6 to be used. Old FTP +servers might not support it, which is why libcurl has a fallback mechanism. +Sometimes that fallback is not enough and then this option might come handy. + +If the server is an IPv6 host, this option has no effect. + +# DEFAULT + +1 + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/old-server/file.txt"); + + /* let's shut off this modern feature */ + curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Along with FTP + +# RETURN VALUE + +Returns CURLE_OK if FTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md b/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md new file mode 100644 index 0000000..f81ca4c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_FTP_USE_PRET +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTP_USE_EPRT (3) + - CURLOPT_FTP_USE_EPSV (3) +--- + +# NAME + +CURLOPT_FTP_USE_PRET - use PRET for FTP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FTP_USE_PRET, long enable); +~~~ + +# DESCRIPTION + +Pass a long. If the value is 1, it tells curl to send a PRET command before +PASV (and EPSV). Certain FTP servers, mainly drftpd, require this non-standard +command for directory listings as well as up and downloads in PASV mode. Has +no effect when using the active FTP transfers mode. + +# DEFAULT + +0 + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/old-server/file.txt"); + + /* a drftpd server, do it! */ + curl_easy_setopt(curl, CURLOPT_FTP_USE_PRET, 1L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md b/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md new file mode 100644 index 0000000..01c1d50 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_GSSAPI_DELEGATION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPAUTH (3) + - CURLOPT_PROXYAUTH (3) +--- + +# NAME + +CURLOPT_GSSAPI_DELEGATION - allowed GSS-API delegation + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_GSSAPI_DELEGATION, long level); +~~~ + +# DESCRIPTION + +Set the long parameter *level* to **CURLGSSAPI_DELEGATION_FLAG** to allow +unconditional GSSAPI credential delegation. The delegation is disabled by +default since 7.21.7. Set the parameter to +**CURLGSSAPI_DELEGATION_POLICY_FLAG** to delegate only if the OK-AS-DELEGATE +flag is set in the service ticket in case this feature is supported by the +GSS-API implementation and the definition of *GSS_C_DELEG_POLICY_FLAG* was +available at compile-time. + +# DEFAULT + +CURLGSSAPI_DELEGATION_NONE + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* delegate if okayed by policy */ + curl_easy_setopt(curl, CURLOPT_GSSAPI_DELEGATION, + (long)CURLGSSAPI_DELEGATION_POLICY_FLAG); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.22.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md new file mode 100644 index 0000000..23299c7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT_MS (3) + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS - head start for IPv6 for happy eyeballs + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, + long timeout); +~~~ + +# DESCRIPTION + +Happy eyeballs is an algorithm that attempts to connect to both IPv4 and IPv6 +addresses for dual-stack hosts, preferring IPv6 first for *timeout* +milliseconds. If the IPv6 address cannot be connected to within that time then +a connection attempt is made to the IPv4 address in parallel. The first +connection to be established is the one that is used. + +The range of suggested useful values for *timeout* is limited. Happy +Eyeballs RFC 6555 says "It is RECOMMENDED that connection attempts be paced +150-250 ms apart to balance human factors against network load." libcurl +currently defaults to 200 ms. Firefox and Chrome currently default to 300 ms. + +# DEFAULT + +CURL_HET_DEFAULT (currently defined as 200L) + +# PROTOCOLS + +All except FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, 300L); + + curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.59.0 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md b/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md new file mode 100644 index 0000000..51eb265 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HAPROXYPROTOCOL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) +--- + +# NAME + +CURLOPT_HAPROXYPROTOCOL - send HAProxy PROXY protocol v1 header + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HAPROXYPROTOCOL, + long haproxy_protocol); +~~~ + +# DESCRIPTION + +A long parameter set to 1 tells the library to send an HAProxy PROXY +protocol v1 header at beginning of the connection. The default action is not to +send this header. + +This option is primarily useful when sending test requests to a service that +expects this header. + +Most applications do not need this option. + +# DEFAULT + +0, do not send any HAProxy PROXY protocol header + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP. Added in 7.60.0. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md b/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md new file mode 100644 index 0000000..ac0da3a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md @@ -0,0 +1,63 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HAPROXY_CLIENT_IP +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HAPROXYPROTOCOL (3) + - CURLOPT_PROXY (3) +--- + +# NAME + +CURLOPT_HAPROXY_CLIENT_IP - set HAProxy PROXY protocol client IP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HAPROXY_CLIENT_IP, + char *client_ip); +~~~ + +# DESCRIPTION + +When this parameter is set to a valid IPv4 or IPv6 numerical address, the +library sends this address as client address in the HAProxy PROXY protocol v1 +header at beginning of the connection. + +This option is an alternative to CURLOPT_HAPROXYPROTOCOL(3) as that one +cannot use a specified address. + +# DEFAULT + +NULL, no HAProxy header is sent + +# PROTOCOLS + +HTTP, HAProxy PROTOCOL + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_HAPROXY_CLIENT_IP, "1.1.1.1"); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP. Added in 8.2.0. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HEADER.md b/docs/libcurl/opts/CURLOPT_HEADER.md new file mode 100644 index 0000000..d5e272a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HEADER.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HEADER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERFUNCTION (3) + - CURLOPT_HTTPHEADER (3) +--- + +# NAME + +CURLOPT_HEADER - pass headers to the data stream + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HEADER, long onoff); +~~~ + +# DESCRIPTION + +Pass the long value *onoff* set to 1 to ask libcurl to include the headers +in the write callback (CURLOPT_WRITEFUNCTION(3)). This option is +relevant for protocols that actually have headers or other meta-data (like +HTTP and FTP). + +When asking to get the headers passed to the same callback as the body, it is +not possible to accurately separate them again without detailed knowledge +about the protocol in use. + +Further: the CURLOPT_WRITEFUNCTION(3) callback is limited to only ever +get a maximum of *CURL_MAX_WRITE_SIZE* bytes passed to it (16KB), while a +header can be longer and the CURLOPT_HEADERFUNCTION(3) supports getting +called with headers up to *CURL_MAX_HTTP_HEADER* bytes big (100KB). + +It is often better to use CURLOPT_HEADERFUNCTION(3) to get the header +data separately. + +While named confusingly similar, CURLOPT_HTTPHEADER(3) is used to set +custom HTTP headers! + +# DEFAULT + +0 + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_HEADER, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Provided in all libcurl versions. + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_HEADERDATA.md b/docs/libcurl/opts/CURLOPT_HEADERDATA.md new file mode 100644 index 0000000..7f05636 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HEADERDATA.md @@ -0,0 +1,89 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HEADERDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERFUNCTION (3) + - CURLOPT_WRITEFUNCTION (3) + - curl_easy_header (3) +--- + +# NAME + +CURLOPT_HEADERDATA - pointer to pass to header callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HEADERDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* to be used to write the header part of the received data +to. + +If CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) is used, +*pointer* is passed in to the respective callback. + +If neither of those options are set, *pointer* must be a valid FILE * and +it is used by a plain fwrite() to write headers to. + +If you are using libcurl as a win32 DLL, you **MUST** use a +CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set +this option or you might experience crashes. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct my_info { + int shoesize; + char *secret; +}; + +static size_t header_callback(char *buffer, size_t size, + size_t nitems, void *userdata) +{ + struct my_info *i = userdata; + printf("shoe size: %d\n", i->shoesize); + /* now this callback can access the my_info struct */ + + return nitems * size; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct my_info my = { 10, "the cookies are in the cupboard" }; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); + + /* pass in custom data to the callback */ + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &my); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md new file mode 100644 index 0000000..eb14cdd --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md @@ -0,0 +1,132 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HEADERFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERDATA (3) + - CURLOPT_WRITEFUNCTION (3) + - curl_easy_header (3) +--- + +# NAME + +CURLOPT_HEADERFUNCTION - callback that receives header data + +# SYNOPSIS + +~~~c +#include + +size_t header_callback(char *buffer, + size_t size, + size_t nitems, + void *userdata); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HEADERFUNCTION, + header_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets invoked by libcurl as soon as it has received +header data. The header callback is called once for each header and only +complete header lines are passed on to the callback. Parsing headers is easy +to do using this callback. *buffer* points to the delivered data, and the +size of that data is *nitems*; *size* is always 1. The provide header +line is not null-terminated! + +The pointer named *userdata* is the one you set with the +CURLOPT_HEADERDATA(3) option. + +Your callback should return the number of bytes actually taken care of. If +that amount differs from the amount passed to your callback function, it +signals an error condition to the library. This causes the transfer to get +aborted and the libcurl function used returns *CURLE_WRITE_ERROR*. + +You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0) + +A complete HTTP header that is passed to this function can be up to +*CURL_MAX_HTTP_HEADER* (100K) bytes and includes the final line terminator. + +If this option is not set, or if it is set to NULL, but +CURLOPT_HEADERDATA(3) is set to anything but NULL, the function used to +accept response data is used instead. That is the function specified with +CURLOPT_WRITEFUNCTION(3), or if it is not specified or NULL - the +default, stream-writing function. + +It is important to note that the callback is invoked for the headers of all +responses received after initiating a request and not just the final +response. This includes all responses which occur during authentication +negotiation. If you need to operate on only the headers from the final +response, you need to collect headers in the callback yourself and use HTTP +status lines, for example, to delimit response boundaries. + +For an HTTP transfer, the status line and the blank line preceding the response +body are both included as headers and passed to this function. + +When a server sends a chunked encoded transfer, it may contain a trailer. That +trailer is identical to an HTTP header and if such a trailer is received it is +passed to the application using this callback as well. There are several ways +to detect it being a trailer and not an ordinary header: 1) it comes after the +response-body. 2) it comes after the final header line (CR LF) 3) a Trailer: +header among the regular response-headers mention what header(s) to expect in +the trailer. + +For non-HTTP protocols like FTP, POP3, IMAP and SMTP this function gets called +with the server responses to the commands that libcurl sends. + +A more convenient way to get HTTP headers might be to use +curl_easy_header(3). + +# LIMITATIONS + +libcurl does not unfold HTTP "folded headers" (deprecated since RFC 7230). A +folded header is a header that continues on a subsequent line and starts with +a whitespace. Such folds are passed to the header callback as separate ones, +although strictly they are just continuations of the previous lines. + +# DEFAULT + +Nothing. + +# PROTOCOLS + +Used for all protocols with headers or meta-data concept: HTTP, FTP, POP3, +IMAP, SMTP and more. + +# EXAMPLE + +~~~c +static size_t header_callback(char *buffer, size_t size, + size_t nitems, void *userdata) +{ + /* received header is nitems * size long in 'buffer' NOT ZERO TERMINATED */ + /* 'userdata' is set with CURLOPT_HEADERDATA */ + return nitems * size; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_HEADEROPT.md b/docs/libcurl/opts/CURLOPT_HEADEROPT.md new file mode 100644 index 0000000..bb3bcf4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HEADEROPT.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HEADEROPT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPHEADER (3) + - CURLOPT_PROXYHEADER (3) +--- + +# NAME + +CURLOPT_HEADEROPT - send HTTP headers to both proxy and host or separately + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HEADEROPT, long bitmask); +~~~ + +# DESCRIPTION + +Pass a long that is a bitmask of options of how to deal with headers. The two +mutually exclusive options are: + +**CURLHEADER_UNIFIED** - the headers specified in +CURLOPT_HTTPHEADER(3) are used in requests both to servers and +proxies. With this option enabled, CURLOPT_PROXYHEADER(3) does not have +any effect. + +**CURLHEADER_SEPARATE** - makes CURLOPT_HTTPHEADER(3) headers only get +sent to a server and not to a proxy. Proxy headers must be set with +CURLOPT_PROXYHEADER(3) to get used. Note that if a non-CONNECT request +is sent to a proxy, libcurl sends both server headers and proxy headers. When +doing CONNECT, libcurl sends CURLOPT_PROXYHEADER(3) headers only to the +proxy and then CURLOPT_HTTPHEADER(3) headers only to the server. + +# DEFAULT + +CURLHEADER_SEPARATE (changed in 7.42.1, used CURLHEADER_UNIFIED before then) + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + struct curl_slist *list; + list = curl_slist_append(NULL, "Shoesize: 10"); + list = curl_slist_append(list, "Accept:"); + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); + + /* HTTPS over a proxy makes a separate CONNECT to the proxy, so tell + libcurl to not send the custom headers to the proxy. Keep them + separate! */ + curl_easy_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE); + ret = curl_easy_perform(curl); + curl_slist_free_all(list); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.37.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HSTS.md b/docs/libcurl/opts/CURLOPT_HSTS.md new file mode 100644 index 0000000..83379f2 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HSTS.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HSTS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ALTSVC (3) + - CURLOPT_HSTS_CTRL (3) + - CURLOPT_RESOLVE (3) +--- + +# NAME + +CURLOPT_HSTS - HSTS cache file name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTS, char *filename); +~~~ + +# DESCRIPTION + +Make the *filename* point to a filename to load an existing HSTS cache +from, and to store the cache in when the easy handle is closed. Setting a file +name with this option also enables HSTS for this handle (the equivalent of +setting *CURLHSTS_ENABLE* with CURLOPT_HSTS_CTRL(3)). + +If the given file does not exist or contains no HSTS entries at startup, the +HSTS cache simply starts empty. Setting the filename to NULL or "" only +enables HSTS without reading from or writing to any file. + +If this option is set multiple times, libcurl loads cache entries from each +given file but only stores the last used name for later writing. + +# FILE FORMAT + +The HSTS cache is saved to and loaded from a text file with one entry per +physical line. Each line in the file has the following format: + +[host] [stamp] + +[host] is the domain name for the entry and the name is dot-prefixed if it is +an entry valid for all subdomains to the name as well or only for the exact +name. + +[stamp] is the time (in UTC) when the entry expires and it uses the format +"YYYYMMDD HH:MM:SS". + +Lines starting with "#" are treated as comments and are ignored. There is +currently no length or size limit. + +# DEFAULT + +NULL, no file name + +# PROTOCOLS + +HTTPS and HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_HSTS, "/home/user/.hsts-cache"); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.74.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md b/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md new file mode 100644 index 0000000..8fbb888 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HSTSREADDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HSTS (3) + - CURLOPT_HSTSREADFUNCTION (3) + - CURLOPT_HSTSWRITEDATA (3) + - CURLOPT_HSTSWRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_HSTSREADDATA - pointer passed to the HSTS read callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTSREADDATA, void *pointer); +~~~ + +# DESCRIPTION + +Data *pointer* to pass to the HSTS read function. If you use the +CURLOPT_HSTSREADFUNCTION(3) option, this is the pointer you get as input +in the 3rd argument to the callback. + +This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to +do that. + +# DEFAULT + +NULL + +# PROTOCOLS + +This feature is only used for HTTP(S) transfer. + +# EXAMPLE + +~~~c +struct MyData { + void *custom; +}; + +int main(void) +{ + CURL *curl = curl_easy_init(); + struct MyData this; + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); + + /* pass pointer that gets passed in to the + CURLOPT_HSTSREADFUNCTION callback */ + curl_easy_setopt(curl, CURLOPT_HSTSREADDATA, &this); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.74.0 + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md b/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md new file mode 100644 index 0000000..cc22163 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md @@ -0,0 +1,106 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HSTSREADFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HSTS (3) + - CURLOPT_HSTSREADDATA (3) + - CURLOPT_HSTSWRITEFUNCTION (3) + - CURLOPT_HSTS_CTRL (3) +--- + +# NAME + +CURLOPT_HSTSREADFUNCTION - read callback for HSTS hosts + +# SYNOPSIS + +~~~c +#include + +struct curl_hstsentry { + char *name; + size_t namelen; + unsigned int includeSubDomains:1; + char expire[18]; /* YYYYMMDD HH:MM:SS [null-terminated] */ +}; + +CURLSTScode hstsread(CURL *easy, struct curl_hstsentry *sts, void *clientp); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTSREADFUNCTION, hstsread); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, as the prototype shows above. + +This callback function gets called by libcurl repeatedly when it populates the +in-memory HSTS cache. + +Set the *clientp* argument with the CURLOPT_HSTSREADDATA(3) option +or it is NULL. + +When this callback is invoked, the *sts* pointer points to a populated +struct: Copy the hostname to *name* (no longer than *namelen* +bytes). Make it null-terminated. Set *includeSubDomains* to TRUE or +FALSE. Set *expire* to a date stamp or a zero length string for *forever* +(wrong date stamp format might cause the name to not get accepted) + +The callback should return *CURLSTS_OK* if it returns a name and is +prepared to be called again (for another host) or *CURLSTS_DONE* if it has +no entry to return. It can also return *CURLSTS_FAIL* to signal +error. Returning *CURLSTS_FAIL* stops the transfer from being performed +and make *CURLE_ABORTED_BY_CALLBACK* get returned. + +This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to +do that. + +# DEFAULT + +NULL - no callback. + +# PROTOCOLS + +This feature is only used for HTTP(S) transfer. + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static CURLSTScode hsts_cb(CURL *easy, struct curl_hstsentry *sts, + void *clientp) +{ + /* populate the struct as documented */ + return CURLSTS_OK; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct priv my_stuff; + CURLcode res; + + /* set HSTS read callback */ + curl_easy_setopt(curl, CURLOPT_HSTSREADFUNCTION, hsts_cb); + + /* pass in suitable argument to the callback */ + curl_easy_setopt(curl, CURLOPT_HSTSREADDATA, &my_stuff); + + res = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.74.0 + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md b/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md new file mode 100644 index 0000000..b4486d7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HSTSWRITEDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HSTS (3) + - CURLOPT_HSTSREADDATA (3) + - CURLOPT_HSTSREADFUNCTION (3) + - CURLOPT_HSTSWRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_HSTSWRITEDATA - pointer passed to the HSTS write callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTSWRITEDATA, void *pointer); +~~~ + +# DESCRIPTION + +Data *pointer* to pass to the HSTS write function. If you use the +CURLOPT_HSTSWRITEFUNCTION(3) option, this is the pointer you get as +input in the fourth argument to the callback. + +This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to +do that. + +# DEFAULT + +NULL + +# PROTOCOLS + +This feature is only used for HTTP(S) transfer. + +# EXAMPLE + +~~~c +struct MyData { + void *custom; +}; + +int main(void) +{ + CURL *curl = curl_easy_init(); + struct MyData this; + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); + + /* pass pointer that gets passed in to the + CURLOPT_HSTSWRITEFUNCTION callback */ + curl_easy_setopt(curl, CURLOPT_HSTSWRITEDATA, &this); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.74.0 + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md b/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md new file mode 100644 index 0000000..ede3521 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md @@ -0,0 +1,110 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HSTSWRITEFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HSTS (3) + - CURLOPT_HSTSWRITEDATA (3) + - CURLOPT_HSTSWRITEFUNCTION (3) + - CURLOPT_HSTS_CTRL (3) +--- + +# NAME + +CURLOPT_HSTSWRITEFUNCTION - write callback for HSTS hosts + +# SYNOPSIS + +~~~c +#include + +struct curl_hstsentry { + char *name; + size_t namelen; + unsigned int includeSubDomains:1; + char expire[18]; /* YYYYMMDD HH:MM:SS [null-terminated] */ +}; + +struct curl_index { + size_t index; /* the provided entry's "index" or count */ + size_t total; /* total number of entries to save */ +}; + +CURLSTScode hstswrite(CURL *easy, struct curl_hstsentry *sts, + struct curl_index *count, void *clientp); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTSWRITEFUNCTION, hstswrite); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, as the prototype shows above. + +This callback function gets called by libcurl repeatedly to allow the +application to store the in-memory HSTS cache when libcurl is about to discard +it. + +Set the *clientp* argument with the CURLOPT_HSTSWRITEDATA(3) option +or it is NULL. +When the callback is invoked, the *sts* pointer points to a populated +struct: Read the hostname to 'name' (it is *namelen* bytes long and null +terminated. The *includeSubDomains* field is non-zero if the entry matches +subdomains. The *expire* string is a date stamp null-terminated string +using the syntax YYYYMMDD HH:MM:SS. + +The callback should return *CURLSTS_OK* if it succeeded and is prepared to +be called again (for another host) or *CURLSTS_DONE* if there is nothing +more to do. It can also return *CURLSTS_FAIL* to signal error. + +This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to +do that. + +# DEFAULT + +NULL - no callback. + +# PROTOCOLS + +This feature is only used for HTTP(S) transfer. + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static CURLSTScode hswr_cb(CURL *easy, struct curl_hstsentry *sts, + struct curl_index *count, void *clientp) +{ + /* save the passed in HSTS data somewhere */ + return CURLSTS_OK; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct priv my_stuff; + CURLcode res; + + /* set HSTS read callback */ + curl_easy_setopt(curl, CURLOPT_HSTSWRITEFUNCTION, hswr_cb); + + /* pass in suitable argument to the callback */ + curl_easy_setopt(curl, CURLOPT_HSTSWRITEDATA, &my_stuff); + + res = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.74.0 + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md b/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md new file mode 100644 index 0000000..d60e58f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HSTS_CTRL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ALTSVC (3) + - CURLOPT_CONNECT_TO (3) + - CURLOPT_HSTS (3) + - CURLOPT_RESOLVE (3) +--- + +# NAME + +CURLOPT_HSTS_CTRL - control HSTS behavior + +# SYNOPSIS + +~~~c +#include + +#define CURLHSTS_ENABLE (1<<0) +#define CURLHSTS_READONLYFILE (1<<1) + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTS_CTRL, long bitmask); +~~~ + +# DESCRIPTION + +HSTS (HTTP Strict Transport Security) means that an HTTPS server can instruct +the client to not contact it again over clear-text HTTP for a certain period +into the future. libcurl then automatically redirects HTTP attempts to such +hosts to instead use HTTPS. This is done by libcurl retaining this knowledge +in an in-memory cache. + +Populate the long *bitmask* with the correct set of features to instruct +libcurl how to handle HSTS for the transfers using this handle. + +# BITS + +## CURLHSTS_ENABLE + +Enable the in-memory HSTS cache for this handle. + +## CURLHSTS_READONLYFILE + +Make the HSTS file (if specified) read-only - makes libcurl not save the cache +to the file when closing the handle. + +# DEFAULT + +0. HSTS is disabled by default. + +# PROTOCOLS + +HTTPS and HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_HSTS_CTRL, (long)CURLHSTS_ENABLE); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.74.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md b/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md new file mode 100644 index 0000000..d359492 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTP09_ALLOWED +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTP_VERSION (3) + - CURLOPT_SSLVERSION (3) +--- + +# NAME + +CURLOPT_HTTP09_ALLOWED - allow HTTP/0.9 response + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTP09_ALLOWED, long allowed); +~~~ + +# DESCRIPTION + +Pass the long argument *allowed* set to 1L to allow HTTP/0.9 responses. + +An HTTP/0.9 response is a server response entirely without headers and only a +body. You can connect to lots of random TCP services and still get a response +that curl might consider to be HTTP/0.9! + +# DEFAULT + +curl allowed HTTP/0.9 responses by default before 7.66.0 + +Since 7.66.0, libcurl requires this option set to 1L to allow HTTP/0.9 +responses. + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_HTTP09_ALLOWED, 1L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Option added in 7.64.0, present along with HTTP. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md b/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md new file mode 100644 index 0000000..b48faf6 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTP200ALIASES +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTP09_ALLOWED (3) + - CURLOPT_HTTP_VERSION (3) +--- + +# NAME + +CURLOPT_HTTP200ALIASES - alternative matches for HTTP 200 OK + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTP200ALIASES, + struct curl_slist *aliases); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of *aliases* to be treated as valid HTTP 200 +responses. Some servers respond with a custom header response line. For +example, SHOUTcast servers respond with "ICY 200 OK". Also some old Icecast +1.3.x servers respond like that for certain user agent headers or in absence +of such. By including this string in your list of aliases, the response gets +treated as a valid HTTP header line such as "HTTP/1.0 200 OK". + +The linked list should be a fully valid list of struct curl_slist structs, and +be properly filled in. Use curl_slist_append(3) to create the list and +curl_slist_free_all(3) to clean up an entire list. + +The alias itself is not parsed for any version strings. The protocol is +assumed to match HTTP 1.0 when an alias match. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct curl_slist *list; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + list = curl_slist_append(NULL, "ICY 200 OK"); + list = curl_slist_append(list, "WEIRDO 99 FINE"); + + curl_easy_setopt(curl, CURLOPT_HTTP200ALIASES, list); + curl_easy_perform(curl); + curl_slist_free_all(list); /* free the list again */ + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.3 + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTPAUTH.md b/docs/libcurl/opts/CURLOPT_HTTPAUTH.md new file mode 100644 index 0000000..ca92f5e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTPAUTH.md @@ -0,0 +1,163 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTPAUTH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PASSWORD (3) + - CURLOPT_PROXYAUTH (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_HTTPAUTH - HTTP server authentication methods to try + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPAUTH, long bitmask); +~~~ + +# DESCRIPTION + +Pass a long as parameter, which is set to a bitmask, to tell libcurl which +authentication method(s) you want it to use speaking to the remote server. + +The available bits are listed below. If more than one bit is set, libcurl +first queries the host to see which authentication methods it supports and +then picks the best one you allow it to use. For some methods, this induces an +extra network round-trip. Set the actual name and password with the +CURLOPT_USERPWD(3) option or with the CURLOPT_USERNAME(3) and the +CURLOPT_PASSWORD(3) options. + +For authentication with a proxy, see CURLOPT_PROXYAUTH(3). + +## CURLAUTH_BASIC + +HTTP Basic authentication. This is the default choice, and the only method +that is in wide-spread use and supported virtually everywhere. This sends +the user name and password over the network in plain text, easily captured by +others. + +## CURLAUTH_DIGEST + +HTTP Digest authentication. Digest authentication is defined in RFC 2617 and +is a more secure way to do authentication over public networks than the +regular old-fashioned Basic method. + +## CURLAUTH_DIGEST_IE + +HTTP Digest authentication with an IE flavor. Digest authentication is defined +in RFC 2617 and is a more secure way to do authentication over public networks +than the regular old-fashioned Basic method. The IE flavor is simply that +libcurl uses a special "quirk" that IE is known to have used before version 7 +and that some servers require the client to use. + +## CURLAUTH_BEARER + +HTTP Bearer token authentication, used primarily in OAuth 2.0 protocol. + +You can set the Bearer token to use with CURLOPT_XOAUTH2_BEARER(3). + +## CURLAUTH_NEGOTIATE + +HTTP Negotiate (SPNEGO) authentication. Negotiate authentication is defined +in RFC 4559 and is the most secure way to perform authentication over HTTP. + +You need to build libcurl with a suitable GSS-API library or SSPI on Windows +for this to work. + +## CURLAUTH_NTLM + +HTTP NTLM authentication. A proprietary protocol invented and used by +Microsoft. It uses a challenge-response and hash concept similar to Digest, to +prevent the password from being eavesdropped. + +You need to build libcurl with either OpenSSL or GnuTLS support for this +option to work, or build libcurl on Windows with SSPI support. + +## CURLAUTH_NTLM_WB + +NTLM delegating to winbind helper. Authentication is performed by a separate +binary application that is executed when needed. The name of the application +is specified at compile time but is typically **/usr/bin/ntlm_auth**. + +Note that libcurl forks when necessary to run the winbind application and kill +it when complete, calling **waitpid()** to await its exit when done. On POSIX +operating systems, killing the process causes a SIGCHLD signal to be raised +(regardless of whether CURLOPT_NOSIGNAL(3) is set), which must be handled +intelligently by the application. In particular, the application must not +unconditionally call wait() in its SIGCHLD signal handler to avoid being +subject to a race condition. This behavior is subject to change in future +versions of libcurl. + +## CURLAUTH_ANY + +This is a convenience macro that sets all bits and thus makes libcurl pick any +it finds suitable. libcurl automatically selects the one it finds most secure. + +## CURLAUTH_ANYSAFE + +This is a convenience macro that sets all bits except Basic and thus makes +libcurl pick any it finds suitable. libcurl automatically selects the one it +finds most secure. + +## CURLAUTH_ONLY + +This is a meta symbol. OR this value together with a single specific auth +value to force libcurl to probe for unrestricted auth and if not, only that +single auth algorithm is acceptable. + +## CURLAUTH_AWS_SIGV4 + +provides AWS V4 signature authentication on HTTPS header +see CURLOPT_AWS_SIGV4(3). + +# DEFAULT + +CURLAUTH_BASIC + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* allow whatever auth the server speaks */ + curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY); + curl_easy_setopt(curl, CURLOPT_USERPWD, "james:bond"); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Option Added in 7.10.6. + +CURLAUTH_DIGEST_IE was added in 7.19.3 + +CURLAUTH_ONLY was added in 7.21.3 + +CURLAUTH_NTLM_WB was added in 7.22.0 + +CURLAUTH_BEARER was added in 7.61.0 + +CURLAUTH_AWS_SIGV4 was added in 7.74.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_NOT_BUILT_IN if the bitmask specified no supported authentication +methods. diff --git a/docs/libcurl/opts/CURLOPT_HTTPGET.md b/docs/libcurl/opts/CURLOPT_HTTPGET.md new file mode 100644 index 0000000..d8b024d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTPGET.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTPGET +Section: 3 +Source: libcurl +See-also: + - CURLOPT_NOBODY (3) + - CURLOPT_POST (3) + - CURLOPT_UPLOAD (3) + - curl_easy_reset (3) +--- + +# NAME + +CURLOPT_HTTPGET - ask for an HTTP GET request + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPGET, long useget); +~~~ + +# DESCRIPTION + +Pass a long. If *useget* is 1, this forces the HTTP request to get back to +using GET. Usable if a POST, HEAD, PUT, etc has been used previously using the +same curl *handle*. + +When setting CURLOPT_HTTPGET(3) to 1, libcurl automatically sets +CURLOPT_NOBODY(3) to 0 and CURLOPT_UPLOAD(3) to 0. + +Setting this option to zero has no effect. Applications need to explicitly +select which HTTP request method to use, they cannot deselect a method. To +reset a handle to default method, consider curl_easy_reset(3). + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* use a GET to fetch this */ + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTPHEADER.md b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md new file mode 100644 index 0000000..0ccda77 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md @@ -0,0 +1,181 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTPHEADER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CUSTOMREQUEST (3) + - CURLOPT_HEADER (3) + - CURLOPT_HEADEROPT (3) + - CURLOPT_MIMEPOST (3) + - CURLOPT_PROXYHEADER (3) + - curl_mime_init (3) +--- + +# NAME + +CURLOPT_HTTPHEADER - set of HTTP headers + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPHEADER, + struct curl_slist *headers); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of HTTP headers to pass to the server and/or +proxy in your HTTP request. The same list can be used for both host and proxy +requests! + +When used within an IMAP or SMTP request to upload a MIME mail, the given +header list establishes the document-level MIME headers to prepend to the +uploaded document described by CURLOPT_MIMEPOST(3). This does not affect +raw mail uploads. + +The linked list should be a fully valid list of **struct curl_slist** +structs properly filled in. Use curl_slist_append(3) to create the list +and curl_slist_free_all(3) to clean up an entire list. If you add a +header that is otherwise generated and used by libcurl internally, your added +header is used instead. If you add a header with no content as in 'Accept:' +(no data on the right side of the colon), the internally used header is +disabled/removed. With this option you can add new headers, replace internal +headers and remove internal headers. To add a header with no content (nothing +to the right side of the colon), use the form 'name;' (note the ending +semicolon). + +The headers included in the linked list **must not** be CRLF-terminated, +because libcurl adds CRLF after each header item itself. Failure to comply +with this might result in strange behavior. libcurl passes on the verbatim +strings you give it, without any filter or other safe guards. That includes +white space and control characters. + +The first line in an HTTP request (containing the method, usually a GET or +POST) is not a header and cannot be replaced using this option. Only the lines +following the request-line are headers. Adding this method line in this list +of headers only causes your request to send an invalid header. Use +CURLOPT_CUSTOMREQUEST(3) to change the method. + +When this option is passed to curl_easy_setopt(3), libcurl does not copy +the entire list so you **must** keep it around until you no longer use this +*handle* for a transfer before you call curl_slist_free_all(3) on +the list. + +Pass a NULL to this option to reset back to no custom headers. + +The most commonly replaced HTTP headers have "shortcuts" in the options +CURLOPT_COOKIE(3), CURLOPT_USERAGENT(3) and +CURLOPT_REFERER(3). We recommend using those. + +There is an alternative option that sets or replaces headers only for requests +that are sent with CONNECT to a proxy: CURLOPT_PROXYHEADER(3). Use +CURLOPT_HEADEROPT(3) to control the behavior. + +# SPECIFIC HTTP HEADERS + +Setting some specific headers causes libcurl to act differently. + +## Host: + +The specified hostname is used for cookie matching if the cookie engine is +also enabled for this transfer. If the request is done over HTTP/2 or HTTP/3, +the custom hostname is instead used in the ":authority" header field and +Host: is not sent at all over the wire. + +## Transfer-Encoding: chunked + +Tells libcurl the upload is to be done using this chunked encoding instead of +providing the Content-Length: field in the request. + +# SPECIFIC MIME HEADERS + +When used to build a MIME email for IMAP or SMTP, the following document-level +headers can be set to override libcurl-generated values: + +## Mime-Version: + +Tells the parser at the receiving site how to interpret the MIME framing. +It defaults to "1.0" and should normally not be altered. + +## Content-Type: + +Indicates the document's global structure type. By default, libcurl sets it +to "multipart/mixed", describing a document made of independent parts. When a +MIME mail is only composed of alternative representations of the same data +(i.e.: HTML and plain text), this header must be set to "multipart/alternative". +In all cases the value must be of the form "multipart/*" to respect the +document structure and may not include the "boundary=" parameter. + +Other specific headers that do not have a libcurl default value but are +strongly desired by mail delivery and user agents should also be included. +These are "From:", "To:", "Date:" and "Subject:" among others and their +presence and value is generally checked by anti-spam utilities. + +# SECURITY CONCERNS + +By default, this option makes libcurl send the given headers in all HTTP +requests done by this handle. You should therefore use this option with +caution if you for example connect to the remote site using a proxy and a +CONNECT request, you should to consider if that proxy is supposed to also get +the headers. They may be private or otherwise sensitive to leak. + +Use CURLOPT_HEADEROPT(3) to make the headers only get sent to where you +intend them to get sent. + +Custom headers are sent in all requests done by the easy handle, which implies +that if you tell libcurl to follow redirects +(CURLOPT_FOLLOWLOCATION(3)), the same set of custom headers is sent in +the subsequent request. Redirects can of course go to other hosts and thus +those servers get all the contents of your custom headers too. + +Starting in 7.58.0, libcurl specifically prevents "Authorization:" headers +from being sent to other hosts than the first used one, unless specifically +permitted with the CURLOPT_UNRESTRICTED_AUTH(3) option. + +Starting in 7.64.0, libcurl specifically prevents "Cookie:" headers from being +sent to other hosts than the first used one, unless specifically permitted +with the CURLOPT_UNRESTRICTED_AUTH(3) option. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP, IMAP and SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + + struct curl_slist *list = NULL; + + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + list = curl_slist_append(list, "Shoesize: 10"); + list = curl_slist_append(list, "Accept:"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); + + curl_easy_perform(curl); + + curl_slist_free_all(list); /* free the list */ + } +} +~~~ + +# AVAILABILITY + +As long as HTTP is enabled. Use in MIME mail added in 7.56.0. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTPPOST.md b/docs/libcurl/opts/CURLOPT_HTTPPOST.md new file mode 100644 index 0000000..6fdfc17 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTPPOST.md @@ -0,0 +1,100 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTPPOST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MIMEPOST (3) + - CURLOPT_POST (3) + - CURLOPT_POSTFIELDS (3) + - curl_formadd (3) + - curl_formfree (3) + - curl_mime_init (3) +--- + +# NAME + +CURLOPT_HTTPPOST - multipart formpost content + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPPOST, + struct curl_httppost *formpost); +~~~ + +# DESCRIPTION + +**This option is deprecated.** Use CURLOPT_MIMEPOST(3) instead. + +Tells libcurl you want a **multipart/formdata** HTTP POST to be made and you +instruct what data to pass on to the server in the *formpost* argument. +Pass a pointer to a linked list of *curl_httppost* structs as parameter. +The easiest way to create such a list, is to use curl_formadd(3) as +documented. The data in this list must remain intact as long as the curl +transfer is alive and is using it. + +Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. +You can disable this header with CURLOPT_HTTPHEADER(3). + +When setting CURLOPT_HTTPPOST(3), libcurl automatically sets +CURLOPT_NOBODY(3) to 0. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + struct curl_httppost *formpost; + struct curl_httppost *lastptr; + + /* Fill in the file upload field. This makes libcurl load data from + the given file name when curl_easy_perform() is called. */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "sendfile", + CURLFORM_FILE, "postit2.c", + CURLFORM_END); + + /* Fill in the filename field */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "filename", + CURLFORM_COPYCONTENTS, "postit2.c", + CURLFORM_END); + + /* Fill in the submit field too, even if this is rarely needed */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "submit", + CURLFORM_COPYCONTENTS, "send", + CURLFORM_END); + + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + curl_easy_perform(curl); + curl_easy_cleanup(curl); + } + curl_formfree(formpost); +} +~~~ + +# AVAILABILITY + +As long as HTTP is enabled. Deprecated in 7.56.0. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md b/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md new file mode 100644 index 0000000..bd67640 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTPPROXYTUNNEL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYPORT (3) + - CURLOPT_PROXYTYPE (3) +--- + +# NAME + +CURLOPT_HTTPPROXYTUNNEL - tunnel through HTTP proxy + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPPROXYTUNNEL, long tunnel); +~~~ + +# DESCRIPTION + +Set the **tunnel** parameter to 1L to make libcurl tunnel all operations +through the HTTP proxy (set with CURLOPT_PROXY(3)). There is a big +difference between using a proxy and to tunnel through it. + +Tunneling means that an HTTP CONNECT request is sent to the proxy, asking it +to connect to a remote host on a specific port number and then the traffic is +just passed through the proxy. Proxies tend to white-list specific port numbers +it allows CONNECT requests to and often only port 80 and 443 are allowed. + +To suppress proxy CONNECT response headers from user callbacks use +CURLOPT_SUPPRESS_CONNECT_HEADERS(3). + +HTTP proxies can generally only speak HTTP (for obvious reasons), which makes +libcurl convert non-HTTP requests to HTTP when using an HTTP proxy without +this tunnel option set. For example, asking for an FTP URL and specifying an +HTTP proxy makes libcurl send an FTP URL in an HTTP GET request to the +proxy. By instead tunneling through the proxy, you avoid that conversion (that +rarely works through the proxy anyway). + +# DEFAULT + +0 + +# PROTOCOLS + +All network protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://127.0.0.1:80"); + curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md b/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md new file mode 100644 index 0000000..b48c0f9 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTP_CONTENT_DECODING +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ACCEPT_ENCODING (3) + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_HTTP_CONTENT_DECODING - HTTP content decoding control + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTP_CONTENT_DECODING, + long enabled); +~~~ + +# DESCRIPTION + +Pass a long to tell libcurl how to act on content decoding. If set to zero, +content decoding is disabled. If set to 1 it is enabled. Libcurl has no +default content decoding but requires you to use +CURLOPT_ACCEPT_ENCODING(3) for that. + +# DEFAULT + +1 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md b/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md new file mode 100644 index 0000000..ba83aca --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTP_TRANSFER_DECODING +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ACCEPT_ENCODING (3) + - CURLOPT_HTTP_CONTENT_DECODING (3) +--- + +# NAME + +CURLOPT_HTTP_TRANSFER_DECODING - HTTP transfer decoding control + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTP_TRANSFER_DECODING, + long enabled); +~~~ + +# DESCRIPTION + +Pass a long to tell libcurl how to act on transfer decoding. If set to zero, +transfer decoding is disabled, if set to 1 it is enabled (default). libcurl +does chunked transfer decoding by default unless this option is set to zero. + +# DEFAULT + +1 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.2 Does not work with the hyper backend (it always has transfer +decoding enabled). + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md new file mode 100644 index 0000000..69dc48c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md @@ -0,0 +1,119 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_HTTP_VERSION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ALTSVC (3) + - CURLOPT_HTTP09_ALLOWED (3) + - CURLOPT_HTTP200ALIASES (3) + - CURLOPT_SSLVERSION (3) +--- + +# NAME + +CURLOPT_HTTP_VERSION - HTTP protocol version to use + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTP_VERSION, long version); +~~~ + +# DESCRIPTION + +Pass *version* a long, set to one of the values described below. They ask +libcurl to use the specific HTTP versions. + +Note that the HTTP version is just a request. libcurl still prioritizes to +reuse existing connections so it might then reuse a connection using an HTTP +version you have not asked for. + +## CURL_HTTP_VERSION_NONE + +We do not care about what version the library uses. libcurl uses whatever it +thinks fit. + +## CURL_HTTP_VERSION_1_0 + +Enforce HTTP 1.0 requests. + +## CURL_HTTP_VERSION_1_1 + +Enforce HTTP 1.1 requests. + +## CURL_HTTP_VERSION_2_0 + +Attempt HTTP 2 requests. libcurl falls back to HTTP 1.1 if HTTP 2 cannot be +negotiated with the server. (Added in 7.33.0) + +When libcurl uses HTTP/2 over HTTPS, it does not itself insist on TLS 1.2 or +higher even though that is required by the specification. A user can add this +version requirement with CURLOPT_SSLVERSION(3). + +The alias *CURL_HTTP_VERSION_2* was added in 7.43.0 to better reflect the +actual protocol name. + +## CURL_HTTP_VERSION_2TLS + +Attempt HTTP 2 over TLS (HTTPS) only. libcurl falls back to HTTP 1.1 if HTTP 2 +cannot be negotiated with the HTTPS server. For clear text HTTP servers, +libcurl uses 1.1. (Added in 7.47.0) + +## CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE + +Issue non-TLS HTTP requests using HTTP/2 without HTTP/1.1 Upgrade. It requires +prior knowledge that the server supports HTTP/2 straight away. HTTPS requests +still do HTTP/2 the standard way with negotiated protocol version in the TLS +handshake. (Added in 7.49.0) + +## CURL_HTTP_VERSION_3 + +(Added in 7.66.0) This option makes libcurl attempt to use HTTP/3 to the host +given in the URL, with fallback to earlier HTTP versions if needed. + +## CURL_HTTP_VERSION_3ONLY + +(Added in 7.88.0) Setting this makes libcurl attempt to use HTTP/3 directly to +server given in the URL and does not downgrade to earlier HTTP version if the +server does not support HTTP/3. + +# DEFAULT + +Since curl 7.62.0: CURL_HTTP_VERSION_2TLS + +Before that: CURL_HTTP_VERSION_1_1 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, + (long)CURL_HTTP_VERSION_2TLS); + ret = curl_easy_perform(curl); + if(ret == CURLE_HTTP_RETURNED_ERROR) { + /* an HTTP response error problem */ + } + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md b/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md new file mode 100644 index 0000000..d12b491 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_IGNORE_CONTENT_LENGTH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTP_VERSION (3) + - CURLOPT_MAXFILESIZE_LARGE (3) +--- + +# NAME + +CURLOPT_IGNORE_CONTENT_LENGTH - ignore content length + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_IGNORE_CONTENT_LENGTH, + long ignore); +~~~ + +# DESCRIPTION + +If *ignore* is set to 1L, ignore the Content-Length header in the HTTP +response and ignore asking for or relying on it for FTP transfers. + +This is useful for doing HTTP transfers with ancient web servers which report +incorrect content length for files over 2 gigabytes. If this option is used, +curl cannot accurately report progress, and it instead stops the download when +the server ends the connection. + +It is also useful with FTP when for example the file is growing while the +transfer is in progress which otherwise unconditionally causes libcurl to +report error. + +Only use this option if strictly necessary. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* we know the server is silly, ignore content-length */ + curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.14.1. Support for FTP added in 7.46.0. This option is not working +for HTTP when libcurl is built to use the hyper backend. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_INFILESIZE.md b/docs/libcurl/opts/CURLOPT_INFILESIZE.md new file mode 100644 index 0000000..eab597f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_INFILESIZE.md @@ -0,0 +1,85 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_INFILESIZE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3) + - CURLOPT_INFILESIZE_LARGE (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_INFILESIZE - size of the input file to send off + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INFILESIZE, long filesize); +~~~ + +# DESCRIPTION + +When uploading a file to a remote site, *filesize* should be used to tell +libcurl what the expected size of the input file is. This value must be passed +as a long. See also CURLOPT_INFILESIZE_LARGE(3) for sending files larger +than 2GB. + +For uploading using SCP, this option or CURLOPT_INFILESIZE_LARGE(3) is +mandatory. + +To unset this value again, set it to -1. + +Using CURLOPT_UPLOAD(3) to an HTTP/1.1 server and this value set to -1, makes +libcurl do a chunked transfer-encoded upload. + +When sending emails using SMTP, this command can be used to specify the +optional SIZE parameter for the MAIL FROM command. + +This option does not limit how much data libcurl actually sends, as that is +controlled entirely by what the read callback returns, but telling one value +and sending a different amount may lead to errors. + +# DEFAULT + +Unset + +# PROTOCOLS + +Many + +# EXAMPLE + +~~~c + +#define FILE_SIZE 12345L + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + long uploadsize = FILE_SIZE; + + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/destination.tar.gz"); + + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + curl_easy_setopt(curl, CURLOPT_INFILESIZE, uploadsize); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +SMTP support added in 7.23.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md b/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md new file mode 100644 index 0000000..5f8a338 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_INFILESIZE_LARGE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3) + - CURLOPT_INFILESIZE (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_INFILESIZE_LARGE - size of the input file to send off + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INFILESIZE_LARGE, + curl_off_t filesize); +~~~ + +# DESCRIPTION + +When uploading a file to a remote site, *filesize* should be used to tell +libcurl what the expected size of the input file is. This value must be passed +as a **curl_off_t**. + +For uploading using SCP, this option or CURLOPT_INFILESIZE(3) is +mandatory. + +To unset this value again, set it to -1. + +When sending emails using SMTP, this command can be used to specify the +optional SIZE parameter for the MAIL FROM command. + +This option does not limit how much data libcurl actually sends, as that is +controlled entirely by what the read callback returns, but telling one value +and sending a different amount may lead to errors. + +# DEFAULT + +Unset + +# PROTOCOLS + +Many + +# EXAMPLE + +~~~c +#define FILE_SIZE 123456 + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_off_t uploadsize = FILE_SIZE; + + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/destination.tar.gz"); + + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadsize); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +SMTP support added in 7.23.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_INTERFACE.md b/docs/libcurl/opts/CURLOPT_INTERFACE.md new file mode 100644 index 0000000..24927fd --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_INTERFACE.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_INTERFACE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SOCKOPTFUNCTION (3) + - CURLOPT_TCP_NODELAY (3) +--- + +# NAME + +CURLOPT_INTERFACE - source interface for outgoing traffic + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INTERFACE, char *interface); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter. This sets the *interface* name to use as +outgoing network interface. The name can be an interface name, an IP address, +or a hostname. + +If the parameter starts with "if!" then it is treated only as an interface +name. If the parameter starts with &"host!" it is treated as either an IP +address or a hostname. + +If "if!" is specified but the parameter does not match an existing interface, +*CURLE_INTERFACE_FAILED* is returned from the libcurl function used to +perform the transfer. + +libcurl does not support using network interface names for this option on +Windows. + +We strongly advise against specifying the interface with a hostname, as it +causes libcurl to do a blocking name resolve call to retrieve the IP +address. That name resolve operation does **not** use DNS-over-HTTPS even if +CURLOPT_DOH_URL(3) is set. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL, use whatever the TCP stack finds suitable + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + curl_easy_setopt(curl, CURLOPT_INTERFACE, "eth0"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +The "if!" and "host!" syntax was added in 7.24.0. + +# RETURN VALUE + +Returns CURLE_OK on success or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md b/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md new file mode 100644 index 0000000..64311f8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_INTERLEAVEDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_INTERLEAVEFUNCTION (3) + - CURLOPT_RTSP_REQUEST (3) +--- + +# NAME + +CURLOPT_INTERLEAVEDATA - pointer passed to RTSP interleave callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INTERLEAVEDATA, void *pointer); +~~~ + +# DESCRIPTION + +This is the userdata *pointer* that is passed to +CURLOPT_INTERLEAVEFUNCTION(3) when interleaved RTP data is received. If +the interleave function callback is not set, this pointer is not used +anywhere. + +# DEFAULT + +NULL + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +struct local { + void *custom; +}; +static size_t rtp_write(void *ptr, size_t size, size_t nmemb, void *userp) +{ + struct local *l = userp; + printf("my pointer: %p\n", l->custom); + /* take care of the packet in 'ptr', then return... */ + return size * nmemb; +} + +int main(void) +{ + struct local rtp_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_INTERLEAVEFUNCTION, rtp_write); + curl_easy_setopt(curl, CURLOPT_INTERLEAVEDATA, &rtp_data); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md b/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md new file mode 100644 index 0000000..5f8e999 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md @@ -0,0 +1,102 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_INTERLEAVEFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_INTERLEAVEDATA (3) + - CURLOPT_RTSP_REQUEST (3) +--- + +# NAME + +CURLOPT_INTERLEAVEFUNCTION - callback for RTSP interleaved data + +# SYNOPSIS + +~~~c +#include + +size_t interleave_callback(void *ptr, size_t size, size_t nmemb, + void *userdata); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INTERLEAVEFUNCTION, + interleave_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl as soon as it has received +interleaved RTP data. This function gets called for each $ block and therefore +contains exactly one upper-layer protocol unit (e.g. one RTP packet). Curl +writes the interleaved header as well as the included data for each call. The +first byte is always an ASCII dollar sign. The dollar sign is followed by a +one byte channel identifier and then a 2 byte integer length in network byte +order. See RFC 2326 Section 10.12 for more information on how RTP interleaving +behaves. If unset or set to NULL, curl uses the default write function. + +Interleaved RTP poses some challenges for the client application. Since the +stream data is sharing the RTSP control connection, it is critical to service +the RTP in a timely fashion. If the RTP data is not handled quickly, +subsequent response processing may become unreasonably delayed and the +connection may close. The application may use *CURL_RTSPREQ_RECEIVE* to +service RTP data when no requests are desired. If the application makes a +request, (e.g. *CURL_RTSPREQ_PAUSE*) then the response handler processes +any pending RTP data before marking the request as finished. + +The CURLOPT_INTERLEAVEDATA(3) is passed in the *userdata* argument in +the callback. + +Your callback should return the number of bytes actually taken care of. If +that amount differs from the amount passed to your callback function, it +signals an error condition to the library. This causes the transfer to abort +and the libcurl function used returns *CURLE_WRITE_ERROR*. + +You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0) + +# DEFAULT + +NULL, the interleave data is then passed to the regular write function: +CURLOPT_WRITEFUNCTION(3). + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +struct local { + void *custom; +}; + +static size_t rtp_write(void *ptr, size_t size, size_t nmemb, void *userp) +{ + struct local *l = userp; + printf("our ptr: %p\n", l->custom); + /* take care of the packet in 'ptr', then return... */ + return size * nmemb; +} + +int main(void) +{ + struct local rtp_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_INTERLEAVEFUNCTION, rtp_write); + curl_easy_setopt(curl, CURLOPT_INTERLEAVEDATA, &rtp_data); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_IOCTLDATA.md b/docs/libcurl/opts/CURLOPT_IOCTLDATA.md new file mode 100644 index 0000000..2490fbc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_IOCTLDATA.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_IOCTLDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_IOCTLFUNCTION (3) + - CURLOPT_SEEKFUNCTION (3) +--- + +# NAME + +CURLOPT_IOCTLDATA - pointer passed to I/O callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_IOCTLDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass the *pointer* that is untouched by libcurl and passed as the 3rd +argument in the ioctl callback set with CURLOPT_IOCTLFUNCTION(3). + +# DEFAULT + +By default, the value of this parameter is NULL. + +# PROTOCOLS + +Used with HTTP + +# EXAMPLE + +~~~c +#include /* for lseek */ + +struct data { + int fd; /* our file descriptor */ +}; + +static curlioerr ioctl_callback(CURL *handle, int cmd, void *clientp) +{ + struct data *io = (struct data *)clientp; + if(cmd == CURLIOCMD_RESTARTREAD) { + lseek(io->fd, 0, SEEK_SET); + return CURLIOE_OK; + } + return CURLIOE_UNKNOWNCMD; +} +int main(void) +{ + struct data ioctl_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_callback); + curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &ioctl_data); + } +} +~~~ + +# AVAILABILITY + +Added in 7.12.3. Deprecated since 7.18.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md new file mode 100644 index 0000000..8804ae5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md @@ -0,0 +1,103 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_IOCTLFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_IOCTLDATA (3) + - CURLOPT_SEEKFUNCTION (3) +--- + +# NAME + +CURLOPT_IOCTLFUNCTION - callback for I/O operations + +# SYNOPSIS + +~~~c +#include + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +curlioerr ioctl_callback(CURL *handle, int cmd, void *clientp); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_IOCTLFUNCTION, ioctl_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl when something special +I/O-related needs to be done that the library cannot do by itself. For now, +rewinding the read data stream is the only action it can request. The +rewinding of the read data stream may be necessary when doing an HTTP PUT or +POST with a multi-pass authentication method. + +The callback MUST return *CURLIOE_UNKNOWNCMD* if the input *cmd* is +not *CURLIOCMD_RESTARTREAD*. + +The *clientp* argument to the callback is set with the +CURLOPT_IOCTLDATA(3) option. + +**This option is deprecated**. Do not use it. Use CURLOPT_SEEKFUNCTION(3) +instead to provide seeking! If CURLOPT_SEEKFUNCTION(3) is set, this +parameter is ignored when seeking. + +# DEFAULT + +By default, this parameter is set to NULL. Not used. + +# PROTOCOLS + +Used with HTTP + +# EXAMPLE + +~~~c +#include /* for lseek */ + +struct data { + int fd; /* our file descriptor */ +}; + +static curlioerr ioctl_callback(CURL *handle, int cmd, void *clientp) +{ + struct data *io = (struct data *)clientp; + if(cmd == CURLIOCMD_RESTARTREAD) { + lseek(io->fd, 0, SEEK_SET); + return CURLIOE_OK; + } + return CURLIOE_UNKNOWNCMD; +} +int main(void) +{ + struct data ioctl_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_callback); + curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &ioctl_data); + } +} +~~~ + +# AVAILABILITY + +Added in 7.12.3. Deprecated since 7.18.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_IPRESOLVE.md b/docs/libcurl/opts/CURLOPT_IPRESOLVE.md new file mode 100644 index 0000000..7d06405 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_IPRESOLVE.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_IPRESOLVE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTP_VERSION (3) + - CURLOPT_RESOLVE (3) + - CURLOPT_SSLVERSION (3) +--- + +# NAME + +CURLOPT_IPRESOLVE - IP protocol version to use + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_IPRESOLVE, long resolve); +~~~ + +# DESCRIPTION + +Allows an application to select what kind of IP addresses to use when +establishing a connection or choosing one from the connection pool. This is +interesting when using host names that resolve to more than one IP family. + +If the URL provided for a transfer contains a numerical IP version as a host +name, this option does not override or prohibit libcurl from using that IP +version. + +Available values for this option are: + +## CURL_IPRESOLVE_WHATEVER + +Default, can use addresses of all IP versions that your system allows. + +## CURL_IPRESOLVE_V4 + +Uses only IPv4 addresses. + +## CURL_IPRESOLVE_V6 + +Uses only IPv6 addresses. + +# DEFAULT + +CURL_IPRESOLVE_WHATEVER + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + /* of all addresses example.com resolves to, only IPv6 ones are used */ + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_ISSUERCERT.md b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md new file mode 100644 index 0000000..9b35d5d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ISSUERCERT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CRLFILE (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_ISSUERCERT - issuer SSL certificate filename + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ISSUERCERT, char *file); +~~~ + +# DESCRIPTION + +Pass a char pointer to a null-terminated string naming a *file* holding a CA +certificate in PEM format. If the option is set, an additional check against +the peer certificate is performed to verify the issuer is indeed the one +associated with the certificate provided by the option. This additional check +is useful in multi-level PKI where one needs to enforce that the peer +certificate is from a specific branch of the tree. + +This option makes sense only when used in combination with the +CURLOPT_SSL_VERIFYPEER(3) option. Otherwise, the result of the check is +not considered as failure. + +A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option, +which is returned if the setup of the SSL/TLS session has failed due to a +mismatch with the issuer of peer certificate (CURLOPT_SSL_VERIFYPEER(3) +has to be set too for the check to fail). (Added in 7.19.0) + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_ISSUERCERT, "/etc/certs/cacert.pem"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If built TLS enabled + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md new file mode 100644 index 0000000..4832f41 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md @@ -0,0 +1,92 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_ISSUERCERT_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CRLFILE (3) + - CURLOPT_ISSUERCERT (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_ISSUERCERT_BLOB - issuer SSL certificate from memory blob + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ISSUERCERT_BLOB, + struct curl_blob *stblob); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_blob structure, which contains information (pointer +and size) about a memory block with binary data of a CA certificate in PEM +format. If the option is set, an additional check against the peer certificate +is performed to verify the issuer is indeed the one associated with the +certificate provided by the option. This additional check is useful in +multi-level PKI where one needs to enforce that the peer certificate is from a +specific branch of the tree. + +This option should be used in combination with the +CURLOPT_SSL_VERIFYPEER(3) option. Otherwise, the result of the check is +not considered as failure. + +A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option, +which is returned if the setup of the SSL/TLS session has failed due to a +mismatch with the issuer of peer certificate (CURLOPT_SSL_VERIFYPEER(3) +has to be set too for the check to fail). + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +This option is an alternative to CURLOPT_ISSUERCERT(3) which instead +expects a filename as input. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c + +extern char *certificateData; +extern size_t filesize; + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + blob.data = certificateData; + blob.len = filesize; + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_ISSUERCERT_BLOB, &blob); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.71.0. This option is supported by the OpenSSL backends. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md b/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md new file mode 100644 index 0000000..090a8fc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_KEEP_SENDING_ON_ERROR +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RESPONSE_CODE (3) + - CURLOPT_FAILONERROR (3) + - CURLOPT_HTTPHEADER (3) +--- + +# NAME + +CURLOPT_KEEP_SENDING_ON_ERROR - keep sending on early HTTP response >= 300 + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KEEP_SENDING_ON_ERROR, + long keep_sending); +~~~ + +# DESCRIPTION + +A long parameter set to 1 tells the library to keep sending the request body +if the HTTP code returned is equal to or larger than 300. The default action +would be to stop sending and close the stream or connection. + +This option is suitable for manual NTLM authentication, i.e. if an application +does not use CURLOPT_HTTPAUTH(3), but instead sets "Authorization: NTLM ..." +headers manually using CURLOPT_HTTPHEADER(3). + +Most applications do not need this option. + +# DEFAULT + +0, stop sending on error + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "sending data"); + curl_easy_setopt(curl, CURLOPT_KEEP_SENDING_ON_ERROR, 1L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP. Added in 7.51.0. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_KEYPASSWD.md b/docs/libcurl/opts/CURLOPT_KEYPASSWD.md new file mode 100644 index 0000000..7407f09 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_KEYPASSWD.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_KEYPASSWD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_PRIVATE_KEYFILE (3) + - CURLOPT_SSLKEY (3) +--- + +# NAME + +CURLOPT_KEYPASSWD - passphrase to private key + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KEYPASSWD, char *pwd); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. It is used as the +password required to use the CURLOPT_SSLKEY(3) or +CURLOPT_SSH_PRIVATE_KEYFILE(3) private key. You never need a pass phrase to +load a certificate but you need one to load your private key. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "superman"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option was known as CURLOPT_SSLKEYPASSWD up to 7.16.4 and +CURLOPT_SSLCERTPASSWD up to 7.9.2. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_KRBLEVEL.md b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md new file mode 100644 index 0000000..cb8e276 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_KRBLEVEL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_KRBLEVEL (3) + - CURLOPT_USE_SSL (3) +--- + +# NAME + +CURLOPT_KRBLEVEL - FTP kerberos security level + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KRBLEVEL, char *level); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter. Set the kerberos security level for FTP; +this also enables kerberos awareness. This is a string that should match one +of the following: &'clear', &'safe', &'confidential' or &'private'. If the +string is set but does not match one of these, 'private' is used. Set the +string to NULL to disable kerberos support for FTP. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_KRBLEVEL, "private"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option was known as CURLOPT_KRB4LEVEL up to 7.16.3 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_LOCALPORT.md b/docs/libcurl/opts/CURLOPT_LOCALPORT.md new file mode 100644 index 0000000..25a21c1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_LOCALPORT.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_LOCALPORT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_LOCAL_PORT (3) + - CURLOPT_INTERFACE (3) + - CURLOPT_LOCALPORTRANGE (3) +--- + +# NAME + +CURLOPT_LOCALPORT - local port number to use for socket + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_LOCALPORT, long port); +~~~ + +# DESCRIPTION + +Pass a long. This sets the local port number of the socket used for the +connection. This can be used in combination with CURLOPT_INTERFACE(3) +and you are recommended to use CURLOPT_LOCALPORTRANGE(3) as well when +this option is set. Valid port numbers are 1 - 65535. + +# DEFAULT + +0, disabled - use whatever the system thinks is fine + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_LOCALPORT, 49152L); + /* and try 20 more ports following that */ + curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, 20L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.2 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md b/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md new file mode 100644 index 0000000..5200207 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_LOCALPORTRANGE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_INTERFACE (3) + - CURLOPT_LOCALPORT (3) +--- + +# NAME + +CURLOPT_LOCALPORTRANGE - number of additional local ports to try + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_LOCALPORTRANGE, + long range); +~~~ + +# DESCRIPTION + +Pass a long. The *range* argument is the number of attempts libcurl makes +to find a working local port number. It starts with the given +CURLOPT_LOCALPORT(3) and adds one to the number for each retry. Setting +this option to 1 or below makes libcurl only do one try for the exact port +number. Port numbers by nature are scarce resources that are busy at times so +setting this value to something too low might cause unnecessary connection +setup failures. + +# DEFAULT + +1 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_LOCALPORT, 49152L); + /* and try 20 more ports following that */ + curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, 20L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.2 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md b/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md new file mode 100644 index 0000000..a57b446 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_LOGIN_OPTIONS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PASSWORD (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_LOGIN_OPTIONS - login options + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_LOGIN_OPTIONS, char *options); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be pointing to the +null-terminated *options* string to use for the transfer. + +For more information about the login options please see RFC 2384, RFC 5092 and +the IETF draft **draft-earhart-url-smtp-00.txt**. + +CURLOPT_LOGIN_OPTIONS(3) can be used to set protocol specific login options, +such as the preferred authentication mechanism via "AUTH=NTLM" or "AUTH=*", +and should be used in conjunction with the CURLOPT_USERNAME(3) option. + +Since 8.2.0, IMAP supports the login option "AUTH=+LOGIN". With this option, +curl uses the plain (not SASL) LOGIN IMAP command even if the server +advertises SASL authentication. Care should be taken in using this option, as +it sends your password in plain text. This does not work if the IMAP server +disables the plain LOGIN (e.g. to prevent password snooping). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +Only IMAP, LDAP, POP3 and SMTP support login options. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/"); + curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, "AUTH=*"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.34.0. Support for OpenLDAP added in 7.82.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md b/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md new file mode 100644 index 0000000..99df9fa --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_LOW_SPEED_LIMIT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_LOW_SPEED_TIME (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) + - CURLOPT_MAX_SEND_SPEED_LARGE (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_LOW_SPEED_LIMIT - low speed limit in bytes per second + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_LOW_SPEED_LIMIT, + long speedlimit); +~~~ + +# DESCRIPTION + +Pass a long as parameter. It contains the average transfer speed in bytes per +second that the transfer should be below during +CURLOPT_LOW_SPEED_TIME(3) seconds for libcurl to consider it to be too +slow and abort. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* abort if slower than 30 bytes/sec during 60 seconds */ + curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60L); + curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 30L); + res = curl_easy_perform(curl); + if(CURLE_OPERATION_TIMEDOUT == res) { + printf("Timeout!\n"); + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md b/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md new file mode 100644 index 0000000..a3a9ef1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_LOW_SPEED_TIME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_LOW_SPEED_TIME - low speed limit time period + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_LOW_SPEED_TIME, + long speedtime); +~~~ + +# DESCRIPTION + +Pass a long as parameter. It contains the time in number seconds that the +transfer speed should be below the CURLOPT_LOW_SPEED_LIMIT(3) for the +library to consider it too slow and abort. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* abort if slower than 30 bytes/sec during 60 seconds */ + curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60L); + curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 30L); + res = curl_easy_perform(curl); + if(CURLE_OPERATION_TIMEDOUT == res) { + printf("Timeout!\n"); + } + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md b/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md new file mode 100644 index 0000000..a5dbc7d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAIL_AUTH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAIL_FROM (3) + - CURLOPT_MAIL_RCPT (3) +--- + +# NAME + +CURLOPT_MAIL_AUTH - SMTP authentication address + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAIL_AUTH, char *auth); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. This is used to +specify the authentication address (identity) of a submitted message that is +being relayed to another server. + +This optional parameter allows co-operating agents in a trusted environment to +communicate the authentication of individual messages and should only be used +by the application program, using libcurl, if the application is itself a mail +server acting in such an environment. If the application is operating as such +and the AUTH address is not known or is invalid, then an empty string should +be used for this parameter. + +Unlike CURLOPT_MAIL_FROM(3) and CURLOPT_MAIL_RCPT(3), the address +should not be specified within a pair of angled brackets (<>). However, if an +empty string is used then a pair of brackets are sent by libcurl as required +by RFC 2554. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/"); + curl_easy_setopt(curl, CURLOPT_MAIL_AUTH, ""); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.25.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_MAIL_FROM.md b/docs/libcurl/opts/CURLOPT_MAIL_FROM.md new file mode 100644 index 0000000..c4984b0 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAIL_FROM.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAIL_FROM +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAIL_AUTH (3) + - CURLOPT_MAIL_RCPT (3) +--- + +# NAME + +CURLOPT_MAIL_FROM - SMTP sender address + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAIL_FROM, char *from); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. This should be used +to specify the sender's email address when sending SMTP mail with libcurl. + +An originator email address should be specified with angled brackets (<>) +around it, which if not specified are added automatically. + +If this parameter is not specified then an empty address is sent to the SMTP +server which might cause the email to be rejected. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +blank + +# PROTOCOLS + +SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/"); + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "president@example.com"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md b/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md new file mode 100644 index 0000000..ce57074 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAIL_RCPT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAIL_AUTH (3) + - CURLOPT_MAIL_FROM (3) +--- + +# NAME + +CURLOPT_MAIL_RCPT - list of SMTP mail recipients + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAIL_RCPT, + struct curl_slist *rcpts); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of recipients to pass to the server in your +SMTP mail request. The linked list should be a fully valid list of +**struct curl_slist** structs properly filled in. Use +curl_slist_append(3) to create the list and curl_slist_free_all(3) +to clean up an entire list. + +When performing a mail transfer, each recipient should be specified within a +pair of angled brackets (<>), however, should you not use an angled bracket as +the first character libcurl assumes you provided a single email address and +encloses that address within brackets for you. + +When performing an address verification (**VRFY** command), each recipient +should be specified as the user name or user name and domain (as per Section +3.5 of RFC 5321). + +When performing a mailing list expand (**EXPN** command), each recipient +should be specified using the mailing list name, such as "Friends" or +"London-Office". + +# DEFAULT + +NULL + +# PROTOCOLS + +SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_slist *list; + list = curl_slist_append(NULL, "root@localhost"); + list = curl_slist_append(list, "person@example.com"); + curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/"); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, list); + res = curl_easy_perform(curl); + curl_slist_free_all(list); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0. The **VRFY** and **EXPN** logic was added in 7.34.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md b/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md new file mode 100644 index 0000000..cf595e2 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAIL_RCPT_ALLOWFAILS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAIL_FROM (3) + - CURLOPT_MAIL_RCPT (3) +--- + +# NAME + +CURLOPT_MAIL_RCPT_ALLOWFAILS - allow RCPT TO command to fail for some recipients + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAIL_RCPT_ALLOWFAILS, + long allow); +~~~ + +# DESCRIPTION + +If *allow* is set to 1L, allow RCPT TO command to fail for some recipients. + +When sending data to multiple recipients, by default curl aborts the SMTP +conversation if either one of the recipients causes the RCPT TO command to +return an error. + +The default behavior can be changed by setting *allow* to 1L which makes +libcurl ignore errors for individual recipients and proceed with the remaining +accepted recipients. + +If all recipients trigger RCPT TO failures and this flag is specified, curl +aborts the SMTP conversation and returns the error received from to the last +RCPT TO command. + +# DEFAULT + +0 + +# PROTOCOLS + +SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct curl_slist *list; + CURLcode res; + + /* Adding one valid and one invalid email address */ + list = curl_slist_append(NULL, "person@example.com"); + list = curl_slist_append(list, "invalidemailaddress"); + + curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/"); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT_ALLOWFAILS, 1L); + + res = curl_easy_perform(curl); + curl_slist_free_all(list); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +This option was called CURLOPT_MAIL_RCPT_ALLLOWFAILS before 8.2.0 + +Added in 7.69.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md b/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md new file mode 100644 index 0000000..3d0a9cb --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAXAGE_CONN +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FORBID_REUSE (3) + - CURLOPT_FRESH_CONNECT (3) + - CURLOPT_MAXLIFETIME_CONN (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_MAXAGE_CONN - max idle time allowed for reusing a connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXAGE_CONN, long age); +~~~ + +# DESCRIPTION + +Pass a long as parameter containing *age* - the maximum time in seconds +allowed for an existing connection to have been idle to be considered for +reuse for this request. + +The "connection cache" holds previously used connections. When a new request +is to be done, libcurl considers any connection that matches for reuse. The +CURLOPT_MAXAGE_CONN(3) limit prevents libcurl from trying too old +connections for reuse, since old connections have a higher risk of not working +and thus trying them is a performance loss and sometimes service loss due to +the difficulties to figure out the situation. If a connection is found in the +cache that is older than this set *age*, it is closed instead. + +# DEFAULT + +Default maximum age is set to 118 seconds. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* only allow 30 seconds idle time */ + curl_easy_setopt(curl, CURLOPT_MAXAGE_CONN, 30L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.65.0 + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md b/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md new file mode 100644 index 0000000..807df4d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAXCONNECTS +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_MAXCONNECTS (3) + - CURLMOPT_MAX_HOST_CONNECTIONS (3) + - CURLMOPT_MAX_TOTAL_CONNECTIONS (3) + - CURLOPT_MAXREDIRS (3) +--- + +# NAME + +CURLOPT_MAXCONNECTS - maximum connection cache size + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXCONNECTS, long amount); +~~~ + +# DESCRIPTION + +Pass a long. The set *amount* is the maximum number of simultaneously open +persistent connections that libcurl may cache in the pool associated with this +handle. The default is 5, and there is not much point in changing this value +unless you are perfectly aware of how this works. This concerns connections +using any of the protocols that support persistent connections. + +When reaching the maximum limit, curl closes the oldest one in the cache to +prevent increasing the number of open connections. + +If you already have performed transfers with this curl handle, setting a +smaller CURLOPT_MAXCONNECTS(3) than before may cause open connections to +get closed unnecessarily. + +If you add this easy handle to a multi handle, this setting is not +acknowledged, and you must instead use curl_multi_setopt(3) and the +CURLMOPT_MAXCONNECTS(3) option. + +# DEFAULT + +5 + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* limit the connection cache for this handle to no more than 3 */ + curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 3L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md b/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md new file mode 100644 index 0000000..a90c94b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAXFILESIZE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAXFILESIZE_LARGE (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) +--- + +# NAME + +CURLOPT_MAXFILESIZE - maximum file size allowed to download + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXFILESIZE, long size); +~~~ + +# DESCRIPTION + +Pass a long as parameter. This specifies the maximum accepted *size* (in +bytes) of a file to download. If the file requested is found larger than this +value, the transfer is aborted and *CURLE_FILESIZE_EXCEEDED* is returned. + +The file size is not always known prior to the download start, and for such +transfers this option has no effect - even if the file transfer eventually +ends up being larger than this given limit. + +If you want a limit above 2GB, use CURLOPT_MAXFILESIZE_LARGE(3). + +Since 8.4.0, this option also stops ongoing transfers if they reach this +threshold. + +# DEFAULT + +None + +# PROTOCOLS + +FTP, HTTP and MQTT + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* refuse to download if larger than 1000 bytes! */ + curl_easy_setopt(curl, CURLOPT_MAXFILESIZE, 1000L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md b/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md new file mode 100644 index 0000000..041282f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAXFILESIZE_LARGE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAXFILESIZE (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) +--- + +# NAME + +CURLOPT_MAXFILESIZE_LARGE - maximum file size allowed to download + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXFILESIZE_LARGE, + curl_off_t size); +~~~ + +# DESCRIPTION + +Pass a curl_off_t as parameter. This specifies the maximum accepted *size* +(in bytes) of a file to download. If the file requested is found larger than +this value, the transfer is aborted and *CURLE_FILESIZE_EXCEEDED* is +returned. + +The file size is not always known prior to the download start, and for such +transfers this option has no effect - even if the file transfer eventually +ends up being larger than this given limit. + +Since 8.4.0, this option also stops ongoing transfers if they reach this +threshold. + +# DEFAULT + +None + +# PROTOCOLS + +FTP, HTTP and MQTT + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_off_t ridiculous = (curl_off_t)1 << 48; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* refuse to download if larger than ridiculous */ + curl_easy_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, ridiculous); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.11.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md new file mode 100644 index 0000000..f731ad9 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAXLIFETIME_CONN +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FORBID_REUSE (3) + - CURLOPT_FRESH_CONNECT (3) + - CURLOPT_MAXAGE_CONN (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_MAXLIFETIME_CONN - max lifetime (since creation) allowed for reusing a connection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXLIFETIME_CONN, + long maxlifetime); +~~~ + +# DESCRIPTION + +Pass a long as parameter containing *maxlifetime* - the maximum time in +seconds, since the creation of the connection, that you allow an existing +connection to have to be considered for reuse for this request. + +libcurl features a connection cache that holds previously used connections. +When a new request is to be done, libcurl considers any connection that +matches for reuse. The CURLOPT_MAXLIFETIME_CONN(3) limit prevents +libcurl from trying too old connections for reuse. This can be used for +client-side load balancing. If a connection is found in the cache that is +older than this set *maxlifetime*, it is instead marked for closure. + +If set to 0, this behavior is disabled: all connections are eligible for reuse. + +# DEFAULT + +Default *maxlifetime* is 0 seconds (i.e., disabled). + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* only allow each connection to be reused for 30 seconds */ + curl_easy_setopt(curl, CURLOPT_MAXLIFETIME_CONN, 30L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.80.0 + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_MAXREDIRS.md b/docs/libcurl/opts/CURLOPT_MAXREDIRS.md new file mode 100644 index 0000000..5ace67e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAXREDIRS.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAXREDIRS +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_COUNT (3) + - CURLINFO_REDIRECT_URL (3) + - CURLOPT_FOLLOWLOCATION (3) +--- + +# NAME + +CURLOPT_MAXREDIRS - maximum number of redirects allowed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXREDIRS, long amount); +~~~ + +# DESCRIPTION + +Pass a long. The set number is the redirection limit *amount*. If that +many redirections have been followed, the next redirect triggers the error +(*CURLE_TOO_MANY_REDIRECTS*). This option only makes sense if the +CURLOPT_FOLLOWLOCATION(3) is used at the same time. + +Setting the limit to 0 makes libcurl refuse any redirect. + +Set it to -1 for an infinite number of redirects. This allows your application +to get stuck in never-ending redirect loops. + +# DEFAULT + +30 (since 8.3.0), it was previously unlimited. + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + + /* enable redirect following */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + /* allow three redirects */ + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 3L); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md b/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md new file mode 100644 index 0000000..646f301 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAX_RECV_SPEED_LARGE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_MAX_SEND_SPEED_LARGE (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_MAX_RECV_SPEED_LARGE - rate limit data download speed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAX_RECV_SPEED_LARGE, + curl_off_t maxspeed); +~~~ + +# DESCRIPTION + +Pass a curl_off_t as parameter. If a download exceeds this *maxspeed* +(counted in bytes per second) the transfer pauses to keep the average speed +less than or equal to the parameter value. Defaults to unlimited speed. + +This is not an exact science. libcurl attempts to keep the average speed below +the given threshold over a period time. + +If you set *maxspeed* to a value lower than CURLOPT_BUFFERSIZE(3), +libcurl might download faster than the set limit initially. + +This option does not affect transfer speeds done with FILE:// URLs. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +All but file:// + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* cap the download speed to 31415 bytes/sec */ + curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)31415); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.5 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md b/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md new file mode 100644 index 0000000..8b709cc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MAX_SEND_SPEED_LARGE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) +--- + +# NAME + +CURLOPT_MAX_SEND_SPEED_LARGE - rate limit data upload speed + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAX_SEND_SPEED_LARGE, + curl_off_t maxspeed); +~~~ + +# DESCRIPTION + +Pass a curl_off_t as parameter with the *maxspeed*. If an upload exceeds +this speed (counted in bytes per second) the transfer pauses to keep the +average speed less than or equal to the parameter value. Defaults to unlimited +speed. + +This is not an exact science. libcurl attempts to keep the average speed below +the given threshold over a period time. + +If you set *maxspeed* to a value lower than +CURLOPT_UPLOAD_BUFFERSIZE(3), libcurl might "shoot over" the limit on +its first send and still send off a full buffer. + +This option does not affect transfer speeds done with FILE:// URLs. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +All except file:// + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* cap the upload speed to 1000 bytes/sec */ + curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t)1000); + /* (set some upload options as well!) */ + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.15.5 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_MIMEPOST.md b/docs/libcurl/opts/CURLOPT_MIMEPOST.md new file mode 100644 index 0000000..588b7e8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MIMEPOST.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MIMEPOST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPPOST (3) + - CURLOPT_POSTFIELDS (3) + - CURLOPT_PUT (3) + - curl_mime_init (3) +--- + +# NAME + +CURLOPT_MIMEPOST - send data from mime structure + +# SYNOPSIS + +~~~c +#include + +curl_mime *mime; + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MIMEPOST, mime); +~~~ + +# DESCRIPTION + +Pass a mime handle previously obtained from curl_mime_init(3). + +This setting is supported by the HTTP protocol to post forms and by the +SMTP and IMAP protocols to provide the email data to send/upload. + +This option is the preferred way of posting an HTTP form, replacing and +extending the CURLOPT_HTTPPOST(3) option. + +When setting CURLOPT_MIMEPOST(3) to NULL, libcurl resets the request +type for HTTP to the default to disable the POST. Typically that would mean it +is reset to GET. Instead you should set a desired request method explicitly. + +# PROTOCOLS + +HTTP, SMTP, IMAP. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_mime *multipart = curl_mime_init(curl); + if(multipart) { + curl_mimepart *part = curl_mime_addpart(multipart); + curl_mime_name(part, "name"); + curl_mime_data(part, "daniel", CURL_ZERO_TERMINATED); + part = curl_mime_addpart(multipart); + curl_mime_name(part, "project"); + curl_mime_data(part, "curl", CURL_ZERO_TERMINATED); + part = curl_mime_addpart(multipart); + curl_mime_name(part, "logotype-image"); + curl_mime_filedata(part, "curl.png"); + + /* Set the form info */ + curl_easy_setopt(curl, CURLOPT_MIMEPOST, multipart); + + curl_easy_perform(curl); /* post away! */ + curl_mime_free(multipart); /* free the post data */ + } + } +} +~~~ + +# AVAILABILITY + +Added in 7.56.0 + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md b/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md new file mode 100644 index 0000000..a8da7d7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md @@ -0,0 +1,97 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_MIME_OPTIONS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPPOST (3) + - CURLOPT_MIMEPOST (3) +--- + +# NAME + +CURLOPT_MIME_OPTIONS - set MIME option flags + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MIME_OPTIONS, long options); +~~~ + +# DESCRIPTION + +Pass a long that holds a bitmask of CURLMIMEOPT_* defines. Each bit is a +Boolean flag used while encoding a MIME tree or multipart form data. + +Available bits are: + +## CURLMIMEOPT_FORMESCAPE + +Tells libcurl to escape multipart form field and file names using the +backslash-escaping algorithm rather than percent-encoding (HTTP only). + +Backslash-escaping consists in preceding backslashes and double quotes with +a backslash. Percent encoding maps all occurrences of double quote, +carriage return and line feed to %22, %0D and %0A respectively. + +Before version 7.81.0, percent-encoding was never applied. + +HTTP browsers used to do backslash-escaping in the past but have over time +transitioned to use percent-encoding. This option allows one to address +server-side applications that have not yet have been converted. + +As an example, consider field or filename *strangename"kind*. When the +containing multipart form is sent, this is normally transmitted as +*strangename%22kind*. When this option is set, it is sent as +*strangename"kind*. + +# DEFAULT + +0, meaning disabled. + +# PROTOCOLS + +HTTP, IMAP, SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + curl_mime *form = NULL; + + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_MIME_OPTIONS, CURLMIMEOPT_FORMESCAPE); + + form = curl_mime_init(curl); + if(form) { + curl_mimepart *part = curl_mime_addpart(form); + + if(part) { + curl_mime_filedata(part, "strange\\file\\name"); + curl_mime_name(part, "strange\"field\"name"); + curl_easy_setopt(curl, CURLOPT_MIMEPOST, form); + + /* Perform the request */ + curl_easy_perform(curl); + } + } + + curl_easy_cleanup(curl); + curl_mime_free(form); + } +} +~~~ + +# AVAILABILITY + +Option added in 7.81.0. + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_NETRC.md b/docs/libcurl/opts/CURLOPT_NETRC.md new file mode 100644 index 0000000..89a55b4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NETRC.md @@ -0,0 +1,141 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NETRC +Section: 3 +Source: libcurl +See-also: + - CURLOPT_NETRC_FILE (3) + - CURLOPT_USERNAME (3) + - CURLOPT_USERPWD (3) +--- + +# NAME + +CURLOPT_NETRC - enable use of .netrc + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NETRC, long level); +~~~ + +# DESCRIPTION + +This parameter controls the preference *level* of libcurl between using +user names and passwords from your *~/.netrc* file, relative to user names +and passwords in the URL supplied with CURLOPT_URL(3). + +On Windows, libcurl uses the file as *%HOME%/_netrc*. If *%HOME%* is +not set on Windows, libcurl falls back to *%USERPROFILE%*. + +You can also tell libcurl a different filename to use with +CURLOPT_NETRC_FILE(3). + +libcurl uses a user name (and supplied or prompted password) supplied with +CURLOPT_USERPWD(3) or CURLOPT_USERNAME(3) in preference to any of +the options controlled by this parameter. + +Only machine name, user name and password are taken into account (init macros +and similar things are not supported). + +libcurl does not verify that the file has the correct properties set (as the +standard Unix ftp client does). It should only be readable by user. + +*level* is a long that should be set to one of the values described below. + +## CURL_NETRC_IGNORED (0) + +libcurl ignores the *.netrc* file. This is the default. + +## CURL_NETRC_OPTIONAL (1) + +The use of the *.netrc* file is optional, and information in the URL is to +be preferred. The file is scanned for the host and user name (to find the +password only) or for the host only, to find the first user name and password +after that *machine*, which ever information is not specified. + +## CURL_NETRC_REQUIRED (2) + +The use of the *.netrc* file is required, and any credential information +present in the URL is ignored. The file is scanned for the host and user name +(to find the password only) or for the host only, to find the first user name +and password after that *machine*, which ever information is not +specified. + +# FILE FORMAT + +The **.netrc** file format is simple: you specify lines with a machine name +and follow the login and password that are associated with that machine. + +Each field is provided as a sequence of letters that ends with a space or +newline. Starting in 7.84.0, libcurl also supports quoted strings. They start +and end with double quotes and support the escaped special letters ", n, +r, and t. Quoted strings are the only way a space character can be used in +a user name or password. + +## machine + +Provides credentials for a host called **name**. libcurl searches the .netrc +file for a machine token that matches the hostname specified in the URL. Once +a match is made, the subsequent tokens are processed, stopping when the end of +file is reached or another "machine" is encountered. + +## default + +This is the same as "machine" name except that default matches any name. There +can be only one default token, and it must be after all machine tokens. To +provide a default anonymous login for hosts that are not otherwise matched, +add a line similar to this in the end: + + default login anonymous password user@domain + +## login + +The user name string for the remote machine. + +## password + +Supply a password. If this token is present, curl supplies the specified +string if the remote server requires a password as part of the login process. +Note that if this token is present in the .netrc file you really should make +sure the file is not readable by anyone besides the user. + +## macdef + +Define a macro. This feature is not supported by libcurl. In order for the +rest of the .netrc to still work fine, libcurl properly skips every definition +done with "macdef" that it finds. + +# DEFAULT + +CURL_NETRC_IGNORED + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/"); + curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_NETRC_FILE.md b/docs/libcurl/opts/CURLOPT_NETRC_FILE.md new file mode 100644 index 0000000..62fe7a5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NETRC_FILE.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NETRC_FILE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_NETRC (3) + - CURLOPT_PASSWORD (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_NETRC_FILE - filename to read .netrc info from + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NETRC_FILE, char *file); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, pointing to a null-terminated string +containing the full path name to the *file* you want libcurl to use as .netrc +file. If this option is omitted, and CURLOPT_NETRC(3) is set, libcurl checks +for a .netrc file in the current user's home directory. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/"); + curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); + curl_easy_setopt(curl, CURLOPT_NETRC_FILE, "/tmp/magic-netrc"); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.9 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md b/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md new file mode 100644 index 0000000..bb302d4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NEW_DIRECTORY_PERMS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FTP_CREATE_MISSING_DIRS (3) + - CURLOPT_NEW_FILE_PERMS (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_NEW_DIRECTORY_PERMS - permissions for remotely created directories + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NEW_DIRECTORY_PERMS, + long mode); +~~~ + +# DESCRIPTION + +Pass a long as a parameter, containing the value of the permissions that is +set on newly created directories on the remote server. The default value is +*0755*, but any valid value can be used. The only protocols that can use +this are *sftp://*, *scp://*, and *file://*. + +# DEFAULT + +0755 + +# PROTOCOLS + +SFTP, SCP and FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, + "sftp://upload.example.com/newdir/file.zip"); + curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L); + curl_easy_setopt(curl, CURLOPT_NEW_DIRECTORY_PERMS, 0644L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md b/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md new file mode 100644 index 0000000..dd12c0b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md @@ -0,0 +1,60 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NEW_FILE_PERMS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_NEW_DIRECTORY_PERMS (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_NEW_FILE_PERMS - permissions for remotely created files + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NEW_FILE_PERMS, + long mode); +~~~ + +# DESCRIPTION + +Pass a long as a parameter, containing the value of the permissions that are +set on newly created files on the remote server. The default value is *0644*. +The only protocols that can use this are *sftp://*, *scp://*, and *file://*. + +# DEFAULT + +0644 + +# PROTOCOLS + +SFTP, SCP and FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://upload.example.com/file.txt"); + curl_easy_setopt(curl, CURLOPT_NEW_FILE_PERMS, 0664L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_NOBODY.md b/docs/libcurl/opts/CURLOPT_NOBODY.md new file mode 100644 index 0000000..9d63154 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NOBODY.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NOBODY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPGET (3) + - CURLOPT_MIMEPOST (3) + - CURLOPT_POSTFIELDS (3) + - CURLOPT_REQUEST_TARGET (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_NOBODY - do the download request without getting the body + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NOBODY, long opt); +~~~ + +# DESCRIPTION + +A long parameter set to 1 tells libcurl to not include the body-part in the +output when doing what would otherwise be a download. For HTTP(S), this makes +libcurl do a HEAD request. For most other protocols it means just not asking +to transfer the body data. + +For HTTP operations when CURLOPT_NOBODY(3) has been set, disabling this +option (with 0) makes it a GET again - only if the method is still set to be +HEAD. The proper way to get back to a GET request is to set +CURLOPT_HTTPGET(3) and for other methods, use the POST or UPLOAD +options. + +Enabling CURLOPT_NOBODY(3) means asking for a download without a body. + +If you do a transfer with HTTP that involves a method other than HEAD, you get +a body (unless the resource and server sends a zero byte body for the specific +URL you request). + +# DEFAULT + +0, the body is transferred + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* get us the resource without a body - use HEAD! */ + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_NOPROGRESS.md b/docs/libcurl/opts/CURLOPT_NOPROGRESS.md new file mode 100644 index 0000000..e2845a9 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NOPROGRESS.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NOPROGRESS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_PROGRESSFUNCTION (3) + - CURLOPT_VERBOSE (3) + - CURLOPT_XFERINFOFUNCTION (3) +--- + +# NAME + +CURLOPT_NOPROGRESS - switch off the progress meter + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NOPROGRESS, long onoff); +~~~ + +# DESCRIPTION + +If *onoff* is to 1, it tells the library to shut off the progress meter +completely for requests done with this *handle*. It also prevents the +CURLOPT_XFERINFOFUNCTION(3) or CURLOPT_PROGRESSFUNCTION(3) from +getting called. + +# DEFAULT + +1, meaning it normally runs without a progress meter. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* enable progress meter */ + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_NOPROXY.md b/docs/libcurl/opts/CURLOPT_NOPROXY.md new file mode 100644 index 0000000..91292e2 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NOPROXY.md @@ -0,0 +1,91 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NOPROXY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYAUTH (3) + - CURLOPT_PROXYTYPE (3) +--- + +# NAME + +CURLOPT_NOPROXY - disable proxy use for specific hosts + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NOPROXY, char *noproxy); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string. The string consists of a comma +separated list of host names that do not require a proxy to get reached, even +if one is specified. The only wildcard available is a single * character, +which matches all hosts, and effectively disables the proxy. Each name in this +list is matched as either a domain which contains the hostname, or the +hostname itself. For example, "ample.com" would match ample.com, ample.com:80, +and www.ample.com, but not www.example.com or ample.com.org. + +Setting the *noproxy* string to "" (an empty string) explicitly enables +the proxy for all host names, even if there is an environment variable set for +it. + +Enter IPv6 numerical addresses in the list of host names without enclosing +brackets: + + "example.com,::1,localhost" + +Since 7.86.0, IP addresses specified to this option can be provided using CIDR +notation: an appended slash and number specifies the number of "network bits" +out of the address to use in the comparison. For example "192.168.0.0/16" +would match all addresses starting with "192.168". + +The application does not have to keep the string around after setting this +option. + +# Environment variables + +If there is an environment variable called **no_proxy** (or **NO_PROXY**), +it is used if the CURLOPT_NOPROXY(3) option is not set. It works exactly +the same way. + +# DEFAULT + +NULL + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* accept various URLs */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* use this proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80"); + /* ... but make sure this host name is not proxied */ + curl_easy_setopt(curl, CURLOPT_NOPROXY, "www.example.com"); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_NOSIGNAL.md b/docs/libcurl/opts/CURLOPT_NOSIGNAL.md new file mode 100644 index 0000000..50ae65c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_NOSIGNAL.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_NOSIGNAL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_NOSIGNAL - skip all signal handling + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NOSIGNAL, long onoff); +~~~ + +# DESCRIPTION + +If *onoff* is 1, libcurl uses no functions that install signal handlers or +any functions that cause signals to be sent to the process. This option is +here to allow multi-threaded unix applications to still set/use all timeout +options etc, without risking getting signals. + +If this option is set and libcurl has been built with the standard name +resolver, timeouts cannot occur while the name resolve takes place. Consider +building libcurl with the c-ares or threaded resolver backends to enable +asynchronous DNS lookups, to enable timeouts for name resolves without the use +of signals. + +Setting CURLOPT_NOSIGNAL(3) to 1 makes libcurl NOT ask the system to +ignore SIGPIPE signals, which otherwise are sent by the system when trying to +send data to a socket which is closed in the other end. libcurl makes an +effort to never cause such SIGPIPE signals to trigger, but some operating +systems have no way to avoid them and even on those that have there are some +corner cases when they may still happen, contrary to our desire. In addition, +using *CURLAUTH_NTLM_WB* authentication could cause a SIGCHLD signal to be +raised. + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md new file mode 100644 index 0000000..f3e7ef8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md @@ -0,0 +1,92 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_OPENSOCKETDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CLOSESOCKETFUNCTION (3) + - CURLOPT_OPENSOCKETFUNCTION (3) + - CURLOPT_SOCKOPTFUNCTION (3) +--- + +# NAME + +CURLOPT_OPENSOCKETDATA - pointer passed to open socket callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_OPENSOCKETDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* that is untouched by libcurl and passed as the first +argument in the open socket callback set with +CURLOPT_OPENSOCKETFUNCTION(3). + +# DEFAULT + +The default value of this parameter is NULL. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +/* make libcurl use the already established socket 'sockfd' */ + +static curl_socket_t opensocket(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address) +{ + curl_socket_t sockfd; + sockfd = *(curl_socket_t *)clientp; + /* the actual externally set socket is passed in via the OPENSOCKETDATA + option */ + return sockfd; +} + +static int sockopt_callback(void *clientp, curl_socket_t curlfd, + curlsocktype purpose) +{ + /* This return code was added in libcurl 7.21.5 */ + return CURL_SOCKOPT_ALREADY_CONNECTED; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + extern int sockfd; /* the already connected one */ + + /* libcurl thinks that you connect to the host + * and port that you specify in the URL option. */ + curl_easy_setopt(curl, CURLOPT_URL, "http://99.99.99.99:9999"); + /* call this function to get a socket */ + curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket); + curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sockfd); + + /* call this function to set options for the socket */ + curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.17.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md new file mode 100644 index 0000000..125ccff --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md @@ -0,0 +1,132 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_OPENSOCKETFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CLOSESOCKETFUNCTION (3) + - CURLOPT_OPENSOCKETFUNCTION (3) + - CURLOPT_SOCKOPTFUNCTION (3) +--- + +# NAME + +CURLOPT_OPENSOCKETFUNCTION - callback for opening socket + +# SYNOPSIS + +~~~c +#include + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ +} curlsocktype; + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; + struct sockaddr addr; +}; + +curl_socket_t opensocket_callback(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_OPENSOCKETFUNCTION, opensocket_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl instead of the *socket(2)* +call. The callback's *purpose* argument identifies the exact purpose for +this particular socket. *CURLSOCKTYPE_IPCXN* is for IP based connections +and is the only purpose currently used in libcurl. Future versions of libcurl +may support more purposes. + +The *clientp* pointer contains whatever user-defined value set using the +CURLOPT_OPENSOCKETDATA(3) function. + +The callback gets the resolved peer address as the *address* argument and +is allowed to modify the address or refuse to connect completely. The callback +function should return the newly created socket or *CURL_SOCKET_BAD* in +case no connection could be established or another error was detected. Any +additional *setsockopt(2)* calls can of course be done on the socket at +the user's discretion. A *CURL_SOCKET_BAD* return value from the callback +function signals an unrecoverable error to libcurl and it returns +*CURLE_COULDNT_CONNECT* from the function that triggered this callback. +This return code can be used for IP address block listing. + +If you want to pass in a socket with an already established connection, pass +the socket back with this callback and then use +CURLOPT_SOCKOPTFUNCTION(3) to signal that it already is connected. + +# DEFAULT + +The default behavior is the equivalent of this: +~~~c + return socket(addr->family, addr->socktype, addr->protocol); +~~~ + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +/* make libcurl use the already established socket 'sockfd' */ + +static curl_socket_t opensocket(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address) +{ + curl_socket_t sockfd; + sockfd = *(curl_socket_t *)clientp; + /* the actual externally set socket is passed in via the OPENSOCKETDATA + option */ + return sockfd; +} + +static int sockopt_callback(void *clientp, curl_socket_t curlfd, + curlsocktype purpose) +{ + /* This return code was added in libcurl 7.21.5 */ + return CURL_SOCKOPT_ALREADY_CONNECTED; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + extern int sockfd; /* the already connected one */ + /* libcurl thinks that you connect to the host + * and port that you specify in the URL option. */ + curl_easy_setopt(curl, CURLOPT_URL, "http://99.99.99.99:9999"); + /* call this function to get a socket */ + curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket); + curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sockfd); + + /* call this function to set options for the socket */ + curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.17.1. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PASSWORD.md b/docs/libcurl/opts/CURLOPT_PASSWORD.md new file mode 100644 index 0000000..9849802 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PASSWORD.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PASSWORD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPAUTH (3) + - CURLOPT_PROXYAUTH (3) + - CURLOPT_USERNAME (3) + - CURLOPT_USERPWD (3) +--- + +# NAME + +CURLOPT_PASSWORD - password to use in authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PASSWORD, char *pwd); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be pointing to the +null-terminated password to use for the transfer. + +The CURLOPT_PASSWORD(3) option should be used in conjunction with the +CURLOPT_USERNAME(3) option. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +blank + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + curl_easy_setopt(curl, CURLOPT_PASSWORD, "qwerty"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md b/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md new file mode 100644 index 0000000..4994691 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PATH_AS_IS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_STDERR (3) + - CURLOPT_URL (3) + - curl_url_set (3) +--- + +# NAME + +CURLOPT_PATH_AS_IS - do not handle dot dot sequences + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PATH_AS_IS, long leaveit); +~~~ + +# DESCRIPTION + +Set the long *leaveit* to 1, to explicitly tell libcurl to not alter the +given path before passing it on to the server. + +This instructs libcurl to NOT squash sequences of "/../" or "/./" that may +exist in the URL's path part and that is supposed to be removed according to +RFC 3986 section 5.2.4. + +Some server implementations are known to (erroneously) require the dot dot +sequences to remain in the path and some clients want to pass these on in +order to try out server implementations. + +By default libcurl normalizes such sequences before using the path. + +The corresponding flag for the curl_url_set(3) function is called +**CURLU_PATH_AS_IS**. + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, + "https://example.com/../../etc/password"); + + curl_easy_setopt(curl, CURLOPT_PATH_AS_IS, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.42.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md new file mode 100644 index 0000000..922e2a6 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md @@ -0,0 +1,143 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PINNEDPUBLICKEY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_CAPATH (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PINNEDPUBLICKEY - pinned public key + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PINNEDPUBLICKEY, + char *pinnedpubkey); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string can be the +filename of your pinned public key. The file format expected is "PEM" or +"DER". The string can also be any number of base64 encoded sha256 hashes +preceded by "sha256//" and separated by ";" + +When negotiating a TLS or SSL connection, the server sends a certificate +indicating its identity. A public key is extracted from this certificate and +if it does not exactly match the public key provided to this option, curl +aborts the connection before sending or receiving any data. + +This option is independent of option CURLOPT_SSL_VERIFYPEER(3). If you turn +off that option then the peer is still verified by public key. + +On mismatch, *CURLE_SSL_PINNEDPUBKEYNOTMATCH* is returned. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY, "/etc/publickey.der"); + /* OR + curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY, + "sha256//YhKJKSzoTt2b5FP18fvpHo7fJYqQCjAa3HWY3" + "tvRMwE=;sha256//t62CeU2tQiqkexU74Gxa2eg7fRbEg" + "oChTociMee9wno="); + */ + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# PUBLIC KEY EXTRACTION + +If you do not have the server's public key file you can extract it from the +server's certificate. +~~~ +# retrieve the server's certificate if you do not already have it +# +# be sure to examine the certificate to see if it is what you expected +# +# Windows-specific: +# - Use NUL instead of /dev/null. +# - OpenSSL may wait for input instead of disconnecting. Hit enter. +# - If you do not have sed, then just copy the certificate into a file: +# Lines from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE-----. +# +openssl s_client -servername www.example.com -connect www.example.com:443 \ + < /dev/null | sed -n "/-----BEGIN/,/-----END/p" > www.example.com.pem + +# extract public key in pem format from certificate +openssl x509 -in www.example.com.pem -pubkey -noout > www.example.com.pubkey.pem + +# convert public key from pem to der +openssl asn1parse -noout -inform pem -in www.example.com.pubkey.pem \ + -out www.example.com.pubkey.der + +# sha256 hash and base64 encode der to string for use +openssl dgst -sha256 -binary www.example.com.pubkey.der | openssl base64 +~~~ + +The public key in PEM format contains a header, base64 data and a +footer: +~~~ +-----BEGIN PUBLIC KEY----- +[BASE 64 DATA] +-----END PUBLIC KEY----- +~~~ + +# AVAILABILITY + +## PEM/DER support + +7.39.0: OpenSSL, GnuTLS + +7.43.0: wolfSSL + +7.47.0: mbedTLS + +7.54.1: Secure Transport on macOS 10.7+/iOS 10+ + +7.58.1: Schannel + +## sha256 support + +7.44.0: OpenSSL, GnuTLS and wolfSSL + +7.47.0: mbedTLS + +7.54.1: Secure Transport on macOS 10.7+/iOS 10+ + +7.58.1: Schannel + +Other SSL backends not supported. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PIPEWAIT.md b/docs/libcurl/opts/CURLOPT_PIPEWAIT.md new file mode 100644 index 0000000..1be844d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PIPEWAIT.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PIPEWAIT +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_MAX_HOST_CONNECTIONS (3) + - CURLMOPT_PIPELINING (3) + - CURLOPT_FORBID_REUSE (3) + - CURLOPT_FRESH_CONNECT (3) +--- + +# NAME + +CURLOPT_PIPEWAIT - wait for multiplexing + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PIPEWAIT, long wait); +~~~ + +# DESCRIPTION + +Set *wait* to 1L to tell libcurl to prefer to wait for a connection to +confirm or deny that it can do multiplexing before continuing. + +When about to perform a new transfer that allows multiplexing, libcurl checks +for existing connections to use. If no such connection exists it immediately +continues and creates a fresh new connection to use. + +By setting this option to 1 - and having CURLMOPT_PIPELINING(3) enabled +for the multi handle this transfer is associated with - libcurl instead waits +for the connection to reveal if it is possible to multiplex on before it +continues. This enables libcurl to much better keep the number of connections +to a minimum when using multiplexing protocols. + +With this option set, libcurl prefers to wait and reuse an existing connection +for multiplexing rather than the opposite: prefer to open a new connection +rather than waiting. + +The waiting time is as long as it takes for the connection to get up and for +libcurl to get the necessary response back that informs it about its protocol +and support level. + +# DEFAULT + +0 (off) + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PIPEWAIT, 1L); + + /* now add this easy handle to the multi handle */ + } +} +~~~ + +# AVAILABILITY + +Added in 7.43.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PORT.md b/docs/libcurl/opts/CURLOPT_PORT.md new file mode 100644 index 0000000..42dc801 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PORT.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PORT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PRIMARY_PORT (3) + - CURLOPT_STDERR (3) + - CURLOPT_URL (3) +--- + +# NAME + +CURLOPT_PORT - remote port number to connect to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PORT, long number); +~~~ + +# DESCRIPTION + +We discourage using this option since its scope is not obvious and hard to +predict. Set the preferred port number in the URL instead. + +This option sets *number* to be the remote port number to connect to, +instead of the one specified in the URL or the default port for the used +protocol. + +Usually, you just let the URL decide which port to use but this allows the +application to override that. + +While this option accepts a 'long', a port number is an unsigned 16 bit number +and therefore using a port number lower than zero or over 65535 causes a +**CURLE_BAD_FUNCTION_ARGUMENT** error. + +# DEFAULT + +By default this is 0 which makes it not used. This also makes port number zero +impossible to set with this API. + +# PROTOCOLS + +Used for all protocols that speak to a port number. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_PORT, 8080L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_POST.md b/docs/libcurl/opts/CURLOPT_POST.md new file mode 100644 index 0000000..96fcd42 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_POST.md @@ -0,0 +1,102 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_POST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPPOST (3) + - CURLOPT_POSTFIELDS (3) + - CURLOPT_PUT (3) +--- + +# NAME + +CURLOPT_POST - make an HTTP POST + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POST, long post); +~~~ + +# DESCRIPTION + +A parameter set to 1 tells libcurl to do a regular HTTP post. This also makes +libcurl use a "Content-Type: application/x-www-form-urlencoded" header. This +is the most commonly used POST method. + +Use one of CURLOPT_POSTFIELDS(3) or CURLOPT_COPYPOSTFIELDS(3) +options to specify what data to post and CURLOPT_POSTFIELDSIZE(3) or +CURLOPT_POSTFIELDSIZE_LARGE(3) to set the data size. + +Optionally, you can provide data to POST using the +CURLOPT_READFUNCTION(3) and CURLOPT_READDATA(3) options but then +you must make sure to not set CURLOPT_POSTFIELDS(3) to anything but +NULL. When providing data with a callback, you must transmit it using chunked +transfer-encoding or you must set the size of the data with the +CURLOPT_POSTFIELDSIZE(3) or CURLOPT_POSTFIELDSIZE_LARGE(3) +options. To enable chunked encoding, you simply pass in the appropriate +Transfer-Encoding header, see the post-callback.c example. + +You can override the default POST Content-Type: header by setting your own +with CURLOPT_HTTPHEADER(3). + +Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. +You can disable this header with CURLOPT_HTTPHEADER(3) as usual. + +If you use POST to an HTTP 1.1 server, you can send data without knowing the +size before starting the POST if you use chunked encoding. You enable this by +adding a header like "Transfer-Encoding: chunked" with +CURLOPT_HTTPHEADER(3). With HTTP 1.0 or without chunked transfer, you +must specify the size in the request. (Since 7.66.0, libcurl automatically +uses chunked encoding for POSTs if the size is unknown.) + +When setting CURLOPT_POST(3) to 1, libcurl automatically sets +CURLOPT_NOBODY(3) and CURLOPT_HTTPGET(3) to 0. + +If you issue a POST request and then want to make a HEAD or GET using the same +reused handle, you must explicitly set the new request type using +CURLOPT_NOBODY(3) or CURLOPT_HTTPGET(3) or similar. + +When setting CURLOPT_POST(3) to 0, libcurl resets the request type to the +default to disable the POST. Typically that means gets reset to GET. Instead +you should set a new request type explicitly as described above. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + + /* set up the read callback with CURLOPT_READFUNCTION */ + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_POSTFIELDS.md b/docs/libcurl/opts/CURLOPT_POSTFIELDS.md new file mode 100644 index 0000000..409e410 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_POSTFIELDS.md @@ -0,0 +1,124 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_POSTFIELDS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_COPYPOSTFIELDS (3) + - CURLOPT_MIMEPOST (3) + - CURLOPT_POSTFIELDSIZE (3) + - CURLOPT_READFUNCTION (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_POSTFIELDS - data to POST to server + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTFIELDS, char *postdata); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, pointing to the data buffer to use in an +HTTP POST operation. The data must be formatted and encoded the way you want +the server to receive it. libcurl does not convert or encode it in any +way. For example, the web server may assume that this data is URL encoded. + +The data pointed to is NOT copied by the library: as a consequence, it must be +preserved by the calling application until the associated transfer finishes. +This behavior can be changed (so libcurl does copy the data) by instead using +the CURLOPT_COPYPOSTFIELDS(3) option. + +This POST is a normal **application/x-www-form-urlencoded** kind (and +libcurl sets that Content-Type by default when this option is used), which is +commonly used by HTML forms. Change Content-Type with +CURLOPT_HTTPHEADER(3). + +You can use curl_easy_escape(3) to URL encode your data, if +necessary. It returns a pointer to an encoded string that can be passed as +*postdata*. + +Using CURLOPT_POSTFIELDS(3) implies setting CURLOPT_POST(3) to 1. + +If CURLOPT_POSTFIELDS(3) is explicitly set to NULL then libcurl gets the +POST data from the read callback. If you want to send a zero-byte POST set +CURLOPT_POSTFIELDS(3) to an empty string, or set CURLOPT_POST(3) +to 1 and CURLOPT_POSTFIELDSIZE(3) to 0. + +libcurl assumes this option points to a null-terminated string unless you also +set CURLOPT_POSTFIELDSIZE(3) to specify the length of the provided data, +which then is strictly required if you want to send off null bytes included in +the data. + +Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header, +and libcurl adds that header automatically if the POST is either known to be +larger than 1MB or if the expected size is unknown. You can disable this +header with CURLOPT_HTTPHEADER(3) as usual. + +To make **multipart/formdata** posts, check out the +CURLOPT_MIMEPOST(3) option combined with curl_mime_init(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +/* send an application/x-www-form-urlencoded POST */ +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + const char *data = "data to send"; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* size of the POST data if strlen() is not good enough */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 12L); + + /* pass in a pointer to the data - libcurl does not copy */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + curl_easy_perform(curl); + } + + /* send an application/json POST */ + curl = curl_easy_init(); + if(curl) { + const char *json = "{\"name\": \"daniel\"}"; + struct curl_slist *slist1 = NULL; + slist1 = curl_slist_append(slist1, "Content-Type: application/json"); + slist1 = curl_slist_append(slist1, "Accept: application/json"); + + /* set custom headers */ + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1); + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* pass in a pointer to the data - libcurl does not copy */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md new file mode 100644 index 0000000..d086809 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_POSTFIELDSIZE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_POSTFIELDS (3) + - CURLOPT_POSTFIELDSIZE_LARGE (3) +--- + +# NAME + +CURLOPT_POSTFIELDSIZE - size of POST data pointed to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTFIELDSIZE, long size); +~~~ + +# DESCRIPTION + +If you want to post static data to the server without having libcurl do a +strlen() to measure the data size, this option must be used. When this option +is used you can post fully binary data, which otherwise is likely to fail. If +this size is set to -1, libcurl uses strlen() to get the size or relies on the +CURLOPT_READFUNCTION(3) (if used) to signal the end of data. + +If you post more than 2GB, use CURLOPT_POSTFIELDSIZE_LARGE(3). + +# DEFAULT + +-1 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +#include /* for strlen */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + const char *data = "data to send"; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* size of the POST data */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) strlen(data)); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md new file mode 100644 index 0000000..36fc0ff --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_POSTFIELDSIZE_LARGE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_COPYPOSTFIELDS (3) + - CURLOPT_POSTFIELDS (3) + - CURLOPT_POSTFIELDSIZE (3) +--- + +# NAME + +CURLOPT_POSTFIELDSIZE_LARGE - size of POST data pointed to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTFIELDSIZE_LARGE, + curl_off_t size); +~~~ + +# DESCRIPTION + +If you want to post static data to the server without having libcurl do a +strlen() to measure the data size, this option must be used. When this option +is used you can post fully binary data, which otherwise is likely to fail. If +this size is set to -1, libcurl uses strlen() to get the size or relies on the +CURLOPT_READFUNCTION(3) (if used) to signal the end of data. + +# DEFAULT + +-1 + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +extern char *large_chunk; /* pointer to somewhere */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + const char *data = large_chunk; + curl_off_t length_of_data; /* set somehow */ + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* size of the POST data */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, length_of_data); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_POSTQUOTE.md b/docs/libcurl/opts/CURLOPT_POSTQUOTE.md new file mode 100644 index 0000000..300a1f2 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_POSTQUOTE.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_POSTQUOTE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PREQUOTE (3) + - CURLOPT_QUOTE (3) +--- + +# NAME + +CURLOPT_POSTQUOTE - (S)FTP commands to run after the transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTQUOTE, + struct curl_slist *cmds); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of FTP or SFTP commands to pass to the server +after your FTP transfer request. The commands are only issues if no error +occur. The linked list should be a fully valid list of struct curl_slist +structs properly filled in as described for CURLOPT_QUOTE(3). + +Disable this operation again by setting a NULL to this option. + +# DEFAULT + +NULL + +# PROTOCOLS + +SFTP and FTP + +# EXAMPLE + +~~~c +int main(void) +{ + struct curl_slist *cmdlist = NULL; + cmdlist = curl_slist_append(cmdlist, "RNFR source-name"); + cmdlist = curl_slist_append(cmdlist, "RNTO new-name"); + + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin"); + + /* pass in the FTP commands to run after the transfer */ + curl_easy_setopt(curl, CURLOPT_POSTQUOTE, cmdlist); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If support for the protocols are built-in. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_POSTREDIR.md b/docs/libcurl/opts/CURLOPT_POSTREDIR.md new file mode 100644 index 0000000..0ca04a9 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_POSTREDIR.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_POSTREDIR +Section: 3 +Source: libcurl +See-also: + - CURLINFO_EFFECTIVE_METHOD (3) + - CURLINFO_REDIRECT_COUNT (3) + - CURLOPT_FOLLOWLOCATION (3) + - CURLOPT_MAXREDIRS (3) + - CURLOPT_POSTFIELDS (3) +--- + +# NAME + +CURLOPT_POSTREDIR - how to act on an HTTP POST redirect + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTREDIR, + long bitmask); +~~~ + +# DESCRIPTION + +Pass a bitmask to control how libcurl acts on redirects after POSTs that get a +301, 302 or 303 response back. A parameter with bit 0 set (value +**CURL_REDIR_POST_301**) tells the library to respect RFC 7231 (section +6.4.2 to 6.4.4) and not convert POST requests into GET requests when following +a 301 redirection. Setting bit 1 (value **CURL_REDIR_POST_302**) makes +libcurl maintain the request method after a 302 redirect whilst setting bit 2 +(value **CURL_REDIR_POST_303**) makes libcurl maintain the request method +after a 303 redirect. The value **CURL_REDIR_POST_ALL** is a convenience +define that sets all three bits. + +The non-RFC behavior is ubiquitous in web browsers, so the library does the +conversion by default to maintain consistency. However, a server may require a +POST to remain a POST after such a redirection. This option is meaningful only +when setting CURLOPT_FOLLOWLOCATION(3). + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP(S) + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* a silly POST example */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "data=true"); + + /* example.com is redirected, so we tell libcurl to send POST on 301, + 302 and 303 HTTP response codes */ + curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.17.1. This option was known as CURLOPT_POST301 up to 7.19.0 as it +only supported the 301 then. CURL_REDIR_POST_303 was added in 7.26.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PREQUOTE.md b/docs/libcurl/opts/CURLOPT_PREQUOTE.md new file mode 100644 index 0000000..e519203 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PREQUOTE.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PREQUOTE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_POSTQUOTE (3) + - CURLOPT_QUOTE (3) +--- + +# NAME + +CURLOPT_PREQUOTE - commands to run before an FTP transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PREQUOTE, + struct curl_slist *cmds); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of FTP commands to pass to the server after +the transfer type is set. The linked list should be a fully valid list of +struct curl_slist structs properly filled in as described for +CURLOPT_QUOTE(3). Disable this operation again by setting a NULL to this +option. + +These commands are not performed when a directory listing is performed, only +for file transfers. + +While CURLOPT_QUOTE(3) and CURLOPT_POSTQUOTE(3) work for SFTP, +this option does not. + +# DEFAULT + +NULL + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + struct curl_slist *cmdlist = NULL; + cmdlist = curl_slist_append(cmdlist, "SYST"); + + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin"); + + /* pass in the FTP commands to run */ + curl_easy_setopt(curl, CURLOPT_PREQUOTE, cmdlist); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Along with the protocol support + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PREREQDATA.md b/docs/libcurl/opts/CURLOPT_PREREQDATA.md new file mode 100644 index 0000000..14ba8e3 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PREREQDATA.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PREREQDATA +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PRIMARY_IP (3) + - CURLINFO_PRIMARY_PORT (3) + - CURLOPT_PREREQFUNCTION (3) +--- + +# NAME + +CURLOPT_PREREQDATA - pointer passed to the pre-request callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PREREQDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* that is untouched by libcurl and passed as the first +argument in the pre-request callback set with CURLOPT_PREREQFUNCTION(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static int prereq_callback(void *clientp, + char *conn_primary_ip, + char *conn_local_ip, + int conn_primary_port, + int conn_local_port) +{ + printf("Connection made to %s:%d\n", conn_primary_ip, conn_primary_port); + return CURL_PREREQFUNC_OK; +} + +int main(void) +{ + struct priv prereq_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, prereq_callback); + curl_easy_setopt(curl, CURLOPT_PREREQDATA, &prereq_data); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.80.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md b/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md new file mode 100644 index 0000000..c814084 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md @@ -0,0 +1,125 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PREREQFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PRIMARY_IP (3) + - CURLINFO_PRIMARY_PORT (3) + - CURLOPT_PREREQDATA (3) +--- + +# NAME + +CURLOPT_PREREQFUNCTION - user callback called when a connection has been +established, but before a request has been made. + +# SYNOPSIS + +~~~c +#include + +/* These are the return codes for the pre-request callback. */ +#define CURL_PREREQFUNC_OK 0 +#define CURL_PREREQFUNC_ABORT 1 /* fail the entire transfer */ + +int prereq_callback(void *clientp, + char *conn_primary_ip, + char *conn_local_ip, + int conn_primary_port, + int conn_local_port); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PREREQFUNCTION, prereq_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This function gets called by libcurl after a connection has been established +or a connection has been reused (including any SSL handshaking), but before any +request is actually made on the connection. For example, for HTTP, this +callback is called once a connection has been established to the server, but +before a GET/HEAD/POST/etc request has been sent. + +This function may be called multiple times if redirections are enabled and are +being followed (see CURLOPT_FOLLOWLOCATION(3)). + +The callback function must return *CURL_PREREQFUNC_OK* on success, or +*CURL_PREREQFUNC_ABORT* to cause the transfer to fail. + +This function is passed the following arguments: + +## conn_primary_ip + +A null-terminated pointer to a C string containing the primary IP of the +remote server established with this connection. For FTP, this is the IP for +the control connection. IPv6 addresses are represented without surrounding +brackets. + +## conn_local_ip + +A null-terminated pointer to a C string containing the originating IP for this +connection. IPv6 addresses are represented without surrounding brackets. + +## conn_primary_port + +The primary port number on the remote server established with this connection. +For FTP, this is the port for the control connection. This can be a TCP or a +UDP port number depending on the protocol. + +## conn_local_port + +The originating port number for this connection. This can be a TCP or a UDP +port number depending on the protocol. + +## clientp + +The pointer you set with CURLOPT_PREREQDATA(3). + +# DEFAULT + +By default, this is NULL and unused. + +# PROTOCOLS + +ALL + +# EXAMPLE + +~~~c +struct priv { + void *custom; +}; + +static int prereq_callback(void *clientp, + char *conn_primary_ip, + char *conn_local_ip, + int conn_primary_port, + int conn_local_port) +{ + printf("Connection made to %s:%d\n", conn_primary_ip, conn_primary_port); + return CURL_PREREQFUNC_OK; +} + +int main(void) +{ + struct priv prereq_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, prereq_callback); + curl_easy_setopt(curl, CURLOPT_PREREQDATA, &prereq_data); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.80.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PRE_PROXY.md b/docs/libcurl/opts/CURLOPT_PRE_PROXY.md new file mode 100644 index 0000000..1afe831 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PRE_PROXY.md @@ -0,0 +1,84 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PRE_PROXY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPPROXYTUNNEL (3) + - CURLOPT_PROXY (3) +--- + +# NAME + +CURLOPT_PRE_PROXY - pre-proxy host to use + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PRE_PROXY, char *preproxy); +~~~ + +# DESCRIPTION + +Set the *preproxy* to use for the upcoming request. The parameter should be a +char * to a null-terminated string holding the hostname or dotted numerical IP +address. A numerical IPv6 address must be written within [brackets]. + +To specify port number in this string, append :[port] to the end of the host +name. The proxy's port number may optionally be specified with the separate +option CURLOPT_PROXYPORT(3). If not specified, libcurl defaults to using +port 1080 for proxies. + +A pre proxy is a SOCKS proxy that curl connects to before it connects to the +HTTP(S) proxy specified in the CURLOPT_PROXY(3) option. The pre proxy +can only be a SOCKS proxy. + +The pre proxy string should be prefixed with [scheme]:// to specify which kind +of socks is used. Use socks4://, socks4a://, socks5:// or socks5h:// (the last +one to enable socks5 and asking the proxy to do the resolving, also known as +*CURLPROXY_SOCKS5_HOSTNAME* type) to request the specific SOCKS version to +be used. Otherwise SOCKS4 is used as default. + +Setting the pre proxy string to "" (an empty string) explicitly disables the +use of a pre proxy. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +Default is NULL, meaning no pre proxy is used. + +When you set a hostname to use, do not assume that there is any particular +single port number used widely for proxies. Specify it! + +# PROTOCOLS + +All except file://. Note that some protocols do not work well over proxy. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.txt"); + curl_easy_setopt(curl, CURLOPT_PRE_PROXY, "socks4://socks-proxy:1080"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80"); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PRIVATE.md b/docs/libcurl/opts/CURLOPT_PRIVATE.md new file mode 100644 index 0000000..571a681 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PRIVATE.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PRIVATE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PRIVATE (3) + - CURLOPT_STDERR (3) + - CURLOPT_VERBOSE (3) +--- + +# NAME + +CURLOPT_PRIVATE - store a private pointer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PRIVATE, void *pointer); +~~~ + +# DESCRIPTION + +Pass a void * as parameter, pointing to data that should be associated with +this curl handle. The pointer can subsequently be retrieved using +curl_easy_getinfo(3) with the CURLINFO_PRIVATE(3) option. libcurl itself +never does anything with this data. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct private { + void *custom; +}; + +int main(void) +{ + CURL *curl = curl_easy_init(); + struct private secrets; + if(curl) { + struct private *extracted; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* store a pointer to our private struct */ + curl_easy_setopt(curl, CURLOPT_PRIVATE, &secrets); + + curl_easy_perform(curl); + + /* we can extract the private pointer again too */ + curl_easy_getinfo(curl, CURLINFO_PRIVATE, &extracted); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.3 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md b/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md new file mode 100644 index 0000000..276bee8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROGRESSDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROGRESSFUNCTION (3) + - CURLOPT_XFERINFOFUNCTION (3) +--- + +# NAME + +CURLOPT_PROGRESSDATA - pointer passed to the progress callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROGRESSDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* that is untouched by libcurl and passed as the first +argument in the progress callback set with CURLOPT_PROGRESSFUNCTION(3). + +# DEFAULT + +The default value of this parameter is NULL. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct progress { + char *private; + size_t size; +}; + +static size_t progress_callback(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow) +{ + struct progress *memory = clientp; + printf("private: %p\n", memory->private); + + /* use the values */ + + return 0; /* all is good */ +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct progress data; + + /* pass struct to callback */ + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &data); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md b/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md new file mode 100644 index 0000000..19d84c8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md @@ -0,0 +1,125 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROGRESSFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_NOPROGRESS (3) + - CURLOPT_VERBOSE (3) + - CURLOPT_XFERINFOFUNCTION (3) +--- + +# NAME + +CURLOPT_PROGRESSFUNCTION - progress meter callback + +# SYNOPSIS + +~~~c +#include + +int progress_callback(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROGRESSFUNCTION, + progress_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This option is deprecated and we encourage users to use the +newer CURLOPT_XFERINFOFUNCTION(3) instead, if you can. + +This function gets called by libcurl instead of its internal equivalent with a +frequent interval. While data is being transferred it is invoked frequently, +and during slow periods like when nothing is being transferred it can slow +down to about one call per second. + +*clientp* is the pointer set with CURLOPT_PROGRESSDATA(3), it is not +used by libcurl but is only passed along from the application to the callback. + +The callback gets told how much data libcurl is about to transfer and has +transferred, in number of bytes. *dltotal* is the total number of bytes +libcurl expects to download in this transfer. *dlnow* is the number of +bytes downloaded so far. *ultotal* is the total number of bytes libcurl +expects to upload in this transfer. *ulnow* is the number of bytes +uploaded so far. + +Unknown/unused argument values passed to the callback are be set to zero (like +if you only download data, the upload size remains 0). Many times the callback +is called one or more times first, before it knows the data sizes so a program +must be made to handle that. + +If your callback function returns CURL_PROGRESSFUNC_CONTINUE it causes libcurl +to continue executing the default progress function. + +Returning any other non-zero value from this callback makes libcurl abort the +transfer and return *CURLE_ABORTED_BY_CALLBACK*. + +If you transfer data with the multi interface, this function is not called +during periods of idleness unless you call the appropriate libcurl function +that performs transfers. + +CURLOPT_NOPROGRESS(3) must be set to 0 to make this function actually +get called. + +# DEFAULT + +By default, libcurl has an internal progress meter. That is rarely wanted by +users. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct progress { + char *private; + size_t size; +}; + +static size_t progress_callback(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow) +{ + struct progress *memory = clientp; + printf("private: %p\n", memory->private); + + /* use the values */ + + return 0; /* all is good */ +} + +int main(void) +{ + struct progress data; + + CURL *curl = curl_easy_init(); + if(curl) { + /* pass struct to callback */ + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &data); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Deprecated since 7.32.0. + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_PROTOCOLS.md b/docs/libcurl/opts/CURLOPT_PROTOCOLS.md new file mode 100644 index 0000000..a4d1a5a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROTOCOLS.md @@ -0,0 +1,104 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROTOCOLS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEFAULT_PROTOCOL (3) + - CURLOPT_REDIR_PROTOCOLS (3) + - CURLOPT_URL (3) +--- + +# NAME + +CURLOPT_PROTOCOLS - allowed protocols + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROTOCOLS, long bitmask); +~~~ + +# DESCRIPTION + +This option is deprecated. We strongly recommend using +CURLOPT_PROTOCOLS_STR(3) instead because this option cannot control all +available protocols! + +Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask +limits what protocols libcurl may use in the transfer. This allows you to have +a libcurl built to support a wide range of protocols but still limit specific +transfers to only be allowed to use a subset of them. By default libcurl +accepts all protocols it supports (*CURLPROTO_ALL*). See also +CURLOPT_REDIR_PROTOCOLS(3). + +These are the available protocol defines: +~~~c +CURLPROTO_DICT +CURLPROTO_FILE +CURLPROTO_FTP +CURLPROTO_FTPS +CURLPROTO_GOPHER +CURLPROTO_HTTP +CURLPROTO_HTTPS +CURLPROTO_IMAP +CURLPROTO_IMAPS +CURLPROTO_LDAP +CURLPROTO_LDAPS +CURLPROTO_POP3 +CURLPROTO_POP3S +CURLPROTO_RTMP +CURLPROTO_RTMPE +CURLPROTO_RTMPS +CURLPROTO_RTMPT +CURLPROTO_RTMPTE +CURLPROTO_RTMPTS +CURLPROTO_RTSP +CURLPROTO_SCP +CURLPROTO_SFTP +CURLPROTO_SMB +CURLPROTO_SMBS +CURLPROTO_SMTP +CURLPROTO_SMTPS +CURLPROTO_TELNET +CURLPROTO_TFTP +~~~ + +# DEFAULT + +All protocols built-in. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(int argc, char **argv) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* pass in the URL from an external source */ + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + + /* only allow HTTP, TFTP and SFTP */ + curl_easy_setopt(curl, CURLOPT_PROTOCOLS, + CURLPROTO_HTTP | CURLPROTO_TFTP | CURLPROTO_SFTP); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.4. Deprecated since 7.85.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md b/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md new file mode 100644 index 0000000..9da056d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md @@ -0,0 +1,88 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROTOCOLS_STR +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SCHEME (3) + - CURLOPT_DEFAULT_PROTOCOL (3) + - CURLOPT_REDIR_PROTOCOLS_STR (3) + - CURLOPT_URL (3) + - curl_version_info (3) +--- + +# NAME + +CURLOPT_PROTOCOLS_STR - allowed protocols + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROTOCOLS_STR, char *spec); +~~~ + +# DESCRIPTION + +Pass a pointer to a string that holds a comma-separated list of case +insensitive protocol names (URL schemes) to allow in the transfer. This +option allows applications to use libcurl built to support a wide range of +protocols but still limit specific transfers to only be allowed to use a +subset of them. By default, libcurl accepts all protocols it was built with +support for. See also CURLOPT_REDIR_PROTOCOLS_STR(3). + +If trying to set a non-existing protocol or if no matching protocol at all is +set, it returns error. + +These are the available protocols: + +DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, +MQTT, POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, SCP, SFTP, +SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, WSS + +You can set "ALL" as a short-cut to enable all protocols. Note that by setting +all, you may enable protocols that were not supported the day you write this +but are introduced in a future libcurl version. + +curl_version_info(3) can be used to get a list of all supported +protocols in the current libcurl. CURLINFO_SCHEME(3) is the recommended +way to figure out the protocol used in a previous transfer. + +# DEFAULT + +All protocols built-in + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(int argc, char **argv) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* pass in the URL from an external source */ + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + + /* only allow HTTP, TFTP and SFTP */ + curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,tftp,sftp"); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.85.0 + +# RETURN VALUE + +Returns CURLE_UNKNOWN_OPTION if the option is not implemented, +CURLE_UNSUPPORTED_PROTOCOL if a listed protocol is not supported or disabled, +CURLE_BAD_FUNCTION_ARGUMENT if no protocol is listed else CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_PROXY.md b/docs/libcurl/opts/CURLOPT_PROXY.md new file mode 100644 index 0000000..89c22df --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY.md @@ -0,0 +1,146 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPPROXYTUNNEL (3) + - CURLOPT_PRE_PROXY (3) + - CURLOPT_PROXYPORT (3) + - CURLOPT_PROXYTYPE (3) +--- + +# NAME + +CURLOPT_PROXY - proxy to use + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY, char *proxy); +~~~ + +# DESCRIPTION + +Set the *proxy* to use for transfers with this easy handle. The parameter +should be a char * to a null-terminated string holding the hostname or dotted +numerical IP address. A numerical IPv6 address must be written within +[brackets]. + +To specify port number in this string, append :[port] to the end of the host +name. The proxy's port number may optionally (but discouraged) be specified +with the separate option CURLOPT_PROXYPORT(3). If not specified, libcurl +defaults to using port 1080 for proxies. + +The proxy string may be prefixed with [scheme]:// to specify which kind of +proxy is used. + +## http:// + +HTTP Proxy. Default when no scheme or proxy type is specified. + +## https:// + +HTTPS Proxy. (Added in 7.52.0 for OpenSSL and GnuTLS Since 7.87.0, it +also works for BearSSL, mbedTLS, rustls, Schannel, Secure Transport and +wolfSSL.) + +This uses HTTP/1 by default. Setting CURLOPT_PROXYTYPE(3) to +**CURLPROXY_HTTPS2** allows libcurl to negotiate using HTTP/2 with proxy. + +## socks4:// + +SOCKS4 Proxy. + +## socks4a:// + +SOCKS4a Proxy. Proxy resolves URL hostname. + +## socks5:// + +SOCKS5 Proxy. + +## socks5h:// + +SOCKS5 Proxy. Proxy resolves URL hostname. + +Without a scheme prefix, CURLOPT_PROXYTYPE(3) can be used to specify +which kind of proxy the string identifies. + +When you tell the library to use an HTTP proxy, libcurl transparently converts +operations to HTTP even if you specify an FTP URL etc. This may have an impact +on what other features of the library you can use, such as +CURLOPT_QUOTE(3) and similar FTP specifics that do not work unless you +tunnel through the HTTP proxy. Such tunneling is activated with +CURLOPT_HTTPPROXYTUNNEL(3). + +Setting the proxy string to "" (an empty string) explicitly disables the use +of a proxy, even if there is an environment variable set for it. + +A proxy host string can also include protocol scheme (http://) and embedded +user + password. + +Unix domain sockets are supported for socks proxies since 7.84.0. Set +localhost for the host part. e.g. socks5h://localhost/path/to/socket.sock + +The application does not have to keep the string around after setting this +option. + +When a proxy is used, the active FTP mode as set with *CUROPT_FTPPORT(3)*, +cannot be used. + +# Environment variables + +libcurl respects the proxy environment variables named **http_proxy**, +**ftp_proxy**, **sftp_proxy** etc. If set, libcurl uses the specified proxy +for that URL scheme. For an "FTP://" URL, the **ftp_proxy** is +considered. **all_proxy** is used if no protocol specific proxy was set. + +If **no_proxy** (or **NO_PROXY**) is set, it is the exact equivalent of +setting the CURLOPT_NOPROXY(3) option. + +The CURLOPT_PROXY(3) and CURLOPT_NOPROXY(3) options override environment +variables. + +# DEFAULT + +Default is NULL, meaning no proxy is used. + +When you set a hostname to use, do not assume that there is any particular +single port number used widely for proxies. Specify it! + +# PROTOCOLS + +All except file://. Note that some protocols do not work well over proxy. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.txt"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80"); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Since 7.14.1 the proxy environment variable names can include the protocol +scheme. + +Since 7.21.7 the proxy string supports the socks protocols as "schemes". + +Since 7.50.2, unsupported schemes in proxy strings cause libcurl to return +error. + +# RETURN VALUE + +Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXYAUTH.md b/docs/libcurl/opts/CURLOPT_PROXYAUTH.md new file mode 100644 index 0000000..8e6dc09 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXYAUTH.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXYAUTH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPAUTH (3) + - CURLOPT_PROXY (3) + - CURLOPT_PROXYPORT (3) + - CURLOPT_PROXYTYPE (3) + - CURLOPT_PROXYUSERPWD (3) +--- + +# NAME + +CURLOPT_PROXYAUTH - HTTP proxy authentication methods + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYAUTH, long bitmask); +~~~ + +# DESCRIPTION + +Pass a long as parameter, which is set to a bitmask, to tell libcurl which +HTTP authentication method(s) you want it to use for your proxy +authentication. If more than one bit is set, libcurl first queries the site to +see what authentication methods it supports and then it picks the best one you +allow it to use. For some methods, this induces an extra network round-trip. +Set the actual name and password with the CURLOPT_PROXYUSERPWD(3) +option. + +The bitmask can be constructed by the bits listed and described in the +CURLOPT_HTTPAUTH(3) man page. + +# DEFAULT + +CURLAUTH_BASIC + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* use this proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "http://local.example.com:1080"); + /* allow whatever auth the proxy speaks */ + curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + /* set the proxy credentials */ + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "james:007"); + ret = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.7 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_NOT_BUILT_IN if the bitmask specified no supported authentication +methods. diff --git a/docs/libcurl/opts/CURLOPT_PROXYHEADER.md b/docs/libcurl/opts/CURLOPT_PROXYHEADER.md new file mode 100644 index 0000000..e44afdd --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXYHEADER.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXYHEADER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADEROPT (3) + - CURLOPT_HTTPHEADER (3) +--- + +# NAME + +CURLOPT_PROXYHEADER - set of HTTP headers to pass to proxy + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYHEADER, + struct curl_slist *headers); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of HTTP headers to pass in your HTTP request +sent to a proxy. The rules for this list is identical to the +CURLOPT_HTTPHEADER(3) option's. + +The headers set with this option is only ever used in requests sent to a proxy +- when there is also a request sent to a host. + +The first line in a request (containing the method, usually a GET or POST) is +NOT a header and cannot be replaced using this option. Only the lines +following the request-line are headers. Adding this method line in this list +of headers causes your request to send an invalid header. + +Pass a NULL to this to reset back to no custom headers. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + + struct curl_slist *list; + + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy.example.com:80"); + + list = curl_slist_append(NULL, "Shoesize: 10"); + list = curl_slist_append(list, "Accept:"); + + curl_easy_setopt(curl, CURLOPT_PROXYHEADER, list); + + curl_easy_perform(curl); + + curl_slist_free_all(list); /* free the list again */ + } +} +~~~ + +# AVAILABILITY + +Added in 7.37.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md b/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md new file mode 100644 index 0000000..22520ea --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXYPASSWORD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPAUTH (3) + - CURLOPT_PASSWORD (3) + - CURLOPT_PROXYAUTH (3) + - CURLOPT_PROXYUSERNAME (3) +--- + +# NAME + +CURLOPT_PROXYPASSWORD - password to use with proxy authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYPASSWORD, char *pwd); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be pointing to the null-terminated +password to use for authentication with the proxy. + +The CURLOPT_PROXYPASSWORD(3) option should be used in conjunction with +the CURLOPT_PROXYUSERNAME(3) option. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +blank + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080"); + curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, "mrsmith"); + curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, "qwerty"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXYPORT.md b/docs/libcurl/opts/CURLOPT_PROXYPORT.md new file mode 100644 index 0000000..0cda8bb --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXYPORT.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXYPORT +Section: 3 +Source: libcurl +See-also: + - CURLINFO_PRIMARY_PORT (3) + - CURLOPT_PORT (3) + - CURLOPT_PROXY (3) + - CURLOPT_PROXYTYPE (3) +--- + +# NAME + +CURLOPT_PROXYPORT - port number the proxy listens on + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYPORT, long port); +~~~ + +# DESCRIPTION + +We discourage use of this option. + +Pass a long with this option to set the proxy port to connect to unless it is +specified in the proxy string CURLOPT_PROXY(3) or uses 443 for https +proxies and 1080 for all others as default. + +While this accepts a 'long', the port number is 16 bit so it cannot be larger +than 65535. + +# DEFAULT + +0, not specified which makes it use the default port + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_PROXY, "localhost"); + curl_easy_setopt(curl, CURLOPT_PROXYPORT, 8080L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_PROXYTYPE.md b/docs/libcurl/opts/CURLOPT_PROXYTYPE.md new file mode 100644 index 0000000..4f06fe5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXYTYPE.md @@ -0,0 +1,99 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXYTYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYPORT (3) +--- + +# NAME + +CURLOPT_PROXYTYPE - proxy protocol type + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYTYPE, long type); +~~~ + +# DESCRIPTION + +Pass one of the values below to set the type of the proxy. + +## CURLPROXY_HTTP + +HTTP Proxy. Default. + +## CURLPROXY_HTTPS + +HTTPS Proxy using HTTP/1. (Added in 7.52.0 for OpenSSL and GnuTLS. Since +7.87.0, it also works for BearSSL, mbedTLS, rustls, Schannel, Secure Transport +and wolfSSL.) + +## CURLPROXY_HTTPS2 + +HTTPS Proxy and attempt to speak HTTP/2 over it. (Added in 8.1.0) + +## CURLPROXY_HTTP_1_0 + +HTTP 1.0 Proxy. This is similar to CURLPROXY_HTTP except it uses HTTP/1.0 for +any CONNECT tunneling. It does not change the HTTP version of the actual HTTP +requests, controlled by CURLOPT_HTTP_VERSION(3). + +## CURLPROXY_SOCKS4 + +SOCKS4 Proxy. + +## CURLPROXY_SOCKS4A + +SOCKS4a Proxy. Proxy resolves URL hostname. + +## CURLPROXY_SOCKS5 + +SOCKS5 Proxy. + +## CURLPROXY_SOCKS5_HOSTNAME + +SOCKS5 Proxy. Proxy resolves URL hostname. + +Often it is more convenient to specify the proxy type with the scheme part of +the CURLOPT_PROXY(3) string. + +# DEFAULT + +CURLPROXY_HTTP + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "local.example.com:1080"); + /* set the proxy type */ + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + ret = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md b/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md new file mode 100644 index 0000000..f0d1dfc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXYUSERNAME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPAUTH (3) + - CURLOPT_PROXYAUTH (3) + - CURLOPT_PROXYPASSWORD (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_PROXYUSERNAME - user name to use for proxy authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYUSERNAME, + char *username); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be pointing to the +null-terminated user name to use for the transfer. + +CURLOPT_PROXYUSERNAME(3) sets the user name to be used in protocol +authentication with the proxy. + +To specify the proxy password use the CURLOPT_PROXYPASSWORD(3). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +blank + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080"); + curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, "mrsmith"); + curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, "qwerty"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md b/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md new file mode 100644 index 0000000..196d587 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXYUSERPWD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYPASSWORD (3) + - CURLOPT_PROXYTYPE (3) + - CURLOPT_PROXYUSERNAME (3) +--- + +# NAME + +CURLOPT_PROXYUSERPWD - user name and password to use for proxy authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYUSERPWD, char *userpwd); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be [user name]:[password] to +use for the connection to the HTTP proxy. Both the name and the password are +URL decoded before used, so to include for example a colon in the user name +you should encode it as %3A. (This is different to how CURLOPT_USERPWD(3) is +used - beware.) + +Use CURLOPT_PROXYAUTH(3) to specify the authentication method. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +This is NULL by default. + +# PROTOCOLS + +Used with all protocols that can use a proxy + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080"); + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "clark%20kent:superman"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md new file mode 100644 index 0000000..473083f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md @@ -0,0 +1,93 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_CAINFO +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_CAINFO_BLOB (3) + - CURLOPT_CAPATH (3) + - CURLOPT_PROXY_CAINFO_BLOB (3) + - CURLOPT_PROXY_CAPATH (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_CAINFO - path to proxy Certificate Authority (CA) bundle + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CAINFO, char *path); +~~~ + +# DESCRIPTION + +This option is for connecting to an HTTPS proxy, not an HTTPS server. + +Pass a char pointer to a null-terminated string naming a file holding one or +more certificates to verify the HTTPS proxy with. + +If CURLOPT_PROXY_SSL_VERIFYPEER(3) is zero and you avoid verifying the +server's certificate, CURLOPT_PROXY_CAINFO(3) need not even indicate an +accessible file. + +This option is by default set to the system path where libcurl's CA +certificate bundle is assumed to be stored, as established at build time. + +(iOS and macOS only) If curl is built against Secure Transport, then this +option is supported for backward compatibility with other SSL engines, but it +should not be set. If the option is not set, then curl uses the certificates +in the system and user Keychain to verify the peer, which is the preferred +method of verifying the peer's certificate chain. + +The application does not have to keep the string around after setting this +option. + +The default value for this can be figured out with CURLINFO_CAINFO(3). + +# DEFAULT + +Built-in system specific + +# PROTOCOLS + +Used with HTTPS proxy + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* using an HTTPS proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443"); + curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO, "/etc/certs/cabundle.pem"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +For TLS backends that do not support certificate files, the +CURLOPT_PROXY_CAINFO(3) option is ignored. Refer to +https://curl.se/docs/ssl-compared.html + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md new file mode 100644 index 0000000..bbf30cb --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md @@ -0,0 +1,92 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_CAINFO_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_CAINFO_BLOB (3) + - CURLOPT_CAPATH (3) + - CURLOPT_PROXY_CAINFO (3) + - CURLOPT_PROXY_CAPATH (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_CAINFO_BLOB - proxy Certificate Authority (CA) bundle in PEM format + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CAINFO_BLOB, + struct curl_blob *stblob); +~~~ + +# DESCRIPTION + +This option is for connecting to an HTTPS proxy, not an HTTPS server. + +Pass a pointer to a curl_blob structure, which contains information (pointer +and size) about a memory block with binary data of PEM encoded content holding +one or more certificates to verify the HTTPS proxy with. + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +If CURLOPT_PROXY_SSL_VERIFYPEER(3) is zero and you avoid verifying the +server's certificate, CURLOPT_PROXY_CAINFO_BLOB(3) is not needed. + +This option overrides CURLOPT_PROXY_CAINFO(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +Used with HTTPS proxy + +# EXAMPLE + +~~~c +#include /* for strlen */ + +extern char *strpem; /* strpem must point to a PEM string */ +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* using an HTTPS proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443"); + blob.data = strpem; + blob.len = strlen(strpem); + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.77.0. + +This option is supported by the rustls (since 7.82.0), OpenSSL, Secure +Transport and Schannel backends. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md b/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md new file mode 100644 index 0000000..2253c9f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_CAPATH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_PROXY_CAINFO (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_PROXY_CAPATH - directory holding HTTPS proxy CA certificates + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CAPATH, char *capath); +~~~ + +# DESCRIPTION + +Pass a char pointer to a null-terminated string naming a directory holding +multiple CA certificates to verify the HTTPS proxy with. If libcurl is built +against OpenSSL, the certificate directory must be prepared using the OpenSSL +**c_rehash** utility. This makes sense only when +CURLOPT_PROXY_SSL_VERIFYPEER(3) is enabled (which it is by default). + +The application does not have to keep the string around after setting this +option. + +The default value for this can be figured out with CURLINFO_CAPATH(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +Everything used over an HTTPS proxy + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* using an HTTPS proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443"); + curl_easy_setopt(curl, CURLOPT_PROXY_CAPATH, "/etc/cert-dir"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +This option is supported by the OpenSSL, GnuTLS, and mbedTLS (since 7.56.0) +backends. + +# RETURN VALUE + +CURLE_OK if supported; or an error such as: + +CURLE_NOT_BUILT_IN - Not supported by the SSL backend + +CURLE_UNKNOWN_OPTION + +CURLE_OUT_OF_MEMORY diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md b/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md new file mode 100644 index 0000000..d12c298 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_CRLFILE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_CRLFILE - HTTPS proxy Certificate Revocation List file + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CRLFILE, char *file); +~~~ + +# DESCRIPTION + +This option is for connecting to an HTTPS proxy, not an HTTPS server. + +Pass a char pointer to a null-terminated string naming a *file* with the +concatenation of CRL (in PEM format) to use in the certificate validation that +occurs during the SSL exchange. + +When curl is built to use GnuTLS, there is no way to influence the use of CRL +passed to help in the verification process. When libcurl is built with OpenSSL +support, X509_V_FLAG_CRL_CHECK and X509_V_FLAG_CRL_CHECK_ALL are both set, +requiring CRL check against all the elements of the certificate chain if a CRL +file is passed. + +This option makes sense only when used in combination with the +CURLOPT_PROXY_SSL_VERIFYPEER(3) option. + +A specific error code (*CURLE_SSL_CRL_BADFILE*) is defined with the option. It +is returned when the SSL exchange fails because the CRL file cannot be loaded. +A failure in certificate verification due to a revocation information found in +the CRL does not trigger this specific error. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +Used with HTTPS proxy. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:80"); + curl_easy_setopt(curl, CURLOPT_PROXY_CRLFILE, "/etc/certs/crl.pem"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md new file mode 100644 index 0000000..3b289d2 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_ISSUERCERT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ISSUERCERT (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_ISSUERCERT - proxy issuer SSL certificate filename + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_ISSUERCERT, char *file); +~~~ + +# DESCRIPTION + +Pass a char pointer to a null-terminated string naming a *file* holding a CA +certificate in PEM format. If the option is set, an additional check against +the peer certificate is performed to verify the issuer of the HTTPS proxy is +indeed the one associated with the certificate provided by the option. This +additional check is useful in multi-level PKI where one needs to enforce that +the peer certificate is from a specific branch of the tree. + +This option makes sense only when used in combination with the +CURLOPT_PROXY_SSL_VERIFYPEER(3) option. Otherwise, the result of the +check is not considered as failure. + +A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option, +which is returned if the setup of the SSL/TLS session has failed due to a +mismatch with the issuer of peer certificate +(CURLOPT_PROXY_SSL_VERIFYPEER(3) has to be set too for the check to +fail). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* using an HTTPS proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443"); + curl_easy_setopt(curl, CURLOPT_PROXY_ISSUERCERT, "/etc/certs/cacert.pem"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.71.0. This option is supported by the OpenSSL backends. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md new file mode 100644 index 0000000..ddd8cf5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md @@ -0,0 +1,95 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_ISSUERCERT_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ISSUERCERT_BLOB (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_ISSUERCERT_BLOB - proxy issuer SSL certificate from memory blob + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_ISSUERCERT_BLOB, + struct curl_blob *blob); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_blob struct, which contains information (pointer and +size) about a memory block with binary data of a CA certificate in PEM +format. If the option is set, an additional check against the peer certificate +is performed to verify the issuer of the HTTPS proxy is indeed the one +associated with the certificate provided by the option. This additional check +is useful in multi-level PKI where one needs to enforce that the peer +certificate is from a specific branch of the tree. + +This option should be used in combination with the +CURLOPT_PROXY_SSL_VERIFYPEER(3) option. Otherwise, the result of the +check is not considered as failure. + +A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option, +which is returned if the setup of the SSL/TLS session has failed due to a +mismatch with the issuer of peer certificate +(CURLOPT_PROXY_SSL_VERIFYPEER(3) has to be set too for the check to fail). + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +This option is an alternative to CURLOPT_PROXY_ISSUERCERT(3) which +instead expects a filename as input. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c + +extern char *certificateData; /* point to the data */ +size_t filesize; /* size of the data */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* using an HTTPS proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443"); + blob.data = certificateData; + blob.len = filesize; + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_PROXY_ISSUERCERT_BLOB, &blob); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.71.0. This option is supported by the OpenSSL backends. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md b/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md new file mode 100644 index 0000000..b29d95f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_KEYPASSWD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_KEYPASSWD (3) + - CURLOPT_PROXY_SSLKEY (3) + - CURLOPT_SSH_PRIVATE_KEYFILE (3) + - CURLOPT_SSLKEY (3) +--- + +# NAME + +CURLOPT_PROXY_KEYPASSWD - passphrase for the proxy private key + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_KEYPASSWD, char *pwd); +~~~ + +# DESCRIPTION + +This option is for connecting to an HTTPS proxy, not an HTTPS server. + +Pass a pointer to a null-terminated string as parameter. It is used as the +password required to use the CURLOPT_PROXY_SSLKEY(3) private key. You +never need a pass phrase to load a certificate but you need one to load your +private key. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +Used with HTTPS proxy + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy:443"); + curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "superman"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md b/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md new file mode 100644 index 0000000..4db1365 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md @@ -0,0 +1,124 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_PINNEDPUBLICKEY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PINNEDPUBLICKEY (3) + - CURLOPT_PROXY_CAINFO (3) + - CURLOPT_PROXY_CAPATH (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_PINNEDPUBLICKEY - pinned public key for https proxy + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_PINNEDPUBLICKEY, + char *pinnedpubkey); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string can be the +filename of your pinned public key. The file format expected is "PEM" or +"DER". The string can also be any number of base64 encoded sha256 hashes +preceded by "sha256//" and separated by ";" + +When negotiating a TLS or SSL connection, the https proxy sends a certificate +indicating its identity. A public key is extracted from this certificate and +if it does not exactly match the public key provided to this option, libcurl +aborts the connection before sending or receiving any data. + +On mismatch, *CURLE_SSL_PINNEDPUBKEYNOTMATCH* is returned. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy:443"); + curl_easy_setopt(curl, CURLOPT_PROXY_PINNEDPUBLICKEY, + "sha256//YhKJKSzoTt2b5FP18fvpHo7fJYqQCjA" + "a3HWY3tvRMwE=;sha256//t62CeU2tQiqkexU74" + "Gxa2eg7fRbEgoChTociMee9wno="); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# PUBLIC KEY EXTRACTION + +If you do not have the https proxy server's public key file you can extract it +from the https proxy server's certificate. +~~~c +# retrieve the server's certificate if you do not already have it +# +# be sure to examine the certificate to see if it is what you expected +# +# Windows-specific: +# - Use NUL instead of /dev/null. +# - OpenSSL may wait for input instead of disconnecting. Hit enter. +# - If you do not have sed, then just copy the certificate into a file: +# Lines from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE-----. +# +openssl s_client -servername www.example.com -connect www.example.com:443 \ + < /dev/null | sed -n "/-----BEGIN/,/-----END/p" > www.example.com.pem + +# extract public key in pem format from certificate +openssl x509 -in www.example.com.pem -pubkey -noout > www.example.com.pubkey.pem + +# convert public key from pem to der +openssl asn1parse -noout -inform pem -in www.example.com.pubkey.pem \ + -out www.example.com.pubkey.der + +# sha256 hash and base64 encode der to string for use +openssl dgst -sha256 -binary www.example.com.pubkey.der | openssl base64 +~~~ +The public key in PEM format contains a header, base64 data and a +footer: +~~~c +-----BEGIN PUBLIC KEY----- +[BASE 64 DATA] +-----END PUBLIC KEY----- +~~~ + +# AVAILABILITY + +PEM/DER support: + + 7.52.0: GnuTLS, OpenSSL, mbedTLS, wolfSSL + +sha256 support: + + 7.52.0: GnuTLS, OpenSSL, mbedTLS, wolfSSL + +Other SSL backends not supported. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md b/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md new file mode 100644 index 0000000..73e5cb7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SERVICE_NAME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYTYPE (3) + - CURLOPT_SERVICE_NAME (3) +--- + +# NAME + +CURLOPT_PROXY_SERVICE_NAME - proxy authentication service name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SERVICE_NAME, + char *name); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter to a string holding the *name* of the +service. The default service name is **"HTTP"** for HTTP based proxies and +**"rcmd"** for SOCKS5. This option allows you to change it. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +See above + +# PROTOCOLS + +All network protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY_SERVICE_NAME, "custom"); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.43.0 for HTTP proxies, 7.49.0 for SOCKS5 proxies. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md new file mode 100644 index 0000000..debc7ea --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md @@ -0,0 +1,79 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSLCERT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLCERTTYPE (3) + - CURLOPT_PROXY_SSLKEY (3) + - CURLOPT_SSLCERT (3) +--- + +# NAME + +CURLOPT_PROXY_SSLCERT - HTTPS proxy client certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLCERT, char *cert); +~~~ + +# DESCRIPTION + +This option is for connecting to an HTTPS proxy, not an HTTPS server. + +Pass a pointer to a null-terminated string as parameter. The string should be +the filename of your client certificate used to connect to the HTTPS proxy. +The default format is "P12" on Secure Transport and "PEM" on other engines, +and can be changed with CURLOPT_PROXY_SSLCERTTYPE(3). + +With Secure Transport, this can also be the nickname of the certificate you +wish to authenticate with as it is named in the security database. If you want +to use a file from the current directory, please precede it with "./" prefix, +in order to avoid confusion with a nickname. + +When using a client certificate, you most likely also need to provide a +private key with CURLOPT_PROXY_SSLKEY(3). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +Used with HTTPS proxy + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md new file mode 100644 index 0000000..ce6c508 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSLCERTTYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLCERT (3) + - CURLOPT_PROXY_SSLKEY (3) + - CURLOPT_SSLCERTTYPE (3) +--- + +# NAME + +CURLOPT_PROXY_SSLCERTTYPE - type of the proxy client SSL certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLCERTTYPE, char *type); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the format of your client certificate used when connecting to an HTTPS proxy. + +Supported formats are "PEM" and "DER", except with Secure Transport or +Schannel. OpenSSL (versions 0.9.3 and later), Secure Transport (on iOS 5 or +later, or OS X 10.7 or later) and Schannel support "P12" for PKCS#12-encoded +files. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +"PEM" + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERTTYPE, "PEM"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md new file mode 100644 index 0000000..e880d38 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md @@ -0,0 +1,85 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSLCERT_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLCERT (3) + - CURLOPT_PROXY_SSLCERTTYPE (3) + - CURLOPT_PROXY_SSLKEY (3) + - CURLOPT_SSLCERT_BLOB (3) +--- + +# NAME + +CURLOPT_PROXY_SSLCERT_BLOB - SSL proxy client certificate from memory blob + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLCERT_BLOB, + struct curl_blob *blob); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_blob structure, which contains information (pointer +and size) about a memory block with binary data of the certificate used to +connect to the HTTPS proxy. The format must be "P12" on Secure Transport or +Schannel. The format must be "P12" or "PEM" on OpenSSL. The string "P12" or +"PEM" must be specified with CURLOPT_PROXY_SSLCERTTYPE(3). + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +This option is an alternative to CURLOPT_PROXY_SSLCERT(3) which instead +expects a filename as input. + +# DEFAULT + +NULL + +# PROTOCOLS + +Used with HTTPS proxy + +# EXAMPLE + +~~~c + +extern char *certificateData; /* point to data */ +extern size_t filesize; /* size of the data */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob blob; + blob.data = certificateData; + blob.len = filesize; + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT_BLOB, &blob); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.71.0. This option is supported by the OpenSSL, Secure Transport and +Schannel backends. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md new file mode 100644 index 0000000..c8400db --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSLKEY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLCERT (3) + - CURLOPT_PROXY_SSLKEYTYPE (3) + - CURLOPT_SSLCERT (3) + - CURLOPT_SSLKEY (3) + - CURLOPT_SSLKEYTYPE (3) +--- + +# NAME + +CURLOPT_PROXY_SSLKEY - private key file for HTTPS proxy client cert + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLKEY, char *keyfile); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the filename of your private key used for connecting to the HTTPS proxy. The +default format is "PEM" and can be changed with +CURLOPT_PROXY_SSLKEYTYPE(3). + +(Windows, iOS and Mac OS X) This option is ignored by Secure Transport and +Schannel SSL backends because they expect the private key to be already +present in the key chain or PKCS#12 file containing the certificate. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md new file mode 100644 index 0000000..97960f4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSLKEYTYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLCERT (3) + - CURLOPT_PROXY_SSLKEY (3) + - CURLOPT_SSLKEYTYPE (3) +--- + +# NAME + +CURLOPT_PROXY_SSLKEYTYPE - type of the proxy private key file + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLKEYTYPE, char *type); +~~~ + +# DESCRIPTION + +This option is for connecting to an HTTPS proxy, not an HTTPS server. + +Pass a pointer to a null-terminated string as parameter. The string should be +the format of your private key. Supported formats are "PEM", "DER" and "ENG". + +The application does not have to keep the string around after setting this +option. + +# PROTOCOLS + +Used with HTTPS proxy + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEYTYPE, "PEM"); + curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md new file mode 100644 index 0000000..48bb2e8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md @@ -0,0 +1,86 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSLKEY_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSLKEY (3) + - CURLOPT_SSLKEYTYPE (3) + - CURLOPT_SSLKEY_BLOB (3) +--- + +# NAME + +CURLOPT_PROXY_SSLKEY_BLOB - private key for proxy cert from memory blob + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLKEY_BLOB, + struct curl_blob *blob); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_blob structure that contains information (pointer and +size) about the private key for connecting to the HTTPS proxy. Compatible with +OpenSSL. The format (like "PEM") must be specified with +CURLOPT_PROXY_SSLKEYTYPE(3). + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c + +extern char *certificateData; /* point to data */ +extern size_t filesize; /* size of data */ + +extern char *privateKeyData; /* point to data */ +extern size_t privateKeySize; /* size */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + blob.data = certificateData; + blob.len = filesize; + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT_BLOB, &blob); + curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERTTYPE, "PEM"); + + blob.data = privateKeyData; + blob.len = privateKeySize; + curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY_BLOB, &blob); + curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.71.0. This option is supported by the OpenSSL backends. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md new file mode 100644 index 0000000..6f159e8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md @@ -0,0 +1,125 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSLVERSION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTP_VERSION (3) + - CURLOPT_IPRESOLVE (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_USE_SSL (3) +--- + +# NAME + +CURLOPT_PROXY_SSLVERSION - preferred HTTPS proxy TLS version + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLVERSION, + long version); +~~~ + +# DESCRIPTION + +Pass a long as parameter to control which version of SSL/TLS to attempt to use +when connecting to an HTTPS proxy. + +Use one of the available defines for this purpose. The available options are: + +## CURL_SSLVERSION_DEFAULT + +The default action. This attempts to figure out the remote SSL protocol +version. + +## CURL_SSLVERSION_TLSv1 + +TLSv1.x + +## CURL_SSLVERSION_TLSv1_0 + +TLSv1.0 + +## CURL_SSLVERSION_TLSv1_1 + +TLSv1.1 + +## CURL_SSLVERSION_TLSv1_2 + +TLSv1.2 + +## CURL_SSLVERSION_TLSv1_3 + +TLSv1.3 +The maximum TLS version can be set by using *one* of the +CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the +CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros. +The MAX macros are not supported for WolfSSL. + +## CURL_SSLVERSION_MAX_DEFAULT + +The flag defines the maximum supported TLS version as TLSv1.2, or the default +value from the SSL library. +(Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_0 + +The flag defines maximum supported TLS version as TLSv1.0. +(Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_1 + +The flag defines maximum supported TLS version as TLSv1.1. +(Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_2 + +The flag defines maximum supported TLS version as TLSv1.2. +(Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_3 + +The flag defines maximum supported TLS version as TLSv1.3. +(Added in 7.54.0) + +In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were +documented to allow *only* the specified TLS version, but behavior was +inconsistent depending on the TLS library. + +# DEFAULT + +CURL_SSLVERSION_DEFAULT + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* ask libcurl to use TLS version 1.0 or later */ + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md new file mode 100644 index 0000000..d7626c3 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md @@ -0,0 +1,91 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSL_CIPHER_LIST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLVERSION (3) + - CURLOPT_PROXY_TLS13_CIPHERS (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_SSL_CIPHER_LIST (3) + - CURLOPT_TLS13_CIPHERS (3) +--- + +# NAME + +CURLOPT_PROXY_SSL_CIPHER_LIST - ciphers to use for HTTPS proxy + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_CIPHER_LIST, + char *list); +~~~ + +# DESCRIPTION + +Pass a char pointer, pointing to a null-terminated string holding the list of +ciphers to use for the connection to the HTTPS proxy. The list must be +syntactically correct, it consists of one or more cipher strings separated by +colons. Commas or spaces are also acceptable separators but colons are +normally used, &!, &- and &+ can be used as operators. + +For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**, +**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally +set when you compile OpenSSL. + +For WolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**, +**AES256-SHA:AES256-SHA256**, etc. + +For BearSSL, valid examples of cipher lists include +**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using IANA names +**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**, +etc. +With BearSSL you do not add/remove ciphers. If one uses this option then all +known ciphers are disabled and only those passed in are enabled. + +Find more details about cipher lists on this URL: + + https://curl.se/docs/ssl-ciphers.html + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL, use internal default + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost"); + curl_easy_setopt(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, "TLSv1"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0, in 7.83.0 for BearSSL + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md new file mode 100644 index 0000000..30d6935 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md @@ -0,0 +1,119 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSL_OPTIONS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLVERSION (3) + - CURLOPT_PROXY_SSL_CIPHER_LIST (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_SSL_CIPHER_LIST (3) +--- + +# NAME + +CURLOPT_PROXY_SSL_OPTIONS - HTTPS proxy SSL behavior options + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_OPTIONS, + long bitmask); +~~~ + +# DESCRIPTION + +Pass a long with a bitmask to tell libcurl about specific SSL +behaviors. Available bits: + +## CURLSSLOPT_ALLOW_BEAST + +Tells libcurl to not attempt to use any workarounds for a security flaw in the +SSL3 and TLS1.0 protocols. If this option is not used or this bit is set to 0, +the SSL layer libcurl uses may use a work-around for this flaw although it +might cause interoperability problems with some (older) SSL implementations. +WARNING: avoiding this work-around lessens the security, and by setting this +option to 1 you ask for exactly that. This option is only supported for Secure +Transport and OpenSSL. + +## CURLSSLOPT_NO_REVOKE + +Tells libcurl to disable certificate revocation checks for those SSL backends +where such behavior is present. This option is only supported for Schannel +(the native Windows SSL library), with an exception in the case of Windows' +Untrusted Publishers block list which it seems cannot be bypassed. (Added in +7.44.0) + +## CURLSSLOPT_NO_PARTIALCHAIN + +Tells libcurl to not accept "partial" certificate chains, which it otherwise +does by default. This option is only supported for OpenSSL and fails the +certificate verification if the chain ends with an intermediate certificate +and not with a root cert. (Added in 7.68.0) + +## CURLSSLOPT_REVOKE_BEST_EFFORT + +Tells libcurl to ignore certificate revocation checks in case of missing or +offline distribution points for those SSL backends where such behavior is +present. This option is only supported for Schannel (the native Windows SSL +library). If combined with *CURLSSLOPT_NO_REVOKE*, the latter takes +precedence. (Added in 7.70.0) + +## CURLSSLOPT_NATIVE_CA + +Tell libcurl to use the operating system's native CA store for certificate +verification. If you set this option and also set a CA certificate file or +directory then during verification those certificates are searched in addition +to the native CA store. + +Works with wolfSSL on Windows, Linux (Debian, Ubuntu, Gentoo, Fedora, RHEL), +macOS, Android and iOS (added in 8.3.0), with GnuTLS (added in 8.5.0) or on +Windows when built to use OpenSSL (Added in 7.71.0). + +## CURLSSLOPT_AUTO_CLIENT_CERT + +Tell libcurl to automatically locate and use a client certificate for +authentication, when requested by the server. This option is only supported +for Schannel (the native Windows SSL library). Prior to 7.77.0 this was the +default behavior in libcurl with Schannel. Since the server can request any +certificate that supports client authentication in the OS certificate store it +could be a privacy violation and unexpected. +(Added in 7.77.0) + +# DEFAULT + +0 + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + /* weaken TLS only for use with silly proxies */ + curl_easy_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST | + CURLSSLOPT_NO_REVOKE); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md new file mode 100644 index 0000000..fdb8249 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md @@ -0,0 +1,94 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSL_VERIFYHOST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_PROXY_CAINFO (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_SSL_VERIFYHOST - verify the proxy certificate's name against host + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_VERIFYHOST, + long verify); +~~~ + +# DESCRIPTION + +Pass a long set to 2L as asking curl to *verify* in the HTTPS proxy's +certificate name fields against the proxy name. + +This option determines whether libcurl verifies that the proxy cert contains +the correct name for the name it is known as. + +When CURLOPT_PROXY_SSL_VERIFYHOST(3) is 2, the proxy certificate must +indicate that the server is the proxy to which you meant to connect to, or the +connection fails. + +Curl considers the proxy the intended one when the Common Name field or a +Subject Alternate Name field in the certificate matches the hostname in the +proxy string which you told curl to use. + +If *verify* value is set to 1: + +In 7.28.0 and earlier: treated as a debug option of some sorts, not supported +anymore due to frequently leading to programmer mistakes. + +From 7.28.1 to 7.65.3: setting it to 1 made curl_easy_setopt(3) return +an error and leaving the flag untouched. + +From 7.66.0: treats 1 and 2 the same. + +When the *verify* value is 0L, the connection succeeds regardless of the +names used in the certificate. Use that ability with caution! + +See also CURLOPT_PROXY_SSL_VERIFYPEER(3) to verify the digital signature +of the proxy certificate. + +# DEFAULT + +2 + +# PROTOCOLS + +All protocols when used over an HTTPS proxy. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the default value: strict name check please */ + curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 2L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0. + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not. + +If 1 is set as argument, *CURLE_BAD_FUNCTION_ARGUMENT* is returned. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md new file mode 100644 index 0000000..f934dde --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md @@ -0,0 +1,94 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_SSL_VERIFYPEER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_PROXY_SSL_VERIFYPEER - verify the proxy's SSL certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_VERIFYPEER, + long verify); +~~~ + +# DESCRIPTION + +Pass a long as parameter set to 1L to enable or 0L to disable. + +This option tells curl to verify the authenticity of the HTTPS proxy's +certificate. A value of 1 means curl verifies; 0 (zero) means it does not. + +This is the proxy version of CURLOPT_SSL_VERIFYPEER(3) that is used for +ordinary HTTPS servers. + +When negotiating a TLS or SSL connection, the server sends a certificate +indicating its identity. Curl verifies whether the certificate is authentic, +i.e. that you can trust that the server is who the certificate says it is. +This trust is based on a chain of digital signatures, rooted in certification +authority (CA) certificates you supply. curl uses a default bundle of CA +certificates (the path for that is determined at build time) and you can +specify alternate certificates with the CURLOPT_PROXY_CAINFO(3) option or +the CURLOPT_PROXY_CAPATH(3) option. + +When CURLOPT_PROXY_SSL_VERIFYPEER(3) is enabled, and the verification +fails to prove that the certificate is authentic, the connection fails. When +the option is zero, the peer certificate verification succeeds regardless. + +Authenticating the certificate is not enough to be sure about the server. You +typically also want to ensure that the server is the server you mean to be +talking to. Use CURLOPT_PROXY_SSL_VERIFYHOST(3) for that. The check that the +hostname in the certificate is valid for the hostname you are connecting to is +done independently of the CURLOPT_PROXY_SSL_VERIFYPEER(3) option. + +WARNING: disabling verification of the certificate allows bad guys to +man-in-the-middle the communication without you knowing it. Disabling +verification makes the communication insecure. Just having encryption on a +transfer is not enough as you cannot be sure that you are communicating with +the correct end-point. + +# DEFAULT + +1 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the default value: strict certificate check please */ + curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md b/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md new file mode 100644 index 0000000..f3c5448 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_TLS13_CIPHERS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLVERSION (3) + - CURLOPT_PROXY_SSL_CIPHER_LIST (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_SSL_CIPHER_LIST (3) + - CURLOPT_TLS13_CIPHERS (3) +--- + +# NAME + +CURLOPT_PROXY_TLS13_CIPHERS - ciphers suites for proxy TLS 1.3 + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TLS13_CIPHERS, + char *list); +~~~ + +# DESCRIPTION + +Pass a char pointer, pointing to a null-terminated string holding the list of +cipher suites to use for the TLS 1.3 connection to a proxy. The list must be +syntactically correct, it consists of one or more cipher suite strings +separated by colons. + +Find more details about cipher lists on this URL: + + https://curl.se/docs/ssl-ciphers.html + +This option is currently used only when curl is built to use OpenSSL 1.1.1 or +later. If you are using a different SSL backend you can try setting TLS 1.3 +cipher suites by using the CURLOPT_PROXY_SSL_CIPHER_LIST(3) option. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL, use internal default + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLS13_CIPHERS, + "TLS_CHACHA20_POLY1305_SHA256"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0. +Available when built with OpenSSL >= 1.1.1. + +# RETURN VALUE + +Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md new file mode 100644 index 0000000..778d1b7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_TLSAUTH_PASSWORD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_TLSAUTH_TYPE (3) + - CURLOPT_PROXY_TLSAUTH_USERNAME (3) + - CURLOPT_TLSAUTH_TYPE (3) + - CURLOPT_TLSAUTH_USERNAME (3) +--- + +# NAME + +CURLOPT_PROXY_TLSAUTH_PASSWORD - password to use for proxy TLS authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TLSAUTH_PASSWORD, + char *pwd); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should point to the null-terminated +password to use for the TLS authentication method specified with the +CURLOPT_PROXY_TLSAUTH_TYPE(3) option. Requires that the +CURLOPT_PROXY_TLSAUTH_USERNAME(3) option also be set. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0, with the OpenSSL and GnuTLS backends only + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md new file mode 100644 index 0000000..d438918 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_TLSAUTH_TYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_TLSAUTH_PASSWORD (3) + - CURLOPT_PROXY_TLSAUTH_USERNAME (3) + - CURLOPT_TLSAUTH_PASSWORD (3) + - CURLOPT_TLSAUTH_USERNAME (3) +--- + +# NAME + +CURLOPT_PROXY_TLSAUTH_TYPE - HTTPS proxy TLS authentication methods + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TLSAUTH_TYPE, + char *type); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the method of the TLS authentication used for the HTTPS connection. Supported +method is "SRP". + +## SRP + +TLS-SRP authentication. Secure Remote Password authentication for TLS is +defined in RFC 5054 and provides mutual authentication if both sides have a +shared secret. To use TLS-SRP, you must also set the +CURLOPT_PROXY_TLSAUTH_USERNAME(3) and +CURLOPT_PROXY_TLSAUTH_PASSWORD(3) options. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +blank + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0 + +You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this +to work. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md new file mode 100644 index 0000000..612ff4f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_TLSAUTH_USERNAME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_TLSAUTH_PASSWORD (3) + - CURLOPT_PROXY_TLSAUTH_TYPE (3) + - CURLOPT_TLSAUTH_PASSWORD (3) + - CURLOPT_TLSAUTH_TYPE (3) +--- + +# NAME + +CURLOPT_PROXY_TLSAUTH_USERNAME - user name to use for proxy TLS authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TLSAUTH_USERNAME, + char *user); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should point to the null-terminated +username to use for the HTTPS proxy TLS authentication method specified with +the CURLOPT_PROXY_TLSAUTH_TYPE(3) option. Requires that the +CURLOPT_PROXY_TLSAUTH_PASSWORD(3) option also be set. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.52.0, with the OpenSSL and GnuTLS backends only. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md b/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md new file mode 100644 index 0000000..c0fed8b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PROXY_TRANSFER_MODE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CRLF (3) + - CURLOPT_HTTPPROXYTUNNEL (3) + - CURLOPT_PROXY (3) + - CURLOPT_TRANSFERTEXT (3) +--- + +# NAME + +CURLOPT_PROXY_TRANSFER_MODE - append FTP transfer mode to URL for proxy + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TRANSFER_MODE, + long enabled); +~~~ + +# DESCRIPTION + +Pass a long. If the value is set to 1 (one), it tells libcurl to set the +transfer mode (binary or ASCII) for FTP transfers done via an HTTP proxy, by +appending ;type=a or ;type=i to the URL. Without this setting, or it being set +to 0 (zero, the default), CURLOPT_TRANSFERTEXT(3) has no effect when +doing FTP via a proxy. Beware that not all proxies support this feature. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +FTP over proxy + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, + "ftp://example.com/old-server/file.txt"); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:80"); + curl_easy_setopt(curl, CURLOPT_PROXY_TRANSFER_MODE, 1L); + curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.18.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if the +enabled value is not supported. diff --git a/docs/libcurl/opts/CURLOPT_PUT.md b/docs/libcurl/opts/CURLOPT_PUT.md new file mode 100644 index 0000000..117eaed --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PUT.md @@ -0,0 +1,89 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_PUT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPGET (3) + - CURLOPT_MIMEPOST (3) + - CURLOPT_POSTFIELDS (3) + - CURLOPT_UPLOAD (3) +--- + +# NAME + +CURLOPT_PUT - make an HTTP PUT request + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PUT, long put); +~~~ + +# DESCRIPTION + +A parameter set to 1 tells the library to use HTTP PUT to transfer data. The +data should be set with CURLOPT_READDATA(3) and +CURLOPT_INFILESIZE(3). + +This option is **deprecated** since version 7.12.1. Use CURLOPT_UPLOAD(3). + +# DEFAULT + +0, disabled + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +static size_t read_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + FILE *src = userdata; + /* copy as much data as possible into the 'ptr' buffer, but no more than + 'size' * 'nmemb' bytes */ + size_t retcode = fread(ptr, size, nmemb, src); + + return retcode; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + FILE *src = fopen("local-file", "r"); + curl_off_t fsize; /* set this to the size of the input file */ + + /* we want to use our own read function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb); + + /* enable PUT */ + curl_easy_setopt(curl, CURLOPT_PUT, 1L); + + /* specify target */ + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/to/newfile"); + + /* now specify which pointer to pass to our callback */ + curl_easy_setopt(curl, CURLOPT_READDATA, src); + + /* Set the size of the file to upload */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); + + /* Now run off and do what you have been told */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Deprecated since 7.12.1. Do not use. + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md b/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md new file mode 100644 index 0000000..4159c02 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_QUICK_EXIT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_FAILONERROR (3) + - CURLOPT_RESOLVE (3) +--- + +# NAME + +CURLOPT_QUICK_EXIT - allow to exit quickly + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_QUICK_EXIT, + long value); +~~~ + +# DESCRIPTION + +Pass a long as a parameter, 1L meaning that when recovering from a timeout, +libcurl should skip lengthy cleanups that are intended to avoid all kinds of +leaks (threads etc.), as the caller program is about to call exit() anyway. +This allows for a swift termination after a DNS timeout for example, by +canceling and/or forgetting about a resolver thread, at the expense of a +possible (though short-lived) leak of associated resources. + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.87.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_QUOTE.md b/docs/libcurl/opts/CURLOPT_QUOTE.md new file mode 100644 index 0000000..f57b45e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_QUOTE.md @@ -0,0 +1,161 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_QUOTE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CUSTOMREQUEST (3) + - CURLOPT_DIRLISTONLY (3) + - CURLOPT_POSTQUOTE (3) + - CURLOPT_PREQUOTE (3) +--- + +# NAME + +CURLOPT_QUOTE - (S)FTP commands to run before transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_QUOTE, + struct curl_slist *cmds); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of FTP or SFTP commands to pass to the server +prior to your request. This is done before any other commands are issued (even +before the CWD command for FTP). The linked list should be a fully valid list +of 'struct curl_slist' structs properly filled in with text strings. Use +curl_slist_append(3) to append strings (commands) to the list, and clear +the entire list afterwards with curl_slist_free_all(3). + +Disable this operation again by setting a NULL to this option. + +When speaking to an FTP server, prefix the command with an asterisk (*) to +make libcurl continue even if the command fails as by default libcurl stops at +first failure. + +The set of valid FTP commands depends on the server (see RFC 959 for a list of +mandatory commands). + +libcurl does not inspect, parse or "understand" the commands passed to the +server using this option. If you change connection state, working directory or +similar using quote commands, libcurl does not know about it. + +The path arguments for FTP or SFTP can use single or double quotes to +distinguish a space from being the parameter separator or being a part of the +path. e.g. rename with sftp using a quote command like this: + + "rename 'test/_upload.txt' 'test/Hello World.txt'" + +# SFTP commands + +## atime date file + +The atime command sets the last access time of the file named by the file +operand. The can be all sorts of date strings, see the +curl_getdate(3) man page for date expression details. (Added in 7.73.0) + +## chgrp group file + +The chgrp command sets the group ID of the file named by the file operand to +the group ID specified by the group operand. The group operand is a decimal +integer group ID. + +## chmod mode file + +The chmod command modifies the file mode bits of the specified file. The +mode operand is an octal integer mode number. + +## chown user file + +The chown command sets the owner of the file named by the file operand to the +user ID specified by the user operand. The user operand is a decimal +integer user ID. + +## ln source_file target_file + +The **ln** and **symlink** commands create a symbolic link at the +target_file location pointing to the source_file location. + +## mkdir directory_name + +The mkdir command creates the directory named by the directory_name operand. + +## mtime date file + +The mtime command sets the last modification time of the file named by the +file operand. The can be all sorts of date strings, see the +curl_getdate(3) man page for date expression details. (Added in 7.73.0) + +## pwd + +The **pwd** command returns the absolute path of the current working +directory. + +## rename source target + +The rename command renames the file or directory named by the source +operand to the destination path named by the target operand. + +## rm file + +The rm command removes the file specified by the file operand. + +## rmdir directory + +The rmdir command removes the directory entry specified by the directory +operand, provided it is empty. + +## statvfs file + +The statvfs command returns statistics on the file system in which specified +file resides. (Added in 7.49.0) + +## symlink source_file target_file + +See ln. + +# DEFAULT + +NULL + +# PROTOCOLS + +SFTP and FTP + +# EXAMPLE + +~~~c +int main(void) +{ + struct curl_slist *cmdlist = NULL; + cmdlist = curl_slist_append(cmdlist, "RNFR source-name"); + cmdlist = curl_slist_append(cmdlist, "RNTO new-name"); + + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin"); + + /* pass in the FTP commands to run before the transfer */ + curl_easy_setopt(curl, CURLOPT_QUOTE, cmdlist); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +SFTP support added in 7.16.3. *-prefix for SFTP added in 7.24.0 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md b/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md new file mode 100644 index 0000000..7675461 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RANDOM_FILE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_EGDSOCKET (3) +--- + +# NAME + +CURLOPT_RANDOM_FILE - file to read random data from + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RANDOM_FILE, char *path); +~~~ + +# DESCRIPTION + +Deprecated option. It serves no purpose anymore. + +Pass a char pointer to a null-terminated filename. The file might be used to +read from to seed the random engine for SSL and more. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL, not used + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_RANDOM_FILE, "junk.txt"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If built with TLS enabled. Only the OpenSSL backend uses this, and only with +OpenSSL versions before 1.1.0. + +This option was deprecated in 7.84.0. + +# RETURN VALUE + +Returns CURLE_OK on success or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_RANGE.md b/docs/libcurl/opts/CURLOPT_RANGE.md new file mode 100644 index 0000000..3f765bc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RANGE.md @@ -0,0 +1,84 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RANGE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_MAXFILESIZE_LARGE (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) + - CURLOPT_RESUME_FROM (3) +--- + +# NAME + +CURLOPT_RANGE - byte range to request + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RANGE, char *range); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should contain the specified range you +want to retrieve. It should be in the format "X-Y", where either X or Y may be +left out and X and Y are byte indexes. + +HTTP transfers also support several intervals, separated with commas as in +*"X-Y,N-M"*. Using this kind of multiple intervals causes the HTTP server +to send the response document in pieces (using standard MIME separation +techniques). Unfortunately, the HTTP standard (RFC 7233 section 3.1) allows +servers to ignore range requests so even when you set CURLOPT_RANGE(3) +for a request, you may end up getting the full response sent back. + +For RTSP, the formatting of a range should follow RFC 2326 Section 12.29. For +RTSP, byte ranges are **not** permitted. Instead, ranges should be given in +**npt**, **utc**, or **smpte** formats. + +For HTTP PUT uploads this option should not be used, since it may conflict with +other options. + +Pass a NULL to this option to disable the use of ranges. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP, FTP, FILE, RTSP and SFTP. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* get the first 200 bytes */ + curl_easy_setopt(curl, CURLOPT_RANGE, "0-199"); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +FILE since 7.18.0, RTSP since 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK on success or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_READDATA.md b/docs/libcurl/opts/CURLOPT_READDATA.md new file mode 100644 index 0000000..d7aa4ff --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_READDATA.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_READDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERDATA (3) + - CURLOPT_READFUNCTION (3) + - CURLOPT_WRITEDATA (3) + - CURLOPT_WRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_READDATA - pointer passed to the read callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_READDATA, void *pointer); +~~~ + +# DESCRIPTION + +Data *pointer* to pass to the file read function. If you use the +CURLOPT_READFUNCTION(3) option, this is the pointer you get as input in +the fourth argument to the callback. + +If you do not specify a read callback but instead rely on the default internal +read function, this data must be a valid readable FILE * (cast to 'void *'). + +If you are using libcurl as a DLL on Windows, you must use the +CURLOPT_READFUNCTION(3) callback if you set this option, otherwise you +might experience crashes. + +# DEFAULT + +By default, this is a FILE * to stdin. + +# PROTOCOLS + +This is used for all protocols when sending data. + +# EXAMPLE + +~~~c +struct MyData { + void *custom; +}; + +int main(void) +{ + CURL *curl = curl_easy_init(); + struct MyData this; + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* pass pointer that gets passed in to the + CURLOPT_READFUNCTION callback */ + curl_easy_setopt(curl, CURLOPT_READDATA, &this); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +This option was once known by the older name CURLOPT_INFILE, the name +CURLOPT_READDATA(3) was introduced in 7.9.7. + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_READFUNCTION.md b/docs/libcurl/opts/CURLOPT_READFUNCTION.md new file mode 100644 index 0000000..978440d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_READFUNCTION.md @@ -0,0 +1,123 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_READFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_POST (3) + - CURLOPT_READDATA (3) + - CURLOPT_SEEKFUNCTION (3) + - CURLOPT_UPLOAD (3) + - CURLOPT_UPLOAD_BUFFERSIZE (3) + - CURLOPT_WRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_READFUNCTION - read callback for data uploads + +# SYNOPSIS + +~~~c +#include + +size_t read_callback(char *buffer, size_t size, size_t nitems, void *userdata); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_READFUNCTION, read_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, as the prototype shows above. + +This callback function gets called by libcurl as soon as it needs to read data +in order to send it to the peer - like if you ask it to upload or post data to +the server. The data area pointed at by the pointer *buffer* should be +filled up with at most *size* multiplied with *nitems* number of bytes +by your function. *size* is always 1. + +Set the *userdata* argument with the CURLOPT_READDATA(3) option. + +Your function must return the actual number of bytes that it stored in the +data area pointed at by the pointer *buffer*. Returning 0 signals +end-of-file to the library and causes it to stop the current transfer. + +If you stop the current transfer by returning 0 "pre-maturely" (i.e before the +server expected it, like when you have said you would upload N bytes and you +upload less than N bytes), you may experience that the server "hangs" waiting +for the rest of the data that is not sent. + +The read callback may return *CURL_READFUNC_ABORT* to stop the current +operation immediately, resulting in a *CURLE_ABORTED_BY_CALLBACK* error +code from the transfer. + +The callback can return *CURL_READFUNC_PAUSE* to cause reading from this +connection to pause. See curl_easy_pause(3) for further details. + +**Bugs**: when doing TFTP uploads, you must return the exact amount of data +that the callback wants, or it is considered the final packet by the server +end and the transfer ends there. + +If you set this callback pointer to NULL, or do not set it at all, the default +internal read function is used. It is doing an fread() on the FILE * userdata +set with CURLOPT_READDATA(3). + +You can set the total size of the data you are sending by using +CURLOPT_INFILESIZE_LARGE(3) or CURLOPT_POSTFIELDSIZE_LARGE(3), +depending on the type of transfer. For some transfer types it may be required +and it allows for better error checking. + +# DEFAULT + +The default internal read callback is fread(). + +# PROTOCOLS + +This is used for all protocols when doing uploads. + +# EXAMPLE + +~~~c +size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + FILE *readhere = (FILE *)userdata; + curl_off_t nread; + + /* copy as much data as possible into the 'ptr' buffer, but no more than + 'size' * 'nmemb' bytes! */ + size_t retcode = fread(ptr, size, nmemb, readhere); + + nread = (curl_off_t)retcode; + + fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T + " bytes from file\n", nread); + return retcode; +} + +int main(int argc, char **argv) +{ + FILE *file = fopen(argv[1], "rb"); + CURLcode result; + + CURL *curl = curl_easy_init(); + if(curl) { + /* set callback to use */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + + /* pass in suitable argument to callback */ + curl_easy_setopt(curl, CURLOPT_READDATA, (void *)file); + + result = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +CURL_READFUNC_PAUSE return code was added in 7.18.0 and CURL_READFUNC_ABORT +was added in 7.12.1. + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md new file mode 100644 index 0000000..4d06d46 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md @@ -0,0 +1,115 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_REDIR_PROTOCOLS +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SCHEME (3) + - CURLOPT_DEFAULT_PROTOCOL (3) + - CURLOPT_PROTOCOLS (3) + - CURLOPT_REDIR_PROTOCOLS_STR (3) +--- + +# NAME + +CURLOPT_REDIR_PROTOCOLS - protocols allowed to redirect to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REDIR_PROTOCOLS, long bitmask); +~~~ + +# DESCRIPTION + +This option is deprecated. We strongly recommend using +CURLOPT_REDIR_PROTOCOLS_STR(3) instead because this option cannot +control all available protocols! + +Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask +limits what protocols libcurl may use in a transfer that it follows to in a +redirect when CURLOPT_FOLLOWLOCATION(3) is enabled. This allows you to +limit specific transfers to only be allowed to use a subset of protocols in +redirections. + +Protocols denied by CURLOPT_PROTOCOLS(3) are not overridden by this +option. + +By default libcurl allows HTTP, HTTPS, FTP and FTPS on redirect (7.65.2). +*CURLPROTO_ALL* enables all protocols on redirect, including those +otherwise disabled for security. + +These are the available protocol defines: +~~~c +CURLPROTO_DICT +CURLPROTO_FILE +CURLPROTO_FTP +CURLPROTO_FTPS +CURLPROTO_GOPHER +CURLPROTO_HTTP +CURLPROTO_HTTPS +CURLPROTO_IMAP +CURLPROTO_IMAPS +CURLPROTO_LDAP +CURLPROTO_LDAPS +CURLPROTO_POP3 +CURLPROTO_POP3S +CURLPROTO_RTMP +CURLPROTO_RTMPE +CURLPROTO_RTMPS +CURLPROTO_RTMPT +CURLPROTO_RTMPTE +CURLPROTO_RTMPTS +CURLPROTO_RTSP +CURLPROTO_SCP +CURLPROTO_SFTP +CURLPROTO_SMB +CURLPROTO_SMBS +CURLPROTO_SMTP +CURLPROTO_SMTPS +CURLPROTO_TELNET +CURLPROTO_TFTP +~~~ + +# DEFAULT + +HTTP, HTTPS, FTP and FTPS (Added in 7.65.2). + +Older versions defaulted to all protocols except FILE, SCP and since 7.40.0 +SMB and SMBS. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(int argc, char **argv) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* pass in the URL from an external source */ + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + + /* only allow redirects to HTTP and HTTPS URLs */ + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, + CURLPROTO_HTTP | CURLPROTO_HTTPS); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.4, before then it would follow all protocols. Deprecated +since 7.85.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md new file mode 100644 index 0000000..9201a4b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md @@ -0,0 +1,94 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_REDIR_PROTOCOLS_STR +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SCHEME (3) + - CURLOPT_DEFAULT_PROTOCOL (3) + - CURLOPT_PROTOCOLS (3) + - CURLOPT_PROTOCOLS_STR (3) + - CURLOPT_REDIR_PROTOCOLS (3) +--- + +# NAME + +CURLOPT_REDIR_PROTOCOLS_STR - protocols allowed to redirect to + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REDIR_PROTOCOLS_STR, + char *spec); +~~~ + +# DESCRIPTION + +Pass a pointer to a string that holds a comma-separated list of case +insensitive protocol names (URL schemes). That list limits what protocols +libcurl may use in a transfer that it follows to in a redirect when +CURLOPT_FOLLOWLOCATION(3) is enabled. This option allows applications to +limit specific transfers to only be allowed to use a subset of protocols in +redirections. + +Protocols denied by CURLOPT_PROTOCOLS_STR(3) are not overridden by this +option. + +By default libcurl allows HTTP, HTTPS, FTP and FTPS on redirects (since +7.65.2). + +These are the available protocols: + +DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, +MQTT, POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, SCP, SFTP, +SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, WSS + +You can set "ALL" as a short-cut to enable all protocols. Note that by setting +all, you may enable protocols that were not supported the day you write this +but are introduced in a future libcurl version. + +If trying to set a non-existing protocol or if no matching protocol at all is +set, it returns error. + +# DEFAULT + +HTTP, HTTPS, FTP and FTPS (Added in 7.65.2). + +Older versions defaulted to all protocols except FILE, SCP and since 7.40.0 +SMB and SMBS. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(int argc, char **argv) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* pass in the URL from an external source */ + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + + /* only allow redirects to HTTP and HTTPS URLs */ + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.85.0. + +# RETURN VALUE + +Returns CURLE_UNKNOWN_OPTION if the option is not implemented, +CURLE_UNSUPPORTED_PROTOCOL if a listed protocol is not supported or disabled, +CURLE_BAD_FUNCTION_ARGUMENT if no protocol is listed else CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_REFERER.md b/docs/libcurl/opts/CURLOPT_REFERER.md new file mode 100644 index 0000000..6af19cb --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_REFERER.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_REFERER +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_URL (3) + - CURLINFO_REFERER (3) + - CURLOPT_HTTPHEADER (3) + - CURLOPT_USERAGENT (3) +--- + +# NAME + +CURLOPT_REFERER - the HTTP referer header + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REFERER, char *where); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. It is used to set the +Referer: header field in the HTTP request sent to the remote server. You can +set any custom header with CURLOPT_HTTPHEADER(3). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* tell it where we found the link to this place */ + curl_easy_setopt(curl, CURLOPT_REFERER, "https://example.org/me.html"); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +If built with HTTP support + +# RETURN VALUE + +Returns CURLE_OK if HTTP support is enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md b/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md new file mode 100644 index 0000000..cfc15d7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_REQUEST_TARGET +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CUSTOMREQUEST (3) + - CURLOPT_HTTPGET (3) + - CURLOPT_PATH_AS_IS (3) + - CURLOPT_URL (3) +--- + +# NAME + +CURLOPT_REQUEST_TARGET - alternative target for this request + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REQUEST_TARGET, string); +~~~ + +# DESCRIPTION + +Pass a char pointer to string which libcurl uses in the upcoming request +instead of the path as extracted from the URL. + +libcurl passes on the verbatim string in its request without any filter or +other safe guards. That includes white space and control characters. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/*"); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS"); + + /* issue an OPTIONS * request (no leading slash) */ + curl_easy_setopt(curl, CURLOPT_REQUEST_TARGET, "*"); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_RESOLVE.md b/docs/libcurl/opts/CURLOPT_RESOLVE.md new file mode 100644 index 0000000..ce446bd --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RESOLVE.md @@ -0,0 +1,115 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RESOLVE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECT_TO (3) + - CURLOPT_DNS_CACHE_TIMEOUT (3) + - CURLOPT_IPRESOLVE (3) +--- + +# NAME + +CURLOPT_RESOLVE - provide custom hostname to IP address resolves + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RESOLVE, + struct curl_slist *hosts); +~~~ + +# DESCRIPTION + +Pass a pointer to a linked list of strings with hostname resolve information +to use for requests with this handle. The linked list should be a fully valid +list of **struct curl_slist** structs properly filled in. Use +curl_slist_append(3) to create the list and curl_slist_free_all(3) to clean up +an entire list. + +Each resolve rule to add should be written using the format + +~~~c + [+]HOST:PORT:ADDRESS[,ADDRESS] +~~~ + +HOST is the name libcurl wants to resolve, PORT is the port number of the +service where libcurl wants to connect to the HOST and ADDRESS is one or more +numerical IP addresses. If you specify multiple IP addresses they need to be +separated by comma. If libcurl is built to support IPv6, each of the ADDRESS +entries can of course be either IPv4 or IPv6 style addressing. + +This option effectively populates the DNS cache with entries for the host+port +pair so redirects and everything that operations against the HOST+PORT instead +use your provided ADDRESS. + +The optional leading "+" specifies that the new entry should time-out. Entries +added without the leading plus character never times out whereas entries added +with "+HOST:..." times out just like ordinary DNS cache entries. + +If the DNS cache already has an entry for the given host+port pair, the new +entry overrides the former one. + +An ADDRESS provided by this option is only used if not restricted by the +setting of CURLOPT_IPRESOLVE(3) to a different IP version. + +To remove names from the DNS cache again, to stop providing these fake +resolves, include a string in the linked list that uses the format + +~~~c + -HOST:PORT +~~~ + +The entry to remove must be prefixed with a dash, and the hostname and port +number must exactly match what was added previously. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl; + struct curl_slist *host = NULL; + host = curl_slist_append(NULL, "example.com:443:127.0.0.1"); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_RESOLVE, host); + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + + curl_slist_free_all(host); +} +~~~ + +# AVAILABILITY + +Added in 7.21.3. Removal support added in 7.42.0. + +Support for providing the ADDRESS within [brackets] was added in 7.57.0. + +Support for providing multiple IP addresses per entry was added in 7.59.0. + +Support for adding non-permanent entries by using the "+" prefix was added in +7.75.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md b/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md new file mode 100644 index 0000000..f34cf8b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RESOLVER_START_DATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PREREQFUNCTION (3) + - CURLOPT_RESOLVER_START_FUNCTION (3) +--- + +# NAME + +CURLOPT_RESOLVER_START_DATA - pointer passed to the resolver start callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RESOLVER_START_DATA, + void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* is be untouched by libcurl and passed as the third +argument in the resolver start callback set with +CURLOPT_RESOLVER_START_FUNCTION(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +static int resolver_start_cb(void *resolver_state, void *reserved, + void *userdata) +{ + (void)reserved; + printf("Received resolver_state=%p userdata=%p\n", + resolver_state, userdata); + return 0; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_RESOLVER_START_FUNCTION, resolver_start_cb); + curl_easy_setopt(curl, CURLOPT_RESOLVER_START_DATA, curl); + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.59.0 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md b/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md new file mode 100644 index 0000000..a9b4907 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md @@ -0,0 +1,88 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RESOLVER_START_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PREREQFUNCTION (3) + - CURLOPT_RESOLVER_START_DATA (3) +--- + +# NAME + +CURLOPT_RESOLVER_START_FUNCTION - callback called before a new name resolve is started + +# SYNOPSIS + +~~~c +#include + +int resolver_start_cb(void *resolver_state, void *reserved, void *userdata); + +CURLcode curl_easy_setopt(CURL *handle, + CURLOPT_RESOLVER_START_FUNCTION, + resolver_start_cb); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl every time before a new resolve +request is started. + +*resolver_state* points to a backend-specific resolver state. Currently only +the ares resolver backend has a resolver state. It can be used to set up any +desired option on the ares channel before it is used, for example setting up +socket callback options. + +*reserved* is reserved. + +*userdata* is the user pointer set with the +CURLOPT_RESOLVER_START_DATA(3) option. + +The callback must return 0 on success. Returning a non-zero value causes the +resolve to fail. + +# DEFAULT + +NULL (No callback) + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +static int start_cb(void *resolver_state, void *reserved, + void *userdata) +{ + (void)reserved; + printf("Received resolver_state=%p userdata=%p\n", + resolver_state, userdata); + return 0; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_RESOLVER_START_FUNCTION, start_cb); + curl_easy_setopt(curl, CURLOPT_RESOLVER_START_DATA, curl); + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.59.0 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_RESUME_FROM.md b/docs/libcurl/opts/CURLOPT_RESUME_FROM.md new file mode 100644 index 0000000..c8de1ee --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RESUME_FROM.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RESUME_FROM +Section: 3 +Source: libcurl +See-also: + - CURLOPT_INFILESIZE (3) + - CURLOPT_RANGE (3) + - CURLOPT_RESUME_FROM_LARGE (3) +--- + +# NAME + +CURLOPT_RESUME_FROM - offset to resume transfer from + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RESUME_FROM, long from); +~~~ + +# DESCRIPTION + +Pass a long as parameter. It contains the offset in number of bytes that you +want the transfer to start from. Set this option to 0 to make the transfer +start from the beginning (effectively disabling resume). For FTP, set this +option to -1 to make the transfer start from the end of the target file +(useful to continue an interrupted upload). + +When doing uploads with FTP, the resume position is where in the local/source +file libcurl should try to resume the upload from and it then appends the +source file to the remote target file. + +If you need to resume a transfer beyond the 2GB limit, use +CURLOPT_RESUME_FROM_LARGE(3) instead. + +# DEFAULT + +0, not used + +# PROTOCOLS + +HTTP, FTP, SFTP, FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + long size_of_file; + + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com"); + + /* resume upload at byte index 200 */ + curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 200L); + + /* ask for upload */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* set total data amount to expect */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE, size_of_file); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md b/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md new file mode 100644 index 0000000..950a4f4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md @@ -0,0 +1,79 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RESUME_FROM_LARGE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_INFILESIZE_LARGE (3) + - CURLOPT_RANGE (3) + - CURLOPT_RESUME_FROM (3) +--- + +# NAME + +CURLOPT_RESUME_FROM_LARGE - offset to resume transfer from + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RESUME_FROM_LARGE, + curl_off_t from); +~~~ + +# DESCRIPTION + +Pass a curl_off_t as parameter. It contains the offset in number of bytes that +you want the transfer to start from. Set this option to 0 to make the transfer +start from the beginning (effectively disabling resume). For FTP, set this +option to -1 to make the transfer start from the end of the target file +(useful to continue an interrupted upload). + +When doing uploads with FTP, the resume position is where in the local/source +file libcurl should try to resume the upload from and it appends the source +file to the remote target file. + +# DEFAULT + +0, not used + +# PROTOCOLS + +HTTP, FTP, SFTP, FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_off_t resume_position; /* get it somehow */ + curl_off_t file_size; /* get it somehow as well */ + + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com"); + + /* resuming upload at this position, possibly beyond 2GB */ + curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, resume_position); + + /* ask for upload */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* set total data amount to expect */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, file_size); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.11.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md b/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md new file mode 100644 index 0000000..6c83663 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RTSP_CLIENT_CSEQ +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RTSP_CLIENT_CSEQ (3) + - CURLINFO_RTSP_SERVER_CSEQ (3) + - CURLOPT_RTSP_REQUEST (3) + - CURLOPT_RTSP_SERVER_CSEQ (3) +--- + +# NAME + +CURLOPT_RTSP_CLIENT_CSEQ - RTSP client CSEQ number + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RTSP_CLIENT_CSEQ, long cseq); +~~~ + +# DESCRIPTION + +Pass a long to set the CSEQ number to issue for the next RTSP request. Useful +if the application is resuming a previously broken connection. The CSEQ +increments from this new number henceforth. + +# DEFAULT + +0 + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); + curl_easy_setopt(curl, CURLOPT_RTSP_CLIENT_CSEQ, 1234L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md b/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md new file mode 100644 index 0000000..d56b34d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md @@ -0,0 +1,139 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RTSP_REQUEST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_RTSP_SESSION_ID (3) + - CURLOPT_RTSP_STREAM_URI (3) +--- + +# NAME + +CURLOPT_RTSP_REQUEST - RTSP request + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RTSP_REQUEST, long request); +~~~ + +# DESCRIPTION + +Tell libcurl what kind of RTSP request to make. Pass one of the following RTSP +enum values as a long in the *request* argument. Unless noted otherwise, +commands require the Session ID to be initialized. + +## CURL_RTSPREQ_OPTIONS + +Used to retrieve the available methods of the server. The application is +responsible for parsing and obeying the response. The session ID is not needed +for this method. + +## CURL_RTSPREQ_DESCRIBE + +Used to get the low level description of a stream. The application should note +what formats it understands in the *'Accept:'* header. Unless set manually, +libcurl automatically adds in *'Accept: application/sdp'*. Time-condition +headers are added to Describe requests if the CURLOPT_TIMECONDITION(3) +option is used. (The session ID is not needed for this method) + +## CURL_RTSPREQ_ANNOUNCE + +When sent by a client, this method changes the description of the session. For +example, if a client is using the server to record a meeting, the client can +use Announce to inform the server of all the meta-information about the +session. ANNOUNCE acts like an HTTP PUT or POST just like +*CURL_RTSPREQ_SET_PARAMETER* + +## CURL_RTSPREQ_SETUP + +Setup is used to initialize the transport layer for the session. The +application must set the desired Transport options for a session by using the +CURLOPT_RTSP_TRANSPORT(3) option prior to calling setup. If no session +ID is currently set with CURLOPT_RTSP_SESSION_ID(3), libcurl extracts +and uses the session ID in the response to this request. The session ID is not +needed for this method. + +## CURL_RTSPREQ_PLAY + +Send a Play command to the server. Use the CURLOPT_RANGE(3) option to +modify the playback time (e.g. *npt=10-15*). + +## CURL_RTSPREQ_PAUSE + +Send a Pause command to the server. Use the CURLOPT_RANGE(3) option with +a single value to indicate when the stream should be +halted. (e.g. *npt=25*) + +## CURL_RTSPREQ_TEARDOWN + +This command terminates an RTSP session. Simply closing a connection does not +terminate the RTSP session since it is valid to control an RTSP session over +different connections. + +## CURL_RTSPREQ_GET_PARAMETER + +Retrieve a parameter from the server. By default, libcurl adds a +*Content-Type: text/parameters* header on all non-empty requests unless a +custom one is set. GET_PARAMETER acts just like an HTTP PUT or POST (see +*CURL_RTSPREQ_SET_PARAMETER*). Applications wishing to send a heartbeat +message (e.g. in the presence of a server-specified timeout) should send use +an empty GET_PARAMETER request. + +## CURL_RTSPREQ_SET_PARAMETER + +Set a parameter on the server. By default, libcurl uses a *Content-Type: +text/parameters* header unless a custom one is set. The interaction with +SET_PARAMETER is much like an HTTP PUT or POST. An application may either use +CURLOPT_UPLOAD(3) with CURLOPT_READDATA(3) like an HTTP PUT, or it may use +CURLOPT_POSTFIELDS(3) like an HTTP POST. No chunked transfers are allowed, so +the application must set the CURLOPT_INFILESIZE(3) in the former and +CURLOPT_POSTFIELDSIZE(3) in the latter. Also, there is no use of multi-part +POSTs within RTSP. + +## CURL_RTSPREQ_RECORD + +Used to tell the server to record a session. Use the CURLOPT_RANGE(3) +option to modify the record time. + +## CURL_RTSPREQ_RECEIVE + +This is a special request because it does not send any data to the server. The +application may call this function in order to receive interleaved RTP +data. It returns after processing one read buffer of data in order to give the +application a chance to run. + +# DEFAULT + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); + /* ask for options! */ + curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md b/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md new file mode 100644 index 0000000..5210843 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RTSP_SERVER_CSEQ +Section: 3 +Source: libcurl +See-also: + - CURLINFO_RTSP_SERVER_CSEQ (3) + - CURLOPT_RTSP_CLIENT_CSEQ (3) + - CURLOPT_RTSP_STREAM_URI (3) +--- + +# NAME + +CURLOPT_RTSP_SERVER_CSEQ - RTSP server CSEQ number + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RTSP_SERVER_CSEQ, long cseq); +~~~ + +# DESCRIPTION + +Pass a long to set the CSEQ number to expect for the next RTSP Server->Client +request. **NOTE**: this feature (listening for Server requests) is +unimplemented. + +# DEFAULT + +0 + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); + curl_easy_setopt(curl, CURLOPT_RTSP_SERVER_CSEQ, 1234L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md b/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md new file mode 100644 index 0000000..8af7f7c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RTSP_SESSION_ID +Section: 3 +Source: libcurl +See-also: + - CURLOPT_RTSP_REQUEST (3) + - CURLOPT_RTSP_STREAM_URI (3) +--- + +# NAME + +CURLOPT_RTSP_SESSION_ID - RTSP session ID + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RTSP_SESSION_ID, char *id); +~~~ + +# DESCRIPTION + +Pass a char pointer as a parameter to set the value of the current RTSP +Session ID for the handle. Useful for resuming an in-progress session. Once +this value is set to any non-NULL value, libcurl returns +*CURLE_RTSP_SESSION_ERROR* if ID received from the server does not match. If +unset (or set to NULL), libcurl automatically sets the ID the first time the +server sets it in a response. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + char *prev_id; /* saved from before somehow */ + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); + curl_easy_setopt(curl, CURLOPT_RTSP_SESSION_ID, prev_id); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md b/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md new file mode 100644 index 0000000..e138a3c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RTSP_STREAM_URI +Section: 3 +Source: libcurl +See-also: + - CURLOPT_RTSP_REQUEST (3) + - CURLOPT_RTSP_TRANSPORT (3) +--- + +# NAME + +CURLOPT_RTSP_STREAM_URI - RTSP stream URI + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RTSP_STREAM_URI, char *URI); +~~~ + +# DESCRIPTION + +Set the stream *URI* to operate on by passing a char * . For example, a single +session may be controlling *rtsp://foo/twister/audio* and +*rtsp://foo/twister/video* and the application can switch to the appropriate +stream using this option. If unset, libcurl defaults to operating on generic +server options by passing '*' in the place of the RTSP Stream URI. This option +is distinct from CURLOPT_URL(3). When working with RTSP, the +CURLOPT_RTSP_STREAM_URI(3) indicates what URL to send to the server in the +request header while the CURLOPT_URL(3) indicates where to make the connection +to. (e.g. the CURLOPT_URL(3) for the above examples might be set to +*rtsp://foo/twister* + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +"*" + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); + curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, + "rtsp://foo.example.com/twister/video"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md b/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md new file mode 100644 index 0000000..b808396 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_RTSP_TRANSPORT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_RTSP_REQUEST (3) + - CURLOPT_RTSP_SESSION_ID (3) +--- + +# NAME + +CURLOPT_RTSP_TRANSPORT - RTSP Transport: header + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RTSP_TRANSPORT, + char *transport); +~~~ + +# DESCRIPTION + +Pass a char pointer to tell libcurl what to pass for the Transport: header for +this RTSP session. This is mainly a convenience method to avoid needing to set +a custom Transport: header for every SETUP request. The application must set a +Transport: header before issuing a SETUP request. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +RTSP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); + curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP); + curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT, + "RTP/AVP;unicast;client_port=4588-4589"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.20.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md b/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md new file mode 100644 index 0000000..5ff67c6 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SASL_AUTHZID +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PASSWORD (3) + - CURLOPT_USERNAME (3) + - CURLOPT_USERPWD (3) +--- + +# NAME + +CURLOPT_SASL_AUTHZID - authorization identity (identity to act as) + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SASL_AUTHZID, char *authzid); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be pointing to the +null-terminated authorization identity (*authzid*) for the transfer. Only +applicable to the PLAIN SASL authentication mechanism where it is optional. + +When not specified only the authentication identity (*authcid*) as +specified by the username is sent to the server, along with the password. The +server derives a *authzid* from the *authcid* when not provided, which +it then uses internally. + +When the *authzid* is specified, the use of which is server dependent, it +can be used to access another user's inbox, that the user has been granted +access to, or a shared mailbox for example. + +# DEFAULT + +blank + +# PROTOCOLS + +IMAP, LDAP, POP3 and SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "imap://example.com/"); + curl_easy_setopt(curl, CURLOPT_USERNAME, "Kurt"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "xipj3plmq"); + curl_easy_setopt(curl, CURLOPT_SASL_AUTHZID, "Ursel"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.66.0. Support for OpenLDAP added in 7.82.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SASL_IR.md b/docs/libcurl/opts/CURLOPT_SASL_IR.md new file mode 100644 index 0000000..204734d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SASL_IR.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SASL_IR +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAIL_AUTH (3) + - CURLOPT_MAIL_FROM (3) + - CURLOPT_SASL_AUTHZID (3) +--- + +# NAME + +CURLOPT_SASL_IR - send initial response in first packet + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SASL_IR, long enable); +~~~ + +# DESCRIPTION + +Pass a long. If the value is 1, curl sends the initial response to the server +in the first authentication packet in order to reduce the number of ping pong +requests. Only applicable to the following supporting SASL authentication +mechanisms: + +* Login +* Plain +* GSSAPI +* NTLM +* OAuth 2.0 + +Note: Whilst IMAP supports this option there is no need to explicitly set it, +as libcurl can determine the feature itself when the server supports the +SASL-IR CAPABILITY. + +# DEFAULT + +0 + +# PROTOCOLS + +IMAP, POP3 and SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/"); + curl_easy_setopt(curl, CURLOPT_SASL_IR, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.31.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SEEKDATA.md b/docs/libcurl/opts/CURLOPT_SEEKDATA.md new file mode 100644 index 0000000..9392c23 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SEEKDATA.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SEEKDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_IOCTLFUNCTION (3) + - CURLOPT_SEEKFUNCTION (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_SEEKDATA - pointer passed to the seek callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SEEKDATA, void *pointer); +~~~ + +# DESCRIPTION + +Data *pointer* to pass to the seek callback function. If you use the +CURLOPT_SEEKFUNCTION(3) option, this is the pointer you get as input. + +# DEFAULT + +If you do not set this, NULL is passed to the callback. + +# PROTOCOLS + +HTTP, FTP, SFTP + +# EXAMPLE + +~~~c +#include /* for lseek() */ + +struct data { + int our_fd; +}; + +static int seek_cb(void *clientp, curl_off_t offset, int origin) +{ + struct data *d = (struct data *)clientp; + lseek(d->our_fd, offset, origin); + return CURL_SEEKFUNC_OK; +} + +int main(void) +{ + struct data seek_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_cb); + curl_easy_setopt(curl, CURLOPT_SEEKDATA, &seek_data); + } +} +~~~ + +# AVAILABILITY + +Added in 7.18.0 + +# RETURN VALUE + diff --git a/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md b/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md new file mode 100644 index 0000000..102bdcf --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md @@ -0,0 +1,102 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SEEKFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_IOCTLFUNCTION (3) + - CURLOPT_SEEKDATA (3) + - CURLOPT_STDERR (3) +--- + +# NAME + +CURLOPT_SEEKFUNCTION - user callback for seeking in input stream + +# SYNOPSIS + +~~~c +#include + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking cannot be done, so + libcurl might try other means instead */ + +int seek_callback(void *clientp, curl_off_t offset, int origin); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SEEKFUNCTION, seek_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This function gets called by libcurl to seek to a certain position in the +input stream and can be used to fast forward a file in a resumed upload +(instead of reading all uploaded bytes with the normal read +function/callback). It is also called to rewind a stream when data has already +been sent to the server and needs to be sent again. This may happen when doing +an HTTP PUT or POST with a multi-pass authentication method, or when an +existing HTTP connection is reused too late and the server closes the +connection. The function shall work like fseek(3) or lseek(3) and it gets +SEEK_SET, SEEK_CUR or SEEK_END as argument for *origin*, although libcurl +currently only passes SEEK_SET. + +*clientp* is the pointer you set with CURLOPT_SEEKDATA(3). + +The callback function must return *CURL_SEEKFUNC_OK* on success, +*CURL_SEEKFUNC_FAIL* to cause the upload operation to fail or +*CURL_SEEKFUNC_CANTSEEK* to indicate that while the seek failed, libcurl +is free to work around the problem if possible. The latter can sometimes be +done by instead reading from the input or similar. + +If you forward the input arguments directly to fseek(3) or lseek(3), note that +the data type for *offset* is not the same as defined for curl_off_t on +many systems! + +# DEFAULT + +By default, this is NULL and unused. + +# PROTOCOLS + +HTTP, FTP, SFTP + +# EXAMPLE + +~~~c +#include /* for lseek */ + +struct data { + int our_fd; +}; +static int seek_cb(void *clientp, curl_off_t offset, int origin) +{ + struct data *d = (struct data *)clientp; + lseek(d->our_fd, offset, origin); + return CURL_SEEKFUNC_OK; +} + +int main(void) +{ + struct data seek_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_cb); + curl_easy_setopt(curl, CURLOPT_SEEKDATA, &seek_data); + } +} +~~~ + +# AVAILABILITY + +Added in 7.18.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md new file mode 100644 index 0000000..5385d52 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SERVER_RESPONSE_TIMEOUT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT (3) + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_SERVER_RESPONSE_TIMEOUT - time allowed to wait for server response + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVER_RESPONSE_TIMEOUT, + long timeout); +~~~ + +# DESCRIPTION + +Pass a long. Causes libcurl to set a *timeout* period (in seconds) on the +amount of time that the server is allowed to take in order to send a response +message for a command before the session is considered dead. While libcurl is +waiting for a response, this value overrides CURLOPT_TIMEOUT(3). It is +recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set +CURLOPT_SERVER_RESPONSE_TIMEOUT(3) to a value smaller than +CURLOPT_TIMEOUT(3). + +This option was formerly known as CURLOPT_FTP_RESPONSE_TIMEOUT. + +# DEFAULT + +None + +# PROTOCOLS + +FTP, IMAP, POP3, SMTP, and SSH + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/slow.txt"); + /* wait no more than 23 seconds */ + curl_easy_setopt(curl, CURLOPT_SERVER_RESPONSE_TIMEOUT, 23L); + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.10.8. Used under this name since 7.20.0 + +Support for SSH is predicated on a new enough (1.11.0) version of libssh2 +being available when compiling libcurl. + +# RETURN VALUE + +Returns CURLE_OK if supported, and CURLE_UNKNOWN_OPTION if not. Returns +CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value or a value that when +converted to milliseconds is too large. diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md new file mode 100644 index 0000000..a7d9c91 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md @@ -0,0 +1,74 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SERVER_RESPONSE_TIMEOUT_MS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT (3) + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_SERVER_RESPONSE_TIMEOUT_MS - time allowed to wait for server response + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, + long timeout); +~~~ + +# DESCRIPTION + +Pass a long. Causes libcurl to set a *timeout* period (in milliseconds) on the +amount of time that the server is allowed to take in order to send a response +message for a command before the session is considered dead. While libcurl is +waiting for a response, this value overrides CURLOPT_TIMEOUT(3). It is +recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set +CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3) to a value smaller than +CURLOPT_TIMEOUT(3). + +The maximum accepted value is 2147483648. + +This is the millisecond version of CURLOPT_SERVER_RESPONSE_TIMEOUT(3). + +# DEFAULT + +None + +# PROTOCOLS + +FTP, IMAP, POP3, SMTP, and SSH + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/slow.txt"); + /* wait no more than 237 milliseconds */ + curl_easy_setopt(curl, CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, 237L); + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 8.6.0. + +# RETURN VALUE + +Returns CURLE_OK if supported, and CURLE_UNKNOWN_OPTION if not. Returns +CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value or a value that when +converted to milliseconds is too large. diff --git a/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md b/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md new file mode 100644 index 0000000..0e13ca7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SERVICE_NAME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYTYPE (3) + - CURLOPT_PROXY_SERVICE_NAME (3) +--- + +# NAME + +CURLOPT_SERVICE_NAME - authentication service name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVICE_NAME, char *name); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter to a string holding the *name* of the service +for DIGEST-MD5, SPNEGO and Kerberos 5 authentication mechanisms. The default +service names are "ftp", "HTTP", "imap", "ldap", "pop" and "smtp". This option +allows you to change them. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +See above + +# PROTOCOLS + +HTTP, FTP, IMAP, LDAP, POP3 and SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SERVICE_NAME, "custom"); + ret = curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.43.0 for HTTP, 7.49.0 for FTP, IMAP, POP3 and SMTP, +7.82.0 for OpenLDAP. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SHARE.md b/docs/libcurl/opts/CURLOPT_SHARE.md new file mode 100644 index 0000000..3c0e7d2 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SHARE.md @@ -0,0 +1,88 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SHARE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_COOKIE (3) + - CURLSHOPT_SHARE (3) +--- + +# NAME + +CURLOPT_SHARE - share handle to use + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SHARE, CURLSH *share); +~~~ + +# DESCRIPTION + +Pass a *share* handle as a parameter. The share handle must have been +created by a previous call to curl_share_init(3). Setting this option, +makes this curl handle use the data from the shared handle instead of keeping +the data to itself. This enables several curl handles to share data. If the +curl handles are used simultaneously in multiple threads, you **MUST** use +the locking methods in the share handle. See curl_share_setopt(3) for +details. + +If you add a share that is set to share cookies, your easy handle uses that +cookie cache and get the cookie engine enabled. If you stop sharing an object +that was using cookies (or change to another object that does not share +cookies), the easy handle gets its cookie engine disabled. + +Data that the share object is not set to share is dealt with the usual way, as +if no share was used. + +Set this option to NULL again to stop using that share object. + +# DEFAULT + +NULL + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + CURL *curl2 = curl_easy_init(); /* a second handle */ + if(curl) { + CURLcode res; + CURLSH *shobject = curl_share_init(); + curl_share_setopt(shobject, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); + curl_easy_setopt(curl, CURLOPT_SHARE, shobject); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + /* the second handle shares cookies from the first */ + curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/second"); + curl_easy_setopt(curl2, CURLOPT_COOKIEFILE, ""); + curl_easy_setopt(curl2, CURLOPT_SHARE, shobject); + res = curl_easy_perform(curl2); + curl_easy_cleanup(curl2); + + curl_share_cleanup(shobject); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md b/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md new file mode 100644 index 0000000..f44bf53 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SOCKOPTDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_OPENSOCKETFUNCTION (3) + - CURLOPT_SOCKOPTFUNCTION (3) +--- + +# NAME + +CURLOPT_SOCKOPTDATA - pointer to pass to sockopt callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SOCKOPTDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* that is untouched by libcurl and passed as the first +argument in the sockopt callback set with CURLOPT_SOCKOPTFUNCTION(3). + +# DEFAULT + +The default value of this parameter is NULL. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +static int sockopt_callback(void *clientp, curl_socket_t curlfd, + curlsocktype purpose) +{ + int val = *(int *)clientp; + setsockopt((int)curlfd, SOL_SOCKET, SO_RCVBUF, + (const char *)&val, sizeof(val)); + return CURL_SOCKOPT_OK; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + int recvbuffersize = 256 * 1024; + + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + + /* call this function to set options for the socket */ + curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); + curl_easy_setopt(curl, CURLOPT_SOCKOPTDATA, &recvbuffersize); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.0 + +# RETURN VALUE + +Returns *CURLE_OK* if the option is supported, and *CURLE_UNKNOWN_OPTION* if not. diff --git a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md new file mode 100644 index 0000000..f5de316 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md @@ -0,0 +1,132 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SOCKOPTFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_OPENSOCKETFUNCTION (3) + - CURLOPT_SEEKFUNCTION (3) + - CURLOPT_SOCKOPTDATA (3) +--- + +# NAME + +CURLOPT_SOCKOPTFUNCTION - callback for setting socket options + +# SYNOPSIS + +~~~c +#include + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +int sockopt_callback(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +When set, this callback function gets called by libcurl when the socket has +been created, but before the connect call to allow applications to change +specific socket options. The callback's *purpose* argument identifies the +exact purpose for this particular socket: + +*CURLSOCKTYPE_IPCXN* for actively created connections or since 7.28.0 +*CURLSOCKTYPE_ACCEPT* for FTP when the connection was setup with PORT/EPSV +(in earlier versions these sockets were not passed to this callback). + +Future versions of libcurl may support more purposes. libcurl passes the newly +created socket descriptor to the callback in the *curlfd* parameter so +additional setsockopt() calls can be done at the user's discretion. + +The *clientp* pointer contains whatever user-defined value set using the +CURLOPT_SOCKOPTDATA(3) function. + +Return *CURL_SOCKOPT_OK* from the callback on success. Return +*CURL_SOCKOPT_ERROR* from the callback function to signal an unrecoverable +error to the library and it closes the socket and returns +*CURLE_COULDNT_CONNECT*. Alternatively, the callback function can return +*CURL_SOCKOPT_ALREADY_CONNECTED*, to tell libcurl that the socket is +already connected and then libcurl does no attempt to connect. This allows an +application to pass in an already connected socket with +CURLOPT_OPENSOCKETFUNCTION(3) and then have this function make libcurl +not attempt to connect (again). + +# DEFAULT + +By default, this callback is NULL and unused. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +/* make libcurl use the already established socket 'sockfd' */ + +static curl_socket_t opensocket(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address) +{ + curl_socket_t sockfd; + sockfd = *(curl_socket_t *)clientp; + /* the actual externally set socket is passed in via the OPENSOCKETDATA + option */ + return sockfd; +} + +static int sockopt_callback(void *clientp, curl_socket_t curlfd, + curlsocktype purpose) +{ + /* This return code was added in libcurl 7.21.5 */ + return CURL_SOCKOPT_ALREADY_CONNECTED; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + int sockfd; /* our custom file descriptor */ + /* libcurl thinks that you connect to the host + * and port that you specify in the URL option. */ + curl_easy_setopt(curl, CURLOPT_URL, "http://99.99.99.99:9999"); + /* call this function to get a socket */ + curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket); + curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sockfd); + + /* call this function to set options for the socket */ + curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.0. The *CURL_SOCKOPT_ALREADY_CONNECTED* return code was +added in 7.21.5. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md b/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md new file mode 100644 index 0000000..457ef99 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SOCKS5_AUTH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYTYPE (3) +--- + +# NAME + +CURLOPT_SOCKS5_AUTH - methods for SOCKS5 proxy authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SOCKS5_AUTH, long bitmask); +~~~ + +# DESCRIPTION + +Pass a long as parameter, which is set to a bitmask, to tell libcurl which +authentication method(s) are allowed for SOCKS5 proxy authentication. The only +supported flags are *CURLAUTH_BASIC*, which allows username/password +authentication, *CURLAUTH_GSSAPI*, which allows GSS-API authentication, and +*CURLAUTH_NONE*, which allows no authentication. Set the actual user name and +password with the CURLOPT_PROXYUSERPWD(3) option. + +# DEFAULT + +CURLAUTH_BASIC|CURLAUTH_GSSAPI + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* request to use a SOCKS5 proxy */ + curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://user:pass@myproxy.com"); + + /* enable username/password authentication only */ + curl_easy_setopt(curl, CURLOPT_SOCKS5_AUTH, (long)CURLAUTH_BASIC); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.55.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_NOT_BUILT_IN if the bitmask contains unsupported flags. diff --git a/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md new file mode 100644 index 0000000..08a1ced --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md @@ -0,0 +1,63 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SOCKS5_GSSAPI_NEC +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_SOCKS5_GSSAPI_SERVICE (3) +--- + +# NAME + +CURLOPT_SOCKS5_GSSAPI_NEC - SOCKS proxy GSSAPI negotiation protection + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SOCKS5_GSSAPI_NEC, long nec); +~~~ + +# DESCRIPTION + +Pass a long set to 1 to enable or 0 to disable. As part of the GSSAPI +negotiation a protection mode is negotiated. The RFC 1961 says in section +4.3/4.4 it should be protected, but the NEC reference implementation does not. +If enabled, this option allows the unprotected exchange of the protection mode +negotiation. + +# DEFAULT + +? + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://proxy"); + curl_easy_setopt(curl, CURLOPT_SOCKS5_GSSAPI_NEC, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md new file mode 100644 index 0000000..47f6e28 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SOCKS5_GSSAPI_SERVICE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY (3) + - CURLOPT_PROXYTYPE (3) +--- + +# NAME + +CURLOPT_SOCKS5_GSSAPI_SERVICE - SOCKS5 proxy authentication service name + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SOCKS5_GSSAPI_SERVICE, + char *name); +~~~ + +# DESCRIPTION + +Deprecated since 7.49.0. Use CURLOPT_PROXY_SERVICE_NAME(3) instead. + +Pass a char pointer as parameter to a string holding the *name* of the +service. The default service name for a SOCKS5 server is *rcmd*. This option +allows you to change it. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +See above + +# PROTOCOLS + +All network protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://proxy"); + curl_easy_setopt(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE, "rcmd-special"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.4, deprecated in 7.49.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md b/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md new file mode 100644 index 0000000..205e94d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_AUTH_TYPES +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3) + - CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 (3) + - CURLOPT_SSH_PUBLIC_KEYFILE (3) +--- + +# NAME + +CURLOPT_SSH_AUTH_TYPES - auth types for SFTP and SCP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_AUTH_TYPES, long bitmask); +~~~ + +# DESCRIPTION + +Pass a long set to a bitmask consisting of one or more of +CURLSSH_AUTH_PUBLICKEY, CURLSSH_AUTH_PASSWORD, CURLSSH_AUTH_HOST, +CURLSSH_AUTH_KEYBOARD and CURLSSH_AUTH_AGENT. + +Set *CURLSSH_AUTH_ANY* to let libcurl pick a suitable one. Currently +CURLSSH_AUTH_HOST has no effect. If CURLSSH_AUTH_AGENT is used, libcurl +attempts to connect to ssh-agent or pageant and let the agent attempt the +authentication. + +# DEFAULT + +CURLSSH_AUTH_ANY (all available) + +# PROTOCOLS + +SFTP and SCP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file"); + curl_easy_setopt(curl, CURLOPT_SSH_AUTH_TYPES, + CURLSSH_AUTH_PUBLICKEY | CURLSSH_AUTH_KEYBOARD); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +CURLSSH_AUTH_HOST was added in 7.16.1, CURLSSH_AUTH_AGENT was added in 7.28.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md b/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md new file mode 100644 index 0000000..5e2b278 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_COMPRESSION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ACCEPT_ENCODING (3) + - CURLOPT_TRANSFER_ENCODING (3) +--- + +# NAME + +CURLOPT_SSH_COMPRESSION - enable SSH compression + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_COMPRESSION, long enable); +~~~ + +# DESCRIPTION + +Pass a long as parameter set to 1L to enable or 0L to disable. + +Enables built-in SSH compression. This is a request, not an order; the server +may or may not do it. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +All SSH based protocols: SCP, SFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com"); + + /* enable built-in compression */ + curl_easy_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.56.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md new file mode 100644 index 0000000..39cbd0d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md @@ -0,0 +1,73 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_KEYDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_HOSTKEYFUNCTION (3) +--- + +# NAME + +CURLOPT_SSH_HOSTKEYDATA - pointer to pass to the SSH host key callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_HOSTKEYDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a void * as parameter. This *pointer* is passed along untouched to +the callback set with CURLOPT_SSH_HOSTKEYFUNCTION(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +SCP and SFTP + +# EXAMPLE + +~~~c +struct mine { + void *custom; +}; + +static int hostkeycb(void *clientp, /* CURLOPT_SSH_HOSTKEYDATA */ + int keytype, /* CURLKHTYPE */ + const char *key, /* host key to check */ + size_t keylen) /* length of the key */ +{ + /* 'clientp' points to the callback_data struct */ + /* investigate the situation and return the correct value */ + return CURLKHMATCH_OK; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct mine callback_data; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/thisfile.txt"); + curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYFUNCTION, hostkeycb); + curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYDATA, &callback_data); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.84.0, works only with libssh2 backend. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md new file mode 100644 index 0000000..ed57975 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md @@ -0,0 +1,98 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_HOSTKEYFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_HOSTKEYDATA (3) + - CURLOPT_SSH_KNOWNHOSTS (3) +--- + +# NAME + +CURLOPT_SSH_HOSTKEYFUNCTION - callback to check host key + +# SYNOPSIS + +~~~c +#include + +int keycallback(void *clientp, + int keytype, + const char *key, + size_t keylen); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_HOSTKEYFUNCTION, + keycallback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. It overrides CURLOPT_SSH_KNOWNHOSTS(3). + +This callback gets called when the verification of the SSH host key is needed. + +**key** is **keylen** bytes long and is the key to check. **keytype** +says what type it is, from the **CURLKHTYPE_*** series in the +**curl_khtype** enum. + +**clientp** is a custom pointer set with CURLOPT_SSH_HOSTKEYDATA(3). + +The callback MUST return one of the following return codes to tell libcurl how +to act: + +## CURLKHMATCH_OK + +The host key is accepted, the connection should continue. + +## CURLKHMATCH_MISMATCH + +the host key is rejected, the connection is canceled. + +# DEFAULT + +NULL + +# PROTOCOLS + +SCP and SFTP + +# EXAMPLE + +~~~c +struct mine { + void *custom; +}; + +int hostkeycb(void *clientp, /* passed with CURLOPT_SSH_HOSTKEYDATA */ + int keytype, /* CURLKHTYPE */ + const char *key, /* host key to check */ + size_t keylen) /* length of the key */ +{ + /* 'clientp' points to the callback_data struct */ + /* investigate the situation and return the correct value */ + return CURLKHMATCH_OK; +} +int main(void) +{ + struct mine callback_data; + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/thisfile.txt"); + curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYFUNCTION, hostkeycb); + curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYDATA, &callback_data); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.84.0 , work only with libssh2 backend. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md new file mode 100644 index 0000000..4b78765 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_AUTH_TYPES (3) + - CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 (3) + - CURLOPT_SSH_KNOWNHOSTS (3) + - CURLOPT_SSH_PUBLIC_KEYFILE (3) +--- + +# NAME + +CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 - MD5 checksum of SSH server public key + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, + char *md5); +~~~ + +# DESCRIPTION + +Pass a char pointer pointing to a string containing 32 hexadecimal digits. The +string should be the 128 bit MD5 checksum of the remote host's public key, and +libcurl aborts the connection to the host unless the MD5 checksum match. + +MD5 is a weak algorithm. We strongly recommend using +CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3) instead. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +SCP and SFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file"); + curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, + "afe17cd62a0f3b61f1ab9cb22ba269a7"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.17.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md new file mode 100644 index 0000000..41562db --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_AUTH_TYPES (3) + - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3) + - CURLOPT_SSH_PUBLIC_KEYFILE (3) +--- + +# NAME + +CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 - SHA256 hash of SSH server public key + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, + char *sha256); +~~~ + +# DESCRIPTION + +Pass a char pointer pointing to a string containing a Base64-encoded SHA256 +hash of the remote host's public key. The transfer fails if the given hash +does not match the hash the remote host provides. + +# DEFAULT + +NULL + +# PROTOCOLS + +SCP and SFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file"); + curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, + "NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ="); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.80.0 +Requires the libssh2 backend. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md b/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md new file mode 100644 index 0000000..e90cace --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_KEYDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_KEYDATA (3) + - CURLOPT_SSH_KNOWNHOSTS (3) +--- + +# NAME + +CURLOPT_SSH_KEYDATA - pointer passed to the SSH key callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_KEYDATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a void * as parameter. This *pointer* is passed along verbatim to the +callback set with CURLOPT_SSH_KEYFUNCTION(3). + +# DEFAULT + +NULL + +# PROTOCOLS + +SFTP and SCP + +# EXAMPLE + +~~~c +struct mine { + void *custom; +}; +static int keycb(CURL *easy, + const struct curl_khkey *knownkey, + const struct curl_khkey *foundkey, + enum curl_khmatch match, + void *clientp) +{ + /* 'clientp' points to the callback_data struct */ + /* investigate the situation and return the correct value */ + return CURLKHSTAT_FINE_ADD_TO_FILE; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct mine callback_data; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/thisfile.txt"); + curl_easy_setopt(curl, CURLOPT_SSH_KEYFUNCTION, keycb); + curl_easy_setopt(curl, CURLOPT_SSH_KEYDATA, &callback_data); + curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/user/known_hosts"); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.6 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md new file mode 100644 index 0000000..5fc4006 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md @@ -0,0 +1,152 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_KEYFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_KEYDATA (3) + - CURLOPT_SSH_KNOWNHOSTS (3) +--- + +# NAME + +CURLOPT_SSH_KEYFUNCTION - callback for known host matching logic + +# SYNOPSIS + +~~~c +#include + +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we cannot answer right + now. Causes a CURLE_PEER_FAILED_VERIFICATION error but + the connection is left intact */ + CURLKHSTAT_FINE_REPLACE +}; + +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ +}; + +struct curl_khkey { + const char *key; /* points to a null-terminated string encoded with + base64 if len is zero, otherwise to the "raw" + data */ + size_t len; + enum curl_khtype keytype; +}; + +int ssh_keycallback(CURL *easy, + const struct curl_khkey *knownkey, + const struct curl_khkey *foundkey, + enum curl_khmatch match, + void *clientp); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_KEYFUNCTION, + ssh_keycallback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +It gets called when the known_host matching has been done, to allow the +application to act and decide for libcurl how to proceed. The callback is only +called if CURLOPT_SSH_KNOWNHOSTS(3) is also set. + +This callback function gets passed the CURL handle, the key from the +known_hosts file *knownkey*, the key from the remote site *foundkey*, +info from libcurl on the matching status and a custom pointer (set with +CURLOPT_SSH_KEYDATA(3)). It MUST return one of the following return +codes to tell libcurl how to act: + +## CURLKHSTAT_FINE_REPLACE + +The new host+key is accepted and libcurl replaces the old host+key into the +known_hosts file before continuing with the connection. This also adds the new +host+key combo to the known_host pool kept in memory if it was not already +present there. The adding of data to the file is done by completely replacing +the file with a new copy, so the permissions of the file must allow +this. (Added in 7.73.0) + +## CURLKHSTAT_FINE_ADD_TO_FILE + +The host+key is accepted and libcurl appends it to the known_hosts file before +continuing with the connection. This also adds the host+key combo to the +known_host pool kept in memory if it was not already present there. The adding +of data to the file is done by completely replacing the file with a new copy, +so the permissions of the file must allow this. + +## CURLKHSTAT_FINE + +The host+key is accepted libcurl continues with the connection. This also adds +the host+key combo to the known_host pool kept in memory if it was not already +present there. + +## CURLKHSTAT_REJECT + +The host+key is rejected. libcurl denies the connection to continue and it is +closed. + +## CURLKHSTAT_DEFER + +The host+key is rejected, but the SSH connection is asked to be kept alive. +This feature could be used when the app wants to return and act on the +host+key situation and then retry without needing the overhead of setting it +up from scratch again. + +# DEFAULT + +NULL + +# PROTOCOLS + +SFTP and SCP + +# EXAMPLE + +~~~c +struct mine { + void *custom; +}; + +static int keycb(CURL *easy, + const struct curl_khkey *knownkey, + const struct curl_khkey *foundkey, + enum curl_khmatch match, + void *clientp) +{ + /* 'clientp' points to the callback_data struct */ + /* investigate the situation and return the correct value */ + return CURLKHSTAT_FINE_ADD_TO_FILE; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct mine callback_data; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/thisfile.txt"); + curl_easy_setopt(curl, CURLOPT_SSH_KEYFUNCTION, keycb); + curl_easy_setopt(curl, CURLOPT_SSH_KEYDATA, &callback_data); + curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/user/known_hosts"); + + curl_easy_perform(curl); +} +} +~~~ + +# AVAILABILITY + +Added in 7.19.6 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md b/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md new file mode 100644 index 0000000..5a5fcbf --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_KNOWNHOSTS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_AUTH_TYPES (3) + - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3) +--- + +# NAME + +CURLOPT_SSH_KNOWNHOSTS - filename holding the SSH known hosts + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_KNOWNHOSTS, char *fname); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string holding the filename of the +known_host file to use. The known_hosts file should use the OpenSSH file +format as supported by libssh2. If this file is specified, libcurl only +accepts connections with hosts that are known and present in that file, with a +matching public key. Use CURLOPT_SSH_KEYFUNCTION(3) to alter the default +behavior on host and key matches and mismatches. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +SFTP and SCP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file"); + curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, + "/home/clarkkent/.ssh/known_hosts"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.6 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md b/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md new file mode 100644 index 0000000..e8a4007 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md @@ -0,0 +1,76 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_PRIVATE_KEYFILE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_AUTH_TYPES (3) + - CURLOPT_SSH_PUBLIC_KEYFILE (3) +--- + +# NAME + +CURLOPT_SSH_PRIVATE_KEYFILE - private key file for SSH auth + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_PRIVATE_KEYFILE, + char *filename); +~~~ + +# DESCRIPTION + +Pass a char pointer pointing to a *filename* for your private key. If not +used, libcurl defaults to **$HOME/.ssh/id_rsa** or **$HOME/.ssh/id_dsa** if +the HOME environment variable is set, and in the current directory if HOME is +not set. + +If the file is password-protected, set the password with +CURLOPT_KEYPASSWD(3). + +The SSH library derives the public key from this private key when possible. If +the SSH library cannot derive the public key from the private one and no +public one is provided with CURLOPT_SSH_PUBLIC_KEYFILE(3), the transfer +fails. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +As explained above + +# PROTOCOLS + +SFTP and SCP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file"); + curl_easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, + "/home/clarkkent/.ssh/id_rsa"); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "password"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md b/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md new file mode 100644 index 0000000..35d65ad --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSH_PUBLIC_KEYFILE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSH_AUTH_TYPES (3) + - CURLOPT_SSH_PRIVATE_KEYFILE (3) +--- + +# NAME + +CURLOPT_SSH_PUBLIC_KEYFILE - public key file for SSH auth + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_PUBLIC_KEYFILE, + char *filename); +~~~ + +# DESCRIPTION + +Pass a char pointer pointing to a *filename* for your public key. If not used, +libcurl defaults to **$HOME/.ssh/id_dsa.pub** if the HOME environment variable +is set, and just "id_dsa.pub" in the current directory if HOME is not set. + +If NULL (or an empty string) is passed to this option, libcurl passes no +public key to the SSH library, which then rather derives it from the private +key. If the SSH library cannot derive the public key from the private one and +no public one is provided, the transfer fails. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +SFTP and SCP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file"); + curl_easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, + "/home/clarkkent/.ssh/id_rsa.pub"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +The "" trick was added in 7.26.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLCERT.md b/docs/libcurl/opts/CURLOPT_SSLCERT.md new file mode 100644 index 0000000..21f052f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLCERT.md @@ -0,0 +1,87 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLCERT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_KEYPASSWD (3) + - CURLOPT_SSLCERTTYPE (3) + - CURLOPT_SSLKEY (3) +--- + +# NAME + +CURLOPT_SSLCERT - SSL client certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLCERT, char *cert); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the filename of your client certificate. The default format is "P12" on Secure +Transport and "PEM" on other engines, and can be changed with +CURLOPT_SSLCERTTYPE(3). + +With Secure Transport, this can also be the nickname of the certificate you +wish to authenticate with as it is named in the security database. If you want +to use a file from the current directory, please precede it with "./" prefix, +in order to avoid confusion with a nickname. + +(Schannel only) Client certificates can be specified by a path expression to a +certificate store. (You can import *PFX* to a store first). You can use +"" to refer to a certificate in the +system certificates store, for example, +**"CurrentUserMY934a7ac6f8a5d579285a74fa"**. The thumbprint is usually a SHA-1 +hex string which you can see in certificate details. Following store locations +are supported: **CurrentUser**, **LocalMachine**, **CurrentService**, +**Services**, **CurrentUserGroupPolicy**, **LocalMachineGroupPolicy**, +**LocalMachineEnterprise**. Schannel also support P12 certificate file, with +the string "P12" specified with CURLOPT_SSLCERTTYPE(3). + +When using a client certificate, you most likely also need to provide a +private key with CURLOPT_SSLKEY(3). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md b/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md new file mode 100644 index 0000000..420ca4f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLCERTTYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSLCERT (3) + - CURLOPT_SSLKEY (3) +--- + +# NAME + +CURLOPT_SSLCERTTYPE - type of client SSL certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLCERTTYPE, char *type); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the format of your certificate. + +Supported formats are "PEM" and "DER", except with Secure Transport or +Schannel. OpenSSL (versions 0.9.3 and later), Secure Transport (on iOS 5 or +later, or OS X 10.7 or later) and Schannel support "P12" for PKCS#12-encoded +files. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +"PEM" + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); + curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If built TLS enabled. Added in 7.9.3 + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md new file mode 100644 index 0000000..1f3ed56 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md @@ -0,0 +1,83 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLCERT_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_KEYPASSWD (3) + - CURLOPT_SSLCERTTYPE (3) + - CURLOPT_SSLKEY (3) +--- + +# NAME + +CURLOPT_SSLCERT_BLOB - SSL client certificate from memory blob + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLCERT_BLOB, + struct curl_blob *stblob); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_blob structure, which contains (pointer and size) a +client certificate. The format must be "P12" on Secure Transport or +Schannel. The format must be "P12" or "PEM" on OpenSSL. The format must be +"DER" or "PEM" on mbedTLS. The format must be specified with +CURLOPT_SSLCERTTYPE(3). + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +This option is an alternative to CURLOPT_SSLCERT(3) which instead +expects a filename as input. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c + +extern char *certificateData; /* point to data */ +extern size_t filesize; /* size of data */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob stblob; + stblob.data = certificateData; + stblob.len = filesize; + stblob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSLCERT_BLOB, &stblob); + curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "P12"); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.71.0. This option is supported by the OpenSSL, Secure Transport, +Schannel and mbedTLS (since 7.78.0) backends. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLENGINE.md b/docs/libcurl/opts/CURLOPT_SSLENGINE.md new file mode 100644 index 0000000..45ccc42 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLENGINE.md @@ -0,0 +1,74 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLENGINE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_SSL_ENGINES (3) + - CURLOPT_SSLENGINE_DEFAULT (3) + - CURLOPT_SSLKEY (3) +--- + +# NAME + +CURLOPT_SSLENGINE - SSL engine identifier + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLENGINE, char *id); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. It is used as the +identifier for the crypto engine you want to use for your private key. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSLENGINE, "dynamic"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Only if the SSL backend is OpenSSL built with engine support. + +# RETURN VALUE + +CURLE_OK - Engine found. + +CURLE_SSL_ENGINE_NOTFOUND - Engine not found, or OpenSSL was not built with +engine support. + +CURLE_SSL_ENGINE_INITFAILED - Engine found but initialization failed. + +CURLE_NOT_BUILT_IN - Option not built in, OpenSSL is not the SSL backend. + +CURLE_UNKNOWN_OPTION - Option not recognized. + +CURLE_OUT_OF_MEMORY - Insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md b/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md new file mode 100644 index 0000000..d082f7b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLENGINE_DEFAULT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSLCERT (3) + - CURLOPT_SSLENGINE (3) +--- + +# NAME + +CURLOPT_SSLENGINE_DEFAULT - make SSL engine default + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLENGINE_DEFAULT, long val); +~~~ + +# DESCRIPTION + +Pass a long set to 1 to make the already specified crypto engine the default +for (asymmetric) crypto operations. + +This option has no effect unless set after CURLOPT_SSLENGINE(3). + +# DEFAULT + +None + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSLENGINE, "dynamic"); + curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Only if the SSL backend is OpenSSL built with engine support. + +# RETURN VALUE + +CURLE_OK - Engine set as default. + +CURLE_SSL_ENGINE_SETFAILED - Engine could not be set as default. + +CURLE_NOT_BUILT_IN - Option not built in, OpenSSL is not the SSL backend. + +CURLE_UNKNOWN_OPTION - Option not recognized. + +CURLE_OUT_OF_MEMORY - Insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLKEY.md b/docs/libcurl/opts/CURLOPT_SSLKEY.md new file mode 100644 index 0000000..292258f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLKEY.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLKEY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSLCERT (3) + - CURLOPT_SSLKEYTYPE (3) + - CURLOPT_SSLKEY_BLOB (3) +--- + +# NAME + +CURLOPT_SSLKEY - private key file for TLS and SSL client cert + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLKEY, char *keyfile); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the filename of your private key. The default format is "PEM" and can be +changed with CURLOPT_SSLKEYTYPE(3). + +(Windows, iOS and Mac OS X) This option is ignored by Secure Transport and +Schannel SSL backends because they expect the private key to be already present +in the key-chain or PKCS#12 file containing the certificate. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md b/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md new file mode 100644 index 0000000..b3f1141 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLKEYTYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLKEYTYPE (3) + - CURLOPT_SSLCERT (3) + - CURLOPT_SSLKEY (3) +--- + +# NAME + +CURLOPT_SSLKEYTYPE - type of the private key file + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLKEYTYPE, char *type); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the format of your private key. Supported formats are "PEM", "DER" and "ENG". + +The format "ENG" enables you to load the private key from a crypto engine. In +this case CURLOPT_SSLKEY(3) is used as an identifier passed to the engine. You +have to set the crypto engine with CURLOPT_SSLENGINE(3). "DER" format key file +currently does not work because of a bug in OpenSSL. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +"PEM" + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem"); + curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem"); + curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM"); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md b/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md new file mode 100644 index 0000000..7442569 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md @@ -0,0 +1,87 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLKEY_BLOB +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSLKEY (3) + - CURLOPT_SSLKEYTYPE (3) +--- + +# NAME + +CURLOPT_SSLKEY_BLOB - private key for client cert from memory blob + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLKEY_BLOB, + struct curl_blob *blob); +~~~ + +# DESCRIPTION + +Pass a pointer to a curl_blob structure, which contains information (pointer +and size) for a private key. Compatible with OpenSSL. The format (like "PEM") +must be specified with CURLOPT_SSLKEYTYPE(3). + +If the blob is initialized with the flags member of struct curl_blob set to +CURL_BLOB_COPY, the application does not have to keep the buffer around after +setting this. + +This option is an alternative to CURLOPT_SSLKEY(3) which instead expects a +filename as input. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c + +extern char *certificateData; /* point to cert */ +extern size_t filesize; /* size of cert */ + +extern char *privateKeyData; /* point to key */ +extern size_t privateKeySize; /* size of key */ + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_blob blob; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + blob.data = certificateData; + blob.len = filesize; + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl, CURLOPT_SSLCERT_BLOB, &blob); + curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); + + blob.data = privateKeyData; + blob.len = privateKeySize; + curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, &blob); + curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret"); + curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.71.0. This option is supported by the OpenSSL backends. + +# RETURN VALUE + +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_SSLVERSION.md new file mode 100644 index 0000000..f64a13b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.md @@ -0,0 +1,143 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSLVERSION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTP_VERSION (3) + - CURLOPT_IPRESOLVE (3) + - CURLOPT_PROXY_SSLVERSION (3) + - CURLOPT_USE_SSL (3) +--- + +# NAME + +CURLOPT_SSLVERSION - preferred TLS/SSL version + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLVERSION, long version); +~~~ + +# DESCRIPTION + +Pass a long as parameter to control which version range of SSL/TLS versions to +use. + +The SSL and TLS versions have typically developed from the most insecure +version to be more and more secure in this order through history: SSL v2, +SSLv3, TLS v1.0, TLS v1.1, TLS v1.2 and the most recent TLS v1.3. + +Use one of the available defines for this purpose. The available options are: + +## CURL_SSLVERSION_DEFAULT + +The default acceptable version range. The minimum acceptable version is by +default TLS v1.0 since 7.39.0 (unless the TLS library has a stricter rule). + +## CURL_SSLVERSION_TLSv1 + +TLS v1.0 or later + +## CURL_SSLVERSION_SSLv2 + +SSL v2 - refused + +## CURL_SSLVERSION_SSLv3 + +SSL v3 - refused + +## CURL_SSLVERSION_TLSv1_0 + +TLS v1.0 or later (Added in 7.34.0) + +## CURL_SSLVERSION_TLSv1_1 + +TLS v1.1 or later (Added in 7.34.0) + +## CURL_SSLVERSION_TLSv1_2 + +TLS v1.2 or later (Added in 7.34.0) + +## CURL_SSLVERSION_TLSv1_3 + +TLS v1.3 or later (Added in 7.52.0) + +The maximum TLS version can be set by using *one* of the +CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the +CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros. +The MAX macros are not supported for WolfSSL. + +## CURL_SSLVERSION_MAX_DEFAULT + +The flag defines the maximum supported TLS version by libcurl, or the default +value from the SSL library is used. libcurl uses a sensible default maximum, +which was TLS v1.2 up to before 7.61.0 and is TLS v1.3 since then - assuming +the TLS library support it. (Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_0 + +The flag defines maximum supported TLS version as TLS v1.0. +(Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_1 + +The flag defines maximum supported TLS version as TLS v1.1. +(Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_2 + +The flag defines maximum supported TLS version as TLS v1.2. +(Added in 7.54.0) + +## CURL_SSLVERSION_MAX_TLSv1_3 + +The flag defines maximum supported TLS version as TLS v1.3. +(Added in 7.54.0) + +In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were +documented to allow *only* the specified TLS version, but behavior was +inconsistent depending on the TLS library. + +# DEFAULT + +CURL_SSLVERSION_DEFAULT + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* ask libcurl to use TLS version 1.0 or later */ + curl_easy_setopt(curl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +SSLv2 and SSLv3 are refused completely since curl 7.77.0 + +SSLv2 is disabled by default since 7.18.1. Other SSL versions availability may +vary depending on which backend libcurl has been built to use. + +SSLv3 is disabled by default since 7.39.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md new file mode 100644 index 0000000..c96c93f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md @@ -0,0 +1,92 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_CIPHER_LIST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSL_CIPHER_LIST (3) + - CURLOPT_PROXY_TLS13_CIPHERS (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_TLS13_CIPHERS (3) + - CURLOPT_USE_SSL (3) +--- + +# NAME + +CURLOPT_SSL_CIPHER_LIST - ciphers to use for TLS + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_CIPHER_LIST, char *list); +~~~ + +# DESCRIPTION + +Pass a char pointer, pointing to a null-terminated string holding the list of +ciphers to use for the SSL connection. The list must be syntactically correct, +it consists of one or more cipher strings separated by colons. Commas or +spaces are also acceptable separators but colons are normally used, !, - and ++ can be used as operators. + +For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**, +**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally set when +you compile OpenSSL. + +For WolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**, +**AES256-SHA:AES256-SHA256**, etc. + +For BearSSL, valid examples of cipher lists include +**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using +IANA names +**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**, +etc. With BearSSL you do not add/remove ciphers. If one uses this option then +all known ciphers are disabled and only those passed in are enabled. + +For Schannel, you can use this option to set algorithms but not specific +cipher suites. Refer to the ciphers lists document for algorithms. + +Find more details about cipher lists on this URL: + + https://curl.se/docs/ssl-ciphers.html + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL, use internal default + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "TLSv1"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.9, in 7.83.0 for BearSSL + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md b/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md new file mode 100644 index 0000000..6e328a5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md @@ -0,0 +1,124 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_CTX_DATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSLVERSION (3) + - CURLOPT_SSL_CTX_FUNCTION (3) +--- + +# NAME + +CURLOPT_SSL_CTX_DATA - pointer passed to SSL context callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_CTX_DATA, void *pointer); +~~~ + +# DESCRIPTION + +Data *pointer* to pass to the ssl context callback set by the option +CURLOPT_SSL_CTX_FUNCTION(3), this is the pointer you get as third +parameter. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +/* OpenSSL specific */ + +#include +#include +#include + +static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) +{ + X509_STORE *store; + X509 *cert = NULL; + BIO *bio; + char *mypem = parm; + /* get a BIO */ + bio = BIO_new_mem_buf(mypem, -1); + /* use it to read the PEM formatted certificate from memory into an + * X509 structure that SSL can use + */ + PEM_read_bio_X509(bio, &cert, 0, NULL); + if(!cert) + printf("PEM_read_bio_X509 failed...\n"); + + /* get a pointer to the X509 certificate store (which may be empty) */ + store = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); + + /* add our certificate to this store */ + if(X509_STORE_add_cert(store, cert) == 0) + printf("error adding certificate\n"); + + /* decrease reference counts */ + X509_free(cert); + BIO_free(bio); + + /* all set to go */ + return CURLE_OK; +} + +int main(void) +{ + CURL *ch; + CURLcode rv; + char *mypem = /* example CA cert PEM - shortened */ + "-----BEGIN CERTIFICATE-----\n" + "MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n" + "IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n" + "IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n" + "Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n" + "GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n" + "zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n" + "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n" + "-----END CERTIFICATE-----\n"; + + curl_global_init(CURL_GLOBAL_ALL); + ch = curl_easy_init(); + + curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); + + curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); + curl_easy_setopt(ch, CURLOPT_SSL_CTX_DATA, mypem); + rv = curl_easy_perform(ch); + if(!rv) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + curl_easy_cleanup(ch); + curl_global_cleanup(); + return rv; +} +~~~ + +# AVAILABILITY + +Added in 7.11.0 for OpenSSL, in 7.42.0 for wolfSSL, in 7.54.0 for mbedTLS, +in 7.83.0 in BearSSL. Other SSL backends are not supported. + +# RETURN VALUE + +CURLE_OK if supported; or an error such as: + +CURLE_NOT_BUILT_IN - Not supported by the SSL backend + +CURLE_UNKNOWN_OPTION diff --git a/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md b/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md new file mode 100644 index 0000000..ae8b8bb --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md @@ -0,0 +1,167 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_CTX_FUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSL_CTX_DATA (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_SSL_CTX_FUNCTION - SSL context callback for OpenSSL, wolfSSL or mbedTLS + +# SYNOPSIS + +~~~c +#include + +CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *clientp); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_CTX_FUNCTION, + ssl_ctx_callback); +~~~ + +# DESCRIPTION + +This option only works for libcurl powered by OpenSSL, wolfSSL, mbedTLS or +BearSSL. If libcurl was built against another SSL library this functionality +is absent. + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl just before the initialization +of an SSL connection after having processed all other SSL related options to +give a last chance to an application to modify the behavior of the SSL +initialization. The *ssl_ctx* parameter is actually a pointer to the SSL +library's *SSL_CTX* for OpenSSL or wolfSSL, a pointer to +*mbedtls_ssl_config* for mbedTLS or a pointer to +*br_ssl_client_context* for BearSSL. If an error is returned from the +callback no attempt to establish a connection is made and the perform +operation returns the callback's error code. Set the *clientp* argument +with the CURLOPT_SSL_CTX_DATA(3) option. + +This function gets called on all new connections made to a server, during the +SSL negotiation. The *ssl_ctx* points to a newly initialized object each +time, but note the pointer may be the same as from a prior call. + +To use this properly, a non-trivial amount of knowledge of your SSL library is +necessary. For example, you can use this function to call library-specific +callbacks to add additional validation code for certificates, and even to +change the actual URI of an HTTPS request. + +For OpenSSL, asynchronous certificate verification via +*SSL_set_retry_verify* is supported. (Added in 8.3.0) + +WARNING: The CURLOPT_SSL_CTX_FUNCTION(3) callback allows the application +to reach in and modify SSL details in the connection without libcurl itself +knowing anything about it, which then subsequently can lead to libcurl +unknowingly reusing SSL connections with different properties. To remedy this +you may set CURLOPT_FORBID_REUSE(3) from the callback function. + +WARNING: If you are using DNS-over-HTTPS (DoH) via CURLOPT_DOH_URL(3) +then this callback is also called for those transfers and the curl handle is +set to an internal handle. **This behavior is subject to change.** We +recommend before performing your transfer set CURLOPT_PRIVATE(3) on your +curl handle so you can identify it in the context callback. If you have a +reason to modify DoH SSL context please let us know on the curl-library +mailing list because we are considering removing this capability. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +/* OpenSSL specific */ + +#include +#include +#include + +static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) +{ + X509_STORE *store; + X509 *cert = NULL; + BIO *bio; + char *mypem = parm; + /* get a BIO */ + bio = BIO_new_mem_buf(mypem, -1); + /* use it to read the PEM formatted certificate from memory into an + * X509 structure that SSL can use + */ + PEM_read_bio_X509(bio, &cert, 0, NULL); + if(!cert) + printf("PEM_read_bio_X509 failed...\n"); + + /* get a pointer to the X509 certificate store (which may be empty) */ + store = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); + + /* add our certificate to this store */ + if(X509_STORE_add_cert(store, cert) == 0) + printf("error adding certificate\n"); + + /* decrease reference counts */ + X509_free(cert); + BIO_free(bio); + + /* all set to go */ + return CURLE_OK; +} + +int main(void) +{ + CURL *ch; + CURLcode rv; + char *mypem = /* example CA cert PEM - shortened */ + "-----BEGIN CERTIFICATE-----\n" + "MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n" + "IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n" + "IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n" + "Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n" + "GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n" + "zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n" + "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n" + "-----END CERTIFICATE-----\n"; + + curl_global_init(CURL_GLOBAL_ALL); + ch = curl_easy_init(); + + curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); + + curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); + curl_easy_setopt(ch, CURLOPT_SSL_CTX_DATA, mypem); + rv = curl_easy_perform(ch); + if(!rv) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + curl_easy_cleanup(ch); + curl_global_cleanup(); + return rv; +} +~~~ + +# AVAILABILITY + +Added in 7.11.0 for OpenSSL, in 7.42.0 for wolfSSL, in 7.54.0 for mbedTLS, +in 7.83.0 in BearSSL. Other SSL backends are not supported. + +# RETURN VALUE + +CURLE_OK if supported; or an error such as: + +CURLE_NOT_BUILT_IN - Not supported by the SSL backend + +CURLE_UNKNOWN_OPTION diff --git a/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md b/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md new file mode 100644 index 0000000..adfaae3 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md @@ -0,0 +1,61 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_EC_CURVES +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSL_CIPHER_LIST (3) + - CURLOPT_SSL_OPTIONS (3) + - CURLOPT_TLS13_CIPHERS (3) +--- + +# NAME + +CURLOPT_SSL_EC_CURVES - key exchange curves + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_EC_CURVES, char *alg_list); +~~~ + +# DESCRIPTION + +Pass a string as parameter with a colon delimited list of (EC) algorithms. This +option defines the client's key exchange algorithms in the SSL handshake (if +the SSL backend libcurl is built to use supports it). + +# DEFAULT + +"", embedded in SSL backend + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSL_EC_CURVES, "X25519:P-521"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.73.0. Supported by the OpenSSL backend. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md new file mode 100644 index 0000000..e1b456a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md @@ -0,0 +1,60 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_ENABLE_ALPN +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSL_ENABLE_NPN (3) + - CURLOPT_SSL_OPTIONS (3) +--- + +# NAME + +CURLOPT_SSL_ENABLE_ALPN - Application Layer Protocol Negotiation + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_ENABLE_ALPN, long npn); +~~~ + +# DESCRIPTION + +Pass a long as parameter, 0 or 1 where 1 is for enable and 0 for disable. This +option enables/disables ALPN in the SSL handshake (if the SSL backend libcurl +is built to use supports it), which can be used to negotiate http2. + +# DEFAULT + +1, enabled + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.36.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md new file mode 100644 index 0000000..36221ca --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_ENABLE_NPN +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSL_ENABLE_ALPN (3) + - CURLOPT_SSL_OPTIONS (3) +--- + +# NAME + +CURLOPT_SSL_ENABLE_NPN - use NPN + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_ENABLE_NPN, long npn); +~~~ + +# DESCRIPTION + +Deprecated in 7.86.0. Setting this option has no function. + +Pass a long as parameter, 0 or 1 where 1 is for enable and 0 for disable. This +option enables/disables NPN in the SSL handshake (if the SSL backend libcurl +is built to use supports it), which can be used to negotiate http2. + +# DEFAULT + +1, enabled + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.36.0. Deprecated in 7.86.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md b/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md new file mode 100644 index 0000000..084728c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_FALSESTART +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TCP_FASTOPEN (3) +--- + +# NAME + +CURLOPT_SSL_FALSESTART - TLS false start + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_FALSESTART, long enable); +~~~ + +# DESCRIPTION + +Pass a long as parameter set to 1L to enable or 0 to disable. + +This option determines whether libcurl should use false start during the TLS +handshake. False start is a mode where a TLS client starts sending application +data before verifying the server's Finished message, thus saving a round trip +when performing a full handshake. + +# DEFAULT + +0 + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_SSL_FALSESTART, 1L); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.42.0. This option is currently only supported by the Secure +Transport (on iOS 7.0 or later, or OS X 10.9 or later) TLS backend. + +# RETURN VALUE + +Returns CURLE_OK if false start is supported by the SSL backend, otherwise +returns CURLE_NOT_BUILT_IN. diff --git a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md new file mode 100644 index 0000000..ffc62c3 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md @@ -0,0 +1,116 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_OPTIONS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSL_OPTIONS (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_SSL_CIPHER_LIST (3) +--- + +# NAME + +CURLOPT_SSL_OPTIONS - SSL behavior options + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_OPTIONS, long bitmask); +~~~ + +# DESCRIPTION + +Pass a long with a bitmask to tell libcurl about specific SSL +behaviors. Available bits: + +## CURLSSLOPT_ALLOW_BEAST + +Tells libcurl to not attempt to use any workarounds for a security flaw in the +SSL3 and TLS1.0 protocols. If this option is not used or this bit is set to 0, +the SSL layer libcurl uses may use a work-around for this flaw although it +might cause interoperability problems with some (older) SSL implementations. +WARNING: avoiding this work-around lessens the security, and by setting this +option to 1 you ask for exactly that. This option is only supported for Secure +Transport and OpenSSL. + +## CURLSSLOPT_NO_REVOKE + +Tells libcurl to disable certificate revocation checks for those SSL backends +where such behavior is present. This option is only supported for Schannel +(the native Windows SSL library), with an exception in the case of Windows' +Untrusted Publishers block list which it seems cannot be bypassed. (Added in +7.44.0) + +## CURLSSLOPT_NO_PARTIALCHAIN + +Tells libcurl to not accept "partial" certificate chains, which it otherwise +does by default. This option is only supported for OpenSSL and fails the +certificate verification if the chain ends with an intermediate certificate +and not with a root cert. (Added in 7.68.0) + +## CURLSSLOPT_REVOKE_BEST_EFFORT + +Tells libcurl to ignore certificate revocation checks in case of missing or +offline distribution points for those SSL backends where such behavior is +present. This option is only supported for Schannel (the native Windows SSL +library). If combined with *CURLSSLOPT_NO_REVOKE*, the latter takes +precedence. (Added in 7.70.0) + +## CURLSSLOPT_NATIVE_CA + +Tell libcurl to use the operating system's native CA store for certificate +verification. If you set this option and also set a CA certificate file or +directory then during verification those certificates are searched in addition +to the native CA store. + +Works with wolfSSL on Windows, Linux (Debian, Ubuntu, Gentoo, Fedora, RHEL), +macOS, Android and iOS (added in 8.3.0), with GnuTLS (added in 8.5.0) or on +Windows when built to use OpenSSL (Added in 7.71.0). + +## CURLSSLOPT_AUTO_CLIENT_CERT + +Tell libcurl to automatically locate and use a client certificate for +authentication, when requested by the server. This option is only supported +for Schannel (the native Windows SSL library). Prior to 7.77.0 this was the +default behavior in libcurl with Schannel. Since the server can request any +certificate that supports client authentication in the OS certificate store it +could be a privacy violation and unexpected. +(Added in 7.77.0) + +# DEFAULT + +0 + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* weaken TLS only for use with silly servers */ + curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST | + CURLSSLOPT_NO_REVOKE); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.25.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md b/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md new file mode 100644 index 0000000..a6b3cf1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_SESSIONID_CACHE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DNS_CACHE_TIMEOUT (3) + - CURLOPT_MAXAGE_CONN (3) + - CURLOPT_MAXLIFETIME_CONN (3) + - CURLOPT_SSLVERSION (3) +--- + +# NAME + +CURLOPT_SSL_SESSIONID_CACHE - use the SSL session-ID cache + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_SESSIONID_CACHE, + long enabled); +~~~ + +# DESCRIPTION + +Pass a long set to 0 to disable libcurl's use of SSL session-ID caching. Set +this to 1 to enable it. By default all transfers are done using the cache +enabled. While nothing ever should get hurt by attempting to reuse SSL +session-IDs, there seem to be or have been broken SSL implementations in the +wild that may require you to disable this in order for you to succeed. + +# DEFAULT + +1 + +# PROTOCOLS + +All TLS-based + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* switch off session-id use! */ + curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.16.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md new file mode 100644 index 0000000..75648a1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md @@ -0,0 +1,114 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_VERIFYHOST +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_PINNEDPUBLICKEY (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_SSL_VERIFYHOST - verify the certificate's name against host + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_VERIFYHOST, long verify); +~~~ + +# DESCRIPTION + +Pass a long as parameter specifying what to *verify*. + +This option determines whether libcurl verifies that the server cert is for +the server it is known as. + +When negotiating TLS and SSL connections, the server sends a certificate +indicating its identity. + +When CURLOPT_SSL_VERIFYHOST(3) is 2, that certificate must indicate that +the server is the server to which you meant to connect, or the connection +fails. Simply put, it means it has to have the same name in the certificate as +is in the URL you operate against. + +Curl considers the server the intended one when the Common Name field or a +Subject Alternate Name field in the certificate matches the hostname in the +URL to which you told Curl to connect. + +If *verify* value is set to 1: + +In 7.28.0 and earlier: treated as a debug option of some sorts, not supported +anymore due to frequently leading to programmer mistakes. + +From 7.28.1 to 7.65.3: setting it to 1 made curl_easy_setopt(3) return +an error and leaving the flag untouched. + +From 7.66.0: treats 1 and 2 the same. + +When the *verify* value is 0, the connection succeeds regardless of the +names in the certificate. Use that ability with caution! + +The default value for this option is 2. + +This option controls checking the server's certificate's claimed identity. +The server could be lying. To control lying, see CURLOPT_SSL_VERIFYPEER(3). + +WARNING: disabling verification of the certificate allows bad guys to +man-in-the-middle the communication without you knowing it. Disabling +verification makes the communication insecure. Just having encryption on a +transfer is not enough as you cannot be sure that you are communicating with +the correct end-point. + +When libcurl uses secure protocols it trusts responses and allows for example +HSTS and Alt-Svc information to be stored and used subsequently. Disabling +certificate verification can make libcurl trust and use such information from +malicious servers. + +# LIMITATIONS + +Secure Transport: If *verify* value is 0, then SNI is also disabled. SNI is +a TLS extension that sends the hostname to the server. The server may use that +information to do such things as sending back a specific certificate for the +hostname, or forwarding the request to a specific origin server. Some hostnames +may be inaccessible if SNI is not sent. + +# DEFAULT + +2 + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the default value: strict name check please */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not. + +If 1 is set as argument, *CURLE_BAD_FUNCTION_ARGUMENT* is returned. diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md new file mode 100644 index 0000000..c9884ce --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md @@ -0,0 +1,98 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_VERIFYPEER +Section: 3 +Source: libcurl +See-also: + - CURLINFO_CAINFO (3) + - CURLINFO_CAPATH (3) + - CURLOPT_CAINFO (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_PROXY_SSL_VERIFYPEER (3) + - CURLOPT_SSL_VERIFYHOST (3) +--- + +# NAME + +CURLOPT_SSL_VERIFYPEER - verify the peer's SSL certificate + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_VERIFYPEER, long verify); +~~~ + +# DESCRIPTION + +Pass a long as parameter to enable or disable. + +This option determines whether curl verifies the authenticity of the peer's +certificate. A value of 1 means curl verifies; 0 (zero) means it does not. + +When negotiating a TLS or SSL connection, the server sends a certificate +indicating its identity. Curl verifies whether the certificate is authentic, +i.e. that you can trust that the server is who the certificate says it is. +This trust is based on a chain of digital signatures, rooted in certification +authority (CA) certificates you supply. curl uses a default bundle of CA +certificates (the path for that is determined at build time) and you can +specify alternate certificates with the CURLOPT_CAINFO(3) option or the +CURLOPT_CAPATH(3) option. + +When CURLOPT_SSL_VERIFYPEER(3) is enabled, and the verification fails to +prove that the certificate is signed by a CA, the connection fails. + +When this option is disabled (set to zero), the CA certificates are not loaded +and the peer certificate verification is simply skipped. + +Authenticating the certificate is not enough to be sure about the server. You +typically also want to ensure that the server is the server you mean to be +talking to. Use CURLOPT_SSL_VERIFYHOST(3) for that. The check that the host +name in the certificate is valid for the hostname you are connecting to is +done independently of the CURLOPT_SSL_VERIFYPEER(3) option. + +WARNING: disabling verification of the certificate allows bad guys to +man-in-the-middle the communication without you knowing it. Disabling +verification makes the communication insecure. Just having encryption on a +transfer is not enough as you cannot be sure that you are communicating with +the correct end-point. + +When libcurl uses secure protocols it trusts responses and allows for example +HSTS and Alt-Svc information to be stored and used subsequently. Disabling +certificate verification can make libcurl trust and use such information from +malicious servers. + +# DEFAULT + +1 - enabled + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the default value: strict certificate check please */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +If built TLS enabled. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md new file mode 100644 index 0000000..66dbd74 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SSL_VERIFYSTATUS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CAINFO (3) + - CURLOPT_SSL_VERIFYHOST (3) + - CURLOPT_SSL_VERIFYPEER (3) +--- + +# NAME + +CURLOPT_SSL_VERIFYSTATUS - verify the certificate's status + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_VERIFYSTATUS, long verify); +~~~ + +# DESCRIPTION + +Pass a long as parameter set to 1 to enable or 0 to disable. + +This option determines whether libcurl verifies the status of the server cert +using the "Certificate Status Request" TLS extension (aka. OCSP stapling). + +Note that if this option is enabled but the server does not support the TLS +extension, the verification fails. + +# DEFAULT + +0 + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* ask for OCSP stapling! */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.41.0. This option is currently only supported by the OpenSSL and +GnuTLS TLS backends. + +# RETURN VALUE + +Returns CURLE_OK if OCSP stapling is supported by the SSL backend, otherwise +returns CURLE_NOT_BUILT_IN. diff --git a/docs/libcurl/opts/CURLOPT_STDERR.md b/docs/libcurl/opts/CURLOPT_STDERR.md new file mode 100644 index 0000000..a20e503 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_STDERR.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_STDERR +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_NOPROGRESS (3) + - CURLOPT_VERBOSE (3) +--- + +# NAME + +CURLOPT_STDERR - redirect stderr to another stream + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_STDERR, FILE *stream); +~~~ + +# DESCRIPTION + +Pass a FILE * as parameter. Tell libcurl to use this *stream* instead of +stderr when showing the progress meter and displaying CURLOPT_VERBOSE(3) +data. + +If you are using libcurl as a Windows DLL, this option causes an exception and +a crash in the library since it cannot access a FILE * passed on from the +application. A work-around is to instead use CURLOPT_DEBUGFUNCTION(3). + +# DEFAULT + +stderr + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + FILE *filep = fopen("dump", "wb"); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_STDERR, filep); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md new file mode 100644 index 0000000..ba2489a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_STREAM_DEPENDS +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PIPELINING (3) + - CURLOPT_HTTP_VERSION (3) + - CURLOPT_STREAM_DEPENDS_E (3) + - CURLOPT_STREAM_WEIGHT (3) +--- + +# NAME + +CURLOPT_STREAM_DEPENDS - stream this transfer depends on + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_STREAM_DEPENDS, + CURL *dephandle); +~~~ + +# DESCRIPTION + +Pass a CURL pointer in *dephandle* to identify the stream within the same +connection that this stream is depending upon. This option clears the +exclusive bit and is mutually exclusive to the CURLOPT_STREAM_DEPENDS_E(3) +option. + +The spec says "Including a dependency expresses a preference to allocate +resources to the identified stream rather than to the dependent stream." + +This option can be set during transfer. + +*dephandle* must not be the same as *handle*, that makes this function return +an error. It must be another easy handle, and it also needs to be a handle of +a transfer that is about to be sent over the same HTTP/2 connection for this +option to have an actual effect. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP/2 + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + CURL *curl2 = curl_easy_init(); /* a second handle */ + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/one"); + + /* the second depends on the first */ + curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two"); + curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS, curl); + + /* then add both to a multi handle and transfer them! */ + } +} +~~~ + +# AVAILABILITY + +Added in 7.46.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md new file mode 100644 index 0000000..e8dbc11 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_STREAM_DEPENDS_E +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PIPELINING (3) + - CURLOPT_HTTP_VERSION (3) + - CURLOPT_STREAM_DEPENDS (3) + - CURLOPT_STREAM_WEIGHT (3) +--- + +# NAME + +CURLOPT_STREAM_DEPENDS_E - stream this transfer depends on exclusively + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_STREAM_DEPENDS_E, + CURL *dephandle); +~~~ + +# DESCRIPTION + +Pass a CURL pointer in *dephandle* to identify the stream within the same +connection that this stream is depending upon exclusively. That means it +depends on it and sets the Exclusive bit. + +The spec says "Including a dependency expresses a preference to allocate +resources to the identified stream rather than to the dependent stream." + +Setting a dependency with the exclusive flag for a reprioritized stream causes +all the dependencies of the new parent stream to become dependent on the +reprioritized stream. + +This option can be set during transfer. + +*dephandle* must not be the same as *handle*, that makes this function return +an error. It must be another easy handle, and it also needs to be a handle of +a transfer that is about to be sent over the same HTTP/2 connection for this +option to have an actual effect. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP/2 + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + CURL *curl2 = curl_easy_init(); /* a second handle */ + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/one"); + + /* the second depends on the first */ + curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two"); + curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS_E, curl); + + /* then add both to a multi handle and transfer them! */ + } +} +~~~ + +# AVAILABILITY + +Added in 7.46.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md b/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md new file mode 100644 index 0000000..914a426 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md @@ -0,0 +1,81 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_STREAM_WEIGHT +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_PIPELINING (3) + - CURLOPT_PIPEWAIT (3) + - CURLOPT_STREAM_DEPENDS (3) + - CURLOPT_STREAM_DEPENDS_E (3) +--- + +# NAME + +CURLOPT_STREAM_WEIGHT - numerical stream weight + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_STREAM_WEIGHT, long weight); +~~~ + +# DESCRIPTION + +Set the long *weight* to a number between 1 and 256. + +When using HTTP/2, this option sets the individual weight for this particular +stream used by the easy *handle*. Setting and using weights only makes +sense and is only usable when doing multiple streams over the same +connections, which thus implies that you use CURLMOPT_PIPELINING(3). + +This option can be set during transfer and causes the updated weight info get +sent to the server the next time an HTTP/2 frame is sent to the server. + +See section 5.3 of RFC 7540 for protocol details. + +Streams with the same parent should be allocated resources proportionally +based on their weight. If you have two streams going, stream A with weight 16 +and stream B with weight 32, stream B gets two thirds (32/48) of the available +bandwidth (assuming the server can send off the data equally for both +streams). + +# DEFAULT + +If nothing is set, the HTTP/2 protocol itself uses its own default which is +16. + +# PROTOCOLS + +HTTP/2 + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + CURL *curl2 = curl_easy_init(); /* a second handle */ + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/one"); + curl_easy_setopt(curl, CURLOPT_STREAM_WEIGHT, 10L); + + /* the second has twice the weight */ + curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two"); + curl_easy_setopt(curl2, CURLOPT_STREAM_WEIGHT, 20L); + + /* then add both to a multi handle and transfer them! */ + } +} +~~~ + +# AVAILABILITY + +Added in 7.46.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md b/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md new file mode 100644 index 0000000..7301925 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md @@ -0,0 +1,103 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_SUPPRESS_CONNECT_HEADERS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADER (3) + - CURLOPT_HTTPPROXYTUNNEL (3) + - CURLOPT_PROXY (3) +--- + +# NAME + +CURLOPT_SUPPRESS_CONNECT_HEADERS - suppress proxy CONNECT response headers + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SUPPRESS_CONNECT_HEADERS, long onoff); +~~~ + +# DESCRIPTION + +When CURLOPT_HTTPPROXYTUNNEL(3) is used and a CONNECT request is made, +suppress proxy CONNECT response headers from the user callback functions +CURLOPT_HEADERFUNCTION(3) and CURLOPT_WRITEFUNCTION(3). + +Proxy CONNECT response headers can complicate header processing since it is +essentially a separate set of headers. You can enable this option to suppress +those headers. + +For example let's assume an HTTPS URL is to be retrieved via CONNECT. On +success there would normally be two sets of headers, and each header line sent +to the header function and/or the write function. The data given to the +callbacks would look like this: + +~~~c +HTTP/1.1 200 Connection established +{headers} +... + +HTTP/1.1 200 OK +Content-Type: application/json +{headers} +... + +{body} +... +~~~ + +However by enabling this option the CONNECT response headers are suppressed, +so the data given to the callbacks would look like this: + +~~~c +HTTP/1.1 200 OK +Content-Type: application/json +{headers} +... + +{body} +... +~~~ + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_HEADER, 1L); + curl_easy_setopt(curl, CURLOPT_PROXY, "http://foo:3128"); + curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L); + curl_easy_setopt(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS, 1L); + + curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.54.0 + +# RETURN VALUE + +CURLE_OK or an error such as CURLE_UNKNOWN_OPTION. diff --git a/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md b/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md new file mode 100644 index 0000000..4db103b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TCP_FASTOPEN +Section: 3 +Source: libcurl +See-also: + - CURLOPT_SSL_FALSESTART (3) +--- + +# NAME + +CURLOPT_TCP_FASTOPEN - TCP Fast Open + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_FASTOPEN, long enable); +~~~ + +# DESCRIPTION + +Pass a long as parameter set to 1L to enable or 0 to disable. + +TCP Fast Open (RFC 7413) is a mechanism that allows data to be carried in the +SYN and SYN-ACK packets and consumed by the receiving end during the initial +connection handshake, saving up to one full round-trip time (RTT). + +Beware: the TLS session cache does not work when TCP Fast Open is enabled. TCP +Fast Open is also known to be problematic on or across certain networks. + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.49.0. This option is currently only supported on Linux and macOS +10.11 or later. + +# RETURN VALUE + +Returns CURLE_OK if fast open is supported by the operating system, otherwise +returns CURLE_NOT_BUILT_IN. diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md new file mode 100644 index 0000000..0904319 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TCP_KEEPALIVE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_MAX_RECV_SPEED_LARGE (3) + - CURLOPT_TCP_KEEPIDLE (3) + - CURLOPT_TCP_KEEPINTVL (3) +--- + +# NAME + +CURLOPT_TCP_KEEPALIVE - TCP keep-alive probing + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPALIVE, long probe); +~~~ + +# DESCRIPTION + +Pass a long. If set to 1, TCP keepalive probes are used. The delay and +frequency of these probes can be controlled by the +CURLOPT_TCP_KEEPIDLE(3) and CURLOPT_TCP_KEEPINTVL(3) options, +provided the operating system supports them. Set to 0 (default behavior) to +disable keepalive probes + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* enable TCP keep-alive for this transfer */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); + + /* keep-alive idle time to 120 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L); + + /* interval time between keep-alive probes: 60 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.25.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md new file mode 100644 index 0000000..d8418ff --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TCP_KEEPIDLE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TCP_KEEPALIVE (3) + - CURLOPT_TCP_KEEPINTVL (3) +--- + +# NAME + +CURLOPT_TCP_KEEPIDLE - TCP keep-alive idle time wait + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPIDLE, long delay); +~~~ + +# DESCRIPTION + +Pass a long. Sets the *delay*, in seconds, to wait while the connection is +idle before sending keepalive probes. Not all operating systems support this +option. + +The maximum value this accepts is 2147483648. Any larger value is capped to +this amount. + +# DEFAULT + +60 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* enable TCP keep-alive for this transfer */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); + + /* set keep-alive idle time to 120 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L); + + /* interval time between keep-alive probes: 60 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.25.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md new file mode 100644 index 0000000..d560cf5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TCP_KEEPINTVL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TCP_KEEPALIVE (3) + - CURLOPT_TCP_KEEPIDLE (3) +--- + +# NAME + +CURLOPT_TCP_KEEPINTVL - TCP keep-alive interval + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPINTVL, long interval); +~~~ + +# DESCRIPTION + +Pass a long. Sets the interval, in seconds, to wait between sending keepalive +probes. Not all operating systems support this option. (Added in 7.25.0) + +The maximum value this accepts is 2147483648. Any larger value is capped to +this amount. + +# DEFAULT + +60 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* enable TCP keep-alive for this transfer */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); + + /* set keep-alive idle time to 120 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L); + + /* interval time between keep-alive probes: 60 seconds */ + curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md b/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md new file mode 100644 index 0000000..7fe286d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TCP_NODELAY +Section: 3 +Source: libcurl +See-also: + - CURLOPT_BUFFERSIZE (3) + - CURLOPT_SOCKOPTFUNCTION (3) + - CURLOPT_TCP_KEEPALIVE (3) +--- + +# NAME + +CURLOPT_TCP_NODELAY - the TCP_NODELAY option + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_NODELAY, long nodelay); +~~~ + +# DESCRIPTION + +Pass a long specifying whether the *TCP_NODELAY* option is to be set or +cleared (1L = set, 0 = clear). The option is set by default. This has no +effect after the connection has been established. + +Setting this option to 1L disables TCP's Nagle algorithm on connections +created using this handle. The purpose of this algorithm is to try to minimize +the number of small packets on the network (where "small packets" means TCP +segments less than the Maximum Segment Size for the network). + +Maximizing the amount of data sent per TCP segment is good because it +amortizes the overhead of the send. However, in some cases small segments may +need to be sent without delay. This is less efficient than sending larger +amounts of data at a time, and can contribute to congestion on the network if +overdone. + +# DEFAULT + +1 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + /* leave Nagle enabled */ + curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 0); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always. The default was changed to 1 from 0 in 7.50.2. + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md b/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md new file mode 100644 index 0000000..e1db12e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TELNETOPTIONS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPHEADER (3) + - CURLOPT_QUOTE (3) +--- + +# NAME + +CURLOPT_TELNETOPTIONS - set of telnet options + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TELNETOPTIONS, + struct curl_slist *cmds); +~~~ + +# DESCRIPTION + +Provide a pointer to a curl_slist with variables to pass to the telnet +negotiations. The variables should be in the format . libcurl +supports the options **TTYPE**, **XDISPLOC** and **NEW_ENV**. See the +TELNET standard for details. + +# DEFAULT + +NULL + +# PROTOCOLS + +TELNET + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + struct curl_slist *options; + options = curl_slist_append(NULL, "TTTYPE=vt100"); + options = curl_slist_append(options, "USER=foobar"); + curl_easy_setopt(curl, CURLOPT_URL, "telnet://example.com/"); + curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, options); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + curl_slist_free_all(options); + } +} +~~~ + +# AVAILABILITY + +Along with TELNET + +# RETURN VALUE + +Returns CURLE_OK if TELNET is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md b/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md new file mode 100644 index 0000000..07cbeba --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md @@ -0,0 +1,63 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TFTP_BLKSIZE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAXFILESIZE (3) +--- + +# NAME + +CURLOPT_TFTP_BLKSIZE - TFTP block size + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TFTP_BLKSIZE, long blocksize); +~~~ + +# DESCRIPTION + +Specify *blocksize* to use for TFTP data transmission. Valid range as per +RFC 2348 is 8-65464 bytes. The default of 512 bytes is used if this option is +not specified. The specified block size is only used if supported by the +remote server. If the server does not return an option acknowledgment or +returns an option acknowledgment with no block size, the default of 512 bytes +is used. + +# DEFAULT + +512 + +# PROTOCOLS + +TFTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "tftp://example.com/bootimage"); + /* try using larger blocks */ + curl_easy_setopt(curl, CURLOPT_TFTP_BLKSIZE, 2048L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md b/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md new file mode 100644 index 0000000..fd4e492 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TFTP_NO_OPTIONS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TFTP_BLKSIZE (3) +--- + +# NAME + +CURLOPT_TFTP_NO_OPTIONS - send no TFTP options requests + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TFTP_NO_OPTIONS, long onoff); +~~~ + +# DESCRIPTION + +Set *onoff* to 1L to exclude all TFTP options defined in RFC 2347, +RFC 2348 and RFC 2349 from read and write requests. + +This option improves interoperability with legacy servers that do not +acknowledge or properly implement TFTP options. When this option is used +CURLOPT_TFTP_BLKSIZE(3) is ignored. + +# DEFAULT + +0 + +# PROTOCOLS + +TFTP + +# EXAMPLE + +~~~c +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *fp) +{ + return fwrite(ptr, size, nmemb, (FILE *)fp); +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + FILE *fp = fopen("foo.bin", "wb"); + if(fp) { + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)fp); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + + curl_easy_setopt(curl, CURLOPT_URL, "tftp://example.com/foo.bin"); + + /* do not send TFTP options requests */ + curl_easy_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L); + + /* Perform the request */ + curl_easy_perform(curl); + + fclose(fp); + } + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.48.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TIMECONDITION.md b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md new file mode 100644 index 0000000..80d93a5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TIMECONDITION +Section: 3 +Source: libcurl +See-also: + - CURLINFO_FILETIME (3) + - CURLOPT_TIMEVALUE (3) +--- + +# NAME + +CURLOPT_TIMECONDITION - select condition for a time request + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMECONDITION, long cond); +~~~ + +# DESCRIPTION + +Pass a long as parameter. This defines how the CURLOPT_TIMEVALUE(3) time +value is treated. You can set this parameter to *CURL_TIMECOND_IFMODSINCE* +or *CURL_TIMECOND_IFUNMODSINCE*. + +The last modification time of a file is not always known and in such instances +this feature has no effect even if the given time condition would not have +been met. curl_easy_getinfo(3) with the *CURLINFO_CONDITION_UNMET* +option can be used after a transfer to learn if a zero-byte successful +"transfer" was due to this condition not matching. + +# DEFAULT + +CURL_TIMECOND_NONE (0) + +# PROTOCOLS + +HTTP, FTP, RTSP, and FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* January 1, 2020 is 1577833200 */ + curl_easy_setopt(curl, CURLOPT_TIMEVALUE, 1577833200L); + + /* If-Modified-Since the above time stamp */ + curl_easy_setopt(curl, CURLOPT_TIMECONDITION, + (long)CURL_TIMECOND_IFMODSINCE); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_TIMEOUT.md new file mode 100644 index 0000000..02a3d3d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TIMEOUT.md @@ -0,0 +1,90 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TIMEOUT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT (3) + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_TCP_KEEPALIVE (3) + - CURLOPT_TIMEOUT_MS (3) +--- + +# NAME + +CURLOPT_TIMEOUT - maximum time the transfer is allowed to complete + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEOUT, long timeout); +~~~ + +# DESCRIPTION + +Pass a long as parameter containing *timeout* - the maximum time in +seconds that you allow the entire transfer operation to take. The whole thing, +from start to end. Normally, name lookups can take a considerable time and +limiting operations risk aborting perfectly normal operations. + +CURLOPT_TIMEOUT_MS(3) is the same function but set in milliseconds. + +If both CURLOPT_TIMEOUT(3) and CURLOPT_TIMEOUT_MS(3) are set, the +value set last is used. + +Since this option puts a hard limit on how long time a request is allowed to +take, it has limited use in dynamic use cases with varying transfer +times. That is especially apparent when using the multi interface, which may +queue the transfer, and that time is included. You are advised to explore +CURLOPT_LOW_SPEED_LIMIT(3), CURLOPT_LOW_SPEED_TIME(3) or using +CURLOPT_PROGRESSFUNCTION(3) to implement your own timeout logic. + +The connection timeout set with CURLOPT_CONNECTTIMEOUT(3) is included in +this general all-covering timeout. + +With CURLOPT_CONNECTTIMEOUT(3) set to 3 and CURLOPT_TIMEOUT(3) set +to 5, the operation can never last longer than 5 seconds. + +With CURLOPT_CONNECTTIMEOUT(3) set to 4 and CURLOPT_TIMEOUT(3) set +to 2, the operation can never last longer than 2 seconds. + +This option may cause libcurl to use the SIGALRM signal to timeout system +calls on builds not using asynch DNS. In unix-like systems, this might cause +signals to be used unless CURLOPT_NOSIGNAL(3) is set. + +# DEFAULT + +Default timeout is 0 (zero) which means it never times out during transfer. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* complete within 20 seconds */ + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK. Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative +value or a value that when converted to milliseconds is too large. diff --git a/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md new file mode 100644 index 0000000..0bb037f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md @@ -0,0 +1,64 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TIMEOUT_MS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECTTIMEOUT (3) + - CURLOPT_LOW_SPEED_LIMIT (3) + - CURLOPT_TCP_KEEPALIVE (3) + - CURLOPT_TIMEOUT (3) +--- + +# NAME + +CURLOPT_TIMEOUT_MS - maximum time the transfer is allowed to complete + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEOUT_MS, long timeout); +~~~ + +# DESCRIPTION + +Pass a long as parameter containing *timeout* - the maximum time in +milliseconds that you allow the libcurl transfer operation to take. + +See CURLOPT_TIMEOUT(3) for details. + +# DEFAULT + +Default timeout is 0 (zero) which means it never times out during transfer. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* complete within 20000 milliseconds */ + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 20000L); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_TIMEVALUE.md b/docs/libcurl/opts/CURLOPT_TIMEVALUE.md new file mode 100644 index 0000000..cc8f603 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TIMEVALUE.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TIMEVALUE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TIMECONDITION (3) + - CURLOPT_TIMEVALUE_LARGE (3) +--- + +# NAME + +CURLOPT_TIMEVALUE - time value for conditional + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEVALUE, long val); +~~~ + +# DESCRIPTION + +Pass a long *val* as parameter. This should be the time counted as seconds +since 1 Jan 1970, and the time is used in a condition as specified with +CURLOPT_TIMECONDITION(3). + +On systems with 32 bit 'long' variables (such as Windows), this option cannot +set dates beyond the year 2038. Consider CURLOPT_TIMEVALUE_LARGE(3) +instead. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP, FTP, RTSP, and FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* January 1, 2020 is 1577833200 */ + curl_easy_setopt(curl, CURLOPT_TIMEVALUE, 1577833200L); + + /* If-Modified-Since the above time stamp */ + curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md b/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md new file mode 100644 index 0000000..1424f66 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TIMEVALUE_LARGE +Section: 3 +Source: libcurl +See-also: + - CURLINFO_FILETIME (3) + - CURLOPT_TIMECONDITION (3) + - CURLOPT_TIMEVALUE (3) +--- + +# NAME + +CURLOPT_TIMEVALUE_LARGE - time value for conditional + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEVALUE_LARGE, + curl_off_t val); +~~~ + +# DESCRIPTION + +Pass a curl_off_t *val* as parameter. This should be the time counted as +seconds since 1 Jan 1970, and the time is used in a condition as specified +with CURLOPT_TIMECONDITION(3). + +The difference between this option and CURLOPT_TIMEVALUE(3) is the type +of the argument. On systems where 'long' is only 32 bit wide, this option has +to be used to set dates beyond the year 2038. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP, FTP, RTSP, and FILE + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* January 1, 2020 is 1577833200 */ + curl_easy_setopt(curl, CURLOPT_TIMEVALUE_LARGE, (curl_off_t)1577833200); + + /* If-Modified-Since the above time stamp */ + curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.59.0. + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md b/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md new file mode 100644 index 0000000..add1f2f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TLS13_CIPHERS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLVERSION (3) + - CURLOPT_PROXY_SSL_CIPHER_LIST (3) + - CURLOPT_PROXY_TLS13_CIPHERS (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_SSL_CIPHER_LIST (3) + - CURLOPT_USE_SSL (3) +--- + +# NAME + +CURLOPT_TLS13_CIPHERS - ciphers suites to use for TLS 1.3 + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLS13_CIPHERS, char *list); +~~~ + +# DESCRIPTION + +Pass a char pointer, pointing to a null-terminated string holding the list of +cipher suites to use for the TLS 1.3 connection. The list must be +syntactically correct, it consists of one or more cipher suite strings +separated by colons. + +Find more details about cipher lists on this URL: + + https://curl.se/docs/ssl-ciphers.html + +This option is currently used only when curl is built to use OpenSSL 1.1.1 or +later, or Schannel. If you are using a different SSL backend you can try +setting TLS 1.3 cipher suites by using the CURLOPT_SSL_CIPHER_LIST(3) +option. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL, use internal default + +# PROTOCOLS + +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_TLS13_CIPHERS, + "TLS_CHACHA20_POLY1305_SHA256"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.61.0 for OpenSSL. Available when built with OpenSSL >= 1.1.1. + +Added in 7.85.0 for Schannel. + +# RETURN VALUE + +Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise. diff --git a/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md b/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md new file mode 100644 index 0000000..1d0e1d0 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md @@ -0,0 +1,70 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TLSAUTH_PASSWORD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_TLSAUTH_PASSWORD (3) + - CURLOPT_TLSAUTH_TYPE (3) + - CURLOPT_TLSAUTH_USERNAME (3) +--- + +# NAME + +CURLOPT_TLSAUTH_PASSWORD - password to use for TLS authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_PASSWORD, char *pwd); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should point to the null-terminated +password to use for the TLS authentication method specified with the +CURLOPT_TLSAUTH_TYPE(3) option. Requires that the +CURLOPT_TLSAUTH_USERNAME(3) option also be set. + +The application does not have to keep the string around after setting this +option. + +This feature relies in TLS SRP which does not work with TLS 1.3. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.21.4, with the OpenSSL and GnuTLS backends only + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md b/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md new file mode 100644 index 0000000..f3e0803 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TLSAUTH_TYPE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TLSAUTH_PASSWORD (3) + - CURLOPT_TLSAUTH_USERNAME (3) +--- + +# NAME + +CURLOPT_TLSAUTH_TYPE - TLS authentication methods + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_TYPE, char *type); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. The string should be +the method of the TLS authentication. Supported method is "SRP". + +## SRP + +TLS-SRP authentication. Secure Remote Password authentication for TLS is +defined in RFC 5054 and provides mutual authentication if both sides have a +shared secret. To use TLS-SRP, you must also set the +CURLOPT_TLSAUTH_USERNAME(3) and CURLOPT_TLSAUTH_PASSWORD(3) +options. + +The application does not have to keep the string around after setting this +option. + +TLS SRP does not work with TLS 1.3. + +# DEFAULT + +blank + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this +to work. Added in 7.21.4 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md b/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md new file mode 100644 index 0000000..1127046 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md @@ -0,0 +1,69 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TLSAUTH_USERNAME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TLSAUTH_PASSWORD (3) + - CURLOPT_TLSAUTH_TYPE (3) +--- + +# NAME + +CURLOPT_TLSAUTH_USERNAME - user name to use for TLS authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_USERNAME, char *user); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should point to the null-terminated +username to use for the TLS authentication method specified with the +CURLOPT_TLSAUTH_TYPE(3) option. Requires that the +CURLOPT_TLSAUTH_PASSWORD(3) option also be set. + +The application does not have to keep the string around after setting this +option. + +This feature relies in TLS SRP which does not work with TLS 1.3. + +# DEFAULT + +NULL + +# PROTOCOLS + +All TLS-based protocols + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.21.4, with the OpenSSL and GnuTLS backends only + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_TRAILERDATA.md b/docs/libcurl/opts/CURLOPT_TRAILERDATA.md new file mode 100644 index 0000000..304b408 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TRAILERDATA.md @@ -0,0 +1,59 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TRAILERDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TRAILERFUNCTION (3) + - CURLOPT_WRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_TRAILERDATA - pointer passed to trailing headers callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TRAILERDATA, void *userdata); +~~~ + +# DESCRIPTION + +Data pointer to be passed to the HTTP trailer callback function. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +struct MyData { + void *custom; +}; + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct MyData data; + curl_easy_setopt(curl, CURLOPT_TRAILERDATA, &data); + } +} +~~~ + +# AVAILABILITY + +This option was added in curl 7.64.0 and is present if HTTP support is enabled + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md b/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md new file mode 100644 index 0000000..5d79214 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md @@ -0,0 +1,110 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TRAILERFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TRAILERDATA (3) + - CURLOPT_WRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_TRAILERFUNCTION - callback for sending trailing headers + +# SYNOPSIS + +~~~c +#include + +int curl_trailer_callback(struct curl_slist ** list, void *userdata); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TRAILERFUNCTION, + curl_trailer_callback *func); +~~~ + +# DESCRIPTION + +Pass a pointer to a callback function. + +This callback function is called once right before sending the final CR LF in +an HTTP chunked transfer to fill a list of trailing headers to be sent before +finishing the HTTP transfer. + +You can set the userdata argument with the CURLOPT_TRAILERDATA(3) +option. + +The trailing headers included in the linked list must not be CRLF-terminated, +because libcurl adds the appropriate line termination characters after each +header item. + +If you use curl_slist_append(3) to add trailing headers to the *curl_slist* +then libcurl duplicates the strings, and frees the *curl_slist* once the +trailers have been sent. + +If one of the trailing header fields is not formatted correctly it is ignored +and an info message is emitted. + +The return value can either be **CURL_TRAILERFUNC_OK** or +**CURL_TRAILERFUNC_ABORT** which would respectively instruct libcurl to +either continue with sending the trailers or to abort the request. + +If you set this option to NULL, then the transfer proceeds as usual +without any interruptions. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP + +# EXAMPLE +~~~c +static int trailer_cb(struct curl_slist **tr, void *data) +{ + /* libcurl frees the list */ + *tr = curl_slist_append(*tr, "My-super-awesome-trailer: trailer-stuff"); + return CURL_TRAILERFUNC_OK; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + + /* Set the URL of the request */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); + /* Now set it as a put */ + curl_easy_setopt(curl, CURLOPT_PUT, 1L); + + /* Assuming we have a function that returns the data to be pushed + Let that function be read_cb */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, trailer_cb); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Trailer: My-super-awesome-trailer"); + res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + /* Set the trailers filling callback */ + curl_easy_setopt(curl, CURLOPT_TRAILERFUNCTION, trailer_cb); + + /* Perform the transfer */ + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + + curl_slist_free_all(headers); + } +} +~~~ +# AVAILABILITY + +This option was added in curl 7.64.0 and is present if HTTP support is enabled. + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md b/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md new file mode 100644 index 0000000..4f6d004 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md @@ -0,0 +1,65 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TRANSFERTEXT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CRLF (3) +--- + +# NAME + +CURLOPT_TRANSFERTEXT - request a text based transfer for FTP + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TRANSFERTEXT, long text); +~~~ + +# DESCRIPTION + +A parameter set to 1 tells the library to use ASCII mode for FTP transfers, +instead of the default binary transfer. For win32 systems it does not set the +stdout to binary mode. This option can be usable when transferring text data +between systems with different views on certain characters, such as newlines +or similar. + +libcurl does not do a complete ASCII conversion when doing ASCII transfers +over FTP. This is a known limitation/flaw that nobody has rectified. libcurl +simply sets the mode to ASCII and performs a standard transfer. + +# DEFAULT + +0, disabled + +# PROTOCOLS + +FTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/textfile"); + curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Along with FTP + +# RETURN VALUE + +Returns CURLE_OK if FTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md new file mode 100644 index 0000000..7fd3848 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md @@ -0,0 +1,68 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_TRANSFER_ENCODING +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ACCEPT_ENCODING (3) + - CURLOPT_HTTP_TRANSFER_DECODING (3) +--- + +# NAME + +CURLOPT_TRANSFER_ENCODING - ask for HTTP Transfer Encoding + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TRANSFER_ENCODING, + long enable); +~~~ + +# DESCRIPTION + +Pass a long set to 1L to *enable* or 0 to disable. + +Adds a request for compressed Transfer Encoding in the outgoing HTTP +request. If the server supports this and so desires, it can respond with the +HTTP response sent using a compressed Transfer-Encoding that is automatically +uncompressed by libcurl on reception. + +Transfer-Encoding differs slightly from the Content-Encoding you ask for with +CURLOPT_ACCEPT_ENCODING(3) in that a Transfer-Encoding is strictly meant +to be for the transfer and thus MUST be decoded before the data arrives in the +client. Traditionally, Transfer-Encoding has been much less used and supported +by both HTTP clients and HTTP servers. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.21.6 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md b/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md new file mode 100644 index 0000000..0ef3ec1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md @@ -0,0 +1,87 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_UNIX_SOCKET_PATH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_ABSTRACT_UNIX_SOCKET (3) + - CURLOPT_OPENSOCKETFUNCTION (3) + - unix (7) +--- + +# NAME + +CURLOPT_UNIX_SOCKET_PATH - Unix domain socket + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UNIX_SOCKET_PATH, char *path); +~~~ + +# DESCRIPTION + +Enables the use of Unix domain sockets as connection endpoint and sets the +path to *path*. If *path* is NULL, then Unix domain sockets are +disabled. + +When enabled, curl connects to the Unix domain socket instead of establishing +a TCP connection to the host. Since no network connection is created, curl +does not resolve the DNS hostname in the URL. + +The maximum path length on Cygwin, Linux and Solaris is 107. On other platforms +it might be even less. + +Proxy and TCP options such as CURLOPT_TCP_NODELAY(3) are not +supported. Proxy options such as CURLOPT_PROXY(3) have no effect either +as these are TCP-oriented, and asking a proxy server to connect to a certain +Unix domain socket is not possible. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +Default is NULL, meaning that no Unix domain sockets are used. + +# PROTOCOLS + +All protocols except for FILE and FTP are supported in theory. HTTP, IMAP, +POP3 and SMTP should in particular work (including their SSL/TLS variants). + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/tmp/httpd.sock"); + curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/"); + + curl_easy_perform(curl); + } +} +~~~ + +If you are on Linux and somehow have a need for paths larger than 107 bytes, +you can use the proc filesystem to bypass the limitation: + +~~~c + int dirfd = open(long_directory_path_to_socket, O_DIRECTORY | O_RDONLY); + char path[108]; + snprintf(path, sizeof(path), "/proc/self/fd/%d/httpd.sock", dirfd); + curl_easy_setopt(curl_handle, CURLOPT_UNIX_SOCKET_PATH, path); + /* Be sure to keep dirfd valid until you discard the handle */ +~~~ + +# AVAILABILITY + +Added in 7.40.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md b/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md new file mode 100644 index 0000000..53b584f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md @@ -0,0 +1,78 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_UNRESTRICTED_AUTH +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_COUNT (3) + - CURLOPT_FOLLOWLOCATION (3) + - CURLOPT_MAXREDIRS (3) + - CURLOPT_REDIR_PROTOCOLS_STR (3) + - CURLOPT_USERPWD (3) +--- + +# NAME + +CURLOPT_UNRESTRICTED_AUTH - send credentials to other hosts too + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UNRESTRICTED_AUTH, + long goahead); +~~~ + +# DESCRIPTION + +Set the long *gohead* parameter to 1L to make libcurl continue to send +authentication (user+password) credentials when following locations, even when +hostname changed. This option is meaningful only when setting +CURLOPT_FOLLOWLOCATION(3). + +Further, when this option is not used or set to **0L**, libcurl does not +send custom nor internally generated Authentication: headers on requests done +to other hosts than the one used for the initial URL. + +By default, libcurl only sends credentials and Authentication headers to the +initial hostname as given in the original URL, to avoid leaking username + +password to other sites. + +This option should be used with caution: when curl follows redirects it +blindly fetches the next URL as instructed by the server. Setting +CURLOPT_UNRESTRICTED_AUTH(3) to 1L makes curl trust the server and sends +possibly sensitive credentials to any host the server points to, possibly +again and again as the following hosts can keep redirecting to new hosts. + +# DEFAULT + +0 + +# PROTOCOLS + +HTTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1L); + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Along with HTTP + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md b/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md new file mode 100644 index 0000000..283efa7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md @@ -0,0 +1,82 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_UPKEEP_INTERVAL_MS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_TCP_KEEPALIVE (3) +--- + +# NAME + +CURLOPT_UPKEEP_INTERVAL_MS - connection upkeep interval + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UPKEEP_INTERVAL_MS, + long upkeep_interval_ms); +~~~ + +# DESCRIPTION + +Some protocols have "connection upkeep" mechanisms. These mechanisms usually +send some traffic on existing connections in order to keep them alive; this +can prevent connections from being closed due to overzealous firewalls, for +example. + +The user needs to explicitly call curl_easy_upkeep(3) in order to +perform the upkeep work. + +Currently the only protocol with a connection upkeep mechanism is HTTP/2: when +the connection upkeep interval is exceeded and curl_easy_upkeep(3) +is called, an HTTP/2 PING frame is sent on the connection. + +# DEFAULT + +CURL_UPKEEP_INTERVAL_DEFAULT (currently defined as 60000L, which is 60 seconds) + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* Make a connection to an HTTP/2 server. */ + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the interval to 30000ms / 30s */ + curl_easy_setopt(curl, CURLOPT_UPKEEP_INTERVAL_MS, 30000L); + + curl_easy_perform(curl); + + /* Perform more work here. */ + + /* While the connection is being held open, curl_easy_upkeep() can be + called. If curl_easy_upkeep() is called and the time since the last + upkeep exceeds the interval, then an HTTP/2 PING is sent. */ + curl_easy_upkeep(curl); + + /* Perform more work here. */ + + /* always cleanup */ + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.62.0 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_UPLOAD.md b/docs/libcurl/opts/CURLOPT_UPLOAD.md new file mode 100644 index 0000000..a54f2fd --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_UPLOAD.md @@ -0,0 +1,97 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_UPLOAD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_INFILESIZE_LARGE (3) + - CURLOPT_PUT (3) + - CURLOPT_READFUNCTION (3) +--- + +# NAME + +CURLOPT_UPLOAD - data upload + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UPLOAD, long upload); +~~~ + +# DESCRIPTION + +The long parameter *upload* set to 1 tells the library to prepare for and +perform an upload. The CURLOPT_READDATA(3) and +CURLOPT_INFILESIZE(3) or CURLOPT_INFILESIZE_LARGE(3) options are +also interesting for uploads. If the protocol is HTTP, uploading means using +the PUT request unless you tell libcurl otherwise. + +Using PUT with HTTP 1.1 implies the use of a "Expect: 100-continue" header. +You can disable this header with CURLOPT_HTTPHEADER(3) as usual. + +If you use PUT to an HTTP 1.1 server, you can upload data without knowing the +size before starting the transfer. The library enables this by adding a header +"Transfer-Encoding: chunked". With HTTP 1.0 or if you prefer not to use chunked +transfer, you must specify the size of the data with +CURLOPT_INFILESIZE(3) or CURLOPT_INFILESIZE_LARGE(3). + +# DEFAULT + +0, default is download + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +static size_t read_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + FILE *src = userdata; + /* copy as much data as possible into the 'ptr' buffer, but no more than + 'size' * 'nmemb' bytes */ + size_t retcode = fread(ptr, size, nmemb, src); + + return retcode; +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + FILE *src = fopen("local-file", "r"); + curl_off_t fsize; /* set this to the size of the input file */ + + /* we want to use our own read function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb); + + /* enable uploading */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* specify target */ + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/to/newfile"); + + /* now specify which pointer to pass to our callback */ + curl_easy_setopt(curl, CURLOPT_READDATA, src); + + /* Set the size of the file to upload */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); + + /* Now run off and do what you have been told! */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md b/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md new file mode 100644 index 0000000..f32a45f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_UPLOAD_BUFFERSIZE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_BUFFERSIZE (3) + - CURLOPT_READFUNCTION (3) + - CURLOPT_TCP_NODELAY (3) +--- + +# NAME + +CURLOPT_UPLOAD_BUFFERSIZE - upload buffer size + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UPLOAD_BUFFERSIZE, long size); +~~~ + +# DESCRIPTION + +Pass a long specifying your preferred *size* (in bytes) for the upload +buffer in libcurl. It makes libcurl uses a larger buffer that gets passed to +the next layer in the stack to get sent off. In some setups and for some +protocols, there is a huge performance benefit of having a larger upload +buffer. + +This is just treated as a request, not an order. You cannot be guaranteed to +actually get the given size. + +The upload buffer size is by default 64 kilobytes. The maximum buffer size +allowed to be set is 2 megabytes. The minimum buffer size allowed to be set is +16 kilobytes. + +The upload buffer is allocated on-demand - so if the handle is not used for +upload, this buffer is not allocated at all. + +DO NOT set this option on a handle that is currently used for an active +transfer as that may lead to unintended consequences. + +# DEFAULT + +65536 bytes + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/foo.bin"); + + /* ask libcurl to allocate a larger upload buffer */ + curl_easy_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 120000L); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.62.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_URL.md b/docs/libcurl/opts/CURLOPT_URL.md new file mode 100644 index 0000000..3a0691b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_URL.md @@ -0,0 +1,145 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_URL +Section: 3 +Source: libcurl +See-also: + - CURLINFO_REDIRECT_URL (3) + - CURLOPT_CURLU (3) + - CURLOPT_FORBID_REUSE (3) + - CURLOPT_FRESH_CONNECT (3) + - CURLOPT_PATH_AS_IS (3) + - CURLOPT_PROTOCOLS (3) + - curl_easy_perform (3) + - curl_url_get (3) + - curl_url_set (3) +--- + +# NAME + +CURLOPT_URL - URL for this transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_URL, char *URL); +~~~ + +# DESCRIPTION + +Pass in a pointer to the *URL* to work with. The parameter should be a +char * to a null-terminated string which must be URL-encoded in the following +format: + +scheme://host:port/path + +For a greater explanation of the format please see RFC 3986. + +libcurl does not validate the syntax or use the URL until the transfer is +started. Even if you set a crazy value here, curl_easy_setopt(3) might +still return *CURLE_OK*. + +If the given URL is missing a scheme name (such as "http://" or "ftp://" etc) +then libcurl guesses based on the host. If the outermost subdomain name +matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that protocol gets used, +otherwise HTTP is used. Since 7.45.0 guessing can be disabled by setting a +default protocol, see CURLOPT_DEFAULT_PROTOCOL(3) for details. + +Should the protocol, either as specified by the URL scheme or deduced by +libcurl from the hostname, not be supported by libcurl then +*CURLE_UNSUPPORTED_PROTOCOL* is returned from either the curl_easy_perform(3) +or curl_multi_perform(3) functions when you call them. Use +curl_version_info(3) for detailed information of which protocols are supported +by the build of libcurl you are using. + +CURLOPT_PROTOCOLS_STR(3) can be used to limit what protocols libcurl may +use for this transfer, independent of what libcurl has been compiled to +support. That may be useful if you accept the URL from an external source and +want to limit the accessibility. + +The CURLOPT_URL(3) string is ignored if CURLOPT_CURLU(3) is set. + +Either CURLOPT_URL(3) or CURLOPT_CURLU(3) must be set before a +transfer is started. + +The application does not have to keep the string around after setting this +option. + +The parser used for handling the URL set with CURLOPT_URL(3) is the same +that curl_url_set(3) uses. + +# ENCODING + +The string pointed to in the CURLOPT_URL(3) argument is generally +expected to be a sequence of characters using an ASCII compatible encoding. + +If libcurl is built with IDN support, the server name part of the URL can use +an "international name" by using the current encoding (according to locale) or +UTF-8 (when winidn is used; or a Windows Unicode build using libidn2). + +If libcurl is built without IDN support, the server name is used exactly as +specified when passed to the name resolver functions. + +# DEFAULT + +There is no default URL. If this option is not set, no transfer can be +performed. + +# SECURITY CONCERNS + +Applications may at times find it convenient to allow users to specify URLs +for various purposes and that string would then end up fed to this option. + +Getting a URL from an external untrusted party brings several security +concerns: + +If you have an application that runs as or in a server application, getting an +unfiltered URL can easily trick your application to access a local resource +instead of a remote. Protecting yourself against localhost accesses is hard +when accepting user provided URLs. + +Such custom URLs can also access other ports than you planned as port numbers +are part of the regular URL format. The combination of a local host and a +custom port number can allow external users to play tricks with your local +services. + +Accepting external URLs may also use other protocols than http:// or other +common ones. Restrict what accept with CURLOPT_PROTOCOLS(3). + +User provided URLs can also be made to point to sites that redirect further on +(possibly to other protocols too). Consider your +CURLOPT_FOLLOWLOCATION(3) and CURLOPT_REDIR_PROTOCOLS(3) settings. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +POP3 and SMTP were added in 7.31.0 + +# RETURN VALUE + +Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient +heap space. + +Note that curl_easy_setopt(3) does not parse the given string so given a +bad URL, it is not detected until curl_easy_perform(3) or similar is +called. diff --git a/docs/libcurl/opts/CURLOPT_USERAGENT.md b/docs/libcurl/opts/CURLOPT_USERAGENT.md new file mode 100644 index 0000000..a5423de --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_USERAGENT.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_USERAGENT +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CUSTOMREQUEST (3) + - CURLOPT_HTTPHEADER (3) + - CURLOPT_REFERER (3) + - CURLOPT_REQUEST_TARGET (3) +--- + +# NAME + +CURLOPT_USERAGENT - HTTP user-agent header + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_USERAGENT, char *ua); +~~~ + +# DESCRIPTION + +Pass a pointer to a null-terminated string as parameter. It is used to set the +User-Agent: header field in the HTTP request sent to the remote server. You +can also set any custom header with CURLOPT_HTTPHEADER(3). + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL, no User-Agent: header is used by default. + +# PROTOCOLS + +HTTP, HTTPS + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0"); + + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +As long as HTTP is supported + +# RETURN VALUE + +Returns CURLE_OK if HTTP is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_USERNAME.md b/docs/libcurl/opts/CURLOPT_USERNAME.md new file mode 100644 index 0000000..f748178 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_USERNAME.md @@ -0,0 +1,92 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_USERNAME +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HTTPAUTH (3) + - CURLOPT_PASSWORD (3) + - CURLOPT_PROXYAUTH (3) + - CURLOPT_USERPWD (3) +--- + +# NAME + +CURLOPT_USERNAME - user name to use in authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_USERNAME, + char *username); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should be pointing to the +null-terminated user name to use for the transfer. + +CURLOPT_USERNAME(3) sets the user name to be used in protocol +authentication. You should not use this option together with the (older) +CURLOPT_USERPWD(3) option. + +When using Kerberos V5 authentication with a Windows based server, you should +include the domain name in order for the server to successfully obtain a +Kerberos Ticket. If you do not then the initial part of the authentication +handshake may fail. + +When using NTLM, the user name can be specified simply as the user name +without the domain name should the server be part of a single domain and +forest. + +To include the domain name use either Down-Level Logon Name or UPN (User +Principal Name) formats. For example, **EXAMPLE\user** and +**user@example.com** respectively. + +Some HTTP servers (on Windows) support inclusion of the domain for Basic +authentication as well. + +To specify the password and login options, along with the user name, use the +CURLOPT_PASSWORD(3) and CURLOPT_LOGIN_OPTIONS(3) options. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +blank + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + curl_easy_setopt(curl, CURLOPT_USERNAME, "clark"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.19.1 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_USERPWD.md b/docs/libcurl/opts/CURLOPT_USERPWD.md new file mode 100644 index 0000000..01c6520 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_USERPWD.md @@ -0,0 +1,98 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_USERPWD +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PASSWORD (3) + - CURLOPT_PROXYUSERPWD (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_USERPWD - user name and password to use in authentication + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_USERPWD, char *userpwd); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, pointing to a null-terminated login details +string for the connection. The format of which is: [user name]:[password]. + +When using Kerberos V5 authentication with a Windows based server, you should +specify the user name part with the domain name in order for the server to +successfully obtain a Kerberos Ticket. If you do not then the initial part of +the authentication handshake may fail. + +When using NTLM, the user name can be specified simply as the user name +without the domain name should the server be part of a single domain and +forest. + +To specify the domain name use either Down-Level Logon Name or UPN (User +Principal Name) formats. For example **EXAMPLE\user** and **user@example.com** +respectively. + +Some HTTP servers (on Windows) support inclusion of the domain for Basic +authentication as well. + +When using HTTP and CURLOPT_FOLLOWLOCATION(3), libcurl might perform several +requests to possibly different hosts. libcurl only sends this user and +password information to hosts using the initial hostname (unless +CURLOPT_UNRESTRICTED_AUTH(3) is set), so if libcurl follows redirects to other +hosts, it does not send the user and password to those. This is enforced to +prevent accidental information leakage. + +Use CURLOPT_HTTPAUTH(3) to specify the authentication method for HTTP +based connections or CURLOPT_LOGIN_OPTIONS(3) to control IMAP, POP3 and +SMTP options. + +The user and password strings are not URL decoded, so there is no way to send +in a user name containing a colon using this option. Use +CURLOPT_USERNAME(3) for that, or include it in the URL. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +Most + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin"); + + curl_easy_setopt(curl, CURLOPT_USERPWD, "clark:kent"); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK on success or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_USE_SSL.md b/docs/libcurl/opts/CURLOPT_USE_SSL.md new file mode 100644 index 0000000..3e227fc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_USE_SSL.md @@ -0,0 +1,86 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_USE_SSL +Section: 3 +Source: libcurl +See-also: + - CURLOPT_PROXY_SSLVERSION (3) + - CURLOPT_SSLVERSION (3) + - CURLOPT_SSL_OPTIONS (3) +--- + +# NAME + +CURLOPT_USE_SSL - request using SSL / TLS for the transfer + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_USE_SSL, long level); +~~~ + +# DESCRIPTION + +Pass a long using one of the values from below, to make libcurl use your +desired *level* of SSL for the transfer. + +These are all protocols that start out plain text and get "upgraded" to SSL +using the STARTTLS command. + +This is for enabling SSL/TLS when you use FTP, SMTP, POP3, IMAP etc. + +## CURLUSESSL_NONE + +do not attempt to use SSL. + +## CURLUSESSL_TRY + +Try using SSL, proceed as normal otherwise. Note that server may close the +connection if the negotiation does not succeed. + +## CURLUSESSL_CONTROL + +Require SSL for the control connection or fail with *CURLE_USE_SSL_FAILED*. + +## CURLUSESSL_ALL + +Require SSL for all communication or fail with *CURLE_USE_SSL_FAILED*. + +# DEFAULT + +CURLUSESSL_NONE + +# PROTOCOLS + +FTP, SMTP, POP3, IMAP, LDAP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/file.ext"); + + /* require use of SSL for this, or fail */ + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.11.0. This option was known as CURLOPT_FTP_SSL up to 7.16.4, and +the constants were known as CURLFTPSSL_* +Handled by LDAP since 7.81.0. Fully supported by the OpenLDAP backend only. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_VERBOSE.md b/docs/libcurl/opts/CURLOPT_VERBOSE.md new file mode 100644 index 0000000..5ecc4b1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_VERBOSE.md @@ -0,0 +1,71 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_VERBOSE +Section: 3 +Source: libcurl +See-also: + - CURLOPT_DEBUGFUNCTION (3) + - CURLOPT_ERRORBUFFER (3) + - CURLOPT_STDERR (3) + - curl_global_trace (3) +--- + +# NAME + +CURLOPT_VERBOSE - verbose mode + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_VERBOSE, long onoff); +~~~ + +# DESCRIPTION + +Set the *onoff* parameter to 1 to make the library display a lot of +verbose information about its operations on this *handle*. Useful for +libcurl and/or protocol debugging and understanding. The verbose information +is sent to stderr, or the stream set with CURLOPT_STDERR(3). + +You hardly ever want this enabled in production use, you almost always want +this used when you debug/report problems. + +To also get all the protocol data sent and received, consider using the +CURLOPT_DEBUGFUNCTION(3). + +# DEFAULT + +0, meaning disabled. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* ask libcurl to show us the verbose output */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* Perform the request */ + curl_easy_perform(curl); + } +} +~~~ + +# AVAILABILITY + +Always + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md b/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md new file mode 100644 index 0000000..7541265 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md @@ -0,0 +1,111 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_WILDCARDMATCH +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CHUNK_BGN_FUNCTION (3) + - CURLOPT_CHUNK_END_FUNCTION (3) + - CURLOPT_FNMATCH_FUNCTION (3) + - CURLOPT_URL (3) +--- + +# NAME + +CURLOPT_WILDCARDMATCH - directory wildcard transfers + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WILDCARDMATCH, long onoff); +~~~ + +# DESCRIPTION + +Set *onoff* to 1 if you want to transfer multiple files according to a +filename pattern. The pattern can be specified as part of the CURLOPT_URL(3) +option, using an **fnmatch**-like pattern (Shell Pattern Matching) in the last +part of URL (filename). + +By default, libcurl uses its internal wildcard matching implementation. You +can provide your own matching function by the +CURLOPT_FNMATCH_FUNCTION(3) option. + +A brief introduction of its syntax follows: + +## * - ASTERISK + + ftp://example.com/some/path/*.txt + +for all txt's from the root directory. Only two asterisks are allowed within +the same pattern string. + +## ? - QUESTION MARK + +Question mark matches any (exactly one) character. + + ftp://example.com/some/path/photo?.jpg + +## [ - BRACKET EXPRESSION + +The left bracket opens a bracket expression. The question mark and asterisk have +no special meaning in a bracket expression. Each bracket expression ends by the +right bracket and matches exactly one character. Some examples follow: + +**[a-zA-Z0-9]** or **[f-gF-G]** - character interval + +**[abc]** - character enumeration + +**[^abc]** or **[!abc]** - negation + +**[[:name:]]** class expression. Supported classes are **alnum**,**lower**, +**space**, **alpha**, **digit**, **print**, **upper**, **blank**, **graph**, +**xdigit**. + +**[][-!^]** - special case - matches only '-', ']', '[', '!' or '^'. These +characters have no special purpose. + +**[[]]** - escape syntax. Matches '[', ']' or 'e'. + +Using the rules above, a filename pattern can be constructed: + + ftp://example.com/some/path/[a-z[:upper:]\\].jpg + +# PROTOCOLS + +This feature is only supported for FTP download. + +# EXAMPLE + +~~~c +extern long begin_cb(struct curl_fileinfo *, void *, int); +extern long end_cb(void *ptr); + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + /* turn on wildcard matching */ + curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L); + + /* callback is called before download of concrete file started */ + curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, begin_cb); + + /* callback is called after data from the file have been transferred */ + curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, end_cb); + + /* See more on https://curl.se/libcurl/c/ftp-wildcard.html */ + } +} +~~~ + +# AVAILABILITY + +Added in 7.21.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_WRITEDATA.md b/docs/libcurl/opts/CURLOPT_WRITEDATA.md new file mode 100644 index 0000000..495c6bf --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_WRITEDATA.md @@ -0,0 +1,63 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_WRITEDATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERDATA (3) + - CURLOPT_READDATA (3) + - CURLOPT_WRITEFUNCTION (3) +--- + +# NAME + +CURLOPT_WRITEDATA - pointer passed to the write callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEDATA, void *pointer); +~~~ + +# DESCRIPTION + +A data *pointer* to pass to the write callback. If you use the +CURLOPT_WRITEFUNCTION(3) option, this is the pointer you get in that +callback's fourth and last argument. If you do not use a write callback, you +must make *pointer* a 'FILE *' (cast to 'void *') as libcurl passes this +to *fwrite(3)* when writing data. + +The internal CURLOPT_WRITEFUNCTION(3) writes the data to the FILE * +given with this option, or to stdout if this option has not been set. + +If you are using libcurl as a Windows DLL, you **MUST** use a +CURLOPT_WRITEFUNCTION(3) if you set this option or you might experience +crashes. + +# DEFAULT + +By default, this is a FILE * to stdout. + +# PROTOCOLS + +Used for all protocols. + +# EXAMPLE + +A common technique is to use the write callback to store the incoming data +into a dynamically growing allocated buffer, and then this +CURLOPT_WRITEDATA(3) is used to point to a struct or the buffer to store +data in. Like in the getinmemory example: +https://curl.se/libcurl/c/getinmemory.html + +# AVAILABILITY + +Available in all libcurl versions. This option was formerly known as +CURLOPT_FILE, the name CURLOPT_WRITEDATA(3) was added in 7.9.7. + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md new file mode 100644 index 0000000..8957439 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md @@ -0,0 +1,136 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_WRITEFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_HEADERFUNCTION (3) + - CURLOPT_READFUNCTION (3) + - CURLOPT_WRITEDATA (3) +--- + +# NAME + +CURLOPT_WRITEFUNCTION - callback for writing received data + +# SYNOPSIS + +~~~c +#include + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEFUNCTION, write_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This callback function gets called by libcurl as soon as there is data +received that needs to be saved. For most transfers, this callback gets called +many times and each invoke delivers another chunk of data. *ptr* points to the +delivered data, and the size of that data is *nmemb*; *size* is always 1. + +The data passed to this function is not null-terminated. + +The callback function is passed as much data as possible in all invokes, but +you must not make any assumptions. It may be one byte, it may be +thousands. The maximum amount of body data that is be passed to the write +callback is defined in the curl.h header file: *CURL_MAX_WRITE_SIZE* (the +usual default is 16K). If CURLOPT_HEADER(3) is enabled, which makes header +data get passed to the write callback, you can get up to +*CURL_MAX_HTTP_HEADER* bytes of header data passed into it. This usually means +100K. + +This function may be called with zero bytes data if the transferred file is +empty. + +Set the *userdata* argument with the CURLOPT_WRITEDATA(3) option. + +Your callback should return the number of bytes actually taken care of. If +that amount differs from the amount passed to your callback function, it +signals an error condition to the library. This causes the transfer to get +aborted and the libcurl function used returns *CURLE_WRITE_ERROR*. + +You can also abort the transfer by returning CURL_WRITEFUNC_ERROR (added in +7.87.0), which makes *CURLE_WRITE_ERROR* get returned. + +If the callback function returns CURL_WRITEFUNC_PAUSE it pauses this +transfer. See curl_easy_pause(3) for further details. + +Set this option to NULL to get the internal default function used instead of +your callback. The internal default function writes the data to the FILE * +given with CURLOPT_WRITEDATA(3). + +This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to +do that. + +# DEFAULT + +libcurl uses 'fwrite' as a callback by default. + +# PROTOCOLS + +For all protocols + +# EXAMPLE + +~~~c +#include /* for realloc */ +#include /* for memcpy */ + +struct memory { + char *response; + size_t size; +}; + +static size_t cb(void *data, size_t size, size_t nmemb, void *clientp) +{ + size_t realsize = size * nmemb; + struct memory *mem = (struct memory *)clientp; + + char *ptr = realloc(mem->response, mem->size + realsize + 1); + if(!ptr) + return 0; /* out of memory! */ + + mem->response = ptr; + memcpy(&(mem->response[mem->size]), data, realsize); + mem->size += realsize; + mem->response[mem->size] = 0; + + return realsize; +} + +int main(void) +{ + struct memory chunk = {0}; + CURLcode res; + CURL *curl = curl_easy_init(); + if(curl) { + /* send all data to this function */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); + + /* send a request */ + res = curl_easy_perform(curl); + + /* remember to free the buffer */ + free(chunk.response); + + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Support for the CURL_WRITEFUNC_PAUSE return code was added in version 7.18.0. + +# RETURN VALUE + +This returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md b/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md new file mode 100644 index 0000000..04af5bc --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md @@ -0,0 +1,75 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_WS_OPTIONS +Section: 3 +Source: libcurl +See-also: + - CURLOPT_CONNECT_ONLY (3) + - curl_ws_recv (3) + - curl_ws_send (3) +--- + +# NAME + +CURLOPT_WS_OPTIONS - WebSocket behavior options + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WS_OPTIONS, long bitmask); +~~~ + +# DESCRIPTION + +Pass a long with a bitmask to tell libcurl about specific WebSocket +behaviors. + +To detach a WebSocket connection and use the curl_ws_send(3) and +curl_ws_recv(3) functions after the HTTP upgrade procedure, set the +CURLOPT_CONNECT_ONLY(3) option to 2L. + +Available bits in the bitmask + +## CURLWS_RAW_MODE (1) + +Deliver "raw" WebSocket traffic to the CURLOPT_WRITEFUNCTION(3) +callback. + +In raw mode, libcurl does not handle pings or any other frame for the +application. + +# DEFAULT + +0 + +# PROTOCOLS + +WebSocket + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "ws://example.com/"); + /* tell curl we deal with all the WebSocket magic ourselves */ + curl_easy_setopt(curl, CURLOPT_WS_OPTIONS, (long)CURLWS_RAW_MODE); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.86.0 + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. diff --git a/docs/libcurl/opts/CURLOPT_XFERINFODATA.md b/docs/libcurl/opts/CURLOPT_XFERINFODATA.md new file mode 100644 index 0000000..145057c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_XFERINFODATA.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_XFERINFODATA +Section: 3 +Source: libcurl +See-also: + - CURLOPT_NOPROGRESS (3) + - CURLOPT_VERBOSE (3) + - CURLOPT_XFERINFOFUNCTION (3) +--- + +# NAME + +CURLOPT_XFERINFODATA - pointer passed to the progress callback + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_XFERINFODATA, void *pointer); +~~~ + +# DESCRIPTION + +Pass a *pointer* that is untouched by libcurl and passed as the first +argument in the progress callback set with CURLOPT_XFERINFOFUNCTION(3). + +This is an alias for CURLOPT_PROGRESSDATA(3). + +# DEFAULT + +The default value of this parameter is NULL. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct progress { + char *private; + size_t size; +}; + +static size_t progress_cb(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow) +{ + struct progress *memory = clientp; + printf("private ptr: %p\n", memory->private); + /* use the values */ + + return 0; /* all is good */ +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct progress data; + + /* pass struct to callback */ + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &data); + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_cb); + } +} +~~~ + +# AVAILABILITY + +Added in 7.32.0 + +# RETURN VALUE + +Returns CURLE_OK diff --git a/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md b/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md new file mode 100644 index 0000000..b965db5 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md @@ -0,0 +1,120 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_XFERINFOFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLOPT_NOPROGRESS (3) + - CURLOPT_XFERINFODATA (3) +--- + +# NAME + +CURLOPT_XFERINFOFUNCTION - progress meter callback + +# SYNOPSIS + +~~~c +#include + +int progress_callback(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_XFERINFOFUNCTION, + progress_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +This function gets called by libcurl instead of its internal equivalent with a +frequent interval. While data is being transferred it gets called frequently, +and during slow periods like when nothing is being transferred it can slow +down to about one call per second. + +*clientp* is the pointer set with CURLOPT_XFERINFODATA(3), it is not +used by libcurl but is only passed along from the application to the callback. + +The callback gets told how much data libcurl is about to transfer and has +already transferred, in number of bytes. *dltotal* is the total number of +bytes libcurl expects to download in this transfer. *dlnow* is the number +of bytes downloaded so far. *ultotal* is the total number of bytes libcurl +expects to upload in this transfer. *ulnow* is the number of bytes +uploaded so far. + +Unknown/unused argument values passed to the callback are set to zero (like if +you only download data, the upload size remains 0). Many times the callback is +called one or more times first, before it knows the data sizes so a program +must be made to handle that. + +If your callback function returns CURL_PROGRESSFUNC_CONTINUE it makes libcurl +to continue executing the default progress function. + +Returning any other non-zero value from this callback makes libcurl abort the +transfer and return *CURLE_ABORTED_BY_CALLBACK*. + +If you transfer data with the multi interface, this function is not called +during periods of idleness unless you call the appropriate libcurl function +that performs transfers. + +CURLOPT_NOPROGRESS(3) must be set to 0 to make this function actually +get called. + +# DEFAULT + +By default, libcurl has an internal progress meter. That is rarely wanted by +users. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct progress { + char *private; + size_t size; +}; + +static size_t progress_callback(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow) +{ + struct progress *memory = clientp; + printf("my ptr: %p\n", memory->private); + + /* use the values */ + + return 0; /* all is good */ +} + +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + struct progress data; + + /* pass struct to callback */ + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &data); + + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); + } +} +~~~ + +# AVAILABILITY + +Added in 7.32.0. This callback replaces CURLOPT_PROGRESSFUNCTION(3) + +# RETURN VALUE + +Returns CURLE_OK. diff --git a/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md b/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md new file mode 100644 index 0000000..af91ea0 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md @@ -0,0 +1,67 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLOPT_XOAUTH2_BEARER +Section: 3 +Source: libcurl +See-also: + - CURLOPT_MAIL_AUTH (3) + - CURLOPT_USERNAME (3) +--- + +# NAME + +CURLOPT_XOAUTH2_BEARER - OAuth 2.0 access token + +# SYNOPSIS + +~~~c +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_XOAUTH2_BEARER, char *token); +~~~ + +# DESCRIPTION + +Pass a char pointer as parameter, which should point to the null-terminated +OAuth 2.0 Bearer Access Token for use with HTTP, IMAP, LDAP, POP3 and SMTP +servers that support the OAuth 2.0 Authorization Framework. + +Note: For IMAP, LDAP, POP3 and SMTP, the user name used to generate the +Bearer Token should be supplied via the CURLOPT_USERNAME(3) option. + +The application does not have to keep the string around after setting this +option. + +# DEFAULT + +NULL + +# PROTOCOLS + +HTTP, IMAP, LDAP, POP3 and SMTP + +# EXAMPLE + +~~~c +int main(void) +{ + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, "pop3://example.com/"); + curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, "1ab9cb22ba269a7"); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } +} +~~~ + +# AVAILABILITY + +Added in 7.33.0. Support for OpenLDAP added in 7.82.0. + +# RETURN VALUE + +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md b/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md new file mode 100644 index 0000000..f41f86e --- /dev/null +++ b/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md @@ -0,0 +1,77 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLSHOPT_LOCKFUNC +Section: 3 +Source: libcurl +See-also: + - CURLSHOPT_UNLOCKFUNC (3) + - curl_share_cleanup (3) + - curl_share_init (3) + - curl_share_setopt (3) +--- + +# NAME + +CURLSHOPT_LOCKFUNC - mutex lock callback + +# SYNOPSIS + +~~~c +#include + +void lockcb(CURL *handle, curl_lock_data data, curl_lock_access access, + void *clientp); + +CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_LOCKFUNC, lockcb); +~~~ + +# DESCRIPTION + +Set a mutex lock callback for the share object, to allow it to get used by +multiple threads concurrently. There is a corresponding +CURLSHOPT_UNLOCKFUNC(3) callback called when the mutex is again released. + +The *lockcb* argument must be a pointer to a function matching the +prototype shown above. The arguments to the callback are: + +*handle* is the currently active easy handle in use when the share object +is intended to get used. + +The *data* argument tells what kind of data libcurl wants to lock. Make +sure that the callback uses a different lock for each kind of data. + +*access* defines what access type libcurl wants, shared or single. + +*clientp* is the private pointer you set with CURLSHOPT_USERDATA(3). +This pointer is not used by libcurl itself. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +extern void mutex_lock(CURL *handle, curl_lock_data data, + curl_lock_access access, void *clientp); + +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, mutex_lock); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +CURLSHE_OK (zero) means that the option was set properly, non-zero means an +error occurred. See libcurl-errors(3) for the full list with +descriptions. diff --git a/docs/libcurl/opts/CURLSHOPT_SHARE.md b/docs/libcurl/opts/CURLSHOPT_SHARE.md new file mode 100644 index 0000000..66ed270 --- /dev/null +++ b/docs/libcurl/opts/CURLSHOPT_SHARE.md @@ -0,0 +1,117 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLSHOPT_SHARE +Section: 3 +Source: libcurl +See-also: + - CURLSHOPT_UNSHARE (3) + - curl_share_cleanup (3) + - curl_share_init (3) + - curl_share_setopt (3) +--- + +# NAME + +CURLSHOPT_SHARE - add data to share + +# SYNOPSIS + +~~~c +#include + +CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_SHARE, long type); +~~~ + +# DESCRIPTION + +The *type* parameter specifies what specific data that should be shared +and kept in the share object that was created with curl_share_init(3). +The given *type* must be be one of the values described below. You can set +CURLSHOPT_SHARE(3) multiple times with different data arguments to have +the share object share multiple types of data. Unset a type again by setting +CURLSHOPT_UNSHARE(3). + +## CURL_LOCK_DATA_COOKIE + +Cookie data is shared across the easy handles using this shared object. Note +that this does not activate an easy handle's cookie handling. You can do that +separately by using CURLOPT_COOKIEFILE(3) for example. + +## CURL_LOCK_DATA_DNS + +Cached DNS hosts are shared across the easy handles using this shared +object. Note that when you use the multi interface, all easy handles added to +the same multi handle share DNS cache by default without using this option. + +## CURL_LOCK_DATA_SSL_SESSION + +SSL session IDs are shared across the easy handles using this shared +object. This reduces the time spent in the SSL handshake when reconnecting to +the same server. Note SSL session IDs are reused within the same easy handle +by default. Note this symbol was added in 7.10.3 but was not implemented until +7.23.0. + +## CURL_LOCK_DATA_CONNECT + +Put the connection cache in the share object and make all easy handles using +this share object share the connection cache. + +It is not supported to share connections between multiple concurrent threads. + +Connections that are used for HTTP/1.1 Pipelining or HTTP/2 multiplexing only +get additional transfers added to them if the existing connection is held by +the same multi or easy handle. libcurl does not support doing HTTP/2 streams +in different threads using a shared connection. + +Support for **CURL_LOCK_DATA_CONNECT** was added in 7.57.0, but the symbol +existed before this. + +Note that when you use the multi interface, all easy handles added to the same +multi handle shares connection cache by default without using this option. + +## CURL_LOCK_DATA_PSL + +The Public Suffix List stored in the share object is made available to all +easy handle bound to the later. Since the Public Suffix List is periodically +refreshed, this avoids updates in too many different contexts. + +Added in 7.61.0. + +Note that when you use the multi interface, all easy handles added to the same +multi handle shares PSL cache by default without using this option. + +## CURL_LOCK_DATA_HSTS + +The in-memory HSTS cache. + +It is not supported to share the HSTS between multiple concurrent threads. + +Added in 7.88.0 + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +CURLSHE_OK (zero) means that the option was set properly, non-zero means an +error occurred. See libcurl-errors(3) for the full list with +descriptions. diff --git a/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md b/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md new file mode 100644 index 0000000..16f9a37 --- /dev/null +++ b/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLSHOPT_UNLOCKFUNC +Section: 3 +Source: libcurl +See-also: + - CURLSHOPT_LOCKFUNC (3) + - curl_share_cleanup (3) + - curl_share_init (3) + - curl_share_setopt (3) +--- + +# NAME + +CURLSHOPT_UNLOCKFUNC - mutex unlock callback + +# SYNOPSIS + +~~~c +#include + +void unlockcb(CURL *handle, curl_lock_data data, void *clientp); + +CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_UNLOCKFUNC, unlockcb); +~~~ + +# DESCRIPTION + +Set a mutex unlock callback for the share object. There is a corresponding +CURLSHOPT_LOCKFUNC(3) callback called when the mutex is first locked. + +The *unlockcb* argument must be a pointer to a function matching the +prototype shown above. The arguments to the callback are: + +*handle* is the currently active easy handle in use when the share object +is released. + +The *data* argument tells what kind of data libcurl wants to unlock. Make +sure that the callback uses a different lock for each kind of data. + +*clientp* is the private pointer you set with CURLSHOPT_USERDATA(3). +This pointer is not used by libcurl itself. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +extern void mutex_unlock(CURL *, curl_lock_data, void *); + +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, mutex_unlock); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +CURLSHE_OK (zero) means that the option was set properly, non-zero means an +error occurred. See libcurl-errors(3) for the full list with +descriptions. diff --git a/docs/libcurl/opts/CURLSHOPT_UNSHARE.md b/docs/libcurl/opts/CURLSHOPT_UNSHARE.md new file mode 100644 index 0000000..e3cf598 --- /dev/null +++ b/docs/libcurl/opts/CURLSHOPT_UNSHARE.md @@ -0,0 +1,84 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLSHOPT_UNSHARE +Section: 3 +Source: libcurl +See-also: + - CURLSHOPT_SHARE (3) + - curl_share_cleanup (3) + - curl_share_init (3) + - curl_share_setopt (3) +--- + +# NAME + +CURLSHOPT_UNSHARE - remove data to share + +# SYNOPSIS + +~~~c +#include + +CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_UNSHARE, long type); +~~~ + +# DESCRIPTION + +The *type* parameter specifies what specific data that should no longer be +shared and kept in the share object that was created with +curl_share_init(3). In other words, stop sharing that data in this +shared object. The given *type* must be be one of the values described +below. You can set CURLSHOPT_UNSHARE(3) multiple times with different +data arguments to remove multiple types from the shared object. Add data to +share again with CURLSHOPT_SHARE(3). + +## CURL_LOCK_DATA_COOKIE + +Cookie data is no longer shared across the easy handles using this shared +object. + +## CURL_LOCK_DATA_DNS + +Cached DNS hosts are no longer shared across the easy handles using this +shared object. + +## CURL_LOCK_DATA_SSL_SESSION + +SSL session IDs are no longer shared across the easy handles using this shared +object. + +## CURL_LOCK_DATA_CONNECT + +The connection cache is no longer shared. + +## CURL_LOCK_DATA_PSL + +The Public Suffix List is no longer shared. + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +int main(void) +{ + CURLSHcode sh; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +CURLSHE_OK (zero) means that the option was set properly, non-zero means an +error occurred. See libcurl-errors(3) for the full list with +descriptions. diff --git a/docs/libcurl/opts/CURLSHOPT_USERDATA.md b/docs/libcurl/opts/CURLSHOPT_USERDATA.md new file mode 100644 index 0000000..d0ec777 --- /dev/null +++ b/docs/libcurl/opts/CURLSHOPT_USERDATA.md @@ -0,0 +1,62 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLSHOPT_USERDATA +Section: 3 +Source: libcurl +See-also: + - CURLSHOPT_LOCKFUNC (3) + - curl_share_cleanup (3) + - curl_share_init (3) + - curl_share_setopt (3) +--- + +# NAME + +CURLSHOPT_USERDATA - pointer passed to the lock and unlock mutex callbacks + +# SYNOPSIS + +~~~c +#include + +CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_USERDATA, void *clientp); +~~~ + +# DESCRIPTION + +The *clientp* parameter is held verbatim by libcurl and is passed on as +the *clientp* argument to the callbacks set with +CURLSHOPT_LOCKFUNC(3) and CURLSHOPT_UNLOCKFUNC(3). + +# PROTOCOLS + +All + +# EXAMPLE + +~~~c +struct secrets { + void *custom; +}; + +int main(void) +{ + CURLSHcode sh; + struct secrets private_stuff; + CURLSH *share = curl_share_init(); + sh = curl_share_setopt(share, CURLSHOPT_USERDATA, &private_stuff); + if(sh) + printf("Error: %s\n", curl_share_strerror(sh)); +} +~~~ + +# AVAILABILITY + +Added in 7.10 + +# RETURN VALUE + +CURLSHE_OK (zero) means that the option was set properly, non-zero means an +error occurred. See libcurl-errors(3) for the full list with +descriptions. diff --git a/docs/libcurl/opts/Makefile.am b/docs/libcurl/opts/Makefile.am new file mode 100644 index 0000000..42f9db4 --- /dev/null +++ b/docs/libcurl/opts/Makefile.am @@ -0,0 +1,44 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +AUTOMAKE_OPTIONS = foreign no-dependencies + +include Makefile.inc + +CURLPAGES = $(man_MANS:.3=.md) +CLEANFILES = $(man_MANS) +nodist_MANS = $(man_MANS) + +EXTRA_DIST = $(CURLPAGES) CMakeLists.txt + +CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ +CD2 = $(CD2_$(V)) +CD2_0 = @echo " RENDER " $@; +CD2_1 = +CD2_ = $(CD2_0) + +SUFFIXES = .3 .md + +.md.3: + $(CD2)$(CD2NROFF) diff --git a/docs/libcurl/opts/Makefile.in b/docs/libcurl/opts/Makefile.in new file mode 100644 index 0000000..fa2b743 --- /dev/null +++ b/docs/libcurl/opts/Makefile.in @@ -0,0 +1,1115 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# Shared between Makefile.am and CMakeLists.txt +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = docs/libcurl/opts +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +depcomp = +am__maybe_remake_depfiles = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man3dir = $(mandir)/man3 +am__installdirs = "$(DESTDIR)$(man3dir)" +MANS = $(man_MANS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign no-dependencies +man_MANS = \ + CURLINFO_ACTIVESOCKET.3 \ + CURLINFO_APPCONNECT_TIME.3 \ + CURLINFO_APPCONNECT_TIME_T.3 \ + CURLINFO_CAINFO.3 \ + CURLINFO_CAPATH.3 \ + CURLINFO_CERTINFO.3 \ + CURLINFO_CONDITION_UNMET.3 \ + CURLINFO_CONNECT_TIME.3 \ + CURLINFO_CONNECT_TIME_T.3 \ + CURLINFO_CONN_ID.3 \ + CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 \ + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.3 \ + CURLINFO_CONTENT_LENGTH_UPLOAD.3 \ + CURLINFO_CONTENT_LENGTH_UPLOAD_T.3 \ + CURLINFO_CONTENT_TYPE.3 \ + CURLINFO_COOKIELIST.3 \ + CURLINFO_EFFECTIVE_METHOD.3 \ + CURLINFO_EFFECTIVE_URL.3 \ + CURLINFO_FILETIME.3 \ + CURLINFO_FILETIME_T.3 \ + CURLINFO_FTP_ENTRY_PATH.3 \ + CURLINFO_HEADER_SIZE.3 \ + CURLINFO_HTTP_CONNECTCODE.3 \ + CURLINFO_HTTP_VERSION.3 \ + CURLINFO_HTTPAUTH_AVAIL.3 \ + CURLINFO_LASTSOCKET.3 \ + CURLINFO_LOCAL_IP.3 \ + CURLINFO_LOCAL_PORT.3 \ + CURLINFO_NAMELOOKUP_TIME.3 \ + CURLINFO_NAMELOOKUP_TIME_T.3 \ + CURLINFO_NUM_CONNECTS.3 \ + CURLINFO_OS_ERRNO.3 \ + CURLINFO_PRETRANSFER_TIME.3 \ + CURLINFO_PRETRANSFER_TIME_T.3 \ + CURLINFO_PRIMARY_IP.3 \ + CURLINFO_PRIMARY_PORT.3 \ + CURLINFO_PRIVATE.3 \ + CURLINFO_PROTOCOL.3 \ + CURLINFO_PROXY_ERROR.3 \ + CURLINFO_PROXY_SSL_VERIFYRESULT.3 \ + CURLINFO_PROXYAUTH_AVAIL.3 \ + CURLINFO_QUEUE_TIME_T.3 \ + CURLINFO_REDIRECT_COUNT.3 \ + CURLINFO_REDIRECT_TIME.3 \ + CURLINFO_REDIRECT_TIME_T.3 \ + CURLINFO_REDIRECT_URL.3 \ + CURLINFO_REFERER.3 \ + CURLINFO_REQUEST_SIZE.3 \ + CURLINFO_RESPONSE_CODE.3 \ + CURLINFO_RETRY_AFTER.3 \ + CURLINFO_RTSP_CLIENT_CSEQ.3 \ + CURLINFO_RTSP_CSEQ_RECV.3 \ + CURLINFO_RTSP_SERVER_CSEQ.3 \ + CURLINFO_RTSP_SESSION_ID.3 \ + CURLINFO_SCHEME.3 \ + CURLINFO_SIZE_DOWNLOAD.3 \ + CURLINFO_SIZE_DOWNLOAD_T.3 \ + CURLINFO_SIZE_UPLOAD.3 \ + CURLINFO_SIZE_UPLOAD_T.3 \ + CURLINFO_SPEED_DOWNLOAD.3 \ + CURLINFO_SPEED_DOWNLOAD_T.3 \ + CURLINFO_SPEED_UPLOAD.3 \ + CURLINFO_SPEED_UPLOAD_T.3 \ + CURLINFO_SSL_ENGINES.3 \ + CURLINFO_SSL_VERIFYRESULT.3 \ + CURLINFO_STARTTRANSFER_TIME.3 \ + CURLINFO_STARTTRANSFER_TIME_T.3 \ + CURLINFO_TLS_SESSION.3 \ + CURLINFO_TLS_SSL_PTR.3 \ + CURLINFO_TOTAL_TIME.3 \ + CURLINFO_TOTAL_TIME_T.3 \ + CURLINFO_XFER_ID.3 \ + CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 \ + CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 \ + CURLMOPT_MAX_CONCURRENT_STREAMS.3 \ + CURLMOPT_MAX_HOST_CONNECTIONS.3 \ + CURLMOPT_MAX_PIPELINE_LENGTH.3 \ + CURLMOPT_MAX_TOTAL_CONNECTIONS.3 \ + CURLMOPT_MAXCONNECTS.3 \ + CURLMOPT_PIPELINING.3 \ + CURLMOPT_PIPELINING_SERVER_BL.3 \ + CURLMOPT_PIPELINING_SITE_BL.3 \ + CURLMOPT_PUSHDATA.3 \ + CURLMOPT_PUSHFUNCTION.3 \ + CURLMOPT_SOCKETDATA.3 \ + CURLMOPT_SOCKETFUNCTION.3 \ + CURLMOPT_TIMERDATA.3 \ + CURLMOPT_TIMERFUNCTION.3 \ + CURLOPT_ABSTRACT_UNIX_SOCKET.3 \ + CURLOPT_ACCEPT_ENCODING.3 \ + CURLOPT_ACCEPTTIMEOUT_MS.3 \ + CURLOPT_ADDRESS_SCOPE.3 \ + CURLOPT_ALTSVC.3 \ + CURLOPT_ALTSVC_CTRL.3 \ + CURLOPT_APPEND.3 \ + CURLOPT_AUTOREFERER.3 \ + CURLOPT_AWS_SIGV4.3 \ + CURLOPT_BUFFERSIZE.3 \ + CURLOPT_CAINFO.3 \ + CURLOPT_CAINFO_BLOB.3 \ + CURLOPT_CAPATH.3 \ + CURLOPT_CA_CACHE_TIMEOUT.3 \ + CURLOPT_CERTINFO.3 \ + CURLOPT_CHUNK_BGN_FUNCTION.3 \ + CURLOPT_CHUNK_DATA.3 \ + CURLOPT_CHUNK_END_FUNCTION.3 \ + CURLOPT_CLOSESOCKETDATA.3 \ + CURLOPT_CLOSESOCKETFUNCTION.3 \ + CURLOPT_CONNECT_ONLY.3 \ + CURLOPT_CONNECT_TO.3 \ + CURLOPT_CONNECTTIMEOUT.3 \ + CURLOPT_CONNECTTIMEOUT_MS.3 \ + CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 \ + CURLOPT_CONV_FROM_UTF8_FUNCTION.3 \ + CURLOPT_CONV_TO_NETWORK_FUNCTION.3 \ + CURLOPT_COOKIE.3 \ + CURLOPT_COOKIEFILE.3 \ + CURLOPT_COOKIEJAR.3 \ + CURLOPT_COOKIELIST.3 \ + CURLOPT_COOKIESESSION.3 \ + CURLOPT_COPYPOSTFIELDS.3 \ + CURLOPT_CRLF.3 \ + CURLOPT_CRLFILE.3 \ + CURLOPT_CURLU.3 \ + CURLOPT_CUSTOMREQUEST.3 \ + CURLOPT_DEBUGDATA.3 \ + CURLOPT_DEBUGFUNCTION.3 \ + CURLOPT_DEFAULT_PROTOCOL.3 \ + CURLOPT_DIRLISTONLY.3 \ + CURLOPT_DISALLOW_USERNAME_IN_URL.3 \ + CURLOPT_DNS_CACHE_TIMEOUT.3 \ + CURLOPT_DNS_INTERFACE.3 \ + CURLOPT_DNS_LOCAL_IP4.3 \ + CURLOPT_DNS_LOCAL_IP6.3 \ + CURLOPT_DNS_SERVERS.3 \ + CURLOPT_DNS_SHUFFLE_ADDRESSES.3 \ + CURLOPT_DNS_USE_GLOBAL_CACHE.3 \ + CURLOPT_DOH_SSL_VERIFYHOST.3 \ + CURLOPT_DOH_SSL_VERIFYPEER.3 \ + CURLOPT_DOH_SSL_VERIFYSTATUS.3 \ + CURLOPT_DOH_URL.3 \ + CURLOPT_EGDSOCKET.3 \ + CURLOPT_ERRORBUFFER.3 \ + CURLOPT_EXPECT_100_TIMEOUT_MS.3 \ + CURLOPT_FAILONERROR.3 \ + CURLOPT_FILETIME.3 \ + CURLOPT_FNMATCH_DATA.3 \ + CURLOPT_FNMATCH_FUNCTION.3 \ + CURLOPT_FOLLOWLOCATION.3 \ + CURLOPT_FORBID_REUSE.3 \ + CURLOPT_FRESH_CONNECT.3 \ + CURLOPT_FTP_ACCOUNT.3 \ + CURLOPT_FTP_ALTERNATIVE_TO_USER.3 \ + CURLOPT_FTP_CREATE_MISSING_DIRS.3 \ + CURLOPT_FTP_FILEMETHOD.3 \ + CURLOPT_FTP_SKIP_PASV_IP.3 \ + CURLOPT_FTP_SSL_CCC.3 \ + CURLOPT_FTP_USE_EPRT.3 \ + CURLOPT_FTP_USE_EPSV.3 \ + CURLOPT_FTP_USE_PRET.3 \ + CURLOPT_FTPPORT.3 \ + CURLOPT_FTPSSLAUTH.3 \ + CURLOPT_GSSAPI_DELEGATION.3 \ + CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 \ + CURLOPT_HAPROXYPROTOCOL.3 \ + CURLOPT_HAPROXY_CLIENT_IP.3 \ + CURLOPT_HEADER.3 \ + CURLOPT_HEADERDATA.3 \ + CURLOPT_HEADERFUNCTION.3 \ + CURLOPT_HEADEROPT.3 \ + CURLOPT_HSTS.3 \ + CURLOPT_HSTS_CTRL.3 \ + CURLOPT_HSTSREADDATA.3 \ + CURLOPT_HSTSREADFUNCTION.3 \ + CURLOPT_HSTSWRITEDATA.3 \ + CURLOPT_HSTSWRITEFUNCTION.3 \ + CURLOPT_HTTP09_ALLOWED.3 \ + CURLOPT_HTTP200ALIASES.3 \ + CURLOPT_HTTP_CONTENT_DECODING.3 \ + CURLOPT_HTTP_TRANSFER_DECODING.3 \ + CURLOPT_HTTP_VERSION.3 \ + CURLOPT_HTTPAUTH.3 \ + CURLOPT_HTTPGET.3 \ + CURLOPT_HTTPHEADER.3 \ + CURLOPT_HTTPPOST.3 \ + CURLOPT_HTTPPROXYTUNNEL.3 \ + CURLOPT_IGNORE_CONTENT_LENGTH.3 \ + CURLOPT_INFILESIZE.3 \ + CURLOPT_INFILESIZE_LARGE.3 \ + CURLOPT_INTERFACE.3 \ + CURLOPT_INTERLEAVEDATA.3 \ + CURLOPT_INTERLEAVEFUNCTION.3 \ + CURLOPT_IOCTLDATA.3 \ + CURLOPT_IOCTLFUNCTION.3 \ + CURLOPT_IPRESOLVE.3 \ + CURLOPT_ISSUERCERT.3 \ + CURLOPT_ISSUERCERT_BLOB.3 \ + CURLOPT_KEEP_SENDING_ON_ERROR.3 \ + CURLOPT_KEYPASSWD.3 \ + CURLOPT_KRBLEVEL.3 \ + CURLOPT_LOCALPORT.3 \ + CURLOPT_LOCALPORTRANGE.3 \ + CURLOPT_LOGIN_OPTIONS.3 \ + CURLOPT_LOW_SPEED_LIMIT.3 \ + CURLOPT_LOW_SPEED_TIME.3 \ + CURLOPT_MAIL_AUTH.3 \ + CURLOPT_MAIL_FROM.3 \ + CURLOPT_MAIL_RCPT.3 \ + CURLOPT_MAIL_RCPT_ALLOWFAILS.3 \ + CURLOPT_MAX_RECV_SPEED_LARGE.3 \ + CURLOPT_MAX_SEND_SPEED_LARGE.3 \ + CURLOPT_MAXAGE_CONN.3 \ + CURLOPT_MAXCONNECTS.3 \ + CURLOPT_MAXFILESIZE.3 \ + CURLOPT_MAXFILESIZE_LARGE.3 \ + CURLOPT_MAXLIFETIME_CONN.3 \ + CURLOPT_MAXREDIRS.3 \ + CURLOPT_MIME_OPTIONS.3 \ + CURLOPT_MIMEPOST.3 \ + CURLOPT_NETRC.3 \ + CURLOPT_NETRC_FILE.3 \ + CURLOPT_NEW_DIRECTORY_PERMS.3 \ + CURLOPT_NEW_FILE_PERMS.3 \ + CURLOPT_NOBODY.3 \ + CURLOPT_NOPROGRESS.3 \ + CURLOPT_NOPROXY.3 \ + CURLOPT_NOSIGNAL.3 \ + CURLOPT_OPENSOCKETDATA.3 \ + CURLOPT_OPENSOCKETFUNCTION.3 \ + CURLOPT_PASSWORD.3 \ + CURLOPT_PATH_AS_IS.3 \ + CURLOPT_PINNEDPUBLICKEY.3 \ + CURLOPT_PIPEWAIT.3 \ + CURLOPT_PORT.3 \ + CURLOPT_POST.3 \ + CURLOPT_POSTFIELDS.3 \ + CURLOPT_POSTFIELDSIZE.3 \ + CURLOPT_POSTFIELDSIZE_LARGE.3 \ + CURLOPT_POSTQUOTE.3 \ + CURLOPT_POSTREDIR.3 \ + CURLOPT_PRE_PROXY.3 \ + CURLOPT_PREQUOTE.3 \ + CURLOPT_PREREQDATA.3 \ + CURLOPT_PREREQFUNCTION.3 \ + CURLOPT_PRIVATE.3 \ + CURLOPT_PROGRESSDATA.3 \ + CURLOPT_PROGRESSFUNCTION.3 \ + CURLOPT_PROTOCOLS.3 \ + CURLOPT_PROTOCOLS_STR.3 \ + CURLOPT_PROXY.3 \ + CURLOPT_PROXY_CAINFO.3 \ + CURLOPT_PROXY_CAINFO_BLOB.3 \ + CURLOPT_PROXY_CAPATH.3 \ + CURLOPT_PROXY_CRLFILE.3 \ + CURLOPT_PROXY_ISSUERCERT.3 \ + CURLOPT_PROXY_ISSUERCERT_BLOB.3 \ + CURLOPT_PROXY_KEYPASSWD.3 \ + CURLOPT_PROXY_PINNEDPUBLICKEY.3 \ + CURLOPT_PROXY_SERVICE_NAME.3 \ + CURLOPT_PROXY_SSL_CIPHER_LIST.3 \ + CURLOPT_PROXY_SSL_OPTIONS.3 \ + CURLOPT_PROXY_SSL_VERIFYHOST.3 \ + CURLOPT_PROXY_SSL_VERIFYPEER.3 \ + CURLOPT_PROXY_SSLCERT.3 \ + CURLOPT_PROXY_SSLCERT_BLOB.3 \ + CURLOPT_PROXY_SSLCERTTYPE.3 \ + CURLOPT_PROXY_SSLKEY.3 \ + CURLOPT_PROXY_SSLKEY_BLOB.3 \ + CURLOPT_PROXY_SSLKEYTYPE.3 \ + CURLOPT_PROXY_SSLVERSION.3 \ + CURLOPT_PROXY_TLS13_CIPHERS.3 \ + CURLOPT_PROXY_TLSAUTH_PASSWORD.3 \ + CURLOPT_PROXY_TLSAUTH_TYPE.3 \ + CURLOPT_PROXY_TLSAUTH_USERNAME.3 \ + CURLOPT_PROXY_TRANSFER_MODE.3 \ + CURLOPT_PROXYAUTH.3 \ + CURLOPT_PROXYHEADER.3 \ + CURLOPT_PROXYPASSWORD.3 \ + CURLOPT_PROXYPORT.3 \ + CURLOPT_PROXYTYPE.3 \ + CURLOPT_PROXYUSERNAME.3 \ + CURLOPT_PROXYUSERPWD.3 \ + CURLOPT_PUT.3 \ + CURLOPT_QUICK_EXIT.3 \ + CURLOPT_QUOTE.3 \ + CURLOPT_RANDOM_FILE.3 \ + CURLOPT_RANGE.3 \ + CURLOPT_READDATA.3 \ + CURLOPT_READFUNCTION.3 \ + CURLOPT_REDIR_PROTOCOLS.3 \ + CURLOPT_REDIR_PROTOCOLS_STR.3 \ + CURLOPT_REFERER.3 \ + CURLOPT_REQUEST_TARGET.3 \ + CURLOPT_RESOLVE.3 \ + CURLOPT_RESOLVER_START_DATA.3 \ + CURLOPT_RESOLVER_START_FUNCTION.3 \ + CURLOPT_RESUME_FROM.3 \ + CURLOPT_RESUME_FROM_LARGE.3 \ + CURLOPT_RTSP_CLIENT_CSEQ.3 \ + CURLOPT_RTSP_REQUEST.3 \ + CURLOPT_RTSP_SERVER_CSEQ.3 \ + CURLOPT_RTSP_SESSION_ID.3 \ + CURLOPT_RTSP_STREAM_URI.3 \ + CURLOPT_RTSP_TRANSPORT.3 \ + CURLOPT_SASL_AUTHZID.3 \ + CURLOPT_SASL_IR.3 \ + CURLOPT_SEEKDATA.3 \ + CURLOPT_SEEKFUNCTION.3 \ + CURLOPT_SERVER_RESPONSE_TIMEOUT.3 \ + CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.3 \ + CURLOPT_SERVICE_NAME.3 \ + CURLOPT_SHARE.3 \ + CURLOPT_SOCKOPTDATA.3 \ + CURLOPT_SOCKOPTFUNCTION.3 \ + CURLOPT_SOCKS5_AUTH.3 \ + CURLOPT_SOCKS5_GSSAPI_NEC.3 \ + CURLOPT_SOCKS5_GSSAPI_SERVICE.3 \ + CURLOPT_SSH_AUTH_TYPES.3 \ + CURLOPT_SSH_COMPRESSION.3 \ + CURLOPT_SSH_HOSTKEYDATA.3 \ + CURLOPT_SSH_HOSTKEYFUNCTION.3 \ + CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 \ + CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.3 \ + CURLOPT_SSH_KEYDATA.3 \ + CURLOPT_SSH_KEYFUNCTION.3 \ + CURLOPT_SSH_KNOWNHOSTS.3 \ + CURLOPT_SSH_PRIVATE_KEYFILE.3 \ + CURLOPT_SSH_PUBLIC_KEYFILE.3 \ + CURLOPT_SSL_CIPHER_LIST.3 \ + CURLOPT_SSL_CTX_DATA.3 \ + CURLOPT_SSL_CTX_FUNCTION.3 \ + CURLOPT_SSL_EC_CURVES.3 \ + CURLOPT_SSL_ENABLE_ALPN.3 \ + CURLOPT_SSL_ENABLE_NPN.3 \ + CURLOPT_SSL_FALSESTART.3 \ + CURLOPT_SSL_OPTIONS.3 \ + CURLOPT_SSL_SESSIONID_CACHE.3 \ + CURLOPT_SSL_VERIFYHOST.3 \ + CURLOPT_SSL_VERIFYPEER.3 \ + CURLOPT_SSL_VERIFYSTATUS.3 \ + CURLOPT_SSLCERT.3 \ + CURLOPT_SSLCERT_BLOB.3 \ + CURLOPT_SSLCERTTYPE.3 \ + CURLOPT_SSLENGINE.3 \ + CURLOPT_SSLENGINE_DEFAULT.3 \ + CURLOPT_SSLKEY.3 \ + CURLOPT_SSLKEY_BLOB.3 \ + CURLOPT_SSLKEYTYPE.3 \ + CURLOPT_SSLVERSION.3 \ + CURLOPT_STDERR.3 \ + CURLOPT_STREAM_DEPENDS.3 \ + CURLOPT_STREAM_DEPENDS_E.3 \ + CURLOPT_STREAM_WEIGHT.3 \ + CURLOPT_SUPPRESS_CONNECT_HEADERS.3 \ + CURLOPT_TCP_FASTOPEN.3 \ + CURLOPT_TCP_KEEPALIVE.3 \ + CURLOPT_TCP_KEEPIDLE.3 \ + CURLOPT_TCP_KEEPINTVL.3 \ + CURLOPT_TCP_NODELAY.3 \ + CURLOPT_TELNETOPTIONS.3 \ + CURLOPT_TFTP_BLKSIZE.3 \ + CURLOPT_TFTP_NO_OPTIONS.3 \ + CURLOPT_TIMECONDITION.3 \ + CURLOPT_TIMEOUT.3 \ + CURLOPT_TIMEOUT_MS.3 \ + CURLOPT_TIMEVALUE.3 \ + CURLOPT_TIMEVALUE_LARGE.3 \ + CURLOPT_TLS13_CIPHERS.3 \ + CURLOPT_TLSAUTH_PASSWORD.3 \ + CURLOPT_TLSAUTH_TYPE.3 \ + CURLOPT_TLSAUTH_USERNAME.3 \ + CURLOPT_TRAILERDATA.3 \ + CURLOPT_TRAILERFUNCTION.3 \ + CURLOPT_TRANSFER_ENCODING.3 \ + CURLOPT_TRANSFERTEXT.3 \ + CURLOPT_UNIX_SOCKET_PATH.3 \ + CURLOPT_UNRESTRICTED_AUTH.3 \ + CURLOPT_UPKEEP_INTERVAL_MS.3 \ + CURLOPT_UPLOAD.3 \ + CURLOPT_UPLOAD_BUFFERSIZE.3 \ + CURLOPT_URL.3 \ + CURLOPT_USE_SSL.3 \ + CURLOPT_USERAGENT.3 \ + CURLOPT_USERNAME.3 \ + CURLOPT_USERPWD.3 \ + CURLOPT_VERBOSE.3 \ + CURLOPT_WILDCARDMATCH.3 \ + CURLOPT_WRITEDATA.3 \ + CURLOPT_WRITEFUNCTION.3 \ + CURLOPT_WS_OPTIONS.3 \ + CURLOPT_XFERINFODATA.3 \ + CURLOPT_XFERINFOFUNCTION.3 \ + CURLOPT_XOAUTH2_BEARER.3 \ + CURLSHOPT_LOCKFUNC.3 \ + CURLSHOPT_SHARE.3 \ + CURLSHOPT_UNLOCKFUNC.3 \ + CURLSHOPT_UNSHARE.3 \ + CURLSHOPT_USERDATA.3 + +CURLPAGES = $(man_MANS:.3=.md) +CLEANFILES = $(man_MANS) +nodist_MANS = $(man_MANS) +EXTRA_DIST = $(CURLPAGES) CMakeLists.txt +CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ +CD2 = $(CD2_$(V)) +CD2_0 = @echo " RENDER " $@; +CD2_1 = +CD2_ = $(CD2_0) +SUFFIXES = .3 .md +all: all-am + +.SUFFIXES: +.SUFFIXES: .3 .md +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.inc $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/libcurl/opts/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign docs/libcurl/opts/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/Makefile.inc $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man3: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man3dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.3[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ + done; } + +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man3dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.3[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(MANS) +installdirs: + for dir in "$(DESTDIR)$(man3dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man3 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-man + +uninstall-man: uninstall-man3 + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-man3 install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags-am uninstall uninstall-am uninstall-man \ + uninstall-man3 + +.PRECIOUS: Makefile + + +.md.3: + $(CD2)$(CD2NROFF) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc new file mode 100644 index 0000000..be7035b --- /dev/null +++ b/docs/libcurl/opts/Makefile.inc @@ -0,0 +1,424 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# Shared between Makefile.am and CMakeLists.txt + +man_MANS = \ + CURLINFO_ACTIVESOCKET.3 \ + CURLINFO_APPCONNECT_TIME.3 \ + CURLINFO_APPCONNECT_TIME_T.3 \ + CURLINFO_CAINFO.3 \ + CURLINFO_CAPATH.3 \ + CURLINFO_CERTINFO.3 \ + CURLINFO_CONDITION_UNMET.3 \ + CURLINFO_CONNECT_TIME.3 \ + CURLINFO_CONNECT_TIME_T.3 \ + CURLINFO_CONN_ID.3 \ + CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 \ + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.3 \ + CURLINFO_CONTENT_LENGTH_UPLOAD.3 \ + CURLINFO_CONTENT_LENGTH_UPLOAD_T.3 \ + CURLINFO_CONTENT_TYPE.3 \ + CURLINFO_COOKIELIST.3 \ + CURLINFO_EFFECTIVE_METHOD.3 \ + CURLINFO_EFFECTIVE_URL.3 \ + CURLINFO_FILETIME.3 \ + CURLINFO_FILETIME_T.3 \ + CURLINFO_FTP_ENTRY_PATH.3 \ + CURLINFO_HEADER_SIZE.3 \ + CURLINFO_HTTP_CONNECTCODE.3 \ + CURLINFO_HTTP_VERSION.3 \ + CURLINFO_HTTPAUTH_AVAIL.3 \ + CURLINFO_LASTSOCKET.3 \ + CURLINFO_LOCAL_IP.3 \ + CURLINFO_LOCAL_PORT.3 \ + CURLINFO_NAMELOOKUP_TIME.3 \ + CURLINFO_NAMELOOKUP_TIME_T.3 \ + CURLINFO_NUM_CONNECTS.3 \ + CURLINFO_OS_ERRNO.3 \ + CURLINFO_PRETRANSFER_TIME.3 \ + CURLINFO_PRETRANSFER_TIME_T.3 \ + CURLINFO_PRIMARY_IP.3 \ + CURLINFO_PRIMARY_PORT.3 \ + CURLINFO_PRIVATE.3 \ + CURLINFO_PROTOCOL.3 \ + CURLINFO_PROXY_ERROR.3 \ + CURLINFO_PROXY_SSL_VERIFYRESULT.3 \ + CURLINFO_PROXYAUTH_AVAIL.3 \ + CURLINFO_QUEUE_TIME_T.3 \ + CURLINFO_REDIRECT_COUNT.3 \ + CURLINFO_REDIRECT_TIME.3 \ + CURLINFO_REDIRECT_TIME_T.3 \ + CURLINFO_REDIRECT_URL.3 \ + CURLINFO_REFERER.3 \ + CURLINFO_REQUEST_SIZE.3 \ + CURLINFO_RESPONSE_CODE.3 \ + CURLINFO_RETRY_AFTER.3 \ + CURLINFO_RTSP_CLIENT_CSEQ.3 \ + CURLINFO_RTSP_CSEQ_RECV.3 \ + CURLINFO_RTSP_SERVER_CSEQ.3 \ + CURLINFO_RTSP_SESSION_ID.3 \ + CURLINFO_SCHEME.3 \ + CURLINFO_SIZE_DOWNLOAD.3 \ + CURLINFO_SIZE_DOWNLOAD_T.3 \ + CURLINFO_SIZE_UPLOAD.3 \ + CURLINFO_SIZE_UPLOAD_T.3 \ + CURLINFO_SPEED_DOWNLOAD.3 \ + CURLINFO_SPEED_DOWNLOAD_T.3 \ + CURLINFO_SPEED_UPLOAD.3 \ + CURLINFO_SPEED_UPLOAD_T.3 \ + CURLINFO_SSL_ENGINES.3 \ + CURLINFO_SSL_VERIFYRESULT.3 \ + CURLINFO_STARTTRANSFER_TIME.3 \ + CURLINFO_STARTTRANSFER_TIME_T.3 \ + CURLINFO_TLS_SESSION.3 \ + CURLINFO_TLS_SSL_PTR.3 \ + CURLINFO_TOTAL_TIME.3 \ + CURLINFO_TOTAL_TIME_T.3 \ + CURLINFO_XFER_ID.3 \ + CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 \ + CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 \ + CURLMOPT_MAX_CONCURRENT_STREAMS.3 \ + CURLMOPT_MAX_HOST_CONNECTIONS.3 \ + CURLMOPT_MAX_PIPELINE_LENGTH.3 \ + CURLMOPT_MAX_TOTAL_CONNECTIONS.3 \ + CURLMOPT_MAXCONNECTS.3 \ + CURLMOPT_PIPELINING.3 \ + CURLMOPT_PIPELINING_SERVER_BL.3 \ + CURLMOPT_PIPELINING_SITE_BL.3 \ + CURLMOPT_PUSHDATA.3 \ + CURLMOPT_PUSHFUNCTION.3 \ + CURLMOPT_SOCKETDATA.3 \ + CURLMOPT_SOCKETFUNCTION.3 \ + CURLMOPT_TIMERDATA.3 \ + CURLMOPT_TIMERFUNCTION.3 \ + CURLOPT_ABSTRACT_UNIX_SOCKET.3 \ + CURLOPT_ACCEPT_ENCODING.3 \ + CURLOPT_ACCEPTTIMEOUT_MS.3 \ + CURLOPT_ADDRESS_SCOPE.3 \ + CURLOPT_ALTSVC.3 \ + CURLOPT_ALTSVC_CTRL.3 \ + CURLOPT_APPEND.3 \ + CURLOPT_AUTOREFERER.3 \ + CURLOPT_AWS_SIGV4.3 \ + CURLOPT_BUFFERSIZE.3 \ + CURLOPT_CAINFO.3 \ + CURLOPT_CAINFO_BLOB.3 \ + CURLOPT_CAPATH.3 \ + CURLOPT_CA_CACHE_TIMEOUT.3 \ + CURLOPT_CERTINFO.3 \ + CURLOPT_CHUNK_BGN_FUNCTION.3 \ + CURLOPT_CHUNK_DATA.3 \ + CURLOPT_CHUNK_END_FUNCTION.3 \ + CURLOPT_CLOSESOCKETDATA.3 \ + CURLOPT_CLOSESOCKETFUNCTION.3 \ + CURLOPT_CONNECT_ONLY.3 \ + CURLOPT_CONNECT_TO.3 \ + CURLOPT_CONNECTTIMEOUT.3 \ + CURLOPT_CONNECTTIMEOUT_MS.3 \ + CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 \ + CURLOPT_CONV_FROM_UTF8_FUNCTION.3 \ + CURLOPT_CONV_TO_NETWORK_FUNCTION.3 \ + CURLOPT_COOKIE.3 \ + CURLOPT_COOKIEFILE.3 \ + CURLOPT_COOKIEJAR.3 \ + CURLOPT_COOKIELIST.3 \ + CURLOPT_COOKIESESSION.3 \ + CURLOPT_COPYPOSTFIELDS.3 \ + CURLOPT_CRLF.3 \ + CURLOPT_CRLFILE.3 \ + CURLOPT_CURLU.3 \ + CURLOPT_CUSTOMREQUEST.3 \ + CURLOPT_DEBUGDATA.3 \ + CURLOPT_DEBUGFUNCTION.3 \ + CURLOPT_DEFAULT_PROTOCOL.3 \ + CURLOPT_DIRLISTONLY.3 \ + CURLOPT_DISALLOW_USERNAME_IN_URL.3 \ + CURLOPT_DNS_CACHE_TIMEOUT.3 \ + CURLOPT_DNS_INTERFACE.3 \ + CURLOPT_DNS_LOCAL_IP4.3 \ + CURLOPT_DNS_LOCAL_IP6.3 \ + CURLOPT_DNS_SERVERS.3 \ + CURLOPT_DNS_SHUFFLE_ADDRESSES.3 \ + CURLOPT_DNS_USE_GLOBAL_CACHE.3 \ + CURLOPT_DOH_SSL_VERIFYHOST.3 \ + CURLOPT_DOH_SSL_VERIFYPEER.3 \ + CURLOPT_DOH_SSL_VERIFYSTATUS.3 \ + CURLOPT_DOH_URL.3 \ + CURLOPT_EGDSOCKET.3 \ + CURLOPT_ERRORBUFFER.3 \ + CURLOPT_EXPECT_100_TIMEOUT_MS.3 \ + CURLOPT_FAILONERROR.3 \ + CURLOPT_FILETIME.3 \ + CURLOPT_FNMATCH_DATA.3 \ + CURLOPT_FNMATCH_FUNCTION.3 \ + CURLOPT_FOLLOWLOCATION.3 \ + CURLOPT_FORBID_REUSE.3 \ + CURLOPT_FRESH_CONNECT.3 \ + CURLOPT_FTP_ACCOUNT.3 \ + CURLOPT_FTP_ALTERNATIVE_TO_USER.3 \ + CURLOPT_FTP_CREATE_MISSING_DIRS.3 \ + CURLOPT_FTP_FILEMETHOD.3 \ + CURLOPT_FTP_SKIP_PASV_IP.3 \ + CURLOPT_FTP_SSL_CCC.3 \ + CURLOPT_FTP_USE_EPRT.3 \ + CURLOPT_FTP_USE_EPSV.3 \ + CURLOPT_FTP_USE_PRET.3 \ + CURLOPT_FTPPORT.3 \ + CURLOPT_FTPSSLAUTH.3 \ + CURLOPT_GSSAPI_DELEGATION.3 \ + CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 \ + CURLOPT_HAPROXYPROTOCOL.3 \ + CURLOPT_HAPROXY_CLIENT_IP.3 \ + CURLOPT_HEADER.3 \ + CURLOPT_HEADERDATA.3 \ + CURLOPT_HEADERFUNCTION.3 \ + CURLOPT_HEADEROPT.3 \ + CURLOPT_HSTS.3 \ + CURLOPT_HSTS_CTRL.3 \ + CURLOPT_HSTSREADDATA.3 \ + CURLOPT_HSTSREADFUNCTION.3 \ + CURLOPT_HSTSWRITEDATA.3 \ + CURLOPT_HSTSWRITEFUNCTION.3 \ + CURLOPT_HTTP09_ALLOWED.3 \ + CURLOPT_HTTP200ALIASES.3 \ + CURLOPT_HTTP_CONTENT_DECODING.3 \ + CURLOPT_HTTP_TRANSFER_DECODING.3 \ + CURLOPT_HTTP_VERSION.3 \ + CURLOPT_HTTPAUTH.3 \ + CURLOPT_HTTPGET.3 \ + CURLOPT_HTTPHEADER.3 \ + CURLOPT_HTTPPOST.3 \ + CURLOPT_HTTPPROXYTUNNEL.3 \ + CURLOPT_IGNORE_CONTENT_LENGTH.3 \ + CURLOPT_INFILESIZE.3 \ + CURLOPT_INFILESIZE_LARGE.3 \ + CURLOPT_INTERFACE.3 \ + CURLOPT_INTERLEAVEDATA.3 \ + CURLOPT_INTERLEAVEFUNCTION.3 \ + CURLOPT_IOCTLDATA.3 \ + CURLOPT_IOCTLFUNCTION.3 \ + CURLOPT_IPRESOLVE.3 \ + CURLOPT_ISSUERCERT.3 \ + CURLOPT_ISSUERCERT_BLOB.3 \ + CURLOPT_KEEP_SENDING_ON_ERROR.3 \ + CURLOPT_KEYPASSWD.3 \ + CURLOPT_KRBLEVEL.3 \ + CURLOPT_LOCALPORT.3 \ + CURLOPT_LOCALPORTRANGE.3 \ + CURLOPT_LOGIN_OPTIONS.3 \ + CURLOPT_LOW_SPEED_LIMIT.3 \ + CURLOPT_LOW_SPEED_TIME.3 \ + CURLOPT_MAIL_AUTH.3 \ + CURLOPT_MAIL_FROM.3 \ + CURLOPT_MAIL_RCPT.3 \ + CURLOPT_MAIL_RCPT_ALLOWFAILS.3 \ + CURLOPT_MAX_RECV_SPEED_LARGE.3 \ + CURLOPT_MAX_SEND_SPEED_LARGE.3 \ + CURLOPT_MAXAGE_CONN.3 \ + CURLOPT_MAXCONNECTS.3 \ + CURLOPT_MAXFILESIZE.3 \ + CURLOPT_MAXFILESIZE_LARGE.3 \ + CURLOPT_MAXLIFETIME_CONN.3 \ + CURLOPT_MAXREDIRS.3 \ + CURLOPT_MIME_OPTIONS.3 \ + CURLOPT_MIMEPOST.3 \ + CURLOPT_NETRC.3 \ + CURLOPT_NETRC_FILE.3 \ + CURLOPT_NEW_DIRECTORY_PERMS.3 \ + CURLOPT_NEW_FILE_PERMS.3 \ + CURLOPT_NOBODY.3 \ + CURLOPT_NOPROGRESS.3 \ + CURLOPT_NOPROXY.3 \ + CURLOPT_NOSIGNAL.3 \ + CURLOPT_OPENSOCKETDATA.3 \ + CURLOPT_OPENSOCKETFUNCTION.3 \ + CURLOPT_PASSWORD.3 \ + CURLOPT_PATH_AS_IS.3 \ + CURLOPT_PINNEDPUBLICKEY.3 \ + CURLOPT_PIPEWAIT.3 \ + CURLOPT_PORT.3 \ + CURLOPT_POST.3 \ + CURLOPT_POSTFIELDS.3 \ + CURLOPT_POSTFIELDSIZE.3 \ + CURLOPT_POSTFIELDSIZE_LARGE.3 \ + CURLOPT_POSTQUOTE.3 \ + CURLOPT_POSTREDIR.3 \ + CURLOPT_PRE_PROXY.3 \ + CURLOPT_PREQUOTE.3 \ + CURLOPT_PREREQDATA.3 \ + CURLOPT_PREREQFUNCTION.3 \ + CURLOPT_PRIVATE.3 \ + CURLOPT_PROGRESSDATA.3 \ + CURLOPT_PROGRESSFUNCTION.3 \ + CURLOPT_PROTOCOLS.3 \ + CURLOPT_PROTOCOLS_STR.3 \ + CURLOPT_PROXY.3 \ + CURLOPT_PROXY_CAINFO.3 \ + CURLOPT_PROXY_CAINFO_BLOB.3 \ + CURLOPT_PROXY_CAPATH.3 \ + CURLOPT_PROXY_CRLFILE.3 \ + CURLOPT_PROXY_ISSUERCERT.3 \ + CURLOPT_PROXY_ISSUERCERT_BLOB.3 \ + CURLOPT_PROXY_KEYPASSWD.3 \ + CURLOPT_PROXY_PINNEDPUBLICKEY.3 \ + CURLOPT_PROXY_SERVICE_NAME.3 \ + CURLOPT_PROXY_SSL_CIPHER_LIST.3 \ + CURLOPT_PROXY_SSL_OPTIONS.3 \ + CURLOPT_PROXY_SSL_VERIFYHOST.3 \ + CURLOPT_PROXY_SSL_VERIFYPEER.3 \ + CURLOPT_PROXY_SSLCERT.3 \ + CURLOPT_PROXY_SSLCERT_BLOB.3 \ + CURLOPT_PROXY_SSLCERTTYPE.3 \ + CURLOPT_PROXY_SSLKEY.3 \ + CURLOPT_PROXY_SSLKEY_BLOB.3 \ + CURLOPT_PROXY_SSLKEYTYPE.3 \ + CURLOPT_PROXY_SSLVERSION.3 \ + CURLOPT_PROXY_TLS13_CIPHERS.3 \ + CURLOPT_PROXY_TLSAUTH_PASSWORD.3 \ + CURLOPT_PROXY_TLSAUTH_TYPE.3 \ + CURLOPT_PROXY_TLSAUTH_USERNAME.3 \ + CURLOPT_PROXY_TRANSFER_MODE.3 \ + CURLOPT_PROXYAUTH.3 \ + CURLOPT_PROXYHEADER.3 \ + CURLOPT_PROXYPASSWORD.3 \ + CURLOPT_PROXYPORT.3 \ + CURLOPT_PROXYTYPE.3 \ + CURLOPT_PROXYUSERNAME.3 \ + CURLOPT_PROXYUSERPWD.3 \ + CURLOPT_PUT.3 \ + CURLOPT_QUICK_EXIT.3 \ + CURLOPT_QUOTE.3 \ + CURLOPT_RANDOM_FILE.3 \ + CURLOPT_RANGE.3 \ + CURLOPT_READDATA.3 \ + CURLOPT_READFUNCTION.3 \ + CURLOPT_REDIR_PROTOCOLS.3 \ + CURLOPT_REDIR_PROTOCOLS_STR.3 \ + CURLOPT_REFERER.3 \ + CURLOPT_REQUEST_TARGET.3 \ + CURLOPT_RESOLVE.3 \ + CURLOPT_RESOLVER_START_DATA.3 \ + CURLOPT_RESOLVER_START_FUNCTION.3 \ + CURLOPT_RESUME_FROM.3 \ + CURLOPT_RESUME_FROM_LARGE.3 \ + CURLOPT_RTSP_CLIENT_CSEQ.3 \ + CURLOPT_RTSP_REQUEST.3 \ + CURLOPT_RTSP_SERVER_CSEQ.3 \ + CURLOPT_RTSP_SESSION_ID.3 \ + CURLOPT_RTSP_STREAM_URI.3 \ + CURLOPT_RTSP_TRANSPORT.3 \ + CURLOPT_SASL_AUTHZID.3 \ + CURLOPT_SASL_IR.3 \ + CURLOPT_SEEKDATA.3 \ + CURLOPT_SEEKFUNCTION.3 \ + CURLOPT_SERVER_RESPONSE_TIMEOUT.3 \ + CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.3 \ + CURLOPT_SERVICE_NAME.3 \ + CURLOPT_SHARE.3 \ + CURLOPT_SOCKOPTDATA.3 \ + CURLOPT_SOCKOPTFUNCTION.3 \ + CURLOPT_SOCKS5_AUTH.3 \ + CURLOPT_SOCKS5_GSSAPI_NEC.3 \ + CURLOPT_SOCKS5_GSSAPI_SERVICE.3 \ + CURLOPT_SSH_AUTH_TYPES.3 \ + CURLOPT_SSH_COMPRESSION.3 \ + CURLOPT_SSH_HOSTKEYDATA.3 \ + CURLOPT_SSH_HOSTKEYFUNCTION.3 \ + CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 \ + CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.3 \ + CURLOPT_SSH_KEYDATA.3 \ + CURLOPT_SSH_KEYFUNCTION.3 \ + CURLOPT_SSH_KNOWNHOSTS.3 \ + CURLOPT_SSH_PRIVATE_KEYFILE.3 \ + CURLOPT_SSH_PUBLIC_KEYFILE.3 \ + CURLOPT_SSL_CIPHER_LIST.3 \ + CURLOPT_SSL_CTX_DATA.3 \ + CURLOPT_SSL_CTX_FUNCTION.3 \ + CURLOPT_SSL_EC_CURVES.3 \ + CURLOPT_SSL_ENABLE_ALPN.3 \ + CURLOPT_SSL_ENABLE_NPN.3 \ + CURLOPT_SSL_FALSESTART.3 \ + CURLOPT_SSL_OPTIONS.3 \ + CURLOPT_SSL_SESSIONID_CACHE.3 \ + CURLOPT_SSL_VERIFYHOST.3 \ + CURLOPT_SSL_VERIFYPEER.3 \ + CURLOPT_SSL_VERIFYSTATUS.3 \ + CURLOPT_SSLCERT.3 \ + CURLOPT_SSLCERT_BLOB.3 \ + CURLOPT_SSLCERTTYPE.3 \ + CURLOPT_SSLENGINE.3 \ + CURLOPT_SSLENGINE_DEFAULT.3 \ + CURLOPT_SSLKEY.3 \ + CURLOPT_SSLKEY_BLOB.3 \ + CURLOPT_SSLKEYTYPE.3 \ + CURLOPT_SSLVERSION.3 \ + CURLOPT_STDERR.3 \ + CURLOPT_STREAM_DEPENDS.3 \ + CURLOPT_STREAM_DEPENDS_E.3 \ + CURLOPT_STREAM_WEIGHT.3 \ + CURLOPT_SUPPRESS_CONNECT_HEADERS.3 \ + CURLOPT_TCP_FASTOPEN.3 \ + CURLOPT_TCP_KEEPALIVE.3 \ + CURLOPT_TCP_KEEPIDLE.3 \ + CURLOPT_TCP_KEEPINTVL.3 \ + CURLOPT_TCP_NODELAY.3 \ + CURLOPT_TELNETOPTIONS.3 \ + CURLOPT_TFTP_BLKSIZE.3 \ + CURLOPT_TFTP_NO_OPTIONS.3 \ + CURLOPT_TIMECONDITION.3 \ + CURLOPT_TIMEOUT.3 \ + CURLOPT_TIMEOUT_MS.3 \ + CURLOPT_TIMEVALUE.3 \ + CURLOPT_TIMEVALUE_LARGE.3 \ + CURLOPT_TLS13_CIPHERS.3 \ + CURLOPT_TLSAUTH_PASSWORD.3 \ + CURLOPT_TLSAUTH_TYPE.3 \ + CURLOPT_TLSAUTH_USERNAME.3 \ + CURLOPT_TRAILERDATA.3 \ + CURLOPT_TRAILERFUNCTION.3 \ + CURLOPT_TRANSFER_ENCODING.3 \ + CURLOPT_TRANSFERTEXT.3 \ + CURLOPT_UNIX_SOCKET_PATH.3 \ + CURLOPT_UNRESTRICTED_AUTH.3 \ + CURLOPT_UPKEEP_INTERVAL_MS.3 \ + CURLOPT_UPLOAD.3 \ + CURLOPT_UPLOAD_BUFFERSIZE.3 \ + CURLOPT_URL.3 \ + CURLOPT_USE_SSL.3 \ + CURLOPT_USERAGENT.3 \ + CURLOPT_USERNAME.3 \ + CURLOPT_USERPWD.3 \ + CURLOPT_VERBOSE.3 \ + CURLOPT_WILDCARDMATCH.3 \ + CURLOPT_WRITEDATA.3 \ + CURLOPT_WRITEFUNCTION.3 \ + CURLOPT_WS_OPTIONS.3 \ + CURLOPT_XFERINFODATA.3 \ + CURLOPT_XFERINFOFUNCTION.3 \ + CURLOPT_XOAUTH2_BEARER.3 \ + CURLSHOPT_LOCKFUNC.3 \ + CURLSHOPT_SHARE.3 \ + CURLSHOPT_UNLOCKFUNC.3 \ + CURLSHOPT_UNSHARE.3 \ + CURLSHOPT_USERDATA.3 diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions new file mode 100644 index 0000000..c20008a --- /dev/null +++ b/docs/libcurl/symbols-in-versions @@ -0,0 +1,1147 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + + This document lists defines and other symbols present in libcurl, together + with exact information about the first libcurl version that provides the + symbol, the first version in which the symbol was marked as deprecated and + for a few symbols the last version that featured it. The names appear in + alphabetical order. + + Name Introduced Deprecated Last + +CURL_AT_LEAST_VERSION 7.43.0 +CURL_BLOB_COPY 7.71.0 +CURL_BLOB_NOCOPY 7.71.0 +CURL_CHUNK_BGN_FUNC_FAIL 7.21.0 +CURL_CHUNK_BGN_FUNC_OK 7.21.0 +CURL_CHUNK_BGN_FUNC_SKIP 7.21.0 +CURL_CHUNK_END_FUNC_FAIL 7.21.0 +CURL_CHUNK_END_FUNC_OK 7.21.0 +CURL_CSELECT_ERR 7.16.3 +CURL_CSELECT_IN 7.16.3 +CURL_CSELECT_OUT 7.16.3 +CURL_DEPRECATED 7.87.0 +CURL_DID_MEMORY_FUNC_TYPEDEFS 7.49.0 +CURL_EASY_NONE 7.14.0 - 7.15.4 +CURL_EASY_TIMEOUT 7.14.0 - 7.15.4 +CURL_ERROR_SIZE 7.1 +CURL_FNMATCHFUNC_FAIL 7.21.0 +CURL_FNMATCHFUNC_MATCH 7.21.0 +CURL_FNMATCHFUNC_NOMATCH 7.21.0 +CURL_FORMADD_DISABLED 7.12.1 7.56.0 +CURL_FORMADD_ILLEGAL_ARRAY 7.9.8 7.56.0 +CURL_FORMADD_INCOMPLETE 7.9.8 7.56.0 +CURL_FORMADD_MEMORY 7.9.8 7.56.0 +CURL_FORMADD_NULL 7.9.8 7.56.0 +CURL_FORMADD_OK 7.9.8 7.56.0 +CURL_FORMADD_OPTION_TWICE 7.9.8 7.56.0 +CURL_FORMADD_UNKNOWN_OPTION 7.9.8 7.56.0 +CURL_GLOBAL_ACK_EINTR 7.30.0 +CURL_GLOBAL_ALL 7.8 +CURL_GLOBAL_DEFAULT 7.8 +CURL_GLOBAL_NOTHING 7.8 +CURL_GLOBAL_SSL 7.8 +CURL_GLOBAL_WIN32 7.8.1 +CURL_HET_DEFAULT 7.59.0 +CURL_HTTP_VERSION_1_0 7.9.1 +CURL_HTTP_VERSION_1_1 7.9.1 +CURL_HTTP_VERSION_2 7.43.0 +CURL_HTTP_VERSION_2_0 7.33.0 +CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE 7.49.0 +CURL_HTTP_VERSION_2TLS 7.47.0 +CURL_HTTP_VERSION_3 7.66.0 +CURL_HTTP_VERSION_3ONLY 7.88.0 +CURL_HTTP_VERSION_NONE 7.9.1 +CURL_HTTPPOST_BUFFER 7.46.0 +CURL_HTTPPOST_CALLBACK 7.46.0 +CURL_HTTPPOST_FILENAME 7.46.0 +CURL_HTTPPOST_LARGE 7.46.0 +CURL_HTTPPOST_PTRBUFFER 7.46.0 +CURL_HTTPPOST_PTRCONTENTS 7.46.0 +CURL_HTTPPOST_PTRNAME 7.46.0 +CURL_HTTPPOST_READFILE 7.46.0 +CURL_IGNORE_DEPRECATION 7.87.0 +CURL_IPRESOLVE_V4 7.10.8 +CURL_IPRESOLVE_V6 7.10.8 +CURL_IPRESOLVE_WHATEVER 7.10.8 +CURL_ISOCPP 7.10.2 +CURL_LOCK_ACCESS_NONE 7.10.3 +CURL_LOCK_ACCESS_SHARED 7.10.3 +CURL_LOCK_ACCESS_SINGLE 7.10.3 +CURL_LOCK_DATA_CONNECT 7.10.3 +CURL_LOCK_DATA_COOKIE 7.10.3 +CURL_LOCK_DATA_DNS 7.10.3 +CURL_LOCK_DATA_HSTS 7.88.0 +CURL_LOCK_DATA_NONE 7.10.3 +CURL_LOCK_DATA_PSL 7.61.0 +CURL_LOCK_DATA_SHARE 7.10.4 +CURL_LOCK_DATA_SSL_SESSION 7.10.3 +CURL_LOCK_TYPE_CONNECT 7.10 - 7.10.2 +CURL_LOCK_TYPE_COOKIE 7.10 - 7.10.2 +CURL_LOCK_TYPE_DNS 7.10 - 7.10.2 +CURL_LOCK_TYPE_NONE 7.10 - 7.10.2 +CURL_LOCK_TYPE_SSL_SESSION 7.10 - 7.10.2 +CURL_MAX_HTTP_HEADER 7.19.7 +CURL_MAX_READ_SIZE 7.53.0 +CURL_MAX_WRITE_SIZE 7.9.7 +CURL_NETRC_IGNORED 7.9.8 +CURL_NETRC_OPTIONAL 7.9.8 +CURL_NETRC_REQUIRED 7.9.8 +CURL_POLL_IN 7.14.0 +CURL_POLL_INOUT 7.14.0 +CURL_POLL_NONE 7.14.0 +CURL_POLL_OUT 7.14.0 +CURL_POLL_REMOVE 7.14.0 +CURL_PREREQFUNC_ABORT 7.79.0 +CURL_PREREQFUNC_OK 7.79.0 +CURL_PROGRESS_BAR 7.1.1 - 7.4.1 +CURL_PROGRESS_STATS 7.1.1 - 7.4.1 +CURL_PROGRESSFUNC_CONTINUE 7.68.0 +CURL_PULL_SYS_POLL_H 7.56.0 +CURL_PUSH_DENY 7.44.0 +CURL_PUSH_ERROROUT 7.72.0 +CURL_PUSH_OK 7.44.0 +CURL_READFUNC_ABORT 7.12.1 +CURL_READFUNC_PAUSE 7.18.0 +CURL_REDIR_GET_ALL 7.19.1 +CURL_REDIR_POST_301 7.19.1 +CURL_REDIR_POST_302 7.19.1 +CURL_REDIR_POST_303 7.25.1 +CURL_REDIR_POST_ALL 7.19.1 +CURL_RTSPREQ_ANNOUNCE 7.20.0 +CURL_RTSPREQ_DESCRIBE 7.20.0 +CURL_RTSPREQ_GET_PARAMETER 7.20.0 +CURL_RTSPREQ_NONE 7.20.0 +CURL_RTSPREQ_OPTIONS 7.20.0 +CURL_RTSPREQ_PAUSE 7.20.0 +CURL_RTSPREQ_PLAY 7.20.0 +CURL_RTSPREQ_RECEIVE 7.20.0 +CURL_RTSPREQ_RECORD 7.20.0 +CURL_RTSPREQ_SET_PARAMETER 7.20.0 +CURL_RTSPREQ_SETUP 7.20.0 +CURL_RTSPREQ_TEARDOWN 7.20.0 +CURL_SEEKFUNC_CANTSEEK 7.19.5 +CURL_SEEKFUNC_FAIL 7.19.5 +CURL_SEEKFUNC_OK 7.19.5 +CURL_SOCKET_BAD 7.14.0 +CURL_SOCKET_TIMEOUT 7.14.0 +CURL_SOCKOPT_ALREADY_CONNECTED 7.21.5 +CURL_SOCKOPT_ERROR 7.21.5 +CURL_SOCKOPT_OK 7.21.5 +CURL_SSLVERSION_DEFAULT 7.9.2 +CURL_SSLVERSION_MAX_DEFAULT 7.54.0 +CURL_SSLVERSION_MAX_NONE 7.54.0 +CURL_SSLVERSION_MAX_TLSv1_0 7.54.0 +CURL_SSLVERSION_MAX_TLSv1_1 7.54.0 +CURL_SSLVERSION_MAX_TLSv1_2 7.54.0 +CURL_SSLVERSION_MAX_TLSv1_3 7.54.0 +CURL_SSLVERSION_SSLv2 7.9.2 +CURL_SSLVERSION_SSLv3 7.9.2 +CURL_SSLVERSION_TLSv1 7.9.2 +CURL_SSLVERSION_TLSv1_0 7.34.0 +CURL_SSLVERSION_TLSv1_1 7.34.0 +CURL_SSLVERSION_TLSv1_2 7.34.0 +CURL_SSLVERSION_TLSv1_3 7.52.0 +CURL_STRICTER 7.50.2 +CURL_TIMECOND_IFMODSINCE 7.9.7 +CURL_TIMECOND_IFUNMODSINCE 7.9.7 +CURL_TIMECOND_LASTMOD 7.9.7 +CURL_TIMECOND_NONE 7.9.7 +CURL_TLSAUTH_NONE 7.21.4 +CURL_TLSAUTH_SRP 7.21.4 +CURL_TRAILERFUNC_ABORT 7.64.0 +CURL_TRAILERFUNC_OK 7.64.0 +CURL_UPKEEP_INTERVAL_DEFAULT 7.62.0 +CURL_VERSION_ALTSVC 7.64.1 +CURL_VERSION_ASYNCHDNS 7.10.7 +CURL_VERSION_BITS 7.43.0 +CURL_VERSION_BROTLI 7.57.0 +CURL_VERSION_CONV 7.15.4 +CURL_VERSION_CURLDEBUG 7.19.6 +CURL_VERSION_DEBUG 7.10.6 +CURL_VERSION_GSASL 7.76.0 +CURL_VERSION_GSSAPI 7.38.0 +CURL_VERSION_GSSNEGOTIATE 7.10.6 7.38.0 +CURL_VERSION_HSTS 7.74.0 +CURL_VERSION_HTTP2 7.33.0 +CURL_VERSION_HTTP3 7.66.0 +CURL_VERSION_HTTPS_PROXY 7.52.0 +CURL_VERSION_IDN 7.12.0 +CURL_VERSION_IPV6 7.10 +CURL_VERSION_KERBEROS4 7.10 7.33.0 +CURL_VERSION_KERBEROS5 7.40.0 +CURL_VERSION_LARGEFILE 7.11.1 +CURL_VERSION_LIBZ 7.10 +CURL_VERSION_MULTI_SSL 7.56.0 +CURL_VERSION_NTLM 7.10.6 +CURL_VERSION_NTLM_WB 7.22.0 +CURL_VERSION_PSL 7.47.0 +CURL_VERSION_SPNEGO 7.10.8 +CURL_VERSION_SSL 7.10 +CURL_VERSION_SSPI 7.13.2 +CURL_VERSION_THREADSAFE 7.84.0 +CURL_VERSION_TLSAUTH_SRP 7.21.4 +CURL_VERSION_UNICODE 7.72.0 +CURL_VERSION_UNIX_SOCKETS 7.40.0 +CURL_VERSION_ZSTD 7.72.0 +CURL_WAIT_POLLIN 7.28.0 +CURL_WAIT_POLLOUT 7.28.0 +CURL_WAIT_POLLPRI 7.28.0 +CURL_WIN32 7.69.0 - 8.5.0 +CURL_WRITEFUNC_ERROR 7.87.0 +CURL_WRITEFUNC_PAUSE 7.18.0 +CURL_ZERO_TERMINATED 7.56.0 +CURLALTSVC_H1 7.64.1 +CURLALTSVC_H2 7.64.1 +CURLALTSVC_H3 7.64.1 +CURLALTSVC_READONLYFILE 7.64.1 +CURLAUTH_ANY 7.10.6 +CURLAUTH_ANYSAFE 7.10.6 +CURLAUTH_AWS_SIGV4 7.75.0 +CURLAUTH_BASIC 7.10.6 +CURLAUTH_BEARER 7.61.0 +CURLAUTH_DIGEST 7.10.6 +CURLAUTH_DIGEST_IE 7.19.3 +CURLAUTH_GSSAPI 7.55.0 +CURLAUTH_GSSNEGOTIATE 7.10.6 7.38.0 +CURLAUTH_NEGOTIATE 7.38.0 +CURLAUTH_NONE 7.10.6 +CURLAUTH_NTLM 7.10.6 +CURLAUTH_NTLM_WB 7.22.0 +CURLAUTH_ONLY 7.21.3 +CURLCLOSEPOLICY_CALLBACK 7.7 7.16.1 +CURLCLOSEPOLICY_LEAST_RECENTLY_USED 7.7 7.16.1 +CURLCLOSEPOLICY_LEAST_TRAFFIC 7.7 7.16.1 +CURLCLOSEPOLICY_NONE 7.7 7.16.1 +CURLCLOSEPOLICY_OLDEST 7.7 7.16.1 +CURLCLOSEPOLICY_SLOWEST 7.7 7.16.1 +CURLE_ABORTED_BY_CALLBACK 7.1 +CURLE_AGAIN 7.18.2 +CURLE_ALREADY_COMPLETE 7.7.2 7.8 +CURLE_AUTH_ERROR 7.66.0 +CURLE_BAD_CALLING_ORDER 7.1 7.17.0 +CURLE_BAD_CONTENT_ENCODING 7.10 +CURLE_BAD_DOWNLOAD_RESUME 7.10 +CURLE_BAD_FUNCTION_ARGUMENT 7.1 +CURLE_BAD_PASSWORD_ENTERED 7.4.2 7.17.0 +CURLE_CHUNK_FAILED 7.21.0 +CURLE_CONV_FAILED 7.15.4 7.82.0 +CURLE_CONV_REQD 7.15.4 7.82.0 +CURLE_COULDNT_CONNECT 7.1 +CURLE_COULDNT_RESOLVE_HOST 7.1 +CURLE_COULDNT_RESOLVE_PROXY 7.1 +CURLE_FAILED_INIT 7.1 +CURLE_FILE_COULDNT_READ_FILE 7.1 +CURLE_FILESIZE_EXCEEDED 7.10.8 +CURLE_FTP_ACCEPT_FAILED 7.24.0 +CURLE_FTP_ACCEPT_TIMEOUT 7.24.0 +CURLE_FTP_ACCESS_DENIED 7.1 7.17.0 +CURLE_FTP_BAD_DOWNLOAD_RESUME 7.1 7.1 +CURLE_FTP_BAD_FILE_LIST 7.21.0 +CURLE_FTP_CANT_GET_HOST 7.1 +CURLE_FTP_CANT_RECONNECT 7.1 7.17.0 +CURLE_FTP_COULDNT_GET_SIZE 7.1 7.17.0 +CURLE_FTP_COULDNT_RETR_FILE 7.1 +CURLE_FTP_COULDNT_SET_ASCII 7.1 7.17.0 +CURLE_FTP_COULDNT_SET_BINARY 7.1 7.17.0 +CURLE_FTP_COULDNT_SET_TYPE 7.17.0 +CURLE_FTP_COULDNT_STOR_FILE 7.1 7.16.3 +CURLE_FTP_COULDNT_USE_REST 7.1 +CURLE_FTP_PARTIAL_FILE 7.1 7.1 +CURLE_FTP_PORT_FAILED 7.1 +CURLE_FTP_PRET_FAILED 7.20.0 +CURLE_FTP_QUOTE_ERROR 7.1 7.17.0 +CURLE_FTP_SSL_FAILED 7.11.0 7.17.0 +CURLE_FTP_USER_PASSWORD_INCORRECT 7.1 7.17.0 +CURLE_FTP_WEIRD_227_FORMAT 7.1 +CURLE_FTP_WEIRD_PASS_REPLY 7.1 +CURLE_FTP_WEIRD_PASV_REPLY 7.1 +CURLE_FTP_WEIRD_SERVER_REPLY 7.1 7.51.0 +CURLE_FTP_WEIRD_USER_REPLY 7.1 7.17.0 +CURLE_FTP_WRITE_ERROR 7.1 7.17.0 +CURLE_FUNCTION_NOT_FOUND 7.1 +CURLE_GOT_NOTHING 7.9.1 +CURLE_HTTP2 7.38.0 +CURLE_HTTP2_STREAM 7.49.0 +CURLE_HTTP3 7.68.0 +CURLE_HTTP_NOT_FOUND 7.1 7.10.3 +CURLE_HTTP_PORT_FAILED 7.3 7.12.0 +CURLE_HTTP_POST_ERROR 7.1 +CURLE_HTTP_RANGE_ERROR 7.1 7.17.0 +CURLE_HTTP_RETURNED_ERROR 7.10.3 +CURLE_INTERFACE_FAILED 7.12.0 +CURLE_LDAP_CANNOT_BIND 7.1 +CURLE_LDAP_INVALID_URL 7.10.8 7.82.0 +CURLE_LDAP_SEARCH_FAILED 7.1 +CURLE_LIBRARY_NOT_FOUND 7.1 7.17.0 +CURLE_LOGIN_DENIED 7.13.1 +CURLE_MALFORMAT_USER 7.1 7.17.0 +CURLE_NO_CONNECTION_AVAILABLE 7.30.0 +CURLE_NOT_BUILT_IN 7.21.5 +CURLE_OK 7.1 +CURLE_OPERATION_TIMEDOUT 7.10.2 +CURLE_OPERATION_TIMEOUTED 7.1 7.17.0 +CURLE_OUT_OF_MEMORY 7.1 +CURLE_PARTIAL_FILE 7.1 +CURLE_PEER_FAILED_VERIFICATION 7.17.1 +CURLE_PROXY 7.73.0 +CURLE_QUIC_CONNECT_ERROR 7.69.0 +CURLE_QUOTE_ERROR 7.17.0 +CURLE_RANGE_ERROR 7.17.0 +CURLE_READ_ERROR 7.1 +CURLE_RECURSIVE_API_CALL 7.59.0 +CURLE_RECV_ERROR 7.10 +CURLE_REMOTE_ACCESS_DENIED 7.17.0 +CURLE_REMOTE_DISK_FULL 7.17.0 +CURLE_REMOTE_FILE_EXISTS 7.17.0 +CURLE_REMOTE_FILE_NOT_FOUND 7.16.1 +CURLE_RTSP_CSEQ_ERROR 7.20.0 +CURLE_RTSP_SESSION_ERROR 7.20.0 +CURLE_SEND_ERROR 7.10 +CURLE_SEND_FAIL_REWIND 7.12.3 +CURLE_SETOPT_OPTION_SYNTAX 7.78.0 +CURLE_SHARE_IN_USE 7.9.6 7.17.0 +CURLE_SSH 7.16.1 +CURLE_SSL_CACERT 7.10 7.62.0 +CURLE_SSL_CACERT_BADFILE 7.16.0 +CURLE_SSL_CERTPROBLEM 7.10 +CURLE_SSL_CIPHER 7.10 +CURLE_SSL_CLIENTCERT 7.77.0 +CURLE_SSL_CONNECT_ERROR 7.1 +CURLE_SSL_CRL_BADFILE 7.19.0 +CURLE_SSL_ENGINE_INITFAILED 7.12.3 +CURLE_SSL_ENGINE_NOTFOUND 7.9.3 +CURLE_SSL_ENGINE_SETFAILED 7.9.3 +CURLE_SSL_INVALIDCERTSTATUS 7.41.0 +CURLE_SSL_ISSUER_ERROR 7.19.0 +CURLE_SSL_PEER_CERTIFICATE 7.8 7.17.1 +CURLE_SSL_PINNEDPUBKEYNOTMATCH 7.39.0 +CURLE_SSL_SHUTDOWN_FAILED 7.16.1 +CURLE_TELNET_OPTION_SYNTAX 7.7 +CURLE_TFTP_DISKFULL 7.15.0 7.17.0 +CURLE_TFTP_EXISTS 7.15.0 7.17.0 +CURLE_TFTP_ILLEGAL 7.15.0 +CURLE_TFTP_NOSUCHUSER 7.15.0 +CURLE_TFTP_NOTFOUND 7.15.0 +CURLE_TFTP_PERM 7.15.0 +CURLE_TFTP_UNKNOWNID 7.15.0 +CURLE_TOO_LARGE 8.6.0 +CURLE_TOO_MANY_REDIRECTS 7.5 +CURLE_UNKNOWN_OPTION 7.21.5 +CURLE_UNKNOWN_TELNET_OPTION 7.7 7.21.5 +CURLE_UNRECOVERABLE_POLL 7.84.0 +CURLE_UNSUPPORTED_PROTOCOL 7.1 +CURLE_UPLOAD_FAILED 7.16.3 +CURLE_URL_MALFORMAT 7.1 +CURLE_URL_MALFORMAT_USER 7.1 7.17.0 +CURLE_USE_SSL_FAILED 7.17.0 +CURLE_WEIRD_SERVER_REPLY 7.51.0 +CURLE_WRITE_ERROR 7.1 +CURLFILETYPE_DEVICE_BLOCK 7.21.0 +CURLFILETYPE_DEVICE_CHAR 7.21.0 +CURLFILETYPE_DIRECTORY 7.21.0 +CURLFILETYPE_DOOR 7.21.0 +CURLFILETYPE_FILE 7.21.0 +CURLFILETYPE_NAMEDPIPE 7.21.0 +CURLFILETYPE_SOCKET 7.21.0 +CURLFILETYPE_SYMLINK 7.21.0 +CURLFILETYPE_UNKNOWN 7.21.0 +CURLFINFOFLAG_KNOWN_FILENAME 7.21.0 +CURLFINFOFLAG_KNOWN_FILETYPE 7.21.0 +CURLFINFOFLAG_KNOWN_GID 7.21.0 +CURLFINFOFLAG_KNOWN_HLINKCOUNT 7.21.0 +CURLFINFOFLAG_KNOWN_PERM 7.21.0 +CURLFINFOFLAG_KNOWN_SIZE 7.21.0 +CURLFINFOFLAG_KNOWN_TIME 7.21.0 +CURLFINFOFLAG_KNOWN_UID 7.21.0 +CURLFORM_ARRAY 7.9.1 7.56.0 +CURLFORM_ARRAY_END 7.9.1 7.9.5 7.9.6 +CURLFORM_ARRAY_START 7.9.1 7.9.5 7.9.6 +CURLFORM_BUFFER 7.9.8 7.56.0 +CURLFORM_BUFFERLENGTH 7.9.8 7.56.0 +CURLFORM_BUFFERPTR 7.9.8 7.56.0 +CURLFORM_CONTENTHEADER 7.9.3 7.56.0 +CURLFORM_CONTENTLEN 7.46.0 7.56.0 +CURLFORM_CONTENTSLENGTH 7.9 7.56.0 +CURLFORM_CONTENTTYPE 7.9 7.56.0 +CURLFORM_COPYCONTENTS 7.9 7.56.0 +CURLFORM_COPYNAME 7.9 7.56.0 +CURLFORM_END 7.9 7.56.0 +CURLFORM_FILE 7.9 7.56.0 +CURLFORM_FILECONTENT 7.9.1 7.56.0 +CURLFORM_FILENAME 7.9.6 7.56.0 +CURLFORM_NAMELENGTH 7.9 7.56.0 +CURLFORM_NOTHING 7.9 7.56.0 +CURLFORM_PTRCONTENTS 7.9 7.56.0 +CURLFORM_PTRNAME 7.9 7.56.0 +CURLFORM_STREAM 7.18.2 7.56.0 +CURLFTP_CREATE_DIR 7.19.4 +CURLFTP_CREATE_DIR_NONE 7.19.4 +CURLFTP_CREATE_DIR_RETRY 7.19.4 +CURLFTPAUTH_DEFAULT 7.12.2 +CURLFTPAUTH_SSL 7.12.2 +CURLFTPAUTH_TLS 7.12.2 +CURLFTPMETHOD_DEFAULT 7.15.3 +CURLFTPMETHOD_MULTICWD 7.15.3 +CURLFTPMETHOD_NOCWD 7.15.3 +CURLFTPMETHOD_SINGLECWD 7.15.3 +CURLFTPSSL_ALL 7.11.0 7.17.0 +CURLFTPSSL_CCC_ACTIVE 7.16.2 +CURLFTPSSL_CCC_NONE 7.16.2 +CURLFTPSSL_CCC_PASSIVE 7.16.1 +CURLFTPSSL_CONTROL 7.11.0 7.17.0 +CURLFTPSSL_NONE 7.11.0 7.17.0 +CURLFTPSSL_TRY 7.11.0 7.17.0 +CURLGSSAPI_DELEGATION_FLAG 7.22.0 +CURLGSSAPI_DELEGATION_NONE 7.22.0 +CURLGSSAPI_DELEGATION_POLICY_FLAG 7.22.0 +CURLH_1XX 7.83.0 +CURLH_CONNECT 7.83.0 +CURLH_HEADER 7.83.0 +CURLH_PSEUDO 7.83.0 +CURLH_TRAILER 7.83.0 +CURLHE_BAD_ARGUMENT 7.83.0 +CURLHE_BADINDEX 7.83.0 +CURLHE_MISSING 7.83.0 +CURLHE_NOHEADERS 7.83.0 +CURLHE_NOREQUEST 7.83.0 +CURLHE_NOT_BUILT_IN 7.83.0 +CURLHE_OK 7.83.0 +CURLHE_OUT_OF_MEMORY 7.83.0 +CURLHEADER_SEPARATE 7.37.0 +CURLHEADER_UNIFIED 7.37.0 +CURLHSTS_ENABLE 7.74.0 +CURLHSTS_READONLYFILE 7.74.0 +CURLINFO_ACTIVESOCKET 7.45.0 +CURLINFO_APPCONNECT_TIME 7.19.0 +CURLINFO_APPCONNECT_TIME_T 7.61.0 +CURLINFO_CAINFO 7.84.0 +CURLINFO_CAPATH 7.84.0 +CURLINFO_CERTINFO 7.19.1 +CURLINFO_CONDITION_UNMET 7.19.4 +CURLINFO_CONN_ID 8.2.0 +CURLINFO_CONNECT_TIME 7.4.1 +CURLINFO_CONNECT_TIME_T 7.61.0 +CURLINFO_CONTENT_LENGTH_DOWNLOAD 7.6.1 7.55.0 +CURLINFO_CONTENT_LENGTH_DOWNLOAD_T 7.55.0 +CURLINFO_CONTENT_LENGTH_UPLOAD 7.6.1 7.55.0 +CURLINFO_CONTENT_LENGTH_UPLOAD_T 7.55.0 +CURLINFO_CONTENT_TYPE 7.9.4 +CURLINFO_COOKIELIST 7.14.1 +CURLINFO_DATA_IN 7.9.6 +CURLINFO_DATA_OUT 7.9.6 +CURLINFO_DOUBLE 7.4.1 +CURLINFO_EFFECTIVE_METHOD 7.72.0 +CURLINFO_EFFECTIVE_URL 7.4 +CURLINFO_END 7.9.6 +CURLINFO_FILETIME 7.5 +CURLINFO_FILETIME_T 7.59.0 +CURLINFO_FTP_ENTRY_PATH 7.15.4 +CURLINFO_HEADER_IN 7.9.6 +CURLINFO_HEADER_OUT 7.9.6 +CURLINFO_HEADER_SIZE 7.4.1 +CURLINFO_HTTP_CODE 7.4.1 7.10.8 +CURLINFO_HTTP_CONNECTCODE 7.10.7 +CURLINFO_HTTP_VERSION 7.50.0 +CURLINFO_HTTPAUTH_AVAIL 7.10.8 +CURLINFO_LASTONE 7.4.1 +CURLINFO_LASTSOCKET 7.15.2 7.45.0 +CURLINFO_LOCAL_IP 7.21.0 +CURLINFO_LOCAL_PORT 7.21.0 +CURLINFO_LONG 7.4.1 +CURLINFO_MASK 7.4.1 +CURLINFO_NAMELOOKUP_TIME 7.4.1 +CURLINFO_NAMELOOKUP_TIME_T 7.61.0 +CURLINFO_NONE 7.4.1 +CURLINFO_NUM_CONNECTS 7.12.3 +CURLINFO_OFF_T 7.55.0 +CURLINFO_OS_ERRNO 7.12.2 +CURLINFO_PRETRANSFER_TIME 7.4.1 +CURLINFO_PRETRANSFER_TIME_T 7.61.0 +CURLINFO_PRIMARY_IP 7.19.0 +CURLINFO_PRIMARY_PORT 7.21.0 +CURLINFO_PRIVATE 7.10.3 +CURLINFO_PROTOCOL 7.52.0 7.85.0 +CURLINFO_PROXY_ERROR 7.73.0 +CURLINFO_PROXY_SSL_VERIFYRESULT 7.52.0 +CURLINFO_PROXYAUTH_AVAIL 7.10.8 +CURLINFO_PTR 7.54.1 +CURLINFO_QUEUE_TIME_T 8.6.0 +CURLINFO_REDIRECT_COUNT 7.9.7 +CURLINFO_REDIRECT_TIME 7.9.7 +CURLINFO_REDIRECT_TIME_T 7.61.0 +CURLINFO_REDIRECT_URL 7.18.2 +CURLINFO_REFERER 7.76.0 +CURLINFO_REQUEST_SIZE 7.4.1 +CURLINFO_RESPONSE_CODE 7.10.8 +CURLINFO_RETRY_AFTER 7.66.0 +CURLINFO_RTSP_CLIENT_CSEQ 7.20.0 +CURLINFO_RTSP_CSEQ_RECV 7.20.0 +CURLINFO_RTSP_SERVER_CSEQ 7.20.0 +CURLINFO_RTSP_SESSION_ID 7.20.0 +CURLINFO_SCHEME 7.52.0 +CURLINFO_SIZE_DOWNLOAD 7.4.1 7.55.0 +CURLINFO_SIZE_DOWNLOAD_T 7.55.0 +CURLINFO_SIZE_UPLOAD 7.4.1 7.55.0 +CURLINFO_SIZE_UPLOAD_T 7.55.0 +CURLINFO_SLIST 7.12.3 +CURLINFO_SOCKET 7.45.0 +CURLINFO_SPEED_DOWNLOAD 7.4.1 7.55.0 +CURLINFO_SPEED_DOWNLOAD_T 7.55.0 +CURLINFO_SPEED_UPLOAD 7.4.1 7.55.0 +CURLINFO_SPEED_UPLOAD_T 7.55.0 +CURLINFO_SSL_DATA_IN 7.12.1 +CURLINFO_SSL_DATA_OUT 7.12.1 +CURLINFO_SSL_ENGINES 7.12.3 +CURLINFO_SSL_VERIFYRESULT 7.5 +CURLINFO_STARTTRANSFER_TIME 7.9.2 +CURLINFO_STARTTRANSFER_TIME_T 7.61.0 +CURLINFO_STRING 7.4.1 +CURLINFO_TEXT 7.9.6 +CURLINFO_TLS_SESSION 7.34.0 7.48.0 +CURLINFO_TLS_SSL_PTR 7.48.0 +CURLINFO_TOTAL_TIME 7.4.1 +CURLINFO_TOTAL_TIME_T 7.61.0 +CURLINFO_TYPEMASK 7.4.1 +CURLINFO_XFER_ID 8.2.0 +CURLIOCMD_NOP 7.12.3 +CURLIOCMD_RESTARTREAD 7.12.3 +CURLIOE_FAILRESTART 7.12.3 +CURLIOE_OK 7.12.3 +CURLIOE_UNKNOWNCMD 7.12.3 +CURLKHMATCH_MISMATCH 7.19.6 +CURLKHMATCH_MISSING 7.19.6 +CURLKHMATCH_OK 7.19.6 +CURLKHSTAT_DEFER 7.19.6 +CURLKHSTAT_FINE 7.19.6 +CURLKHSTAT_FINE_ADD_TO_FILE 7.19.6 +CURLKHSTAT_FINE_REPLACE 7.73.0 +CURLKHSTAT_REJECT 7.19.6 +CURLKHTYPE_DSS 7.19.6 +CURLKHTYPE_ECDSA 7.58.0 +CURLKHTYPE_ED25519 7.58.0 +CURLKHTYPE_RSA 7.19.6 +CURLKHTYPE_RSA1 7.19.6 +CURLKHTYPE_UNKNOWN 7.19.6 +CURLM_ABORTED_BY_CALLBACK 7.81.0 +CURLM_ADDED_ALREADY 7.32.1 +CURLM_BAD_EASY_HANDLE 7.9.6 +CURLM_BAD_FUNCTION_ARGUMENT 7.69.0 +CURLM_BAD_HANDLE 7.9.6 +CURLM_BAD_SOCKET 7.15.4 +CURLM_CALL_MULTI_PERFORM 7.9.6 +CURLM_CALL_MULTI_SOCKET 7.15.5 +CURLM_INTERNAL_ERROR 7.9.6 +CURLM_OK 7.9.6 +CURLM_OUT_OF_MEMORY 7.9.6 +CURLM_RECURSIVE_API_CALL 7.59.0 +CURLM_UNKNOWN_OPTION 7.15.4 +CURLM_UNRECOVERABLE_POLL 7.84.0 +CURLM_WAKEUP_FAILURE 7.68.0 +CURLMIMEOPT_FORMESCAPE 7.81.0 +CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 7.30.0 +CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 7.30.0 +CURLMOPT_MAX_CONCURRENT_STREAMS 7.67.0 +CURLMOPT_MAX_HOST_CONNECTIONS 7.30.0 +CURLMOPT_MAX_PIPELINE_LENGTH 7.30.0 +CURLMOPT_MAX_TOTAL_CONNECTIONS 7.30.0 +CURLMOPT_MAXCONNECTS 7.16.3 +CURLMOPT_PIPELINING 7.16.0 +CURLMOPT_PIPELINING_SERVER_BL 7.30.0 +CURLMOPT_PIPELINING_SITE_BL 7.30.0 +CURLMOPT_PUSHDATA 7.44.0 +CURLMOPT_PUSHFUNCTION 7.44.0 +CURLMOPT_SOCKETDATA 7.15.4 +CURLMOPT_SOCKETFUNCTION 7.15.4 +CURLMOPT_TIMERDATA 7.16.0 +CURLMOPT_TIMERFUNCTION 7.16.0 +CURLMSG_DONE 7.9.6 +CURLMSG_NONE 7.9.6 +CURLOPT 7.69.0 +CURLOPT_ABSTRACT_UNIX_SOCKET 7.53.0 +CURLOPT_ACCEPT_ENCODING 7.21.6 +CURLOPT_ACCEPTTIMEOUT_MS 7.24.0 +CURLOPT_ADDRESS_SCOPE 7.19.0 +CURLOPT_ALTSVC 7.64.1 +CURLOPT_ALTSVC_CTRL 7.64.1 +CURLOPT_APPEND 7.17.0 +CURLOPT_AUTOREFERER 7.1 +CURLOPT_AWS_SIGV4 7.75.0 +CURLOPT_BUFFERSIZE 7.10 +CURLOPT_CAINFO 7.4.2 +CURLOPT_CAINFO_BLOB 7.77.0 +CURLOPT_CAPATH 7.9.8 +CURLOPT_CA_CACHE_TIMEOUT 7.87.0 +CURLOPT_CERTINFO 7.19.1 +CURLOPT_CHUNK_BGN_FUNCTION 7.21.0 +CURLOPT_CHUNK_DATA 7.21.0 +CURLOPT_CHUNK_END_FUNCTION 7.21.0 +CURLOPT_CLOSEFUNCTION 7.7 7.11.1 7.15.5 +CURLOPT_CLOSEPOLICY 7.7 7.16.1 +CURLOPT_CLOSESOCKETDATA 7.21.7 +CURLOPT_CLOSESOCKETFUNCTION 7.21.7 +CURLOPT_CONNECT_ONLY 7.15.2 +CURLOPT_CONNECT_TO 7.49.0 +CURLOPT_CONNECTTIMEOUT 7.7 +CURLOPT_CONNECTTIMEOUT_MS 7.16.2 +CURLOPT_CONV_FROM_NETWORK_FUNCTION 7.15.4 7.82.0 +CURLOPT_CONV_FROM_UTF8_FUNCTION 7.15.4 7.82.0 +CURLOPT_CONV_TO_NETWORK_FUNCTION 7.15.4 7.82.0 +CURLOPT_COOKIE 7.1 +CURLOPT_COOKIEFILE 7.1 +CURLOPT_COOKIEJAR 7.9 +CURLOPT_COOKIELIST 7.14.1 +CURLOPT_COOKIESESSION 7.9.7 +CURLOPT_COPYPOSTFIELDS 7.17.1 +CURLOPT_CRLF 7.1 +CURLOPT_CRLFILE 7.19.0 +CURLOPT_CURLU 7.63.0 +CURLOPT_CUSTOMREQUEST 7.1 +CURLOPT_DEBUGDATA 7.9.6 +CURLOPT_DEBUGFUNCTION 7.9.6 +CURLOPT_DEFAULT_PROTOCOL 7.45.0 +CURLOPT_DIRLISTONLY 7.17.0 +CURLOPT_DISALLOW_USERNAME_IN_URL 7.61.0 +CURLOPT_DNS_CACHE_TIMEOUT 7.9.3 +CURLOPT_DNS_INTERFACE 7.33.0 +CURLOPT_DNS_LOCAL_IP4 7.33.0 +CURLOPT_DNS_LOCAL_IP6 7.33.0 +CURLOPT_DNS_SERVERS 7.24.0 +CURLOPT_DNS_SHUFFLE_ADDRESSES 7.60.0 +CURLOPT_DNS_USE_GLOBAL_CACHE 7.9.3 7.11.1 +CURLOPT_DOH_SSL_VERIFYHOST 7.76.0 +CURLOPT_DOH_SSL_VERIFYPEER 7.76.0 +CURLOPT_DOH_SSL_VERIFYSTATUS 7.76.0 +CURLOPT_DOH_URL 7.62.0 +CURLOPT_EGDSOCKET 7.7 7.84.0 +CURLOPT_ENCODING 7.10 7.21.6 +CURLOPT_ERRORBUFFER 7.1 +CURLOPT_EXPECT_100_TIMEOUT_MS 7.36.0 +CURLOPT_FAILONERROR 7.1 +CURLOPT_FILE 7.1 7.9.7 +CURLOPT_FILETIME 7.5 +CURLOPT_FNMATCH_DATA 7.21.0 +CURLOPT_FNMATCH_FUNCTION 7.21.0 +CURLOPT_FOLLOWLOCATION 7.1 +CURLOPT_FORBID_REUSE 7.7 +CURLOPT_FRESH_CONNECT 7.7 +CURLOPT_FTP_ACCOUNT 7.13.0 +CURLOPT_FTP_ALTERNATIVE_TO_USER 7.15.5 +CURLOPT_FTP_CREATE_MISSING_DIRS 7.10.7 +CURLOPT_FTP_FILEMETHOD 7.15.1 +CURLOPT_FTP_RESPONSE_TIMEOUT 7.10.8 7.85.0 +CURLOPT_FTP_SKIP_PASV_IP 7.15.0 +CURLOPT_FTP_SSL 7.11.0 7.16.4 +CURLOPT_FTP_SSL_CCC 7.16.1 +CURLOPT_FTP_USE_EPRT 7.10.5 +CURLOPT_FTP_USE_EPSV 7.9.2 +CURLOPT_FTP_USE_PRET 7.20.0 +CURLOPT_FTPAPPEND 7.1 7.16.4 +CURLOPT_FTPASCII 7.1 7.11.1 7.15.5 +CURLOPT_FTPLISTONLY 7.1 7.16.4 +CURLOPT_FTPPORT 7.1 +CURLOPT_FTPSSLAUTH 7.12.2 +CURLOPT_GSSAPI_DELEGATION 7.22.0 +CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS 7.59.0 +CURLOPT_HAPROXYPROTOCOL 7.60.0 +CURLOPT_HAPROXY_CLIENT_IP 8.2.0 +CURLOPT_HEADER 7.1 +CURLOPT_HEADERDATA 7.10 +CURLOPT_HEADERFUNCTION 7.7.2 +CURLOPT_HEADEROPT 7.37.0 +CURLOPT_HSTS 7.74.0 +CURLOPT_HSTS_CTRL 7.74.0 +CURLOPT_HSTSREADDATA 7.74.0 +CURLOPT_HSTSREADFUNCTION 7.74.0 +CURLOPT_HSTSWRITEDATA 7.74.0 +CURLOPT_HSTSWRITEFUNCTION 7.74.0 +CURLOPT_HTTP09_ALLOWED 7.64.0 +CURLOPT_HTTP200ALIASES 7.10.3 +CURLOPT_HTTP_CONTENT_DECODING 7.16.2 +CURLOPT_HTTP_TRANSFER_DECODING 7.16.2 +CURLOPT_HTTP_VERSION 7.9.1 +CURLOPT_HTTPAUTH 7.10.6 +CURLOPT_HTTPGET 7.8.1 +CURLOPT_HTTPHEADER 7.1 +CURLOPT_HTTPPOST 7.1 7.56.0 +CURLOPT_HTTPPROXYTUNNEL 7.3 +CURLOPT_HTTPREQUEST 7.1 - 7.15.5 +CURLOPT_IGNORE_CONTENT_LENGTH 7.14.1 +CURLOPT_INFILE 7.1 7.9.7 +CURLOPT_INFILESIZE 7.1 +CURLOPT_INFILESIZE_LARGE 7.11.0 +CURLOPT_INTERFACE 7.3 +CURLOPT_INTERLEAVEDATA 7.20.0 +CURLOPT_INTERLEAVEFUNCTION 7.20.0 +CURLOPT_IOCTLDATA 7.12.3 7.18.0 +CURLOPT_IOCTLFUNCTION 7.12.3 7.18.0 +CURLOPT_IPRESOLVE 7.10.8 +CURLOPT_ISSUERCERT 7.19.0 +CURLOPT_ISSUERCERT_BLOB 7.71.0 +CURLOPT_KEEP_SENDING_ON_ERROR 7.51.0 +CURLOPT_KEYPASSWD 7.17.0 +CURLOPT_KRB4LEVEL 7.3 7.17.0 +CURLOPT_KRBLEVEL 7.16.4 +CURLOPT_LOCALPORT 7.15.2 +CURLOPT_LOCALPORTRANGE 7.15.2 +CURLOPT_LOGIN_OPTIONS 7.34.0 +CURLOPT_LOW_SPEED_LIMIT 7.1 +CURLOPT_LOW_SPEED_TIME 7.1 +CURLOPT_MAIL_AUTH 7.25.0 +CURLOPT_MAIL_FROM 7.20.0 +CURLOPT_MAIL_RCPT 7.20.0 +CURLOPT_MAIL_RCPT_ALLLOWFAILS 7.69.0 8.2.0 +CURLOPT_MAIL_RCPT_ALLOWFAILS 8.2.0 +CURLOPT_QUICK_EXIT 7.87.0 +CURLOPT_MAX_RECV_SPEED_LARGE 7.15.5 +CURLOPT_MAX_SEND_SPEED_LARGE 7.15.5 +CURLOPT_MAXAGE_CONN 7.65.0 +CURLOPT_MAXCONNECTS 7.7 +CURLOPT_MAXFILESIZE 7.10.8 +CURLOPT_MAXFILESIZE_LARGE 7.11.0 +CURLOPT_MAXLIFETIME_CONN 7.80.0 +CURLOPT_MAXREDIRS 7.5 +CURLOPT_MIME_OPTIONS 7.81.0 +CURLOPT_MIMEPOST 7.56.0 +CURLOPT_MUTE 7.1 7.8 7.15.5 +CURLOPT_NETRC 7.1 +CURLOPT_NETRC_FILE 7.11.0 +CURLOPT_NEW_DIRECTORY_PERMS 7.16.4 +CURLOPT_NEW_FILE_PERMS 7.16.4 +CURLOPT_NOBODY 7.1 +CURLOPT_NOPROGRESS 7.1 +CURLOPT_NOPROXY 7.19.4 +CURLOPT_NOSIGNAL 7.10 +CURLOPT_NOTHING 7.1.1 7.11.1 7.11.0 +CURLOPT_OPENSOCKETDATA 7.17.1 +CURLOPT_OPENSOCKETFUNCTION 7.17.1 +CURLOPT_PASSWDDATA 7.4.2 7.11.1 7.15.5 +CURLOPT_PASSWDFUNCTION 7.4.2 7.11.1 7.15.5 +CURLOPT_PASSWORD 7.19.1 +CURLOPT_PASV_HOST 7.12.1 7.16.0 7.15.5 +CURLOPT_PATH_AS_IS 7.42.0 +CURLOPT_PINNEDPUBLICKEY 7.39.0 +CURLOPT_PIPEWAIT 7.43.0 +CURLOPT_PORT 7.1 +CURLOPT_POST 7.1 +CURLOPT_POST301 7.17.1 7.19.1 +CURLOPT_POSTFIELDS 7.1 +CURLOPT_POSTFIELDSIZE 7.2 +CURLOPT_POSTFIELDSIZE_LARGE 7.11.1 +CURLOPT_POSTQUOTE 7.1 +CURLOPT_POSTREDIR 7.19.1 +CURLOPT_PRE_PROXY 7.52.0 +CURLOPT_PREQUOTE 7.9.5 +CURLOPT_PREREQDATA 7.80.0 +CURLOPT_PREREQFUNCTION 7.80.0 +CURLOPT_PRIVATE 7.10.3 +CURLOPT_PROGRESSDATA 7.1 +CURLOPT_PROGRESSFUNCTION 7.1 7.32.0 +CURLOPT_PROTOCOLS 7.19.4 7.85.0 +CURLOPT_PROTOCOLS_STR 7.85.0 +CURLOPT_PROXY 7.1 +CURLOPT_PROXY_CAINFO 7.52.0 +CURLOPT_PROXY_CAINFO_BLOB 7.77.0 +CURLOPT_PROXY_CAPATH 7.52.0 +CURLOPT_PROXY_CRLFILE 7.52.0 +CURLOPT_PROXY_ISSUERCERT 7.71.0 +CURLOPT_PROXY_ISSUERCERT_BLOB 7.71.0 +CURLOPT_PROXY_KEYPASSWD 7.52.0 +CURLOPT_PROXY_PINNEDPUBLICKEY 7.52.0 +CURLOPT_PROXY_SERVICE_NAME 7.43.0 +CURLOPT_PROXY_SSL_CIPHER_LIST 7.52.0 +CURLOPT_PROXY_SSL_OPTIONS 7.52.0 +CURLOPT_PROXY_SSL_VERIFYHOST 7.52.0 +CURLOPT_PROXY_SSL_VERIFYPEER 7.52.0 +CURLOPT_PROXY_SSLCERT 7.52.0 +CURLOPT_PROXY_SSLCERT_BLOB 7.71.0 +CURLOPT_PROXY_SSLCERTTYPE 7.52.0 +CURLOPT_PROXY_SSLKEY 7.52.0 +CURLOPT_PROXY_SSLKEY_BLOB 7.71.0 +CURLOPT_PROXY_SSLKEYTYPE 7.52.0 +CURLOPT_PROXY_SSLVERSION 7.52.0 +CURLOPT_PROXY_TLS13_CIPHERS 7.61.0 +CURLOPT_PROXY_TLSAUTH_PASSWORD 7.52.0 +CURLOPT_PROXY_TLSAUTH_TYPE 7.52.0 +CURLOPT_PROXY_TLSAUTH_USERNAME 7.52.0 +CURLOPT_PROXY_TRANSFER_MODE 7.18.0 +CURLOPT_PROXYAUTH 7.10.7 +CURLOPT_PROXYHEADER 7.37.0 +CURLOPT_PROXYPASSWORD 7.19.1 +CURLOPT_PROXYPORT 7.1 +CURLOPT_PROXYTYPE 7.10 +CURLOPT_PROXYUSERNAME 7.19.1 +CURLOPT_PROXYUSERPWD 7.1 +CURLOPT_PUT 7.1 7.12.1 +CURLOPT_QUOTE 7.1 +CURLOPT_RANDOM_FILE 7.7 7.84.0 +CURLOPT_RANGE 7.1 +CURLOPT_READDATA 7.9.7 +CURLOPT_READFUNCTION 7.1 +CURLOPT_REDIR_PROTOCOLS 7.19.4 7.85.0 +CURLOPT_REDIR_PROTOCOLS_STR 7.85.0 +CURLOPT_REFERER 7.1 +CURLOPT_REQUEST_TARGET 7.55.0 +CURLOPT_RESOLVE 7.21.3 +CURLOPT_RESOLVER_START_DATA 7.59.0 +CURLOPT_RESOLVER_START_FUNCTION 7.59.0 +CURLOPT_RESUME_FROM 7.1 +CURLOPT_RESUME_FROM_LARGE 7.11.0 +CURLOPT_RTSP_CLIENT_CSEQ 7.20.0 +CURLOPT_RTSP_REQUEST 7.20.0 +CURLOPT_RTSP_SERVER_CSEQ 7.20.0 +CURLOPT_RTSP_SESSION_ID 7.20.0 +CURLOPT_RTSP_STREAM_URI 7.20.0 +CURLOPT_RTSP_TRANSPORT 7.20.0 +CURLOPT_RTSPHEADER 7.20.0 +CURLOPT_SASL_AUTHZID 7.66.0 +CURLOPT_SASL_IR 7.31.0 +CURLOPT_SEEKDATA 7.18.0 +CURLOPT_SEEKFUNCTION 7.18.0 +CURLOPT_SERVER_RESPONSE_TIMEOUT 7.20.0 +CURLOPT_SERVER_RESPONSE_TIMEOUT_MS 8.6.0 +CURLOPT_SERVICE_NAME 7.43.0 +CURLOPT_SHARE 7.10 +CURLOPT_SOCKOPTDATA 7.16.0 +CURLOPT_SOCKOPTFUNCTION 7.16.0 +CURLOPT_SOCKS5_AUTH 7.55.0 +CURLOPT_SOCKS5_GSSAPI_NEC 7.19.4 +CURLOPT_SOCKS5_GSSAPI_SERVICE 7.19.4 7.49.0 +CURLOPT_SOURCE_HOST 7.12.1 - 7.15.5 +CURLOPT_SOURCE_PATH 7.12.1 - 7.15.5 +CURLOPT_SOURCE_PORT 7.12.1 - 7.15.5 +CURLOPT_SOURCE_POSTQUOTE 7.12.1 - 7.15.5 +CURLOPT_SOURCE_PREQUOTE 7.12.1 - 7.15.5 +CURLOPT_SOURCE_QUOTE 7.13.0 - 7.15.5 +CURLOPT_SOURCE_URL 7.13.0 - 7.15.5 +CURLOPT_SOURCE_USERPWD 7.12.1 - 7.15.5 +CURLOPT_SSH_AUTH_TYPES 7.16.1 +CURLOPT_SSH_COMPRESSION 7.56.0 +CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 7.17.1 +CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 7.80.0 +CURLOPT_SSH_HOSTKEYDATA 7.84.0 +CURLOPT_SSH_HOSTKEYFUNCTION 7.84.0 +CURLOPT_SSH_KEYDATA 7.19.6 +CURLOPT_SSH_KEYFUNCTION 7.19.6 +CURLOPT_SSH_KNOWNHOSTS 7.19.6 +CURLOPT_SSH_PRIVATE_KEYFILE 7.16.1 +CURLOPT_SSH_PUBLIC_KEYFILE 7.16.1 +CURLOPT_SSL_CIPHER_LIST 7.9 +CURLOPT_SSL_CTX_DATA 7.10.6 +CURLOPT_SSL_CTX_FUNCTION 7.10.6 +CURLOPT_SSL_EC_CURVES 7.73.0 +CURLOPT_SSL_ENABLE_ALPN 7.36.0 +CURLOPT_SSL_ENABLE_NPN 7.36.0 7.86.0 +CURLOPT_SSL_FALSESTART 7.42.0 +CURLOPT_SSL_OPTIONS 7.25.0 +CURLOPT_SSL_SESSIONID_CACHE 7.16.0 +CURLOPT_SSL_VERIFYHOST 7.8.1 +CURLOPT_SSL_VERIFYPEER 7.4.2 +CURLOPT_SSL_VERIFYSTATUS 7.41.0 +CURLOPT_SSLCERT 7.1 +CURLOPT_SSLCERT_BLOB 7.71.0 +CURLOPT_SSLCERTPASSWD 7.1.1 7.17.0 +CURLOPT_SSLCERTTYPE 7.9.3 +CURLOPT_SSLENGINE 7.9.3 +CURLOPT_SSLENGINE_DEFAULT 7.9.3 +CURLOPT_SSLKEY 7.9.3 +CURLOPT_SSLKEY_BLOB 7.71.0 +CURLOPT_SSLKEYPASSWD 7.9.3 7.17.0 +CURLOPT_SSLKEYTYPE 7.9.3 +CURLOPT_SSLVERSION 7.1 +CURLOPT_STDERR 7.1 +CURLOPT_STREAM_DEPENDS 7.46.0 +CURLOPT_STREAM_DEPENDS_E 7.46.0 +CURLOPT_STREAM_WEIGHT 7.46.0 +CURLOPT_SUPPRESS_CONNECT_HEADERS 7.54.0 +CURLOPT_TCP_FASTOPEN 7.49.0 +CURLOPT_TCP_KEEPALIVE 7.25.0 +CURLOPT_TCP_KEEPIDLE 7.25.0 +CURLOPT_TCP_KEEPINTVL 7.25.0 +CURLOPT_TCP_NODELAY 7.11.2 +CURLOPT_TELNETOPTIONS 7.7 +CURLOPT_TFTP_BLKSIZE 7.19.4 +CURLOPT_TFTP_NO_OPTIONS 7.48.0 +CURLOPT_TIMECONDITION 7.1 +CURLOPT_TIMEOUT 7.1 +CURLOPT_TIMEOUT_MS 7.16.2 +CURLOPT_TIMEVALUE 7.1 +CURLOPT_TIMEVALUE_LARGE 7.59.0 +CURLOPT_TLS13_CIPHERS 7.61.0 +CURLOPT_TLSAUTH_PASSWORD 7.21.4 +CURLOPT_TLSAUTH_TYPE 7.21.4 +CURLOPT_TLSAUTH_USERNAME 7.21.4 +CURLOPT_TRAILERDATA 7.64.0 +CURLOPT_TRAILERFUNCTION 7.64.0 +CURLOPT_TRANSFER_ENCODING 7.21.6 +CURLOPT_TRANSFERTEXT 7.1.1 +CURLOPT_UNIX_SOCKET_PATH 7.40.0 +CURLOPT_UNRESTRICTED_AUTH 7.10.4 +CURLOPT_UPKEEP_INTERVAL_MS 7.62.0 +CURLOPT_UPLOAD 7.1 +CURLOPT_UPLOAD_BUFFERSIZE 7.62.0 +CURLOPT_URL 7.1 +CURLOPT_USE_SSL 7.17.0 +CURLOPT_USERAGENT 7.1 +CURLOPT_USERNAME 7.19.1 +CURLOPT_USERPWD 7.1 +CURLOPT_VERBOSE 7.1 +CURLOPT_WILDCARDMATCH 7.21.0 +CURLOPT_WRITEDATA 7.9.7 +CURLOPT_WRITEFUNCTION 7.1 +CURLOPT_WRITEHEADER 7.1 +CURLOPT_WRITEINFO 7.1 +CURLOPT_WS_OPTIONS 7.86.0 +CURLOPT_XFERINFODATA 7.32.0 +CURLOPT_XFERINFOFUNCTION 7.32.0 +CURLOPT_XOAUTH2_BEARER 7.33.0 +CURLOPTDEPRECATED 7.87.0 +CURLOPTTYPE_BLOB 7.71.0 +CURLOPTTYPE_CBPOINT 7.73.0 +CURLOPTTYPE_FUNCTIONPOINT 7.1 +CURLOPTTYPE_LONG 7.1 +CURLOPTTYPE_OBJECTPOINT 7.1 +CURLOPTTYPE_OFF_T 7.11.0 +CURLOPTTYPE_SLISTPOINT 7.65.2 +CURLOPTTYPE_STRINGPOINT 7.46.0 +CURLOPTTYPE_VALUES 7.73.0 +CURLOT_BLOB 7.73.0 +CURLOT_CBPTR 7.73.0 +CURLOT_FLAG_ALIAS 7.73.0 +CURLOT_FUNCTION 7.73.0 +CURLOT_LONG 7.73.0 +CURLOT_OBJECT 7.73.0 +CURLOT_OFF_T 7.73.0 +CURLOT_SLIST 7.73.0 +CURLOT_STRING 7.73.0 +CURLOT_VALUES 7.73.0 +CURLPAUSE_ALL 7.18.0 +CURLPAUSE_CONT 7.18.0 +CURLPAUSE_RECV 7.18.0 +CURLPAUSE_RECV_CONT 7.18.0 +CURLPAUSE_SEND 7.18.0 +CURLPAUSE_SEND_CONT 7.18.0 +CURLPIPE_HTTP1 7.43.0 +CURLPIPE_MULTIPLEX 7.43.0 +CURLPIPE_NOTHING 7.43.0 +CURLPROTO_ALL 7.19.4 +CURLPROTO_DICT 7.19.4 +CURLPROTO_FILE 7.19.4 +CURLPROTO_FTP 7.19.4 +CURLPROTO_FTPS 7.19.4 +CURLPROTO_GOPHER 7.21.2 +CURLPROTO_GOPHERS 7.75.0 +CURLPROTO_HTTP 7.19.4 +CURLPROTO_HTTPS 7.19.4 +CURLPROTO_IMAP 7.20.0 +CURLPROTO_IMAPS 7.20.0 +CURLPROTO_LDAP 7.19.4 +CURLPROTO_LDAPS 7.19.4 +CURLPROTO_MQTT 7.71.0 +CURLPROTO_POP3 7.20.0 +CURLPROTO_POP3S 7.20.0 +CURLPROTO_RTMP 7.21.0 +CURLPROTO_RTMPE 7.21.0 +CURLPROTO_RTMPS 7.21.0 +CURLPROTO_RTMPT 7.21.0 +CURLPROTO_RTMPTE 7.21.0 +CURLPROTO_RTMPTS 7.21.0 +CURLPROTO_RTSP 7.20.0 +CURLPROTO_SCP 7.19.4 +CURLPROTO_SFTP 7.19.4 +CURLPROTO_SMB 7.40.0 +CURLPROTO_SMBS 7.40.0 +CURLPROTO_SMTP 7.20.0 +CURLPROTO_SMTPS 7.20.0 +CURLPROTO_TELNET 7.19.4 +CURLPROTO_TFTP 7.19.4 +CURLPROXY_HTTP 7.10 +CURLPROXY_HTTP_1_0 7.19.4 +CURLPROXY_HTTPS 7.52.0 +CURLPROXY_HTTPS2 8.1.0 +CURLPROXY_SOCKS4 7.10 +CURLPROXY_SOCKS4A 7.18.0 +CURLPROXY_SOCKS5 7.10 +CURLPROXY_SOCKS5_HOSTNAME 7.18.0 +CURLPX_BAD_ADDRESS_TYPE 7.73.0 +CURLPX_BAD_VERSION 7.73.0 +CURLPX_CLOSED 7.73.0 +CURLPX_GSSAPI 7.73.0 +CURLPX_GSSAPI_PERMSG 7.73.0 +CURLPX_GSSAPI_PROTECTION 7.73.0 +CURLPX_IDENTD 7.73.0 +CURLPX_IDENTD_DIFFER 7.73.0 +CURLPX_LONG_HOSTNAME 7.73.0 +CURLPX_LONG_PASSWD 7.73.0 +CURLPX_LONG_USER 7.73.0 +CURLPX_NO_AUTH 7.73.0 +CURLPX_OK 7.73.0 +CURLPX_RECV_ADDRESS 7.73.0 +CURLPX_RECV_AUTH 7.73.0 +CURLPX_RECV_CONNECT 7.73.0 +CURLPX_RECV_REQACK 7.73.0 +CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED 7.73.0 +CURLPX_REPLY_COMMAND_NOT_SUPPORTED 7.73.0 +CURLPX_REPLY_CONNECTION_REFUSED 7.73.0 +CURLPX_REPLY_GENERAL_SERVER_FAILURE 7.73.0 +CURLPX_REPLY_HOST_UNREACHABLE 7.73.0 +CURLPX_REPLY_NETWORK_UNREACHABLE 7.73.0 +CURLPX_REPLY_NOT_ALLOWED 7.73.0 +CURLPX_REPLY_TTL_EXPIRED 7.73.0 +CURLPX_REPLY_UNASSIGNED 7.73.0 +CURLPX_REQUEST_FAILED 7.73.0 +CURLPX_RESOLVE_HOST 7.73.0 +CURLPX_SEND_AUTH 7.73.0 +CURLPX_SEND_CONNECT 7.73.0 +CURLPX_SEND_REQUEST 7.73.0 +CURLPX_UNKNOWN_FAIL 7.73.0 +CURLPX_UNKNOWN_MODE 7.73.0 +CURLPX_USER_REJECTED 7.73.0 +CURLSHE_BAD_OPTION 7.10.3 +CURLSHE_IN_USE 7.10.3 +CURLSHE_INVALID 7.10.3 +CURLSHE_NOMEM 7.12.0 +CURLSHE_NOT_BUILT_IN 7.23.0 +CURLSHE_OK 7.10.3 +CURLSHOPT_LOCKFUNC 7.10.3 +CURLSHOPT_NONE 7.10.3 +CURLSHOPT_SHARE 7.10.3 +CURLSHOPT_UNLOCKFUNC 7.10.3 +CURLSHOPT_UNSHARE 7.10.3 +CURLSHOPT_USERDATA 7.10.3 +CURLSOCKTYPE_ACCEPT 7.28.0 +CURLSOCKTYPE_IPCXN 7.16.0 +CURLSSH_AUTH_AGENT 7.28.0 +CURLSSH_AUTH_ANY 7.16.1 +CURLSSH_AUTH_DEFAULT 7.16.1 +CURLSSH_AUTH_GSSAPI 7.58.0 +CURLSSH_AUTH_HOST 7.16.1 +CURLSSH_AUTH_KEYBOARD 7.16.1 +CURLSSH_AUTH_NONE 7.16.1 +CURLSSH_AUTH_PASSWORD 7.16.1 +CURLSSH_AUTH_PUBLICKEY 7.16.1 +CURLSSLBACKEND_AWSLC 8.1.0 +CURLSSLBACKEND_AXTLS 7.38.0 7.61.0 +CURLSSLBACKEND_BEARSSL 7.68.0 +CURLSSLBACKEND_BORINGSSL 7.49.0 +CURLSSLBACKEND_CYASSL 7.34.0 +CURLSSLBACKEND_DARWINSSL 7.34.0 7.64.1 +CURLSSLBACKEND_GNUTLS 7.34.0 +CURLSSLBACKEND_GSKIT 7.34.0 +CURLSSLBACKEND_LIBRESSL 7.49.0 +CURLSSLBACKEND_MBEDTLS 7.46.0 +CURLSSLBACKEND_MESALINK 7.62.0 +CURLSSLBACKEND_NONE 7.34.0 +CURLSSLBACKEND_NSS 7.34.0 +CURLSSLBACKEND_OPENSSL 7.34.0 +CURLSSLBACKEND_POLARSSL 7.34.0 7.69.0 +CURLSSLBACKEND_QSOSSL 7.34.0 - 7.38.0 +CURLSSLBACKEND_RUSTLS 7.76.0 +CURLSSLBACKEND_SCHANNEL 7.34.0 +CURLSSLBACKEND_SECURETRANSPORT 7.64.1 +CURLSSLBACKEND_WOLFSSL 7.49.0 +CURLSSLOPT_ALLOW_BEAST 7.25.0 +CURLSSLOPT_AUTO_CLIENT_CERT 7.77.0 +CURLSSLOPT_NATIVE_CA 7.71.0 +CURLSSLOPT_NO_PARTIALCHAIN 7.68.0 +CURLSSLOPT_NO_REVOKE 7.44.0 +CURLSSLOPT_REVOKE_BEST_EFFORT 7.70.0 +CURLSSLSET_NO_BACKENDS 7.56.0 +CURLSSLSET_OK 7.56.0 +CURLSSLSET_TOO_LATE 7.56.0 +CURLSSLSET_UNKNOWN_BACKEND 7.56.0 +CURLSTS_DONE 7.74.0 +CURLSTS_FAIL 7.74.0 +CURLSTS_OK 7.74.0 +CURLU_ALLOW_SPACE 7.78.0 +CURLU_APPENDQUERY 7.62.0 +CURLU_DEFAULT_PORT 7.62.0 +CURLU_DEFAULT_SCHEME 7.62.0 +CURLU_DISALLOW_USER 7.62.0 +CURLU_GUESS_SCHEME 7.62.0 +CURLU_NO_AUTHORITY 7.67.0 +CURLU_NO_DEFAULT_PORT 7.62.0 +CURLU_NON_SUPPORT_SCHEME 7.62.0 +CURLU_PATH_AS_IS 7.62.0 +CURLU_PUNY2IDN 8.3.0 +CURLU_PUNYCODE 7.88.0 +CURLU_URLDECODE 7.62.0 +CURLU_URLENCODE 7.62.0 +CURLUE_BAD_FILE_URL 7.81.0 +CURLUE_BAD_FRAGMENT 7.81.0 +CURLUE_BAD_HANDLE 7.62.0 +CURLUE_BAD_HOSTNAME 7.81.0 +CURLUE_BAD_IPV6 7.81.0 +CURLUE_BAD_LOGIN 7.81.0 +CURLUE_BAD_PARTPOINTER 7.62.0 +CURLUE_BAD_PASSWORD 7.81.0 +CURLUE_BAD_PATH 7.81.0 +CURLUE_BAD_PORT_NUMBER 7.62.0 +CURLUE_BAD_QUERY 7.81.0 +CURLUE_BAD_SCHEME 7.81.0 +CURLUE_BAD_SLASHES 7.81.0 +CURLUE_BAD_USER 7.81.0 +CURLUE_LACKS_IDN 7.88.0 +CURLUE_MALFORMED_INPUT 7.62.0 +CURLUE_NO_FRAGMENT 7.62.0 +CURLUE_NO_HOST 7.62.0 +CURLUE_NO_OPTIONS 7.62.0 +CURLUE_NO_PASSWORD 7.62.0 +CURLUE_NO_PORT 7.62.0 +CURLUE_NO_QUERY 7.62.0 +CURLUE_NO_SCHEME 7.62.0 +CURLUE_NO_USER 7.62.0 +CURLUE_NO_ZONEID 7.81.0 +CURLUE_OK 7.62.0 +CURLUE_OUT_OF_MEMORY 7.62.0 +CURLUE_TOO_LARGE 8.6.0 +CURLUE_UNKNOWN_PART 7.62.0 +CURLUE_UNSUPPORTED_SCHEME 7.62.0 +CURLUE_URLDECODE 7.62.0 +CURLUE_USER_NOT_ALLOWED 7.62.0 +CURLUPART_FRAGMENT 7.62.0 +CURLUPART_HOST 7.62.0 +CURLUPART_OPTIONS 7.62.0 +CURLUPART_PASSWORD 7.62.0 +CURLUPART_PATH 7.62.0 +CURLUPART_PORT 7.62.0 +CURLUPART_QUERY 7.62.0 +CURLUPART_SCHEME 7.62.0 +CURLUPART_URL 7.62.0 +CURLUPART_USER 7.62.0 +CURLUPART_ZONEID 7.65.0 +CURLUSESSL_ALL 7.17.0 +CURLUSESSL_CONTROL 7.17.0 +CURLUSESSL_NONE 7.17.0 +CURLUSESSL_TRY 7.17.0 +CURLVERSION_EIGHTH 7.72.0 +CURLVERSION_ELEVENTH 7.87.0 +CURLVERSION_FIFTH 7.57.0 +CURLVERSION_FIRST 7.10 +CURLVERSION_FOURTH 7.16.1 +CURLVERSION_NINTH 7.75.0 +CURLVERSION_NOW 7.10 +CURLVERSION_SECOND 7.11.1 +CURLVERSION_SEVENTH 7.70.0 +CURLVERSION_SIXTH 7.66.0 +CURLVERSION_TENTH 7.77.0 +CURLVERSION_THIRD 7.12.0 +CURLWARNING 7.66.0 +CURLWS_BINARY 7.86.0 +CURLWS_CLOSE 7.86.0 +CURLWS_CONT 7.86.0 +CURLWS_OFFSET 7.86.0 +CURLWS_PING 7.86.0 +CURLWS_PONG 7.86.0 +CURLWS_RAW_MODE 7.86.0 +CURLWS_TEXT 7.86.0 +LIBCURL_COPYRIGHT 7.18.0 +LIBCURL_TIMESTAMP 7.16.2 +LIBCURL_VERSION 7.11.0 +LIBCURL_VERSION_MAJOR 7.11.0 +LIBCURL_VERSION_MINOR 7.11.0 +LIBCURL_VERSION_NUM 7.11.0 +LIBCURL_VERSION_PATCH 7.11.0 diff --git a/docs/libcurl/symbols.pl b/docs/libcurl/symbols.pl new file mode 100755 index 0000000..1105ae6 --- /dev/null +++ b/docs/libcurl/symbols.pl @@ -0,0 +1,102 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# +# Experience has shown that the symbols-in-versions file is useful to +# applications that want to build with a wide range of libcurl versions. It +# is however easy to get it wrong and the source gets a bit messy with all the +# fixed numerical comparisons. +# +# The point of this script is to provide an easy-to-use macro for libcurl- +# using applications to do preprocessor checks for specific libcurl defines, +# and yet make the code clearly show what the macro is used for. +# +# Run this script and generate libcurl-symbols.h and then use that header in +# a fashion similar to: +# +# #include "libcurl-symbols.h" +# +# #if LIBCURL_HAS(CURLOPT_MUTE) +# has mute +# #else +# no mute +# #endif +# +# +open F, " + +#define LIBCURL_HAS(x) \\ + (defined(x ## _FIRST) && (x ## _FIRST <= LIBCURL_VERSION_NUM) && \\ + (!defined(x ## _LAST) || ( x ## _LAST >= LIBCURL_VERSION_NUM))) + +EOS + ; + +while() { + if(/^(CURL[^ ]*)[ \t]*(.*)/) { + my ($sym, $vers)=($1, $2); + + my $intr; + my $rm; + my $dep; + + # is there removed info? + if($vers =~ /([\d.]+)[ \t-]+([\d.-]+)[ \t]+([\d.]+)/) { + ($intr, $dep, $rm)=($1, $2, $3); + } + # is it a dep-only line? + elsif($vers =~ /([\d.]+)[ \t-]+([\d.]+)/) { + ($intr, $dep)=($1, $2); + } + else { + $intr = $vers; + } + + my $inum = str2num($intr); + + print <, et al. +SPDX-License-Identifier: curl +Title: mk-ca-bundle +Section: 1 +Source: mk-ca-bundle +See-also: + - curl (1) +--- + +# NAME + +mk-ca-bundle - convert Mozilla's certificate bundle to PEM format + +# SYNOPSIS + +mk-ca-bundle [options] +*[outputfile]* + +# DESCRIPTION + +The mk-ca-bundle tool downloads the *certdata.txt* file from Mozilla's source +tree over HTTPS, then parses *certdata.txt* and extracts certificates into PEM +format. By default, only CA root certificates trusted to issue SSL server +authentication certificates are extracted. These are then processed with the +OpenSSL command line tool to produce the final ca-bundle file. + +The default *outputfile* name is **ca-bundle.crt**. By setting it to '-' (a +single dash) you will get the output sent to STDOUT instead of a file. + +The PEM format this scripts uses for output makes the result readily available +for use by just about all OpenSSL or GnuTLS powered applications, such as curl +and others. + +# OPTIONS + +The following options are supported: + +## -b + +backup an existing version of *outputfilename* + +## -d [name] + +specify which Mozilla tree to pull *certdata.txt* from (or a custom +URL). Valid names are: aurora, beta, central, Mozilla, nss, release +(default). They are shortcuts for which source tree to get the certificates +data from. + +## -f + +force rebuild even if *certdata.txt* is current (Added in version 1.17) + +## -i + +print version info about used modules + +## -k + +Allow insecure data transfer. By default (since 1.27) this command will fail +if the HTTPS transfer fails. This overrides that decision (and opens for +man-in-the-middle attacks). + +## -l + +print license info about *certdata.txt* + +## -m + +(Added in 1.26) Include meta data comments in the output. The meta data is +specific information about each certificate that is stored in the original +file as comments and using this option will make those comments get passed on +to the output file. The meta data is not parsed in any way by mk-ca-bundle. + +## -n + +no download of *certdata.txt* (to use existing) + +## -p [purposes]:[levels] + +list of Mozilla trust purposes and levels for certificates to include in +output. Takes the form of a comma separated list of purposes, a colon, and a +comma separated list of levels. The default is to include all certificates +trusted to issue SSL Server certificates (*SERVER_AUTH:TRUSTED_DELEGATOR*). + +Valid purposes are: *ALL*, *DIGITAL_SIGNATURE*, *NON_REPUDIATION*, +*KEY_ENCIPHERMENT*, *DATA_ENCIPHERMENT*, *KEY_AGREEMENT*, *KEY_CERT_SIGN*, +*CRL_SIGN*, *SERVER_AUTH* (default), *CLIENT_AUTH*, *CODE_SIGNING*, +*EMAIL_PROTECTION*, *IPSEC_END_SYSTEM*, *IPSEC_TUNNEL*, *IPSEC_USER*, +*TIME_STAMPING*, *STEP_UP_APPROVED* + +Valid trust levels are: *ALL*, *TRUSTED_DELEGATOR* (default), *NOT_TRUSTED*, +*MUST_VERIFY_TRUST*, *TRUSTED* + +## -q + +be really quiet (no progress output at all) + +## -t + +include plain text listing of certificates + +## -s [algorithms] + +comma separated list of signature algorithms with which to hash/fingerprint +each certificate and output when run in plain text mode. + +Valid algorithms are: +ALL, NONE, MD5 (default), SHA1, SHA256, SHA384, SHA512 + +## -u + +unlink (remove) *certdata.txt* after processing + +## -v + +be verbose and print out processed certificate authorities + +# EXIT STATUS + +Returns 0 on success. Returns 1 if it fails to download data. + +# FILE FORMAT + +The file format used by Mozilla for this trust information is documented here: +~~~c +https://p11-glue.freedesktop.org/doc/storing-trust-policy/storing-trust-existing.html +~~~ diff --git a/docs/options-in-versions b/docs/options-in-versions new file mode 100644 index 0000000..0905809 --- /dev/null +++ b/docs/options-in-versions @@ -0,0 +1,270 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + | (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + + This document lists all command line options present in curl, together with + exact information about the first curl version that supports it. The options + are sorted alphabetically on the long name. + + Long (short) Introduced + +--abstract-unix-socket 7.53.0 +--alt-svc 7.64.1 +--anyauth 7.10.6 +--append (-a) 4.8 +--aws-sigv4 7.75.0 +--basic 7.10.6 +--ca-native 8.2.0 +--cacert 7.5 +--capath 7.9.8 +--cert (-E) 5.0 +--cert-status 7.41.0 +--cert-type 7.9.3 +--ciphers 7.9 +--compressed 7.10 +--compressed-ssh 7.56.0 +--config (-K) 4.10 +--connect-timeout 7.7 +--connect-to 7.49.0 +--continue-at (-C) 4.8 +--cookie (-b) 4.9 +--cookie-jar (-c) 7.9 +--create-dirs 7.10.3 +--create-file-mode 7.75.0 +--crlf 5.7 +--crlfile 7.19.7 +--curves 7.73.0 +--data (-d) 4.0 +--data-ascii 7.2 +--data-binary 7.2 +--data-raw 7.43.0 +--data-urlencode 7.18.0 +--delegation 7.22.0 +--digest 7.10.6 +--disable (-q) 5.0 +--disable-eprt 7.10.5 +--disable-epsv 7.9.2 +--disallow-username-in-url 7.61.0 +--dns-interface 7.33.0 +--dns-ipv4-addr 7.33.0 +--dns-ipv6-addr 7.33.0 +--dns-servers 7.33.0 +--doh-cert-status 7.76.0 +--doh-insecure 7.76.0 +--doh-url 7.62.0 +--dump-header (-D) 5.7 +--egd-file 7.7 +--engine 7.9.3 +--etag-compare 7.68.0 +--etag-save 7.68.0 +--expect100-timeout 7.47.0 +--fail (-f) 4.0 +--fail-early 7.52.0 +--fail-with-body 7.76.0 +--false-start 7.42.0 +--form (-F) 5.0 +--form-escape 7.81.0 +--form-string 7.13.2 +--ftp-account 7.13.0 +--ftp-alternative-to-user 7.15.5 +--ftp-create-dirs 7.10.7 +--ftp-method 7.15.1 +--ftp-pasv 7.11.0 +--ftp-port (-P) 4.0 +--ftp-pret 7.20.0 +--ftp-skip-pasv-ip 7.14.2 +--ftp-ssl-ccc 7.16.1 +--ftp-ssl-ccc-mode 7.16.2 +--ftp-ssl-control 7.16.0 +--get (-G) 7.8.1 +--globoff (-g) 7.6 +--happy-eyeballs-timeout-ms 7.59.0 +--haproxy-protocol 7.60.0 +--haproxy-clientip 8.2.0 +--head (-I) 4.0 +--header (-H) 5.0 +--help (-h) 4.0 +--hostpubmd5 7.17.1 +--hostpubsha256 7.80.0 +--hsts 7.74.0 +--http0.9 7.64.0 +--http1.0 (-0) 7.9.1 +--http1.1 7.33.0 +--http2 7.33.0 +--http2-prior-knowledge 7.49.0 +--http3 7.66.0 +--http3-only 7.88.0 +--ignore-content-length 7.14.1 +--ipfs-gateway 8.4.0 +--include (-i) 4.8 +--insecure (-k) 7.10 +--interface 7.3 +--ipv4 (-4) 7.10.8 +--ipv6 (-6) 7.10.8 +--json 7.82.0 +--junk-session-cookies (-j) 7.9.7 +--keepalive-time 7.18.0 +--key 7.9.3 +--key-type 7.9.3 +--krb 7.3 +--libcurl 7.16.1 +--limit-rate 7.10 +--list-only (-l) 4.0 +--local-port 7.15.2 +--location (-L) 4.9 +--location-trusted 7.10.4 +--login-options 7.34.0 +--mail-auth 7.25.0 +--mail-from 7.20.0 +--mail-rcpt 7.20.0 +--mail-rcpt-allowfails 7.69.0 +--manual (-M) 5.2 +--max-filesize 7.10.8 +--max-redirs 7.5 +--max-time (-m) 4.0 +--metalink 7.27.0 +--negotiate 7.10.6 +--netrc (-n) 4.6 +--netrc-file 7.21.5 +--netrc-optional 7.9.8 +--next (-:) 7.36.0 +--no-alpn 7.36.0 +--no-buffer (-N) 6.5 +--no-clobber 7.83.0 +--no-keepalive 7.18.0 +--no-npn 7.36.0 +--no-progress-meter 7.67.0 +--no-sessionid 7.16.0 +--noproxy 7.19.4 +--ntlm 7.10.6 +--ntlm-wb 7.22.0 +--oauth2-bearer 7.33.0 +--output (-o) 4.0 +--output-dir 7.73.0 +--parallel (-Z) 7.66.0 +--parallel-immediate 7.68.0 +--parallel-max 7.66.0 +--pass 7.9.3 +--path-as-is 7.42.0 +--pinnedpubkey 7.39.0 +--post301 7.17.1 +--post302 7.19.1 +--post303 7.26.0 +--preproxy 7.52.0 +--progress-bar (-#) 5.10 +--proto 7.20.2 +--proto-default 7.45.0 +--proto-redir 7.20.2 +--proxy (-x) 4.0 +--proxy-anyauth 7.13.2 +--proxy-basic 7.12.0 +--proxy-ca-native 8.2.0 +--proxy-cacert 7.52.0 +--proxy-capath 7.52.0 +--proxy-cert 7.52.0 +--proxy-cert-type 7.52.0 +--proxy-ciphers 7.52.0 +--proxy-crlfile 7.52.0 +--proxy-digest 7.12.0 +--proxy-header 7.37.0 +--proxy-http2 8.1.0 +--proxy-insecure 7.52.0 +--proxy-key 7.52.0 +--proxy-key-type 7.52.0 +--proxy-negotiate 7.17.1 +--proxy-ntlm 7.10.7 +--proxy-pass 7.52.0 +--proxy-pinnedpubkey 7.59.0 +--proxy-service-name 7.43.0 +--proxy-ssl-allow-beast 7.52.0 +--proxy-ssl-auto-client-cert 7.77.0 +--proxy-tls13-ciphers 7.61.0 +--proxy-tlsauthtype 7.52.0 +--proxy-tlspassword 7.52.0 +--proxy-tlsuser 7.52.0 +--proxy-tlsv1 7.52.0 +--proxy-user (-U) 4.0 +--proxy1.0 7.19.4 +--proxytunnel (-p) 7.3 +--pubkey 7.16.2 +--quote (-Q) 5.3 +--random-file 7.7 +--range (-r) 4.0 +--rate 7.84.0 +--raw 7.16.2 +--referer (-e) 4.0 +--remote-header-name (-J) 7.20.0 +--remote-name (-O) 4.0 +--remote-name-all 7.19.0 +--remote-time (-R) 7.9 +--remove-on-error 7.83.0 +--request (-X) 6.0 +--request-target 7.55.0 +--resolve 7.21.3 +--retry 7.12.3 +--retry-all-errors 7.71.0 +--retry-connrefused 7.52.0 +--retry-delay 7.12.3 +--retry-max-time 7.12.3 +--sasl-authzid 7.66.0 +--sasl-ir 7.31.0 +--service-name 7.43.0 +--show-error (-S) 5.9 +--silent (-s) 4.0 +--socks4 7.15.2 +--socks4a 7.18.0 +--socks5 7.18.0 +--socks5-basic 7.55.0 +--socks5-gssapi 7.55.0 +--socks5-gssapi-nec 7.19.4 +--socks5-gssapi-service 7.19.4 +--socks5-hostname 7.18.0 +--speed-limit (-Y) 4.7 +--speed-time (-y) 4.7 +--ssl 7.20.0 +--ssl-allow-beast 7.25.0 +--ssl-auto-client-cert 7.77.0 +--ssl-no-revoke 7.44.0 +--ssl-reqd 7.20.0 +--ssl-revoke-best-effort 7.70.0 +--sslv2 (-2) 5.9 +--sslv3 (-3) 5.9 +--stderr 6.2 +--styled-output 7.61.0 +--suppress-connect-headers 7.54.0 +--tcp-fastopen 7.49.0 +--tcp-nodelay 7.11.2 +--telnet-option (-t) 7.7 +--tftp-blksize 7.20.0 +--tftp-no-options 7.48.0 +--time-cond (-z) 5.8 +--tls-max 7.54.0 +--tls13-ciphers 7.61.0 +--tlsauthtype 7.21.4 +--tlspassword 7.21.4 +--tlsuser 7.21.4 +--tlsv1 (-1) 7.9.2 +--tlsv1.0 7.34.0 +--tlsv1.1 7.34.0 +--tlsv1.2 7.34.0 +--tlsv1.3 7.52.0 +--tr-encoding 7.21.6 +--trace 7.9.7 +--trace-ascii 7.9.7 +--trace-config 8.3.0 +--trace-ids 8.2.0 +--trace-time 7.14.0 +--unix-socket 7.40.0 +--upload-file (-T) 4.0 +--url 7.5 +--url-query 7.87.0 +--use-ascii (-B) 5.0 +--user (-u) 4.0 +--user-agent (-A) 4.5.1 +--variable 8.3.0 +--verbose (-v) 4.0 +--version (-V) 4.0 +--write-out (-w) 6.5 +--xattr 7.21.3 diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..d65bfea --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,28 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +SUBDIRS = curl + +EXTRA_DIST = README.md + +AUTOMAKE_OPTIONS = foreign no-dependencies diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100644 index 0000000..12810e3 --- /dev/null +++ b/include/Makefile.in @@ -0,0 +1,775 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = include +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +depcomp = +am__maybe_remake_depfiles = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in README.md +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +SUBDIRS = curl +EXTRA_DIST = README.md +AUTOMAKE_OPTIONS = foreign no-dependencies +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/include/README.md b/include/README.md new file mode 100644 index 0000000..c965932 --- /dev/null +++ b/include/README.md @@ -0,0 +1,20 @@ + + +# include + +Public include files for libcurl, external users. + +They're all placed in the curl subdirectory here for better fit in any kind of +environment. You must include files from here using... + + #include + +... style and point the compiler's include path to the directory holding the +curl subdirectory. It makes it more likely to survive future modifications. + +The public curl include files can be shared freely between different platforms +and different architectures. diff --git a/include/curl/Makefile.am b/include/curl/Makefile.am new file mode 100644 index 0000000..a655aff --- /dev/null +++ b/include/curl/Makefile.am @@ -0,0 +1,41 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +pkginclude_HEADERS = \ + curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \ + typecheck-gcc.h system.h urlapi.h options.h header.h websockets.h + +pkgincludedir= $(includedir)/curl + +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) + +checksrc: + $(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS) + +if CURLDEBUG +# for debug builds, we scan the sources on all regular make invokes +all-local: checksrc +endif diff --git a/include/curl/Makefile.in b/include/curl/Makefile.in new file mode 100644 index 0000000..7aac1c7 --- /dev/null +++ b/include/curl/Makefile.in @@ -0,0 +1,726 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = include/curl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(pkginclude_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +HEADERS = $(pkginclude_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgincludedir = $(includedir)/curl +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +pkginclude_HEADERS = \ + curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \ + typecheck-gcc.h system.h urlapi.h options.h header.h websockets.h + +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/curl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/curl/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +@CURLDEBUG_FALSE@all-local: +all-am: Makefile $(HEADERS) all-local +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkgincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + distclean distclean-generic distclean-libtool distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkgincludeHEADERS \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-pkgincludeHEADERS + +.PRECIOUS: Makefile + + +checksrc: + $(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS) + +# for debug builds, we scan the sources on all regular make invokes +@CURLDEBUG_TRUE@all-local: checksrc + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/include/curl/curl.h b/include/curl/curl.h new file mode 100644 index 0000000..eb06022 --- /dev/null +++ b/include/curl/curl.h @@ -0,0 +1,3239 @@ +#ifndef CURLINC_CURL_H +#define CURLINC_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.se/libcurl/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +/* Compile-time deprecation macros. */ +#if defined(__GNUC__) && \ + ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) && \ + !defined(__INTEL_COMPILER) && \ + !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL) +#define CURL_DEPRECATED(version, message) \ + __attribute__((deprecated("since " # version ". " message))) +#define CURL_IGNORE_DEPRECATION(statements) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + statements \ + _Pragma("GCC diagnostic pop") +#else +#define CURL_DEPRECATED(version, message) +#define CURL_IGNORE_DEPRECATION(statements) statements +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "system.h" /* determine things run-time */ + +#include +#include + +#if defined(__FreeBSD__) || defined(__MidnightBSD__) +/* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \ + (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \ + defined(__sun__) || defined(__serenity__) || defined(__vxworks__) +#include +#endif + +#if !defined(_WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(_WIN32) +#include +#endif + +/* Compatibility for non-Clang compilers */ +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(x) 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(_WIN32) || \ + (__has_declspec_attribute(dllexport) && \ + __has_declspec_attribute(dllimport)) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS CURL_DEPRECATED(8.3.0, "") = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT CURL_DEPRECATED(8.3.0, "") = 5, + CURLSSLBACKEND_POLARSSL CURL_DEPRECATED(7.69.0, "") = 6, + CURLSSLBACKEND_WOLFSSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_SECURETRANSPORT = 9, + CURLSSLBACKEND_AXTLS CURL_DEPRECATED(7.61.0, "") = 10, + CURLSSLBACKEND_MBEDTLS = 11, + CURLSSLBACKEND_MESALINK CURL_DEPRECATED(7.82.0, "") = 12, + CURLSSLBACKEND_BEARSSL = 13, + CURLSSLBACKEND_RUSTLS = 14 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_AWSLC CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL + +/* deprecated names: */ +#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL +#define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + + +/* This is a return code for the progress callback that, when returned, will + signal libcurl to continue executing the default progress function */ +#define CURL_PROGRESSFUNC_CONTINUE 0x10000001 + +/* This is the CURLOPT_PROGRESSFUNCTION callback prototype. It is now + considered deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback prototype. It was introduced + in 7.32.0, avoids the use of floating point numbers and provides more + detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_READ_SIZE + /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ +#define CURL_MAX_READ_SIZE (10*1024*1024) +#endif + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +/* This is a magic return code for the write callback that, when returned, + will signal an error from the callback. */ +#define CURL_WRITEFUNC_ERROR 0xFFFFFFFF + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + +/* This callback will be called when a new resolver request is made */ +typedef int (*curl_resolver_start_callback)(void *resolver_state, + void *reserved, void *userdata); + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Information about a single file, used when doing FTP wildcard matching */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; /* always zero! */ + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* These are libcurl private struct fields. Previously used by libcurl, so + they must never be interfered with. */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +/* Return code for when the trailing headers' callback has terminated + without any errors */ +#define CURL_TRAILERFUNC_OK 0 +/* Return code for when was an error in the trailing header's list and we + want to abort the request */ +#define CURL_TRAILERFUNC_ABORT 1 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef int (*curl_trailer_callback)(struct curl_slist **list, + void *userdata); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback */ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* This is the CURLOPT_PREREQFUNCTION callback prototype. */ +typedef int (*curl_prereq_callback)(void *clientp, + char *conn_primary_ip, + char *conn_local_ip, + int conn_primary_port, + int conn_local_port); + +/* Return code for when the pre-request callback has terminated without + any errors */ +#define CURL_PREREQFUNC_OK 0 +/* Return code for when the pre-request callback wants to abort the + request */ +#define CURL_PREREQFUNC_ABORT 1 + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_SETOPT_OPTION_SYNTAX, /* 49 - Malformed setopt option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_OBSOLETE51, /* 51 - NOT USED */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_OBSOLETE62, /* 62 - NOT IN USE since 7.82.0 */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_OBSOLETE75, /* 75 - NOT IN USE since 7.82.0 */ + CURLE_OBSOLETE76, /* 76 - NOT IN USE since 7.82.0 */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from + inside a callback */ + CURLE_AUTH_ERROR, /* 94 - an authentication function returned an + error */ + CURLE_HTTP3, /* 95 - An HTTP/3 layer problem */ + CURLE_QUIC_CONNECT_ERROR, /* 96 - QUIC connection error */ + CURLE_PROXY, /* 97 - proxy handshake error */ + CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */ + CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */ + CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code reused in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes reused in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY + +/* The following were added in 7.62.0 */ +#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* Added for 7.78.0 */ +#define CURLE_TELNET_OPTION_SYNTAX CURLE_SETOPT_OPTION_SYNTAX + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME +#define CURLE_LDAP_INVALID_URL CURLE_OBSOLETE62 +#define CURLE_CONV_REQD CURLE_OBSOLETE76 +#define CURLE_CONV_FAILED CURLE_OBSOLETE75 + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /* !CURL_NO_OLDIES */ + +/* + * Proxy error codes. Returned in CURLINFO_PROXY_ERROR if CURLE_PROXY was + * return for the transfers. + */ +typedef enum { + CURLPX_OK, + CURLPX_BAD_ADDRESS_TYPE, + CURLPX_BAD_VERSION, + CURLPX_CLOSED, + CURLPX_GSSAPI, + CURLPX_GSSAPI_PERMSG, + CURLPX_GSSAPI_PROTECTION, + CURLPX_IDENTD, + CURLPX_IDENTD_DIFFER, + CURLPX_LONG_HOSTNAME, + CURLPX_LONG_PASSWD, + CURLPX_LONG_USER, + CURLPX_NO_AUTH, + CURLPX_RECV_ADDRESS, + CURLPX_RECV_AUTH, + CURLPX_RECV_CONNECT, + CURLPX_RECV_REQACK, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_UNASSIGNED, + CURLPX_REQUEST_FAILED, + CURLPX_RESOLVE_HOST, + CURLPX_SEND_AUTH, + CURLPX_SEND_CONNECT, + CURLPX_SEND_REQUEST, + CURLPX_UNKNOWN_FAIL, + CURLPX_UNKNOWN_MODE, + CURLPX_USER_REJECTED, + CURLPX_LAST /* never use */ +} CURLproxycode; + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an OpenSSL + or WolfSSL SSL_CTX, + or an mbedTLS + mbedtls_ssl_config */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* HTTPS but stick to HTTP/1 added in 7.52.0 */ + CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_BEARER - HTTP Bearer token authentication + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ +#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_BEARER (((unsigned long)1)<<6) +#define CURLAUTH_AWS_SIGV4 (((unsigned long)1)<<7) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS, + CURLKHTYPE_ECDSA, + CURLKHTYPE_ED25519 +}; + +struct curl_khkey { + const char *key; /* points to a null-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now. + Causes a CURLE_PEER_FAILED_VERIFICATION error but the + connection will be left intact etc */ + CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed with */ + /* CURLOPT_SSH_KEYDATA */ + +typedef int + (*curl_sshhostkeycallback) (void *clientp,/* custom pointer passed */ + /* with CURLOPT_SSH_HOSTKEYDATA */ + int keytype, /* CURLKHTYPE */ + const char *key, /* hostkey to check */ + size_t keylen); /* length of the key */ + /* return CURLE_OK to accept */ + /* or something else to refuse */ + + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +/* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain + if possible. The OpenSSL backend has this ability. */ +#define CURLSSLOPT_NO_PARTIALCHAIN (1<<2) + +/* - REVOKE_BEST_EFFORT tells libcurl to ignore certificate revocation offline + checks and ignore missing revocation list for those SSL backends where such + behavior is present. */ +#define CURLSSLOPT_REVOKE_BEST_EFFORT (1<<3) + +/* - CURLSSLOPT_NATIVE_CA tells libcurl to use standard certificate store of + operating system. Currently implemented under MS-Windows. */ +#define CURLSSLOPT_NATIVE_CA (1<<4) + +/* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use + a client certificate for authentication. (Schannel) */ +#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5) + +/* The default connection attempt delay in milliseconds for happy eyeballs. + CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document + this value, keep them in sync. */ +#define CURL_HET_DEFAULT 200L + +/* The default connection upkeep interval in milliseconds. */ +#define CURL_UPKEEP_INTERVAL_DEFAULT 60000L + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /* !CURL_NO_OLDIES */ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */ +#define CURLALTSVC_READONLYFILE (1<<2) +#define CURLALTSVC_H1 (1<<3) +#define CURLALTSVC_H2 (1<<4) +#define CURLALTSVC_H3 (1<<5) + + +struct curl_hstsentry { + char *name; + size_t namelen; + unsigned int includeSubDomains:1; + char expire[18]; /* YYYYMMDD HH:MM:SS [null-terminated] */ +}; + +struct curl_index { + size_t index; /* the provided entry's "index" or count */ + size_t total; /* total number of entries to save */ +}; + +typedef enum { + CURLSTS_OK, + CURLSTS_DONE, + CURLSTS_FAIL +} CURLSTScode; + +typedef CURLSTScode (*curl_hstsread_callback)(CURL *easy, + struct curl_hstsentry *e, + void *userp); +typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy, + struct curl_hstsentry *e, + struct curl_index *i, + void *userp); + +/* CURLHSTS_* are bits for the CURLOPT_HSTS option */ +#define CURLHSTS_ENABLE (long)(1<<0) +#define CURLHSTS_READONLYFILE (long)(1<<1) + +/* The CURLPROTO_ defines below are for the **deprecated** CURLOPT_*PROTOCOLS + options. Do not use. */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_MQTT (1<<28) +#define CURLPROTO_GOPHERS (1<<29) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 +#define CURLOPTTYPE_BLOB 40000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + + +#define CURLOPT(na,t,nu) na = t + nu +#define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu + +/* CURLOPT aliases that make no run-time difference */ + +/* 'char *' argument to a string with a trailing zero */ +#define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT + +/* 'struct curl_slist *' argument */ +#define CURLOPTTYPE_SLISTPOINT CURLOPTTYPE_OBJECTPOINT + +/* 'void *' argument passed untouched to callback */ +#define CURLOPTTYPE_CBPOINT CURLOPTTYPE_OBJECTPOINT + +/* 'long' argument with a set of values/bitmask */ +#define CURLOPTTYPE_VALUES CURLOPTTYPE_LONG + +/* + * All CURLOPT_* values. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_CBPOINT, 1), + + /* The full URL to get/put */ + CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CURLOPT(CURLOPT_PORT, CURLOPTTYPE_LONG, 3), + + /* Name of proxy to use. */ + CURLOPT(CURLOPT_PROXY, CURLOPTTYPE_STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CURLOPT(CURLOPT_USERPWD, CURLOPTTYPE_STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CURLOPT(CURLOPT_PROXYUSERPWD, CURLOPTTYPE_STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CURLOPT(CURLOPT_RANGE, CURLOPTTYPE_STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_CBPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. */ + CURLOPT(CURLOPT_ERRORBUFFER, CURLOPTTYPE_OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CURLOPT(CURLOPT_WRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CURLOPT(CURLOPT_READFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13), + + /* If CURLOPT_READDATA is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14), + + /* POST static input fields. */ + CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CURLOPT(CURLOPT_REFERER, CURLOPTTYPE_STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CURLOPT(CURLOPT_FTPPORT, CURLOPTTYPE_STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CURLOPT(CURLOPT_USERAGENT, CURLOPTTYPE_STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CURLOPT(CURLOPT_LOW_SPEED_LIMIT, CURLOPTTYPE_LONG, 19), + + /* Set the "low speed time" */ + CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21), + + /* Set cookie in request: */ + CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CURLOPTDEPRECATED(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24, + 7.56.0, "Use CURLOPT_MIMEPOST"), + + /* name of the file keeping your private SSL-certificate */ + CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CURLOPT(CURLOPT_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 26), + + /* send TYPE parameter? */ + CURLOPT(CURLOPT_CRLF, CURLOPTTYPE_LONG, 27), + + /* send linked-list of QUOTE commands */ + CURLOPT(CURLOPT_QUOTE, CURLOPTTYPE_SLISTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_CBPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CURLOPT(CURLOPT_COOKIEFILE, CURLOPTTYPE_STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_VALUES, 32), + + /* What kind of HTTP time condition to use, see defines */ + CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_VALUES, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CURLOPT(CURLOPT_TIMEVALUE, CURLOPTTYPE_LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CURLOPT(CURLOPT_CUSTOMREQUEST, CURLOPTTYPE_STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CURLOPT(CURLOPT_STDERR, CURLOPTTYPE_OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39), + + /* OBSOLETE, do not use! */ + CURLOPT(CURLOPT_OBSOLETE40, CURLOPTTYPE_OBJECTPOINT, 40), + + /* talk a lot */ + CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41), + + /* throw the header out too */ + CURLOPT(CURLOPT_HEADER, CURLOPTTYPE_LONG, 42), + + /* shut off the progress meter */ + CURLOPT(CURLOPT_NOPROGRESS, CURLOPTTYPE_LONG, 43), + + /* use HEAD to get http document */ + CURLOPT(CURLOPT_NOBODY, CURLOPTTYPE_LONG, 44), + + /* no output on http error codes >= 400 */ + CURLOPT(CURLOPT_FAILONERROR, CURLOPTTYPE_LONG, 45), + + /* this is an upload */ + CURLOPT(CURLOPT_UPLOAD, CURLOPTTYPE_LONG, 46), + + /* HTTP POST method */ + CURLOPT(CURLOPT_POST, CURLOPTTYPE_LONG, 47), + + /* bare names when listing directories */ + CURLOPT(CURLOPT_DIRLISTONLY, CURLOPTTYPE_LONG, 48), + + /* Append instead of overwrite on upload! */ + CURLOPT(CURLOPT_APPEND, CURLOPTTYPE_LONG, 50), + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_VALUES, 51), + + /* use Location: Luke! */ + CURLOPT(CURLOPT_FOLLOWLOCATION, CURLOPTTYPE_LONG, 52), + + /* transfer data in text/ASCII format */ + CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53), + + /* HTTP PUT */ + CURLOPTDEPRECATED(CURLOPT_PUT, CURLOPTTYPE_LONG, 54, + 7.12.1, "Use CURLOPT_UPLOAD"), + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CURLOPTDEPRECATED(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56, + 7.32.0, "Use CURLOPT_XFERINFOFUNCTION"), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CURLOPT(CURLOPT_XFERINFODATA, CURLOPTTYPE_CBPOINT, 57), +#define CURLOPT_PROGRESSDATA CURLOPT_XFERINFODATA + + /* We want the referrer field set automatically when following locations */ + CURLOPT(CURLOPT_AUTOREFERER, CURLOPTTYPE_LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CURLOPT(CURLOPT_PROXYPORT, CURLOPTTYPE_LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60), + + /* tunnel non-http operations through an HTTP proxy */ + CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_CAINFO, CURLOPTTYPE_STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CURLOPT(CURLOPT_MAXREDIRS, CURLOPTTYPE_LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CURLOPT(CURLOPT_FILETIME, CURLOPTTYPE_LONG, 69), + + /* This points to a linked list of telnet options */ + CURLOPT(CURLOPT_TELNETOPTIONS, CURLOPTTYPE_SLISTPOINT, 70), + + /* Max amount of cached alive connections */ + CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71), + + /* OBSOLETE, do not use! */ + CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72), + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be reused + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76, + 7.84.0, "Serves no purpose anymore"), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CURLOPTDEPRECATED(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77, + 7.84.0, "Serves no purpose anymore"), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CURLOPT(CURLOPT_CONNECTTIMEOUT, CURLOPTTYPE_LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CURLOPT(CURLOPT_HEADERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_VALUES, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CURLOPT(CURLOPT_FTP_USE_EPSV, CURLOPTTYPE_LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CURLOPT(CURLOPT_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CURLOPT(CURLOPT_SSLKEY, CURLOPTTYPE_STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CURLOPT(CURLOPT_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CURLOPT(CURLOPT_SSLENGINE, CURLOPTTYPE_STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CURLOPT(CURLOPT_SSLENGINE_DEFAULT, CURLOPTTYPE_LONG, 90), + + /* Non-zero value means to use the global dns cache */ + /* DEPRECATED, do not use! */ + CURLOPTDEPRECATED(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91, + 7.11.1, "Use CURLOPT_SHARE"), + + /* DNS cache timeout */ + CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CURLOPT(CURLOPT_PREQUOTE, CURLOPTTYPE_SLISTPOINT, 93), + + /* set the debug function */ + CURLOPT(CURLOPT_DEBUGFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_CBPOINT, 95), + + /* mark this as start of a cookie session */ + CURLOPT(CURLOPT_COOKIESESSION, CURLOPTTYPE_LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_CAPATH, CURLOPTTYPE_STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CURLOPT(CURLOPT_BUFFERSIZE, CURLOPTTYPE_LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CURLOPT(CURLOPT_NOSIGNAL, CURLOPTTYPE_LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CURLOPT(CURLOPT_SHARE, CURLOPTTYPE_OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ + CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_VALUES, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CURLOPT(CURLOPT_ACCEPT_ENCODING, CURLOPTTYPE_STRINGPOINT, 102), + + /* Set pointer to private data */ + CURLOPT(CURLOPT_PRIVATE, CURLOPTTYPE_OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CURLOPT(CURLOPT_HTTP200ALIASES, CURLOPTTYPE_SLISTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CURLOPT(CURLOPT_UNRESTRICTED_AUTH, CURLOPTTYPE_LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CURLOPT(CURLOPT_FTP_USE_EPRT, CURLOPTTYPE_LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107), + + /* Set the ssl context callback function, currently only for OpenSSL or + WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument. + The function must match the curl_ssl_ctx_callback prototype. */ + CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_CBPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111), + + /* Option that changes the timeout, in seconds, associated with getting a + response. This is different from transfer timeout time and essentially + places a demand on the server to acknowledge commands in a timely + manner. For FTP, SMTP, IMAP and POP3. */ + CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112), + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to use those IP versions only. This only has effect on + systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115), + + /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version + * of this; look above for RESUME_FROM. + */ + CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_VALUES, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CURLOPT(CURLOPT_POSTFIELDSIZE_LARGE, CURLOPTTYPE_OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CURLOPT(CURLOPT_TCP_NODELAY, CURLOPTTYPE_LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_VALUES, 129), + + CURLOPTDEPRECATED(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130, + 7.18.0, "Use CURLOPT_SEEKFUNCTION"), + CURLOPTDEPRECATED(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131, + 7.18.0, "Use CURLOPT_SEEKDATA"), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* null-terminated string for pass on to the FTP server when asked for + "account" info */ + CURLOPT(CURLOPT_FTP_ACCOUNT, CURLOPTTYPE_STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CURLOPT(CURLOPT_COOKIELIST, CURLOPTTYPE_STRINGPOINT, 135), + + /* ignore Content-Length */ + CURLOPT(CURLOPT_IGNORE_CONTENT_LENGTH, CURLOPTTYPE_LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CURLOPT(CURLOPT_FTP_SKIP_PASV_IP, CURLOPTTYPE_LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_VALUES, 138), + + /* Local port number to bind the socket to */ + CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CURLOPT(CURLOPT_LOCALPORTRANGE, CURLOPTTYPE_LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CURLOPT(CURLOPT_CONNECT_ONLY, CURLOPTTYPE_LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CURLOPTDEPRECATED(CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPTTYPE_FUNCTIONPOINT, 142, + 7.82.0, "Serves no purpose anymore"), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CURLOPTDEPRECATED(CURLOPT_CONV_TO_NETWORK_FUNCTION, + CURLOPTTYPE_FUNCTIONPOINT, 143, + 7.82.0, "Serves no purpose anymore"), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CURLOPTDEPRECATED(CURLOPT_CONV_FROM_UTF8_FUNCTION, + CURLOPTTYPE_FUNCTIONPOINT, 144, + 7.82.0, "Serves no purpose anymore"), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CURLOPT(CURLOPT_MAX_SEND_SPEED_LARGE, CURLOPTTYPE_OFF_T, 145), + CURLOPT(CURLOPT_MAX_RECV_SPEED_LARGE, CURLOPTTYPE_OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CURLOPT(CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPTTYPE_STRINGPOINT, 147), + + /* callback function for setting socket options */ + CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148), + CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_CBPOINT, 149), + + /* set to 0 to disable session ID reuse for this transfer, default is + enabled (== 1) */ + CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150), + + /* allowed SSH authentication methods */ + CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_VALUES, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CURLOPT(CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPTTYPE_STRINGPOINT, 152), + CURLOPT(CURLOPT_SSH_PRIVATE_KEYFILE, CURLOPTTYPE_STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CURLOPT(CURLOPT_FTP_SSL_CCC, CURLOPTTYPE_LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CURLOPT(CURLOPT_TIMEOUT_MS, CURLOPTTYPE_LONG, 155), + CURLOPT(CURLOPT_CONNECTTIMEOUT_MS, CURLOPTTYPE_LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CURLOPT(CURLOPT_HTTP_TRANSFER_DECODING, CURLOPTTYPE_LONG, 157), + CURLOPT(CURLOPT_HTTP_CONTENT_DECODING, CURLOPTTYPE_LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159), + CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160), + + /* Set the behavior of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161), + + /* used by scp/sftp to verify the host's public key */ + CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163), + CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164), + + /* POST volatile input fields. */ + CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CURLOPT(CURLOPT_PROXY_TRANSFER_MODE, CURLOPTTYPE_LONG, 166), + + /* Callback function for seeking in the input stream */ + CURLOPT(CURLOPT_SEEKFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 167), + CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_CBPOINT, 168), + + /* CRL file */ + CURLOPT(CURLOPT_CRLFILE, CURLOPTTYPE_STRINGPOINT, 169), + + /* Issuer certificate */ + CURLOPT(CURLOPT_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CURLOPT(CURLOPT_ADDRESS_SCOPE, CURLOPTTYPE_LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CURLOPT(CURLOPT_CERTINFO, CURLOPTTYPE_LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CURLOPT(CURLOPT_USERNAME, CURLOPTTYPE_STRINGPOINT, 173), + CURLOPT(CURLOPT_PASSWORD, CURLOPTTYPE_STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CURLOPT(CURLOPT_PROXYUSERNAME, CURLOPTTYPE_STRINGPOINT, 175), + CURLOPT(CURLOPT_PROXYPASSWORD, CURLOPTTYPE_STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CURLOPT(CURLOPT_NOPROXY, CURLOPTTYPE_STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CURLOPT(CURLOPT_TFTP_BLKSIZE, CURLOPTTYPE_LONG, 178), + + /* Socks Service */ + /* DEPRECATED, do not use! */ + CURLOPTDEPRECATED(CURLOPT_SOCKS5_GSSAPI_SERVICE, + CURLOPTTYPE_STRINGPOINT, 179, + 7.49.0, "Use CURLOPT_PROXY_SERVICE_NAME"), + + /* Socks Service */ + CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CURLOPTDEPRECATED(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181, + 7.85.0, "Use CURLOPT_PROTOCOLS_STR"), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. */ + CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182, + 7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"), + + /* set the SSH knownhost file name to use */ + CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_CBPOINT, 185), + + /* set the SMTP mail originator */ + CURLOPT(CURLOPT_MAIL_FROM, CURLOPTTYPE_STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CURLOPT(CURLOPT_MAIL_RCPT, CURLOPTTYPE_SLISTPOINT, 187), + + /* FTP: send PRET before PASV */ + CURLOPT(CURLOPT_FTP_USE_PRET, CURLOPTTYPE_LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_VALUES, 189), + + /* The RTSP session identifier */ + CURLOPT(CURLOPT_RTSP_SESSION_ID, CURLOPTTYPE_STRINGPOINT, 190), + + /* The RTSP stream URI */ + CURLOPT(CURLOPT_RTSP_STREAM_URI, CURLOPTTYPE_STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CURLOPT(CURLOPT_RTSP_TRANSPORT, CURLOPTTYPE_STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CURLOPT(CURLOPT_RTSP_CLIENT_CSEQ, CURLOPTTYPE_LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CURLOPT(CURLOPT_RTSP_SERVER_CSEQ, CURLOPTTYPE_LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_CBPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CURLOPT(CURLOPT_INTERLEAVEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CURLOPT(CURLOPT_WILDCARDMATCH, CURLOPTTYPE_LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CURLOPT(CURLOPT_CHUNK_BGN_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CURLOPT(CURLOPT_CHUNK_END_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CURLOPT(CURLOPT_FNMATCH_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_CBPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_CBPOINT, 202), + + /* send linked-list of name:port:address sets */ + CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203), + + /* Set a username for authenticated TLS */ + CURLOPT(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CURLOPT(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CURLOPT(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CURLOPT(CURLOPT_CLOSESOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 208), + CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_CBPOINT, 209), + + /* allow GSSAPI credential delegation */ + CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_VALUES, 210), + + /* Set the name servers to use for DNS resolution. + * Only supported by the c-ares DNS backend */ + CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of milliseconds. */ + CURLOPT(CURLOPT_ACCEPTTIMEOUT_MS, CURLOPTTYPE_LONG, 212), + + /* Set TCP keepalive */ + CURLOPT(CURLOPT_TCP_KEEPALIVE, CURLOPTTYPE_LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CURLOPT(CURLOPT_TCP_KEEPIDLE, CURLOPTTYPE_LONG, 214), + CURLOPT(CURLOPT_TCP_KEEPINTVL, CURLOPTTYPE_LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_VALUES, 216), + + /* Set the SMTP auth originator */ + CURLOPT(CURLOPT_MAIL_AUTH, CURLOPTTYPE_STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CURLOPT(CURLOPT_SASL_IR, CURLOPTTYPE_LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CURLOPT(CURLOPT_XFERINFOFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CURLOPT(CURLOPT_XOAUTH2_BEARER, CURLOPTTYPE_STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CURLOPT(CURLOPT_DNS_INTERFACE, CURLOPTTYPE_STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CURLOPT(CURLOPT_DNS_LOCAL_IP4, CURLOPTTYPE_STRINGPOINT, 222), + + /* Set the local IPv6 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CURLOPT(CURLOPT_DNS_LOCAL_IP6, CURLOPTTYPE_STRINGPOINT, 223), + + /* Set authentication options directly */ + CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CURLOPTDEPRECATED(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225, + 7.86.0, "Has no function"), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226), + + /* Time to wait for a response to an HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CURLOPT(CURLOPT_PROXYHEADER, CURLOPTTYPE_SLISTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_VALUES, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CURLOPT(CURLOPT_UNIX_SOCKET_PATH, CURLOPTTYPE_STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232), + + /* Set if we should enable TLS false start. */ + CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233), + + /* Do not squash dot-dot sequences */ + CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234), + + /* Proxy Service Name */ + CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235), + + /* Service Name */ + CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239), + + /* Set stream dependency on another CURL handle */ + CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CURLOPT(CURLOPT_CONNECT_TO, CURLOPTTYPE_SLISTPOINT, 243), + + /* Set TCP Fast Open */ + CURLOPT(CURLOPT_TCP_FASTOPEN, CURLOPTTYPE_LONG, 244), + + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CURLOPT(CURLOPT_KEEP_SENDING_ON_ERROR, CURLOPTTYPE_LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_PROXY_CAINFO, CURLOPTTYPE_STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_PROXY_CAPATH, CURLOPTTYPE_STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_VALUES, 250), + + /* Set a username for authenticated TLS for proxy */ + CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CURLOPT(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CURLOPT(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CURLOPT(CURLOPT_PROXY_SSLCERT, CURLOPTTYPE_STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CURLOPT(CURLOPT_PROXY_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CURLOPT(CURLOPT_PROXY_SSLKEY, CURLOPTTYPE_STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CURLOPT(CURLOPT_PROXY_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259), + + /* CRL file for proxy */ + CURLOPT(CURLOPT_PROXY_CRLFILE, CURLOPTTYPE_STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CURLOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLOPTTYPE_LONG, 261), + + /* Name of pre proxy to use. */ + CURLOPT(CURLOPT_PRE_PROXY, CURLOPTTYPE_STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 263), + + /* Path to an abstract Unix domain socket */ + CURLOPT(CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOPTTYPE_STRINGPOINT, 264), + + /* Suppress proxy CONNECT response headers from user callbacks */ + CURLOPT(CURLOPT_SUPPRESS_CONNECT_HEADERS, CURLOPTTYPE_LONG, 265), + + /* The request target, instead of extracted from the URL */ + CURLOPT(CURLOPT_REQUEST_TARGET, CURLOPTTYPE_STRINGPOINT, 266), + + /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ + CURLOPT(CURLOPT_SOCKS5_AUTH, CURLOPTTYPE_LONG, 267), + + /* Enable/disable SSH compression */ + CURLOPT(CURLOPT_SSH_COMPRESSION, CURLOPTTYPE_LONG, 268), + + /* Post MIME data. */ + CURLOPT(CURLOPT_MIMEPOST, CURLOPTTYPE_OBJECTPOINT, 269), + + /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of + seconds since 1 Jan 1970. */ + CURLOPT(CURLOPT_TIMEVALUE_LARGE, CURLOPTTYPE_OFF_T, 270), + + /* Head start in milliseconds to give happy eyeballs. */ + CURLOPT(CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOPTTYPE_LONG, 271), + + /* Function that will be called before a resolver request is made */ + CURLOPT(CURLOPT_RESOLVER_START_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 272), + + /* User data to pass to the resolver start callback. */ + CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_CBPOINT, 273), + + /* send HAProxy PROXY protocol header? */ + CURLOPT(CURLOPT_HAPROXYPROTOCOL, CURLOPTTYPE_LONG, 274), + + /* shuffle addresses before use when DNS returns multiple */ + CURLOPT(CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOPTTYPE_LONG, 275), + + /* Specify which TLS 1.3 ciphers suites to use */ + CURLOPT(CURLOPT_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 276), + CURLOPT(CURLOPT_PROXY_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 277), + + /* Disallow specifying username/login in URL. */ + CURLOPT(CURLOPT_DISALLOW_USERNAME_IN_URL, CURLOPTTYPE_LONG, 278), + + /* DNS-over-HTTPS URL */ + CURLOPT(CURLOPT_DOH_URL, CURLOPTTYPE_STRINGPOINT, 279), + + /* Preferred buffer size to use for uploads */ + CURLOPT(CURLOPT_UPLOAD_BUFFERSIZE, CURLOPTTYPE_LONG, 280), + + /* Time in ms between connection upkeep calls for long-lived connections. */ + CURLOPT(CURLOPT_UPKEEP_INTERVAL_MS, CURLOPTTYPE_LONG, 281), + + /* Specify URL using CURL URL API. */ + CURLOPT(CURLOPT_CURLU, CURLOPTTYPE_OBJECTPOINT, 282), + + /* add trailing data just after no more data is available */ + CURLOPT(CURLOPT_TRAILERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 283), + + /* pointer to be passed to HTTP_TRAILER_FUNCTION */ + CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_CBPOINT, 284), + + /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */ + CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285), + + /* alt-svc control bitmask */ + CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286), + + /* alt-svc cache file name to possibly read from/write to */ + CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287), + + /* maximum age (idle time) of a connection to consider it for reuse + * (in seconds) */ + CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288), + + /* SASL authorization identity */ + CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289), + + /* allow RCPT TO command to fail for some recipients */ + CURLOPT(CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOPTTYPE_LONG, 290), + + /* the private SSL-certificate as a "blob" */ + CURLOPT(CURLOPT_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 291), + CURLOPT(CURLOPT_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 292), + CURLOPT(CURLOPT_PROXY_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 293), + CURLOPT(CURLOPT_PROXY_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 294), + CURLOPT(CURLOPT_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 295), + + /* Issuer certificate for proxy */ + CURLOPT(CURLOPT_PROXY_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 296), + CURLOPT(CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 297), + + /* the EC curves requested by the TLS client (RFC 8422, 5.1); + * OpenSSL support via 'set_groups'/'set_curves': + * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html + */ + CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298), + + /* HSTS bitmask */ + CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299), + /* HSTS file name */ + CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300), + + /* HSTS read callback */ + CURLOPT(CURLOPT_HSTSREADFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 301), + CURLOPT(CURLOPT_HSTSREADDATA, CURLOPTTYPE_CBPOINT, 302), + + /* HSTS write callback */ + CURLOPT(CURLOPT_HSTSWRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 303), + CURLOPT(CURLOPT_HSTSWRITEDATA, CURLOPTTYPE_CBPOINT, 304), + + /* Parameters for V4 signature */ + CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305), + + /* Same as CURLOPT_SSL_VERIFYPEER but for DoH (DNS-over-HTTPS) servers. */ + CURLOPT(CURLOPT_DOH_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 306), + + /* Same as CURLOPT_SSL_VERIFYHOST but for DoH (DNS-over-HTTPS) servers. */ + CURLOPT(CURLOPT_DOH_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 307), + + /* Same as CURLOPT_SSL_VERIFYSTATUS but for DoH (DNS-over-HTTPS) servers. */ + CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308), + + /* The CA certificates as "blob" used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309), + + /* The CA certificates as "blob" used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310), + + /* used by scp/sftp to verify the host's public key */ + CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311), + + /* Function that will be called immediately before the initial request + is made on a connection (after any protocol negotiation step). */ + CURLOPT(CURLOPT_PREREQFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 312), + + /* Data passed to the CURLOPT_PREREQFUNCTION callback */ + CURLOPT(CURLOPT_PREREQDATA, CURLOPTTYPE_CBPOINT, 313), + + /* maximum age (since creation) of a connection to consider it for reuse + * (in seconds) */ + CURLOPT(CURLOPT_MAXLIFETIME_CONN, CURLOPTTYPE_LONG, 314), + + /* Set MIME option flags. */ + CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CURLOPT(CURLOPT_SSH_HOSTKEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 316), + + /* set the SSH host key callback custom pointer */ + CURLOPT(CURLOPT_SSH_HOSTKEYDATA, CURLOPTTYPE_CBPOINT, 317), + + /* specify which protocols that are allowed to be used for the transfer, + which thus helps the app which takes URLs from users or other external + inputs and want to restrict what protocol(s) to deal with. Defaults to + all built-in protocols. */ + CURLOPT(CURLOPT_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 318), + + /* specify which protocols that libcurl is allowed to follow directs to */ + CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319), + + /* websockets options */ + CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320), + + /* CA cache timeout */ + CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321), + + /* Can leak things, gonna exit() soon */ + CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322), + + /* set a specific client IP for HAProxy PROXY protocol header? */ + CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323), + + /* millisecond version */ + CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +/* */ +#define CURLOPT_FTP_RESPONSE_TIMEOUT CURLOPT_SERVER_RESPONSE_TIMEOUT + +/* Added in 8.2.0 */ +#define CURLOPT_MAIL_RCPT_ALLLOWFAILS CURLOPT_MAIL_RCPT_ALLOWFAILS + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* uses only IPv4 addresses/connections */ +#define CURL_IPRESOLVE_V6 2 /* uses only IPv6 addresses/connections */ + + /* Convenient "aliases" */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + CURL_HTTP_VERSION_3 = 30, /* Use HTTP/3, fallback to HTTP/2 or HTTP/1 if + needed. For HTTPS only. For HTTP, this option + makes libcurl return error. */ + CURL_HTTP_VERSION_3ONLY = 31, /* Use HTTP/3 without fallback. For HTTPS + only. For HTTP, this makes libcurl + return error. */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum { + CURL_SSLVERSION_MAX_NONE = 0, + CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), + CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), + CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), + CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), + CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), + + /* never use, keep last */ + CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + +/* Special size_t value signaling a null-terminated string. */ +#define CURL_ZERO_TERMINATED ((size_t) -1) + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + release */ +CURL_EXTERN int curl_strequal(const char *s1, const char *s2); +CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); + +/* Mime/form handling support. */ +typedef struct curl_mime curl_mime; /* Mime context. */ +typedef struct curl_mimepart curl_mimepart; /* Mime part context. */ + +/* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */ +#define CURLMIMEOPT_FORMESCAPE (1<<0) /* Use backslash-escaping for forms. */ + +/* + * NAME curl_mime_init() + * + * DESCRIPTION + * + * Create a mime context and return its handle. The easy parameter is the + * target handle. + */ +CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); + +/* + * NAME curl_mime_free() + * + * DESCRIPTION + * + * release a mime handle and its substructures. + */ +CURL_EXTERN void curl_mime_free(curl_mime *mime); + +/* + * NAME curl_mime_addpart() + * + * DESCRIPTION + * + * Append a new empty part to the given mime context and return a handle to + * the created part. + */ +CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); + +/* + * NAME curl_mime_name() + * + * DESCRIPTION + * + * Set mime/form part name. + */ +CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); + +/* + * NAME curl_mime_filename() + * + * DESCRIPTION + * + * Set mime part remote file name. + */ +CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_type() + * + * DESCRIPTION + * + * Set mime part type. + */ +CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); + +/* + * NAME curl_mime_encoder() + * + * DESCRIPTION + * + * Set mime data transfer encoder. + */ +CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, + const char *encoding); + +/* + * NAME curl_mime_data() + * + * DESCRIPTION + * + * Set mime part data source from memory data, + */ +CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize); + +/* + * NAME curl_mime_filedata() + * + * DESCRIPTION + * + * Set mime part data source from named file. + */ +CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_data_cb() + * + * DESCRIPTION + * + * Set mime part data source from callback function. + */ +CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg); + +/* + * NAME curl_mime_subparts() + * + * DESCRIPTION + * + * Set mime part data source from subparts. + */ +CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, + curl_mime *subparts); +/* + * NAME curl_mime_headers() + * + * DESCRIPTION + * + * Set mime part headers. + */ +CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, + int take_ownership); + +typedef enum { + /********* the first one is unused ************/ + CURLFORM_NOTHING CURL_DEPRECATED(7.56.0, ""), + CURLFORM_COPYNAME CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"), + CURLFORM_PTRNAME CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"), + CURLFORM_NAMELENGTH CURL_DEPRECATED(7.56.0, ""), + CURLFORM_COPYCONTENTS CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), + CURLFORM_PTRCONTENTS CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), + CURLFORM_CONTENTSLENGTH CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), + CURLFORM_FILECONTENT CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"), + CURLFORM_ARRAY CURL_DEPRECATED(7.56.0, ""), + CURLFORM_OBSOLETE, + CURLFORM_FILE CURL_DEPRECATED(7.56.0, "Use curl_mime_filedata()"), + + CURLFORM_BUFFER CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"), + CURLFORM_BUFFERPTR CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), + CURLFORM_BUFFERLENGTH CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), + + CURLFORM_CONTENTTYPE CURL_DEPRECATED(7.56.0, "Use curl_mime_type()"), + CURLFORM_CONTENTHEADER CURL_DEPRECATED(7.56.0, "Use curl_mime_headers()"), + CURLFORM_FILENAME CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"), + CURLFORM_END, + CURLFORM_OBSOLETE2, + + CURLFORM_STREAM CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"), + CURLFORM_CONTENTLEN /* added in 7.46.0, provide a curl_off_t length */ + CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK CURL_DEPRECATED(7.56.0, ""), /* 1st, no error */ + + CURL_FORMADD_MEMORY CURL_DEPRECATED(7.56.0, ""), + CURL_FORMADD_OPTION_TWICE CURL_DEPRECATED(7.56.0, ""), + CURL_FORMADD_NULL CURL_DEPRECATED(7.56.0, ""), + CURL_FORMADD_UNKNOWN_OPTION CURL_DEPRECATED(7.56.0, ""), + CURL_FORMADD_INCOMPLETE CURL_DEPRECATED(7.56.0, ""), + CURL_FORMADD_ILLEGAL_ARRAY CURL_DEPRECATED(7.56.0, ""), + /* libcurl was built with form api disabled */ + CURL_FORMADD_DISABLED CURL_DEPRECATED(7.56.0, ""), + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode CURL_DEPRECATED(7.56.0, "Use curl_mime_init()") +curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int CURL_DEPRECATED(7.56.0, "") +curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void CURL_DEPRECATED(7.56.0, "Use curl_mime_free()") +curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + + * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the + * curl_version_info_data.features flag (fetch by curl_version_info()). + + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines will be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* + * NAME curl_global_trace() + * + * DESCRIPTION + * + * curl_global_trace() can be invoked at application start to + * configure which components in curl should participate in tracing. + + * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the + * curl_version_info_data.features flag (fetch by curl_version_info()). + + */ +CURL_EXTERN CURLcode curl_global_trace(const char *config); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_global_sslset() + * + * DESCRIPTION + * + * When built with multiple SSL backends, curl_global_sslset() allows to + * choose one. This function can only be called once, and it must be called + * *before* curl_global_init(). + * + * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The + * backend can also be specified via the name parameter (passing -1 as id). + * If both id and name are specified, the name will be ignored. If neither id + * nor name are specified, the function will fail with + * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the + * NULL-terminated list of available backends. + * + * Upon success, the function returns CURLSSLSET_OK. + * + * If the specified SSL backend is not available, the function returns + * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated + * list of available SSL backends. + * + * The SSL backend can be set only once. If it has already been set, a + * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. + */ + +struct curl_ssl_backend { + curl_sslbackend id; + const char *name; +}; +typedef struct curl_ssl_backend curl_ssl_backend; + +typedef enum { + CURLSSLSET_OK = 0, + CURLSSLSET_UNKNOWN_BACKEND, + CURLSSLSET_TOO_LATE, + CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ +} CURLsslset; + +CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *list, + const char *data); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *list); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, for SSL backends that support it. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information for a + certificate in the format "name:content". + eg "Subject:foo", "Issuer:bar", etc. */ +}; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_PTR 0x400000 /* same as SLIST */ +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_OFF_T 0x600000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_UPLOAD_T") + = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, + CURLINFO_SIZE_DOWNLOAD + CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_DOWNLOAD_T") + = CURLINFO_DOUBLE + 8, + CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, + CURLINFO_SPEED_DOWNLOAD + CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_DOWNLOAD_T") + = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, + CURLINFO_SPEED_UPLOAD + CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_UPLOAD_T") + = CURLINFO_DOUBLE + 10, + CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD + CURL_DEPRECATED(7.55.0, + "Use CURLINFO_CONTENT_LENGTH_DOWNLOAD_T") + = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD + CURL_DEPRECATED(7.55.0, + "Use CURLINFO_CONTENT_LENGTH_UPLOAD_T") + = CURLINFO_DOUBLE + 16, + CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET CURL_DEPRECATED(7.45.0, "Use CURLINFO_ACTIVESOCKET") + = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_PTR + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION CURL_DEPRECATED(7.48.0, "Use CURLINFO_TLS_SSL_PTR") + = CURLINFO_PTR + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL CURL_DEPRECATED(7.85.0, "Use CURLINFO_SCHEME") + = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, + CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50, + CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51, + CURLINFO_CONNECT_TIME_T = CURLINFO_OFF_T + 52, + CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53, + CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54, + CURLINFO_REDIRECT_TIME_T = CURLINFO_OFF_T + 55, + CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56, + CURLINFO_RETRY_AFTER = CURLINFO_OFF_T + 57, + CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58, + CURLINFO_PROXY_ERROR = CURLINFO_LONG + 59, + CURLINFO_REFERER = CURLINFO_STRING + 60, + CURLINFO_CAINFO = CURLINFO_STRING + 61, + CURLINFO_CAPATH = CURLINFO_STRING + 62, + CURLINFO_XFER_ID = CURLINFO_OFF_T + 63, + CURLINFO_CONN_ID = CURLINFO_OFF_T + 64, + CURLINFO_QUEUE_TIME_T = CURLINFO_OFF_T + 65, + CURLINFO_LASTONE = 65 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) /* no purpose since 7.57.0 */ +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_PSL, + CURL_LOCK_DATA_HSTS, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option, + ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_FIFTH, + CURLVERSION_SIXTH, + CURLVERSION_SEVENTH, + CURLVERSION_EIGHTH, + CURLVERSION_NINTH, + CURLVERSION_TENTH, + CURLVERSION_ELEVENTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_ELEVENTH + +struct curl_version_info_data { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + + /* These fields were added in CURLVERSION_FIFTH */ + unsigned int brotli_ver_num; /* Numeric Brotli version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *brotli_version; /* human readable string. */ + + /* These fields were added in CURLVERSION_SIXTH */ + unsigned int nghttp2_ver_num; /* Numeric nghttp2 version + (MAJOR << 16) | (MINOR << 8) | PATCH */ + const char *nghttp2_version; /* human readable string. */ + const char *quic_version; /* human readable quic (+ HTTP/3) library + + version or NULL */ + + /* These fields were added in CURLVERSION_SEVENTH */ + const char *cainfo; /* the built-in default CURLOPT_CAINFO, might + be NULL */ + const char *capath; /* the built-in default CURLOPT_CAPATH, might + be NULL */ + + /* These fields were added in CURLVERSION_EIGHTH */ + unsigned int zstd_ver_num; /* Numeric Zstd version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *zstd_version; /* human readable string. */ + + /* These fields were added in CURLVERSION_NINTH */ + const char *hyper_version; /* human readable string. */ + + /* These fields were added in CURLVERSION_TENTH */ + const char *gsasl_version; /* human readable string. */ + + /* These fields were added in CURLVERSION_ELEVENTH */ + /* feature_names is terminated by an entry with a NULL feature name */ + const char * const *feature_names; +}; +typedef struct curl_version_info_data curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is supported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ +#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ +#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ +#define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */ +#define CURL_VERSION_HTTP3 (1<<25) /* HTTP3 support built-in */ +#define CURL_VERSION_ZSTD (1<<26) /* zstd features are present */ +#define CURL_VERSION_UNICODE (1<<27) /* Unicode support on Windows */ +#define CURL_VERSION_HSTS (1<<28) /* HSTS is supported */ +#define CURL_VERSION_GSASL (1<<29) /* libgsasl is supported */ +#define CURL_VERSION_THREADSAFE (1<<30) /* libcurl API is thread-safe */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" +#include "urlapi.h" +#include "options.h" +#include "header.h" +#include "websockets.h" +#include "mprintf.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus && !CURL_DISABLE_TYPECHECK */ + +#endif /* CURLINC_CURL_H */ diff --git a/include/curl/curlver.h b/include/curl/curlver.h new file mode 100644 index 0000000..1e660cb --- /dev/null +++ b/include/curl/curlver.h @@ -0,0 +1,79 @@ +#ifndef CURLINC_CURLVER_H +#define CURLINC_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "8.6.0" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 8 +#define LIBCURL_VERSION_MINOR 6 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x080600 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date follows this template: + * + * "2007-11-23" + */ +#define LIBCURL_TIMESTAMP "2024-01-31" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* CURLINC_CURLVER_H */ diff --git a/include/curl/easy.h b/include/curl/easy.h new file mode 100644 index 0000000..1285101 --- /dev/null +++ b/include/curl/easy.h @@ -0,0 +1,125 @@ +#ifndef CURLINC_EASY_H +#define CURLINC_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/* Flag bits in the curl_blob struct: */ +#define CURL_BLOB_COPY 1 /* tell libcurl to copy the data */ +#define CURL_BLOB_NOCOPY 0 /* tell libcurl to NOT copy the data */ + +struct curl_blob { + void *data; + size_t len; + unsigned int flags; /* bit 0 is defined, the rest are reserved and should be + left zeroes */ +}; + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. + * The third argument MUST be pointing to the specific type of the used option + * which is documented in each man page of the option. The data pointed to + * will be filled in accordingly and can be relied upon only if the function + * returns CURLE_OK. This function is intended to get used *AFTER* a performed + * transfer, all results from this function are undefined until the transfer + * is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + + +/* + * NAME curl_easy_upkeep() + * + * DESCRIPTION + * + * Performs connection upkeep for the given session handle. + */ +CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/include/curl/header.h b/include/curl/header.h new file mode 100644 index 0000000..8df11e1 --- /dev/null +++ b/include/curl/header.h @@ -0,0 +1,74 @@ +#ifndef CURLINC_HEADER_H +#define CURLINC_HEADER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct curl_header { + char *name; /* this might not use the same case */ + char *value; + size_t amount; /* number of headers using this name */ + size_t index; /* ... of this instance, 0 or higher */ + unsigned int origin; /* see bits below */ + void *anchor; /* handle privately used by libcurl */ +}; + +/* 'origin' bits */ +#define CURLH_HEADER (1<<0) /* plain server header */ +#define CURLH_TRAILER (1<<1) /* trailers */ +#define CURLH_CONNECT (1<<2) /* CONNECT headers */ +#define CURLH_1XX (1<<3) /* 1xx headers */ +#define CURLH_PSEUDO (1<<4) /* pseudo headers */ + +typedef enum { + CURLHE_OK, + CURLHE_BADINDEX, /* header exists but not with this index */ + CURLHE_MISSING, /* no such header exists */ + CURLHE_NOHEADERS, /* no headers at all exist (yet) */ + CURLHE_NOREQUEST, /* no request with this number was used */ + CURLHE_OUT_OF_MEMORY, /* out of memory while processing */ + CURLHE_BAD_ARGUMENT, /* a function argument was not okay */ + CURLHE_NOT_BUILT_IN /* if API was disabled in the build */ +} CURLHcode; + +CURL_EXTERN CURLHcode curl_easy_header(CURL *easy, + const char *name, + size_t index, + unsigned int origin, + int request, + struct curl_header **hout); + +CURL_EXTERN struct curl_header *curl_easy_nextheader(CURL *easy, + unsigned int origin, + int request, + struct curl_header *prev); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* CURLINC_HEADER_H */ diff --git a/include/curl/mprintf.h b/include/curl/mprintf.h new file mode 100644 index 0000000..4f70454 --- /dev/null +++ b/include/curl/mprintf.h @@ -0,0 +1,78 @@ +#ifndef CURLINC_MPRINTF_H +#define CURLINC_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ +#include "curl.h" /* for CURL_EXTERN */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(__GNUC__) || defined(__clang__)) && \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(CURL_NO_FMT_CHECKS) +#if defined(__MINGW32__) && !defined(__clang__) +#define CURL_TEMP_PRINTF(fmt, arg) \ + __attribute__((format(gnu_printf, fmt, arg))) +#else +#define CURL_TEMP_PRINTF(fmt, arg) \ + __attribute__((format(printf, fmt, arg))) +#endif +#else +#define CURL_TEMP_PRINTF(fmt, arg) +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...) + CURL_TEMP_PRINTF(1, 2); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...) + CURL_TEMP_PRINTF(2, 3); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...) + CURL_TEMP_PRINTF(2, 3); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...) + CURL_TEMP_PRINTF(3, 4); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args) + CURL_TEMP_PRINTF(1, 0); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args) + CURL_TEMP_PRINTF(2, 0); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args) + CURL_TEMP_PRINTF(2, 0); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args) + CURL_TEMP_PRINTF(3, 0); +CURL_EXTERN char *curl_maprintf(const char *format, ...) + CURL_TEMP_PRINTF(1, 2); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args) + CURL_TEMP_PRINTF(1, 0); + +#undef CURL_TEMP_PRINTF + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* CURLINC_MPRINTF_H */ diff --git a/include/curl/multi.h b/include/curl/multi.h new file mode 100644 index 0000000..e79b48f --- /dev/null +++ b/include/curl/multi.h @@ -0,0 +1,471 @@ +#ifndef CURLINC_MULTI_H +#define CURLINC_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a + callback */ + CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */ + CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */ + CURLM_ABORTED_BY_CALLBACK, + CURLM_UNRECOVERABLE_POLL, + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; +}; + +/* + * Name: curl_multi_init() + * + * Desc: initialize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + +/* + * Name: curl_multi_poll() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + +/* + * Name: curl_multi_wakeup() + * + * Desc: wakes up a sleeping curl_multi_poll call. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on individual transfers even when + * this returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic information. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a null-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()") +curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()") +curl_multi_socket_all(CURLM *multi_handle, int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +typedef enum { + /* This is the socket callback function pointer */ + CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3), + + /* This is the timer callback function pointer */ + CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7), + + /* maximum number of requests in a pipeline */ + CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10), + + /* a list of site names(+port) that are blocked from pipelining */ + CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11), + + /* a list of server types that are blocked from pipelining */ + CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13), + + /* This is the server push callback function pointer */ + CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15), + + /* maximum number of concurrent streams to support on a connection */ + CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + +/* + * Name: curl_multi_get_handles() + * + * Desc: Returns an allocated array holding all handles currently added to + * the multi handle. Marks the final entry with a NULL pointer. If + * there is no easy handle added to the multi handle, this function + * returns an array with the first entry as a NULL pointer. + * + * Returns: NULL on failure, otherwise a CURL **array pointer + */ +CURL_EXTERN CURL **curl_multi_get_handles(CURLM *multi_handle); + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. It can also decide + * to completely fail the connection. + * + * Returns: CURL_PUSH_OK, CURL_PUSH_DENY or CURL_PUSH_ERROROUT + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 +#define CURL_PUSH_ERROROUT 2 /* added in 7.72.0 */ + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/include/curl/options.h b/include/curl/options.h new file mode 100644 index 0000000..1ed76a9 --- /dev/null +++ b/include/curl/options.h @@ -0,0 +1,70 @@ +#ifndef CURLINC_OPTIONS_H +#define CURLINC_OPTIONS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + CURLOT_LONG, /* long (a range of values) */ + CURLOT_VALUES, /* (a defined set or bitmask) */ + CURLOT_OFF_T, /* curl_off_t (a range of values) */ + CURLOT_OBJECT, /* pointer (void *) */ + CURLOT_STRING, /* (char * to null-terminated buffer) */ + CURLOT_SLIST, /* (struct curl_slist *) */ + CURLOT_CBPTR, /* (void * passed as-is to a callback) */ + CURLOT_BLOB, /* blob (struct curl_blob *) */ + CURLOT_FUNCTION /* function pointer */ +} curl_easytype; + +/* Flag bits */ + +/* "alias" means it is provided for old programs to remain functional, + we prefer another name */ +#define CURLOT_FLAG_ALIAS (1<<0) + +/* The CURLOPTTYPE_* id ranges can still be used to figure out what type/size + to use for curl_easy_setopt() for the given id */ +struct curl_easyoption { + const char *name; + CURLoption id; + curl_easytype type; + unsigned int flags; +}; + +CURL_EXTERN const struct curl_easyoption * +curl_easy_option_by_name(const char *name); + +CURL_EXTERN const struct curl_easyoption * +curl_easy_option_by_id(CURLoption id); + +CURL_EXTERN const struct curl_easyoption * +curl_easy_option_next(const struct curl_easyoption *prev); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif +#endif /* CURLINC_OPTIONS_H */ diff --git a/include/curl/stdcheaders.h b/include/curl/stdcheaders.h new file mode 100644 index 0000000..7451aa3 --- /dev/null +++ b/include/curl/stdcheaders.h @@ -0,0 +1,35 @@ +#ifndef CURLINC_STDCHEADERS_H +#define CURLINC_STDCHEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* CURLINC_STDCHEADERS_H */ diff --git a/include/curl/system.h b/include/curl/system.h new file mode 100644 index 0000000..81a1b81 --- /dev/null +++ b/include/curl/system.h @@ -0,0 +1,496 @@ +#ifndef CURLINC_SYSTEM_H +#define CURLINC_SYSTEM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Try to keep one section per platform, compiler and architecture, otherwise, + * if an existing section is reused for a different one and later on the + * original is adjusted, probably the piggybacking one can be adversely + * changed. + * + * In order to differentiate between platforms/compilers/architectures use + * only compiler built in predefined preprocessor symbols. + * + * curl_off_t + * ---------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit + * wide signed integral data type. The width of this data type must remain + * constant and independent of any possible large file support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit + * wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall + * only be violated if off_t is the only 64-bit data type available and the + * size of off_t is independent of large file support settings. Keep your + * build on the safe side avoiding an off_t gating. If you have a 64-bit + * off_t then take for sure that another 64-bit data type exists, dig deeper + * and you will find it. + * + */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SALFORDC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TURBOC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__LCC__) +# if defined(__MCST__) /* MCST eLbrus Compiler Collection */ +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# else /* Local (or Little) C Compiler */ +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# endif + +#elif defined(macintosh) +# include +# if TYPE_LONGLONG +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__TANDEM) +# if ! defined(__LP64) + /* Required for 32-bit NonStop builds only. */ +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# endif + +#elif defined(_WIN32_WCE) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__MINGW32__) +# include +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T PRId64 +# define CURL_FORMAT_CURL_OFF_TU PRIu64 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_PULL_SYS_TYPES_H 1 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__OS400__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__MVS__) +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TINYC__) /* also known as tcc */ +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */ +# if !defined(__LP64) && (defined(__ILP32) || \ + defined(__i386) || \ + defined(__sparcv8) || \ + defined(__sparcv8plus)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64) || \ + defined(__amd64) || defined(__sparcv9) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__xlc__) /* IBM xlc compiler */ +# if !defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__hpux) /* HP aCC compiler */ +# if !defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 1800) +# include +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T PRId64 +# define CURL_FORMAT_CURL_OFF_TU PRIu64 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# elif (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) && !defined(_SCO_DS) +# if !defined(__LP64__) && \ + (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ + defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ + defined(__XTENSA__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ + defined(__e2k__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +/* generic "safe guess" on old 32 bit style */ +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +#endif + +#ifdef _AIX +/* AIX needs */ +#define CURL_PULL_SYS_POLL_H +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ +/* sys/poll.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define CURLINC_OFF_T_C_HLPR2(x) x +# define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ + CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ + CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +#endif /* CURLINC_SYSTEM_H */ diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h new file mode 100644 index 0000000..b880f3d --- /dev/null +++ b/include/curl/typecheck-gcc.h @@ -0,0 +1,717 @@ +#ifndef CURLINC_TYPECHECK_GCC_H +#define CURLINC_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(curlcheck_sometype_option(_curl_opt)) + * if(!curlcheck_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define curlcheck_sometype_option, curlcheck_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ + __extension__({ \ + CURLoption _curl_opt = (option); \ + if(__builtin_constant_p(_curl_opt)) { \ + CURL_IGNORE_DEPRECATION( \ + if(curlcheck_long_option(_curl_opt)) \ + if(!curlcheck_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(curlcheck_off_t_option(_curl_opt)) \ + if(!curlcheck_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(curlcheck_string_option(_curl_opt)) \ + if(!curlcheck_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(curlcheck_write_cb_option(_curl_opt)) \ + if(!curlcheck_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \ + if(!curlcheck_resolver_start_callback(value)) \ + _curl_easy_setopt_err_resolver_start_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!curlcheck_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!curlcheck_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!curlcheck_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!curlcheck_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!curlcheck_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!curlcheck_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!curlcheck_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(curlcheck_conv_cb_option(_curl_opt)) \ + if(!curlcheck_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!curlcheck_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(curlcheck_cb_data_option(_curl_opt)) \ + if(!curlcheck_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!curlcheck_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!curlcheck_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(curlcheck_postfields_option(_curl_opt)) \ + if(!curlcheck_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!curlcheck_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if((_curl_opt) == CURLOPT_MIMEPOST) \ + if(!curlcheck_ptr((value), curl_mime)) \ + _curl_easy_setopt_err_curl_mimepost(); \ + if(curlcheck_slist_option(_curl_opt)) \ + if(!curlcheck_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!curlcheck_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + ) \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ + }) + +/* wraps curl_easy_getinfo() with typechecking */ +#define curl_easy_getinfo(handle, info, arg) \ + __extension__({ \ + CURLINFO _curl_info = (info); \ + if(__builtin_constant_p(_curl_info)) { \ + CURL_IGNORE_DEPRECATION( \ + if(curlcheck_string_info(_curl_info)) \ + if(!curlcheck_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(curlcheck_long_info(_curl_info)) \ + if(!curlcheck_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(curlcheck_double_info(_curl_info)) \ + if(!curlcheck_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(curlcheck_slist_info(_curl_info)) \ + if(!curlcheck_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + if(curlcheck_tlssessioninfo_info(_curl_info)) \ + if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \ + _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ + if(curlcheck_certinfo_info(_curl_info)) \ + if(!curlcheck_arr((arg), struct curl_certinfo *)) \ + _curl_easy_getinfo_err_curl_certinfo(); \ + if(curlcheck_socket_info(_curl_info)) \ + if(!curlcheck_arr((arg), curl_socket_t)) \ + _curl_easy_getinfo_err_curl_socket(); \ + if(curlcheck_off_t_info(_curl_info)) \ + if(!curlcheck_arr((arg), curl_off_t)) \ + _curl_easy_getinfo_err_curl_off_t(); \ + ) \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ + }) + +/* + * For now, just make sure that the functions are called with three arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define CURLWARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +CURLWARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +CURLWARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +CURLWARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string ('char *' or char[]) argument for this option" + ) +CURLWARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_resolver_start_callback, + "curl_easy_setopt expects a " + "curl_resolver_start_callback argument for this option" + ) +CURLWARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +CURLWARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +CURLWARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +CURLWARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +CURLWARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a 'FILE *' argument for this option") +CURLWARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") +CURLWARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") +CURLWARNING(_curl_easy_setopt_err_curl_mimepost, + "curl_easy_setopt expects a 'curl_mime *' " + "argument for this option") +CURLWARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") +CURLWARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +CURLWARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to 'char *' for this info") +CURLWARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +CURLWARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +CURLWARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") +CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_tlssessioninfo *' for this info") +CURLWARNING(_curl_easy_getinfo_err_curl_certinfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_certinfo *' for this info") +CURLWARNING(_curl_easy_getinfo_err_curl_socket, + "curl_easy_getinfo expects a pointer to curl_socket_t for this info") +CURLWARNING(_curl_easy_getinfo_err_curl_off_t, + "curl_easy_getinfo expects a pointer to curl_off_t for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define curlcheck_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define curlcheck_off_t_option(option) \ + (((option) > CURLOPTTYPE_OFF_T) && ((option) < CURLOPTTYPE_BLOB)) + +/* evaluates to true if option takes a char* argument */ +#define curlcheck_string_option(option) \ + ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_ALTSVC || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_DOH_URL || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_HSTS || \ + (option) == CURLOPT_HAPROXY_CLIENT_IP || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PRE_PROXY || \ + (option) == CURLOPT_PROTOCOLS_STR || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXY_CAINFO || \ + (option) == CURLOPT_PROXY_CAPATH || \ + (option) == CURLOPT_PROXY_CRLFILE || \ + (option) == CURLOPT_PROXY_ISSUERCERT || \ + (option) == CURLOPT_PROXY_KEYPASSWD || \ + (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ + (option) == CURLOPT_PROXY_SSLCERT || \ + (option) == CURLOPT_PROXY_SSLCERTTYPE || \ + (option) == CURLOPT_PROXY_SSLKEY || \ + (option) == CURLOPT_PROXY_SSLKEYTYPE || \ + (option) == CURLOPT_PROXY_TLS13_CIPHERS || \ + (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ + (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REDIR_PROTOCOLS_STR || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_REQUEST_TARGET || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SASL_AUTHZID || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLS13_CIPHERS || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_AWS_SIGV4 || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + (option) == CURLOPT_SSL_EC_CURVES || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define curlcheck_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define curlcheck_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define curlcheck_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_HSTSREADDATA || \ + (option) == CURLOPT_HSTSWRITEDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PREREQDATA || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + (option) == CURLOPT_RESOLVER_START_DATA || \ + (option) == CURLOPT_TRAILERDATA || \ + (option) == CURLOPT_SSH_HOSTKEYDATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define curlcheck_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define curlcheck_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + (option) == CURLOPT_CONNECT_TO || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define curlcheck_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG && \ + (info) != CURLINFO_PRIVATE) + +/* evaluates to true if info expects a pointer to long argument */ +#define curlcheck_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define curlcheck_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define curlcheck_slist_info(info) \ + (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) + +/* true if info expects a pointer to struct curl_tlssessioninfo * argument */ +#define curlcheck_tlssessioninfo_info(info) \ + (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) + +/* true if info expects a pointer to struct curl_certinfo * argument */ +#define curlcheck_certinfo_info(info) ((info) == CURLINFO_CERTINFO) + +/* true if info expects a pointer to struct curl_socket_t argument */ +#define curlcheck_socket_info(info) \ + (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) + +/* true if info expects a pointer to curl_off_t argument */ +#define curlcheck_off_t_info(info) \ + (CURLINFO_OFF_T < (info)) + + +/* typecheck helpers -- check whether given expression has requested type */ + +/* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true if expr is a pointer */ +#define curlcheck_any_ptr(expr) \ + (sizeof(expr) == sizeof(void *)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define curlcheck_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define curlcheck_ptr(expr, type) \ + (curlcheck_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define curlcheck_arr(expr, type) \ + (curlcheck_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define curlcheck_string(expr) \ + (curlcheck_arr((expr), char) || \ + curlcheck_arr((expr), signed char) || \ + curlcheck_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define curlcheck_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define curlcheck_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define curlcheck_error_buffer(expr) \ + (curlcheck_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define curlcheck_cb_data(expr) \ + (curlcheck_ptr((expr), void) || \ + curlcheck_ptr((expr), FILE)) +#else /* be less strict */ +#define curlcheck_cb_data(expr) \ + curlcheck_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define curlcheck_FILE(expr) \ + (curlcheck_NULL(expr) || \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *))) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define curlcheck_postfields(expr) \ + (curlcheck_ptr((expr), void) || \ + curlcheck_arr((expr), char) || \ + curlcheck_arr((expr), unsigned char)) + +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define curlcheck_cb_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func) *, type)) + +/* evaluates to true if expr is of type curl_resolver_start_callback */ +#define curlcheck_resolver_start_callback(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_resolver_start_callback)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define curlcheck_read_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), __typeof__(fread) *) || \ + curlcheck_cb_compatible((expr), curl_read_callback) || \ + curlcheck_cb_compatible((expr), _curl_read_callback1) || \ + curlcheck_cb_compatible((expr), _curl_read_callback2) || \ + curlcheck_cb_compatible((expr), _curl_read_callback3) || \ + curlcheck_cb_compatible((expr), _curl_read_callback4) || \ + curlcheck_cb_compatible((expr), _curl_read_callback5) || \ + curlcheck_cb_compatible((expr), _curl_read_callback6)) +typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define curlcheck_write_cb(expr) \ + (curlcheck_read_cb(expr) || \ + curlcheck_cb_compatible((expr), __typeof__(fwrite) *) || \ + curlcheck_cb_compatible((expr), curl_write_callback) || \ + curlcheck_cb_compatible((expr), _curl_write_callback1) || \ + curlcheck_cb_compatible((expr), _curl_write_callback2) || \ + curlcheck_cb_compatible((expr), _curl_write_callback3) || \ + curlcheck_cb_compatible((expr), _curl_write_callback4) || \ + curlcheck_cb_compatible((expr), _curl_write_callback5) || \ + curlcheck_cb_compatible((expr), _curl_write_callback6)) +typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define curlcheck_ioctl_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_ioctl_callback) || \ + curlcheck_cb_compatible((expr), _curl_ioctl_callback1) || \ + curlcheck_cb_compatible((expr), _curl_ioctl_callback2) || \ + curlcheck_cb_compatible((expr), _curl_ioctl_callback3) || \ + curlcheck_cb_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define curlcheck_sockopt_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_sockopt_callback) || \ + curlcheck_cb_compatible((expr), _curl_sockopt_callback1) || \ + curlcheck_cb_compatible((expr), _curl_sockopt_callback2)) +typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define curlcheck_opensocket_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_opensocket_callback) || \ + curlcheck_cb_compatible((expr), _curl_opensocket_callback1) || \ + curlcheck_cb_compatible((expr), _curl_opensocket_callback2) || \ + curlcheck_cb_compatible((expr), _curl_opensocket_callback3) || \ + curlcheck_cb_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (*_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define curlcheck_progress_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_progress_callback) || \ + curlcheck_cb_compatible((expr), _curl_progress_callback1) || \ + curlcheck_cb_compatible((expr), _curl_progress_callback2)) +typedef int (*_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (*_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define curlcheck_debug_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_debug_callback) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback1) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback2) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback3) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback4) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback5) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback6) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback7) || \ + curlcheck_cb_compatible((expr), _curl_debug_callback8)) +typedef int (*_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (*_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (*_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (*_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (*_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (*_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define curlcheck_ssl_ctx_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) || \ + curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, + const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define curlcheck_conv_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_conv_callback) || \ + curlcheck_cb_compatible((expr), _curl_conv_callback1) || \ + curlcheck_cb_compatible((expr), _curl_conv_callback2) || \ + curlcheck_cb_compatible((expr), _curl_conv_callback3) || \ + curlcheck_cb_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define curlcheck_seek_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_seek_callback) || \ + curlcheck_cb_compatible((expr), _curl_seek_callback1) || \ + curlcheck_cb_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* CURLINC_TYPECHECK_GCC_H */ diff --git a/include/curl/urlapi.h b/include/curl/urlapi.h new file mode 100644 index 0000000..91f8c45 --- /dev/null +++ b/include/curl/urlapi.h @@ -0,0 +1,151 @@ +#ifndef CURLINC_URLAPI_H +#define CURLINC_URLAPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* the error codes for the URL API */ +typedef enum { + CURLUE_OK, + CURLUE_BAD_HANDLE, /* 1 */ + CURLUE_BAD_PARTPOINTER, /* 2 */ + CURLUE_MALFORMED_INPUT, /* 3 */ + CURLUE_BAD_PORT_NUMBER, /* 4 */ + CURLUE_UNSUPPORTED_SCHEME, /* 5 */ + CURLUE_URLDECODE, /* 6 */ + CURLUE_OUT_OF_MEMORY, /* 7 */ + CURLUE_USER_NOT_ALLOWED, /* 8 */ + CURLUE_UNKNOWN_PART, /* 9 */ + CURLUE_NO_SCHEME, /* 10 */ + CURLUE_NO_USER, /* 11 */ + CURLUE_NO_PASSWORD, /* 12 */ + CURLUE_NO_OPTIONS, /* 13 */ + CURLUE_NO_HOST, /* 14 */ + CURLUE_NO_PORT, /* 15 */ + CURLUE_NO_QUERY, /* 16 */ + CURLUE_NO_FRAGMENT, /* 17 */ + CURLUE_NO_ZONEID, /* 18 */ + CURLUE_BAD_FILE_URL, /* 19 */ + CURLUE_BAD_FRAGMENT, /* 20 */ + CURLUE_BAD_HOSTNAME, /* 21 */ + CURLUE_BAD_IPV6, /* 22 */ + CURLUE_BAD_LOGIN, /* 23 */ + CURLUE_BAD_PASSWORD, /* 24 */ + CURLUE_BAD_PATH, /* 25 */ + CURLUE_BAD_QUERY, /* 26 */ + CURLUE_BAD_SCHEME, /* 27 */ + CURLUE_BAD_SLASHES, /* 28 */ + CURLUE_BAD_USER, /* 29 */ + CURLUE_LACKS_IDN, /* 30 */ + CURLUE_TOO_LARGE, /* 31 */ + CURLUE_LAST +} CURLUcode; + +typedef enum { + CURLUPART_URL, + CURLUPART_SCHEME, + CURLUPART_USER, + CURLUPART_PASSWORD, + CURLUPART_OPTIONS, + CURLUPART_HOST, + CURLUPART_PORT, + CURLUPART_PATH, + CURLUPART_QUERY, + CURLUPART_FRAGMENT, + CURLUPART_ZONEID /* added in 7.65.0 */ +} CURLUPart; + +#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */ +#define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set, + if the port number matches the + default for the scheme */ +#define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if + missing */ +#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */ +#define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */ +#define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */ +#define CURLU_URLDECODE (1<<6) /* URL decode on get */ +#define CURLU_URLENCODE (1<<7) /* URL encode on set */ +#define CURLU_APPENDQUERY (1<<8) /* append a form style part */ +#define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */ +#define CURLU_NO_AUTHORITY (1<<10) /* Allow empty authority when the + scheme is unknown. */ +#define CURLU_ALLOW_SPACE (1<<11) /* Allow spaces in the URL */ +#define CURLU_PUNYCODE (1<<12) /* get the host name in punycode */ +#define CURLU_PUNY2IDN (1<<13) /* punycode => IDN conversion */ + +typedef struct Curl_URL CURLU; + +/* + * curl_url() creates a new CURLU handle and returns a pointer to it. + * Must be freed with curl_url_cleanup(). + */ +CURL_EXTERN CURLU *curl_url(void); + +/* + * curl_url_cleanup() frees the CURLU handle and related resources used for + * the URL parsing. It will not free strings previously returned with the URL + * API. + */ +CURL_EXTERN void curl_url_cleanup(CURLU *handle); + +/* + * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new + * handle must also be freed with curl_url_cleanup(). + */ +CURL_EXTERN CURLU *curl_url_dup(const CURLU *in); + +/* + * curl_url_get() extracts a specific part of the URL from a CURLU + * handle. Returns error code. The returned pointer MUST be freed with + * curl_free() afterwards. + */ +CURL_EXTERN CURLUcode curl_url_get(const CURLU *handle, CURLUPart what, + char **part, unsigned int flags); + +/* + * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns + * error code. The passed in string will be copied. Passing a NULL instead of + * a part string, clears that part. + */ +CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what, + const char *part, unsigned int flags); + +/* + * curl_url_strerror() turns a CURLUcode value into the equivalent human + * readable error string. This is useful for printing meaningful error + * messages. + */ +CURL_EXTERN const char *curl_url_strerror(CURLUcode); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* CURLINC_URLAPI_H */ diff --git a/include/curl/websockets.h b/include/curl/websockets.h new file mode 100644 index 0000000..6ef6a2b --- /dev/null +++ b/include/curl/websockets.h @@ -0,0 +1,84 @@ +#ifndef CURLINC_WEBSOCKETS_H +#define CURLINC_WEBSOCKETS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct curl_ws_frame { + int age; /* zero */ + int flags; /* See the CURLWS_* defines */ + curl_off_t offset; /* the offset of this data into the frame */ + curl_off_t bytesleft; /* number of pending bytes left of the payload */ + size_t len; /* size of the current data chunk */ +}; + +/* flag bits */ +#define CURLWS_TEXT (1<<0) +#define CURLWS_BINARY (1<<1) +#define CURLWS_CONT (1<<2) +#define CURLWS_CLOSE (1<<3) +#define CURLWS_PING (1<<4) +#define CURLWS_OFFSET (1<<5) + +/* + * NAME curl_ws_recv() + * + * DESCRIPTION + * + * Receives data from the websocket connection. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, + size_t *recv, + const struct curl_ws_frame **metap); + +/* flags for curl_ws_send() */ +#define CURLWS_PONG (1<<6) + +/* + * NAME curl_ws_send() + * + * DESCRIPTION + * + * Sends data over the websocket connection. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t fragsize, + unsigned int flags); + +/* bits for the CURLOPT_WS_OPTIONS bitmask: */ +#define CURLWS_RAW_MODE (1<<0) + +CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *curl); + +#ifdef __cplusplus +} +#endif + +#endif /* CURLINC_WEBSOCKETS_H */ diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..ec298b5 --- /dev/null +++ b/install-sh @@ -0,0 +1,541 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2020-11-14.01; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. + -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -p) cpprog="$cpprog -p";; + + -s) stripcmd=$stripprog;; + + -S) backupsuffix="$2" + shift;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/lib/.checksrc b/lib/.checksrc new file mode 100644 index 0000000..16133a4 --- /dev/null +++ b/lib/.checksrc @@ -0,0 +1 @@ +enable STRERROR diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..51d5257 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,240 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +set(LIB_NAME libcurl) +set(LIBCURL_OUTPUT_NAME libcurl CACHE STRING "Basename of the curl library") +add_definitions(-DBUILDING_LIBCURL) + +configure_file(curl_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h) + +transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) + +list(APPEND HHEADERS + ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h + ) + +# The rest of the build + +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +if(USE_ARES) + include_directories(${CARES_INCLUDE_DIR}) +endif() + +if(BUILD_TESTING) + add_library( + curlu # special libcurlu library just for unittests + STATIC + EXCLUDE_FROM_ALL + ${HHEADERS} ${CSOURCES} + ) + target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB) +endif() + +if(ENABLE_CURLDEBUG) + # We must compile these sources separately to avoid memdebug.h redefinitions + # applying to them. + set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) +endif() + +if(BUILD_TESTING) + target_link_libraries(curlu PRIVATE ${CURL_LIBS}) +endif() + +transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake") +include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake) + +if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR + CMAKE_SYSTEM_NAME STREQUAL "Linux" OR + CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR + CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR + CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR + + # FreeBSD comes with the a.out and elf flavours + # but a.out was supported up to version 3.x and + # elf from 3.x. I cannot imagine someone running + # CMake on those ancient systems + CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + + CMAKE_SYSTEM_NAME STREQUAL "Haiku") + + math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}") + set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}") +else() + unset(CMAKESONAME) +endif() + +## Library definition + +# Add "_imp" as a suffix before the extension to avoid conflicting with +# the statically linked "libcurl.lib" (typically with MSVC) +if(WIN32 AND + NOT IMPORT_LIB_SUFFIX AND + CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX) + set(IMPORT_LIB_SUFFIX "_imp") +endif() + +# Whether to do a single compilation pass for libcurl sources and reuse these +# objects to generate both static and shared target. +if(NOT DEFINED SHARE_LIB_OBJECT) + # Enable it by default on platforms where PIC is the default for both shared + # and static and there is a way to tell the linker which libcurl symbols it + # should export (vs. marking these symbols exportable at compile-time). + if(WIN32) + set(SHARE_LIB_OBJECT ON) + else() + # On other platforms, make it an option disabled by default + set(SHARE_LIB_OBJECT OFF) + endif() +endif() + +if(WIN32) + # Define CURL_STATICLIB always, to disable __declspec(dllexport) for exported + # libcurl symbols. We handle exports via libcurl.def instead. Except with + # symbol hiding disabled or debug mode enabled, when we export _all_ symbols + # from libcurl DLL, without using libcurl.def. + add_definitions("-DCURL_STATICLIB") +endif() + +if(SHARE_LIB_OBJECT) + set(LIB_OBJECT "libcurl_object") + add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES}) + target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS}) + set_target_properties(${LIB_OBJECT} PROPERTIES + POSITION_INDEPENDENT_CODE ON) + if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") + endif() + if(CURL_HAS_LTO) + set_target_properties(${LIB_OBJECT} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) + endif() + + target_include_directories(${LIB_OBJECT} INTERFACE + $ + $) + + set(LIB_SOURCE $) +else() + set(LIB_SOURCE ${HHEADERS} ${CSOURCES}) +endif() + +# we want it to be called libcurl on all platforms +if(BUILD_STATIC_LIBS) + list(APPEND libcurl_export ${LIB_STATIC}) + add_library(${LIB_STATIC} STATIC ${LIB_SOURCE}) + add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC}) + target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS}) + # Remove the "lib" prefix since the library is already named "libcurl". + set_target_properties(${LIB_STATIC} PROPERTIES + PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}" + SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}" + INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB") + if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") + endif() + if(CURL_HAS_LTO) + set_target_properties(${LIB_STATIC} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) + endif() + if(CMAKEVERSION AND CMAKESONAME) + set_target_properties(${LIB_STATIC} PROPERTIES + VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME}) + endif() + + target_include_directories(${LIB_STATIC} INTERFACE + $ + $) +endif() + +if(BUILD_SHARED_LIBS) + list(APPEND libcurl_export ${LIB_SHARED}) + add_library(${LIB_SHARED} SHARED ${LIB_SOURCE}) + add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED}) + if(WIN32) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc) + if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def") + endif() + endif() + target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS}) + # Remove the "lib" prefix since the library is already named "libcurl". + set_target_properties(${LIB_SHARED} PROPERTIES + PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}" + IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}" + POSITION_INDEPENDENT_CODE ON) + if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") + endif() + if(CURL_HAS_LTO) + set_target_properties(${LIB_SHARED} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) + endif() + if(CMAKEVERSION AND CMAKESONAME) + set_target_properties(${LIB_SHARED} PROPERTIES + VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME}) + endif() + + target_include_directories(${LIB_SHARED} INTERFACE + $ + $) +endif() + +add_library(${LIB_NAME} ALIAS ${LIB_SELECTED}) +add_library(${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_SELECTED}) + +if(CURL_ENABLE_EXPORT_TARGET) + if(BUILD_STATIC_LIBS) + install(TARGETS ${LIB_STATIC} + EXPORT ${TARGETS_EXPORT_NAME} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + endif() + if(BUILD_SHARED_LIBS) + install(TARGETS ${LIB_SHARED} + EXPORT ${TARGETS_EXPORT_NAME} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + endif() + + export(TARGETS ${libcurl_export} + FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake + NAMESPACE ${PROJECT_NAME}:: + ) +endif() diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..1237c8e --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,149 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +AUTOMAKE_OPTIONS = foreign nostdinc + +CMAKE_DIST = CMakeLists.txt curl_config.h.cmake + +EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \ + config-riscos.h config-mac.h curl_config.h.in config-dos.h \ + libcurl.plist libcurl.rc config-amigaos.h config-win32ce.h \ + config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \ + Makefile.soname + +lib_LTLIBRARIES = libcurl.la + +if BUILD_UNITTESTS +noinst_LTLIBRARIES = libcurlu.la +else +noinst_LTLIBRARIES = +endif + +# This might hold -Werror +CFLAGS += @CURL_CFLAG_EXTRAS@ + +# Specify our include paths here, and do it relative to $(top_srcdir) and +# $(top_builddir), to ensure that these paths which belong to the library +# being currently built and tested are searched before the library which +# might possibly already be installed in the system. +# +# $(top_srcdir)/include is for libcurl's external include files +# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file +# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "private" files + +AM_CPPFLAGS = -I$(top_srcdir)/include \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/lib + +# Prevent LIBS from being used for all link targets +LIBS = $(BLANK_AT_MAKETIME) + +include Makefile.soname + +AM_CPPFLAGS += -DBUILDING_LIBCURL +AM_LDFLAGS = +AM_CFLAGS = + +# Makefile.inc provides the CSOURCES and HHEADERS defines +include Makefile.inc + +libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) +libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) + +libcurl_la_CPPFLAGS_EXTRA = +libcurl_la_LDFLAGS_EXTRA = +libcurl_la_CFLAGS_EXTRA = + +if CURL_LT_SHLIB_USE_VERSION_INFO +libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO) +endif + +if CURL_LT_SHLIB_USE_NO_UNDEFINED +libcurl_la_LDFLAGS_EXTRA += -no-undefined +endif + +if CURL_LT_SHLIB_USE_MIMPURE_TEXT +libcurl_la_LDFLAGS_EXTRA += -mimpure-text +endif + +if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS +libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers +else +# if symbol-hiding is enabled, hide them! +if DOING_CURL_SYMBOL_HIDING +libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' +endif +endif + +if USE_CPPFLAG_CURL_STATICLIB +libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB +else +if HAVE_WINDRES +libcurl_la_SOURCES += $(LIB_RCFILES) +$(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h +endif +endif + +if DOING_CURL_SYMBOL_HIDING +libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS +libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) +endif + +libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) +libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS) +libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) + +libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS +libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) +libcurlu_la_CFLAGS = $(AM_CFLAGS) + +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) + +checksrc: + $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \ + -W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch] \ + $(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch]) + +if CURLDEBUG +# for debug builds, we scan the sources on all regular make invokes +all-local: checksrc +endif + +# disable the tests that are mostly causing false positives +TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet + +TIDY:=clang-tidy + +tidy: + $(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H + +optiontable: + perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c + +if HAVE_WINDRES +.rc.lo: + $(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@ +endif diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 0000000..6bdf5cf --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,5422 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@CURL_LT_SHLIB_USE_VERSION_INFO_TRUE@am__append_1 = $(VERSIONINFO) +@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_2 = -no-undefined +@CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE@am__append_3 = -mimpure-text +@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE@am__append_4 = -Wl,--version-script=libcurl.vers +# if symbol-hiding is enabled, hide them! +@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE@@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_5 = -export-symbols-regex '^curl_.*' +@USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_6 = -DCURL_STATICLIB +@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__append_7 = $(LIB_RCFILES) +@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_8 = -DCURL_HIDDEN_SYMBOLS +@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_9 = $(CFLAG_CURL_SYMBOL_HIDING) +subdir = lib +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = curl_config.h +CONFIG_CLEAN_FILES = libcurl.vers libcurl.plist +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) +libcurl_la_LIBADD = +am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \ + asyn-thread.c base64.c bufq.c bufref.c c-hyper.c cf-h1-proxy.c \ + cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-socket.c \ + cfilters.c conncache.c connect.c content_encoding.c cookie.c \ + curl_addrinfo.c curl_des.c curl_endian.c curl_fnmatch.c \ + curl_get_line.c curl_gethostname.c curl_gssapi.c \ + curl_memrchr.c curl_multibyte.c curl_ntlm_core.c \ + curl_ntlm_wb.c curl_path.c curl_range.c curl_rtmp.c \ + curl_sasl.c curl_sspi.c curl_threads.c curl_trc.c dict.c doh.c \ + dynbuf.c dynhds.c easy.c easygetopt.c easyoptions.c escape.c \ + file.c fileinfo.c fopen.c formdata.c ftp.c ftplistparser.c \ + getenv.c getinfo.c gopher.c hash.c headers.c hmac.c hostasyn.c \ + hostip.c hostip4.c hostip6.c hostsyn.c hsts.c http.c http1.c \ + http2.c http_aws_sigv4.c http_chunks.c http_digest.c \ + http_negotiate.c http_ntlm.c http_proxy.c idn.c if2ip.c imap.c \ + inet_ntop.c inet_pton.c krb5.c ldap.c llist.c macos.c md4.c \ + md5.c memdebug.c mime.c mprintf.c mqtt.c multi.c netrc.c \ + nonblock.c noproxy.c openldap.c parsedate.c pingpong.c pop3.c \ + progress.c psl.c rand.c rename.c rtsp.c select.c sendf.c \ + setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c \ + socks.c socks_gssapi.c socks_sspi.c speedcheck.c splay.c \ + strcase.c strdup.c strerror.c strtok.c strtoofft.c \ + system_win32.c telnet.c tftp.c timediff.c timeval.c transfer.c \ + url.c urlapi.c version.c version_win32.c warnless.c ws.c \ + vauth/cleartext.c vauth/cram.c vauth/digest.c \ + vauth/digest_sspi.c vauth/gsasl.c vauth/krb5_gssapi.c \ + vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c \ + vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \ + vauth/vauth.c vtls/bearssl.c vtls/gtls.c vtls/hostcheck.c \ + vtls/keylog.c vtls/mbedtls.c vtls/mbedtls_threadlock.c \ + vtls/openssl.c vtls/rustls.c vtls/schannel.c \ + vtls/schannel_verify.c vtls/sectransp.c vtls/vtls.c \ + vtls/wolfssl.c vtls/x509asn1.c vquic/curl_msh3.c \ + vquic/curl_ngtcp2.c vquic/curl_osslq.c vquic/curl_quiche.c \ + vquic/vquic.c vquic/vquic-tls.c vssh/libssh.c vssh/libssh2.c \ + vssh/wolfssh.c altsvc.h amigaos.h arpa_telnet.h asyn.h bufq.h \ + bufref.h c-hyper.h cf-h1-proxy.h cf-h2-proxy.h cf-haproxy.h \ + cf-https-connect.h cf-socket.h cfilters.h conncache.h \ + connect.h content_encoding.h cookie.h curl_addrinfo.h \ + curl_base64.h curl_ctype.h curl_des.h curl_endian.h \ + curl_fnmatch.h curl_get_line.h curl_gethostname.h \ + curl_gssapi.h curl_hmac.h curl_krb5.h curl_ldap.h curl_md4.h \ + curl_md5.h curl_memory.h curl_memrchr.h curl_multibyte.h \ + curl_ntlm_core.h curl_ntlm_wb.h curl_path.h curl_printf.h \ + curl_range.h curl_rtmp.h curl_sasl.h curl_setup.h \ + curl_setup_once.h curl_sha256.h curl_sspi.h curl_threads.h \ + curl_trc.h curlx.h dict.h doh.h dynbuf.h dynhds.h easy_lock.h \ + easyif.h easyoptions.h escape.h file.h fileinfo.h fopen.h \ + formdata.h ftp.h ftplistparser.h functypes.h getinfo.h \ + gopher.h hash.h headers.h hostip.h hsts.h http.h http1.h \ + http2.h http_aws_sigv4.h http_chunks.h http_digest.h \ + http_negotiate.h http_ntlm.h http_proxy.h idn.h if2ip.h imap.h \ + inet_ntop.h inet_pton.h llist.h macos.h memdebug.h mime.h \ + mqtt.h multihandle.h multiif.h netrc.h nonblock.h noproxy.h \ + parsedate.h pingpong.h pop3.h progress.h psl.h rand.h rename.h \ + rtsp.h select.h sendf.h setopt.h setup-vms.h share.h sigpipe.h \ + slist.h smb.h smtp.h sockaddr.h socketpair.h socks.h \ + speedcheck.h splay.h strcase.h strdup.h strerror.h strtok.h \ + strtoofft.h system_win32.h telnet.h tftp.h timediff.h \ + timeval.h transfer.h url.h urlapi-int.h urldata.h \ + version_win32.h warnless.h ws.h vauth/digest.h vauth/ntlm.h \ + vauth/vauth.h vtls/bearssl.h vtls/gtls.h vtls/hostcheck.h \ + vtls/keylog.h vtls/mbedtls.h vtls/mbedtls_threadlock.h \ + vtls/openssl.h vtls/rustls.h vtls/schannel.h \ + vtls/schannel_int.h vtls/sectransp.h vtls/vtls.h \ + vtls/vtls_int.h vtls/wolfssl.h vtls/x509asn1.h \ + vquic/curl_msh3.h vquic/curl_ngtcp2.h vquic/curl_osslq.h \ + vquic/curl_quiche.h vquic/vquic.h vquic/vquic_int.h \ + vquic/vquic-tls.h vssh/ssh.h libcurl.rc +am__objects_1 = libcurl_la-altsvc.lo libcurl_la-amigaos.lo \ + libcurl_la-asyn-ares.lo libcurl_la-asyn-thread.lo \ + libcurl_la-base64.lo libcurl_la-bufq.lo libcurl_la-bufref.lo \ + libcurl_la-c-hyper.lo libcurl_la-cf-h1-proxy.lo \ + libcurl_la-cf-h2-proxy.lo libcurl_la-cf-haproxy.lo \ + libcurl_la-cf-https-connect.lo libcurl_la-cf-socket.lo \ + libcurl_la-cfilters.lo libcurl_la-conncache.lo \ + libcurl_la-connect.lo libcurl_la-content_encoding.lo \ + libcurl_la-cookie.lo libcurl_la-curl_addrinfo.lo \ + libcurl_la-curl_des.lo libcurl_la-curl_endian.lo \ + libcurl_la-curl_fnmatch.lo libcurl_la-curl_get_line.lo \ + libcurl_la-curl_gethostname.lo libcurl_la-curl_gssapi.lo \ + libcurl_la-curl_memrchr.lo libcurl_la-curl_multibyte.lo \ + libcurl_la-curl_ntlm_core.lo libcurl_la-curl_ntlm_wb.lo \ + libcurl_la-curl_path.lo libcurl_la-curl_range.lo \ + libcurl_la-curl_rtmp.lo libcurl_la-curl_sasl.lo \ + libcurl_la-curl_sspi.lo libcurl_la-curl_threads.lo \ + libcurl_la-curl_trc.lo libcurl_la-dict.lo libcurl_la-doh.lo \ + libcurl_la-dynbuf.lo libcurl_la-dynhds.lo libcurl_la-easy.lo \ + libcurl_la-easygetopt.lo libcurl_la-easyoptions.lo \ + libcurl_la-escape.lo libcurl_la-file.lo libcurl_la-fileinfo.lo \ + libcurl_la-fopen.lo libcurl_la-formdata.lo libcurl_la-ftp.lo \ + libcurl_la-ftplistparser.lo libcurl_la-getenv.lo \ + libcurl_la-getinfo.lo libcurl_la-gopher.lo libcurl_la-hash.lo \ + libcurl_la-headers.lo libcurl_la-hmac.lo \ + libcurl_la-hostasyn.lo libcurl_la-hostip.lo \ + libcurl_la-hostip4.lo libcurl_la-hostip6.lo \ + libcurl_la-hostsyn.lo libcurl_la-hsts.lo libcurl_la-http.lo \ + libcurl_la-http1.lo libcurl_la-http2.lo \ + libcurl_la-http_aws_sigv4.lo libcurl_la-http_chunks.lo \ + libcurl_la-http_digest.lo libcurl_la-http_negotiate.lo \ + libcurl_la-http_ntlm.lo libcurl_la-http_proxy.lo \ + libcurl_la-idn.lo libcurl_la-if2ip.lo libcurl_la-imap.lo \ + libcurl_la-inet_ntop.lo libcurl_la-inet_pton.lo \ + libcurl_la-krb5.lo libcurl_la-ldap.lo libcurl_la-llist.lo \ + libcurl_la-macos.lo libcurl_la-md4.lo libcurl_la-md5.lo \ + libcurl_la-memdebug.lo libcurl_la-mime.lo \ + libcurl_la-mprintf.lo libcurl_la-mqtt.lo libcurl_la-multi.lo \ + libcurl_la-netrc.lo libcurl_la-nonblock.lo \ + libcurl_la-noproxy.lo libcurl_la-openldap.lo \ + libcurl_la-parsedate.lo libcurl_la-pingpong.lo \ + libcurl_la-pop3.lo libcurl_la-progress.lo libcurl_la-psl.lo \ + libcurl_la-rand.lo libcurl_la-rename.lo libcurl_la-rtsp.lo \ + libcurl_la-select.lo libcurl_la-sendf.lo libcurl_la-setopt.lo \ + libcurl_la-sha256.lo libcurl_la-share.lo libcurl_la-slist.lo \ + libcurl_la-smb.lo libcurl_la-smtp.lo libcurl_la-socketpair.lo \ + libcurl_la-socks.lo libcurl_la-socks_gssapi.lo \ + libcurl_la-socks_sspi.lo libcurl_la-speedcheck.lo \ + libcurl_la-splay.lo libcurl_la-strcase.lo libcurl_la-strdup.lo \ + libcurl_la-strerror.lo libcurl_la-strtok.lo \ + libcurl_la-strtoofft.lo libcurl_la-system_win32.lo \ + libcurl_la-telnet.lo libcurl_la-tftp.lo libcurl_la-timediff.lo \ + libcurl_la-timeval.lo libcurl_la-transfer.lo libcurl_la-url.lo \ + libcurl_la-urlapi.lo libcurl_la-version.lo \ + libcurl_la-version_win32.lo libcurl_la-warnless.lo \ + libcurl_la-ws.lo +am__dirstamp = $(am__leading_dot)dirstamp +am__objects_2 = vauth/libcurl_la-cleartext.lo vauth/libcurl_la-cram.lo \ + vauth/libcurl_la-digest.lo vauth/libcurl_la-digest_sspi.lo \ + vauth/libcurl_la-gsasl.lo vauth/libcurl_la-krb5_gssapi.lo \ + vauth/libcurl_la-krb5_sspi.lo vauth/libcurl_la-ntlm.lo \ + vauth/libcurl_la-ntlm_sspi.lo vauth/libcurl_la-oauth2.lo \ + vauth/libcurl_la-spnego_gssapi.lo \ + vauth/libcurl_la-spnego_sspi.lo vauth/libcurl_la-vauth.lo +am__objects_3 = vtls/libcurl_la-bearssl.lo vtls/libcurl_la-gtls.lo \ + vtls/libcurl_la-hostcheck.lo vtls/libcurl_la-keylog.lo \ + vtls/libcurl_la-mbedtls.lo \ + vtls/libcurl_la-mbedtls_threadlock.lo \ + vtls/libcurl_la-openssl.lo vtls/libcurl_la-rustls.lo \ + vtls/libcurl_la-schannel.lo vtls/libcurl_la-schannel_verify.lo \ + vtls/libcurl_la-sectransp.lo vtls/libcurl_la-vtls.lo \ + vtls/libcurl_la-wolfssl.lo vtls/libcurl_la-x509asn1.lo +am__objects_4 = vquic/libcurl_la-curl_msh3.lo \ + vquic/libcurl_la-curl_ngtcp2.lo vquic/libcurl_la-curl_osslq.lo \ + vquic/libcurl_la-curl_quiche.lo vquic/libcurl_la-vquic.lo \ + vquic/libcurl_la-vquic-tls.lo +am__objects_5 = vssh/libcurl_la-libssh.lo vssh/libcurl_la-libssh2.lo \ + vssh/libcurl_la-wolfssh.lo +am__objects_6 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + $(am__objects_4) $(am__objects_5) +am__objects_7 = +am__objects_8 = $(am__objects_7) $(am__objects_7) $(am__objects_7) \ + $(am__objects_7) $(am__objects_7) +am__objects_9 = libcurl.lo +@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__objects_10 = $(am__objects_9) +am_libcurl_la_OBJECTS = $(am__objects_6) $(am__objects_8) \ + $(am__objects_10) +libcurl_la_OBJECTS = $(am_libcurl_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libcurl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libcurl_la_CFLAGS) \ + $(CFLAGS) $(libcurl_la_LDFLAGS) $(LDFLAGS) -o $@ +libcurlu_la_LIBADD = +am__objects_11 = libcurlu_la-altsvc.lo libcurlu_la-amigaos.lo \ + libcurlu_la-asyn-ares.lo libcurlu_la-asyn-thread.lo \ + libcurlu_la-base64.lo libcurlu_la-bufq.lo \ + libcurlu_la-bufref.lo libcurlu_la-c-hyper.lo \ + libcurlu_la-cf-h1-proxy.lo libcurlu_la-cf-h2-proxy.lo \ + libcurlu_la-cf-haproxy.lo libcurlu_la-cf-https-connect.lo \ + libcurlu_la-cf-socket.lo libcurlu_la-cfilters.lo \ + libcurlu_la-conncache.lo libcurlu_la-connect.lo \ + libcurlu_la-content_encoding.lo libcurlu_la-cookie.lo \ + libcurlu_la-curl_addrinfo.lo libcurlu_la-curl_des.lo \ + libcurlu_la-curl_endian.lo libcurlu_la-curl_fnmatch.lo \ + libcurlu_la-curl_get_line.lo libcurlu_la-curl_gethostname.lo \ + libcurlu_la-curl_gssapi.lo libcurlu_la-curl_memrchr.lo \ + libcurlu_la-curl_multibyte.lo libcurlu_la-curl_ntlm_core.lo \ + libcurlu_la-curl_ntlm_wb.lo libcurlu_la-curl_path.lo \ + libcurlu_la-curl_range.lo libcurlu_la-curl_rtmp.lo \ + libcurlu_la-curl_sasl.lo libcurlu_la-curl_sspi.lo \ + libcurlu_la-curl_threads.lo libcurlu_la-curl_trc.lo \ + libcurlu_la-dict.lo libcurlu_la-doh.lo libcurlu_la-dynbuf.lo \ + libcurlu_la-dynhds.lo libcurlu_la-easy.lo \ + libcurlu_la-easygetopt.lo libcurlu_la-easyoptions.lo \ + libcurlu_la-escape.lo libcurlu_la-file.lo \ + libcurlu_la-fileinfo.lo libcurlu_la-fopen.lo \ + libcurlu_la-formdata.lo libcurlu_la-ftp.lo \ + libcurlu_la-ftplistparser.lo libcurlu_la-getenv.lo \ + libcurlu_la-getinfo.lo libcurlu_la-gopher.lo \ + libcurlu_la-hash.lo libcurlu_la-headers.lo libcurlu_la-hmac.lo \ + libcurlu_la-hostasyn.lo libcurlu_la-hostip.lo \ + libcurlu_la-hostip4.lo libcurlu_la-hostip6.lo \ + libcurlu_la-hostsyn.lo libcurlu_la-hsts.lo libcurlu_la-http.lo \ + libcurlu_la-http1.lo libcurlu_la-http2.lo \ + libcurlu_la-http_aws_sigv4.lo libcurlu_la-http_chunks.lo \ + libcurlu_la-http_digest.lo libcurlu_la-http_negotiate.lo \ + libcurlu_la-http_ntlm.lo libcurlu_la-http_proxy.lo \ + libcurlu_la-idn.lo libcurlu_la-if2ip.lo libcurlu_la-imap.lo \ + libcurlu_la-inet_ntop.lo libcurlu_la-inet_pton.lo \ + libcurlu_la-krb5.lo libcurlu_la-ldap.lo libcurlu_la-llist.lo \ + libcurlu_la-macos.lo libcurlu_la-md4.lo libcurlu_la-md5.lo \ + libcurlu_la-memdebug.lo libcurlu_la-mime.lo \ + libcurlu_la-mprintf.lo libcurlu_la-mqtt.lo \ + libcurlu_la-multi.lo libcurlu_la-netrc.lo \ + libcurlu_la-nonblock.lo libcurlu_la-noproxy.lo \ + libcurlu_la-openldap.lo libcurlu_la-parsedate.lo \ + libcurlu_la-pingpong.lo libcurlu_la-pop3.lo \ + libcurlu_la-progress.lo libcurlu_la-psl.lo libcurlu_la-rand.lo \ + libcurlu_la-rename.lo libcurlu_la-rtsp.lo \ + libcurlu_la-select.lo libcurlu_la-sendf.lo \ + libcurlu_la-setopt.lo libcurlu_la-sha256.lo \ + libcurlu_la-share.lo libcurlu_la-slist.lo libcurlu_la-smb.lo \ + libcurlu_la-smtp.lo libcurlu_la-socketpair.lo \ + libcurlu_la-socks.lo libcurlu_la-socks_gssapi.lo \ + libcurlu_la-socks_sspi.lo libcurlu_la-speedcheck.lo \ + libcurlu_la-splay.lo libcurlu_la-strcase.lo \ + libcurlu_la-strdup.lo libcurlu_la-strerror.lo \ + libcurlu_la-strtok.lo libcurlu_la-strtoofft.lo \ + libcurlu_la-system_win32.lo libcurlu_la-telnet.lo \ + libcurlu_la-tftp.lo libcurlu_la-timediff.lo \ + libcurlu_la-timeval.lo libcurlu_la-transfer.lo \ + libcurlu_la-url.lo libcurlu_la-urlapi.lo \ + libcurlu_la-version.lo libcurlu_la-version_win32.lo \ + libcurlu_la-warnless.lo libcurlu_la-ws.lo +am__objects_12 = vauth/libcurlu_la-cleartext.lo \ + vauth/libcurlu_la-cram.lo vauth/libcurlu_la-digest.lo \ + vauth/libcurlu_la-digest_sspi.lo vauth/libcurlu_la-gsasl.lo \ + vauth/libcurlu_la-krb5_gssapi.lo \ + vauth/libcurlu_la-krb5_sspi.lo vauth/libcurlu_la-ntlm.lo \ + vauth/libcurlu_la-ntlm_sspi.lo vauth/libcurlu_la-oauth2.lo \ + vauth/libcurlu_la-spnego_gssapi.lo \ + vauth/libcurlu_la-spnego_sspi.lo vauth/libcurlu_la-vauth.lo +am__objects_13 = vtls/libcurlu_la-bearssl.lo vtls/libcurlu_la-gtls.lo \ + vtls/libcurlu_la-hostcheck.lo vtls/libcurlu_la-keylog.lo \ + vtls/libcurlu_la-mbedtls.lo \ + vtls/libcurlu_la-mbedtls_threadlock.lo \ + vtls/libcurlu_la-openssl.lo vtls/libcurlu_la-rustls.lo \ + vtls/libcurlu_la-schannel.lo \ + vtls/libcurlu_la-schannel_verify.lo \ + vtls/libcurlu_la-sectransp.lo vtls/libcurlu_la-vtls.lo \ + vtls/libcurlu_la-wolfssl.lo vtls/libcurlu_la-x509asn1.lo +am__objects_14 = vquic/libcurlu_la-curl_msh3.lo \ + vquic/libcurlu_la-curl_ngtcp2.lo \ + vquic/libcurlu_la-curl_osslq.lo \ + vquic/libcurlu_la-curl_quiche.lo vquic/libcurlu_la-vquic.lo \ + vquic/libcurlu_la-vquic-tls.lo +am__objects_15 = vssh/libcurlu_la-libssh.lo \ + vssh/libcurlu_la-libssh2.lo vssh/libcurlu_la-wolfssh.lo +am__objects_16 = $(am__objects_11) $(am__objects_12) $(am__objects_13) \ + $(am__objects_14) $(am__objects_15) +am_libcurlu_la_OBJECTS = $(am__objects_16) $(am__objects_8) +libcurlu_la_OBJECTS = $(am_libcurlu_la_OBJECTS) +libcurlu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libcurlu_la_CFLAGS) \ + $(CFLAGS) $(libcurlu_la_LDFLAGS) $(LDFLAGS) -o $@ +@BUILD_UNITTESTS_TRUE@am_libcurlu_la_rpath = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ + ./$(DEPDIR)/libcurl_la-amigaos.Plo \ + ./$(DEPDIR)/libcurl_la-asyn-ares.Plo \ + ./$(DEPDIR)/libcurl_la-asyn-thread.Plo \ + ./$(DEPDIR)/libcurl_la-base64.Plo \ + ./$(DEPDIR)/libcurl_la-bufq.Plo \ + ./$(DEPDIR)/libcurl_la-bufref.Plo \ + ./$(DEPDIR)/libcurl_la-c-hyper.Plo \ + ./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo \ + ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo \ + ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo \ + ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo \ + ./$(DEPDIR)/libcurl_la-cf-socket.Plo \ + ./$(DEPDIR)/libcurl_la-cfilters.Plo \ + ./$(DEPDIR)/libcurl_la-conncache.Plo \ + ./$(DEPDIR)/libcurl_la-connect.Plo \ + ./$(DEPDIR)/libcurl_la-content_encoding.Plo \ + ./$(DEPDIR)/libcurl_la-cookie.Plo \ + ./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo \ + ./$(DEPDIR)/libcurl_la-curl_des.Plo \ + ./$(DEPDIR)/libcurl_la-curl_endian.Plo \ + ./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo \ + ./$(DEPDIR)/libcurl_la-curl_get_line.Plo \ + ./$(DEPDIR)/libcurl_la-curl_gethostname.Plo \ + ./$(DEPDIR)/libcurl_la-curl_gssapi.Plo \ + ./$(DEPDIR)/libcurl_la-curl_memrchr.Plo \ + ./$(DEPDIR)/libcurl_la-curl_multibyte.Plo \ + ./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo \ + ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo \ + ./$(DEPDIR)/libcurl_la-curl_path.Plo \ + ./$(DEPDIR)/libcurl_la-curl_range.Plo \ + ./$(DEPDIR)/libcurl_la-curl_rtmp.Plo \ + ./$(DEPDIR)/libcurl_la-curl_sasl.Plo \ + ./$(DEPDIR)/libcurl_la-curl_sspi.Plo \ + ./$(DEPDIR)/libcurl_la-curl_threads.Plo \ + ./$(DEPDIR)/libcurl_la-curl_trc.Plo \ + ./$(DEPDIR)/libcurl_la-dict.Plo ./$(DEPDIR)/libcurl_la-doh.Plo \ + ./$(DEPDIR)/libcurl_la-dynbuf.Plo \ + ./$(DEPDIR)/libcurl_la-dynhds.Plo \ + ./$(DEPDIR)/libcurl_la-easy.Plo \ + ./$(DEPDIR)/libcurl_la-easygetopt.Plo \ + ./$(DEPDIR)/libcurl_la-easyoptions.Plo \ + ./$(DEPDIR)/libcurl_la-escape.Plo \ + ./$(DEPDIR)/libcurl_la-file.Plo \ + ./$(DEPDIR)/libcurl_la-fileinfo.Plo \ + ./$(DEPDIR)/libcurl_la-fopen.Plo \ + ./$(DEPDIR)/libcurl_la-formdata.Plo \ + ./$(DEPDIR)/libcurl_la-ftp.Plo \ + ./$(DEPDIR)/libcurl_la-ftplistparser.Plo \ + ./$(DEPDIR)/libcurl_la-getenv.Plo \ + ./$(DEPDIR)/libcurl_la-getinfo.Plo \ + ./$(DEPDIR)/libcurl_la-gopher.Plo \ + ./$(DEPDIR)/libcurl_la-hash.Plo \ + ./$(DEPDIR)/libcurl_la-headers.Plo \ + ./$(DEPDIR)/libcurl_la-hmac.Plo \ + ./$(DEPDIR)/libcurl_la-hostasyn.Plo \ + ./$(DEPDIR)/libcurl_la-hostip.Plo \ + ./$(DEPDIR)/libcurl_la-hostip4.Plo \ + ./$(DEPDIR)/libcurl_la-hostip6.Plo \ + ./$(DEPDIR)/libcurl_la-hostsyn.Plo \ + ./$(DEPDIR)/libcurl_la-hsts.Plo \ + ./$(DEPDIR)/libcurl_la-http.Plo \ + ./$(DEPDIR)/libcurl_la-http1.Plo \ + ./$(DEPDIR)/libcurl_la-http2.Plo \ + ./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo \ + ./$(DEPDIR)/libcurl_la-http_chunks.Plo \ + ./$(DEPDIR)/libcurl_la-http_digest.Plo \ + ./$(DEPDIR)/libcurl_la-http_negotiate.Plo \ + ./$(DEPDIR)/libcurl_la-http_ntlm.Plo \ + ./$(DEPDIR)/libcurl_la-http_proxy.Plo \ + ./$(DEPDIR)/libcurl_la-idn.Plo \ + ./$(DEPDIR)/libcurl_la-if2ip.Plo \ + ./$(DEPDIR)/libcurl_la-imap.Plo \ + ./$(DEPDIR)/libcurl_la-inet_ntop.Plo \ + ./$(DEPDIR)/libcurl_la-inet_pton.Plo \ + ./$(DEPDIR)/libcurl_la-krb5.Plo \ + ./$(DEPDIR)/libcurl_la-ldap.Plo \ + ./$(DEPDIR)/libcurl_la-llist.Plo \ + ./$(DEPDIR)/libcurl_la-macos.Plo \ + ./$(DEPDIR)/libcurl_la-md4.Plo ./$(DEPDIR)/libcurl_la-md5.Plo \ + ./$(DEPDIR)/libcurl_la-memdebug.Plo \ + ./$(DEPDIR)/libcurl_la-mime.Plo \ + ./$(DEPDIR)/libcurl_la-mprintf.Plo \ + ./$(DEPDIR)/libcurl_la-mqtt.Plo \ + ./$(DEPDIR)/libcurl_la-multi.Plo \ + ./$(DEPDIR)/libcurl_la-netrc.Plo \ + ./$(DEPDIR)/libcurl_la-nonblock.Plo \ + ./$(DEPDIR)/libcurl_la-noproxy.Plo \ + ./$(DEPDIR)/libcurl_la-openldap.Plo \ + ./$(DEPDIR)/libcurl_la-parsedate.Plo \ + ./$(DEPDIR)/libcurl_la-pingpong.Plo \ + ./$(DEPDIR)/libcurl_la-pop3.Plo \ + ./$(DEPDIR)/libcurl_la-progress.Plo \ + ./$(DEPDIR)/libcurl_la-psl.Plo ./$(DEPDIR)/libcurl_la-rand.Plo \ + ./$(DEPDIR)/libcurl_la-rename.Plo \ + ./$(DEPDIR)/libcurl_la-rtsp.Plo \ + ./$(DEPDIR)/libcurl_la-select.Plo \ + ./$(DEPDIR)/libcurl_la-sendf.Plo \ + ./$(DEPDIR)/libcurl_la-setopt.Plo \ + ./$(DEPDIR)/libcurl_la-sha256.Plo \ + ./$(DEPDIR)/libcurl_la-share.Plo \ + ./$(DEPDIR)/libcurl_la-slist.Plo \ + ./$(DEPDIR)/libcurl_la-smb.Plo ./$(DEPDIR)/libcurl_la-smtp.Plo \ + ./$(DEPDIR)/libcurl_la-socketpair.Plo \ + ./$(DEPDIR)/libcurl_la-socks.Plo \ + ./$(DEPDIR)/libcurl_la-socks_gssapi.Plo \ + ./$(DEPDIR)/libcurl_la-socks_sspi.Plo \ + ./$(DEPDIR)/libcurl_la-speedcheck.Plo \ + ./$(DEPDIR)/libcurl_la-splay.Plo \ + ./$(DEPDIR)/libcurl_la-strcase.Plo \ + ./$(DEPDIR)/libcurl_la-strdup.Plo \ + ./$(DEPDIR)/libcurl_la-strerror.Plo \ + ./$(DEPDIR)/libcurl_la-strtok.Plo \ + ./$(DEPDIR)/libcurl_la-strtoofft.Plo \ + ./$(DEPDIR)/libcurl_la-system_win32.Plo \ + ./$(DEPDIR)/libcurl_la-telnet.Plo \ + ./$(DEPDIR)/libcurl_la-tftp.Plo \ + ./$(DEPDIR)/libcurl_la-timediff.Plo \ + ./$(DEPDIR)/libcurl_la-timeval.Plo \ + ./$(DEPDIR)/libcurl_la-transfer.Plo \ + ./$(DEPDIR)/libcurl_la-url.Plo \ + ./$(DEPDIR)/libcurl_la-urlapi.Plo \ + ./$(DEPDIR)/libcurl_la-version.Plo \ + ./$(DEPDIR)/libcurl_la-version_win32.Plo \ + ./$(DEPDIR)/libcurl_la-warnless.Plo \ + ./$(DEPDIR)/libcurl_la-ws.Plo \ + ./$(DEPDIR)/libcurlu_la-altsvc.Plo \ + ./$(DEPDIR)/libcurlu_la-amigaos.Plo \ + ./$(DEPDIR)/libcurlu_la-asyn-ares.Plo \ + ./$(DEPDIR)/libcurlu_la-asyn-thread.Plo \ + ./$(DEPDIR)/libcurlu_la-base64.Plo \ + ./$(DEPDIR)/libcurlu_la-bufq.Plo \ + ./$(DEPDIR)/libcurlu_la-bufref.Plo \ + ./$(DEPDIR)/libcurlu_la-c-hyper.Plo \ + ./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo \ + ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo \ + ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo \ + ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo \ + ./$(DEPDIR)/libcurlu_la-cf-socket.Plo \ + ./$(DEPDIR)/libcurlu_la-cfilters.Plo \ + ./$(DEPDIR)/libcurlu_la-conncache.Plo \ + ./$(DEPDIR)/libcurlu_la-connect.Plo \ + ./$(DEPDIR)/libcurlu_la-content_encoding.Plo \ + ./$(DEPDIR)/libcurlu_la-cookie.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_des.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_endian.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_get_line.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_path.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_range.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_sasl.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_sspi.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_threads.Plo \ + ./$(DEPDIR)/libcurlu_la-curl_trc.Plo \ + ./$(DEPDIR)/libcurlu_la-dict.Plo \ + ./$(DEPDIR)/libcurlu_la-doh.Plo \ + ./$(DEPDIR)/libcurlu_la-dynbuf.Plo \ + ./$(DEPDIR)/libcurlu_la-dynhds.Plo \ + ./$(DEPDIR)/libcurlu_la-easy.Plo \ + ./$(DEPDIR)/libcurlu_la-easygetopt.Plo \ + ./$(DEPDIR)/libcurlu_la-easyoptions.Plo \ + ./$(DEPDIR)/libcurlu_la-escape.Plo \ + ./$(DEPDIR)/libcurlu_la-file.Plo \ + ./$(DEPDIR)/libcurlu_la-fileinfo.Plo \ + ./$(DEPDIR)/libcurlu_la-fopen.Plo \ + ./$(DEPDIR)/libcurlu_la-formdata.Plo \ + ./$(DEPDIR)/libcurlu_la-ftp.Plo \ + ./$(DEPDIR)/libcurlu_la-ftplistparser.Plo \ + ./$(DEPDIR)/libcurlu_la-getenv.Plo \ + ./$(DEPDIR)/libcurlu_la-getinfo.Plo \ + ./$(DEPDIR)/libcurlu_la-gopher.Plo \ + ./$(DEPDIR)/libcurlu_la-hash.Plo \ + ./$(DEPDIR)/libcurlu_la-headers.Plo \ + ./$(DEPDIR)/libcurlu_la-hmac.Plo \ + ./$(DEPDIR)/libcurlu_la-hostasyn.Plo \ + ./$(DEPDIR)/libcurlu_la-hostip.Plo \ + ./$(DEPDIR)/libcurlu_la-hostip4.Plo \ + ./$(DEPDIR)/libcurlu_la-hostip6.Plo \ + ./$(DEPDIR)/libcurlu_la-hostsyn.Plo \ + ./$(DEPDIR)/libcurlu_la-hsts.Plo \ + ./$(DEPDIR)/libcurlu_la-http.Plo \ + ./$(DEPDIR)/libcurlu_la-http1.Plo \ + ./$(DEPDIR)/libcurlu_la-http2.Plo \ + ./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo \ + ./$(DEPDIR)/libcurlu_la-http_chunks.Plo \ + ./$(DEPDIR)/libcurlu_la-http_digest.Plo \ + ./$(DEPDIR)/libcurlu_la-http_negotiate.Plo \ + ./$(DEPDIR)/libcurlu_la-http_ntlm.Plo \ + ./$(DEPDIR)/libcurlu_la-http_proxy.Plo \ + ./$(DEPDIR)/libcurlu_la-idn.Plo \ + ./$(DEPDIR)/libcurlu_la-if2ip.Plo \ + ./$(DEPDIR)/libcurlu_la-imap.Plo \ + ./$(DEPDIR)/libcurlu_la-inet_ntop.Plo \ + ./$(DEPDIR)/libcurlu_la-inet_pton.Plo \ + ./$(DEPDIR)/libcurlu_la-krb5.Plo \ + ./$(DEPDIR)/libcurlu_la-ldap.Plo \ + ./$(DEPDIR)/libcurlu_la-llist.Plo \ + ./$(DEPDIR)/libcurlu_la-macos.Plo \ + ./$(DEPDIR)/libcurlu_la-md4.Plo \ + ./$(DEPDIR)/libcurlu_la-md5.Plo \ + ./$(DEPDIR)/libcurlu_la-memdebug.Plo \ + ./$(DEPDIR)/libcurlu_la-mime.Plo \ + ./$(DEPDIR)/libcurlu_la-mprintf.Plo \ + ./$(DEPDIR)/libcurlu_la-mqtt.Plo \ + ./$(DEPDIR)/libcurlu_la-multi.Plo \ + ./$(DEPDIR)/libcurlu_la-netrc.Plo \ + ./$(DEPDIR)/libcurlu_la-nonblock.Plo \ + ./$(DEPDIR)/libcurlu_la-noproxy.Plo \ + ./$(DEPDIR)/libcurlu_la-openldap.Plo \ + ./$(DEPDIR)/libcurlu_la-parsedate.Plo \ + ./$(DEPDIR)/libcurlu_la-pingpong.Plo \ + ./$(DEPDIR)/libcurlu_la-pop3.Plo \ + ./$(DEPDIR)/libcurlu_la-progress.Plo \ + ./$(DEPDIR)/libcurlu_la-psl.Plo \ + ./$(DEPDIR)/libcurlu_la-rand.Plo \ + ./$(DEPDIR)/libcurlu_la-rename.Plo \ + ./$(DEPDIR)/libcurlu_la-rtsp.Plo \ + ./$(DEPDIR)/libcurlu_la-select.Plo \ + ./$(DEPDIR)/libcurlu_la-sendf.Plo \ + ./$(DEPDIR)/libcurlu_la-setopt.Plo \ + ./$(DEPDIR)/libcurlu_la-sha256.Plo \ + ./$(DEPDIR)/libcurlu_la-share.Plo \ + ./$(DEPDIR)/libcurlu_la-slist.Plo \ + ./$(DEPDIR)/libcurlu_la-smb.Plo \ + ./$(DEPDIR)/libcurlu_la-smtp.Plo \ + ./$(DEPDIR)/libcurlu_la-socketpair.Plo \ + ./$(DEPDIR)/libcurlu_la-socks.Plo \ + ./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo \ + ./$(DEPDIR)/libcurlu_la-socks_sspi.Plo \ + ./$(DEPDIR)/libcurlu_la-speedcheck.Plo \ + ./$(DEPDIR)/libcurlu_la-splay.Plo \ + ./$(DEPDIR)/libcurlu_la-strcase.Plo \ + ./$(DEPDIR)/libcurlu_la-strdup.Plo \ + ./$(DEPDIR)/libcurlu_la-strerror.Plo \ + ./$(DEPDIR)/libcurlu_la-strtok.Plo \ + ./$(DEPDIR)/libcurlu_la-strtoofft.Plo \ + ./$(DEPDIR)/libcurlu_la-system_win32.Plo \ + ./$(DEPDIR)/libcurlu_la-telnet.Plo \ + ./$(DEPDIR)/libcurlu_la-tftp.Plo \ + ./$(DEPDIR)/libcurlu_la-timediff.Plo \ + ./$(DEPDIR)/libcurlu_la-timeval.Plo \ + ./$(DEPDIR)/libcurlu_la-transfer.Plo \ + ./$(DEPDIR)/libcurlu_la-url.Plo \ + ./$(DEPDIR)/libcurlu_la-urlapi.Plo \ + ./$(DEPDIR)/libcurlu_la-version.Plo \ + ./$(DEPDIR)/libcurlu_la-version_win32.Plo \ + ./$(DEPDIR)/libcurlu_la-warnless.Plo \ + ./$(DEPDIR)/libcurlu_la-ws.Plo \ + vauth/$(DEPDIR)/libcurl_la-cleartext.Plo \ + vauth/$(DEPDIR)/libcurl_la-cram.Plo \ + vauth/$(DEPDIR)/libcurl_la-digest.Plo \ + vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo \ + vauth/$(DEPDIR)/libcurl_la-gsasl.Plo \ + vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo \ + vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo \ + vauth/$(DEPDIR)/libcurl_la-ntlm.Plo \ + vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo \ + vauth/$(DEPDIR)/libcurl_la-oauth2.Plo \ + vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo \ + vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo \ + vauth/$(DEPDIR)/libcurl_la-vauth.Plo \ + vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo \ + vauth/$(DEPDIR)/libcurlu_la-cram.Plo \ + vauth/$(DEPDIR)/libcurlu_la-digest.Plo \ + vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo \ + vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo \ + vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo \ + vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo \ + vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo \ + vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo \ + vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo \ + vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo \ + vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo \ + vauth/$(DEPDIR)/libcurlu_la-vauth.Plo \ + vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo \ + vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo \ + vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo \ + vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo \ + vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo \ + vquic/$(DEPDIR)/libcurl_la-vquic.Plo \ + vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo \ + vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo \ + vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo \ + vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo \ + vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo \ + vquic/$(DEPDIR)/libcurlu_la-vquic.Plo \ + vssh/$(DEPDIR)/libcurl_la-libssh.Plo \ + vssh/$(DEPDIR)/libcurl_la-libssh2.Plo \ + vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo \ + vssh/$(DEPDIR)/libcurlu_la-libssh.Plo \ + vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo \ + vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo \ + vtls/$(DEPDIR)/libcurl_la-bearssl.Plo \ + vtls/$(DEPDIR)/libcurl_la-gtls.Plo \ + vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo \ + vtls/$(DEPDIR)/libcurl_la-keylog.Plo \ + vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo \ + vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo \ + vtls/$(DEPDIR)/libcurl_la-openssl.Plo \ + vtls/$(DEPDIR)/libcurl_la-rustls.Plo \ + vtls/$(DEPDIR)/libcurl_la-schannel.Plo \ + vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo \ + vtls/$(DEPDIR)/libcurl_la-sectransp.Plo \ + vtls/$(DEPDIR)/libcurl_la-vtls.Plo \ + vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo \ + vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo \ + vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo \ + vtls/$(DEPDIR)/libcurlu_la-gtls.Plo \ + vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo \ + vtls/$(DEPDIR)/libcurlu_la-keylog.Plo \ + vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo \ + vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo \ + vtls/$(DEPDIR)/libcurlu_la-openssl.Plo \ + vtls/$(DEPDIR)/libcurlu_la-rustls.Plo \ + vtls/$(DEPDIR)/libcurlu_la-schannel.Plo \ + vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo \ + vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo \ + vtls/$(DEPDIR)/libcurlu_la-vtls.Plo \ + vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo \ + vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libcurl_la_SOURCES) $(libcurlu_la_SOURCES) +DIST_SOURCES = $(am__libcurl_la_SOURCES_DIST) $(libcurlu_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ + curl_config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc \ + $(srcdir)/Makefile.soname $(srcdir)/curl_config.h.in \ + $(srcdir)/libcurl.plist.in $(srcdir)/libcurl.vers.in \ + $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ + +# This might hold -Werror +CFLAGS = @CFLAGS@ @CURL_CFLAG_EXTRAS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ + +# Prevent LIBS from being used for all link targets +LIBS = $(BLANK_AT_MAKETIME) +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +AUTOMAKE_OPTIONS = foreign nostdinc +CMAKE_DIST = CMakeLists.txt curl_config.h.cmake +EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \ + config-riscos.h config-mac.h curl_config.h.in config-dos.h \ + libcurl.plist libcurl.rc config-amigaos.h config-win32ce.h \ + config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \ + Makefile.soname + +lib_LTLIBRARIES = libcurl.la +@BUILD_UNITTESTS_FALSE@noinst_LTLIBRARIES = +@BUILD_UNITTESTS_TRUE@noinst_LTLIBRARIES = libcurlu.la + +# Specify our include paths here, and do it relative to $(top_srcdir) and +# $(top_builddir), to ensure that these paths which belong to the library +# being currently built and tested are searched before the library which +# might possibly already be installed in the system. +# +# $(top_srcdir)/include is for libcurl's external include files +# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file +# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "private" files +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/lib \ + -I$(top_srcdir)/lib -DBUILDING_LIBCURL +VERSIONCHANGE = 12 +VERSIONADD = 0 +VERSIONDEL = 8 + +# libtool version: +VERSIONINFO = -version-info $(VERSIONCHANGE):$(VERSIONADD):$(VERSIONDEL) +AM_LDFLAGS = +AM_CFLAGS = +LIB_VAUTH_CFILES = \ + vauth/cleartext.c \ + vauth/cram.c \ + vauth/digest.c \ + vauth/digest_sspi.c \ + vauth/gsasl.c \ + vauth/krb5_gssapi.c \ + vauth/krb5_sspi.c \ + vauth/ntlm.c \ + vauth/ntlm_sspi.c \ + vauth/oauth2.c \ + vauth/spnego_gssapi.c \ + vauth/spnego_sspi.c \ + vauth/vauth.c + +LIB_VAUTH_HFILES = \ + vauth/digest.h \ + vauth/ntlm.h \ + vauth/vauth.h + +LIB_VTLS_CFILES = \ + vtls/bearssl.c \ + vtls/gtls.c \ + vtls/hostcheck.c \ + vtls/keylog.c \ + vtls/mbedtls.c \ + vtls/mbedtls_threadlock.c \ + vtls/openssl.c \ + vtls/rustls.c \ + vtls/schannel.c \ + vtls/schannel_verify.c \ + vtls/sectransp.c \ + vtls/vtls.c \ + vtls/wolfssl.c \ + vtls/x509asn1.c + +LIB_VTLS_HFILES = \ + vtls/bearssl.h \ + vtls/gtls.h \ + vtls/hostcheck.h \ + vtls/keylog.h \ + vtls/mbedtls.h \ + vtls/mbedtls_threadlock.h \ + vtls/openssl.h \ + vtls/rustls.h \ + vtls/schannel.h \ + vtls/schannel_int.h \ + vtls/sectransp.h \ + vtls/vtls.h \ + vtls/vtls_int.h \ + vtls/wolfssl.h \ + vtls/x509asn1.h + +LIB_VQUIC_CFILES = \ + vquic/curl_msh3.c \ + vquic/curl_ngtcp2.c \ + vquic/curl_osslq.c \ + vquic/curl_quiche.c \ + vquic/vquic.c \ + vquic/vquic-tls.c + +LIB_VQUIC_HFILES = \ + vquic/curl_msh3.h \ + vquic/curl_ngtcp2.h \ + vquic/curl_osslq.h \ + vquic/curl_quiche.h \ + vquic/vquic.h \ + vquic/vquic_int.h \ + vquic/vquic-tls.h + +LIB_VSSH_CFILES = \ + vssh/libssh.c \ + vssh/libssh2.c \ + vssh/wolfssh.c + +LIB_VSSH_HFILES = \ + vssh/ssh.h + +LIB_CFILES = \ + altsvc.c \ + amigaos.c \ + asyn-ares.c \ + asyn-thread.c \ + base64.c \ + bufq.c \ + bufref.c \ + c-hyper.c \ + cf-h1-proxy.c \ + cf-h2-proxy.c \ + cf-haproxy.c \ + cf-https-connect.c \ + cf-socket.c \ + cfilters.c \ + conncache.c \ + connect.c \ + content_encoding.c \ + cookie.c \ + curl_addrinfo.c \ + curl_des.c \ + curl_endian.c \ + curl_fnmatch.c \ + curl_get_line.c \ + curl_gethostname.c \ + curl_gssapi.c \ + curl_memrchr.c \ + curl_multibyte.c \ + curl_ntlm_core.c \ + curl_ntlm_wb.c \ + curl_path.c \ + curl_range.c \ + curl_rtmp.c \ + curl_sasl.c \ + curl_sspi.c \ + curl_threads.c \ + curl_trc.c \ + dict.c \ + doh.c \ + dynbuf.c \ + dynhds.c \ + easy.c \ + easygetopt.c \ + easyoptions.c \ + escape.c \ + file.c \ + fileinfo.c \ + fopen.c \ + formdata.c \ + ftp.c \ + ftplistparser.c \ + getenv.c \ + getinfo.c \ + gopher.c \ + hash.c \ + headers.c \ + hmac.c \ + hostasyn.c \ + hostip.c \ + hostip4.c \ + hostip6.c \ + hostsyn.c \ + hsts.c \ + http.c \ + http1.c \ + http2.c \ + http_aws_sigv4.c \ + http_chunks.c \ + http_digest.c \ + http_negotiate.c \ + http_ntlm.c \ + http_proxy.c \ + idn.c \ + if2ip.c \ + imap.c \ + inet_ntop.c \ + inet_pton.c \ + krb5.c \ + ldap.c \ + llist.c \ + macos.c \ + md4.c \ + md5.c \ + memdebug.c \ + mime.c \ + mprintf.c \ + mqtt.c \ + multi.c \ + netrc.c \ + nonblock.c \ + noproxy.c \ + openldap.c \ + parsedate.c \ + pingpong.c \ + pop3.c \ + progress.c \ + psl.c \ + rand.c \ + rename.c \ + rtsp.c \ + select.c \ + sendf.c \ + setopt.c \ + sha256.c \ + share.c \ + slist.c \ + smb.c \ + smtp.c \ + socketpair.c \ + socks.c \ + socks_gssapi.c \ + socks_sspi.c \ + speedcheck.c \ + splay.c \ + strcase.c \ + strdup.c \ + strerror.c \ + strtok.c \ + strtoofft.c \ + system_win32.c \ + telnet.c \ + tftp.c \ + timediff.c \ + timeval.c \ + transfer.c \ + url.c \ + urlapi.c \ + version.c \ + version_win32.c \ + warnless.c \ + ws.c + +LIB_HFILES = \ + altsvc.h \ + amigaos.h \ + arpa_telnet.h \ + asyn.h \ + bufq.h \ + bufref.h \ + c-hyper.h \ + cf-h1-proxy.h \ + cf-h2-proxy.h \ + cf-haproxy.h \ + cf-https-connect.h \ + cf-socket.h \ + cfilters.h \ + conncache.h \ + connect.h \ + content_encoding.h \ + cookie.h \ + curl_addrinfo.h \ + curl_base64.h \ + curl_ctype.h \ + curl_des.h \ + curl_endian.h \ + curl_fnmatch.h \ + curl_get_line.h \ + curl_gethostname.h \ + curl_gssapi.h \ + curl_hmac.h \ + curl_krb5.h \ + curl_ldap.h \ + curl_md4.h \ + curl_md5.h \ + curl_memory.h \ + curl_memrchr.h \ + curl_multibyte.h \ + curl_ntlm_core.h \ + curl_ntlm_wb.h \ + curl_path.h \ + curl_printf.h \ + curl_range.h \ + curl_rtmp.h \ + curl_sasl.h \ + curl_setup.h \ + curl_setup_once.h \ + curl_sha256.h \ + curl_sspi.h \ + curl_threads.h \ + curl_trc.h \ + curlx.h \ + dict.h \ + doh.h \ + dynbuf.h \ + dynhds.h \ + easy_lock.h \ + easyif.h \ + easyoptions.h \ + escape.h \ + file.h \ + fileinfo.h \ + fopen.h \ + formdata.h \ + ftp.h \ + ftplistparser.h \ + functypes.h \ + getinfo.h \ + gopher.h \ + hash.h \ + headers.h \ + hostip.h \ + hsts.h \ + http.h \ + http1.h \ + http2.h \ + http_aws_sigv4.h \ + http_chunks.h \ + http_digest.h \ + http_negotiate.h \ + http_ntlm.h \ + http_proxy.h \ + idn.h \ + if2ip.h \ + imap.h \ + inet_ntop.h \ + inet_pton.h \ + llist.h \ + macos.h \ + memdebug.h \ + mime.h \ + mqtt.h \ + multihandle.h \ + multiif.h \ + netrc.h \ + nonblock.h \ + noproxy.h \ + parsedate.h \ + pingpong.h \ + pop3.h \ + progress.h \ + psl.h \ + rand.h \ + rename.h \ + rtsp.h \ + select.h \ + sendf.h \ + setopt.h \ + setup-vms.h \ + share.h \ + sigpipe.h \ + slist.h \ + smb.h \ + smtp.h \ + sockaddr.h \ + socketpair.h \ + socks.h \ + speedcheck.h \ + splay.h \ + strcase.h \ + strdup.h \ + strerror.h \ + strtok.h \ + strtoofft.h \ + system_win32.h \ + telnet.h \ + tftp.h \ + timediff.h \ + timeval.h \ + transfer.h \ + url.h \ + urlapi-int.h \ + urldata.h \ + version_win32.h \ + warnless.h \ + ws.h + +LIB_RCFILES = libcurl.rc +CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \ + $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) + +HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \ + $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) + + +# Makefile.inc provides the CSOURCES and HHEADERS defines +libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) $(am__append_7) +libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) +libcurl_la_CPPFLAGS_EXTRA = $(am__append_6) $(am__append_8) +libcurl_la_LDFLAGS_EXTRA = $(am__append_1) $(am__append_2) \ + $(am__append_3) $(am__append_4) $(am__append_5) +libcurl_la_CFLAGS_EXTRA = $(am__append_9) +libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) +libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS) +libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) +libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS +libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) +libcurlu_la_CFLAGS = $(AM_CFLAGS) +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) + +# disable the tests that are mostly causing false positives +TIDYFLAGS = -checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet +TIDY := clang-tidy +all: curl_config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj .rc +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.soname $(srcdir)/Makefile.inc $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/Makefile.soname $(srcdir)/Makefile.inc $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +curl_config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/curl_config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status lib/curl_config.h +$(srcdir)/curl_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f curl_config.h stamp-h1 +libcurl.vers: $(top_builddir)/config.status $(srcdir)/libcurl.vers.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +libcurl.plist: $(top_builddir)/config.status $(srcdir)/libcurl.plist.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +vauth/$(am__dirstamp): + @$(MKDIR_P) vauth + @: > vauth/$(am__dirstamp) +vauth/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) vauth/$(DEPDIR) + @: > vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-cleartext.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-cram.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-digest.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-digest_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-gsasl.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-krb5_gssapi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-krb5_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-ntlm.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-ntlm_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-oauth2.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-spnego_gssapi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-spnego_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurl_la-vauth.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vtls/$(am__dirstamp): + @$(MKDIR_P) vtls + @: > vtls/$(am__dirstamp) +vtls/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) vtls/$(DEPDIR) + @: > vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-bearssl.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-gtls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-hostcheck.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-keylog.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-mbedtls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-mbedtls_threadlock.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-openssl.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-rustls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-schannel.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-schannel_verify.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-sectransp.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-vtls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-wolfssl.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurl_la-x509asn1.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vquic/$(am__dirstamp): + @$(MKDIR_P) vquic + @: > vquic/$(am__dirstamp) +vquic/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) vquic/$(DEPDIR) + @: > vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-curl_msh3.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-curl_osslq.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-curl_quiche.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-vquic.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-vquic-tls.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vssh/$(am__dirstamp): + @$(MKDIR_P) vssh + @: > vssh/$(am__dirstamp) +vssh/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) vssh/$(DEPDIR) + @: > vssh/$(DEPDIR)/$(am__dirstamp) +vssh/libcurl_la-libssh.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) +vssh/libcurl_la-libssh2.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) +vssh/libcurl_la-wolfssh.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) + +libcurl.la: $(libcurl_la_OBJECTS) $(libcurl_la_DEPENDENCIES) $(EXTRA_libcurl_la_DEPENDENCIES) + $(AM_V_CCLD)$(libcurl_la_LINK) -rpath $(libdir) $(libcurl_la_OBJECTS) $(libcurl_la_LIBADD) $(LIBS) +vauth/libcurlu_la-cleartext.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-cram.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-digest.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-digest_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-gsasl.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-krb5_gssapi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-krb5_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-ntlm.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-ntlm_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-oauth2.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-spnego_gssapi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-spnego_sspi.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vauth/libcurlu_la-vauth.lo: vauth/$(am__dirstamp) \ + vauth/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-bearssl.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-gtls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-hostcheck.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-keylog.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-mbedtls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-mbedtls_threadlock.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-openssl.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-rustls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-schannel.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-schannel_verify.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-sectransp.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-vtls.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-wolfssl.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vtls/libcurlu_la-x509asn1.lo: vtls/$(am__dirstamp) \ + vtls/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-curl_msh3.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-curl_osslq.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-curl_quiche.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-vquic.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-vquic-tls.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) +vssh/libcurlu_la-libssh.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) +vssh/libcurlu_la-libssh2.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) +vssh/libcurlu_la-wolfssh.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) + +libcurlu.la: $(libcurlu_la_OBJECTS) $(libcurlu_la_DEPENDENCIES) $(EXTRA_libcurlu_la_DEPENDENCIES) + $(AM_V_CCLD)$(libcurlu_la_LINK) $(am_libcurlu_la_rpath) $(libcurlu_la_OBJECTS) $(libcurlu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f vauth/*.$(OBJEXT) + -rm -f vauth/*.lo + -rm -f vquic/*.$(OBJEXT) + -rm -f vquic/*.lo + -rm -f vssh/*.$(OBJEXT) + -rm -f vssh/*.lo + -rm -f vtls/*.$(OBJEXT) + -rm -f vtls/*.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-altsvc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-amigaos.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-asyn-ares.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-asyn-thread.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-base64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-bufq.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-bufref.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-c-hyper.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-haproxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-https-connect.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-socket.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cfilters.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-conncache.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-connect.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-content_encoding.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cookie.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_des.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_endian.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_get_line.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_gethostname.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_memrchr.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_multibyte.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_path.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_range.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_rtmp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_sasl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_threads.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_trc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dict.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-doh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dynbuf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dynhds.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-easy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-easygetopt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-easyoptions.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-escape.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-file.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-fileinfo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-fopen.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-formdata.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ftp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ftplistparser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-getenv.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-getinfo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-gopher.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hash.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-headers.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hmac.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostasyn.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostip.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostip4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostip6.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostsyn.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hsts.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http1.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_chunks.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_digest.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_negotiate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_ntlm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_proxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-idn.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-if2ip.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-imap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-inet_ntop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-inet_pton.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-krb5.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ldap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-llist.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-macos.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-md4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-md5.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-memdebug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mime.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mprintf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mqtt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-multi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-netrc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-nonblock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-noproxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-openldap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-parsedate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-pingpong.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-pop3.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-progress.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-psl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rand.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rename.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rtsp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-select.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-sendf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-setopt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-sha256.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-share.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-slist.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-smb.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-smtp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socketpair.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socks.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socks_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socks_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-speedcheck.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-splay.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strcase.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strdup.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strerror.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strtok.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strtoofft.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-system_win32.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-telnet.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-tftp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-timediff.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-timeval.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-transfer.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-url.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-urlapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-version.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-version_win32.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-warnless.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ws.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-altsvc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-amigaos.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-asyn-ares.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-asyn-thread.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-base64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-bufq.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-bufref.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-c-hyper.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-socket.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cfilters.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-conncache.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-connect.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-content_encoding.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cookie.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_des.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_endian.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_get_line.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_path.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_range.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_sasl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_threads.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_trc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dict.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-doh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dynbuf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dynhds.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-easy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-easygetopt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-easyoptions.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-escape.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-file.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-fileinfo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-fopen.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-formdata.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ftp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ftplistparser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-getenv.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-getinfo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-gopher.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hash.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-headers.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hmac.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostasyn.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostip.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostip4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostip6.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostsyn.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hsts.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http1.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_chunks.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_digest.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_negotiate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_ntlm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_proxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-idn.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-if2ip.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-imap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-inet_ntop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-inet_pton.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-krb5.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ldap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-llist.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-macos.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-md4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-md5.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-memdebug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mime.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mprintf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mqtt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-multi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-netrc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-nonblock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-noproxy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-openldap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-parsedate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-pingpong.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-pop3.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-progress.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-psl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rand.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rename.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rtsp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-select.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-sendf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-setopt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-sha256.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-share.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-slist.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-smb.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-smtp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socketpair.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socks.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socks_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-speedcheck.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-splay.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strcase.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strdup.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strerror.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strtok.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strtoofft.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-system_win32.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-telnet.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-tftp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-timediff.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-timeval.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-transfer.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-url.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-urlapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-version.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-version_win32.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-warnless.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ws.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-cleartext.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-cram.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-digest.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-gsasl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-ntlm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-oauth2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-vauth.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-cram.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-digest.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-vauth.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-vquic.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-libssh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-bearssl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-gtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-keylog.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-openssl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-rustls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-sectransp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-vtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-gtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-keylog.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-openssl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-rustls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-schannel.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-vtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libcurl_la-altsvc.lo: altsvc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-altsvc.lo -MD -MP -MF $(DEPDIR)/libcurl_la-altsvc.Tpo -c -o libcurl_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-altsvc.Tpo $(DEPDIR)/libcurl_la-altsvc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='altsvc.c' object='libcurl_la-altsvc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c + +libcurl_la-amigaos.lo: amigaos.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-amigaos.lo -MD -MP -MF $(DEPDIR)/libcurl_la-amigaos.Tpo -c -o libcurl_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-amigaos.Tpo $(DEPDIR)/libcurl_la-amigaos.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='amigaos.c' object='libcurl_la-amigaos.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c + +libcurl_la-asyn-ares.lo: asyn-ares.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-asyn-ares.lo -MD -MP -MF $(DEPDIR)/libcurl_la-asyn-ares.Tpo -c -o libcurl_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-asyn-ares.Tpo $(DEPDIR)/libcurl_la-asyn-ares.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asyn-ares.c' object='libcurl_la-asyn-ares.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c + +libcurl_la-asyn-thread.lo: asyn-thread.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-asyn-thread.lo -MD -MP -MF $(DEPDIR)/libcurl_la-asyn-thread.Tpo -c -o libcurl_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-asyn-thread.Tpo $(DEPDIR)/libcurl_la-asyn-thread.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asyn-thread.c' object='libcurl_la-asyn-thread.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c + +libcurl_la-base64.lo: base64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-base64.lo -MD -MP -MF $(DEPDIR)/libcurl_la-base64.Tpo -c -o libcurl_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-base64.Tpo $(DEPDIR)/libcurl_la-base64.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='base64.c' object='libcurl_la-base64.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c + +libcurl_la-bufq.lo: bufq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-bufq.lo -MD -MP -MF $(DEPDIR)/libcurl_la-bufq.Tpo -c -o libcurl_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-bufq.Tpo $(DEPDIR)/libcurl_la-bufq.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bufq.c' object='libcurl_la-bufq.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c + +libcurl_la-bufref.lo: bufref.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-bufref.lo -MD -MP -MF $(DEPDIR)/libcurl_la-bufref.Tpo -c -o libcurl_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-bufref.Tpo $(DEPDIR)/libcurl_la-bufref.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bufref.c' object='libcurl_la-bufref.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c + +libcurl_la-c-hyper.lo: c-hyper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-c-hyper.lo -MD -MP -MF $(DEPDIR)/libcurl_la-c-hyper.Tpo -c -o libcurl_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-c-hyper.Tpo $(DEPDIR)/libcurl_la-c-hyper.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='c-hyper.c' object='libcurl_la-c-hyper.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c + +libcurl_la-cf-h1-proxy.lo: cf-h1-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-h1-proxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-h1-proxy.Tpo -c -o libcurl_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-h1-proxy.Tpo $(DEPDIR)/libcurl_la-cf-h1-proxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-h1-proxy.c' object='libcurl_la-cf-h1-proxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c + +libcurl_la-cf-h2-proxy.lo: cf-h2-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-h2-proxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-h2-proxy.Tpo -c -o libcurl_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-h2-proxy.Tpo $(DEPDIR)/libcurl_la-cf-h2-proxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-h2-proxy.c' object='libcurl_la-cf-h2-proxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c + +libcurl_la-cf-haproxy.lo: cf-haproxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-haproxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-haproxy.Tpo -c -o libcurl_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-haproxy.Tpo $(DEPDIR)/libcurl_la-cf-haproxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-haproxy.c' object='libcurl_la-cf-haproxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c + +libcurl_la-cf-https-connect.lo: cf-https-connect.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-https-connect.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-https-connect.Tpo -c -o libcurl_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-https-connect.Tpo $(DEPDIR)/libcurl_la-cf-https-connect.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-https-connect.c' object='libcurl_la-cf-https-connect.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c + +libcurl_la-cf-socket.lo: cf-socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-socket.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-socket.Tpo -c -o libcurl_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-socket.Tpo $(DEPDIR)/libcurl_la-cf-socket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-socket.c' object='libcurl_la-cf-socket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c + +libcurl_la-cfilters.lo: cfilters.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cfilters.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cfilters.Tpo -c -o libcurl_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cfilters.Tpo $(DEPDIR)/libcurl_la-cfilters.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cfilters.c' object='libcurl_la-cfilters.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c + +libcurl_la-conncache.lo: conncache.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-conncache.lo -MD -MP -MF $(DEPDIR)/libcurl_la-conncache.Tpo -c -o libcurl_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-conncache.Tpo $(DEPDIR)/libcurl_la-conncache.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='conncache.c' object='libcurl_la-conncache.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c + +libcurl_la-connect.lo: connect.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-connect.lo -MD -MP -MF $(DEPDIR)/libcurl_la-connect.Tpo -c -o libcurl_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-connect.Tpo $(DEPDIR)/libcurl_la-connect.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connect.c' object='libcurl_la-connect.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c + +libcurl_la-content_encoding.lo: content_encoding.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-content_encoding.lo -MD -MP -MF $(DEPDIR)/libcurl_la-content_encoding.Tpo -c -o libcurl_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-content_encoding.Tpo $(DEPDIR)/libcurl_la-content_encoding.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='content_encoding.c' object='libcurl_la-content_encoding.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c + +libcurl_la-cookie.lo: cookie.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cookie.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cookie.Tpo -c -o libcurl_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cookie.Tpo $(DEPDIR)/libcurl_la-cookie.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cookie.c' object='libcurl_la-cookie.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c + +libcurl_la-curl_addrinfo.lo: curl_addrinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_addrinfo.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_addrinfo.Tpo -c -o libcurl_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_addrinfo.Tpo $(DEPDIR)/libcurl_la-curl_addrinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_addrinfo.c' object='libcurl_la-curl_addrinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c + +libcurl_la-curl_des.lo: curl_des.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_des.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_des.Tpo -c -o libcurl_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_des.Tpo $(DEPDIR)/libcurl_la-curl_des.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_des.c' object='libcurl_la-curl_des.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c + +libcurl_la-curl_endian.lo: curl_endian.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_endian.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_endian.Tpo -c -o libcurl_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_endian.Tpo $(DEPDIR)/libcurl_la-curl_endian.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_endian.c' object='libcurl_la-curl_endian.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c + +libcurl_la-curl_fnmatch.lo: curl_fnmatch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_fnmatch.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_fnmatch.Tpo -c -o libcurl_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_fnmatch.Tpo $(DEPDIR)/libcurl_la-curl_fnmatch.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_fnmatch.c' object='libcurl_la-curl_fnmatch.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c + +libcurl_la-curl_get_line.lo: curl_get_line.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_get_line.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_get_line.Tpo -c -o libcurl_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_get_line.Tpo $(DEPDIR)/libcurl_la-curl_get_line.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_get_line.c' object='libcurl_la-curl_get_line.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c + +libcurl_la-curl_gethostname.lo: curl_gethostname.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_gethostname.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_gethostname.Tpo -c -o libcurl_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_gethostname.Tpo $(DEPDIR)/libcurl_la-curl_gethostname.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_gethostname.c' object='libcurl_la-curl_gethostname.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c + +libcurl_la-curl_gssapi.lo: curl_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_gssapi.Tpo -c -o libcurl_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_gssapi.Tpo $(DEPDIR)/libcurl_la-curl_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_gssapi.c' object='libcurl_la-curl_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c + +libcurl_la-curl_memrchr.lo: curl_memrchr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_memrchr.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_memrchr.Tpo -c -o libcurl_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_memrchr.Tpo $(DEPDIR)/libcurl_la-curl_memrchr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_memrchr.c' object='libcurl_la-curl_memrchr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c + +libcurl_la-curl_multibyte.lo: curl_multibyte.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_multibyte.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_multibyte.Tpo -c -o libcurl_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_multibyte.Tpo $(DEPDIR)/libcurl_la-curl_multibyte.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_multibyte.c' object='libcurl_la-curl_multibyte.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c + +libcurl_la-curl_ntlm_core.lo: curl_ntlm_core.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_ntlm_core.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_ntlm_core.Tpo -c -o libcurl_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_ntlm_core.Tpo $(DEPDIR)/libcurl_la-curl_ntlm_core.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_ntlm_core.c' object='libcurl_la-curl_ntlm_core.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c + +libcurl_la-curl_ntlm_wb.lo: curl_ntlm_wb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_ntlm_wb.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_ntlm_wb.Tpo -c -o libcurl_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_ntlm_wb.Tpo $(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_ntlm_wb.c' object='libcurl_la-curl_ntlm_wb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c + +libcurl_la-curl_path.lo: curl_path.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_path.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_path.Tpo -c -o libcurl_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_path.Tpo $(DEPDIR)/libcurl_la-curl_path.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_path.c' object='libcurl_la-curl_path.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c + +libcurl_la-curl_range.lo: curl_range.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_range.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_range.Tpo -c -o libcurl_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_range.Tpo $(DEPDIR)/libcurl_la-curl_range.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_range.c' object='libcurl_la-curl_range.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c + +libcurl_la-curl_rtmp.lo: curl_rtmp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_rtmp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_rtmp.Tpo -c -o libcurl_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_rtmp.Tpo $(DEPDIR)/libcurl_la-curl_rtmp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_rtmp.c' object='libcurl_la-curl_rtmp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c + +libcurl_la-curl_sasl.lo: curl_sasl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_sasl.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_sasl.Tpo -c -o libcurl_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_sasl.Tpo $(DEPDIR)/libcurl_la-curl_sasl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_sasl.c' object='libcurl_la-curl_sasl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c + +libcurl_la-curl_sspi.lo: curl_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_sspi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_sspi.Tpo -c -o libcurl_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_sspi.Tpo $(DEPDIR)/libcurl_la-curl_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_sspi.c' object='libcurl_la-curl_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c + +libcurl_la-curl_threads.lo: curl_threads.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_threads.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_threads.Tpo -c -o libcurl_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_threads.Tpo $(DEPDIR)/libcurl_la-curl_threads.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_threads.c' object='libcurl_la-curl_threads.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c + +libcurl_la-curl_trc.lo: curl_trc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_trc.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_trc.Tpo -c -o libcurl_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_trc.Tpo $(DEPDIR)/libcurl_la-curl_trc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_trc.c' object='libcurl_la-curl_trc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c + +libcurl_la-dict.lo: dict.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dict.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dict.Tpo -c -o libcurl_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dict.Tpo $(DEPDIR)/libcurl_la-dict.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dict.c' object='libcurl_la-dict.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c + +libcurl_la-doh.lo: doh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurl_la-doh.Tpo -c -o libcurl_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-doh.Tpo $(DEPDIR)/libcurl_la-doh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='doh.c' object='libcurl_la-doh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c + +libcurl_la-dynbuf.lo: dynbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dynbuf.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dynbuf.Tpo -c -o libcurl_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dynbuf.Tpo $(DEPDIR)/libcurl_la-dynbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dynbuf.c' object='libcurl_la-dynbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c + +libcurl_la-dynhds.lo: dynhds.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dynhds.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dynhds.Tpo -c -o libcurl_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dynhds.Tpo $(DEPDIR)/libcurl_la-dynhds.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dynhds.c' object='libcurl_la-dynhds.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c + +libcurl_la-easy.lo: easy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-easy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-easy.Tpo -c -o libcurl_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-easy.Tpo $(DEPDIR)/libcurl_la-easy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='easy.c' object='libcurl_la-easy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c + +libcurl_la-easygetopt.lo: easygetopt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-easygetopt.lo -MD -MP -MF $(DEPDIR)/libcurl_la-easygetopt.Tpo -c -o libcurl_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-easygetopt.Tpo $(DEPDIR)/libcurl_la-easygetopt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='easygetopt.c' object='libcurl_la-easygetopt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c + +libcurl_la-easyoptions.lo: easyoptions.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-easyoptions.lo -MD -MP -MF $(DEPDIR)/libcurl_la-easyoptions.Tpo -c -o libcurl_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-easyoptions.Tpo $(DEPDIR)/libcurl_la-easyoptions.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='easyoptions.c' object='libcurl_la-easyoptions.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c + +libcurl_la-escape.lo: escape.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-escape.lo -MD -MP -MF $(DEPDIR)/libcurl_la-escape.Tpo -c -o libcurl_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-escape.Tpo $(DEPDIR)/libcurl_la-escape.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='escape.c' object='libcurl_la-escape.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c + +libcurl_la-file.lo: file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-file.lo -MD -MP -MF $(DEPDIR)/libcurl_la-file.Tpo -c -o libcurl_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-file.Tpo $(DEPDIR)/libcurl_la-file.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='file.c' object='libcurl_la-file.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c + +libcurl_la-fileinfo.lo: fileinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-fileinfo.lo -MD -MP -MF $(DEPDIR)/libcurl_la-fileinfo.Tpo -c -o libcurl_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-fileinfo.Tpo $(DEPDIR)/libcurl_la-fileinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fileinfo.c' object='libcurl_la-fileinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c + +libcurl_la-fopen.lo: fopen.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-fopen.lo -MD -MP -MF $(DEPDIR)/libcurl_la-fopen.Tpo -c -o libcurl_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-fopen.Tpo $(DEPDIR)/libcurl_la-fopen.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fopen.c' object='libcurl_la-fopen.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c + +libcurl_la-formdata.lo: formdata.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-formdata.lo -MD -MP -MF $(DEPDIR)/libcurl_la-formdata.Tpo -c -o libcurl_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-formdata.Tpo $(DEPDIR)/libcurl_la-formdata.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='formdata.c' object='libcurl_la-formdata.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c + +libcurl_la-ftp.lo: ftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ftp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ftp.Tpo -c -o libcurl_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ftp.Tpo $(DEPDIR)/libcurl_la-ftp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ftp.c' object='libcurl_la-ftp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c + +libcurl_la-ftplistparser.lo: ftplistparser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ftplistparser.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ftplistparser.Tpo -c -o libcurl_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ftplistparser.Tpo $(DEPDIR)/libcurl_la-ftplistparser.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ftplistparser.c' object='libcurl_la-ftplistparser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c + +libcurl_la-getenv.lo: getenv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-getenv.lo -MD -MP -MF $(DEPDIR)/libcurl_la-getenv.Tpo -c -o libcurl_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-getenv.Tpo $(DEPDIR)/libcurl_la-getenv.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getenv.c' object='libcurl_la-getenv.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c + +libcurl_la-getinfo.lo: getinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-getinfo.lo -MD -MP -MF $(DEPDIR)/libcurl_la-getinfo.Tpo -c -o libcurl_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-getinfo.Tpo $(DEPDIR)/libcurl_la-getinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getinfo.c' object='libcurl_la-getinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c + +libcurl_la-gopher.lo: gopher.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-gopher.lo -MD -MP -MF $(DEPDIR)/libcurl_la-gopher.Tpo -c -o libcurl_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-gopher.Tpo $(DEPDIR)/libcurl_la-gopher.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gopher.c' object='libcurl_la-gopher.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c + +libcurl_la-hash.lo: hash.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hash.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hash.Tpo -c -o libcurl_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hash.Tpo $(DEPDIR)/libcurl_la-hash.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hash.c' object='libcurl_la-hash.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c + +libcurl_la-headers.lo: headers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-headers.lo -MD -MP -MF $(DEPDIR)/libcurl_la-headers.Tpo -c -o libcurl_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-headers.Tpo $(DEPDIR)/libcurl_la-headers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='headers.c' object='libcurl_la-headers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c + +libcurl_la-hmac.lo: hmac.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hmac.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hmac.Tpo -c -o libcurl_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hmac.Tpo $(DEPDIR)/libcurl_la-hmac.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hmac.c' object='libcurl_la-hmac.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c + +libcurl_la-hostasyn.lo: hostasyn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostasyn.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostasyn.Tpo -c -o libcurl_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostasyn.Tpo $(DEPDIR)/libcurl_la-hostasyn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostasyn.c' object='libcurl_la-hostasyn.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c + +libcurl_la-hostip.lo: hostip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostip.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostip.Tpo -c -o libcurl_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostip.Tpo $(DEPDIR)/libcurl_la-hostip.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostip.c' object='libcurl_la-hostip.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c + +libcurl_la-hostip4.lo: hostip4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostip4.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostip4.Tpo -c -o libcurl_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostip4.Tpo $(DEPDIR)/libcurl_la-hostip4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostip4.c' object='libcurl_la-hostip4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c + +libcurl_la-hostip6.lo: hostip6.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostip6.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostip6.Tpo -c -o libcurl_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostip6.Tpo $(DEPDIR)/libcurl_la-hostip6.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostip6.c' object='libcurl_la-hostip6.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c + +libcurl_la-hostsyn.lo: hostsyn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostsyn.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostsyn.Tpo -c -o libcurl_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostsyn.Tpo $(DEPDIR)/libcurl_la-hostsyn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostsyn.c' object='libcurl_la-hostsyn.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c + +libcurl_la-hsts.lo: hsts.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hsts.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hsts.Tpo -c -o libcurl_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hsts.Tpo $(DEPDIR)/libcurl_la-hsts.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hsts.c' object='libcurl_la-hsts.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c + +libcurl_la-http.lo: http.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http.Tpo -c -o libcurl_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http.Tpo $(DEPDIR)/libcurl_la-http.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http.c' object='libcurl_la-http.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c + +libcurl_la-http1.lo: http1.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http1.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http1.Tpo -c -o libcurl_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http1.Tpo $(DEPDIR)/libcurl_la-http1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http1.c' object='libcurl_la-http1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c + +libcurl_la-http2.lo: http2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http2.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http2.Tpo -c -o libcurl_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http2.Tpo $(DEPDIR)/libcurl_la-http2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http2.c' object='libcurl_la-http2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c + +libcurl_la-http_aws_sigv4.lo: http_aws_sigv4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_aws_sigv4.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_aws_sigv4.Tpo -c -o libcurl_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_aws_sigv4.Tpo $(DEPDIR)/libcurl_la-http_aws_sigv4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_aws_sigv4.c' object='libcurl_la-http_aws_sigv4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c + +libcurl_la-http_chunks.lo: http_chunks.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_chunks.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_chunks.Tpo -c -o libcurl_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_chunks.Tpo $(DEPDIR)/libcurl_la-http_chunks.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_chunks.c' object='libcurl_la-http_chunks.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c + +libcurl_la-http_digest.lo: http_digest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_digest.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_digest.Tpo -c -o libcurl_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_digest.Tpo $(DEPDIR)/libcurl_la-http_digest.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_digest.c' object='libcurl_la-http_digest.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c + +libcurl_la-http_negotiate.lo: http_negotiate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_negotiate.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_negotiate.Tpo -c -o libcurl_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_negotiate.Tpo $(DEPDIR)/libcurl_la-http_negotiate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_negotiate.c' object='libcurl_la-http_negotiate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c + +libcurl_la-http_ntlm.lo: http_ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_ntlm.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_ntlm.Tpo -c -o libcurl_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_ntlm.Tpo $(DEPDIR)/libcurl_la-http_ntlm.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_ntlm.c' object='libcurl_la-http_ntlm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c + +libcurl_la-http_proxy.lo: http_proxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_proxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_proxy.Tpo -c -o libcurl_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_proxy.Tpo $(DEPDIR)/libcurl_la-http_proxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_proxy.c' object='libcurl_la-http_proxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c + +libcurl_la-idn.lo: idn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-idn.lo -MD -MP -MF $(DEPDIR)/libcurl_la-idn.Tpo -c -o libcurl_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-idn.Tpo $(DEPDIR)/libcurl_la-idn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='idn.c' object='libcurl_la-idn.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c + +libcurl_la-if2ip.lo: if2ip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-if2ip.lo -MD -MP -MF $(DEPDIR)/libcurl_la-if2ip.Tpo -c -o libcurl_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-if2ip.Tpo $(DEPDIR)/libcurl_la-if2ip.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='if2ip.c' object='libcurl_la-if2ip.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c + +libcurl_la-imap.lo: imap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-imap.lo -MD -MP -MF $(DEPDIR)/libcurl_la-imap.Tpo -c -o libcurl_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-imap.Tpo $(DEPDIR)/libcurl_la-imap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap.c' object='libcurl_la-imap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c + +libcurl_la-inet_ntop.lo: inet_ntop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-inet_ntop.lo -MD -MP -MF $(DEPDIR)/libcurl_la-inet_ntop.Tpo -c -o libcurl_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-inet_ntop.Tpo $(DEPDIR)/libcurl_la-inet_ntop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='inet_ntop.c' object='libcurl_la-inet_ntop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c + +libcurl_la-inet_pton.lo: inet_pton.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-inet_pton.lo -MD -MP -MF $(DEPDIR)/libcurl_la-inet_pton.Tpo -c -o libcurl_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-inet_pton.Tpo $(DEPDIR)/libcurl_la-inet_pton.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='inet_pton.c' object='libcurl_la-inet_pton.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c + +libcurl_la-krb5.lo: krb5.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-krb5.lo -MD -MP -MF $(DEPDIR)/libcurl_la-krb5.Tpo -c -o libcurl_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-krb5.Tpo $(DEPDIR)/libcurl_la-krb5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='krb5.c' object='libcurl_la-krb5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c + +libcurl_la-ldap.lo: ldap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ldap.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ldap.Tpo -c -o libcurl_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ldap.Tpo $(DEPDIR)/libcurl_la-ldap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ldap.c' object='libcurl_la-ldap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c + +libcurl_la-llist.lo: llist.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-llist.lo -MD -MP -MF $(DEPDIR)/libcurl_la-llist.Tpo -c -o libcurl_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-llist.Tpo $(DEPDIR)/libcurl_la-llist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='llist.c' object='libcurl_la-llist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c + +libcurl_la-macos.lo: macos.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-macos.lo -MD -MP -MF $(DEPDIR)/libcurl_la-macos.Tpo -c -o libcurl_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-macos.Tpo $(DEPDIR)/libcurl_la-macos.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='macos.c' object='libcurl_la-macos.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c + +libcurl_la-md4.lo: md4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-md4.lo -MD -MP -MF $(DEPDIR)/libcurl_la-md4.Tpo -c -o libcurl_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-md4.Tpo $(DEPDIR)/libcurl_la-md4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md4.c' object='libcurl_la-md4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c + +libcurl_la-md5.lo: md5.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-md5.lo -MD -MP -MF $(DEPDIR)/libcurl_la-md5.Tpo -c -o libcurl_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-md5.Tpo $(DEPDIR)/libcurl_la-md5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md5.c' object='libcurl_la-md5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c + +libcurl_la-memdebug.lo: memdebug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-memdebug.lo -MD -MP -MF $(DEPDIR)/libcurl_la-memdebug.Tpo -c -o libcurl_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-memdebug.Tpo $(DEPDIR)/libcurl_la-memdebug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='memdebug.c' object='libcurl_la-memdebug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c + +libcurl_la-mime.lo: mime.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-mime.lo -MD -MP -MF $(DEPDIR)/libcurl_la-mime.Tpo -c -o libcurl_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-mime.Tpo $(DEPDIR)/libcurl_la-mime.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mime.c' object='libcurl_la-mime.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c + +libcurl_la-mprintf.lo: mprintf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-mprintf.lo -MD -MP -MF $(DEPDIR)/libcurl_la-mprintf.Tpo -c -o libcurl_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-mprintf.Tpo $(DEPDIR)/libcurl_la-mprintf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mprintf.c' object='libcurl_la-mprintf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c + +libcurl_la-mqtt.lo: mqtt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-mqtt.lo -MD -MP -MF $(DEPDIR)/libcurl_la-mqtt.Tpo -c -o libcurl_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-mqtt.Tpo $(DEPDIR)/libcurl_la-mqtt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mqtt.c' object='libcurl_la-mqtt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c + +libcurl_la-multi.lo: multi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-multi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-multi.Tpo -c -o libcurl_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-multi.Tpo $(DEPDIR)/libcurl_la-multi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='multi.c' object='libcurl_la-multi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c + +libcurl_la-netrc.lo: netrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-netrc.lo -MD -MP -MF $(DEPDIR)/libcurl_la-netrc.Tpo -c -o libcurl_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-netrc.Tpo $(DEPDIR)/libcurl_la-netrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netrc.c' object='libcurl_la-netrc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c + +libcurl_la-nonblock.lo: nonblock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-nonblock.lo -MD -MP -MF $(DEPDIR)/libcurl_la-nonblock.Tpo -c -o libcurl_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-nonblock.Tpo $(DEPDIR)/libcurl_la-nonblock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nonblock.c' object='libcurl_la-nonblock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c + +libcurl_la-noproxy.lo: noproxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-noproxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-noproxy.Tpo -c -o libcurl_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-noproxy.Tpo $(DEPDIR)/libcurl_la-noproxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='noproxy.c' object='libcurl_la-noproxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c + +libcurl_la-openldap.lo: openldap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-openldap.lo -MD -MP -MF $(DEPDIR)/libcurl_la-openldap.Tpo -c -o libcurl_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-openldap.Tpo $(DEPDIR)/libcurl_la-openldap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openldap.c' object='libcurl_la-openldap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c + +libcurl_la-parsedate.lo: parsedate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-parsedate.lo -MD -MP -MF $(DEPDIR)/libcurl_la-parsedate.Tpo -c -o libcurl_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-parsedate.Tpo $(DEPDIR)/libcurl_la-parsedate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='parsedate.c' object='libcurl_la-parsedate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c + +libcurl_la-pingpong.lo: pingpong.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-pingpong.lo -MD -MP -MF $(DEPDIR)/libcurl_la-pingpong.Tpo -c -o libcurl_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-pingpong.Tpo $(DEPDIR)/libcurl_la-pingpong.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pingpong.c' object='libcurl_la-pingpong.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c + +libcurl_la-pop3.lo: pop3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-pop3.lo -MD -MP -MF $(DEPDIR)/libcurl_la-pop3.Tpo -c -o libcurl_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-pop3.Tpo $(DEPDIR)/libcurl_la-pop3.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pop3.c' object='libcurl_la-pop3.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c + +libcurl_la-progress.lo: progress.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-progress.lo -MD -MP -MF $(DEPDIR)/libcurl_la-progress.Tpo -c -o libcurl_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-progress.Tpo $(DEPDIR)/libcurl_la-progress.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='libcurl_la-progress.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c + +libcurl_la-psl.lo: psl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-psl.lo -MD -MP -MF $(DEPDIR)/libcurl_la-psl.Tpo -c -o libcurl_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-psl.Tpo $(DEPDIR)/libcurl_la-psl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='psl.c' object='libcurl_la-psl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c + +libcurl_la-rand.lo: rand.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-rand.lo -MD -MP -MF $(DEPDIR)/libcurl_la-rand.Tpo -c -o libcurl_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-rand.Tpo $(DEPDIR)/libcurl_la-rand.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rand.c' object='libcurl_la-rand.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c + +libcurl_la-rename.lo: rename.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-rename.lo -MD -MP -MF $(DEPDIR)/libcurl_la-rename.Tpo -c -o libcurl_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-rename.Tpo $(DEPDIR)/libcurl_la-rename.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rename.c' object='libcurl_la-rename.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c + +libcurl_la-rtsp.lo: rtsp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-rtsp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-rtsp.Tpo -c -o libcurl_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-rtsp.Tpo $(DEPDIR)/libcurl_la-rtsp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtsp.c' object='libcurl_la-rtsp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c + +libcurl_la-select.lo: select.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-select.lo -MD -MP -MF $(DEPDIR)/libcurl_la-select.Tpo -c -o libcurl_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-select.Tpo $(DEPDIR)/libcurl_la-select.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='select.c' object='libcurl_la-select.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c + +libcurl_la-sendf.lo: sendf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-sendf.lo -MD -MP -MF $(DEPDIR)/libcurl_la-sendf.Tpo -c -o libcurl_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-sendf.Tpo $(DEPDIR)/libcurl_la-sendf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sendf.c' object='libcurl_la-sendf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c + +libcurl_la-setopt.lo: setopt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-setopt.lo -MD -MP -MF $(DEPDIR)/libcurl_la-setopt.Tpo -c -o libcurl_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-setopt.Tpo $(DEPDIR)/libcurl_la-setopt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='setopt.c' object='libcurl_la-setopt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c + +libcurl_la-sha256.lo: sha256.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-sha256.lo -MD -MP -MF $(DEPDIR)/libcurl_la-sha256.Tpo -c -o libcurl_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-sha256.Tpo $(DEPDIR)/libcurl_la-sha256.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sha256.c' object='libcurl_la-sha256.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c + +libcurl_la-share.lo: share.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-share.lo -MD -MP -MF $(DEPDIR)/libcurl_la-share.Tpo -c -o libcurl_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-share.Tpo $(DEPDIR)/libcurl_la-share.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='share.c' object='libcurl_la-share.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c + +libcurl_la-slist.lo: slist.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-slist.lo -MD -MP -MF $(DEPDIR)/libcurl_la-slist.Tpo -c -o libcurl_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-slist.Tpo $(DEPDIR)/libcurl_la-slist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slist.c' object='libcurl_la-slist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c + +libcurl_la-smb.lo: smb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-smb.lo -MD -MP -MF $(DEPDIR)/libcurl_la-smb.Tpo -c -o libcurl_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-smb.Tpo $(DEPDIR)/libcurl_la-smb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='smb.c' object='libcurl_la-smb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c + +libcurl_la-smtp.lo: smtp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-smtp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-smtp.Tpo -c -o libcurl_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-smtp.Tpo $(DEPDIR)/libcurl_la-smtp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='smtp.c' object='libcurl_la-smtp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c + +libcurl_la-socketpair.lo: socketpair.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socketpair.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socketpair.Tpo -c -o libcurl_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socketpair.Tpo $(DEPDIR)/libcurl_la-socketpair.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socketpair.c' object='libcurl_la-socketpair.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c + +libcurl_la-socks.lo: socks.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socks.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socks.Tpo -c -o libcurl_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socks.Tpo $(DEPDIR)/libcurl_la-socks.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socks.c' object='libcurl_la-socks.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c + +libcurl_la-socks_gssapi.lo: socks_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socks_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socks_gssapi.Tpo -c -o libcurl_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socks_gssapi.Tpo $(DEPDIR)/libcurl_la-socks_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socks_gssapi.c' object='libcurl_la-socks_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c + +libcurl_la-socks_sspi.lo: socks_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socks_sspi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socks_sspi.Tpo -c -o libcurl_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socks_sspi.Tpo $(DEPDIR)/libcurl_la-socks_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socks_sspi.c' object='libcurl_la-socks_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c + +libcurl_la-speedcheck.lo: speedcheck.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-speedcheck.lo -MD -MP -MF $(DEPDIR)/libcurl_la-speedcheck.Tpo -c -o libcurl_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-speedcheck.Tpo $(DEPDIR)/libcurl_la-speedcheck.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='speedcheck.c' object='libcurl_la-speedcheck.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c + +libcurl_la-splay.lo: splay.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-splay.lo -MD -MP -MF $(DEPDIR)/libcurl_la-splay.Tpo -c -o libcurl_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-splay.Tpo $(DEPDIR)/libcurl_la-splay.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='splay.c' object='libcurl_la-splay.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c + +libcurl_la-strcase.lo: strcase.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strcase.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strcase.Tpo -c -o libcurl_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strcase.Tpo $(DEPDIR)/libcurl_la-strcase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strcase.c' object='libcurl_la-strcase.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c + +libcurl_la-strdup.lo: strdup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strdup.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strdup.Tpo -c -o libcurl_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strdup.Tpo $(DEPDIR)/libcurl_la-strdup.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strdup.c' object='libcurl_la-strdup.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c + +libcurl_la-strerror.lo: strerror.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strerror.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strerror.Tpo -c -o libcurl_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strerror.Tpo $(DEPDIR)/libcurl_la-strerror.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strerror.c' object='libcurl_la-strerror.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c + +libcurl_la-strtok.lo: strtok.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strtok.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strtok.Tpo -c -o libcurl_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strtok.Tpo $(DEPDIR)/libcurl_la-strtok.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtok.c' object='libcurl_la-strtok.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c + +libcurl_la-strtoofft.lo: strtoofft.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strtoofft.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strtoofft.Tpo -c -o libcurl_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strtoofft.Tpo $(DEPDIR)/libcurl_la-strtoofft.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtoofft.c' object='libcurl_la-strtoofft.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c + +libcurl_la-system_win32.lo: system_win32.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-system_win32.lo -MD -MP -MF $(DEPDIR)/libcurl_la-system_win32.Tpo -c -o libcurl_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-system_win32.Tpo $(DEPDIR)/libcurl_la-system_win32.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='system_win32.c' object='libcurl_la-system_win32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c + +libcurl_la-telnet.lo: telnet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-telnet.lo -MD -MP -MF $(DEPDIR)/libcurl_la-telnet.Tpo -c -o libcurl_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-telnet.Tpo $(DEPDIR)/libcurl_la-telnet.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='telnet.c' object='libcurl_la-telnet.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c + +libcurl_la-tftp.lo: tftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-tftp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-tftp.Tpo -c -o libcurl_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-tftp.Tpo $(DEPDIR)/libcurl_la-tftp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tftp.c' object='libcurl_la-tftp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c + +libcurl_la-timediff.lo: timediff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-timediff.lo -MD -MP -MF $(DEPDIR)/libcurl_la-timediff.Tpo -c -o libcurl_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-timediff.Tpo $(DEPDIR)/libcurl_la-timediff.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timediff.c' object='libcurl_la-timediff.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c + +libcurl_la-timeval.lo: timeval.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-timeval.lo -MD -MP -MF $(DEPDIR)/libcurl_la-timeval.Tpo -c -o libcurl_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-timeval.Tpo $(DEPDIR)/libcurl_la-timeval.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timeval.c' object='libcurl_la-timeval.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c + +libcurl_la-transfer.lo: transfer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-transfer.lo -MD -MP -MF $(DEPDIR)/libcurl_la-transfer.Tpo -c -o libcurl_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-transfer.Tpo $(DEPDIR)/libcurl_la-transfer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='transfer.c' object='libcurl_la-transfer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c + +libcurl_la-url.lo: url.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-url.lo -MD -MP -MF $(DEPDIR)/libcurl_la-url.Tpo -c -o libcurl_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-url.Tpo $(DEPDIR)/libcurl_la-url.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='url.c' object='libcurl_la-url.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c + +libcurl_la-urlapi.lo: urlapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-urlapi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-urlapi.Tpo -c -o libcurl_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-urlapi.Tpo $(DEPDIR)/libcurl_la-urlapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='urlapi.c' object='libcurl_la-urlapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c + +libcurl_la-version.lo: version.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-version.lo -MD -MP -MF $(DEPDIR)/libcurl_la-version.Tpo -c -o libcurl_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-version.Tpo $(DEPDIR)/libcurl_la-version.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='version.c' object='libcurl_la-version.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c + +libcurl_la-version_win32.lo: version_win32.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-version_win32.lo -MD -MP -MF $(DEPDIR)/libcurl_la-version_win32.Tpo -c -o libcurl_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-version_win32.Tpo $(DEPDIR)/libcurl_la-version_win32.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='version_win32.c' object='libcurl_la-version_win32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c + +libcurl_la-warnless.lo: warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-warnless.lo -MD -MP -MF $(DEPDIR)/libcurl_la-warnless.Tpo -c -o libcurl_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-warnless.Tpo $(DEPDIR)/libcurl_la-warnless.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='warnless.c' object='libcurl_la-warnless.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c + +libcurl_la-ws.lo: ws.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ws.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ws.Tpo -c -o libcurl_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ws.Tpo $(DEPDIR)/libcurl_la-ws.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ws.c' object='libcurl_la-ws.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c + +vauth/libcurl_la-cleartext.lo: vauth/cleartext.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-cleartext.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-cleartext.Tpo -c -o vauth/libcurl_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-cleartext.Tpo vauth/$(DEPDIR)/libcurl_la-cleartext.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/cleartext.c' object='vauth/libcurl_la-cleartext.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c + +vauth/libcurl_la-cram.lo: vauth/cram.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-cram.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-cram.Tpo -c -o vauth/libcurl_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-cram.Tpo vauth/$(DEPDIR)/libcurl_la-cram.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/cram.c' object='vauth/libcurl_la-cram.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c + +vauth/libcurl_la-digest.lo: vauth/digest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-digest.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-digest.Tpo -c -o vauth/libcurl_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-digest.Tpo vauth/$(DEPDIR)/libcurl_la-digest.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/digest.c' object='vauth/libcurl_la-digest.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c + +vauth/libcurl_la-digest_sspi.lo: vauth/digest_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-digest_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-digest_sspi.Tpo -c -o vauth/libcurl_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-digest_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/digest_sspi.c' object='vauth/libcurl_la-digest_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c + +vauth/libcurl_la-gsasl.lo: vauth/gsasl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-gsasl.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-gsasl.Tpo -c -o vauth/libcurl_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-gsasl.Tpo vauth/$(DEPDIR)/libcurl_la-gsasl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/gsasl.c' object='vauth/libcurl_la-gsasl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c + +vauth/libcurl_la-krb5_gssapi.lo: vauth/krb5_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-krb5_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Tpo -c -o vauth/libcurl_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Tpo vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/krb5_gssapi.c' object='vauth/libcurl_la-krb5_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c + +vauth/libcurl_la-krb5_sspi.lo: vauth/krb5_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-krb5_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Tpo -c -o vauth/libcurl_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/krb5_sspi.c' object='vauth/libcurl_la-krb5_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c + +vauth/libcurl_la-ntlm.lo: vauth/ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-ntlm.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-ntlm.Tpo -c -o vauth/libcurl_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-ntlm.Tpo vauth/$(DEPDIR)/libcurl_la-ntlm.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/ntlm.c' object='vauth/libcurl_la-ntlm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c + +vauth/libcurl_la-ntlm_sspi.lo: vauth/ntlm_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-ntlm_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Tpo -c -o vauth/libcurl_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/ntlm_sspi.c' object='vauth/libcurl_la-ntlm_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c + +vauth/libcurl_la-oauth2.lo: vauth/oauth2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-oauth2.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-oauth2.Tpo -c -o vauth/libcurl_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-oauth2.Tpo vauth/$(DEPDIR)/libcurl_la-oauth2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/oauth2.c' object='vauth/libcurl_la-oauth2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c + +vauth/libcurl_la-spnego_gssapi.lo: vauth/spnego_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-spnego_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Tpo -c -o vauth/libcurl_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Tpo vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/spnego_gssapi.c' object='vauth/libcurl_la-spnego_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c + +vauth/libcurl_la-spnego_sspi.lo: vauth/spnego_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-spnego_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Tpo -c -o vauth/libcurl_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/spnego_sspi.c' object='vauth/libcurl_la-spnego_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c + +vauth/libcurl_la-vauth.lo: vauth/vauth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-vauth.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-vauth.Tpo -c -o vauth/libcurl_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-vauth.Tpo vauth/$(DEPDIR)/libcurl_la-vauth.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/vauth.c' object='vauth/libcurl_la-vauth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c + +vtls/libcurl_la-bearssl.lo: vtls/bearssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-bearssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-bearssl.Tpo -c -o vtls/libcurl_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-bearssl.Tpo vtls/$(DEPDIR)/libcurl_la-bearssl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/bearssl.c' object='vtls/libcurl_la-bearssl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c + +vtls/libcurl_la-gtls.lo: vtls/gtls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-gtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-gtls.Tpo -c -o vtls/libcurl_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-gtls.Tpo vtls/$(DEPDIR)/libcurl_la-gtls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/gtls.c' object='vtls/libcurl_la-gtls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c + +vtls/libcurl_la-hostcheck.lo: vtls/hostcheck.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-hostcheck.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-hostcheck.Tpo -c -o vtls/libcurl_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-hostcheck.Tpo vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/hostcheck.c' object='vtls/libcurl_la-hostcheck.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c + +vtls/libcurl_la-keylog.lo: vtls/keylog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-keylog.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-keylog.Tpo -c -o vtls/libcurl_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-keylog.Tpo vtls/$(DEPDIR)/libcurl_la-keylog.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/keylog.c' object='vtls/libcurl_la-keylog.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c + +vtls/libcurl_la-mbedtls.lo: vtls/mbedtls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-mbedtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-mbedtls.Tpo -c -o vtls/libcurl_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-mbedtls.Tpo vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/mbedtls.c' object='vtls/libcurl_la-mbedtls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c + +vtls/libcurl_la-mbedtls_threadlock.lo: vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-mbedtls_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Tpo -c -o vtls/libcurl_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Tpo vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/mbedtls_threadlock.c' object='vtls/libcurl_la-mbedtls_threadlock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c + +vtls/libcurl_la-openssl.lo: vtls/openssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-openssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-openssl.Tpo -c -o vtls/libcurl_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-openssl.Tpo vtls/$(DEPDIR)/libcurl_la-openssl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/openssl.c' object='vtls/libcurl_la-openssl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c + +vtls/libcurl_la-rustls.lo: vtls/rustls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-rustls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-rustls.Tpo -c -o vtls/libcurl_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-rustls.Tpo vtls/$(DEPDIR)/libcurl_la-rustls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/rustls.c' object='vtls/libcurl_la-rustls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c + +vtls/libcurl_la-schannel.lo: vtls/schannel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-schannel.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-schannel.Tpo -c -o vtls/libcurl_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-schannel.Tpo vtls/$(DEPDIR)/libcurl_la-schannel.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/schannel.c' object='vtls/libcurl_la-schannel.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c + +vtls/libcurl_la-schannel_verify.lo: vtls/schannel_verify.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-schannel_verify.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-schannel_verify.Tpo -c -o vtls/libcurl_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-schannel_verify.Tpo vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/schannel_verify.c' object='vtls/libcurl_la-schannel_verify.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c + +vtls/libcurl_la-sectransp.lo: vtls/sectransp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-sectransp.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-sectransp.Tpo -c -o vtls/libcurl_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-sectransp.Tpo vtls/$(DEPDIR)/libcurl_la-sectransp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/sectransp.c' object='vtls/libcurl_la-sectransp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c + +vtls/libcurl_la-vtls.lo: vtls/vtls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-vtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-vtls.Tpo -c -o vtls/libcurl_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-vtls.Tpo vtls/$(DEPDIR)/libcurl_la-vtls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/vtls.c' object='vtls/libcurl_la-vtls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c + +vtls/libcurl_la-wolfssl.lo: vtls/wolfssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-wolfssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-wolfssl.Tpo -c -o vtls/libcurl_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-wolfssl.Tpo vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/wolfssl.c' object='vtls/libcurl_la-wolfssl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c + +vtls/libcurl_la-x509asn1.lo: vtls/x509asn1.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-x509asn1.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-x509asn1.Tpo -c -o vtls/libcurl_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-x509asn1.Tpo vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/x509asn1.c' object='vtls/libcurl_la-x509asn1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c + +vquic/libcurl_la-curl_msh3.lo: vquic/curl_msh3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_msh3.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_msh3.Tpo -c -o vquic/libcurl_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_msh3.Tpo vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_msh3.c' object='vquic/libcurl_la-curl_msh3.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c + +vquic/libcurl_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_ngtcp2.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Tpo -c -o vquic/libcurl_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Tpo vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_ngtcp2.c' object='vquic/libcurl_la-curl_ngtcp2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c + +vquic/libcurl_la-curl_osslq.lo: vquic/curl_osslq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_osslq.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_osslq.Tpo -c -o vquic/libcurl_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_osslq.Tpo vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_osslq.c' object='vquic/libcurl_la-curl_osslq.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c + +vquic/libcurl_la-curl_quiche.lo: vquic/curl_quiche.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_quiche.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_quiche.Tpo -c -o vquic/libcurl_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_quiche.Tpo vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_quiche.c' object='vquic/libcurl_la-curl_quiche.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c + +vquic/libcurl_la-vquic.lo: vquic/vquic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-vquic.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-vquic.Tpo -c -o vquic/libcurl_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-vquic.Tpo vquic/$(DEPDIR)/libcurl_la-vquic.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/vquic.c' object='vquic/libcurl_la-vquic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c + +vquic/libcurl_la-vquic-tls.lo: vquic/vquic-tls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-vquic-tls.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-vquic-tls.Tpo -c -o vquic/libcurl_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-vquic-tls.Tpo vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/vquic-tls.c' object='vquic/libcurl_la-vquic-tls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c + +vssh/libcurl_la-libssh.lo: vssh/libssh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vssh/libcurl_la-libssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-libssh.Tpo -c -o vssh/libcurl_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-libssh.Tpo vssh/$(DEPDIR)/libcurl_la-libssh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/libssh.c' object='vssh/libcurl_la-libssh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c + +vssh/libcurl_la-libssh2.lo: vssh/libssh2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vssh/libcurl_la-libssh2.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-libssh2.Tpo -c -o vssh/libcurl_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-libssh2.Tpo vssh/$(DEPDIR)/libcurl_la-libssh2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/libssh2.c' object='vssh/libcurl_la-libssh2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c + +vssh/libcurl_la-wolfssh.lo: vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vssh/libcurl_la-wolfssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-wolfssh.Tpo -c -o vssh/libcurl_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-wolfssh.Tpo vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/wolfssh.c' object='vssh/libcurl_la-wolfssh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c + +libcurlu_la-altsvc.lo: altsvc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-altsvc.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-altsvc.Tpo -c -o libcurlu_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-altsvc.Tpo $(DEPDIR)/libcurlu_la-altsvc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='altsvc.c' object='libcurlu_la-altsvc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c + +libcurlu_la-amigaos.lo: amigaos.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-amigaos.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-amigaos.Tpo -c -o libcurlu_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-amigaos.Tpo $(DEPDIR)/libcurlu_la-amigaos.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='amigaos.c' object='libcurlu_la-amigaos.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c + +libcurlu_la-asyn-ares.lo: asyn-ares.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-asyn-ares.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-asyn-ares.Tpo -c -o libcurlu_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-asyn-ares.Tpo $(DEPDIR)/libcurlu_la-asyn-ares.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asyn-ares.c' object='libcurlu_la-asyn-ares.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c + +libcurlu_la-asyn-thread.lo: asyn-thread.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-asyn-thread.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-asyn-thread.Tpo -c -o libcurlu_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-asyn-thread.Tpo $(DEPDIR)/libcurlu_la-asyn-thread.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asyn-thread.c' object='libcurlu_la-asyn-thread.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c + +libcurlu_la-base64.lo: base64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-base64.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-base64.Tpo -c -o libcurlu_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-base64.Tpo $(DEPDIR)/libcurlu_la-base64.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='base64.c' object='libcurlu_la-base64.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c + +libcurlu_la-bufq.lo: bufq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-bufq.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-bufq.Tpo -c -o libcurlu_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-bufq.Tpo $(DEPDIR)/libcurlu_la-bufq.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bufq.c' object='libcurlu_la-bufq.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c + +libcurlu_la-bufref.lo: bufref.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-bufref.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-bufref.Tpo -c -o libcurlu_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-bufref.Tpo $(DEPDIR)/libcurlu_la-bufref.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bufref.c' object='libcurlu_la-bufref.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c + +libcurlu_la-c-hyper.lo: c-hyper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-c-hyper.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-c-hyper.Tpo -c -o libcurlu_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-c-hyper.Tpo $(DEPDIR)/libcurlu_la-c-hyper.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='c-hyper.c' object='libcurlu_la-c-hyper.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c + +libcurlu_la-cf-h1-proxy.lo: cf-h1-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-h1-proxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-h1-proxy.Tpo -c -o libcurlu_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-h1-proxy.Tpo $(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-h1-proxy.c' object='libcurlu_la-cf-h1-proxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c + +libcurlu_la-cf-h2-proxy.lo: cf-h2-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-h2-proxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-h2-proxy.Tpo -c -o libcurlu_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-h2-proxy.Tpo $(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-h2-proxy.c' object='libcurlu_la-cf-h2-proxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c + +libcurlu_la-cf-haproxy.lo: cf-haproxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-haproxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-haproxy.Tpo -c -o libcurlu_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-haproxy.Tpo $(DEPDIR)/libcurlu_la-cf-haproxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-haproxy.c' object='libcurlu_la-cf-haproxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c + +libcurlu_la-cf-https-connect.lo: cf-https-connect.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-https-connect.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-https-connect.Tpo -c -o libcurlu_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-https-connect.Tpo $(DEPDIR)/libcurlu_la-cf-https-connect.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-https-connect.c' object='libcurlu_la-cf-https-connect.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c + +libcurlu_la-cf-socket.lo: cf-socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-socket.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-socket.Tpo -c -o libcurlu_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-socket.Tpo $(DEPDIR)/libcurlu_la-cf-socket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-socket.c' object='libcurlu_la-cf-socket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c + +libcurlu_la-cfilters.lo: cfilters.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cfilters.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cfilters.Tpo -c -o libcurlu_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cfilters.Tpo $(DEPDIR)/libcurlu_la-cfilters.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cfilters.c' object='libcurlu_la-cfilters.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c + +libcurlu_la-conncache.lo: conncache.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-conncache.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-conncache.Tpo -c -o libcurlu_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-conncache.Tpo $(DEPDIR)/libcurlu_la-conncache.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='conncache.c' object='libcurlu_la-conncache.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c + +libcurlu_la-connect.lo: connect.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-connect.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-connect.Tpo -c -o libcurlu_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-connect.Tpo $(DEPDIR)/libcurlu_la-connect.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connect.c' object='libcurlu_la-connect.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c + +libcurlu_la-content_encoding.lo: content_encoding.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-content_encoding.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-content_encoding.Tpo -c -o libcurlu_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-content_encoding.Tpo $(DEPDIR)/libcurlu_la-content_encoding.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='content_encoding.c' object='libcurlu_la-content_encoding.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c + +libcurlu_la-cookie.lo: cookie.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cookie.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cookie.Tpo -c -o libcurlu_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cookie.Tpo $(DEPDIR)/libcurlu_la-cookie.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cookie.c' object='libcurlu_la-cookie.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c + +libcurlu_la-curl_addrinfo.lo: curl_addrinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_addrinfo.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_addrinfo.Tpo -c -o libcurlu_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_addrinfo.Tpo $(DEPDIR)/libcurlu_la-curl_addrinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_addrinfo.c' object='libcurlu_la-curl_addrinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c + +libcurlu_la-curl_des.lo: curl_des.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_des.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_des.Tpo -c -o libcurlu_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_des.Tpo $(DEPDIR)/libcurlu_la-curl_des.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_des.c' object='libcurlu_la-curl_des.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c + +libcurlu_la-curl_endian.lo: curl_endian.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_endian.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_endian.Tpo -c -o libcurlu_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_endian.Tpo $(DEPDIR)/libcurlu_la-curl_endian.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_endian.c' object='libcurlu_la-curl_endian.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c + +libcurlu_la-curl_fnmatch.lo: curl_fnmatch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_fnmatch.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_fnmatch.Tpo -c -o libcurlu_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_fnmatch.Tpo $(DEPDIR)/libcurlu_la-curl_fnmatch.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_fnmatch.c' object='libcurlu_la-curl_fnmatch.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c + +libcurlu_la-curl_get_line.lo: curl_get_line.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_get_line.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_get_line.Tpo -c -o libcurlu_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_get_line.Tpo $(DEPDIR)/libcurlu_la-curl_get_line.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_get_line.c' object='libcurlu_la-curl_get_line.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c + +libcurlu_la-curl_gethostname.lo: curl_gethostname.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_gethostname.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_gethostname.Tpo -c -o libcurlu_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_gethostname.Tpo $(DEPDIR)/libcurlu_la-curl_gethostname.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_gethostname.c' object='libcurlu_la-curl_gethostname.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c + +libcurlu_la-curl_gssapi.lo: curl_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_gssapi.Tpo -c -o libcurlu_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_gssapi.Tpo $(DEPDIR)/libcurlu_la-curl_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_gssapi.c' object='libcurlu_la-curl_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c + +libcurlu_la-curl_memrchr.lo: curl_memrchr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_memrchr.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_memrchr.Tpo -c -o libcurlu_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_memrchr.Tpo $(DEPDIR)/libcurlu_la-curl_memrchr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_memrchr.c' object='libcurlu_la-curl_memrchr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c + +libcurlu_la-curl_multibyte.lo: curl_multibyte.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_multibyte.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_multibyte.Tpo -c -o libcurlu_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_multibyte.Tpo $(DEPDIR)/libcurlu_la-curl_multibyte.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_multibyte.c' object='libcurlu_la-curl_multibyte.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c + +libcurlu_la-curl_ntlm_core.lo: curl_ntlm_core.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_ntlm_core.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_ntlm_core.Tpo -c -o libcurlu_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_ntlm_core.Tpo $(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_ntlm_core.c' object='libcurlu_la-curl_ntlm_core.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c + +libcurlu_la-curl_ntlm_wb.lo: curl_ntlm_wb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_ntlm_wb.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Tpo -c -o libcurlu_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Tpo $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_ntlm_wb.c' object='libcurlu_la-curl_ntlm_wb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c + +libcurlu_la-curl_path.lo: curl_path.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_path.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_path.Tpo -c -o libcurlu_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_path.Tpo $(DEPDIR)/libcurlu_la-curl_path.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_path.c' object='libcurlu_la-curl_path.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c + +libcurlu_la-curl_range.lo: curl_range.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_range.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_range.Tpo -c -o libcurlu_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_range.Tpo $(DEPDIR)/libcurlu_la-curl_range.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_range.c' object='libcurlu_la-curl_range.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c + +libcurlu_la-curl_rtmp.lo: curl_rtmp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_rtmp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_rtmp.Tpo -c -o libcurlu_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_rtmp.Tpo $(DEPDIR)/libcurlu_la-curl_rtmp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_rtmp.c' object='libcurlu_la-curl_rtmp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c + +libcurlu_la-curl_sasl.lo: curl_sasl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_sasl.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_sasl.Tpo -c -o libcurlu_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_sasl.Tpo $(DEPDIR)/libcurlu_la-curl_sasl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_sasl.c' object='libcurlu_la-curl_sasl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c + +libcurlu_la-curl_sspi.lo: curl_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_sspi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_sspi.Tpo -c -o libcurlu_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_sspi.Tpo $(DEPDIR)/libcurlu_la-curl_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_sspi.c' object='libcurlu_la-curl_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c + +libcurlu_la-curl_threads.lo: curl_threads.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_threads.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_threads.Tpo -c -o libcurlu_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_threads.Tpo $(DEPDIR)/libcurlu_la-curl_threads.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_threads.c' object='libcurlu_la-curl_threads.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c + +libcurlu_la-curl_trc.lo: curl_trc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_trc.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_trc.Tpo -c -o libcurlu_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_trc.Tpo $(DEPDIR)/libcurlu_la-curl_trc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_trc.c' object='libcurlu_la-curl_trc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c + +libcurlu_la-dict.lo: dict.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dict.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dict.Tpo -c -o libcurlu_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dict.Tpo $(DEPDIR)/libcurlu_la-dict.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dict.c' object='libcurlu_la-dict.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c + +libcurlu_la-doh.lo: doh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-doh.Tpo -c -o libcurlu_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-doh.Tpo $(DEPDIR)/libcurlu_la-doh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='doh.c' object='libcurlu_la-doh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c + +libcurlu_la-dynbuf.lo: dynbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dynbuf.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dynbuf.Tpo -c -o libcurlu_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dynbuf.Tpo $(DEPDIR)/libcurlu_la-dynbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dynbuf.c' object='libcurlu_la-dynbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c + +libcurlu_la-dynhds.lo: dynhds.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dynhds.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dynhds.Tpo -c -o libcurlu_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dynhds.Tpo $(DEPDIR)/libcurlu_la-dynhds.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dynhds.c' object='libcurlu_la-dynhds.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c + +libcurlu_la-easy.lo: easy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-easy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-easy.Tpo -c -o libcurlu_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-easy.Tpo $(DEPDIR)/libcurlu_la-easy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='easy.c' object='libcurlu_la-easy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c + +libcurlu_la-easygetopt.lo: easygetopt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-easygetopt.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-easygetopt.Tpo -c -o libcurlu_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-easygetopt.Tpo $(DEPDIR)/libcurlu_la-easygetopt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='easygetopt.c' object='libcurlu_la-easygetopt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c + +libcurlu_la-easyoptions.lo: easyoptions.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-easyoptions.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-easyoptions.Tpo -c -o libcurlu_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-easyoptions.Tpo $(DEPDIR)/libcurlu_la-easyoptions.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='easyoptions.c' object='libcurlu_la-easyoptions.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c + +libcurlu_la-escape.lo: escape.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-escape.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-escape.Tpo -c -o libcurlu_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-escape.Tpo $(DEPDIR)/libcurlu_la-escape.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='escape.c' object='libcurlu_la-escape.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c + +libcurlu_la-file.lo: file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-file.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-file.Tpo -c -o libcurlu_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-file.Tpo $(DEPDIR)/libcurlu_la-file.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='file.c' object='libcurlu_la-file.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c + +libcurlu_la-fileinfo.lo: fileinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-fileinfo.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-fileinfo.Tpo -c -o libcurlu_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-fileinfo.Tpo $(DEPDIR)/libcurlu_la-fileinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fileinfo.c' object='libcurlu_la-fileinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c + +libcurlu_la-fopen.lo: fopen.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-fopen.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-fopen.Tpo -c -o libcurlu_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-fopen.Tpo $(DEPDIR)/libcurlu_la-fopen.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fopen.c' object='libcurlu_la-fopen.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c + +libcurlu_la-formdata.lo: formdata.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-formdata.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-formdata.Tpo -c -o libcurlu_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-formdata.Tpo $(DEPDIR)/libcurlu_la-formdata.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='formdata.c' object='libcurlu_la-formdata.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c + +libcurlu_la-ftp.lo: ftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ftp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ftp.Tpo -c -o libcurlu_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ftp.Tpo $(DEPDIR)/libcurlu_la-ftp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ftp.c' object='libcurlu_la-ftp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c + +libcurlu_la-ftplistparser.lo: ftplistparser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ftplistparser.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ftplistparser.Tpo -c -o libcurlu_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ftplistparser.Tpo $(DEPDIR)/libcurlu_la-ftplistparser.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ftplistparser.c' object='libcurlu_la-ftplistparser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c + +libcurlu_la-getenv.lo: getenv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-getenv.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-getenv.Tpo -c -o libcurlu_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-getenv.Tpo $(DEPDIR)/libcurlu_la-getenv.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getenv.c' object='libcurlu_la-getenv.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c + +libcurlu_la-getinfo.lo: getinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-getinfo.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-getinfo.Tpo -c -o libcurlu_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-getinfo.Tpo $(DEPDIR)/libcurlu_la-getinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getinfo.c' object='libcurlu_la-getinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c + +libcurlu_la-gopher.lo: gopher.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-gopher.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-gopher.Tpo -c -o libcurlu_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-gopher.Tpo $(DEPDIR)/libcurlu_la-gopher.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gopher.c' object='libcurlu_la-gopher.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c + +libcurlu_la-hash.lo: hash.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hash.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hash.Tpo -c -o libcurlu_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hash.Tpo $(DEPDIR)/libcurlu_la-hash.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hash.c' object='libcurlu_la-hash.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c + +libcurlu_la-headers.lo: headers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-headers.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-headers.Tpo -c -o libcurlu_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-headers.Tpo $(DEPDIR)/libcurlu_la-headers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='headers.c' object='libcurlu_la-headers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c + +libcurlu_la-hmac.lo: hmac.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hmac.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hmac.Tpo -c -o libcurlu_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hmac.Tpo $(DEPDIR)/libcurlu_la-hmac.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hmac.c' object='libcurlu_la-hmac.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c + +libcurlu_la-hostasyn.lo: hostasyn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostasyn.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostasyn.Tpo -c -o libcurlu_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostasyn.Tpo $(DEPDIR)/libcurlu_la-hostasyn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostasyn.c' object='libcurlu_la-hostasyn.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c + +libcurlu_la-hostip.lo: hostip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostip.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostip.Tpo -c -o libcurlu_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostip.Tpo $(DEPDIR)/libcurlu_la-hostip.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostip.c' object='libcurlu_la-hostip.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c + +libcurlu_la-hostip4.lo: hostip4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostip4.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostip4.Tpo -c -o libcurlu_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostip4.Tpo $(DEPDIR)/libcurlu_la-hostip4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostip4.c' object='libcurlu_la-hostip4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c + +libcurlu_la-hostip6.lo: hostip6.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostip6.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostip6.Tpo -c -o libcurlu_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostip6.Tpo $(DEPDIR)/libcurlu_la-hostip6.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostip6.c' object='libcurlu_la-hostip6.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c + +libcurlu_la-hostsyn.lo: hostsyn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostsyn.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostsyn.Tpo -c -o libcurlu_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostsyn.Tpo $(DEPDIR)/libcurlu_la-hostsyn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostsyn.c' object='libcurlu_la-hostsyn.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c + +libcurlu_la-hsts.lo: hsts.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hsts.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hsts.Tpo -c -o libcurlu_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hsts.Tpo $(DEPDIR)/libcurlu_la-hsts.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hsts.c' object='libcurlu_la-hsts.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c + +libcurlu_la-http.lo: http.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http.Tpo -c -o libcurlu_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http.Tpo $(DEPDIR)/libcurlu_la-http.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http.c' object='libcurlu_la-http.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c + +libcurlu_la-http1.lo: http1.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http1.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http1.Tpo -c -o libcurlu_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http1.Tpo $(DEPDIR)/libcurlu_la-http1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http1.c' object='libcurlu_la-http1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c + +libcurlu_la-http2.lo: http2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http2.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http2.Tpo -c -o libcurlu_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http2.Tpo $(DEPDIR)/libcurlu_la-http2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http2.c' object='libcurlu_la-http2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c + +libcurlu_la-http_aws_sigv4.lo: http_aws_sigv4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_aws_sigv4.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_aws_sigv4.Tpo -c -o libcurlu_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_aws_sigv4.Tpo $(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_aws_sigv4.c' object='libcurlu_la-http_aws_sigv4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c + +libcurlu_la-http_chunks.lo: http_chunks.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_chunks.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_chunks.Tpo -c -o libcurlu_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_chunks.Tpo $(DEPDIR)/libcurlu_la-http_chunks.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_chunks.c' object='libcurlu_la-http_chunks.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c + +libcurlu_la-http_digest.lo: http_digest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_digest.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_digest.Tpo -c -o libcurlu_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_digest.Tpo $(DEPDIR)/libcurlu_la-http_digest.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_digest.c' object='libcurlu_la-http_digest.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c + +libcurlu_la-http_negotiate.lo: http_negotiate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_negotiate.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_negotiate.Tpo -c -o libcurlu_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_negotiate.Tpo $(DEPDIR)/libcurlu_la-http_negotiate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_negotiate.c' object='libcurlu_la-http_negotiate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c + +libcurlu_la-http_ntlm.lo: http_ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_ntlm.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_ntlm.Tpo -c -o libcurlu_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_ntlm.Tpo $(DEPDIR)/libcurlu_la-http_ntlm.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_ntlm.c' object='libcurlu_la-http_ntlm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c + +libcurlu_la-http_proxy.lo: http_proxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_proxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_proxy.Tpo -c -o libcurlu_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_proxy.Tpo $(DEPDIR)/libcurlu_la-http_proxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_proxy.c' object='libcurlu_la-http_proxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c + +libcurlu_la-idn.lo: idn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-idn.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-idn.Tpo -c -o libcurlu_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-idn.Tpo $(DEPDIR)/libcurlu_la-idn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='idn.c' object='libcurlu_la-idn.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c + +libcurlu_la-if2ip.lo: if2ip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-if2ip.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-if2ip.Tpo -c -o libcurlu_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-if2ip.Tpo $(DEPDIR)/libcurlu_la-if2ip.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='if2ip.c' object='libcurlu_la-if2ip.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c + +libcurlu_la-imap.lo: imap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-imap.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-imap.Tpo -c -o libcurlu_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-imap.Tpo $(DEPDIR)/libcurlu_la-imap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap.c' object='libcurlu_la-imap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c + +libcurlu_la-inet_ntop.lo: inet_ntop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-inet_ntop.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-inet_ntop.Tpo -c -o libcurlu_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-inet_ntop.Tpo $(DEPDIR)/libcurlu_la-inet_ntop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='inet_ntop.c' object='libcurlu_la-inet_ntop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c + +libcurlu_la-inet_pton.lo: inet_pton.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-inet_pton.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-inet_pton.Tpo -c -o libcurlu_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-inet_pton.Tpo $(DEPDIR)/libcurlu_la-inet_pton.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='inet_pton.c' object='libcurlu_la-inet_pton.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c + +libcurlu_la-krb5.lo: krb5.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-krb5.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-krb5.Tpo -c -o libcurlu_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-krb5.Tpo $(DEPDIR)/libcurlu_la-krb5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='krb5.c' object='libcurlu_la-krb5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c + +libcurlu_la-ldap.lo: ldap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ldap.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ldap.Tpo -c -o libcurlu_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ldap.Tpo $(DEPDIR)/libcurlu_la-ldap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ldap.c' object='libcurlu_la-ldap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c + +libcurlu_la-llist.lo: llist.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-llist.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-llist.Tpo -c -o libcurlu_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-llist.Tpo $(DEPDIR)/libcurlu_la-llist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='llist.c' object='libcurlu_la-llist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c + +libcurlu_la-macos.lo: macos.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-macos.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-macos.Tpo -c -o libcurlu_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-macos.Tpo $(DEPDIR)/libcurlu_la-macos.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='macos.c' object='libcurlu_la-macos.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c + +libcurlu_la-md4.lo: md4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-md4.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-md4.Tpo -c -o libcurlu_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-md4.Tpo $(DEPDIR)/libcurlu_la-md4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md4.c' object='libcurlu_la-md4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c + +libcurlu_la-md5.lo: md5.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-md5.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-md5.Tpo -c -o libcurlu_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-md5.Tpo $(DEPDIR)/libcurlu_la-md5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md5.c' object='libcurlu_la-md5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c + +libcurlu_la-memdebug.lo: memdebug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-memdebug.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-memdebug.Tpo -c -o libcurlu_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-memdebug.Tpo $(DEPDIR)/libcurlu_la-memdebug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='memdebug.c' object='libcurlu_la-memdebug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c + +libcurlu_la-mime.lo: mime.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-mime.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-mime.Tpo -c -o libcurlu_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-mime.Tpo $(DEPDIR)/libcurlu_la-mime.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mime.c' object='libcurlu_la-mime.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c + +libcurlu_la-mprintf.lo: mprintf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-mprintf.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-mprintf.Tpo -c -o libcurlu_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-mprintf.Tpo $(DEPDIR)/libcurlu_la-mprintf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mprintf.c' object='libcurlu_la-mprintf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c + +libcurlu_la-mqtt.lo: mqtt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-mqtt.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-mqtt.Tpo -c -o libcurlu_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-mqtt.Tpo $(DEPDIR)/libcurlu_la-mqtt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mqtt.c' object='libcurlu_la-mqtt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c + +libcurlu_la-multi.lo: multi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-multi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-multi.Tpo -c -o libcurlu_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-multi.Tpo $(DEPDIR)/libcurlu_la-multi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='multi.c' object='libcurlu_la-multi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c + +libcurlu_la-netrc.lo: netrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-netrc.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-netrc.Tpo -c -o libcurlu_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-netrc.Tpo $(DEPDIR)/libcurlu_la-netrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netrc.c' object='libcurlu_la-netrc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c + +libcurlu_la-nonblock.lo: nonblock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-nonblock.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-nonblock.Tpo -c -o libcurlu_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-nonblock.Tpo $(DEPDIR)/libcurlu_la-nonblock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nonblock.c' object='libcurlu_la-nonblock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c + +libcurlu_la-noproxy.lo: noproxy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-noproxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-noproxy.Tpo -c -o libcurlu_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-noproxy.Tpo $(DEPDIR)/libcurlu_la-noproxy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='noproxy.c' object='libcurlu_la-noproxy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c + +libcurlu_la-openldap.lo: openldap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-openldap.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-openldap.Tpo -c -o libcurlu_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-openldap.Tpo $(DEPDIR)/libcurlu_la-openldap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openldap.c' object='libcurlu_la-openldap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c + +libcurlu_la-parsedate.lo: parsedate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-parsedate.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-parsedate.Tpo -c -o libcurlu_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-parsedate.Tpo $(DEPDIR)/libcurlu_la-parsedate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='parsedate.c' object='libcurlu_la-parsedate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c + +libcurlu_la-pingpong.lo: pingpong.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-pingpong.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-pingpong.Tpo -c -o libcurlu_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-pingpong.Tpo $(DEPDIR)/libcurlu_la-pingpong.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pingpong.c' object='libcurlu_la-pingpong.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c + +libcurlu_la-pop3.lo: pop3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-pop3.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-pop3.Tpo -c -o libcurlu_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-pop3.Tpo $(DEPDIR)/libcurlu_la-pop3.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pop3.c' object='libcurlu_la-pop3.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c + +libcurlu_la-progress.lo: progress.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-progress.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-progress.Tpo -c -o libcurlu_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-progress.Tpo $(DEPDIR)/libcurlu_la-progress.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='libcurlu_la-progress.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c + +libcurlu_la-psl.lo: psl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-psl.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-psl.Tpo -c -o libcurlu_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-psl.Tpo $(DEPDIR)/libcurlu_la-psl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='psl.c' object='libcurlu_la-psl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c + +libcurlu_la-rand.lo: rand.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-rand.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-rand.Tpo -c -o libcurlu_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-rand.Tpo $(DEPDIR)/libcurlu_la-rand.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rand.c' object='libcurlu_la-rand.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c + +libcurlu_la-rename.lo: rename.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-rename.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-rename.Tpo -c -o libcurlu_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-rename.Tpo $(DEPDIR)/libcurlu_la-rename.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rename.c' object='libcurlu_la-rename.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c + +libcurlu_la-rtsp.lo: rtsp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-rtsp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-rtsp.Tpo -c -o libcurlu_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-rtsp.Tpo $(DEPDIR)/libcurlu_la-rtsp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtsp.c' object='libcurlu_la-rtsp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c + +libcurlu_la-select.lo: select.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-select.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-select.Tpo -c -o libcurlu_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-select.Tpo $(DEPDIR)/libcurlu_la-select.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='select.c' object='libcurlu_la-select.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c + +libcurlu_la-sendf.lo: sendf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-sendf.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-sendf.Tpo -c -o libcurlu_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-sendf.Tpo $(DEPDIR)/libcurlu_la-sendf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sendf.c' object='libcurlu_la-sendf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c + +libcurlu_la-setopt.lo: setopt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-setopt.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-setopt.Tpo -c -o libcurlu_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-setopt.Tpo $(DEPDIR)/libcurlu_la-setopt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='setopt.c' object='libcurlu_la-setopt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c + +libcurlu_la-sha256.lo: sha256.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-sha256.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-sha256.Tpo -c -o libcurlu_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-sha256.Tpo $(DEPDIR)/libcurlu_la-sha256.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sha256.c' object='libcurlu_la-sha256.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c + +libcurlu_la-share.lo: share.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-share.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-share.Tpo -c -o libcurlu_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-share.Tpo $(DEPDIR)/libcurlu_la-share.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='share.c' object='libcurlu_la-share.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c + +libcurlu_la-slist.lo: slist.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-slist.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-slist.Tpo -c -o libcurlu_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-slist.Tpo $(DEPDIR)/libcurlu_la-slist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slist.c' object='libcurlu_la-slist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c + +libcurlu_la-smb.lo: smb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-smb.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-smb.Tpo -c -o libcurlu_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-smb.Tpo $(DEPDIR)/libcurlu_la-smb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='smb.c' object='libcurlu_la-smb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c + +libcurlu_la-smtp.lo: smtp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-smtp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-smtp.Tpo -c -o libcurlu_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-smtp.Tpo $(DEPDIR)/libcurlu_la-smtp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='smtp.c' object='libcurlu_la-smtp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c + +libcurlu_la-socketpair.lo: socketpair.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socketpair.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socketpair.Tpo -c -o libcurlu_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socketpair.Tpo $(DEPDIR)/libcurlu_la-socketpair.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socketpair.c' object='libcurlu_la-socketpair.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c + +libcurlu_la-socks.lo: socks.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socks.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socks.Tpo -c -o libcurlu_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socks.Tpo $(DEPDIR)/libcurlu_la-socks.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socks.c' object='libcurlu_la-socks.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c + +libcurlu_la-socks_gssapi.lo: socks_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socks_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socks_gssapi.Tpo -c -o libcurlu_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socks_gssapi.Tpo $(DEPDIR)/libcurlu_la-socks_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socks_gssapi.c' object='libcurlu_la-socks_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c + +libcurlu_la-socks_sspi.lo: socks_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socks_sspi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socks_sspi.Tpo -c -o libcurlu_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socks_sspi.Tpo $(DEPDIR)/libcurlu_la-socks_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='socks_sspi.c' object='libcurlu_la-socks_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c + +libcurlu_la-speedcheck.lo: speedcheck.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-speedcheck.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-speedcheck.Tpo -c -o libcurlu_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-speedcheck.Tpo $(DEPDIR)/libcurlu_la-speedcheck.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='speedcheck.c' object='libcurlu_la-speedcheck.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c + +libcurlu_la-splay.lo: splay.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-splay.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-splay.Tpo -c -o libcurlu_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-splay.Tpo $(DEPDIR)/libcurlu_la-splay.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='splay.c' object='libcurlu_la-splay.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c + +libcurlu_la-strcase.lo: strcase.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strcase.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strcase.Tpo -c -o libcurlu_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strcase.Tpo $(DEPDIR)/libcurlu_la-strcase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strcase.c' object='libcurlu_la-strcase.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c + +libcurlu_la-strdup.lo: strdup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strdup.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strdup.Tpo -c -o libcurlu_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strdup.Tpo $(DEPDIR)/libcurlu_la-strdup.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strdup.c' object='libcurlu_la-strdup.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c + +libcurlu_la-strerror.lo: strerror.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strerror.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strerror.Tpo -c -o libcurlu_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strerror.Tpo $(DEPDIR)/libcurlu_la-strerror.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strerror.c' object='libcurlu_la-strerror.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c + +libcurlu_la-strtok.lo: strtok.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strtok.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strtok.Tpo -c -o libcurlu_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strtok.Tpo $(DEPDIR)/libcurlu_la-strtok.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtok.c' object='libcurlu_la-strtok.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c + +libcurlu_la-strtoofft.lo: strtoofft.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strtoofft.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strtoofft.Tpo -c -o libcurlu_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strtoofft.Tpo $(DEPDIR)/libcurlu_la-strtoofft.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtoofft.c' object='libcurlu_la-strtoofft.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c + +libcurlu_la-system_win32.lo: system_win32.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-system_win32.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-system_win32.Tpo -c -o libcurlu_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-system_win32.Tpo $(DEPDIR)/libcurlu_la-system_win32.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='system_win32.c' object='libcurlu_la-system_win32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c + +libcurlu_la-telnet.lo: telnet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-telnet.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-telnet.Tpo -c -o libcurlu_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-telnet.Tpo $(DEPDIR)/libcurlu_la-telnet.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='telnet.c' object='libcurlu_la-telnet.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c + +libcurlu_la-tftp.lo: tftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-tftp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-tftp.Tpo -c -o libcurlu_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-tftp.Tpo $(DEPDIR)/libcurlu_la-tftp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tftp.c' object='libcurlu_la-tftp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c + +libcurlu_la-timediff.lo: timediff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-timediff.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-timediff.Tpo -c -o libcurlu_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-timediff.Tpo $(DEPDIR)/libcurlu_la-timediff.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timediff.c' object='libcurlu_la-timediff.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c + +libcurlu_la-timeval.lo: timeval.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-timeval.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-timeval.Tpo -c -o libcurlu_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-timeval.Tpo $(DEPDIR)/libcurlu_la-timeval.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timeval.c' object='libcurlu_la-timeval.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c + +libcurlu_la-transfer.lo: transfer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-transfer.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-transfer.Tpo -c -o libcurlu_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-transfer.Tpo $(DEPDIR)/libcurlu_la-transfer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='transfer.c' object='libcurlu_la-transfer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c + +libcurlu_la-url.lo: url.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-url.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-url.Tpo -c -o libcurlu_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-url.Tpo $(DEPDIR)/libcurlu_la-url.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='url.c' object='libcurlu_la-url.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c + +libcurlu_la-urlapi.lo: urlapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-urlapi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-urlapi.Tpo -c -o libcurlu_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-urlapi.Tpo $(DEPDIR)/libcurlu_la-urlapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='urlapi.c' object='libcurlu_la-urlapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c + +libcurlu_la-version.lo: version.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-version.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-version.Tpo -c -o libcurlu_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-version.Tpo $(DEPDIR)/libcurlu_la-version.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='version.c' object='libcurlu_la-version.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c + +libcurlu_la-version_win32.lo: version_win32.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-version_win32.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-version_win32.Tpo -c -o libcurlu_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-version_win32.Tpo $(DEPDIR)/libcurlu_la-version_win32.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='version_win32.c' object='libcurlu_la-version_win32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c + +libcurlu_la-warnless.lo: warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-warnless.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-warnless.Tpo -c -o libcurlu_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-warnless.Tpo $(DEPDIR)/libcurlu_la-warnless.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='warnless.c' object='libcurlu_la-warnless.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c + +libcurlu_la-ws.lo: ws.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ws.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ws.Tpo -c -o libcurlu_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ws.Tpo $(DEPDIR)/libcurlu_la-ws.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ws.c' object='libcurlu_la-ws.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c + +vauth/libcurlu_la-cleartext.lo: vauth/cleartext.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-cleartext.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-cleartext.Tpo -c -o vauth/libcurlu_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-cleartext.Tpo vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/cleartext.c' object='vauth/libcurlu_la-cleartext.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c + +vauth/libcurlu_la-cram.lo: vauth/cram.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-cram.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-cram.Tpo -c -o vauth/libcurlu_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-cram.Tpo vauth/$(DEPDIR)/libcurlu_la-cram.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/cram.c' object='vauth/libcurlu_la-cram.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c + +vauth/libcurlu_la-digest.lo: vauth/digest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-digest.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-digest.Tpo -c -o vauth/libcurlu_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-digest.Tpo vauth/$(DEPDIR)/libcurlu_la-digest.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/digest.c' object='vauth/libcurlu_la-digest.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c + +vauth/libcurlu_la-digest_sspi.lo: vauth/digest_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-digest_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Tpo -c -o vauth/libcurlu_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/digest_sspi.c' object='vauth/libcurlu_la-digest_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c + +vauth/libcurlu_la-gsasl.lo: vauth/gsasl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-gsasl.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-gsasl.Tpo -c -o vauth/libcurlu_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-gsasl.Tpo vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/gsasl.c' object='vauth/libcurlu_la-gsasl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c + +vauth/libcurlu_la-krb5_gssapi.lo: vauth/krb5_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-krb5_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Tpo -c -o vauth/libcurlu_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Tpo vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/krb5_gssapi.c' object='vauth/libcurlu_la-krb5_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c + +vauth/libcurlu_la-krb5_sspi.lo: vauth/krb5_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-krb5_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Tpo -c -o vauth/libcurlu_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/krb5_sspi.c' object='vauth/libcurlu_la-krb5_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c + +vauth/libcurlu_la-ntlm.lo: vauth/ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-ntlm.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-ntlm.Tpo -c -o vauth/libcurlu_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-ntlm.Tpo vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/ntlm.c' object='vauth/libcurlu_la-ntlm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c + +vauth/libcurlu_la-ntlm_sspi.lo: vauth/ntlm_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-ntlm_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Tpo -c -o vauth/libcurlu_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/ntlm_sspi.c' object='vauth/libcurlu_la-ntlm_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c + +vauth/libcurlu_la-oauth2.lo: vauth/oauth2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-oauth2.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-oauth2.Tpo -c -o vauth/libcurlu_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-oauth2.Tpo vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/oauth2.c' object='vauth/libcurlu_la-oauth2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c + +vauth/libcurlu_la-spnego_gssapi.lo: vauth/spnego_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-spnego_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Tpo -c -o vauth/libcurlu_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Tpo vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/spnego_gssapi.c' object='vauth/libcurlu_la-spnego_gssapi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c + +vauth/libcurlu_la-spnego_sspi.lo: vauth/spnego_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-spnego_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Tpo -c -o vauth/libcurlu_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/spnego_sspi.c' object='vauth/libcurlu_la-spnego_sspi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c + +vauth/libcurlu_la-vauth.lo: vauth/vauth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-vauth.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-vauth.Tpo -c -o vauth/libcurlu_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-vauth.Tpo vauth/$(DEPDIR)/libcurlu_la-vauth.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vauth/vauth.c' object='vauth/libcurlu_la-vauth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c + +vtls/libcurlu_la-bearssl.lo: vtls/bearssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-bearssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-bearssl.Tpo -c -o vtls/libcurlu_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-bearssl.Tpo vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/bearssl.c' object='vtls/libcurlu_la-bearssl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c + +vtls/libcurlu_la-gtls.lo: vtls/gtls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-gtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-gtls.Tpo -c -o vtls/libcurlu_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-gtls.Tpo vtls/$(DEPDIR)/libcurlu_la-gtls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/gtls.c' object='vtls/libcurlu_la-gtls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c + +vtls/libcurlu_la-hostcheck.lo: vtls/hostcheck.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-hostcheck.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-hostcheck.Tpo -c -o vtls/libcurlu_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-hostcheck.Tpo vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/hostcheck.c' object='vtls/libcurlu_la-hostcheck.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c + +vtls/libcurlu_la-keylog.lo: vtls/keylog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-keylog.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-keylog.Tpo -c -o vtls/libcurlu_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-keylog.Tpo vtls/$(DEPDIR)/libcurlu_la-keylog.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/keylog.c' object='vtls/libcurlu_la-keylog.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c + +vtls/libcurlu_la-mbedtls.lo: vtls/mbedtls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-mbedtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-mbedtls.Tpo -c -o vtls/libcurlu_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-mbedtls.Tpo vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/mbedtls.c' object='vtls/libcurlu_la-mbedtls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c + +vtls/libcurlu_la-mbedtls_threadlock.lo: vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-mbedtls_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Tpo -c -o vtls/libcurlu_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Tpo vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/mbedtls_threadlock.c' object='vtls/libcurlu_la-mbedtls_threadlock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c + +vtls/libcurlu_la-openssl.lo: vtls/openssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-openssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-openssl.Tpo -c -o vtls/libcurlu_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-openssl.Tpo vtls/$(DEPDIR)/libcurlu_la-openssl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/openssl.c' object='vtls/libcurlu_la-openssl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c + +vtls/libcurlu_la-rustls.lo: vtls/rustls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-rustls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-rustls.Tpo -c -o vtls/libcurlu_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-rustls.Tpo vtls/$(DEPDIR)/libcurlu_la-rustls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/rustls.c' object='vtls/libcurlu_la-rustls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c + +vtls/libcurlu_la-schannel.lo: vtls/schannel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-schannel.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-schannel.Tpo -c -o vtls/libcurlu_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-schannel.Tpo vtls/$(DEPDIR)/libcurlu_la-schannel.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/schannel.c' object='vtls/libcurlu_la-schannel.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c + +vtls/libcurlu_la-schannel_verify.lo: vtls/schannel_verify.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-schannel_verify.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Tpo -c -o vtls/libcurlu_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Tpo vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/schannel_verify.c' object='vtls/libcurlu_la-schannel_verify.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c + +vtls/libcurlu_la-sectransp.lo: vtls/sectransp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-sectransp.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-sectransp.Tpo -c -o vtls/libcurlu_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-sectransp.Tpo vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/sectransp.c' object='vtls/libcurlu_la-sectransp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c + +vtls/libcurlu_la-vtls.lo: vtls/vtls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-vtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-vtls.Tpo -c -o vtls/libcurlu_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-vtls.Tpo vtls/$(DEPDIR)/libcurlu_la-vtls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/vtls.c' object='vtls/libcurlu_la-vtls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c + +vtls/libcurlu_la-wolfssl.lo: vtls/wolfssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-wolfssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-wolfssl.Tpo -c -o vtls/libcurlu_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-wolfssl.Tpo vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/wolfssl.c' object='vtls/libcurlu_la-wolfssl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c + +vtls/libcurlu_la-x509asn1.lo: vtls/x509asn1.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-x509asn1.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-x509asn1.Tpo -c -o vtls/libcurlu_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-x509asn1.Tpo vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/x509asn1.c' object='vtls/libcurlu_la-x509asn1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c + +vquic/libcurlu_la-curl_msh3.lo: vquic/curl_msh3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_msh3.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Tpo -c -o vquic/libcurlu_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_msh3.c' object='vquic/libcurlu_la-curl_msh3.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c + +vquic/libcurlu_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_ngtcp2.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Tpo -c -o vquic/libcurlu_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_ngtcp2.c' object='vquic/libcurlu_la-curl_ngtcp2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c + +vquic/libcurlu_la-curl_osslq.lo: vquic/curl_osslq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_osslq.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Tpo -c -o vquic/libcurlu_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_osslq.c' object='vquic/libcurlu_la-curl_osslq.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c + +vquic/libcurlu_la-curl_quiche.lo: vquic/curl_quiche.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_quiche.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Tpo -c -o vquic/libcurlu_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_quiche.c' object='vquic/libcurlu_la-curl_quiche.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c + +vquic/libcurlu_la-vquic.lo: vquic/vquic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-vquic.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-vquic.Tpo -c -o vquic/libcurlu_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-vquic.Tpo vquic/$(DEPDIR)/libcurlu_la-vquic.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/vquic.c' object='vquic/libcurlu_la-vquic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c + +vquic/libcurlu_la-vquic-tls.lo: vquic/vquic-tls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-vquic-tls.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Tpo -c -o vquic/libcurlu_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Tpo vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/vquic-tls.c' object='vquic/libcurlu_la-vquic-tls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c + +vssh/libcurlu_la-libssh.lo: vssh/libssh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vssh/libcurlu_la-libssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-libssh.Tpo -c -o vssh/libcurlu_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-libssh.Tpo vssh/$(DEPDIR)/libcurlu_la-libssh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/libssh.c' object='vssh/libcurlu_la-libssh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c + +vssh/libcurlu_la-libssh2.lo: vssh/libssh2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vssh/libcurlu_la-libssh2.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-libssh2.Tpo -c -o vssh/libcurlu_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-libssh2.Tpo vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/libssh2.c' object='vssh/libcurlu_la-libssh2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c + +vssh/libcurlu_la-wolfssh.lo: vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vssh/libcurlu_la-wolfssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-wolfssh.Tpo -c -o vssh/libcurlu_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-wolfssh.Tpo vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/wolfssh.c' object='vssh/libcurlu_la-wolfssh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf vauth/.libs vauth/_libs + -rm -rf vquic/.libs vquic/_libs + -rm -rf vssh/.libs vssh/_libs + -rm -rf vtls/.libs vtls/_libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +@CURLDEBUG_FALSE@all-local: +all-am: Makefile $(LTLIBRARIES) curl_config.h all-local +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f vauth/$(DEPDIR)/$(am__dirstamp) + -rm -f vauth/$(am__dirstamp) + -rm -f vquic/$(DEPDIR)/$(am__dirstamp) + -rm -f vquic/$(am__dirstamp) + -rm -f vssh/$(DEPDIR)/$(am__dirstamp) + -rm -f vssh/$(am__dirstamp) + -rm -f vtls/$(DEPDIR)/$(am__dirstamp) + -rm -f vtls/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/libcurl_la-altsvc.Plo + -rm -f ./$(DEPDIR)/libcurl_la-amigaos.Plo + -rm -f ./$(DEPDIR)/libcurl_la-asyn-ares.Plo + -rm -f ./$(DEPDIR)/libcurl_la-asyn-thread.Plo + -rm -f ./$(DEPDIR)/libcurl_la-base64.Plo + -rm -f ./$(DEPDIR)/libcurl_la-bufq.Plo + -rm -f ./$(DEPDIR)/libcurl_la-bufref.Plo + -rm -f ./$(DEPDIR)/libcurl_la-c-hyper.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-socket.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cfilters.Plo + -rm -f ./$(DEPDIR)/libcurl_la-conncache.Plo + -rm -f ./$(DEPDIR)/libcurl_la-connect.Plo + -rm -f ./$(DEPDIR)/libcurl_la-content_encoding.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cookie.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_des.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_endian.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_get_line.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_gethostname.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_memrchr.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_multibyte.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_path.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_range.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_rtmp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_sasl.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_sspi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_threads.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo + -rm -f ./$(DEPDIR)/libcurl_la-dict.Plo + -rm -f ./$(DEPDIR)/libcurl_la-doh.Plo + -rm -f ./$(DEPDIR)/libcurl_la-dynbuf.Plo + -rm -f ./$(DEPDIR)/libcurl_la-dynhds.Plo + -rm -f ./$(DEPDIR)/libcurl_la-easy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-easygetopt.Plo + -rm -f ./$(DEPDIR)/libcurl_la-easyoptions.Plo + -rm -f ./$(DEPDIR)/libcurl_la-escape.Plo + -rm -f ./$(DEPDIR)/libcurl_la-file.Plo + -rm -f ./$(DEPDIR)/libcurl_la-fileinfo.Plo + -rm -f ./$(DEPDIR)/libcurl_la-fopen.Plo + -rm -f ./$(DEPDIR)/libcurl_la-formdata.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ftp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ftplistparser.Plo + -rm -f ./$(DEPDIR)/libcurl_la-getenv.Plo + -rm -f ./$(DEPDIR)/libcurl_la-getinfo.Plo + -rm -f ./$(DEPDIR)/libcurl_la-gopher.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hash.Plo + -rm -f ./$(DEPDIR)/libcurl_la-headers.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hmac.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostasyn.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostip.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostip4.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostip6.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostsyn.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hsts.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http1.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http2.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_chunks.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_digest.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_negotiate.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_ntlm.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_proxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-idn.Plo + -rm -f ./$(DEPDIR)/libcurl_la-if2ip.Plo + -rm -f ./$(DEPDIR)/libcurl_la-imap.Plo + -rm -f ./$(DEPDIR)/libcurl_la-inet_ntop.Plo + -rm -f ./$(DEPDIR)/libcurl_la-inet_pton.Plo + -rm -f ./$(DEPDIR)/libcurl_la-krb5.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ldap.Plo + -rm -f ./$(DEPDIR)/libcurl_la-llist.Plo + -rm -f ./$(DEPDIR)/libcurl_la-macos.Plo + -rm -f ./$(DEPDIR)/libcurl_la-md4.Plo + -rm -f ./$(DEPDIR)/libcurl_la-md5.Plo + -rm -f ./$(DEPDIR)/libcurl_la-memdebug.Plo + -rm -f ./$(DEPDIR)/libcurl_la-mime.Plo + -rm -f ./$(DEPDIR)/libcurl_la-mprintf.Plo + -rm -f ./$(DEPDIR)/libcurl_la-mqtt.Plo + -rm -f ./$(DEPDIR)/libcurl_la-multi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-netrc.Plo + -rm -f ./$(DEPDIR)/libcurl_la-nonblock.Plo + -rm -f ./$(DEPDIR)/libcurl_la-noproxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-openldap.Plo + -rm -f ./$(DEPDIR)/libcurl_la-parsedate.Plo + -rm -f ./$(DEPDIR)/libcurl_la-pingpong.Plo + -rm -f ./$(DEPDIR)/libcurl_la-pop3.Plo + -rm -f ./$(DEPDIR)/libcurl_la-progress.Plo + -rm -f ./$(DEPDIR)/libcurl_la-psl.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rename.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rtsp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-select.Plo + -rm -f ./$(DEPDIR)/libcurl_la-sendf.Plo + -rm -f ./$(DEPDIR)/libcurl_la-setopt.Plo + -rm -f ./$(DEPDIR)/libcurl_la-sha256.Plo + -rm -f ./$(DEPDIR)/libcurl_la-share.Plo + -rm -f ./$(DEPDIR)/libcurl_la-slist.Plo + -rm -f ./$(DEPDIR)/libcurl_la-smb.Plo + -rm -f ./$(DEPDIR)/libcurl_la-smtp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socketpair.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socks.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socks_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socks_sspi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-speedcheck.Plo + -rm -f ./$(DEPDIR)/libcurl_la-splay.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strcase.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strdup.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strerror.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strtok.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strtoofft.Plo + -rm -f ./$(DEPDIR)/libcurl_la-system_win32.Plo + -rm -f ./$(DEPDIR)/libcurl_la-telnet.Plo + -rm -f ./$(DEPDIR)/libcurl_la-tftp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-timediff.Plo + -rm -f ./$(DEPDIR)/libcurl_la-timeval.Plo + -rm -f ./$(DEPDIR)/libcurl_la-transfer.Plo + -rm -f ./$(DEPDIR)/libcurl_la-url.Plo + -rm -f ./$(DEPDIR)/libcurl_la-urlapi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-version.Plo + -rm -f ./$(DEPDIR)/libcurl_la-version_win32.Plo + -rm -f ./$(DEPDIR)/libcurl_la-warnless.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ws.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-altsvc.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-amigaos.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-asyn-ares.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-asyn-thread.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-base64.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-bufq.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-bufref.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-c-hyper.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-socket.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cfilters.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-conncache.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-connect.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-content_encoding.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cookie.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_des.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_endian.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_get_line.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_path.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_range.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_sasl.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_sspi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_threads.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-dynbuf.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-dynhds.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-easy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-easygetopt.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-easyoptions.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-escape.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-file.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-fileinfo.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-fopen.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-formdata.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ftp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ftplistparser.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-getenv.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-getinfo.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-gopher.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hash.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-headers.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hmac.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostasyn.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostip.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostip4.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostip6.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostsyn.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hsts.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http1.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http2.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_chunks.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_digest.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_negotiate.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_ntlm.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_proxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-idn.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-if2ip.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-imap.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-inet_ntop.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-inet_pton.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-krb5.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ldap.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-llist.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-macos.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-md4.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-md5.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-memdebug.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-mime.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-mprintf.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-mqtt.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-multi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-netrc.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-nonblock.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-noproxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-openldap.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-parsedate.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-pingpong.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-pop3.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-progress.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-psl.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rename.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rtsp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-select.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-sendf.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-setopt.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-sha256.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-share.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-slist.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-smb.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-smtp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socketpair.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socks.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socks_sspi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-speedcheck.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-splay.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strcase.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strdup.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strerror.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strtok.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strtoofft.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-system_win32.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-telnet.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-tftp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-timediff.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-timeval.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-transfer.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-url.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-urlapi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-version.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-version_win32.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-warnless.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ws.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-cleartext.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-cram.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-digest.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-gsasl.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-ntlm.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-oauth2.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-vauth.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-cram.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-digest.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-keylog.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-openssl.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-rustls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-sectransp.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-vtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-keylog.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-openssl.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-rustls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-vtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/libcurl_la-altsvc.Plo + -rm -f ./$(DEPDIR)/libcurl_la-amigaos.Plo + -rm -f ./$(DEPDIR)/libcurl_la-asyn-ares.Plo + -rm -f ./$(DEPDIR)/libcurl_la-asyn-thread.Plo + -rm -f ./$(DEPDIR)/libcurl_la-base64.Plo + -rm -f ./$(DEPDIR)/libcurl_la-bufq.Plo + -rm -f ./$(DEPDIR)/libcurl_la-bufref.Plo + -rm -f ./$(DEPDIR)/libcurl_la-c-hyper.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-socket.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cfilters.Plo + -rm -f ./$(DEPDIR)/libcurl_la-conncache.Plo + -rm -f ./$(DEPDIR)/libcurl_la-connect.Plo + -rm -f ./$(DEPDIR)/libcurl_la-content_encoding.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cookie.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_des.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_endian.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_get_line.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_gethostname.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_memrchr.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_multibyte.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_path.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_range.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_rtmp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_sasl.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_sspi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_threads.Plo + -rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo + -rm -f ./$(DEPDIR)/libcurl_la-dict.Plo + -rm -f ./$(DEPDIR)/libcurl_la-doh.Plo + -rm -f ./$(DEPDIR)/libcurl_la-dynbuf.Plo + -rm -f ./$(DEPDIR)/libcurl_la-dynhds.Plo + -rm -f ./$(DEPDIR)/libcurl_la-easy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-easygetopt.Plo + -rm -f ./$(DEPDIR)/libcurl_la-easyoptions.Plo + -rm -f ./$(DEPDIR)/libcurl_la-escape.Plo + -rm -f ./$(DEPDIR)/libcurl_la-file.Plo + -rm -f ./$(DEPDIR)/libcurl_la-fileinfo.Plo + -rm -f ./$(DEPDIR)/libcurl_la-fopen.Plo + -rm -f ./$(DEPDIR)/libcurl_la-formdata.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ftp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ftplistparser.Plo + -rm -f ./$(DEPDIR)/libcurl_la-getenv.Plo + -rm -f ./$(DEPDIR)/libcurl_la-getinfo.Plo + -rm -f ./$(DEPDIR)/libcurl_la-gopher.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hash.Plo + -rm -f ./$(DEPDIR)/libcurl_la-headers.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hmac.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostasyn.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostip.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostip4.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostip6.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hostsyn.Plo + -rm -f ./$(DEPDIR)/libcurl_la-hsts.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http1.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http2.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_chunks.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_digest.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_negotiate.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_ntlm.Plo + -rm -f ./$(DEPDIR)/libcurl_la-http_proxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-idn.Plo + -rm -f ./$(DEPDIR)/libcurl_la-if2ip.Plo + -rm -f ./$(DEPDIR)/libcurl_la-imap.Plo + -rm -f ./$(DEPDIR)/libcurl_la-inet_ntop.Plo + -rm -f ./$(DEPDIR)/libcurl_la-inet_pton.Plo + -rm -f ./$(DEPDIR)/libcurl_la-krb5.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ldap.Plo + -rm -f ./$(DEPDIR)/libcurl_la-llist.Plo + -rm -f ./$(DEPDIR)/libcurl_la-macos.Plo + -rm -f ./$(DEPDIR)/libcurl_la-md4.Plo + -rm -f ./$(DEPDIR)/libcurl_la-md5.Plo + -rm -f ./$(DEPDIR)/libcurl_la-memdebug.Plo + -rm -f ./$(DEPDIR)/libcurl_la-mime.Plo + -rm -f ./$(DEPDIR)/libcurl_la-mprintf.Plo + -rm -f ./$(DEPDIR)/libcurl_la-mqtt.Plo + -rm -f ./$(DEPDIR)/libcurl_la-multi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-netrc.Plo + -rm -f ./$(DEPDIR)/libcurl_la-nonblock.Plo + -rm -f ./$(DEPDIR)/libcurl_la-noproxy.Plo + -rm -f ./$(DEPDIR)/libcurl_la-openldap.Plo + -rm -f ./$(DEPDIR)/libcurl_la-parsedate.Plo + -rm -f ./$(DEPDIR)/libcurl_la-pingpong.Plo + -rm -f ./$(DEPDIR)/libcurl_la-pop3.Plo + -rm -f ./$(DEPDIR)/libcurl_la-progress.Plo + -rm -f ./$(DEPDIR)/libcurl_la-psl.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rename.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rtsp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-select.Plo + -rm -f ./$(DEPDIR)/libcurl_la-sendf.Plo + -rm -f ./$(DEPDIR)/libcurl_la-setopt.Plo + -rm -f ./$(DEPDIR)/libcurl_la-sha256.Plo + -rm -f ./$(DEPDIR)/libcurl_la-share.Plo + -rm -f ./$(DEPDIR)/libcurl_la-slist.Plo + -rm -f ./$(DEPDIR)/libcurl_la-smb.Plo + -rm -f ./$(DEPDIR)/libcurl_la-smtp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socketpair.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socks.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socks_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-socks_sspi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-speedcheck.Plo + -rm -f ./$(DEPDIR)/libcurl_la-splay.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strcase.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strdup.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strerror.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strtok.Plo + -rm -f ./$(DEPDIR)/libcurl_la-strtoofft.Plo + -rm -f ./$(DEPDIR)/libcurl_la-system_win32.Plo + -rm -f ./$(DEPDIR)/libcurl_la-telnet.Plo + -rm -f ./$(DEPDIR)/libcurl_la-tftp.Plo + -rm -f ./$(DEPDIR)/libcurl_la-timediff.Plo + -rm -f ./$(DEPDIR)/libcurl_la-timeval.Plo + -rm -f ./$(DEPDIR)/libcurl_la-transfer.Plo + -rm -f ./$(DEPDIR)/libcurl_la-url.Plo + -rm -f ./$(DEPDIR)/libcurl_la-urlapi.Plo + -rm -f ./$(DEPDIR)/libcurl_la-version.Plo + -rm -f ./$(DEPDIR)/libcurl_la-version_win32.Plo + -rm -f ./$(DEPDIR)/libcurl_la-warnless.Plo + -rm -f ./$(DEPDIR)/libcurl_la-ws.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-altsvc.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-amigaos.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-asyn-ares.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-asyn-thread.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-base64.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-bufq.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-bufref.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-c-hyper.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-socket.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cfilters.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-conncache.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-connect.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-content_encoding.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cookie.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_des.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_endian.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_get_line.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_path.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_range.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_sasl.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_sspi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_threads.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-dynbuf.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-dynhds.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-easy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-easygetopt.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-easyoptions.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-escape.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-file.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-fileinfo.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-fopen.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-formdata.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ftp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ftplistparser.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-getenv.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-getinfo.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-gopher.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hash.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-headers.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hmac.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostasyn.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostip.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostip4.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostip6.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hostsyn.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-hsts.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http1.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http2.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_chunks.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_digest.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_negotiate.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_ntlm.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-http_proxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-idn.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-if2ip.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-imap.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-inet_ntop.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-inet_pton.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-krb5.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ldap.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-llist.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-macos.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-md4.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-md5.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-memdebug.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-mime.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-mprintf.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-mqtt.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-multi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-netrc.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-nonblock.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-noproxy.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-openldap.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-parsedate.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-pingpong.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-pop3.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-progress.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-psl.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rename.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rtsp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-select.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-sendf.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-setopt.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-sha256.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-share.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-slist.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-smb.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-smtp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socketpair.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socks.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-socks_sspi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-speedcheck.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-splay.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strcase.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strdup.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strerror.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strtok.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-strtoofft.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-system_win32.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-telnet.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-tftp.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-timediff.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-timeval.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-transfer.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-url.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-urlapi.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-version.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-version_win32.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-warnless.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-ws.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-cleartext.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-cram.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-digest.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-gsasl.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-ntlm.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-oauth2.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurl_la-vauth.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-cram.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-digest.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo + -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-keylog.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-openssl.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-rustls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-sectransp.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-vtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-keylog.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-openssl.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-rustls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-vtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: all install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am all-local am--depfiles check \ + check-am clean clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-libLTLIBRARIES + +.PRECIOUS: Makefile + +# This flag accepts an argument of the form current[:revision[:age]]. So, +# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to +# 1. +# +# Here's the simplified rule guide on how to change -version-info: +# (current version is C:R:A) +# +# 1. if there are only source changes, use C:R+1:A +# 2. if interfaces were added use C+1:0:A+1 +# 3. if interfaces were removed, then use C+1:0:0 +# +# For the full guide on libcurl ABI rules, see docs/libcurl/ABI +@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@$(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h + +checksrc: + $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \ + -W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch] \ + $(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch]) + +# for debug builds, we scan the sources on all regular make invokes +@CURLDEBUG_TRUE@all-local: checksrc + +tidy: + $(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H + +optiontable: + perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c + +@HAVE_WINDRES_TRUE@.rc.lo: +@HAVE_WINDRES_TRUE@ $(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/Makefile.inc b/lib/Makefile.inc new file mode 100644 index 0000000..627148a --- /dev/null +++ b/lib/Makefile.inc @@ -0,0 +1,374 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +LIB_VAUTH_CFILES = \ + vauth/cleartext.c \ + vauth/cram.c \ + vauth/digest.c \ + vauth/digest_sspi.c \ + vauth/gsasl.c \ + vauth/krb5_gssapi.c \ + vauth/krb5_sspi.c \ + vauth/ntlm.c \ + vauth/ntlm_sspi.c \ + vauth/oauth2.c \ + vauth/spnego_gssapi.c \ + vauth/spnego_sspi.c \ + vauth/vauth.c + +LIB_VAUTH_HFILES = \ + vauth/digest.h \ + vauth/ntlm.h \ + vauth/vauth.h + +LIB_VTLS_CFILES = \ + vtls/bearssl.c \ + vtls/gtls.c \ + vtls/hostcheck.c \ + vtls/keylog.c \ + vtls/mbedtls.c \ + vtls/mbedtls_threadlock.c \ + vtls/openssl.c \ + vtls/rustls.c \ + vtls/schannel.c \ + vtls/schannel_verify.c \ + vtls/sectransp.c \ + vtls/vtls.c \ + vtls/wolfssl.c \ + vtls/x509asn1.c + +LIB_VTLS_HFILES = \ + vtls/bearssl.h \ + vtls/gtls.h \ + vtls/hostcheck.h \ + vtls/keylog.h \ + vtls/mbedtls.h \ + vtls/mbedtls_threadlock.h \ + vtls/openssl.h \ + vtls/rustls.h \ + vtls/schannel.h \ + vtls/schannel_int.h \ + vtls/sectransp.h \ + vtls/vtls.h \ + vtls/vtls_int.h \ + vtls/wolfssl.h \ + vtls/x509asn1.h + +LIB_VQUIC_CFILES = \ + vquic/curl_msh3.c \ + vquic/curl_ngtcp2.c \ + vquic/curl_osslq.c \ + vquic/curl_quiche.c \ + vquic/vquic.c \ + vquic/vquic-tls.c + +LIB_VQUIC_HFILES = \ + vquic/curl_msh3.h \ + vquic/curl_ngtcp2.h \ + vquic/curl_osslq.h \ + vquic/curl_quiche.h \ + vquic/vquic.h \ + vquic/vquic_int.h \ + vquic/vquic-tls.h + +LIB_VSSH_CFILES = \ + vssh/libssh.c \ + vssh/libssh2.c \ + vssh/wolfssh.c + +LIB_VSSH_HFILES = \ + vssh/ssh.h + +LIB_CFILES = \ + altsvc.c \ + amigaos.c \ + asyn-ares.c \ + asyn-thread.c \ + base64.c \ + bufq.c \ + bufref.c \ + c-hyper.c \ + cf-h1-proxy.c \ + cf-h2-proxy.c \ + cf-haproxy.c \ + cf-https-connect.c \ + cf-socket.c \ + cfilters.c \ + conncache.c \ + connect.c \ + content_encoding.c \ + cookie.c \ + curl_addrinfo.c \ + curl_des.c \ + curl_endian.c \ + curl_fnmatch.c \ + curl_get_line.c \ + curl_gethostname.c \ + curl_gssapi.c \ + curl_memrchr.c \ + curl_multibyte.c \ + curl_ntlm_core.c \ + curl_ntlm_wb.c \ + curl_path.c \ + curl_range.c \ + curl_rtmp.c \ + curl_sasl.c \ + curl_sspi.c \ + curl_threads.c \ + curl_trc.c \ + dict.c \ + doh.c \ + dynbuf.c \ + dynhds.c \ + easy.c \ + easygetopt.c \ + easyoptions.c \ + escape.c \ + file.c \ + fileinfo.c \ + fopen.c \ + formdata.c \ + ftp.c \ + ftplistparser.c \ + getenv.c \ + getinfo.c \ + gopher.c \ + hash.c \ + headers.c \ + hmac.c \ + hostasyn.c \ + hostip.c \ + hostip4.c \ + hostip6.c \ + hostsyn.c \ + hsts.c \ + http.c \ + http1.c \ + http2.c \ + http_aws_sigv4.c \ + http_chunks.c \ + http_digest.c \ + http_negotiate.c \ + http_ntlm.c \ + http_proxy.c \ + idn.c \ + if2ip.c \ + imap.c \ + inet_ntop.c \ + inet_pton.c \ + krb5.c \ + ldap.c \ + llist.c \ + macos.c \ + md4.c \ + md5.c \ + memdebug.c \ + mime.c \ + mprintf.c \ + mqtt.c \ + multi.c \ + netrc.c \ + nonblock.c \ + noproxy.c \ + openldap.c \ + parsedate.c \ + pingpong.c \ + pop3.c \ + progress.c \ + psl.c \ + rand.c \ + rename.c \ + rtsp.c \ + select.c \ + sendf.c \ + setopt.c \ + sha256.c \ + share.c \ + slist.c \ + smb.c \ + smtp.c \ + socketpair.c \ + socks.c \ + socks_gssapi.c \ + socks_sspi.c \ + speedcheck.c \ + splay.c \ + strcase.c \ + strdup.c \ + strerror.c \ + strtok.c \ + strtoofft.c \ + system_win32.c \ + telnet.c \ + tftp.c \ + timediff.c \ + timeval.c \ + transfer.c \ + url.c \ + urlapi.c \ + version.c \ + version_win32.c \ + warnless.c \ + ws.c + +LIB_HFILES = \ + altsvc.h \ + amigaos.h \ + arpa_telnet.h \ + asyn.h \ + bufq.h \ + bufref.h \ + c-hyper.h \ + cf-h1-proxy.h \ + cf-h2-proxy.h \ + cf-haproxy.h \ + cf-https-connect.h \ + cf-socket.h \ + cfilters.h \ + conncache.h \ + connect.h \ + content_encoding.h \ + cookie.h \ + curl_addrinfo.h \ + curl_base64.h \ + curl_ctype.h \ + curl_des.h \ + curl_endian.h \ + curl_fnmatch.h \ + curl_get_line.h \ + curl_gethostname.h \ + curl_gssapi.h \ + curl_hmac.h \ + curl_krb5.h \ + curl_ldap.h \ + curl_md4.h \ + curl_md5.h \ + curl_memory.h \ + curl_memrchr.h \ + curl_multibyte.h \ + curl_ntlm_core.h \ + curl_ntlm_wb.h \ + curl_path.h \ + curl_printf.h \ + curl_range.h \ + curl_rtmp.h \ + curl_sasl.h \ + curl_setup.h \ + curl_setup_once.h \ + curl_sha256.h \ + curl_sspi.h \ + curl_threads.h \ + curl_trc.h \ + curlx.h \ + dict.h \ + doh.h \ + dynbuf.h \ + dynhds.h \ + easy_lock.h \ + easyif.h \ + easyoptions.h \ + escape.h \ + file.h \ + fileinfo.h \ + fopen.h \ + formdata.h \ + ftp.h \ + ftplistparser.h \ + functypes.h \ + getinfo.h \ + gopher.h \ + hash.h \ + headers.h \ + hostip.h \ + hsts.h \ + http.h \ + http1.h \ + http2.h \ + http_aws_sigv4.h \ + http_chunks.h \ + http_digest.h \ + http_negotiate.h \ + http_ntlm.h \ + http_proxy.h \ + idn.h \ + if2ip.h \ + imap.h \ + inet_ntop.h \ + inet_pton.h \ + llist.h \ + macos.h \ + memdebug.h \ + mime.h \ + mqtt.h \ + multihandle.h \ + multiif.h \ + netrc.h \ + nonblock.h \ + noproxy.h \ + parsedate.h \ + pingpong.h \ + pop3.h \ + progress.h \ + psl.h \ + rand.h \ + rename.h \ + rtsp.h \ + select.h \ + sendf.h \ + setopt.h \ + setup-vms.h \ + share.h \ + sigpipe.h \ + slist.h \ + smb.h \ + smtp.h \ + sockaddr.h \ + socketpair.h \ + socks.h \ + speedcheck.h \ + splay.h \ + strcase.h \ + strdup.h \ + strerror.h \ + strtok.h \ + strtoofft.h \ + system_win32.h \ + telnet.h \ + tftp.h \ + timediff.h \ + timeval.h \ + transfer.h \ + url.h \ + urlapi-int.h \ + urldata.h \ + version_win32.h \ + warnless.h \ + ws.h + +LIB_RCFILES = libcurl.rc + +CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \ + $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) +HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \ + $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) diff --git a/lib/Makefile.mk b/lib/Makefile.mk new file mode 100644 index 0000000..95f281b --- /dev/null +++ b/lib/Makefile.mk @@ -0,0 +1,334 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +# Makefile to build curl parts with GCC-like toolchains and optional features. +# +# Usage: make -f Makefile.mk CFG=-feat1[-feat2][-feat3][...] +# Example: make -f Makefile.mk CFG=-zlib-ssl-libssh2-ipv6 +# +# Look for ' ?=' to find all accepted customization variables. + +# This script is reused by 'src' and 'docs/examples' Makefile.mk scripts. + +ifndef PROOT + PROOT := .. + LOCAL := 1 +endif + +### Common + +CFLAGS ?= +CPPFLAGS ?= +LDFLAGS ?= +LIBS ?= + +CROSSPREFIX ?= + +ifeq ($(CC),cc) + CC := gcc +endif +CC := $(CROSSPREFIX)$(CC) +AR := $(CROSSPREFIX)$(AR) + +TRIPLET ?= $(shell $(CC) -dumpmachine) + +BIN_EXT := + +ifneq ($(findstring msdos,$(TRIPLET)),) + # Cross-tools: https://github.com/andrewwutw/build-djgpp + MSDOS := 1 + BIN_EXT := .exe +else ifneq ($(findstring amigaos,$(TRIPLET)),) + # Cross-tools: https://github.com/bebbo/amiga-gcc + AMIGA := 1 +endif + +CPPFLAGS += -I. -I$(PROOT)/include + +### Deprecated settings. For compatibility. + +ifdef WATT_ROOT + WATT_PATH := $(realpath $(WATT_ROOT)) +endif + +### Optional features + +ifneq ($(findstring -debug,$(CFG)),) + CFLAGS += -g + CPPFLAGS += -DDEBUGBUILD +else + CPPFLAGS += -DNDEBUG +endif +ifneq ($(findstring -trackmem,$(CFG)),) + CPPFLAGS += -DCURLDEBUG +endif +ifneq ($(findstring -map,$(CFG)),) + MAP := 1 +endif + +# CPPFLAGS below are only necessary when building libcurl via 'lib' (see +# comments below about exceptions). Always include them anyway to match +# behavior of other build systems. + +ifneq ($(findstring -sync,$(CFG)),) + CPPFLAGS += -DUSE_SYNC_DNS +else ifneq ($(findstring -ares,$(CFG)),) + LIBCARES_PATH ?= $(PROOT)/../c-ares + CPPFLAGS += -DUSE_ARES + CPPFLAGS += -I"$(LIBCARES_PATH)/include" + LDFLAGS += -L"$(LIBCARES_PATH)/lib" + LIBS += -lcares +endif + +ifneq ($(findstring -rtmp,$(CFG)),) + LIBRTMP_PATH ?= $(PROOT)/../librtmp + CPPFLAGS += -DUSE_LIBRTMP + CPPFLAGS += -I"$(LIBRTMP_PATH)" + LDFLAGS += -L"$(LIBRTMP_PATH)/librtmp" + LIBS += -lrtmp + ZLIB := 1 +endif + +ifneq ($(findstring -ssh2,$(CFG)),) + LIBSSH2_PATH ?= $(PROOT)/../libssh2 + CPPFLAGS += -DUSE_LIBSSH2 + CPPFLAGS += -I"$(LIBSSH2_PATH)/include" + LDFLAGS += -L"$(LIBSSH2_PATH)/lib" + LIBS += -lssh2 +else ifneq ($(findstring -libssh,$(CFG)),) + LIBSSH_PATH ?= $(PROOT)/../libssh + CPPFLAGS += -DUSE_LIBSSH + CPPFLAGS += -I"$(LIBSSH_PATH)/include" + LDFLAGS += -L"$(LIBSSH_PATH)/lib" + LIBS += -lssh +else ifneq ($(findstring -wolfssh,$(CFG)),) + WOLFSSH_PATH ?= $(PROOT)/../wolfssh + CPPFLAGS += -DUSE_WOLFSSH + CPPFLAGS += -I"$(WOLFSSH_PATH)/include" + LDFLAGS += -L"$(WOLFSSH_PATH)/lib" + LIBS += -lwolfssh +endif + +ifneq ($(findstring -ssl,$(CFG)),) + OPENSSL_PATH ?= $(PROOT)/../openssl + CPPFLAGS += -DUSE_OPENSSL + CPPFLAGS += -DCURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG + OPENSSL_INCLUDE ?= $(OPENSSL_PATH)/include + OPENSSL_LIBPATH ?= $(OPENSSL_PATH)/lib + CPPFLAGS += -I"$(OPENSSL_INCLUDE)" + LDFLAGS += -L"$(OPENSSL_LIBPATH)" + OPENSSL_LIBS ?= -lssl -lcrypto + LIBS += $(OPENSSL_LIBS) + + ifneq ($(findstring -srp,$(CFG)),) + ifneq ($(wildcard $(OPENSSL_INCLUDE)/openssl/srp.h),) + # OpenSSL 1.0.1 and later. + CPPFLAGS += -DHAVE_OPENSSL_SRP -DUSE_TLS_SRP + endif + endif + SSLLIBS += 1 +endif +ifneq ($(findstring -wolfssl,$(CFG)),) + WOLFSSL_PATH ?= $(PROOT)/../wolfssl + CPPFLAGS += -DUSE_WOLFSSL + CPPFLAGS += -DSIZEOF_LONG_LONG=8 + CPPFLAGS += -I"$(WOLFSSL_PATH)/include" + LDFLAGS += -L"$(WOLFSSL_PATH)/lib" + LIBS += -lwolfssl + SSLLIBS += 1 +endif +ifneq ($(findstring -mbedtls,$(CFG)),) + MBEDTLS_PATH ?= $(PROOT)/../mbedtls + CPPFLAGS += -DUSE_MBEDTLS + CPPFLAGS += -I"$(MBEDTLS_PATH)/include" + LDFLAGS += -L"$(MBEDTLS_PATH)/lib" + LIBS += -lmbedtls -lmbedx509 -lmbedcrypto + SSLLIBS += 1 +endif + +ifneq ($(findstring -nghttp2,$(CFG)),) + NGHTTP2_PATH ?= $(PROOT)/../nghttp2 + CPPFLAGS += -DUSE_NGHTTP2 + CPPFLAGS += -I"$(NGHTTP2_PATH)/include" + LDFLAGS += -L"$(NGHTTP2_PATH)/lib" + LIBS += -lnghttp2 +endif + +ifeq ($(findstring -nghttp3,$(CFG))$(findstring -ngtcp2,$(CFG)),-nghttp3-ngtcp2) + NGHTTP3_PATH ?= $(PROOT)/../nghttp3 + CPPFLAGS += -DUSE_NGHTTP3 + CPPFLAGS += -I"$(NGHTTP3_PATH)/include" + LDFLAGS += -L"$(NGHTTP3_PATH)/lib" + LIBS += -lnghttp3 + + NGTCP2_PATH ?= $(PROOT)/../ngtcp2 + CPPFLAGS += -DUSE_NGTCP2 + CPPFLAGS += -I"$(NGTCP2_PATH)/include" + LDFLAGS += -L"$(NGTCP2_PATH)/lib" + + NGTCP2_LIBS ?= + ifeq ($(NGTCP2_LIBS),) + ifneq ($(findstring -ssl,$(CFG)),) + ifneq ($(wildcard $(OPENSSL_INCLUDE)/openssl/aead.h),) + NGTCP2_LIBS := -lngtcp2_crypto_boringssl + else # including libressl + NGTCP2_LIBS := -lngtcp2_crypto_quictls + endif + else ifneq ($(findstring -wolfssl,$(CFG)),) + NGTCP2_LIBS := -lngtcp2_crypto_wolfssl + endif + endif + + LIBS += -lngtcp2 $(NGTCP2_LIBS) +endif + +ifneq ($(findstring -zlib,$(CFG))$(ZLIB),) + ZLIB_PATH ?= $(PROOT)/../zlib + # These CPPFLAGS are also required when compiling the curl tool via 'src'. + CPPFLAGS += -DHAVE_LIBZ + CPPFLAGS += -I"$(ZLIB_PATH)/include" + LDFLAGS += -L"$(ZLIB_PATH)/lib" + ZLIB_LIBS ?= -lz + LIBS += $(ZLIB_LIBS) + ZLIB := 1 +endif +ifneq ($(findstring -zstd,$(CFG)),) + ZSTD_PATH ?= $(PROOT)/../zstd + CPPFLAGS += -DHAVE_ZSTD + CPPFLAGS += -I"$(ZSTD_PATH)/include" + LDFLAGS += -L"$(ZSTD_PATH)/lib" + ZSTD_LIBS ?= -lzstd + LIBS += $(ZSTD_LIBS) +endif +ifneq ($(findstring -brotli,$(CFG)),) + BROTLI_PATH ?= $(PROOT)/../brotli + CPPFLAGS += -DHAVE_BROTLI + CPPFLAGS += -I"$(BROTLI_PATH)/include" + LDFLAGS += -L"$(BROTLI_PATH)/lib" + BROTLI_LIBS ?= -lbrotlidec -lbrotlicommon + LIBS += $(BROTLI_LIBS) +endif +ifneq ($(findstring -gsasl,$(CFG)),) + LIBGSASL_PATH ?= $(PROOT)/../gsasl + CPPFLAGS += -DUSE_GSASL + CPPFLAGS += -I"$(LIBGSASL_PATH)/include" + LDFLAGS += -L"$(LIBGSASL_PATH)/lib" + LIBS += -lgsasl +endif + +ifneq ($(findstring -idn2,$(CFG)),) + LIBIDN2_PATH ?= $(PROOT)/../libidn2 + CPPFLAGS += -DUSE_LIBIDN2 + CPPFLAGS += -I"$(LIBIDN2_PATH)/include" + LDFLAGS += -L"$(LIBIDN2_PATH)/lib" + LIBS += -lidn2 + +ifneq ($(findstring -psl,$(CFG)),) + LIBPSL_PATH ?= $(PROOT)/../libpsl + CPPFLAGS += -DUSE_LIBPSL + CPPFLAGS += -I"$(LIBPSL_PATH)/include" + LDFLAGS += -L"$(LIBPSL_PATH)/lib" + LIBS += -lpsl +endif +endif + +ifneq ($(findstring -ipv6,$(CFG)),) + CPPFLAGS += -DENABLE_IPV6 +endif + +ifneq ($(findstring -watt,$(CFG))$(MSDOS),) + WATT_PATH ?= $(PROOT)/../watt + CPPFLAGS += -I"$(WATT_PATH)/inc" + LDFLAGS += -L"$(WATT_PATH)/lib" + LIBS += -lwatt +endif + +ifneq ($(findstring 11,$(subst $(subst ,, ),,$(SSLLIBS))),) + CPPFLAGS += -DCURL_WITH_MULTI_SSL +endif + +### Common rules + +OBJ_DIR := $(TRIPLET) + +ifneq ($(findstring /sh,$(SHELL)),) +DEL = rm -f $1 +COPY = -cp -afv $1 $2 +MKDIR = mkdir -p $1 +RMDIR = rm -fr $1 +WHICH = $(SHELL) -c "command -v $1" +else +DEL = -del 2>NUL /q /f $(subst /,\,$1) +COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2) +MKDIR = -md 2>NUL $(subst /,\,$1) +RMDIR = -rd 2>NUL /q /s $(subst /,\,$1) +WHICH = where $1 +endif + +all: $(TARGETS) + +$(OBJ_DIR): + -$(call MKDIR, $(OBJ_DIR)) + +$(OBJ_DIR)/%.o: %.c + $(CC) -W -Wall $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +clean: + @$(call DEL, $(TOCLEAN)) + @$(RMDIR) $(OBJ_DIR) + +distclean vclean: clean + @$(call DEL, $(TARGETS) $(TOVCLEAN)) + +### Local + +ifdef LOCAL + +CPPFLAGS += -DBUILDING_LIBCURL + +### Sources and targets + +# Provides CSOURCES, HHEADERS +include Makefile.inc + +vpath %.c vauth vquic vssh vtls + +libcurl_a_LIBRARY := libcurl.a + +TARGETS := $(libcurl_a_LIBRARY) + +libcurl_a_OBJECTS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(notdir $(strip $(CSOURCES)))) +libcurl_a_DEPENDENCIES := $(strip $(CSOURCES) $(HHEADERS)) + +TOCLEAN := +TOVCLEAN := + +### Rules + +$(libcurl_a_LIBRARY): $(libcurl_a_OBJECTS) $(libcurl_a_DEPENDENCIES) + @$(call DEL, $@) + $(AR) rcs $@ $(libcurl_a_OBJECTS) + +all: $(OBJ_DIR) $(TARGETS) +endif diff --git a/lib/Makefile.soname b/lib/Makefile.soname new file mode 100644 index 0000000..02e003a --- /dev/null +++ b/lib/Makefile.soname @@ -0,0 +1,42 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +VERSIONCHANGE=12 +VERSIONADD=0 +VERSIONDEL=8 + +# libtool version: +VERSIONINFO=-version-info $(VERSIONCHANGE):$(VERSIONADD):$(VERSIONDEL) +# This flag accepts an argument of the form current[:revision[:age]]. So, +# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to +# 1. +# +# Here's the simplified rule guide on how to change -version-info: +# (current version is C:R:A) +# +# 1. if there are only source changes, use C:R+1:A +# 2. if interfaces were added use C+1:0:A+1 +# 3. if interfaces were removed, then use C+1:0:0 +# +# For the full guide on libcurl ABI rules, see docs/libcurl/ABI diff --git a/lib/altsvc.c b/lib/altsvc.c new file mode 100644 index 0000000..e9f62bf --- /dev/null +++ b/lib/altsvc.c @@ -0,0 +1,716 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * The Alt-Svc: header is defined in RFC 7838: + * https://datatracker.ietf.org/doc/html/rfc7838 + */ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC) +#include +#include "urldata.h" +#include "altsvc.h" +#include "curl_get_line.h" +#include "strcase.h" +#include "parsedate.h" +#include "sendf.h" +#include "warnless.h" +#include "fopen.h" +#include "rename.h" +#include "strdup.h" +#include "inet_pton.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define MAX_ALTSVC_LINE 4095 +#define MAX_ALTSVC_DATELENSTR "64" +#define MAX_ALTSVC_DATELEN 64 +#define MAX_ALTSVC_HOSTLENSTR "512" +#define MAX_ALTSVC_HOSTLEN 512 +#define MAX_ALTSVC_ALPNLENSTR "10" +#define MAX_ALTSVC_ALPNLEN 10 + +#define H3VERSION "h3" + +static enum alpnid alpn2alpnid(char *name) +{ + if(strcasecompare(name, "h1")) + return ALPN_h1; + if(strcasecompare(name, "h2")) + return ALPN_h2; + if(strcasecompare(name, H3VERSION)) + return ALPN_h3; + return ALPN_none; /* unknown, probably rubbish input */ +} + +/* Given the ALPN ID, return the name */ +const char *Curl_alpnid2str(enum alpnid id) +{ + switch(id) { + case ALPN_h1: + return "h1"; + case ALPN_h2: + return "h2"; + case ALPN_h3: + return H3VERSION; + default: + return ""; /* bad */ + } +} + + +static void altsvc_free(struct altsvc *as) +{ + free(as->src.host); + free(as->dst.host); + free(as); +} + +static struct altsvc *altsvc_createid(const char *srchost, + const char *dsthost, + enum alpnid srcalpnid, + enum alpnid dstalpnid, + unsigned int srcport, + unsigned int dstport) +{ + struct altsvc *as = calloc(1, sizeof(struct altsvc)); + size_t hlen; + size_t dlen; + if(!as) + return NULL; + hlen = strlen(srchost); + dlen = strlen(dsthost); + DEBUGASSERT(hlen); + DEBUGASSERT(dlen); + if(!hlen || !dlen) { + /* bad input */ + free(as); + return NULL; + } + if((hlen > 2) && srchost[0] == '[') { + /* IPv6 address, strip off brackets */ + srchost++; + hlen -= 2; + } + else if(srchost[hlen - 1] == '.') + /* strip off trailing dot */ + hlen--; + if((dlen > 2) && dsthost[0] == '[') { + /* IPv6 address, strip off brackets */ + dsthost++; + dlen -= 2; + } + + as->src.host = Curl_memdup0(srchost, hlen); + if(!as->src.host) + goto error; + + as->dst.host = Curl_memdup0(dsthost, dlen); + if(!as->dst.host) + goto error; + + as->src.alpnid = srcalpnid; + as->dst.alpnid = dstalpnid; + as->src.port = curlx_ultous(srcport); + as->dst.port = curlx_ultous(dstport); + + return as; +error: + altsvc_free(as); + return NULL; +} + +static struct altsvc *altsvc_create(char *srchost, + char *dsthost, + char *srcalpn, + char *dstalpn, + unsigned int srcport, + unsigned int dstport) +{ + enum alpnid dstalpnid = alpn2alpnid(dstalpn); + enum alpnid srcalpnid = alpn2alpnid(srcalpn); + if(!srcalpnid || !dstalpnid) + return NULL; + return altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid, + srcport, dstport); +} + +/* only returns SERIOUS errors */ +static CURLcode altsvc_add(struct altsvcinfo *asi, char *line) +{ + /* Example line: + h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1 + */ + char srchost[MAX_ALTSVC_HOSTLEN + 1]; + char dsthost[MAX_ALTSVC_HOSTLEN + 1]; + char srcalpn[MAX_ALTSVC_ALPNLEN + 1]; + char dstalpn[MAX_ALTSVC_ALPNLEN + 1]; + char date[MAX_ALTSVC_DATELEN + 1]; + unsigned int srcport; + unsigned int dstport; + unsigned int prio; + unsigned int persist; + int rc; + + rc = sscanf(line, + "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u " + "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u " + "\"%" MAX_ALTSVC_DATELENSTR "[^\"]\" %u %u", + srcalpn, srchost, &srcport, + dstalpn, dsthost, &dstport, + date, &persist, &prio); + if(9 == rc) { + struct altsvc *as; + time_t expires = Curl_getdate_capped(date); + as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport); + if(as) { + as->expires = expires; + as->prio = prio; + as->persist = persist ? 1 : 0; + Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); + } + } + + return CURLE_OK; +} + +/* + * Load alt-svc entries from the given file. The text based line-oriented file + * format is documented here: https://curl.se/docs/alt-svc.html + * + * This function only returns error on major problems that prevent alt-svc + * handling to work completely. It will ignore individual syntactical errors + * etc. + */ +static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) +{ + CURLcode result = CURLE_OK; + char *line = NULL; + FILE *fp; + + /* we need a private copy of the file name so that the altsvc cache file + name survives an easy handle reset */ + free(asi->filename); + asi->filename = strdup(file); + if(!asi->filename) + return CURLE_OUT_OF_MEMORY; + + fp = fopen(file, FOPEN_READTEXT); + if(fp) { + line = malloc(MAX_ALTSVC_LINE); + if(!line) + goto fail; + while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) { + char *lineptr = line; + while(*lineptr && ISBLANK(*lineptr)) + lineptr++; + if(*lineptr == '#') + /* skip commented lines */ + continue; + + altsvc_add(asi, lineptr); + } + free(line); /* free the line buffer */ + fclose(fp); + } + return result; + +fail: + Curl_safefree(asi->filename); + free(line); + fclose(fp); + return CURLE_OUT_OF_MEMORY; +} + +/* + * Write this single altsvc entry to a single output line + */ + +static CURLcode altsvc_out(struct altsvc *as, FILE *fp) +{ + struct tm stamp; + const char *dst6_pre = ""; + const char *dst6_post = ""; + const char *src6_pre = ""; + const char *src6_post = ""; + CURLcode result = Curl_gmtime(as->expires, &stamp); + if(result) + return result; +#ifdef ENABLE_IPV6 + else { + char ipv6_unused[16]; + if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) { + dst6_pre = "["; + dst6_post = "]"; + } + if(1 == Curl_inet_pton(AF_INET6, as->src.host, ipv6_unused)) { + src6_pre = "["; + src6_post = "]"; + } + } +#endif + fprintf(fp, + "%s %s%s%s %u " + "%s %s%s%s %u " + "\"%d%02d%02d " + "%02d:%02d:%02d\" " + "%u %d\n", + Curl_alpnid2str(as->src.alpnid), + src6_pre, as->src.host, src6_post, + as->src.port, + + Curl_alpnid2str(as->dst.alpnid), + dst6_pre, as->dst.host, dst6_post, + as->dst.port, + + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec, + as->persist, as->prio); + return CURLE_OK; +} + +/* ---- library-wide functions below ---- */ + +/* + * Curl_altsvc_init() creates a new altsvc cache. + * It returns the new instance or NULL if something goes wrong. + */ +struct altsvcinfo *Curl_altsvc_init(void) +{ + struct altsvcinfo *asi = calloc(1, sizeof(struct altsvcinfo)); + if(!asi) + return NULL; + Curl_llist_init(&asi->list, NULL); + + /* set default behavior */ + asi->flags = CURLALTSVC_H1 +#ifdef USE_HTTP2 + | CURLALTSVC_H2 +#endif +#ifdef ENABLE_QUIC + | CURLALTSVC_H3 +#endif + ; + return asi; +} + +/* + * Curl_altsvc_load() loads alt-svc from file. + */ +CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file) +{ + CURLcode result; + DEBUGASSERT(asi); + result = altsvc_load(asi, file); + return result; +} + +/* + * Curl_altsvc_ctrl() passes on the external bitmask. + */ +CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl) +{ + DEBUGASSERT(asi); + asi->flags = ctrl; + return CURLE_OK; +} + +/* + * Curl_altsvc_cleanup() frees an altsvc cache instance and all associated + * resources. + */ +void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp) +{ + struct Curl_llist_element *e; + struct Curl_llist_element *n; + if(*altsvcp) { + struct altsvcinfo *altsvc = *altsvcp; + for(e = altsvc->list.head; e; e = n) { + struct altsvc *as = e->ptr; + n = e->next; + altsvc_free(as); + } + free(altsvc->filename); + free(altsvc); + *altsvcp = NULL; /* clear the pointer */ + } +} + +/* + * Curl_altsvc_save() writes the altsvc cache to a file. + */ +CURLcode Curl_altsvc_save(struct Curl_easy *data, + struct altsvcinfo *altsvc, const char *file) +{ + struct Curl_llist_element *e; + struct Curl_llist_element *n; + CURLcode result = CURLE_OK; + FILE *out; + char *tempstore = NULL; + + if(!altsvc) + /* no cache activated */ + return CURLE_OK; + + /* if not new name is given, use the one we stored from the load */ + if(!file && altsvc->filename) + file = altsvc->filename; + + if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0]) + /* marked as read-only, no file or zero length file name */ + return CURLE_OK; + + result = Curl_fopen(data, file, &out, &tempstore); + if(!result) { + fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n", + out); + for(e = altsvc->list.head; e; e = n) { + struct altsvc *as = e->ptr; + n = e->next; + result = altsvc_out(as, out); + if(result) + break; + } + fclose(out); + if(!result && tempstore && Curl_rename(tempstore, file)) + result = CURLE_WRITE_ERROR; + + if(result && tempstore) + unlink(tempstore); + } + free(tempstore); + return result; +} + +static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen) +{ + size_t len; + const char *protop; + const char *p = *ptr; + while(*p && ISBLANK(*p)) + p++; + protop = p; + while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '=')) + p++; + len = p - protop; + *ptr = p; + + if(!len || (len >= buflen)) + return CURLE_BAD_FUNCTION_ARGUMENT; + memcpy(alpnbuf, protop, len); + alpnbuf[len] = 0; + return CURLE_OK; +} + +/* hostcompare() returns true if 'host' matches 'check'. The first host + * argument may have a trailing dot present that will be ignored. + */ +static bool hostcompare(const char *host, const char *check) +{ + size_t hlen = strlen(host); + size_t clen = strlen(check); + + if(hlen && (host[hlen - 1] == '.')) + hlen--; + if(hlen != clen) + /* they can't match if they have different lengths */ + return FALSE; + return strncasecompare(host, check, hlen); +} + +/* altsvc_flush() removes all alternatives for this source origin from the + list */ +static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid, + const char *srchost, unsigned short srcport) +{ + struct Curl_llist_element *e; + struct Curl_llist_element *n; + for(e = asi->list.head; e; e = n) { + struct altsvc *as = e->ptr; + n = e->next; + if((srcalpnid == as->src.alpnid) && + (srcport == as->src.port) && + hostcompare(srchost, as->src.host)) { + Curl_llist_remove(&asi->list, e, NULL); + altsvc_free(as); + } + } +} + +#ifdef DEBUGBUILD +/* to play well with debug builds, we can *set* a fixed time this will + return */ +static time_t altsvc_debugtime(void *unused) +{ + char *timestr = getenv("CURL_TIME"); + (void)unused; + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + return (time_t)val; + } + return time(NULL); +} +#undef time +#define time(x) altsvc_debugtime(x) +#endif + +#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r') + +/* + * Curl_altsvc_parse() takes an incoming alt-svc response header and stores + * the data correctly in the cache. + * + * 'value' points to the header *value*. That's contents to the right of the + * header name. + * + * Currently this function rejects invalid data without returning an error. + * Invalid host name, port number will result in the specific alternative + * being rejected. Unknown protocols are skipped. + */ +CURLcode Curl_altsvc_parse(struct Curl_easy *data, + struct altsvcinfo *asi, const char *value, + enum alpnid srcalpnid, const char *srchost, + unsigned short srcport) +{ + const char *p = value; + size_t len; + char namebuf[MAX_ALTSVC_HOSTLEN] = ""; + char alpnbuf[MAX_ALTSVC_ALPNLEN] = ""; + struct altsvc *as; + unsigned short dstport = srcport; /* the same by default */ + CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); + size_t entries = 0; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; +#endif + if(result) { + infof(data, "Excessive alt-svc header, ignoring."); + return CURLE_OK; + } + + DEBUGASSERT(asi); + + /* "clear" is a magic keyword */ + if(strcasecompare(alpnbuf, "clear")) { + /* Flush cached alternatives for this source origin */ + altsvc_flush(asi, srcalpnid, srchost, srcport); + return CURLE_OK; + } + + do { + if(*p == '=') { + /* [protocol]="[host][:port]" */ + enum alpnid dstalpnid = alpn2alpnid(alpnbuf); /* the same by default */ + p++; + if(*p == '\"') { + const char *dsthost = ""; + const char *value_ptr; + char option[32]; + unsigned long num; + char *end_ptr; + bool quoted = FALSE; + time_t maxage = 24 * 3600; /* default is 24 hours */ + bool persist = FALSE; + bool valid = TRUE; + p++; + if(*p != ':') { + /* host name starts here */ + const char *hostp = p; + if(*p == '[') { + /* pass all valid IPv6 letters - does not handle zone id */ + len = strspn(++p, "0123456789abcdefABCDEF:."); + if(p[len] != ']') + /* invalid host syntax, bail out */ + break; + /* we store the IPv6 numerical address *with* brackets */ + len += 2; + p = &p[len-1]; + } + else { + while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-'))) + p++; + len = p - hostp; + } + if(!len || (len >= MAX_ALTSVC_HOSTLEN)) { + infof(data, "Excessive alt-svc host name, ignoring."); + valid = FALSE; + } + else { + memcpy(namebuf, hostp, len); + namebuf[len] = 0; + dsthost = namebuf; + } + } + else { + /* no destination name, use source host */ + dsthost = srchost; + } + if(*p == ':') { + unsigned long port = 0; + p++; + if(ISDIGIT(*p)) + /* a port number */ + port = strtoul(p, &end_ptr, 10); + else + end_ptr = (char *)p; /* not left uninitialized */ + if(!port || port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') { + infof(data, "Unknown alt-svc port number, ignoring."); + valid = FALSE; + } + else { + dstport = curlx_ultous(port); + p = end_ptr; + } + } + if(*p++ != '\"') + break; + /* Handle the optional 'ma' and 'persist' flags. Unknown flags + are skipped. */ + for(;;) { + while(ISBLANK(*p)) + p++; + if(*p != ';') + break; + p++; /* pass the semicolon */ + if(!*p || ISNEWLINE(*p)) + break; + result = getalnum(&p, option, sizeof(option)); + if(result) { + /* skip option if name is too long */ + option[0] = '\0'; + } + while(*p && ISBLANK(*p)) + p++; + if(*p != '=') + return CURLE_OK; + p++; + while(*p && ISBLANK(*p)) + p++; + if(!*p) + return CURLE_OK; + if(*p == '\"') { + /* quoted value */ + p++; + quoted = TRUE; + } + value_ptr = p; + if(quoted) { + while(*p && *p != '\"') + p++; + if(!*p++) + return CURLE_OK; + } + else { + while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',') + p++; + } + num = strtoul(value_ptr, &end_ptr, 10); + if((end_ptr != value_ptr) && (num < ULONG_MAX)) { + if(strcasecompare("ma", option)) + maxage = num; + else if(strcasecompare("persist", option) && (num == 1)) + persist = TRUE; + } + } + if(dstalpnid && valid) { + if(!entries++) + /* Flush cached alternatives for this source origin, if any - when + this is the first entry of the line. */ + altsvc_flush(asi, srcalpnid, srchost, srcport); + + as = altsvc_createid(srchost, dsthost, + srcalpnid, dstalpnid, + srcport, dstport); + if(as) { + /* The expires time also needs to take the Age: value (if any) into + account. [See RFC 7838 section 3.1] */ + as->expires = maxage + time(NULL); + as->persist = persist; + Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); + infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport, + Curl_alpnid2str(dstalpnid)); + } + } + } + else + break; + /* after the double quote there can be a comma if there's another + string or a semicolon if no more */ + if(*p == ',') { + /* comma means another alternative is presented */ + p++; + result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); + if(result) + break; + } + } + else + break; + } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r')); + + return CURLE_OK; +} + +/* + * Return TRUE on a match + */ +bool Curl_altsvc_lookup(struct altsvcinfo *asi, + enum alpnid srcalpnid, const char *srchost, + int srcport, + struct altsvc **dstentry, + const int versions) /* one or more bits */ +{ + struct Curl_llist_element *e; + struct Curl_llist_element *n; + time_t now = time(NULL); + DEBUGASSERT(asi); + DEBUGASSERT(srchost); + DEBUGASSERT(dstentry); + + for(e = asi->list.head; e; e = n) { + struct altsvc *as = e->ptr; + n = e->next; + if(as->expires < now) { + /* an expired entry, remove */ + Curl_llist_remove(&asi->list, e, NULL); + altsvc_free(as); + continue; + } + if((as->src.alpnid == srcalpnid) && + hostcompare(srchost, as->src.host) && + (as->src.port == srcport) && + (versions & as->dst.alpnid)) { + /* match */ + *dstentry = as; + return TRUE; + } + } + return FALSE; +} + +#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */ diff --git a/lib/altsvc.h b/lib/altsvc.h new file mode 100644 index 0000000..7fea143 --- /dev/null +++ b/lib/altsvc.h @@ -0,0 +1,81 @@ +#ifndef HEADER_CURL_ALTSVC_H +#define HEADER_CURL_ALTSVC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC) +#include +#include "llist.h" + +enum alpnid { + ALPN_none = 0, + ALPN_h1 = CURLALTSVC_H1, + ALPN_h2 = CURLALTSVC_H2, + ALPN_h3 = CURLALTSVC_H3 +}; + +struct althost { + char *host; + unsigned short port; + enum alpnid alpnid; +}; + +struct altsvc { + struct althost src; + struct althost dst; + time_t expires; + bool persist; + int prio; + struct Curl_llist_element node; +}; + +struct altsvcinfo { + char *filename; + struct Curl_llist list; /* list of entries */ + long flags; /* the publicly set bitmask */ +}; + +const char *Curl_alpnid2str(enum alpnid id); +struct altsvcinfo *Curl_altsvc_init(void); +CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file); +CURLcode Curl_altsvc_save(struct Curl_easy *data, + struct altsvcinfo *asi, const char *file); +CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl); +void Curl_altsvc_cleanup(struct altsvcinfo **altsvc); +CURLcode Curl_altsvc_parse(struct Curl_easy *data, + struct altsvcinfo *altsvc, const char *value, + enum alpnid srcalpn, const char *srchost, + unsigned short srcport); +bool Curl_altsvc_lookup(struct altsvcinfo *asi, + enum alpnid srcalpnid, const char *srchost, + int srcport, + struct altsvc **dstentry, + const int versions); /* CURLALTSVC_H* bits */ +#else +/* disabled */ +#define Curl_altsvc_save(a,b,c) +#define Curl_altsvc_cleanup(x) +#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */ +#endif /* HEADER_CURL_ALTSVC_H */ diff --git a/lib/amigaos.c b/lib/amigaos.c new file mode 100644 index 0000000..139309b --- /dev/null +++ b/lib/amigaos.c @@ -0,0 +1,247 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef __AMIGA__ + +#include + +#include "hostip.h" +#include "amigaos.h" + +#ifdef HAVE_PROTO_BSDSOCKET_H +# if defined(__amigaos4__) +# include +# elif !defined(USE_AMISSL) +# include +# endif +# ifdef __libnix__ +# include +# endif +#endif + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef HAVE_PROTO_BSDSOCKET_H + +#ifdef __amigaos4__ +/* + * AmigaOS 4.x specific code + */ + +/* + * hostip4.c - Curl_ipv4_resolve_r() replacement code + * + * Logic that needs to be considered are the following build cases: + * - newlib networking + * - clib2 networking + * - direct bsdsocket.library networking (usually AmiSSL builds) + * Each with the threaded resolver enabled or not. + * + * With the threaded resolver enabled, try to use gethostbyname_r() where + * available, otherwise (re)open bsdsocket.library and fallback to + * gethostbyname(). + */ + +#include + +static struct SocketIFace *__CurlISocket = NULL; +static uint32 SocketFeatures = 0; + +#define HAVE_BSDSOCKET_GETHOSTBYNAME_R 0x01 +#define HAVE_BSDSOCKET_GETADDRINFO 0x02 + +CURLcode Curl_amiga_init(void) +{ + struct SocketIFace *ISocket; + struct Library *base = OpenLibrary("bsdsocket.library", 4); + + if(base) { + ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL); + if(ISocket) { + ULONG enabled = 0; + + SocketBaseTags(SBTM_SETVAL(SBTC_CAN_SHARE_LIBRARY_BASES), TRUE, + SBTM_GETREF(SBTC_HAVE_GETHOSTADDR_R_API), (ULONG)&enabled, + TAG_DONE); + + if(enabled) { + SocketFeatures |= HAVE_BSDSOCKET_GETHOSTBYNAME_R; + } + + __CurlISocket = ISocket; + + atexit(Curl_amiga_cleanup); + + return CURLE_OK; + } + CloseLibrary(base); + } + + return CURLE_FAILED_INIT; +} + +void Curl_amiga_cleanup(void) +{ + if(__CurlISocket) { + struct Library *base = __CurlISocket->Data.LibBase; + DropInterface((struct Interface *)__CurlISocket); + CloseLibrary(base); + __CurlISocket = NULL; + } +} + +#ifdef CURLRES_AMIGA +/* + * Because we need to handle the different cases in hostip4.c at run-time, + * not at compile-time, based on what was detected in Curl_amiga_init(), + * we replace it completely with our own as to not complicate the baseline + * code. Assumes malloc/calloc/free are thread safe because Curl_he2ai() + * allocates memory also. + */ + +struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, + int port) +{ + struct Curl_addrinfo *ai = NULL; + struct hostent *h; + struct SocketIFace *ISocket = __CurlISocket; + + if(SocketFeatures & HAVE_BSDSOCKET_GETHOSTBYNAME_R) { + LONG h_errnop = 0; + struct hostent *buf; + + buf = calloc(1, CURL_HOSTENT_SIZE); + if(buf) { + h = gethostbyname_r((STRPTR)hostname, buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h_errnop); + if(h) { + ai = Curl_he2ai(h, port); + } + free(buf); + } + } + else { + #ifdef CURLRES_THREADED + /* gethostbyname() is not thread safe, so we need to reopen bsdsocket + * on the thread's context + */ + struct Library *base = OpenLibrary("bsdsocket.library", 4); + if(base) { + ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL); + if(ISocket) { + h = gethostbyname((STRPTR)hostname); + if(h) { + ai = Curl_he2ai(h, port); + } + DropInterface((struct Interface *)ISocket); + } + CloseLibrary(base); + } + #else + /* not using threaded resolver - safe to use this as-is */ + h = gethostbyname(hostname); + if(h) { + ai = Curl_he2ai(h, port); + } + #endif + } + + return ai; +} +#endif /* CURLRES_AMIGA */ + +#ifdef USE_AMISSL +#include +int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *errorfds, struct timeval *timeout) +{ + int r = WaitSelect(nfds, readfds, writefds, errorfds, timeout, 0); + /* Ensure Ctrl-C signal is actioned */ + if((r == -1) && (SOCKERRNO == EINTR)) + raise(SIGINT); + return r; +} +#endif /* USE_AMISSL */ + +#elif !defined(USE_AMISSL) /* __amigaos4__ */ +/* + * Amiga OS3 specific code + */ + +struct Library *SocketBase = NULL; +extern int errno, h_errno; + +#ifdef __libnix__ +void __request(const char *msg); +#else +# define __request(msg) Printf(msg "\n\a") +#endif + +void Curl_amiga_cleanup(void) +{ + if(SocketBase) { + CloseLibrary(SocketBase); + SocketBase = NULL; + } +} + +CURLcode Curl_amiga_init(void) +{ + if(!SocketBase) + SocketBase = OpenLibrary("bsdsocket.library", 4); + + if(!SocketBase) { + __request("No TCP/IP Stack running!"); + return CURLE_FAILED_INIT; + } + + if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, + SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", + TAG_DONE)) { + __request("SocketBaseTags ERROR"); + return CURLE_FAILED_INIT; + } + +#ifndef __libnix__ + atexit(Curl_amiga_cleanup); +#endif + + return CURLE_OK; +} + +#ifdef __libnix__ +ADD2EXIT(Curl_amiga_cleanup, -50); +#endif + +#endif /* !USE_AMISSL */ + +#endif /* HAVE_PROTO_BSDSOCKET_H */ + +#endif /* __AMIGA__ */ diff --git a/lib/amigaos.h b/lib/amigaos.h new file mode 100644 index 0000000..c99d963 --- /dev/null +++ b/lib/amigaos.h @@ -0,0 +1,41 @@ +#ifndef HEADER_CURL_AMIGAOS_H +#define HEADER_CURL_AMIGAOS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(__AMIGA__) && defined(HAVE_PROTO_BSDSOCKET_H) && \ + (!defined(USE_AMISSL) || defined(__amigaos4__)) + +CURLcode Curl_amiga_init(void); +void Curl_amiga_cleanup(void); + +#else + +#define Curl_amiga_init() CURLE_OK +#define Curl_amiga_cleanup() Curl_nop_stmt + +#endif + +#endif /* HEADER_CURL_AMIGAOS_H */ diff --git a/lib/arpa_telnet.h b/lib/arpa_telnet.h new file mode 100644 index 0000000..228b446 --- /dev/null +++ b/lib/arpa_telnet.h @@ -0,0 +1,117 @@ +#ifndef HEADER_CURL_ARPA_TELNET_H +#define HEADER_CURL_ARPA_TELNET_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifndef CURL_DISABLE_TELNET +/* + * Telnet option defines. Add more here if in need. + */ +#define CURL_TELOPT_BINARY 0 /* binary 8bit data */ +#define CURL_TELOPT_ECHO 1 /* just echo! */ +#define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */ +#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */ +#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */ +#define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */ +#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */ + +#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */ +#define CURL_NEW_ENV_VAR 0 +#define CURL_NEW_ENV_VALUE 1 + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +/* + * The telnet options represented as strings + */ +static const char * const telnetoptions[]= +{ + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", + "NAME", "STATUS", "TIMING MARK", "RCTE", + "NAOL", "NAOP", "NAOCRD", "NAOHTS", + "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", + "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION", + "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING", + "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS", + "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC", + "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON" +}; +#define CURL_TELOPT(x) telnetoptions[x] +#else +#define CURL_TELOPT(x) "" +#endif + +#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON + +#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM) + +#define CURL_NTELOPTS 40 + +/* + * First some defines + */ +#define CURL_xEOF 236 /* End Of File */ +#define CURL_SE 240 /* Sub negotiation End */ +#define CURL_NOP 241 /* No OPeration */ +#define CURL_DM 242 /* Data Mark */ +#define CURL_GA 249 /* Go Ahead, reverse the line */ +#define CURL_SB 250 /* SuBnegotiation */ +#define CURL_WILL 251 /* Our side WILL use this option */ +#define CURL_WONT 252 /* Our side WON'T use this option */ +#define CURL_DO 253 /* DO use this option! */ +#define CURL_DONT 254 /* DON'T use this option! */ +#define CURL_IAC 255 /* Interpret As Command */ + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +/* + * Then those numbers represented as strings: + */ +static const char * const telnetcmds[]= +{ + "EOF", "SUSP", "ABORT", "EOR", "SE", + "NOP", "DMARK", "BRK", "IP", "AO", + "AYT", "EC", "EL", "GA", "SB", + "WILL", "WONT", "DO", "DONT", "IAC" +}; +#endif + +#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */ +#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */ + +#define CURL_TELQUAL_IS 0 +#define CURL_TELQUAL_SEND 1 +#define CURL_TELQUAL_INFO 2 +#define CURL_TELQUAL_NAME 3 + +#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \ + ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) ) + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM] +#else +#define CURL_TELCMD(x) "" +#endif + +#endif /* CURL_DISABLE_TELNET */ + +#endif /* HEADER_CURL_ARPA_TELNET_H */ diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c new file mode 100644 index 0000000..76efba7 --- /dev/null +++ b/lib/asyn-ares.c @@ -0,0 +1,958 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/*********************************************************************** + * Only for ares-enabled builds + * And only for functions that fulfill the asynch resolver backend API + * as defined in asyn.h, nothing else belongs in this file! + **********************************************************************/ + +#ifdef CURLRES_ARES + +#include +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "url.h" +#include "multiif.h" +#include "inet_pton.h" +#include "connect.h" +#include "select.h" +#include "progress.h" +#include "timediff.h" + +#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ + defined(_WIN32) +# define CARES_STATICLIB +#endif +#include +#include /* really old c-ares didn't include this by + itself */ + +#if ARES_VERSION >= 0x010500 +/* c-ares 1.5.0 or later, the callback proto is modified */ +#define HAVE_CARES_CALLBACK_TIMEOUTS 1 +#endif + +#if ARES_VERSION >= 0x010601 +/* IPv6 supported since 1.6.1 */ +#define HAVE_CARES_IPV6 1 +#endif + +#if ARES_VERSION >= 0x010704 +#define HAVE_CARES_SERVERS_CSV 1 +#define HAVE_CARES_LOCAL_DEV 1 +#define HAVE_CARES_SET_LOCAL 1 +#endif + +#if ARES_VERSION >= 0x010b00 +#define HAVE_CARES_PORTS_CSV 1 +#endif + +#if ARES_VERSION >= 0x011000 +/* 1.16.0 or later has ares_getaddrinfo */ +#define HAVE_CARES_GETADDRINFO 1 +#endif + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +struct thread_data { + int num_pending; /* number of outstanding c-ares requests */ + struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares + parts */ + int last_status; +#ifndef HAVE_CARES_GETADDRINFO + struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ +#endif + char hostname[1]; +}; + +/* How long we are willing to wait for additional parallel responses after + obtaining a "definitive" one. For old c-ares without getaddrinfo. + + This is intended to equal the c-ares default timeout. cURL always uses that + default value. Unfortunately, c-ares doesn't expose its default timeout in + its API, but it is officially documented as 5 seconds. + + See query_completed_cb() for an explanation of how this is used. + */ +#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 + +#define CARES_TIMEOUT_PER_ATTEMPT 2000 + +/* + * Curl_resolver_global_init() - the generic low-level asynchronous name + * resolve API. Called from curl_global_init() to initialize global resolver + * environment. Initializes ares library. + */ +int Curl_resolver_global_init(void) +{ +#ifdef CARES_HAVE_ARES_LIBRARY_INIT + if(ares_library_init(ARES_LIB_INIT_ALL)) { + return CURLE_FAILED_INIT; + } +#endif + return CURLE_OK; +} + +/* + * Curl_resolver_global_cleanup() + * + * Called from curl_global_cleanup() to destroy global resolver environment. + * Deinitializes ares library. + */ +void Curl_resolver_global_cleanup(void) +{ +#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP + ares_library_cleanup(); +#endif +} + + +static void sock_state_cb(void *data, ares_socket_t socket_fd, + int readable, int writable) +{ + struct Curl_easy *easy = data; + if(!readable && !writable) { + DEBUGASSERT(easy); + Curl_multi_closed(easy, socket_fd); + } +} + +/* + * Curl_resolver_init() + * + * Called from curl_easy_init() -> Curl_open() to initialize resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Fills the passed pointer by the initialized ares_channel. + */ +CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) +{ + int status; + struct ares_options options; + int optmask = ARES_OPT_SOCK_STATE_CB; + static int ares_ver = 0; + options.sock_state_cb = sock_state_cb; + options.sock_state_cb_data = easy; + if(ares_ver == 0) + ares_version(&ares_ver); + + if(ares_ver < 0x011400) { /* c-ares included similar change since 1.20.0 */ + options.timeout = CARES_TIMEOUT_PER_ATTEMPT; + optmask |= ARES_OPT_TIMEOUTMS; + } + + /* + if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s) + + if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need + to set the timeout value; + + if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to + overwrite c-ares' timeout. + */ + + status = ares_init_options((ares_channel*)resolver, &options, optmask); + if(status != ARES_SUCCESS) { + if(status == ARES_ENOMEM) + return CURLE_OUT_OF_MEMORY; + else + return CURLE_FAILED_INIT; + } + return CURLE_OK; + /* make sure that all other returns from this function should destroy the + ares channel before returning error! */ +} + +/* + * Curl_resolver_cleanup() + * + * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Destroys the ares channel. + */ +void Curl_resolver_cleanup(void *resolver) +{ + ares_destroy((ares_channel)resolver); +} + +/* + * Curl_resolver_duphandle() + * + * Called from curl_easy_duphandle() to duplicate resolver URL-state specific + * environment ('resolver' member of the UrlState structure). Duplicates the + * 'from' ares channel and passes the resulting channel to the 'to' pointer. + */ +CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) +{ + (void)from; + /* + * it would be better to call ares_dup instead, but right now + * it is not possible to set 'sock_state_cb_data' outside of + * ares_init_options + */ + return Curl_resolver_init(easy, to); +} + +static void destroy_async_data(struct Curl_async *async); + +/* + * Cancel all possibly still on-going resolves for this connection. + */ +void Curl_resolver_cancel(struct Curl_easy *data) +{ + DEBUGASSERT(data); + if(data->state.async.resolver) + ares_cancel((ares_channel)data->state.async.resolver); + destroy_async_data(&data->state.async); +} + +/* + * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We + * never block. + */ +void Curl_resolver_kill(struct Curl_easy *data) +{ + /* We don't need to check the resolver state because we can be called safely + at any time and we always do the same thing. */ + Curl_resolver_cancel(data); +} + +/* + * destroy_async_data() cleans up async resolver data. + */ +static void destroy_async_data(struct Curl_async *async) +{ + if(async->tdata) { + struct thread_data *res = async->tdata; + if(res) { + if(res->temp_ai) { + Curl_freeaddrinfo(res->temp_ai); + res->temp_ai = NULL; + } + free(res); + } + async->tdata = NULL; + } +} + +/* + * Curl_resolver_getsock() is called when someone from the outside world + * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking + * with ares. The caller must make sure that this function is only called when + * we have a working ares channel. + * + * Returns: sockets-in-use-bitmap + */ + +int Curl_resolver_getsock(struct Curl_easy *data, + curl_socket_t *socks) +{ + struct timeval maxtime; + struct timeval timebuf; + struct timeval *timeout; + long milli; + int max = ares_getsock((ares_channel)data->state.async.resolver, + (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); + + maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; + maxtime.tv_usec = 0; + + timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime, + &timebuf); + milli = (long)curlx_tvtoms(timeout); + if(milli == 0) + milli += 10; + Curl_expire(data, milli, EXPIRE_ASYNC_NAME); + + return max; +} + +/* + * waitperform() + * + * 1) Ask ares what sockets it currently plays with, then + * 2) wait for the timeout period to check for action on ares' sockets. + * 3) tell ares to act on all the sockets marked as "with action" + * + * return number of sockets it worked on, or -1 on error + */ + +static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) +{ + int nfds; + int bitmask; + ares_socket_t socks[ARES_GETSOCK_MAXNUM]; + struct pollfd pfd[ARES_GETSOCK_MAXNUM]; + int i; + int num = 0; + + bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks, + ARES_GETSOCK_MAXNUM); + + for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { + pfd[i].events = 0; + pfd[i].revents = 0; + if(ARES_GETSOCK_READABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLRDNORM|POLLIN; + } + if(ARES_GETSOCK_WRITABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLWRNORM|POLLOUT; + } + if(pfd[i].events) + num++; + else + break; + } + + if(num) { + nfds = Curl_poll(pfd, num, timeout_ms); + if(nfds < 0) + return -1; + } + else + nfds = 0; + + if(!nfds) + /* Call ares_process() unconditionally here, even if we simply timed out + above, as otherwise the ares name resolve won't timeout! */ + ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD, + ARES_SOCKET_BAD); + else { + /* move through the descriptors and ask for processing on them */ + for(i = 0; i < num; i++) + ares_process_fd((ares_channel)data->state.async.resolver, + (pfd[i].revents & (POLLRDNORM|POLLIN))? + pfd[i].fd:ARES_SOCKET_BAD, + (pfd[i].revents & (POLLWRNORM|POLLOUT))? + pfd[i].fd:ARES_SOCKET_BAD); + } + return nfds; +} + +/* + * Curl_resolver_is_resolved() is called repeatedly to check if a previous + * name resolve request has completed. It should also make sure to time-out if + * the operation seems to take too long. + * + * Returns normal CURLcode errors. + */ +CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, + struct Curl_dns_entry **dns) +{ + struct thread_data *res = data->state.async.tdata; + CURLcode result = CURLE_OK; + + DEBUGASSERT(dns); + *dns = NULL; + + if(waitperform(data, 0) < 0) + return CURLE_UNRECOVERABLE_POLL; + +#ifndef HAVE_CARES_GETADDRINFO + /* Now that we've checked for any last minute results above, see if there are + any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer + expires. */ + if(res + && res->num_pending + /* This is only set to non-zero if the timer was started. */ + && (res->happy_eyeballs_dns_time.tv_sec + || res->happy_eyeballs_dns_time.tv_usec) + && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time) + >= HAPPY_EYEBALLS_DNS_TIMEOUT)) { + /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer + running. */ + memset( + &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time)); + + /* Cancel the raw c-ares request, which will fire query_completed_cb() with + ARES_ECANCELLED synchronously for all pending responses. This will + leave us with res->num_pending == 0, which is perfect for the next + block. */ + ares_cancel((ares_channel)data->state.async.resolver); + DEBUGASSERT(res->num_pending == 0); + } +#endif + + if(res && !res->num_pending) { + (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai); + /* temp_ai ownership is moved to the connection, so we need not free-up + them */ + res->temp_ai = NULL; + + if(!data->state.async.dns) + result = Curl_resolver_error(data); + else + *dns = data->state.async.dns; + + destroy_async_data(&data->state.async); + } + + return result; +} + +/* + * Curl_resolver_wait_resolv() + * + * Waits for a resolve to finish. This function should be avoided since using + * this risk getting the multi interface to "hang". + * + * 'entry' MUST be non-NULL. + * + * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, + * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. + */ +CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, + struct Curl_dns_entry **entry) +{ + CURLcode result = CURLE_OK; + timediff_t timeout; + struct curltime now = Curl_now(); + + DEBUGASSERT(entry); + *entry = NULL; /* clear on entry */ + + timeout = Curl_timeleft(data, &now, TRUE); + if(timeout < 0) { + /* already expired! */ + connclose(data->conn, "Timed out before name resolve started"); + return CURLE_OPERATION_TIMEDOUT; + } + if(!timeout) + timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ + + /* Wait for the name resolve query to complete. */ + while(!result) { + struct timeval *tvp, tv, store; + int itimeout; + timediff_t timeout_ms; + +#if TIMEDIFF_T_MAX > INT_MAX + itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout; +#else + itimeout = (int)timeout; +#endif + + store.tv_sec = itimeout/1000; + store.tv_usec = (itimeout%1000)*1000; + + tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv); + + /* use the timeout period ares returned to us above if less than one + second is left, otherwise just use 1000ms to make sure the progress + callback gets called frequent enough */ + if(!tvp->tv_sec) + timeout_ms = (timediff_t)(tvp->tv_usec/1000); + else + timeout_ms = 1000; + + if(waitperform(data, timeout_ms) < 0) + return CURLE_UNRECOVERABLE_POLL; + result = Curl_resolver_is_resolved(data, entry); + + if(result || data->state.async.done) + break; + + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + else { + struct curltime now2 = Curl_now(); + timediff_t timediff = Curl_timediff(now2, now); /* spent time */ + if(timediff <= 0) + timeout -= 1; /* always deduct at least 1 */ + else if(timediff > timeout) + timeout = -1; + else + timeout -= timediff; + now = now2; /* for next loop */ + } + if(timeout < 0) + result = CURLE_OPERATION_TIMEDOUT; + } + if(result) + /* failure, so we cancel the ares operation */ + ares_cancel((ares_channel)data->state.async.resolver); + + /* Operation complete, if the lookup was successful we now have the entry + in the cache. */ + if(entry) + *entry = data->state.async.dns; + + if(result) + /* close the connection, since we can't return failure here without + cleaning up this connection properly. */ + connclose(data->conn, "c-ares resolve failed"); + + return result; +} + +#ifndef HAVE_CARES_GETADDRINFO + +/* Connects results to the list */ +static void compound_results(struct thread_data *res, + struct Curl_addrinfo *ai) +{ + if(!ai) + return; + +#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ + if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) { + /* We have results already, put the new IPv6 entries at the head of the + list. */ + struct Curl_addrinfo *temp_ai_tail = res->temp_ai; + + while(temp_ai_tail->ai_next) + temp_ai_tail = temp_ai_tail->ai_next; + + temp_ai_tail->ai_next = ai; + } + else +#endif /* CURLRES_IPV6 */ + { + /* Add the new results to the list of old results. */ + struct Curl_addrinfo *ai_tail = ai; + while(ai_tail->ai_next) + ai_tail = ai_tail->ai_next; + + ai_tail->ai_next = res->temp_ai; + res->temp_ai = ai; + } +} + +/* + * ares_query_completed_cb() is the callback that ares will call when + * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), + * when using ares, is completed either successfully or with failure. + */ +static void query_completed_cb(void *arg, /* (struct connectdata *) */ + int status, +#ifdef HAVE_CARES_CALLBACK_TIMEOUTS + int timeouts, +#endif + struct hostent *hostent) +{ + struct Curl_easy *data = (struct Curl_easy *)arg; + struct thread_data *res; + +#ifdef HAVE_CARES_CALLBACK_TIMEOUTS + (void)timeouts; /* ignored */ +#endif + + if(ARES_EDESTRUCTION == status) + /* when this ares handle is getting destroyed, the 'arg' pointer may not + be valid so only defer it when we know the 'status' says its fine! */ + return; + + res = data->state.async.tdata; + if(res) { + res->num_pending--; + + if(CURL_ASYNC_SUCCESS == status) { + struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port); + if(ai) { + compound_results(res, ai); + } + } + /* A successful result overwrites any previous error */ + if(res->last_status != ARES_SUCCESS) + res->last_status = status; + + /* If there are responses still pending, we presume they must be the + complementary IPv4 or IPv6 lookups that we started in parallel in + Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we've got a + "definitive" response from one of a set of parallel queries, we need to + think about how long we're willing to wait for more responses. */ + if(res->num_pending + /* Only these c-ares status values count as "definitive" for these + purposes. For example, ARES_ENODATA is what we expect when there is + no IPv6 entry for a domain name, and that's not a reason to get more + aggressive in our timeouts for the other response. Other errors are + either a result of bad input (which should affect all parallel + requests), local or network conditions, non-definitive server + responses, or us cancelling the request. */ + && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) { + /* Right now, there can only be up to two parallel queries, so don't + bother handling any other cases. */ + DEBUGASSERT(res->num_pending == 1); + + /* It's possible that one of these parallel queries could succeed + quickly, but the other could always fail or timeout (when we're + talking to a pool of DNS servers that can only successfully resolve + IPv4 address, for example). + + It's also possible that the other request could always just take + longer because it needs more time or only the second DNS server can + fulfill it successfully. But, to align with the philosophy of Happy + Eyeballs, we don't want to wait _too_ long or users will think + requests are slow when IPv6 lookups don't actually work (but IPv4 ones + do). + + So, now that we have a usable answer (some IPv4 addresses, some IPv6 + addresses, or "no such domain"), we start a timeout for the remaining + pending responses. Even though it is typical that this resolved + request came back quickly, that needn't be the case. It might be that + this completing request didn't get a result from the first DNS server + or even the first round of the whole DNS server pool. So it could + already be quite some time after we issued the DNS queries in the + first place. Without modifying c-ares, we can't know exactly where in + its retry cycle we are. We could guess based on how much time has + gone by, but it doesn't really matter. Happy Eyeballs tells us that, + given usable information in hand, we simply don't want to wait "too + much longer" after we get a result. + + We simply wait an additional amount of time equal to the default + c-ares query timeout. That is enough time for a typical parallel + response to arrive without being "too long". Even on a network + where one of the two types of queries is failing or timing out + constantly, this will usually mean we wait a total of the default + c-ares timeout (5 seconds) plus the round trip time for the successful + request, which seems bearable. The downside is that c-ares might race + with us to issue one more retry just before we give up, but it seems + better to "waste" that request instead of trying to guess the perfect + timeout to prevent it. After all, we don't even know where in the + c-ares retry cycle each request is. + */ + res->happy_eyeballs_dns_time = Curl_now(); + Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT, + EXPIRE_HAPPY_EYEBALLS_DNS); + } + } +} +#else +/* c-ares 1.16.0 or later */ + +/* + * ares2addr() converts an address list provided by c-ares to an internal + * libcurl compatible list + */ +static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node) +{ + /* traverse the ares_addrinfo_node list */ + struct ares_addrinfo_node *ai; + struct Curl_addrinfo *cafirst = NULL; + struct Curl_addrinfo *calast = NULL; + int error = 0; + + for(ai = node; ai != NULL; ai = ai->ai_next) { + size_t ss_size; + struct Curl_addrinfo *ca; + /* ignore elements with unsupported address family, */ + /* settle family-specific sockaddr structure size. */ + if(ai->ai_family == AF_INET) + ss_size = sizeof(struct sockaddr_in); +#ifdef ENABLE_IPV6 + else if(ai->ai_family == AF_INET6) + ss_size = sizeof(struct sockaddr_in6); +#endif + else + continue; + + /* ignore elements without required address info */ + if(!ai->ai_addr || !(ai->ai_addrlen > 0)) + continue; + + /* ignore elements with bogus address size */ + if((size_t)ai->ai_addrlen < ss_size) + continue; + + ca = malloc(sizeof(struct Curl_addrinfo) + ss_size); + if(!ca) { + error = EAI_MEMORY; + break; + } + + /* copy each structure member individually, member ordering, */ + /* size, or padding might be different for each platform. */ + + ca->ai_flags = ai->ai_flags; + ca->ai_family = ai->ai_family; + ca->ai_socktype = ai->ai_socktype; + ca->ai_protocol = ai->ai_protocol; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_addr = NULL; + ca->ai_canonname = NULL; + ca->ai_next = NULL; + + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, ai->ai_addr, ss_size); + + /* if the return list is empty, this becomes the first element */ + if(!cafirst) + cafirst = ca; + + /* add this element last in the return list */ + if(calast) + calast->ai_next = ca; + calast = ca; + } + + /* if we failed, destroy the Curl_addrinfo list */ + if(error) { + Curl_freeaddrinfo(cafirst); + cafirst = NULL; + } + + return cafirst; +} + +static void addrinfo_cb(void *arg, int status, int timeouts, + struct ares_addrinfo *result) +{ + struct Curl_easy *data = (struct Curl_easy *)arg; + struct thread_data *res = data->state.async.tdata; + (void)timeouts; + if(ARES_SUCCESS == status) { + res->temp_ai = ares2addr(result->nodes); + res->last_status = CURL_ASYNC_SUCCESS; + ares_freeaddrinfo(result); + } + res->num_pending--; +} + +#endif +/* + * Curl_resolver_getaddrinfo() - when using ares + * + * Returns name information about the given hostname and port number. If + * successful, the 'hostent' is returned and the fourth argument will point to + * memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + */ +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp) +{ + struct thread_data *res = NULL; + size_t namelen = strlen(hostname); + *waitp = 0; /* default to synchronous response */ + + res = calloc(1, sizeof(struct thread_data) + namelen); + if(res) { + strcpy(res->hostname, hostname); + data->state.async.hostname = res->hostname; + data->state.async.port = port; + data->state.async.done = FALSE; /* not done */ + data->state.async.status = 0; /* clear */ + data->state.async.dns = NULL; /* clear */ + data->state.async.tdata = res; + + /* initial status - failed */ + res->last_status = ARES_ENOTFOUND; + +#ifdef HAVE_CARES_GETADDRINFO + { + struct ares_addrinfo_hints hints; + char service[12]; + int pf = PF_INET; + memset(&hints, 0, sizeof(hints)); +#ifdef CURLRES_IPV6 + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && + Curl_ipv6works(data)) { + /* The stack seems to be IPv6-enabled */ + if(data->conn->ip_version == CURL_IPRESOLVE_V6) + pf = PF_INET6; + else + pf = PF_UNSPEC; + } +#endif /* CURLRES_IPV6 */ + hints.ai_family = pf; + hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)? + SOCK_STREAM : SOCK_DGRAM; + /* Since the service is a numerical one, set the hint flags + * accordingly to save a call to getservbyname in inside C-Ares + */ + hints.ai_flags = ARES_AI_NUMERICSERV; + msnprintf(service, sizeof(service), "%d", port); + res->num_pending = 1; + ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, + service, &hints, addrinfo_cb, data); + } +#else + +#ifdef HAVE_CARES_IPV6 + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { + /* The stack seems to be IPv6-enabled */ + res->num_pending = 2; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, + PF_INET, query_completed_cb, data); + ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, + PF_INET6, query_completed_cb, data); + } + else +#endif + { + res->num_pending = 1; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.async.resolver, + hostname, PF_INET, + query_completed_cb, data); + } +#endif + *waitp = 1; /* expect asynchronous response */ + } + return NULL; /* no struct yet */ +} + +CURLcode Curl_set_dns_servers(struct Curl_easy *data, + char *servers) +{ + CURLcode result = CURLE_NOT_BUILT_IN; + int ares_result; + + /* If server is NULL or empty, this would purge all DNS servers + * from ares library, which will cause any and all queries to fail. + * So, just return OK if none are configured and don't actually make + * any changes to c-ares. This lets c-ares use it's defaults, which + * it gets from the OS (for instance from /etc/resolv.conf on Linux). + */ + if(!(servers && servers[0])) + return CURLE_OK; + +#ifdef HAVE_CARES_SERVERS_CSV +#ifdef HAVE_CARES_PORTS_CSV + ares_result = ares_set_servers_ports_csv(data->state.async.resolver, + servers); +#else + ares_result = ares_set_servers_csv(data->state.async.resolver, servers); +#endif + switch(ares_result) { + case ARES_SUCCESS: + result = CURLE_OK; + break; + case ARES_ENOMEM: + result = CURLE_OUT_OF_MEMORY; + break; + case ARES_ENOTINITIALIZED: + case ARES_ENODATA: + case ARES_EBADSTR: + default: + DEBUGF(infof(data, "bad servers set")); + result = CURLE_BAD_FUNCTION_ARGUMENT; + break; + } +#else /* too old c-ares version! */ + (void)data; + (void)(ares_result); +#endif + return result; +} + +CURLcode Curl_set_dns_interface(struct Curl_easy *data, + const char *interf) +{ +#ifdef HAVE_CARES_LOCAL_DEV + if(!interf) + interf = ""; + + ares_set_local_dev((ares_channel)data->state.async.resolver, interf); + + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)interf; + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, + const char *local_ip4) +{ +#ifdef HAVE_CARES_SET_LOCAL + struct in_addr a4; + + if((!local_ip4) || (local_ip4[0] == 0)) { + a4.s_addr = 0; /* disabled: do not bind to a specific address */ + } + else { + if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { + DEBUGF(infof(data, "bad DNS IPv4 address")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + + ares_set_local_ip4((ares_channel)data->state.async.resolver, + ntohl(a4.s_addr)); + + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, + const char *local_ip6) +{ +#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6) + unsigned char a6[INET6_ADDRSTRLEN]; + + if((!local_ip6) || (local_ip6[0] == 0)) { + /* disabled: do not bind to a specific address */ + memset(a6, 0, sizeof(a6)); + } + else { + if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { + DEBUGF(infof(data, "bad DNS IPv6 address")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + + ares_set_local_ip6((ares_channel)data->state.async.resolver, a6); + + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +#endif +} +#endif /* CURLRES_ARES */ diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c new file mode 100644 index 0000000..d4d382a --- /dev/null +++ b/lib/asyn-thread.c @@ -0,0 +1,985 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "socketpair.h" + +/*********************************************************************** + * Only for threaded name resolves builds + **********************************************************************/ +#ifdef CURLRES_THREADED + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) +# include +#endif + +#ifdef HAVE_GETADDRINFO +# define RESOLVER_ENOMEM EAI_MEMORY +#else +# define RESOLVER_ENOMEM ENOMEM +#endif + +#include "system_win32.h" +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "url.h" +#include "multiif.h" +#include "inet_ntop.h" +#include "curl_threads.h" +#include "connect.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +struct resdata { + struct curltime start; +}; + +/* + * Curl_resolver_global_init() + * Called from curl_global_init() to initialize global resolver environment. + * Does nothing here. + */ +int Curl_resolver_global_init(void) +{ + return CURLE_OK; +} + +/* + * Curl_resolver_global_cleanup() + * Called from curl_global_cleanup() to destroy global resolver environment. + * Does nothing here. + */ +void Curl_resolver_global_cleanup(void) +{ +} + +/* + * Curl_resolver_init() + * Called from curl_easy_init() -> Curl_open() to initialize resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). + */ +CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) +{ + (void)easy; + *resolver = calloc(1, sizeof(struct resdata)); + if(!*resolver) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +} + +/* + * Curl_resolver_cleanup() + * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). + */ +void Curl_resolver_cleanup(void *resolver) +{ + free(resolver); +} + +/* + * Curl_resolver_duphandle() + * Called from curl_easy_duphandle() to duplicate resolver URL state-specific + * environment ('resolver' member of the UrlState structure). + */ +CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) +{ + (void)from; + return Curl_resolver_init(easy, to); +} + +static void destroy_async_data(struct Curl_async *); + +/* + * Cancel all possibly still on-going resolves for this connection. + */ +void Curl_resolver_cancel(struct Curl_easy *data) +{ + destroy_async_data(&data->state.async); +} + +/* This function is used to init a threaded resolve */ +static bool init_resolve_thread(struct Curl_easy *data, + const char *hostname, int port, + const struct addrinfo *hints); + +#ifdef _WIN32 +/* Thread sync data used by GetAddrInfoExW for win8+ */ +struct thread_sync_data_w8 +{ + OVERLAPPED overlapped; + ADDRINFOEXW_ *res; + HANDLE cancel_ev; + ADDRINFOEXW_ hints; +}; +#endif + +/* Data for synchronization between resolver thread and its parent */ +struct thread_sync_data { +#ifdef _WIN32 + struct thread_sync_data_w8 w8; +#endif + curl_mutex_t *mtx; + int done; + int port; + char *hostname; /* hostname to resolve, Curl_async.hostname + duplicate */ +#ifndef CURL_DISABLE_SOCKETPAIR + struct Curl_easy *data; + curl_socket_t sock_pair[2]; /* socket pair */ +#endif + int sock_error; + struct Curl_addrinfo *res; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints; +#endif + struct thread_data *td; /* for thread-self cleanup */ +}; + +struct thread_data { +#ifdef _WIN32 + HANDLE complete_ev; +#endif + curl_thread_t thread_hnd; + unsigned int poll_interval; + timediff_t interval_end; + struct thread_sync_data tsd; +}; + +static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data) +{ + return &(data->state.async.tdata->tsd); +} + +/* Destroy resolver thread synchronization data */ +static +void destroy_thread_sync_data(struct thread_sync_data *tsd) +{ + if(tsd->mtx) { + Curl_mutex_destroy(tsd->mtx); + free(tsd->mtx); + } + + free(tsd->hostname); + + if(tsd->res) + Curl_freeaddrinfo(tsd->res); + +#ifndef CURL_DISABLE_SOCKETPAIR + /* + * close one end of the socket pair (may be done in resolver thread); + * the other end (for reading) is always closed in the parent thread. + */ + if(tsd->sock_pair[1] != CURL_SOCKET_BAD) { + wakeup_close(tsd->sock_pair[1]); + } +#endif + memset(tsd, 0, sizeof(*tsd)); +} + +/* Initialize resolver thread synchronization data */ +static +int init_thread_sync_data(struct thread_data *td, + const char *hostname, + int port, + const struct addrinfo *hints) +{ + struct thread_sync_data *tsd = &td->tsd; + + memset(tsd, 0, sizeof(*tsd)); + + tsd->td = td; + tsd->port = port; + /* Treat the request as done until the thread actually starts so any early + * cleanup gets done properly. + */ + tsd->done = 1; +#ifdef HAVE_GETADDRINFO + DEBUGASSERT(hints); + tsd->hints = *hints; +#else + (void) hints; +#endif + + tsd->mtx = malloc(sizeof(curl_mutex_t)); + if(!tsd->mtx) + goto err_exit; + + Curl_mutex_init(tsd->mtx); + +#ifndef CURL_DISABLE_SOCKETPAIR + /* create socket pair or pipe */ + if(wakeup_create(&tsd->sock_pair[0]) < 0) { + tsd->sock_pair[0] = CURL_SOCKET_BAD; + tsd->sock_pair[1] = CURL_SOCKET_BAD; + goto err_exit; + } +#endif + tsd->sock_error = CURL_ASYNC_SUCCESS; + + /* Copying hostname string because original can be destroyed by parent + * thread during gethostbyname execution. + */ + tsd->hostname = strdup(hostname); + if(!tsd->hostname) + goto err_exit; + + return 1; + +err_exit: +#ifndef CURL_DISABLE_SOCKETPAIR + if(tsd->sock_pair[0] != CURL_SOCKET_BAD) { + wakeup_close(tsd->sock_pair[0]); + tsd->sock_pair[0] = CURL_SOCKET_BAD; + } +#endif + destroy_thread_sync_data(tsd); + return 0; +} + +static CURLcode getaddrinfo_complete(struct Curl_easy *data) +{ + struct thread_sync_data *tsd = conn_thread_sync_data(data); + CURLcode result; + + result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res); + /* The tsd->res structure has been copied to async.dns and perhaps the DNS + cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it. + */ + tsd->res = NULL; + + return result; +} + +#ifdef _WIN32 +static VOID WINAPI +query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped) +{ + size_t ss_size; + const ADDRINFOEXW_ *ai; + struct Curl_addrinfo *ca; + struct Curl_addrinfo *cafirst = NULL; + struct Curl_addrinfo *calast = NULL; +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-align" +#endif + struct thread_sync_data *tsd = + CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + struct thread_data *td = tsd->td; + const ADDRINFOEXW_ *res = tsd->w8.res; + int error = (int)err; + (void)bytes; + + if(error == ERROR_SUCCESS) { + /* traverse the addrinfo list */ + + for(ai = res; ai != NULL; ai = ai->ai_next) { + size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0; + /* ignore elements with unsupported address family, */ + /* settle family-specific sockaddr structure size. */ + if(ai->ai_family == AF_INET) + ss_size = sizeof(struct sockaddr_in); +#ifdef ENABLE_IPV6 + else if(ai->ai_family == AF_INET6) + ss_size = sizeof(struct sockaddr_in6); +#endif + else + continue; + + /* ignore elements without required address info */ + if(!ai->ai_addr || !(ai->ai_addrlen > 0)) + continue; + + /* ignore elements with bogus address size */ + if((size_t)ai->ai_addrlen < ss_size) + continue; + + ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen); + if(!ca) { + error = EAI_MEMORY; + break; + } + + /* copy each structure member individually, member ordering, */ + /* size, or padding might be different for each platform. */ + ca->ai_flags = ai->ai_flags; + ca->ai_family = ai->ai_family; + ca->ai_socktype = ai->ai_socktype; + ca->ai_protocol = ai->ai_protocol; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_addr = NULL; + ca->ai_canonname = NULL; + ca->ai_next = NULL; + + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, ai->ai_addr, ss_size); + + if(namelen) { + size_t i; + ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size); + for(i = 0; i < namelen; ++i) /* convert wide string to ascii */ + ca->ai_canonname[i] = (char)ai->ai_canonname[i]; + ca->ai_canonname[namelen] = '\0'; + } + + /* if the return list is empty, this becomes the first element */ + if(!cafirst) + cafirst = ca; + + /* add this element last in the return list */ + if(calast) + calast->ai_next = ca; + calast = ca; + } + + /* if we failed, also destroy the Curl_addrinfo list */ + if(error) { + Curl_freeaddrinfo(cafirst); + cafirst = NULL; + } + else if(!cafirst) { +#ifdef EAI_NONAME + /* rfc3493 conformant */ + error = EAI_NONAME; +#else + /* rfc3493 obsoleted */ + error = EAI_NODATA; +#endif +#ifdef USE_WINSOCK + SET_SOCKERRNO(error); +#endif + } + tsd->res = cafirst; + } + + if(tsd->w8.res) { + Curl_FreeAddrInfoExW(tsd->w8.res); + tsd->w8.res = NULL; + } + + if(error) { + tsd->sock_error = SOCKERRNO?SOCKERRNO:error; + if(tsd->sock_error == 0) + tsd->sock_error = RESOLVER_ENOMEM; + } + else { + Curl_addrinfo_set_port(tsd->res, tsd->port); + } + + Curl_mutex_acquire(tsd->mtx); + if(tsd->done) { + /* too late, gotta clean up the mess */ + Curl_mutex_release(tsd->mtx); + destroy_thread_sync_data(tsd); + free(td); + } + else { +#ifndef CURL_DISABLE_SOCKETPAIR + char buf[1]; + if(tsd->sock_pair[1] != CURL_SOCKET_BAD) { + /* DNS has been resolved, signal client task */ + buf[0] = 1; + if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) { + /* update sock_erro to errno */ + tsd->sock_error = SOCKERRNO; + } + } +#endif + tsd->done = 1; + Curl_mutex_release(tsd->mtx); + if(td->complete_ev) + SetEvent(td->complete_ev); /* Notify caller that the query completed */ + } +} +#endif + +#ifdef HAVE_GETADDRINFO + +/* + * getaddrinfo_thread() resolves a name and then exits. + * + * For builds without ARES, but with ENABLE_IPV6, create a resolver thread + * and wait on it. + */ +static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg) +{ + struct thread_sync_data *tsd = (struct thread_sync_data *)arg; + struct thread_data *td = tsd->td; + char service[12]; + int rc; +#ifndef CURL_DISABLE_SOCKETPAIR + char buf[1]; +#endif + + msnprintf(service, sizeof(service), "%d", tsd->port); + + rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res); + + if(rc) { + tsd->sock_error = SOCKERRNO?SOCKERRNO:rc; + if(tsd->sock_error == 0) + tsd->sock_error = RESOLVER_ENOMEM; + } + else { + Curl_addrinfo_set_port(tsd->res, tsd->port); + } + + Curl_mutex_acquire(tsd->mtx); + if(tsd->done) { + /* too late, gotta clean up the mess */ + Curl_mutex_release(tsd->mtx); + destroy_thread_sync_data(tsd); + free(td); + } + else { +#ifndef CURL_DISABLE_SOCKETPAIR + if(tsd->sock_pair[1] != CURL_SOCKET_BAD) { + /* DNS has been resolved, signal client task */ + buf[0] = 1; + if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) { + /* update sock_erro to errno */ + tsd->sock_error = SOCKERRNO; + } + } +#endif + tsd->done = 1; + Curl_mutex_release(tsd->mtx); + } + + return 0; +} + +#else /* HAVE_GETADDRINFO */ + +/* + * gethostbyname_thread() resolves a name and then exits. + */ +static unsigned int CURL_STDCALL gethostbyname_thread(void *arg) +{ + struct thread_sync_data *tsd = (struct thread_sync_data *)arg; + struct thread_data *td = tsd->td; + + tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port); + + if(!tsd->res) { + tsd->sock_error = SOCKERRNO; + if(tsd->sock_error == 0) + tsd->sock_error = RESOLVER_ENOMEM; + } + + Curl_mutex_acquire(tsd->mtx); + if(tsd->done) { + /* too late, gotta clean up the mess */ + Curl_mutex_release(tsd->mtx); + destroy_thread_sync_data(tsd); + free(td); + } + else { + tsd->done = 1; + Curl_mutex_release(tsd->mtx); + } + + return 0; +} + +#endif /* HAVE_GETADDRINFO */ + +/* + * destroy_async_data() cleans up async resolver data and thread handle. + */ +static void destroy_async_data(struct Curl_async *async) +{ + if(async->tdata) { + struct thread_data *td = async->tdata; + int done; +#ifndef CURL_DISABLE_SOCKETPAIR + curl_socket_t sock_rd = td->tsd.sock_pair[0]; + struct Curl_easy *data = td->tsd.data; +#endif + + /* + * if the thread is still blocking in the resolve syscall, detach it and + * let the thread do the cleanup... + */ + Curl_mutex_acquire(td->tsd.mtx); + done = td->tsd.done; + td->tsd.done = 1; + Curl_mutex_release(td->tsd.mtx); + + if(!done) { +#ifdef _WIN32 + if(td->complete_ev) + CloseHandle(td->complete_ev); + else +#endif + Curl_thread_destroy(td->thread_hnd); + } + else { +#ifdef _WIN32 + if(td->complete_ev) { + Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev); + WaitForSingleObject(td->complete_ev, INFINITE); + CloseHandle(td->complete_ev); + } +#endif + if(td->thread_hnd != curl_thread_t_null) + Curl_thread_join(&td->thread_hnd); + + destroy_thread_sync_data(&td->tsd); + + free(async->tdata); + } +#ifndef CURL_DISABLE_SOCKETPAIR + /* + * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE + * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL + */ + Curl_multi_closed(data, sock_rd); + sclose(sock_rd); +#endif + } + async->tdata = NULL; + + free(async->hostname); + async->hostname = NULL; +} + +/* + * init_resolve_thread() starts a new thread that performs the actual + * resolve. This function returns before the resolve is done. + * + * Returns FALSE in case of failure, otherwise TRUE. + */ +static bool init_resolve_thread(struct Curl_easy *data, + const char *hostname, int port, + const struct addrinfo *hints) +{ + struct thread_data *td = calloc(1, sizeof(struct thread_data)); + int err = ENOMEM; + struct Curl_async *asp = &data->state.async; + + data->state.async.tdata = td; + if(!td) + goto errno_exit; + + asp->port = port; + asp->done = FALSE; + asp->status = 0; + asp->dns = NULL; + td->thread_hnd = curl_thread_t_null; +#ifdef _WIN32 + td->complete_ev = NULL; +#endif + + if(!init_thread_sync_data(td, hostname, port, hints)) { + asp->tdata = NULL; + free(td); + goto errno_exit; + } + + free(asp->hostname); + asp->hostname = strdup(hostname); + if(!asp->hostname) + goto err_exit; + + /* The thread will set this to 1 when complete. */ + td->tsd.done = 0; + +#ifdef _WIN32 + if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW && + Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) { +#define MAX_NAME_LEN 256 /* max domain name is 253 chars */ +#define MAX_PORT_LEN 8 + WCHAR namebuf[MAX_NAME_LEN]; + WCHAR portbuf[MAX_PORT_LEN]; + /* calculate required length */ + int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname, + -1, NULL, 0); + if((w_len > 0) && (w_len < MAX_NAME_LEN)) { + /* do utf8 conversion */ + w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len); + if((w_len > 0) && (w_len < MAX_NAME_LEN)) { + swprintf(portbuf, MAX_PORT_LEN, L"%d", port); + td->tsd.w8.hints.ai_family = hints->ai_family; + td->tsd.w8.hints.ai_socktype = hints->ai_socktype; + td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL); + if(!td->complete_ev) { + /* failed to start, mark it as done here for proper cleanup. */ + td->tsd.done = 1; + goto err_exit; + } + err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS, + NULL, &td->tsd.w8.hints, &td->tsd.w8.res, + NULL, &td->tsd.w8.overlapped, + &query_complete, &td->tsd.w8.cancel_ev); + if(err != WSA_IO_PENDING) + query_complete(err, 0, &td->tsd.w8.overlapped); + return TRUE; + } + } + } +#endif + +#ifdef HAVE_GETADDRINFO + td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); +#else + td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd); +#endif + + if(!td->thread_hnd) { + /* The thread never started, so mark it as done here for proper cleanup. */ + td->tsd.done = 1; + err = errno; + goto err_exit; + } + + return TRUE; + +err_exit: + destroy_async_data(asp); + +errno_exit: + errno = err; + return FALSE; +} + +/* + * 'entry' may be NULL and then no data is returned + */ +static CURLcode thread_wait_resolv(struct Curl_easy *data, + struct Curl_dns_entry **entry, + bool report) +{ + struct thread_data *td; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + td = data->state.async.tdata; + DEBUGASSERT(td); +#ifdef _WIN32 + DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null); +#else + DEBUGASSERT(td->thread_hnd != curl_thread_t_null); +#endif + + /* wait for the thread to resolve the name */ +#ifdef _WIN32 + if(td->complete_ev) { + WaitForSingleObject(td->complete_ev, INFINITE); + CloseHandle(td->complete_ev); + if(entry) + result = getaddrinfo_complete(data); + } + else +#endif + if(Curl_thread_join(&td->thread_hnd)) { + if(entry) + result = getaddrinfo_complete(data); + } + else + DEBUGASSERT(0); + + data->state.async.done = TRUE; + + if(entry) + *entry = data->state.async.dns; + + if(!data->state.async.dns && report) + /* a name was not resolved, report error */ + result = Curl_resolver_error(data); + + destroy_async_data(&data->state.async); + + if(!data->state.async.dns && report) + connclose(data->conn, "asynch resolve failed"); + + return result; +} + + +/* + * Until we gain a way to signal the resolver threads to stop early, we must + * simply wait for them and ignore their results. + */ +void Curl_resolver_kill(struct Curl_easy *data) +{ + struct thread_data *td = data->state.async.tdata; + + /* If we're still resolving, we must wait for the threads to fully clean up, + unfortunately. Otherwise, we can simply cancel to clean up any resolver + data. */ + if(td && td->thread_hnd != curl_thread_t_null + && (data->set.quick_exit != 1L)) + (void)thread_wait_resolv(data, NULL, FALSE); + else + Curl_resolver_cancel(data); +} + +/* + * Curl_resolver_wait_resolv() + * + * Waits for a resolve to finish. This function should be avoided since using + * this risk getting the multi interface to "hang". + * + * If 'entry' is non-NULL, make it point to the resolved dns entry + * + * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, + * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. + * + * This is the version for resolves-in-a-thread. + */ +CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, + struct Curl_dns_entry **entry) +{ + return thread_wait_resolv(data, entry, TRUE); +} + +/* + * Curl_resolver_is_resolved() is called repeatedly to check if a previous + * name resolve request has completed. It should also make sure to time-out if + * the operation seems to take too long. + */ +CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, + struct Curl_dns_entry **entry) +{ + struct thread_data *td = data->state.async.tdata; + int done = 0; + + DEBUGASSERT(entry); + *entry = NULL; + + if(!td) { + DEBUGASSERT(td); + return CURLE_COULDNT_RESOLVE_HOST; + } + + Curl_mutex_acquire(td->tsd.mtx); + done = td->tsd.done; + Curl_mutex_release(td->tsd.mtx); + + if(done) { + getaddrinfo_complete(data); + + if(!data->state.async.dns) { + CURLcode result = Curl_resolver_error(data); + destroy_async_data(&data->state.async); + return result; + } + destroy_async_data(&data->state.async); + *entry = data->state.async.dns; + } + else { + /* poll for name lookup done with exponential backoff up to 250ms */ + /* should be fine even if this converts to 32 bit */ + timediff_t elapsed = Curl_timediff(Curl_now(), + data->progress.t_startsingle); + if(elapsed < 0) + elapsed = 0; + + if(td->poll_interval == 0) + /* Start at 1ms poll interval */ + td->poll_interval = 1; + else if(elapsed >= td->interval_end) + /* Back-off exponentially if last interval expired */ + td->poll_interval *= 2; + + if(td->poll_interval > 250) + td->poll_interval = 250; + + td->interval_end = elapsed + td->poll_interval; + Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME); + } + + return CURLE_OK; +} + +int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks) +{ + int ret_val = 0; + timediff_t milli; + timediff_t ms; + struct resdata *reslv = (struct resdata *)data->state.async.resolver; +#ifndef CURL_DISABLE_SOCKETPAIR + struct thread_data *td = data->state.async.tdata; +#else + (void)socks; +#endif + +#ifndef CURL_DISABLE_SOCKETPAIR + if(td) { + /* return read fd to client for polling the DNS resolution status */ + socks[0] = td->tsd.sock_pair[0]; + td->tsd.data = data; + ret_val = GETSOCK_READSOCK(0); + } + else { +#endif + ms = Curl_timediff(Curl_now(), reslv->start); + if(ms < 3) + milli = 0; + else if(ms <= 50) + milli = ms/3; + else if(ms <= 250) + milli = 50; + else + milli = 200; + Curl_expire(data, milli, EXPIRE_ASYNC_NAME); +#ifndef CURL_DISABLE_SOCKETPAIR + } +#endif + + + return ret_val; +} + +#ifndef HAVE_GETADDRINFO +/* + * Curl_getaddrinfo() - for platforms without getaddrinfo + */ +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp) +{ + struct resdata *reslv = (struct resdata *)data->state.async.resolver; + + *waitp = 0; /* default to synchronous response */ + + reslv->start = Curl_now(); + + /* fire up a new resolver thread! */ + if(init_resolve_thread(data, hostname, port, NULL)) { + *waitp = 1; /* expect asynchronous response */ + return NULL; + } + + failf(data, "getaddrinfo() thread failed"); + + return NULL; +} + +#else /* !HAVE_GETADDRINFO */ + +/* + * Curl_resolver_getaddrinfo() - for getaddrinfo + */ +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp) +{ + struct addrinfo hints; + int pf = PF_INET; + struct resdata *reslv = (struct resdata *)data->state.async.resolver; + + *waitp = 0; /* default to synchronous response */ + +#ifdef CURLRES_IPV6 + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { + /* The stack seems to be IPv6-enabled */ + if(data->conn->ip_version == CURL_IPRESOLVE_V6) + pf = PF_INET6; + else + pf = PF_UNSPEC; + } +#endif /* CURLRES_IPV6 */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = pf; + hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)? + SOCK_STREAM : SOCK_DGRAM; + + reslv->start = Curl_now(); + /* fire up a new resolver thread! */ + if(init_resolve_thread(data, hostname, port, &hints)) { + *waitp = 1; /* expect asynchronous response */ + return NULL; + } + + failf(data, "getaddrinfo() thread failed to start"); + return NULL; + +} + +#endif /* !HAVE_GETADDRINFO */ + +CURLcode Curl_set_dns_servers(struct Curl_easy *data, + char *servers) +{ + (void)data; + (void)servers; + return CURLE_NOT_BUILT_IN; + +} + +CURLcode Curl_set_dns_interface(struct Curl_easy *data, + const char *interf) +{ + (void)data; + (void)interf; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, + const char *local_ip4) +{ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, + const char *local_ip6) +{ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +} + +#endif /* CURLRES_THREADED */ diff --git a/lib/asyn.h b/lib/asyn.h new file mode 100644 index 0000000..7e207c4 --- /dev/null +++ b/lib/asyn.h @@ -0,0 +1,184 @@ +#ifndef HEADER_CURL_ASYN_H +#define HEADER_CURL_ASYN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "curl_addrinfo.h" + +struct addrinfo; +struct hostent; +struct Curl_easy; +struct connectdata; +struct Curl_dns_entry; + +/* + * This header defines all functions in the internal asynch resolver interface. + * All asynch resolvers need to provide these functions. + * asyn-ares.c and asyn-thread.c are the current implementations of asynch + * resolver backends. + */ + +/* + * Curl_resolver_global_init() + * + * Called from curl_global_init() to initialize global resolver environment. + * Returning anything else than CURLE_OK fails curl_global_init(). + */ +int Curl_resolver_global_init(void); + +/* + * Curl_resolver_global_cleanup() + * Called from curl_global_cleanup() to destroy global resolver environment. + */ +void Curl_resolver_global_cleanup(void); + +/* + * Curl_resolver_init() + * Called from curl_easy_init() -> Curl_open() to initialize resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Should fill the passed pointer by the initialized handler. + * Returning anything else than CURLE_OK fails curl_easy_init() with the + * correspondent code. + */ +CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver); + +/* + * Curl_resolver_cleanup() + * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Should destroy the handler and free all resources connected to + * it. + */ +void Curl_resolver_cleanup(void *resolver); + +/* + * Curl_resolver_duphandle() + * Called from curl_easy_duphandle() to duplicate resolver URL-state specific + * environment ('resolver' member of the UrlState structure). Should + * duplicate the 'from' handle and pass the resulting handle to the 'to' + * pointer. Returning anything else than CURLE_OK causes failed + * curl_easy_duphandle() call. + */ +CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, + void *from); + +/* + * Curl_resolver_cancel(). + * + * It is called from inside other functions to cancel currently performing + * resolver request. Should also free any temporary resources allocated to + * perform a request. This never waits for resolver threads to complete. + * + * It is safe to call this when conn is in any state. + */ +void Curl_resolver_cancel(struct Curl_easy *data); + +/* + * Curl_resolver_kill(). + * + * This acts like Curl_resolver_cancel() except it will block until any threads + * associated with the resolver are complete. This never blocks for resolvers + * that do not use threads. This is intended to be the "last chance" function + * that cleans up an in-progress resolver completely (before its owner is about + * to die). + * + * It is safe to call this when conn is in any state. + */ +void Curl_resolver_kill(struct Curl_easy *data); + +/* Curl_resolver_getsock() + * + * This function is called from the multi_getsock() function. 'sock' is a + * pointer to an array to hold the file descriptors, with 'numsock' being the + * size of that array (in number of entries). This function is supposed to + * return bitmask indicating what file descriptors (referring to array indexes + * in the 'sock' array) to wait for, read/write. + */ +int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *sock); + +/* + * Curl_resolver_is_resolved() + * + * Called repeatedly to check if a previous name resolve request has + * completed. It should also make sure to time-out if the operation seems to + * take too long. + * + * Returns normal CURLcode errors. + */ +CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, + struct Curl_dns_entry **dns); + +/* + * Curl_resolver_wait_resolv() + * + * Waits for a resolve to finish. This function should be avoided since using + * this risk getting the multi interface to "hang". + * + * If 'entry' is non-NULL, make it point to the resolved dns entry + * + * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, + * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. + */ +CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, + struct Curl_dns_entry **dnsentry); + +/* + * Curl_resolver_getaddrinfo() - when using this resolver + * + * Returns name information about the given hostname and port number. If + * successful, the 'hostent' is returned and the fourth argument will point to + * memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + * + * Each resolver backend must of course make sure to return data in the + * correct format to comply with this. + */ +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp); + +#ifndef CURLRES_ASYNCH +/* convert these functions if an asynch resolver isn't used */ +#define Curl_resolver_cancel(x) Curl_nop_stmt +#define Curl_resolver_kill(x) Curl_nop_stmt +#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST +#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST +#define Curl_resolver_duphandle(x,y,z) CURLE_OK +#define Curl_resolver_init(x,y) CURLE_OK +#define Curl_resolver_global_init() CURLE_OK +#define Curl_resolver_global_cleanup() Curl_nop_stmt +#define Curl_resolver_cleanup(x) Curl_nop_stmt +#endif + +#ifdef CURLRES_ASYNCH +#define Curl_resolver_asynch() 1 +#else +#define Curl_resolver_asynch() 0 +#endif + + +/********** end of generic resolver interface functions *****************/ +#endif /* HEADER_CURL_ASYN_H */ diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 0000000..919eb62 --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,293 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* Base64 encoding/decoding */ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \ + !defined(CURL_DISABLE_LDAP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_POP3) || \ + !defined(CURL_DISABLE_IMAP) || \ + !defined(CURL_DISABLE_DIGEST_AUTH) || \ + !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || defined(BUILDING_CURL) +#include "curl/curl.h" +#include "warnless.h" +#include "curl_base64.h" + +/* The last 2 #include files should be in this order */ +#ifdef BUILDING_LIBCURL +#include "curl_memory.h" +#endif +#include "memdebug.h" + +/* ---- Base64 Encoding/Decoding Table --- */ +/* Padding character string starts at offset 64. */ +static const char base64encdec[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648 + section 5 */ +static const char base64url[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +static const unsigned char decodetable[] = +{ 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, + 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51 }; +/* + * Curl_base64_decode() + * + * Given a base64 NUL-terminated string at src, decode it and return a + * pointer in *outptr to a newly allocated memory area holding decoded + * data. Size of decoded data is returned in variable pointed by outlen. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * When decoded data length is 0, returns NULL in *outptr. + * + * @unittest: 1302 + */ +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen) +{ + size_t srclen = 0; + size_t padding = 0; + size_t i; + size_t numQuantums; + size_t fullQuantums; + size_t rawlen = 0; + unsigned char *pos; + unsigned char *newstr; + unsigned char lookup[256]; + + *outptr = NULL; + *outlen = 0; + srclen = strlen(src); + + /* Check the length of the input string is valid */ + if(!srclen || srclen % 4) + return CURLE_BAD_CONTENT_ENCODING; + + /* srclen is at least 4 here */ + while(src[srclen - 1 - padding] == '=') { + /* count padding characters */ + padding++; + /* A maximum of two = padding characters is allowed */ + if(padding > 2) + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Calculate the number of quantums */ + numQuantums = srclen / 4; + fullQuantums = numQuantums - (padding ? 1 : 0); + + /* Calculate the size of the decoded string */ + rawlen = (numQuantums * 3) - padding; + + /* Allocate our buffer including room for a null-terminator */ + newstr = malloc(rawlen + 1); + if(!newstr) + return CURLE_OUT_OF_MEMORY; + + pos = newstr; + + memset(lookup, 0xff, sizeof(lookup)); + memcpy(&lookup['+'], decodetable, sizeof(decodetable)); + /* replaces + { + unsigned char c; + const unsigned char *p = (const unsigned char *)base64encdec; + for(c = 0; *p; c++, p++) + lookup[*p] = c; + } + */ + + /* Decode the complete quantums first */ + for(i = 0; i < fullQuantums; i++) { + unsigned char val; + unsigned int x = 0; + int j; + + for(j = 0; j < 4; j++) { + val = lookup[(unsigned char)*src++]; + if(val == 0xff) /* bad symbol */ + goto bad; + x = (x << 6) | val; + } + pos[2] = x & 0xff; + pos[1] = (x >> 8) & 0xff; + pos[0] = (x >> 16) & 0xff; + pos += 3; + } + if(padding) { + /* this means either 8 or 16 bits output */ + unsigned char val; + unsigned int x = 0; + int j; + size_t padc = 0; + for(j = 0; j < 4; j++) { + if(*src == '=') { + x <<= 6; + src++; + if(++padc > padding) + /* this is a badly placed '=' symbol! */ + goto bad; + } + else { + val = lookup[(unsigned char)*src++]; + if(val == 0xff) /* bad symbol */ + goto bad; + x = (x << 6) | val; + } + } + if(padding == 1) + pos[1] = (x >> 8) & 0xff; + pos[0] = (x >> 16) & 0xff; + pos += 3 - padding; + } + + /* Zero terminate */ + *pos = '\0'; + + /* Return the decoded data */ + *outptr = newstr; + *outlen = rawlen; + + return CURLE_OK; +bad: + free(newstr); + return CURLE_BAD_CONTENT_ENCODING; +} + +static CURLcode base64_encode(const char *table64, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) +{ + char *output; + char *base64data; + const unsigned char *in = (unsigned char *)inputbuff; + const char *padstr = &table64[64]; /* Point to padding string. */ + + *outptr = NULL; + *outlen = 0; + + if(!insize) + insize = strlen(inputbuff); + +#if SIZEOF_SIZE_T == 4 + if(insize > UINT_MAX/4) + return CURLE_OUT_OF_MEMORY; +#endif + + base64data = output = malloc((insize + 2) / 3 * 4 + 1); + if(!output) + return CURLE_OUT_OF_MEMORY; + + while(insize >= 3) { + *output++ = table64[ in[0] >> 2 ]; + *output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ]; + *output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ]; + *output++ = table64[ in[2] & 0x3F ]; + insize -= 3; + in += 3; + } + if(insize) { + /* this is only one or two bytes now */ + *output++ = table64[ in[0] >> 2 ]; + if(insize == 1) { + *output++ = table64[ ((in[0] & 0x03) << 4) ]; + if(*padstr) { + *output++ = *padstr; + *output++ = *padstr; + } + } + else { + /* insize == 2 */ + *output++ = table64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4) ]; + *output++ = table64[ ((in[1] & 0x0F) << 2) ]; + if(*padstr) + *output++ = *padstr; + } + } + + /* Zero terminate */ + *output = '\0'; + + /* Return the pointer to the new data (allocated memory) */ + *outptr = base64data; + + /* Return the length of the new data */ + *outlen = output - base64data; + + return CURLE_OK; +} + +/* + * Curl_base64_encode() + * + * Given a pointer to an input buffer and an input size, encode it and + * return a pointer in *outptr to a newly allocated memory area holding + * encoded data. Size of encoded data is returned in variable pointed by + * outlen. + * + * Input length of 0 indicates input buffer holds a NUL-terminated string. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * @unittest: 1302 + */ +CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) +{ + return base64_encode(base64encdec, inputbuff, insize, outptr, outlen); +} + +/* + * Curl_base64url_encode() + * + * Given a pointer to an input buffer and an input size, encode it and + * return a pointer in *outptr to a newly allocated memory area holding + * encoded data. Size of encoded data is returned in variable pointed by + * outlen. + * + * Input length of 0 indicates input buffer holds a NUL-terminated string. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * @unittest: 1302 + */ +CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) +{ + return base64_encode(base64url, inputbuff, insize, outptr, outlen); +} + +#endif /* no users so disabled */ diff --git a/lib/bufq.c b/lib/bufq.c new file mode 100644 index 0000000..d03906d --- /dev/null +++ b/lib/bufq.c @@ -0,0 +1,656 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "bufq.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static bool chunk_is_empty(const struct buf_chunk *chunk) +{ + return chunk->r_offset >= chunk->w_offset; +} + +static bool chunk_is_full(const struct buf_chunk *chunk) +{ + return chunk->w_offset >= chunk->dlen; +} + +static size_t chunk_len(const struct buf_chunk *chunk) +{ + return chunk->w_offset - chunk->r_offset; +} + +static size_t chunk_space(const struct buf_chunk *chunk) +{ + return chunk->dlen - chunk->w_offset; +} + +static void chunk_reset(struct buf_chunk *chunk) +{ + chunk->next = NULL; + chunk->r_offset = chunk->w_offset = 0; +} + +static size_t chunk_append(struct buf_chunk *chunk, + const unsigned char *buf, size_t len) +{ + unsigned char *p = &chunk->x.data[chunk->w_offset]; + size_t n = chunk->dlen - chunk->w_offset; + DEBUGASSERT(chunk->dlen >= chunk->w_offset); + if(n) { + n = CURLMIN(n, len); + memcpy(p, buf, n); + chunk->w_offset += n; + } + return n; +} + +static size_t chunk_read(struct buf_chunk *chunk, + unsigned char *buf, size_t len) +{ + unsigned char *p = &chunk->x.data[chunk->r_offset]; + size_t n = chunk->w_offset - chunk->r_offset; + DEBUGASSERT(chunk->w_offset >= chunk->r_offset); + if(!n) { + return 0; + } + else if(n <= len) { + memcpy(buf, p, n); + chunk->r_offset = chunk->w_offset = 0; + return n; + } + else { + memcpy(buf, p, len); + chunk->r_offset += len; + return len; + } +} + +static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len, + Curl_bufq_reader *reader, + void *reader_ctx, CURLcode *err) +{ + unsigned char *p = &chunk->x.data[chunk->w_offset]; + size_t n = chunk->dlen - chunk->w_offset; /* free amount */ + ssize_t nread; + + DEBUGASSERT(chunk->dlen >= chunk->w_offset); + if(!n) { + *err = CURLE_AGAIN; + return -1; + } + if(max_len && n > max_len) + n = max_len; + nread = reader(reader_ctx, p, n, err); + if(nread > 0) { + DEBUGASSERT((size_t)nread <= n); + chunk->w_offset += nread; + } + return nread; +} + +static void chunk_peek(const struct buf_chunk *chunk, + const unsigned char **pbuf, size_t *plen) +{ + DEBUGASSERT(chunk->w_offset >= chunk->r_offset); + *pbuf = &chunk->x.data[chunk->r_offset]; + *plen = chunk->w_offset - chunk->r_offset; +} + +static void chunk_peek_at(const struct buf_chunk *chunk, size_t offset, + const unsigned char **pbuf, size_t *plen) +{ + offset += chunk->r_offset; + DEBUGASSERT(chunk->w_offset >= offset); + *pbuf = &chunk->x.data[offset]; + *plen = chunk->w_offset - offset; +} + +static size_t chunk_skip(struct buf_chunk *chunk, size_t amount) +{ + size_t n = chunk->w_offset - chunk->r_offset; + DEBUGASSERT(chunk->w_offset >= chunk->r_offset); + if(n) { + n = CURLMIN(n, amount); + chunk->r_offset += n; + if(chunk->r_offset == chunk->w_offset) + chunk->r_offset = chunk->w_offset = 0; + } + return n; +} + +static void chunk_list_free(struct buf_chunk **anchor) +{ + struct buf_chunk *chunk; + while(*anchor) { + chunk = *anchor; + *anchor = chunk->next; + free(chunk); + } +} + + + +void Curl_bufcp_init(struct bufc_pool *pool, + size_t chunk_size, size_t spare_max) +{ + DEBUGASSERT(chunk_size > 0); + DEBUGASSERT(spare_max > 0); + memset(pool, 0, sizeof(*pool)); + pool->chunk_size = chunk_size; + pool->spare_max = spare_max; +} + +static CURLcode bufcp_take(struct bufc_pool *pool, + struct buf_chunk **pchunk) +{ + struct buf_chunk *chunk = NULL; + + if(pool->spare) { + chunk = pool->spare; + pool->spare = chunk->next; + --pool->spare_count; + chunk_reset(chunk); + *pchunk = chunk; + return CURLE_OK; + } + + chunk = calloc(1, sizeof(*chunk) + pool->chunk_size); + if(!chunk) { + *pchunk = NULL; + return CURLE_OUT_OF_MEMORY; + } + chunk->dlen = pool->chunk_size; + *pchunk = chunk; + return CURLE_OK; +} + +static void bufcp_put(struct bufc_pool *pool, + struct buf_chunk *chunk) +{ + if(pool->spare_count >= pool->spare_max) { + free(chunk); + } + else { + chunk_reset(chunk); + chunk->next = pool->spare; + pool->spare = chunk; + ++pool->spare_count; + } +} + +void Curl_bufcp_free(struct bufc_pool *pool) +{ + chunk_list_free(&pool->spare); + pool->spare_count = 0; +} + +static void bufq_init(struct bufq *q, struct bufc_pool *pool, + size_t chunk_size, size_t max_chunks, int opts) +{ + DEBUGASSERT(chunk_size > 0); + DEBUGASSERT(max_chunks > 0); + memset(q, 0, sizeof(*q)); + q->chunk_size = chunk_size; + q->max_chunks = max_chunks; + q->pool = pool; + q->opts = opts; +} + +void Curl_bufq_init2(struct bufq *q, size_t chunk_size, size_t max_chunks, + int opts) +{ + bufq_init(q, NULL, chunk_size, max_chunks, opts); +} + +void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks) +{ + bufq_init(q, NULL, chunk_size, max_chunks, BUFQ_OPT_NONE); +} + +void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool, + size_t max_chunks, int opts) +{ + bufq_init(q, pool, pool->chunk_size, max_chunks, opts); +} + +void Curl_bufq_free(struct bufq *q) +{ + chunk_list_free(&q->head); + chunk_list_free(&q->spare); + q->tail = NULL; + q->chunk_count = 0; +} + +void Curl_bufq_reset(struct bufq *q) +{ + struct buf_chunk *chunk; + while(q->head) { + chunk = q->head; + q->head = chunk->next; + chunk->next = q->spare; + q->spare = chunk; + } + q->tail = NULL; +} + +size_t Curl_bufq_len(const struct bufq *q) +{ + const struct buf_chunk *chunk = q->head; + size_t len = 0; + while(chunk) { + len += chunk_len(chunk); + chunk = chunk->next; + } + return len; +} + +size_t Curl_bufq_space(const struct bufq *q) +{ + size_t space = 0; + if(q->tail) + space += chunk_space(q->tail); + if(q->spare) { + struct buf_chunk *chunk = q->spare; + while(chunk) { + space += chunk->dlen; + chunk = chunk->next; + } + } + if(q->chunk_count < q->max_chunks) { + space += (q->max_chunks - q->chunk_count) * q->chunk_size; + } + return space; +} + +bool Curl_bufq_is_empty(const struct bufq *q) +{ + return !q->head || chunk_is_empty(q->head); +} + +bool Curl_bufq_is_full(const struct bufq *q) +{ + if(!q->tail || q->spare) + return FALSE; + if(q->chunk_count < q->max_chunks) + return FALSE; + if(q->chunk_count > q->max_chunks) + return TRUE; + /* we have no spares and cannot make more, is the tail full? */ + return chunk_is_full(q->tail); +} + +static struct buf_chunk *get_spare(struct bufq *q) +{ + struct buf_chunk *chunk = NULL; + + if(q->spare) { + chunk = q->spare; + q->spare = chunk->next; + chunk_reset(chunk); + return chunk; + } + + if(q->chunk_count >= q->max_chunks && (!(q->opts & BUFQ_OPT_SOFT_LIMIT))) + return NULL; + + if(q->pool) { + if(bufcp_take(q->pool, &chunk)) + return NULL; + ++q->chunk_count; + return chunk; + } + else { + chunk = calloc(1, sizeof(*chunk) + q->chunk_size); + if(!chunk) + return NULL; + chunk->dlen = q->chunk_size; + ++q->chunk_count; + return chunk; + } +} + +static void prune_head(struct bufq *q) +{ + struct buf_chunk *chunk; + + while(q->head && chunk_is_empty(q->head)) { + chunk = q->head; + q->head = chunk->next; + if(q->tail == chunk) + q->tail = q->head; + if(q->pool) { + bufcp_put(q->pool, chunk); + --q->chunk_count; + } + else if((q->chunk_count > q->max_chunks) || + (q->opts & BUFQ_OPT_NO_SPARES)) { + /* SOFT_LIMIT allowed us more than max. free spares until + * we are at max again. Or free them if we are configured + * to not use spares. */ + free(chunk); + --q->chunk_count; + } + else { + chunk->next = q->spare; + q->spare = chunk; + } + } +} + +static struct buf_chunk *get_non_full_tail(struct bufq *q) +{ + struct buf_chunk *chunk; + + if(q->tail && !chunk_is_full(q->tail)) + return q->tail; + chunk = get_spare(q); + if(chunk) { + /* new tail, and possibly new head */ + if(q->tail) { + q->tail->next = chunk; + q->tail = chunk; + } + else { + DEBUGASSERT(!q->head); + q->head = q->tail = chunk; + } + } + return chunk; +} + +ssize_t Curl_bufq_write(struct bufq *q, + const unsigned char *buf, size_t len, + CURLcode *err) +{ + struct buf_chunk *tail; + ssize_t nwritten = 0; + size_t n; + + DEBUGASSERT(q->max_chunks > 0); + while(len) { + tail = get_non_full_tail(q); + if(!tail) { + if(q->chunk_count < q->max_chunks) { + *err = CURLE_OUT_OF_MEMORY; + return -1; + } + break; + } + n = chunk_append(tail, buf, len); + if(!n) + break; + nwritten += n; + buf += n; + len -= n; + } + if(nwritten == 0 && len) { + *err = CURLE_AGAIN; + return -1; + } + *err = CURLE_OK; + return nwritten; +} + +ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, + CURLcode *err) +{ + ssize_t nread = 0; + size_t n; + + *err = CURLE_OK; + while(len && q->head) { + n = chunk_read(q->head, buf, len); + if(n) { + nread += n; + buf += n; + len -= n; + } + prune_head(q); + } + if(nread == 0) { + *err = CURLE_AGAIN; + return -1; + } + return nread; +} + +bool Curl_bufq_peek(struct bufq *q, + const unsigned char **pbuf, size_t *plen) +{ + if(q->head && chunk_is_empty(q->head)) { + prune_head(q); + } + if(q->head && !chunk_is_empty(q->head)) { + chunk_peek(q->head, pbuf, plen); + return TRUE; + } + *pbuf = NULL; + *plen = 0; + return FALSE; +} + +bool Curl_bufq_peek_at(struct bufq *q, size_t offset, + const unsigned char **pbuf, size_t *plen) +{ + struct buf_chunk *c = q->head; + size_t clen; + + while(c) { + clen = chunk_len(c); + if(!clen) + break; + if(offset >= clen) { + offset -= clen; + c = c->next; + continue; + } + chunk_peek_at(c, offset, pbuf, plen); + return TRUE; + } + *pbuf = NULL; + *plen = 0; + return FALSE; +} + +void Curl_bufq_skip(struct bufq *q, size_t amount) +{ + size_t n; + + while(amount && q->head) { + n = chunk_skip(q->head, amount); + amount -= n; + prune_head(q); + } +} + +ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, + void *writer_ctx, CURLcode *err) +{ + const unsigned char *buf; + size_t blen; + ssize_t nwritten = 0; + + while(Curl_bufq_peek(q, &buf, &blen)) { + ssize_t chunk_written; + + chunk_written = writer(writer_ctx, buf, blen, err); + if(chunk_written < 0) { + if(!nwritten || *err != CURLE_AGAIN) { + /* blocked on first write or real error, fail */ + nwritten = -1; + } + break; + } + if(!chunk_written) { + if(!nwritten) { + /* treat as blocked */ + *err = CURLE_AGAIN; + nwritten = -1; + } + break; + } + Curl_bufq_skip(q, (size_t)chunk_written); + nwritten += chunk_written; + } + return nwritten; +} + +ssize_t Curl_bufq_write_pass(struct bufq *q, + const unsigned char *buf, size_t len, + Curl_bufq_writer *writer, void *writer_ctx, + CURLcode *err) +{ + ssize_t nwritten = 0, n; + + *err = CURLE_OK; + while(len) { + if(Curl_bufq_is_full(q)) { + /* try to make room in case we are full */ + n = Curl_bufq_pass(q, writer, writer_ctx, err); + if(n < 0) { + if(*err != CURLE_AGAIN) { + /* real error, fail */ + return -1; + } + /* would block, bufq is full, give up */ + break; + } + } + + /* Add whatever is remaining now to bufq */ + n = Curl_bufq_write(q, buf, len, err); + if(n < 0) { + if(*err != CURLE_AGAIN) { + /* real error, fail */ + return -1; + } + /* no room in bufq */ + break; + } + /* edge case of writer returning 0 (and len is >0) + * break or we might enter an infinite loop here */ + if(n == 0) + break; + + /* Maybe only part of `data` has been added, continue to loop */ + buf += (size_t)n; + len -= (size_t)n; + nwritten += (size_t)n; + } + + if(!nwritten && len) { + *err = CURLE_AGAIN; + return -1; + } + *err = CURLE_OK; + return nwritten; +} + +ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len, + Curl_bufq_reader *reader, void *reader_ctx, + CURLcode *err) +{ + struct buf_chunk *tail = NULL; + ssize_t nread; + + *err = CURLE_AGAIN; + tail = get_non_full_tail(q); + if(!tail) { + if(q->chunk_count < q->max_chunks) { + *err = CURLE_OUT_OF_MEMORY; + return -1; + } + /* full, blocked */ + *err = CURLE_AGAIN; + return -1; + } + + nread = chunk_slurpn(tail, max_len, reader, reader_ctx, err); + if(nread < 0) { + return -1; + } + else if(nread == 0) { + /* eof */ + *err = CURLE_OK; + } + return nread; +} + +/** + * Read up to `max_len` bytes and append it to the end of the buffer queue. + * if `max_len` is 0, no limit is imposed and the call behaves exactly + * the same as `Curl_bufq_slurp()`. + * Returns the total amount of buf read (may be 0) or -1 on other + * reader errors. + * Note that even in case of a -1 chunks may have been read and + * the buffer queue will have different length than before. + */ +static ssize_t bufq_slurpn(struct bufq *q, size_t max_len, + Curl_bufq_reader *reader, void *reader_ctx, + CURLcode *err) +{ + ssize_t nread = 0, n; + + *err = CURLE_AGAIN; + while(1) { + + n = Curl_bufq_sipn(q, max_len, reader, reader_ctx, err); + if(n < 0) { + if(!nread || *err != CURLE_AGAIN) { + /* blocked on first read or real error, fail */ + nread = -1; + } + else + *err = CURLE_OK; + break; + } + else if(n == 0) { + /* eof */ + *err = CURLE_OK; + break; + } + nread += (size_t)n; + if(max_len) { + DEBUGASSERT((size_t)n <= max_len); + max_len -= (size_t)n; + if(!max_len) + break; + } + /* give up slurping when we get less bytes than we asked for */ + if(q->tail && !chunk_is_full(q->tail)) + break; + } + return nread; +} + +ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, + void *reader_ctx, CURLcode *err) +{ + return bufq_slurpn(q, 0, reader, reader_ctx, err); +} diff --git a/lib/bufq.h b/lib/bufq.h new file mode 100644 index 0000000..089d61b --- /dev/null +++ b/lib/bufq.h @@ -0,0 +1,265 @@ +#ifndef HEADER_CURL_BUFQ_H +#define HEADER_CURL_BUFQ_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#include + +/** + * A chunk of bytes for reading and writing. + * The size is fixed a creation with read and write offset + * for where unread content is. + */ +struct buf_chunk { + struct buf_chunk *next; /* to keep it in a list */ + size_t dlen; /* the amount of allocated x.data[] */ + size_t r_offset; /* first unread bytes */ + size_t w_offset; /* one after last written byte */ + union { + unsigned char data[1]; /* the buffer for `dlen` bytes */ + void *dummy; /* alignment */ + } x; +}; + +/** + * A pool for providing/keeping a number of chunks of the same size + * + * The same pool can be shared by many `bufq` instances. However, a pool + * is not thread safe. All bufqs using it are supposed to operate in the + * same thread. + */ +struct bufc_pool { + struct buf_chunk *spare; /* list of available spare chunks */ + size_t chunk_size; /* the size of chunks in this pool */ + size_t spare_count; /* current number of spare chunks in list */ + size_t spare_max; /* max number of spares to keep */ +}; + +void Curl_bufcp_init(struct bufc_pool *pool, + size_t chunk_size, size_t spare_max); + +void Curl_bufcp_free(struct bufc_pool *pool); + +/** + * A queue of byte chunks for reading and writing. + * Reading is done from `head`, writing is done to `tail`. + * + * `bufq`s can be empty or full or neither. Its `len` is the number + * of bytes that can be read. For an empty bufq, `len` will be 0. + * + * By default, a bufq can hold up to `max_chunks * chunk_size` number + * of bytes. When `max_chunks` are used (in the `head` list) and the + * `tail` chunk is full, the bufq will report that it is full. + * + * On a full bufq, `len` may be less than the maximum number of bytes, + * e.g. when the head chunk is partially read. `len` may also become + * larger than the max when option `BUFQ_OPT_SOFT_LIMIT` is used. + * + * By default, writing to a full bufq will return (-1, CURLE_AGAIN). Same + * as reading from an empty bufq. + * With `BUFQ_OPT_SOFT_LIMIT` set, a bufq will allow writing becond this + * limit and use more than `max_chunks`. However it will report that it + * is full nevertheless. This is provided for situation where writes + * preferably never fail (except for memory exhaustion). + * + * By default and without a pool, a bufq will keep chunks that read + * read empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will + * disable that and free chunks once they become empty. + * + * When providing a pool to a bufq, all chunk creation and spare handling + * will be delegated to that pool. + */ +struct bufq { + struct buf_chunk *head; /* chunk with bytes to read from */ + struct buf_chunk *tail; /* chunk to write to */ + struct buf_chunk *spare; /* list of free chunks, unless `pool` */ + struct bufc_pool *pool; /* optional pool for free chunks */ + size_t chunk_count; /* current number of chunks in `head+spare` */ + size_t max_chunks; /* max `head` chunks to use */ + size_t chunk_size; /* size of chunks to manage */ + int opts; /* options for handling queue, see below */ +}; + +/** + * Default behaviour: chunk limit is "hard", meaning attempts to write + * more bytes than can be hold in `max_chunks` is refused and will return + * -1, CURLE_AGAIN. */ +#define BUFQ_OPT_NONE (0) +/** + * Make `max_chunks` a "soft" limit. A bufq will report that it is "full" + * when `max_chunks` are used, but allows writing beyond this limit. + */ +#define BUFQ_OPT_SOFT_LIMIT (1 << 0) +/** + * Do not keep spare chunks. + */ +#define BUFQ_OPT_NO_SPARES (1 << 1) + +/** + * Initialize a buffer queue that can hold up to `max_chunks` buffers + * each of size `chunk_size`. The bufq will not allow writing of + * more bytes than can be held in `max_chunks`. + */ +void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks); + +/** + * Initialize a buffer queue that can hold up to `max_chunks` buffers + * each of size `chunk_size` with the given options. See `BUFQ_OPT_*`. + */ +void Curl_bufq_init2(struct bufq *q, size_t chunk_size, + size_t max_chunks, int opts); + +void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool, + size_t max_chunks, int opts); + +/** + * Reset the buffer queue to be empty. Will keep any allocated buffer + * chunks around. + */ +void Curl_bufq_reset(struct bufq *q); + +/** + * Free all resources held by the buffer queue. + */ +void Curl_bufq_free(struct bufq *q); + +/** + * Return the total amount of data in the queue. + */ +size_t Curl_bufq_len(const struct bufq *q); + +/** + * Return the total amount of free space in the queue. + * The returned length is the number of bytes that can + * be expected to be written successfully to the bufq, + * providing no memory allocations fail. + */ +size_t Curl_bufq_space(const struct bufq *q); + +/** + * Returns TRUE iff there is no data in the buffer queue. + */ +bool Curl_bufq_is_empty(const struct bufq *q); + +/** + * Returns TRUE iff there is no space left in the buffer queue. + */ +bool Curl_bufq_is_full(const struct bufq *q); + +/** + * Write buf to the end of the buffer queue. The buf is copied + * and the amount of copied bytes is returned. + * A return code of -1 indicates an error, setting `err` to the + * cause. An err of CURLE_AGAIN is returned if the buffer queue is full. + */ +ssize_t Curl_bufq_write(struct bufq *q, + const unsigned char *buf, size_t len, + CURLcode *err); + +/** + * Read buf from the start of the buffer queue. The buf is copied + * and the amount of copied bytes is returned. + * A return code of -1 indicates an error, setting `err` to the + * cause. An err of CURLE_AGAIN is returned if the buffer queue is empty. + */ +ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, + CURLcode *err); + +/** + * Peek at the head chunk in the buffer queue. Returns a pointer to + * the chunk buf (at the current offset) and its length. Does not + * modify the buffer queue. + * Returns TRUE iff bytes are available. Sets `pbuf` to NULL and `plen` + * to 0 when no bytes are available. + * Repeated calls return the same information until the buffer queue + * is modified, see `Curl_bufq_skip()`` + */ +bool Curl_bufq_peek(struct bufq *q, + const unsigned char **pbuf, size_t *plen); + +bool Curl_bufq_peek_at(struct bufq *q, size_t offset, + const unsigned char **pbuf, size_t *plen); + +/** + * Tell the buffer queue to discard `amount` buf bytes at the head + * of the queue. Skipping more buf than is currently buffered will + * just empty the queue. + */ +void Curl_bufq_skip(struct bufq *q, size_t amount); + +typedef ssize_t Curl_bufq_writer(void *writer_ctx, + const unsigned char *buf, size_t len, + CURLcode *err); +/** + * Passes the chunks in the buffer queue to the writer and returns + * the amount of buf written. A writer may return -1 and CURLE_AGAIN + * to indicate blocking at which point the queue will stop and return + * the amount of buf passed so far. + * -1 is returned on any other errors reported by the writer. + * Note that in case of a -1 chunks may have been written and + * the buffer queue will have different length than before. + */ +ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, + void *writer_ctx, CURLcode *err); + +typedef ssize_t Curl_bufq_reader(void *reader_ctx, + unsigned char *buf, size_t len, + CURLcode *err); + +/** + * Read date and append it to the end of the buffer queue until the + * reader returns blocking or the queue is full. A reader returns + * -1 and CURLE_AGAIN to indicate blocking. + * Returns the total amount of buf read (may be 0) or -1 on other + * reader errors. + * Note that in case of a -1 chunks may have been read and + * the buffer queue will have different length than before. + */ +ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, + void *reader_ctx, CURLcode *err); + +/** + * Read *once* up to `max_len` bytes and append it to the buffer. + * if `max_len` is 0, no limit is imposed besides the chunk space. + * Returns the total amount of buf read (may be 0) or -1 on other + * reader errors. + */ +ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len, + Curl_bufq_reader *reader, void *reader_ctx, + CURLcode *err); + +/** + * Write buf to the end of the buffer queue. + * Will write bufq content or passed `buf` directly using the `writer` + * callback when it sees fit. 'buf' might get passed directly + * on or is placed into the buffer, depending on `len` and current + * amount buffered, chunk size, etc. + */ +ssize_t Curl_bufq_write_pass(struct bufq *q, + const unsigned char *buf, size_t len, + Curl_bufq_writer *writer, void *writer_ctx, + CURLcode *err); + +#endif /* HEADER_CURL_BUFQ_H */ diff --git a/lib/bufref.c b/lib/bufref.c new file mode 100644 index 0000000..f0a0e2a --- /dev/null +++ b/lib/bufref.c @@ -0,0 +1,127 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "urldata.h" +#include "bufref.h" +#include "strdup.h" + +#include "curl_memory.h" +#include "memdebug.h" + +#define SIGNATURE 0x5c48e9b2 /* Random pattern. */ + +/* + * Init a bufref struct. + */ +void Curl_bufref_init(struct bufref *br) +{ + DEBUGASSERT(br); + br->dtor = NULL; + br->ptr = NULL; + br->len = 0; + +#ifdef DEBUGBUILD + br->signature = SIGNATURE; +#endif +} + +/* + * Free the buffer and re-init the necessary fields. It doesn't touch the + * 'signature' field and thus this buffer reference can be reused. + */ + +void Curl_bufref_free(struct bufref *br) +{ + DEBUGASSERT(br); + DEBUGASSERT(br->signature == SIGNATURE); + DEBUGASSERT(br->ptr || !br->len); + + if(br->ptr && br->dtor) + br->dtor((void *) br->ptr); + + br->dtor = NULL; + br->ptr = NULL; + br->len = 0; +} + +/* + * Set the buffer reference to new values. The previously referenced buffer + * is released before assignment. + */ +void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len, + void (*dtor)(void *)) +{ + DEBUGASSERT(ptr || !len); + DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH); + + Curl_bufref_free(br); + br->ptr = (const unsigned char *) ptr; + br->len = len; + br->dtor = dtor; +} + +/* + * Get a pointer to the referenced buffer. + */ +const unsigned char *Curl_bufref_ptr(const struct bufref *br) +{ + DEBUGASSERT(br); + DEBUGASSERT(br->signature == SIGNATURE); + DEBUGASSERT(br->ptr || !br->len); + + return br->ptr; +} + +/* + * Get the length of the referenced buffer data. + */ +size_t Curl_bufref_len(const struct bufref *br) +{ + DEBUGASSERT(br); + DEBUGASSERT(br->signature == SIGNATURE); + DEBUGASSERT(br->ptr || !br->len); + + return br->len; +} + +CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len) +{ + unsigned char *cpy = NULL; + + DEBUGASSERT(br); + DEBUGASSERT(br->signature == SIGNATURE); + DEBUGASSERT(br->ptr || !br->len); + DEBUGASSERT(ptr || !len); + DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH); + + if(ptr) { + cpy = Curl_memdup0(ptr, len); + if(!cpy) + return CURLE_OUT_OF_MEMORY; + } + + Curl_bufref_set(br, cpy, len, curl_free); + return CURLE_OK; +} diff --git a/lib/bufref.h b/lib/bufref.h new file mode 100644 index 0000000..dd424f1 --- /dev/null +++ b/lib/bufref.h @@ -0,0 +1,48 @@ +#ifndef HEADER_CURL_BUFREF_H +#define HEADER_CURL_BUFREF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Generic buffer reference. + */ +struct bufref { + void (*dtor)(void *); /* Associated destructor. */ + const unsigned char *ptr; /* Referenced data buffer. */ + size_t len; /* The data size in bytes. */ +#ifdef DEBUGBUILD + int signature; /* Detect API use mistakes. */ +#endif +}; + + +void Curl_bufref_init(struct bufref *br); +void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len, + void (*dtor)(void *)); +const unsigned char *Curl_bufref_ptr(const struct bufref *br); +size_t Curl_bufref_len(const struct bufref *br); +CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len); +void Curl_bufref_free(struct bufref *br); + +#endif diff --git a/lib/c-hyper.c b/lib/c-hyper.c new file mode 100644 index 0000000..d02ecd7 --- /dev/null +++ b/lib/c-hyper.c @@ -0,0 +1,1250 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* Curl's integration with Hyper. This replaces certain functions in http.c, + * based on configuration #defines. This implementation supports HTTP/1.1 but + * not HTTP/2. + */ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "transfer.h" +#include "multiif.h" +#include "progress.h" +#include "content_encoding.h" +#include "ws.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +typedef enum { + USERDATA_NOT_SET = 0, /* for tasks with no userdata set; must be zero */ + USERDATA_RESP_BODY +} userdata_t; + +size_t Curl_hyper_recv(void *userp, hyper_context *ctx, + uint8_t *buf, size_t buflen) +{ + struct Curl_easy *data = userp; + struct connectdata *conn = data->conn; + CURLcode result; + ssize_t nread; + DEBUGASSERT(conn); + (void)ctx; + + DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen)); + result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread); + if(result == CURLE_AGAIN) { + /* would block, register interest */ + DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen)); + if(data->hyp.read_waker) + hyper_waker_free(data->hyp.read_waker); + data->hyp.read_waker = hyper_context_waker(ctx); + if(!data->hyp.read_waker) { + failf(data, "Couldn't make the read hyper_context_waker"); + return HYPER_IO_ERROR; + } + return HYPER_IO_PENDING; + } + else if(result) { + failf(data, "Curl_read failed"); + return HYPER_IO_ERROR; + } + DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> %zd", buflen, nread)); + return (size_t)nread; +} + +size_t Curl_hyper_send(void *userp, hyper_context *ctx, + const uint8_t *buf, size_t buflen) +{ + struct Curl_easy *data = userp; + struct connectdata *conn = data->conn; + CURLcode result; + ssize_t nwrote; + + DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen)); + result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote); + if(!result && !nwrote) + result = CURLE_AGAIN; + if(result == CURLE_AGAIN) { + DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen)); + /* would block, register interest */ + if(data->hyp.write_waker) + hyper_waker_free(data->hyp.write_waker); + data->hyp.write_waker = hyper_context_waker(ctx); + if(!data->hyp.write_waker) { + failf(data, "Couldn't make the write hyper_context_waker"); + return HYPER_IO_ERROR; + } + return HYPER_IO_PENDING; + } + else if(result) { + failf(data, "Curl_write failed"); + return HYPER_IO_ERROR; + } + DEBUGF(infof(data, "Curl_hyper_send(%zu) -> %zd", buflen, nwrote)); + return (size_t)nwrote; +} + +static int hyper_each_header(void *userdata, + const uint8_t *name, + size_t name_len, + const uint8_t *value, + size_t value_len) +{ + struct Curl_easy *data = (struct Curl_easy *)userdata; + size_t len; + char *headp; + CURLcode result; + int writetype; + + if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) { + failf(data, "Too long response header"); + data->state.hresult = CURLE_TOO_LARGE; + return HYPER_ITER_BREAK; + } + + if(!data->req.bytecount) + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + + Curl_dyn_reset(&data->state.headerb); + if(name_len) { + if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n", + (int) name_len, name, (int) value_len, value)) + return HYPER_ITER_BREAK; + } + else { + if(Curl_dyn_addn(&data->state.headerb, STRCONST("\r\n"))) + return HYPER_ITER_BREAK; + } + len = Curl_dyn_len(&data->state.headerb); + headp = Curl_dyn_ptr(&data->state.headerb); + + result = Curl_http_header(data, data->conn, headp); + if(result) { + data->state.hresult = result; + return HYPER_ITER_BREAK; + } + + Curl_debug(data, CURLINFO_HEADER_IN, headp, len); + + writetype = CLIENTWRITE_HEADER; + if(data->state.hconnect) + writetype |= CLIENTWRITE_CONNECT; + if(data->req.httpcode/100 == 1) + writetype |= CLIENTWRITE_1XX; + result = Curl_client_write(data, writetype, headp, len); + if(result) { + data->state.hresult = CURLE_ABORTED_BY_CALLBACK; + return HYPER_ITER_BREAK; + } + + result = Curl_bump_headersize(data, len, FALSE); + if(result) { + data->state.hresult = result; + return HYPER_ITER_BREAK; + } + return HYPER_ITER_CONTINUE; +} + +static int hyper_body_chunk(void *userdata, const hyper_buf *chunk) +{ + char *buf = (char *)hyper_buf_bytes(chunk); + size_t len = hyper_buf_len(chunk); + struct Curl_easy *data = (struct Curl_easy *)userdata; + struct SingleRequest *k = &data->req; + CURLcode result = CURLE_OK; + + if(0 == k->bodywrites) { + bool done = FALSE; +#if defined(USE_NTLM) + struct connectdata *conn = data->conn; + if(conn->bits.close && + (((data->req.httpcode == 401) && + (conn->http_ntlm_state == NTLMSTATE_TYPE2)) || + ((data->req.httpcode == 407) && + (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) { + infof(data, "Connection closed while negotiating NTLM"); + data->state.authproblem = TRUE; + Curl_safefree(data->req.newurl); + } +#endif + if(data->state.expect100header) { + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + if(data->req.httpcode < 400) { + k->exp100 = EXP100_SEND_DATA; + if(data->hyp.exp100_waker) { + hyper_waker_wake(data->hyp.exp100_waker); + data->hyp.exp100_waker = NULL; + } + } + else { /* >= 4xx */ + k->exp100 = EXP100_FAILED; + } + } + if(data->state.hconnect && (data->req.httpcode/100 != 2) && + data->state.authproxy.done) { + done = TRUE; + result = CURLE_OK; + } + else + result = Curl_http_firstwrite(data, data->conn, &done); + if(result || done) { + infof(data, "Return early from hyper_body_chunk"); + data->state.hresult = result; + return HYPER_ITER_BREAK; + } + } + result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len); + + if(result) { + data->state.hresult = result; + return HYPER_ITER_BREAK; + } + + return HYPER_ITER_CONTINUE; +} + +/* + * Hyper does not consider the status line, the first line in an HTTP/1 + * response, to be a header. The libcurl API does. This function sends the + * status line in the header callback. */ +static CURLcode status_line(struct Curl_easy *data, + struct connectdata *conn, + uint16_t http_status, + int http_version, + const uint8_t *reason, size_t rlen) +{ + CURLcode result; + size_t len; + const char *vstr; + int writetype; + vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" : + (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0"); + + /* We need to set 'httpcodeq' for functions that check the response code in + a single place. */ + data->req.httpcode = http_status; + + if(data->state.hconnect) + /* CONNECT */ + data->info.httpproxycode = http_status; + else { + conn->httpversion = + http_version == HYPER_HTTP_VERSION_1_1 ? 11 : + (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10); + if(http_version == HYPER_HTTP_VERSION_1_0) + data->state.httpwant = CURL_HTTP_VERSION_1_0; + + result = Curl_http_statusline(data, conn); + if(result) + return result; + } + + Curl_dyn_reset(&data->state.headerb); + + result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n", + vstr, + (int)http_status, + (int)rlen, reason); + if(result) + return result; + len = Curl_dyn_len(&data->state.headerb); + Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb), + len); + + writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS; + if(data->state.hconnect) + writetype |= CLIENTWRITE_CONNECT; + result = Curl_client_write(data, writetype, + Curl_dyn_ptr(&data->state.headerb), len); + if(result) + return result; + + result = Curl_bump_headersize(data, len, FALSE); + return result; +} + +/* + * Hyper does not pass on the last empty response header. The libcurl API + * does. This function sends an empty header in the header callback. + */ +static CURLcode empty_header(struct Curl_easy *data) +{ + CURLcode result = Curl_http_size(data); + if(!result) { + result = hyper_each_header(data, NULL, 0, NULL, 0) ? + CURLE_WRITE_ERROR : CURLE_OK; + if(result) + failf(data, "hyperstream: couldn't pass blank header"); + /* Hyper does chunked decoding itself. If it was added during + * response header processing, remove it again. */ + Curl_cwriter_remove_by_name(data, "chunked"); + } + return result; +} + +CURLcode Curl_hyper_stream(struct Curl_easy *data, + struct connectdata *conn, + int *didwhat, + bool *done, + int select_res) +{ + hyper_response *resp = NULL; + uint16_t http_status; + int http_version; + hyper_headers *headers = NULL; + hyper_body *resp_body = NULL; + struct hyptransfer *h = &data->hyp; + hyper_task *task; + hyper_task *foreach; + const uint8_t *reasonp; + size_t reason_len; + CURLcode result = CURLE_OK; + struct SingleRequest *k = &data->req; + (void)conn; + + if(k->exp100 > EXP100_SEND_DATA) { + struct curltime now = Curl_now(); + timediff_t ms = Curl_timediff(now, k->start100); + if(ms >= data->set.expect_100_timeout) { + /* we've waited long enough, continue anyway */ + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + infof(data, "Done waiting for 100-continue"); + if(data->hyp.exp100_waker) { + hyper_waker_wake(data->hyp.exp100_waker); + data->hyp.exp100_waker = NULL; + } + } + } + + if(select_res & CURL_CSELECT_IN) { + if(h->read_waker) + hyper_waker_wake(h->read_waker); + h->read_waker = NULL; + } + if(select_res & CURL_CSELECT_OUT) { + if(h->write_waker) + hyper_waker_wake(h->write_waker); + h->write_waker = NULL; + } + + *done = FALSE; + do { + hyper_task_return_type t; + task = hyper_executor_poll(h->exec); + if(!task) { + *didwhat = KEEP_RECV; + break; + } + t = hyper_task_type(task); + if(t == HYPER_TASK_ERROR) { + hyper_error *hypererr = hyper_task_value(task); + hyper_task_free(task); + if(data->state.hresult) { + /* override Hyper's view, might not even be an error */ + result = data->state.hresult; + infof(data, "hyperstream is done (by early callback)"); + } + else { + uint8_t errbuf[256]; + size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf)); + hyper_code code = hyper_error_code(hypererr); + failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf); + switch(code) { + case HYPERE_ABORTED_BY_CALLBACK: + result = CURLE_OK; + break; + case HYPERE_UNEXPECTED_EOF: + if(!data->req.bytecount) + result = CURLE_GOT_NOTHING; + else + result = CURLE_RECV_ERROR; + break; + case HYPERE_INVALID_PEER_MESSAGE: + /* bump headerbytecount to avoid the count remaining at zero and + appearing to not having read anything from the peer at all */ + data->req.headerbytecount++; + result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */ + break; + default: + result = CURLE_RECV_ERROR; + break; + } + } + *done = TRUE; + hyper_error_free(hypererr); + break; + } + else if(t == HYPER_TASK_EMPTY) { + void *userdata = hyper_task_userdata(task); + hyper_task_free(task); + if((userdata_t)userdata == USERDATA_RESP_BODY) { + /* end of transfer */ + *done = TRUE; + infof(data, "hyperstream is done"); + if(!k->bodywrites) { + /* hyper doesn't always call the body write callback */ + bool stilldone; + result = Curl_http_firstwrite(data, data->conn, &stilldone); + } + break; + } + else { + /* A background task for hyper; ignore */ + continue; + } + } + + DEBUGASSERT(HYPER_TASK_RESPONSE); + + resp = hyper_task_value(task); + hyper_task_free(task); + + *didwhat = KEEP_RECV; + if(!resp) { + failf(data, "hyperstream: couldn't get response"); + return CURLE_RECV_ERROR; + } + + http_status = hyper_response_status(resp); + http_version = hyper_response_version(resp); + reasonp = hyper_response_reason_phrase(resp); + reason_len = hyper_response_reason_phrase_len(resp); + + if(http_status == 417 && data->state.expect100header) { + infof(data, "Got 417 while waiting for a 100"); + data->state.disableexpect = TRUE; + data->req.newurl = strdup(data->state.url); + Curl_done_sending(data, k); + } + + result = status_line(data, conn, + http_status, http_version, reasonp, reason_len); + if(result) + break; + + headers = hyper_response_headers(resp); + if(!headers) { + failf(data, "hyperstream: couldn't get response headers"); + result = CURLE_RECV_ERROR; + break; + } + + /* the headers are already received */ + hyper_headers_foreach(headers, hyper_each_header, data); + if(data->state.hresult) { + result = data->state.hresult; + break; + } + + result = empty_header(data); + if(result) + break; + + k->deductheadercount = + (100 <= http_status && 199 >= http_status)?k->headerbytecount:0; +#ifdef USE_WEBSOCKETS + if(k->upgr101 == UPGR101_WS) { + if(http_status == 101) { + /* verify the response */ + result = Curl_ws_accept(data, NULL, 0); + if(result) + return result; + } + else { + failf(data, "Expected 101, got %u", k->httpcode); + result = CURLE_HTTP_RETURNED_ERROR; + break; + } + } +#endif + + /* Curl_http_auth_act() checks what authentication methods that are + * available and decides which one (if any) to use. It will set 'newurl' + * if an auth method was picked. */ + result = Curl_http_auth_act(data); + if(result) + break; + + resp_body = hyper_response_body(resp); + if(!resp_body) { + failf(data, "hyperstream: couldn't get response body"); + result = CURLE_RECV_ERROR; + break; + } + foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data); + if(!foreach) { + failf(data, "hyperstream: body foreach failed"); + result = CURLE_OUT_OF_MEMORY; + break; + } + hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY); + if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) { + failf(data, "Couldn't hyper_executor_push the body-foreach"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + hyper_response_free(resp); + resp = NULL; + } while(1); + if(resp) + hyper_response_free(resp); + return result; +} + +static CURLcode debug_request(struct Curl_easy *data, + const char *method, + const char *path) +{ + char *req = aprintf("%s %s HTTP/1.1\r\n", method, path); + if(!req) + return CURLE_OUT_OF_MEMORY; + Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req)); + free(req); + return CURLE_OK; +} + +/* + * Given a full header line "name: value" (optional CRLF in the input, should + * be in the output), add to Hyper and send to the debug callback. + * + * Supports multiple headers. + */ + +CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers, + const char *line) +{ + const char *p; + const char *n; + size_t nlen; + const char *v; + size_t vlen; + bool newline = TRUE; + int numh = 0; + + if(!line) + return CURLE_OK; + n = line; + do { + size_t linelen = 0; + + p = strchr(n, ':'); + if(!p) + /* this is fine if we already added at least one header */ + return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT; + nlen = p - n; + p++; /* move past the colon */ + while(*p == ' ') + p++; + v = p; + p = strchr(v, '\r'); + if(!p) { + p = strchr(v, '\n'); + if(p) + linelen = 1; /* LF only */ + else { + p = strchr(v, '\0'); + newline = FALSE; /* no newline */ + } + } + else + linelen = 2; /* CRLF ending */ + linelen += (p - n); + vlen = p - v; + + if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen, + (uint8_t *)v, vlen)) { + failf(data, "hyper refused to add header '%s'", line); + return CURLE_OUT_OF_MEMORY; + } + if(data->set.verbose) { + char *ptr = NULL; + if(!newline) { + ptr = aprintf("%.*s\r\n", (int)linelen, line); + if(!ptr) + return CURLE_OUT_OF_MEMORY; + Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2); + free(ptr); + } + else + Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen); + } + numh++; + n += linelen; + } while(newline); + return CURLE_OK; +} + +static CURLcode request_target(struct Curl_easy *data, + struct connectdata *conn, + const char *method, + hyper_request *req) +{ + CURLcode result; + struct dynbuf r; + + Curl_dyn_init(&r, DYN_HTTP_REQUEST); + + result = Curl_http_target(data, conn, &r); + if(result) + return result; + + if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r), + Curl_dyn_len(&r))) { + failf(data, "error setting uri to hyper"); + result = CURLE_OUT_OF_MEMORY; + } + else + result = debug_request(data, method, Curl_dyn_ptr(&r)); + + Curl_dyn_free(&r); + + return result; +} + +static int uploadpostfields(void *userdata, hyper_context *ctx, + hyper_buf **chunk) +{ + struct Curl_easy *data = (struct Curl_easy *)userdata; + (void)ctx; + if(data->req.exp100 > EXP100_SEND_DATA) { + if(data->req.exp100 == EXP100_FAILED) + return HYPER_POLL_ERROR; + + /* still waiting confirmation */ + if(data->hyp.exp100_waker) + hyper_waker_free(data->hyp.exp100_waker); + data->hyp.exp100_waker = hyper_context_waker(ctx); + return HYPER_POLL_PENDING; + } + if(data->req.upload_done) + *chunk = NULL; /* nothing more to deliver */ + else { + /* send everything off in a single go */ + hyper_buf *copy = hyper_buf_copy(data->set.postfields, + (size_t)data->req.p.http->postsize); + if(copy) + *chunk = copy; + else { + data->state.hresult = CURLE_OUT_OF_MEMORY; + return HYPER_POLL_ERROR; + } + /* increasing the writebytecount here is a little premature but we + don't know exactly when the body is sent */ + data->req.writebytecount += (size_t)data->req.p.http->postsize; + Curl_pgrsSetUploadCounter(data, data->req.writebytecount); + data->req.upload_done = TRUE; + } + return HYPER_POLL_READY; +} + +static int uploadstreamed(void *userdata, hyper_context *ctx, + hyper_buf **chunk) +{ + size_t fillcount; + struct Curl_easy *data = (struct Curl_easy *)userdata; + struct connectdata *conn = (struct connectdata *)data->conn; + CURLcode result; + (void)ctx; + + if(data->req.exp100 > EXP100_SEND_DATA) { + if(data->req.exp100 == EXP100_FAILED) + return HYPER_POLL_ERROR; + + /* still waiting confirmation */ + if(data->hyp.exp100_waker) + hyper_waker_free(data->hyp.exp100_waker); + data->hyp.exp100_waker = hyper_context_waker(ctx); + return HYPER_POLL_PENDING; + } + + if(data->req.upload_chunky && conn->bits.authneg) { + fillcount = 0; + data->req.upload_chunky = FALSE; + result = CURLE_OK; + } + else { + result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, + &fillcount); + } + if(result) { + data->state.hresult = result; + return HYPER_POLL_ERROR; + } + if(!fillcount) { + if((data->req.keepon & KEEP_SEND_PAUSE) != KEEP_SEND_PAUSE) + /* done! */ + *chunk = NULL; + else { + /* paused, save a waker */ + if(data->hyp.send_body_waker) + hyper_waker_free(data->hyp.send_body_waker); + data->hyp.send_body_waker = hyper_context_waker(ctx); + return HYPER_POLL_PENDING; + } + } + else { + hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount); + if(copy) + *chunk = copy; + else { + data->state.hresult = CURLE_OUT_OF_MEMORY; + return HYPER_POLL_ERROR; + } + /* increasing the writebytecount here is a little premature but we + don't know exactly when the body is sent */ + data->req.writebytecount += fillcount; + Curl_pgrsSetUploadCounter(data, data->req.writebytecount); + } + return HYPER_POLL_READY; +} + +/* + * bodysend() sets up headers in the outgoing request for an HTTP transfer that + * sends a body + */ + +static CURLcode bodysend(struct Curl_easy *data, + struct connectdata *conn, + hyper_headers *headers, + hyper_request *hyperreq, + Curl_HttpReq httpreq) +{ + struct HTTP *http = data->req.p.http; + CURLcode result = CURLE_OK; + struct dynbuf req; + if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) + Curl_pgrsSetUploadSize(data, 0); /* no request body */ + else { + hyper_body *body; + Curl_dyn_init(&req, DYN_HTTP_REQUEST); + result = Curl_http_bodysend(data, conn, &req, httpreq); + + if(!result) + result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req)); + + Curl_dyn_free(&req); + + body = hyper_body_new(); + hyper_body_set_userdata(body, data); + if(data->set.postfields) + hyper_body_set_data_func(body, uploadpostfields); + else { + result = Curl_get_upload_buffer(data); + if(result) { + hyper_body_free(body); + return result; + } + /* init the "upload from here" pointer */ + data->req.upload_fromhere = data->state.ulbuf; + hyper_body_set_data_func(body, uploadstreamed); + } + if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) { + /* fail */ + result = CURLE_OUT_OF_MEMORY; + } + } + http->sending = HTTPSEND_BODY; + return result; +} + +static CURLcode cookies(struct Curl_easy *data, + struct connectdata *conn, + hyper_headers *headers) +{ + struct dynbuf req; + CURLcode result; + Curl_dyn_init(&req, DYN_HTTP_REQUEST); + + result = Curl_http_cookies(data, conn, &req); + if(!result) + result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req)); + Curl_dyn_free(&req); + return result; +} + +/* called on 1xx responses */ +static void http1xx_cb(void *arg, struct hyper_response *resp) +{ + struct Curl_easy *data = (struct Curl_easy *)arg; + hyper_headers *headers = NULL; + CURLcode result = CURLE_OK; + uint16_t http_status; + int http_version; + const uint8_t *reasonp; + size_t reason_len; + + infof(data, "Got HTTP 1xx informational"); + + http_status = hyper_response_status(resp); + http_version = hyper_response_version(resp); + reasonp = hyper_response_reason_phrase(resp); + reason_len = hyper_response_reason_phrase_len(resp); + + result = status_line(data, data->conn, + http_status, http_version, reasonp, reason_len); + if(!result) { + headers = hyper_response_headers(resp); + if(!headers) { + failf(data, "hyperstream: couldn't get 1xx response headers"); + result = CURLE_RECV_ERROR; + } + } + data->state.hresult = result; + + if(!result) { + /* the headers are already received */ + hyper_headers_foreach(headers, hyper_each_header, data); + /* this callback also sets data->state.hresult on error */ + + if(empty_header(data)) + result = CURLE_OUT_OF_MEMORY; + } + + if(data->state.hresult) + infof(data, "ERROR in 1xx, bail out"); +} + +/* + * Curl_http() gets called from the generic multi_do() function when an HTTP + * request is to be performed. This creates and sends a properly constructed + * HTTP request. + */ +CURLcode Curl_http(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct hyptransfer *h = &data->hyp; + hyper_io *io = NULL; + hyper_clientconn_options *options = NULL; + hyper_task *task = NULL; /* for the handshake */ + hyper_task *sendtask = NULL; /* for the send */ + hyper_clientconn *client = NULL; + hyper_request *req = NULL; + hyper_headers *headers = NULL; + hyper_task *handshake = NULL; + CURLcode result; + const char *p_accept; /* Accept: string */ + const char *method; + Curl_HttpReq httpreq; + const char *te = NULL; /* transfer-encoding */ + hyper_code rc; + + /* Always consider the DO phase done after this function call, even if there + may be parts of the request that is not yet sent, since we can deal with + the rest of the request in the PERFORM phase. */ + *done = TRUE; + Curl_client_cleanup(data); + + infof(data, "Time for the Hyper dance"); + memset(h, 0, sizeof(struct hyptransfer)); + + result = Curl_http_host(data, conn); + if(result) + return result; + + Curl_http_method(data, conn, &method, &httpreq); + + DEBUGASSERT(data->req.bytecount == 0); + + /* setup the authentication headers */ + { + char *pq = NULL; + if(data->state.up.query) { + pq = aprintf("%s?%s", data->state.up.path, data->state.up.query); + if(!pq) + return CURLE_OUT_OF_MEMORY; + } + result = Curl_http_output_auth(data, conn, method, httpreq, + (pq ? pq : data->state.up.path), FALSE); + free(pq); + if(result) + return result; + } + + result = Curl_http_resume(data, conn, httpreq); + if(result) + return result; + + result = Curl_http_range(data, httpreq); + if(result) + return result; + + result = Curl_http_useragent(data); + if(result) + return result; + + io = hyper_io_new(); + if(!io) { + failf(data, "Couldn't create hyper IO"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + /* tell Hyper how to read/write network data */ + hyper_io_set_userdata(io, data); + hyper_io_set_read(io, Curl_hyper_recv); + hyper_io_set_write(io, Curl_hyper_send); + + /* create an executor to poll futures */ + if(!h->exec) { + h->exec = hyper_executor_new(); + if(!h->exec) { + failf(data, "Couldn't create hyper executor"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + } + + options = hyper_clientconn_options_new(); + if(!options) { + failf(data, "Couldn't create hyper client options"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + if(conn->alpn == CURL_HTTP_VERSION_2) { + failf(data, "ALPN protocol h2 not supported with Hyper"); + result = CURLE_UNSUPPORTED_PROTOCOL; + goto error; + } + hyper_clientconn_options_set_preserve_header_case(options, 1); + hyper_clientconn_options_set_preserve_header_order(options, 1); + hyper_clientconn_options_http1_allow_multiline_headers(options, 1); + + hyper_clientconn_options_exec(options, h->exec); + + /* "Both the `io` and the `options` are consumed in this function call" */ + handshake = hyper_clientconn_handshake(io, options); + if(!handshake) { + failf(data, "Couldn't create hyper client handshake"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + io = NULL; + options = NULL; + + if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) { + failf(data, "Couldn't hyper_executor_push the handshake"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + handshake = NULL; /* ownership passed on */ + + task = hyper_executor_poll(h->exec); + if(!task) { + failf(data, "Couldn't hyper_executor_poll the handshake"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + client = hyper_task_value(task); + hyper_task_free(task); + + req = hyper_request_new(); + if(!req) { + failf(data, "Couldn't hyper_request_new"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + if(!Curl_use_http_1_1plus(data, conn)) { + if(HYPERE_OK != hyper_request_set_version(req, + HYPER_HTTP_VERSION_1_0)) { + failf(data, "error setting HTTP version"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + } + else { + if(!data->state.disableexpect) { + data->state.expect100header = TRUE; + } + } + + if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) { + failf(data, "error setting method"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + result = request_target(data, conn, method, req); + if(result) + goto error; + + headers = hyper_request_headers(req); + if(!headers) { + failf(data, "hyper_request_headers"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + rc = hyper_request_on_informational(req, http1xx_cb, data); + if(rc) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + result = Curl_http_body(data, conn, httpreq, &te); + if(result) + goto error; + + if(data->state.aptr.host) { + result = Curl_hyper_header(data, headers, data->state.aptr.host); + if(result) + goto error; + } + + if(data->state.aptr.proxyuserpwd) { + result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd); + if(result) + goto error; + } + + if(data->state.aptr.userpwd) { + result = Curl_hyper_header(data, headers, data->state.aptr.userpwd); + if(result) + goto error; + } + + if((data->state.use_range && data->state.aptr.rangeline)) { + result = Curl_hyper_header(data, headers, data->state.aptr.rangeline); + if(result) + goto error; + } + + if(data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && + data->state.aptr.uagent) { + result = Curl_hyper_header(data, headers, data->state.aptr.uagent); + if(result) + goto error; + } + + p_accept = Curl_checkheaders(data, + STRCONST("Accept"))?NULL:"Accept: */*\r\n"; + if(p_accept) { + result = Curl_hyper_header(data, headers, p_accept); + if(result) + goto error; + } + if(te) { + result = Curl_hyper_header(data, headers, te); + if(result) + goto error; + } + +#ifndef CURL_DISABLE_ALTSVC + if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) { + char *altused = aprintf("Alt-Used: %s:%d\r\n", + conn->conn_to_host.name, conn->conn_to_port); + if(!altused) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + result = Curl_hyper_header(data, headers, altused); + if(result) + goto error; + free(altused); + } +#endif + +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy && + !Curl_checkheaders(data, STRCONST("Proxy-Connection")) && + !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) { + result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"); + if(result) + goto error; + } +#endif + + Curl_safefree(data->state.aptr.ref); + if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) { + data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); + if(!data->state.aptr.ref) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_hyper_header(data, headers, data->state.aptr.ref); + if(result) + goto error; + } + +#ifdef HAVE_LIBZ + /* we only consider transfer-encoding magic if libz support is built-in */ + result = Curl_transferencode(data); + if(result) + goto error; + result = Curl_hyper_header(data, headers, data->state.aptr.te); + if(result) + goto error; +#endif + + if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && + data->set.str[STRING_ENCODING]) { + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = + aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); + if(!data->state.aptr.accept_encoding) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_hyper_header(data, headers, + data->state.aptr.accept_encoding); + if(result) + goto error; + } + else + Curl_safefree(data->state.aptr.accept_encoding); + + result = cookies(data, conn, headers); + if(result) + goto error; + + if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + result = Curl_ws_request(data, headers); + + result = Curl_add_timecondition(data, headers); + if(result) + goto error; + + result = Curl_add_custom_headers(data, FALSE, headers); + if(result) + goto error; + + result = bodysend(data, conn, headers, req, httpreq); + if(result) + goto error; + + Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2); + + if(data->req.upload_chunky && conn->bits.authneg) { + data->req.upload_chunky = TRUE; + } + else { + data->req.upload_chunky = FALSE; + } + sendtask = hyper_clientconn_send(client, req); + if(!sendtask) { + failf(data, "hyper_clientconn_send"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + req = NULL; + + if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) { + failf(data, "Couldn't hyper_executor_push the send"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + sendtask = NULL; /* ownership passed on */ + + hyper_clientconn_free(client); + client = NULL; + + if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) { + /* HTTP GET/HEAD download */ + Curl_pgrsSetUploadSize(data, 0); /* nothing */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); + } + conn->datastream = Curl_hyper_stream; + if(data->state.expect100header) + /* Timeout count starts now since with Hyper we don't know exactly when + the full request has been sent. */ + data->req.start100 = Curl_now(); + + /* clear userpwd and proxyuserpwd to avoid reusing old credentials + * from reused connections */ + Curl_safefree(data->state.aptr.userpwd); + Curl_safefree(data->state.aptr.proxyuserpwd); + return CURLE_OK; +error: + DEBUGASSERT(result); + if(io) + hyper_io_free(io); + + if(options) + hyper_clientconn_options_free(options); + + if(handshake) + hyper_task_free(handshake); + + if(client) + hyper_clientconn_free(client); + + if(req) + hyper_request_free(req); + + return result; +} + +void Curl_hyper_done(struct Curl_easy *data) +{ + struct hyptransfer *h = &data->hyp; + if(h->exec) { + hyper_executor_free(h->exec); + h->exec = NULL; + } + if(h->read_waker) { + hyper_waker_free(h->read_waker); + h->read_waker = NULL; + } + if(h->write_waker) { + hyper_waker_free(h->write_waker); + h->write_waker = NULL; + } + if(h->exp100_waker) { + hyper_waker_free(h->exp100_waker); + h->exp100_waker = NULL; + } +} + +#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */ diff --git a/lib/c-hyper.h b/lib/c-hyper.h new file mode 100644 index 0000000..0c7de90 --- /dev/null +++ b/lib/c-hyper.h @@ -0,0 +1,59 @@ +#ifndef HEADER_CURL_HYPER_H +#define HEADER_CURL_HYPER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) + +#include + +/* per-transfer data for the Hyper backend */ +struct hyptransfer { + hyper_waker *write_waker; + hyper_waker *read_waker; + const hyper_executor *exec; + hyper_waker *exp100_waker; + hyper_waker *send_body_waker; +}; + +size_t Curl_hyper_recv(void *userp, hyper_context *ctx, + uint8_t *buf, size_t buflen); +size_t Curl_hyper_send(void *userp, hyper_context *ctx, + const uint8_t *buf, size_t buflen); +CURLcode Curl_hyper_stream(struct Curl_easy *data, + struct connectdata *conn, + int *didwhat, + bool *done, + int select_res); + +CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers, + const char *line); +void Curl_hyper_done(struct Curl_easy *); + +#else +#define Curl_hyper_done(x) + +#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */ +#endif /* HEADER_CURL_HYPER_H */ diff --git a/lib/cf-h1-proxy.c b/lib/cf-h1-proxy.c new file mode 100644 index 0000000..167e531 --- /dev/null +++ b/lib/cf-h1-proxy.c @@ -0,0 +1,1095 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) + +#include +#ifdef USE_HYPER +#include +#endif +#include "urldata.h" +#include "dynbuf.h" +#include "sendf.h" +#include "http.h" +#include "http1.h" +#include "http_proxy.h" +#include "url.h" +#include "select.h" +#include "progress.h" +#include "cfilters.h" +#include "cf-h1-proxy.h" +#include "connect.h" +#include "curl_trc.h" +#include "curlx.h" +#include "vtls/vtls.h" +#include "transfer.h" +#include "multiif.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +typedef enum { + H1_TUNNEL_INIT, /* init/default/no tunnel state */ + H1_TUNNEL_CONNECT, /* CONNECT request is being send */ + H1_TUNNEL_RECEIVE, /* CONNECT answer is being received */ + H1_TUNNEL_RESPONSE, /* CONNECT response received completely */ + H1_TUNNEL_ESTABLISHED, + H1_TUNNEL_FAILED +} h1_tunnel_state; + +/* struct for HTTP CONNECT tunneling */ +struct h1_tunnel_state { + struct HTTP CONNECT; + struct dynbuf rcvbuf; + struct dynbuf request_data; + size_t nsent; + size_t headerlines; + struct Curl_chunker ch; + enum keeponval { + KEEPON_DONE, + KEEPON_CONNECT, + KEEPON_IGNORE + } keepon; + curl_off_t cl; /* size of content to read and ignore */ + h1_tunnel_state tunnel_state; + BIT(chunked_encoding); + BIT(close_connection); +}; + + +static bool tunnel_is_established(struct h1_tunnel_state *ts) +{ + return ts && (ts->tunnel_state == H1_TUNNEL_ESTABLISHED); +} + +static bool tunnel_is_failed(struct h1_tunnel_state *ts) +{ + return ts && (ts->tunnel_state == H1_TUNNEL_FAILED); +} + +static CURLcode tunnel_reinit(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts) +{ + (void)data; + (void)cf; + DEBUGASSERT(ts); + Curl_dyn_reset(&ts->rcvbuf); + Curl_dyn_reset(&ts->request_data); + ts->tunnel_state = H1_TUNNEL_INIT; + ts->keepon = KEEPON_CONNECT; + ts->cl = 0; + ts->close_connection = FALSE; + return CURLE_OK; +} + +static CURLcode tunnel_init(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state **pts) +{ + struct h1_tunnel_state *ts; + CURLcode result; + + if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) { + failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme); + return CURLE_UNSUPPORTED_PROTOCOL; + } + + /* we might need the upload buffer for streaming a partial request */ + result = Curl_get_upload_buffer(data); + if(result) + return result; + + ts = calloc(1, sizeof(*ts)); + if(!ts) + return CURLE_OUT_OF_MEMORY; + + infof(data, "allocate connect buffer"); + + Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS); + Curl_dyn_init(&ts->request_data, DYN_HTTP_REQUEST); + Curl_httpchunk_init(data, &ts->ch, TRUE); + + *pts = ts; + connkeep(cf->conn, "HTTP proxy CONNECT"); + return tunnel_reinit(cf, data, ts); +} + +static void h1_tunnel_go_state(struct Curl_cfilter *cf, + struct h1_tunnel_state *ts, + h1_tunnel_state new_state, + struct Curl_easy *data) +{ + if(ts->tunnel_state == new_state) + return; + /* entering this one */ + switch(new_state) { + case H1_TUNNEL_INIT: + CURL_TRC_CF(data, cf, "new tunnel state 'init'"); + tunnel_reinit(cf, data, ts); + break; + + case H1_TUNNEL_CONNECT: + CURL_TRC_CF(data, cf, "new tunnel state 'connect'"); + ts->tunnel_state = H1_TUNNEL_CONNECT; + ts->keepon = KEEPON_CONNECT; + Curl_dyn_reset(&ts->rcvbuf); + break; + + case H1_TUNNEL_RECEIVE: + CURL_TRC_CF(data, cf, "new tunnel state 'receive'"); + ts->tunnel_state = H1_TUNNEL_RECEIVE; + break; + + case H1_TUNNEL_RESPONSE: + CURL_TRC_CF(data, cf, "new tunnel state 'response'"); + ts->tunnel_state = H1_TUNNEL_RESPONSE; + break; + + case H1_TUNNEL_ESTABLISHED: + CURL_TRC_CF(data, cf, "new tunnel state 'established'"); + infof(data, "CONNECT phase completed"); + data->state.authproxy.done = TRUE; + data->state.authproxy.multipass = FALSE; + FALLTHROUGH(); + case H1_TUNNEL_FAILED: + if(new_state == H1_TUNNEL_FAILED) + CURL_TRC_CF(data, cf, "new tunnel state 'failed'"); + ts->tunnel_state = new_state; + Curl_dyn_reset(&ts->rcvbuf); + Curl_dyn_reset(&ts->request_data); + /* restore the protocol pointer */ + data->info.httpcode = 0; /* clear it as it might've been used for the + proxy */ + /* If a proxy-authorization header was used for the proxy, then we should + make sure that it isn't accidentally used for the document request + after we've connected. So let's free and clear it here. */ + Curl_safefree(data->state.aptr.proxyuserpwd); +#ifdef USE_HYPER + data->state.hconnect = FALSE; +#endif + break; + } +} + +static void tunnel_free(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct h1_tunnel_state *ts = cf->ctx; + if(ts) { + h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data); + Curl_dyn_free(&ts->rcvbuf); + Curl_dyn_free(&ts->request_data); + Curl_httpchunk_free(data, &ts->ch); + free(ts); + cf->ctx = NULL; + } +} + +#ifndef USE_HYPER +static CURLcode start_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts) +{ + struct httpreq *req = NULL; + int http_minor; + CURLcode result; + + /* This only happens if we've looped here due to authentication + reasons, and we don't really use the newly cloned URL here + then. Just free() it. */ + Curl_safefree(data->req.newurl); + + result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1); + if(result) + goto out; + + infof(data, "Establish HTTP proxy tunnel to %s", req->authority); + + Curl_dyn_reset(&ts->request_data); + ts->nsent = 0; + ts->headerlines = 0; + http_minor = (cf->conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? 0 : 1; + + result = Curl_h1_req_write_head(req, http_minor, &ts->request_data); + +out: + if(result) + failf(data, "Failed sending CONNECT to proxy"); + if(req) + Curl_http_req_free(req); + return result; +} + +static CURLcode send_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts, + bool *done) +{ + char *buf = Curl_dyn_ptr(&ts->request_data); + size_t request_len = Curl_dyn_len(&ts->request_data); + size_t blen = request_len; + CURLcode result = CURLE_OK; + ssize_t nwritten; + + if(blen <= ts->nsent) + goto out; /* we are done */ + + blen -= ts->nsent; + buf += ts->nsent; + + nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, &result); + if(nwritten < 0) { + if(result == CURLE_AGAIN) { + result = CURLE_OK; + } + goto out; + } + + DEBUGASSERT(blen >= (size_t)nwritten); + ts->nsent += (size_t)nwritten; + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten); + +out: + if(result) + failf(data, "Failed sending CONNECT to proxy"); + *done = (!result && (ts->nsent >= request_len)); + return result; +} + +static CURLcode on_resp_header(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts, + const char *header) +{ + CURLcode result = CURLE_OK; + struct SingleRequest *k = &data->req; + (void)cf; + + if((checkprefix("WWW-Authenticate:", header) && + (401 == k->httpcode)) || + (checkprefix("Proxy-authenticate:", header) && + (407 == k->httpcode))) { + + bool proxy = (k->httpcode == 407) ? TRUE : FALSE; + char *auth = Curl_copy_header_value(header); + if(!auth) + return CURLE_OUT_OF_MEMORY; + + CURL_TRC_CF(data, cf, "CONNECT: fwd auth header '%s'", header); + result = Curl_http_input_auth(data, proxy, auth); + + free(auth); + + if(result) + return result; + } + else if(checkprefix("Content-Length:", header)) { + if(k->httpcode/100 == 2) { + /* A client MUST ignore any Content-Length or Transfer-Encoding + header fields received in a successful response to CONNECT. + "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ + infof(data, "Ignoring Content-Length in CONNECT %03d response", + k->httpcode); + } + else { + (void)curlx_strtoofft(header + strlen("Content-Length:"), + NULL, 10, &ts->cl); + } + } + else if(Curl_compareheader(header, + STRCONST("Connection:"), STRCONST("close"))) + ts->close_connection = TRUE; + else if(checkprefix("Transfer-Encoding:", header)) { + if(k->httpcode/100 == 2) { + /* A client MUST ignore any Content-Length or Transfer-Encoding + header fields received in a successful response to CONNECT. + "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ + infof(data, "Ignoring Transfer-Encoding in " + "CONNECT %03d response", k->httpcode); + } + else if(Curl_compareheader(header, + STRCONST("Transfer-Encoding:"), + STRCONST("chunked"))) { + infof(data, "CONNECT responded chunked"); + ts->chunked_encoding = TRUE; + /* reset our chunky engine */ + Curl_httpchunk_reset(data, &ts->ch, TRUE); + } + } + else if(Curl_compareheader(header, + STRCONST("Proxy-Connection:"), + STRCONST("close"))) + ts->close_connection = TRUE; + else if(!strncmp(header, "HTTP/1.", 7) && + ((header[7] == '0') || (header[7] == '1')) && + (header[8] == ' ') && + ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) && + !ISDIGIT(header[12])) { + /* store the HTTP code from the proxy */ + data->info.httpproxycode = k->httpcode = (header[9] - '0') * 100 + + (header[10] - '0') * 10 + (header[11] - '0'); + } + return result; +} + +static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts, + bool *done) +{ + CURLcode result = CURLE_OK; + struct SingleRequest *k = &data->req; + curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data); + char *linep; + size_t line_len; + int error, writetype; + +#define SELECT_OK 0 +#define SELECT_ERROR 1 + + error = SELECT_OK; + *done = FALSE; + + if(!Curl_conn_data_pending(data, cf->sockindex)) + return CURLE_OK; + + while(ts->keepon) { + ssize_t nread; + char byte; + + /* Read one byte at a time to avoid a race condition. Wait at most one + second before looping to ensure continuous pgrsUpdates. */ + result = Curl_read(data, tunnelsocket, &byte, 1, &nread); + if(result == CURLE_AGAIN) + /* socket buffer drained, return */ + return CURLE_OK; + + if(Curl_pgrsUpdate(data)) + return CURLE_ABORTED_BY_CALLBACK; + + if(result) { + ts->keepon = KEEPON_DONE; + break; + } + + if(nread <= 0) { + if(data->set.proxyauth && data->state.authproxy.avail && + data->state.aptr.proxyuserpwd) { + /* proxy auth was requested and there was proxy auth available, + then deem this as "mere" proxy disconnect */ + ts->close_connection = TRUE; + infof(data, "Proxy CONNECT connection closed"); + } + else { + error = SELECT_ERROR; + failf(data, "Proxy CONNECT aborted"); + } + ts->keepon = KEEPON_DONE; + break; + } + + if(ts->keepon == KEEPON_IGNORE) { + /* This means we are currently ignoring a response-body */ + + if(ts->cl) { + /* A Content-Length based body: simply count down the counter + and make sure to break out of the loop when we're done! */ + ts->cl--; + if(ts->cl <= 0) { + ts->keepon = KEEPON_DONE; + break; + } + } + else if(ts->chunked_encoding) { + /* chunked-encoded body, so we need to do the chunked dance + properly to know when the end of the body is reached */ + size_t consumed = 0; + + /* now parse the chunked piece of data so that we can + properly tell when the stream ends */ + result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed); + if(result) + return result; + if(Curl_httpchunk_is_done(data, &ts->ch)) { + /* we're done reading chunks! */ + infof(data, "chunk reading DONE"); + ts->keepon = KEEPON_DONE; + } + } + continue; + } + + if(Curl_dyn_addn(&ts->rcvbuf, &byte, 1)) { + failf(data, "CONNECT response too large"); + return CURLE_RECV_ERROR; + } + + /* if this is not the end of a header line then continue */ + if(byte != 0x0a) + continue; + + ts->headerlines++; + linep = Curl_dyn_ptr(&ts->rcvbuf); + line_len = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */ + + /* output debug if that is requested */ + Curl_debug(data, CURLINFO_HEADER_IN, linep, line_len); + + /* send the header to the callback */ + writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT | + (ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0); + result = Curl_client_write(data, writetype, linep, line_len); + if(result) + return result; + + result = Curl_bump_headersize(data, line_len, TRUE); + if(result) + return result; + + /* Newlines are CRLF, so the CR is ignored as the line isn't + really terminated until the LF comes. Treat a following CR + as end-of-headers as well.*/ + + if(('\r' == linep[0]) || + ('\n' == linep[0])) { + /* end of response-headers from the proxy */ + + if((407 == k->httpcode) && !data->state.authproblem) { + /* If we get a 407 response code with content length + when we have no auth problem, we must ignore the + whole response-body */ + ts->keepon = KEEPON_IGNORE; + + if(ts->cl) { + infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T + " bytes of response-body", ts->cl); + } + else if(ts->chunked_encoding) { + infof(data, "Ignore chunked response-body"); + } + else { + /* without content-length or chunked encoding, we + can't keep the connection alive since the close is + the end signal so we bail out at once instead */ + CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked"); + ts->keepon = KEEPON_DONE; + } + } + else { + ts->keepon = KEEPON_DONE; + } + + DEBUGASSERT(ts->keepon == KEEPON_IGNORE + || ts->keepon == KEEPON_DONE); + continue; + } + + result = on_resp_header(cf, data, ts, linep); + if(result) + return result; + + Curl_dyn_reset(&ts->rcvbuf); + } /* while there's buffer left and loop is requested */ + + if(error) + result = CURLE_RECV_ERROR; + *done = (ts->keepon == KEEPON_DONE); + if(!result && *done && data->info.httpproxycode/100 != 2) { + /* Deal with the possibly already received authenticate + headers. 'newurl' is set to a new URL if we must loop. */ + result = Curl_http_auth_act(data); + } + return result; +} + +#else /* USE_HYPER */ + +static CURLcode CONNECT_host(struct Curl_cfilter *cf, + struct Curl_easy *data, + char **pauthority, + char **phost_header) +{ + const char *hostname; + int port; + bool ipv6_ip; + CURLcode result; + char *authority; /* for CONNECT, the destination host + port */ + char *host_header = NULL; /* Host: authority */ + + result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip); + if(result) + return result; + + authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", + port); + if(!authority) + return CURLE_OUT_OF_MEMORY; + + /* If user is not overriding the Host header later */ + if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) { + host_header = aprintf("Host: %s\r\n", authority); + if(!host_header) { + free(authority); + return CURLE_OUT_OF_MEMORY; + } + } + *pauthority = authority; + *phost_header = host_header; + return CURLE_OK; +} + +/* The Hyper version of CONNECT */ +static CURLcode start_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts) +{ + struct connectdata *conn = cf->conn; + struct hyptransfer *h = &data->hyp; + curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data); + hyper_io *io = NULL; + hyper_request *req = NULL; + hyper_headers *headers = NULL; + hyper_clientconn_options *options = NULL; + hyper_task *handshake = NULL; + hyper_task *task = NULL; /* for the handshake */ + hyper_clientconn *client = NULL; + hyper_task *sendtask = NULL; /* for the send */ + char *authority = NULL; /* for CONNECT */ + char *host_header = NULL; /* Host: */ + CURLcode result = CURLE_OUT_OF_MEMORY; + (void)ts; + + io = hyper_io_new(); + if(!io) { + failf(data, "Couldn't create hyper IO"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + /* tell Hyper how to read/write network data */ + hyper_io_set_userdata(io, data); + hyper_io_set_read(io, Curl_hyper_recv); + hyper_io_set_write(io, Curl_hyper_send); + conn->sockfd = tunnelsocket; + + data->state.hconnect = TRUE; + + /* create an executor to poll futures */ + if(!h->exec) { + h->exec = hyper_executor_new(); + if(!h->exec) { + failf(data, "Couldn't create hyper executor"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + } + + options = hyper_clientconn_options_new(); + if(!options) { + failf(data, "Couldn't create hyper client options"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + hyper_clientconn_options_set_preserve_header_case(options, 1); + hyper_clientconn_options_set_preserve_header_order(options, 1); + + hyper_clientconn_options_exec(options, h->exec); + + /* "Both the `io` and the `options` are consumed in this function + call" */ + handshake = hyper_clientconn_handshake(io, options); + if(!handshake) { + failf(data, "Couldn't create hyper client handshake"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + io = NULL; + options = NULL; + + if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) { + failf(data, "Couldn't hyper_executor_push the handshake"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + handshake = NULL; /* ownership passed on */ + + task = hyper_executor_poll(h->exec); + if(!task) { + failf(data, "Couldn't hyper_executor_poll the handshake"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + client = hyper_task_value(task); + hyper_task_free(task); + + req = hyper_request_new(); + if(!req) { + failf(data, "Couldn't hyper_request_new"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + if(hyper_request_set_method(req, (uint8_t *)"CONNECT", + strlen("CONNECT"))) { + failf(data, "error setting method"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + /* This only happens if we've looped here due to authentication + reasons, and we don't really use the newly cloned URL here + then. Just free() it. */ + Curl_safefree(data->req.newurl); + + result = CONNECT_host(cf, data, &authority, &host_header); + if(result) + goto error; + + infof(data, "Establish HTTP proxy tunnel to %s", authority); + + if(hyper_request_set_uri(req, (uint8_t *)authority, + strlen(authority))) { + failf(data, "error setting path"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + if(data->set.verbose) { + char *se = aprintf("CONNECT %s HTTP/1.1\r\n", authority); + if(!se) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se)); + free(se); + } + /* Setup the proxy-authorization header, if any */ + result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET, + authority, TRUE); + if(result) + goto error; + Curl_safefree(authority); + + /* default is 1.1 */ + if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) && + (HYPERE_OK != hyper_request_set_version(req, + HYPER_HTTP_VERSION_1_0))) { + failf(data, "error setting HTTP version"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + headers = hyper_request_headers(req); + if(!headers) { + failf(data, "hyper_request_headers"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + if(host_header) { + result = Curl_hyper_header(data, headers, host_header); + if(result) + goto error; + Curl_safefree(host_header); + } + + if(data->state.aptr.proxyuserpwd) { + result = Curl_hyper_header(data, headers, + data->state.aptr.proxyuserpwd); + if(result) + goto error; + } + + if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) && + data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) { + struct dynbuf ua; + Curl_dyn_init(&ua, DYN_HTTP_REQUEST); + result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n", + data->set.str[STRING_USERAGENT]); + if(result) + goto error; + result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua)); + if(result) + goto error; + Curl_dyn_free(&ua); + } + + if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) { + result = Curl_hyper_header(data, headers, + "Proxy-Connection: Keep-Alive"); + if(result) + goto error; + } + + result = Curl_add_custom_headers(data, TRUE, headers); + if(result) + goto error; + + sendtask = hyper_clientconn_send(client, req); + if(!sendtask) { + failf(data, "hyper_clientconn_send"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + req = NULL; + + if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) { + failf(data, "Couldn't hyper_executor_push the send"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + sendtask = NULL; /* ownership passed on */ + + hyper_clientconn_free(client); + client = NULL; + +error: + free(host_header); + free(authority); + if(io) + hyper_io_free(io); + if(options) + hyper_clientconn_options_free(options); + if(handshake) + hyper_task_free(handshake); + if(client) + hyper_clientconn_free(client); + if(req) + hyper_request_free(req); + + return result; +} + +static CURLcode send_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts, + bool *done) +{ + struct hyptransfer *h = &data->hyp; + struct connectdata *conn = cf->conn; + hyper_task *task = NULL; + hyper_error *hypererr = NULL; + CURLcode result = CURLE_OK; + + (void)ts; + (void)conn; + do { + task = hyper_executor_poll(h->exec); + if(task) { + bool error = hyper_task_type(task) == HYPER_TASK_ERROR; + if(error) + hypererr = hyper_task_value(task); + hyper_task_free(task); + if(error) { + /* this could probably use a better error code? */ + result = CURLE_OUT_OF_MEMORY; + goto error; + } + } + } while(task); +error: + *done = (result == CURLE_OK); + if(hypererr) { + uint8_t errbuf[256]; + size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf)); + failf(data, "Hyper: %.*s", (int)errlen, errbuf); + hyper_error_free(hypererr); + } + return result; +} + +static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts, + bool *done) +{ + struct hyptransfer *h = &data->hyp; + CURLcode result; + int didwhat; + + (void)ts; + *done = FALSE; + result = Curl_hyper_stream(data, cf->conn, &didwhat, done, + CURL_CSELECT_IN | CURL_CSELECT_OUT); + if(result || !*done) + return result; + if(h->exec) { + hyper_executor_free(h->exec); + h->exec = NULL; + } + if(h->read_waker) { + hyper_waker_free(h->read_waker); + h->read_waker = NULL; + } + if(h->write_waker) { + hyper_waker_free(h->write_waker); + h->write_waker = NULL; + } + return result; +} + +#endif /* USE_HYPER */ + +static CURLcode H1_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts) +{ + struct connectdata *conn = cf->conn; + CURLcode result; + bool done; + + if(tunnel_is_established(ts)) + return CURLE_OK; + if(tunnel_is_failed(ts)) + return CURLE_RECV_ERROR; /* Need a cfilter close and new bootstrap */ + + do { + timediff_t check; + + check = Curl_timeleft(data, NULL, TRUE); + if(check <= 0) { + failf(data, "Proxy CONNECT aborted due to timeout"); + result = CURLE_OPERATION_TIMEDOUT; + goto out; + } + + switch(ts->tunnel_state) { + case H1_TUNNEL_INIT: + /* Prepare the CONNECT request and make a first attempt to send. */ + CURL_TRC_CF(data, cf, "CONNECT start"); + result = start_CONNECT(cf, data, ts); + if(result) + goto out; + h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data); + FALLTHROUGH(); + + case H1_TUNNEL_CONNECT: + /* see that the request is completely sent */ + CURL_TRC_CF(data, cf, "CONNECT send"); + result = send_CONNECT(cf, data, ts, &done); + if(result || !done) + goto out; + h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data); + FALLTHROUGH(); + + case H1_TUNNEL_RECEIVE: + /* read what is there */ + CURL_TRC_CF(data, cf, "CONNECT receive"); + result = recv_CONNECT_resp(cf, data, ts, &done); + if(Curl_pgrsUpdate(data)) { + result = CURLE_ABORTED_BY_CALLBACK; + goto out; + } + /* error or not complete yet. return for more multi-multi */ + if(result || !done) + goto out; + /* got it */ + h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data); + FALLTHROUGH(); + + case H1_TUNNEL_RESPONSE: + CURL_TRC_CF(data, cf, "CONNECT response"); + if(data->req.newurl) { + /* not the "final" response, we need to do a follow up request. + * If the other side indicated a connection close, or if someone + * else told us to close this connection, do so now. + */ + if(ts->close_connection || conn->bits.close) { + /* Close this filter and the sub-chain, re-connect the + * sub-chain and continue. Closing this filter will + * reset our tunnel state. To avoid recursion, we return + * and expect to be called again. + */ + CURL_TRC_CF(data, cf, "CONNECT need to close+open"); + infof(data, "Connect me again please"); + Curl_conn_cf_close(cf, data); + connkeep(conn, "HTTP proxy CONNECT"); + result = Curl_conn_cf_connect(cf->next, data, FALSE, &done); + goto out; + } + else { + /* staying on this connection, reset state */ + h1_tunnel_go_state(cf, ts, H1_TUNNEL_INIT, data); + } + } + break; + + default: + break; + } + + } while(data->req.newurl); + + DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE); + if(data->info.httpproxycode/100 != 2) { + /* a non-2xx response and we have no next url to try. */ + Curl_safefree(data->req.newurl); + /* failure, close this connection to avoid reuse */ + streamclose(conn, "proxy CONNECT failure"); + h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data); + failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode); + return CURLE_RECV_ERROR; + } + /* 2xx response, SUCCESS! */ + h1_tunnel_go_state(cf, ts, H1_TUNNEL_ESTABLISHED, data); + infof(data, "CONNECT tunnel established, response %d", + data->info.httpproxycode); + result = CURLE_OK; + +out: + if(result) + h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data); + return result; +} + +static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + CURLcode result; + struct h1_tunnel_state *ts = cf->ctx; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + CURL_TRC_CF(data, cf, "connect"); + result = cf->next->cft->do_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + + *done = FALSE; + if(!ts) { + result = tunnel_init(cf, data, &ts); + if(result) + return result; + cf->ctx = ts; + } + + /* TODO: can we do blocking? */ + /* We want "seamless" operations through HTTP proxy tunnel */ + + result = H1_CONNECT(cf, data, ts); + if(result) + goto out; + Curl_safefree(data->state.aptr.proxyuserpwd); + +out: + *done = (result == CURLE_OK) && tunnel_is_established(cf->ctx); + if(*done) { + cf->connected = TRUE; + /* Restore `data->req` fields that may habe been touched */ + data->req.header = TRUE; /* assume header */ + data->req.bytecount = 0; + data->req.ignorebody = FALSE; + Curl_client_cleanup(data); + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + + tunnel_free(cf, data); + } + return result; +} + +static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct h1_tunnel_state *ts = cf->ctx; + + if(!cf->connected) { + /* If we are not connected, but the filter "below" is + * and not waiting on something, we are tunneling. */ + curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); + if(ts) { + /* when we've sent a CONNECT to a proxy, we should rather either + wait for the socket to become readable to be able to get the + response headers or if we're still sending the request, wait + for write. */ + if(ts->CONNECT.sending == HTTPSEND_REQUEST) + Curl_pollset_set_out_only(data, ps, sock); + else + Curl_pollset_set_in_only(data, ps, sock); + } + else + Curl_pollset_set_out_only(data, ps, sock); + } +} + +static void cf_h1_proxy_destroy(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURL_TRC_CF(data, cf, "destroy"); + tunnel_free(cf, data); +} + +static void cf_h1_proxy_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURL_TRC_CF(data, cf, "close"); + cf->connected = FALSE; + if(cf->ctx) { + h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data); + } + if(cf->next) + cf->next->cft->do_close(cf->next, data); +} + + +struct Curl_cftype Curl_cft_h1_proxy = { + "H1-PROXY", + CF_TYPE_IP_CONNECT, + 0, + cf_h1_proxy_destroy, + cf_h1_proxy_connect, + cf_h1_proxy_close, + Curl_cf_http_proxy_get_host, + cf_h1_proxy_adjust_pollset, + Curl_cf_def_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, +}; + +CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + CURLcode result; + + (void)data; + result = Curl_cf_create(&cf, &Curl_cft_h1_proxy, NULL); + if(!result) + Curl_conn_cf_insert_after(cf_at, cf); + return result; +} + +#endif /* !CURL_DISABLE_PROXY && ! CURL_DISABLE_HTTP */ diff --git a/lib/cf-h1-proxy.h b/lib/cf-h1-proxy.h new file mode 100644 index 0000000..ac5bed0 --- /dev/null +++ b/lib/cf-h1-proxy.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_H1_PROXY_H +#define HEADER_CURL_H1_PROXY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) + +CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf, + struct Curl_easy *data); + +extern struct Curl_cftype Curl_cft_h1_proxy; + + +#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */ + +#endif /* HEADER_CURL_H1_PROXY_H */ diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c new file mode 100644 index 0000000..f8f2f3c --- /dev/null +++ b/lib/cf-h2-proxy.c @@ -0,0 +1,1567 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) + +#include +#include "urldata.h" +#include "cfilters.h" +#include "connect.h" +#include "curl_trc.h" +#include "bufq.h" +#include "dynbuf.h" +#include "dynhds.h" +#include "http1.h" +#include "http2.h" +#include "http_proxy.h" +#include "multiif.h" +#include "cf-h2-proxy.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define PROXY_H2_CHUNK_SIZE (16*1024) + +#define PROXY_HTTP2_HUGE_WINDOW_SIZE (100 * 1024 * 1024) +#define H2_TUNNEL_WINDOW_SIZE (10 * 1024 * 1024) + +#define PROXY_H2_NW_RECV_CHUNKS (H2_TUNNEL_WINDOW_SIZE / PROXY_H2_CHUNK_SIZE) +#define PROXY_H2_NW_SEND_CHUNKS 1 + +#define H2_TUNNEL_RECV_CHUNKS (H2_TUNNEL_WINDOW_SIZE / PROXY_H2_CHUNK_SIZE) +#define H2_TUNNEL_SEND_CHUNKS ((128 * 1024) / PROXY_H2_CHUNK_SIZE) + + +typedef enum { + H2_TUNNEL_INIT, /* init/default/no tunnel state */ + H2_TUNNEL_CONNECT, /* CONNECT request is being send */ + H2_TUNNEL_RESPONSE, /* CONNECT response received completely */ + H2_TUNNEL_ESTABLISHED, + H2_TUNNEL_FAILED +} h2_tunnel_state; + +struct tunnel_stream { + struct http_resp *resp; + struct bufq recvbuf; + struct bufq sendbuf; + char *authority; + int32_t stream_id; + uint32_t error; + size_t upload_blocked_len; + h2_tunnel_state state; + BIT(has_final_response); + BIT(closed); + BIT(reset); +}; + +static CURLcode tunnel_stream_init(struct Curl_cfilter *cf, + struct tunnel_stream *ts) +{ + const char *hostname; + int port; + bool ipv6_ip; + CURLcode result; + + ts->state = H2_TUNNEL_INIT; + ts->stream_id = -1; + Curl_bufq_init2(&ts->recvbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS, + BUFQ_OPT_SOFT_LIMIT); + Curl_bufq_init(&ts->sendbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS); + + result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip); + if(result) + return result; + + ts->authority = /* host:port with IPv6 support */ + aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", port); + if(!ts->authority) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +static void tunnel_stream_clear(struct tunnel_stream *ts) +{ + Curl_http_resp_free(ts->resp); + Curl_bufq_free(&ts->recvbuf); + Curl_bufq_free(&ts->sendbuf); + Curl_safefree(ts->authority); + memset(ts, 0, sizeof(*ts)); + ts->state = H2_TUNNEL_INIT; +} + +static void h2_tunnel_go_state(struct Curl_cfilter *cf, + struct tunnel_stream *ts, + h2_tunnel_state new_state, + struct Curl_easy *data) +{ + (void)cf; + + if(ts->state == new_state) + return; + /* leaving this one */ + switch(ts->state) { + case H2_TUNNEL_CONNECT: + data->req.ignorebody = FALSE; + break; + default: + break; + } + /* entering this one */ + switch(new_state) { + case H2_TUNNEL_INIT: + CURL_TRC_CF(data, cf, "[%d] new tunnel state 'init'", ts->stream_id); + tunnel_stream_clear(ts); + break; + + case H2_TUNNEL_CONNECT: + CURL_TRC_CF(data, cf, "[%d] new tunnel state 'connect'", ts->stream_id); + ts->state = H2_TUNNEL_CONNECT; + break; + + case H2_TUNNEL_RESPONSE: + CURL_TRC_CF(data, cf, "[%d] new tunnel state 'response'", ts->stream_id); + ts->state = H2_TUNNEL_RESPONSE; + break; + + case H2_TUNNEL_ESTABLISHED: + CURL_TRC_CF(data, cf, "[%d] new tunnel state 'established'", + ts->stream_id); + infof(data, "CONNECT phase completed"); + data->state.authproxy.done = TRUE; + data->state.authproxy.multipass = FALSE; + FALLTHROUGH(); + case H2_TUNNEL_FAILED: + if(new_state == H2_TUNNEL_FAILED) + CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id); + ts->state = new_state; + /* If a proxy-authorization header was used for the proxy, then we should + make sure that it isn't accidentally used for the document request + after we've connected. So let's free and clear it here. */ + Curl_safefree(data->state.aptr.proxyuserpwd); + break; + } +} + +struct cf_h2_proxy_ctx { + nghttp2_session *h2; + /* The easy handle used in the current filter call, cleared at return */ + struct cf_call_data call_data; + + struct bufq inbufq; /* network receive buffer */ + struct bufq outbufq; /* network send buffer */ + + struct tunnel_stream tunnel; /* our tunnel CONNECT stream */ + int32_t goaway_error; + int32_t last_stream_id; + BIT(conn_closed); + BIT(goaway); + BIT(nw_out_blocked); +}; + +/* How to access `call_data` from a cf_h2 filter */ +#undef CF_CTX_CALL_DATA +#define CF_CTX_CALL_DATA(cf) \ + ((struct cf_h2_proxy_ctx *)(cf)->ctx)->call_data + +static void cf_h2_proxy_ctx_clear(struct cf_h2_proxy_ctx *ctx) +{ + struct cf_call_data save = ctx->call_data; + + if(ctx->h2) { + nghttp2_session_del(ctx->h2); + } + Curl_bufq_free(&ctx->inbufq); + Curl_bufq_free(&ctx->outbufq); + tunnel_stream_clear(&ctx->tunnel); + memset(ctx, 0, sizeof(*ctx)); + ctx->call_data = save; +} + +static void cf_h2_proxy_ctx_free(struct cf_h2_proxy_ctx *ctx) +{ + if(ctx) { + cf_h2_proxy_ctx_clear(ctx); + free(ctx); + } +} + +static void drain_tunnel(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct tunnel_stream *tunnel) +{ + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x", + tunnel->stream_id, bits); + data->state.select_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +static ssize_t proxy_nw_in_reader(void *reader_ctx, + unsigned char *buf, size_t buflen, + CURLcode *err) +{ + struct Curl_cfilter *cf = reader_ctx; + ssize_t nread; + + if(cf) { + struct Curl_easy *data = CF_DATA_CURRENT(cf); + nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err); + CURL_TRC_CF(data, cf, "[0] nw_in_reader(len=%zu) -> %zd, %d", + buflen, nread, *err); + } + else { + nread = 0; + } + return nread; +} + +static ssize_t proxy_h2_nw_out_writer(void *writer_ctx, + const unsigned char *buf, size_t buflen, + CURLcode *err) +{ + struct Curl_cfilter *cf = writer_ctx; + ssize_t nwritten; + + if(cf) { + struct Curl_easy *data = CF_DATA_CURRENT(cf); + nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen, + err); + CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d", + buflen, nwritten, *err); + } + else { + nwritten = 0; + } + return nwritten; +} + +static int proxy_h2_client_new(struct Curl_cfilter *cf, + nghttp2_session_callbacks *cbs) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + nghttp2_option *o; + + int rc = nghttp2_option_new(&o); + if(rc) + return rc; + /* We handle window updates ourself to enforce buffer limits */ + nghttp2_option_set_no_auto_window_update(o, 1); +#if NGHTTP2_VERSION_NUM >= 0x013200 + /* with 1.50.0 */ + /* turn off RFC 9113 leading and trailing white spaces validation against + HTTP field value. */ + nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1); +#endif + rc = nghttp2_session_client_new2(&ctx->h2, cbs, cf, o); + nghttp2_option_del(o); + return rc; +} + +static ssize_t on_session_send(nghttp2_session *h2, + const uint8_t *buf, size_t blen, + int flags, void *userp); +static int proxy_h2_on_frame_recv(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp); +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static int proxy_h2_on_frame_send(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp); +#endif +static int proxy_h2_on_stream_close(nghttp2_session *session, + int32_t stream_id, + uint32_t error_code, void *userp); +static int proxy_h2_on_header(nghttp2_session *session, + const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, + void *userp); +static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const uint8_t *mem, size_t len, void *userp); + +/* + * Initialize the cfilter context + */ +static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OUT_OF_MEMORY; + nghttp2_session_callbacks *cbs = NULL; + int rc; + + DEBUGASSERT(!ctx->h2); + memset(&ctx->tunnel, 0, sizeof(ctx->tunnel)); + + Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS); + Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS); + + if(tunnel_stream_init(cf, &ctx->tunnel)) + goto out; + + rc = nghttp2_session_callbacks_new(&cbs); + if(rc) { + failf(data, "Couldn't initialize nghttp2 callbacks"); + goto out; + } + + nghttp2_session_callbacks_set_send_callback(cbs, on_session_send); + nghttp2_session_callbacks_set_on_frame_recv_callback( + cbs, proxy_h2_on_frame_recv); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + nghttp2_session_callbacks_set_on_frame_send_callback(cbs, + proxy_h2_on_frame_send); +#endif + nghttp2_session_callbacks_set_on_data_chunk_recv_callback( + cbs, tunnel_recv_callback); + nghttp2_session_callbacks_set_on_stream_close_callback( + cbs, proxy_h2_on_stream_close); + nghttp2_session_callbacks_set_on_header_callback(cbs, proxy_h2_on_header); + + /* The nghttp2 session is not yet setup, do it */ + rc = proxy_h2_client_new(cf, cbs); + if(rc) { + failf(data, "Couldn't initialize nghttp2"); + goto out; + } + + { + nghttp2_settings_entry iv[3]; + + iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; + iv[0].value = Curl_multi_max_concurrent_streams(data->multi); + iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + iv[1].value = H2_TUNNEL_WINDOW_SIZE; + iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + iv[2].value = 0; + rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE, iv, 3); + if(rc) { + failf(data, "nghttp2_submit_settings() failed: %s(%d)", + nghttp2_strerror(rc), rc); + result = CURLE_HTTP2; + goto out; + } + } + + rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0, + PROXY_HTTP2_HUGE_WINDOW_SIZE); + if(rc) { + failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", + nghttp2_strerror(rc), rc); + result = CURLE_HTTP2; + goto out; + } + + + /* all set, traffic will be send on connect */ + result = CURLE_OK; + +out: + if(cbs) + nghttp2_session_callbacks_del(cbs); + CURL_TRC_CF(data, cf, "[0] init proxy ctx -> %d", result); + return result; +} + +static int proxy_h2_should_close_session(struct cf_h2_proxy_ctx *ctx) +{ + return !nghttp2_session_want_read(ctx->h2) && + !nghttp2_session_want_write(ctx->h2); +} + +static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + ssize_t nwritten; + CURLcode result; + + (void)data; + if(Curl_bufq_is_empty(&ctx->outbufq)) + return CURLE_OK; + + nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf, + &result); + if(nwritten < 0) { + if(result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "[0] flush nw send buffer(%zu) -> EAGAIN", + Curl_bufq_len(&ctx->outbufq)); + ctx->nw_out_blocked = 1; + } + return result; + } + CURL_TRC_CF(data, cf, "[0] nw send buffer flushed"); + return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN; +} + +/* + * Processes pending input left in network input buffer. + * This function returns 0 if it succeeds, or -1 and error code will + * be assigned to *err. + */ +static int proxy_h2_process_pending_input(struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLcode *err) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + const unsigned char *buf; + size_t blen; + ssize_t rv; + + while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) { + + rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen); + CURL_TRC_CF(data, cf, "[0] %zu bytes to nghttp2 -> %zd", blen, rv); + if(rv < 0) { + failf(data, + "process_pending_input: nghttp2_session_mem_recv() returned " + "%zd:%s", rv, nghttp2_strerror((int)rv)); + *err = CURLE_RECV_ERROR; + return -1; + } + Curl_bufq_skip(&ctx->inbufq, (size_t)rv); + if(Curl_bufq_is_empty(&ctx->inbufq)) { + CURL_TRC_CF(data, cf, "[0] all data in connection buffer processed"); + break; + } + else { + CURL_TRC_CF(data, cf, "[0] process_pending_input: %zu bytes left " + "in connection buffer", Curl_bufq_len(&ctx->inbufq)); + } + } + + return 0; +} + +static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + ssize_t nread; + + /* Process network input buffer fist */ + if(!Curl_bufq_is_empty(&ctx->inbufq)) { + CURL_TRC_CF(data, cf, "[0] process %zu bytes in connection buffer", + Curl_bufq_len(&ctx->inbufq)); + if(proxy_h2_process_pending_input(cf, data, &result) < 0) + return result; + } + + /* Receive data from the "lower" filters, e.g. network until + * it is time to stop or we have enough data for this stream */ + while(!ctx->conn_closed && /* not closed the connection */ + !ctx->tunnel.closed && /* nor the tunnel */ + Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */ + !Curl_bufq_is_full(&ctx->tunnel.recvbuf)) { + + nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result); + CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %zd, %d", + Curl_bufq_len(&ctx->inbufq), nread, result); + if(nread < 0) { + if(result != CURLE_AGAIN) { + failf(data, "Failed receiving HTTP2 data"); + return result; + } + break; + } + else if(nread == 0) { + ctx->conn_closed = TRUE; + break; + } + + if(proxy_h2_process_pending_input(cf, data, &result)) + return result; + } + + if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { + connclose(cf->conn, "GOAWAY received"); + } + + return CURLE_OK; +} + +static CURLcode proxy_h2_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + int rv = 0; + + ctx->nw_out_blocked = 0; + while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2)) + rv = nghttp2_session_send(ctx->h2); + + if(nghttp2_is_fatal(rv)) { + CURL_TRC_CF(data, cf, "[0] nghttp2_session_send error (%s)%d", + nghttp2_strerror(rv), rv); + return CURLE_SEND_ERROR; + } + return proxy_h2_nw_out_flush(cf, data); +} + +static ssize_t on_session_send(nghttp2_session *h2, + const uint8_t *buf, size_t blen, int flags, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_proxy_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result = CURLE_OK; + + (void)h2; + (void)flags; + DEBUGASSERT(data); + + nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, + proxy_h2_nw_out_writer, cf, &result); + if(nwritten < 0) { + if(result == CURLE_AGAIN) { + return NGHTTP2_ERR_WOULDBLOCK; + } + failf(data, "Failed sending HTTP2 data"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + if(!nwritten) + return NGHTTP2_ERR_WOULDBLOCK; + + return nwritten; +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static int proxy_h2_fr_print(const nghttp2_frame *frame, + char *buffer, size_t blen) +{ + switch(frame->hd.type) { + case NGHTTP2_DATA: { + return msnprintf(buffer, blen, + "FRAME[DATA, len=%d, eos=%d, padlen=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), + (int)frame->data.padlen); + } + case NGHTTP2_HEADERS: { + return msnprintf(buffer, blen, + "FRAME[HEADERS, len=%d, hend=%d, eos=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); + } + case NGHTTP2_PRIORITY: { + return msnprintf(buffer, blen, + "FRAME[PRIORITY, len=%d, flags=%d]", + (int)frame->hd.length, frame->hd.flags); + } + case NGHTTP2_RST_STREAM: { + return msnprintf(buffer, blen, + "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]", + (int)frame->hd.length, frame->hd.flags, + frame->rst_stream.error_code); + } + case NGHTTP2_SETTINGS: { + if(frame->hd.flags & NGHTTP2_FLAG_ACK) { + return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]"); + } + return msnprintf(buffer, blen, + "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); + } + case NGHTTP2_PUSH_PROMISE: { + return msnprintf(buffer, blen, + "FRAME[PUSH_PROMISE, len=%d, hend=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); + } + case NGHTTP2_PING: { + return msnprintf(buffer, blen, + "FRAME[PING, len=%d, ack=%d]", + (int)frame->hd.length, + frame->hd.flags&NGHTTP2_FLAG_ACK); + } + case NGHTTP2_GOAWAY: { + char scratch[128]; + size_t s_len = sizeof(scratch)/sizeof(scratch[0]); + size_t len = (frame->goaway.opaque_data_len < s_len)? + frame->goaway.opaque_data_len : s_len-1; + if(len) + memcpy(scratch, frame->goaway.opaque_data, len); + scratch[len] = '\0'; + return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', " + "last_stream=%d]", frame->goaway.error_code, + scratch, frame->goaway.last_stream_id); + } + case NGHTTP2_WINDOW_UPDATE: { + return msnprintf(buffer, blen, + "FRAME[WINDOW_UPDATE, incr=%d]", + frame->window_update.window_size_increment); + } + default: + return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]", + frame->hd.type, (int)frame->hd.length, + frame->hd.flags); + } +} + +static int proxy_h2_on_frame_send(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + + (void)session; + DEBUGASSERT(data); + if(data && Curl_trc_cf_is_verbose(cf, data)) { + char buffer[256]; + int len; + len = proxy_h2_fr_print(frame, buffer, sizeof(buffer)-1); + buffer[len] = 0; + CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer); + } + return 0; +} +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ + +static int proxy_h2_on_frame_recv(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_proxy_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + int32_t stream_id = frame->hd.stream_id; + + (void)session; + DEBUGASSERT(data); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_cf_is_verbose(cf, data)) { + char buffer[256]; + int len; + len = proxy_h2_fr_print(frame, buffer, sizeof(buffer)-1); + buffer[len] = 0; + CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer); + } +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ + + if(!stream_id) { + /* stream ID zero is for connection-oriented stuff */ + DEBUGASSERT(data); + switch(frame->hd.type) { + case NGHTTP2_SETTINGS: + /* Since the initial stream window is 64K, a request might be on HOLD, + * due to exhaustion. The (initial) SETTINGS may announce a much larger + * window and *assume* that we treat this like a WINDOW_UPDATE. Some + * servers send an explicit WINDOW_UPDATE, but not all seem to do that. + * To be safe, we UNHOLD a stream in order not to stall. */ + if(CURL_WANT_SEND(data)) { + drain_tunnel(cf, data, &ctx->tunnel); + } + break; + case NGHTTP2_GOAWAY: + ctx->goaway = TRUE; + break; + default: + break; + } + return 0; + } + + if(stream_id != ctx->tunnel.stream_id) { + CURL_TRC_CF(data, cf, "[%d] rcvd FRAME not for tunnel", stream_id); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + switch(frame->hd.type) { + case NGHTTP2_HEADERS: + /* nghttp2 guarantees that :status is received, and we store it to + stream->status_code. Fuzzing has proven this can still be reached + without status code having been set. */ + if(!ctx->tunnel.resp) + return NGHTTP2_ERR_CALLBACK_FAILURE; + /* Only final status code signals the end of header */ + CURL_TRC_CF(data, cf, "[%d] got http status: %d", + stream_id, ctx->tunnel.resp->status); + if(!ctx->tunnel.has_final_response) { + if(ctx->tunnel.resp->status / 100 != 1) { + ctx->tunnel.has_final_response = TRUE; + } + } + break; + case NGHTTP2_WINDOW_UPDATE: + if(CURL_WANT_SEND(data)) { + drain_tunnel(cf, data, &ctx->tunnel); + } + break; + default: + break; + } + return 0; +} + +static int proxy_h2_on_header(nghttp2_session *session, + const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_proxy_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + int32_t stream_id = frame->hd.stream_id; + CURLcode result; + + (void)flags; + (void)data; + (void)session; + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ + if(stream_id != ctx->tunnel.stream_id) { + CURL_TRC_CF(data, cf, "[%d] header for non-tunnel stream: " + "%.*s: %.*s", stream_id, + (int)namelen, name, (int)valuelen, value); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + if(frame->hd.type == NGHTTP2_PUSH_PROMISE) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + if(ctx->tunnel.has_final_response) { + /* we do not do anything with trailers for tunnel streams */ + return 0; + } + + if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 && + memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) { + int http_status; + struct http_resp *resp; + + /* status: always comes first, we might get more than one response, + * link the previous ones for keepers */ + result = Curl_http_decode_status(&http_status, + (const char *)value, valuelen); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + result = Curl_http_resp_make(&resp, http_status, NULL); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + resp->prev = ctx->tunnel.resp; + ctx->tunnel.resp = resp; + CURL_TRC_CF(data, cf, "[%d] status: HTTP/2 %03d", + stream_id, ctx->tunnel.resp->status); + return 0; + } + + if(!ctx->tunnel.resp) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + result = Curl_dynhds_add(&ctx->tunnel.resp->headers, + (const char *)name, namelen, + (const char *)value, valuelen); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + CURL_TRC_CF(data, cf, "[%d] header: %.*s: %.*s", + stream_id, (int)namelen, name, (int)valuelen, value); + + return 0; /* 0 is successful */ +} + +static ssize_t tunnel_send_callback(nghttp2_session *session, + int32_t stream_id, + uint8_t *buf, size_t length, + uint32_t *data_flags, + nghttp2_data_source *source, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_proxy_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + struct tunnel_stream *ts; + CURLcode result; + ssize_t nread; + + (void)source; + (void)data; + (void)ctx; + + if(!stream_id) + return NGHTTP2_ERR_INVALID_ARGUMENT; + + ts = nghttp2_session_get_stream_user_data(session, stream_id); + if(!ts) + return NGHTTP2_ERR_CALLBACK_FAILURE; + DEBUGASSERT(ts == &ctx->tunnel); + + nread = Curl_bufq_read(&ts->sendbuf, buf, length, &result); + if(nread < 0) { + if(result != CURLE_AGAIN) + return NGHTTP2_ERR_CALLBACK_FAILURE; + return NGHTTP2_ERR_DEFERRED; + } + if(ts->closed && Curl_bufq_is_empty(&ts->sendbuf)) + *data_flags = NGHTTP2_DATA_FLAG_EOF; + + CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd", + ts->stream_id, nread); + return nread; +} + +static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const uint8_t *mem, size_t len, void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_proxy_ctx *ctx = cf->ctx; + ssize_t nwritten; + CURLcode result; + + (void)flags; + (void)session; + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ + + if(stream_id != ctx->tunnel.stream_id) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + nwritten = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &result); + if(nwritten < 0) { + if(result != CURLE_AGAIN) + return NGHTTP2_ERR_CALLBACK_FAILURE; + nwritten = 0; + } + DEBUGASSERT((size_t)nwritten == len); + return 0; +} + +static int proxy_h2_on_stream_close(nghttp2_session *session, + int32_t stream_id, + uint32_t error_code, void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_proxy_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + + (void)session; + (void)data; + + if(stream_id != ctx->tunnel.stream_id) + return 0; + + CURL_TRC_CF(data, cf, "[%d] proxy_h2_on_stream_close, %s (err %d)", + stream_id, nghttp2_http2_strerror(error_code), error_code); + ctx->tunnel.closed = TRUE; + ctx->tunnel.error = error_code; + + return 0; +} + +static CURLcode proxy_h2_submit(int32_t *pstream_id, + struct Curl_cfilter *cf, + struct Curl_easy *data, + nghttp2_session *h2, + struct httpreq *req, + const nghttp2_priority_spec *pri_spec, + void *stream_user_data, + nghttp2_data_source_read_callback read_callback, + void *read_ctx) +{ + struct dynhds h2_headers; + nghttp2_nv *nva = NULL; + int32_t stream_id = -1; + size_t nheader; + CURLcode result; + + (void)cf; + Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); + result = Curl_http_req_to_h2(&h2_headers, req, data); + if(result) + goto out; + + nva = Curl_dynhds_to_nva(&h2_headers, &nheader); + if(!nva) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(read_callback) { + nghttp2_data_provider data_prd; + + data_prd.read_callback = read_callback; + data_prd.source.ptr = read_ctx; + stream_id = nghttp2_submit_request(h2, pri_spec, nva, nheader, + &data_prd, stream_user_data); + } + else { + stream_id = nghttp2_submit_request(h2, pri_spec, nva, nheader, + NULL, stream_user_data); + } + + if(stream_id < 0) { + failf(data, "nghttp2_session_upgrade2() failed: %s(%d)", + nghttp2_strerror(stream_id), stream_id); + result = CURLE_SEND_ERROR; + goto out; + } + result = CURLE_OK; + +out: + free(nva); + Curl_dynhds_free(&h2_headers); + *pstream_id = stream_id; + return result; +} + +static CURLcode submit_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct tunnel_stream *ts) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + CURLcode result; + struct httpreq *req = NULL; + + result = Curl_http_proxy_create_CONNECT(&req, cf, data, 2); + if(result) + goto out; + + infof(data, "Establish HTTP/2 proxy tunnel to %s", req->authority); + + result = proxy_h2_submit(&ts->stream_id, cf, data, ctx->h2, req, + NULL, ts, tunnel_send_callback, cf); + if(result) { + CURL_TRC_CF(data, cf, "[%d] send, nghttp2_submit_request error: %s", + ts->stream_id, nghttp2_strerror(ts->stream_id)); + } + +out: + if(req) + Curl_http_req_free(req); + if(result) + failf(data, "Failed sending CONNECT to proxy"); + return result; +} + +static CURLcode inspect_response(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct tunnel_stream *ts) +{ + CURLcode result = CURLE_OK; + struct dynhds_entry *auth_reply = NULL; + (void)cf; + + DEBUGASSERT(ts->resp); + if(ts->resp->status/100 == 2) { + infof(data, "CONNECT tunnel established, response %d", ts->resp->status); + h2_tunnel_go_state(cf, ts, H2_TUNNEL_ESTABLISHED, data); + return CURLE_OK; + } + + if(ts->resp->status == 401) { + auth_reply = Curl_dynhds_cget(&ts->resp->headers, "WWW-Authenticate"); + } + else if(ts->resp->status == 407) { + auth_reply = Curl_dynhds_cget(&ts->resp->headers, "Proxy-Authenticate"); + } + + if(auth_reply) { + CURL_TRC_CF(data, cf, "[0] CONNECT: fwd auth header '%s'", + auth_reply->value); + result = Curl_http_input_auth(data, ts->resp->status == 407, + auth_reply->value); + if(result) + return result; + if(data->req.newurl) { + /* Indicator that we should try again */ + Curl_safefree(data->req.newurl); + h2_tunnel_go_state(cf, ts, H2_TUNNEL_INIT, data); + return CURLE_OK; + } + } + + /* Seems to have failed */ + return CURLE_RECV_ERROR; +} + +static CURLcode H2_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct tunnel_stream *ts) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + DEBUGASSERT(ts); + DEBUGASSERT(ts->authority); + do { + switch(ts->state) { + case H2_TUNNEL_INIT: + /* Prepare the CONNECT request and make a first attempt to send. */ + CURL_TRC_CF(data, cf, "[0] CONNECT start for %s", ts->authority); + result = submit_CONNECT(cf, data, ts); + if(result) + goto out; + h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data); + FALLTHROUGH(); + + case H2_TUNNEL_CONNECT: + /* see that the request is completely sent */ + result = proxy_h2_progress_ingress(cf, data); + if(!result) + result = proxy_h2_progress_egress(cf, data); + if(result && result != CURLE_AGAIN) { + h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data); + break; + } + + if(ts->has_final_response) { + h2_tunnel_go_state(cf, ts, H2_TUNNEL_RESPONSE, data); + } + else { + result = CURLE_OK; + goto out; + } + FALLTHROUGH(); + + case H2_TUNNEL_RESPONSE: + DEBUGASSERT(ts->has_final_response); + result = inspect_response(cf, data, ts); + if(result) + goto out; + break; + + case H2_TUNNEL_ESTABLISHED: + return CURLE_OK; + + case H2_TUNNEL_FAILED: + return CURLE_RECV_ERROR; + + default: + break; + } + + } while(ts->state == H2_TUNNEL_INIT); + +out: + if(result || ctx->tunnel.closed) + h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data); + return result; +} + +static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + timediff_t check; + struct tunnel_stream *ts = &ctx->tunnel; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* Connect the lower filters first */ + if(!cf->next->connected) { + result = Curl_conn_cf_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + } + + *done = FALSE; + + CF_DATA_SAVE(save, cf, data); + if(!ctx->h2) { + result = cf_h2_proxy_ctx_init(cf, data); + if(result) + goto out; + } + DEBUGASSERT(ts->authority); + + check = Curl_timeleft(data, NULL, TRUE); + if(check <= 0) { + failf(data, "Proxy CONNECT aborted due to timeout"); + result = CURLE_OPERATION_TIMEDOUT; + goto out; + } + + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + result = H2_CONNECT(cf, data, ts); + +out: + *done = (result == CURLE_OK) && (ts->state == H2_TUNNEL_ESTABLISHED); + cf->connected = *done; + CF_DATA_RESTORE(cf, save); + return result; +} + +static void cf_h2_proxy_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + + if(ctx) { + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + cf_h2_proxy_ctx_clear(ctx); + CF_DATA_RESTORE(cf, save); + } + if(cf->next) + cf->next->cft->do_close(cf->next, data); +} + +static void cf_h2_proxy_destroy(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + + (void)data; + if(ctx) { + cf_h2_proxy_ctx_free(ctx); + cf->ctx = NULL; + } +} + +static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + if((ctx && !Curl_bufq_is_empty(&ctx->inbufq)) || + (ctx && ctx->tunnel.state == H2_TUNNEL_ESTABLISHED && + !Curl_bufq_is_empty(&ctx->tunnel.recvbuf))) + return TRUE; + return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE; +} + +static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); + bool want_recv, want_send; + + Curl_pollset_check(data, ps, sock, &want_recv, &want_send); + if(ctx->h2 && (want_recv || want_send)) { + struct cf_call_data save; + bool c_exhaust, s_exhaust; + + CF_DATA_SAVE(save, cf, data); + c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2); + s_exhaust = ctx->tunnel.stream_id >= 0 && + !nghttp2_session_get_stream_remote_window_size( + ctx->h2, ctx->tunnel.stream_id); + want_recv = (want_recv || c_exhaust || s_exhaust); + want_send = (!s_exhaust && want_send) || + (!c_exhaust && nghttp2_session_want_write(ctx->h2)); + + Curl_pollset_set(data, ps, sock, want_recv, want_send); + CF_DATA_RESTORE(cf, save); + } +} + +static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLcode *err) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + ssize_t rv = 0; + + if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) { + CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new " + "connection", ctx->tunnel.stream_id); + connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */ + *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ + return -1; + } + else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) { + failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)", + ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error), + ctx->tunnel.error); + *err = CURLE_HTTP2_STREAM; + return -1; + } + else if(ctx->tunnel.reset) { + failf(data, "HTTP/2 stream %u was reset", ctx->tunnel.stream_id); + *err = CURLE_RECV_ERROR; + return -1; + } + + *err = CURLE_OK; + rv = 0; + CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> %zd, %d", + ctx->tunnel.stream_id, rv, *err); + return rv; +} + +static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + ssize_t nread = -1; + + *err = CURLE_AGAIN; + if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) { + nread = Curl_bufq_read(&ctx->tunnel.recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) + goto out; + DEBUGASSERT(nread > 0); + } + + if(nread < 0) { + if(ctx->tunnel.closed) { + nread = h2_handle_tunnel_close(cf, data, err); + } + else if(ctx->tunnel.reset || + (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || + (ctx->goaway && ctx->last_stream_id < ctx->tunnel.stream_id)) { + *err = CURLE_RECV_ERROR; + nread = -1; + } + } + else if(nread == 0) { + *err = CURLE_AGAIN; + nread = -1; + } + +out: + CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %zd, %d", + ctx->tunnel.stream_id, len, nread, *err); + return nread; +} + +static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + ssize_t nread = -1; + struct cf_call_data save; + CURLcode result; + + if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) { + *err = CURLE_RECV_ERROR; + return -1; + } + CF_DATA_SAVE(save, cf, data); + + if(Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) { + *err = proxy_h2_progress_ingress(cf, data); + if(*err) + goto out; + } + + nread = tunnel_recv(cf, data, buf, len, err); + + if(nread > 0) { + CURL_TRC_CF(data, cf, "[%d] increase window by %zd", + ctx->tunnel.stream_id, nread); + nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread); + } + + result = proxy_h2_progress_egress(cf, data); + if(result == CURLE_AGAIN) { + /* pending data to send, need to be called again. Ideally, we'd + * monitor the socket for POLLOUT, but we might not be in SENDING + * transfer state any longer and are unable to make this happen. + */ + CURL_TRC_CF(data, cf, "[%d] egress blocked, DRAIN", + ctx->tunnel.stream_id); + drain_tunnel(cf, data, &ctx->tunnel); + } + else if(result) { + *err = result; + nread = -1; + } + +out: + if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) && + (nread >= 0 || *err == CURLE_AGAIN)) { + /* data pending and no fatal error to report. Need to trigger + * draining to avoid stalling when no socket events happen. */ + drain_tunnel(cf, data, &ctx->tunnel); + } + CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d", + ctx->tunnel.stream_id, len, nread, *err); + CF_DATA_RESTORE(cf, save); + return nread; +} + +static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + struct cf_call_data save; + int rv; + ssize_t nwritten; + CURLcode result; + int blocked = 0; + + if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) { + *err = CURLE_SEND_ERROR; + return -1; + } + CF_DATA_SAVE(save, cf, data); + + if(ctx->tunnel.closed) { + nwritten = -1; + *err = CURLE_SEND_ERROR; + goto out; + } + else if(ctx->tunnel.upload_blocked_len) { + /* the data in `buf` has already been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + DEBUGASSERT(len >= ctx->tunnel.upload_blocked_len); + if(len < ctx->tunnel.upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happen. We are not prepared to handle that. */ + failf(data, "HTTP/2 proxy, send again with decreased length"); + *err = CURLE_HTTP2; + nwritten = -1; + goto out; + } + nwritten = (ssize_t)ctx->tunnel.upload_blocked_len; + ctx->tunnel.upload_blocked_len = 0; + *err = CURLE_OK; + } + else { + nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err); + if(nwritten < 0) { + if(*err != CURLE_AGAIN) + goto out; + nwritten = 0; + } + } + + if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) { + /* req body data is buffered, resume the potentially suspended stream */ + rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id); + if(nghttp2_is_fatal(rv)) { + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + } + + result = proxy_h2_progress_ingress(cf, data); + if(result) { + *err = result; + nwritten = -1; + goto out; + } + + /* Call the nghttp2 send loop and flush to write ALL buffered data, + * headers and/or request body completely out to the network */ + result = proxy_h2_progress_egress(cf, data); + if(result == CURLE_AGAIN) { + blocked = 1; + } + else if(result) { + *err = result; + nwritten = -1; + goto out; + } + else if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) { + /* although we wrote everything that nghttp2 wants to send now, + * there is data left in our stream send buffer unwritten. This may + * be due to the stream's HTTP/2 flow window being exhausted. */ + blocked = 1; + } + + if(blocked) { + /* Unable to send all data, due to connection blocked or H2 window + * exhaustion. Data is left in our stream buffer, or nghttp2's internal + * frame buffer or our network out buffer. */ + size_t rwin = nghttp2_session_get_stream_remote_window_size( + ctx->h2, ctx->tunnel.stream_id); + if(rwin == 0) { + /* H2 flow window exhaustion. + * FIXME: there is no way to HOLD all transfers that use this + * proxy connection AND to UNHOLD all of them again when the + * window increases. + * We *could* iterate over all data on this conn maybe? */ + CURL_TRC_CF(data, cf, "[%d] remote flow " + "window is exhausted", ctx->tunnel.stream_id); + } + + /* Whatever the cause, we need to return CURL_EAGAIN for this call. + * We have unwritten state that needs us being invoked again and EAGAIN + * is the only way to ensure that. */ + ctx->tunnel.upload_blocked_len = nwritten; + CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu " + "blocked_len=%zu", + ctx->tunnel.stream_id, len, + nghttp2_session_get_remote_window_size(ctx->h2), rwin, + nwritten); + drain_tunnel(cf, data, &ctx->tunnel); + *err = CURLE_AGAIN; + nwritten = -1; + goto out; + } + else if(proxy_h2_should_close_session(ctx)) { + /* nghttp2 thinks this session is done. If the stream has not been + * closed, this is an error state for out transfer */ + if(ctx->tunnel.closed) { + *err = CURLE_SEND_ERROR; + nwritten = -1; + } + else { + CURL_TRC_CF(data, cf, "[0] send: nothing to do in this session"); + *err = CURLE_HTTP2; + nwritten = -1; + } + } + +out: + if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) && + (nwritten >= 0 || *err == CURLE_AGAIN)) { + /* data pending and no fatal error to report. Need to trigger + * draining to avoid stalling when no socket events happen. */ + drain_tunnel(cf, data, &ctx->tunnel); + } + CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, " + "h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)", + ctx->tunnel.stream_id, len, nwritten, *err, + nghttp2_session_get_stream_remote_window_size( + ctx->h2, ctx->tunnel.stream_id), + nghttp2_session_get_remote_window_size(ctx->h2), + Curl_bufq_len(&ctx->tunnel.sendbuf), + Curl_bufq_len(&ctx->outbufq)); + CF_DATA_RESTORE(cf, save); + return nwritten; +} + +static bool proxy_h2_connisalive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + bool alive = TRUE; + + *input_pending = FALSE; + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + return FALSE; + + if(*input_pending) { + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + CURLcode result; + ssize_t nread = -1; + + *input_pending = FALSE; + nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result); + if(nread != -1) { + if(proxy_h2_process_pending_input(cf, data, &result) < 0) + /* immediate error, considered dead */ + alive = FALSE; + else { + alive = !proxy_h2_should_close_session(ctx); + } + } + else if(result != CURLE_AGAIN) { + /* the read failed so let's say this is dead anyway */ + alive = FALSE; + } + } + + return alive; +} + +static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + CURLcode result; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending)); + CURL_TRC_CF(data, cf, "[0] conn alive -> %d, input_pending=%d", + result, *input_pending); + CF_DATA_RESTORE(cf, save); + return result; +} + +struct Curl_cftype Curl_cft_h2_proxy = { + "H2-PROXY", + CF_TYPE_IP_CONNECT, + CURL_LOG_LVL_NONE, + cf_h2_proxy_destroy, + cf_h2_proxy_connect, + cf_h2_proxy_close, + Curl_cf_http_proxy_get_host, + cf_h2_proxy_adjust_pollset, + cf_h2_proxy_data_pending, + cf_h2_proxy_send, + cf_h2_proxy_recv, + Curl_cf_def_cntrl, + cf_h2_proxy_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, +}; + +CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf_h2_proxy = NULL; + struct cf_h2_proxy_ctx *ctx; + CURLcode result = CURLE_OUT_OF_MEMORY; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) + goto out; + + result = Curl_cf_create(&cf_h2_proxy, &Curl_cft_h2_proxy, ctx); + if(result) + goto out; + + Curl_conn_cf_insert_after(cf, cf_h2_proxy); + result = CURLE_OK; + +out: + if(result) + cf_h2_proxy_ctx_free(ctx); + return result; +} + +#endif /* defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) */ diff --git a/lib/cf-h2-proxy.h b/lib/cf-h2-proxy.h new file mode 100644 index 0000000..c01bf62 --- /dev/null +++ b/lib/cf-h2-proxy.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_H2_PROXY_H +#define HEADER_CURL_H2_PROXY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) + +CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf, + struct Curl_easy *data); + +extern struct Curl_cftype Curl_cft_h2_proxy; + + +#endif /* defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) */ + +#endif /* HEADER_CURL_H2_PROXY_H */ diff --git a/lib/cf-haproxy.c b/lib/cf-haproxy.c new file mode 100644 index 0000000..c062887 --- /dev/null +++ b/lib/cf-haproxy.c @@ -0,0 +1,245 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_PROXY) + +#include +#include "urldata.h" +#include "cfilters.h" +#include "cf-haproxy.h" +#include "curl_trc.h" +#include "multiif.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +typedef enum { + HAPROXY_INIT, /* init/default/no tunnel state */ + HAPROXY_SEND, /* data_out being sent */ + HAPROXY_DONE /* all work done */ +} haproxy_state; + +struct cf_haproxy_ctx { + int state; + struct dynbuf data_out; +}; + +static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx) +{ + DEBUGASSERT(ctx); + ctx->state = HAPROXY_INIT; + Curl_dyn_reset(&ctx->data_out); +} + +static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx) +{ + if(ctx) { + Curl_dyn_free(&ctx->data_out); + free(ctx); + } +} + +static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf, + struct Curl_easy *data) +{ + struct cf_haproxy_ctx *ctx = cf->ctx; + CURLcode result; + const char *tcp_version; + const char *client_ip; + + DEBUGASSERT(ctx); + DEBUGASSERT(ctx->state == HAPROXY_INIT); +#ifdef USE_UNIX_SOCKETS + if(cf->conn->unix_domain_socket) + /* the buffer is large enough to hold this! */ + result = Curl_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n")); + else { +#endif /* USE_UNIX_SOCKETS */ + /* Emit the correct prefix for IPv6 */ + tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4"; + if(data->set.str[STRING_HAPROXY_CLIENT_IP]) + client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP]; + else + client_ip = data->info.conn_local_ip; + + result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n", + tcp_version, + client_ip, + data->info.conn_primary_ip, + data->info.conn_local_port, + data->info.conn_primary_port); + +#ifdef USE_UNIX_SOCKETS + } +#endif /* USE_UNIX_SOCKETS */ + return result; +} + +static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_haproxy_ctx *ctx = cf->ctx; + CURLcode result; + size_t len; + + DEBUGASSERT(ctx); + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + result = cf->next->cft->do_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + + switch(ctx->state) { + case HAPROXY_INIT: + result = cf_haproxy_date_out_set(cf, data); + if(result) + goto out; + ctx->state = HAPROXY_SEND; + FALLTHROUGH(); + case HAPROXY_SEND: + len = Curl_dyn_len(&ctx->data_out); + if(len > 0) { + ssize_t written = Curl_conn_send(data, cf->sockindex, + Curl_dyn_ptr(&ctx->data_out), + len, &result); + if(written < 0) + goto out; + Curl_dyn_tail(&ctx->data_out, len - (size_t)written); + if(Curl_dyn_len(&ctx->data_out) > 0) { + result = CURLE_OK; + goto out; + } + } + ctx->state = HAPROXY_DONE; + FALLTHROUGH(); + default: + Curl_dyn_free(&ctx->data_out); + break; + } + +out: + *done = (!result) && (ctx->state == HAPROXY_DONE); + cf->connected = *done; + return result; +} + +static void cf_haproxy_destroy(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + (void)data; + CURL_TRC_CF(data, cf, "destroy"); + cf_haproxy_ctx_free(cf->ctx); +} + +static void cf_haproxy_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURL_TRC_CF(data, cf, "close"); + cf->connected = FALSE; + cf_haproxy_ctx_reset(cf->ctx); + if(cf->next) + cf->next->cft->do_close(cf->next, data); +} + +static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + if(cf->next->connected && !cf->connected) { + /* If we are not connected, but the filter "below" is + * and not waiting on something, we are sending. */ + Curl_pollset_set_out_only(data, ps, Curl_conn_cf_get_socket(cf, data)); + } +} + +struct Curl_cftype Curl_cft_haproxy = { + "HAPROXY", + 0, + 0, + cf_haproxy_destroy, + cf_haproxy_connect, + cf_haproxy_close, + Curl_cf_def_get_host, + cf_haproxy_adjust_pollset, + Curl_cf_def_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, +}; + +static CURLcode cf_haproxy_create(struct Curl_cfilter **pcf, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf = NULL; + struct cf_haproxy_ctx *ctx; + CURLcode result; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + ctx->state = HAPROXY_INIT; + Curl_dyn_init(&ctx->data_out, DYN_HAXPROXY); + + result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx); + if(result) + goto out; + ctx = NULL; + +out: + cf_haproxy_ctx_free(ctx); + *pcf = result? NULL : cf; + return result; +} + +CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + CURLcode result; + + result = cf_haproxy_create(&cf, data); + if(result) + goto out; + Curl_conn_cf_insert_after(cf_at, cf); + +out: + return result; +} + +#endif /* !CURL_DISABLE_PROXY */ diff --git a/lib/cf-haproxy.h b/lib/cf-haproxy.h new file mode 100644 index 0000000..d02c323 --- /dev/null +++ b/lib/cf-haproxy.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_CF_HAPROXY_H +#define HEADER_CURL_CF_HAPROXY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "urldata.h" + +#if !defined(CURL_DISABLE_PROXY) + +CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data); + +extern struct Curl_cftype Curl_cft_haproxy; + +#endif /* !CURL_DISABLE_PROXY */ + +#endif /* HEADER_CURL_CF_HAPROXY_H */ diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c new file mode 100644 index 0000000..b23fa05 --- /dev/null +++ b/lib/cf-https-connect.c @@ -0,0 +1,531 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) + +#include "urldata.h" +#include +#include "curl_trc.h" +#include "cfilters.h" +#include "connect.h" +#include "multiif.h" +#include "cf-https-connect.h" +#include "http2.h" +#include "vquic/vquic.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +typedef enum { + CF_HC_INIT, + CF_HC_CONNECT, + CF_HC_SUCCESS, + CF_HC_FAILURE +} cf_hc_state; + +struct cf_hc_baller { + const char *name; + struct Curl_cfilter *cf; + CURLcode result; + struct curltime started; + int reply_ms; + bool enabled; +}; + +static void cf_hc_baller_reset(struct cf_hc_baller *b, + struct Curl_easy *data) +{ + if(b->cf) { + Curl_conn_cf_close(b->cf, data); + Curl_conn_cf_discard_chain(&b->cf, data); + b->cf = NULL; + } + b->result = CURLE_OK; + b->reply_ms = -1; +} + +static bool cf_hc_baller_is_active(struct cf_hc_baller *b) +{ + return b->enabled && b->cf && !b->result; +} + +static bool cf_hc_baller_has_started(struct cf_hc_baller *b) +{ + return !!b->cf; +} + +static int cf_hc_baller_reply_ms(struct cf_hc_baller *b, + struct Curl_easy *data) +{ + if(b->reply_ms < 0) + b->cf->cft->query(b->cf, data, CF_QUERY_CONNECT_REPLY_MS, + &b->reply_ms, NULL); + return b->reply_ms; +} + +static bool cf_hc_baller_data_pending(struct cf_hc_baller *b, + const struct Curl_easy *data) +{ + return b->cf && !b->result && b->cf->cft->has_data_pending(b->cf, data); +} + +struct cf_hc_ctx { + cf_hc_state state; + const struct Curl_dns_entry *remotehost; + struct curltime started; /* when connect started */ + CURLcode result; /* overall result */ + struct cf_hc_baller h3_baller; + struct cf_hc_baller h21_baller; + int soft_eyeballs_timeout_ms; + int hard_eyeballs_timeout_ms; +}; + +static void cf_hc_baller_init(struct cf_hc_baller *b, + struct Curl_cfilter *cf, + struct Curl_easy *data, + const char *name, + int transport) +{ + struct cf_hc_ctx *ctx = cf->ctx; + struct Curl_cfilter *save = cf->next; + + b->name = name; + cf->next = NULL; + b->started = Curl_now(); + b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost, + transport, CURL_CF_SSL_ENABLE); + b->cf = cf->next; + cf->next = save; +} + +static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + struct Curl_cfilter *save = cf->next; + + cf->next = b->cf; + b->result = Curl_conn_cf_connect(cf->next, data, FALSE, done); + b->cf = cf->next; /* it might mutate */ + cf->next = save; + return b->result; +} + +static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_hc_ctx *ctx = cf->ctx; + + if(ctx) { + cf_hc_baller_reset(&ctx->h3_baller, data); + cf_hc_baller_reset(&ctx->h21_baller, data); + ctx->state = CF_HC_INIT; + ctx->result = CURLE_OK; + ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout; + ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2; + } +} + +static CURLcode baller_connected(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_hc_baller *winner) +{ + struct cf_hc_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + DEBUGASSERT(winner->cf); + if(winner != &ctx->h3_baller) + cf_hc_baller_reset(&ctx->h3_baller, data); + if(winner != &ctx->h21_baller) + cf_hc_baller_reset(&ctx->h21_baller, data); + + CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms", + winner->name, (int)Curl_timediff(Curl_now(), winner->started), + cf_hc_baller_reply_ms(winner, data)); + cf->next = winner->cf; + winner->cf = NULL; + + switch(cf->conn->alpn) { + case CURL_HTTP_VERSION_3: + infof(data, "using HTTP/3"); + break; + case CURL_HTTP_VERSION_2: +#ifdef USE_NGHTTP2 + /* Using nghttp2, we add the filter "below" us, so when the conn + * closes, we tear it down for a fresh reconnect */ + result = Curl_http2_switch_at(cf, data); + if(result) { + ctx->state = CF_HC_FAILURE; + ctx->result = result; + return result; + } +#endif + infof(data, "using HTTP/2"); + break; + default: + infof(data, "using HTTP/1.x"); + break; + } + ctx->state = CF_HC_SUCCESS; + cf->connected = TRUE; + Curl_conn_cf_cntrl(cf->next, data, TRUE, + CF_CTRL_CONN_INFO_UPDATE, 0, NULL); + return result; +} + + +static bool time_to_start_h21(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct curltime now) +{ + struct cf_hc_ctx *ctx = cf->ctx; + timediff_t elapsed_ms; + + if(!ctx->h21_baller.enabled || cf_hc_baller_has_started(&ctx->h21_baller)) + return FALSE; + + if(!ctx->h3_baller.enabled || !cf_hc_baller_is_active(&ctx->h3_baller)) + return TRUE; + + elapsed_ms = Curl_timediff(now, ctx->started); + if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) { + CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting h21", + ctx->hard_eyeballs_timeout_ms); + return TRUE; + } + + if(elapsed_ms >= ctx->soft_eyeballs_timeout_ms) { + if(cf_hc_baller_reply_ms(&ctx->h3_baller, data) < 0) { + CURL_TRC_CF(data, cf, "soft timeout of %dms reached, h3 has not " + "seen any data, starting h21", + ctx->soft_eyeballs_timeout_ms); + return TRUE; + } + /* set the effective hard timeout again */ + Curl_expire(data, ctx->hard_eyeballs_timeout_ms - elapsed_ms, + EXPIRE_ALPN_EYEBALLS); + } + return FALSE; +} + +static CURLcode cf_hc_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_hc_ctx *ctx = cf->ctx; + struct curltime now; + CURLcode result = CURLE_OK; + + (void)blocking; + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + *done = FALSE; + now = Curl_now(); + switch(ctx->state) { + case CF_HC_INIT: + DEBUGASSERT(!ctx->h3_baller.cf); + DEBUGASSERT(!ctx->h21_baller.cf); + DEBUGASSERT(!cf->next); + CURL_TRC_CF(data, cf, "connect, init"); + ctx->started = now; + if(ctx->h3_baller.enabled) { + cf_hc_baller_init(&ctx->h3_baller, cf, data, "h3", TRNSPRT_QUIC); + if(ctx->h21_baller.enabled) + Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS); + } + else if(ctx->h21_baller.enabled) + cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", + cf->conn->transport); + ctx->state = CF_HC_CONNECT; + FALLTHROUGH(); + + case CF_HC_CONNECT: + if(cf_hc_baller_is_active(&ctx->h3_baller)) { + result = cf_hc_baller_connect(&ctx->h3_baller, cf, data, done); + if(!result && *done) { + result = baller_connected(cf, data, &ctx->h3_baller); + goto out; + } + } + + if(time_to_start_h21(cf, data, now)) { + cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", + cf->conn->transport); + } + + if(cf_hc_baller_is_active(&ctx->h21_baller)) { + CURL_TRC_CF(data, cf, "connect, check h21"); + result = cf_hc_baller_connect(&ctx->h21_baller, cf, data, done); + if(!result && *done) { + result = baller_connected(cf, data, &ctx->h21_baller); + goto out; + } + } + + if((!ctx->h3_baller.enabled || ctx->h3_baller.result) && + (!ctx->h21_baller.enabled || ctx->h21_baller.result)) { + /* both failed or disabled. we give up */ + CURL_TRC_CF(data, cf, "connect, all failed"); + result = ctx->result = ctx->h3_baller.enabled? + ctx->h3_baller.result : ctx->h21_baller.result; + ctx->state = CF_HC_FAILURE; + goto out; + } + result = CURLE_OK; + *done = FALSE; + break; + + case CF_HC_FAILURE: + result = ctx->result; + cf->connected = FALSE; + *done = FALSE; + break; + + case CF_HC_SUCCESS: + result = CURLE_OK; + cf->connected = TRUE; + *done = TRUE; + break; + } + +out: + CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done); + return result; +} + +static void cf_hc_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + if(!cf->connected) { + struct cf_hc_ctx *ctx = cf->ctx; + struct cf_hc_baller *ballers[2]; + size_t i; + + ballers[0] = &ctx->h3_baller; + ballers[1] = &ctx->h21_baller; + for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) { + struct cf_hc_baller *b = ballers[i]; + if(!cf_hc_baller_is_active(b)) + continue; + Curl_conn_cf_adjust_pollset(b->cf, data, ps); + } + CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num); + } +} + +static bool cf_hc_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct cf_hc_ctx *ctx = cf->ctx; + + if(cf->connected) + return cf->next->cft->has_data_pending(cf->next, data); + + CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending"); + return cf_hc_baller_data_pending(&ctx->h3_baller, data) + || cf_hc_baller_data_pending(&ctx->h21_baller, data); +} + +static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query) +{ + struct cf_hc_ctx *ctx = cf->ctx; + struct Curl_cfilter *cfb; + struct curltime t, tmax; + + memset(&tmax, 0, sizeof(tmax)); + memset(&t, 0, sizeof(t)); + cfb = ctx->h21_baller.enabled? ctx->h21_baller.cf : NULL; + if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { + if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) + tmax = t; + } + memset(&t, 0, sizeof(t)); + cfb = ctx->h3_baller.enabled? ctx->h3_baller.cf : NULL; + if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { + if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) + tmax = t; + } + return tmax; +} + +static CURLcode cf_hc_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + if(!cf->connected) { + switch(query) { + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); + return CURLE_OK; + } + default: + break; + } + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + CURL_TRC_CF(data, cf, "close"); + cf_hc_reset(cf, data); + cf->connected = FALSE; + + if(cf->next) { + cf->next->cft->do_close(cf->next, data); + Curl_conn_cf_discard_chain(&cf->next, data); + } +} + +static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_hc_ctx *ctx = cf->ctx; + + (void)data; + CURL_TRC_CF(data, cf, "destroy"); + cf_hc_reset(cf, data); + Curl_safefree(ctx); +} + +struct Curl_cftype Curl_cft_http_connect = { + "HTTPS-CONNECT", + 0, + CURL_LOG_LVL_NONE, + cf_hc_destroy, + cf_hc_connect, + cf_hc_close, + Curl_cf_def_get_host, + cf_hc_adjust_pollset, + cf_hc_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_hc_query, +}; + +static CURLcode cf_hc_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + const struct Curl_dns_entry *remotehost, + bool try_h3, bool try_h21) +{ + struct Curl_cfilter *cf = NULL; + struct cf_hc_ctx *ctx; + CURLcode result = CURLE_OK; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + ctx->remotehost = remotehost; + ctx->h3_baller.enabled = try_h3; + ctx->h21_baller.enabled = try_h21; + + result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx); + if(result) + goto out; + ctx = NULL; + cf_hc_reset(cf, data); + +out: + *pcf = result? NULL : cf; + free(ctx); + return result; +} + +static CURLcode cf_http_connect_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + const struct Curl_dns_entry *remotehost, + bool try_h3, bool try_h21) +{ + struct Curl_cfilter *cf; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + result = cf_hc_create(&cf, data, remotehost, try_h3, try_h21); + if(result) + goto out; + Curl_conn_cf_add(data, conn, sockindex, cf); +out: + return result; +} + +CURLcode Curl_cf_https_setup(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + const struct Curl_dns_entry *remotehost) +{ + bool try_h3 = FALSE, try_h21 = TRUE; /* defaults, for now */ + CURLcode result = CURLE_OK; + + (void)sockindex; + (void)remotehost; + + if(!conn->bits.tls_enable_alpn) + goto out; + + if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) { + result = Curl_conn_may_http3(data, conn); + if(result) /* can't do it */ + goto out; + try_h3 = TRUE; + try_h21 = FALSE; + } + else if(data->state.httpwant >= CURL_HTTP_VERSION_3) { + /* We assume that silently not even trying H3 is ok here */ + /* TODO: should we fail instead? */ + try_h3 = (Curl_conn_may_http3(data, conn) == CURLE_OK); + try_h21 = TRUE; + } + + result = cf_http_connect_add(data, conn, sockindex, remotehost, + try_h3, try_h21); +out: + return result; +} + +#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */ diff --git a/lib/cf-https-connect.h b/lib/cf-https-connect.h new file mode 100644 index 0000000..6a39527 --- /dev/null +++ b/lib/cf-https-connect.h @@ -0,0 +1,58 @@ +#ifndef HEADER_CURL_CF_HTTP_H +#define HEADER_CURL_CF_HTTP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) + +struct Curl_cfilter; +struct Curl_easy; +struct connectdata; +struct Curl_cftype; +struct Curl_dns_entry; + +extern struct Curl_cftype Curl_cft_http_connect; + +CURLcode Curl_cf_http_connect_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + const struct Curl_dns_entry *remotehost, + bool try_h3, bool try_h21); + +CURLcode +Curl_cf_http_connect_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data, + const struct Curl_dns_entry *remotehost, + bool try_h3, bool try_h21); + + +CURLcode Curl_cf_https_setup(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + const struct Curl_dns_entry *remotehost); + + +#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */ +#endif /* HEADER_CURL_CF_HTTP_H */ diff --git a/lib/cf-socket.c b/lib/cf-socket.c new file mode 100644 index 0000000..742902f --- /dev/null +++ b/lib/cf-socket.c @@ -0,0 +1,1985 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include /* may need it */ +#endif +#ifdef HAVE_SYS_UN_H +#include /* for sockaddr_un */ +#endif +#ifdef HAVE_LINUX_TCP_H +#include +#elif defined(HAVE_NETINET_TCP_H) +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "bufq.h" +#include "sendf.h" +#include "if2ip.h" +#include "strerror.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "connect.h" +#include "select.h" +#include "url.h" /* for Curl_safefree() */ +#include "multiif.h" +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "inet_ntop.h" +#include "inet_pton.h" +#include "progress.h" +#include "warnless.h" +#include "conncache.h" +#include "multihandle.h" +#include "rand.h" +#include "share.h" +#include "version_win32.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32) +/* It makes support for IPv4-mapped IPv6 addresses. + * Linux kernel, NetBSD, FreeBSD and Darwin: default is off; + * Windows Vista and later: default is on; + * DragonFly BSD: acts like off, and dummy setting; + * OpenBSD and earlier Windows: unsupported. + * Linux: controlled by /proc/sys/net/ipv6/bindv6only. + */ +static void set_ipv6_v6only(curl_socket_t sockfd, int on) +{ + (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)); +} +#else +#define set_ipv6_v6only(x,y) +#endif + +static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd) +{ +#if defined(TCP_NODELAY) + curl_socklen_t onoff = (curl_socklen_t) 1; + int level = IPPROTO_TCP; + char buffer[STRERROR_LEN]; + + if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, + sizeof(onoff)) < 0) + infof(data, "Could not set TCP_NODELAY: %s", + Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); +#else + (void)data; + (void)sockfd; +#endif +} + +#ifdef SO_NOSIGPIPE +/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when + sending data to a dead peer (instead of relying on the 4th argument to send + being MSG_NOSIGNAL). Possibly also existing and in use on other BSD + systems? */ +static void nosigpipe(struct Curl_easy *data, + curl_socket_t sockfd) +{ + int onoff = 1; + (void)data; + if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, + sizeof(onoff)) < 0) { +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + char buffer[STRERROR_LEN]; + infof(data, "Could not set SO_NOSIGPIPE: %s", + Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); +#endif + } +} +#else +#define nosigpipe(x,y) Curl_nop_stmt +#endif + +#if defined(__DragonFly__) || defined(USE_WINSOCK) +/* DragonFlyBSD and Windows use millisecond units */ +#define KEEPALIVE_FACTOR(x) (x *= 1000) +#else +#define KEEPALIVE_FACTOR(x) +#endif + +#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS) +#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) + +struct tcp_keepalive { + u_long onoff; + u_long keepalivetime; + u_long keepaliveinterval; +}; +#endif + +static void +tcpkeepalive(struct Curl_easy *data, + curl_socket_t sockfd) +{ + int optval = data->set.tcp_keepalive?1:0; + + /* only set IDLE and INTVL if setting KEEPALIVE is successful */ + if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set SO_KEEPALIVE on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); + } + else { +#if defined(SIO_KEEPALIVE_VALS) + struct tcp_keepalive vals; + DWORD dummy; + vals.onoff = 1; + optval = curlx_sltosi(data->set.tcp_keepidle); + KEEPALIVE_FACTOR(optval); + vals.keepalivetime = optval; + optval = curlx_sltosi(data->set.tcp_keepintvl); + KEEPALIVE_FACTOR(optval); + vals.keepaliveinterval = optval; + if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals), + NULL, 0, &dummy, NULL, NULL) != 0) { + infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); + } +#else +#ifdef TCP_KEEPIDLE + optval = curlx_sltosi(data->set.tcp_keepidle); + KEEPALIVE_FACTOR(optval); + if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set TCP_KEEPIDLE on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); + } +#elif defined(TCP_KEEPALIVE) + /* Mac OS X style */ + optval = curlx_sltosi(data->set.tcp_keepidle); + KEEPALIVE_FACTOR(optval); + if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set TCP_KEEPALIVE on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); + } +#endif +#ifdef TCP_KEEPINTVL + optval = curlx_sltosi(data->set.tcp_keepintvl); + KEEPALIVE_FACTOR(optval); + if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set TCP_KEEPINTVL on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); + } +#endif +#endif + } +} + +/** + * Assign the address `ai` to the Curl_sockaddr_ex `dest` and + * set the transport used. + */ +void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest, + const struct Curl_addrinfo *ai, + int transport) +{ + /* + * The Curl_sockaddr_ex structure is basically libcurl's external API + * curl_sockaddr structure with enough space available to directly hold + * any protocol-specific address structures. The variable declared here + * will be used to pass / receive data to/from the fopensocket callback + * if this has been set, before that, it is initialized from parameters. + */ + dest->family = ai->ai_family; + switch(transport) { + case TRNSPRT_TCP: + dest->socktype = SOCK_STREAM; + dest->protocol = IPPROTO_TCP; + break; + case TRNSPRT_UNIX: + dest->socktype = SOCK_STREAM; + dest->protocol = IPPROTO_IP; + break; + default: /* UDP and QUIC */ + dest->socktype = SOCK_DGRAM; + dest->protocol = IPPROTO_UDP; + break; + } + dest->addrlen = ai->ai_addrlen; + + if(dest->addrlen > sizeof(struct Curl_sockaddr_storage)) + dest->addrlen = sizeof(struct Curl_sockaddr_storage); + memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen); +} + +static CURLcode socket_open(struct Curl_easy *data, + struct Curl_sockaddr_ex *addr, + curl_socket_t *sockfd) +{ + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + if(data->set.fopensocket) { + /* + * If the opensocket callback is set, all the destination address + * information is passed to the callback. Depending on this information the + * callback may opt to abort the connection, this is indicated returning + * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When + * the callback returns a valid socket the destination address information + * might have been changed and this 'new' address will actually be used + * here to connect. + */ + Curl_set_in_callback(data, true); + *sockfd = data->set.fopensocket(data->set.opensocket_client, + CURLSOCKTYPE_IPCXN, + (struct curl_sockaddr *)addr); + Curl_set_in_callback(data, false); + } + else { + /* opensocket callback not set, so simply create the socket now */ + *sockfd = socket(addr->family, addr->socktype, addr->protocol); + } + + if(*sockfd == CURL_SOCKET_BAD) + /* no socket, no connection */ + return CURLE_COULDNT_CONNECT; + +#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) + if(data->conn->scope_id && (addr->family == AF_INET6)) { + struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr; + sa6->sin6_scope_id = data->conn->scope_id; + } +#endif + return CURLE_OK; +} + +/* + * Create a socket based on info from 'conn' and 'ai'. + * + * 'addr' should be a pointer to the correct struct to get data back, or NULL. + * 'sockfd' must be a pointer to a socket descriptor. + * + * If the open socket callback is set, used that! + * + */ +CURLcode Curl_socket_open(struct Curl_easy *data, + const struct Curl_addrinfo *ai, + struct Curl_sockaddr_ex *addr, + int transport, + curl_socket_t *sockfd) +{ + struct Curl_sockaddr_ex dummy; + + if(!addr) + /* if the caller doesn't want info back, use a local temp copy */ + addr = &dummy; + + Curl_sock_assign_addr(addr, ai, transport); + return socket_open(data, addr, sockfd); +} + +static int socket_close(struct Curl_easy *data, struct connectdata *conn, + int use_callback, curl_socket_t sock) +{ + if(use_callback && conn && conn->fclosesocket) { + int rc; + Curl_multi_closed(data, sock); + Curl_set_in_callback(data, true); + rc = conn->fclosesocket(conn->closesocket_client, sock); + Curl_set_in_callback(data, false); + return rc; + } + + if(conn) + /* tell the multi-socket code about this */ + Curl_multi_closed(data, sock); + + sclose(sock); + + return 0; +} + +/* + * Close a socket. + * + * 'conn' can be NULL, beware! + */ +int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t sock) +{ + return socket_close(data, conn, FALSE, sock); +} + +#ifdef USE_WINSOCK +/* When you run a program that uses the Windows Sockets API, you may + experience slow performance when you copy data to a TCP server. + + https://support.microsoft.com/kb/823764 + + Work-around: Make the Socket Send Buffer Size Larger Than the Program Send + Buffer Size + + The problem described in this knowledge-base is applied only to pre-Vista + Windows. Following function trying to detect OS version and skips + SO_SNDBUF adjustment for Windows Vista and above. +*/ +#define DETECT_OS_NONE 0 +#define DETECT_OS_PREVISTA 1 +#define DETECT_OS_VISTA_OR_LATER 2 + +void Curl_sndbufset(curl_socket_t sockfd) +{ + int val = CURL_MAX_WRITE_SIZE + 32; + int curval = 0; + int curlen = sizeof(curval); + + static int detectOsState = DETECT_OS_NONE; + + if(detectOsState == DETECT_OS_NONE) { + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) + detectOsState = DETECT_OS_VISTA_OR_LATER; + else + detectOsState = DETECT_OS_PREVISTA; + } + + if(detectOsState == DETECT_OS_VISTA_OR_LATER) + return; + + if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0) + if(curval > val) + return; + + setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val)); +} +#endif + +#ifndef CURL_DISABLE_BINDLOCAL +static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t sockfd, int af, unsigned int scope) +{ + struct Curl_sockaddr_storage sa; + struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */ + curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */ + struct sockaddr_in *si4 = (struct sockaddr_in *)&sa; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa; +#endif + + struct Curl_dns_entry *h = NULL; + unsigned short port = data->set.localport; /* use this port number, 0 for + "random" */ + /* how many port numbers to try to bind to, increasing one at a time */ + int portnum = data->set.localportrange; + const char *dev = data->set.str[STRING_DEVICE]; + int error; +#ifdef IP_BIND_ADDRESS_NO_PORT + int on = 1; +#endif +#ifndef ENABLE_IPV6 + (void)scope; +#endif + + /************************************************************* + * Select device to bind socket to + *************************************************************/ + if(!dev && !port) + /* no local kind of binding was requested */ + return CURLE_OK; + + memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); + + if(dev && (strlen(dev)<255) ) { + char myhost[256] = ""; + int done = 0; /* -1 for error, 1 for address found */ + bool is_interface = FALSE; + bool is_host = FALSE; + static const char *if_prefix = "if!"; + static const char *host_prefix = "host!"; + + if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) { + dev += strlen(if_prefix); + is_interface = TRUE; + } + else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) { + dev += strlen(host_prefix); + is_host = TRUE; + } + + /* interface */ + if(!is_host) { +#ifdef SO_BINDTODEVICE + /* + * This binds the local socket to a particular interface. This will + * force even requests to other local interfaces to go out the external + * interface. Only bind to the interface when specified as interface, + * not just as a hostname or ip address. + * + * The interface might be a VRF, eg: vrf-blue, which means it cannot be + * converted to an IP address and would fail Curl_if2ip. Simply try to + * use it straight away. + */ + if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + dev, (curl_socklen_t)strlen(dev) + 1) == 0) { + /* This is often "errno 1, error: Operation not permitted" if you're + * not running as root or another suitable privileged user. If it + * succeeds it means the parameter was a valid interface and not an IP + * address. Return immediately. + */ + infof(data, "socket successfully bound to interface '%s'", dev); + return CURLE_OK; + } +#endif + + switch(Curl_if2ip(af, +#ifdef ENABLE_IPV6 + scope, conn->scope_id, +#endif + dev, myhost, sizeof(myhost))) { + case IF2IP_NOT_FOUND: + if(is_interface) { + /* Do not fall back to treating it as a host name */ + failf(data, "Couldn't bind to interface '%s'", dev); + return CURLE_INTERFACE_FAILED; + } + break; + case IF2IP_AF_NOT_SUPPORTED: + /* Signal the caller to try another address family if available */ + return CURLE_UNSUPPORTED_PROTOCOL; + case IF2IP_FOUND: + is_interface = TRUE; + /* + * We now have the numerical IP address in the 'myhost' buffer + */ + infof(data, "Local Interface %s is ip %s using address family %i", + dev, myhost, af); + done = 1; + break; + } + } + if(!is_interface) { + /* + * This was not an interface, resolve the name as a host name + * or IP number + * + * Temporarily force name resolution to use only the address type + * of the connection. The resolve functions should really be changed + * to take a type parameter instead. + */ + unsigned char ipver = conn->ip_version; + int rc; + + if(af == AF_INET) + conn->ip_version = CURL_IPRESOLVE_V4; +#ifdef ENABLE_IPV6 + else if(af == AF_INET6) + conn->ip_version = CURL_IPRESOLVE_V6; +#endif + + rc = Curl_resolv(data, dev, 80, FALSE, &h); + if(rc == CURLRESOLV_PENDING) + (void)Curl_resolver_wait_resolv(data, &h); + conn->ip_version = ipver; + + if(h) { + /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ + Curl_printable_address(h->addr, myhost, sizeof(myhost)); + infof(data, "Name '%s' family %i resolved to '%s' family %i", + dev, af, myhost, h->addr->ai_family); + Curl_resolv_unlock(data, h); + if(af != h->addr->ai_family) { + /* bad IP version combo, signal the caller to try another address + family if available */ + return CURLE_UNSUPPORTED_PROTOCOL; + } + done = 1; + } + else { + /* + * provided dev was no interface (or interfaces are not supported + * e.g. solaris) no ip address and no domain we fail here + */ + done = -1; + } + } + + if(done > 0) { +#ifdef ENABLE_IPV6 + /* IPv6 address */ + if(af == AF_INET6) { +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + char *scope_ptr = strchr(myhost, '%'); + if(scope_ptr) + *(scope_ptr++) = '\0'; +#endif + if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) { + si6->sin6_family = AF_INET6; + si6->sin6_port = htons(port); +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + if(scope_ptr) { + /* The "myhost" string either comes from Curl_if2ip or from + Curl_printable_address. The latter returns only numeric scope + IDs and the former returns none at all. So the scope ID, if + present, is known to be numeric */ + unsigned long scope_id = strtoul(scope_ptr, NULL, 10); + if(scope_id > UINT_MAX) + return CURLE_UNSUPPORTED_PROTOCOL; + + si6->sin6_scope_id = (unsigned int)scope_id; + } +#endif + } + sizeof_sa = sizeof(struct sockaddr_in6); + } + else +#endif + /* IPv4 address */ + if((af == AF_INET) && + (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) { + si4->sin_family = AF_INET; + si4->sin_port = htons(port); + sizeof_sa = sizeof(struct sockaddr_in); + } + } + + if(done < 1) { + /* errorbuf is set false so failf will overwrite any message already in + the error buffer, so the user receives this error message instead of a + generic resolve error. */ + data->state.errorbuf = FALSE; + failf(data, "Couldn't bind to '%s'", dev); + return CURLE_INTERFACE_FAILED; + } + } + else { + /* no device was given, prepare sa to match af's needs */ +#ifdef ENABLE_IPV6 + if(af == AF_INET6) { + si6->sin6_family = AF_INET6; + si6->sin6_port = htons(port); + sizeof_sa = sizeof(struct sockaddr_in6); + } + else +#endif + if(af == AF_INET) { + si4->sin_family = AF_INET; + si4->sin_port = htons(port); + sizeof_sa = sizeof(struct sockaddr_in); + } + } +#ifdef IP_BIND_ADDRESS_NO_PORT + (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on)); +#endif + for(;;) { + if(bind(sockfd, sock, sizeof_sa) >= 0) { + /* we succeeded to bind */ + struct Curl_sockaddr_storage add; + curl_socklen_t size = sizeof(add); + memset(&add, 0, sizeof(struct Curl_sockaddr_storage)); + if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { + char buffer[STRERROR_LEN]; + data->state.os_errno = error = SOCKERRNO; + failf(data, "getsockname() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return CURLE_INTERFACE_FAILED; + } + infof(data, "Local port: %hu", port); + conn->bits.bound = TRUE; + return CURLE_OK; + } + + if(--portnum > 0) { + port++; /* try next port */ + if(port == 0) + break; + infof(data, "Bind to local port %d failed, trying next", port - 1); + /* We reuse/clobber the port variable here below */ + if(sock->sa_family == AF_INET) + si4->sin_port = ntohs(port); +#ifdef ENABLE_IPV6 + else + si6->sin6_port = ntohs(port); +#endif + } + else + break; + } + { + char buffer[STRERROR_LEN]; + data->state.os_errno = error = SOCKERRNO; + failf(data, "bind failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + } + + return CURLE_INTERFACE_FAILED; +} +#endif + +/* + * verifyconnect() returns TRUE if the connect really has happened. + */ +static bool verifyconnect(curl_socket_t sockfd, int *error) +{ + bool rc = TRUE; +#ifdef SO_ERROR + int err = 0; + curl_socklen_t errSize = sizeof(err); + +#ifdef _WIN32 + /* + * In October 2003 we effectively nullified this function on Windows due to + * problems with it using all CPU in multi-threaded cases. + * + * In May 2004, we bring it back to offer more info back on connect failures. + * Gisle Vanem could reproduce the former problems with this function, but + * could avoid them by adding this SleepEx() call below: + * + * "I don't have Rational Quantify, but the hint from his post was + * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe + * just Sleep(0) would be enough?) would release whatever + * mutex/critical-section the ntdll call is waiting on. + * + * Someone got to verify this on Win-NT 4.0, 2000." + */ + +#ifdef _WIN32_WCE + Sleep(0); +#else + SleepEx(0, FALSE); +#endif + +#endif + + if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize)) + err = SOCKERRNO; +#ifdef _WIN32_WCE + /* Old WinCE versions don't support SO_ERROR */ + if(WSAENOPROTOOPT == err) { + SET_SOCKERRNO(0); + err = 0; + } +#endif +#if defined(EBADIOCTL) && defined(__minix) + /* Minix 3.1.x doesn't support getsockopt on UDP sockets */ + if(EBADIOCTL == err) { + SET_SOCKERRNO(0); + err = 0; + } +#endif + if((0 == err) || (EISCONN == err)) + /* we are connected, awesome! */ + rc = TRUE; + else + /* This wasn't a successful connect */ + rc = FALSE; + if(error) + *error = err; +#else + (void)sockfd; + if(error) + *error = SOCKERRNO; +#endif + return rc; +} + +/** + * Determine the curl code for a socket connect() == -1 with errno. + */ +static CURLcode socket_connect_result(struct Curl_easy *data, + const char *ipaddress, int error) +{ + switch(error) { + case EINPROGRESS: + case EWOULDBLOCK: +#if defined(EAGAIN) +#if (EAGAIN) != (EWOULDBLOCK) + /* On some platforms EAGAIN and EWOULDBLOCK are the + * same value, and on others they are different, hence + * the odd #if + */ + case EAGAIN: +#endif +#endif + return CURLE_OK; + + default: + /* unknown error, fallthrough and try another address! */ +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)ipaddress; +#else + { + char buffer[STRERROR_LEN]; + infof(data, "Immediate connect fail for %s: %s", + ipaddress, Curl_strerror(error, buffer, sizeof(buffer))); + } +#endif + data->state.os_errno = error; + /* connect failed */ + return CURLE_COULDNT_CONNECT; + } +} + +/* We have a recv buffer to enhance reads with len < NW_SMALL_READS. + * This happens often on TLS connections where the TLS implementation + * tries to read the head of a TLS record, determine the length of the + * full record and then make a subsequent read for that. + * On large reads, we will not fill the buffer to avoid the double copy. */ +#define NW_RECV_CHUNK_SIZE (64 * 1024) +#define NW_RECV_CHUNKS 1 +#define NW_SMALL_READS (1024) + +struct cf_socket_ctx { + int transport; + struct Curl_sockaddr_ex addr; /* address to connect to */ + curl_socket_t sock; /* current attempt socket */ + struct bufq recvbuf; /* used when `buffer_recv` is set */ + char r_ip[MAX_IPADR_LEN]; /* remote IP as string */ + int r_port; /* remote port number */ + char l_ip[MAX_IPADR_LEN]; /* local IP as string */ + int l_port; /* local port number */ + struct curltime started_at; /* when socket was created */ + struct curltime connected_at; /* when socket connected/got first byte */ + struct curltime first_byte_at; /* when first byte was recvd */ + int error; /* errno of last failure or 0 */ +#ifdef DEBUGBUILD + int wblock_percent; /* percent of writes doing EAGAIN */ + int wpartial_percent; /* percent of bytes written in send */ + int rblock_percent; /* percent of reads doing EAGAIN */ + size_t recv_max; /* max enforced read size */ +#endif + BIT(got_first_byte); /* if first byte was received */ + BIT(accepted); /* socket was accepted, not connected */ + BIT(sock_connected); /* socket is "connected", e.g. in UDP */ + BIT(active); + BIT(buffer_recv); +}; + +static void cf_socket_ctx_init(struct cf_socket_ctx *ctx, + const struct Curl_addrinfo *ai, + int transport) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->sock = CURL_SOCKET_BAD; + ctx->transport = transport; + Curl_sock_assign_addr(&ctx->addr, ai, transport); + Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS); +#ifdef DEBUGBUILD + { + char *p = getenv("CURL_DBG_SOCK_WBLOCK"); + if(p) { + long l = strtol(p, NULL, 10); + if(l >= 0 && l <= 100) + ctx->wblock_percent = (int)l; + } + p = getenv("CURL_DBG_SOCK_WPARTIAL"); + if(p) { + long l = strtol(p, NULL, 10); + if(l >= 0 && l <= 100) + ctx->wpartial_percent = (int)l; + } + p = getenv("CURL_DBG_SOCK_RBLOCK"); + if(p) { + long l = strtol(p, NULL, 10); + if(l >= 0 && l <= 100) + ctx->rblock_percent = (int)l; + } + p = getenv("CURL_DBG_SOCK_RMAX"); + if(p) { + long l = strtol(p, NULL, 10); + if(l >= 0) + ctx->recv_max = (size_t)l; + } + } +#endif +} + +struct reader_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; +}; + +static ssize_t nw_in_read(void *reader_ctx, + unsigned char *buf, size_t len, + CURLcode *err) +{ + struct reader_ctx *rctx = reader_ctx; + struct cf_socket_ctx *ctx = rctx->cf->ctx; + ssize_t nread; + + *err = CURLE_OK; + nread = sread(ctx->sock, buf, len); + + if(-1 == nread) { + int sockerr = SOCKERRNO; + + if( +#ifdef WSAEWOULDBLOCK + /* This is how Windows does it */ + (WSAEWOULDBLOCK == sockerr) +#else + /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned + due to its inability to send off data without blocking. We therefore + treat both error codes the same here */ + (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) +#endif + ) { + /* this is just a case of EWOULDBLOCK */ + *err = CURLE_AGAIN; + nread = -1; + } + else { + char buffer[STRERROR_LEN]; + + failf(rctx->data, "Recv failure: %s", + Curl_strerror(sockerr, buffer, sizeof(buffer))); + rctx->data->state.os_errno = sockerr; + *err = CURLE_RECV_ERROR; + nread = -1; + } + } + CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu) -> %d, err=%d", + len, (int)nread, *err); + return nread; +} + +static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + if(ctx && CURL_SOCKET_BAD != ctx->sock) { + CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T + ")", ctx->sock); + if(ctx->sock == cf->conn->sock[cf->sockindex]) + cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD; + socket_close(data, cf->conn, !ctx->accepted, ctx->sock); + ctx->sock = CURL_SOCKET_BAD; + if(ctx->active && cf->sockindex == FIRSTSOCKET) + cf->conn->remote_addr = NULL; + Curl_bufq_reset(&ctx->recvbuf); + ctx->active = FALSE; + ctx->buffer_recv = FALSE; + memset(&ctx->started_at, 0, sizeof(ctx->started_at)); + memset(&ctx->connected_at, 0, sizeof(ctx->connected_at)); + } + + cf->connected = FALSE; +} + +static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + cf_socket_close(cf, data); + CURL_TRC_CF(data, cf, "destroy"); + Curl_bufq_free(&ctx->recvbuf); + free(ctx); + cf->ctx = NULL; +} + +static CURLcode set_local_ip(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + +#ifdef HAVE_GETSOCKNAME + if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) { + /* TFTP does not connect, so it cannot get the IP like this */ + + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssloc; + curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage); + + memset(&ssloc, 0, sizeof(ssloc)); + if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) { + int error = SOCKERRNO; + failf(data, "getsockname() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return CURLE_FAILED_INIT; + } + if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, + ctx->l_ip, &ctx->l_port)) { + failf(data, "ssloc inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return CURLE_FAILED_INIT; + } + } +#else + (void)data; + ctx->l_ip[0] = 0; + ctx->l_port = -1; +#endif + return CURLE_OK; +} + +static CURLcode set_remote_ip(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + /* store remote address and port used in this connection attempt */ + if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen, + ctx->r_ip, &ctx->r_port)) { + char buffer[STRERROR_LEN]; + + ctx->error = errno; + /* malformed address or bug in inet_ntop, try next address */ + failf(data, "sa_addr inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return CURLE_FAILED_INIT; + } + return CURLE_OK; +} + +static CURLcode cf_socket_open(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + int error = 0; + bool isconnected = FALSE; + CURLcode result = CURLE_COULDNT_CONNECT; + bool is_tcp; + + (void)data; + DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD); + ctx->started_at = Curl_now(); + result = socket_open(data, &ctx->addr, &ctx->sock); + if(result) + goto out; + + result = set_remote_ip(cf, data); + if(result) + goto out; + +#ifdef ENABLE_IPV6 + if(ctx->addr.family == AF_INET6) { + set_ipv6_v6only(ctx->sock, 0); + infof(data, " Trying [%s]:%d...", ctx->r_ip, ctx->r_port); + } + else +#endif + infof(data, " Trying %s:%d...", ctx->r_ip, ctx->r_port); + +#ifdef ENABLE_IPV6 + is_tcp = (ctx->addr.family == AF_INET + || ctx->addr.family == AF_INET6) && + ctx->addr.socktype == SOCK_STREAM; +#else + is_tcp = (ctx->addr.family == AF_INET) && + ctx->addr.socktype == SOCK_STREAM; +#endif + if(is_tcp && data->set.tcp_nodelay) + tcpnodelay(data, ctx->sock); + + nosigpipe(data, ctx->sock); + + Curl_sndbufset(ctx->sock); + + if(is_tcp && data->set.tcp_keepalive) + tcpkeepalive(data, ctx->sock); + + if(data->set.fsockopt) { + /* activate callback for setting socket options */ + Curl_set_in_callback(data, true); + error = data->set.fsockopt(data->set.sockopt_client, + ctx->sock, + CURLSOCKTYPE_IPCXN); + Curl_set_in_callback(data, false); + + if(error == CURL_SOCKOPT_ALREADY_CONNECTED) + isconnected = TRUE; + else if(error) { + result = CURLE_ABORTED_BY_CALLBACK; + goto out; + } + } + +#ifndef CURL_DISABLE_BINDLOCAL + /* possibly bind the local end to an IP, interface or port */ + if(ctx->addr.family == AF_INET +#ifdef ENABLE_IPV6 + || ctx->addr.family == AF_INET6 +#endif + ) { + result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family, + Curl_ipv6_scope(&ctx->addr.sa_addr)); + if(result) { + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + /* The address family is not supported on this interface. + We can continue trying addresses */ + result = CURLE_COULDNT_CONNECT; + } + goto out; + } + } +#endif + + /* set socket non-blocking */ + (void)curlx_nonblock(ctx->sock, TRUE); + ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM); +out: + if(result) { + if(ctx->sock != CURL_SOCKET_BAD) { + socket_close(data, cf->conn, TRUE, ctx->sock); + ctx->sock = CURL_SOCKET_BAD; + } + } + else if(isconnected) { + set_local_ip(cf, data); + ctx->connected_at = Curl_now(); + cf->connected = TRUE; + } + CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T, + result, ctx->sock); + return result; +} + +static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data, + bool is_tcp_fastopen) +{ + struct cf_socket_ctx *ctx = cf->ctx; +#ifdef TCP_FASTOPEN_CONNECT + int optval = 1; +#endif + int rc = -1; + + (void)data; + if(is_tcp_fastopen) { +#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */ +# if defined(HAVE_BUILTIN_AVAILABLE) + /* while connectx function is available since macOS 10.11 / iOS 9, + it did not have the interface declared correctly until + Xcode 9 / macOS SDK 10.13 */ + if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) { + sa_endpoints_t endpoints; + endpoints.sae_srcif = 0; + endpoints.sae_srcaddr = NULL; + endpoints.sae_srcaddrlen = 0; + endpoints.sae_dstaddr = &ctx->addr.sa_addr; + endpoints.sae_dstaddrlen = ctx->addr.addrlen; + + rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY, + CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, + NULL, 0, NULL, NULL); + } + else { + rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); + } +# else + rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); +# endif /* HAVE_BUILTIN_AVAILABLE */ +#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */ + if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, + (void *)&optval, sizeof(optval)) < 0) + infof(data, "Failed to enable TCP Fast Open on fd %" + CURL_FORMAT_SOCKET_T, ctx->sock); + + rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); +#elif defined(MSG_FASTOPEN) /* old Linux */ + if(cf->conn->given->flags & PROTOPT_SSL) + rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); + else + rc = 0; /* Do nothing */ +#endif + } + else { + rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); + } + return rc; +} + +static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_socket_ctx *ctx = cf->ctx; + CURLcode result = CURLE_COULDNT_CONNECT; + int rc = 0; + + (void)data; + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* TODO: need to support blocking connect? */ + if(blocking) + return CURLE_UNSUPPORTED_PROTOCOL; + + *done = FALSE; /* a very negative world view is best */ + if(ctx->sock == CURL_SOCKET_BAD) { + int error; + + result = cf_socket_open(cf, data); + if(result) + goto out; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* Connect TCP socket */ + rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen); + error = SOCKERRNO; + set_local_ip(cf, data); + CURL_TRC_CF(data, cf, "local address %s port %d...", + ctx->l_ip, ctx->l_port); + if(-1 == rc) { + result = socket_connect_result(data, ctx->r_ip, error); + goto out; + } + } + +#ifdef mpeix + /* Call this function once now, and ignore the results. We do this to + "clear" the error state on the socket so that we can later read it + reliably. This is reported necessary on the MPE/iX operating + system. */ + (void)verifyconnect(ctx->sock, NULL); +#endif + /* check socket for connect */ + rc = SOCKET_WRITABLE(ctx->sock, 0); + + if(rc == 0) { /* no connection yet */ + CURL_TRC_CF(data, cf, "not connected yet"); + return CURLE_OK; + } + else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) { + if(verifyconnect(ctx->sock, &ctx->error)) { + /* we are connected with TCP, awesome! */ + ctx->connected_at = Curl_now(); + set_local_ip(cf, data); + *done = TRUE; + cf->connected = TRUE; + CURL_TRC_CF(data, cf, "connected"); + return CURLE_OK; + } + } + else if(rc & CURL_CSELECT_ERR) { + (void)verifyconnect(ctx->sock, &ctx->error); + result = CURLE_COULDNT_CONNECT; + } + +out: + if(result) { + if(ctx->error) { + set_local_ip(cf, data); + data->state.os_errno = ctx->error; + SET_SOCKERRNO(ctx->error); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + { + char buffer[STRERROR_LEN]; + infof(data, "connect to %s port %u from %s port %d failed: %s", + ctx->r_ip, ctx->r_port, ctx->l_ip, ctx->l_port, + Curl_strerror(ctx->error, buffer, sizeof(buffer))); + } +#endif + } + if(ctx->sock != CURL_SOCKET_BAD) { + socket_close(data, cf->conn, TRUE, ctx->sock); + ctx->sock = CURL_SOCKET_BAD; + } + *done = FALSE; + } + return result; +} + +static void cf_socket_get_host(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char **phost, + const char **pdisplay_host, + int *pport) +{ + (void)data; + *phost = cf->conn->host.name; + *pdisplay_host = cf->conn->host.dispname; + *pport = cf->conn->port; +} + +static void cf_socket_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + if(ctx->sock != CURL_SOCKET_BAD) { + if(!cf->connected) { + Curl_pollset_set_out_only(data, ps, ctx->sock); + CURL_TRC_CF(data, cf, "adjust_pollset(!connected) -> %d socks", ps->num); + } + else if(!ctx->active) { + Curl_pollset_add_in(data, ps, ctx->sock); + CURL_TRC_CF(data, cf, "adjust_pollset(!active) -> %d socks", ps->num); + } + } +} + +static bool cf_socket_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + int readable; + + (void)data; + if(!Curl_bufq_is_empty(&ctx->recvbuf)) + return TRUE; + + readable = SOCKET_READABLE(ctx->sock, 0); + return (readable > 0 && (readable & CURL_CSELECT_IN)); +} + +static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_socket_ctx *ctx = cf->ctx; + curl_socket_t fdsave; + ssize_t nwritten; + size_t orig_len = len; + + *err = CURLE_OK; + fdsave = cf->conn->sock[cf->sockindex]; + cf->conn->sock[cf->sockindex] = ctx->sock; + +#ifdef DEBUGBUILD + /* simulate network blocking/partial writes */ + if(ctx->wblock_percent > 0) { + unsigned char c; + Curl_rand(data, &c, 1); + if(c >= ((100-ctx->wblock_percent)*256/100)) { + CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len); + *err = CURLE_AGAIN; + nwritten = -1; + cf->conn->sock[cf->sockindex] = fdsave; + return nwritten; + } + } + if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) { + len = len * ctx->wpartial_percent / 100; + if(!len) + len = 1; + CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes", + orig_len, len); + } +#endif + +#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */ + if(cf->conn->bits.tcp_fastopen) { + nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN, + &cf->conn->remote_addr->sa_addr, + cf->conn->remote_addr->addrlen); + cf->conn->bits.tcp_fastopen = FALSE; + } + else +#endif + nwritten = swrite(ctx->sock, buf, len); + + if(-1 == nwritten) { + int sockerr = SOCKERRNO; + + if( +#ifdef WSAEWOULDBLOCK + /* This is how Windows does it */ + (WSAEWOULDBLOCK == sockerr) +#else + /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned + due to its inability to send off data without blocking. We therefore + treat both error codes the same here */ + (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) || + (EINPROGRESS == sockerr) +#endif + ) { + /* this is just a case of EWOULDBLOCK */ + *err = CURLE_AGAIN; + } + else { + char buffer[STRERROR_LEN]; + failf(data, "Send failure: %s", + Curl_strerror(sockerr, buffer, sizeof(buffer))); + data->state.os_errno = sockerr; + *err = CURLE_SEND_ERROR; + } + } + + CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d", + orig_len, (int)nwritten, *err); + cf->conn->sock[cf->sockindex] = fdsave; + return nwritten; +} + +static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct cf_socket_ctx *ctx = cf->ctx; + curl_socket_t fdsave; + ssize_t nread; + + *err = CURLE_OK; + + fdsave = cf->conn->sock[cf->sockindex]; + cf->conn->sock[cf->sockindex] = ctx->sock; + +#ifdef DEBUGBUILD + /* simulate network blocking/partial reads */ + if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) { + unsigned char c; + Curl_rand(data, &c, 1); + if(c >= ((100-ctx->rblock_percent)*256/100)) { + CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len); + *err = CURLE_AGAIN; + nread = -1; + cf->conn->sock[cf->sockindex] = fdsave; + return nread; + } + } + if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) { + size_t orig_len = len; + len = ctx->recv_max; + CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes", + orig_len, len); + } +#endif + + if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) { + CURL_TRC_CF(data, cf, "recv from buffer"); + nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err); + } + else { + struct reader_ctx rctx; + + rctx.cf = cf; + rctx.data = data; + + /* "small" reads may trigger filling our buffer, "large" reads + * are probably not worth the additional copy */ + if(ctx->buffer_recv && len < NW_SMALL_READS) { + ssize_t nwritten; + nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err); + if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) { + /* we have a partial read with an error. need to deliver + * what we got, return the error later. */ + CURL_TRC_CF(data, cf, "partial read: empty buffer first"); + nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err); + } + else if(nwritten < 0) { + nread = -1; + goto out; + } + else if(nwritten == 0) { + /* eof */ + *err = CURLE_OK; + nread = 0; + } + else { + CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten); + nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err); + } + } + else { + nread = nw_in_read(&rctx, (unsigned char *)buf, len, err); + } + } + +out: + CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread, + *err); + if(nread > 0 && !ctx->got_first_byte) { + ctx->first_byte_at = Curl_now(); + ctx->got_first_byte = TRUE; + } + cf->conn->sock[cf->sockindex] = fdsave; + return nread; +} + +static void conn_set_primary_ip(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + (void)data; + DEBUGASSERT(sizeof(ctx->r_ip) == sizeof(cf->conn->primary_ip)); + memcpy(cf->conn->primary_ip, ctx->r_ip, sizeof(cf->conn->primary_ip)); +} + +static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + /* use this socket from now on */ + cf->conn->sock[cf->sockindex] = ctx->sock; + /* the first socket info gets set at conn and data */ + if(cf->sockindex == FIRSTSOCKET) { + cf->conn->remote_addr = &ctx->addr; + #ifdef ENABLE_IPV6 + cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE; + #endif + conn_set_primary_ip(cf, data); + set_local_ip(cf, data); + Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port); + /* buffering is currently disabled by default because we have stalls + * in parallel transfers where not all buffered data is consumed and no + * socket events happen. + */ + ctx->buffer_recv = FALSE; + } + ctx->active = TRUE; +} + +static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_CONN_INFO_UPDATE: + cf_socket_active(cf, data); + break; + case CF_CTRL_DATA_SETUP: + Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port); + break; + case CF_CTRL_FORGET_SOCKET: + ctx->sock = CURL_SOCKET_BAD; + break; + } + return CURLE_OK; +} + +static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_socket_ctx *ctx = cf->ctx; + struct pollfd pfd[1]; + int r; + + *input_pending = FALSE; + (void)data; + if(!ctx || ctx->sock == CURL_SOCKET_BAD) + return FALSE; + + /* Check with 0 timeout if there are any events pending on the socket */ + pfd[0].fd = ctx->sock; + pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[0].revents = 0; + + r = Curl_poll(pfd, 1, 0); + if(r < 0) { + CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead"); + return FALSE; + } + else if(r == 0) { + CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive"); + return TRUE; + } + else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) { + CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead"); + return FALSE; + } + + CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive"); + *input_pending = TRUE; + return TRUE; +} + +static CURLcode cf_socket_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_socket_ctx *ctx = cf->ctx; + + switch(query) { + case CF_QUERY_SOCKET: + DEBUGASSERT(pres2); + *((curl_socket_t *)pres2) = ctx->sock; + return CURLE_OK; + case CF_QUERY_CONNECT_REPLY_MS: + if(ctx->got_first_byte) { + timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at); + *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX; + } + else + *pres1 = -1; + return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + switch(ctx->transport) { + case TRNSPRT_UDP: + case TRNSPRT_QUIC: + /* Since UDP connected sockets work different from TCP, we use the + * time of the first byte from the peer as the "connect" time. */ + if(ctx->got_first_byte) { + *when = ctx->first_byte_at; + break; + } + FALLTHROUGH(); + default: + *when = ctx->connected_at; + break; + } + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +struct Curl_cftype Curl_cft_tcp = { + "TCP", + CF_TYPE_IP_CONNECT, + CURL_LOG_LVL_NONE, + cf_socket_destroy, + cf_tcp_connect, + cf_socket_close, + cf_socket_get_host, + cf_socket_adjust_pollset, + cf_socket_data_pending, + cf_socket_send, + cf_socket_recv, + cf_socket_cntrl, + cf_socket_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_socket_query, +}; + +CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport) +{ + struct cf_socket_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL; + CURLcode result; + + (void)data; + (void)conn; + DEBUGASSERT(transport == TRNSPRT_TCP); + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + cf_socket_ctx_init(ctx, ai, transport); + + result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx); + +out: + *pcf = (!result)? cf : NULL; + if(result) { + Curl_safefree(cf); + Curl_safefree(ctx); + } + + return result; +} + +static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; + int rc; + + /* QUIC needs a connected socket, nonblocking */ + DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD); + +#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC) + (void)rc; + /* On macOS OpenSSL QUIC fails on connected sockets. + * see: */ +#else + rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); + if(-1 == rc) { + return socket_connect_result(data, ctx->r_ip, SOCKERRNO); + } + ctx->sock_connected = TRUE; +#endif + set_local_ip(cf, data); + CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T + " connected: [%s:%d] -> [%s:%d]", + (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP", + ctx->sock, ctx->l_ip, ctx->l_port, ctx->r_ip, ctx->r_port); + + (void)curlx_nonblock(ctx->sock, TRUE); + switch(ctx->addr.family) { +#if defined(__linux__) && defined(IP_MTU_DISCOVER) + case AF_INET: { + int val = IP_PMTUDISC_DO; + (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, + sizeof(val)); + break; + } +#endif +#if defined(__linux__) && defined(IPV6_MTU_DISCOVER) + case AF_INET6: { + int val = IPV6_PMTUDISC_DO; + (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, + sizeof(val)); + break; + } +#endif + } + return CURLE_OK; +} + +static CURLcode cf_udp_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_socket_ctx *ctx = cf->ctx; + CURLcode result = CURLE_COULDNT_CONNECT; + + (void)blocking; + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + *done = FALSE; + if(ctx->sock == CURL_SOCKET_BAD) { + result = cf_socket_open(cf, data); + if(result) { + CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result); + goto out; + } + + if(ctx->transport == TRNSPRT_QUIC) { + result = cf_udp_setup_quic(cf, data); + if(result) + goto out; + CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%" + CURL_FORMAT_SOCKET_T " (%s:%d)", + ctx->sock, ctx->l_ip, ctx->l_port); + } + else { + CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%" + CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock); + } + *done = TRUE; + cf->connected = TRUE; + } +out: + return result; +} + +struct Curl_cftype Curl_cft_udp = { + "UDP", + CF_TYPE_IP_CONNECT, + CURL_LOG_LVL_NONE, + cf_socket_destroy, + cf_udp_connect, + cf_socket_close, + cf_socket_get_host, + cf_socket_adjust_pollset, + cf_socket_data_pending, + cf_socket_send, + cf_socket_recv, + cf_socket_cntrl, + cf_socket_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_socket_query, +}; + +CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport) +{ + struct cf_socket_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL; + CURLcode result; + + (void)data; + (void)conn; + DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC); + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + cf_socket_ctx_init(ctx, ai, transport); + + result = Curl_cf_create(&cf, &Curl_cft_udp, ctx); + +out: + *pcf = (!result)? cf : NULL; + if(result) { + Curl_safefree(cf); + Curl_safefree(ctx); + } + + return result; +} + +/* this is the TCP filter which can also handle this case */ +struct Curl_cftype Curl_cft_unix = { + "UNIX", + CF_TYPE_IP_CONNECT, + CURL_LOG_LVL_NONE, + cf_socket_destroy, + cf_tcp_connect, + cf_socket_close, + cf_socket_get_host, + cf_socket_adjust_pollset, + cf_socket_data_pending, + cf_socket_send, + cf_socket_recv, + cf_socket_cntrl, + cf_socket_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_socket_query, +}; + +CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport) +{ + struct cf_socket_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL; + CURLcode result; + + (void)data; + (void)conn; + DEBUGASSERT(transport == TRNSPRT_UNIX); + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + cf_socket_ctx_init(ctx, ai, transport); + + result = Curl_cf_create(&cf, &Curl_cft_unix, ctx); + +out: + *pcf = (!result)? cf : NULL; + if(result) { + Curl_safefree(cf); + Curl_safefree(ctx); + } + + return result; +} + +static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + /* we start accepted, if we ever close, we cannot go on */ + (void)data; + (void)blocking; + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + return CURLE_FAILED_INIT; +} + +struct Curl_cftype Curl_cft_tcp_accept = { + "TCP-ACCEPT", + CF_TYPE_IP_CONNECT, + CURL_LOG_LVL_NONE, + cf_socket_destroy, + cf_tcp_accept_connect, + cf_socket_close, + cf_socket_get_host, /* TODO: not accurate */ + cf_socket_adjust_pollset, + cf_socket_data_pending, + cf_socket_send, + cf_socket_recv, + cf_socket_cntrl, + cf_socket_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_socket_query, +}; + +CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, curl_socket_t *s) +{ + CURLcode result; + struct Curl_cfilter *cf = NULL; + struct cf_socket_ctx *ctx = NULL; + + /* replace any existing */ + Curl_conn_cf_discard_all(data, conn, sockindex); + DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD); + + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + ctx->transport = conn->transport; + ctx->sock = *s; + ctx->accepted = FALSE; + result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx); + if(result) + goto out; + Curl_conn_cf_add(data, conn, sockindex, cf); + + conn->sock[sockindex] = ctx->sock; + set_local_ip(cf, data); + ctx->active = TRUE; + ctx->connected_at = Curl_now(); + cf->connected = TRUE; + CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%" + CURL_FORMAT_SOCKET_T ")", ctx->sock); + +out: + if(result) { + Curl_safefree(cf); + Curl_safefree(ctx); + } + return result; +} + +static void set_accepted_remote_ip(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; +#ifdef HAVE_GETPEERNAME + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssrem; + curl_socklen_t plen; + + ctx->r_ip[0] = 0; + ctx->r_port = 0; + plen = sizeof(ssrem); + memset(&ssrem, 0, plen); + if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) { + int error = SOCKERRNO; + failf(data, "getpeername() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } + if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, + ctx->r_ip, &ctx->r_port)) { + failf(data, "ssrem inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } +#else + ctx->r_ip[0] = 0; + ctx->r_port = 0; + (void)data; +#endif +} + +CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, curl_socket_t *s) +{ + struct Curl_cfilter *cf = NULL; + struct cf_socket_ctx *ctx = NULL; + + cf = conn->cfilter[sockindex]; + if(!cf || cf->cft != &Curl_cft_tcp_accept) + return CURLE_FAILED_INIT; + + ctx = cf->ctx; + /* discard the listen socket */ + socket_close(data, conn, TRUE, ctx->sock); + ctx->sock = *s; + conn->sock[sockindex] = ctx->sock; + set_accepted_remote_ip(cf, data); + set_local_ip(cf, data); + ctx->active = TRUE; + ctx->accepted = TRUE; + ctx->connected_at = Curl_now(); + cf->connected = TRUE; + CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T + ", remote=%s port=%d)", + ctx->sock, ctx->r_ip, ctx->r_port); + + return CURLE_OK; +} + +/** + * Return TRUE iff `cf` is a socket filter. + */ +static bool cf_is_socket(struct Curl_cfilter *cf) +{ + return cf && (cf->cft == &Curl_cft_tcp || + cf->cft == &Curl_cft_udp || + cf->cft == &Curl_cft_unix || + cf->cft == &Curl_cft_tcp_accept); +} + +CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf, + struct Curl_easy *data, + curl_socket_t *psock, + const struct Curl_sockaddr_ex **paddr, + const char **pr_ip_str, int *pr_port, + const char **pl_ip_str, int *pl_port) +{ + if(cf_is_socket(cf) && cf->ctx) { + struct cf_socket_ctx *ctx = cf->ctx; + + if(psock) + *psock = ctx->sock; + if(paddr) + *paddr = &ctx->addr; + if(pr_ip_str) + *pr_ip_str = ctx->r_ip; + if(pr_port) + *pr_port = ctx->r_port; + if(pl_port ||pl_ip_str) { + set_local_ip(cf, data); + if(pl_ip_str) + *pl_ip_str = ctx->l_ip; + if(pl_port) + *pl_port = ctx->l_port; + } + return CURLE_OK; + } + return CURLE_FAILED_INIT; +} diff --git a/lib/cf-socket.h b/lib/cf-socket.h new file mode 100644 index 0000000..87e0f30 --- /dev/null +++ b/lib/cf-socket.h @@ -0,0 +1,174 @@ +#ifndef HEADER_CURL_CF_SOCKET_H +#define HEADER_CURL_CF_SOCKET_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */ +#include "sockaddr.h" + +struct Curl_addrinfo; +struct Curl_cfilter; +struct Curl_easy; +struct connectdata; +struct Curl_sockaddr_ex; + +/* + * The Curl_sockaddr_ex structure is basically libcurl's external API + * curl_sockaddr structure with enough space available to directly hold any + * protocol-specific address structures. The variable declared here will be + * used to pass / receive data to/from the fopensocket callback if this has + * been set, before that, it is initialized from parameters. + */ +struct Curl_sockaddr_ex { + int family; + int socktype; + int protocol; + unsigned int addrlen; + union { + struct sockaddr addr; + struct Curl_sockaddr_storage buff; + } _sa_ex_u; +}; +#define sa_addr _sa_ex_u.addr + + +/* + * Create a socket based on info from 'conn' and 'ai'. + * + * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open + * socket callback is set, used that! + * + */ +CURLcode Curl_socket_open(struct Curl_easy *data, + const struct Curl_addrinfo *ai, + struct Curl_sockaddr_ex *addr, + int transport, + curl_socket_t *sockfd); + +int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t sock); + +#ifdef USE_WINSOCK +/* When you run a program that uses the Windows Sockets API, you may + experience slow performance when you copy data to a TCP server. + + https://support.microsoft.com/kb/823764 + + Work-around: Make the Socket Send Buffer Size Larger Than the Program Send + Buffer Size + +*/ +void Curl_sndbufset(curl_socket_t sockfd); +#else +#define Curl_sndbufset(y) Curl_nop_stmt +#endif + +/** + * Assign the address `ai` to the Curl_sockaddr_ex `dest` and + * set the transport used. + */ +void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest, + const struct Curl_addrinfo *ai, + int transport); + +/** + * Creates a cfilter that opens a TCP socket to the given address + * when calling its `connect` implementation. + * The filter will not touch any connection/data flags and can be + * used in happy eyeballing. Once selected for use, its `_active()` + * method needs to be called. + */ +CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport); + +/** + * Creates a cfilter that opens a UDP socket to the given address + * when calling its `connect` implementation. + * The filter will not touch any connection/data flags and can be + * used in happy eyeballing. Once selected for use, its `_active()` + * method needs to be called. + */ +CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport); + +/** + * Creates a cfilter that opens a UNIX socket to the given address + * when calling its `connect` implementation. + * The filter will not touch any connection/data flags and can be + * used in happy eyeballing. Once selected for use, its `_active()` + * method needs to be called. + */ +CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport); + +/** + * Creates a cfilter that keeps a listening socket. + */ +CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + curl_socket_t *s); + +/** + * Replace the listen socket with the accept()ed one. + */ +CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + curl_socket_t *s); + +/** + * Peek at the socket and remote ip/port the socket filter is using. + * The filter owns all returned values. + * @param psock pointer to hold socket descriptor or NULL + * @param paddr pointer to hold addr reference or NULL + * @param pr_ip_str pointer to hold remote addr as string or NULL + * @param pr_port pointer to hold remote port number or NULL + * @param pl_ip_str pointer to hold local addr as string or NULL + * @param pl_port pointer to hold local port number or NULL + * Returns error if the filter is of invalid type. + */ +CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf, + struct Curl_easy *data, + curl_socket_t *psock, + const struct Curl_sockaddr_ex **paddr, + const char **pr_ip_str, int *pr_port, + const char **pl_ip_str, int *pl_port); + +extern struct Curl_cftype Curl_cft_tcp; +extern struct Curl_cftype Curl_cft_udp; +extern struct Curl_cftype Curl_cft_unix; +extern struct Curl_cftype Curl_cft_tcp_accept; + +#endif /* HEADER_CURL_CF_SOCKET_H */ diff --git a/lib/cfilters.c b/lib/cfilters.c new file mode 100644 index 0000000..823e90c --- /dev/null +++ b/lib/cfilters.c @@ -0,0 +1,788 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "urldata.h" +#include "strerror.h" +#include "cfilters.h" +#include "connect.h" +#include "url.h" /* for Curl_safefree() */ +#include "sendf.h" +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "multiif.h" +#include "progress.h" +#include "select.h" +#include "warnless.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#ifdef DEBUGBUILD +/* used by unit2600.c */ +void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + cf->connected = FALSE; + if(cf->next) + cf->next->cft->do_close(cf->next, data); +} +#endif + +static void conn_report_connect_stats(struct Curl_easy *data, + struct connectdata *conn); + +void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data, + const char **phost, const char **pdisplay_host, + int *pport) +{ + if(cf->next) + cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport); + else { + *phost = cf->conn->host.name; + *pdisplay_host = cf->conn->host.dispname; + *pport = cf->conn->port; + } +} + +void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + /* NOP */ + (void)cf; + (void)data; + (void)ps; +} + +bool Curl_cf_def_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + return cf->next? + cf->next->cft->has_data_pending(cf->next, data) : FALSE; +} + +ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + return cf->next? + cf->next->cft->do_send(cf->next, data, buf, len, err) : + CURLE_RECV_ERROR; +} + +ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + return cf->next? + cf->next->cft->do_recv(cf->next, data, buf, len, err) : + CURLE_SEND_ERROR; +} + +bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + return cf->next? + cf->next->cft->is_alive(cf->next, data, input_pending) : + FALSE; /* pessimistic in absence of data */ +} + +CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + return cf->next? + cf->next->cft->keep_alive(cf->next, data) : + CURLE_OK; +} + +CURLcode Curl_cf_def_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf, + struct Curl_easy *data) +{ + struct Curl_cfilter *cfn, *cf = *pcf; + + if(cf) { + *pcf = NULL; + while(cf) { + cfn = cf->next; + /* prevent destroying filter to mess with its sub-chain, since + * we have the reference now and will call destroy on it. + */ + cf->next = NULL; + cf->cft->destroy(cf, data); + free(cf); + cf = cfn; + } + } +} + +void Curl_conn_cf_discard_all(struct Curl_easy *data, + struct connectdata *conn, int index) +{ + Curl_conn_cf_discard_chain(&conn->cfilter[index], data); +} + +void Curl_conn_close(struct Curl_easy *data, int index) +{ + struct Curl_cfilter *cf; + + DEBUGASSERT(data->conn); + /* it is valid to call that without filters being present */ + cf = data->conn->cfilter[index]; + if(cf) { + cf->cft->do_close(cf, data); + } +} + +ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf, + size_t len, CURLcode *code) +{ + struct Curl_cfilter *cf; + + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + cf = data->conn->cfilter[num]; + while(cf && !cf->connected) { + cf = cf->next; + } + if(cf) { + return cf->cft->do_recv(cf, data, buf, len, code); + } + failf(data, "recv: no filter connected"); + *code = CURLE_FAILED_INIT; + return -1; +} + +ssize_t Curl_conn_send(struct Curl_easy *data, int num, + const void *mem, size_t len, CURLcode *code) +{ + struct Curl_cfilter *cf; + + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + cf = data->conn->cfilter[num]; + while(cf && !cf->connected) { + cf = cf->next; + } + if(cf) { + return cf->cft->do_send(cf, data, mem, len, code); + } + failf(data, "send: no filter connected"); + DEBUGASSERT(0); + *code = CURLE_FAILED_INIT; + return -1; +} + +CURLcode Curl_cf_create(struct Curl_cfilter **pcf, + const struct Curl_cftype *cft, + void *ctx) +{ + struct Curl_cfilter *cf; + CURLcode result = CURLE_OUT_OF_MEMORY; + + DEBUGASSERT(cft); + cf = calloc(1, sizeof(*cf)); + if(!cf) + goto out; + + cf->cft = cft; + cf->ctx = ctx; + result = CURLE_OK; +out: + *pcf = cf; + return result; +} + +void Curl_conn_cf_add(struct Curl_easy *data, + struct connectdata *conn, + int index, + struct Curl_cfilter *cf) +{ + (void)data; + DEBUGASSERT(conn); + DEBUGASSERT(!cf->conn); + DEBUGASSERT(!cf->next); + + cf->next = conn->cfilter[index]; + cf->conn = conn; + cf->sockindex = index; + conn->cfilter[index] = cf; + CURL_TRC_CF(data, cf, "added"); +} + +void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at, + struct Curl_cfilter *cf_new) +{ + struct Curl_cfilter *tail, **pnext; + + DEBUGASSERT(cf_at); + DEBUGASSERT(cf_new); + DEBUGASSERT(!cf_new->conn); + + tail = cf_at->next; + cf_at->next = cf_new; + do { + cf_new->conn = cf_at->conn; + cf_new->sockindex = cf_at->sockindex; + pnext = &cf_new->next; + cf_new = cf_new->next; + } while(cf_new); + *pnext = tail; +} + +bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, + struct Curl_cfilter *discard, + struct Curl_easy *data, + bool destroy_always) +{ + struct Curl_cfilter **pprev = &cf->next; + bool found = FALSE; + + /* remove from sub-chain and destroy */ + DEBUGASSERT(cf); + while(*pprev) { + if(*pprev == cf) { + *pprev = discard->next; + discard->next = NULL; + found = TRUE; + break; + } + pprev = &((*pprev)->next); + } + if(found || destroy_always) { + discard->next = NULL; + discard->cft->destroy(discard, data); + free(discard); + } + return found; +} + +CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + if(cf) + return cf->cft->do_connect(cf, data, blocking, done); + return CURLE_FAILED_INIT; +} + +void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + if(cf) + cf->cft->do_close(cf, data); +} + +ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + if(cf) + return cf->cft->do_send(cf, data, buf, len, err); + *err = CURLE_SEND_ERROR; + return -1; +} + +ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + if(cf) + return cf->cft->do_recv(cf, data, buf, len, err); + *err = CURLE_RECV_ERROR; + return -1; +} + +CURLcode Curl_conn_connect(struct Curl_easy *data, + int sockindex, + bool blocking, + bool *done) +{ + struct Curl_cfilter *cf; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + + cf = data->conn->cfilter[sockindex]; + DEBUGASSERT(cf); + if(!cf) + return CURLE_FAILED_INIT; + + *done = cf->connected; + if(!*done) { + result = cf->cft->do_connect(cf, data, blocking, done); + if(!result && *done) { + Curl_conn_ev_update_info(data, data->conn); + conn_report_connect_stats(data, data->conn); + data->conn->keepalive = Curl_now(); + } + else if(result) { + conn_report_connect_stats(data, data->conn); + } + } + + return result; +} + +bool Curl_conn_is_connected(struct connectdata *conn, int sockindex) +{ + struct Curl_cfilter *cf; + + cf = conn->cfilter[sockindex]; + return cf && cf->connected; +} + +bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex) +{ + struct Curl_cfilter *cf; + + cf = data->conn->cfilter[sockindex]; + while(cf) { + if(cf->connected) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + cf = cf->next; + } + return FALSE; +} + +bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf) +{ + for(; cf; cf = cf->next) { + if(cf->cft->flags & CF_TYPE_SSL) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; +} + +bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex) +{ + return conn? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE; +} + +bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) +{ + struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL; + + for(; cf; cf = cf->next) { + if(cf->cft->flags & CF_TYPE_MULTIPLEX) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT + || cf->cft->flags & CF_TYPE_SSL) + return FALSE; + } + return FALSE; +} + +bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex) +{ + struct Curl_cfilter *cf; + + (void)data; + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + + cf = data->conn->cfilter[sockindex]; + while(cf && !cf->connected) { + cf = cf->next; + } + if(cf) { + return cf->cft->has_data_pending(cf, data); + } + return FALSE; +} + +void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + /* Get the lowest not-connected filter, if there are any */ + while(cf && !cf->connected && cf->next && !cf->next->connected) + cf = cf->next; + /* From there on, give all filters a chance to adjust the pollset. + * Lower filters are called later, so they may override */ + while(cf) { + cf->cft->adjust_pollset(cf, data, ps); + cf = cf->next; + } +} + +void Curl_conn_adjust_pollset(struct Curl_easy *data, + struct easy_pollset *ps) +{ + int i; + + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + for(i = 0; i < 2; ++i) { + Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps); + } +} + +void Curl_conn_get_host(struct Curl_easy *data, int sockindex, + const char **phost, const char **pdisplay_host, + int *pport) +{ + struct Curl_cfilter *cf; + + DEBUGASSERT(data->conn); + cf = data->conn->cfilter[sockindex]; + if(cf) { + cf->cft->get_host(cf, data, phost, pdisplay_host, pport); + } + else { + /* Some filter ask during shutdown for this, mainly for debugging + * purposes. We hand out the defaults, however this is not always + * accurate, as the connection might be tunneled, etc. But all that + * state is already gone here. */ + *phost = data->conn->host.name; + *pdisplay_host = data->conn->host.dispname; + *pport = data->conn->remote_port; + } +} + +CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + (void)cf; + (void)data; + (void)event; + (void)arg1; + (void)arg2; + return CURLE_OK; +} + +CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool ignore_result, + int event, int arg1, void *arg2) +{ + CURLcode result = CURLE_OK; + + for(; cf; cf = cf->next) { + if(Curl_cf_def_cntrl == cf->cft->cntrl) + continue; + result = cf->cft->cntrl(cf, data, event, arg1, arg2); + if(!ignore_result && result) + break; + } + return result; +} + +curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + curl_socket_t sock; + if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock)) + return sock; + return CURL_SOCKET_BAD; +} + +curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex) +{ + struct Curl_cfilter *cf; + + cf = data->conn? data->conn->cfilter[sockindex] : NULL; + /* if the top filter has not connected, ask it (and its sub-filters) + * for the socket. Otherwise conn->sock[sockindex] should have it. + */ + if(cf && !cf->connected) + return Curl_conn_cf_get_socket(cf, data); + return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD; +} + +void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex) +{ + if(data->conn) { + struct Curl_cfilter *cf = data->conn->cfilter[sockindex]; + if(cf) + (void)Curl_conn_cf_cntrl(cf, data, TRUE, + CF_CTRL_FORGET_SOCKET, 0, NULL); + fake_sclose(data->conn->sock[sockindex]); + data->conn->sock[sockindex] = CURL_SOCKET_BAD; + } +} + +static CURLcode cf_cntrl_all(struct connectdata *conn, + struct Curl_easy *data, + bool ignore_result, + int event, int arg1, void *arg2) +{ + CURLcode result = CURLE_OK; + size_t i; + + for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) { + result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result, + event, arg1, arg2); + if(!ignore_result && result) + break; + } + return result; +} + +void Curl_conn_ev_data_attach(struct connectdata *conn, + struct Curl_easy *data) +{ + cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL); +} + +void Curl_conn_ev_data_detach(struct connectdata *conn, + struct Curl_easy *data) +{ + cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL); +} + +CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data) +{ + return cf_cntrl_all(data->conn, data, FALSE, + CF_CTRL_DATA_SETUP, 0, NULL); +} + +CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data) +{ + return cf_cntrl_all(data->conn, data, FALSE, + CF_CTRL_DATA_IDLE, 0, NULL); +} + +/** + * Notify connection filters that the transfer represented by `data` + * is donw with sending data (e.g. has uploaded everything). + */ +void Curl_conn_ev_data_done_send(struct Curl_easy *data) +{ + cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL); +} + +/** + * Notify connection filters that the transfer represented by `data` + * is finished - eventually premature, e.g. before being complete. + */ +void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature) +{ + cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL); +} + +CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause) +{ + return cf_cntrl_all(data->conn, data, FALSE, + CF_CTRL_DATA_PAUSE, do_pause, NULL); +} + +void Curl_conn_ev_update_info(struct Curl_easy *data, + struct connectdata *conn) +{ + cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL); +} + +/** + * Update connection statistics + */ +static void conn_report_connect_stats(struct Curl_easy *data, + struct connectdata *conn) +{ + struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; + if(cf) { + struct curltime connected; + struct curltime appconnected; + + memset(&connected, 0, sizeof(connected)); + cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected); + if(connected.tv_sec || connected.tv_usec) + Curl_pgrsTimeWas(data, TIMER_CONNECT, connected); + + memset(&appconnected, 0, sizeof(appconnected)); + cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected); + if(appconnected.tv_sec || appconnected.tv_usec) + Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected); + } +} + +bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, + bool *input_pending) +{ + struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; + return cf && !cf->conn->bits.close && + cf->cft->is_alive(cf, data, input_pending); +} + +CURLcode Curl_conn_keep_alive(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf = conn->cfilter[sockindex]; + return cf? cf->cft->keep_alive(cf, data) : CURLE_OK; +} + +size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + CURLcode result; + int n = 0; + + struct Curl_cfilter *cf = conn->cfilter[sockindex]; + result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT, + &n, NULL) : CURLE_UNKNOWN_OPTION; + return (result || n <= 0)? 1 : (size_t)n; +} + + +void Curl_pollset_reset(struct Curl_easy *data, + struct easy_pollset *ps) +{ + size_t i; + (void)data; + memset(ps, 0, sizeof(*ps)); + for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) + ps->sockets[i] = CURL_SOCKET_BAD; +} + +/** + * + */ +void Curl_pollset_change(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + int add_flags, int remove_flags) +{ + unsigned int i; + + (void)data; + DEBUGASSERT(VALID_SOCK(sock)); + if(!VALID_SOCK(sock)) + return; + + DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); + DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); + DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */ + for(i = 0; i < ps->num; ++i) { + if(ps->sockets[i] == sock) { + ps->actions[i] &= (unsigned char)(~remove_flags); + ps->actions[i] |= (unsigned char)add_flags; + /* all gone? remove socket */ + if(!ps->actions[i]) { + if((i + 1) < ps->num) { + memmove(&ps->sockets[i], &ps->sockets[i + 1], + (ps->num - (i + 1)) * sizeof(ps->sockets[0])); + memmove(&ps->actions[i], &ps->actions[i + 1], + (ps->num - (i + 1)) * sizeof(ps->actions[0])); + } + --ps->num; + } + return; + } + } + /* not present */ + if(add_flags) { + /* Having more SOCKETS per easy handle than what is defined + * is a programming error. This indicates that we need + * to raise this limit, making easy_pollset larger. + * Since we use this in tight loops, we do not want to make + * the pollset dynamic unnecessarily. + * The current maximum in practise is HTTP/3 eyeballing where + * we have up to 4 sockets involved in connection setup. + */ + DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE); + if(i < MAX_SOCKSPEREASYHANDLE) { + ps->sockets[i] = sock; + ps->actions[i] = (unsigned char)add_flags; + ps->num = i + 1; + } + } +} + +void Curl_pollset_set(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool do_in, bool do_out) +{ + Curl_pollset_change(data, ps, sock, + (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0), + (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0)); +} + +static void ps_add(struct Curl_easy *data, struct easy_pollset *ps, + int bitmap, curl_socket_t *socks) +{ + if(bitmap) { + int i; + for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) { + if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) { + break; + } + if(bitmap & GETSOCK_READSOCK(i)) { + if(bitmap & GETSOCK_WRITESOCK(i)) + Curl_pollset_add_inout(data, ps, socks[i]); + else + /* is READ, since we checked MASK_RW above */ + Curl_pollset_add_in(data, ps, socks[i]); + } + else + Curl_pollset_add_out(data, ps, socks[i]); + } + } +} + +void Curl_pollset_add_socks(struct Curl_easy *data, + struct easy_pollset *ps, + int (*get_socks_cb)(struct Curl_easy *data, + curl_socket_t *socks)) +{ + curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; + int bitmap; + + bitmap = get_socks_cb(data, socks); + ps_add(data, ps, bitmap, socks); +} + +void Curl_pollset_check(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool *pwant_read, bool *pwant_write) +{ + unsigned int i; + + (void)data; + DEBUGASSERT(VALID_SOCK(sock)); + for(i = 0; i < ps->num; ++i) { + if(ps->sockets[i] == sock) { + *pwant_read = !!(ps->actions[i] & CURL_POLL_IN); + *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT); + return; + } + } + *pwant_read = *pwant_write = FALSE; +} diff --git a/lib/cfilters.h b/lib/cfilters.h new file mode 100644 index 0000000..f838429 --- /dev/null +++ b/lib/cfilters.h @@ -0,0 +1,611 @@ +#ifndef HEADER_CURL_CFILTERS_H +#define HEADER_CURL_CFILTERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + + +struct Curl_cfilter; +struct Curl_easy; +struct Curl_dns_entry; +struct connectdata; + +/* Callback to destroy resources held by this filter instance. + * Implementations MUST NOT chain calls to cf->next. + */ +typedef void Curl_cft_destroy_this(struct Curl_cfilter *cf, + struct Curl_easy *data); + +typedef void Curl_cft_close(struct Curl_cfilter *cf, + struct Curl_easy *data); + +typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done); + +/* Return the hostname and port the connection goes to. + * This may change with the connection state of filters when tunneling + * is involved. + * @param cf the filter to ask + * @param data the easy handle currently active + * @param phost on return, points to the relevant, real hostname. + * this is owned by the connection. + * @param pdisplay_host on return, points to the printable hostname. + * this is owned by the connection. + * @param pport on return, contains the port number + */ +typedef void Curl_cft_get_host(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char **phost, + const char **pdisplay_host, + int *pport); + +struct easy_pollset; + +/* Passing in an easy_pollset for monitoring of sockets, let + * filters add or remove sockets actions (CURL_POLL_OUT, CURL_POLL_IN). + * This may add a socket or, in case no actions remain, remove + * a socket from the set. + * + * Filter implementations need to call filters "below" *after* they have + * made their adjustments. This allows lower filters to override "upper" + * actions. If a "lower" filter is unable to write, it needs to be able + * to disallow POLL_OUT. + * + * A filter without own restrictions/preferences should not modify + * the pollset. Filters, whose filter "below" is not connected, should + * also do no adjustments. + * + * Examples: a TLS handshake, while ongoing, might remove POLL_IN + * when it needs to write, or vice versa. A HTTP/2 filter might remove + * POLL_OUT when a stream window is exhausted and a WINDOW_UPDATE needs + * to be received first and add instead POLL_IN. + * + * @param cf the filter to ask + * @param data the easy handle the pollset is about + * @param ps the pollset (inout) for the easy handle + */ +typedef void Curl_cft_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps); + +typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data); + +typedef ssize_t Curl_cft_send(struct Curl_cfilter *cf, + struct Curl_easy *data, /* transfer */ + const void *buf, /* data to write */ + size_t len, /* amount to write */ + CURLcode *err); /* error to return */ + +typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, /* transfer */ + char *buf, /* store data here */ + size_t len, /* amount to read */ + CURLcode *err); /* error to return */ + +typedef bool Curl_cft_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending); + +typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf, + struct Curl_easy *data); + +/** + * Events/controls for connection filters, their arguments and + * return code handling. Filter callbacks are invoked "top down". + * Return code handling: + * "first fail" meaning that the first filter returning != CURLE_OK, will + * abort further event distribution and determine the result. + * "ignored" meaning return values are ignored and the event is distributed + * to all filters in the chain. Overall result is always CURLE_OK. + */ +/* data event arg1 arg2 return */ +#define CF_CTRL_DATA_ATTACH 1 /* 0 NULL ignored */ +#define CF_CTRL_DATA_DETACH 2 /* 0 NULL ignored */ +#define CF_CTRL_DATA_SETUP 4 /* 0 NULL first fail */ +#define CF_CTRL_DATA_IDLE 5 /* 0 NULL first fail */ +#define CF_CTRL_DATA_PAUSE 6 /* on/off NULL first fail */ +#define CF_CTRL_DATA_DONE 7 /* premature NULL ignored */ +#define CF_CTRL_DATA_DONE_SEND 8 /* 0 NULL ignored */ +/* update conn info at connection and data */ +#define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0 NULL ignored */ +#define CF_CTRL_FORGET_SOCKET (256+1) /* 0 NULL ignored */ + +/** + * Handle event/control for the filter. + * Implementations MUST NOT chain calls to cf->next. + */ +typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2); + + +/** + * Queries to ask via a `Curl_cft_query *query` method on a cfilter chain. + * - MAX_CONCURRENT: the maximum number of parallel transfers the filter + * chain expects to handle at the same time. + * default: 1 if no filter overrides. + * - CONNECT_REPLY_MS: milliseconds until the first indication of a server + * response was received on a connect. For TCP, this + * reflects the time until the socket connected. On UDP + * this gives the time the first bytes from the server + * were received. + * -1 if not determined yet. + * - CF_QUERY_SOCKET: the socket used by the filter chain + */ +/* query res1 res2 */ +#define CF_QUERY_MAX_CONCURRENT 1 /* number - */ +#define CF_QUERY_CONNECT_REPLY_MS 2 /* number - */ +#define CF_QUERY_SOCKET 3 /* - curl_socket_t */ +#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */ +#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */ + +/** + * Query the cfilter for properties. Filters ignorant of a query will + * pass it "down" the filter chain. + */ +typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2); + +/** + * Type flags for connection filters. A filter can have none, one or + * many of those. Use to evaluate state/capabilities of a filter chain. + * + * CF_TYPE_IP_CONNECT: provides an IP connection or sth equivalent, like + * a CONNECT tunnel, a UNIX domain socket, a QUIC + * connection, etc. + * CF_TYPE_SSL: provide SSL/TLS + * CF_TYPE_MULTIPLEX: provides multiplexing of easy handles + */ +#define CF_TYPE_IP_CONNECT (1 << 0) +#define CF_TYPE_SSL (1 << 1) +#define CF_TYPE_MULTIPLEX (1 << 2) + +/* A connection filter type, e.g. specific implementation. */ +struct Curl_cftype { + const char *name; /* name of the filter type */ + int flags; /* flags of filter type */ + int log_level; /* log level for such filters */ + Curl_cft_destroy_this *destroy; /* destroy resources of this cf */ + Curl_cft_connect *do_connect; /* establish connection */ + Curl_cft_close *do_close; /* close conn */ + Curl_cft_get_host *get_host; /* host filter talks to */ + Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */ + Curl_cft_data_pending *has_data_pending;/* conn has data pending */ + Curl_cft_send *do_send; /* send data */ + Curl_cft_recv *do_recv; /* receive data */ + Curl_cft_cntrl *cntrl; /* events/control */ + Curl_cft_conn_is_alive *is_alive; /* FALSE if conn is dead, Jim! */ + Curl_cft_conn_keep_alive *keep_alive; /* try to keep it alive */ + Curl_cft_query *query; /* query filter chain */ +}; + +/* A connection filter instance, e.g. registered at a connection */ +struct Curl_cfilter { + const struct Curl_cftype *cft; /* the type providing implementation */ + struct Curl_cfilter *next; /* next filter in chain */ + void *ctx; /* filter type specific settings */ + struct connectdata *conn; /* the connection this filter belongs to */ + int sockindex; /* the index the filter is installed at */ + BIT(connected); /* != 0 iff this filter is connected */ +}; + +/* Default implementations for the type functions, implementing nop. */ +void Curl_cf_def_destroy_this(struct Curl_cfilter *cf, + struct Curl_easy *data); + +/* Default implementations for the type functions, implementing pass-through + * the filter chain. */ +void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data, + const char **phost, const char **pdisplay_host, + int *pport); +void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps); +bool Curl_cf_def_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data); +ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err); +ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err); +CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2); +bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending); +CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf, + struct Curl_easy *data); +CURLcode Curl_cf_def_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2); + +/** + * Create a new filter instance, unattached to the filter chain. + * Use Curl_conn_cf_add() to add it to the chain. + * @param pcf on success holds the created instance + * @param cft the filter type + * @param ctx the type specific context to use + */ +CURLcode Curl_cf_create(struct Curl_cfilter **pcf, + const struct Curl_cftype *cft, + void *ctx); + +/** + * Add a filter instance to the `sockindex` filter chain at connection + * `conn`. The filter must not already be attached. It is inserted at + * the start of the chain (top). + */ +void Curl_conn_cf_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + struct Curl_cfilter *cf); + +/** + * Insert a filter (chain) after `cf_at`. + * `cf_new` must not already be attached. + */ +void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at, + struct Curl_cfilter *cf_new); + +/** + * Discard, e.g. remove and destroy `discard` iff + * it still is in the filter chain below `cf`. If `discard` + * is no longer found beneath `cf` return FALSE. + * if `destroy_always` is TRUE, will call `discard`s destroy + * function and free it even if not found in the subchain. + */ +bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, + struct Curl_cfilter *discard, + struct Curl_easy *data, + bool destroy_always); + +/** + * Discard all cfilters starting with `*pcf` and clearing it afterwards. + */ +void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf, + struct Curl_easy *data); + +/** + * Remove and destroy all filters at chain `sockindex` on connection `conn`. + */ +void Curl_conn_cf_discard_all(struct Curl_easy *data, + struct connectdata *conn, + int sockindex); + + +CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done); +void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data); +ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err); +ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err); +CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool ignore_result, + int event, int arg1, void *arg2); + +/** + * Determine if the connection filter chain is using SSL to the remote host + * (or will be once connected). + */ +bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf); + +/** + * Get the socket used by the filter chain starting at `cf`. + * Returns CURL_SOCKET_BAD if not available. + */ +curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf, + struct Curl_easy *data); + + +#define CURL_CF_SSL_DEFAULT -1 +#define CURL_CF_SSL_DISABLE 0 +#define CURL_CF_SSL_ENABLE 1 + +/** + * Bring the filter chain at `sockindex` for connection `data->conn` into + * connected state. Which will set `*done` to TRUE. + * This can be called on an already connected chain with no side effects. + * When not `blocking`, calls may return without error and `*done != TRUE`, + * while the individual filters negotiated the connection. + */ +CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex, + bool blocking, bool *done); + +/** + * Check if the filter chain at `sockindex` for connection `conn` is + * completely connected. + */ +bool Curl_conn_is_connected(struct connectdata *conn, int sockindex); + +/** + * Determine if we have reached the remote host on IP level, e.g. + * have a TCP connection. This turns TRUE before a possible SSL + * handshake has been started/done. + */ +bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex); + +/** + * Determine if the connection is using SSL to the remote host + * (or will be once connected). This will return FALSE, if SSL + * is only used in proxying and not for the tunnel itself. + */ +bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex); + +/** + * Connection provides multiplexing of easy handles at `socketindex`. + */ +bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex); + +/** + * Close the filter chain at `sockindex` for connection `data->conn`. + * Filters remain in place and may be connected again afterwards. + */ +void Curl_conn_close(struct Curl_easy *data, int sockindex); + +/** + * Return if data is pending in some connection filter at chain + * `sockindex` for connection `data->conn`. + */ +bool Curl_conn_data_pending(struct Curl_easy *data, + int sockindex); + +/** + * Return the socket used on data's connection for the index. + * Returns CURL_SOCKET_BAD if not available. + */ +curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex); + +/** + * Tell filters to forget about the socket at sockindex. + */ +void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex); + +/** + * Adjust the pollset for the filter chain startgin at `cf`. + */ +void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps); + +/** + * Adjust pollset from filters installed at transfer's connection. + */ +void Curl_conn_adjust_pollset(struct Curl_easy *data, + struct easy_pollset *ps); + +/** + * Receive data through the filter chain at `sockindex` for connection + * `data->conn`. Copy at most `len` bytes into `buf`. Return the + * actuel number of bytes copied or a negative value on error. + * The error code is placed into `*code`. + */ +ssize_t Curl_conn_recv(struct Curl_easy *data, int sockindex, char *buf, + size_t len, CURLcode *code); + +/** + * Send `len` bytes of data from `buf` through the filter chain `sockindex` + * at connection `data->conn`. Return the actual number of bytes written + * or a negative value on error. + * The error code is placed into `*code`. + */ +ssize_t Curl_conn_send(struct Curl_easy *data, int sockindex, + const void *buf, size_t len, CURLcode *code); + +/** + * The easy handle `data` is being attached to `conn`. This does + * not mean that data will actually do a transfer. Attachment is + * also used for temporary actions on the connection. + */ +void Curl_conn_ev_data_attach(struct connectdata *conn, + struct Curl_easy *data); + +/** + * The easy handle `data` is being detached (no longer served) + * by connection `conn`. All filters are informed to release any resources + * related to `data`. + * Note: there may be several `data` attached to a connection at the same + * time. + */ +void Curl_conn_ev_data_detach(struct connectdata *conn, + struct Curl_easy *data); + +/** + * Notify connection filters that they need to setup data for + * a transfer. + */ +CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data); + +/** + * Notify connection filters that now would be a good time to + * perform any idle, e.g. time related, actions. + */ +CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data); + +/** + * Notify connection filters that the transfer represented by `data` + * is donw with sending data (e.g. has uploaded everything). + */ +void Curl_conn_ev_data_done_send(struct Curl_easy *data); + +/** + * Notify connection filters that the transfer represented by `data` + * is finished - eventually premature, e.g. before being complete. + */ +void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature); + +/** + * Notify connection filters that the transfer of data is paused/unpaused. + */ +CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause); + +/** + * Inform connection filters to update their info in `conn`. + */ +void Curl_conn_ev_update_info(struct Curl_easy *data, + struct connectdata *conn); + +/** + * Check if FIRSTSOCKET's cfilter chain deems connection alive. + */ +bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, + bool *input_pending); + +/** + * Try to upkeep the connection filters at sockindex. + */ +CURLcode Curl_conn_keep_alive(struct Curl_easy *data, + struct connectdata *conn, + int sockindex); + +void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data); +void Curl_conn_get_host(struct Curl_easy *data, int sockindex, + const char **phost, const char **pdisplay_host, + int *pport); + +/** + * Get the maximum number of parallel transfers the connection + * expects to be able to handle at `sockindex`. + */ +size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, + struct connectdata *conn, + int sockindex); + + +void Curl_pollset_reset(struct Curl_easy *data, + struct easy_pollset *ps); + +/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for + * socket `sock`. If the socket is not already part of the poll set, it + * will be added. + * If the socket is present and all poll flags are cleared, it will be removed. + */ +void Curl_pollset_change(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + int add_flags, int remove_flags); + +void Curl_pollset_set(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool do_in, bool do_out); + +#define Curl_pollset_add_in(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0) +#define Curl_pollset_add_out(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), CURL_POLL_OUT, 0) +#define Curl_pollset_add_inout(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), \ + CURL_POLL_IN|CURL_POLL_OUT, 0) +#define Curl_pollset_set_in_only(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), \ + CURL_POLL_IN, CURL_POLL_OUT) +#define Curl_pollset_set_out_only(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), \ + CURL_POLL_OUT, CURL_POLL_IN) + +void Curl_pollset_add_socks(struct Curl_easy *data, + struct easy_pollset *ps, + int (*get_socks_cb)(struct Curl_easy *data, + curl_socket_t *socks)); + +/** + * Check if the pollset, as is, wants to read and/or write regarding + * the given socket. + */ +void Curl_pollset_check(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool *pwant_read, bool *pwant_write); + +/** + * Types and macros used to keep the current easy handle in filter calls, + * allowing for nested invocations. See #10336. + * + * `cf_call_data` is intended to be a member of the cfilter's `ctx` type. + * A filter defines the macro `CF_CTX_CALL_DATA` to give access to that. + * + * With all values 0, the default, this indicates that there is no cfilter + * call with `data` ongoing. + * Macro `CF_DATA_SAVE` preserves the current `cf_call_data` in a local + * variable and sets the `data` given, incrementing the `depth` counter. + * + * Macro `CF_DATA_RESTORE` restores the old values from the local variable, + * while checking that `depth` values are as expected (debug build), catching + * cases where a "lower" RESTORE was not called. + * + * Finally, macro `CF_DATA_CURRENT` gives the easy handle of the current + * invocation. + */ +struct cf_call_data { + struct Curl_easy *data; +#ifdef DEBUGBUILD + int depth; +#endif +}; + +/** + * define to access the `struct cf_call_data for a cfilter. Normally + * a member in the cfilter's `ctx`. + * + * #define CF_CTX_CALL_DATA(cf) -> struct cf_call_data instance +*/ + +#ifdef DEBUGBUILD + +#define CF_DATA_SAVE(save, cf, data) \ + do { \ + (save) = CF_CTX_CALL_DATA(cf); \ + DEBUGASSERT((save).data == NULL || (save).depth > 0); \ + CF_CTX_CALL_DATA(cf).depth++; \ + CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \ + } while(0) + +#define CF_DATA_RESTORE(cf, save) \ + do { \ + DEBUGASSERT(CF_CTX_CALL_DATA(cf).depth == (save).depth + 1); \ + DEBUGASSERT((save).data == NULL || (save).depth > 0); \ + CF_CTX_CALL_DATA(cf) = (save); \ + } while(0) + +#else /* DEBUGBUILD */ + +#define CF_DATA_SAVE(save, cf, data) \ + do { \ + (save) = CF_CTX_CALL_DATA(cf); \ + CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \ + } while(0) + +#define CF_DATA_RESTORE(cf, save) \ + do { \ + CF_CTX_CALL_DATA(cf) = (save); \ + } while(0) + +#endif /* !DEBUGBUILD */ + +#define CF_DATA_CURRENT(cf) \ + ((cf)? (CF_CTX_CALL_DATA(cf).data) : NULL) + +#endif /* HEADER_CURL_CFILTERS_H */ diff --git a/lib/config-amigaos.h b/lib/config-amigaos.h new file mode 100644 index 0000000..d168b44 --- /dev/null +++ b/lib/config-amigaos.h @@ -0,0 +1,129 @@ +#ifndef HEADER_CURL_CONFIG_AMIGAOS_H +#define HEADER_CURL_CONFIG_AMIGAOS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* ================================================================ */ +/* Hand crafted config file for AmigaOS */ +/* ================================================================ */ + +#ifdef __AMIGA__ /* Any AmigaOS flavour */ + +#define HAVE_ARPA_INET_H 1 +#define HAVE_CLOSESOCKET_CAMEL 1 +#define HAVE_IOCTLSOCKET_CAMEL 1 +#define HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1 +#define HAVE_LONGLONG 1 +#define HAVE_NETDB_H 1 +#define HAVE_NETINET_IN_H 1 +#define HAVE_NET_IF_H 1 +#define HAVE_PWD_H 1 +#define HAVE_SELECT 1 +#define HAVE_SIGNAL 1 +#define HAVE_SOCKET 1 +#define HAVE_STRCASECMP 1 +#define HAVE_STRDUP 1 +#define HAVE_STRICMP 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRUCT_TIMEVAL 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_SYS_SOCKIO_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UTIME 1 +#define HAVE_UTIME_H 1 +#define HAVE_WRITABLE_ARGV 1 +#define HAVE_SYS_IOCTL_H 1 + +#define NEED_MALLOC_H 1 + +#define SIZEOF_INT 4 +#define SIZEOF_SIZE_T 4 + +#ifndef SIZEOF_CURL_OFF_T +#define SIZEOF_CURL_OFF_T 8 +#endif + +#define USE_MANUAL 1 +#define CURL_DISABLE_LDAP 1 + +#ifndef OS +#define OS "AmigaOS" +#endif + +#define PACKAGE "curl" +#define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.se/mail/" +#define PACKAGE_NAME "curl" +#define PACKAGE_STRING "curl -" +#define PACKAGE_TARNAME "curl" +#define PACKAGE_VERSION "-" + +#if defined(USE_AMISSL) +#define CURL_CA_PATH "AmiSSL:Certs" +#elif defined(__MORPHOS__) +#define CURL_CA_BUNDLE "MOSSYS:Data/SSL/curl-ca-bundle.crt" +#else +#define CURL_CA_BUNDLE "s:curl-ca-bundle.crt" +#endif + +#define STDC_HEADERS 1 + +#define in_addr_t int + +#ifndef F_OK +# define F_OK 0 +#endif + +#ifndef O_RDONLY +# define O_RDONLY 0x0000 +#endif + +#ifndef LONG_MAX +# define LONG_MAX 0x7fffffffL +#endif + +#ifndef LONG_MIN +# define LONG_MIN (-0x7fffffffL-1) +#endif + +#define HAVE_RECV 1 +#define RECV_TYPE_ARG1 long +#define RECV_TYPE_ARG2 char * +#define RECV_TYPE_ARG3 long +#define RECV_TYPE_ARG4 long +#define RECV_TYPE_RETV long + +#define HAVE_SEND 1 +#define SEND_TYPE_ARG1 int +#define SEND_QUAL_ARG2 const +#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_ARG4 int +#define SEND_TYPE_RETV int + +#endif /* __AMIGA__ */ +#endif /* HEADER_CURL_CONFIG_AMIGAOS_H */ diff --git a/lib/config-dos.h b/lib/config-dos.h new file mode 100644 index 0000000..c6fbba7 --- /dev/null +++ b/lib/config-dos.h @@ -0,0 +1,138 @@ +#ifndef HEADER_CURL_CONFIG_DOS_H +#define HEADER_CURL_CONFIG_DOS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + + +/* ================================================================ */ +/* lib/config-dos.h - Hand crafted config file for DOS */ +/* ================================================================ */ + +#ifndef OS +#if defined(DJGPP) + #define OS "MSDOS/djgpp" +#elif defined(__HIGHC__) + #define OS "MSDOS/HighC" +#else + #define OS "MSDOS/?" +#endif +#endif + +#define PACKAGE "curl" + +#define USE_MANUAL 1 + +#define HAVE_ARPA_INET_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FREEADDRINFO 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_IO_H 1 +#define HAVE_IOCTL_FIONBIO 1 +#define HAVE_IOCTLSOCKET 1 +#define HAVE_IOCTLSOCKET_FIONBIO 1 +#define HAVE_LOCALE_H 1 +#define HAVE_LONGLONG 1 +#define HAVE_NETDB_H 1 +#define HAVE_NETINET_IN_H 1 +#define HAVE_NETINET_TCP_H 1 +#define HAVE_NET_IF_H 1 +#define HAVE_RECV 1 +#define HAVE_SELECT 1 +#define HAVE_SEND 1 +#define HAVE_SETLOCALE 1 +#define HAVE_SETMODE 1 +#define HAVE_SIGNAL 1 +#define HAVE_SOCKET 1 +#define HAVE_STRDUP 1 +#define HAVE_STRICMP 1 +#define HAVE_STRTOLL 1 +#define HAVE_STRUCT_TIMEVAL 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UNISTD_H 1 + +#define NEED_MALLOC_H 1 + +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 +#define SIZEOF_SIZE_T 4 +#define SIZEOF_CURL_OFF_T 8 +#define STDC_HEADERS 1 + +/* Qualifiers for send() and recv() */ + +#define SEND_TYPE_ARG1 int +#define SEND_QUAL_ARG2 const +#define SEND_TYPE_ARG2 void * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_ARG4 int +#define SEND_TYPE_RETV int + +#define RECV_TYPE_ARG1 int +#define RECV_TYPE_ARG2 void * +#define RECV_TYPE_ARG3 int +#define RECV_TYPE_ARG4 int +#define RECV_TYPE_RETV int + +#define BSD + +/* CURLDEBUG definition enables memory tracking */ +/* #define CURLDEBUG */ + +/* to disable LDAP */ +#define CURL_DISABLE_LDAP 1 + +#define in_addr_t u_long + +#if defined(__HIGHC__) || \ + (defined(__GNUC__) && (__GNUC__ < 4)) + #define ssize_t int +#endif + +/* Target HAVE_x section */ + +#if defined(DJGPP) + #define HAVE_BASENAME 1 + #define HAVE_STRCASECMP 1 + #define HAVE_SIGACTION 1 + #define HAVE_SIGSETJMP 1 + #define HAVE_SYS_TIME_H 1 + #define HAVE_TERMIOS_H 1 + +#elif defined(__HIGHC__) + #define HAVE_SYS_TIME_H 1 + #define strerror(e) strerror_s_((e)) +#endif + +#ifdef MSDOS /* Watt-32 */ + #define HAVE_CLOSE_S 1 +#endif + +#undef word +#undef byte + +#endif /* HEADER_CURL_CONFIG_DOS_H */ diff --git a/lib/config-mac.h b/lib/config-mac.h new file mode 100644 index 0000000..c29888f --- /dev/null +++ b/lib/config-mac.h @@ -0,0 +1,103 @@ +#ifndef HEADER_CURL_CONFIG_MAC_H +#define HEADER_CURL_CONFIG_MAC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* =================================================================== */ +/* Hand crafted config file for Mac OS 9 */ +/* =================================================================== */ +/* On Mac OS X you must run configure to generate curl_config.h file */ +/* =================================================================== */ + +#ifndef OS +#define OS "mac" +#endif + +#include +#if TYPE_LONGLONG +#define HAVE_LONGLONG 1 +#endif + +/* Define if you want the built-in manual */ +#define USE_MANUAL 1 + +#define HAVE_NETINET_IN_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_NETDB_H 1 +#define HAVE_ARPA_INET_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_NET_IF_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_FCNTL_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_UTIME_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_UTIME_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_ALARM 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_UTIME 1 +#define HAVE_SELECT 1 +#define HAVE_SOCKET 1 +#define HAVE_STRUCT_TIMEVAL 1 + +#define HAVE_SIGACTION 1 + +#ifdef MACOS_SSL_SUPPORT +# define USE_OPENSSL 1 +#endif + +#define CURL_DISABLE_LDAP 1 + +#define HAVE_IOCTL_FIONBIO 1 + +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 +#define SIZEOF_SIZE_T 4 +#ifdef HAVE_LONGLONG +#define SIZEOF_CURL_OFF_T 8 +#else +#define SIZEOF_CURL_OFF_T 4 +#endif + +#define HAVE_RECV 1 +#define RECV_TYPE_ARG1 int +#define RECV_TYPE_ARG2 void * +#define RECV_TYPE_ARG3 size_t +#define RECV_TYPE_ARG4 int +#define RECV_TYPE_RETV ssize_t + +#define HAVE_SEND 1 +#define SEND_TYPE_ARG1 int +#define SEND_QUAL_ARG2 const +#define SEND_TYPE_ARG2 void * +#define SEND_TYPE_ARG3 size_t +#define SEND_TYPE_ARG4 int +#define SEND_TYPE_RETV ssize_t + +#define HAVE_EXTRA_STRICMP_H 1 +#define HAVE_EXTRA_STRDUP_H 1 + +#endif /* HEADER_CURL_CONFIG_MAC_H */ diff --git a/lib/config-os400.h b/lib/config-os400.h new file mode 100644 index 0000000..32852bb --- /dev/null +++ b/lib/config-os400.h @@ -0,0 +1,334 @@ +#ifndef HEADER_CURL_CONFIG_OS400_H +#define HEADER_CURL_CONFIG_OS400_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* ================================================================ */ +/* Hand crafted config file for OS/400 */ +/* ================================================================ */ + +#pragma enum(int) + +#undef PACKAGE + +/* Version number of this archive. */ +#undef VERSION + +/* Define cpu-machine-OS */ +#ifndef OS +#define OS "OS/400" +#endif + +/* OS400 supports a 3-argument ASCII version of gethostbyaddr_r(), but its + * prototype is incompatible with the "standard" one (1st argument is not + * const). However, getaddrinfo() is supported (ASCII version defined as + * a local wrapper in setup-os400.h) in a threadsafe way: we can then + * configure getaddrinfo() as such and get rid of gethostbyname_r() without + * loss of threadsafeness. */ +#undef HAVE_GETHOSTBYNAME_R +#undef HAVE_GETHOSTBYNAME_R_3 +#undef HAVE_GETHOSTBYNAME_R_5 +#undef HAVE_GETHOSTBYNAME_R_6 +#define HAVE_GETADDRINFO +#define HAVE_GETADDRINFO_THREADSAFE + +/* Define if you need the _REENTRANT define for some functions */ +#undef NEED_REENTRANT + +/* Define if you want to enable IPv6 support */ +#define ENABLE_IPV6 + +/* Define if struct sockaddr_in6 has the sin6_scope_id member */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define this to 'int' if ssize_t is not an available typedefed type */ +#undef ssize_t + +/* Define this as a suitable file to read random data from */ +#undef RANDOM_FILE + +/* Define to 1 if you have the alarm function. */ +#define HAVE_ALARM 1 + +/* Define if you have the header file. */ +#define HAVE_ARPA_INET_H + +/* Define if you have the `closesocket' function. */ +#undef HAVE_CLOSESOCKET + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H + +/* Define if you have the `geteuid' function. */ +#define HAVE_GETEUID + +/* Define if you have the `gethostname' function. */ +#define HAVE_GETHOSTNAME + +/* Define if you have the `getpass_r' function. */ +#undef HAVE_GETPASS_R + +/* Define to 1 if you have the getpeername function. */ +#define HAVE_GETPEERNAME 1 + +/* Define if you have the `getpwuid' function. */ +#define HAVE_GETPWUID + +/* Define to 1 if you have the getsockname function. */ +#define HAVE_GETSOCKNAME 1 + +/* Define if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY + +/* Define if you have the `timeval' struct. */ +#define HAVE_STRUCT_TIMEVAL + +/* Define if you have the header file. */ +#undef HAVE_IO_H + +/* Define if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define if you have GSS API. */ +#define HAVE_GSSAPI + +/* Define if you have the GNU gssapi libraries */ +#undef HAVE_GSSGNU + +/* Define if you need the malloc.h header file even with stdlib.h */ +/* #define NEED_MALLOC_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_NETDB_H + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H + +/* Define if you have the header file. */ +#define HAVE_PWD_H + +/* Define if you have the `select' function. */ +#define HAVE_SELECT + +/* Define if you have the `sigaction' function. */ +#define HAVE_SIGACTION + +/* Define if you have the `signal' function. */ +#undef HAVE_SIGNAL + +/* Define if you have the `socket' function. */ +#define HAVE_SOCKET + + +/* The following define is needed on OS400 to enable strcmpi(), stricmp() and + strdup(). */ +#define __cplusplus__strings__ + +/* Define if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the `strcmpi' function. */ +#define HAVE_STRCMPI + +/* Define if you have the `stricmp' function. */ +#define HAVE_STRICMP + +/* Define if you have the `strdup' function. */ +#define HAVE_STRDUP + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_STROPTS_H + +/* Define if you have the `strtok_r' function. */ +#define HAVE_STRTOK_R + +/* Define if you have the `strtoll' function. */ +#undef HAVE_STRTOLL /* Allows ASCII compile on V5R1. */ + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* Define if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG + +/* The size of a `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 4 + +/* The size of `curl_off_t', as computed by sizeof. */ +#define SIZEOF_CURL_OFF_T 8 + +/* Define this if you have struct sockaddr_storage */ +#define HAVE_STRUCT_SOCKADDR_STORAGE + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS + +/* Define to enable HTTP3 support (experimental, requires NGTCP2, QUICHE or + MSH3) */ +#undef ENABLE_QUIC + +/* Version number of package */ +#undef VERSION + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#define _LARGE_FILES + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* type to use in place of in_addr_t if not defined */ +#define in_addr_t unsigned long + +/* Define to `unsigned' if does not define. */ +#undef size_t + +/* Define if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO + +/* Define if you have a working ioctl SIOCGIFADDR function. */ +#define HAVE_IOCTL_SIOCGIFADDR + +/* To disable LDAP */ +#undef CURL_DISABLE_LDAP + +/* Definition to make a library symbol externally visible. */ +#define CURL_EXTERN_SYMBOL + +/* Define if you have the ldap_url_parse procedure. */ +/* #define HAVE_LDAP_URL_PARSE */ /* Disabled because of an IBM bug. */ + +/* Define if you have the recv function. */ +#define HAVE_RECV + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 char * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 int + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV int + +/* Define if you have the send function. */ +#define HAVE_SEND + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 char * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 int + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV int + +/* Define to use the OS/400 crypto library. */ +#define USE_OS400CRYPTO + +/* Define to use Unix sockets. */ +#define USE_UNIX_SOCKETS + +/* Use the system keyring as the default CA bundle. */ +#define CURL_CA_BUNDLE "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB" + +/* ---------------------------------------------------------------- */ +/* ADDITIONAL DEFINITIONS */ +/* ---------------------------------------------------------------- */ + +/* The following must be defined BEFORE system header files inclusion. */ + +#define __ptr128 /* No teraspace. */ +#define qadrt_use_fputc_inline /* Generate fputc() wrapper inline. */ +#define qadrt_use_fread_inline /* Generate fread() wrapper inline. */ +#define qadrt_use_fwrite_inline /* Generate fwrite() wrapper inline. */ + +#endif /* HEADER_CURL_CONFIG_OS400_H */ diff --git a/lib/config-plan9.h b/lib/config-plan9.h new file mode 100644 index 0000000..aa9623f --- /dev/null +++ b/lib/config-plan9.h @@ -0,0 +1,147 @@ +#ifndef HEADER_CURL_CONFIG_PLAN9_H +#define HEADER_CURL_CONFIG_PLAN9_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#define BUILDING_LIBCURL 1 +#define CURL_CA_BUNDLE "/sys/lib/tls/ca.pem" +#define CURL_CA_PATH "/sys/lib/tls" +#define CURL_STATICLIB 1 +#define ENABLE_IPV6 1 +#define CURL_DISABLE_LDAP 1 + +#define NEED_REENTRANT 1 +#ifndef OS +#define OS "plan9" +#endif +#define PACKAGE "curl" +#define PACKAGE_NAME "curl" +#define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.se/mail/" +#define PACKAGE_STRING "curl -" +#define PACKAGE_TARNAME "curl" +#define PACKAGE_VERSION "-" +#define RANDOM_FILE "/dev/random" +#define VERSION "0.0.0" /* TODO */ + +#define STDC_HEADERS 1 + +#ifdef _BITS64 +#error not implement +#else +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 +#define SIZEOF_OFF_T 8 +#define SIZEOF_CURL_OFF_T 4 /* curl_off_t = timediff_t = int */ +#define SIZEOF_SIZE_T 4 +#define SIZEOF_TIME_T 4 +#endif + +#define HAVE_RECV 1 +#define RECV_TYPE_ARG1 int +#define RECV_TYPE_ARG2 void * +#define RECV_TYPE_ARG3 int +#define RECV_TYPE_ARG4 int +#define RECV_TYPE_RETV int + +#define HAVE_SELECT 1 + +#define HAVE_SEND 1 +#define SEND_TYPE_ARG1 int +#define SEND_TYPE_ARG2 void * +#define SEND_QUAL_ARG2 +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_ARG4 int +#define SEND_TYPE_RETV int + +#define HAVE_ALARM 1 +#define HAVE_ARPA_INET_H 1 +#define HAVE_BASENAME 1 +#define HAVE_BOOL_T 1 +#define HAVE_FCNTL 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FREEADDRINFO 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETEUID 1 +#define HAVE_GETHOSTNAME 1 +#define HAVE_GETPPID 1 +#define HAVE_GETPWUID 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_GMTIME_R 1 +#define HAVE_INET_NTOP 1 +#define HAVE_INET_PTON 1 +#define HAVE_LIBGEN_H 1 +#define HAVE_LIBZ 1 +#define HAVE_LOCALE_H 1 +#define HAVE_LONGLONG 1 +#define HAVE_NETDB_H 1 +#define HAVE_NETINET_IN_H 1 +#define HAVE_NETINET_TCP_H 1 +#define HAVE_PWD_H 1 +#define HAVE_SYS_SELECT_H 1 + +#define USE_OPENSSL 1 + +#define HAVE_PIPE 1 +#define HAVE_POLL_FINE 1 +#define HAVE_POLL_H 1 +#define HAVE_PTHREAD_H 1 +#define HAVE_SETLOCALE 1 + +#define HAVE_SIGACTION 1 +#define HAVE_SIGNAL 1 +#define HAVE_SIGSETJMP 1 +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 +#define HAVE_SOCKET 1 +#define HAVE_SSL_GET_SHUTDOWN 1 +#define HAVE_STDBOOL_H 1 +#define HAVE_STRCASECMP 1 +#define HAVE_STRDUP 1 +#define HAVE_STRTOK_R 1 +#define HAVE_STRTOLL 1 +#define HAVE_STRUCT_TIMEVAL 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_RESOURCE_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_UN_H 1 +#define HAVE_TERMIOS_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UTIME 1 +#define HAVE_UTIME_H 1 + +#define HAVE_POSIX_STRERROR_R 1 +#define HAVE_STRERROR_R 1 +#define USE_MANUAL 1 + +#define __attribute__(x) + +#ifndef __cplusplus +#undef inline +#endif + +#endif /* HEADER_CURL_CONFIG_PLAN9_H */ diff --git a/lib/config-riscos.h b/lib/config-riscos.h new file mode 100644 index 0000000..f3a8e68 --- /dev/null +++ b/lib/config-riscos.h @@ -0,0 +1,280 @@ +#ifndef HEADER_CURL_CONFIG_RISCOS_H +#define HEADER_CURL_CONFIG_RISCOS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* ================================================================ */ +/* Hand crafted config file for RISC OS */ +/* ================================================================ */ + +/* Name of this package! */ +#undef PACKAGE + +/* Version number of this archive. */ +#undef VERSION + +/* Define cpu-machine-OS */ +#ifndef OS +#define OS "ARM-RISC OS" +#endif + +/* Define if you want the built-in manual */ +#define USE_MANUAL + +/* Define if you have the gethostbyname_r() function with 3 arguments */ +#undef HAVE_GETHOSTBYNAME_R_3 + +/* Define if you have the gethostbyname_r() function with 5 arguments */ +#undef HAVE_GETHOSTBYNAME_R_5 + +/* Define if you have the gethostbyname_r() function with 6 arguments */ +#undef HAVE_GETHOSTBYNAME_R_6 + +/* Define if you need the _REENTRANT define for some functions */ +#undef NEED_REENTRANT + +/* Define if you want to enable IPv6 support */ +#undef ENABLE_IPV6 + +/* Define if struct sockaddr_in6 has the sin6_scope_id member */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define this to 'int' if ssize_t is not an available typedefed type */ +#undef ssize_t + +/* Define this as a suitable file to read random data from */ +#undef RANDOM_FILE + +/* Define if you want to enable IPv6 support */ +#undef ENABLE_IPV6 + +/* Define if you have the alarm function. */ +#define HAVE_ALARM + +/* Define if you have the header file. */ +#define HAVE_ARPA_INET_H + +/* Define if you have the `closesocket' function. */ +#undef HAVE_CLOSESOCKET + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H + +/* Define if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE + +/* Define if getaddrinfo exists and works */ +#define HAVE_GETADDRINFO + +/* Define if you have the `geteuid' function. */ +#undef HAVE_GETEUID + +/* Define if you have the `gethostbyname_r' function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define if you have the `gethostname' function. */ +#define HAVE_GETHOSTNAME + +/* Define if you have the `getpass_r' function. */ +#undef HAVE_GETPASS_R + +/* Define if you have the `getpwuid' function. */ +#undef HAVE_GETPWUID + +/* Define if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY + +/* Define if you have the `timeval' struct. */ +#define HAVE_STRUCT_TIMEVAL + +/* Define if you have the header file. */ +#undef HAVE_IO_H + +/* Define if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define if you need the malloc.h header file even with stdlib.h */ +/* #define NEED_MALLOC_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_NETDB_H + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H + +/* Define if you have the header file. */ +#undef HAVE_PWD_H + +/* Define if you have the `select' function. */ +#define HAVE_SELECT + +/* Define if you have the `sigaction' function. */ +#undef HAVE_SIGACTION + +/* Define if you have the `signal' function. */ +#define HAVE_SIGNAL + +/* Define if you have the `socket' function. */ +#define HAVE_SOCKET + +/* Define if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the `strcmpi' function. */ +#undef HAVE_STRCMPI + +/* Define if you have the `strdup' function. */ +#define HAVE_STRDUP + +/* Define if you have the `stricmp' function. */ +#define HAVE_STRICMP + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the `strtok_r' function. */ +#undef HAVE_STRTOK_R + +/* Define if you have the `strtoll' function. */ +#undef HAVE_STRTOLL + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 4 + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `unsigned' if does not define. */ +#undef size_t + +/* Define to `int' if does not define. */ +#undef ssize_t + +/* Define if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO + +/* to disable LDAP */ +#define CURL_DISABLE_LDAP + +/* Define if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV ssize_t + +/* Define if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV ssize_t + +#endif /* HEADER_CURL_CONFIG_RISCOS_H */ diff --git a/lib/config-win32.h b/lib/config-win32.h new file mode 100644 index 0000000..89ed1a0 --- /dev/null +++ b/lib/config-win32.h @@ -0,0 +1,516 @@ +#ifndef HEADER_CURL_CONFIG_WIN32_H +#define HEADER_CURL_CONFIG_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* ================================================================ */ +/* Hand crafted config file for Windows */ +/* ================================================================ */ + +/* ---------------------------------------------------------------- */ +/* HEADER FILES */ +/* ---------------------------------------------------------------- */ + +/* Define if you have the header file. */ +/* #define HAVE_ARPA_INET_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you need header even with header file. */ +#define NEED_MALLOC_H 1 + +/* Define if you have the header file. */ +/* #define HAVE_NETDB_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_NETINET_IN_H 1 */ + +/* Define to 1 if you have the header file. */ +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__) +#define HAVE_STDBOOL_H 1 +#endif + +/* Define if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_SYS_PARAM_H 1 +#endif + +/* Define if you have the header file. */ +/* #define HAVE_SYS_SELECT_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_SYS_SOCKET_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_SYS_SOCKIO_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_SYS_TIME_H 1 +#endif + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UTIME_H 1 + +/* Define if you have the header file. */ +/* #define HAVE_TERMIO_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_TERMIOS_H 1 */ + +/* Define if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_LIBGEN_H 1 +#endif + +/* ---------------------------------------------------------------- */ +/* OTHER HEADER INFO */ +/* ---------------------------------------------------------------- */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if bool is an available type. */ +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__) +#define HAVE_BOOL_T 1 +#endif + +/* ---------------------------------------------------------------- */ +/* FUNCTIONS */ +/* ---------------------------------------------------------------- */ + +/* Define if you have the closesocket function. */ +#define HAVE_CLOSESOCKET 1 + +/* Define if you have the ftruncate function. */ +#if defined(__MINGW32__) +#define HAVE_FTRUNCATE 1 +#endif + +/* Define to 1 if you have the `getpeername' function. */ +#define HAVE_GETPEERNAME 1 + +/* Define to 1 if you have the getsockname function. */ +#define HAVE_GETSOCKNAME 1 + +/* Define if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define if you have the gettimeofday function. */ +#if defined(__MINGW32__) +#define HAVE_GETTIMEOFDAY 1 +#endif + +/* Define if you have the ioctlsocket function. */ +#define HAVE_IOCTLSOCKET 1 + +/* Define if you have a working ioctlsocket FIONBIO function. */ +#define HAVE_IOCTLSOCKET_FIONBIO 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the setlocale function. */ +#define HAVE_SETLOCALE 1 + +/* Define if you have the setmode function. */ +#define HAVE_SETMODE 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strcasecmp function. */ +#if defined(__MINGW32__) +#define HAVE_STRCASECMP 1 +#endif + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the stricmp function. */ +#define HAVE_STRICMP 1 + +/* Define if you have the strtoll function. */ +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__) +#define HAVE_STRTOLL 1 +#endif + +/* Define if you have the utime function. */ +#define HAVE_UTIME 1 + +/* Define if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 SOCKET + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 char * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 int + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV int + +/* Define if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 SOCKET + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 char * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 int + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV int + +/* Define to 1 if you have the snprintf function. */ +#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || defined(__MINGW32__) +#define HAVE_SNPRINTF 1 +#endif + +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 /* Vista */ +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 +#endif + +/* Define to 1 if you have the `basename' function. */ +#if defined(__MINGW32__) +#define HAVE_BASENAME 1 +#endif + +/* Define to 1 if you have the strtok_r function. */ +#if defined(__MINGW32__) +#define HAVE_STRTOK_R 1 +#endif + +/* Define to 1 if you have the signal function. */ +#define HAVE_SIGNAL 1 + +/* ---------------------------------------------------------------- */ +/* TYPEDEF REPLACEMENTS */ +/* ---------------------------------------------------------------- */ + +/* Define if in_addr_t is not an available 'typedefed' type. */ +#define in_addr_t unsigned long + +/* Define if ssize_t is not an available 'typedefed' type. */ +#ifndef _SSIZE_T_DEFINED +# if defined(__MINGW32__) +# elif defined(_WIN64) +# define _SSIZE_T_DEFINED +# define ssize_t __int64 +# else +# define _SSIZE_T_DEFINED +# define ssize_t int +# endif +#endif + +/* ---------------------------------------------------------------- */ +/* TYPE SIZES */ +/* ---------------------------------------------------------------- */ + +/* Define to the size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* Define to the size of `long long', as computed by sizeof. */ +/* #define SIZEOF_LONG_LONG 8 */ + +/* Define to the size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* Define to the size of `size_t', as computed by sizeof. */ +#if defined(_WIN64) +# define SIZEOF_SIZE_T 8 +#else +# define SIZEOF_SIZE_T 4 +#endif + +/* Define to the size of `curl_off_t', as computed by sizeof. */ +#define SIZEOF_CURL_OFF_T 8 + +/* ---------------------------------------------------------------- */ +/* COMPILER SPECIFIC */ +/* ---------------------------------------------------------------- */ + +/* Define to nothing if compiler does not support 'const' qualifier. */ +/* #define const */ + +/* Define to nothing if compiler does not support 'volatile' qualifier. */ +/* #define volatile */ + +/* Windows should not have HAVE_GMTIME_R defined */ +/* #undef HAVE_GMTIME_R */ + +/* Define if the compiler supports the 'long long' data type. */ +#if (defined(_MSC_VER) && (_MSC_VER >= 1310)) || defined(__MINGW32__) +#define HAVE_LONGLONG 1 +#endif + +/* Define to avoid VS2005 complaining about portable C functions. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif + +/* mingw-w64 and visual studio >= 2005 (MSVCR80) + all default to 64-bit time_t unless _USE_32BIT_TIME_T is defined */ +#if (defined(_MSC_VER) && (_MSC_VER >= 1400)) || defined(__MINGW32__) +# ifndef _USE_32BIT_TIME_T +# define SIZEOF_TIME_T 8 +# else +# define SIZEOF_TIME_T 4 +# endif +#endif + +/* Define some minimum and default build targets for Visual Studio */ +#if defined(_MSC_VER) + /* Officially, Microsoft's Windows SDK versions 6.X does not support Windows + 2000 as a supported build target. VS2008 default installations provides + an embedded Windows SDK v6.0A along with the claim that Windows 2000 is a + valid build target for VS2008. Popular belief is that binaries built with + VS2008 using Windows SDK versions v6.X and Windows 2000 as a build target + are functional. */ +# define VS2008_MIN_TARGET 0x0500 + + /* The minimum build target for VS2012 is Vista unless Update 1 is installed + and the v110_xp toolset is chosen. */ +# if defined(_USING_V110_SDK71_) +# define VS2012_MIN_TARGET 0x0501 +# else +# define VS2012_MIN_TARGET 0x0600 +# endif + + /* VS2008 default build target is Windows Vista. We override default target + to be Windows XP. */ +# define VS2008_DEF_TARGET 0x0501 + + /* VS2012 default build target is Windows Vista unless Update 1 is installed + and the v110_xp toolset is chosen. */ +# if defined(_USING_V110_SDK71_) +# define VS2012_DEF_TARGET 0x0501 +# else +# define VS2012_DEF_TARGET 0x0600 +# endif +#endif + +/* VS2008 default target settings and minimum build target check. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_MSC_VER <= 1600) +# ifndef _WIN32_WINNT +# define _WIN32_WINNT VS2008_DEF_TARGET +# endif +# ifndef WINVER +# define WINVER VS2008_DEF_TARGET +# endif +# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) +# error VS2008 does not support Windows build targets prior to Windows 2000 +# endif +#endif + +/* VS2012 default target settings and minimum build target check. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1700) +# ifndef _WIN32_WINNT +# define _WIN32_WINNT VS2012_DEF_TARGET +# endif +# ifndef WINVER +# define WINVER VS2012_DEF_TARGET +# endif +# if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET) +# if defined(_USING_V110_SDK71_) +# error VS2012 does not support Windows build targets prior to Windows XP +# else +# error VS2012 does not support Windows build targets prior to Windows \ +Vista +# endif +# endif +#endif + +/* Windows XP is required for freeaddrinfo, getaddrinfo */ +#define HAVE_FREEADDRINFO 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* ---------------------------------------------------------------- */ +/* STRUCT RELATED */ +/* ---------------------------------------------------------------- */ + +/* Define if you have struct sockaddr_storage. */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define if you have struct timeval. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define if struct sockaddr_in6 has the sin6_scope_id member. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* ---------------------------------------------------------------- */ +/* LARGE FILE SUPPORT */ +/* ---------------------------------------------------------------- */ + +#if defined(_MSC_VER) && !defined(_WIN32_WCE) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define USE_WIN32_LARGE_FILES +# else +# define USE_WIN32_SMALL_FILES +# endif +#endif + +#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES) +# define USE_WIN32_LARGE_FILES +#endif + +#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES) +# define USE_WIN32_SMALL_FILES +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#if defined(USE_WIN32_LARGE_FILES) && defined(__MINGW32__) +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +#endif + +#ifdef USE_WIN32_LARGE_FILES +#define HAVE__FSEEKI64 +#endif + +/* Define to the size of `off_t', as computed by sizeof. */ +#if defined(__MINGW32__) && \ + defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64) +# define SIZEOF_OFF_T 8 +#else +# define SIZEOF_OFF_T 4 +#endif + +/* ---------------------------------------------------------------- */ +/* DNS RESOLVER SPECIALTY */ +/* ---------------------------------------------------------------- */ + +/* + * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS. + */ + +/* Define to enable c-ares asynchronous DNS lookups. */ +/* #define USE_ARES 1 */ + +/* Default define to enable threaded asynchronous DNS lookups. */ +#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \ + !defined(USE_THREADS_WIN32) +# define USE_THREADS_WIN32 1 +#endif + +#if defined(USE_ARES) && defined(USE_THREADS_WIN32) +# error "Only one DNS lookup specialty may be defined at most" +#endif + +/* ---------------------------------------------------------------- */ +/* LDAP SUPPORT */ +/* ---------------------------------------------------------------- */ + +#if defined(CURL_HAS_NOVELL_LDAPSDK) +#undef USE_WIN32_LDAP +#define HAVE_LDAP_SSL_H 1 +#define HAVE_LDAP_URL_PARSE 1 +#elif defined(CURL_HAS_OPENLDAP_LDAPSDK) +#undef USE_WIN32_LDAP +#define HAVE_LDAP_URL_PARSE 1 +#else +#undef HAVE_LDAP_URL_PARSE +#define HAVE_LDAP_SSL 1 +#define USE_WIN32_LDAP 1 +#endif + +/* Define to use the Windows crypto library. */ +#if !defined(CURL_WINDOWS_APP) +#define USE_WIN32_CRYPTO +#endif + +/* Define to use Unix sockets. */ +#define USE_UNIX_SOCKETS + +/* ---------------------------------------------------------------- */ +/* ADDITIONAL DEFINITIONS */ +/* ---------------------------------------------------------------- */ + +/* Define cpu-machine-OS */ +#ifndef OS +#if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */ +#define OS "i386-pc-win32" +#elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (MSVC >=2005 or gcc) */ +#define OS "x86_64-pc-win32" +#elif defined(_M_IA64) || defined(__ia64__) /* Itanium */ +#define OS "ia64-pc-win32" +#elif defined(_M_ARM_NT) || defined(__arm__) /* ARMv7-Thumb2 (Windows RT) */ +#define OS "thumbv7a-pc-win32" +#elif defined(_M_ARM64) || defined(__aarch64__) /* ARM64 (Windows 10) */ +#define OS "aarch64-pc-win32" +#else +#define OS "unknown-pc-win32" +#endif +#endif + +/* Name of package */ +#define PACKAGE "curl" + +/* If you want to build curl with the built-in manual */ +#define USE_MANUAL 1 + +#if defined(USE_IPV6) +# define ENABLE_IPV6 1 +#endif + +#endif /* HEADER_CURL_CONFIG_WIN32_H */ diff --git a/lib/config-win32ce.h b/lib/config-win32ce.h new file mode 100644 index 0000000..ae3ca29 --- /dev/null +++ b/lib/config-win32ce.h @@ -0,0 +1,303 @@ +#ifndef HEADER_CURL_CONFIG_WIN32CE_H +#define HEADER_CURL_CONFIG_WIN32CE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* ================================================================ */ +/* lib/config-win32ce.h - Hand crafted config file for windows ce */ +/* ================================================================ */ + +/* ---------------------------------------------------------------- */ +/* HEADER FILES */ +/* ---------------------------------------------------------------- */ + +/* Define if you have the header file. */ +/* #define HAVE_ARPA_INET_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define if you need the malloc.h header file even with stdlib.h */ +#define NEED_MALLOC_H 1 + +/* Define if you have the header file. */ +/* #define HAVE_NETDB_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_NETINET_IN_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_SYS_PARAM_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_SYS_SELECT_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_SYS_SOCKET_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_SYS_SOCKIO_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file */ +/* #define HAVE_SYS_TIME_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_SYS_TYPES_H 1 */ + +/* Define if you have the header file */ +#define HAVE_SYS_UTIME_H 1 + +/* Define if you have the header file. */ +/* #define HAVE_TERMIO_H 1 */ + +/* Define if you have the header file. */ +/* #define HAVE_TERMIOS_H 1 */ + +/* Define if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_UNISTD_H 1 +#endif + +/* ---------------------------------------------------------------- */ +/* OTHER HEADER INFO */ +/* ---------------------------------------------------------------- */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* ---------------------------------------------------------------- */ +/* FUNCTIONS */ +/* ---------------------------------------------------------------- */ + +/* Define if you have the closesocket function. */ +#define HAVE_CLOSESOCKET 1 + +/* Define if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define if you have the gettimeofday function. */ +/* #define HAVE_GETTIMEOFDAY 1 */ + +/* Define if you have the ioctlsocket function. */ +#define HAVE_IOCTLSOCKET 1 + +/* Define if you have a working ioctlsocket FIONBIO function. */ +#define HAVE_IOCTLSOCKET_FIONBIO 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strcasecmp function. */ +/* #define HAVE_STRCASECMP 1 */ + +/* Define if you have the strdup function. */ +/* #define HAVE_STRDUP 1 */ + +/* Define if you have the stricmp function. */ +/* #define HAVE_STRICMP 1 */ + +/* Define if you have the strtoll function. */ +#if defined(__MINGW32__) +#define HAVE_STRTOLL 1 +#endif + +/* Define if you have the utime function */ +#define HAVE_UTIME 1 + +/* Define if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 SOCKET + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 char * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 int + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV int + +/* Define if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 SOCKET + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 char * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 int + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV int + +/* ---------------------------------------------------------------- */ +/* TYPEDEF REPLACEMENTS */ +/* ---------------------------------------------------------------- */ + +/* Define this if in_addr_t is not an available 'typedefed' type */ +#define in_addr_t unsigned long + +/* Define ssize_t if it is not an available 'typedefed' type */ +#if defined(_WIN64) +#define ssize_t __int64 +#else +#define ssize_t int +#endif + +/* ---------------------------------------------------------------- */ +/* TYPE SIZES */ +/* ---------------------------------------------------------------- */ + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long long', as computed by sizeof. */ +/* #define SIZEOF_LONG_LONG 8 */ + +/* Define to the size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `size_t', as computed by sizeof. */ +#if defined(_WIN64) +# define SIZEOF_SIZE_T 8 +#else +# define SIZEOF_SIZE_T 4 +#endif + +/* ---------------------------------------------------------------- */ +/* STRUCT RELATED */ +/* ---------------------------------------------------------------- */ + +/* Define this if you have struct sockaddr_storage */ +/* #define HAVE_STRUCT_SOCKADDR_STORAGE 1 */ + +/* Define this if you have struct timeval */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define this if struct sockaddr_in6 has the sin6_scope_id member */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* ---------------------------------------------------------------- */ +/* COMPILER SPECIFIC */ +/* ---------------------------------------------------------------- */ + +/* Undef keyword 'const' if it does not work. */ +/* #undef const */ + +/* Define to avoid VS2005 complaining about portable C functions */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif + +/* VS2005 and later default size for time_t is 64-bit, unless */ +/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +# ifndef _USE_32BIT_TIME_T +# define SIZEOF_TIME_T 8 +# else +# define SIZEOF_TIME_T 4 +# endif +#endif + +/* ---------------------------------------------------------------- */ +/* LARGE FILE SUPPORT */ +/* ---------------------------------------------------------------- */ + +#if defined(_MSC_VER) && !defined(_WIN32_WCE) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define USE_WIN32_LARGE_FILES +# else +# define USE_WIN32_SMALL_FILES +# endif +#endif + +#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES) +# define USE_WIN32_SMALL_FILES +#endif + +/* ---------------------------------------------------------------- */ +/* LDAP SUPPORT */ +/* ---------------------------------------------------------------- */ + +#define USE_WIN32_LDAP 1 +#undef HAVE_LDAP_URL_PARSE + +/* ---------------------------------------------------------------- */ +/* ADDITIONAL DEFINITIONS */ +/* ---------------------------------------------------------------- */ + +/* Define cpu-machine-OS */ +#ifndef OS +#define OS "i386-pc-win32ce" +#endif + +/* Name of package */ +#define PACKAGE "curl" + +/* ---------------------------------------------------------------- */ +/* WinCE */ +/* ---------------------------------------------------------------- */ + +#ifndef UNICODE +# define UNICODE +#endif + +#ifndef _UNICODE +# define _UNICODE +#endif + +#define CURL_DISABLE_FILE 1 +#define CURL_DISABLE_TELNET 1 +#define CURL_DISABLE_LDAP 1 + +#define ENOSPC 1 +#define ENOMEM 2 +#define EAGAIN 3 + +extern int stat(const char *path, struct stat *buffer); + +#endif /* HEADER_CURL_CONFIG_WIN32CE_H */ diff --git a/lib/conncache.c b/lib/conncache.c new file mode 100644 index 0000000..66f18ec --- /dev/null +++ b/lib/conncache.c @@ -0,0 +1,588 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Linus Nielsen Feltzing, + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "urldata.h" +#include "url.h" +#include "progress.h" +#include "multiif.h" +#include "sendf.h" +#include "conncache.h" +#include "share.h" +#include "sigpipe.h" +#include "connect.h" +#include "strcase.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define HASHKEY_SIZE 128 + +static CURLcode bundle_create(struct connectbundle **bundlep) +{ + DEBUGASSERT(*bundlep == NULL); + *bundlep = malloc(sizeof(struct connectbundle)); + if(!*bundlep) + return CURLE_OUT_OF_MEMORY; + + (*bundlep)->num_connections = 0; + (*bundlep)->multiuse = BUNDLE_UNKNOWN; + + Curl_llist_init(&(*bundlep)->conn_list, NULL); + return CURLE_OK; +} + +static void bundle_destroy(struct connectbundle *bundle) +{ + free(bundle); +} + +/* Add a connection to a bundle */ +static void bundle_add_conn(struct connectbundle *bundle, + struct connectdata *conn) +{ + Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn, + &conn->bundle_node); + conn->bundle = bundle; + bundle->num_connections++; +} + +/* Remove a connection from a bundle */ +static int bundle_remove_conn(struct connectbundle *bundle, + struct connectdata *conn) +{ + struct Curl_llist_element *curr; + + curr = bundle->conn_list.head; + while(curr) { + if(curr->ptr == conn) { + Curl_llist_remove(&bundle->conn_list, curr, NULL); + bundle->num_connections--; + conn->bundle = NULL; + return 1; /* we removed a handle */ + } + curr = curr->next; + } + DEBUGASSERT(0); + return 0; +} + +static void free_bundle_hash_entry(void *freethis) +{ + struct connectbundle *b = (struct connectbundle *) freethis; + + bundle_destroy(b); +} + +int Curl_conncache_init(struct conncache *connc, int size) +{ + /* allocate a new easy handle to use when closing cached connections */ + connc->closure_handle = curl_easy_init(); + if(!connc->closure_handle) + return 1; /* bad */ + connc->closure_handle->state.internal = true; + + Curl_hash_init(&connc->hash, size, Curl_hash_str, + Curl_str_key_compare, free_bundle_hash_entry); + connc->closure_handle->state.conn_cache = connc; + + return 0; /* good */ +} + +void Curl_conncache_destroy(struct conncache *connc) +{ + if(connc) + Curl_hash_destroy(&connc->hash); +} + +/* creates a key to find a bundle for this connection */ +static void hashkey(struct connectdata *conn, char *buf, size_t len) +{ + const char *hostname; + long port = conn->remote_port; + DEBUGASSERT(len >= HASHKEY_SIZE); +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + hostname = conn->http_proxy.host.name; + port = conn->port; + } + else +#endif + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + + /* put the numbers first so that the hostname gets cut off if too long */ +#ifdef ENABLE_IPV6 + msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname); +#else + msnprintf(buf, len, "%ld/%s", port, hostname); +#endif + Curl_strntolower(buf, buf, len); +} + +/* Returns number of connections currently held in the connection cache. + Locks/unlocks the cache itself! +*/ +size_t Curl_conncache_size(struct Curl_easy *data) +{ + size_t num; + CONNCACHE_LOCK(data); + num = data->state.conn_cache->num_conn; + CONNCACHE_UNLOCK(data); + return num; +} + +/* Look up the bundle with all the connections to the same host this + connectdata struct is setup to use. + + **NOTE**: When it returns, it holds the connection cache lock! */ +struct connectbundle * +Curl_conncache_find_bundle(struct Curl_easy *data, + struct connectdata *conn, + struct conncache *connc) +{ + struct connectbundle *bundle = NULL; + CONNCACHE_LOCK(data); + if(connc) { + char key[HASHKEY_SIZE]; + hashkey(conn, key, sizeof(key)); + bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); + } + + return bundle; +} + +static void *conncache_add_bundle(struct conncache *connc, + char *key, + struct connectbundle *bundle) +{ + return Curl_hash_add(&connc->hash, key, strlen(key), bundle); +} + +static void conncache_remove_bundle(struct conncache *connc, + struct connectbundle *bundle) +{ + struct Curl_hash_iterator iter; + struct Curl_hash_element *he; + + if(!connc) + return; + + Curl_hash_start_iterate(&connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + if(he->ptr == bundle) { + /* The bundle is destroyed by the hash destructor function, + free_bundle_hash_entry() */ + Curl_hash_delete(&connc->hash, he->key, he->key_len); + return; + } + + he = Curl_hash_next_element(&iter); + } +} + +CURLcode Curl_conncache_add_conn(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectbundle *bundle = NULL; + struct connectdata *conn = data->conn; + struct conncache *connc = data->state.conn_cache; + DEBUGASSERT(conn); + + /* *find_bundle() locks the connection cache */ + bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache); + if(!bundle) { + char key[HASHKEY_SIZE]; + + result = bundle_create(&bundle); + if(result) { + goto unlock; + } + + hashkey(conn, key, sizeof(key)); + + if(!conncache_add_bundle(data->state.conn_cache, key, bundle)) { + bundle_destroy(bundle); + result = CURLE_OUT_OF_MEMORY; + goto unlock; + } + } + + bundle_add_conn(bundle, conn); + conn->connection_id = connc->next_connection_id++; + connc->num_conn++; + + DEBUGF(infof(data, "Added connection %" CURL_FORMAT_CURL_OFF_T ". " + "The cache now contains %zu members", + conn->connection_id, connc->num_conn)); + +unlock: + CONNCACHE_UNLOCK(data); + + return result; +} + +/* + * Removes the connectdata object from the connection cache, but the transfer + * still owns this connection. + * + * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function + * already holds the lock or not. + */ +void Curl_conncache_remove_conn(struct Curl_easy *data, + struct connectdata *conn, bool lock) +{ + struct connectbundle *bundle = conn->bundle; + struct conncache *connc = data->state.conn_cache; + + /* The bundle pointer can be NULL, since this function can be called + due to a failed connection attempt, before being added to a bundle */ + if(bundle) { + if(lock) { + CONNCACHE_LOCK(data); + } + bundle_remove_conn(bundle, conn); + if(bundle->num_connections == 0) + conncache_remove_bundle(connc, bundle); + conn->bundle = NULL; /* removed from it */ + if(connc) { + connc->num_conn--; + DEBUGF(infof(data, "The cache now contains %zu members", + connc->num_conn)); + } + if(lock) { + CONNCACHE_UNLOCK(data); + } + } +} + +/* This function iterates the entire connection cache and calls the function + func() with the connection pointer as the first argument and the supplied + 'param' argument as the other. + + The conncache lock is still held when the callback is called. It needs it, + so that it can safely continue traversing the lists once the callback + returns. + + Returns 1 if the loop was aborted due to the callback's return code. + + Return 0 from func() to continue the loop, return 1 to abort it. + */ +bool Curl_conncache_foreach(struct Curl_easy *data, + struct conncache *connc, + void *param, + int (*func)(struct Curl_easy *data, + struct connectdata *conn, void *param)) +{ + struct Curl_hash_iterator iter; + struct Curl_llist_element *curr; + struct Curl_hash_element *he; + + if(!connc) + return FALSE; + + CONNCACHE_LOCK(data); + Curl_hash_start_iterate(&connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct connectbundle *bundle; + + bundle = he->ptr; + he = Curl_hash_next_element(&iter); + + curr = bundle->conn_list.head; + while(curr) { + /* Yes, we need to update curr before calling func(), because func() + might decide to remove the connection */ + struct connectdata *conn = curr->ptr; + curr = curr->next; + + if(1 == func(data, conn, param)) { + CONNCACHE_UNLOCK(data); + return TRUE; + } + } + } + CONNCACHE_UNLOCK(data); + return FALSE; +} + +/* Return the first connection found in the cache. Used when closing all + connections. + + NOTE: no locking is done here as this is presumably only done when cleaning + up a cache! +*/ +static struct connectdata * +conncache_find_first_connection(struct conncache *connc) +{ + struct Curl_hash_iterator iter; + struct Curl_hash_element *he; + struct connectbundle *bundle; + + Curl_hash_start_iterate(&connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct Curl_llist_element *curr; + bundle = he->ptr; + + curr = bundle->conn_list.head; + if(curr) { + return curr->ptr; + } + + he = Curl_hash_next_element(&iter); + } + + return NULL; +} + +/* + * Give ownership of a connection back to the connection cache. Might + * disconnect the oldest existing in there to make space. + * + * Return TRUE if stored, FALSE if closed. + */ +bool Curl_conncache_return_conn(struct Curl_easy *data, + struct connectdata *conn) +{ + unsigned int maxconnects = !data->multi->maxconnects ? + data->multi->num_easy * 4: data->multi->maxconnects; + struct connectdata *conn_candidate = NULL; + + conn->lastused = Curl_now(); /* it was used up until now */ + if(maxconnects && Curl_conncache_size(data) > maxconnects) { + infof(data, "Connection cache is full, closing the oldest one"); + + conn_candidate = Curl_conncache_extract_oldest(data); + if(conn_candidate) { + /* Use the closure handle for this disconnect so that anything that + happens during the disconnect is not stored and associated with the + 'data' handle which already just finished a transfer and it is + important that details from this (unrelated) disconnect does not + taint meta-data in the data handle. */ + struct conncache *connc = data->state.conn_cache; + connc->closure_handle->state.buffer = data->state.buffer; + connc->closure_handle->set.buffer_size = data->set.buffer_size; + Curl_disconnect(connc->closure_handle, conn_candidate, + /* dead_connection */ FALSE); + } + } + + return (conn_candidate == conn) ? FALSE : TRUE; + +} + +/* + * This function finds the connection in the connection bundle that has been + * unused for the longest time. + * + * Does not lock the connection cache! + * + * Returns the pointer to the oldest idle connection, or NULL if none was + * found. + */ +struct connectdata * +Curl_conncache_extract_bundle(struct Curl_easy *data, + struct connectbundle *bundle) +{ + struct Curl_llist_element *curr; + timediff_t highscore = -1; + timediff_t score; + struct curltime now; + struct connectdata *conn_candidate = NULL; + struct connectdata *conn; + + (void)data; + + now = Curl_now(); + + curr = bundle->conn_list.head; + while(curr) { + conn = curr->ptr; + + if(!CONN_INUSE(conn)) { + /* Set higher score for the age passed since the connection was used */ + score = Curl_timediff(now, conn->lastused); + + if(score > highscore) { + highscore = score; + conn_candidate = conn; + } + } + curr = curr->next; + } + if(conn_candidate) { + /* remove it to prevent another thread from nicking it */ + bundle_remove_conn(bundle, conn_candidate); + data->state.conn_cache->num_conn--; + DEBUGF(infof(data, "The cache now contains %zu members", + data->state.conn_cache->num_conn)); + } + + return conn_candidate; +} + +/* + * This function finds the connection in the connection cache that has been + * unused for the longest time and extracts that from the bundle. + * + * Returns the pointer to the connection, or NULL if none was found. + */ +struct connectdata * +Curl_conncache_extract_oldest(struct Curl_easy *data) +{ + struct conncache *connc = data->state.conn_cache; + struct Curl_hash_iterator iter; + struct Curl_llist_element *curr; + struct Curl_hash_element *he; + timediff_t highscore =- 1; + timediff_t score; + struct curltime now; + struct connectdata *conn_candidate = NULL; + struct connectbundle *bundle; + struct connectbundle *bundle_candidate = NULL; + + now = Curl_now(); + + CONNCACHE_LOCK(data); + Curl_hash_start_iterate(&connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct connectdata *conn; + + bundle = he->ptr; + + curr = bundle->conn_list.head; + while(curr) { + conn = curr->ptr; + + if(!CONN_INUSE(conn) && !conn->bits.close && + !conn->connect_only) { + /* Set higher score for the age passed since the connection was used */ + score = Curl_timediff(now, conn->lastused); + + if(score > highscore) { + highscore = score; + conn_candidate = conn; + bundle_candidate = bundle; + } + } + curr = curr->next; + } + + he = Curl_hash_next_element(&iter); + } + if(conn_candidate) { + /* remove it to prevent another thread from nicking it */ + bundle_remove_conn(bundle_candidate, conn_candidate); + connc->num_conn--; + DEBUGF(infof(data, "The cache now contains %zu members", + connc->num_conn)); + } + CONNCACHE_UNLOCK(data); + + return conn_candidate; +} + +void Curl_conncache_close_all_connections(struct conncache *connc) +{ + struct connectdata *conn; + char buffer[READBUFFER_MIN + 1]; + SIGPIPE_VARIABLE(pipe_st); + if(!connc->closure_handle) + return; + connc->closure_handle->state.buffer = buffer; + connc->closure_handle->set.buffer_size = READBUFFER_MIN; + + conn = conncache_find_first_connection(connc); + while(conn) { + sigpipe_ignore(connc->closure_handle, &pipe_st); + /* This will remove the connection from the cache */ + connclose(conn, "kill all"); + Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE); + Curl_disconnect(connc->closure_handle, conn, FALSE); + sigpipe_restore(&pipe_st); + + conn = conncache_find_first_connection(connc); + } + + connc->closure_handle->state.buffer = NULL; + sigpipe_ignore(connc->closure_handle, &pipe_st); + + Curl_hostcache_clean(connc->closure_handle, + connc->closure_handle->dns.hostcache); + Curl_close(&connc->closure_handle); + sigpipe_restore(&pipe_st); +} + +#if 0 +/* Useful for debugging the connection cache */ +void Curl_conncache_print(struct conncache *connc) +{ + struct Curl_hash_iterator iter; + struct Curl_llist_element *curr; + struct Curl_hash_element *he; + + if(!connc) + return; + + fprintf(stderr, "=Bundle cache=\n"); + + Curl_hash_start_iterate(connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct connectbundle *bundle; + struct connectdata *conn; + + bundle = he->ptr; + + fprintf(stderr, "%s -", he->key); + curr = bundle->conn_list->head; + while(curr) { + conn = curr->ptr; + + fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); + curr = curr->next; + } + fprintf(stderr, "\n"); + + he = Curl_hash_next_element(&iter); + } +} +#endif diff --git a/lib/conncache.h b/lib/conncache.h new file mode 100644 index 0000000..c60f844 --- /dev/null +++ b/lib/conncache.h @@ -0,0 +1,122 @@ +#ifndef HEADER_CURL_CONNCACHE_H +#define HEADER_CURL_CONNCACHE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Linus Nielsen Feltzing, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * All accesses to struct fields and changing of data in the connection cache + * and connectbundles must be done with the conncache LOCKED. The cache might + * be shared. + */ + +#include +#include "timeval.h" + +struct connectdata; + +struct conncache { + struct Curl_hash hash; + size_t num_conn; + curl_off_t next_connection_id; + curl_off_t next_easy_id; + struct curltime last_cleanup; + /* handle used for closing cached connections */ + struct Curl_easy *closure_handle; +}; + +#define BUNDLE_NO_MULTIUSE -1 +#define BUNDLE_UNKNOWN 0 /* initial value */ +#define BUNDLE_MULTIPLEX 2 + +#ifdef CURLDEBUG +/* the debug versions of these macros make extra certain that the lock is + never doubly locked or unlocked */ +#define CONNCACHE_LOCK(x) \ + do { \ + if((x)->share) { \ + Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, \ + CURL_LOCK_ACCESS_SINGLE); \ + DEBUGASSERT(!(x)->state.conncache_lock); \ + (x)->state.conncache_lock = TRUE; \ + } \ + } while(0) + +#define CONNCACHE_UNLOCK(x) \ + do { \ + if((x)->share) { \ + DEBUGASSERT((x)->state.conncache_lock); \ + (x)->state.conncache_lock = FALSE; \ + Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \ + } \ + } while(0) +#else +#define CONNCACHE_LOCK(x) if((x)->share) \ + Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE) +#define CONNCACHE_UNLOCK(x) if((x)->share) \ + Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT) +#endif + +struct connectbundle { + int multiuse; /* supports multi-use */ + size_t num_connections; /* Number of connections in the bundle */ + struct Curl_llist conn_list; /* The connectdata members of the bundle */ +}; + +/* returns 1 on error, 0 is fine */ +int Curl_conncache_init(struct conncache *, int size); +void Curl_conncache_destroy(struct conncache *connc); + +/* return the correct bundle, to a host or a proxy */ +struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data, + struct connectdata *conn, + struct conncache *connc); +/* returns number of connections currently held in the connection cache */ +size_t Curl_conncache_size(struct Curl_easy *data); + +bool Curl_conncache_return_conn(struct Curl_easy *data, + struct connectdata *conn); +CURLcode Curl_conncache_add_conn(struct Curl_easy *data) WARN_UNUSED_RESULT; +void Curl_conncache_remove_conn(struct Curl_easy *data, + struct connectdata *conn, + bool lock); +bool Curl_conncache_foreach(struct Curl_easy *data, + struct conncache *connc, + void *param, + int (*func)(struct Curl_easy *data, + struct connectdata *conn, + void *param)); + +struct connectdata * +Curl_conncache_find_first_connection(struct conncache *connc); + +struct connectdata * +Curl_conncache_extract_bundle(struct Curl_easy *data, + struct connectbundle *bundle); +struct connectdata * +Curl_conncache_extract_oldest(struct Curl_easy *data); +void Curl_conncache_close_all_connections(struct conncache *connc); +void Curl_conncache_print(struct conncache *connc); + +#endif /* HEADER_CURL_CONNCACHE_H */ diff --git a/lib/connect.c b/lib/connect.c new file mode 100644 index 0000000..45743e9 --- /dev/null +++ b/lib/connect.c @@ -0,0 +1,1439 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include /* may need it */ +#endif +#ifdef HAVE_SYS_UN_H +#include /* for sockaddr_un */ +#endif +#ifdef HAVE_LINUX_TCP_H +#include +#elif defined(HAVE_NETINET_TCP_H) +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "if2ip.h" +#include "strerror.h" +#include "cfilters.h" +#include "connect.h" +#include "cf-haproxy.h" +#include "cf-https-connect.h" +#include "cf-socket.h" +#include "select.h" +#include "url.h" /* for Curl_safefree() */ +#include "multiif.h" +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "inet_ntop.h" +#include "inet_pton.h" +#include "vtls/vtls.h" /* for vtsl cfilters */ +#include "progress.h" +#include "warnless.h" +#include "conncache.h" +#include "multihandle.h" +#include "share.h" +#include "version_win32.h" +#include "vquic/vquic.h" /* for quic cfilters */ +#include "http_proxy.h" +#include "socks.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +/* + * Curl_timeleft() returns the amount of milliseconds left allowed for the + * transfer/connection. If the value is 0, there's no timeout (ie there's + * infinite time left). If the value is negative, the timeout time has already + * elapsed. + * @param data the transfer to check on + * @param nowp timestamp to use for calculdation, NULL to use Curl_now() + * @param duringconnect TRUE iff connect timeout is also taken into account. + * @unittest: 1303 + */ +timediff_t Curl_timeleft(struct Curl_easy *data, + struct curltime *nowp, + bool duringconnect) +{ + timediff_t timeleft_ms = 0; + timediff_t ctimeleft_ms = 0; + struct curltime now; + + /* The duration of a connect and the total transfer are calculated from two + different time-stamps. It can end up with the total timeout being reached + before the connect timeout expires and we must acknowledge whichever + timeout that is reached first. The total timeout is set per entire + operation, while the connect timeout is set per connect. */ + if(data->set.timeout <= 0 && !duringconnect) + return 0; /* no timeout in place or checked, return "no limit" */ + + if(!nowp) { + now = Curl_now(); + nowp = &now; + } + + if(data->set.timeout > 0) { + timeleft_ms = data->set.timeout - + Curl_timediff(*nowp, data->progress.t_startop); + if(!timeleft_ms) + timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */ + if(!duringconnect) + return timeleft_ms; /* no connect check, this is it */ + } + + if(duringconnect) { + timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ? + data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT; + ctimeleft_ms = ctimeout_ms - + Curl_timediff(*nowp, data->progress.t_startsingle); + if(!ctimeleft_ms) + ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */ + if(!timeleft_ms) + return ctimeleft_ms; /* no general timeout, this is it */ + } + /* return minimal time left or max amount already expired */ + return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms; +} + +/* Copies connection info into the transfer handle to make it available when + the transfer handle is no longer associated with the connection. */ +void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn, + char *local_ip, int local_port) +{ + memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN); + if(local_ip && local_ip[0]) + memcpy(data->info.conn_local_ip, local_ip, MAX_IPADR_LEN); + else + data->info.conn_local_ip[0] = 0; + data->info.conn_scheme = conn->handler->scheme; + /* conn_protocol can only provide "old" protocols */ + data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK; + data->info.conn_primary_port = conn->port; + data->info.conn_remote_port = conn->remote_port; + data->info.conn_local_port = local_port; +} + +static const struct Curl_addrinfo * +addr_first_match(const struct Curl_addrinfo *addr, int family) +{ + while(addr) { + if(addr->ai_family == family) + return addr; + addr = addr->ai_next; + } + return NULL; +} + +static const struct Curl_addrinfo * +addr_next_match(const struct Curl_addrinfo *addr, int family) +{ + while(addr && addr->ai_next) { + addr = addr->ai_next; + if(addr->ai_family == family) + return addr; + } + return NULL; +} + +/* retrieves ip address and port from a sockaddr structure. + note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */ +bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, + char *addr, int *port) +{ + struct sockaddr_in *si = NULL; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *si6 = NULL; +#endif +#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX) + struct sockaddr_un *su = NULL; +#else + (void)salen; +#endif + + switch(sa->sa_family) { + case AF_INET: + si = (struct sockaddr_in *)(void *) sa; + if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, + addr, MAX_IPADR_LEN)) { + unsigned short us_port = ntohs(si->sin_port); + *port = us_port; + return TRUE; + } + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + si6 = (struct sockaddr_in6 *)(void *) sa; + if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, + addr, MAX_IPADR_LEN)) { + unsigned short us_port = ntohs(si6->sin6_port); + *port = us_port; + return TRUE; + } + break; +#endif +#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX) + case AF_UNIX: + if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) { + su = (struct sockaddr_un*)sa; + msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); + } + else + addr[0] = 0; /* socket with no name */ + *port = 0; + return TRUE; +#endif + default: + break; + } + + addr[0] = '\0'; + *port = 0; + errno = EAFNOSUPPORT; + return FALSE; +} + +struct connfind { + curl_off_t id_tofind; + struct connectdata *found; +}; + +static int conn_is_conn(struct Curl_easy *data, + struct connectdata *conn, void *param) +{ + struct connfind *f = (struct connfind *)param; + (void)data; + if(conn->connection_id == f->id_tofind) { + f->found = conn; + return 1; + } + return 0; +} + +/* + * Used to extract socket and connectdata struct for the most recent + * transfer on the given Curl_easy. + * + * The returned socket will be CURL_SOCKET_BAD in case of failure! + */ +curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, + struct connectdata **connp) +{ + DEBUGASSERT(data); + + /* this works for an easy handle: + * - that has been used for curl_easy_perform() + * - that is associated with a multi handle, and whose connection + * was detached with CURLOPT_CONNECT_ONLY + */ + if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) { + struct connectdata *c; + struct connfind find; + find.id_tofind = data->state.lastconnect_id; + find.found = NULL; + + Curl_conncache_foreach(data, + data->share && (data->share->specifier + & (1<< CURL_LOCK_DATA_CONNECT))? + &data->share->conn_cache: + data->multi_easy? + &data->multi_easy->conn_cache: + &data->multi->conn_cache, &find, conn_is_conn); + + if(!find.found) { + data->state.lastconnect_id = -1; + return CURL_SOCKET_BAD; + } + + c = find.found; + if(connp) + /* only store this if the caller cares for it */ + *connp = c; + return c->sock[FIRSTSOCKET]; + } + return CURL_SOCKET_BAD; +} + +/* + * Curl_conncontrol() marks streams or connection for closure. + */ +void Curl_conncontrol(struct connectdata *conn, + int ctrl /* see defines in header */ +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + , const char *reason +#endif + ) +{ + /* close if a connection, or a stream that isn't multiplexed. */ + /* This function will be called both before and after this connection is + associated with a transfer. */ + bool closeit, is_multiplex; + DEBUGASSERT(conn); +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + (void)reason; /* useful for debugging */ +#endif + is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET); + closeit = (ctrl == CONNCTRL_CONNECTION) || + ((ctrl == CONNCTRL_STREAM) && !is_multiplex); + if((ctrl == CONNCTRL_STREAM) && is_multiplex) + ; /* stream signal on multiplex conn never affects close state */ + else if((bit)closeit != conn->bits.close) { + conn->bits.close = closeit; /* the only place in the source code that + should assign this bit */ + } +} + +/** + * job walking the matching addr infos, creating a sub-cfilter with the + * provided method `cf_create` and running setup/connect on it. + */ +struct eyeballer { + const char *name; + const struct Curl_addrinfo *first; /* complete address list, not owned */ + const struct Curl_addrinfo *addr; /* List of addresses to try, not owned */ + int ai_family; /* matching address family only */ + cf_ip_connect_create *cf_create; /* for creating cf */ + struct Curl_cfilter *cf; /* current sub-cfilter connecting */ + struct eyeballer *primary; /* eyeballer this one is backup for */ + timediff_t delay_ms; /* delay until start */ + struct curltime started; /* start of current attempt */ + timediff_t timeoutms; /* timeout for current attempt */ + expire_id timeout_id; /* ID for Curl_expire() */ + CURLcode result; + int error; + BIT(rewinded); /* if we rewinded the addr list */ + BIT(has_started); /* attempts have started */ + BIT(is_done); /* out of addresses/time */ + BIT(connected); /* cf has connected */ + BIT(inconclusive); /* connect was not a hard failure, we + * might talk to a restarting server */ +}; + + +typedef enum { + SCFST_INIT, + SCFST_WAITING, + SCFST_DONE +} cf_connect_state; + +struct cf_he_ctx { + int transport; + cf_ip_connect_create *cf_create; + const struct Curl_dns_entry *remotehost; + cf_connect_state state; + struct eyeballer *baller[2]; + struct eyeballer *winner; + struct curltime started; +}; + +/* when there are more than one IP address left to use, this macro returns how + much of the given timeout to spend on *this* attempt */ +#define TIMEOUT_LARGE 600 +#define USETIME(ms) ((ms > TIMEOUT_LARGE) ? (ms / 2) : ms) + +static CURLcode eyeballer_new(struct eyeballer **pballer, + cf_ip_connect_create *cf_create, + const struct Curl_addrinfo *addr, + int ai_family, + struct eyeballer *primary, + timediff_t delay_ms, + timediff_t timeout_ms, + expire_id timeout_id) +{ + struct eyeballer *baller; + + *pballer = NULL; + baller = calloc(1, sizeof(*baller)); + if(!baller) + return CURLE_OUT_OF_MEMORY; + + baller->name = ((ai_family == AF_INET)? "ipv4" : ( +#ifdef ENABLE_IPV6 + (ai_family == AF_INET6)? "ipv6" : +#endif + "ip")); + baller->cf_create = cf_create; + baller->first = baller->addr = addr; + baller->ai_family = ai_family; + baller->primary = primary; + baller->delay_ms = delay_ms; + baller->timeoutms = addr_next_match(baller->addr, baller->ai_family)? + USETIME(timeout_ms) : timeout_ms; + baller->timeout_id = timeout_id; + baller->result = CURLE_COULDNT_CONNECT; + + *pballer = baller; + return CURLE_OK; +} + +static void baller_close(struct eyeballer *baller, + struct Curl_easy *data) +{ + if(baller && baller->cf) { + Curl_conn_cf_discard_chain(&baller->cf, data); + } +} + +static void baller_free(struct eyeballer *baller, + struct Curl_easy *data) +{ + if(baller) { + baller_close(baller, data); + free(baller); + } +} + +static void baller_rewind(struct eyeballer *baller) +{ + baller->rewinded = TRUE; + baller->addr = baller->first; + baller->inconclusive = FALSE; +} + +static void baller_next_addr(struct eyeballer *baller) +{ + baller->addr = addr_next_match(baller->addr, baller->ai_family); +} + +/* + * Initiate a connect attempt walk. + * + * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to + * CURL_SOCKET_BAD. Other errors will however return proper errors. + */ +static void baller_initiate(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct eyeballer *baller) +{ + struct cf_he_ctx *ctx = cf->ctx; + struct Curl_cfilter *cf_prev = baller->cf; + struct Curl_cfilter *wcf; + CURLcode result; + + + /* Don't close a previous cfilter yet to ensure that the next IP's + socket gets a different file descriptor, which can prevent bugs when + the curl_multi_socket_action interface is used with certain select() + replacements such as kqueue. */ + result = baller->cf_create(&baller->cf, data, cf->conn, baller->addr, + ctx->transport); + if(result) + goto out; + + /* the new filter might have sub-filters */ + for(wcf = baller->cf; wcf; wcf = wcf->next) { + wcf->conn = cf->conn; + wcf->sockindex = cf->sockindex; + } + + if(addr_next_match(baller->addr, baller->ai_family)) { + Curl_expire(data, baller->timeoutms, baller->timeout_id); + } + +out: + if(result) { + CURL_TRC_CF(data, cf, "%s failed", baller->name); + baller_close(baller, data); + } + if(cf_prev) + Curl_conn_cf_discard_chain(&cf_prev, data); + baller->result = result; +} + +/** + * Start a connection attempt on the current baller address. + * Will return CURLE_OK on the first address where a socket + * could be created and the non-blocking connect started. + * Returns error when all remaining addresses have been tried. + */ +static CURLcode baller_start(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct eyeballer *baller, + timediff_t timeoutms) +{ + baller->error = 0; + baller->connected = FALSE; + baller->has_started = TRUE; + + while(baller->addr) { + baller->started = Curl_now(); + baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ? + USETIME(timeoutms) : timeoutms; + baller_initiate(cf, data, baller); + if(!baller->result) + break; + baller_next_addr(baller); + } + if(!baller->addr) { + baller->is_done = TRUE; + } + return baller->result; +} + + +/* Used within the multi interface. Try next IP address, returns error if no + more address exists or error */ +static CURLcode baller_start_next(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct eyeballer *baller, + timediff_t timeoutms) +{ + if(cf->sockindex == FIRSTSOCKET) { + baller_next_addr(baller); + /* If we get inconclusive answers from the server(s), we make + * a second iteration over the address list */ + if(!baller->addr && baller->inconclusive && !baller->rewinded) + baller_rewind(baller); + baller_start(cf, data, baller, timeoutms); + } + else { + baller->error = 0; + baller->connected = FALSE; + baller->has_started = TRUE; + baller->is_done = TRUE; + baller->result = CURLE_COULDNT_CONNECT; + } + return baller->result; +} + +static CURLcode baller_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct eyeballer *baller, + struct curltime *now, + bool *connected) +{ + (void)cf; + *connected = baller->connected; + if(!baller->result && !*connected) { + /* evaluate again */ + baller->result = Curl_conn_cf_connect(baller->cf, data, 0, connected); + + if(!baller->result) { + if(*connected) { + baller->connected = TRUE; + baller->is_done = TRUE; + } + else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) { + infof(data, "%s connect timeout after %" CURL_FORMAT_TIMEDIFF_T + "ms, move on!", baller->name, baller->timeoutms); +#if defined(ETIMEDOUT) + baller->error = ETIMEDOUT; +#endif + baller->result = CURLE_OPERATION_TIMEDOUT; + } + } + else if(baller->result == CURLE_WEIRD_SERVER_REPLY) + baller->inconclusive = TRUE; + } + return baller->result; +} + +/* + * is_connected() checks if the socket has connected. + */ +static CURLcode is_connected(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *connected) +{ + struct cf_he_ctx *ctx = cf->ctx; + struct connectdata *conn = cf->conn; + CURLcode result; + struct curltime now; + size_t i; + int ongoing, not_started; + const char *hostname; + + /* Check if any of the conn->tempsock we use for establishing connections + * succeeded and, if so, close any ongoing other ones. + * Transfer the successful conn->tempsock to conn->sock[sockindex] + * and set conn->tempsock to CURL_SOCKET_BAD. + * If transport is QUIC, we need to shutdown the ongoing 'other' + * cot ballers in a QUIC appropriate way. */ +evaluate: + *connected = FALSE; /* a very negative world view is best */ + now = Curl_now(); + ongoing = not_started = 0; + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + struct eyeballer *baller = ctx->baller[i]; + + if(!baller || baller->is_done) + continue; + + if(!baller->has_started) { + ++not_started; + continue; + } + baller->result = baller_connect(cf, data, baller, &now, connected); + CURL_TRC_CF(data, cf, "%s connect -> %d, connected=%d", + baller->name, baller->result, *connected); + + if(!baller->result) { + if(*connected) { + /* connected, declare the winner */ + ctx->winner = baller; + ctx->baller[i] = NULL; + break; + } + else { /* still waiting */ + ++ongoing; + } + } + else if(!baller->is_done) { + /* The baller failed to connect, start its next attempt */ + if(baller->error) { + data->state.os_errno = baller->error; + SET_SOCKERRNO(baller->error); + } + baller_start_next(cf, data, baller, Curl_timeleft(data, &now, TRUE)); + if(baller->is_done) { + CURL_TRC_CF(data, cf, "%s done", baller->name); + } + else { + /* next attempt was started */ + CURL_TRC_CF(data, cf, "%s trying next", baller->name); + ++ongoing; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + } + } + + if(ctx->winner) { + *connected = TRUE; + return CURLE_OK; + } + + /* Nothing connected, check the time before we might + * start new ballers or return ok. */ + if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) { + failf(data, "Connection timeout after %" CURL_FORMAT_CURL_OFF_T " ms", + Curl_timediff(now, data->progress.t_startsingle)); + return CURLE_OPERATION_TIMEDOUT; + } + + /* Check if we have any waiting ballers to start now. */ + if(not_started > 0) { + int added = 0; + + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + struct eyeballer *baller = ctx->baller[i]; + + if(!baller || baller->has_started) + continue; + /* We start its primary baller has failed to connect or if + * its start delay_ms have expired */ + if((baller->primary && baller->primary->is_done) || + Curl_timediff(now, ctx->started) >= baller->delay_ms) { + baller_start(cf, data, baller, Curl_timeleft(data, &now, TRUE)); + if(baller->is_done) { + CURL_TRC_CF(data, cf, "%s done", baller->name); + } + else { + CURL_TRC_CF(data, cf, "%s starting (timeout=%" + CURL_FORMAT_TIMEDIFF_T "ms)", + baller->name, baller->timeoutms); + ++ongoing; + ++added; + } + } + } + if(added > 0) + goto evaluate; + } + + if(ongoing > 0) { + /* We are still trying, return for more waiting */ + *connected = FALSE; + return CURLE_OK; + } + + /* all ballers have failed to connect. */ + CURL_TRC_CF(data, cf, "all eyeballers failed"); + result = CURLE_COULDNT_CONNECT; + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + struct eyeballer *baller = ctx->baller[i]; + if(!baller) + continue; + CURL_TRC_CF(data, cf, "%s assess started=%d, result=%d", + baller->name, baller->has_started, baller->result); + if(baller->has_started && baller->result) { + result = baller->result; + break; + } + } + +#ifndef CURL_DISABLE_PROXY + if(conn->bits.socksproxy) + hostname = conn->socks_proxy.host.name; + else if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; + else +#endif + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + + failf(data, "Failed to connect to %s port %u after " + "%" CURL_FORMAT_TIMEDIFF_T " ms: %s", + hostname, conn->port, + Curl_timediff(now, data->progress.t_startsingle), + curl_easy_strerror(result)); + +#ifdef WSAETIMEDOUT + if(WSAETIMEDOUT == data->state.os_errno) + result = CURLE_OPERATION_TIMEDOUT; +#elif defined(ETIMEDOUT) + if(ETIMEDOUT == data->state.os_errno) + result = CURLE_OPERATION_TIMEDOUT; +#endif + + return result; +} + +/* + * Connect to the given host with timeout, proxy or remote doesn't matter. + * There might be more than one IP address to try out. + */ +static CURLcode start_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + const struct Curl_dns_entry *remotehost) +{ + struct cf_he_ctx *ctx = cf->ctx; + struct connectdata *conn = cf->conn; + CURLcode result = CURLE_COULDNT_CONNECT; + int ai_family0, ai_family1; + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + const struct Curl_addrinfo *addr0, *addr1; + + if(timeout_ms < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "Connection time-out"); + return CURLE_OPERATION_TIMEDOUT; + } + + ctx->started = Curl_now(); + + /* remotehost->addr is the list of addresses from the resolver, each + * with an address family. The list has at least one entry, possibly + * many more. + * We try at most 2 at a time, until we either get a connection or + * run out of addresses to try. Since likelihood of success is tied + * to the address family (e.g. IPV6 might not work at all ), we want + * the 2 connect attempt ballers to try different families, if possible. + * + */ + if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) { + /* any IP version is allowed */ + ai_family0 = remotehost->addr? + remotehost->addr->ai_family : 0; +#ifdef ENABLE_IPV6 + ai_family1 = ai_family0 == AF_INET6 ? + AF_INET : AF_INET6; +#else + ai_family1 = AF_UNSPEC; +#endif + } + else { + /* only one IP version is allowed */ + ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ? + AF_INET : +#ifdef ENABLE_IPV6 + AF_INET6; +#else + AF_UNSPEC; +#endif + ai_family1 = AF_UNSPEC; + } + + /* Get the first address in the list that matches the family, + * this might give NULL, if we do not have any matches. */ + addr0 = addr_first_match(remotehost->addr, ai_family0); + addr1 = addr_first_match(remotehost->addr, ai_family1); + if(!addr0 && addr1) { + /* switch around, so a single baller always uses addr0 */ + addr0 = addr1; + ai_family0 = ai_family1; + addr1 = NULL; + } + + /* We found no address that matches our criteria, we cannot connect */ + if(!addr0) { + return CURLE_COULDNT_CONNECT; + } + + memset(ctx->baller, 0, sizeof(ctx->baller)); + result = eyeballer_new(&ctx->baller[0], ctx->cf_create, addr0, ai_family0, + NULL, 0, /* no primary/delay, start now */ + timeout_ms, EXPIRE_DNS_PER_NAME); + if(result) + return result; + CURL_TRC_CF(data, cf, "created %s (timeout %" + CURL_FORMAT_TIMEDIFF_T "ms)", + ctx->baller[0]->name, ctx->baller[0]->timeoutms); + if(addr1) { + /* second one gets a delayed start */ + result = eyeballer_new(&ctx->baller[1], ctx->cf_create, addr1, ai_family1, + ctx->baller[0], /* wait on that to fail */ + /* or start this delayed */ + data->set.happy_eyeballs_timeout, + timeout_ms, EXPIRE_DNS_PER_NAME2); + if(result) + return result; + CURL_TRC_CF(data, cf, "created %s (timeout %" + CURL_FORMAT_TIMEDIFF_T "ms)", + ctx->baller[1]->name, ctx->baller[1]->timeoutms); + Curl_expire(data, data->set.happy_eyeballs_timeout, + EXPIRE_HAPPY_EYEBALLS); + } + + return CURLE_OK; +} + +static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_he_ctx *ctx = cf->ctx; + size_t i; + + DEBUGASSERT(ctx); + DEBUGASSERT(data); + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + baller_free(ctx->baller[i], data); + ctx->baller[i] = NULL; + } + baller_free(ctx->winner, data); + ctx->winner = NULL; +} + +static void cf_he_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_he_ctx *ctx = cf->ctx; + size_t i; + + if(!cf->connected) { + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + struct eyeballer *baller = ctx->baller[i]; + if(!baller || !baller->cf) + continue; + Curl_conn_cf_adjust_pollset(baller->cf, data, ps); + } + CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num); + } +} + +static CURLcode cf_he_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_he_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + (void)blocking; /* TODO: do we want to support this? */ + DEBUGASSERT(ctx); + *done = FALSE; + + switch(ctx->state) { + case SCFST_INIT: + DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data)); + DEBUGASSERT(!cf->connected); + result = start_connect(cf, data, ctx->remotehost); + if(result) + return result; + ctx->state = SCFST_WAITING; + FALLTHROUGH(); + case SCFST_WAITING: + result = is_connected(cf, data, done); + if(!result && *done) { + DEBUGASSERT(ctx->winner); + DEBUGASSERT(ctx->winner->cf); + DEBUGASSERT(ctx->winner->cf->connected); + /* we have a winner. Install and activate it. + * close/free all others. */ + ctx->state = SCFST_DONE; + cf->connected = TRUE; + cf->next = ctx->winner->cf; + ctx->winner->cf = NULL; + cf_he_ctx_clear(cf, data); + Curl_conn_cf_cntrl(cf->next, data, TRUE, + CF_CTRL_CONN_INFO_UPDATE, 0, NULL); + + if(cf->conn->handler->protocol & PROTO_FAMILY_SSH) + Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */ + Curl_verboseconnect(data, cf->conn); + data->info.numconnects++; /* to track the # of connections made */ + } + break; + case SCFST_DONE: + *done = TRUE; + break; + } + return result; +} + +static void cf_he_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_he_ctx *ctx = cf->ctx; + + CURL_TRC_CF(data, cf, "close"); + cf_he_ctx_clear(cf, data); + cf->connected = FALSE; + ctx->state = SCFST_INIT; + + if(cf->next) { + cf->next->cft->do_close(cf->next, data); + Curl_conn_cf_discard_chain(&cf->next, data); + } +} + +static bool cf_he_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct cf_he_ctx *ctx = cf->ctx; + size_t i; + + if(cf->connected) + return cf->next->cft->has_data_pending(cf->next, data); + + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + struct eyeballer *baller = ctx->baller[i]; + if(!baller || !baller->cf) + continue; + if(baller->cf->cft->has_data_pending(baller->cf, data)) + return TRUE; + } + return FALSE; +} + +static struct curltime get_max_baller_time(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query) +{ + struct cf_he_ctx *ctx = cf->ctx; + struct curltime t, tmax; + size_t i; + + memset(&tmax, 0, sizeof(tmax)); + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + struct eyeballer *baller = ctx->baller[i]; + + memset(&t, 0, sizeof(t)); + if(baller && baller->cf && + !baller->cf->cft->query(baller->cf, data, query, NULL, &t)) { + if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) + tmax = t; + } + } + return tmax; +} + +static CURLcode cf_he_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_he_ctx *ctx = cf->ctx; + + if(!cf->connected) { + switch(query) { + case CF_QUERY_CONNECT_REPLY_MS: { + int reply_ms = -1; + size_t i; + + for(i = 0; i < ARRAYSIZE(ctx->baller); i++) { + struct eyeballer *baller = ctx->baller[i]; + int breply_ms; + + if(baller && baller->cf && + !baller->cf->cft->query(baller->cf, data, query, + &breply_ms, NULL)) { + if(breply_ms >= 0 && (reply_ms < 0 || breply_ms < reply_ms)) + reply_ms = breply_ms; + } + } + *pres1 = reply_ms; + CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1); + return CURLE_OK; + } + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); + return CURLE_OK; + } + default: + break; + } + } + + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static void cf_he_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_he_ctx *ctx = cf->ctx; + + CURL_TRC_CF(data, cf, "destroy"); + if(ctx) { + cf_he_ctx_clear(cf, data); + } + /* release any resources held in state */ + Curl_safefree(ctx); +} + +struct Curl_cftype Curl_cft_happy_eyeballs = { + "HAPPY-EYEBALLS", + 0, + CURL_LOG_LVL_NONE, + cf_he_destroy, + cf_he_connect, + cf_he_close, + Curl_cf_def_get_host, + cf_he_adjust_pollset, + cf_he_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_he_query, +}; + +/** + * Create a happy eyeball connection filter that uses the, once resolved, + * address information to connect on ip families based on connection + * configuration. + * @param pcf output, the created cfilter + * @param data easy handle used in creation + * @param conn connection the filter is created for + * @param cf_create method to create the sub-filters performing the + * actual connects. + */ +static CURLcode +cf_happy_eyeballs_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + cf_ip_connect_create *cf_create, + const struct Curl_dns_entry *remotehost, + int transport) +{ + struct cf_he_ctx *ctx = NULL; + CURLcode result; + + (void)data; + (void)conn; + *pcf = NULL; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + ctx->transport = transport; + ctx->cf_create = cf_create; + ctx->remotehost = remotehost; + + result = Curl_cf_create(pcf, &Curl_cft_happy_eyeballs, ctx); + +out: + if(result) { + Curl_safefree(*pcf); + Curl_safefree(ctx); + } + return result; +} + +struct transport_provider { + int transport; + cf_ip_connect_create *cf_create; +}; + +static +#ifndef DEBUGBUILD +const +#endif +struct transport_provider transport_providers[] = { + { TRNSPRT_TCP, Curl_cf_tcp_create }, +#ifdef ENABLE_QUIC + { TRNSPRT_QUIC, Curl_cf_quic_create }, +#endif +#ifndef CURL_DISABLE_TFTP + { TRNSPRT_UDP, Curl_cf_udp_create }, +#endif +#ifdef USE_UNIX_SOCKETS + { TRNSPRT_UNIX, Curl_cf_unix_create }, +#endif +}; + +static cf_ip_connect_create *get_cf_create(int transport) +{ + size_t i; + for(i = 0; i < ARRAYSIZE(transport_providers); ++i) { + if(transport == transport_providers[i].transport) + return transport_providers[i].cf_create; + } + return NULL; +} + +static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data, + const struct Curl_dns_entry *remotehost, + int transport) +{ + cf_ip_connect_create *cf_create; + struct Curl_cfilter *cf; + CURLcode result; + + /* Need to be first */ + DEBUGASSERT(cf_at); + cf_create = get_cf_create(transport); + if(!cf_create) { + CURL_TRC_CF(data, cf_at, "unsupported transport type %d", transport); + return CURLE_UNSUPPORTED_PROTOCOL; + } + result = cf_happy_eyeballs_create(&cf, data, cf_at->conn, + cf_create, remotehost, + transport); + if(result) + return result; + + Curl_conn_cf_insert_after(cf_at, cf); + return CURLE_OK; +} + +typedef enum { + CF_SETUP_INIT, + CF_SETUP_CNNCT_EYEBALLS, + CF_SETUP_CNNCT_SOCKS, + CF_SETUP_CNNCT_HTTP_PROXY, + CF_SETUP_CNNCT_HAPROXY, + CF_SETUP_CNNCT_SSL, + CF_SETUP_DONE +} cf_setup_state; + +struct cf_setup_ctx { + cf_setup_state state; + const struct Curl_dns_entry *remotehost; + int ssl_mode; + int transport; +}; + +static CURLcode cf_setup_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_setup_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* connect current sub-chain */ +connect_sub_chain: + if(cf->next && !cf->next->connected) { + result = Curl_conn_cf_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + } + + if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) { + result = cf_he_insert_after(cf, data, ctx->remotehost, ctx->transport); + if(result) + return result; + ctx->state = CF_SETUP_CNNCT_EYEBALLS; + if(!cf->next || !cf->next->connected) + goto connect_sub_chain; + } + + /* sub-chain connected, do we need to add more? */ +#ifndef CURL_DISABLE_PROXY + if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) { + result = Curl_cf_socks_proxy_insert_after(cf, data); + if(result) + return result; + ctx->state = CF_SETUP_CNNCT_SOCKS; + if(!cf->next || !cf->next->connected) + goto connect_sub_chain; + } + + if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) { +#ifdef USE_SSL + if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype) + && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { + result = Curl_cf_ssl_proxy_insert_after(cf, data); + if(result) + return result; + } +#endif /* USE_SSL */ + +#if !defined(CURL_DISABLE_HTTP) + if(cf->conn->bits.tunnel_proxy) { + result = Curl_cf_http_proxy_insert_after(cf, data); + if(result) + return result; + } +#endif /* !CURL_DISABLE_HTTP */ + ctx->state = CF_SETUP_CNNCT_HTTP_PROXY; + if(!cf->next || !cf->next->connected) + goto connect_sub_chain; + } +#endif /* !CURL_DISABLE_PROXY */ + + if(ctx->state < CF_SETUP_CNNCT_HAPROXY) { +#if !defined(CURL_DISABLE_PROXY) + if(data->set.haproxyprotocol) { + if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) { + failf(data, "haproxy protocol not support with SSL " + "encryption in place (QUIC?)"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + result = Curl_cf_haproxy_insert_after(cf, data); + if(result) + return result; + } +#endif /* !CURL_DISABLE_PROXY */ + ctx->state = CF_SETUP_CNNCT_HAPROXY; + if(!cf->next || !cf->next->connected) + goto connect_sub_chain; + } + + if(ctx->state < CF_SETUP_CNNCT_SSL) { +#ifdef USE_SSL + if((ctx->ssl_mode == CURL_CF_SSL_ENABLE + || (ctx->ssl_mode != CURL_CF_SSL_DISABLE + && cf->conn->handler->flags & PROTOPT_SSL)) /* we want SSL */ + && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */ + result = Curl_cf_ssl_insert_after(cf, data); + if(result) + return result; + } +#endif /* USE_SSL */ + ctx->state = CF_SETUP_CNNCT_SSL; + if(!cf->next || !cf->next->connected) + goto connect_sub_chain; + } + + ctx->state = CF_SETUP_DONE; + cf->connected = TRUE; + *done = TRUE; + return CURLE_OK; +} + +static void cf_setup_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_setup_ctx *ctx = cf->ctx; + + CURL_TRC_CF(data, cf, "close"); + cf->connected = FALSE; + ctx->state = CF_SETUP_INIT; + + if(cf->next) { + cf->next->cft->do_close(cf->next, data); + Curl_conn_cf_discard_chain(&cf->next, data); + } +} + +static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_setup_ctx *ctx = cf->ctx; + + (void)data; + CURL_TRC_CF(data, cf, "destroy"); + Curl_safefree(ctx); +} + + +struct Curl_cftype Curl_cft_setup = { + "SETUP", + 0, + CURL_LOG_LVL_NONE, + cf_setup_destroy, + cf_setup_connect, + cf_setup_close, + Curl_cf_def_get_host, + Curl_cf_def_adjust_pollset, + Curl_cf_def_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, +}; + +static CURLcode cf_setup_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + const struct Curl_dns_entry *remotehost, + int transport, + int ssl_mode) +{ + struct Curl_cfilter *cf = NULL; + struct cf_setup_ctx *ctx; + CURLcode result = CURLE_OK; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + ctx->state = CF_SETUP_INIT; + ctx->remotehost = remotehost; + ctx->ssl_mode = ssl_mode; + ctx->transport = transport; + + result = Curl_cf_create(&cf, &Curl_cft_setup, ctx); + if(result) + goto out; + ctx = NULL; + +out: + *pcf = result? NULL : cf; + free(ctx); + return result; +} + +static CURLcode cf_setup_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + const struct Curl_dns_entry *remotehost, + int transport, + int ssl_mode) +{ + struct Curl_cfilter *cf; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode); + if(result) + goto out; + Curl_conn_cf_add(data, conn, sockindex, cf); +out: + return result; +} + +#ifdef DEBUGBUILD +/* used by unit2600.c */ +void Curl_debug_set_transport_provider(int transport, + cf_ip_connect_create *cf_create) +{ + size_t i; + for(i = 0; i < ARRAYSIZE(transport_providers); ++i) { + if(transport == transport_providers[i].transport) { + transport_providers[i].cf_create = cf_create; + return; + } + } +} +#endif /* DEBUGBUILD */ + +CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data, + const struct Curl_dns_entry *remotehost, + int transport, + int ssl_mode) +{ + struct Curl_cfilter *cf; + CURLcode result; + + DEBUGASSERT(data); + result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode); + if(result) + goto out; + Curl_conn_cf_insert_after(cf_at, cf); +out: + return result; +} + +CURLcode Curl_conn_setup(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + const struct Curl_dns_entry *remotehost, + int ssl_mode) +{ + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + DEBUGASSERT(conn->handler); + +#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) + if(!conn->cfilter[sockindex] && + conn->handler->protocol == CURLPROTO_HTTPS) { + DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE); + result = Curl_cf_https_setup(data, conn, sockindex, remotehost); + if(result) + goto out; + } +#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */ + + /* Still no cfilter set, apply default. */ + if(!conn->cfilter[sockindex]) { + result = cf_setup_add(data, conn, sockindex, remotehost, + conn->transport, ssl_mode); + if(result) + goto out; + } + + DEBUGASSERT(conn->cfilter[sockindex]); +out: + return result; +} diff --git a/lib/connect.h b/lib/connect.h new file mode 100644 index 0000000..58264bd --- /dev/null +++ b/lib/connect.h @@ -0,0 +1,132 @@ +#ifndef HEADER_CURL_CONNECT_H +#define HEADER_CURL_CONNECT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */ +#include "sockaddr.h" +#include "timeval.h" + +struct Curl_dns_entry; + +/* generic function that returns how much time there's left to run, according + to the timeouts set */ +timediff_t Curl_timeleft(struct Curl_easy *data, + struct curltime *nowp, + bool duringconnect); + +#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ + +/* + * Used to extract socket and connectdata struct for the most recent + * transfer on the given Curl_easy. + * + * The returned socket will be CURL_SOCKET_BAD in case of failure! + */ +curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, + struct connectdata **connp); + +bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, + char *addr, int *port); + +void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn, + char *local_ip, int local_port); + +/* + * Curl_conncontrol() marks the end of a connection/stream. The 'closeit' + * argument specifies if it is the end of a connection or a stream. + * + * For stream-based protocols (such as HTTP/2), a stream close will not cause + * a connection close. Other protocols will close the connection for both + * cases. + * + * It sets the bit.close bit to TRUE (with an explanation for debug builds), + * when the connection will close. + */ + +#define CONNCTRL_KEEP 0 /* undo a marked closure */ +#define CONNCTRL_CONNECTION 1 +#define CONNCTRL_STREAM 2 + +void Curl_conncontrol(struct connectdata *conn, + int closeit +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + , const char *reason +#endif + ); + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y) +#else /* if !DEBUGBUILD || CURL_DISABLE_VERBOSE_STRINGS */ +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) +#endif + +/** + * Create a cfilter for making an "ip" connection to the + * given address, using parameters from `conn`. The "ip" connection + * can be a TCP socket, a UDP socket or even a QUIC connection. + * + * It MUST use only the supplied `ai` for its connection attempt. + * + * Such a filter may be used in "happy eyeball" scenarios, and its + * `connect` implementation needs to support non-blocking. Once connected, + * it MAY be installed in the connection filter chain to serve transfers. + */ +typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport); + +CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data, + const struct Curl_dns_entry *remotehost, + int transport, + int ssl_mode); + +/** + * Setup the cfilters at `sockindex` in connection `conn`. + * If no filter chain is installed yet, inspects the configuration + * in `data` and `conn? to install a suitable filter chain. + */ +CURLcode Curl_conn_setup(struct Curl_easy *data, + struct connectdata *conn, + int sockindex, + const struct Curl_dns_entry *remotehost, + int ssl_mode); + +extern struct Curl_cftype Curl_cft_happy_eyeballs; +extern struct Curl_cftype Curl_cft_setup; + +#ifdef DEBUGBUILD +void Curl_debug_set_transport_provider(int transport, + cf_ip_connect_create *cf_create); +#endif + +#endif /* HEADER_CURL_CONNECT_H */ diff --git a/lib/content_encoding.c b/lib/content_encoding.c new file mode 100644 index 0000000..c1abf24 --- /dev/null +++ b/lib/content_encoding.c @@ -0,0 +1,1052 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "urldata.h" +#include +#include + +#ifdef HAVE_LIBZ +#include +#endif + +#ifdef HAVE_BROTLI +#if defined(__GNUC__) +/* Ignore -Wvla warnings in brotli headers */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvla" +#endif +#include +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#endif + +#ifdef HAVE_ZSTD +#include +#endif + +#include "sendf.h" +#include "http.h" +#include "content_encoding.h" +#include "strdup.h" +#include "strcase.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define CONTENT_ENCODING_DEFAULT "identity" + +#ifndef CURL_DISABLE_HTTP + +/* allow no more than 5 "chained" compression steps */ +#define MAX_ENCODE_STACK 5 + +#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */ + + +#ifdef HAVE_LIBZ + +/* Comment this out if zlib is always going to be at least ver. 1.2.0.4 + (doing so will reduce code size slightly). */ +#define OLD_ZLIB_SUPPORT 1 + +#define GZIP_MAGIC_0 0x1f +#define GZIP_MAGIC_1 0x8b + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef enum { + ZLIB_UNINIT, /* uninitialized */ + ZLIB_INIT, /* initialized */ + ZLIB_INFLATING, /* inflating started. */ + ZLIB_EXTERNAL_TRAILER, /* reading external trailer */ + ZLIB_GZIP_HEADER, /* reading gzip header */ + ZLIB_GZIP_INFLATING, /* inflating gzip stream */ + ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ +} zlibInitState; + +/* Deflate and gzip writer. */ +struct zlib_writer { + struct Curl_cwriter super; + zlibInitState zlib_init; /* zlib init state */ + uInt trailerlen; /* Remaining trailer byte count. */ + z_stream z; /* State structure for zlib. */ +}; + + +static voidpf +zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) +{ + (void) opaque; + /* not a typo, keep it calloc() */ + return (voidpf) calloc(items, size); +} + +static void +zfree_cb(voidpf opaque, voidpf ptr) +{ + (void) opaque; + free(ptr); +} + +static CURLcode +process_zlib_error(struct Curl_easy *data, z_stream *z) +{ + if(z->msg) + failf(data, "Error while processing content unencoding: %s", + z->msg); + else + failf(data, "Error while processing content unencoding: " + "Unknown failure within decompression software."); + + return CURLE_BAD_CONTENT_ENCODING; +} + +static CURLcode +exit_zlib(struct Curl_easy *data, + z_stream *z, zlibInitState *zlib_init, CURLcode result) +{ + if(*zlib_init == ZLIB_GZIP_HEADER) + Curl_safefree(z->next_in); + + if(*zlib_init != ZLIB_UNINIT) { + if(inflateEnd(z) != Z_OK && result == CURLE_OK) + result = process_zlib_error(data, z); + *zlib_init = ZLIB_UNINIT; + } + + return result; +} + +static CURLcode process_trailer(struct Curl_easy *data, + struct zlib_writer *zp) +{ + z_stream *z = &zp->z; + CURLcode result = CURLE_OK; + uInt len = z->avail_in < zp->trailerlen? z->avail_in: zp->trailerlen; + + /* Consume expected trailer bytes. Terminate stream if exhausted. + Issue an error if unexpected bytes follow. */ + + zp->trailerlen -= len; + z->avail_in -= len; + z->next_in += len; + if(z->avail_in) + result = CURLE_WRITE_ERROR; + if(result || !zp->trailerlen) + result = exit_zlib(data, z, &zp->zlib_init, result); + else { + /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */ + zp->zlib_init = ZLIB_EXTERNAL_TRAILER; + } + return result; +} + +static CURLcode inflate_stream(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + zlibInitState started) +{ + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + uInt nread = z->avail_in; + Bytef *orig_in = z->next_in; + bool done = FALSE; + CURLcode result = CURLE_OK; /* Curl_client_write status */ + char *decomp; /* Put the decompressed data here. */ + + /* Check state. */ + if(zp->zlib_init != ZLIB_INIT && + zp->zlib_init != ZLIB_INFLATING && + zp->zlib_init != ZLIB_INIT_GZIP && + zp->zlib_init != ZLIB_GZIP_INFLATING) + return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR); + + /* Dynamically allocate a buffer for decompression because it's uncommonly + large to hold on the stack */ + decomp = malloc(DSIZ); + if(!decomp) + return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); + + /* because the buffer size is fixed, iteratively decompress and transfer to + the client via next_write function. */ + while(!done) { + int status; /* zlib status */ + done = TRUE; + + /* (re)set buffer for decompressed output for every iteration */ + z->next_out = (Bytef *) decomp; + z->avail_out = DSIZ; + +#ifdef Z_BLOCK + /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */ + status = inflate(z, Z_BLOCK); +#else + /* fallback for zlib ver. < 1.2.0.5 */ + status = inflate(z, Z_SYNC_FLUSH); +#endif + + /* Flush output data if some. */ + if(z->avail_out != DSIZ) { + if(status == Z_OK || status == Z_STREAM_END) { + zp->zlib_init = started; /* Data started. */ + result = Curl_cwriter_write(data, writer->next, type, decomp, + DSIZ - z->avail_out); + if(result) { + exit_zlib(data, z, &zp->zlib_init, result); + break; + } + } + } + + /* Dispatch by inflate() status. */ + switch(status) { + case Z_OK: + /* Always loop: there may be unflushed latched data in zlib state. */ + done = FALSE; + break; + case Z_BUF_ERROR: + /* No more data to flush: just exit loop. */ + break; + case Z_STREAM_END: + result = process_trailer(data, zp); + break; + case Z_DATA_ERROR: + /* some servers seem to not generate zlib headers, so this is an attempt + to fix and continue anyway */ + if(zp->zlib_init == ZLIB_INIT) { + /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */ + (void) inflateEnd(z); /* don't care about the return code */ + if(inflateInit2(z, -MAX_WBITS) == Z_OK) { + z->next_in = orig_in; + z->avail_in = nread; + zp->zlib_init = ZLIB_INFLATING; + zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */ + done = FALSE; + break; + } + zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */ + } + result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); + break; + default: + result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); + break; + } + } + free(decomp); + + /* We're about to leave this call so the `nread' data bytes won't be seen + again. If we are in a state that would wrongly allow restart in raw mode + at the next call, assume output has already started. */ + if(nread && zp->zlib_init == ZLIB_INIT) + zp->zlib_init = started; /* Cannot restart anymore. */ + + return result; +} + + +/* Deflate handler. */ +static CURLcode deflate_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + + /* Initialize zlib */ + z->zalloc = (alloc_func) zalloc_cb; + z->zfree = (free_func) zfree_cb; + + if(inflateInit(z) != Z_OK) + return process_zlib_error(data, z); + zp->zlib_init = ZLIB_INIT; + return CURLE_OK; +} + +static CURLcode deflate_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + /* Set the compressed input when this function is called */ + z->next_in = (Bytef *) buf; + z->avail_in = (uInt) nbytes; + + if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER) + return process_trailer(data, zp); + + /* Now uncompress the data */ + return inflate_stream(data, writer, type, ZLIB_INFLATING); +} + +static void deflate_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + + exit_zlib(data, z, &zp->zlib_init, CURLE_OK); +} + +static const struct Curl_cwtype deflate_encoding = { + "deflate", + NULL, + deflate_do_init, + deflate_do_write, + deflate_do_close, + sizeof(struct zlib_writer) +}; + + +/* Gzip handler. */ +static CURLcode gzip_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + + /* Initialize zlib */ + z->zalloc = (alloc_func) zalloc_cb; + z->zfree = (free_func) zfree_cb; + + if(strcmp(zlibVersion(), "1.2.0.4") >= 0) { + /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ + if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) { + return process_zlib_error(data, z); + } + zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */ + } + else { + /* we must parse the gzip header and trailer ourselves */ + if(inflateInit2(z, -MAX_WBITS) != Z_OK) { + return process_zlib_error(data, z); + } + zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */ + zp->zlib_init = ZLIB_INIT; /* Initial call state */ + } + + return CURLE_OK; +} + +#ifdef OLD_ZLIB_SUPPORT +/* Skip over the gzip header */ +typedef enum { + GZIP_OK, + GZIP_BAD, + GZIP_UNDERFLOW +} gzip_status; + +static gzip_status check_gzip_header(unsigned char const *data, ssize_t len, + ssize_t *headerlen) +{ + int method, flags; + const ssize_t totallen = len; + + /* The shortest header is 10 bytes */ + if(len < 10) + return GZIP_UNDERFLOW; + + if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1)) + return GZIP_BAD; + + method = data[2]; + flags = data[3]; + + if(method != Z_DEFLATED || (flags & RESERVED) != 0) { + /* Can't handle this compression method or unknown flag */ + return GZIP_BAD; + } + + /* Skip over time, xflags, OS code and all previous bytes */ + len -= 10; + data += 10; + + if(flags & EXTRA_FIELD) { + ssize_t extra_len; + + if(len < 2) + return GZIP_UNDERFLOW; + + extra_len = (data[1] << 8) | data[0]; + + if(len < (extra_len + 2)) + return GZIP_UNDERFLOW; + + len -= (extra_len + 2); + data += (extra_len + 2); + } + + if(flags & ORIG_NAME) { + /* Skip over NUL-terminated file name */ + while(len && *data) { + --len; + ++data; + } + if(!len || *data) + return GZIP_UNDERFLOW; + + /* Skip over the NUL */ + --len; + ++data; + } + + if(flags & COMMENT) { + /* Skip over NUL-terminated comment */ + while(len && *data) { + --len; + ++data; + } + if(!len || *data) + return GZIP_UNDERFLOW; + + /* Skip over the NUL */ + --len; + } + + if(flags & HEAD_CRC) { + if(len < 2) + return GZIP_UNDERFLOW; + + len -= 2; + } + + *headerlen = totallen - len; + return GZIP_OK; +} +#endif + +static CURLcode gzip_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + if(zp->zlib_init == ZLIB_INIT_GZIP) { + /* Let zlib handle the gzip decompression entirely */ + z->next_in = (Bytef *) buf; + z->avail_in = (uInt) nbytes; + /* Now uncompress the data */ + return inflate_stream(data, writer, type, ZLIB_INIT_GZIP); + } + +#ifndef OLD_ZLIB_SUPPORT + /* Support for old zlib versions is compiled away and we are running with + an old version, so return an error. */ + return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR); + +#else + /* This next mess is to get around the potential case where there isn't + * enough data passed in to skip over the gzip header. If that happens, we + * malloc a block and copy what we have then wait for the next call. If + * there still isn't enough (this is definitely a worst-case scenario), we + * make the block bigger, copy the next part in and keep waiting. + * + * This is only required with zlib versions < 1.2.0.4 as newer versions + * can handle the gzip header themselves. + */ + + switch(zp->zlib_init) { + /* Skip over gzip header? */ + case ZLIB_INIT: + { + /* Initial call state */ + ssize_t hlen; + + switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) { + case GZIP_OK: + z->next_in = (Bytef *) buf + hlen; + z->avail_in = (uInt) (nbytes - hlen); + zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ + break; + + case GZIP_UNDERFLOW: + /* We need more data so we can find the end of the gzip header. It's + * possible that the memory block we malloc here will never be freed if + * the transfer abruptly aborts after this point. Since it's unlikely + * that circumstances will be right for this code path to be followed in + * the first place, and it's even more unlikely for a transfer to fail + * immediately afterwards, it should seldom be a problem. + */ + z->avail_in = (uInt) nbytes; + z->next_in = malloc(z->avail_in); + if(!z->next_in) { + return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); + } + memcpy(z->next_in, buf, z->avail_in); + zp->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */ + /* We don't have any data to inflate yet */ + return CURLE_OK; + + case GZIP_BAD: + default: + return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); + } + + } + break; + + case ZLIB_GZIP_HEADER: + { + /* Need more gzip header data state */ + ssize_t hlen; + z->avail_in += (uInt) nbytes; + z->next_in = Curl_saferealloc(z->next_in, z->avail_in); + if(!z->next_in) { + return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); + } + /* Append the new block of data to the previous one */ + memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes); + + switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) { + case GZIP_OK: + /* This is the zlib stream data */ + free(z->next_in); + /* Don't point into the malloced block since we just freed it */ + z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in; + z->avail_in = (uInt) (z->avail_in - hlen); + zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ + break; + + case GZIP_UNDERFLOW: + /* We still don't have any data to inflate! */ + return CURLE_OK; + + case GZIP_BAD: + default: + return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); + } + + } + break; + + case ZLIB_EXTERNAL_TRAILER: + z->next_in = (Bytef *) buf; + z->avail_in = (uInt) nbytes; + return process_trailer(data, zp); + + case ZLIB_GZIP_INFLATING: + default: + /* Inflating stream state */ + z->next_in = (Bytef *) buf; + z->avail_in = (uInt) nbytes; + break; + } + + if(z->avail_in == 0) { + /* We don't have any data to inflate; wait until next time */ + return CURLE_OK; + } + + /* We've parsed the header, now uncompress the data */ + return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING); +#endif +} + +static void gzip_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + + exit_zlib(data, z, &zp->zlib_init, CURLE_OK); +} + +static const struct Curl_cwtype gzip_encoding = { + "gzip", + "x-gzip", + gzip_do_init, + gzip_do_write, + gzip_do_close, + sizeof(struct zlib_writer) +}; + +#endif /* HAVE_LIBZ */ + + +#ifdef HAVE_BROTLI +/* Brotli writer. */ +struct brotli_writer { + struct Curl_cwriter super; + BrotliDecoderState *br; /* State structure for brotli. */ +}; + +static CURLcode brotli_map_error(BrotliDecoderErrorCode be) +{ + switch(be) { + case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE: + case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE: + case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET: + case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME: + case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE: + case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE: + case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT: + case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1: + case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2: + case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM: + case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY: + case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS: + case BROTLI_DECODER_ERROR_FORMAT_PADDING_1: + case BROTLI_DECODER_ERROR_FORMAT_PADDING_2: +#ifdef BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY + case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY: +#endif +#ifdef BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET + case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET: +#endif + case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS: + return CURLE_BAD_CONTENT_ENCODING; + case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES: + case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS: + case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP: + case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1: + case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2: + case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES: + return CURLE_OUT_OF_MEMORY; + default: + break; + } + return CURLE_WRITE_ERROR; +} + +static CURLcode brotli_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct brotli_writer *bp = (struct brotli_writer *) writer; + (void) data; + + bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL); + return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY; +} + +static CURLcode brotli_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + struct brotli_writer *bp = (struct brotli_writer *) writer; + const uint8_t *src = (const uint8_t *) buf; + char *decomp; + uint8_t *dst; + size_t dstleft; + CURLcode result = CURLE_OK; + BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; + + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + if(!bp->br) + return CURLE_WRITE_ERROR; /* Stream already ended. */ + + decomp = malloc(DSIZ); + if(!decomp) + return CURLE_OUT_OF_MEMORY; + + while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) && + result == CURLE_OK) { + dst = (uint8_t *) decomp; + dstleft = DSIZ; + r = BrotliDecoderDecompressStream(bp->br, + &nbytes, &src, &dstleft, &dst, NULL); + result = Curl_cwriter_write(data, writer->next, type, + decomp, DSIZ - dstleft); + if(result) + break; + switch(r) { + case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: + case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: + break; + case BROTLI_DECODER_RESULT_SUCCESS: + BrotliDecoderDestroyInstance(bp->br); + bp->br = NULL; + if(nbytes) + result = CURLE_WRITE_ERROR; + break; + default: + result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br)); + break; + } + } + free(decomp); + return result; +} + +static void brotli_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct brotli_writer *bp = (struct brotli_writer *) writer; + + (void) data; + + if(bp->br) { + BrotliDecoderDestroyInstance(bp->br); + bp->br = NULL; + } +} + +static const struct Curl_cwtype brotli_encoding = { + "br", + NULL, + brotli_do_init, + brotli_do_write, + brotli_do_close, + sizeof(struct brotli_writer) +}; +#endif + + +#ifdef HAVE_ZSTD +/* Zstd writer. */ +struct zstd_writer { + struct Curl_cwriter super; + ZSTD_DStream *zds; /* State structure for zstd. */ + void *decomp; +}; + +static CURLcode zstd_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct zstd_writer *zp = (struct zstd_writer *) writer; + + (void)data; + + zp->zds = ZSTD_createDStream(); + zp->decomp = NULL; + return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY; +} + +static CURLcode zstd_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + CURLcode result = CURLE_OK; + struct zstd_writer *zp = (struct zstd_writer *) writer; + ZSTD_inBuffer in; + ZSTD_outBuffer out; + size_t errorCode; + + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + if(!zp->decomp) { + zp->decomp = malloc(DSIZ); + if(!zp->decomp) + return CURLE_OUT_OF_MEMORY; + } + in.pos = 0; + in.src = buf; + in.size = nbytes; + + for(;;) { + out.pos = 0; + out.dst = zp->decomp; + out.size = DSIZ; + + errorCode = ZSTD_decompressStream(zp->zds, &out, &in); + if(ZSTD_isError(errorCode)) { + return CURLE_BAD_CONTENT_ENCODING; + } + if(out.pos > 0) { + result = Curl_cwriter_write(data, writer->next, type, + zp->decomp, out.pos); + if(result) + break; + } + if((in.pos == nbytes) && (out.pos < out.size)) + break; + } + + return result; +} + +static void zstd_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct zstd_writer *zp = (struct zstd_writer *) writer; + + (void)data; + + if(zp->decomp) { + free(zp->decomp); + zp->decomp = NULL; + } + if(zp->zds) { + ZSTD_freeDStream(zp->zds); + zp->zds = NULL; + } +} + +static const struct Curl_cwtype zstd_encoding = { + "zstd", + NULL, + zstd_do_init, + zstd_do_write, + zstd_do_close, + sizeof(struct zstd_writer) +}; +#endif + + +/* Identity handler. */ +static const struct Curl_cwtype identity_encoding = { + "identity", + "none", + Curl_cwriter_def_init, + Curl_cwriter_def_write, + Curl_cwriter_def_close, + sizeof(struct Curl_cwriter) +}; + + +/* supported general content decoders. */ +static const struct Curl_cwtype * const general_unencoders[] = { + &identity_encoding, +#ifdef HAVE_LIBZ + &deflate_encoding, + &gzip_encoding, +#endif +#ifdef HAVE_BROTLI + &brotli_encoding, +#endif +#ifdef HAVE_ZSTD + &zstd_encoding, +#endif + NULL +}; + +/* supported content decoders only for transfer encodings */ +static const struct Curl_cwtype * const transfer_unencoders[] = { +#ifndef CURL_DISABLE_HTTP + &Curl_httpchunk_unencoder, +#endif + NULL +}; + +/* Provide a list of comma-separated names of supported encodings. +*/ +void Curl_all_content_encodings(char *buf, size_t blen) +{ + size_t len = 0; + const struct Curl_cwtype * const *cep; + const struct Curl_cwtype *ce; + + DEBUGASSERT(buf); + DEBUGASSERT(blen); + buf[0] = 0; + + for(cep = general_unencoders; *cep; cep++) { + ce = *cep; + if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) + len += strlen(ce->name) + 2; + } + + if(!len) { + if(blen >= sizeof(CONTENT_ENCODING_DEFAULT)) + strcpy(buf, CONTENT_ENCODING_DEFAULT); + } + else if(blen > len) { + char *p = buf; + for(cep = general_unencoders; *cep; cep++) { + ce = *cep; + if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) { + strcpy(p, ce->name); + p += strlen(p); + *p++ = ','; + *p++ = ' '; + } + } + p[-2] = '\0'; + } +} + +/* Deferred error dummy writer. */ +static CURLcode error_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + (void)data; + (void)writer; + return CURLE_OK; +} + +static CURLcode error_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + char all[256]; + (void)Curl_all_content_encodings(all, sizeof(all)); + + (void) writer; + (void) buf; + (void) nbytes; + + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + failf(data, "Unrecognized content encoding type. " + "libcurl understands %s content encodings.", all); + return CURLE_BAD_CONTENT_ENCODING; +} + +static void error_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + (void) data; + (void) writer; +} + +static const struct Curl_cwtype error_writer = { + "ce-error", + NULL, + error_do_init, + error_do_write, + error_do_close, + sizeof(struct Curl_cwriter) +}; + +/* Find the content encoding by name. */ +static const struct Curl_cwtype *find_unencode_writer(const char *name, + size_t len, + Curl_cwriter_phase phase) +{ + const struct Curl_cwtype * const *cep; + + if(phase == CURL_CW_TRANSFER_DECODE) { + for(cep = transfer_unencoders; *cep; cep++) { + const struct Curl_cwtype *ce = *cep; + if((strncasecompare(name, ce->name, len) && !ce->name[len]) || + (ce->alias && strncasecompare(name, ce->alias, len) + && !ce->alias[len])) + return ce; + } + } + /* look among the general decoders */ + for(cep = general_unencoders; *cep; cep++) { + const struct Curl_cwtype *ce = *cep; + if((strncasecompare(name, ce->name, len) && !ce->name[len]) || + (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len])) + return ce; + } + return NULL; +} + +/* Set-up the unencoding stack from the Content-Encoding header value. + * See RFC 7231 section 3.1.2.2. */ +CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, + const char *enclist, int is_transfer) +{ + Curl_cwriter_phase phase = is_transfer? + CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE; + CURLcode result; + + do { + const char *name; + size_t namelen; + + /* Parse a single encoding name. */ + while(ISBLANK(*enclist) || *enclist == ',') + enclist++; + + name = enclist; + + for(namelen = 0; *enclist && *enclist != ','; enclist++) + if(!ISSPACE(*enclist)) + namelen = enclist - name + 1; + + if(namelen) { + const struct Curl_cwtype *cwt; + struct Curl_cwriter *writer; + + /* if we skip the decoding in this phase, do not look further. + * Exception is "chunked" transfer-encoding which always must happen */ + if((is_transfer && !data->set.http_transfer_encoding && + (namelen != 7 || !strncasecompare(name, "chunked", 7))) || + (!is_transfer && data->set.http_ce_skip)) { + /* not requested, ignore */ + return CURLE_OK; + } + + if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) { + failf(data, "Reject response due to more than %u content encodings", + MAX_ENCODE_STACK); + return CURLE_BAD_CONTENT_ENCODING; + } + + cwt = find_unencode_writer(name, namelen, phase); + if(!cwt) + cwt = &error_writer; /* Defer error at use. */ + + result = Curl_cwriter_create(&writer, data, cwt, phase); + if(result) + return result; + + result = Curl_cwriter_add(data, writer); + if(result) { + Curl_cwriter_free(data, writer); + return result; + } + } + } while(*enclist); + + return CURLE_OK; +} + +#else +/* Stubs for builds without HTTP. */ +CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, + const char *enclist, int is_transfer) +{ + (void) data; + (void) enclist; + (void) is_transfer; + return CURLE_NOT_BUILT_IN; +} + +void Curl_all_content_encodings(char *buf, size_t blen) +{ + DEBUGASSERT(buf); + DEBUGASSERT(blen); + if(blen < sizeof(CONTENT_ENCODING_DEFAULT)) + buf[0] = 0; + else + strcpy(buf, CONTENT_ENCODING_DEFAULT); +} + + +#endif /* CURL_DISABLE_HTTP */ diff --git a/lib/content_encoding.h b/lib/content_encoding.h new file mode 100644 index 0000000..1addf23 --- /dev/null +++ b/lib/content_encoding.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_CONTENT_ENCODING_H +#define HEADER_CURL_CONTENT_ENCODING_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +struct Curl_cwriter; + +void Curl_all_content_encodings(char *buf, size_t blen); + +CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, + const char *enclist, int is_transfer); +#endif /* HEADER_CURL_CONTENT_ENCODING_H */ diff --git a/lib/cookie.c b/lib/cookie.c new file mode 100644 index 0000000..dc319b6 --- /dev/null +++ b/lib/cookie.c @@ -0,0 +1,1783 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/*** + + +RECEIVING COOKIE INFORMATION +============================ + +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, + const char *file, struct CookieInfo *inc, bool newsession); + + Inits a cookie struct to store data in a local file. This is always + called before any cookies are set. + +struct Cookie *Curl_cookie_add(struct Curl_easy *data, + struct CookieInfo *c, bool httpheader, bool noexpire, + char *lineptr, const char *domain, const char *path, + bool secure); + + The 'lineptr' parameter is a full "Set-cookie:" line as + received from a server. + + The function need to replace previously stored lines that this new + line supersedes. + + It may remove lines that are expired. + + It should return an indication of success/error. + + +SENDING COOKIE INFORMATION +========================== + +struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie, + char *host, char *path, bool secure); + + For a given host and path, return a linked list of cookies that + the client should send to the server if used now. The secure + boolean informs the cookie if a secure connection is achieved or + not. + + It shall only return cookies that haven't expired. + + +Example set of cookies: + + Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure + Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/ftgw; secure + Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: + Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday, + 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure +****/ + + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + +#include "urldata.h" +#include "cookie.h" +#include "psl.h" +#include "strtok.h" +#include "sendf.h" +#include "slist.h" +#include "share.h" +#include "strtoofft.h" +#include "strcase.h" +#include "curl_get_line.h" +#include "curl_memrchr.h" +#include "parsedate.h" +#include "rename.h" +#include "fopen.h" +#include "strdup.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static void strstore(char **str, const char *newstr, size_t len); + +static void freecookie(struct Cookie *co) +{ + free(co->domain); + free(co->path); + free(co->spath); + free(co->name); + free(co->value); + free(co); +} + +static bool cookie_tailmatch(const char *cookie_domain, + size_t cookie_domain_len, + const char *hostname) +{ + size_t hostname_len = strlen(hostname); + + if(hostname_len < cookie_domain_len) + return FALSE; + + if(!strncasecompare(cookie_domain, + hostname + hostname_len-cookie_domain_len, + cookie_domain_len)) + return FALSE; + + /* + * A lead char of cookie_domain is not '.'. + * RFC6265 4.1.2.3. The Domain Attribute says: + * For example, if the value of the Domain attribute is + * "example.com", the user agent will include the cookie in the Cookie + * header when making HTTP requests to example.com, www.example.com, and + * www.corp.example.com. + */ + if(hostname_len == cookie_domain_len) + return TRUE; + if('.' == *(hostname + hostname_len - cookie_domain_len - 1)) + return TRUE; + return FALSE; +} + +/* + * matching cookie path and url path + * RFC6265 5.1.4 Paths and Path-Match + */ +static bool pathmatch(const char *cookie_path, const char *request_uri) +{ + size_t cookie_path_len; + size_t uri_path_len; + char *uri_path = NULL; + char *pos; + bool ret = FALSE; + + /* cookie_path must not have last '/' separator. ex: /sample */ + cookie_path_len = strlen(cookie_path); + if(1 == cookie_path_len) { + /* cookie_path must be '/' */ + return TRUE; + } + + uri_path = strdup(request_uri); + if(!uri_path) + return FALSE; + pos = strchr(uri_path, '?'); + if(pos) + *pos = 0x0; + + /* #-fragments are already cut off! */ + if(0 == strlen(uri_path) || uri_path[0] != '/') { + strstore(&uri_path, "/", 1); + if(!uri_path) + return FALSE; + } + + /* + * here, RFC6265 5.1.4 says + * 4. Output the characters of the uri-path from the first character up + * to, but not including, the right-most %x2F ("/"). + * but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site + * without redirect. + * Ignore this algorithm because /hoge is uri path for this case + * (uri path is not /). + */ + + uri_path_len = strlen(uri_path); + + if(uri_path_len < cookie_path_len) { + ret = FALSE; + goto pathmatched; + } + + /* not using checkprefix() because matching should be case-sensitive */ + if(strncmp(cookie_path, uri_path, cookie_path_len)) { + ret = FALSE; + goto pathmatched; + } + + /* The cookie-path and the uri-path are identical. */ + if(cookie_path_len == uri_path_len) { + ret = TRUE; + goto pathmatched; + } + + /* here, cookie_path_len < uri_path_len */ + if(uri_path[cookie_path_len] == '/') { + ret = TRUE; + goto pathmatched; + } + + ret = FALSE; + +pathmatched: + free(uri_path); + return ret; +} + +/* + * Return the top-level domain, for optimal hashing. + */ +static const char *get_top_domain(const char * const domain, size_t *outlen) +{ + size_t len = 0; + const char *first = NULL, *last; + + if(domain) { + len = strlen(domain); + last = memrchr(domain, '.', len); + if(last) { + first = memrchr(domain, '.', (last - domain)); + if(first) + len -= (++first - domain); + } + } + + if(outlen) + *outlen = len; + + return first? first: domain; +} + +/* Avoid C1001, an "internal error" with MSVC14 */ +#if defined(_MSC_VER) && (_MSC_VER == 1900) +#pragma optimize("", off) +#endif + +/* + * A case-insensitive hash for the cookie domains. + */ +static size_t cookie_hash_domain(const char *domain, const size_t len) +{ + const char *end = domain + len; + size_t h = 5381; + + while(domain < end) { + h += h << 5; + h ^= Curl_raw_toupper(*domain++); + } + + return (h % COOKIE_HASH_SIZE); +} + +#if defined(_MSC_VER) && (_MSC_VER == 1900) +#pragma optimize("", on) +#endif + +/* + * Hash this domain. + */ +static size_t cookiehash(const char * const domain) +{ + const char *top; + size_t len; + + if(!domain || Curl_host_is_ipnum(domain)) + return 0; + + top = get_top_domain(domain, &len); + return cookie_hash_domain(top, len); +} + +/* + * cookie path sanitize + */ +static char *sanitize_cookie_path(const char *cookie_path) +{ + size_t len; + char *new_path = strdup(cookie_path); + if(!new_path) + return NULL; + + /* some stupid site sends path attribute with '"'. */ + len = strlen(new_path); + if(new_path[0] == '\"') { + memmove(new_path, new_path + 1, len); + len--; + } + if(len && (new_path[len - 1] == '\"')) { + new_path[--len] = 0x0; + } + + /* RFC6265 5.2.4 The Path Attribute */ + if(new_path[0] != '/') { + /* Let cookie-path be the default-path. */ + strstore(&new_path, "/", 1); + return new_path; + } + + /* convert /hoge/ to /hoge */ + if(len && new_path[len - 1] == '/') { + new_path[len - 1] = 0x0; + } + + return new_path; +} + +/* + * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). + * + * NOTE: OOM or cookie parsing failures are ignored. + */ +void Curl_cookie_loadfiles(struct Curl_easy *data) +{ + struct curl_slist *list = data->state.cookielist; + if(list) { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + while(list) { + struct CookieInfo *newcookies = + Curl_cookie_init(data, list->data, data->cookies, + data->set.cookiesession); + if(!newcookies) + /* + * Failure may be due to OOM or a bad cookie; both are ignored + * but only the first should be + */ + infof(data, "ignoring failed cookie_init for %s", list->data); + else + data->cookies = newcookies; + list = list->next; + } + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } +} + +/* + * strstore + * + * A thin wrapper around strdup which ensures that any memory allocated at + * *str will be freed before the string allocated by strdup is stored there. + * The intended usecase is repeated assignments to the same variable during + * parsing in a last-wins scenario. The caller is responsible for checking + * for OOM errors. + */ +static void strstore(char **str, const char *newstr, size_t len) +{ + DEBUGASSERT(newstr); + DEBUGASSERT(str); + free(*str); + *str = Curl_memdup0(newstr, len); +} + +/* + * remove_expired + * + * Remove expired cookies from the hash by inspecting the expires timestamp on + * each cookie in the hash, freeing and deleting any where the timestamp is in + * the past. If the cookiejar has recorded the next timestamp at which one or + * more cookies expire, then processing will exit early in case this timestamp + * is in the future. + */ +static void remove_expired(struct CookieInfo *cookies) +{ + struct Cookie *co, *nx; + curl_off_t now = (curl_off_t)time(NULL); + unsigned int i; + + /* + * If the earliest expiration timestamp in the jar is in the future we can + * skip scanning the whole jar and instead exit early as there won't be any + * cookies to evict. If we need to evict however, reset the next_expiration + * counter in order to track the next one. In case the recorded first + * expiration is the max offset, then perform the safe fallback of checking + * all cookies. + */ + if(now < cookies->next_expiration && + cookies->next_expiration != CURL_OFF_T_MAX) + return; + else + cookies->next_expiration = CURL_OFF_T_MAX; + + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + struct Cookie *pv = NULL; + co = cookies->cookies[i]; + while(co) { + nx = co->next; + if(co->expires && co->expires < now) { + if(!pv) { + cookies->cookies[i] = co->next; + } + else { + pv->next = co->next; + } + cookies->numcookies--; + freecookie(co); + } + else { + /* + * If this cookie has an expiration timestamp earlier than what we've + * seen so far then record it for the next round of expirations. + */ + if(co->expires && co->expires < cookies->next_expiration) + cookies->next_expiration = co->expires; + pv = co; + } + co = nx; + } + } +} + +/* Make sure domain contains a dot or is localhost. */ +static bool bad_domain(const char *domain, size_t len) +{ + if((len == 9) && strncasecompare(domain, "localhost", 9)) + return FALSE; + else { + /* there must be a dot present, but that dot must not be a trailing dot */ + char *dot = memchr(domain, '.', len); + if(dot) { + size_t i = dot - domain; + if((len - i) > 1) + /* the dot is not the last byte */ + return FALSE; + } + } + return TRUE; +} + +/* + RFC 6265 section 4.1.1 says a server should accept this range: + + cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E + + But Firefox and Chrome as of June 2022 accept space, comma and double-quotes + fine. The prime reason for filtering out control bytes is that some HTTP + servers return 400 for requests that contain such. +*/ +static int invalid_octets(const char *p) +{ + /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */ + static const char badoctets[] = { + "\x01\x02\x03\x04\x05\x06\x07\x08\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" + }; + size_t len; + /* scan for all the octets that are *not* in cookie-octet */ + len = strcspn(p, badoctets); + return (p[len] != '\0'); +} + +/* + * Curl_cookie_add + * + * Add a single cookie line to the cookie keeping object. Be aware that + * sometimes we get an IP-only host name, and that might also be a numerical + * IPv6 address. + * + * Returns NULL on out of memory or invalid cookie. This is suboptimal, + * as they should be treated separately. + */ +struct Cookie * +Curl_cookie_add(struct Curl_easy *data, + struct CookieInfo *c, + bool httpheader, /* TRUE if HTTP header-style line */ + bool noexpire, /* if TRUE, skip remove_expired() */ + const char *lineptr, /* first character of the line */ + const char *domain, /* default domain */ + const char *path, /* full path used when this cookie is set, + used to get default path for the cookie + unless set */ + bool secure) /* TRUE if connection is over secure origin */ +{ + struct Cookie *clist; + struct Cookie *co; + struct Cookie *lastc = NULL; + struct Cookie *replace_co = NULL; + struct Cookie *replace_clist = NULL; + time_t now = time(NULL); + bool replace_old = FALSE; + bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ + size_t myhash; + + DEBUGASSERT(data); + DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */ + if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT) + return NULL; + + /* First, alloc and init a new struct for it */ + co = calloc(1, sizeof(struct Cookie)); + if(!co) + return NULL; /* bail out if we're this low on memory */ + + if(httpheader) { + /* This line was read off an HTTP-header */ + const char *ptr; + + size_t linelength = strlen(lineptr); + if(linelength > MAX_COOKIE_LINE) { + /* discard overly long lines at once */ + free(co); + return NULL; + } + + ptr = lineptr; + do { + size_t vlen; + size_t nlen; + + while(*ptr && ISBLANK(*ptr)) + ptr++; + + /* we have a = pair or a stand-alone word here */ + nlen = strcspn(ptr, ";\t\r\n="); + if(nlen) { + bool done = FALSE; + bool sep = FALSE; + const char *namep = ptr; + const char *valuep; + + ptr += nlen; + + /* trim trailing spaces and tabs after name */ + while(nlen && ISBLANK(namep[nlen - 1])) + nlen--; + + if(*ptr == '=') { + vlen = strcspn(++ptr, ";\r\n"); + valuep = ptr; + sep = TRUE; + ptr = &valuep[vlen]; + + /* Strip off trailing whitespace from the value */ + while(vlen && ISBLANK(valuep[vlen-1])) + vlen--; + + /* Skip leading whitespace from the value */ + while(vlen && ISBLANK(*valuep)) { + valuep++; + vlen--; + } + + /* Reject cookies with a TAB inside the value */ + if(memchr(valuep, '\t', vlen)) { + freecookie(co); + infof(data, "cookie contains TAB, dropping"); + return NULL; + } + } + else { + valuep = NULL; + vlen = 0; + } + + /* + * Check for too long individual name or contents, or too long + * combination of name + contents. Chrome and Firefox support 4095 or + * 4096 bytes combo + */ + if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) || + ((nlen + vlen) > MAX_NAME)) { + freecookie(co); + infof(data, "oversized cookie dropped, name/val %zu + %zu bytes", + nlen, vlen); + return NULL; + } + + /* + * Check if we have a reserved prefix set before anything else, as we + * otherwise have to test for the prefix in both the cookie name and + * "the rest". Prefixes must start with '__' and end with a '-', so + * only test for names where that can possibly be true. + */ + if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') { + if(strncasecompare("__Secure-", namep, 9)) + co->prefix |= COOKIE_PREFIX__SECURE; + else if(strncasecompare("__Host-", namep, 7)) + co->prefix |= COOKIE_PREFIX__HOST; + } + + /* + * Use strstore() below to properly deal with received cookie + * headers that have the same string property set more than once, + * and then we use the last one. + */ + + if(!co->name) { + /* The very first name/value pair is the actual cookie name */ + if(!sep) { + /* Bad name/value pair. */ + badcookie = TRUE; + break; + } + strstore(&co->name, namep, nlen); + strstore(&co->value, valuep, vlen); + done = TRUE; + if(!co->name || !co->value) { + badcookie = TRUE; + break; + } + if(invalid_octets(co->value) || invalid_octets(co->name)) { + infof(data, "invalid octets in name/value, cookie dropped"); + badcookie = TRUE; + break; + } + } + else if(!vlen) { + /* + * this was a "=" with no content, and we must allow + * 'secure' and 'httponly' specified this weirdly + */ + done = TRUE; + /* + * secure cookies are only allowed to be set when the connection is + * using a secure protocol, or when the cookie is being set by + * reading from file + */ + if((nlen == 6) && strncasecompare("secure", namep, 6)) { + if(secure || !c->running) { + co->secure = TRUE; + } + else { + badcookie = TRUE; + break; + } + } + else if((nlen == 8) && strncasecompare("httponly", namep, 8)) + co->httponly = TRUE; + else if(sep) + /* there was a '=' so we're not done parsing this field */ + done = FALSE; + } + if(done) + ; + else if((nlen == 4) && strncasecompare("path", namep, 4)) { + strstore(&co->path, valuep, vlen); + if(!co->path) { + badcookie = TRUE; /* out of memory bad */ + break; + } + free(co->spath); /* if this is set again */ + co->spath = sanitize_cookie_path(co->path); + if(!co->spath) { + badcookie = TRUE; /* out of memory bad */ + break; + } + } + else if((nlen == 6) && + strncasecompare("domain", namep, 6) && vlen) { + bool is_ip; + + /* + * Now, we make sure that our host is within the given domain, or + * the given domain is not valid and thus cannot be set. + */ + + if('.' == valuep[0]) { + valuep++; /* ignore preceding dot */ + vlen--; + } + +#ifndef USE_LIBPSL + /* + * Without PSL we don't know when the incoming cookie is set on a + * TLD or otherwise "protected" suffix. To reduce risk, we require a + * dot OR the exact host name being "localhost". + */ + if(bad_domain(valuep, vlen)) + domain = ":"; +#endif + + is_ip = Curl_host_is_ipnum(domain ? domain : valuep); + + if(!domain + || (is_ip && !strncmp(valuep, domain, vlen) && + (vlen == strlen(domain))) + || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) { + strstore(&co->domain, valuep, vlen); + if(!co->domain) { + badcookie = TRUE; + break; + } + if(!is_ip) + co->tailmatch = TRUE; /* we always do that if the domain name was + given */ + } + else { + /* + * We did not get a tailmatch and then the attempted set domain is + * not a domain to which the current host belongs. Mark as bad. + */ + badcookie = TRUE; + infof(data, "skipped cookie with bad tailmatch domain: %s", + valuep); + } + } + else if((nlen == 7) && strncasecompare("version", namep, 7)) { + /* just ignore */ + } + else if((nlen == 7) && strncasecompare("max-age", namep, 7)) { + /* + * Defined in RFC2109: + * + * Optional. The Max-Age attribute defines the lifetime of the + * cookie, in seconds. The delta-seconds value is a decimal non- + * negative integer. After delta-seconds seconds elapse, the + * client should discard the cookie. A value of zero means the + * cookie should be discarded immediately. + */ + CURLofft offt; + const char *maxage = valuep; + offt = curlx_strtoofft((*maxage == '\"')? + &maxage[1]:&maxage[0], NULL, 10, + &co->expires); + switch(offt) { + case CURL_OFFT_FLOW: + /* overflow, used max value */ + co->expires = CURL_OFF_T_MAX; + break; + case CURL_OFFT_INVAL: + /* negative or otherwise bad, expire */ + co->expires = 1; + break; + case CURL_OFFT_OK: + if(!co->expires) + /* already expired */ + co->expires = 1; + else if(CURL_OFF_T_MAX - now < co->expires) + /* would overflow */ + co->expires = CURL_OFF_T_MAX; + else + co->expires += now; + break; + } + } + else if((nlen == 7) && strncasecompare("expires", namep, 7)) { + char date[128]; + if(!co->expires && (vlen < sizeof(date))) { + /* copy the date so that it can be null terminated */ + memcpy(date, valuep, vlen); + date[vlen] = 0; + /* + * Let max-age have priority. + * + * If the date cannot get parsed for whatever reason, the cookie + * will be treated as a session cookie + */ + co->expires = Curl_getdate_capped(date); + + /* + * Session cookies have expires set to 0 so if we get that back + * from the date parser let's add a second to make it a + * non-session cookie + */ + if(co->expires == 0) + co->expires = 1; + else if(co->expires < 0) + co->expires = 0; + } + } + + /* + * Else, this is the second (or more) name we don't know about! + */ + } + else { + /* this is an "illegal" = pair */ + } + + while(*ptr && ISBLANK(*ptr)) + ptr++; + if(*ptr == ';') + ptr++; + else + break; + } while(1); + + if(!badcookie && !co->domain) { + if(domain) { + /* no domain was given in the header line, set the default */ + co->domain = strdup(domain); + if(!co->domain) + badcookie = TRUE; + } + } + + if(!badcookie && !co->path && path) { + /* + * No path was given in the header line, set the default. Note that the + * passed-in path to this function MAY have a '?' and following part that + * MUST NOT be stored as part of the path. + */ + char *queryp = strchr(path, '?'); + + /* + * queryp is where the interesting part of the path ends, so now we + * want to the find the last + */ + char *endslash; + if(!queryp) + endslash = strrchr(path, '/'); + else + endslash = memrchr(path, '/', (queryp - path)); + if(endslash) { + size_t pathlen = (endslash-path + 1); /* include end slash */ + co->path = Curl_memdup0(path, pathlen); + if(co->path) { + co->spath = sanitize_cookie_path(co->path); + if(!co->spath) + badcookie = TRUE; /* out of memory bad */ + } + else + badcookie = TRUE; + } + } + + /* + * If we didn't get a cookie name, or a bad one, the this is an illegal + * line so bail out. + */ + if(badcookie || !co->name) { + freecookie(co); + return NULL; + } + data->req.setcookies++; + } + else { + /* + * This line is NOT an HTTP header style line, we do offer support for + * reading the odd netscape cookies-file format here + */ + char *ptr; + char *firstptr; + char *tok_buf = NULL; + int fields; + + /* + * IE introduced HTTP-only cookies to prevent XSS attacks. Cookies marked + * with httpOnly after the domain name are not accessible from javascripts, + * but since curl does not operate at javascript level, we include them + * anyway. In Firefox's cookie files, these lines are preceded with + * #HttpOnly_ and then everything is as usual, so we skip 10 characters of + * the line.. + */ + if(strncmp(lineptr, "#HttpOnly_", 10) == 0) { + lineptr += 10; + co->httponly = TRUE; + } + + if(lineptr[0]=='#') { + /* don't even try the comments */ + free(co); + return NULL; + } + /* strip off the possible end-of-line characters */ + ptr = strchr(lineptr, '\r'); + if(ptr) + *ptr = 0; /* clear it */ + ptr = strchr(lineptr, '\n'); + if(ptr) + *ptr = 0; /* clear it */ + + firstptr = strtok_r((char *)lineptr, "\t", &tok_buf); /* tokenize on TAB */ + + /* + * Now loop through the fields and init the struct we already have + * allocated + */ + for(ptr = firstptr, fields = 0; ptr && !badcookie; + ptr = strtok_r(NULL, "\t", &tok_buf), fields++) { + switch(fields) { + case 0: + if(ptr[0]=='.') /* skip preceding dots */ + ptr++; + co->domain = strdup(ptr); + if(!co->domain) + badcookie = TRUE; + break; + case 1: + /* + * flag: A TRUE/FALSE value indicating if all machines within a given + * domain can access the variable. Set TRUE when the cookie says + * .domain.com and to false when the domain is complete www.domain.com + */ + co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE; + break; + case 2: + /* The file format allows the path field to remain not filled in */ + if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) { + /* only if the path doesn't look like a boolean option! */ + co->path = strdup(ptr); + if(!co->path) + badcookie = TRUE; + else { + co->spath = sanitize_cookie_path(co->path); + if(!co->spath) { + badcookie = TRUE; /* out of memory bad */ + } + } + break; + } + /* this doesn't look like a path, make one up! */ + co->path = strdup("/"); + if(!co->path) + badcookie = TRUE; + co->spath = strdup("/"); + if(!co->spath) + badcookie = TRUE; + fields++; /* add a field and fall down to secure */ + FALLTHROUGH(); + case 3: + co->secure = FALSE; + if(strcasecompare(ptr, "TRUE")) { + if(secure || c->running) + co->secure = TRUE; + else + badcookie = TRUE; + } + break; + case 4: + if(curlx_strtoofft(ptr, NULL, 10, &co->expires)) + badcookie = TRUE; + break; + case 5: + co->name = strdup(ptr); + if(!co->name) + badcookie = TRUE; + else { + /* For Netscape file format cookies we check prefix on the name */ + if(strncasecompare("__Secure-", co->name, 9)) + co->prefix |= COOKIE_PREFIX__SECURE; + else if(strncasecompare("__Host-", co->name, 7)) + co->prefix |= COOKIE_PREFIX__HOST; + } + break; + case 6: + co->value = strdup(ptr); + if(!co->value) + badcookie = TRUE; + break; + } + } + if(6 == fields) { + /* we got a cookie with blank contents, fix it */ + co->value = strdup(""); + if(!co->value) + badcookie = TRUE; + else + fields++; + } + + if(!badcookie && (7 != fields)) + /* we did not find the sufficient number of fields */ + badcookie = TRUE; + + if(badcookie) { + freecookie(co); + return NULL; + } + + } + + if(co->prefix & COOKIE_PREFIX__SECURE) { + /* The __Secure- prefix only requires that the cookie be set secure */ + if(!co->secure) { + freecookie(co); + return NULL; + } + } + if(co->prefix & COOKIE_PREFIX__HOST) { + /* + * The __Host- prefix requires the cookie to be secure, have a "/" path + * and not have a domain set. + */ + if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch) + ; + else { + freecookie(co); + return NULL; + } + } + + if(!c->running && /* read from a file */ + c->newsession && /* clean session cookies */ + !co->expires) { /* this is a session cookie since it doesn't expire! */ + freecookie(co); + return NULL; + } + + co->livecookie = c->running; + co->creationtime = ++c->lastct; + + /* + * Now we have parsed the incoming line, we must now check if this supersedes + * an already existing cookie, which it may if the previous have the same + * domain and path as this. + */ + + /* at first, remove expired cookies */ + if(!noexpire) + remove_expired(c); + +#ifdef USE_LIBPSL + /* + * Check if the domain is a Public Suffix and if yes, ignore the cookie. We + * must also check that the data handle isn't NULL since the psl code will + * dereference it. + */ + if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) { + bool acceptable = FALSE; + char lcase[256]; + char lcookie[256]; + size_t dlen = strlen(domain); + size_t clen = strlen(co->domain); + if((dlen < sizeof(lcase)) && (clen < sizeof(lcookie))) { + const psl_ctx_t *psl = Curl_psl_use(data); + if(psl) { + /* the PSL check requires lowercase domain name and pattern */ + Curl_strntolower(lcase, domain, dlen + 1); + Curl_strntolower(lcookie, co->domain, clen + 1); + acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie); + Curl_psl_release(data); + } + else + acceptable = !bad_domain(domain, strlen(domain)); + } + + if(!acceptable) { + infof(data, "cookie '%s' dropped, domain '%s' must not " + "set cookies for '%s'", co->name, domain, co->domain); + freecookie(co); + return NULL; + } + } +#endif + + /* A non-secure cookie may not overlay an existing secure cookie. */ + myhash = cookiehash(co->domain); + clist = c->cookies[myhash]; + while(clist) { + if(strcasecompare(clist->name, co->name)) { + /* the names are identical */ + bool matching_domains = FALSE; + + if(clist->domain && co->domain) { + if(strcasecompare(clist->domain, co->domain)) + /* The domains are identical */ + matching_domains = TRUE; + } + else if(!clist->domain && !co->domain) + matching_domains = TRUE; + + if(matching_domains && /* the domains were identical */ + clist->spath && co->spath && /* both have paths */ + clist->secure && !co->secure && !secure) { + size_t cllen; + const char *sep; + + /* + * A non-secure cookie may not overlay an existing secure cookie. + * For an existing cookie "a" with path "/login", refuse a new + * cookie "a" with for example path "/login/en", while the path + * "/loginhelper" is ok. + */ + + sep = strchr(clist->spath + 1, '/'); + + if(sep) + cllen = sep - clist->spath; + else + cllen = strlen(clist->spath); + + if(strncasecompare(clist->spath, co->spath, cllen)) { + infof(data, "cookie '%s' for domain '%s' dropped, would " + "overlay an existing cookie", co->name, co->domain); + freecookie(co); + return NULL; + } + } + } + + if(!replace_co && strcasecompare(clist->name, co->name)) { + /* the names are identical */ + + if(clist->domain && co->domain) { + if(strcasecompare(clist->domain, co->domain) && + (clist->tailmatch == co->tailmatch)) + /* The domains are identical */ + replace_old = TRUE; + } + else if(!clist->domain && !co->domain) + replace_old = TRUE; + + if(replace_old) { + /* the domains were identical */ + + if(clist->spath && co->spath && + !strcasecompare(clist->spath, co->spath)) + replace_old = FALSE; + else if(!clist->spath != !co->spath) + replace_old = FALSE; + } + + if(replace_old && !co->livecookie && clist->livecookie) { + /* + * Both cookies matched fine, except that the already present cookie is + * "live", which means it was set from a header, while the new one was + * read from a file and thus isn't "live". "live" cookies are preferred + * so the new cookie is freed. + */ + freecookie(co); + return NULL; + } + if(replace_old) { + replace_co = co; + replace_clist = clist; + } + } + lastc = clist; + clist = clist->next; + } + if(replace_co) { + co = replace_co; + clist = replace_clist; + co->next = clist->next; /* get the next-pointer first */ + + /* when replacing, creationtime is kept from old */ + co->creationtime = clist->creationtime; + + /* then free all the old pointers */ + free(clist->name); + free(clist->value); + free(clist->domain); + free(clist->path); + free(clist->spath); + + *clist = *co; /* then store all the new data */ + + free(co); /* free the newly allocated memory */ + co = clist; + } + + if(c->running) + /* Only show this when NOT reading the cookies from a file */ + infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, " + "expire %" CURL_FORMAT_CURL_OFF_T, + replace_old?"Replaced":"Added", co->name, co->value, + co->domain, co->path, co->expires); + + if(!replace_old) { + /* then make the last item point on this new one */ + if(lastc) + lastc->next = co; + else + c->cookies[myhash] = co; + c->numcookies++; /* one more cookie in the jar */ + } + + /* + * Now that we've added a new cookie to the jar, update the expiration + * tracker in case it is the next one to expire. + */ + if(co->expires && (co->expires < c->next_expiration)) + c->next_expiration = co->expires; + + return co; +} + + +/* + * Curl_cookie_init() + * + * Inits a cookie struct to read data from a local file. This is always + * called before any cookies are set. File may be NULL in which case only the + * struct is initialized. Is file is "-" then STDIN is read. + * + * If 'newsession' is TRUE, discard all "session cookies" on read from file. + * + * Note that 'data' might be called as NULL pointer. If data is NULL, 'file' + * will be ignored. + * + * Returns NULL on out of memory. Invalid cookies are ignored. + */ +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, + const char *file, + struct CookieInfo *inc, + bool newsession) +{ + struct CookieInfo *c; + char *line = NULL; + FILE *handle = NULL; + + if(!inc) { + /* we didn't get a struct, create one */ + c = calloc(1, sizeof(struct CookieInfo)); + if(!c) + return NULL; /* failed to get memory */ + /* + * Initialize the next_expiration time to signal that we don't have enough + * information yet. + */ + c->next_expiration = CURL_OFF_T_MAX; + } + else { + /* we got an already existing one, use that */ + c = inc; + } + c->newsession = newsession; /* new session? */ + + if(data) { + FILE *fp = NULL; + if(file && *file) { + if(!strcmp(file, "-")) + fp = stdin; + else { + fp = fopen(file, "rb"); + if(!fp) + infof(data, "WARNING: failed to open cookie file \"%s\"", file); + else + handle = fp; + } + } + + c->running = FALSE; /* this is not running, this is init */ + if(fp) { + + line = malloc(MAX_COOKIE_LINE); + if(!line) + goto fail; + while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) { + char *lineptr = line; + bool headerline = FALSE; + if(checkprefix("Set-Cookie:", line)) { + /* This is a cookie line, get it! */ + lineptr = &line[11]; + headerline = TRUE; + while(*lineptr && ISBLANK(*lineptr)) + lineptr++; + } + + Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE); + } + free(line); /* free the line buffer */ + + /* + * Remove expired cookies from the hash. We must make sure to run this + * after reading the file, and not on every cookie. + */ + remove_expired(c); + + if(handle) + fclose(handle); + } + data->state.cookie_engine = TRUE; + } + c->running = TRUE; /* now, we're running */ + + return c; + +fail: + free(line); + /* + * Only clean up if we allocated it here, as the original could still be in + * use by a share handle. + */ + if(!inc) + Curl_cookie_cleanup(c); + if(handle) + fclose(handle); + return NULL; /* out of memory */ +} + +/* + * cookie_sort + * + * Helper function to sort cookies such that the longest path gets before the + * shorter path. Path, domain and name lengths are considered in that order, + * with the creationtime as the tiebreaker. The creationtime is guaranteed to + * be unique per cookie, so we know we will get an ordering at that point. + */ +static int cookie_sort(const void *p1, const void *p2) +{ + struct Cookie *c1 = *(struct Cookie **)p1; + struct Cookie *c2 = *(struct Cookie **)p2; + size_t l1, l2; + + /* 1 - compare cookie path lengths */ + l1 = c1->path ? strlen(c1->path) : 0; + l2 = c2->path ? strlen(c2->path) : 0; + + if(l1 != l2) + return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ + + /* 2 - compare cookie domain lengths */ + l1 = c1->domain ? strlen(c1->domain) : 0; + l2 = c2->domain ? strlen(c2->domain) : 0; + + if(l1 != l2) + return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ + + /* 3 - compare cookie name lengths */ + l1 = c1->name ? strlen(c1->name) : 0; + l2 = c2->name ? strlen(c2->name) : 0; + + if(l1 != l2) + return (l2 > l1) ? 1 : -1; + + /* 4 - compare cookie creation time */ + return (c2->creationtime > c1->creationtime) ? 1 : -1; +} + +/* + * cookie_sort_ct + * + * Helper function to sort cookies according to creation time. + */ +static int cookie_sort_ct(const void *p1, const void *p2) +{ + struct Cookie *c1 = *(struct Cookie **)p1; + struct Cookie *c2 = *(struct Cookie **)p2; + + return (c2->creationtime > c1->creationtime) ? 1 : -1; +} + +#define CLONE(field) \ + do { \ + if(src->field) { \ + d->field = strdup(src->field); \ + if(!d->field) \ + goto fail; \ + } \ + } while(0) + +static struct Cookie *dup_cookie(struct Cookie *src) +{ + struct Cookie *d = calloc(1, sizeof(struct Cookie)); + if(d) { + CLONE(domain); + CLONE(path); + CLONE(spath); + CLONE(name); + CLONE(value); + d->expires = src->expires; + d->tailmatch = src->tailmatch; + d->secure = src->secure; + d->livecookie = src->livecookie; + d->httponly = src->httponly; + d->creationtime = src->creationtime; + } + return d; + +fail: + freecookie(d); + return NULL; +} + +/* + * Curl_cookie_getlist + * + * For a given host and path, return a linked list of cookies that the client + * should send to the server if used now. The secure boolean informs the cookie + * if a secure connection is achieved or not. + * + * It shall only return cookies that haven't expired. + */ +struct Cookie *Curl_cookie_getlist(struct Curl_easy *data, + struct CookieInfo *c, + const char *host, const char *path, + bool secure) +{ + struct Cookie *newco; + struct Cookie *co; + struct Cookie *mainco = NULL; + size_t matches = 0; + bool is_ip; + const size_t myhash = cookiehash(host); + + if(!c || !c->cookies[myhash]) + return NULL; /* no cookie struct or no cookies in the struct */ + + /* at first, remove expired cookies */ + remove_expired(c); + + /* check if host is an IP(v4|v6) address */ + is_ip = Curl_host_is_ipnum(host); + + co = c->cookies[myhash]; + + while(co) { + /* if the cookie requires we're secure we must only continue if we are! */ + if(co->secure?secure:TRUE) { + + /* now check if the domain is correct */ + if(!co->domain || + (co->tailmatch && !is_ip && + cookie_tailmatch(co->domain, strlen(co->domain), host)) || + ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { + /* + * the right part of the host matches the domain stuff in the + * cookie data + */ + + /* + * now check the left part of the path with the cookies path + * requirement + */ + if(!co->spath || pathmatch(co->spath, path) ) { + + /* + * and now, we know this is a match and we should create an + * entry for the return-linked-list + */ + + newco = dup_cookie(co); + if(newco) { + /* then modify our next */ + newco->next = mainco; + + /* point the main to us */ + mainco = newco; + + matches++; + if(matches >= MAX_COOKIE_SEND_AMOUNT) { + infof(data, "Included max number of cookies (%zu) in request!", + matches); + break; + } + } + else + goto fail; + } + } + } + co = co->next; + } + + if(matches) { + /* + * Now we need to make sure that if there is a name appearing more than + * once, the longest specified path version comes first. To make this + * the swiftest way, we just sort them all based on path length. + */ + struct Cookie **array; + size_t i; + + /* alloc an array and store all cookie pointers */ + array = malloc(sizeof(struct Cookie *) * matches); + if(!array) + goto fail; + + co = mainco; + + for(i = 0; co; co = co->next) + array[i++] = co; + + /* now sort the cookie pointers in path length order */ + qsort(array, matches, sizeof(struct Cookie *), cookie_sort); + + /* remake the linked list order according to the new order */ + + mainco = array[0]; /* start here */ + for(i = 0; inext = array[i + 1]; + array[matches-1]->next = NULL; /* terminate the list */ + + free(array); /* remove the temporary data again */ + } + + return mainco; /* return the new list */ + +fail: + /* failure, clear up the allocated chain and return NULL */ + Curl_cookie_freelist(mainco); + return NULL; +} + +/* + * Curl_cookie_clearall + * + * Clear all existing cookies and reset the counter. + */ +void Curl_cookie_clearall(struct CookieInfo *cookies) +{ + if(cookies) { + unsigned int i; + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + Curl_cookie_freelist(cookies->cookies[i]); + cookies->cookies[i] = NULL; + } + cookies->numcookies = 0; + } +} + +/* + * Curl_cookie_freelist + * + * Free a list of cookies previously returned by Curl_cookie_getlist(); + */ +void Curl_cookie_freelist(struct Cookie *co) +{ + struct Cookie *next; + while(co) { + next = co->next; + freecookie(co); + co = next; + } +} + +/* + * Curl_cookie_clearsess + * + * Free all session cookies in the cookies list. + */ +void Curl_cookie_clearsess(struct CookieInfo *cookies) +{ + struct Cookie *first, *curr, *next, *prev = NULL; + unsigned int i; + + if(!cookies) + return; + + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + if(!cookies->cookies[i]) + continue; + + first = curr = prev = cookies->cookies[i]; + + for(; curr; curr = next) { + next = curr->next; + if(!curr->expires) { + if(first == curr) + first = next; + + if(prev == curr) + prev = next; + else + prev->next = next; + + freecookie(curr); + cookies->numcookies--; + } + else + prev = curr; + } + + cookies->cookies[i] = first; + } +} + +/* + * Curl_cookie_cleanup() + * + * Free a "cookie object" previous created with Curl_cookie_init(). + */ +void Curl_cookie_cleanup(struct CookieInfo *c) +{ + if(c) { + unsigned int i; + for(i = 0; i < COOKIE_HASH_SIZE; i++) + Curl_cookie_freelist(c->cookies[i]); + free(c); /* free the base struct as well */ + } +} + +/* + * get_netscape_format() + * + * Formats a string for Netscape output file, w/o a newline at the end. + * Function returns a char * to a formatted line. The caller is responsible + * for freeing the returned pointer. + */ +static char *get_netscape_format(const struct Cookie *co) +{ + return aprintf( + "%s" /* httponly preamble */ + "%s%s\t" /* domain */ + "%s\t" /* tailmatch */ + "%s\t" /* path */ + "%s\t" /* secure */ + "%" CURL_FORMAT_CURL_OFF_T "\t" /* expires */ + "%s\t" /* name */ + "%s", /* value */ + co->httponly?"#HttpOnly_":"", + /* + * Make sure all domains are prefixed with a dot if they allow + * tailmatching. This is Mozilla-style. + */ + (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"", + co->domain?co->domain:"unknown", + co->tailmatch?"TRUE":"FALSE", + co->path?co->path:"/", + co->secure?"TRUE":"FALSE", + co->expires, + co->name, + co->value?co->value:""); +} + +/* + * cookie_output() + * + * Writes all internally known cookies to the specified file. Specify + * "-" as file name to write to stdout. + * + * The function returns non-zero on write failure. + */ +static CURLcode cookie_output(struct Curl_easy *data, + struct CookieInfo *c, const char *filename) +{ + struct Cookie *co; + FILE *out = NULL; + bool use_stdout = FALSE; + char *tempstore = NULL; + CURLcode error = CURLE_OK; + + if(!c) + /* no cookie engine alive */ + return CURLE_OK; + + /* at first, remove expired cookies */ + remove_expired(c); + + if(!strcmp("-", filename)) { + /* use stdout */ + out = stdout; + use_stdout = TRUE; + } + else { + error = Curl_fopen(data, filename, &out, &tempstore); + if(error) + goto error; + } + + fputs("# Netscape HTTP Cookie File\n" + "# https://curl.se/docs/http-cookies.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n\n", + out); + + if(c->numcookies) { + unsigned int i; + size_t nvalid = 0; + struct Cookie **array; + + array = calloc(1, sizeof(struct Cookie *) * c->numcookies); + if(!array) { + error = CURLE_OUT_OF_MEMORY; + goto error; + } + + /* only sort the cookies with a domain property */ + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + for(co = c->cookies[i]; co; co = co->next) { + if(!co->domain) + continue; + array[nvalid++] = co; + } + } + + qsort(array, nvalid, sizeof(struct Cookie *), cookie_sort_ct); + + for(i = 0; i < nvalid; i++) { + char *format_ptr = get_netscape_format(array[i]); + if(!format_ptr) { + free(array); + error = CURLE_OUT_OF_MEMORY; + goto error; + } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); + } + + free(array); + } + + if(!use_stdout) { + fclose(out); + out = NULL; + if(tempstore && Curl_rename(tempstore, filename)) { + unlink(tempstore); + error = CURLE_WRITE_ERROR; + goto error; + } + } + + /* + * If we reach here we have successfully written a cookie file so there is + * no need to inspect the error, any error case should have jumped into the + * error block below. + */ + free(tempstore); + return CURLE_OK; + +error: + if(out && !use_stdout) + fclose(out); + free(tempstore); + return error; +} + +static struct curl_slist *cookie_list(struct Curl_easy *data) +{ + struct curl_slist *list = NULL; + struct curl_slist *beg; + struct Cookie *c; + char *line; + unsigned int i; + + if(!data->cookies || (data->cookies->numcookies == 0)) + return NULL; + + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + for(c = data->cookies->cookies[i]; c; c = c->next) { + if(!c->domain) + continue; + line = get_netscape_format(c); + if(!line) { + curl_slist_free_all(list); + return NULL; + } + beg = Curl_slist_append_nodup(list, line); + if(!beg) { + free(line); + curl_slist_free_all(list); + return NULL; + } + list = beg; + } + } + + return list; +} + +struct curl_slist *Curl_cookie_list(struct Curl_easy *data) +{ + struct curl_slist *list; + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + list = cookie_list(data); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + return list; +} + +void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) +{ + CURLcode res; + + if(data->set.str[STRING_COOKIEJAR]) { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + + /* if we have a destination file for all the cookies to get dumped to */ + res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]); + if(res) + infof(data, "WARNING: failed to save cookies in %s: %s", + data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res)); + } + else { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + } + + if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { + Curl_cookie_cleanup(data->cookies); + data->cookies = NULL; + } + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); +} + +#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */ diff --git a/lib/cookie.h b/lib/cookie.h new file mode 100644 index 0000000..012dd89 --- /dev/null +++ b/lib/cookie.h @@ -0,0 +1,138 @@ +#ifndef HEADER_CURL_COOKIE_H +#define HEADER_CURL_COOKIE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#include + +struct Cookie { + struct Cookie *next; /* next in the chain */ + char *name; /* = value */ + char *value; /* name = */ + char *path; /* path = which is in Set-Cookie: */ + char *spath; /* sanitized cookie path */ + char *domain; /* domain = */ + curl_off_t expires; /* expires = */ + bool tailmatch; /* whether we do tail-matching of the domain name */ + bool secure; /* whether the 'secure' keyword was used */ + bool livecookie; /* updated from a server, not a stored file */ + bool httponly; /* true if the httponly directive is present */ + int creationtime; /* time when the cookie was written */ + unsigned char prefix; /* bitmap fields indicating which prefix are set */ +}; + +/* + * Available cookie prefixes, as defined in + * draft-ietf-httpbis-rfc6265bis-02 + */ +#define COOKIE_PREFIX__SECURE (1<<0) +#define COOKIE_PREFIX__HOST (1<<1) + +#define COOKIE_HASH_SIZE 63 + +struct CookieInfo { + /* linked list of cookies we know of */ + struct Cookie *cookies[COOKIE_HASH_SIZE]; + curl_off_t next_expiration; /* the next time at which expiration happens */ + int numcookies; /* number of cookies in the "jar" */ + int lastct; /* last creation-time used in the jar */ + bool running; /* state info, for cookie adding information */ + bool newsession; /* new session, discard session cookies on load */ +}; + +/* The maximum sizes we accept for cookies. RFC 6265 section 6.1 says + "general-use user agents SHOULD provide each of the following minimum + capabilities": + + - At least 4096 bytes per cookie (as measured by the sum of the length of + the cookie's name, value, and attributes). + In the 6265bis draft document section 5.4 it is phrased even stronger: "If + the sum of the lengths of the name string and the value string is more than + 4096 octets, abort these steps and ignore the set-cookie-string entirely." +*/ + +/** Limits for INCOMING cookies **/ + +/* The longest we allow a line to be when reading a cookie from a HTTP header + or from a cookie jar */ +#define MAX_COOKIE_LINE 5000 + +/* Maximum length of an incoming cookie name or content we deal with. Longer + cookies are ignored. */ +#define MAX_NAME 4096 + +/* Maximum number of Set-Cookie: lines accepted in a single response. If more + such header lines are received, they are ignored. This value must be less + than 256 since an unsigned char is used to count. */ +#define MAX_SET_COOKIE_AMOUNT 50 + +/** Limits for OUTGOING cookies **/ + +/* Maximum size for an outgoing cookie line libcurl will use in an http + request. This is the default maximum length used in some versions of Apache + httpd. */ +#define MAX_COOKIE_HEADER_LEN 8190 + +/* Maximum number of cookies libcurl will send in a single request, even if + there might be more cookies that match. One reason to cap the number is to + keep the maximum HTTP request within the maximum allowed size. */ +#define MAX_COOKIE_SEND_AMOUNT 150 + +struct Curl_easy; +/* + * Add a cookie to the internal list of cookies. The domain and path arguments + * are only used if the header boolean is TRUE. + */ + +struct Cookie *Curl_cookie_add(struct Curl_easy *data, + struct CookieInfo *c, bool header, + bool noexpiry, const char *lineptr, + const char *domain, const char *path, + bool secure); + +struct Cookie *Curl_cookie_getlist(struct Curl_easy *data, + struct CookieInfo *c, const char *host, + const char *path, bool secure); +void Curl_cookie_freelist(struct Cookie *cookies); +void Curl_cookie_clearall(struct CookieInfo *cookies); +void Curl_cookie_clearsess(struct CookieInfo *cookies); + +#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) +#define Curl_cookie_list(x) NULL +#define Curl_cookie_loadfiles(x) Curl_nop_stmt +#define Curl_cookie_init(x,y,z,w) NULL +#define Curl_cookie_cleanup(x) Curl_nop_stmt +#define Curl_flush_cookies(x,y) Curl_nop_stmt +#else +void Curl_flush_cookies(struct Curl_easy *data, bool cleanup); +void Curl_cookie_cleanup(struct CookieInfo *c); +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, + const char *file, struct CookieInfo *inc, + bool newsession); +struct curl_slist *Curl_cookie_list(struct Curl_easy *data); +void Curl_cookie_loadfiles(struct Curl_easy *data); +#endif + +#endif /* HEADER_CURL_COOKIE_H */ diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c new file mode 100644 index 0000000..f9211d3 --- /dev/null +++ b/lib/curl_addrinfo.c @@ -0,0 +1,592 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETINET_IN6_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_SYS_UN_H +# include +#endif + +#ifdef __VMS +# include +# include +#endif + +#include + +#include "curl_addrinfo.h" +#include "inet_pton.h" +#include "warnless.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_freeaddrinfo() + * + * This is used to free a linked list of Curl_addrinfo structs along + * with all its associated allocated storage. This function should be + * called once for each successful call to Curl_getaddrinfo_ex() or to + * any function call which actually allocates a Curl_addrinfo struct. + */ + +#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ + defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) + /* workaround icc 9.1 optimizer issue */ +# define vqualifier volatile +#else +# define vqualifier +#endif + +void +Curl_freeaddrinfo(struct Curl_addrinfo *cahead) +{ + struct Curl_addrinfo *vqualifier canext; + struct Curl_addrinfo *ca; + + for(ca = cahead; ca; ca = canext) { + canext = ca->ai_next; + free(ca); + } +} + + +#ifdef HAVE_GETADDRINFO +/* + * Curl_getaddrinfo_ex() + * + * This is a wrapper function around system's getaddrinfo(), with + * the only difference that instead of returning a linked list of + * addrinfo structs this one returns a linked list of Curl_addrinfo + * ones. The memory allocated by this function *MUST* be free'd with + * Curl_freeaddrinfo(). For each successful call to this function + * there must be an associated call later to Curl_freeaddrinfo(). + * + * There should be no single call to system's getaddrinfo() in the + * whole library, any such call should be 'routed' through this one. + */ + +int +Curl_getaddrinfo_ex(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct Curl_addrinfo **result) +{ + const struct addrinfo *ai; + struct addrinfo *aihead; + struct Curl_addrinfo *cafirst = NULL; + struct Curl_addrinfo *calast = NULL; + struct Curl_addrinfo *ca; + size_t ss_size; + int error; + + *result = NULL; /* assume failure */ + + error = getaddrinfo(nodename, servname, hints, &aihead); + if(error) + return error; + + /* traverse the addrinfo list */ + + for(ai = aihead; ai != NULL; ai = ai->ai_next) { + size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0; + /* ignore elements with unsupported address family, */ + /* settle family-specific sockaddr structure size. */ + if(ai->ai_family == AF_INET) + ss_size = sizeof(struct sockaddr_in); +#ifdef ENABLE_IPV6 + else if(ai->ai_family == AF_INET6) + ss_size = sizeof(struct sockaddr_in6); +#endif + else + continue; + + /* ignore elements without required address info */ + if(!ai->ai_addr || !(ai->ai_addrlen > 0)) + continue; + + /* ignore elements with bogus address size */ + if((size_t)ai->ai_addrlen < ss_size) + continue; + + ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen); + if(!ca) { + error = EAI_MEMORY; + break; + } + + /* copy each structure member individually, member ordering, */ + /* size, or padding might be different for each platform. */ + + ca->ai_flags = ai->ai_flags; + ca->ai_family = ai->ai_family; + ca->ai_socktype = ai->ai_socktype; + ca->ai_protocol = ai->ai_protocol; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_addr = NULL; + ca->ai_canonname = NULL; + ca->ai_next = NULL; + + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, ai->ai_addr, ss_size); + + if(namelen) { + ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size); + memcpy(ca->ai_canonname, ai->ai_canonname, namelen); + } + + /* if the return list is empty, this becomes the first element */ + if(!cafirst) + cafirst = ca; + + /* add this element last in the return list */ + if(calast) + calast->ai_next = ca; + calast = ca; + + } + + /* destroy the addrinfo list */ + if(aihead) + freeaddrinfo(aihead); + + /* if we failed, also destroy the Curl_addrinfo list */ + if(error) { + Curl_freeaddrinfo(cafirst); + cafirst = NULL; + } + else if(!cafirst) { +#ifdef EAI_NONAME + /* rfc3493 conformant */ + error = EAI_NONAME; +#else + /* rfc3493 obsoleted */ + error = EAI_NODATA; +#endif +#ifdef USE_WINSOCK + SET_SOCKERRNO(error); +#endif + } + + *result = cafirst; + + /* This is not a CURLcode */ + return error; +} +#endif /* HAVE_GETADDRINFO */ + + +/* + * Curl_he2ai() + * + * This function returns a pointer to the first element of a newly allocated + * Curl_addrinfo struct linked list filled with the data of a given hostent. + * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6 + * stack, but usable also for IPv4, all hosts and environments. + * + * The memory allocated by this function *MUST* be free'd later on calling + * Curl_freeaddrinfo(). For each successful call to this function there + * must be an associated call later to Curl_freeaddrinfo(). + * + * Curl_addrinfo defined in "lib/curl_addrinfo.h" + * + * struct Curl_addrinfo { + * int ai_flags; + * int ai_family; + * int ai_socktype; + * int ai_protocol; + * curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo * + * char *ai_canonname; + * struct sockaddr *ai_addr; + * struct Curl_addrinfo *ai_next; + * }; + * + * hostent defined in + * + * struct hostent { + * char *h_name; + * char **h_aliases; + * int h_addrtype; + * int h_length; + * char **h_addr_list; + * }; + * + * for backward compatibility: + * + * #define h_addr h_addr_list[0] + */ + +struct Curl_addrinfo * +Curl_he2ai(const struct hostent *he, int port) +{ + struct Curl_addrinfo *ai; + struct Curl_addrinfo *prevai = NULL; + struct Curl_addrinfo *firstai = NULL; + struct sockaddr_in *addr; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *addr6; +#endif + CURLcode result = CURLE_OK; + int i; + char *curr; + + if(!he) + /* no input == no output! */ + return NULL; + + DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL)); + + for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { + size_t ss_size; + size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */ +#ifdef ENABLE_IPV6 + if(he->h_addrtype == AF_INET6) + ss_size = sizeof(struct sockaddr_in6); + else +#endif + ss_size = sizeof(struct sockaddr_in); + + /* allocate memory to hold the struct, the address and the name */ + ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen); + if(!ai) { + result = CURLE_OUT_OF_MEMORY; + break; + } + /* put the address after the struct */ + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + /* then put the name after the address */ + ai->ai_canonname = (char *)ai->ai_addr + ss_size; + memcpy(ai->ai_canonname, he->h_name, namelen); + + if(!firstai) + /* store the pointer we want to return from this function */ + firstai = ai; + + if(prevai) + /* make the previous entry point to this */ + prevai->ai_next = ai; + + ai->ai_family = he->h_addrtype; + + /* we return all names as STREAM, so when using this address for TFTP + the type must be ignored and conn->socktype be used instead! */ + ai->ai_socktype = SOCK_STREAM; + + ai->ai_addrlen = (curl_socklen_t)ss_size; + + /* leave the rest of the struct filled with zero */ + + switch(ai->ai_family) { + case AF_INET: + addr = (void *)ai->ai_addr; /* storage area for this info */ + + memcpy(&addr->sin_addr, curr, sizeof(struct in_addr)); + addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype); + addr->sin_port = htons((unsigned short)port); + break; + +#ifdef ENABLE_IPV6 + case AF_INET6: + addr6 = (void *)ai->ai_addr; /* storage area for this info */ + + memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr)); + addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype); + addr6->sin6_port = htons((unsigned short)port); + break; +#endif + } + + prevai = ai; + } + + if(result) { + Curl_freeaddrinfo(firstai); + firstai = NULL; + } + + return firstai; +} + + +struct namebuff { + struct hostent hostentry; + union { + struct in_addr ina4; +#ifdef ENABLE_IPV6 + struct in6_addr ina6; +#endif + } addrentry; + char *h_addr_list[2]; +}; + + +/* + * Curl_ip2addr() + * + * This function takes an internet address, in binary form, as input parameter + * along with its address family and the string version of the address, and it + * returns a Curl_addrinfo chain filled in correctly with information for the + * given address/host + */ + +struct Curl_addrinfo * +Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) +{ + struct Curl_addrinfo *ai; + +#if defined(__VMS) && \ + defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) +#pragma pointer_size save +#pragma pointer_size short +#pragma message disable PTRMISMATCH +#endif + + struct hostent *h; + struct namebuff *buf; + char *addrentry; + char *hoststr; + size_t addrsize; + + DEBUGASSERT(inaddr && hostname); + + buf = malloc(sizeof(struct namebuff)); + if(!buf) + return NULL; + + hoststr = strdup(hostname); + if(!hoststr) { + free(buf); + return NULL; + } + + switch(af) { + case AF_INET: + addrsize = sizeof(struct in_addr); + addrentry = (void *)&buf->addrentry.ina4; + memcpy(addrentry, inaddr, sizeof(struct in_addr)); + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + addrsize = sizeof(struct in6_addr); + addrentry = (void *)&buf->addrentry.ina6; + memcpy(addrentry, inaddr, sizeof(struct in6_addr)); + break; +#endif + default: + free(hoststr); + free(buf); + return NULL; + } + + h = &buf->hostentry; + h->h_name = hoststr; + h->h_aliases = NULL; + h->h_addrtype = (short)af; + h->h_length = (short)addrsize; + h->h_addr_list = &buf->h_addr_list[0]; + h->h_addr_list[0] = addrentry; + h->h_addr_list[1] = NULL; /* terminate list of entries */ + +#if defined(__VMS) && \ + defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) +#pragma pointer_size restore +#pragma message enable PTRMISMATCH +#endif + + ai = Curl_he2ai(h, port); + + free(hoststr); + free(buf); + + return ai; +} + +/* + * Given an IPv4 or IPv6 dotted string address, this converts it to a proper + * allocated Curl_addrinfo struct and returns it. + */ +struct Curl_addrinfo *Curl_str2addr(char *address, int port) +{ + struct in_addr in; + if(Curl_inet_pton(AF_INET, address, &in) > 0) + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(AF_INET, &in, address, port); +#ifdef ENABLE_IPV6 + { + struct in6_addr in6; + if(Curl_inet_pton(AF_INET6, address, &in6) > 0) + /* This is a dotted IPv6 address ::1-style */ + return Curl_ip2addr(AF_INET6, &in6, address, port); + } +#endif + return NULL; /* bad input format */ +} + +#ifdef USE_UNIX_SOCKETS +/** + * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo + * struct initialized with this path. + * Set '*longpath' to TRUE if the error is a too long path. + */ +struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, + bool abstract) +{ + struct Curl_addrinfo *ai; + struct sockaddr_un *sa_un; + size_t path_len; + + *longpath = FALSE; + + ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un)); + if(!ai) + return NULL; + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + + sa_un = (void *) ai->ai_addr; + sa_un->sun_family = AF_UNIX; + + /* sun_path must be able to store the NUL-terminated path */ + path_len = strlen(path) + 1; + if(path_len > sizeof(sa_un->sun_path)) { + free(ai); + *longpath = TRUE; + return NULL; + } + + ai->ai_family = AF_UNIX; + ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ + ai->ai_addrlen = (curl_socklen_t) + ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF); + + /* Abstract Unix domain socket have NULL prefix instead of suffix */ + if(abstract) + memcpy(sa_un->sun_path + 1, path, path_len - 1); + else + memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */ + + return ai; +} +#endif + +#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ + defined(HAVE_FREEADDRINFO) +/* + * curl_dbg_freeaddrinfo() + * + * This is strictly for memory tracing and are using the same style as the + * family otherwise present in memdebug.c. I put these ones here since they + * require a bunch of structs I didn't want to include in memdebug.c + */ + +void +curl_dbg_freeaddrinfo(struct addrinfo *freethis, + int line, const char *source) +{ + curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n", + source, line, (void *)freethis); +#ifdef USE_LWIPSOCK + lwip_freeaddrinfo(freethis); +#else + (freeaddrinfo)(freethis); +#endif +} +#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */ + + +#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) +/* + * curl_dbg_getaddrinfo() + * + * This is strictly for memory tracing and are using the same style as the + * family otherwise present in memdebug.c. I put these ones here since they + * require a bunch of structs I didn't want to include in memdebug.c + */ + +int +curl_dbg_getaddrinfo(const char *hostname, + const char *service, + const struct addrinfo *hints, + struct addrinfo **result, + int line, const char *source) +{ +#ifdef USE_LWIPSOCK + int res = lwip_getaddrinfo(hostname, service, hints, result); +#else + int res = (getaddrinfo)(hostname, service, hints, result); +#endif + if(0 == res) + /* success */ + curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n", + source, line, (void *)*result); + else + curl_dbg_log("ADDR %s:%d getaddrinfo() failed\n", + source, line); + return res; +} +#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ + +#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS) +/* + * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X + * 10.11.5. + */ +void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port) +{ + struct Curl_addrinfo *ca; + struct sockaddr_in *addr; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *addr6; +#endif + for(ca = addrinfo; ca != NULL; ca = ca->ai_next) { + switch(ca->ai_family) { + case AF_INET: + addr = (void *)ca->ai_addr; /* storage area for this info */ + addr->sin_port = htons((unsigned short)port); + break; + +#ifdef ENABLE_IPV6 + case AF_INET6: + addr6 = (void *)ca->ai_addr; /* storage area for this info */ + addr6->sin6_port = htons((unsigned short)port); + break; +#endif + } + } +} +#endif diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h new file mode 100644 index 0000000..c757c49 --- /dev/null +++ b/lib/curl_addrinfo.h @@ -0,0 +1,108 @@ +#ifndef HEADER_CURL_ADDRINFO_H +#define HEADER_CURL_ADDRINFO_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#ifdef __VMS +# include +# include +# include +#endif + +/* + * Curl_addrinfo is our internal struct definition that we use to allow + * consistent internal handling of this data. We use this even when the + * system provides an addrinfo structure definition. And we use this for + * all sorts of IPv4 and IPV6 builds. + */ + +struct Curl_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + curl_socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */ + char *ai_canonname; + struct sockaddr *ai_addr; + struct Curl_addrinfo *ai_next; +}; + +void +Curl_freeaddrinfo(struct Curl_addrinfo *cahead); + +#ifdef HAVE_GETADDRINFO +int +Curl_getaddrinfo_ex(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct Curl_addrinfo **result); +#endif + +struct Curl_addrinfo * +Curl_he2ai(const struct hostent *he, int port); + +struct Curl_addrinfo * +Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); + +struct Curl_addrinfo *Curl_str2addr(char *dotted, int port); + +#ifdef USE_UNIX_SOCKETS +struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, + bool abstract); +#endif + +#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ + defined(HAVE_FREEADDRINFO) +void +curl_dbg_freeaddrinfo(struct addrinfo *freethis, int line, const char *source); +#endif + +#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) +int +curl_dbg_getaddrinfo(const char *hostname, const char *service, + const struct addrinfo *hints, struct addrinfo **result, + int line, const char *source); +#endif + +#ifdef HAVE_GETADDRINFO +#ifdef USE_RESOLVE_ON_IPS +void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port); +#else +#define Curl_addrinfo_set_port(x,y) +#endif +#endif + +#endif /* HEADER_CURL_ADDRINFO_H */ diff --git a/lib/curl_base64.h b/lib/curl_base64.h new file mode 100644 index 0000000..7f7cd1d --- /dev/null +++ b/lib/curl_base64.h @@ -0,0 +1,41 @@ +#ifndef HEADER_CURL_BASE64_H +#define HEADER_CURL_BASE64_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifndef BUILDING_LIBCURL +/* this renames functions so that the tool code can use the same code + without getting symbol collisions */ +#define Curl_base64_encode(a,b,c,d) curlx_base64_encode(a,b,c,d) +#define Curl_base64url_encode(a,b,c,d) curlx_base64url_encode(a,b,c,d) +#define Curl_base64_decode(a,b,c) curlx_base64_decode(a,b,c) +#endif + +CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, + char **outptr, size_t *outlen); +CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize, + char **outptr, size_t *outlen); +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen); +#endif /* HEADER_CURL_BASE64_H */ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake new file mode 100644 index 0000000..937b93e --- /dev/null +++ b/lib/curl_config.h.cmake @@ -0,0 +1,795 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* lib/curl_config.h.in. Generated somehow by cmake. */ + +/* Location of default ca bundle */ +#cmakedefine CURL_CA_BUNDLE "${CURL_CA_BUNDLE}" + +/* define "1" to use built-in ca store of TLS backend */ +#cmakedefine CURL_CA_FALLBACK 1 + +/* Location of default ca path */ +#cmakedefine CURL_CA_PATH "${CURL_CA_PATH}" + +/* Default SSL backend */ +#cmakedefine CURL_DEFAULT_SSL_BACKEND "${CURL_DEFAULT_SSL_BACKEND}" + +/* disables alt-svc */ +#cmakedefine CURL_DISABLE_ALTSVC 1 + +/* disables cookies support */ +#cmakedefine CURL_DISABLE_COOKIES 1 + +/* disables Basic authentication */ +#cmakedefine CURL_DISABLE_BASIC_AUTH 1 + +/* disables Bearer authentication */ +#cmakedefine CURL_DISABLE_BEARER_AUTH 1 + +/* disables Digest authentication */ +#cmakedefine CURL_DISABLE_DIGEST_AUTH 1 + +/* disables Kerberos authentication */ +#cmakedefine CURL_DISABLE_KERBEROS_AUTH 1 + +/* disables negotiate authentication */ +#cmakedefine CURL_DISABLE_NEGOTIATE_AUTH 1 + +/* disables AWS-SIG4 */ +#cmakedefine CURL_DISABLE_AWS 1 + +/* disables DICT */ +#cmakedefine CURL_DISABLE_DICT 1 + +/* disables DNS-over-HTTPS */ +#cmakedefine CURL_DISABLE_DOH 1 + +/* disables FILE */ +#cmakedefine CURL_DISABLE_FILE 1 + +/* disables form api */ +#cmakedefine CURL_DISABLE_FORM_API 1 + +/* disables FTP */ +#cmakedefine CURL_DISABLE_FTP 1 + +/* disables curl_easy_options API for existing options to curl_easy_setopt */ +#cmakedefine CURL_DISABLE_GETOPTIONS 1 + +/* disables GOPHER */ +#cmakedefine CURL_DISABLE_GOPHER 1 + +/* disables headers-api support */ +#cmakedefine CURL_DISABLE_HEADERS_API 1 + +/* disables HSTS support */ +#cmakedefine CURL_DISABLE_HSTS 1 + +/* disables HTTP */ +#cmakedefine CURL_DISABLE_HTTP 1 + +/* disables IMAP */ +#cmakedefine CURL_DISABLE_IMAP 1 + +/* disables LDAP */ +#cmakedefine CURL_DISABLE_LDAP 1 + +/* disables LDAPS */ +#cmakedefine CURL_DISABLE_LDAPS 1 + +/* disables --libcurl option from the curl tool */ +#cmakedefine CURL_DISABLE_LIBCURL_OPTION 1 + +/* disables MIME support */ +#cmakedefine CURL_DISABLE_MIME 1 + +/* disables local binding support */ +#cmakedefine CURL_DISABLE_BINDLOCAL 1 + +/* disables MQTT */ +#cmakedefine CURL_DISABLE_MQTT 1 + +/* disables netrc parser */ +#cmakedefine CURL_DISABLE_NETRC 1 + +/* disables NTLM support */ +#cmakedefine CURL_DISABLE_NTLM 1 + +/* disables date parsing */ +#cmakedefine CURL_DISABLE_PARSEDATE 1 + +/* disables POP3 */ +#cmakedefine CURL_DISABLE_POP3 1 + +/* disables built-in progress meter */ +#cmakedefine CURL_DISABLE_PROGRESS_METER 1 + +/* disables proxies */ +#cmakedefine CURL_DISABLE_PROXY 1 + +/* disables RTSP */ +#cmakedefine CURL_DISABLE_RTSP 1 + +/* disables SMB */ +#cmakedefine CURL_DISABLE_SMB 1 + +/* disables SMTP */ +#cmakedefine CURL_DISABLE_SMTP 1 + +/* disables use of socketpair for curl_multi_poll */ +#cmakedefine CURL_DISABLE_SOCKETPAIR 1 + +/* disables TELNET */ +#cmakedefine CURL_DISABLE_TELNET 1 + +/* disables TFTP */ +#cmakedefine CURL_DISABLE_TFTP 1 + +/* disables verbose strings */ +#cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 + +/* to make a symbol visible */ +#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL} +/* Ensure using CURL_EXTERN_SYMBOL is possible */ +#ifndef CURL_EXTERN_SYMBOL +#define CURL_EXTERN_SYMBOL +#endif + +/* Allow SMB to work on Windows */ +#cmakedefine USE_WIN32_CRYPTO 1 + +/* Use Windows LDAP implementation */ +#cmakedefine USE_WIN32_LDAP 1 + +/* Define if you want to enable IPv6 support */ +#cmakedefine ENABLE_IPV6 1 + +/* Define to 1 if you have the alarm function. */ +#cmakedefine HAVE_ALARM 1 + +/* Define to 1 if you have the arc4random function. */ +#cmakedefine HAVE_ARC4RANDOM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have _Atomic support. */ +#cmakedefine HAVE_ATOMIC 1 + +/* Define to 1 if you have the `fnmatch' function. */ +#cmakedefine HAVE_FNMATCH 1 + +/* Define to 1 if you have the `basename' function. */ +#cmakedefine HAVE_BASENAME 1 + +/* Define to 1 if bool is an available type. */ +#cmakedefine HAVE_BOOL_T 1 + +/* Define to 1 if you have the __builtin_available function. */ +#cmakedefine HAVE_BUILTIN_AVAILABLE 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have the clock_gettime function and raw monotonic timer. + */ +#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1 + +/* Define to 1 if you have the `closesocket' function. */ +#cmakedefine HAVE_CLOSESOCKET 1 + +/* Define to 1 if you have the fcntl function. */ +#cmakedefine HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#cmakedefine HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#cmakedefine HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have the fseeko function. */ +#cmakedefine HAVE_FSEEKO 1 + +/* Define to 1 if you have the fseeko declaration. */ +#cmakedefine HAVE_DECL_FSEEKO 1 + +/* Define to 1 if you have the _fseeki64 function. */ +#cmakedefine HAVE__FSEEKI64 1 + +/* Define to 1 if you have the ftruncate function. */ +#cmakedefine HAVE_FTRUNCATE 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#cmakedefine HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#cmakedefine HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the `geteuid' function. */ +#cmakedefine HAVE_GETEUID 1 + +/* Define to 1 if you have the `getppid' function. */ +#cmakedefine HAVE_GETPPID 1 + +/* Define to 1 if you have the gethostbyname_r function. */ +#cmakedefine HAVE_GETHOSTBYNAME_R 1 + +/* gethostbyname_r() takes 3 args */ +#cmakedefine HAVE_GETHOSTBYNAME_R_3 1 + +/* gethostbyname_r() takes 5 args */ +#cmakedefine HAVE_GETHOSTBYNAME_R_5 1 + +/* gethostbyname_r() takes 6 args */ +#cmakedefine HAVE_GETHOSTBYNAME_R_6 1 + +/* Define to 1 if you have the gethostname function. */ +#cmakedefine HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have a working getifaddrs function. */ +#cmakedefine HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the `getpass_r' function. */ +#cmakedefine HAVE_GETPASS_R 1 + +/* Define to 1 if you have the `getpeername' function. */ +#cmakedefine HAVE_GETPEERNAME 1 + +/* Define to 1 if you have the `getsockname' function. */ +#cmakedefine HAVE_GETSOCKNAME 1 + +/* Define to 1 if you have the `if_nametoindex' function. */ +#cmakedefine HAVE_IF_NAMETOINDEX 1 + +/* Define to 1 if you have the `getpwuid' function. */ +#cmakedefine HAVE_GETPWUID 1 + +/* Define to 1 if you have the `getpwuid_r' function. */ +#cmakedefine HAVE_GETPWUID_R 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#cmakedefine HAVE_GETRLIMIT 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have a working glibc-style strerror_r function. */ +#cmakedefine HAVE_GLIBC_STRERROR_R 1 + +/* Define to 1 if you have a working gmtime_r function. */ +#cmakedefine HAVE_GMTIME_R 1 + +/* if you have the gssapi libraries */ +#cmakedefine HAVE_GSSAPI 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_GSSAPI_GSSAPI_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1 + +/* if you have the GNU gssapi libraries */ +#cmakedefine HAVE_GSSGNU 1 + +/* Define to 1 if you have the `idna_strerror' function. */ +#cmakedefine HAVE_IDNA_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IFADDRS_H 1 + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#cmakedefine HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#cmakedefine HAVE_INET_PTON 1 + +/* Define to 1 if symbol `sa_family_t' exists */ +#cmakedefine HAVE_SA_FAMILY_T 1 + +/* Define to 1 if symbol `ADDRESS_FAMILY' exists */ +#cmakedefine HAVE_ADDRESS_FAMILY 1 + +/* Define to 1 if you have the ioctlsocket function. */ +#cmakedefine HAVE_IOCTLSOCKET 1 + +/* Define to 1 if you have the IoctlSocket camel case function. */ +#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1 + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1 + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +#cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1 + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#cmakedefine HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#cmakedefine HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IO_H 1 + +/* Define to 1 if you have the lber.h header file. */ +#cmakedefine HAVE_LBER_H 1 + +/* Define to 1 if you have the ldap.h header file. */ +#cmakedefine HAVE_LDAP_H 1 + +/* Use LDAPS implementation */ +#cmakedefine HAVE_LDAP_SSL 1 + +/* Define to 1 if you have the ldap_ssl.h header file. */ +#cmakedefine HAVE_LDAP_SSL_H 1 + +/* Define to 1 if you have the `ldap_url_parse' function. */ +#cmakedefine HAVE_LDAP_URL_PARSE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBGEN_H 1 + +/* Define to 1 if you have the `idn2' library (-lidn2). */ +#cmakedefine HAVE_LIBIDN2 1 + +/* Define to 1 if you have the idn2.h header file. */ +#cmakedefine HAVE_IDN2_H 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#cmakedefine HAVE_LIBSOCKET 1 + +/* Define to 1 if you have the `ssh2' library (-lssh2). */ +#cmakedefine HAVE_LIBSSH2 1 + +/* if zlib is available */ +#cmakedefine HAVE_LIBZ 1 + +/* if brotli is available */ +#cmakedefine HAVE_BROTLI 1 + +/* if zstd is available */ +#cmakedefine HAVE_ZSTD 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LOCALE_H 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#cmakedefine HAVE_LONGLONG 1 + +/* Define to 1 if you have the 'suseconds_t' data type. */ +#cmakedefine HAVE_SUSECONDS_T 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +#cmakedefine HAVE_MSG_NOSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_UDP_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LINUX_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_IF_H 1 + +/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ +#cmakedefine HAVE_OLD_GSSMIT 1 + +/* Define to 1 if you have the `pipe' function. */ +#cmakedefine HAVE_PIPE 1 + +/* If you have a fine poll */ +#cmakedefine HAVE_POLL_FINE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_POLL_H 1 + +/* Define to 1 if you have a working POSIX-style strerror_r function. */ +#cmakedefine HAVE_POSIX_STRERROR_R 1 + +/* Define to 1 if you have the header file */ +#cmakedefine HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PWD_H 1 + +/* Define to 1 if OpenSSL has the `SSL_set0_wbio` function. */ +#cmakedefine HAVE_SSL_SET0_WBIO 1 + +/* Define to 1 if you have the recv function. */ +#cmakedefine HAVE_RECV 1 + +/* Define to 1 if you have the select function. */ +#cmakedefine HAVE_SELECT 1 + +/* Define to 1 if you have the sched_yield function. */ +#cmakedefine HAVE_SCHED_YIELD 1 + +/* Define to 1 if you have the send function. */ +#cmakedefine HAVE_SEND 1 + +/* Define to 1 if you have the sendmsg function. */ +#cmakedefine HAVE_SENDMSG 1 + +/* Define to 1 if you have the 'fsetxattr' function. */ +#cmakedefine HAVE_FSETXATTR 1 + +/* fsetxattr() takes 5 args */ +#cmakedefine HAVE_FSETXATTR_5 1 + +/* fsetxattr() takes 6 args */ +#cmakedefine HAVE_FSETXATTR_6 1 + +/* Define to 1 if you have the `setlocale' function. */ +#cmakedefine HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setmode' function. */ +#cmakedefine HAVE_SETMODE 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#cmakedefine HAVE_SETRLIMIT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1 + +/* Define to 1 if you have the sigaction function. */ +#cmakedefine HAVE_SIGACTION 1 + +/* Define to 1 if you have the siginterrupt function. */ +#cmakedefine HAVE_SIGINTERRUPT 1 + +/* Define to 1 if you have the signal function. */ +#cmakedefine HAVE_SIGNAL 1 + +/* Define to 1 if you have the sigsetjmp function or macro. */ +#cmakedefine HAVE_SIGSETJMP 1 + +/* Define to 1 if you have the `snprintf' function. */ +#cmakedefine HAVE_SNPRINTF 1 + +/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ +#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the `socket' function. */ +#cmakedefine HAVE_SOCKET 1 + +/* Define to 1 if you have the socketpair function. */ +#cmakedefine HAVE_SOCKETPAIR 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDATOMIC_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#cmakedefine HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +#cmakedefine HAVE_STRCMPI 1 + +/* Define to 1 if you have the strdup function. */ +#cmakedefine HAVE_STRDUP 1 + +/* Define to 1 if you have the strerror_r function. */ +#cmakedefine HAVE_STRERROR_R 1 + +/* Define to 1 if you have the stricmp function. */ +#cmakedefine HAVE_STRICMP 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STROPTS_H 1 + +/* Define to 1 if you have the strtok_r function. */ +#cmakedefine HAVE_STRTOK_R 1 + +/* Define to 1 if you have the strtoll function. */ +#cmakedefine HAVE_STRTOLL 1 + +/* Define to 1 if you have the memrchr function. */ +#cmakedefine HAVE_MEMRCHR 1 + +/* if struct sockaddr_storage is defined */ +#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#cmakedefine HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_FILIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_UN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_UTIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TERMIOS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TERMIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `utime' function. */ +#cmakedefine HAVE_UTIME 1 + +/* Define to 1 if you have the `utimes' function. */ +#cmakedefine HAVE_UTIMES 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UTIME_H 1 + +/* Define this symbol if your OS supports changing the contents of argv */ +#cmakedefine HAVE_WRITABLE_ARGV 1 + +/* Define to 1 if you need the lber.h header file even with ldap.h */ +#cmakedefine NEED_LBER_H 1 + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +#cmakedefine NEED_MALLOC_H 1 + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +#cmakedefine NEED_REENTRANT 1 + +/* cpu-machine-OS */ +#cmakedefine OS ${OS} + +/* Name of package */ +#cmakedefine PACKAGE ${PACKAGE} + +/* Define to the address where bug reports for this package should be sent. */ +#cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT} + +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME ${PACKAGE_NAME} + +/* Define to the full name and version of this package. */ +#cmakedefine PACKAGE_STRING ${PACKAGE_STRING} + +/* Define to the one symbol short name of this package. */ +#cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME} + +/* Define to the version of this package. */ +#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION} + +/* a suitable file to read random data from */ +#cmakedefine RANDOM_FILE "${RANDOM_FILE}" + +/* + Note: SIZEOF_* variables are fetched with CMake through check_type_size(). + As per CMake documentation on CheckTypeSize, C preprocessor code is + generated by CMake into SIZEOF_*_CODE. This is what we use in the + following statements. + + Reference: https://cmake.org/cmake/help/latest/module/CheckTypeSize.html +*/ + +/* The size of `int', as computed by sizeof. */ +${SIZEOF_INT_CODE} + +/* The size of `long', as computed by sizeof. */ +${SIZEOF_LONG_CODE} + +/* The size of `long long', as computed by sizeof. */ +${SIZEOF_LONG_LONG_CODE} + +/* The size of `off_t', as computed by sizeof. */ +${SIZEOF_OFF_T_CODE} + +/* The size of `curl_off_t', as computed by sizeof. */ +${SIZEOF_CURL_OFF_T_CODE} + +/* The size of `curl_socket_t', as computed by sizeof. */ +${SIZEOF_CURL_SOCKET_T_CODE} + +/* The size of `size_t', as computed by sizeof. */ +${SIZEOF_SIZE_T_CODE} + +/* The size of `time_t', as computed by sizeof. */ +${SIZEOF_TIME_T_CODE} + +/* Define to 1 if you have the ANSI C header files. */ +#cmakedefine STDC_HEADERS 1 + +/* Define if you want to enable c-ares support */ +#cmakedefine USE_ARES 1 + +/* Define if you want to enable POSIX threaded DNS lookup */ +#cmakedefine USE_THREADS_POSIX 1 + +/* Define if you want to enable WIN32 threaded DNS lookup */ +#cmakedefine USE_THREADS_WIN32 1 + +/* if GnuTLS is enabled */ +#cmakedefine USE_GNUTLS 1 + +/* if Secure Transport is enabled */ +#cmakedefine USE_SECTRANSP 1 + +/* if mbedTLS is enabled */ +#cmakedefine USE_MBEDTLS 1 + +/* if BearSSL is enabled */ +#cmakedefine USE_BEARSSL 1 + +/* if WolfSSL is enabled */ +#cmakedefine USE_WOLFSSL 1 + +/* if libSSH is in use */ +#cmakedefine USE_LIBSSH 1 + +/* if libSSH2 is in use */ +#cmakedefine USE_LIBSSH2 1 + +/* if libPSL is in use */ +#cmakedefine USE_LIBPSL 1 + +/* if you want to use OpenLDAP code instead of legacy ldap implementation */ +#cmakedefine USE_OPENLDAP 1 + +/* if OpenSSL is in use */ +#cmakedefine USE_OPENSSL 1 + +/* Define to 1 if you don't want the OpenSSL configuration to be loaded + automatically */ +#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1 + +/* to enable NGHTTP2 */ +#cmakedefine USE_NGHTTP2 1 + +/* to enable NGTCP2 */ +#cmakedefine USE_NGTCP2 1 + +/* to enable NGHTTP3 */ +#cmakedefine USE_NGHTTP3 1 + +/* to enable quiche */ +#cmakedefine USE_QUICHE 1 + +/* Define to 1 if you have the quiche_conn_set_qlog_fd function. */ +#cmakedefine HAVE_QUICHE_CONN_SET_QLOG_FD 1 + +/* to enable msh3 */ +#cmakedefine USE_MSH3 1 + +/* if Unix domain sockets are enabled */ +#cmakedefine USE_UNIX_SOCKETS 1 + +/* Define to 1 if you are building a Windows target with large file support. */ +#cmakedefine USE_WIN32_LARGE_FILES 1 + +/* to enable SSPI support */ +#cmakedefine USE_WINDOWS_SSPI 1 + +/* to enable Windows SSL */ +#cmakedefine USE_SCHANNEL 1 + +/* enable multiple SSL backends */ +#cmakedefine CURL_WITH_MULTI_SSL 1 + +/* Version number of package */ +#cmakedefine VERSION ${VERSION} + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS} + +/* Define for large files, on AIX-style hosts. */ +#cmakedefine _LARGE_FILES ${_LARGE_FILES} + +/* define this if you need it to compile thread-safe code */ +#cmakedefine _THREAD_SAFE ${_THREAD_SAFE} + +/* Define to empty if `const' does not conform to ANSI C. */ +#cmakedefine const ${const} + +/* Type to use in place of in_addr_t when system does not provide it. */ +#cmakedefine in_addr_t ${in_addr_t} + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#cmakedefine size_t ${size_t} + +/* the signed version of size_t */ +#cmakedefine ssize_t ${ssize_t} + +/* Define to 1 if you have the mach_absolute_time function. */ +#cmakedefine HAVE_MACH_ABSOLUTE_TIME 1 + +/* to enable Windows IDN */ +#cmakedefine USE_WIN32_IDN 1 + +/* Define to 1 to enable websocket support. */ +#cmakedefine USE_WEBSOCKETS 1 + +/* Define to 1 if OpenSSL has the SSL_CTX_set_srp_username function. */ +#cmakedefine HAVE_OPENSSL_SRP 1 + +/* Define to 1 if GnuTLS has the gnutls_srp_verifier function. */ +#cmakedefine HAVE_GNUTLS_SRP 1 + +/* Define to 1 to enable TLS-SRP support. */ +#cmakedefine USE_TLS_SRP 1 diff --git a/lib/curl_config.h.in b/lib/curl_config.h.in new file mode 100644 index 0000000..617724e --- /dev/null +++ b/lib/curl_config.h.in @@ -0,0 +1,992 @@ +/* lib/curl_config.h.in. Generated from configure.ac by autoheader. */ + +/* to enable curl debug memory tracking */ +#undef CURLDEBUG + +/* Location of default ca bundle */ +#undef CURL_CA_BUNDLE + +/* define "1" to use built in CA store of SSL library */ +#undef CURL_CA_FALLBACK + +/* Location of default ca path */ +#undef CURL_CA_PATH + +/* Default SSL backend */ +#undef CURL_DEFAULT_SSL_BACKEND + +/* disable alt-svc */ +#undef CURL_DISABLE_ALTSVC + +/* to disable AWS sig support */ +#undef CURL_DISABLE_AWS + +/* to disable basic authentication */ +#undef CURL_DISABLE_BASIC_AUTH + +/* to disable bearer authentication */ +#undef CURL_DISABLE_BEARER_AUTH + +/* disable local binding support */ +#undef CURL_DISABLE_BINDLOCAL + +/* to disable cookies support */ +#undef CURL_DISABLE_COOKIES + +/* to disable DICT */ +#undef CURL_DISABLE_DICT + +/* to disable digest authentication */ +#undef CURL_DISABLE_DIGEST_AUTH + +/* disable DoH */ +#undef CURL_DISABLE_DOH + +/* to disable FILE */ +#undef CURL_DISABLE_FILE + +/* disable form API */ +#undef CURL_DISABLE_FORM_API + +/* to disable FTP */ +#undef CURL_DISABLE_FTP + +/* to disable curl_easy_options */ +#undef CURL_DISABLE_GETOPTIONS + +/* to disable Gopher */ +#undef CURL_DISABLE_GOPHER + +/* disable headers-api */ +#undef CURL_DISABLE_HEADERS_API + +/* disable alt-svc */ +#undef CURL_DISABLE_HSTS + +/* to disable HTTP */ +#undef CURL_DISABLE_HTTP + +/* disable HTTP authentication */ +#undef CURL_DISABLE_HTTP_AUTH + +/* to disable IMAP */ +#undef CURL_DISABLE_IMAP + +/* to disable kerberos authentication */ +#undef CURL_DISABLE_KERBEROS_AUTH + +/* to disable LDAP */ +#undef CURL_DISABLE_LDAP + +/* to disable LDAPS */ +#undef CURL_DISABLE_LDAPS + +/* to disable --libcurl C code generation option */ +#undef CURL_DISABLE_LIBCURL_OPTION + +/* disable mime API */ +#undef CURL_DISABLE_MIME + +/* to disable MQTT */ +#undef CURL_DISABLE_MQTT + +/* to disable negotiate authentication */ +#undef CURL_DISABLE_NEGOTIATE_AUTH + +/* disable netrc parsing */ +#undef CURL_DISABLE_NETRC + +/* to disable NTLM support */ +#undef CURL_DISABLE_NTLM + +/* if the OpenSSL configuration won't be loaded automatically */ +#undef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG + +/* disable date parsing */ +#undef CURL_DISABLE_PARSEDATE + +/* to disable POP3 */ +#undef CURL_DISABLE_POP3 + +/* disable progress-meter */ +#undef CURL_DISABLE_PROGRESS_METER + +/* to disable proxies */ +#undef CURL_DISABLE_PROXY + +/* to disable RTSP */ +#undef CURL_DISABLE_RTSP + +/* disable DNS shuffling */ +#undef CURL_DISABLE_SHUFFLE_DNS + +/* to disable SMB/CIFS */ +#undef CURL_DISABLE_SMB + +/* to disable SMTP */ +#undef CURL_DISABLE_SMTP + +/* to disable socketpair support */ +#undef CURL_DISABLE_SOCKETPAIR + +/* to disable TELNET */ +#undef CURL_DISABLE_TELNET + +/* to disable TFTP */ +#undef CURL_DISABLE_TFTP + +/* to disable verbose strings */ +#undef CURL_DISABLE_VERBOSE_STRINGS + +/* Definition to make a library symbol externally visible. */ +#undef CURL_EXTERN_SYMBOL + +/* IP address type in sockaddr */ +#undef CURL_SA_FAMILY_T + +/* built with multiple SSL backends */ +#undef CURL_WITH_MULTI_SSL + +/* enable debug build options */ +#undef DEBUGBUILD + +/* Define if you want to enable IPv6 support */ +#undef ENABLE_IPV6 + +/* Define to the type of arg 2 for gethostname. */ +#undef GETHOSTNAME_TYPE_ARG2 + +/* Define to 1 if you have the alarm function. */ +#undef HAVE_ALARM + +/* Define to 1 if you have the `arc4random' function. */ +#undef HAVE_ARC4RANDOM + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have _Atomic support. */ +#undef HAVE_ATOMIC + +/* Define to 1 if you have the basename function. */ +#undef HAVE_BASENAME + +/* Define to 1 if bool is an available type. */ +#undef HAVE_BOOL_T + +/* if BROTLI is in use */ +#undef HAVE_BROTLI + +/* Define to 1 if you have the header file. */ +#undef HAVE_BROTLI_DECODE_H + +/* Define to 1 if you have the __builtin_available function. */ +#undef HAVE_BUILTIN_AVAILABLE + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#undef HAVE_CLOCK_GETTIME_MONOTONIC + +/* Define to 1 if you have the clock_gettime function and raw monotonic timer. + */ +#undef HAVE_CLOCK_GETTIME_MONOTONIC_RAW + +/* Define to 1 if you have the closesocket function. */ +#undef HAVE_CLOSESOCKET + +/* Define to 1 if you have the CloseSocket camel case function. */ +#undef HAVE_CLOSESOCKET_CAMEL + +/* Define to 1 if you have the header file. */ +#undef HAVE_CRYPTO_H + +/* Define to 1 if you have the fseeko declaration */ +#undef HAVE_DECL_FSEEKO + +/* Define to 1 if you have the declaration of `getpwuid_r', and to 0 if you + don't. */ +#undef HAVE_DECL_GETPWUID_R + +/* "Set if getpwuid_r() declaration is missing" */ +#undef HAVE_DECL_GETPWUID_R_MISSING + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERR_H + +/* Define to 1 if you have the fcntl function. */ +#undef HAVE_FCNTL + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#undef HAVE_FCNTL_O_NONBLOCK + +/* Define to 1 if you have the `fnmatch' function. */ +#undef HAVE_FNMATCH + +/* Define to 1 if you have the freeaddrinfo function. */ +#undef HAVE_FREEADDRINFO + +/* Define to 1 if you have the `fseeko' function. */ +#undef HAVE_FSEEKO + +/* Define to 1 if you have the fsetxattr function. */ +#undef HAVE_FSETXATTR + +/* fsetxattr() takes 5 args */ +#undef HAVE_FSETXATTR_5 + +/* fsetxattr() takes 6 args */ +#undef HAVE_FSETXATTR_6 + +/* Define to 1 if you have the ftruncate function. */ +#undef HAVE_FTRUNCATE + +/* Define to 1 if you have a working getaddrinfo function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#undef HAVE_GETADDRINFO_THREADSAFE + +/* Define to 1 if you have the `geteuid' function. */ +#undef HAVE_GETEUID + +/* Define to 1 if you have the gethostbyname function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the gethostbyname_r function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* gethostbyname_r() takes 3 args */ +#undef HAVE_GETHOSTBYNAME_R_3 + +/* gethostbyname_r() takes 5 args */ +#undef HAVE_GETHOSTBYNAME_R_5 + +/* gethostbyname_r() takes 6 args */ +#undef HAVE_GETHOSTBYNAME_R_6 + +/* Define to 1 if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have a working getifaddrs function. */ +#undef HAVE_GETIFADDRS + +/* Define to 1 if you have the `getpass_r' function. */ +#undef HAVE_GETPASS_R + +/* Define to 1 if you have the getpeername function. */ +#undef HAVE_GETPEERNAME + +/* Define to 1 if you have the `getppid' function. */ +#undef HAVE_GETPPID + +/* Define to 1 if you have the `getpwuid' function. */ +#undef HAVE_GETPWUID + +/* Define to 1 if you have the `getpwuid_r' function. */ +#undef HAVE_GETPWUID_R + +/* Define to 1 if you have the `getrlimit' function. */ +#undef HAVE_GETRLIMIT + +/* Define to 1 if you have the getsockname function. */ +#undef HAVE_GETSOCKNAME + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have a working glibc-style strerror_r function. */ +#undef HAVE_GLIBC_STRERROR_R + +/* Define to 1 if you have a working gmtime_r function. */ +#undef HAVE_GMTIME_R + +/* if you have the function gnutls_srp_verifier */ +#undef HAVE_GNUTLS_SRP + +/* if you have GSS-API libraries */ +#undef HAVE_GSSAPI + +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_GSSAPI_GENERIC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_GSSAPI_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_GSSAPI_KRB5_H + +/* if you have GNU GSS */ +#undef HAVE_GSSGNU + +/* Define to 1 if you have the header file. */ +#undef HAVE_HYPER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_IDN2_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_IFADDRS_H + +/* Define to 1 if you have the `if_nametoindex' function. */ +#undef HAVE_IF_NAMETOINDEX + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#undef HAVE_INET_NTOP + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#undef HAVE_INET_PTON + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the ioctl function. */ +#undef HAVE_IOCTL + +/* Define to 1 if you have the ioctlsocket function. */ +#undef HAVE_IOCTLSOCKET + +/* Define to 1 if you have the IoctlSocket camel case function. */ +#undef HAVE_IOCTLSOCKET_CAMEL + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +#undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +#undef HAVE_IOCTLSOCKET_FIONBIO + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#undef HAVE_IOCTL_FIONBIO + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#undef HAVE_IOCTL_SIOCGIFADDR + +/* Define to 1 if you have the header file. */ +#undef HAVE_IO_H + +/* Define to 1 if you have the lber.h header file. */ +#undef HAVE_LBER_H + +/* Define to 1 if you have the ldap.h header file. */ +#undef HAVE_LDAP_H + +/* Define to 1 if you have the `ldap_init_fd' function. */ +#undef HAVE_LDAP_INIT_FD + +/* Use LDAPS implementation */ +#undef HAVE_LDAP_SSL + +/* Define to 1 if you have the ldap_ssl.h header file. */ +#undef HAVE_LDAP_SSL_H + +/* Define to 1 if you have the `ldap_url_parse' function. */ +#undef HAVE_LDAP_URL_PARSE + +/* Define to 1 if you have the `brotlidec' library (-lbrotlidec). */ +#undef HAVE_LIBBROTLIDEC + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBGEN_H + +/* Define to 1 if you have the `idn2' library (-lidn2). */ +#undef HAVE_LIBIDN2 + +/* Define to 1 if using libressl. */ +#undef HAVE_LIBRESSL + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBRTMP_RTMP_H + +/* Define to 1 if you have the `ssh' library (-lssh). */ +#undef HAVE_LIBSSH + +/* Define to 1 if you have the `ssh2' library (-lssh2). */ +#undef HAVE_LIBSSH2 + +/* Define to 1 if you have the `ssl' library (-lssl). */ +#undef HAVE_LIBSSL + +/* Define to 1 if you have the `wolfssh' library (-lwolfssh). */ +#undef HAVE_LIBWOLFSSH + +/* if zlib is available */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the `zstd' library (-lzstd). */ +#undef HAVE_LIBZSTD + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_TCP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#undef HAVE_LONGLONG + +/* Define to 1 if you have the `mach_absolute_time' function. */ +#undef HAVE_MACH_ABSOLUTE_TIME + +/* Define to 1 if you have the memrchr function or macro. */ +#undef HAVE_MEMRCHR + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +#undef HAVE_MSG_NOSIGNAL + +/* Define to 1 if you have the header file. */ +#undef HAVE_MSH3_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN6_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_TCP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_UDP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NGHTTP2_NGHTTP2_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NGHTTP3_NGHTTP3_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NGTCP2_NGTCP2_CRYPTO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NGTCP2_NGTCP2_H + +/* if you have an old MIT Kerberos version, lacking GSS_C_NT_HOSTBASED_SERVICE + */ +#undef HAVE_OLD_GSSMIT + +/* Define to 1 if using OpenSSL 3 or later. */ +#undef HAVE_OPENSSL3 + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_CRYPTO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_ERR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_PEM_H + +/* if you have the functions OSSL_QUIC_client_method */ +#undef HAVE_OPENSSL_QUIC + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_RSA_H + +/* if you have the functions SSL_CTX_set_srp_username and + SSL_CTX_set_srp_password */ +#undef HAVE_OPENSSL_SRP + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_SSL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_X509_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PEM_H + +/* Define to 1 if you have the `pipe' function. */ +#undef HAVE_PIPE + +/* If you have a fine poll */ +#undef HAVE_POLL_FINE + +/* Define to 1 if you have the header file. */ +#undef HAVE_POLL_H + +/* Define to 1 if you have a working POSIX-style strerror_r function. */ +#undef HAVE_POSIX_STRERROR_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_PROTO_BSDSOCKET_H + +/* if you have */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PWD_H + +/* Define to 1 if you have the `quiche_conn_set_qlog_fd' function. */ +#undef HAVE_QUICHE_CONN_SET_QLOG_FD + +/* Define to 1 if you have the header file. */ +#undef HAVE_QUICHE_H + +/* Define to 1 if you have the recv function. */ +#undef HAVE_RECV + +/* Define to 1 if you have the header file. */ +#undef HAVE_RSA_H + +/* Define to 1 if you have the `sched_yield' function. */ +#undef HAVE_SCHED_YIELD + +/* Define to 1 if you have the select function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the send function. */ +#undef HAVE_SEND + +/* Define to 1 if you have the `sendmsg' function. */ +#undef HAVE_SENDMSG + +/* Define to 1 if you have the header file. */ +#undef HAVE_SETJMP_H + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `setmode' function. */ +#undef HAVE_SETMODE + +/* Define to 1 if you have the `setrlimit' function. */ +#undef HAVE_SETRLIMIT + +/* Define to 1 if you have the sigaction function. */ +#undef HAVE_SIGACTION + +/* Define to 1 if you have the siginterrupt function. */ +#undef HAVE_SIGINTERRUPT + +/* Define to 1 if you have the signal function. */ +#undef HAVE_SIGNAL + +/* Define to 1 if you have the sigsetjmp function or macro. */ +#undef HAVE_SIGSETJMP + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ +#undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + +/* Define to 1 if you have the socket function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the socketpair function. */ +#undef HAVE_SOCKETPAIR + +/* Define to 1 if you have the header file. */ +#undef HAVE_SOCKET_H + +/* Define to 1 if you have the `SSL_get_ech_status' function. */ +#undef HAVE_SSL_GET_ECH_STATUS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SSL_H + +/* Define to 1 if you have the `SSL_set0_wbio' function. */ +#undef HAVE_SSL_SET0_WBIO + +/* Define to 1 if you have the `SSL_set_quic_use_legacy_codepoint' function. + */ +#undef HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDATOMIC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the strcmpi function. */ +#undef HAVE_STRCMPI + +/* Define to 1 if you have the strdup function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the strerror_r function. */ +#undef HAVE_STRERROR_R + +/* Define to 1 if you have the stricmp function. */ +#undef HAVE_STRICMP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STROPTS_H + +/* Define to 1 if you have the strtok_r function. */ +#undef HAVE_STRTOK_R + +/* Define to 1 if you have the strtoll function. */ +#undef HAVE_STRTOLL + +/* if struct sockaddr_storage is defined */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE + +/* Define to 1 if you have the timeval struct. */ +#undef HAVE_STRUCT_TIMEVAL + +/* Define to 1 if suseconds_t is an available type. */ +#undef HAVE_SUSECONDS_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_POLL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UTIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_XATTR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define this if time_t is unsigned */ +#undef HAVE_TIME_T_UNSIGNED + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `utime' function. */ +#undef HAVE_UTIME + +/* Define to 1 if you have the `utimes' function. */ +#undef HAVE_UTIMES + +/* Define to 1 if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WOLFSSH_SSH_H + +/* if you have wolfSSL_DES_ecb_encrypt */ +#undef HAVE_WOLFSSL_DES_ECB_ENCRYPT + +/* if you have wolfSSL_BIO_set_shutdown */ +#undef HAVE_WOLFSSL_FULL_BIO + +/* Define to 1 if you have the `wolfSSL_get_peer_certificate' function. */ +#undef HAVE_WOLFSSL_GET_PEER_CERTIFICATE + +/* Define to 1 if you have the `wolfSSL_UseALPN' function. */ +#undef HAVE_WOLFSSL_USEALPN + +/* Define this symbol if your OS supports changing the contents of argv */ +#undef HAVE_WRITABLE_ARGV + +/* Define to 1 if you have the header file. */ +#undef HAVE_X509_H + +/* if libzstd is in use */ +#undef HAVE_ZSTD + +/* Define to 1 if you have the header file. */ +#undef HAVE_ZSTD_H + +/* Define to 1 if you have the `_fseeki64' function. */ +#undef HAVE__FSEEKI64 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Define to 1 if you need the lber.h header file even with ldap.h */ +#undef NEED_LBER_H + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +#undef NEED_REENTRANT + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +#undef NEED_THREAD_SAFE + +/* Define to enable NTLM delegation to winbind's ntlm_auth helper. */ +#undef NTLM_WB_ENABLED + +/* Define absolute filename for winbind's ntlm_auth helper. */ +#undef NTLM_WB_FILE + +/* cpu-machine-OS */ +#undef OS + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* a suitable file to read random data from */ +#undef RANDOM_FILE + +/* Size of curl_off_t in number of bytes */ +#undef SIZEOF_CURL_OFF_T + +/* Size of curl_socket_t in number of bytes */ +#undef SIZEOF_CURL_SOCKET_T + +/* Size of int in number of bytes */ +#undef SIZEOF_INT + +/* Size of long in number of bytes */ +#undef SIZEOF_LONG + +/* Size of long long in number of bytes */ +#undef SIZEOF_LONG_LONG + +/* Size of off_t in number of bytes */ +#undef SIZEOF_OFF_T + +/* Size of size_t in number of bytes */ +#undef SIZEOF_SIZE_T + +/* Size of time_t in number of bytes */ +#undef SIZEOF_TIME_T + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#undef STDC_HEADERS + +/* if AmiSSL is in use */ +#undef USE_AMISSL + +/* Define to enable c-ares support */ +#undef USE_ARES + +/* if BearSSL is enabled */ +#undef USE_BEARSSL + +/* if ECH support is available */ +#undef USE_ECH + +/* if GnuTLS is enabled */ +#undef USE_GNUTLS + +/* GSASL support enabled */ +#undef USE_GSASL + +/* if hyper is in use */ +#undef USE_HYPER + +/* PSL support enabled */ +#undef USE_LIBPSL + +/* if librtmp is in use */ +#undef USE_LIBRTMP + +/* if libSSH is in use */ +#undef USE_LIBSSH + +/* if libSSH2 is in use */ +#undef USE_LIBSSH2 + +/* If you want to build curl with the built-in manual */ +#undef USE_MANUAL + +/* if mbedTLS is enabled */ +#undef USE_MBEDTLS + +/* if msh3 is in use */ +#undef USE_MSH3 + +/* if nghttp2 is in use */ +#undef USE_NGHTTP2 + +/* if nghttp3 is in use */ +#undef USE_NGHTTP3 + +/* if ngtcp2 is in use */ +#undef USE_NGTCP2 + +/* if ngtcp2_crypto_boringssl is in use */ +#undef USE_NGTCP2_CRYPTO_BORINGSSL + +/* if ngtcp2_crypto_gnutls is in use */ +#undef USE_NGTCP2_CRYPTO_GNUTLS + +/* if ngtcp2_crypto_quictls is in use */ +#undef USE_NGTCP2_CRYPTO_QUICTLS + +/* if ngtcp2_crypto_wolfssl is in use */ +#undef USE_NGTCP2_CRYPTO_WOLFSSL + +/* if ngtcp2 + nghttp3 is in use */ +#undef USE_NGTCP2_H3 + +/* Use OpenLDAP-specific code */ +#undef USE_OPENLDAP + +/* if OpenSSL is in use */ +#undef USE_OPENSSL + +/* if openssl quic + nghttp3 is in use */ +#undef USE_OPENSSL_H3 + +/* if openssl QUIC is in use */ +#undef USE_OPENSSL_QUIC + +/* if quiche is in use */ +#undef USE_QUICHE + +/* if rustls is enabled */ +#undef USE_RUSTLS + +/* to enable Windows native SSL/TLS support */ +#undef USE_SCHANNEL + +/* enable Secure Transport */ +#undef USE_SECTRANSP + +/* if you want POSIX threaded DNS lookup */ +#undef USE_THREADS_POSIX + +/* if you want Win32 threaded DNS lookup */ +#undef USE_THREADS_WIN32 + +/* Use TLS-SRP authentication */ +#undef USE_TLS_SRP + +/* Use Unix domain sockets */ +#undef USE_UNIX_SOCKETS + +/* enable websockets support */ +#undef USE_WEBSOCKETS + +/* Define to 1 if you are building a Windows target with crypto API support. + */ +#undef USE_WIN32_CRYPTO + +/* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */ +#undef USE_WIN32_IDN + +/* Define to 1 if you are building a Windows target with large file support. + */ +#undef USE_WIN32_LARGE_FILES + +/* Use Windows LDAP implementation */ +#undef USE_WIN32_LDAP + +/* Define to 1 if you are building a Windows target without large file + support. */ +#undef USE_WIN32_SMALL_FILES + +/* to enable SSPI support */ +#undef USE_WINDOWS_SSPI + +/* if wolfSSH is in use */ +#undef USE_WOLFSSH + +/* if wolfSSL is enabled */ +#undef USE_WOLFSSL + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Type to use in place of in_addr_t when system does not provide it. */ +#undef in_addr_t + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* the signed version of size_t */ +#undef ssize_t diff --git a/lib/curl_ctype.h b/lib/curl_ctype.h new file mode 100644 index 0000000..7f0d0cc --- /dev/null +++ b/lib/curl_ctype.h @@ -0,0 +1,51 @@ +#ifndef HEADER_CURL_CTYPE_H +#define HEADER_CURL_CTYPE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#define ISLOWHEXALHA(x) (((x) >= 'a') && ((x) <= 'f')) +#define ISUPHEXALHA(x) (((x) >= 'A') && ((x) <= 'F')) + +#define ISLOWCNTRL(x) ((unsigned char)(x) <= 0x1f) +#define IS7F(x) ((x) == 0x7f) + +#define ISLOWPRINT(x) (((x) >= 9) && ((x) <= 0x0d)) + +#define ISPRINT(x) (ISLOWPRINT(x) || (((x) >= ' ') && ((x) <= 0x7e))) +#define ISGRAPH(x) (ISLOWPRINT(x) || (((x) > ' ') && ((x) <= 0x7e))) +#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x)) +#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x)) +#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x)) +#define ISALNUM(x) (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x)) +#define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z')) +#define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z')) +#define ISDIGIT(x) (((x) >= '0') && ((x) <= '9')) +#define ISBLANK(x) (((x) == ' ') || ((x) == '\t')) +#define ISSPACE(x) (ISBLANK(x) || (((x) >= 0xa) && ((x) <= 0x0d))) +#define ISURLPUNTCS(x) (((x) == '-') || ((x) == '.') || ((x) == '_') || \ + ((x) == '~')) +#define ISUNRESERVED(x) (ISALNUM(x) || ISURLPUNTCS(x)) + + +#endif /* HEADER_CURL_CTYPE_H */ diff --git a/lib/curl_des.c b/lib/curl_des.c new file mode 100644 index 0000000..b77763f --- /dev/null +++ b/lib/curl_des.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \ + (defined(USE_GNUTLS) || \ + defined(USE_SECTRANSP) || \ + defined(USE_OS400CRYPTO) || \ + defined(USE_WIN32_CRYPTO)) + +#include "curl_des.h" + +/* + * Curl_des_set_odd_parity() + * + * This is used to apply odd parity to the given byte array. It is typically + * used by when a cryptography engines doesn't have it's own version. + * + * The function is a port of the Java based oddParity() function over at: + * + * https://davenport.sourceforge.net/ntlm.html + * + * Parameters: + * + * bytes [in/out] - The data whose parity bits are to be adjusted for + * odd parity. + * len [out] - The length of the data. + */ +void Curl_des_set_odd_parity(unsigned char *bytes, size_t len) +{ + size_t i; + + for(i = 0; i < len; i++) { + unsigned char b = bytes[i]; + + bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ + (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ + (b >> 1)) & 0x01) == 0; + + if(needs_parity) + bytes[i] |= 0x01; + else + bytes[i] &= 0xfe; + } +} + +#endif diff --git a/lib/curl_des.h b/lib/curl_des.h new file mode 100644 index 0000000..66525ab --- /dev/null +++ b/lib/curl_des.h @@ -0,0 +1,40 @@ +#ifndef HEADER_CURL_DES_H +#define HEADER_CURL_DES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \ + (defined(USE_GNUTLS) || \ + defined(USE_SECTRANSP) || \ + defined(USE_OS400CRYPTO) || \ + defined(USE_WIN32_CRYPTO)) + +/* Applies odd parity to the given byte array */ +void Curl_des_set_odd_parity(unsigned char *bytes, size_t length); + +#endif + +#endif /* HEADER_CURL_DES_H */ diff --git a/lib/curl_endian.c b/lib/curl_endian.c new file mode 100644 index 0000000..11c662a --- /dev/null +++ b/lib/curl_endian.c @@ -0,0 +1,84 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "curl_endian.h" + +/* + * Curl_read16_le() + * + * This function converts a 16-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 2 byte buffer. + * + * Returns the integer. + */ +unsigned short Curl_read16_le(const unsigned char *buf) +{ + return (unsigned short)(((unsigned short)buf[0]) | + ((unsigned short)buf[1] << 8)); +} + +/* + * Curl_read32_le() + * + * This function converts a 32-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 4 byte buffer. + * + * Returns the integer. + */ +unsigned int Curl_read32_le(const unsigned char *buf) +{ + return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | + ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); +} + +/* + * Curl_read16_be() + * + * This function converts a 16-bit integer from the big endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 2 byte buffer. + * + * Returns the integer. + */ +unsigned short Curl_read16_be(const unsigned char *buf) +{ + return (unsigned short)(((unsigned short)buf[0] << 8) | + ((unsigned short)buf[1])); +} diff --git a/lib/curl_endian.h b/lib/curl_endian.h new file mode 100644 index 0000000..fa28321 --- /dev/null +++ b/lib/curl_endian.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_ENDIAN_H +#define HEADER_CURL_ENDIAN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* Converts a 16-bit integer from little endian */ +unsigned short Curl_read16_le(const unsigned char *buf); + +/* Converts a 32-bit integer from little endian */ +unsigned int Curl_read32_le(const unsigned char *buf); + +/* Converts a 16-bit integer from big endian */ +unsigned short Curl_read16_be(const unsigned char *buf); + +#endif /* HEADER_CURL_ENDIAN_H */ diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c new file mode 100644 index 0000000..5f9ca4f --- /dev/null +++ b/lib/curl_fnmatch.c @@ -0,0 +1,390 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#ifndef CURL_DISABLE_FTP +#include + +#include "curl_fnmatch.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#ifndef HAVE_FNMATCH + +#define CURLFNM_CHARSET_LEN (sizeof(char) * 256) +#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15) + +#define CURLFNM_NEGATE CURLFNM_CHARSET_LEN + +#define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1) +#define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2) +#define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3) +#define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4) +#define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5) +#define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6) +#define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7) +#define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8) +#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9) +#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10) + +typedef enum { + CURLFNM_SCHS_DEFAULT = 0, + CURLFNM_SCHS_RIGHTBR, + CURLFNM_SCHS_RIGHTBRLEFTBR +} setcharset_state; + +typedef enum { + CURLFNM_PKW_INIT = 0, + CURLFNM_PKW_DDOT +} parsekey_state; + +typedef enum { + CCLASS_OTHER = 0, + CCLASS_DIGIT, + CCLASS_UPPER, + CCLASS_LOWER +} char_class; + +#define SETCHARSET_OK 1 +#define SETCHARSET_FAIL 0 + +static int parsekeyword(unsigned char **pattern, unsigned char *charset) +{ + parsekey_state state = CURLFNM_PKW_INIT; +#define KEYLEN 10 + char keyword[KEYLEN] = { 0 }; + int i; + unsigned char *p = *pattern; + bool found = FALSE; + for(i = 0; !found; i++) { + char c = *p++; + if(i >= KEYLEN) + return SETCHARSET_FAIL; + switch(state) { + case CURLFNM_PKW_INIT: + if(ISLOWER(c)) + keyword[i] = c; + else if(c == ':') + state = CURLFNM_PKW_DDOT; + else + return SETCHARSET_FAIL; + break; + case CURLFNM_PKW_DDOT: + if(c == ']') + found = TRUE; + else + return SETCHARSET_FAIL; + } + } +#undef KEYLEN + + *pattern = p; /* move caller's pattern pointer */ + if(strcmp(keyword, "digit") == 0) + charset[CURLFNM_DIGIT] = 1; + else if(strcmp(keyword, "alnum") == 0) + charset[CURLFNM_ALNUM] = 1; + else if(strcmp(keyword, "alpha") == 0) + charset[CURLFNM_ALPHA] = 1; + else if(strcmp(keyword, "xdigit") == 0) + charset[CURLFNM_XDIGIT] = 1; + else if(strcmp(keyword, "print") == 0) + charset[CURLFNM_PRINT] = 1; + else if(strcmp(keyword, "graph") == 0) + charset[CURLFNM_GRAPH] = 1; + else if(strcmp(keyword, "space") == 0) + charset[CURLFNM_SPACE] = 1; + else if(strcmp(keyword, "blank") == 0) + charset[CURLFNM_BLANK] = 1; + else if(strcmp(keyword, "upper") == 0) + charset[CURLFNM_UPPER] = 1; + else if(strcmp(keyword, "lower") == 0) + charset[CURLFNM_LOWER] = 1; + else + return SETCHARSET_FAIL; + return SETCHARSET_OK; +} + +/* Return the character class. */ +static char_class charclass(unsigned char c) +{ + if(ISUPPER(c)) + return CCLASS_UPPER; + if(ISLOWER(c)) + return CCLASS_LOWER; + if(ISDIGIT(c)) + return CCLASS_DIGIT; + return CCLASS_OTHER; +} + +/* Include a character or a range in set. */ +static void setcharorrange(unsigned char **pp, unsigned char *charset) +{ + unsigned char *p = (*pp)++; + unsigned char c = *p++; + + charset[c] = 1; + if(ISALNUM(c) && *p++ == '-') { + char_class cc = charclass(c); + unsigned char endrange = *p++; + + if(endrange == '\\') + endrange = *p++; + if(endrange >= c && charclass(endrange) == cc) { + while(c++ != endrange) + if(charclass(c) == cc) /* Chars in class may be not consecutive. */ + charset[c] = 1; + *pp = p; + } + } +} + +/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */ +static int setcharset(unsigned char **p, unsigned char *charset) +{ + setcharset_state state = CURLFNM_SCHS_DEFAULT; + bool something_found = FALSE; + unsigned char c; + + memset(charset, 0, CURLFNM_CHSET_SIZE); + for(;;) { + c = **p; + if(!c) + return SETCHARSET_FAIL; + + switch(state) { + case CURLFNM_SCHS_DEFAULT: + if(c == ']') { + if(something_found) + return SETCHARSET_OK; + something_found = TRUE; + state = CURLFNM_SCHS_RIGHTBR; + charset[c] = 1; + (*p)++; + } + else if(c == '[') { + unsigned char *pp = *p + 1; + + if(*pp++ == ':' && parsekeyword(&pp, charset)) + *p = pp; + else { + charset[c] = 1; + (*p)++; + } + something_found = TRUE; + } + else if(c == '^' || c == '!') { + if(!something_found) { + if(charset[CURLFNM_NEGATE]) { + charset[c] = 1; + something_found = TRUE; + } + else + charset[CURLFNM_NEGATE] = 1; /* negate charset */ + } + else + charset[c] = 1; + (*p)++; + } + else if(c == '\\') { + c = *(++(*p)); + if(c) + setcharorrange(p, charset); + else + charset['\\'] = 1; + something_found = TRUE; + } + else { + setcharorrange(p, charset); + something_found = TRUE; + } + break; + case CURLFNM_SCHS_RIGHTBR: + if(c == '[') { + state = CURLFNM_SCHS_RIGHTBRLEFTBR; + charset[c] = 1; + (*p)++; + } + else if(c == ']') { + return SETCHARSET_OK; + } + else if(ISPRINT(c)) { + charset[c] = 1; + (*p)++; + state = CURLFNM_SCHS_DEFAULT; + } + else + /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a + * nonsense warning 'statement not reached' at end of the fnc when + * compiling on Solaris */ + goto fail; + break; + case CURLFNM_SCHS_RIGHTBRLEFTBR: + if(c == ']') + return SETCHARSET_OK; + state = CURLFNM_SCHS_DEFAULT; + charset[c] = 1; + (*p)++; + break; + } + } +fail: + return SETCHARSET_FAIL; +} + +static int loop(const unsigned char *pattern, const unsigned char *string, + int maxstars) +{ + unsigned char *p = (unsigned char *)pattern; + unsigned char *s = (unsigned char *)string; + unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 }; + + for(;;) { + unsigned char *pp; + + switch(*p) { + case '*': + if(!maxstars) + return CURL_FNMATCH_NOMATCH; + /* Regroup consecutive stars and question marks. This can be done because + '*?*?*' can be expressed as '??*'. */ + for(;;) { + if(*++p == '\0') + return CURL_FNMATCH_MATCH; + if(*p == '?') { + if(!*s++) + return CURL_FNMATCH_NOMATCH; + } + else if(*p != '*') + break; + } + /* Skip string characters until we find a match with pattern suffix. */ + for(maxstars--; *s; s++) { + if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH) + return CURL_FNMATCH_MATCH; + } + return CURL_FNMATCH_NOMATCH; + case '?': + if(!*s) + return CURL_FNMATCH_NOMATCH; + s++; + p++; + break; + case '\0': + return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH; + case '\\': + if(p[1]) + p++; + if(*s++ != *p++) + return CURL_FNMATCH_NOMATCH; + break; + case '[': + pp = p + 1; /* Copy in case of syntax error in set. */ + if(setcharset(&pp, charset)) { + int found = FALSE; + if(!*s) + return CURL_FNMATCH_NOMATCH; + if(charset[(unsigned int)*s]) + found = TRUE; + else if(charset[CURLFNM_ALNUM]) + found = ISALNUM(*s); + else if(charset[CURLFNM_ALPHA]) + found = ISALPHA(*s); + else if(charset[CURLFNM_DIGIT]) + found = ISDIGIT(*s); + else if(charset[CURLFNM_XDIGIT]) + found = ISXDIGIT(*s); + else if(charset[CURLFNM_PRINT]) + found = ISPRINT(*s); + else if(charset[CURLFNM_SPACE]) + found = ISSPACE(*s); + else if(charset[CURLFNM_UPPER]) + found = ISUPPER(*s); + else if(charset[CURLFNM_LOWER]) + found = ISLOWER(*s); + else if(charset[CURLFNM_BLANK]) + found = ISBLANK(*s); + else if(charset[CURLFNM_GRAPH]) + found = ISGRAPH(*s); + + if(charset[CURLFNM_NEGATE]) + found = !found; + + if(!found) + return CURL_FNMATCH_NOMATCH; + p = pp + 1; + s++; + break; + } + /* Syntax error in set; mismatch! */ + return CURL_FNMATCH_NOMATCH; + + default: + if(*p++ != *s++) + return CURL_FNMATCH_NOMATCH; + break; + } + } +} + +/* + * @unittest: 1307 + */ +int Curl_fnmatch(void *ptr, const char *pattern, const char *string) +{ + (void)ptr; /* the argument is specified by the curl_fnmatch_callback + prototype, but not used by Curl_fnmatch() */ + if(!pattern || !string) { + return CURL_FNMATCH_FAIL; + } + return loop((unsigned char *)pattern, (unsigned char *)string, 2); +} +#else +#include +/* + * @unittest: 1307 + */ +int Curl_fnmatch(void *ptr, const char *pattern, const char *string) +{ + (void)ptr; /* the argument is specified by the curl_fnmatch_callback + prototype, but not used by Curl_fnmatch() */ + if(!pattern || !string) { + return CURL_FNMATCH_FAIL; + } + + switch(fnmatch(pattern, string, 0)) { + case 0: + return CURL_FNMATCH_MATCH; + case FNM_NOMATCH: + return CURL_FNMATCH_NOMATCH; + default: + return CURL_FNMATCH_FAIL; + } + /* not reached */ +} + +#endif + +#endif /* if FTP is disabled */ diff --git a/lib/curl_fnmatch.h b/lib/curl_fnmatch.h new file mode 100644 index 0000000..595646f --- /dev/null +++ b/lib/curl_fnmatch.h @@ -0,0 +1,46 @@ +#ifndef HEADER_CURL_FNMATCH_H +#define HEADER_CURL_FNMATCH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#define CURL_FNMATCH_MATCH 0 +#define CURL_FNMATCH_NOMATCH 1 +#define CURL_FNMATCH_FAIL 2 + +/* default pattern matching function + * ================================= + * Implemented with recursive backtracking, if you want to use Curl_fnmatch, + * please note that there is not implemented UTF/UNICODE support. + * + * Implemented features: + * '?' notation, does not match UTF characters + * '*' can also work with UTF string + * [a-zA-Z0-9] enumeration support + * + * keywords: alnum, digit, xdigit, alpha, print, blank, lower, graph, space + * and upper (use as "[[:alnum:]]") + */ +int Curl_fnmatch(void *ptr, const char *pattern, const char *string); + +#endif /* HEADER_CURL_FNMATCH_H */ diff --git a/lib/curl_get_line.c b/lib/curl_get_line.c new file mode 100644 index 0000000..686abe7 --- /dev/null +++ b/lib/curl_get_line.c @@ -0,0 +1,86 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \ + !defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC) + +#include "curl_get_line.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Curl_get_line() makes sure to only return complete whole lines that fit in + * 'len' bytes and end with a newline. + */ +char *Curl_get_line(char *buf, int len, FILE *input) +{ + bool partial = FALSE; + while(1) { + char *b = fgets(buf, len, input); + + if(b) { + size_t rlen = strlen(b); + + if(!rlen) + break; + + if(b[rlen-1] == '\n') { + /* b is \n terminated */ + if(partial) { + partial = FALSE; + continue; + } + return b; + } + else if(feof(input)) { + if(partial) + /* Line is already too large to return, ignore rest */ + break; + + if(rlen + 1 < (size_t) len) { + /* b is EOF terminated, insert missing \n */ + b[rlen] = '\n'; + b[rlen + 1] = '\0'; + return b; + } + else + /* Maximum buffersize reached + EOF + * This line is impossible to add a \n to so we'll ignore it + */ + break; + } + else + /* Maximum buffersize reached */ + partial = TRUE; + } + else + break; + } + return NULL; +} + +#endif /* if not disabled */ diff --git a/lib/curl_get_line.h b/lib/curl_get_line.h new file mode 100644 index 0000000..0ff32c5 --- /dev/null +++ b/lib/curl_get_line.h @@ -0,0 +1,31 @@ +#ifndef HEADER_CURL_GET_LINE_H +#define HEADER_CURL_GET_LINE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* get_line() makes sure to only return complete whole lines that fit in 'len' + * bytes and end with a newline. */ +char *Curl_get_line(char *buf, int len, FILE *input); + +#endif /* HEADER_CURL_GET_LINE_H */ diff --git a/lib/curl_gethostname.c b/lib/curl_gethostname.c new file mode 100644 index 0000000..706b2e6 --- /dev/null +++ b/lib/curl_gethostname.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "curl_gethostname.h" + +/* + * Curl_gethostname() is a wrapper around gethostname() which allows + * overriding the host name that the function would normally return. + * This capability is used by the test suite to verify exact matching + * of NTLM authentication, which exercises libcurl's MD4 and DES code + * as well as by the SMTP module when a hostname is not provided. + * + * For libcurl debug enabled builds host name overriding takes place + * when environment variable CURL_GETHOSTNAME is set, using the value + * held by the variable to override returned host name. + * + * Note: The function always returns the un-qualified hostname rather + * than being provider dependent. + * + * For libcurl shared library release builds the test suite preloads + * another shared library named libhostname using the LD_PRELOAD + * mechanism which intercepts, and might override, the gethostname() + * function call. In this case a given platform must support the + * LD_PRELOAD mechanism and additionally have environment variable + * CURL_GETHOSTNAME set in order to override the returned host name. + * + * For libcurl static library release builds no overriding takes place. + */ + +int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen) +{ +#ifndef HAVE_GETHOSTNAME + + /* Allow compilation and return failure when unavailable */ + (void) name; + (void) namelen; + return -1; + +#else + int err; + char *dot; + +#ifdef DEBUGBUILD + + /* Override host name when environment variable CURL_GETHOSTNAME is set */ + const char *force_hostname = getenv("CURL_GETHOSTNAME"); + if(force_hostname) { + strncpy(name, force_hostname, namelen); + err = 0; + } + else { + name[0] = '\0'; + err = gethostname(name, namelen); + } + +#else /* DEBUGBUILD */ + + /* The call to system's gethostname() might get intercepted by the + libhostname library when libcurl is built as a non-debug shared + library when running the test suite. */ + name[0] = '\0'; + err = gethostname(name, namelen); + +#endif + + name[namelen - 1] = '\0'; + + if(err) + return err; + + /* Truncate domain, leave only machine name */ + dot = strchr(name, '.'); + if(dot) + *dot = '\0'; + + return 0; +#endif + +} diff --git a/lib/curl_gethostname.h b/lib/curl_gethostname.h new file mode 100644 index 0000000..9281d9c --- /dev/null +++ b/lib/curl_gethostname.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_GETHOSTNAME_H +#define HEADER_CURL_GETHOSTNAME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* Hostname buffer size */ +#define HOSTNAME_MAX 1024 + +/* This returns the local machine's un-qualified hostname */ +int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen); + +#endif /* HEADER_CURL_GETHOSTNAME_H */ diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c new file mode 100644 index 0000000..c6fe125 --- /dev/null +++ b/lib/curl_gssapi.c @@ -0,0 +1,152 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_GSSAPI + +#include "curl_gssapi.h" +#include "sendf.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if defined(__GNUC__) +#define CURL_ALIGN8 __attribute__ ((aligned(8))) +#else +#define CURL_ALIGN8 +#endif + +gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = { + 6, (char *)"\x2b\x06\x01\x05\x05\x02" +}; +gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = { + 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" +}; + +OM_uint32 Curl_gss_init_sec_context( + struct Curl_easy *data, + OM_uint32 *minor_status, + gss_ctx_id_t *context, + gss_name_t target_name, + gss_OID mech_type, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + const bool mutual_auth, + OM_uint32 *ret_flags) +{ + OM_uint32 req_flags = GSS_C_REPLAY_FLAG; + + if(mutual_auth) + req_flags |= GSS_C_MUTUAL_FLAG; + + if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { +#ifdef GSS_C_DELEG_POLICY_FLAG + req_flags |= GSS_C_DELEG_POLICY_FLAG; +#else + infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " + "compiled in"); +#endif + } + + if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG) + req_flags |= GSS_C_DELEG_FLAG; + + return gss_init_sec_context(minor_status, + GSS_C_NO_CREDENTIAL, /* cred_handle */ + context, + target_name, + mech_type, + req_flags, + 0, /* time_req */ + input_chan_bindings, + input_token, + NULL, /* actual_mech_type */ + output_token, + ret_flags, + NULL /* time_rec */); +} + +#define GSS_LOG_BUFFER_LEN 1024 +static size_t display_gss_error(OM_uint32 status, int type, + char *buf, size_t len) { + OM_uint32 maj_stat; + OM_uint32 min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER; + + do { + maj_stat = gss_display_status(&min_stat, + status, + type, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if(maj_stat == GSS_S_COMPLETE && status_string.length > 0) { + if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { + len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len, + "%.*s. ", (int)status_string.length, + (char *)status_string.value); + } + } + gss_release_buffer(&min_stat, &status_string); + } while(!GSS_ERROR(maj_stat) && msg_ctx); + + return len; +} + +/* + * Curl_gss_log_error() + * + * This is used to log a GSS-API error status. + * + * Parameters: + * + * data [in] - The session handle. + * prefix [in] - The prefix of the log message. + * major [in] - The major status code. + * minor [in] - The minor status code. + */ +void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, + OM_uint32 major, OM_uint32 minor) +{ + char buf[GSS_LOG_BUFFER_LEN]; + size_t len = 0; + + if(major != GSS_S_FAILURE) + len = display_gss_error(major, GSS_C_GSS_CODE, buf, len); + + display_gss_error(minor, GSS_C_MECH_CODE, buf, len); + + infof(data, "%s%s", prefix, buf); +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; + (void)prefix; +#endif +} + +#endif /* HAVE_GSSAPI */ diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h new file mode 100644 index 0000000..7b9a534 --- /dev/null +++ b/lib/curl_gssapi.h @@ -0,0 +1,63 @@ +#ifndef HEADER_CURL_GSSAPI_H +#define HEADER_CURL_GSSAPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "urldata.h" + +#ifdef HAVE_GSSAPI +extern gss_OID_desc Curl_spnego_mech_oid; +extern gss_OID_desc Curl_krb5_mech_oid; + +/* Common method for using GSS-API */ +OM_uint32 Curl_gss_init_sec_context( + struct Curl_easy *data, + OM_uint32 *minor_status, + gss_ctx_id_t *context, + gss_name_t target_name, + gss_OID mech_type, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + const bool mutual_auth, + OM_uint32 *ret_flags); + +/* Helper to log a GSS-API error status */ +void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, + OM_uint32 major, OM_uint32 minor); + +/* Provide some definitions missing in old headers */ +#ifdef HAVE_OLD_GSSMIT +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 +#endif + +/* Define our privacy and integrity protection values */ +#define GSSAUTH_P_NONE 1 +#define GSSAUTH_P_INTEGRITY 2 +#define GSSAUTH_P_PRIVACY 4 + +#endif /* HAVE_GSSAPI */ +#endif /* HEADER_CURL_GSSAPI_H */ diff --git a/lib/curl_hmac.h b/lib/curl_hmac.h new file mode 100644 index 0000000..7a5387a --- /dev/null +++ b/lib/curl_hmac.h @@ -0,0 +1,78 @@ +#ifndef HEADER_CURL_HMAC_H +#define HEADER_CURL_HMAC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ + || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \ + || defined(USE_LIBSSH2) + +#include + +#define HMAC_MD5_LENGTH 16 + +typedef CURLcode (* HMAC_hinit_func)(void *context); +typedef void (* HMAC_hupdate_func)(void *context, + const unsigned char *data, + unsigned int len); +typedef void (* HMAC_hfinal_func)(unsigned char *result, void *context); + + +/* Per-hash function HMAC parameters. */ +struct HMAC_params { + HMAC_hinit_func + hmac_hinit; /* Initialize context procedure. */ + HMAC_hupdate_func hmac_hupdate; /* Update context with data. */ + HMAC_hfinal_func hmac_hfinal; /* Get final result procedure. */ + unsigned int hmac_ctxtsize; /* Context structure size. */ + unsigned int hmac_maxkeylen; /* Maximum key length (bytes). */ + unsigned int hmac_resultlen; /* Result length (bytes). */ +}; + + +/* HMAC computation context. */ +struct HMAC_context { + const struct HMAC_params *hmac_hash; /* Hash function definition. */ + void *hmac_hashctxt1; /* Hash function context 1. */ + void *hmac_hashctxt2; /* Hash function context 2. */ +}; + + +/* Prototypes. */ +struct HMAC_context *Curl_HMAC_init(const struct HMAC_params *hashparams, + const unsigned char *key, + unsigned int keylen); +int Curl_HMAC_update(struct HMAC_context *context, + const unsigned char *data, + unsigned int len); +int Curl_HMAC_final(struct HMAC_context *context, unsigned char *result); + +CURLcode Curl_hmacit(const struct HMAC_params *hashparams, + const unsigned char *key, const size_t keylen, + const unsigned char *data, const size_t datalen, + unsigned char *output); + +#endif + +#endif /* HEADER_CURL_HMAC_H */ diff --git a/lib/curl_krb5.h b/lib/curl_krb5.h new file mode 100644 index 0000000..ccf6b96 --- /dev/null +++ b/lib/curl_krb5.h @@ -0,0 +1,52 @@ +#ifndef HEADER_CURL_KRB5_H +#define HEADER_CURL_KRB5_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +struct Curl_sec_client_mech { + const char *name; + size_t size; + int (*init)(void *); + int (*auth)(void *, struct Curl_easy *data, struct connectdata *); + void (*end)(void *); + int (*check_prot)(void *, int); + int (*encode)(void *, const void *, int, int, void **); + int (*decode)(void *, void *, int, int, struct connectdata *); +}; + +#define AUTH_OK 0 +#define AUTH_CONTINUE 1 +#define AUTH_ERROR 2 + +#ifdef HAVE_GSSAPI +int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *, + enum protection_level); +void Curl_sec_end(struct connectdata *); +CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *); +int Curl_sec_request_prot(struct connectdata *conn, const char *level); +#else +#define Curl_sec_end(x) +#endif + +#endif /* HEADER_CURL_KRB5_H */ diff --git a/lib/curl_ldap.h b/lib/curl_ldap.h new file mode 100644 index 0000000..8a1d807 --- /dev/null +++ b/lib/curl_ldap.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_LDAP_H +#define HEADER_CURL_LDAP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifndef CURL_DISABLE_LDAP +extern const struct Curl_handler Curl_handler_ldap; + +#if !defined(CURL_DISABLE_LDAPS) && \ + ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ + (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) +extern const struct Curl_handler Curl_handler_ldaps; +#endif + +#endif +#endif /* HEADER_CURL_LDAP_H */ diff --git a/lib/curl_md4.h b/lib/curl_md4.h new file mode 100644 index 0000000..4706e49 --- /dev/null +++ b/lib/curl_md4.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_MD4_H +#define HEADER_CURL_MD4_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include + +#if defined(USE_CURL_NTLM_CORE) + +#define MD4_DIGEST_LENGTH 16 + +CURLcode Curl_md4it(unsigned char *output, const unsigned char *input, + const size_t len); + +#endif /* defined(USE_CURL_NTLM_CORE) */ + +#endif /* HEADER_CURL_MD4_H */ diff --git a/lib/curl_md5.h b/lib/curl_md5.h new file mode 100644 index 0000000..61671c3 --- /dev/null +++ b/lib/curl_md5.h @@ -0,0 +1,67 @@ +#ifndef HEADER_CURL_MD5_H +#define HEADER_CURL_MD5_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ + || !defined(CURL_DISABLE_DIGEST_AUTH) + +#include "curl_hmac.h" + +#define MD5_DIGEST_LEN 16 + +typedef CURLcode (* Curl_MD5_init_func)(void *context); +typedef void (* Curl_MD5_update_func)(void *context, + const unsigned char *data, + unsigned int len); +typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context); + +struct MD5_params { + Curl_MD5_init_func md5_init_func; /* Initialize context procedure */ + Curl_MD5_update_func md5_update_func; /* Update context with data */ + Curl_MD5_final_func md5_final_func; /* Get final result procedure */ + unsigned int md5_ctxtsize; /* Context structure size */ + unsigned int md5_resultlen; /* Result length (bytes) */ +}; + +struct MD5_context { + const struct MD5_params *md5_hash; /* Hash function definition */ + void *md5_hashctx; /* Hash function context */ +}; + +extern const struct MD5_params Curl_DIGEST_MD5[1]; +extern const struct HMAC_params Curl_HMAC_MD5[1]; + +CURLcode Curl_md5it(unsigned char *output, const unsigned char *input, + const size_t len); + +struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params); +CURLcode Curl_MD5_update(struct MD5_context *context, + const unsigned char *data, + unsigned int len); +CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result); + +#endif + +#endif /* HEADER_CURL_MD5_H */ diff --git a/lib/curl_memory.h b/lib/curl_memory.h new file mode 100644 index 0000000..714ad71 --- /dev/null +++ b/lib/curl_memory.h @@ -0,0 +1,178 @@ +#ifndef HEADER_CURL_MEMORY_H +#define HEADER_CURL_MEMORY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Nasty internal details ahead... + * + * File curl_memory.h must be included by _all_ *.c source files + * that use memory related functions strdup, malloc, calloc, realloc + * or free, and given source file is used to build libcurl library. + * It should be included immediately before memdebug.h as the last files + * included to avoid undesired interaction with other memory function + * headers in dependent libraries. + * + * There is nearly no exception to above rule. All libcurl source + * files in 'lib' subdirectory as well as those living deep inside + * 'packages' subdirectories and linked together in order to build + * libcurl library shall follow it. + * + * File lib/strdup.c is an exception, given that it provides a strdup + * clone implementation while using malloc. Extra care needed inside + * this one. + * + * The need for curl_memory.h inclusion is due to libcurl's feature + * of allowing library user to provide memory replacement functions, + * memory callbacks, at runtime with curl_global_init_mem() + * + * Any *.c source file used to build libcurl library that does not + * include curl_memory.h and uses any memory function of the five + * mentioned above will compile without any indication, but it will + * trigger weird memory related issues at runtime. + * + */ + +#ifdef HEADER_CURL_MEMDEBUG_H +/* cleanup after memdebug.h */ + +#ifdef MEMDEBUG_NODEFINES +#ifdef CURLDEBUG + +#undef strdup +#undef malloc +#undef calloc +#undef realloc +#undef free +#undef send +#undef recv + +#ifdef _WIN32 +# ifdef UNICODE +# undef wcsdup +# undef _wcsdup +# undef _tcsdup +# else +# undef _tcsdup +# endif +#endif + +#undef socket +#undef accept +#ifdef HAVE_SOCKETPAIR +#undef socketpair +#endif + +#ifdef HAVE_GETADDRINFO +#if defined(getaddrinfo) && defined(__osf__) +#undef ogetaddrinfo +#else +#undef getaddrinfo +#endif +#endif /* HAVE_GETADDRINFO */ + +#ifdef HAVE_FREEADDRINFO +#undef freeaddrinfo +#endif /* HAVE_FREEADDRINFO */ + +/* sclose is probably already defined, redefine it! */ +#undef sclose +#undef fopen +#undef fdopen +#undef fclose + +#endif /* MEMDEBUG_NODEFINES */ +#endif /* CURLDEBUG */ + +#undef HEADER_CURL_MEMDEBUG_H +#endif /* HEADER_CURL_MEMDEBUG_H */ + +/* +** Following section applies even when CURLDEBUG is not defined. +*/ + +#undef fake_sclose + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ +/* + * The following memory function replacement typedef's are COPIED from + * curl/curl.h and MUST match the originals. We copy them to avoid having to + * include curl/curl.h here. We avoid that include since it includes stdio.h + * and other headers that may get messed up with defines done here. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +extern curl_malloc_callback Curl_cmalloc; +extern curl_free_callback Curl_cfree; +extern curl_realloc_callback Curl_crealloc; +extern curl_strdup_callback Curl_cstrdup; +extern curl_calloc_callback Curl_ccalloc; +#if defined(_WIN32) && defined(UNICODE) +extern curl_wcsdup_callback Curl_cwcsdup; +#endif + +#ifndef CURLDEBUG + +/* + * libcurl's 'memory tracking' system defines strdup, malloc, calloc, + * realloc and free, along with others, in memdebug.h in a different + * way although still using memory callbacks forward declared above. + * When using the 'memory tracking' system (CURLDEBUG defined) we do + * not define here the five memory functions given that definitions + * from memdebug.h are the ones that shall be used. + */ + +#undef strdup +#define strdup(ptr) Curl_cstrdup(ptr) +#undef malloc +#define malloc(size) Curl_cmalloc(size) +#undef calloc +#define calloc(nbelem,size) Curl_ccalloc(nbelem, size) +#undef realloc +#define realloc(ptr,size) Curl_crealloc(ptr, size) +#undef free +#define free(ptr) Curl_cfree(ptr) + +#ifdef _WIN32 +# ifdef UNICODE +# undef wcsdup +# define wcsdup(ptr) Curl_cwcsdup(ptr) +# undef _wcsdup +# define _wcsdup(ptr) Curl_cwcsdup(ptr) +# undef _tcsdup +# define _tcsdup(ptr) Curl_cwcsdup(ptr) +# else +# undef _tcsdup +# define _tcsdup(ptr) Curl_cstrdup(ptr) +# endif +#endif + +#endif /* CURLDEBUG */ +#endif /* HEADER_CURL_MEMORY_H */ diff --git a/lib/curl_memrchr.c b/lib/curl_memrchr.c new file mode 100644 index 0000000..3f3dc6d --- /dev/null +++ b/lib/curl_memrchr.c @@ -0,0 +1,64 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "curl_memrchr.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#ifndef HAVE_MEMRCHR + +/* + * Curl_memrchr() + * + * Our memrchr() function clone for systems which lack this function. The + * memrchr() function is like the memchr() function, except that it searches + * backwards from the end of the n bytes pointed to by s instead of forward + * from the beginning. + */ + +void * +Curl_memrchr(const void *s, int c, size_t n) +{ + if(n > 0) { + const unsigned char *p = s; + const unsigned char *q = s; + + p += n - 1; + + while(p >= q) { + if(*p == (unsigned char)c) + return (void *)p; + p--; + } + } + return NULL; +} + +#endif /* HAVE_MEMRCHR */ diff --git a/lib/curl_memrchr.h b/lib/curl_memrchr.h new file mode 100644 index 0000000..45bb38c --- /dev/null +++ b/lib/curl_memrchr.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_MEMRCHR_H +#define HEADER_CURL_MEMRCHR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_MEMRCHR + +#include +#ifdef HAVE_STRINGS_H +# include +#endif + +#else /* HAVE_MEMRCHR */ + +void *Curl_memrchr(const void *s, int c, size_t n); + +#define memrchr(x,y,z) Curl_memrchr((x),(y),(z)) + +#endif /* HAVE_MEMRCHR */ + +#endif /* HEADER_CURL_MEMRCHR_H */ diff --git a/lib/curl_multibyte.c b/lib/curl_multibyte.c new file mode 100644 index 0000000..ff21098 --- /dev/null +++ b/lib/curl_multibyte.c @@ -0,0 +1,179 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * This file is 'mem-include-scan' clean, which means memdebug.h and + * curl_memory.h are purposely not included in this file. See test 1132. + * + * The functions in this file are curlx functions which are not tracked by the + * curl memory tracker memdebug. + */ + +#include "curl_setup.h" + +#if defined(_WIN32) + +#include "curl_multibyte.h" + +/* + * MultiByte conversions using Windows kernel32 library. + */ + +wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8) +{ + wchar_t *str_w = NULL; + + if(str_utf8) { + int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + str_utf8, -1, NULL, 0); + if(str_w_len > 0) { + str_w = malloc(str_w_len * sizeof(wchar_t)); + if(str_w) { + if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w, + str_w_len) == 0) { + free(str_w); + return NULL; + } + } + } + } + + return str_w; +} + +char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w) +{ + char *str_utf8 = NULL; + + if(str_w) { + int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, + NULL, 0, NULL, NULL); + if(bytes > 0) { + str_utf8 = malloc(bytes); + if(str_utf8) { + if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes, + NULL, NULL) == 0) { + free(str_utf8); + return NULL; + } + } + } + } + + return str_utf8; +} + +#endif /* _WIN32 */ + +#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES) + +int curlx_win32_open(const char *filename, int oflag, ...) +{ + int pmode = 0; + +#ifdef _UNICODE + int result = -1; + wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); +#endif + + va_list param; + va_start(param, oflag); + if(oflag & O_CREAT) + pmode = va_arg(param, int); + va_end(param); + +#ifdef _UNICODE + if(filename_w) { + result = _wopen(filename_w, oflag, pmode); + curlx_unicodefree(filename_w); + } + else + errno = EINVAL; + return result; +#else + return (_open)(filename, oflag, pmode); +#endif +} + +FILE *curlx_win32_fopen(const char *filename, const char *mode) +{ +#ifdef _UNICODE + FILE *result = NULL; + wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); + wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode); + if(filename_w && mode_w) + result = _wfopen(filename_w, mode_w); + else + errno = EINVAL; + curlx_unicodefree(filename_w); + curlx_unicodefree(mode_w); + return result; +#else + return (fopen)(filename, mode); +#endif +} + +int curlx_win32_stat(const char *path, struct_stat *buffer) +{ +#ifdef _UNICODE + int result = -1; + wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); + if(path_w) { +#if defined(USE_WIN32_SMALL_FILES) + result = _wstat(path_w, buffer); +#else + result = _wstati64(path_w, buffer); +#endif + curlx_unicodefree(path_w); + } + else + errno = EINVAL; + return result; +#else +#if defined(USE_WIN32_SMALL_FILES) + return _stat(path, buffer); +#else + return _stati64(path, buffer); +#endif +#endif +} + +int curlx_win32_access(const char *path, int mode) +{ +#if defined(_UNICODE) + int result = -1; + wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); + if(path_w) { + result = _waccess(path_w, mode); + curlx_unicodefree(path_w); + } + else + errno = EINVAL; + return result; +#else + return _access(path, mode); +#endif +} + +#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */ diff --git a/lib/curl_multibyte.h b/lib/curl_multibyte.h new file mode 100644 index 0000000..8b9ac71 --- /dev/null +++ b/lib/curl_multibyte.h @@ -0,0 +1,91 @@ +#ifndef HEADER_CURL_MULTIBYTE_H +#define HEADER_CURL_MULTIBYTE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(_WIN32) + + /* + * MultiByte conversions using Windows kernel32 library. + */ + +wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8); +char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w); +#endif /* _WIN32 */ + +/* + * Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8() + * and curlx_unicodefree() main purpose is to minimize the number of + * preprocessor conditional directives needed by code using these + * to differentiate UNICODE from non-UNICODE builds. + * + * In the case of a non-UNICODE build the tchar strings are char strings that + * are duplicated via strdup and remain in whatever the passed in encoding is, + * which is assumed to be UTF-8 but may be other encoding. Therefore the + * significance of the conversion functions is primarily for UNICODE builds. + * + * Allocated memory should be free'd with curlx_unicodefree(). + * + * Note: Because these are curlx functions their memory usage is not tracked + * by the curl memory tracker memdebug. You'll notice that curlx function-like + * macros call free and strdup in parentheses, eg (strdup)(ptr), and that's to + * ensure that the curl memdebug override macros do not replace them. + */ + +#if defined(UNICODE) && defined(_WIN32) + +#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr)) +#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr)) + +typedef union { + unsigned short *tchar_ptr; + const unsigned short *const_tchar_ptr; + unsigned short *tbyte_ptr; + const unsigned short *const_tbyte_ptr; +} xcharp_u; + +#else + +#define curlx_convert_UTF8_to_tchar(ptr) (strdup)(ptr) +#define curlx_convert_tchar_to_UTF8(ptr) (strdup)(ptr) + +typedef union { + char *tchar_ptr; + const char *const_tchar_ptr; + unsigned char *tbyte_ptr; + const unsigned char *const_tbyte_ptr; +} xcharp_u; + +#endif /* UNICODE && _WIN32 */ + +#define curlx_unicodefree(ptr) \ + do { \ + if(ptr) { \ + (free)(ptr); \ + (ptr) = NULL; \ + } \ + } while(0) + +#endif /* HEADER_CURL_MULTIBYTE_H */ diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c new file mode 100644 index 0000000..6f6d75c --- /dev/null +++ b/lib/curl_ntlm_core.c @@ -0,0 +1,669 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_CURL_NTLM_CORE) + +/* + * NTLM details: + * + * https://davenport.sourceforge.net/ntlm.html + * https://www.innovation.ch/java/ntlm.html + */ + +/* Please keep the SSL backend-specific #if branches in this order: + + 1. USE_OPENSSL + 2. USE_WOLFSSL + 3. USE_GNUTLS + 4. - + 5. USE_MBEDTLS + 6. USE_SECTRANSP + 7. USE_OS400CRYPTO + 8. USE_WIN32_CRYPTO + + This ensures that: + - the same SSL branch gets activated throughout this source + file even if multiple backends are enabled at the same time. + - OpenSSL has higher priority than Windows Crypt, due + to issues with the latter supporting NTLM2Session responses + in NTLM type-3 messages. + */ + +#if defined(USE_OPENSSL) + #include + #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0) + #define USE_OPENSSL_DES + #endif +#endif + +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) + +#if defined(USE_OPENSSL) +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +#endif + +# if (defined(OPENSSL_VERSION_NUMBER) && \ + (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL) +# define DES_key_schedule des_key_schedule +# define DES_cblock des_cblock +# define DES_set_odd_parity des_set_odd_parity +# define DES_set_key des_set_key +# define DES_ecb_encrypt des_ecb_encrypt +# define DESKEY(x) x +# define DESKEYARG(x) x +# elif defined(OPENSSL_IS_AWSLC) +# define DES_set_key_unchecked (void)DES_set_key +# define DESKEYARG(x) *x +# define DESKEY(x) &x +# else +# define DESKEYARG(x) *x +# define DESKEY(x) &x +# endif + +#elif defined(USE_GNUTLS) + +# include + +#elif defined(USE_MBEDTLS) + +# include + +#elif defined(USE_SECTRANSP) + +# include +# include + +#elif defined(USE_OS400CRYPTO) +# include "cipher.mih" /* mih/cipher */ +#elif defined(USE_WIN32_CRYPTO) +# include +#else +# error "Can't compile NTLM support without a crypto library with DES." +# define CURL_NTLM_NOT_SUPPORTED +#endif + +#include "urldata.h" +#include "strcase.h" +#include "curl_ntlm_core.h" +#include "curl_md5.h" +#include "curl_hmac.h" +#include "warnless.h" +#include "curl_endian.h" +#include "curl_des.h" +#include "curl_md4.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00" +#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4) + +#if !defined(CURL_NTLM_NOT_SUPPORTED) +/* +* Turns a 56-bit key into being 64-bit wide. +*/ +static void extend_key_56_to_64(const unsigned char *key_56, char *key) +{ + key[0] = key_56[0]; + key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); + key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); + key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); + key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); + key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); + key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); + key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); +} +#endif + +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) +/* + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The + * key schedule ks is also set. + */ +static void setup_des_key(const unsigned char *key_56, + DES_key_schedule DESKEYARG(ks)) +{ + DES_cblock key; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, (char *) &key); + + /* Set the key parity to odd */ + DES_set_odd_parity(&key); + + /* Set the key */ + DES_set_key_unchecked(&key, ks); +} + +#elif defined(USE_GNUTLS) + +static void setup_des_key(const unsigned char *key_56, + struct des_ctx *des) +{ + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Set the key */ + des_set_key(des, (const uint8_t *) key); +} + +#elif defined(USE_MBEDTLS) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + mbedtls_des_context ctx; + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + mbedtls_des_key_set_parity((unsigned char *) key); + + /* Perform the encryption */ + mbedtls_des_init(&ctx); + mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); + return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; +} + +#elif defined(USE_SECTRANSP) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + char key[8]; + size_t out_len; + CCCryptorStatus err; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Perform the encryption */ + err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, + kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out, + 8 /* outbuflen */, &out_len); + + return err == kCCSuccess; +} + +#elif defined(USE_OS400CRYPTO) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + char key[8]; + _CIPHER_Control_T ctl; + + /* Setup the cipher control structure */ + ctl.Func_ID = ENCRYPT_ONLY; + ctl.Data_Len = sizeof(key); + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, ctl.Crypto_Key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len); + + /* Perform the encryption */ + _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in); + + return TRUE; +} + +#elif defined(USE_WIN32_CRYPTO) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + HCRYPTPROV hprov; + HCRYPTKEY hkey; + struct { + BLOBHEADER hdr; + unsigned int len; + char key[8]; + } blob; + DWORD len = 8; + + /* Acquire the crypto provider */ + if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return FALSE; + + /* Setup the key blob structure */ + memset(&blob, 0, sizeof(blob)); + blob.hdr.bType = PLAINTEXTKEYBLOB; + blob.hdr.bVersion = 2; + blob.hdr.aiKeyAlg = CALG_DES; + blob.len = sizeof(blob.key); + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, blob.key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key)); + + /* Import the key */ + if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) { + CryptReleaseContext(hprov, 0); + + return FALSE; + } + + memcpy(out, in, 8); + + /* Perform the encryption */ + CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len); + + CryptDestroyKey(hkey); + CryptReleaseContext(hprov, 0); + + return TRUE; +} + +#endif /* defined(USE_WIN32_CRYPTO) */ + + /* + * takes a 21 byte array and treats it as 3 56-bit DES keys. The + * 8 byte plaintext is encrypted with each key and the resulting 24 + * bytes are stored in the results array. + */ +void Curl_ntlm_core_lm_resp(const unsigned char *keys, + const unsigned char *plaintext, + unsigned char *results) +{ +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) + DES_key_schedule ks; + + setup_des_key(keys, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys + 7, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8), + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys + 14, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16), + DESKEY(ks), DES_ENCRYPT); +#elif defined(USE_GNUTLS) + struct des_ctx des; + setup_des_key(keys, &des); + des_encrypt(&des, 8, results, plaintext); + setup_des_key(keys + 7, &des); + des_encrypt(&des, 8, results + 8, plaintext); + setup_des_key(keys + 14, &des); + des_encrypt(&des, 8, results + 16, plaintext); +#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \ + || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) + encrypt_des(plaintext, results, keys); + encrypt_des(plaintext, results + 8, keys + 7); + encrypt_des(plaintext, results + 16, keys + 14); +#else + (void)keys; + (void)plaintext; + (void)results; +#endif +} + +/* + * Set up lanmanager hashed password + */ +CURLcode Curl_ntlm_core_mk_lm_hash(const char *password, + unsigned char *lmbuffer /* 21 bytes */) +{ + unsigned char pw[14]; +#if !defined(CURL_NTLM_NOT_SUPPORTED) + static const unsigned char magic[] = { + 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ + }; +#endif + size_t len = CURLMIN(strlen(password), 14); + + Curl_strntoupper((char *)pw, password, len); + memset(&pw[len], 0, 14 - len); + + { + /* Create LanManager hashed password. */ + +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) + DES_key_schedule ks; + + setup_des_key(pw, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(pw + 7, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8), + DESKEY(ks), DES_ENCRYPT); +#elif defined(USE_GNUTLS) + struct des_ctx des; + setup_des_key(pw, &des); + des_encrypt(&des, 8, lmbuffer, magic); + setup_des_key(pw + 7, &des); + des_encrypt(&des, 8, lmbuffer + 8, magic); +#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \ + || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) + encrypt_des(magic, lmbuffer, pw); + encrypt_des(magic, lmbuffer + 8, pw + 7); +#endif + + memset(lmbuffer + 16, 0, 21 - 16); + } + + return CURLE_OK; +} + +static void ascii_to_unicode_le(unsigned char *dest, const char *src, + size_t srclen) +{ + size_t i; + for(i = 0; i < srclen; i++) { + dest[2 * i] = (unsigned char)src[i]; + dest[2 * i + 1] = '\0'; + } +} + +#if !defined(USE_WINDOWS_SSPI) + +static void ascii_uppercase_to_unicode_le(unsigned char *dest, + const char *src, size_t srclen) +{ + size_t i; + for(i = 0; i < srclen; i++) { + dest[2 * i] = (unsigned char)(Curl_raw_toupper(src[i])); + dest[2 * i + 1] = '\0'; + } +} + +#endif /* !USE_WINDOWS_SSPI */ + +/* + * Set up nt hashed passwords + * @unittest: 1600 + */ +CURLcode Curl_ntlm_core_mk_nt_hash(const char *password, + unsigned char *ntbuffer /* 21 bytes */) +{ + size_t len = strlen(password); + unsigned char *pw; + CURLcode result; + if(len > SIZE_T_MAX/2) /* avoid integer overflow */ + return CURLE_OUT_OF_MEMORY; + pw = len ? malloc(len * 2) : (unsigned char *)strdup(""); + if(!pw) + return CURLE_OUT_OF_MEMORY; + + ascii_to_unicode_le(pw, password, len); + + /* Create NT hashed password. */ + result = Curl_md4it(ntbuffer, pw, 2 * len); + if(!result) + memset(ntbuffer + 16, 0, 21 - 16); + + free(pw); + + return result; +} + +#if !defined(USE_WINDOWS_SSPI) + +/* Timestamp in tenths of a microsecond since January 1, 1601 00:00:00 UTC. */ +struct ms_filetime { + unsigned int dwLowDateTime; + unsigned int dwHighDateTime; +}; + +/* Convert a time_t to an MS FILETIME (MS-DTYP section 2.3.3). */ +static void time2filetime(struct ms_filetime *ft, time_t t) +{ +#if SIZEOF_TIME_T > 4 + t = (t + CURL_OFF_T_C(11644473600)) * 10000000; + ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF); + ft->dwHighDateTime = (unsigned int) (t >> 32); +#else + unsigned int r, s; + unsigned int i; + + ft->dwLowDateTime = t & 0xFFFFFFFF; + ft->dwHighDateTime = 0; + +# ifndef HAVE_TIME_T_UNSIGNED + /* Extend sign if needed. */ + if(ft->dwLowDateTime & 0x80000000) + ft->dwHighDateTime = ~0; +# endif + + /* Bias seconds to Jan 1, 1601. + 134774 days = 11644473600 seconds = 0x2B6109100 */ + r = ft->dwLowDateTime; + ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF; + ft->dwHighDateTime += ft->dwLowDateTime < r? 0x03: 0x02; + + /* Convert to tenths of microseconds. */ + ft->dwHighDateTime *= 10000000; + i = 32; + do { + i -= 8; + s = ((ft->dwLowDateTime >> i) & 0xFF) * (10000000 - 1); + r = (s << i) & 0xFFFFFFFF; + s >>= 1; /* Split shift to avoid width overflow. */ + s >>= 31 - i; + ft->dwLowDateTime = (ft->dwLowDateTime + r) & 0xFFFFFFFF; + if(ft->dwLowDateTime < r) + s++; + ft->dwHighDateTime += s; + } while(i); + ft->dwHighDateTime &= 0xFFFFFFFF; +#endif +} + +/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode + * (uppercase UserName + Domain) as the data + */ +CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, + const char *domain, size_t domlen, + unsigned char *ntlmhash, + unsigned char *ntlmv2hash) +{ + /* Unicode representation */ + size_t identity_len; + unsigned char *identity; + CURLcode result = CURLE_OK; + + if((userlen > CURL_MAX_INPUT_LENGTH) || (domlen > CURL_MAX_INPUT_LENGTH)) + return CURLE_OUT_OF_MEMORY; + + identity_len = (userlen + domlen) * 2; + identity = malloc(identity_len + 1); + + if(!identity) + return CURLE_OUT_OF_MEMORY; + + ascii_uppercase_to_unicode_le(identity, user, userlen); + ascii_to_unicode_le(identity + (userlen << 1), domain, domlen); + + result = Curl_hmacit(Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len, + ntlmv2hash); + free(identity); + + return result; +} + +/* + * Curl_ntlm_core_mk_ntlmv2_resp() + * + * This creates the NTLMv2 response as set in the ntlm type-3 message. + * + * Parameters: + * + * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) + * challenge_client [in] - The client nonce (8 bytes) + * ntlm [in] - The ntlm data struct being used to read TargetInfo + and Server challenge received in the type-2 message + * ntresp [out] - The address where a pointer to newly allocated + * memory holding the NTLMv2 response. + * ntresp_len [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + struct ntlmdata *ntlm, + unsigned char **ntresp, + unsigned int *ntresp_len) +{ +/* NTLMv2 response structure : +------------------------------------------------------------------------------ +0 HMAC MD5 16 bytes +------BLOB-------------------------------------------------------------------- +16 Signature 0x01010000 +20 Reserved long (0x00000000) +24 Timestamp LE, 64-bit signed value representing the number of + tenths of a microsecond since January 1, 1601. +32 Client Nonce 8 bytes +40 Unknown 4 bytes +44 Target Info N bytes (from the type-2 message) +44+N Unknown 4 bytes +------------------------------------------------------------------------------ +*/ + + unsigned int len = 0; + unsigned char *ptr = NULL; + unsigned char hmac_output[HMAC_MD5_LENGTH]; + struct ms_filetime tw; + + CURLcode result = CURLE_OK; + + /* Calculate the timestamp */ +#ifdef DEBUGBUILD + char *force_timestamp = getenv("CURL_FORCETIME"); + if(force_timestamp) + time2filetime(&tw, (time_t) 0); + else +#endif + time2filetime(&tw, time(NULL)); + + /* Calculate the response len */ + len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN; + + /* Allocate the response */ + ptr = calloc(1, len); + if(!ptr) + return CURLE_OUT_OF_MEMORY; + + /* Create the BLOB structure */ + msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN, + "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ + "%c%c%c%c" /* Reserved = 0 */ + "%c%c%c%c%c%c%c%c", /* Timestamp */ + NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], + NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], + 0, 0, 0, 0, + LONGQUARTET(tw.dwLowDateTime), LONGQUARTET(tw.dwHighDateTime)); + + memcpy(ptr + 32, challenge_client, 8); + if(ntlm->target_info_len) + memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len); + + /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */ + memcpy(ptr + 8, &ntlm->nonce[0], 8); + result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8, + NTLMv2_BLOB_LEN + 8, hmac_output); + if(result) { + free(ptr); + return result; + } + + /* Concatenate the HMAC MD5 output with the BLOB */ + memcpy(ptr, hmac_output, HMAC_MD5_LENGTH); + + /* Return the response */ + *ntresp = ptr; + *ntresp_len = len; + + return result; +} + +/* + * Curl_ntlm_core_mk_lmv2_resp() + * + * This creates the LMv2 response as used in the ntlm type-3 message. + * + * Parameters: + * + * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) + * challenge_client [in] - The client nonce (8 bytes) + * challenge_client [in] - The server challenge (8 bytes) + * lmresp [out] - The LMv2 response (24 bytes) + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + unsigned char *challenge_server, + unsigned char *lmresp) +{ + unsigned char data[16]; + unsigned char hmac_output[16]; + CURLcode result = CURLE_OK; + + memcpy(&data[0], challenge_server, 8); + memcpy(&data[8], challenge_client, 8); + + result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16, + hmac_output); + if(result) + return result; + + /* Concatenate the HMAC MD5 output with the client nonce */ + memcpy(lmresp, hmac_output, 16); + memcpy(lmresp + 16, challenge_client, 8); + + return result; +} + +#endif /* !USE_WINDOWS_SSPI */ + +#endif /* USE_CURL_NTLM_CORE */ diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h new file mode 100644 index 0000000..0c62ee0 --- /dev/null +++ b/lib/curl_ntlm_core.h @@ -0,0 +1,79 @@ +#ifndef HEADER_CURL_NTLM_CORE_H +#define HEADER_CURL_NTLM_CORE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_CURL_NTLM_CORE) + +#if defined(USE_OPENSSL) +# include +#elif defined(USE_WOLFSSL) +# include +# include +#endif + +/* Helpers to generate function byte arguments in little endian order */ +#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)) +#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \ + ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff)) + +void Curl_ntlm_core_lm_resp(const unsigned char *keys, + const unsigned char *plaintext, + unsigned char *results); + +CURLcode Curl_ntlm_core_mk_lm_hash(const char *password, + unsigned char *lmbuffer /* 21 bytes */); + +CURLcode Curl_ntlm_core_mk_nt_hash(const char *password, + unsigned char *ntbuffer /* 21 bytes */); + +#if !defined(USE_WINDOWS_SSPI) + +CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, + const unsigned char *data, unsigned int datalen, + unsigned char *output); + +CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, + const char *domain, size_t domlen, + unsigned char *ntlmhash, + unsigned char *ntlmv2hash); + +CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + struct ntlmdata *ntlm, + unsigned char **ntresp, + unsigned int *ntresp_len); + +CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + unsigned char *challenge_server, + unsigned char *lmresp); + +#endif /* !USE_WINDOWS_SSPI */ + +#endif /* USE_CURL_NTLM_CORE */ + +#endif /* HEADER_CURL_NTLM_CORE_H */ diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c new file mode 100644 index 0000000..0c7892a --- /dev/null +++ b/lib/curl_ntlm_wb.c @@ -0,0 +1,500 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + +/* + * NTLM details: + * + * https://davenport.sourceforge.net/ntlm.html + * https://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#include +#ifdef HAVE_PWD_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "select.h" +#include "vauth/ntlm.h" +#include "curl_ntlm_core.h" +#include "curl_ntlm_wb.h" +#include "url.h" +#include "strerror.h" +#include "strdup.h" +#include "strcase.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if DEBUG_ME +# define DEBUG_OUT(x) x +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +/* Portable 'sclose_nolog' used only in child process instead of 'sclose' + to avoid fooling the socket leak detector */ +#ifdef HAVE_PIPE +# define sclose_nolog(x) close((x)) +#elif defined(HAVE_CLOSESOCKET) +# define sclose_nolog(x) closesocket((x)) +#elif defined(HAVE_CLOSESOCKET_CAMEL) +# define sclose_nolog(x) CloseSocket((x)) +#else +# define sclose_nolog(x) close((x)) +#endif + +static void ntlm_wb_cleanup(struct ntlmdata *ntlm) +{ + if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { + sclose(ntlm->ntlm_auth_hlpr_socket); + ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + } + + if(ntlm->ntlm_auth_hlpr_pid) { + int i; + for(i = 0; i < 4; i++) { + pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG); + if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD) + break; + switch(i) { + case 0: + kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM); + break; + case 1: + /* Give the process another moment to shut down cleanly before + bringing down the axe */ + Curl_wait_ms(1); + break; + case 2: + kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL); + break; + case 3: + break; + } + } + ntlm->ntlm_auth_hlpr_pid = 0; + } + + Curl_safefree(ntlm->challenge); + Curl_safefree(ntlm->response); +} + +static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm, + const char *userp) +{ + curl_socket_t sockfds[2]; + pid_t child_pid; + const char *username; + char *slash, *domain = NULL; + const char *ntlm_auth = NULL; + char *ntlm_auth_alloc = NULL; +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + struct passwd pw, *pw_res; + char pwbuf[1024]; +#endif + char buffer[STRERROR_LEN]; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + /* Return if communication with ntlm_auth already set up */ + if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || + ntlm->ntlm_auth_hlpr_pid) + return CURLE_OK; + + username = userp; + /* The real ntlm_auth really doesn't like being invoked with an + empty username. It won't make inferences for itself, and expects + the client to do so (mostly because it's really designed for + servers like squid to use for auth, and client support is an + afterthought for it). So try hard to provide a suitable username + if we don't already have one. But if we can't, provide the + empty one anyway. Perhaps they have an implementation of the + ntlm_auth helper which *doesn't* need it so we might as well try */ + if(!username || !username[0]) { + username = getenv("NTLMUSER"); + if(!username || !username[0]) + username = getenv("LOGNAME"); + if(!username || !username[0]) + username = getenv("USER"); +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + if((!username || !username[0]) && + !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) && + pw_res) { + username = pw.pw_name; + } +#endif + if(!username || !username[0]) + username = userp; + } + slash = strpbrk(username, "\\/"); + if(slash) { + domain = strdup(username); + if(!domain) + return CURLE_OUT_OF_MEMORY; + slash = domain + (slash - username); + *slash = '\0'; + username = username + (slash - domain) + 1; + } + + /* For testing purposes, when DEBUGBUILD is defined and environment + variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform + NTLM challenge/response which only accepts commands and output + strings pre-written in test case definitions */ +#ifdef DEBUGBUILD + ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE"); + if(ntlm_auth_alloc) + ntlm_auth = ntlm_auth_alloc; + else +#endif + ntlm_auth = NTLM_WB_FILE; + + if(access(ntlm_auth, X_OK) != 0) { + failf(data, "Could not access ntlm_auth: %s errno %d: %s", + ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer))); + goto done; + } + + if(wakeup_create(sockfds)) { + failf(data, "Could not open socket pair. errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + goto done; + } + + child_pid = fork(); + if(child_pid == -1) { + wakeup_close(sockfds[0]); + wakeup_close(sockfds[1]); + failf(data, "Could not fork. errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + goto done; + } + else if(!child_pid) { + /* + * child process + */ + + /* Don't use sclose in the child since it fools the socket leak detector */ + sclose_nolog(sockfds[0]); + if(dup2(sockfds[1], STDIN_FILENO) == -1) { + failf(data, "Could not redirect child stdin. errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + exit(1); + } + + if(dup2(sockfds[1], STDOUT_FILENO) == -1) { + failf(data, "Could not redirect child stdout. errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + exit(1); + } + + if(domain) + execl(ntlm_auth, ntlm_auth, + "--helper-protocol", "ntlmssp-client-1", + "--use-cached-creds", + "--username", username, + "--domain", domain, + NULL); + else + execl(ntlm_auth, ntlm_auth, + "--helper-protocol", "ntlmssp-client-1", + "--use-cached-creds", + "--username", username, + NULL); + + sclose_nolog(sockfds[1]); + failf(data, "Could not execl(). errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + exit(1); + } + + sclose(sockfds[1]); + ntlm->ntlm_auth_hlpr_socket = sockfds[0]; + ntlm->ntlm_auth_hlpr_pid = child_pid; + free(domain); + free(ntlm_auth_alloc); + return CURLE_OK; + +done: + free(domain); + free(ntlm_auth_alloc); + return CURLE_REMOTE_ACCESS_DENIED; +} + +/* if larger than this, something is seriously wrong */ +#define MAX_NTLM_WB_RESPONSE 100000 + +static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, + const char *input, curlntlm state) +{ + size_t len_in = strlen(input), len_out = 0; + struct dynbuf b; + char *ptr = NULL; + usigned char buf[1024] + Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE); + + while(len_in > 0) { + ssize_t written = wakeup_write(ntlm->ntlm_auth_hlpr_socket, input, len_in); + if(written == -1) { + /* Interrupted by a signal, retry it */ + if(errno == EINTR) + continue; + /* write failed if other errors happen */ + goto done; + } + input += written; + len_in -= written; + } + /* Read one line */ + while(1) { + ssize_t size = + wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, sizeof(buf)); + if(size == -1) { + if(errno == EINTR) + continue; + goto done; + } + else if(size == 0) + goto done; + + if(Curl_dyn_addn(&b, buf, size)) + goto done; + + len_out = Curl_dyn_len(&b); + ptr = Curl_dyn_ptr(&b); + if(len_out && ptr[len_out - 1] == '\n') { + ptr[len_out - 1] = '\0'; + break; /* done! */ + } + /* loop */ + } + + /* Samba/winbind installed but not configured */ + if(state == NTLMSTATE_TYPE1 && + len_out == 3 && + ptr[0] == 'P' && ptr[1] == 'W') + goto done; + /* invalid response */ + if(len_out < 4) + goto done; + if(state == NTLMSTATE_TYPE1 && + (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' ')) + goto done; + if(state == NTLMSTATE_TYPE2 && + (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') && + (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' ')) + goto done; + + ntlm->response = strdup(ptr + 3); + Curl_dyn_free(&b); + if(!ntlm->response) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +done: + Curl_dyn_free(&b); + return CURLE_REMOTE_ACCESS_DENIED; +} + +CURLcode Curl_input_ntlm_wb(struct Curl_easy *data, + struct connectdata *conn, + bool proxy, + const char *header) +{ + struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; + curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; + + (void) data; /* In case it gets unused by nop log macros. */ + + if(!checkprefix("NTLM", header)) + return CURLE_BAD_CONTENT_ENCODING; + + header += strlen("NTLM"); + while(*header && ISSPACE(*header)) + header++; + + if(*header) { + ntlm->challenge = strdup(header); + if(!ntlm->challenge) + return CURLE_OUT_OF_MEMORY; + + *state = NTLMSTATE_TYPE2; /* We got a type-2 message */ + } + else { + if(*state == NTLMSTATE_LAST) { + infof(data, "NTLM auth restarted"); + Curl_http_auth_cleanup_ntlm_wb(conn); + } + else if(*state == NTLMSTATE_TYPE3) { + infof(data, "NTLM handshake rejected"); + Curl_http_auth_cleanup_ntlm_wb(conn); + *state = NTLMSTATE_NONE; + return CURLE_REMOTE_ACCESS_DENIED; + } + else if(*state >= NTLMSTATE_TYPE1) { + infof(data, "NTLM handshake failure (internal error)"); + return CURLE_REMOTE_ACCESS_DENIED; + } + + *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ + } + + return CURLE_OK; +} + +/* + * This is for creating ntlm header output by delegating challenge/response + * to Samba's winbind daemon helper ntlm_auth. + */ +CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn, + bool proxy) +{ + /* point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for an HTTP proxy */ + char **allocuserpwd; + /* point to the name and password for this */ + const char *userp; + struct ntlmdata *ntlm; + curlntlm *state; + struct auth *authp; + + CURLcode res = CURLE_OK; + + DEBUGASSERT(conn); + DEBUGASSERT(data); + + if(proxy) { +#ifndef CURL_DISABLE_PROXY + allocuserpwd = &data->state.aptr.proxyuserpwd; + userp = conn->http_proxy.user; + ntlm = &conn->proxyntlm; + state = &conn->proxy_ntlm_state; + authp = &data->state.authproxy; +#else + return CURLE_NOT_BUILT_IN; +#endif + } + else { + allocuserpwd = &data->state.aptr.userpwd; + userp = conn->user; + ntlm = &conn->ntlm; + state = &conn->http_ntlm_state; + authp = &data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp = ""; + + switch(*state) { + case NTLMSTATE_TYPE1: + default: + /* Use Samba's 'winbind' daemon to support NTLM authentication, + * by delegating the NTLM challenge/response protocol to a helper + * in ntlm_auth. + * https://web.archive.org/web/20190925164737 + * /devel.squid-cache.org/ntlm/squid_helper_protocol.html + * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html + * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html + * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this + * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute + * filename of ntlm_auth helper. + * If NTLM authentication using winbind fails, go back to original + * request handling process. + */ + /* Create communication with ntlm_auth */ + res = ntlm_wb_init(data, ntlm, userp); + if(res) + return res; + res = ntlm_wb_response(data, ntlm, "YR\n", *state); + if(res) + return res; + + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + ntlm->response); + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + Curl_safefree(ntlm->response); + if(!*allocuserpwd) + return CURLE_OUT_OF_MEMORY; + break; + + case NTLMSTATE_TYPE2: { + char *input = aprintf("TT %s\n", ntlm->challenge); + if(!input) + return CURLE_OUT_OF_MEMORY; + res = ntlm_wb_response(data, ntlm, input, *state); + free(input); + if(res) + return res; + + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + ntlm->response); + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + *state = NTLMSTATE_TYPE3; /* we sent a type-3 */ + authp->done = TRUE; + Curl_http_auth_cleanup_ntlm_wb(conn); + if(!*allocuserpwd) + return CURLE_OUT_OF_MEMORY; + break; + } + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + *state = NTLMSTATE_LAST; + FALLTHROUGH(); + case NTLMSTATE_LAST: + Curl_safefree(*allocuserpwd); + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + +void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn) +{ + ntlm_wb_cleanup(&conn->ntlm); + ntlm_wb_cleanup(&conn->proxyntlm); +} + +#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ diff --git a/lib/curl_ntlm_wb.h b/lib/curl_ntlm_wb.h new file mode 100644 index 0000000..37704c0 --- /dev/null +++ b/lib/curl_ntlm_wb.h @@ -0,0 +1,45 @@ +#ifndef HEADER_CURL_NTLM_WB_H +#define HEADER_CURL_NTLM_WB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + +/* this is for ntlm header input */ +CURLcode Curl_input_ntlm_wb(struct Curl_easy *data, + struct connectdata *conn, bool proxy, + const char *header); + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn, + bool proxy); + +void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn); + +#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ + +#endif /* HEADER_CURL_NTLM_WB_H */ diff --git a/lib/curl_path.c b/lib/curl_path.c new file mode 100644 index 0000000..856423d --- /dev/null +++ b/lib/curl_path.c @@ -0,0 +1,199 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl AND ISC + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_SSH) + +#include +#include "curl_memory.h" +#include "curl_path.h" +#include "escape.h" +#include "memdebug.h" + +#define MAX_SSHPATH_LEN 100000 /* arbitrary */ + +/* figure out the path to work with in this particular request */ +CURLcode Curl_getworkingpath(struct Curl_easy *data, + char *homedir, /* when SFTP is used */ + char **path) /* returns the allocated + real path to work with */ +{ + char *working_path; + size_t working_path_len; + struct dynbuf npath; + CURLcode result = + Curl_urldecode(data->state.up.path, 0, &working_path, + &working_path_len, REJECT_ZERO); + if(result) + return result; + + /* new path to switch to in case we need to */ + Curl_dyn_init(&npath, MAX_SSHPATH_LEN); + + /* Check for /~/, indicating relative to the user's home directory */ + if((data->conn->handler->protocol & CURLPROTO_SCP) && + (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) { + /* It is referenced to the home directory, so strip the leading '/~/' */ + if(Curl_dyn_addn(&npath, &working_path[3], working_path_len - 3)) { + free(working_path); + return CURLE_OUT_OF_MEMORY; + } + } + else if((data->conn->handler->protocol & CURLPROTO_SFTP) && + (!strcmp("/~", working_path) || + ((working_path_len > 2) && !memcmp(working_path, "/~/", 3)))) { + if(Curl_dyn_add(&npath, homedir)) { + free(working_path); + return CURLE_OUT_OF_MEMORY; + } + if(working_path_len > 2) { + size_t len; + const char *p; + int copyfrom = 3; + /* Copy a separating '/' if homedir does not end with one */ + len = Curl_dyn_len(&npath); + p = Curl_dyn_ptr(&npath); + if(len && (p[len-1] != '/')) + copyfrom = 2; + + if(Curl_dyn_addn(&npath, + &working_path[copyfrom], working_path_len - copyfrom)) { + free(working_path); + return CURLE_OUT_OF_MEMORY; + } + } + } + + if(Curl_dyn_len(&npath)) { + free(working_path); + + /* store the pointer for the caller to receive */ + *path = Curl_dyn_ptr(&npath); + } + else + *path = working_path; + + return CURLE_OK; +} + +/* The get_pathname() function is being borrowed from OpenSSH sftp.c + version 4.6p1. */ +/* + * Copyright (c) 2001-2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir) +{ + const char *cp = *cpp, *end; + char quot; + unsigned int i, j; + size_t fullPathLength, pathLength; + bool relativePath = false; + static const char WHITESPACE[] = " \t\r\n"; + + DEBUGASSERT(homedir); + if(!*cp || !homedir) { + *cpp = NULL; + *path = NULL; + return CURLE_QUOTE_ERROR; + } + /* Ignore leading whitespace */ + cp += strspn(cp, WHITESPACE); + /* Allocate enough space for home directory and filename + separator */ + fullPathLength = strlen(cp) + strlen(homedir) + 2; + *path = malloc(fullPathLength); + if(!*path) + return CURLE_OUT_OF_MEMORY; + + /* Check for quoted filenames */ + if(*cp == '\"' || *cp == '\'') { + quot = *cp++; + + /* Search for terminating quote, unescape some chars */ + for(i = j = 0; i <= strlen(cp); i++) { + if(cp[i] == quot) { /* Found quote */ + i++; + (*path)[j] = '\0'; + break; + } + if(cp[i] == '\0') { /* End of string */ + goto fail; + } + if(cp[i] == '\\') { /* Escaped characters */ + i++; + if(cp[i] != '\'' && cp[i] != '\"' && + cp[i] != '\\') { + goto fail; + } + } + (*path)[j++] = cp[i]; + } + + if(j == 0) { + goto fail; + } + *cpp = cp + i + strspn(cp + i, WHITESPACE); + } + else { + /* Read to end of filename - either to whitespace or terminator */ + end = strpbrk(cp, WHITESPACE); + if(!end) + end = strchr(cp, '\0'); + /* return pointer to second parameter if it exists */ + *cpp = end + strspn(end, WHITESPACE); + pathLength = 0; + relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/'); + /* Handling for relative path - prepend home directory */ + if(relativePath) { + strcpy(*path, homedir); + pathLength = strlen(homedir); + (*path)[pathLength++] = '/'; + (*path)[pathLength] = '\0'; + cp += 3; + } + /* Copy path name up until first "whitespace" */ + memcpy(&(*path)[pathLength], cp, (int)(end - cp)); + pathLength += (int)(end - cp); + (*path)[pathLength] = '\0'; + } + return CURLE_OK; + +fail: + Curl_safefree(*path); + return CURLE_QUOTE_ERROR; +} + +#endif /* if SSH is used */ diff --git a/lib/curl_path.h b/lib/curl_path.h new file mode 100644 index 0000000..cbe51c2 --- /dev/null +++ b/lib/curl_path.h @@ -0,0 +1,49 @@ +#ifndef HEADER_CURL_PATH_H +#define HEADER_CURL_PATH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include +#include "urldata.h" + +#ifdef _WIN32 +# undef PATH_MAX +# define PATH_MAX MAX_PATH +# ifndef R_OK +# define R_OK 4 +# endif +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 /* just an extra precaution since there are systems that + have their definition hidden well */ +#endif + +CURLcode Curl_getworkingpath(struct Curl_easy *data, + char *homedir, + char **path); + +CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir); +#endif /* HEADER_CURL_PATH_H */ diff --git a/lib/curl_printf.h b/lib/curl_printf.h new file mode 100644 index 0000000..c2457d2 --- /dev/null +++ b/lib/curl_printf.h @@ -0,0 +1,55 @@ +#ifndef HEADER_CURL_PRINTF_H +#define HEADER_CURL_PRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * This header should be included by ALL code in libcurl that uses any + * *rintf() functions. + */ + +#include + +#define MERR_OK 0 +#define MERR_MEM 1 +#define MERR_TOO_LARGE 2 + +# undef printf +# undef fprintf +# undef msnprintf +# undef vprintf +# undef vfprintf +# undef vsnprintf +# undef mvsnprintf +# undef aprintf +# undef vaprintf +# define printf curl_mprintf +# define fprintf curl_mfprintf +# define msnprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define mvsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf +#endif /* HEADER_CURL_PRINTF_H */ diff --git a/lib/curl_range.c b/lib/curl_range.c new file mode 100644 index 0000000..d499953 --- /dev/null +++ b/lib/curl_range.c @@ -0,0 +1,96 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include +#include "curl_range.h" +#include "sendf.h" +#include "strtoofft.h" + +/* Only include this function if one or more of FTP, FILE are enabled. */ +#if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE) + + /* + Check if this is a range download, and if so, set the internal variables + properly. + */ +CURLcode Curl_range(struct Curl_easy *data) +{ + curl_off_t from, to; + char *ptr; + char *ptr2; + + if(data->state.use_range && data->state.range) { + CURLofft from_t; + CURLofft to_t; + from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from); + if(from_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) + ptr++; + to_t = curlx_strtoofft(ptr, &ptr2, 10, &to); + if(to_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + if((to_t == CURL_OFFT_INVAL) && !from_t) { + /* X - */ + data->state.resume_from = from; + DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file", + from)); + } + else if((from_t == CURL_OFFT_INVAL) && !to_t) { + /* -Y */ + data->req.maxdownload = to; + data->state.resume_from = -to; + DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes", + to)); + } + else { + /* X-Y */ + curl_off_t totalsize; + + /* Ensure the range is sensible - to should follow from. */ + if(from > to) + return CURLE_RANGE_ERROR; + + totalsize = to - from; + if(totalsize == CURL_OFF_T_MAX) + return CURLE_RANGE_ERROR; + + data->req.maxdownload = totalsize + 1; /* include last byte */ + data->state.resume_from = from; + DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T + " getting %" CURL_FORMAT_CURL_OFF_T " bytes", + from, data->req.maxdownload)); + } + DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T + " to %" CURL_FORMAT_CURL_OFF_T ", totally %" + CURL_FORMAT_CURL_OFF_T " bytes", + from, to, data->req.maxdownload)); + } + else + data->req.maxdownload = -1; + return CURLE_OK; +} + +#endif diff --git a/lib/curl_range.h b/lib/curl_range.h new file mode 100644 index 0000000..77679e2 --- /dev/null +++ b/lib/curl_range.h @@ -0,0 +1,31 @@ +#ifndef HEADER_CURL_RANGE_H +#define HEADER_CURL_RANGE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "urldata.h" + +CURLcode Curl_range(struct Curl_easy *data); +#endif /* HEADER_CURL_RANGE_H */ diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c new file mode 100644 index 0000000..147b12a --- /dev/null +++ b/lib/curl_rtmp.c @@ -0,0 +1,338 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Howard Chu, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_LIBRTMP + +#include "curl_rtmp.h" +#include "urldata.h" +#include "nonblock.h" /* for curlx_nonblock */ +#include "progress.h" /* for Curl_pgrsSetUploadSize */ +#include "transfer.h" +#include "warnless.h" +#include +#include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +#if defined(_WIN32) && !defined(USE_LWIPSOCK) +#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e) +#define SET_RCVTIMEO(tv,s) int tv = s*1000 +#elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD) +#define SET_RCVTIMEO(tv,s) int tv = s*1000 +#else +#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0} +#endif + +#define DEF_BUFTIME (2*60*60*1000) /* 2 hours */ + +static CURLcode rtmp_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static CURLcode rtmp_do(struct Curl_easy *data, bool *done); +static CURLcode rtmp_done(struct Curl_easy *data, CURLcode, bool premature); +static CURLcode rtmp_connect(struct Curl_easy *data, bool *done); +static CURLcode rtmp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); + +static Curl_recv rtmp_recv; +static Curl_send rtmp_send; + +/* + * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu + */ + +const struct Curl_handler Curl_handler_rtmp = { + "RTMP", /* scheme */ + rtmp_setup_connection, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_RTMP, /* defport */ + CURLPROTO_RTMP, /* protocol */ + CURLPROTO_RTMP, /* family */ + PROTOPT_NONE /* flags */ +}; + +const struct Curl_handler Curl_handler_rtmpt = { + "RTMPT", /* scheme */ + rtmp_setup_connection, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_RTMPT, /* defport */ + CURLPROTO_RTMPT, /* protocol */ + CURLPROTO_RTMPT, /* family */ + PROTOPT_NONE /* flags */ +}; + +const struct Curl_handler Curl_handler_rtmpe = { + "RTMPE", /* scheme */ + rtmp_setup_connection, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_RTMP, /* defport */ + CURLPROTO_RTMPE, /* protocol */ + CURLPROTO_RTMPE, /* family */ + PROTOPT_NONE /* flags */ +}; + +const struct Curl_handler Curl_handler_rtmpte = { + "RTMPTE", /* scheme */ + rtmp_setup_connection, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_RTMPT, /* defport */ + CURLPROTO_RTMPTE, /* protocol */ + CURLPROTO_RTMPTE, /* family */ + PROTOPT_NONE /* flags */ +}; + +const struct Curl_handler Curl_handler_rtmps = { + "RTMPS", /* scheme */ + rtmp_setup_connection, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_RTMPS, /* defport */ + CURLPROTO_RTMPS, /* protocol */ + CURLPROTO_RTMP, /* family */ + PROTOPT_NONE /* flags */ +}; + +const struct Curl_handler Curl_handler_rtmpts = { + "RTMPTS", /* scheme */ + rtmp_setup_connection, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_RTMPS, /* defport */ + CURLPROTO_RTMPTS, /* protocol */ + CURLPROTO_RTMPT, /* family */ + PROTOPT_NONE /* flags */ +}; + +static CURLcode rtmp_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + RTMP *r = RTMP_Alloc(); + if(!r) + return CURLE_OUT_OF_MEMORY; + + RTMP_Init(r); + RTMP_SetBufferMS(r, DEF_BUFTIME); + if(!RTMP_SetupURL(r, data->state.url)) { + RTMP_Free(r); + return CURLE_URL_MALFORMAT; + } + conn->proto.rtmp = r; + return CURLE_OK; +} + +static CURLcode rtmp_connect(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + RTMP *r = conn->proto.rtmp; + SET_RCVTIMEO(tv, 10); + + r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET]; + + /* We have to know if it's a write before we send the + * connect request packet + */ + if(data->state.upload) + r->Link.protocol |= RTMP_FEATURE_WRITE; + + /* For plain streams, use the buffer toggle trick to keep data flowing */ + if(!(r->Link.lFlags & RTMP_LF_LIVE) && + !(r->Link.protocol & RTMP_FEATURE_HTTP)) + r->Link.lFlags |= RTMP_LF_BUFX; + + (void)curlx_nonblock(r->m_sb.sb_socket, FALSE); + setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, + (char *)&tv, sizeof(tv)); + + if(!RTMP_Connect1(r, NULL)) + return CURLE_FAILED_INIT; + + /* Clients must send a periodic BytesReceived report to the server */ + r->m_bSendCounter = true; + + *done = TRUE; + conn->recv[FIRSTSOCKET] = rtmp_recv; + conn->send[FIRSTSOCKET] = rtmp_send; + return CURLE_OK; +} + +static CURLcode rtmp_do(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + RTMP *r = conn->proto.rtmp; + + if(!RTMP_ConnectStream(r, 0)) + return CURLE_FAILED_INIT; + + if(data->state.upload) { + Curl_pgrsSetUploadSize(data, data->state.infilesize); + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + } + else + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + *done = TRUE; + return CURLE_OK; +} + +static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + (void)data; /* unused */ + (void)status; /* unused */ + (void)premature; /* unused */ + + return CURLE_OK; +} + +static CURLcode rtmp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + RTMP *r = conn->proto.rtmp; + (void)data; + (void)dead_connection; + if(r) { + conn->proto.rtmp = NULL; + RTMP_Close(r); + RTMP_Free(r); + } + return CURLE_OK; +} + +static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf, + size_t len, CURLcode *err) +{ + struct connectdata *conn = data->conn; + RTMP *r = conn->proto.rtmp; + ssize_t nread; + + (void)sockindex; /* unused */ + + nread = RTMP_Read(r, buf, curlx_uztosi(len)); + if(nread < 0) { + if(r->m_read.status == RTMP_READ_COMPLETE || + r->m_read.status == RTMP_READ_EOF) { + data->req.size = data->req.bytecount; + nread = 0; + } + else + *err = CURLE_RECV_ERROR; + } + return nread; +} + +static ssize_t rtmp_send(struct Curl_easy *data, int sockindex, + const void *buf, size_t len, CURLcode *err) +{ + struct connectdata *conn = data->conn; + RTMP *r = conn->proto.rtmp; + ssize_t num; + + (void)sockindex; /* unused */ + + num = RTMP_Write(r, (char *)buf, curlx_uztosi(len)); + if(num < 0) + *err = CURLE_SEND_ERROR; + + return num; +} +#endif /* USE_LIBRTMP */ diff --git a/lib/curl_rtmp.h b/lib/curl_rtmp.h new file mode 100644 index 0000000..9b93ee0 --- /dev/null +++ b/lib/curl_rtmp.h @@ -0,0 +1,35 @@ +#ifndef HEADER_CURL_RTMP_H +#define HEADER_CURL_RTMP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Howard Chu, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifdef USE_LIBRTMP +extern const struct Curl_handler Curl_handler_rtmp; +extern const struct Curl_handler Curl_handler_rtmpt; +extern const struct Curl_handler Curl_handler_rtmpe; +extern const struct Curl_handler Curl_handler_rtmpte; +extern const struct Curl_handler Curl_handler_rtmps; +extern const struct Curl_handler Curl_handler_rtmpts; +#endif + +#endif /* HEADER_CURL_RTMP_H */ diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c new file mode 100644 index 0000000..66639cb --- /dev/null +++ b/lib/curl_sasl.c @@ -0,0 +1,760 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC2195 CRAM-MD5 authentication + * RFC2617 Basic and Digest Access Authentication + * RFC2831 DIGEST-MD5 authentication + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4616 PLAIN authentication + * RFC5802 SCRAM-SHA-1 authentication + * RFC7677 SCRAM-SHA-256 authentication + * RFC6749 OAuth 2.0 Authorization Framework + * RFC7628 A Set of SASL Mechanisms for OAuth + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_POP3) || \ + (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)) + +#include +#include "urldata.h" + +#include "curl_base64.h" +#include "curl_md5.h" +#include "vauth/vauth.h" +#include "cfilters.h" +#include "vtls/vtls.h" +#include "curl_hmac.h" +#include "curl_sasl.h" +#include "warnless.h" +#include "strtok.h" +#include "sendf.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* Supported mechanisms */ +static const struct { + const char *name; /* Name */ + size_t len; /* Name length */ + unsigned short bit; /* Flag bit */ +} mechtable[] = { + { "LOGIN", 5, SASL_MECH_LOGIN }, + { "PLAIN", 5, SASL_MECH_PLAIN }, + { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 }, + { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 }, + { "GSSAPI", 6, SASL_MECH_GSSAPI }, + { "EXTERNAL", 8, SASL_MECH_EXTERNAL }, + { "NTLM", 4, SASL_MECH_NTLM }, + { "XOAUTH2", 7, SASL_MECH_XOAUTH2 }, + { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER }, + { "SCRAM-SHA-1", 11, SASL_MECH_SCRAM_SHA_1 }, + { "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 }, + { ZERO_NULL, 0, 0 } +}; + +/* + * Curl_sasl_cleanup() + * + * This is used to cleanup any libraries or curl modules used by the sasl + * functions. + * + * Parameters: + * + * conn [in] - The connection data. + * authused [in] - The authentication mechanism used. + */ +void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused) +{ + (void)conn; + (void)authused; + +#if defined(USE_KERBEROS5) + /* Cleanup the gssapi structure */ + if(authused == SASL_MECH_GSSAPI) { + Curl_auth_cleanup_gssapi(&conn->krb5); + } +#endif + +#if defined(USE_GSASL) + /* Cleanup the GSASL structure */ + if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) { + Curl_auth_gsasl_cleanup(&conn->gsasl); + } +#endif + +#if defined(USE_NTLM) + /* Cleanup the NTLM structure */ + if(authused == SASL_MECH_NTLM) { + Curl_auth_cleanup_ntlm(&conn->ntlm); + } +#endif +} + +/* + * Curl_sasl_decode_mech() + * + * Convert a SASL mechanism name into a token. + * + * Parameters: + * + * ptr [in] - The mechanism string. + * maxlen [in] - Maximum mechanism string length. + * len [out] - If not NULL, effective name length. + * + * Returns the SASL mechanism token or 0 if no match. + */ +unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen, + size_t *len) +{ + unsigned int i; + char c; + + for(i = 0; mechtable[i].name; i++) { + if(maxlen >= mechtable[i].len && + !memcmp(ptr, mechtable[i].name, mechtable[i].len)) { + if(len) + *len = mechtable[i].len; + + if(maxlen == mechtable[i].len) + return mechtable[i].bit; + + c = ptr[mechtable[i].len]; + if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_') + return mechtable[i].bit; + } + } + + return 0; +} + +/* + * Curl_sasl_parse_url_auth_option() + * + * Parse the URL login options. + */ +CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, + const char *value, size_t len) +{ + CURLcode result = CURLE_OK; + size_t mechlen; + + if(!len) + return CURLE_URL_MALFORMAT; + + if(sasl->resetprefs) { + sasl->resetprefs = FALSE; + sasl->prefmech = SASL_AUTH_NONE; + } + + if(!strncmp(value, "*", len)) + sasl->prefmech = SASL_AUTH_DEFAULT; + else { + unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen); + if(mechbit && mechlen == len) + sasl->prefmech |= mechbit; + else + result = CURLE_URL_MALFORMAT; + } + + return result; +} + +/* + * Curl_sasl_init() + * + * Initializes the SASL structure. + */ +void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data, + const struct SASLproto *params) +{ + unsigned long auth = data->set.httpauth; + + sasl->params = params; /* Set protocol dependent parameters */ + sasl->state = SASL_STOP; /* Not yet running */ + sasl->curmech = NULL; /* No mechanism yet. */ + sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ + sasl->prefmech = params->defmechs; /* Default preferred mechanisms */ + sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */ + sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ + sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ + sasl->force_ir = FALSE; /* Respect external option */ + + if(auth != CURLAUTH_BASIC) { + unsigned short mechs = SASL_AUTH_NONE; + + /* If some usable http authentication options have been set, determine + new defaults from them. */ + if(auth & CURLAUTH_BASIC) + mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN; + if(auth & CURLAUTH_DIGEST) + mechs |= SASL_MECH_DIGEST_MD5; + if(auth & CURLAUTH_NTLM) + mechs |= SASL_MECH_NTLM; + if(auth & CURLAUTH_BEARER) + mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2; + if(auth & CURLAUTH_GSSAPI) + mechs |= SASL_MECH_GSSAPI; + + if(mechs != SASL_AUTH_NONE) + sasl->prefmech = mechs; + } +} + +/* + * sasl_state() + * + * This is the ONLY way to change SASL state! + */ +static void sasl_state(struct SASL *sasl, struct Curl_easy *data, + saslstate newstate) +{ +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[]={ + "STOP", + "PLAIN", + "LOGIN", + "LOGIN_PASSWD", + "EXTERNAL", + "CRAMMD5", + "DIGESTMD5", + "DIGESTMD5_RESP", + "NTLM", + "NTLM_TYPE2MSG", + "GSSAPI", + "GSSAPI_TOKEN", + "GSSAPI_NO_DATA", + "OAUTH2", + "OAUTH2_RESP", + "GSASL", + "CANCEL", + "FINAL", + /* LAST */ + }; + + if(sasl->state != newstate) + infof(data, "SASL %p state change from %s to %s", + (void *)sasl, names[sasl->state], names[newstate]); +#else + (void) data; +#endif + + sasl->state = newstate; +} + +#if defined(USE_NTLM) || defined(USE_GSASL) || defined(USE_KERBEROS5) || \ + !defined(CURL_DISABLE_DIGEST_AUTH) +/* Get the SASL server message and convert it to binary. */ +static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data, + struct bufref *out) +{ + CURLcode result = CURLE_OK; + + result = sasl->params->getmessage(data, out); + if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) { + unsigned char *msg; + size_t msglen; + const char *serverdata = (const char *) Curl_bufref_ptr(out); + + if(!*serverdata || *serverdata == '=') + Curl_bufref_set(out, NULL, 0, NULL); + else { + result = Curl_base64_decode(serverdata, &msg, &msglen); + if(!result) + Curl_bufref_set(out, msg, msglen, curl_free); + } + } + return result; +} +#endif + +/* Encode the outgoing SASL message. */ +static CURLcode build_message(struct SASL *sasl, struct bufref *msg) +{ + CURLcode result = CURLE_OK; + + if(sasl->params->flags & SASL_FLAG_BASE64) { + if(!Curl_bufref_ptr(msg)) /* Empty message. */ + Curl_bufref_set(msg, "", 0, NULL); + else if(!Curl_bufref_len(msg)) /* Explicit empty response. */ + Curl_bufref_set(msg, "=", 1, NULL); + else { + char *base64; + size_t base64len; + + result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg), + Curl_bufref_len(msg), &base64, &base64len); + if(!result) + Curl_bufref_set(msg, base64, base64len, curl_free); + } + } + + return result; +} + +/* + * Curl_sasl_can_authenticate() + * + * Check if we have enough auth data and capabilities to authenticate. + */ +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data) +{ + /* Have credentials been provided? */ + if(data->state.aptr.user) + return TRUE; + + /* EXTERNAL can authenticate without a user name and/or password */ + if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL) + return TRUE; + + return FALSE; +} + +/* + * Curl_sasl_start() + * + * Calculate the required login details for SASL authentication. + */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, + bool force_ir, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + unsigned short enabledmechs; + const char *mech = NULL; + struct bufref resp; + saslstate state1 = SASL_STOP; + saslstate state2 = SASL_FINAL; + const char *hostname, *disp_hostname; + int port; +#if defined(USE_KERBEROS5) || defined(USE_NTLM) + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; +#endif + const char *oauth_bearer = data->set.str[STRING_BEARER]; + struct bufref nullmsg; + + Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port); + Curl_bufref_init(&nullmsg); + Curl_bufref_init(&resp); + sasl->force_ir = force_ir; /* Latch for future use */ + sasl->authused = 0; /* No mechanism used yet */ + enabledmechs = sasl->authmechs & sasl->prefmech; + *progress = SASL_IDLE; + + /* Calculate the supported authentication mechanism, by decreasing order of + security, as well as the initial response where appropriate */ + if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { + mech = SASL_MECH_STRING_EXTERNAL; + state1 = SASL_EXTERNAL; + sasl->authused = SASL_MECH_EXTERNAL; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_external_message(conn->user, &resp); + } + else if(data->state.aptr.user) { +#if defined(USE_KERBEROS5) + if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && + Curl_auth_user_contains_domain(conn->user)) { + sasl->mutual_auth = FALSE; + mech = SASL_MECH_STRING_GSSAPI; + state1 = SASL_GSSAPI; + state2 = SASL_GSSAPI_TOKEN; + sasl->authused = SASL_MECH_GSSAPI; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_gssapi_user_message(data, conn->user, + conn->passwd, + service, + conn->host.name, + sasl->mutual_auth, + NULL, &conn->krb5, + &resp); + } + else +#endif +#ifdef USE_GSASL + if((enabledmechs & SASL_MECH_SCRAM_SHA_256) && + Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256, + &conn->gsasl)) { + mech = SASL_MECH_STRING_SCRAM_SHA_256; + sasl->authused = SASL_MECH_SCRAM_SHA_256; + state1 = SASL_GSASL; + state2 = SASL_GSASL; + + result = Curl_auth_gsasl_start(data, conn->user, + conn->passwd, &conn->gsasl); + if(result == CURLE_OK && (force_ir || data->set.sasl_ir)) + result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp); + } + else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) && + Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1, + &conn->gsasl)) { + mech = SASL_MECH_STRING_SCRAM_SHA_1; + sasl->authused = SASL_MECH_SCRAM_SHA_1; + state1 = SASL_GSASL; + state2 = SASL_GSASL; + + result = Curl_auth_gsasl_start(data, conn->user, + conn->passwd, &conn->gsasl); + if(result == CURLE_OK && (force_ir || data->set.sasl_ir)) + result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp); + } + else +#endif +#ifndef CURL_DISABLE_DIGEST_AUTH + if((enabledmechs & SASL_MECH_DIGEST_MD5) && + Curl_auth_is_digest_supported()) { + mech = SASL_MECH_STRING_DIGEST_MD5; + state1 = SASL_DIGESTMD5; + sasl->authused = SASL_MECH_DIGEST_MD5; + } + else if(enabledmechs & SASL_MECH_CRAM_MD5) { + mech = SASL_MECH_STRING_CRAM_MD5; + state1 = SASL_CRAMMD5; + sasl->authused = SASL_MECH_CRAM_MD5; + } + else +#endif +#ifdef USE_NTLM + if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { + mech = SASL_MECH_STRING_NTLM; + state1 = SASL_NTLM; + state2 = SASL_NTLM_TYPE2MSG; + sasl->authused = SASL_MECH_NTLM; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_ntlm_type1_message(data, + conn->user, conn->passwd, + service, + hostname, + &conn->ntlm, &resp); + } + else +#endif + if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) { + mech = SASL_MECH_STRING_OAUTHBEARER; + state1 = SASL_OAUTH2; + state2 = SASL_OAUTH2_RESP; + sasl->authused = SASL_MECH_OAUTHBEARER; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_oauth_bearer_message(conn->user, + hostname, + port, + oauth_bearer, + &resp); + } + else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) { + mech = SASL_MECH_STRING_XOAUTH2; + state1 = SASL_OAUTH2; + sasl->authused = SASL_MECH_XOAUTH2; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_xoauth_bearer_message(conn->user, + oauth_bearer, + &resp); + } + else if(enabledmechs & SASL_MECH_PLAIN) { + mech = SASL_MECH_STRING_PLAIN; + state1 = SASL_PLAIN; + sasl->authused = SASL_MECH_PLAIN; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_plain_message(conn->sasl_authzid, + conn->user, conn->passwd, + &resp); + } + else if(enabledmechs & SASL_MECH_LOGIN) { + mech = SASL_MECH_STRING_LOGIN; + state1 = SASL_LOGIN; + state2 = SASL_LOGIN_PASSWD; + sasl->authused = SASL_MECH_LOGIN; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_login_message(conn->user, &resp); + } + } + + if(!result && mech) { + sasl->curmech = mech; + if(Curl_bufref_ptr(&resp)) + result = build_message(sasl, &resp); + + if(sasl->params->maxirlen && + strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen) + Curl_bufref_free(&resp); + + if(!result) + result = sasl->params->sendauth(data, mech, &resp); + + if(!result) { + *progress = SASL_INPROGRESS; + sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1); + } + } + + Curl_bufref_free(&resp); + return result; +} + +/* + * Curl_sasl_continue() + * + * Continue the authentication. + */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, + int code, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + saslstate newstate = SASL_FINAL; + struct bufref resp; + const char *hostname, *disp_hostname; + int port; +#if defined(USE_KERBEROS5) || defined(USE_NTLM) \ + || !defined(CURL_DISABLE_DIGEST_AUTH) + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; +#endif + const char *oauth_bearer = data->set.str[STRING_BEARER]; + struct bufref serverdata; + + Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port); + Curl_bufref_init(&serverdata); + Curl_bufref_init(&resp); + *progress = SASL_INPROGRESS; + + if(sasl->state == SASL_FINAL) { + if(code != sasl->params->finalcode) + result = CURLE_LOGIN_DENIED; + *progress = SASL_DONE; + sasl_state(sasl, data, SASL_STOP); + return result; + } + + if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP && + code != sasl->params->contcode) { + *progress = SASL_DONE; + sasl_state(sasl, data, SASL_STOP); + return CURLE_LOGIN_DENIED; + } + + switch(sasl->state) { + case SASL_STOP: + *progress = SASL_DONE; + return result; + case SASL_PLAIN: + result = Curl_auth_create_plain_message(conn->sasl_authzid, + conn->user, conn->passwd, &resp); + break; + case SASL_LOGIN: + result = Curl_auth_create_login_message(conn->user, &resp); + newstate = SASL_LOGIN_PASSWD; + break; + case SASL_LOGIN_PASSWD: + result = Curl_auth_create_login_message(conn->passwd, &resp); + break; + case SASL_EXTERNAL: + result = Curl_auth_create_external_message(conn->user, &resp); + break; +#ifdef USE_GSASL + case SASL_GSASL: + result = get_server_message(sasl, data, &serverdata); + if(!result) + result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp); + if(!result && Curl_bufref_len(&resp) > 0) + newstate = SASL_GSASL; + break; +#endif +#ifndef CURL_DISABLE_DIGEST_AUTH + case SASL_CRAMMD5: + result = get_server_message(sasl, data, &serverdata); + if(!result) + result = Curl_auth_create_cram_md5_message(&serverdata, conn->user, + conn->passwd, &resp); + break; + case SASL_DIGESTMD5: + result = get_server_message(sasl, data, &serverdata); + if(!result) + result = Curl_auth_create_digest_md5_message(data, &serverdata, + conn->user, conn->passwd, + service, &resp); + if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) + newstate = SASL_DIGESTMD5_RESP; + break; + case SASL_DIGESTMD5_RESP: + /* Keep response NULL to output an empty line. */ + break; +#endif + +#ifdef USE_NTLM + case SASL_NTLM: + /* Create the type-1 message */ + result = Curl_auth_create_ntlm_type1_message(data, + conn->user, conn->passwd, + service, hostname, + &conn->ntlm, &resp); + newstate = SASL_NTLM_TYPE2MSG; + break; + case SASL_NTLM_TYPE2MSG: + /* Decode the type-2 message */ + result = get_server_message(sasl, data, &serverdata); + if(!result) + result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, + &conn->ntlm); + if(!result) + result = Curl_auth_create_ntlm_type3_message(data, conn->user, + conn->passwd, &conn->ntlm, + &resp); + break; +#endif + +#if defined(USE_KERBEROS5) + case SASL_GSSAPI: + result = Curl_auth_create_gssapi_user_message(data, conn->user, + conn->passwd, + service, + conn->host.name, + sasl->mutual_auth, NULL, + &conn->krb5, + &resp); + newstate = SASL_GSSAPI_TOKEN; + break; + case SASL_GSSAPI_TOKEN: + result = get_server_message(sasl, data, &serverdata); + if(!result) { + if(sasl->mutual_auth) { + /* Decode the user token challenge and create the optional response + message */ + result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, + NULL, NULL, + sasl->mutual_auth, + &serverdata, + &conn->krb5, + &resp); + newstate = SASL_GSSAPI_NO_DATA; + } + else + /* Decode the security challenge and create the response message */ + result = Curl_auth_create_gssapi_security_message(data, + conn->sasl_authzid, + &serverdata, + &conn->krb5, + &resp); + } + break; + case SASL_GSSAPI_NO_DATA: + /* Decode the security challenge and create the response message */ + result = get_server_message(sasl, data, &serverdata); + if(!result) + result = Curl_auth_create_gssapi_security_message(data, + conn->sasl_authzid, + &serverdata, + &conn->krb5, + &resp); + break; +#endif + + case SASL_OAUTH2: + /* Create the authorization message */ + if(sasl->authused == SASL_MECH_OAUTHBEARER) { + result = Curl_auth_create_oauth_bearer_message(conn->user, + hostname, + port, + oauth_bearer, + &resp); + + /* Failures maybe sent by the server as continuations for OAUTHBEARER */ + newstate = SASL_OAUTH2_RESP; + } + else + result = Curl_auth_create_xoauth_bearer_message(conn->user, + oauth_bearer, + &resp); + break; + + case SASL_OAUTH2_RESP: + /* The continuation is optional so check the response code */ + if(code == sasl->params->finalcode) { + /* Final response was received so we are done */ + *progress = SASL_DONE; + sasl_state(sasl, data, SASL_STOP); + return result; + } + else if(code == sasl->params->contcode) { + /* Acknowledge the continuation by sending a 0x01 response. */ + Curl_bufref_set(&resp, "\x01", 1, NULL); + break; + } + else { + *progress = SASL_DONE; + sasl_state(sasl, data, SASL_STOP); + return CURLE_LOGIN_DENIED; + } + + case SASL_CANCEL: + /* Remove the offending mechanism from the supported list */ + sasl->authmechs ^= sasl->authused; + + /* Start an alternative SASL authentication */ + return Curl_sasl_start(sasl, data, sasl->force_ir, progress); + default: + failf(data, "Unsupported SASL authentication mechanism"); + result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ + break; + } + + Curl_bufref_free(&serverdata); + + switch(result) { + case CURLE_BAD_CONTENT_ENCODING: + /* Cancel dialog */ + result = sasl->params->cancelauth(data, sasl->curmech); + newstate = SASL_CANCEL; + break; + case CURLE_OK: + result = build_message(sasl, &resp); + if(!result) + result = sasl->params->contauth(data, sasl->curmech, &resp); + break; + default: + newstate = SASL_STOP; /* Stop on error */ + *progress = SASL_DONE; + break; + } + + Curl_bufref_free(&resp); + + sasl_state(sasl, data, newstate); + + return result; +} +#endif /* protocols are enabled that use SASL */ diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h new file mode 100644 index 0000000..e94e643 --- /dev/null +++ b/lib/curl_sasl.h @@ -0,0 +1,165 @@ +#ifndef HEADER_CURL_SASL_H +#define HEADER_CURL_SASL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +#include "bufref.h" + +struct Curl_easy; +struct connectdata; + +/* Authentication mechanism flags */ +#define SASL_MECH_LOGIN (1 << 0) +#define SASL_MECH_PLAIN (1 << 1) +#define SASL_MECH_CRAM_MD5 (1 << 2) +#define SASL_MECH_DIGEST_MD5 (1 << 3) +#define SASL_MECH_GSSAPI (1 << 4) +#define SASL_MECH_EXTERNAL (1 << 5) +#define SASL_MECH_NTLM (1 << 6) +#define SASL_MECH_XOAUTH2 (1 << 7) +#define SASL_MECH_OAUTHBEARER (1 << 8) +#define SASL_MECH_SCRAM_SHA_1 (1 << 9) +#define SASL_MECH_SCRAM_SHA_256 (1 << 10) + +/* Authentication mechanism values */ +#define SASL_AUTH_NONE 0 +#define SASL_AUTH_ANY 0xffff +#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) + +/* Authentication mechanism strings */ +#define SASL_MECH_STRING_LOGIN "LOGIN" +#define SASL_MECH_STRING_PLAIN "PLAIN" +#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" +#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" +#define SASL_MECH_STRING_GSSAPI "GSSAPI" +#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" +#define SASL_MECH_STRING_NTLM "NTLM" +#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" +#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" +#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1" +#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256" + +/* SASL flags */ +#define SASL_FLAG_BASE64 0x0001 /* Messages are base64-encoded */ + +/* SASL machine states */ +typedef enum { + SASL_STOP, + SASL_PLAIN, + SASL_LOGIN, + SASL_LOGIN_PASSWD, + SASL_EXTERNAL, + SASL_CRAMMD5, + SASL_DIGESTMD5, + SASL_DIGESTMD5_RESP, + SASL_NTLM, + SASL_NTLM_TYPE2MSG, + SASL_GSSAPI, + SASL_GSSAPI_TOKEN, + SASL_GSSAPI_NO_DATA, + SASL_OAUTH2, + SASL_OAUTH2_RESP, + SASL_GSASL, + SASL_CANCEL, + SASL_FINAL +} saslstate; + +/* Progress indicator */ +typedef enum { + SASL_IDLE, + SASL_INPROGRESS, + SASL_DONE +} saslprogress; + +/* Protocol dependent SASL parameters */ +struct SASLproto { + const char *service; /* The service name */ + CURLcode (*sendauth)(struct Curl_easy *data, const char *mech, + const struct bufref *ir); + /* Send authentication command */ + CURLcode (*contauth)(struct Curl_easy *data, const char *mech, + const struct bufref *contauth); + /* Send authentication continuation */ + CURLcode (*cancelauth)(struct Curl_easy *data, const char *mech); + /* Cancel authentication. */ + CURLcode (*getmessage)(struct Curl_easy *data, struct bufref *out); + /* Get SASL response message */ + size_t maxirlen; /* Maximum initial response + mechanism length, + or zero if no max. This is normally the max + command length - other characters count. + This has to be zero for non-base64 protocols. */ + int contcode; /* Code to receive when continuation is expected */ + int finalcode; /* Code to receive upon authentication success */ + unsigned short defmechs; /* Mechanisms enabled by default */ + unsigned short flags; /* Configuration flags. */ +}; + +/* Per-connection parameters */ +struct SASL { + const struct SASLproto *params; /* Protocol dependent parameters */ + saslstate state; /* Current machine state */ + const char *curmech; /* Current mechanism id. */ + unsigned short authmechs; /* Accepted authentication mechanisms */ + unsigned short prefmech; /* Preferred authentication mechanism */ + unsigned short authused; /* Auth mechanism used for the connection */ + BIT(resetprefs); /* For URL auth option parsing. */ + BIT(mutual_auth); /* Mutual authentication enabled (GSSAPI only) */ + BIT(force_ir); /* Protocol always supports initial response */ +}; + +/* This is used to test whether the line starts with the given mechanism */ +#define sasl_mech_equal(line, wordlen, mech) \ + (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ + !memcmp(line, mech, wordlen)) + +/* This is used to cleanup any libraries or curl modules used by the sasl + functions */ +void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused); + +/* Convert a mechanism name to a token */ +unsigned short Curl_sasl_decode_mech(const char *ptr, + size_t maxlen, size_t *len); + +/* Parse the URL login options */ +CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, + const char *value, size_t len); + +/* Initializes an SASL structure */ +void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data, + const struct SASLproto *params); + +/* Check if we have enough auth data and capabilities to authenticate */ +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data); + +/* Calculate the required login details for SASL authentication */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, + bool force_ir, saslprogress *progress); + +/* Continue an SASL authentication */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, + int code, saslprogress *progress); + +#endif /* HEADER_CURL_SASL_H */ diff --git a/lib/curl_setup.h b/lib/curl_setup.h new file mode 100644 index 0000000..703e903 --- /dev/null +++ b/lib/curl_setup.h @@ -0,0 +1,868 @@ +#ifndef HEADER_CURL_SETUP_H +#define HEADER_CURL_SETUP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#if defined(BUILDING_LIBCURL) && !defined(CURL_NO_OLDIES) +#define CURL_NO_OLDIES +#endif + +/* FIXME: Delete this once the warnings have been fixed. */ +#if !defined(CURL_WARN_SIGN_CONVERSION) +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif +#endif + +/* Set default _WIN32_WINNT */ +#ifdef __MINGW32__ +#include <_mingw.h> +#endif + +/* + * Disable Visual Studio warnings: + * 4127 "conditional expression is constant" + */ +#ifdef _MSC_VER +#pragma warning(disable:4127) +#endif + +#ifdef _WIN32 +/* + * Don't include unneeded stuff in Windows headers to avoid compiler + * warnings and macro clashes. + * Make sure to define this macro before including any Windows headers. + */ +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOGDI +# define NOGDI +# endif +/* Detect Windows App environment which has a restricted access + * to the Win32 APIs. */ +# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \ + defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define CURL_WINDOWS_APP +# endif +# endif +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H + +#include "curl_config.h" + +#else /* HAVE_CONFIG_H */ + +#ifdef _WIN32_WCE +# include "config-win32ce.h" +#else +# ifdef _WIN32 +# include "config-win32.h" +# endif +#endif + +#ifdef macintosh +# include "config-mac.h" +#endif + +#ifdef __riscos__ +# include "config-riscos.h" +#endif + +#ifdef __AMIGA__ +# include "config-amigaos.h" +#endif + +#ifdef __OS400__ +# include "config-os400.h" +#endif + +#ifdef __PLAN9__ +# include "config-plan9.h" +#endif + +#ifdef MSDOS +# include "config-dos.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behavior or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* Solaris needs this to get a POSIX-conformant getpwuid_r */ +#if defined(sun) || defined(__sun) +# ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * Disable other protocols when http is the only one desired. + */ + +#ifdef HTTP_ONLY +# ifndef CURL_DISABLE_DICT +# define CURL_DISABLE_DICT +# endif +# ifndef CURL_DISABLE_FILE +# define CURL_DISABLE_FILE +# endif +# ifndef CURL_DISABLE_FTP +# define CURL_DISABLE_FTP +# endif +# ifndef CURL_DISABLE_GOPHER +# define CURL_DISABLE_GOPHER +# endif +# ifndef CURL_DISABLE_IMAP +# define CURL_DISABLE_IMAP +# endif +# ifndef CURL_DISABLE_LDAP +# define CURL_DISABLE_LDAP +# endif +# ifndef CURL_DISABLE_LDAPS +# define CURL_DISABLE_LDAPS +# endif +# ifndef CURL_DISABLE_MQTT +# define CURL_DISABLE_MQTT +# endif +# ifndef CURL_DISABLE_POP3 +# define CURL_DISABLE_POP3 +# endif +# ifndef CURL_DISABLE_RTSP +# define CURL_DISABLE_RTSP +# endif +# ifndef CURL_DISABLE_SMB +# define CURL_DISABLE_SMB +# endif +# ifndef CURL_DISABLE_SMTP +# define CURL_DISABLE_SMTP +# endif +# ifndef CURL_DISABLE_TELNET +# define CURL_DISABLE_TELNET +# endif +# ifndef CURL_DISABLE_TFTP +# define CURL_DISABLE_TFTP +# endif +#endif + +/* + * When http is disabled rtsp is not supported. + */ + +#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP) +# define CURL_DISABLE_RTSP +#endif + +/* + * When HTTP is disabled, disable HTTP-only features + */ + +#if defined(CURL_DISABLE_HTTP) +# define CURL_DISABLE_ALTSVC 1 +# define CURL_DISABLE_COOKIES 1 +# define CURL_DISABLE_BASIC_AUTH 1 +# define CURL_DISABLE_BEARER_AUTH 1 +# define CURL_DISABLE_AWS 1 +# define CURL_DISABLE_DOH 1 +# define CURL_DISABLE_FORM_API 1 +# define CURL_DISABLE_HEADERS_API 1 +# define CURL_DISABLE_HSTS 1 +# define CURL_DISABLE_HTTP_AUTH 1 +#endif + +/* ================================================================ */ +/* No system header file shall be included in this file before this */ +/* point. */ +/* ================================================================ */ + +/* + * OS/400 setup file includes some system headers. + */ + +#ifdef __OS400__ +# include "setup-os400.h" +#endif + +/* + * VMS setup file includes some system headers. + */ + +#ifdef __VMS +# include "setup-vms.h" +#endif + +/* + * Windows setup file includes some system headers. + */ + +#ifdef _WIN32 +# include "setup-win32.h" +#endif + +#include + +/* curl uses its own printf() function internally. It understands the GNU + * format. Use this format, so that is matches the GNU format attribute we + * use with the mingw compiler, allowing it to verify them at compile-time. + */ +#ifdef __MINGW32__ +# undef CURL_FORMAT_CURL_OFF_T +# undef CURL_FORMAT_CURL_OFF_TU +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +#endif + +/* based on logic in "curl/mprintf.h" */ + +#if (defined(__GNUC__) || defined(__clang__)) && \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(CURL_NO_FMT_CHECKS) +#if defined(__MINGW32__) && !defined(__clang__) +#define CURL_PRINTF(fmt, arg) \ + __attribute__((format(gnu_printf, fmt, arg))) +#else +#define CURL_PRINTF(fmt, arg) \ + __attribute__((format(__printf__, fmt, arg))) +#endif +#else +#define CURL_PRINTF(fmt, arg) +#endif + +/* + * Use getaddrinfo to resolve the IPv4 address literal. If the current network + * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, + * performing this task will result in a synthesized IPv6 address. + */ +#if defined(__APPLE__) && !defined(USE_ARES) +#include +#define USE_RESOLVE_ON_IPS 1 +# if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \ + defined(ENABLE_IPV6) +# define CURL_MACOS_CALL_COPYPROXIES 1 +# endif +#endif + +#ifdef USE_LWIPSOCK +# include +# include +# include +#endif + +#ifdef HAVE_EXTRA_STRICMP_H +# include +#endif + +#ifdef HAVE_EXTRA_STRDUP_H +# include +#endif + +#ifdef __AMIGA__ +# ifdef __amigaos4__ +# define __USE_INLINE__ + /* use our own resolver which uses runtime feature detection */ +# define CURLRES_AMIGA + /* getaddrinfo() currently crashes bsdsocket.library, so disable */ +# undef HAVE_GETADDRINFO +# if !(defined(__NEWLIB__) || \ + (defined(__CLIB2__) && defined(__THREAD_SAFE))) + /* disable threaded resolver with clib2 - requires newlib or clib-ts */ +# undef USE_THREADS_POSIX +# endif +# endif +# include +# include +# include +# include +# include +# if defined(HAVE_PROTO_BSDSOCKET_H) && \ + (!defined(__amigaos4__) || defined(USE_AMISSL)) + /* use bsdsocket.library directly, instead of libc networking functions */ +# define _SYS_MBUF_H /* m_len define clashes with curl */ +# include +# ifdef __amigaos4__ + int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *errorfds, struct timeval *timeout); +# define select(a,b,c,d,e) Curl_amiga_select(a,b,c,d,e) +# else +# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) +# endif + /* must not use libc's fcntl() on bsdsocket.library sockfds! */ +# undef HAVE_FCNTL +# undef HAVE_FCNTL_O_NONBLOCK +# else + /* use libc networking and hence close() and fnctl() */ +# undef HAVE_CLOSESOCKET_CAMEL +# undef HAVE_IOCTLSOCKET_CAMEL +# endif +/* + * In clib2 arpa/inet.h warns that some prototypes may clash + * with bsdsocket.library. This avoids the definition of those. + */ +# define __NO_NET_API +#endif + +#include +#include + +#ifdef __TANDEM /* for ns*-tandem-nsk systems */ +# if ! defined __LP64 +# include /* FLOSS is only used for 32-bit builds. */ +# endif +#endif + +#ifndef STDC_HEADERS /* no standard C headers! */ +#include +#endif + +/* + * Large file (>2Gb) support using WIN32 functions. + */ + +#ifdef USE_WIN32_LARGE_FILES +# include +# include +# include +# undef lseek +# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) +# undef fstat +# define fstat(fdes,stp) _fstati64(fdes, stp) +# undef stat +# define stat(fname,stp) curlx_win32_stat(fname, stp) +# define struct_stat struct _stati64 +# define LSEEK_ERROR (__int64)-1 +# define open curlx_win32_open +# define fopen(fname,mode) curlx_win32_fopen(fname, mode) +# define access(fname,mode) curlx_win32_access(fname, mode) + int curlx_win32_open(const char *filename, int oflag, ...); + int curlx_win32_stat(const char *path, struct_stat *buffer); + FILE *curlx_win32_fopen(const char *filename, const char *mode); + int curlx_win32_access(const char *path, int mode); +#endif + +/* + * Small file (<2Gb) support using WIN32 functions. + */ + +#ifdef USE_WIN32_SMALL_FILES +# include +# include +# include +# ifndef _WIN32_WCE +# undef lseek +# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) +# define fstat(fdes,stp) _fstat(fdes, stp) +# define stat(fname,stp) curlx_win32_stat(fname, stp) +# define struct_stat struct _stat +# define open curlx_win32_open +# define fopen(fname,mode) curlx_win32_fopen(fname, mode) +# define access(fname,mode) curlx_win32_access(fname, mode) + int curlx_win32_stat(const char *path, struct_stat *buffer); + int curlx_win32_open(const char *filename, int oflag, ...); + FILE *curlx_win32_fopen(const char *filename, const char *mode); + int curlx_win32_access(const char *path, int mode); +# endif +# define LSEEK_ERROR (long)-1 +#endif + +#ifndef struct_stat +# define struct_stat struct stat +#endif + +#ifndef LSEEK_ERROR +# define LSEEK_ERROR (off_t)-1 +#endif + +#ifndef SIZEOF_TIME_T +/* assume default size of time_t to be 32 bit */ +#define SIZEOF_TIME_T 4 +#endif + +#ifndef SIZEOF_CURL_SOCKET_T +/* configure and cmake check and set the define */ +# ifdef _WIN64 +# define SIZEOF_CURL_SOCKET_T 8 +# else +/* default guess */ +# define SIZEOF_CURL_SOCKET_T 4 +# endif +#endif + +#if SIZEOF_CURL_SOCKET_T < 8 +# define CURL_FORMAT_SOCKET_T "d" +#elif defined(__MINGW32__) +# define CURL_FORMAT_SOCKET_T "zd" +#else +# define CURL_FORMAT_SOCKET_T "qd" +#endif + +/* + * Default sizeof(off_t) in case it hasn't been defined in config file. + */ + +#ifndef SIZEOF_OFF_T +# if defined(__VMS) && !defined(__VAX) +# if defined(_LARGEFILE) +# define SIZEOF_OFF_T 8 +# endif +# elif defined(__OS400__) && defined(__ILEC400__) +# if defined(_LARGE_FILES) +# define SIZEOF_OFF_T 8 +# endif +# elif defined(__MVS__) && defined(__IBMC__) +# if defined(_LP64) || defined(_LARGE_FILES) +# define SIZEOF_OFF_T 8 +# endif +# elif defined(__370__) && defined(__IBMC__) +# if defined(_LP64) || defined(_LARGE_FILES) +# define SIZEOF_OFF_T 8 +# endif +# endif +# ifndef SIZEOF_OFF_T +# define SIZEOF_OFF_T 4 +# endif +#endif + +#if (SIZEOF_CURL_OFF_T < 8) +#error "too small curl_off_t" +#else + /* assume SIZEOF_CURL_OFF_T == 8 */ +# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) +#endif +#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1)) + +#if (SIZEOF_TIME_T == 4) +# ifdef HAVE_TIME_T_UNSIGNED +# define TIME_T_MAX UINT_MAX +# define TIME_T_MIN 0 +# else +# define TIME_T_MAX INT_MAX +# define TIME_T_MIN INT_MIN +# endif +#else +# ifdef HAVE_TIME_T_UNSIGNED +# define TIME_T_MAX 0xFFFFFFFFFFFFFFFF +# define TIME_T_MIN 0 +# else +# define TIME_T_MAX 0x7FFFFFFFFFFFFFFF +# define TIME_T_MIN (-TIME_T_MAX - 1) +# endif +#endif + +#ifndef SIZE_T_MAX +/* some limits.h headers have this defined, some don't */ +#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4) +#define SIZE_T_MAX 18446744073709551615U +#else +#define SIZE_T_MAX 4294967295U +#endif +#endif + +#ifndef SSIZE_T_MAX +/* some limits.h headers have this defined, some don't */ +#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4) +#define SSIZE_T_MAX 9223372036854775807 +#else +#define SSIZE_T_MAX 2147483647 +#endif +#endif + +/* + * Arg 2 type for gethostname in case it hasn't been defined in config file. + */ + +#ifndef GETHOSTNAME_TYPE_ARG2 +# ifdef USE_WINSOCK +# define GETHOSTNAME_TYPE_ARG2 int +# else +# define GETHOSTNAME_TYPE_ARG2 size_t +# endif +#endif + +/* Below we define some functions. They should + + 4. set the SIGALRM signal timeout + 5. set dir/file naming defines + */ + +#ifdef _WIN32 + +# define DIR_CHAR "\\" + +#else /* _WIN32 */ + +# ifdef MSDOS /* Watt-32 */ + +# include +# define select(n,r,w,x,t) select_s(n,r,w,x,t) +# define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z)) +# include +# ifdef word +# undef word +# endif +# ifdef byte +# undef byte +# endif + +# endif /* MSDOS */ + +# ifdef __minix + /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */ + extern char *strtok_r(char *s, const char *delim, char **last); + extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp); +# endif + +# define DIR_CHAR "/" + +#endif /* _WIN32 */ + +/* ---------------------------------------------------------------- */ +/* resolver specialty compile-time defines */ +/* CURLRES_* defines to use in the host*.c sources */ +/* ---------------------------------------------------------------- */ + +/* + * MSVC threads support requires a multi-threaded runtime library. + * _beginthreadex() is not available in single-threaded ones. + */ + +#if defined(_MSC_VER) && !defined(_MT) +# undef USE_THREADS_POSIX +# undef USE_THREADS_WIN32 +#endif + +/* + * Mutually exclusive CURLRES_* definitions. + */ + +#if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO) +# define CURLRES_IPV6 +#elif defined(ENABLE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__)) +/* assume on Windows that IPv6 without getaddrinfo is a broken build */ +# error "Unexpected build: IPv6 is enabled but getaddrinfo was not found." +#else +# define CURLRES_IPV4 +#endif + +#ifdef USE_ARES +# define CURLRES_ASYNCH +# define CURLRES_ARES +/* now undef the stock libc functions just to avoid them being used */ +# undef HAVE_GETADDRINFO +# undef HAVE_FREEADDRINFO +#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) +# define CURLRES_ASYNCH +# define CURLRES_THREADED +#else +# define CURLRES_SYNCH +#endif + +/* ---------------------------------------------------------------- */ + +#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN) +/* The lib and header are present */ +#define USE_LIBIDN2 +#endif + +#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN) +#error "Both libidn2 and WinIDN are enabled, choose one." +#endif + +#define LIBIDN_REQUIRED_VERSION "0.4.1" + +#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \ + defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \ + defined(USE_BEARSSL) || defined(USE_RUSTLS) +#define USE_SSL /* SSL support has been enabled */ +#endif + +/* Single point where USE_SPNEGO definition might be defined */ +#if !defined(CURL_DISABLE_NEGOTIATE_AUTH) && \ + (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) +#define USE_SPNEGO +#endif + +/* Single point where USE_KERBEROS5 definition might be defined */ +#if !defined(CURL_DISABLE_KERBEROS_AUTH) && \ + (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) +#define USE_KERBEROS5 +#endif + +/* Single point where USE_NTLM definition might be defined */ +#if !defined(CURL_DISABLE_NTLM) +# if defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \ + defined(USE_GNUTLS) || defined(USE_SECTRANSP) || \ + defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \ + (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT)) +# define USE_CURL_NTLM_CORE +# endif +# if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI) +# define USE_NTLM +# endif +#endif + +#ifdef CURL_WANTS_CA_BUNDLE_ENV +#error "No longer supported. Set CURLOPT_CAINFO at runtime instead." +#endif + +#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH) +#define USE_SSH +#endif + +/* + * Provide a mechanism to silence picky compilers, such as gcc 4.6+. + * Parameters should of course normally not be unused, but for example when + * we have multiple implementations of the same interface it may happen. + */ + +#if defined(__GNUC__) && ((__GNUC__ >= 3) || \ + ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) +# define UNUSED_PARAM __attribute__((__unused__)) +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define UNUSED_PARAM /* NOTHING */ +# define WARN_UNUSED_RESULT +#endif + +/* noreturn attribute */ + +#if !defined(CURL_NORETURN) +#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) +# define CURL_NORETURN __attribute__((__noreturn__)) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) +# define CURL_NORETURN __declspec(noreturn) +#else +# define CURL_NORETURN +#endif +#endif + +/* fallthrough attribute */ + +#if !defined(FALLTHROUGH) +#if (defined(__GNUC__) && __GNUC__ >= 7) || \ + (defined(__clang__) && __clang_major__ >= 10) +# define FALLTHROUGH() __attribute__((fallthrough)) +#else +# define FALLTHROUGH() do {} while (0) +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef HEADER_CURL_SETUP_ONCE_H +#include "curl_setup_once.h" +#endif + +/* + * Definition of our NOP statement Object-like macro + */ + +#ifndef Curl_nop_stmt +# define Curl_nop_stmt do { } while(0) +#endif + +/* + * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. + */ + +#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) +# if defined(SOCKET) || defined(USE_WINSOCK) +# error "WinSock and lwIP TCP/IP stack definitions shall not coexist!" +# endif +#endif + +/* + * shutdown() flags for systems that don't define them + */ + +#ifndef SHUT_RD +#define SHUT_RD 0x00 +#endif + +#ifndef SHUT_WR +#define SHUT_WR 0x01 +#endif + +#ifndef SHUT_RDWR +#define SHUT_RDWR 0x02 +#endif + +/* Define S_ISREG if not defined by system headers, e.g. MSVC */ +#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* Define S_ISDIR if not defined by system headers, e.g. MSVC */ +#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +/* In Windows the default file mode is text but an application can override it. +Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 +*/ +#if defined(_WIN32) || defined(MSDOS) +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "wt" +#define FOPEN_APPENDTEXT "at" +#elif defined(__CYGWIN__) +/* Cygwin has specific behavior we need to address when WIN32 is not defined. +https://cygwin.com/cygwin-ug-net/using-textbinary.html +For write we want our output to have line endings of LF and be compatible with +other Cygwin utilities. For read we want to handle input that may have line +endings either CRLF or LF so 't' is appropriate. +*/ +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "w" +#define FOPEN_APPENDTEXT "a" +#else +#define FOPEN_READTEXT "r" +#define FOPEN_WRITETEXT "w" +#define FOPEN_APPENDTEXT "a" +#endif + +/* for systems that don't detect this in configure */ +#ifndef CURL_SA_FAMILY_T +# if defined(HAVE_SA_FAMILY_T) +# define CURL_SA_FAMILY_T sa_family_t +# elif defined(HAVE_ADDRESS_FAMILY) +# define CURL_SA_FAMILY_T ADDRESS_FAMILY +# else +/* use a sensible default */ +# define CURL_SA_FAMILY_T unsigned short +# endif +#endif + +/* Some convenience macros to get the larger/smaller value out of two given. + We prefix with CURL to prevent name collisions. */ +#define CURLMAX(x,y) ((x)>(y)?(x):(y)) +#define CURLMIN(x,y) ((x)<(y)?(x):(y)) + +/* 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 + +/* Some versions of the Android SDK is missing the declaration */ +#if defined(HAVE_GETPWUID_R) && defined(HAVE_DECL_GETPWUID_R_MISSING) +struct passwd; +int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, + size_t buflen, struct passwd **result); +#endif + +#ifdef DEBUGBUILD +#define UNITTEST +#else +#define UNITTEST static +#endif + +/* Hyper supports HTTP2 also, but Curl's integration with Hyper does not */ +#if defined(USE_NGHTTP2) +#define USE_HTTP2 +#endif + +#if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \ + (defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)) || \ + defined(USE_QUICHE) || defined(USE_MSH3) + +#ifdef CURL_WITH_MULTI_SSL +#error "Multi-SSL combined with QUIC is not supported" +#endif + +#define ENABLE_QUIC +#define USE_HTTP3 +#endif + +/* Certain Windows implementations are not aligned with what curl expects, + so always use the local one on this platform. E.g. the mingw-w64 + implementation can return wrong results for non-ASCII inputs. */ +#if defined(HAVE_BASENAME) && defined(_WIN32) +#undef HAVE_BASENAME +#endif + +#if defined(USE_UNIX_SOCKETS) && defined(_WIN32) +# if !defined(UNIX_PATH_MAX) + /* Replicating logic present in afunix.h + (distributed with newer Windows 10 SDK versions only) */ +# define UNIX_PATH_MAX 108 + /* !checksrc! disable TYPEDEFSTRUCT 1 */ + typedef struct sockaddr_un { + ADDRESS_FAMILY sun_family; + char sun_path[UNIX_PATH_MAX]; + } SOCKADDR_UN, *PSOCKADDR_UN; +# define WIN32_SOCKADDR_UN +# endif +#endif + +/* OpenSSLv3 marks DES, MD5 and ENGINE functions deprecated but we have no + replacements (yet) so tell the compiler to not warn for them. */ +#ifdef USE_OPENSSL +#define OPENSSL_SUPPRESS_DEPRECATED +#endif + +#endif /* HEADER_CURL_SETUP_H */ diff --git a/lib/curl_setup_once.h b/lib/curl_setup_once.h new file mode 100644 index 0000000..bf0ee66 --- /dev/null +++ b/lib/curl_setup_once.h @@ -0,0 +1,418 @@ +#ifndef HEADER_CURL_SETUP_ONCE_H +#define HEADER_CURL_SETUP_ONCE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + + +/* + * Inclusion of common header files. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef NEED_MALLOC_H +#include +#endif + +#ifdef NEED_MEMORY_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef _WIN32 +#include +#include +#endif + +#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T) +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef USE_WOLFSSL +#include +#endif + +#ifdef USE_SCHANNEL +/* Must set this before is included directly or indirectly by + another Windows header. */ +# define SCHANNEL_USE_BLACKLISTS 1 +#endif + +#ifdef __hpux +# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) +# ifdef _APP32_64BIT_OFF_T +# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T +# undef _APP32_64BIT_OFF_T +# else +# undef OLD_APP32_64BIT_OFF_T +# endif +# endif +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "functypes.h" + +#ifdef __hpux +# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) +# ifdef OLD_APP32_64BIT_OFF_T +# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T +# undef OLD_APP32_64BIT_OFF_T +# endif +# endif +#endif + +/* + * Definition of timeval struct for platforms that don't have it. + */ + +#ifndef HAVE_STRUCT_TIMEVAL +struct timeval { + long tv_sec; + long tv_usec; +}; +#endif + + +/* + * If we have the MSG_NOSIGNAL define, make sure we use + * it as the fourth argument of function send() + */ + +#ifdef HAVE_MSG_NOSIGNAL +#define SEND_4TH_ARG MSG_NOSIGNAL +#else +#define SEND_4TH_ARG 0 +#endif + + +#if defined(__minix) +/* Minix doesn't support recv on TCP sockets */ +#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \ + (RECV_TYPE_ARG2)(y), \ + (RECV_TYPE_ARG3)(z)) + +#elif defined(HAVE_RECV) +/* + * The definitions for the return type and arguments types + * of functions recv() and send() belong and come from the + * configuration file. Do not define them in any other place. + * + * HAVE_RECV is defined if you have a function named recv() + * which is used to read incoming data from sockets. If your + * function has another name then don't define HAVE_RECV. + * + * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2, + * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also + * be defined. + * + * HAVE_SEND is defined if you have a function named send() + * which is used to write outgoing data on a connected socket. + * If yours has another name then don't define HAVE_SEND. + * + * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2, + * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and + * SEND_TYPE_RETV must also be defined. + */ + +#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ + (RECV_TYPE_ARG2)(y), \ + (RECV_TYPE_ARG3)(z), \ + (RECV_TYPE_ARG4)(0)) +#else /* HAVE_RECV */ +#ifndef sread + /* */ + Error Missing_definition_of_macro_sread + /* */ +#endif +#endif /* HAVE_RECV */ + + +#if defined(__minix) +/* Minix doesn't support send on TCP sockets */ +#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \ + (SEND_TYPE_ARG2)(y), \ + (SEND_TYPE_ARG3)(z)) + +#elif defined(HAVE_SEND) +#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ + (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \ + (SEND_TYPE_ARG3)(z), \ + (SEND_TYPE_ARG4)(SEND_4TH_ARG)) +#else /* HAVE_SEND */ +#ifndef swrite + /* */ + Error Missing_definition_of_macro_swrite + /* */ +#endif +#endif /* HAVE_SEND */ + + +/* + * Function-like macro definition used to close a socket. + */ + +#if defined(HAVE_CLOSESOCKET) +# define sclose(x) closesocket((x)) +#elif defined(HAVE_CLOSESOCKET_CAMEL) +# define sclose(x) CloseSocket((x)) +#elif defined(HAVE_CLOSE_S) +# define sclose(x) close_s((x)) +#elif defined(USE_LWIPSOCK) +# define sclose(x) lwip_close((x)) +#else +# define sclose(x) close((x)) +#endif + +/* + * Stack-independent version of fcntl() on sockets: + */ +#if defined(USE_LWIPSOCK) +# define sfcntl lwip_fcntl +#else +# define sfcntl fcntl +#endif + +/* + * 'bool' stuff compatible with HP-UX headers. + */ + +#if defined(__hpux) && !defined(HAVE_BOOL_T) + typedef int bool; +# define false 0 +# define true 1 +# define HAVE_BOOL_T +#endif + + +/* + * 'bool' exists on platforms with , i.e. C99 platforms. + * On non-C99 platforms there's no bool, so define an enum for that. + * On C99 platforms 'false' and 'true' also exist. Enum uses a + * global namespace though, so use bool_false and bool_true. + */ + +#ifndef HAVE_BOOL_T + typedef enum { + bool_false = 0, + bool_true = 1 + } bool; + +/* + * Use a define to let 'true' and 'false' use those enums. There + * are currently no use of true and false in libcurl proper, but + * there are some in the examples. This will cater for any later + * code happening to use true and false. + */ +# define false bool_false +# define true bool_true +# define HAVE_BOOL_T +#endif + +/* the type we use for storing a single boolean bit */ +#ifdef _MSC_VER +typedef bool bit; +#define BIT(x) bool x +#else +typedef unsigned int bit; +#define BIT(x) bit x:1 +#endif + +/* + * Redefine TRUE and FALSE too, to catch current use. With this + * change, 'bool found = 1' will give a warning on MIPSPro, but + * 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro, + * AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too. + */ + +#ifndef TRUE +#define TRUE true +#endif +#ifndef FALSE +#define FALSE false +#endif + +#include "curl_ctype.h" + + +/* + * Macro used to include code only in debug builds. + */ + +#ifdef DEBUGBUILD +#define DEBUGF(x) x +#else +#define DEBUGF(x) do { } while(0) +#endif + + +/* + * Macro used to include assertion code only in debug builds. + */ + +#undef DEBUGASSERT +#if defined(DEBUGBUILD) +#define DEBUGASSERT(x) assert(x) +#else +#define DEBUGASSERT(x) do { } while(0) +#endif + + +/* + * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno + * (or equivalent) on this platform to hide platform details to code using it. + */ + +#ifdef USE_WINSOCK +#define SOCKERRNO ((int)WSAGetLastError()) +#define SET_SOCKERRNO(x) (WSASetLastError((int)(x))) +#else +#define SOCKERRNO (errno) +#define SET_SOCKERRNO(x) (errno = (x)) +#endif + + +/* + * Portable error number symbolic names defined to Winsock error codes. + */ + +#ifdef USE_WINSOCK +#undef EBADF /* override definition in errno.h */ +#define EBADF WSAEBADF +#undef EINTR /* override definition in errno.h */ +#define EINTR WSAEINTR +#undef EINVAL /* override definition in errno.h */ +#define EINVAL WSAEINVAL +#undef EWOULDBLOCK /* override definition in errno.h */ +#define EWOULDBLOCK WSAEWOULDBLOCK +#undef EINPROGRESS /* override definition in errno.h */ +#define EINPROGRESS WSAEINPROGRESS +#undef EALREADY /* override definition in errno.h */ +#define EALREADY WSAEALREADY +#undef ENOTSOCK /* override definition in errno.h */ +#define ENOTSOCK WSAENOTSOCK +#undef EDESTADDRREQ /* override definition in errno.h */ +#define EDESTADDRREQ WSAEDESTADDRREQ +#undef EMSGSIZE /* override definition in errno.h */ +#define EMSGSIZE WSAEMSGSIZE +#undef EPROTOTYPE /* override definition in errno.h */ +#define EPROTOTYPE WSAEPROTOTYPE +#undef ENOPROTOOPT /* override definition in errno.h */ +#define ENOPROTOOPT WSAENOPROTOOPT +#undef EPROTONOSUPPORT /* override definition in errno.h */ +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#undef EOPNOTSUPP /* override definition in errno.h */ +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#undef EAFNOSUPPORT /* override definition in errno.h */ +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#undef EADDRINUSE /* override definition in errno.h */ +#define EADDRINUSE WSAEADDRINUSE +#undef EADDRNOTAVAIL /* override definition in errno.h */ +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#undef ENETDOWN /* override definition in errno.h */ +#define ENETDOWN WSAENETDOWN +#undef ENETUNREACH /* override definition in errno.h */ +#define ENETUNREACH WSAENETUNREACH +#undef ENETRESET /* override definition in errno.h */ +#define ENETRESET WSAENETRESET +#undef ECONNABORTED /* override definition in errno.h */ +#define ECONNABORTED WSAECONNABORTED +#undef ECONNRESET /* override definition in errno.h */ +#define ECONNRESET WSAECONNRESET +#undef ENOBUFS /* override definition in errno.h */ +#define ENOBUFS WSAENOBUFS +#undef EISCONN /* override definition in errno.h */ +#define EISCONN WSAEISCONN +#undef ENOTCONN /* override definition in errno.h */ +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#undef ETIMEDOUT /* override definition in errno.h */ +#define ETIMEDOUT WSAETIMEDOUT +#undef ECONNREFUSED /* override definition in errno.h */ +#define ECONNREFUSED WSAECONNREFUSED +#undef ELOOP /* override definition in errno.h */ +#define ELOOP WSAELOOP +#ifndef ENAMETOOLONG /* possible previous definition in errno.h */ +#define ENAMETOOLONG WSAENAMETOOLONG +#endif +#define EHOSTDOWN WSAEHOSTDOWN +#undef EHOSTUNREACH /* override definition in errno.h */ +#define EHOSTUNREACH WSAEHOSTUNREACH +#ifndef ENOTEMPTY /* possible previous definition in errno.h */ +#define ENOTEMPTY WSAENOTEMPTY +#endif +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE +#endif + +/* + * Macro argv_item_t hides platform details to code using it. + */ + +#ifdef __VMS +#define argv_item_t __char_ptr32 +#elif defined(_UNICODE) +#define argv_item_t wchar_t * +#else +#define argv_item_t char * +#endif + + +/* + * We use this ZERO_NULL to avoid picky compiler warnings, + * when assigning a NULL pointer to a function pointer var. + */ + +#define ZERO_NULL 0 + + +#endif /* HEADER_CURL_SETUP_ONCE_H */ diff --git a/lib/curl_sha256.h b/lib/curl_sha256.h new file mode 100644 index 0000000..d99f958 --- /dev/null +++ b/lib/curl_sha256.h @@ -0,0 +1,50 @@ +#ifndef HEADER_CURL_SHA256_H +#define HEADER_CURL_SHA256_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Florin Petriuc, + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \ + || defined(USE_LIBSSH2) + +#include +#include "curl_hmac.h" + +extern const struct HMAC_params Curl_HMAC_SHA256[1]; + +#ifdef USE_WOLFSSL +/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from + * sha.h */ +#include +#include +#else +#define SHA256_DIGEST_LENGTH 32 +#endif + +CURLcode Curl_sha256it(unsigned char *outbuffer, const unsigned char *input, + const size_t len); + +#endif + +#endif /* HEADER_CURL_SHA256_H */ diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c new file mode 100644 index 0000000..eb21e7e --- /dev/null +++ b/lib/curl_sspi.c @@ -0,0 +1,239 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_WINDOWS_SSPI + +#include +#include "curl_sspi.h" +#include "curl_multibyte.h" +#include "system_win32.h" +#include "version_win32.h" +#include "warnless.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* We use our own typedef here since some headers might lack these */ +typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID); + +/* See definition of SECURITY_ENTRYPOINT in sspi.h */ +#ifdef UNICODE +# ifdef _WIN32_WCE +# define SECURITYENTRYPOINT L"InitSecurityInterfaceW" +# else +# define SECURITYENTRYPOINT "InitSecurityInterfaceW" +# endif +#else +# define SECURITYENTRYPOINT "InitSecurityInterfaceA" +#endif + +/* Handle of security.dll or secur32.dll, depending on Windows version */ +HMODULE s_hSecDll = NULL; + +/* Pointer to SSPI dispatch table */ +PSecurityFunctionTable s_pSecFn = NULL; + +/* + * Curl_sspi_global_init() + * + * This is used to load the Security Service Provider Interface (SSPI) + * dynamic link library portably across all Windows versions, without + * the need to directly link libcurl, nor the application using it, at + * build time. + * + * Once this function has been executed, Windows SSPI functions can be + * called through the Security Service Provider Interface dispatch table. + * + * Parameters: + * + * None. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sspi_global_init(void) +{ + INITSECURITYINTERFACE_FN pInitSecurityInterface; + + /* If security interface is not yet initialized try to do this */ + if(!s_hSecDll) { + /* Security Service Provider Interface (SSPI) functions are located in + * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP + * have both these DLLs (security.dll forwards calls to secur32.dll) */ + + /* Load SSPI dll into the address space of the calling process */ + if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL)) + s_hSecDll = Curl_load_library(TEXT("security.dll")); + else + s_hSecDll = Curl_load_library(TEXT("secur32.dll")); + if(!s_hSecDll) + return CURLE_FAILED_INIT; + + /* Get address of the InitSecurityInterfaceA function from the SSPI dll */ + pInitSecurityInterface = + CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN, + (GetProcAddress(s_hSecDll, SECURITYENTRYPOINT))); + if(!pInitSecurityInterface) + return CURLE_FAILED_INIT; + + /* Get pointer to Security Service Provider Interface dispatch table */ + s_pSecFn = pInitSecurityInterface(); + if(!s_pSecFn) + return CURLE_FAILED_INIT; + } + + return CURLE_OK; +} + +/* + * Curl_sspi_global_cleanup() + * + * This deinitializes the Security Service Provider Interface from libcurl. + * + * Parameters: + * + * None. + */ +void Curl_sspi_global_cleanup(void) +{ + if(s_hSecDll) { + FreeLibrary(s_hSecDll); + s_hSecDll = NULL; + s_pSecFn = NULL; + } +} + +/* + * Curl_create_sspi_identity() + * + * This is used to populate a SSPI identity structure based on the supplied + * username and password. + * + * Parameters: + * + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * identity [in/out] - The identity structure. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, + SEC_WINNT_AUTH_IDENTITY *identity) +{ + xcharp_u useranddomain; + xcharp_u user, dup_user; + xcharp_u domain, dup_domain; + xcharp_u passwd, dup_passwd; + size_t domlen = 0; + + domain.const_tchar_ptr = TEXT(""); + + /* Initialize the identity */ + memset(identity, 0, sizeof(*identity)); + + useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)userp); + if(!useranddomain.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + + user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\')); + if(!user.const_tchar_ptr) + user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/')); + + if(user.tchar_ptr) { + domain.tchar_ptr = useranddomain.tchar_ptr; + domlen = user.tchar_ptr - useranddomain.tchar_ptr; + user.tchar_ptr++; + } + else { + user.tchar_ptr = useranddomain.tchar_ptr; + domain.const_tchar_ptr = TEXT(""); + domlen = 0; + } + + /* Setup the identity's user and length */ + dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); + if(!dup_user.tchar_ptr) { + curlx_unicodefree(useranddomain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + identity->User = dup_user.tbyte_ptr; + identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr)); + dup_user.tchar_ptr = NULL; + + /* Setup the identity's domain and length */ + dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); + if(!dup_domain.tchar_ptr) { + curlx_unicodefree(useranddomain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); + *(dup_domain.tchar_ptr + domlen) = TEXT('\0'); + identity->Domain = dup_domain.tbyte_ptr; + identity->DomainLength = curlx_uztoul(domlen); + dup_domain.tchar_ptr = NULL; + + curlx_unicodefree(useranddomain.tchar_ptr); + + /* Setup the identity's password and length */ + passwd.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)passwdp); + if(!passwd.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); + if(!dup_passwd.tchar_ptr) { + curlx_unicodefree(passwd.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + identity->Password = dup_passwd.tbyte_ptr; + identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); + dup_passwd.tchar_ptr = NULL; + + curlx_unicodefree(passwd.tchar_ptr); + + /* Setup the identity's flags */ + identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY; + + return CURLE_OK; +} + +/* + * Curl_sspi_free_identity() + * + * This is used to free the contents of a SSPI identifier structure. + * + * Parameters: + * + * identity [in/out] - The identity structure. + */ +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) +{ + if(identity) { + Curl_safefree(identity->User); + Curl_safefree(identity->Password); + Curl_safefree(identity->Domain); + } +} + +#endif /* USE_WINDOWS_SSPI */ diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h new file mode 100644 index 0000000..b26c391 --- /dev/null +++ b/lib/curl_sspi.h @@ -0,0 +1,123 @@ +#ifndef HEADER_CURL_SSPI_H +#define HEADER_CURL_SSPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_WINDOWS_SSPI + +#include + +/* + * When including the following three headers, it is mandatory to define either + * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code. + */ + +#undef SECURITY_WIN32 +#undef SECURITY_KERNEL +#define SECURITY_WIN32 1 +#include +#include +#include + +CURLcode Curl_sspi_global_init(void); +void Curl_sspi_global_cleanup(void); + +/* This is used to populate the domain in a SSPI identity structure */ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *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); + +/* This is used to free an SSPI identity structure */ +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); + +/* Forward-declaration of global variables defined in curl_sspi.c */ +extern HMODULE s_hSecDll; +extern PSecurityFunctionTable s_pSecFn; + +/* Provide some definitions missing in old headers */ +#define SP_NAME_DIGEST "WDigest" +#define SP_NAME_NTLM "NTLM" +#define SP_NAME_NEGOTIATE "Negotiate" +#define SP_NAME_KERBEROS "Kerberos" + +#ifndef ISC_REQ_USE_HTTP_STYLE +#define ISC_REQ_USE_HTTP_STYLE 0x01000000 +#endif + +#ifndef SEC_E_INVALID_PARAMETER +# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) +#endif +#ifndef SEC_E_DELEGATION_POLICY +# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) +#endif +#ifndef SEC_E_POLICY_NLTM_ONLY +# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) +#endif + +#ifndef SEC_I_SIGNATURE_NEEDED +# define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) +#endif + +#ifndef CRYPT_E_REVOKED +# define CRYPT_E_REVOKED ((HRESULT)0x80092010L) +#endif + +#ifndef CRYPT_E_NO_REVOCATION_DLL +# define CRYPT_E_NO_REVOCATION_DLL ((HRESULT)0x80092011L) +#endif + +#ifndef CRYPT_E_NO_REVOCATION_CHECK +# define CRYPT_E_NO_REVOCATION_CHECK ((HRESULT)0x80092012L) +#endif + +#ifndef CRYPT_E_REVOCATION_OFFLINE +# define CRYPT_E_REVOCATION_OFFLINE ((HRESULT)0x80092013L) +#endif + +#ifndef CRYPT_E_NOT_IN_REVOCATION_DATABASE +# define CRYPT_E_NOT_IN_REVOCATION_DATABASE ((HRESULT)0x80092014L) +#endif + +#ifdef UNICODE +# define SECFLAG_WINNT_AUTH_IDENTITY \ + (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE +#else +# define SECFLAG_WINNT_AUTH_IDENTITY \ + (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI +#endif + +/* + * Definitions required from ntsecapi.h are directly provided below this point + * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h + */ +#define KERB_WRAP_NO_ENCRYPT 0x80000001 + +#endif /* USE_WINDOWS_SSPI */ + +#endif /* HEADER_CURL_SSPI_H */ diff --git a/lib/curl_threads.c b/lib/curl_threads.c new file mode 100644 index 0000000..222d936 --- /dev/null +++ b/lib/curl_threads.c @@ -0,0 +1,153 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#if defined(USE_THREADS_POSIX) +# ifdef HAVE_PTHREAD_H +# include +# endif +#elif defined(USE_THREADS_WIN32) +# include +#endif + +#include "curl_threads.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +#if defined(USE_THREADS_POSIX) + +struct Curl_actual_call { + unsigned int (*func)(void *); + void *arg; +}; + +static void *curl_thread_create_thunk(void *arg) +{ + struct Curl_actual_call *ac = arg; + unsigned int (*func)(void *) = ac->func; + void *real_arg = ac->arg; + + free(ac); + + (*func)(real_arg); + + return 0; +} + +curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg) +{ + curl_thread_t t = malloc(sizeof(pthread_t)); + struct Curl_actual_call *ac = malloc(sizeof(struct Curl_actual_call)); + if(!(ac && t)) + goto err; + + ac->func = func; + ac->arg = arg; + + if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0) + goto err; + + return t; + +err: + free(t); + free(ac); + return curl_thread_t_null; +} + +void Curl_thread_destroy(curl_thread_t hnd) +{ + if(hnd != curl_thread_t_null) { + pthread_detach(*hnd); + free(hnd); + } +} + +int Curl_thread_join(curl_thread_t *hnd) +{ + int ret = (pthread_join(**hnd, NULL) == 0); + + free(*hnd); + *hnd = curl_thread_t_null; + + return ret; +} + +#elif defined(USE_THREADS_WIN32) + +/* !checksrc! disable SPACEBEFOREPAREN 1 */ +curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), + void *arg) +{ +#ifdef _WIN32_WCE + typedef HANDLE curl_win_thread_handle_t; +#else + typedef uintptr_t curl_win_thread_handle_t; +#endif + curl_thread_t t; + curl_win_thread_handle_t thread_handle; +#ifdef _WIN32_WCE + thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL); +#else + thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL); +#endif + t = (curl_thread_t)thread_handle; + if((t == 0) || (t == LongToHandle(-1L))) { +#ifdef _WIN32_WCE + DWORD gle = GetLastError(); + errno = ((gle == ERROR_ACCESS_DENIED || + gle == ERROR_NOT_ENOUGH_MEMORY) ? + EACCES : EINVAL); +#endif + return curl_thread_t_null; + } + return t; +} + +void Curl_thread_destroy(curl_thread_t hnd) +{ + CloseHandle(hnd); +} + +int Curl_thread_join(curl_thread_t *hnd) +{ +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) + int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); +#else + int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); +#endif + + Curl_thread_destroy(*hnd); + + *hnd = curl_thread_t_null; + + return ret; +} + +#endif /* USE_THREADS_* */ diff --git a/lib/curl_threads.h b/lib/curl_threads.h new file mode 100644 index 0000000..27a478d --- /dev/null +++ b/lib/curl_threads.h @@ -0,0 +1,65 @@ +#ifndef HEADER_CURL_THREADS_H +#define HEADER_CURL_THREADS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(USE_THREADS_POSIX) +# define CURL_STDCALL +# define curl_mutex_t pthread_mutex_t +# define curl_thread_t pthread_t * +# define curl_thread_t_null (pthread_t *)0 +# define Curl_mutex_init(m) pthread_mutex_init(m, NULL) +# define Curl_mutex_acquire(m) pthread_mutex_lock(m) +# define Curl_mutex_release(m) pthread_mutex_unlock(m) +# define Curl_mutex_destroy(m) pthread_mutex_destroy(m) +#elif defined(USE_THREADS_WIN32) +# define CURL_STDCALL __stdcall +# define curl_mutex_t CRITICAL_SECTION +# define curl_thread_t HANDLE +# define curl_thread_t_null (HANDLE)0 +# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) +# define Curl_mutex_init(m) InitializeCriticalSection(m) +# else +# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1) +# endif +# define Curl_mutex_acquire(m) EnterCriticalSection(m) +# define Curl_mutex_release(m) LeaveCriticalSection(m) +# define Curl_mutex_destroy(m) DeleteCriticalSection(m) +#endif + +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) + +/* !checksrc! disable SPACEBEFOREPAREN 1 */ +curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), + void *arg); + +void Curl_thread_destroy(curl_thread_t hnd); + +int Curl_thread_join(curl_thread_t *hnd); + +#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ + +#endif /* HEADER_CURL_THREADS_H */ diff --git a/lib/curl_trc.c b/lib/curl_trc.c new file mode 100644 index 0000000..b8dccc4 --- /dev/null +++ b/lib/curl_trc.c @@ -0,0 +1,243 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "curl_trc.h" +#include "urldata.h" +#include "easyif.h" +#include "cfilters.h" +#include "timeval.h" +#include "multiif.h" +#include "strcase.h" + +#include "cf-socket.h" +#include "connect.h" +#include "http2.h" +#include "http_proxy.h" +#include "cf-h1-proxy.h" +#include "cf-h2-proxy.h" +#include "cf-haproxy.h" +#include "cf-https-connect.h" +#include "socks.h" +#include "strtok.h" +#include "vtls/vtls.h" +#include "vquic/vquic.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +void Curl_debug(struct Curl_easy *data, curl_infotype type, + char *ptr, size_t size) +{ + if(data->set.verbose) { + static const char s_infotype[CURLINFO_END][3] = { + "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; + if(data->set.fdebug) { + bool inCallback = Curl_is_in_callback(data); + Curl_set_in_callback(data, true); + (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata); + Curl_set_in_callback(data, inCallback); + } + else { + switch(type) { + case CURLINFO_TEXT: + case CURLINFO_HEADER_OUT: + case CURLINFO_HEADER_IN: + fwrite(s_infotype[type], 2, 1, data->set.err); + fwrite(ptr, size, 1, data->set.err); + break; + default: /* nada */ + break; + } + } + } +} + + +/* Curl_failf() is for messages stating why we failed. + * The message SHALL NOT include any LF or CR. + */ +void Curl_failf(struct Curl_easy *data, const char *fmt, ...) +{ + DEBUGASSERT(!strchr(fmt, '\n')); + if(data->set.verbose || data->set.errorbuffer) { + va_list ap; + int len; + char error[CURL_ERROR_SIZE + 2]; + va_start(ap, fmt); + len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); + + if(data->set.errorbuffer && !data->state.errorbuf) { + strcpy(data->set.errorbuffer, error); + data->state.errorbuf = TRUE; /* wrote error string */ + } + error[len++] = '\n'; + error[len] = '\0'; + Curl_debug(data, CURLINFO_TEXT, error, len); + va_end(ap); + } +} + +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + +/* Curl_infof() is for info message along the way */ +#define MAXINFO 2048 + +void Curl_infof(struct Curl_easy *data, const char *fmt, ...) +{ + DEBUGASSERT(!strchr(fmt, '\n')); + if(data && data->set.verbose) { + va_list ap; + int len; + char buffer[MAXINFO + 2]; + va_start(ap, fmt); + len = mvsnprintf(buffer, MAXINFO, fmt, ap); + va_end(ap); + buffer[len++] = '\n'; + buffer[len] = '\0'; + Curl_debug(data, CURLINFO_TEXT, buffer, len); + } +} + +void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf, + const char *fmt, ...) +{ + DEBUGASSERT(cf); + if(Curl_trc_cf_is_verbose(cf, data)) { + va_list ap; + int len; + char buffer[MAXINFO + 2]; + len = msnprintf(buffer, MAXINFO, "[%s] ", cf->cft->name); + va_start(ap, fmt); + len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap); + va_end(ap); + buffer[len++] = '\n'; + buffer[len] = '\0'; + Curl_debug(data, CURLINFO_TEXT, buffer, len); + } +} + + +static struct Curl_cftype *cf_types[] = { + &Curl_cft_tcp, + &Curl_cft_udp, + &Curl_cft_unix, + &Curl_cft_tcp_accept, + &Curl_cft_happy_eyeballs, + &Curl_cft_setup, +#ifdef USE_NGHTTP2 + &Curl_cft_nghttp2, +#endif +#ifdef USE_SSL + &Curl_cft_ssl, +#ifndef CURL_DISABLE_PROXY + &Curl_cft_ssl_proxy, +#endif +#endif +#if !defined(CURL_DISABLE_PROXY) +#if !defined(CURL_DISABLE_HTTP) + &Curl_cft_h1_proxy, +#ifdef USE_NGHTTP2 + &Curl_cft_h2_proxy, +#endif + &Curl_cft_http_proxy, +#endif /* !CURL_DISABLE_HTTP */ + &Curl_cft_haproxy, + &Curl_cft_socks_proxy, +#endif /* !CURL_DISABLE_PROXY */ +#ifdef ENABLE_QUIC + &Curl_cft_http3, +#endif +#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) + &Curl_cft_http_connect, +#endif + NULL, +}; + +CURLcode Curl_trc_opt(const char *config) +{ + char *token, *tok_buf, *tmp; + size_t i; + int lvl; + + tmp = strdup(config); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ", ", &tok_buf); + while(token) { + switch(*token) { + case '-': + lvl = CURL_LOG_LVL_NONE; + ++token; + break; + case '+': + lvl = CURL_LOG_LVL_INFO; + ++token; + break; + default: + lvl = CURL_LOG_LVL_INFO; + break; + } + for(i = 0; cf_types[i]; ++i) { + if(strcasecompare(token, "all")) { + cf_types[i]->log_level = lvl; + } + else if(strcasecompare(token, cf_types[i]->name)) { + cf_types[i]->log_level = lvl; + break; + } + } + token = strtok_r(NULL, ", ", &tok_buf); + } + free(tmp); + return CURLE_OK; +} + +CURLcode Curl_trc_init(void) +{ +#ifdef DEBUGBUILD + /* WIP: we use the auto-init from an env var only in DEBUG builds for + * convenience. */ + const char *config = getenv("CURL_DEBUG"); + if(config) { + return Curl_trc_opt(config); + } +#endif /* DEBUGBUILD */ + return CURLE_OK; +} +#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */ + +CURLcode Curl_trc_init(void) +{ + return CURLE_OK; +} + +#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */ diff --git a/lib/curl_trc.h b/lib/curl_trc.h new file mode 100644 index 0000000..3a5387a --- /dev/null +++ b/lib/curl_trc.h @@ -0,0 +1,127 @@ +#ifndef HEADER_CURL_TRC_H +#define HEADER_CURL_TRC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +struct Curl_easy; +struct Curl_cfilter; + +/** + * Init logging, return != 0 on failure. + */ +CURLcode Curl_trc_init(void); + +/** + * Configure tracing. May be called several times during global + * initialization. Later calls may not take effect. + * + * Configuration format supported: + * - comma-separated list of component names to enable logging on. + * E.g. 'http/2,ssl'. Unknown names are ignored. Names are compared + * case-insensitive. + * - component 'all' applies to all known log components + * - prefixing a component with '+' or '-' will en-/disable logging for + * that component + * Example: 'all,-ssl' would enable logging for all components but the + * SSL filters. + * + * @param config configuration string + */ +CURLcode Curl_trc_opt(const char *config); + +/* the function used to output verbose information */ +void Curl_debug(struct Curl_easy *data, curl_infotype type, + char *ptr, size_t size); + +/** + * Output a failure message on registered callbacks for transfer. + */ +void Curl_failf(struct Curl_easy *data, + const char *fmt, ...) CURL_PRINTF(2, 3); + +#define failf Curl_failf + +#define CURL_LOG_LVL_NONE 0 +#define CURL_LOG_LVL_INFO 1 + + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define CURL_HAVE_C99 +#endif + +#ifdef CURL_HAVE_C99 +#define infof(data, ...) \ + do { if(Curl_trc_is_verbose(data)) \ + Curl_infof(data, __VA_ARGS__); } while(0) +#define CURL_TRC_CF(data, cf, ...) \ + do { if(Curl_trc_cf_is_verbose(cf, data)) \ + Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0) + +#else +#define infof Curl_infof +#define CURL_TRC_CF Curl_trc_cf_infof +#endif + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +/* informational messages enabled */ + +#define Curl_trc_is_verbose(data) ((data) && (data)->set.verbose) +#define Curl_trc_cf_is_verbose(cf, data) \ + ((data) && (data)->set.verbose && \ + (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO) + +/** + * Output an informational message when transfer's verbose logging is enabled. + */ +void Curl_infof(struct Curl_easy *data, + const char *fmt, ...) CURL_PRINTF(2, 3); + +/** + * Output an informational message when both transfer's verbose logging + * and connection filters verbose logging are enabled. + */ +void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf, + const char *fmt, ...) CURL_PRINTF(3, 4); + +#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */ +/* All informational messages are not compiled in for size savings */ + +#define Curl_trc_is_verbose(d) ((void)(d), FALSE) +#define Curl_trc_cf_is_verbose(x,y) ((void)(x), (void)(y), FALSE) + +static void Curl_infof(struct Curl_easy *data, const char *fmt, ...) +{ + (void)data; (void)fmt; +} + +static void Curl_trc_cf_infof(struct Curl_easy *data, + struct Curl_cfilter *cf, + const char *fmt, ...) +{ + (void)data; (void)cf; (void)fmt; +} + +#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */ + +#endif /* HEADER_CURL_TRC_H */ diff --git a/lib/curlx.h b/lib/curlx.h new file mode 100644 index 0000000..7a753d6 --- /dev/null +++ b/lib/curlx.h @@ -0,0 +1,118 @@ +#ifndef HEADER_CURL_CURLX_H +#define HEADER_CURL_CURLX_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Defines protos and includes all header files that provide the curlx_* + * functions. The curlx_* functions are not part of the libcurl API, but are + * stand-alone functions whose sources can be built and linked by apps if need + * be. + */ + +#include +/* this is still a public header file that provides the curl_mprintf() + functions while they still are offered publicly. They will be made library- + private one day */ + +#include "strcase.h" +/* "strcase.h" provides the strcasecompare protos */ + +#include "strtoofft.h" +/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a + curl_off_t number from a given string. +*/ + +#include "nonblock.h" +/* "nonblock.h" provides curlx_nonblock() */ + +#include "warnless.h" +/* "warnless.h" provides functions: + + curlx_ultous() + curlx_ultouc() + curlx_uztosi() +*/ + +#include "curl_multibyte.h" +/* "curl_multibyte.h" provides these functions and macros: + + curlx_convert_UTF8_to_wchar() + curlx_convert_wchar_to_UTF8() + curlx_convert_UTF8_to_tchar() + curlx_convert_tchar_to_UTF8() + curlx_unicodefree() +*/ + +#include "version_win32.h" +/* "version_win32.h" provides curlx_verify_windows_version() */ + +/* Now setup curlx_ * names for the functions that are to become curlx_ and + be removed from a future libcurl official API: + curlx_getenv + curlx_mprintf (and its variations) + curlx_strcasecompare + curlx_strncasecompare + +*/ + +#define curlx_getenv curl_getenv +#define curlx_mvsnprintf curl_mvsnprintf +#define curlx_msnprintf curl_msnprintf +#define curlx_maprintf curl_maprintf +#define curlx_mvaprintf curl_mvaprintf +#define curlx_msprintf curl_msprintf +#define curlx_mprintf curl_mprintf +#define curlx_mfprintf curl_mfprintf +#define curlx_mvsprintf curl_mvsprintf +#define curlx_mvprintf curl_mvprintf +#define curlx_mvfprintf curl_mvfprintf + +#ifdef ENABLE_CURLX_PRINTF +/* If this define is set, we define all "standard" printf() functions to use + the curlx_* version instead. It makes the source code transparent and + easier to understand/patch. Undefine them first. */ +# undef printf +# undef fprintf +# undef sprintf +# undef msnprintf +# undef vprintf +# undef vfprintf +# undef vsprintf +# undef mvsnprintf +# undef aprintf +# undef vaprintf + +# define printf curlx_mprintf +# define fprintf curlx_mfprintf +# define sprintf curlx_msprintf +# define msnprintf curlx_msnprintf +# define vprintf curlx_mvprintf +# define vfprintf curlx_mvfprintf +# define mvsnprintf curlx_mvsnprintf +# define aprintf curlx_maprintf +# define vaprintf curlx_mvaprintf +#endif /* ENABLE_CURLX_PRINTF */ + +#endif /* HEADER_CURL_CURLX_H */ diff --git a/lib/dict.c b/lib/dict.c new file mode 100644 index 0000000..3239848 --- /dev/null +++ b/lib/dict.c @@ -0,0 +1,323 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_DICT + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "escape.h" +#include "progress.h" +#include "dict.h" +#include "curl_printf.h" +#include "strcase.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Forward declarations. + */ + +static CURLcode dict_do(struct Curl_easy *data, bool *done); + +/* + * DICT protocol handler. + */ + +const struct Curl_handler Curl_handler_dict = { + "DICT", /* scheme */ + ZERO_NULL, /* setup_connection */ + dict_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_DICT, /* defport */ + CURLPROTO_DICT, /* protocol */ + CURLPROTO_DICT, /* family */ + PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ +}; + +#define DYN_DICT_WORD 10000 +static char *unescape_word(const char *input) +{ + struct dynbuf out; + const char *ptr; + CURLcode result = CURLE_OK; + Curl_dyn_init(&out, DYN_DICT_WORD); + + /* According to RFC2229 section 2.2, these letters need to be escaped with + \[letter] */ + for(ptr = input; *ptr; ptr++) { + char ch = *ptr; + if((ch <= 32) || (ch == 127) || + (ch == '\'') || (ch == '\"') || (ch == '\\')) + result = Curl_dyn_addn(&out, "\\", 1); + if(!result) + result = Curl_dyn_addn(&out, ptr, 1); + if(result) + return NULL; + } + return Curl_dyn_ptr(&out); +} + +/* sendf() sends formatted data to the server */ +static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data, + const char *fmt, ...) CURL_PRINTF(3, 4); + +static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data, + const char *fmt, ...) +{ + ssize_t bytes_written; + size_t write_len; + CURLcode result = CURLE_OK; + char *s; + char *sptr; + va_list ap; + va_start(ap, fmt); + s = vaprintf(fmt, ap); /* returns an allocated string */ + va_end(ap); + if(!s) + return CURLE_OUT_OF_MEMORY; /* failure */ + + bytes_written = 0; + write_len = strlen(s); + sptr = s; + + for(;;) { + /* Write the buffer to the socket */ + result = Curl_write(data, sockfd, sptr, write_len, &bytes_written); + + if(result) + break; + + Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written); + + if((size_t)bytes_written != write_len) { + /* if not all was written at once, we must advance the pointer, decrease + the size left and try again! */ + write_len -= bytes_written; + sptr += bytes_written; + } + else + break; + } + + free(s); /* free the output string */ + + return result; +} + +static CURLcode dict_do(struct Curl_easy *data, bool *done) +{ + char *word; + char *eword = NULL; + char *ppath; + char *database = NULL; + char *strategy = NULL; + char *nthdef = NULL; /* This is not part of the protocol, but required + by RFC 2229 */ + CURLcode result; + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + + char *path; + + *done = TRUE; /* unconditionally */ + + /* url-decode path before further evaluation */ + result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL); + if(result) + return result; + + if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || + strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || + strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { + + word = strchr(path, ':'); + if(word) { + word++; + database = strchr(word, ':'); + if(database) { + *database++ = (char)0; + strategy = strchr(database, ':'); + if(strategy) { + *strategy++ = (char)0; + nthdef = strchr(strategy, ':'); + if(nthdef) { + *nthdef = (char)0; + } + } + } + } + + if(!word || (*word == (char)0)) { + infof(data, "lookup word is missing"); + word = (char *)"default"; + } + if(!database || (*database == (char)0)) { + database = (char *)"!"; + } + if(!strategy || (*strategy == (char)0)) { + strategy = (char *)"."; + } + + eword = unescape_word(word); + if(!eword) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + result = sendf(sockfd, data, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" + "MATCH " + "%s " /* database */ + "%s " /* strategy */ + "%s\r\n" /* word */ + "QUIT\r\n", + database, + strategy, + eword); + + if(result) { + failf(data, "Failed sending DICT request"); + goto error; + } + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */ + } + else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || + strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || + strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { + + word = strchr(path, ':'); + if(word) { + word++; + database = strchr(word, ':'); + if(database) { + *database++ = (char)0; + nthdef = strchr(database, ':'); + if(nthdef) { + *nthdef = (char)0; + } + } + } + + if(!word || (*word == (char)0)) { + infof(data, "lookup word is missing"); + word = (char *)"default"; + } + if(!database || (*database == (char)0)) { + database = (char *)"!"; + } + + eword = unescape_word(word); + if(!eword) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + result = sendf(sockfd, data, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" + "DEFINE " + "%s " /* database */ + "%s\r\n" /* word */ + "QUIT\r\n", + database, + eword); + + if(result) { + failf(data, "Failed sending DICT request"); + goto error; + } + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + } + else { + + ppath = strchr(path, '/'); + if(ppath) { + int i; + + ppath++; + for(i = 0; ppath[i]; i++) { + if(ppath[i] == ':') + ppath[i] = ' '; + } + result = sendf(sockfd, data, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" + "%s\r\n" + "QUIT\r\n", ppath); + if(result) { + failf(data, "Failed sending DICT request"); + goto error; + } + + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + } + } + +error: + free(eword); + free(path); + return result; +} +#endif /* CURL_DISABLE_DICT */ diff --git a/lib/dict.h b/lib/dict.h new file mode 100644 index 0000000..ba9a927 --- /dev/null +++ b/lib/dict.h @@ -0,0 +1,31 @@ +#ifndef HEADER_CURL_DICT_H +#define HEADER_CURL_DICT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifndef CURL_DISABLE_DICT +extern const struct Curl_handler Curl_handler_dict; +#endif + +#endif /* HEADER_CURL_DICT_H */ diff --git a/lib/doh.c b/lib/doh.c new file mode 100644 index 0000000..ef32d50 --- /dev/null +++ b/lib/doh.c @@ -0,0 +1,995 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_DOH + +#include "urldata.h" +#include "curl_addrinfo.h" +#include "doh.h" + +#include "sendf.h" +#include "multiif.h" +#include "url.h" +#include "share.h" +#include "curl_base64.h" +#include "connect.h" +#include "strdup.h" +#include "dynbuf.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define DNS_CLASS_IN 0x01 + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static const char * const errors[]={ + "", + "Bad label", + "Out of range", + "Label loop", + "Too small", + "Out of memory", + "RDATA length", + "Malformat", + "Bad RCODE", + "Unexpected TYPE", + "Unexpected CLASS", + "No content", + "Bad ID", + "Name too long" +}; + +static const char *doh_strerror(DOHcode code) +{ + if((code >= DOH_OK) && (code <= DOH_DNS_NAME_TOO_LONG)) + return errors[code]; + return "bad error code"; +} +#endif + +/* @unittest 1655 + */ +UNITTEST DOHcode doh_encode(const char *host, + DNStype dnstype, + unsigned char *dnsp, /* buffer */ + size_t len, /* buffer size */ + size_t *olen) /* output length */ +{ + const size_t hostlen = strlen(host); + unsigned char *orig = dnsp; + const char *hostp = host; + + /* The expected output length is 16 bytes more than the length of + * the QNAME-encoding of the host name. + * + * A valid DNS name may not contain a zero-length label, except at + * the end. For this reason, a name beginning with a dot, or + * containing a sequence of two or more consecutive dots, is invalid + * and cannot be encoded as a QNAME. + * + * If the host name ends with a trailing dot, the corresponding + * QNAME-encoding is one byte longer than the host name. If (as is + * also valid) the hostname is shortened by the omission of the + * trailing dot, then its QNAME-encoding will be two bytes longer + * than the host name. + * + * Each [ label, dot ] pair is encoded as [ length, label ], + * preserving overall length. A final [ label ] without a dot is + * also encoded as [ length, label ], increasing overall length + * by one. The encoding is completed by appending a zero byte, + * representing the zero-length root label, again increasing + * the overall length by one. + */ + + size_t expected_len; + DEBUGASSERT(hostlen); + expected_len = 12 + 1 + hostlen + 4; + if(host[hostlen-1]!='.') + expected_len++; + + if(expected_len > (256 + 16)) /* RFCs 1034, 1035 */ + return DOH_DNS_NAME_TOO_LONG; + + if(len < expected_len) + return DOH_TOO_SMALL_BUFFER; + + *dnsp++ = 0; /* 16 bit id */ + *dnsp++ = 0; + *dnsp++ = 0x01; /* |QR| Opcode |AA|TC|RD| Set the RD bit */ + *dnsp++ = '\0'; /* |RA| Z | RCODE | */ + *dnsp++ = '\0'; + *dnsp++ = 1; /* QDCOUNT (number of entries in the question section) */ + *dnsp++ = '\0'; + *dnsp++ = '\0'; /* ANCOUNT */ + *dnsp++ = '\0'; + *dnsp++ = '\0'; /* NSCOUNT */ + *dnsp++ = '\0'; + *dnsp++ = '\0'; /* ARCOUNT */ + + /* encode each label and store it in the QNAME */ + while(*hostp) { + size_t labellen; + char *dot = strchr(hostp, '.'); + if(dot) + labellen = dot - hostp; + else + labellen = strlen(hostp); + if((labellen > 63) || (!labellen)) { + /* label is too long or too short, error out */ + *olen = 0; + return DOH_DNS_BAD_LABEL; + } + /* label is non-empty, process it */ + *dnsp++ = (unsigned char)labellen; + memcpy(dnsp, hostp, labellen); + dnsp += labellen; + hostp += labellen; + /* advance past dot, but only if there is one */ + if(dot) + hostp++; + } /* next label */ + + *dnsp++ = 0; /* append zero-length label for root */ + + /* There are assigned TYPE codes beyond 255: use range [1..65535] */ + *dnsp++ = (unsigned char)(255 & (dnstype>>8)); /* upper 8 bit TYPE */ + *dnsp++ = (unsigned char)(255 & dnstype); /* lower 8 bit TYPE */ + + *dnsp++ = '\0'; /* upper 8 bit CLASS */ + *dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */ + + *olen = dnsp - orig; + + /* verify that our estimation of length is valid, since + * this has led to buffer overflows in this function */ + DEBUGASSERT(*olen == expected_len); + return DOH_OK; +} + +static size_t +doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct dynbuf *mem = (struct dynbuf *)userp; + + if(Curl_dyn_addn(mem, contents, realsize)) + return 0; + + return realsize; +} + +/* called from multi.c when this DoH transfer is complete */ +static int doh_done(struct Curl_easy *doh, CURLcode result) +{ + struct Curl_easy *data = doh->set.dohfor; + struct dohdata *dohp = data->req.doh; + /* so one of the DoH request done for the 'data' transfer is now complete! */ + dohp->pending--; + infof(data, "a DoH request is completed, %u to go", dohp->pending); + if(result) + infof(data, "DoH request %s", curl_easy_strerror(result)); + + if(!dohp->pending) { + /* DoH completed */ + curl_slist_free_all(dohp->headers); + dohp->headers = NULL; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + return 0; +} + +#define ERROR_CHECK_SETOPT(x,y) \ +do { \ + result = curl_easy_setopt(doh, x, y); \ + if(result && \ + result != CURLE_NOT_BUILT_IN && \ + result != CURLE_UNKNOWN_OPTION) \ + goto error; \ +} while(0) + +static CURLcode dohprobe(struct Curl_easy *data, + struct dnsprobe *p, DNStype dnstype, + const char *host, + const char *url, CURLM *multi, + struct curl_slist *headers) +{ + struct Curl_easy *doh = NULL; + CURLcode result = CURLE_OK; + timediff_t timeout_ms; + DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer), + &p->dohlen); + if(d) { + failf(data, "Failed to encode DoH packet [%d]", d); + return CURLE_OUT_OF_MEMORY; + } + + p->dnstype = dnstype; + Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE); + + timeout_ms = Curl_timeleft(data, NULL, TRUE); + if(timeout_ms <= 0) { + result = CURLE_OPERATION_TIMEDOUT; + goto error; + } + /* Curl_open() is the internal version of curl_easy_init() */ + result = Curl_open(&doh); + if(!result) { + /* pass in the struct pointer via a local variable to please coverity and + the gcc typecheck helpers */ + struct dynbuf *resp = &p->serverdoh; + doh->state.internal = true; + ERROR_CHECK_SETOPT(CURLOPT_URL, url); + ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https"); + ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); + ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp); + ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer); + ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen); + ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers); +#ifdef USE_HTTP2 + ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); + ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L); +#endif +#ifndef CURLDEBUG + /* enforce HTTPS if not debug */ + ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS); +#else + /* in debug mode, also allow http */ + ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS); +#endif + ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms); + ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share); + if(data->set.err && data->set.err != stderr) + ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err); + if(data->set.verbose) + ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L); + if(data->set.no_signal) + ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L); + + ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST, + data->set.doh_verifyhost ? 2L : 0L); + ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER, + data->set.doh_verifypeer ? 1L : 0L); + ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS, + data->set.doh_verifystatus ? 1L : 0L); + + /* Inherit *some* SSL options from the user's transfer. This is a + best-guess as to which options are needed for compatibility. #3661 + + Note DoH does not inherit the user's proxy server so proxy SSL settings + have no effect and are not inherited. If that changes then two new + options should be added to check doh proxy insecure separately, + CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER. + */ + if(data->set.ssl.falsestart) + ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L); + if(data->set.str[STRING_SSL_CAFILE]) { + ERROR_CHECK_SETOPT(CURLOPT_CAINFO, + data->set.str[STRING_SSL_CAFILE]); + } + if(data->set.blobs[BLOB_CAINFO]) { + ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB, + data->set.blobs[BLOB_CAINFO]); + } + if(data->set.str[STRING_SSL_CAPATH]) { + ERROR_CHECK_SETOPT(CURLOPT_CAPATH, + data->set.str[STRING_SSL_CAPATH]); + } + if(data->set.str[STRING_SSL_CRLFILE]) { + ERROR_CHECK_SETOPT(CURLOPT_CRLFILE, + data->set.str[STRING_SSL_CRLFILE]); + } + if(data->set.ssl.certinfo) + ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L); + if(data->set.ssl.fsslctx) + ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx); + if(data->set.ssl.fsslctxp) + ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp); + if(data->set.fdebug) + ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug); + if(data->set.debugdata) + ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata); + if(data->set.str[STRING_SSL_EC_CURVES]) { + ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES, + data->set.str[STRING_SSL_EC_CURVES]); + } + + { + long mask = + (data->set.ssl.enable_beast ? + CURLSSLOPT_ALLOW_BEAST : 0) | + (data->set.ssl.no_revoke ? + CURLSSLOPT_NO_REVOKE : 0) | + (data->set.ssl.no_partialchain ? + CURLSSLOPT_NO_PARTIALCHAIN : 0) | + (data->set.ssl.revoke_best_effort ? + CURLSSLOPT_REVOKE_BEST_EFFORT : 0) | + (data->set.ssl.native_ca_store ? + CURLSSLOPT_NATIVE_CA : 0) | + (data->set.ssl.auto_client_cert ? + CURLSSLOPT_AUTO_CLIENT_CERT : 0); + + (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask); + } + + doh->set.fmultidone = doh_done; + doh->set.dohfor = data; /* identify for which transfer this is done */ + p->easy = doh; + + /* DoH handles must not inherit private_data. The handles may be passed to + the user via callbacks and the user will be able to identify them as + internal handles because private data is not set. The user can then set + private_data via CURLOPT_PRIVATE if they so choose. */ + DEBUGASSERT(!doh->set.private_data); + + if(curl_multi_add_handle(multi, doh)) + goto error; + } + else + goto error; + return CURLE_OK; + +error: + Curl_close(&doh); + return result; +} + +/* + * Curl_doh() resolves a name using DoH. It resolves a name and returns a + * 'Curl_addrinfo *' with the address information. + */ + +struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp) +{ + CURLcode result = CURLE_OK; + int slot; + struct dohdata *dohp; + struct connectdata *conn = data->conn; + *waitp = FALSE; + (void)hostname; + (void)port; + + DEBUGASSERT(!data->req.doh); + DEBUGASSERT(conn); + + /* start clean, consider allocating this struct on demand */ + dohp = data->req.doh = calloc(1, sizeof(struct dohdata)); + if(!dohp) + return NULL; + + conn->bits.doh = TRUE; + dohp->host = hostname; + dohp->port = port; + dohp->headers = + curl_slist_append(NULL, + "Content-Type: application/dns-message"); + if(!dohp->headers) + goto error; + + /* create IPv4 DoH request */ + result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4], + DNS_TYPE_A, hostname, data->set.str[STRING_DOH], + data->multi, dohp->headers); + if(result) + goto error; + dohp->pending++; + +#ifdef ENABLE_IPV6 + if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { + /* create IPv6 DoH request */ + result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6], + DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH], + data->multi, dohp->headers); + if(result) + goto error; + dohp->pending++; + } +#endif + *waitp = TRUE; /* this never returns synchronously */ + return NULL; + +error: + curl_slist_free_all(dohp->headers); + data->req.doh->headers = NULL; + for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { + (void)curl_multi_remove_handle(data->multi, dohp->probe[slot].easy); + Curl_close(&dohp->probe[slot].easy); + } + Curl_safefree(data->req.doh); + return NULL; +} + +static DOHcode skipqname(const unsigned char *doh, size_t dohlen, + unsigned int *indexp) +{ + unsigned char length; + do { + if(dohlen < (*indexp + 1)) + return DOH_DNS_OUT_OF_RANGE; + length = doh[*indexp]; + if((length & 0xc0) == 0xc0) { + /* name pointer, advance over it and be done */ + if(dohlen < (*indexp + 2)) + return DOH_DNS_OUT_OF_RANGE; + *indexp += 2; + break; + } + if(length & 0xc0) + return DOH_DNS_BAD_LABEL; + if(dohlen < (*indexp + 1 + length)) + return DOH_DNS_OUT_OF_RANGE; + *indexp += (unsigned int)(1 + length); + } while(length); + return DOH_OK; +} + +static unsigned short get16bit(const unsigned char *doh, int index) +{ + return (unsigned short)((doh[index] << 8) | doh[index + 1]); +} + +static unsigned int get32bit(const unsigned char *doh, int index) +{ + /* make clang and gcc optimize this to bswap by incrementing + the pointer first. */ + doh += index; + + /* avoid undefined behavior by casting to unsigned before shifting + 24 bits, possibly into the sign bit. codegen is same, but + ub sanitizer won't be upset */ + return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) | + ((unsigned)doh[2] << 8) | doh[3]; +} + +static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d) +{ + /* silently ignore addresses over the limit */ + if(d->numaddr < DOH_MAX_ADDR) { + struct dohaddr *a = &d->addr[d->numaddr]; + a->type = DNS_TYPE_A; + memcpy(&a->ip.v4, &doh[index], 4); + d->numaddr++; + } + return DOH_OK; +} + +static DOHcode store_aaaa(const unsigned char *doh, + int index, + struct dohentry *d) +{ + /* silently ignore addresses over the limit */ + if(d->numaddr < DOH_MAX_ADDR) { + struct dohaddr *a = &d->addr[d->numaddr]; + a->type = DNS_TYPE_AAAA; + memcpy(&a->ip.v6, &doh[index], 16); + d->numaddr++; + } + return DOH_OK; +} + +static DOHcode store_cname(const unsigned char *doh, + size_t dohlen, + unsigned int index, + struct dohentry *d) +{ + struct dynbuf *c; + unsigned int loop = 128; /* a valid DNS name can never loop this much */ + unsigned char length; + + if(d->numcname == DOH_MAX_CNAME) + return DOH_OK; /* skip! */ + + c = &d->cname[d->numcname++]; + do { + if(index >= dohlen) + return DOH_DNS_OUT_OF_RANGE; + length = doh[index]; + if((length & 0xc0) == 0xc0) { + int newpos; + /* name pointer, get the new offset (14 bits) */ + if((index + 1) >= dohlen) + return DOH_DNS_OUT_OF_RANGE; + + /* move to the new index */ + newpos = (length & 0x3f) << 8 | doh[index + 1]; + index = newpos; + continue; + } + else if(length & 0xc0) + return DOH_DNS_BAD_LABEL; /* bad input */ + else + index++; + + if(length) { + if(Curl_dyn_len(c)) { + if(Curl_dyn_addn(c, STRCONST("."))) + return DOH_OUT_OF_MEM; + } + if((index + length) > dohlen) + return DOH_DNS_BAD_LABEL; + + if(Curl_dyn_addn(c, &doh[index], length)) + return DOH_OUT_OF_MEM; + index += length; + } + } while(length && --loop); + + if(!loop) + return DOH_DNS_LABEL_LOOP; + return DOH_OK; +} + +static DOHcode rdata(const unsigned char *doh, + size_t dohlen, + unsigned short rdlength, + unsigned short type, + int index, + struct dohentry *d) +{ + /* RDATA + - A (TYPE 1): 4 bytes + - AAAA (TYPE 28): 16 bytes + - NS (TYPE 2): N bytes */ + DOHcode rc; + + switch(type) { + case DNS_TYPE_A: + if(rdlength != 4) + return DOH_DNS_RDATA_LEN; + rc = store_a(doh, index, d); + if(rc) + return rc; + break; + case DNS_TYPE_AAAA: + if(rdlength != 16) + return DOH_DNS_RDATA_LEN; + rc = store_aaaa(doh, index, d); + if(rc) + return rc; + break; + case DNS_TYPE_CNAME: + rc = store_cname(doh, dohlen, index, d); + if(rc) + return rc; + break; + case DNS_TYPE_DNAME: + /* explicit for clarity; just skip; rely on synthesized CNAME */ + break; + default: + /* unsupported type, just skip it */ + break; + } + return DOH_OK; +} + +UNITTEST void de_init(struct dohentry *de) +{ + int i; + memset(de, 0, sizeof(*de)); + de->ttl = INT_MAX; + for(i = 0; i < DOH_MAX_CNAME; i++) + Curl_dyn_init(&de->cname[i], DYN_DOH_CNAME); +} + + +UNITTEST DOHcode doh_decode(const unsigned char *doh, + size_t dohlen, + DNStype dnstype, + struct dohentry *d) +{ + unsigned char rcode; + unsigned short qdcount; + unsigned short ancount; + unsigned short type = 0; + unsigned short rdlength; + unsigned short nscount; + unsigned short arcount; + unsigned int index = 12; + DOHcode rc; + + if(dohlen < 12) + return DOH_TOO_SMALL_BUFFER; /* too small */ + if(!doh || doh[0] || doh[1]) + return DOH_DNS_BAD_ID; /* bad ID */ + rcode = doh[3] & 0x0f; + if(rcode) + return DOH_DNS_BAD_RCODE; /* bad rcode */ + + qdcount = get16bit(doh, 4); + while(qdcount) { + rc = skipqname(doh, dohlen, &index); + if(rc) + return rc; /* bad qname */ + if(dohlen < (index + 4)) + return DOH_DNS_OUT_OF_RANGE; + index += 4; /* skip question's type and class */ + qdcount--; + } + + ancount = get16bit(doh, 6); + while(ancount) { + unsigned short class; + unsigned int ttl; + + rc = skipqname(doh, dohlen, &index); + if(rc) + return rc; /* bad qname */ + + if(dohlen < (index + 2)) + return DOH_DNS_OUT_OF_RANGE; + + type = get16bit(doh, index); + if((type != DNS_TYPE_CNAME) /* may be synthesized from DNAME */ + && (type != DNS_TYPE_DNAME) /* if present, accept and ignore */ + && (type != dnstype)) + /* Not the same type as was asked for nor CNAME nor DNAME */ + return DOH_DNS_UNEXPECTED_TYPE; + index += 2; + + if(dohlen < (index + 2)) + return DOH_DNS_OUT_OF_RANGE; + class = get16bit(doh, index); + if(DNS_CLASS_IN != class) + return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */ + index += 2; + + if(dohlen < (index + 4)) + return DOH_DNS_OUT_OF_RANGE; + + ttl = get32bit(doh, index); + if(ttl < d->ttl) + d->ttl = ttl; + index += 4; + + if(dohlen < (index + 2)) + return DOH_DNS_OUT_OF_RANGE; + + rdlength = get16bit(doh, index); + index += 2; + if(dohlen < (index + rdlength)) + return DOH_DNS_OUT_OF_RANGE; + + rc = rdata(doh, dohlen, rdlength, type, index, d); + if(rc) + return rc; /* bad rdata */ + index += rdlength; + ancount--; + } + + nscount = get16bit(doh, 8); + while(nscount) { + rc = skipqname(doh, dohlen, &index); + if(rc) + return rc; /* bad qname */ + + if(dohlen < (index + 8)) + return DOH_DNS_OUT_OF_RANGE; + + index += 2 + 2 + 4; /* type, class and ttl */ + + if(dohlen < (index + 2)) + return DOH_DNS_OUT_OF_RANGE; + + rdlength = get16bit(doh, index); + index += 2; + if(dohlen < (index + rdlength)) + return DOH_DNS_OUT_OF_RANGE; + index += rdlength; + nscount--; + } + + arcount = get16bit(doh, 10); + while(arcount) { + rc = skipqname(doh, dohlen, &index); + if(rc) + return rc; /* bad qname */ + + if(dohlen < (index + 8)) + return DOH_DNS_OUT_OF_RANGE; + + index += 2 + 2 + 4; /* type, class and ttl */ + + if(dohlen < (index + 2)) + return DOH_DNS_OUT_OF_RANGE; + + rdlength = get16bit(doh, index); + index += 2; + if(dohlen < (index + rdlength)) + return DOH_DNS_OUT_OF_RANGE; + index += rdlength; + arcount--; + } + + if(index != dohlen) + return DOH_DNS_MALFORMAT; /* something is wrong */ + + if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr) + /* nothing stored! */ + return DOH_NO_CONTENT; + + return DOH_OK; /* ok */ +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void showdoh(struct Curl_easy *data, + const struct dohentry *d) +{ + int i; + infof(data, "TTL: %u seconds", d->ttl); + for(i = 0; i < d->numaddr; i++) { + const struct dohaddr *a = &d->addr[i]; + if(a->type == DNS_TYPE_A) { + infof(data, "DoH A: %u.%u.%u.%u", + a->ip.v4[0], a->ip.v4[1], + a->ip.v4[2], a->ip.v4[3]); + } + else if(a->type == DNS_TYPE_AAAA) { + int j; + char buffer[128]; + char *ptr; + size_t len; + msnprintf(buffer, 128, "DoH AAAA: "); + ptr = &buffer[10]; + len = 118; + for(j = 0; j < 16; j += 2) { + size_t l; + msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j], + d->addr[i].ip.v6[j + 1]); + l = strlen(ptr); + len -= l; + ptr += l; + } + infof(data, "%s", buffer); + } + } + for(i = 0; i < d->numcname; i++) { + infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i])); + } +} +#else +#define showdoh(x,y) +#endif + +/* + * doh2ai() + * + * This function returns a pointer to the first element of a newly allocated + * Curl_addrinfo struct linked list filled with the data from a set of DoH + * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for + * a IPv6 stack, but usable also for IPv4, all hosts and environments. + * + * The memory allocated by this function *MUST* be free'd later on calling + * Curl_freeaddrinfo(). For each successful call to this function there + * must be an associated call later to Curl_freeaddrinfo(). + */ + +static CURLcode doh2ai(const struct dohentry *de, const char *hostname, + int port, struct Curl_addrinfo **aip) +{ + struct Curl_addrinfo *ai; + struct Curl_addrinfo *prevai = NULL; + struct Curl_addrinfo *firstai = NULL; + struct sockaddr_in *addr; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *addr6; +#endif + CURLcode result = CURLE_OK; + int i; + size_t hostlen = strlen(hostname) + 1; /* include null-terminator */ + + DEBUGASSERT(de); + + if(!de->numaddr) + return CURLE_COULDNT_RESOLVE_HOST; + + for(i = 0; i < de->numaddr; i++) { + size_t ss_size; + CURL_SA_FAMILY_T addrtype; + if(de->addr[i].type == DNS_TYPE_AAAA) { +#ifndef ENABLE_IPV6 + /* we can't handle IPv6 addresses */ + continue; +#else + ss_size = sizeof(struct sockaddr_in6); + addrtype = AF_INET6; +#endif + } + else { + ss_size = sizeof(struct sockaddr_in); + addrtype = AF_INET; + } + + ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen); + if(!ai) { + result = CURLE_OUT_OF_MEMORY; + break; + } + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + ai->ai_canonname = (void *)((char *)ai->ai_addr + ss_size); + memcpy(ai->ai_canonname, hostname, hostlen); + + if(!firstai) + /* store the pointer we want to return from this function */ + firstai = ai; + + if(prevai) + /* make the previous entry point to this */ + prevai->ai_next = ai; + + ai->ai_family = addrtype; + + /* we return all names as STREAM, so when using this address for TFTP + the type must be ignored and conn->socktype be used instead! */ + ai->ai_socktype = SOCK_STREAM; + + ai->ai_addrlen = (curl_socklen_t)ss_size; + + /* leave the rest of the struct filled with zero */ + + switch(ai->ai_family) { + case AF_INET: + addr = (void *)ai->ai_addr; /* storage area for this info */ + DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4)); + memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr)); + addr->sin_family = addrtype; + addr->sin_port = htons((unsigned short)port); + break; + +#ifdef ENABLE_IPV6 + case AF_INET6: + addr6 = (void *)ai->ai_addr; /* storage area for this info */ + DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6)); + memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr)); + addr6->sin6_family = addrtype; + addr6->sin6_port = htons((unsigned short)port); + break; +#endif + } + + prevai = ai; + } + + if(result) { + Curl_freeaddrinfo(firstai); + firstai = NULL; + } + *aip = firstai; + + return result; +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static const char *type2name(DNStype dnstype) +{ + return (dnstype == DNS_TYPE_A)?"A":"AAAA"; +} +#endif + +UNITTEST void de_cleanup(struct dohentry *d) +{ + int i = 0; + for(i = 0; i < d->numcname; i++) { + Curl_dyn_free(&d->cname[i]); + } +} + +CURLcode Curl_doh_is_resolved(struct Curl_easy *data, + struct Curl_dns_entry **dnsp) +{ + CURLcode result; + struct dohdata *dohp = data->req.doh; + *dnsp = NULL; /* defaults to no response */ + if(!dohp) + return CURLE_OUT_OF_MEMORY; + + if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy && + !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) { + failf(data, "Could not DoH-resolve: %s", data->state.async.hostname); + return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY: + CURLE_COULDNT_RESOLVE_HOST; + } + else if(!dohp->pending) { + DOHcode rc[DOH_PROBE_SLOTS] = { + DOH_OK, DOH_OK + }; + struct dohentry de; + int slot; + /* remove DoH handles from multi handle and close them */ + for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { + curl_multi_remove_handle(data->multi, dohp->probe[slot].easy); + Curl_close(&dohp->probe[slot].easy); + } + /* parse the responses, create the struct and return it! */ + de_init(&de); + for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { + struct dnsprobe *p = &dohp->probe[slot]; + if(!p->dnstype) + continue; + rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh), + Curl_dyn_len(&p->serverdoh), + p->dnstype, + &de); + Curl_dyn_free(&p->serverdoh); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(rc[slot]) { + infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]), + type2name(p->dnstype), dohp->host); + } +#endif + } /* next slot */ + + result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */ + if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) { + /* we have an address, of one kind or other */ + struct Curl_dns_entry *dns; + struct Curl_addrinfo *ai; + + infof(data, "DoH Host name: %s", dohp->host); + showdoh(data, &de); + + result = doh2ai(&de, dohp->host, dohp->port, &ai); + if(result) { + de_cleanup(&de); + return result; + } + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* we got a response, store it in the cache */ + dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + if(!dns) { + /* returned failure, bail out nicely */ + Curl_freeaddrinfo(ai); + } + else { + data->state.async.dns = dns; + *dnsp = dns; + result = CURLE_OK; /* address resolution OK */ + } + } /* address processing done */ + + /* Now process any build-specific attributes retrieved from DNS */ + + /* All done */ + de_cleanup(&de); + Curl_safefree(data->req.doh); + return result; + + } /* !dohp->pending */ + + /* else wait for pending DoH transactions to complete */ + return CURLE_OK; +} + +#endif /* CURL_DISABLE_DOH */ diff --git a/lib/doh.h b/lib/doh.h new file mode 100644 index 0000000..7d7b694 --- /dev/null +++ b/lib/doh.h @@ -0,0 +1,128 @@ +#ifndef HEADER_CURL_DOH_H +#define HEADER_CURL_DOH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "urldata.h" +#include "curl_addrinfo.h" + +#ifndef CURL_DISABLE_DOH + +typedef enum { + DOH_OK, + DOH_DNS_BAD_LABEL, /* 1 */ + DOH_DNS_OUT_OF_RANGE, /* 2 */ + DOH_DNS_LABEL_LOOP, /* 3 */ + DOH_TOO_SMALL_BUFFER, /* 4 */ + DOH_OUT_OF_MEM, /* 5 */ + DOH_DNS_RDATA_LEN, /* 6 */ + DOH_DNS_MALFORMAT, /* 7 */ + DOH_DNS_BAD_RCODE, /* 8 - no such name */ + DOH_DNS_UNEXPECTED_TYPE, /* 9 */ + DOH_DNS_UNEXPECTED_CLASS, /* 10 */ + DOH_NO_CONTENT, /* 11 */ + DOH_DNS_BAD_ID, /* 12 */ + DOH_DNS_NAME_TOO_LONG /* 13 */ +} DOHcode; + +typedef enum { + DNS_TYPE_A = 1, + DNS_TYPE_NS = 2, + DNS_TYPE_CNAME = 5, + DNS_TYPE_AAAA = 28, + DNS_TYPE_DNAME = 39 /* RFC6672 */ +} DNStype; + +/* one of these for each DoH request */ +struct dnsprobe { + CURL *easy; + DNStype dnstype; + unsigned char dohbuffer[512]; + size_t dohlen; + struct dynbuf serverdoh; +}; + +struct dohdata { + struct curl_slist *headers; + struct dnsprobe probe[DOH_PROBE_SLOTS]; + unsigned int pending; /* still outstanding requests */ + int port; + const char *host; +}; + +/* + * Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name + * and returns a 'Curl_addrinfo *' with the address information. + */ + +struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp); + +CURLcode Curl_doh_is_resolved(struct Curl_easy *data, + struct Curl_dns_entry **dns); + +int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks); + +#define DOH_MAX_ADDR 24 +#define DOH_MAX_CNAME 4 + +struct dohaddr { + int type; + union { + unsigned char v4[4]; /* network byte order */ + unsigned char v6[16]; + } ip; +}; + +struct dohentry { + struct dynbuf cname[DOH_MAX_CNAME]; + struct dohaddr addr[DOH_MAX_ADDR]; + int numaddr; + unsigned int ttl; + int numcname; +}; + + +#ifdef DEBUGBUILD +DOHcode doh_encode(const char *host, + DNStype dnstype, + unsigned char *dnsp, /* buffer */ + size_t len, /* buffer size */ + size_t *olen); /* output length */ +DOHcode doh_decode(const unsigned char *doh, + size_t dohlen, + DNStype dnstype, + struct dohentry *d); +void de_init(struct dohentry *d); +void de_cleanup(struct dohentry *d); +#endif + +#else /* if DoH is disabled */ +#define Curl_doh(a,b,c,d) NULL +#define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST +#endif + +#endif /* HEADER_CURL_DOH_H */ diff --git a/lib/dynbuf.c b/lib/dynbuf.c new file mode 100644 index 0000000..a4c599d --- /dev/null +++ b/lib/dynbuf.c @@ -0,0 +1,282 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "dynbuf.h" +#include "curl_printf.h" +#ifdef BUILDING_LIBCURL +#include "curl_memory.h" +#endif +#include "memdebug.h" + +#define MIN_FIRST_ALLOC 32 + +#define DYNINIT 0xbee51da /* random pattern */ + +/* + * Init a dynbuf struct. + */ +void Curl_dyn_init(struct dynbuf *s, size_t toobig) +{ + DEBUGASSERT(s); + DEBUGASSERT(toobig); + s->bufr = NULL; + s->leng = 0; + s->allc = 0; + s->toobig = toobig; +#ifdef DEBUGBUILD + s->init = DYNINIT; +#endif +} + +/* + * free the buffer and re-init the necessary fields. It doesn't touch the + * 'init' field and thus this buffer can be reused to add data to again. + */ +void Curl_dyn_free(struct dynbuf *s) +{ + DEBUGASSERT(s); + Curl_safefree(s->bufr); + s->leng = s->allc = 0; +} + +/* + * Store/append an chunk of memory to the dynbuf. + */ +static CURLcode dyn_nappend(struct dynbuf *s, + const unsigned char *mem, size_t len) +{ + size_t indx = s->leng; + size_t a = s->allc; + size_t fit = len + indx + 1; /* new string + old string + zero byte */ + + /* try to detect if there's rubbish in the struct */ + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(s->toobig); + DEBUGASSERT(indx < s->toobig); + DEBUGASSERT(!s->leng || s->bufr); + DEBUGASSERT(a <= s->toobig); + DEBUGASSERT(!len || mem); + + if(fit > s->toobig) { + Curl_dyn_free(s); + return CURLE_TOO_LARGE; + } + else if(!a) { + DEBUGASSERT(!indx); + /* first invoke */ + if(MIN_FIRST_ALLOC > s->toobig) + a = s->toobig; + else if(fit < MIN_FIRST_ALLOC) + a = MIN_FIRST_ALLOC; + else + a = fit; + } + else { + while(a < fit) + a *= 2; + if(a > s->toobig) + /* no point in allocating a larger buffer than this is allowed to use */ + a = s->toobig; + } + + if(a != s->allc) { + /* this logic is not using Curl_saferealloc() to make the tool not have to + include that as well when it uses this code */ + void *p = realloc(s->bufr, a); + if(!p) { + Curl_dyn_free(s); + return CURLE_OUT_OF_MEMORY; + } + s->bufr = p; + s->allc = a; + } + + if(len) + memcpy(&s->bufr[indx], mem, len); + s->leng = indx + len; + s->bufr[s->leng] = 0; + return CURLE_OK; +} + +/* + * Clears the string, keeps the allocation. This can also be called on a + * buffer that already was freed. + */ +void Curl_dyn_reset(struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(s->leng) + s->bufr[0] = 0; + s->leng = 0; +} + +/* + * Specify the size of the tail to keep (number of bytes from the end of the + * buffer). The rest will be dropped. + */ +CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(trail > s->leng) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(trail == s->leng) + return CURLE_OK; + else if(!trail) { + Curl_dyn_reset(s); + } + else { + memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail); + s->leng = trail; + s->bufr[s->leng] = 0; + } + return CURLE_OK; + +} + +/* + * Appends a buffer with length. + */ +CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return dyn_nappend(s, mem, len); +} + +/* + * Append a null-terminated string at the end. + */ +CURLcode Curl_dyn_add(struct dynbuf *s, const char *str) +{ + size_t n; + DEBUGASSERT(str); + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + n = strlen(str); + return dyn_nappend(s, (unsigned char *)str, n); +} + +/* + * Append a string vprintf()-style + */ +CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap) +{ +#ifdef BUILDING_LIBCURL + int rc; + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + DEBUGASSERT(fmt); + rc = Curl_dyn_vprintf(s, fmt, ap); + + if(!rc) + return CURLE_OK; + else if(rc == MERR_TOO_LARGE) + return CURLE_TOO_LARGE; + return CURLE_OUT_OF_MEMORY; +#else + char *str; + str = vaprintf(fmt, ap); /* this allocs a new string to append */ + + if(str) { + CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str)); + free(str); + return result; + } + /* If we failed, we cleanup the whole buffer and return error */ + Curl_dyn_free(s); + return CURLE_OK; +#endif +} + +/* + * Append a string printf()-style + */ +CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) +{ + CURLcode result; + va_list ap; + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + va_start(ap, fmt); + result = Curl_dyn_vaddf(s, fmt, ap); + va_end(ap); + return result; +} + +/* + * Returns a pointer to the buffer. + */ +char *Curl_dyn_ptr(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return s->bufr; +} + +/* + * Returns an unsigned pointer to the buffer. + */ +unsigned char *Curl_dyn_uptr(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return (unsigned char *)s->bufr; +} + +/* + * Returns the length of the buffer. + */ +size_t Curl_dyn_len(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return s->leng; +} + +/* + * Set a new (smaller) length. + */ +CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(set > s->leng) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->leng = set; + s->bufr[s->leng] = 0; + return CURLE_OK; +} diff --git a/lib/dynbuf.h b/lib/dynbuf.h new file mode 100644 index 0000000..7dbaab8 --- /dev/null +++ b/lib/dynbuf.h @@ -0,0 +1,93 @@ +#ifndef HEADER_CURL_DYNBUF_H +#define HEADER_CURL_DYNBUF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +#ifndef BUILDING_LIBCURL +/* this renames the functions so that the tool code can use the same code + without getting symbol collisions */ +#define Curl_dyn_init(a,b) curlx_dyn_init(a,b) +#define Curl_dyn_add(a,b) curlx_dyn_add(a,b) +#define Curl_dyn_addn(a,b,c) curlx_dyn_addn(a,b,c) +#define Curl_dyn_addf curlx_dyn_addf +#define Curl_dyn_vaddf curlx_dyn_vaddf +#define Curl_dyn_free(a) curlx_dyn_free(a) +#define Curl_dyn_ptr(a) curlx_dyn_ptr(a) +#define Curl_dyn_uptr(a) curlx_dyn_uptr(a) +#define Curl_dyn_len(a) curlx_dyn_len(a) +#define Curl_dyn_reset(a) curlx_dyn_reset(a) +#define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b) +#define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b) +#define curlx_dynbuf dynbuf /* for the struct name */ +#endif + +struct dynbuf { + char *bufr; /* point to a null-terminated allocated buffer */ + size_t leng; /* number of bytes *EXCLUDING* the null-terminator */ + size_t allc; /* size of the current allocation */ + size_t toobig; /* size limit for the buffer */ +#ifdef DEBUGBUILD + int init; /* detect API usage mistakes */ +#endif +}; + +void Curl_dyn_init(struct dynbuf *s, size_t toobig); +void Curl_dyn_free(struct dynbuf *s); +CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) + WARN_UNUSED_RESULT; +CURLcode Curl_dyn_add(struct dynbuf *s, const char *str) + WARN_UNUSED_RESULT; +CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) + WARN_UNUSED_RESULT CURL_PRINTF(2, 3); +CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap) + WARN_UNUSED_RESULT CURL_PRINTF(2, 0); +void Curl_dyn_reset(struct dynbuf *s); +CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail); +CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set); +char *Curl_dyn_ptr(const struct dynbuf *s); +unsigned char *Curl_dyn_uptr(const struct dynbuf *s); +size_t Curl_dyn_len(const struct dynbuf *s); + +/* returns 0 on success, -1 on error */ +/* The implementation of this function exists in mprintf.c */ +int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save); + +/* Dynamic buffer max sizes */ +#define DYN_DOH_RESPONSE 3000 +#define DYN_DOH_CNAME 256 +#define DYN_PAUSE_BUFFER (64 * 1024 * 1024) +#define DYN_HAXPROXY 2048 +#define DYN_HTTP_REQUEST (1024*1024) +#define DYN_APRINTF 8000000 +#define DYN_RTSP_REQ_HEADER (64*1024) +#define DYN_TRAILERS (64*1024) +#define DYN_PROXY_CONNECT_HEADERS 16384 +#define DYN_QLOG_NAME 1024 +#define DYN_H1_TRAILER 4096 +#define DYN_PINGPPONG_CMD (64*1024) +#define DYN_IMAP_CMD (64*1024) +#define DYN_MQTT_RECV (64*1024) +#endif diff --git a/lib/dynhds.c b/lib/dynhds.c new file mode 100644 index 0000000..d754895 --- /dev/null +++ b/lib/dynhds.c @@ -0,0 +1,396 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "dynhds.h" +#include "strcase.h" + +/* The last 3 #include files should be in this order */ +#ifdef USE_NGHTTP2 +#include +#include +#endif /* USE_NGHTTP2 */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +static struct dynhds_entry * +entry_new(const char *name, size_t namelen, + const char *value, size_t valuelen, int opts) +{ + struct dynhds_entry *e; + char *p; + + DEBUGASSERT(name); + DEBUGASSERT(value); + e = calloc(1, sizeof(*e) + namelen + valuelen + 2); + if(!e) + return NULL; + e->name = p = ((char *)e) + sizeof(*e); + memcpy(p, name, namelen); + e->namelen = namelen; + e->value = p += namelen + 1; /* leave a \0 at the end of name */ + memcpy(p, value, valuelen); + e->valuelen = valuelen; + if(opts & DYNHDS_OPT_LOWERCASE) + Curl_strntolower(e->name, e->name, e->namelen); + return e; +} + +static struct dynhds_entry * +entry_append(struct dynhds_entry *e, + const char *value, size_t valuelen) +{ + struct dynhds_entry *e2; + size_t valuelen2 = e->valuelen + 1 + valuelen; + char *p; + + DEBUGASSERT(value); + e2 = calloc(1, sizeof(*e) + e->namelen + valuelen2 + 2); + if(!e2) + return NULL; + e2->name = p = ((char *)e2) + sizeof(*e2); + memcpy(p, e->name, e->namelen); + e2->namelen = e->namelen; + e2->value = p += e->namelen + 1; /* leave a \0 at the end of name */ + memcpy(p, e->value, e->valuelen); + p += e->valuelen; + p[0] = ' '; + memcpy(p + 1, value, valuelen); + e2->valuelen = valuelen2; + return e2; +} + +static void entry_free(struct dynhds_entry *e) +{ + free(e); +} + +void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries, + size_t max_strs_size) +{ + DEBUGASSERT(dynhds); + DEBUGASSERT(max_strs_size); + dynhds->hds = NULL; + dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0; + dynhds->max_entries = max_entries; + dynhds->max_strs_size = max_strs_size; + dynhds->opts = 0; +} + +void Curl_dynhds_free(struct dynhds *dynhds) +{ + DEBUGASSERT(dynhds); + if(dynhds->hds && dynhds->hds_len) { + size_t i; + DEBUGASSERT(dynhds->hds); + for(i = 0; i < dynhds->hds_len; ++i) { + entry_free(dynhds->hds[i]); + } + } + Curl_safefree(dynhds->hds); + dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0; +} + +void Curl_dynhds_reset(struct dynhds *dynhds) +{ + DEBUGASSERT(dynhds); + if(dynhds->hds_len) { + size_t i; + DEBUGASSERT(dynhds->hds); + for(i = 0; i < dynhds->hds_len; ++i) { + entry_free(dynhds->hds[i]); + dynhds->hds[i] = NULL; + } + } + dynhds->hds_len = dynhds->strs_len = 0; +} + +size_t Curl_dynhds_count(struct dynhds *dynhds) +{ + return dynhds->hds_len; +} + +void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts) +{ + dynhds->opts = opts; +} + +struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n) +{ + DEBUGASSERT(dynhds); + return (n < dynhds->hds_len)? dynhds->hds[n] : NULL; +} + +struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name, + size_t namelen) +{ + size_t i; + for(i = 0; i < dynhds->hds_len; ++i) { + if(dynhds->hds[i]->namelen == namelen && + strncasecompare(dynhds->hds[i]->name, name, namelen)) { + return dynhds->hds[i]; + } + } + return NULL; +} + +struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name) +{ + return Curl_dynhds_get(dynhds, name, strlen(name)); +} + +CURLcode Curl_dynhds_add(struct dynhds *dynhds, + const char *name, size_t namelen, + const char *value, size_t valuelen) +{ + struct dynhds_entry *entry = NULL; + CURLcode result = CURLE_OUT_OF_MEMORY; + + DEBUGASSERT(dynhds); + if(dynhds->max_entries && dynhds->hds_len >= dynhds->max_entries) + return CURLE_OUT_OF_MEMORY; + if(dynhds->strs_len + namelen + valuelen > dynhds->max_strs_size) + return CURLE_OUT_OF_MEMORY; + +entry = entry_new(name, namelen, value, valuelen, dynhds->opts); + if(!entry) + goto out; + + if(dynhds->hds_len + 1 >= dynhds->hds_allc) { + size_t nallc = dynhds->hds_len + 16; + struct dynhds_entry **nhds; + + if(dynhds->max_entries && nallc > dynhds->max_entries) + nallc = dynhds->max_entries; + + nhds = calloc(nallc, sizeof(struct dynhds_entry *)); + if(!nhds) + goto out; + if(dynhds->hds) { + memcpy(nhds, dynhds->hds, + dynhds->hds_len * sizeof(struct dynhds_entry *)); + Curl_safefree(dynhds->hds); + } + dynhds->hds = nhds; + dynhds->hds_allc = nallc; + } + dynhds->hds[dynhds->hds_len++] = entry; + entry = NULL; + dynhds->strs_len += namelen + valuelen; + result = CURLE_OK; + +out: + if(entry) + entry_free(entry); + return result; +} + +CURLcode Curl_dynhds_cadd(struct dynhds *dynhds, + const char *name, const char *value) +{ + return Curl_dynhds_add(dynhds, name, strlen(name), value, strlen(value)); +} + +CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds, + const char *line, size_t line_len) +{ + const char *p; + const char *name; + size_t namelen; + const char *value; + size_t valuelen, i; + + if(!line || !line_len) + return CURLE_OK; + + if((line[0] == ' ') || (line[0] == '\t')) { + struct dynhds_entry *e, *e2; + /* header continuation, yikes! */ + if(!dynhds->hds_len) + return CURLE_BAD_FUNCTION_ARGUMENT; + + while(line_len && ISBLANK(line[0])) { + ++line; + --line_len; + } + if(!line_len) + return CURLE_BAD_FUNCTION_ARGUMENT; + e = dynhds->hds[dynhds->hds_len-1]; + e2 = entry_append(e, line, line_len); + if(!e2) + return CURLE_OUT_OF_MEMORY; + dynhds->hds[dynhds->hds_len-1] = e2; + entry_free(e); + return CURLE_OK; + } + else { + p = memchr(line, ':', line_len); + if(!p) + return CURLE_BAD_FUNCTION_ARGUMENT; + name = line; + namelen = p - line; + p++; /* move past the colon */ + for(i = namelen + 1; i < line_len; ++i, ++p) { + if(!ISBLANK(*p)) + break; + } + value = p; + valuelen = line_len - i; + + p = memchr(value, '\r', valuelen); + if(!p) + p = memchr(value, '\n', valuelen); + if(p) + valuelen = (size_t)(p - value); + + return Curl_dynhds_add(dynhds, name, namelen, value, valuelen); + } +} + +CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line) +{ + return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0); +} + +#ifdef DEBUGBUILD +/* used by unit2602.c */ + +bool Curl_dynhds_contains(struct dynhds *dynhds, + const char *name, size_t namelen) +{ + return !!Curl_dynhds_get(dynhds, name, namelen); +} + +bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name) +{ + return Curl_dynhds_contains(dynhds, name, strlen(name)); +} + +size_t Curl_dynhds_count_name(struct dynhds *dynhds, + const char *name, size_t namelen) +{ + size_t n = 0; + if(dynhds->hds_len) { + size_t i; + for(i = 0; i < dynhds->hds_len; ++i) { + if((namelen == dynhds->hds[i]->namelen) && + strncasecompare(name, dynhds->hds[i]->name, namelen)) + ++n; + } + } + return n; +} + +size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name) +{ + return Curl_dynhds_count_name(dynhds, name, strlen(name)); +} + +CURLcode Curl_dynhds_set(struct dynhds *dynhds, + const char *name, size_t namelen, + const char *value, size_t valuelen) +{ + Curl_dynhds_remove(dynhds, name, namelen); + return Curl_dynhds_add(dynhds, name, namelen, value, valuelen); +} + +size_t Curl_dynhds_remove(struct dynhds *dynhds, + const char *name, size_t namelen) +{ + size_t n = 0; + if(dynhds->hds_len) { + size_t i, len; + for(i = 0; i < dynhds->hds_len; ++i) { + if((namelen == dynhds->hds[i]->namelen) && + strncasecompare(name, dynhds->hds[i]->name, namelen)) { + ++n; + --dynhds->hds_len; + dynhds->strs_len -= (dynhds->hds[i]->namelen + + dynhds->hds[i]->valuelen); + entry_free(dynhds->hds[i]); + len = dynhds->hds_len - i; /* remaining entries */ + if(len) { + memmove(&dynhds->hds[i], &dynhds->hds[i + 1], + len * sizeof(dynhds->hds[i])); + } + --i; /* do this index again */ + } + } + } + return n; +} + +size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name) +{ + return Curl_dynhds_remove(dynhds, name, strlen(name)); +} + +#endif + +CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf) +{ + CURLcode result = CURLE_OK; + size_t i; + + if(!dynhds->hds_len) + return result; + + for(i = 0; i < dynhds->hds_len; ++i) { + result = Curl_dyn_addf(dbuf, "%.*s: %.*s\r\n", + (int)dynhds->hds[i]->namelen, dynhds->hds[i]->name, + (int)dynhds->hds[i]->valuelen, dynhds->hds[i]->value); + if(result) + break; + } + + return result; +} + +#ifdef USE_NGHTTP2 + +nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount) +{ + nghttp2_nv *nva = calloc(1, sizeof(nghttp2_nv) * dynhds->hds_len); + size_t i; + + *pcount = 0; + if(!nva) + return NULL; + + for(i = 0; i < dynhds->hds_len; ++i) { + struct dynhds_entry *e = dynhds->hds[i]; + DEBUGASSERT(e); + nva[i].name = (unsigned char *)e->name; + nva[i].namelen = e->namelen; + nva[i].value = (unsigned char *)e->value; + nva[i].valuelen = e->valuelen; + nva[i].flags = NGHTTP2_NV_FLAG_NONE; + } + *pcount = dynhds->hds_len; + return nva; +} + +#endif /* USE_NGHTTP2 */ diff --git a/lib/dynhds.h b/lib/dynhds.h new file mode 100644 index 0000000..3b53600 --- /dev/null +++ b/lib/dynhds.h @@ -0,0 +1,183 @@ +#ifndef HEADER_CURL_DYNHDS_H +#define HEADER_CURL_DYNHDS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#include +#include "dynbuf.h" + +struct dynbuf; + +/** + * A single header entry. + * `name` and `value` are non-NULL and always NUL terminated. + */ +struct dynhds_entry { + char *name; + char *value; + size_t namelen; + size_t valuelen; +}; + +struct dynhds { + struct dynhds_entry **hds; + size_t hds_len; /* number of entries in hds */ + size_t hds_allc; /* size of hds allocation */ + size_t max_entries; /* size limit number of entries */ + size_t strs_len; /* length of all strings */ + size_t max_strs_size; /* max length of all strings */ + int opts; +}; + +#define DYNHDS_OPT_NONE (0) +#define DYNHDS_OPT_LOWERCASE (1 << 0) + +/** + * Init for use on first time or after a reset. + * Allow `max_entries` headers to be added, 0 for unlimited. + * Allow size of all name and values added to not exceed `max_strs_size`` + */ +void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries, + size_t max_strs_size); +/** + * Frees all data held in `dynhds`, but not the struct itself. + */ +void Curl_dynhds_free(struct dynhds *dynhds); + +/** + * Reset `dyndns` to the initial init state. May keep allocations + * around. + */ +void Curl_dynhds_reset(struct dynhds *dynhds); + +/** + * Return the number of header entries. + */ +size_t Curl_dynhds_count(struct dynhds *dynhds); + +/** + * Set the options to use, replacing any existing ones. + * This will not have an effect on already existing headers. + */ +void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts); + +/** + * Return the n-th header entry or NULL if it does not exist. + */ +struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n); + +/** + * Return the 1st header entry of the name or NULL if none exists. + */ +struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, + const char *name, size_t namelen); +struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name); + +/** + * Return TRUE iff one or more headers with the given name exist. + */ +bool Curl_dynhds_contains(struct dynhds *dynhds, + const char *name, size_t namelen); +bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name); + +/** + * Return how often the given name appears in `dynhds`. + * Names are case-insensitive. + */ +size_t Curl_dynhds_count_name(struct dynhds *dynhds, + const char *name, size_t namelen); + +/** + * Return how often the given 0-terminated name appears in `dynhds`. + * Names are case-insensitive. + */ +size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name); + +/** + * Add a header, name + value, to `dynhds` at the end. Does *not* + * check for duplicate names. + */ +CURLcode Curl_dynhds_add(struct dynhds *dynhds, + const char *name, size_t namelen, + const char *value, size_t valuelen); + +/** + * Add a header, c-string name + value, to `dynhds` at the end. + */ +CURLcode Curl_dynhds_cadd(struct dynhds *dynhds, + const char *name, const char *value); + +/** + * Remove all entries with the given name. + * Returns number of entries removed. + */ +size_t Curl_dynhds_remove(struct dynhds *dynhds, + const char *name, size_t namelen); +size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name); + + +/** + * Set the give header name and value, replacing any entries with + * the same name. The header is added at the end of all (remaining) + * entries. + */ +CURLcode Curl_dynhds_set(struct dynhds *dynhds, + const char *name, size_t namelen, + const char *value, size_t valuelen); + +CURLcode Curl_dynhds_cset(struct dynhds *dynhds, + const char *name, const char *value); + +/** + * Add a single header from a HTTP/1.1 formatted line at the end. Line + * may contain a delimiting \r\n or just \n. Any characters after + * that will be ignored. + */ +CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line); + +/** + * Add a single header from a HTTP/1.1 formatted line at the end. Line + * may contain a delimiting \r\n or just \n. Any characters after + * that will be ignored. + */ +CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds, + const char *line, size_t line_len); + +/** + * Add the headers to the given `dynbuf` in HTTP/1.1 format with + * cr+lf line endings. Will NOT output a last empty line. + */ +CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf); + +#ifdef USE_NGHTTP2 + +#include +#include + +nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount); + +#endif /* USE_NGHTTP2 */ + +#endif /* HEADER_CURL_DYNHDS_H */ diff --git a/lib/easy.c b/lib/easy.c new file mode 100644 index 0000000..067b6d7 --- /dev/null +++ b/lib/easy.c @@ -0,0 +1,1361 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "vtls/vtls.h" +#include "url.h" +#include "getinfo.h" +#include "hostip.h" +#include "share.h" +#include "strdup.h" +#include "progress.h" +#include "easyif.h" +#include "multiif.h" +#include "select.h" +#include "cfilters.h" +#include "sendf.h" /* for failf function prototype */ +#include "connect.h" /* for Curl_getconnectinfo */ +#include "slist.h" +#include "mime.h" +#include "amigaos.h" +#include "macos.h" +#include "warnless.h" +#include "sigpipe.h" +#include "vssh/ssh.h" +#include "setopt.h" +#include "http_digest.h" +#include "system_win32.h" +#include "http2.h" +#include "dynbuf.h" +#include "altsvc.h" +#include "hsts.h" + +#include "easy_lock.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* true globals -- for curl_global_init() and curl_global_cleanup() */ +static unsigned int initialized; +static long easy_init_flags; + +#ifdef GLOBAL_INIT_IS_THREADSAFE + +static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT; +#define global_init_lock() curl_simple_lock_lock(&s_lock) +#define global_init_unlock() curl_simple_lock_unlock(&s_lock) + +#else + +#define global_init_lock() +#define global_init_unlock() + +#endif + +/* + * strdup (and other memory functions) is redefined in complicated + * ways, but at this point it must be defined as the system-supplied strdup + * so the callback pointer is initialized correctly. + */ +#if defined(_WIN32_WCE) +#define system_strdup _strdup +#elif !defined(HAVE_STRDUP) +#define system_strdup Curl_strdup +#else +#define system_strdup strdup +#endif + +#if defined(_MSC_VER) && defined(_DLL) +# pragma warning(disable:4232) /* MSVC extension, dllimport identity */ +#endif + +/* + * If a memory-using function (like curl_getenv) is used before + * curl_global_init() is called, we need to have these pointers set already. + */ +curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; +curl_free_callback Curl_cfree = (curl_free_callback)free; +curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; +curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; +curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; +#if defined(_WIN32) && defined(UNICODE) +curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup; +#endif + +#if defined(_MSC_VER) && defined(_DLL) +# pragma warning(default:4232) /* MSVC extension, dllimport identity */ +#endif + +#ifdef DEBUGBUILD +static char *leakpointer; +#endif + +/** + * curl_global_init() globally initializes curl given a bitwise set of the + * different features of what to initialize. + */ +static CURLcode global_init(long flags, bool memoryfuncs) +{ + if(initialized++) + return CURLE_OK; + + if(memoryfuncs) { + /* Setup the default memory functions here (again) */ + Curl_cmalloc = (curl_malloc_callback)malloc; + Curl_cfree = (curl_free_callback)free; + Curl_crealloc = (curl_realloc_callback)realloc; + Curl_cstrdup = (curl_strdup_callback)system_strdup; + Curl_ccalloc = (curl_calloc_callback)calloc; +#if defined(_WIN32) && defined(UNICODE) + Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; +#endif + } + + if(Curl_trc_init()) { + DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n")); + goto fail; + } + + if(!Curl_ssl_init()) { + DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n")); + goto fail; + } + + if(Curl_win32_init(flags)) { + DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); + goto fail; + } + + if(Curl_amiga_init()) { + DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n")); + goto fail; + } + + if(Curl_macos_init()) { + DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n")); + goto fail; + } + + if(Curl_resolver_global_init()) { + DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); + goto fail; + } + + if(Curl_ssh_init()) { + DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n")); + goto fail; + } + + easy_init_flags = flags; + +#ifdef DEBUGBUILD + if(getenv("CURL_GLOBAL_INIT")) + /* alloc data that will leak if *cleanup() is not called! */ + leakpointer = malloc(1); +#endif + + return CURLE_OK; + +fail: + initialized--; /* undo the increase */ + return CURLE_FAILED_INIT; +} + + +/** + * curl_global_init() globally initializes curl given a bitwise set of the + * different features of what to initialize. + */ +CURLcode curl_global_init(long flags) +{ + CURLcode result; + global_init_lock(); + + result = global_init(flags, TRUE); + + global_init_unlock(); + + return result; +} + +/* + * curl_global_init_mem() globally initializes curl and also registers the + * user provided callback routines. + */ +CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, + curl_free_callback f, curl_realloc_callback r, + curl_strdup_callback s, curl_calloc_callback c) +{ + CURLcode result; + + /* Invalid input, return immediately */ + if(!m || !f || !r || !s || !c) + return CURLE_FAILED_INIT; + + global_init_lock(); + + if(initialized) { + /* Already initialized, don't do it again, but bump the variable anyway to + work like curl_global_init() and require the same amount of cleanup + calls. */ + initialized++; + global_init_unlock(); + return CURLE_OK; + } + + /* set memory functions before global_init() in case it wants memory + functions */ + Curl_cmalloc = m; + Curl_cfree = f; + Curl_cstrdup = s; + Curl_crealloc = r; + Curl_ccalloc = c; + + /* Call the actual init function, but without setting */ + result = global_init(flags, FALSE); + + global_init_unlock(); + + return result; +} + +/** + * curl_global_cleanup() globally cleanups curl, uses the value of + * "easy_init_flags" to determine what needs to be cleaned up and what doesn't. + */ +void curl_global_cleanup(void) +{ + global_init_lock(); + + if(!initialized) { + global_init_unlock(); + return; + } + + if(--initialized) { + global_init_unlock(); + return; + } + + Curl_ssl_cleanup(); + Curl_resolver_global_cleanup(); + +#ifdef _WIN32 + Curl_win32_cleanup(easy_init_flags); +#endif + + Curl_amiga_cleanup(); + + Curl_ssh_cleanup(); + +#ifdef DEBUGBUILD + free(leakpointer); +#endif + + easy_init_flags = 0; + + global_init_unlock(); +} + +/** + * curl_global_trace() globally initializes curl logging. + */ +CURLcode curl_global_trace(const char *config) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + CURLcode result; + global_init_lock(); + + result = Curl_trc_opt(config); + + global_init_unlock(); + + return result; +#else + (void)config; + return CURLE_OK; +#endif +} + +/* + * curl_global_sslset() globally initializes the SSL backend to use. + */ +CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) +{ + CURLsslset rc; + + global_init_lock(); + + rc = Curl_init_sslset_nolock(id, name, avail); + + global_init_unlock(); + + return rc; +} + +/* + * curl_easy_init() is the external interface to alloc, setup and init an + * easy handle that is returned. If anything goes wrong, NULL is returned. + */ +struct Curl_easy *curl_easy_init(void) +{ + CURLcode result; + struct Curl_easy *data; + + /* Make sure we inited the global SSL stuff */ + global_init_lock(); + + if(!initialized) { + result = global_init(CURL_GLOBAL_DEFAULT, TRUE); + if(result) { + /* something in the global init failed, return nothing */ + DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); + global_init_unlock(); + return NULL; + } + } + global_init_unlock(); + + /* We use curl_open() with undefined URL so far */ + result = Curl_open(&data); + if(result) { + DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); + return NULL; + } + + return data; +} + +#ifdef CURLDEBUG + +struct socketmonitor { + struct socketmonitor *next; /* the next node in the list or NULL */ + struct pollfd socket; /* socket info of what to monitor */ +}; + +struct events { + long ms; /* timeout, run the timeout function when reached */ + bool msbump; /* set TRUE when timeout is set by callback */ + int num_sockets; /* number of nodes in the monitor list */ + struct socketmonitor *list; /* list of sockets to monitor */ + int running_handles; /* store the returned number */ +}; + +/* events_timer + * + * Callback that gets called with a new value when the timeout should be + * updated. + */ + +static int events_timer(struct Curl_multi *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp) /* private callback pointer */ +{ + struct events *ev = userp; + (void)multi; + if(timeout_ms == -1) + /* timeout removed */ + timeout_ms = 0; + else if(timeout_ms == 0) + /* timeout is already reached! */ + timeout_ms = 1; /* trigger asap */ + + ev->ms = timeout_ms; + ev->msbump = TRUE; + return 0; +} + + +/* poll2cselect + * + * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones + */ +static int poll2cselect(int pollmask) +{ + int omask = 0; + if(pollmask & POLLIN) + omask |= CURL_CSELECT_IN; + if(pollmask & POLLOUT) + omask |= CURL_CSELECT_OUT; + if(pollmask & POLLERR) + omask |= CURL_CSELECT_ERR; + return omask; +} + + +/* socketcb2poll + * + * convert from libcurl' CURL_POLL_* bit definitions to poll()'s + */ +static short socketcb2poll(int pollmask) +{ + short omask = 0; + if(pollmask & CURL_POLL_IN) + omask |= POLLIN; + if(pollmask & CURL_POLL_OUT) + omask |= POLLOUT; + return omask; +} + +/* events_socket + * + * Callback that gets called with information about socket activity to + * monitor. + */ +static int events_socket(struct Curl_easy *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp) /* private socket + pointer */ +{ + struct events *ev = userp; + struct socketmonitor *m; + struct socketmonitor *prev = NULL; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) easy; +#endif + (void)socketp; + + m = ev->list; + while(m) { + if(m->socket.fd == s) { + + if(what == CURL_POLL_REMOVE) { + struct socketmonitor *nxt = m->next; + /* remove this node from the list of monitored sockets */ + if(prev) + prev->next = nxt; + else + ev->list = nxt; + free(m); + m = nxt; + infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T + " REMOVED", s); + } + else { + /* The socket 's' is already being monitored, update the activity + mask. Convert from libcurl bitmask to the poll one. */ + m->socket.events = socketcb2poll(what); + infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T + " UPDATED as %s%s", s, + (what&CURL_POLL_IN)?"IN":"", + (what&CURL_POLL_OUT)?"OUT":""); + } + break; + } + prev = m; + m = m->next; /* move to next node */ + } + if(!m) { + if(what == CURL_POLL_REMOVE) { + /* this happens a bit too often, libcurl fix perhaps? */ + /* fprintf(stderr, + "%s: socket %d asked to be REMOVED but not present!\n", + __func__, s); */ + } + else { + m = malloc(sizeof(struct socketmonitor)); + if(m) { + m->next = ev->list; + m->socket.fd = s; + m->socket.events = socketcb2poll(what); + m->socket.revents = 0; + ev->list = m; + infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T + " ADDED as %s%s", s, + (what&CURL_POLL_IN)?"IN":"", + (what&CURL_POLL_OUT)?"OUT":""); + } + else + return CURLE_OUT_OF_MEMORY; + } + } + + return 0; +} + + +/* + * events_setup() + * + * Do the multi handle setups that only event-based transfers need. + */ +static void events_setup(struct Curl_multi *multi, struct events *ev) +{ + /* timer callback */ + curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer); + curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev); + + /* socket callback */ + curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket); + curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev); +} + + +/* wait_or_timeout() + * + * waits for activity on any of the given sockets, or the timeout to trigger. + */ + +static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) +{ + bool done = FALSE; + CURLMcode mcode = CURLM_OK; + CURLcode result = CURLE_OK; + + while(!done) { + CURLMsg *msg; + struct socketmonitor *m; + struct pollfd *f; + struct pollfd fds[4]; + int numfds = 0; + int pollrc; + int i; + struct curltime before; + struct curltime after; + + /* populate the fds[] array */ + for(m = ev->list, f = &fds[0]; m; m = m->next) { + f->fd = m->socket.fd; + f->events = m->socket.events; + f->revents = 0; + /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */ + f++; + numfds++; + } + + /* get the time stamp to use to figure out how long poll takes */ + before = Curl_now(); + + /* wait for activity or timeout */ + pollrc = Curl_poll(fds, numfds, ev->ms); + if(pollrc < 0) + return CURLE_UNRECOVERABLE_POLL; + + after = Curl_now(); + + ev->msbump = FALSE; /* reset here */ + + if(!pollrc) { + /* timeout! */ + ev->ms = 0; + /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ + mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, + &ev->running_handles); + } + else { + /* here pollrc is > 0 */ + + /* loop over the monitored sockets to see which ones had activity */ + for(i = 0; i< numfds; i++) { + if(fds[i].revents) { + /* socket activity, tell libcurl */ + int act = poll2cselect(fds[i].revents); /* convert */ + infof(multi->easyp, + "call curl_multi_socket_action(socket " + "%" CURL_FORMAT_SOCKET_T ")", fds[i].fd); + mcode = curl_multi_socket_action(multi, fds[i].fd, act, + &ev->running_handles); + } + } + + if(!ev->msbump) { + /* If nothing updated the timeout, we decrease it by the spent time. + * If it was updated, it has the new timeout time stored already. + */ + timediff_t timediff = Curl_timediff(after, before); + if(timediff > 0) { + if(timediff > ev->ms) + ev->ms = 0; + else + ev->ms -= (long)timediff; + } + } + } + + if(mcode) + return CURLE_URL_MALFORMAT; + + /* we don't really care about the "msgs_in_queue" value returned in the + second argument */ + msg = curl_multi_info_read(multi, &pollrc); + if(msg) { + result = msg->data.result; + done = TRUE; + } + } + + return result; +} + + +/* easy_events() + * + * Runs a transfer in a blocking manner using the events-based API + */ +static CURLcode easy_events(struct Curl_multi *multi) +{ + /* this struct is made static to allow it to be used after this function + returns and curl_multi_remove_handle() is called */ + static struct events evs = {2, FALSE, 0, NULL, 0}; + + /* if running event-based, do some further multi inits */ + events_setup(multi, &evs); + + return wait_or_timeout(multi, &evs); +} +#else /* CURLDEBUG */ +/* when not built with debug, this function doesn't exist */ +#define easy_events(x) CURLE_NOT_BUILT_IN +#endif + +static CURLcode easy_transfer(struct Curl_multi *multi) +{ + bool done = FALSE; + CURLMcode mcode = CURLM_OK; + CURLcode result = CURLE_OK; + + while(!done && !mcode) { + int still_running = 0; + + mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL); + + if(!mcode) + mcode = curl_multi_perform(multi, &still_running); + + /* only read 'still_running' if curl_multi_perform() return OK */ + if(!mcode && !still_running) { + int rc; + CURLMsg *msg = curl_multi_info_read(multi, &rc); + if(msg) { + result = msg->data.result; + done = TRUE; + } + } + } + + /* Make sure to return some kind of error if there was a multi problem */ + if(mcode) { + result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : + /* The other multi errors should never happen, so return + something suitably generic */ + CURLE_BAD_FUNCTION_ARGUMENT; + } + + return result; +} + + +/* + * easy_perform() is the external interface that performs a blocking + * transfer as previously setup. + * + * CONCEPT: This function creates a multi handle, adds the easy handle to it, + * runs curl_multi_perform() until the transfer is done, then detaches the + * easy handle, destroys the multi handle and returns the easy handle's return + * code. + * + * REALITY: it can't just create and destroy the multi handle that easily. It + * needs to keep it around since if this easy handle is used again by this + * function, the same multi handle must be reused so that the same pools and + * caches can be used. + * + * DEBUG: if 'events' is set TRUE, this function will use a replacement engine + * instead of curl_multi_perform() and use curl_multi_socket_action(). + */ +static CURLcode easy_perform(struct Curl_easy *data, bool events) +{ + struct Curl_multi *multi; + CURLMcode mcode; + CURLcode result = CURLE_OK; + SIGPIPE_VARIABLE(pipe_st); + + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(data->set.errorbuffer) + /* clear this as early as possible */ + data->set.errorbuffer[0] = 0; + + if(data->multi) { + failf(data, "easy handle already used in multi handle"); + return CURLE_FAILED_INIT; + } + + if(data->multi_easy) + multi = data->multi_easy; + else { + /* this multi handle will only ever have a single easy handled attached + to it, so make it use minimal hashes */ + multi = Curl_multi_handle(1, 3, 7); + if(!multi) + return CURLE_OUT_OF_MEMORY; + data->multi_easy = multi; + } + + if(multi->in_callback) + return CURLE_RECURSIVE_API_CALL; + + /* Copy the MAXCONNECTS option to the multi handle */ + curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects); + + mcode = curl_multi_add_handle(multi, data); + if(mcode) { + curl_multi_cleanup(multi); + data->multi_easy = NULL; + if(mcode == CURLM_OUT_OF_MEMORY) + return CURLE_OUT_OF_MEMORY; + return CURLE_FAILED_INIT; + } + + sigpipe_ignore(data, &pipe_st); + + /* run the transfer */ + result = events ? easy_events(multi) : easy_transfer(multi); + + /* ignoring the return code isn't nice, but atm we can't really handle + a failure here, room for future improvement! */ + (void)curl_multi_remove_handle(multi, data); + + sigpipe_restore(&pipe_st); + + /* The multi handle is kept alive, owned by the easy handle */ + return result; +} + + +/* + * curl_easy_perform() is the external interface that performs a blocking + * transfer as previously setup. + */ +CURLcode curl_easy_perform(struct Curl_easy *data) +{ + return easy_perform(data, FALSE); +} + +#ifdef CURLDEBUG +/* + * curl_easy_perform_ev() is the external interface that performs a blocking + * transfer using the event-based API internally. + */ +CURLcode curl_easy_perform_ev(struct Curl_easy *data) +{ + return easy_perform(data, TRUE); +} + +#endif + +/* + * curl_easy_cleanup() is the external interface to cleaning/freeing the given + * easy handle. + */ +void curl_easy_cleanup(struct Curl_easy *data) +{ + if(GOOD_EASY_HANDLE(data)) { + SIGPIPE_VARIABLE(pipe_st); + sigpipe_ignore(data, &pipe_st); + Curl_close(&data); + sigpipe_restore(&pipe_st); + } +} + +/* + * curl_easy_getinfo() is an external interface that allows an app to retrieve + * information from a performed transfer and similar. + */ +#undef curl_easy_getinfo +CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...) +{ + va_list arg; + void *paramp; + CURLcode result; + + va_start(arg, info); + paramp = va_arg(arg, void *); + + result = Curl_getinfo(data, info, paramp); + + va_end(arg); + return result; +} + +static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) +{ + CURLcode result = CURLE_OK; + enum dupstring i; + enum dupblob j; + + /* Copy src->set into dst->set first, then deal with the strings + afterwards */ + dst->set = src->set; + Curl_mime_initpart(&dst->set.mimepost); + + /* clear all dest string and blob pointers first, in case we error out + mid-function */ + memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); + memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *)); + + /* duplicate all strings */ + for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { + result = Curl_setstropt(&dst->set.str[i], src->set.str[i]); + if(result) + return result; + } + + /* duplicate all blobs */ + for(j = (enum dupblob)0; j < BLOB_LAST; j++) { + result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]); + if(result) + return result; + } + + /* duplicate memory areas pointed to */ + i = STRING_COPYPOSTFIELDS; + if(src->set.str[i]) { + if(src->set.postfieldsize == -1) + dst->set.str[i] = strdup(src->set.str[i]); + else + /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */ + dst->set.str[i] = Curl_memdup(src->set.str[i], + curlx_sotouz(src->set.postfieldsize)); + if(!dst->set.str[i]) + return CURLE_OUT_OF_MEMORY; + /* point to the new copy */ + dst->set.postfields = dst->set.str[i]; + } + + /* Duplicate mime data. */ + result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost); + + if(src->set.resolve) + dst->state.resolve = dst->set.resolve; + + return result; +} + +/* + * curl_easy_duphandle() is an external interface to allow duplication of a + * given input easy handle. The returned handle will be a new working handle + * with all options set exactly as the input source handle. + */ +struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +{ + struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); + if(!outcurl) + goto fail; + + /* + * We setup a few buffers we need. We should probably make them + * get setup on-demand in the code, as that would probably decrease + * the likeliness of us forgetting to init a buffer here in the future. + */ + outcurl->set.buffer_size = data->set.buffer_size; + + /* copy all userdefined values */ + if(dupset(outcurl, data)) + goto fail; + + Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER); + + /* the connection cache is setup on demand */ + outcurl->state.conn_cache = NULL; + outcurl->state.lastconnect_id = -1; + outcurl->state.recent_conn_id = -1; + outcurl->id = -1; + + outcurl->progress.flags = data->progress.flags; + outcurl->progress.callback = data->progress.callback; + +#ifndef CURL_DISABLE_COOKIES + outcurl->state.cookielist = NULL; + if(data->cookies && data->state.cookie_engine) { + /* If cookies are enabled in the parent handle, we enable them + in the clone as well! */ + outcurl->cookies = Curl_cookie_init(outcurl, NULL, outcurl->cookies, + data->set.cookiesession); + if(!outcurl->cookies) + goto fail; + } + + if(data->state.cookielist) { + outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist); + if(!outcurl->state.cookielist) + goto fail; + } +#endif + + if(data->state.url) { + outcurl->state.url = strdup(data->state.url); + if(!outcurl->state.url) + goto fail; + outcurl->state.url_alloc = TRUE; + } + + if(data->state.referer) { + outcurl->state.referer = strdup(data->state.referer); + if(!outcurl->state.referer) + goto fail; + outcurl->state.referer_alloc = TRUE; + } + + /* Reinitialize an SSL engine for the new handle + * note: the engine name has already been copied by dupset */ + if(outcurl->set.str[STRING_SSL_ENGINE]) { + if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE])) + goto fail; + } + +#ifndef CURL_DISABLE_ALTSVC + if(data->asi) { + outcurl->asi = Curl_altsvc_init(); + if(!outcurl->asi) + goto fail; + if(outcurl->set.str[STRING_ALTSVC]) + (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]); + } +#endif +#ifndef CURL_DISABLE_HSTS + if(data->hsts) { + outcurl->hsts = Curl_hsts_init(); + if(!outcurl->hsts) + goto fail; + if(outcurl->set.str[STRING_HSTS]) + (void)Curl_hsts_loadfile(outcurl, + outcurl->hsts, outcurl->set.str[STRING_HSTS]); + (void)Curl_hsts_loadcb(outcurl, outcurl->hsts); + } +#endif + +#ifdef CURLRES_ASYNCH + /* Clone the resolver handle, if present, for the new handle */ + if(Curl_resolver_duphandle(outcurl, + &outcurl->state.async.resolver, + data->state.async.resolver)) + goto fail; +#endif + +#ifdef USE_ARES + { + CURLcode rc; + + rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + } +#endif /* USE_ARES */ + + Curl_initinfo(outcurl); + + outcurl->magic = CURLEASY_MAGIC_NUMBER; + + /* we reach this point and thus we are OK */ + + return outcurl; + +fail: + + if(outcurl) { +#ifndef CURL_DISABLE_COOKIES + free(outcurl->cookies); +#endif + free(outcurl->state.buffer); + Curl_dyn_free(&outcurl->state.headerb); + Curl_altsvc_cleanup(&outcurl->asi); + Curl_hsts_cleanup(&outcurl->hsts); + Curl_freeset(outcurl); + free(outcurl); + } + + return NULL; +} + +/* + * curl_easy_reset() is an external interface that allows an app to re- + * initialize a session handle to the default values. + */ +void curl_easy_reset(struct Curl_easy *data) +{ + Curl_free_request_state(data); + + /* zero out UserDefined data: */ + Curl_freeset(data); + memset(&data->set, 0, sizeof(struct UserDefined)); + (void)Curl_init_userdefined(data); + + /* zero out Progress data: */ + memset(&data->progress, 0, sizeof(struct Progress)); + + /* zero out PureInfo data: */ + Curl_initinfo(data); + + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ + data->state.retrycount = 0; /* reset the retry counter */ + + /* zero out authentication data: */ + memset(&data->state.authhost, 0, sizeof(struct auth)); + memset(&data->state.authproxy, 0, sizeof(struct auth)); + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) + Curl_http_auth_cleanup_digest(data); +#endif +} + +/* + * curl_easy_pause() allows an application to pause or unpause a specific + * transfer and direction. This function sets the full new state for the + * current connection this easy handle operates on. + * + * NOTE: if you have the receiving paused and you call this function to remove + * the pausing, you may get your write callback called at this point. + * + * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h + * + * NOTE: This is one of few API functions that are allowed to be called from + * within a callback. + */ +CURLcode curl_easy_pause(struct Curl_easy *data, int action) +{ + struct SingleRequest *k; + CURLcode result = CURLE_OK; + int oldstate; + int newstate; + bool recursive = FALSE; + + if(!GOOD_EASY_HANDLE(data) || !data->conn) + /* crazy input, don't continue */ + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(Curl_is_in_callback(data)) + recursive = TRUE; + k = &data->req; + oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); + + /* first switch off both pause bits then set the new pause bits */ + newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) | + ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | + ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); + + if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) { + /* Not changing any pause state, return */ + DEBUGF(infof(data, "pause: no change, early return")); + return CURLE_OK; + } + + /* Unpause parts in active mime tree. */ + if((k->keepon & ~newstate & KEEP_SEND_PAUSE) && + (data->mstate == MSTATE_PERFORMING || + data->mstate == MSTATE_RATELIMITING) && + data->state.fread_func == (curl_read_callback) Curl_mime_read) { + Curl_mime_unpause(data->state.in); + } + + /* put it back in the keepon */ + k->keepon = newstate; + + if(!(newstate & KEEP_RECV_PAUSE)) { + Curl_conn_ev_data_pause(data, FALSE); + result = Curl_client_unpause(data); + if(result) + return result; + } + +#ifdef USE_HYPER + if(!(newstate & KEEP_SEND_PAUSE)) { + /* need to wake the send body waker */ + if(data->hyp.send_body_waker) { + hyper_waker_wake(data->hyp.send_body_waker); + data->hyp.send_body_waker = NULL; + } + } +#endif + + /* if there's no error and we're not pausing both directions, we want + to have this handle checked soon */ + if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != + (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) { + Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ + + /* reset the too-slow time keeper */ + data->state.keeps_speed.tv_sec = 0; + + if(!data->state.tempcount) + /* if not pausing again, force a recv/send check of this connection as + the data might've been read off the socket already */ + data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; + if(data->multi) { + if(Curl_update_timer(data->multi)) + return CURLE_ABORTED_BY_CALLBACK; + } + } + + if(!data->state.done) + /* This transfer may have been moved in or out of the bundle, update the + corresponding socket callback, if used */ + result = Curl_updatesocket(data); + + if(recursive) + /* this might have called a callback recursively which might have set this + to false again on exit */ + Curl_set_in_callback(data, TRUE); + + return result; +} + + +static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, + struct connectdata **connp) +{ + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */ + if(!data->set.connect_only) { + failf(data, "CONNECT_ONLY is required"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + + *sfd = Curl_getconnectinfo(data, connp); + + if(*sfd == CURL_SOCKET_BAD) { + failf(data, "Failed to get recent socket"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + + return CURLE_OK; +} + +/* + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + * Returns CURLE_OK on success, error code on error. + */ +CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, + size_t *n) +{ + curl_socket_t sfd; + CURLcode result; + ssize_t n1; + struct connectdata *c; + + if(Curl_is_in_callback(data)) + return CURLE_RECURSIVE_API_CALL; + + result = easy_connection(data, &sfd, &c); + if(result) + return result; + + if(!data->conn) + /* on first invoke, the transfer has been detached from the connection and + needs to be reattached */ + Curl_attach_connection(data, c); + + *n = 0; + result = Curl_read(data, sfd, buffer, buflen, &n1); + + if(result) + return result; + + *n = (size_t)n1; + return CURLE_OK; +} + +#ifdef USE_WEBSOCKETS +CURLcode Curl_connect_only_attach(struct Curl_easy *data) +{ + curl_socket_t sfd; + CURLcode result; + struct connectdata *c = NULL; + + result = easy_connection(data, &sfd, &c); + if(result) + return result; + + if(!data->conn) + /* on first invoke, the transfer has been detached from the connection and + needs to be reattached */ + Curl_attach_connection(data, c); + + return CURLE_OK; +} +#endif /* USE_WEBSOCKETS */ + +/* + * Sends data over the connected socket. + * + * This is the private internal version of curl_easy_send() + */ +CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, + size_t buflen, ssize_t *n) +{ + curl_socket_t sfd; + CURLcode result; + ssize_t n1; + struct connectdata *c = NULL; + SIGPIPE_VARIABLE(pipe_st); + + result = easy_connection(data, &sfd, &c); + if(result) + return result; + + if(!data->conn) + /* on first invoke, the transfer has been detached from the connection and + needs to be reattached */ + Curl_attach_connection(data, c); + + *n = 0; + sigpipe_ignore(data, &pipe_st); + result = Curl_write(data, sfd, buffer, buflen, &n1); + sigpipe_restore(&pipe_st); + + if(n1 == -1) + return CURLE_SEND_ERROR; + + /* detect EAGAIN */ + if(!result && !n1) + return CURLE_AGAIN; + + *n = n1; + + return result; +} + +/* + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, + size_t buflen, size_t *n) +{ + ssize_t written = 0; + CURLcode result; + if(Curl_is_in_callback(data)) + return CURLE_RECURSIVE_API_CALL; + + result = Curl_senddata(data, buffer, buflen, &written); + *n = (size_t)written; + return result; +} + +/* + * Wrapper to call functions in Curl_conncache_foreach() + * + * Returns always 0. + */ +static int conn_upkeep(struct Curl_easy *data, + struct connectdata *conn, + void *param) +{ + struct curltime *now = param; + + if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms) + return 0; + + /* briefly attach for action */ + Curl_attach_connection(data, conn); + if(conn->handler->connection_check) { + /* Do a protocol-specific keepalive check on the connection. */ + conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE); + } + else { + /* Do the generic action on the FIRSTSOCKE filter chain */ + Curl_conn_keep_alive(data, conn, FIRSTSOCKET); + } + Curl_detach_connection(data); + + conn->keepalive = *now; + return 0; /* continue iteration */ +} + +static CURLcode upkeep(struct conncache *conn_cache, void *data) +{ + struct curltime now = Curl_now(); + /* Loop over every connection and make connection alive. */ + Curl_conncache_foreach(data, + conn_cache, + &now, + conn_upkeep); + return CURLE_OK; +} + +/* + * Performs connection upkeep for the given session handle. + */ +CURLcode curl_easy_upkeep(struct Curl_easy *data) +{ + /* Verify that we got an easy handle we can work with. */ + if(!GOOD_EASY_HANDLE(data)) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(data->multi_easy) { + /* Use the common function to keep connections alive. */ + return upkeep(&data->multi_easy->conn_cache, data); + } + else { + /* No connections, so just return success */ + return CURLE_OK; + } +} diff --git a/lib/easy_lock.h b/lib/easy_lock.h new file mode 100644 index 0000000..4f6764d --- /dev/null +++ b/lib/easy_lock.h @@ -0,0 +1,111 @@ +#ifndef HEADER_CURL_EASY_LOCK_H +#define HEADER_CURL_EASY_LOCK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#define GLOBAL_INIT_IS_THREADSAFE + +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 + +#ifdef __MINGW32__ +#ifndef SRWLOCK_INIT +#define SRWLOCK_INIT NULL +#endif +#endif /* __MINGW32__ */ + +#define curl_simple_lock SRWLOCK +#define CURL_SIMPLE_LOCK_INIT SRWLOCK_INIT + +#define curl_simple_lock_lock(m) AcquireSRWLockExclusive(m) +#define curl_simple_lock_unlock(m) ReleaseSRWLockExclusive(m) + +#elif defined(HAVE_ATOMIC) && defined(HAVE_STDATOMIC_H) +#include +#if defined(HAVE_SCHED_YIELD) +#include +#endif + +#define curl_simple_lock atomic_int +#define CURL_SIMPLE_LOCK_INIT 0 + +/* a clang-thing */ +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __INTEL_COMPILER +/* The Intel compiler tries to look like GCC *and* clang *and* lies in its + __has_builtin() function, so override it. */ + +/* if GCC on i386/x86_64 or if the built-in is present */ +#if ( (defined(__GNUC__) && !defined(__clang__)) && \ + (defined(__i386__) || defined(__x86_64__))) || \ + __has_builtin(__builtin_ia32_pause) +#define HAVE_BUILTIN_IA32_PAUSE +#endif + +#endif + +static inline void curl_simple_lock_lock(curl_simple_lock *lock) +{ + for(;;) { + if(!atomic_exchange_explicit(lock, true, memory_order_acquire)) + break; + /* Reduce cache coherency traffic */ + while(atomic_load_explicit(lock, memory_order_relaxed)) { + /* Reduce load (not mandatory) */ +#ifdef HAVE_BUILTIN_IA32_PAUSE + __builtin_ia32_pause(); +#elif defined(__aarch64__) + __asm__ volatile("yield" ::: "memory"); +#elif defined(HAVE_SCHED_YIELD) + sched_yield(); +#endif + } + } +} + +static inline void curl_simple_lock_unlock(curl_simple_lock *lock) +{ + atomic_store_explicit(lock, false, memory_order_release); +} + +#elif defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) + +#include + +#define curl_simple_lock pthread_mutex_t +#define CURL_SIMPLE_LOCK_INIT PTHREAD_MUTEX_INITIALIZER +#define curl_simple_lock_lock(m) pthread_mutex_lock(m) +#define curl_simple_lock_unlock(m) pthread_mutex_unlock(m) + +#else + +#undef GLOBAL_INIT_IS_THREADSAFE + +#endif + +#endif /* HEADER_CURL_EASY_LOCK_H */ diff --git a/lib/easygetopt.c b/lib/easygetopt.c new file mode 100644 index 0000000..2b8a521 --- /dev/null +++ b/lib/easygetopt.c @@ -0,0 +1,98 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ | | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * ___|___/|_| ______| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "strcase.h" +#include "easyoptions.h" + +#ifndef CURL_DISABLE_GETOPTIONS + +/* Lookups easy options at runtime */ +static struct curl_easyoption *lookup(const char *name, CURLoption id) +{ + DEBUGASSERT(name || id); + DEBUGASSERT(!Curl_easyopts_check()); + if(name || id) { + struct curl_easyoption *o = &Curl_easyopts[0]; + do { + if(name) { + if(strcasecompare(o->name, name)) + return o; + } + else { + if((o->id == id) && !(o->flags & CURLOT_FLAG_ALIAS)) + /* don't match alias options */ + return o; + } + o++; + } while(o->name); + } + return NULL; +} + +const struct curl_easyoption *curl_easy_option_by_name(const char *name) +{ + /* when name is used, the id argument is ignored */ + return lookup(name, CURLOPT_LASTENTRY); +} + +const struct curl_easyoption *curl_easy_option_by_id(CURLoption id) +{ + return lookup(NULL, id); +} + +/* Iterates over available options */ +const struct curl_easyoption * +curl_easy_option_next(const struct curl_easyoption *prev) +{ + if(prev && prev->name) { + prev++; + if(prev->name) + return prev; + } + else if(!prev) + return &Curl_easyopts[0]; + return NULL; +} + +#else +const struct curl_easyoption *curl_easy_option_by_name(const char *name) +{ + (void)name; + return NULL; +} + +const struct curl_easyoption *curl_easy_option_by_id (CURLoption id) +{ + (void)id; + return NULL; +} + +const struct curl_easyoption * +curl_easy_option_next(const struct curl_easyoption *prev) +{ + (void)prev; + return NULL; +} +#endif diff --git a/lib/easyif.h b/lib/easyif.h new file mode 100644 index 0000000..6448952 --- /dev/null +++ b/lib/easyif.h @@ -0,0 +1,41 @@ +#ifndef HEADER_CURL_EASYIF_H +#define HEADER_CURL_EASYIF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Prototypes for library-wide functions provided by easy.c + */ +CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, + size_t buflen, ssize_t *n); + +#ifdef USE_WEBSOCKETS +CURLcode Curl_connect_only_attach(struct Curl_easy *data); +#endif + +#ifdef CURLDEBUG +CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy); +#endif + +#endif /* HEADER_CURL_EASYIF_H */ diff --git a/lib/easyoptions.c b/lib/easyoptions.c new file mode 100644 index 0000000..da4c611 --- /dev/null +++ b/lib/easyoptions.c @@ -0,0 +1,380 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* This source code is generated by optiontable.pl - DO NOT EDIT BY HAND */ + +#include "curl_setup.h" +#include "easyoptions.h" + +/* all easy setopt options listed in alphabetical order */ +struct curl_easyoption Curl_easyopts[] = { + {"ABSTRACT_UNIX_SOCKET", CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOT_STRING, 0}, + {"ACCEPTTIMEOUT_MS", CURLOPT_ACCEPTTIMEOUT_MS, CURLOT_LONG, 0}, + {"ACCEPT_ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, 0}, + {"ADDRESS_SCOPE", CURLOPT_ADDRESS_SCOPE, CURLOT_LONG, 0}, + {"ALTSVC", CURLOPT_ALTSVC, CURLOT_STRING, 0}, + {"ALTSVC_CTRL", CURLOPT_ALTSVC_CTRL, CURLOT_LONG, 0}, + {"APPEND", CURLOPT_APPEND, CURLOT_LONG, 0}, + {"AUTOREFERER", CURLOPT_AUTOREFERER, CURLOT_LONG, 0}, + {"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0}, + {"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0}, + {"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0}, + {"CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CURLOT_BLOB, 0}, + {"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0}, + {"CA_CACHE_TIMEOUT", CURLOPT_CA_CACHE_TIMEOUT, CURLOT_LONG, 0}, + {"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0}, + {"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0}, + {"CHUNK_DATA", CURLOPT_CHUNK_DATA, CURLOT_CBPTR, 0}, + {"CHUNK_END_FUNCTION", CURLOPT_CHUNK_END_FUNCTION, CURLOT_FUNCTION, 0}, + {"CLOSESOCKETDATA", CURLOPT_CLOSESOCKETDATA, CURLOT_CBPTR, 0}, + {"CLOSESOCKETFUNCTION", CURLOPT_CLOSESOCKETFUNCTION, CURLOT_FUNCTION, 0}, + {"CONNECTTIMEOUT", CURLOPT_CONNECTTIMEOUT, CURLOT_LONG, 0}, + {"CONNECTTIMEOUT_MS", CURLOPT_CONNECTTIMEOUT_MS, CURLOT_LONG, 0}, + {"CONNECT_ONLY", CURLOPT_CONNECT_ONLY, CURLOT_LONG, 0}, + {"CONNECT_TO", CURLOPT_CONNECT_TO, CURLOT_SLIST, 0}, + {"CONV_FROM_NETWORK_FUNCTION", CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOT_FUNCTION, 0}, + {"CONV_FROM_UTF8_FUNCTION", CURLOPT_CONV_FROM_UTF8_FUNCTION, + CURLOT_FUNCTION, 0}, + {"CONV_TO_NETWORK_FUNCTION", CURLOPT_CONV_TO_NETWORK_FUNCTION, + CURLOT_FUNCTION, 0}, + {"COOKIE", CURLOPT_COOKIE, CURLOT_STRING, 0}, + {"COOKIEFILE", CURLOPT_COOKIEFILE, CURLOT_STRING, 0}, + {"COOKIEJAR", CURLOPT_COOKIEJAR, CURLOT_STRING, 0}, + {"COOKIELIST", CURLOPT_COOKIELIST, CURLOT_STRING, 0}, + {"COOKIESESSION", CURLOPT_COOKIESESSION, CURLOT_LONG, 0}, + {"COPYPOSTFIELDS", CURLOPT_COPYPOSTFIELDS, CURLOT_OBJECT, 0}, + {"CRLF", CURLOPT_CRLF, CURLOT_LONG, 0}, + {"CRLFILE", CURLOPT_CRLFILE, CURLOT_STRING, 0}, + {"CURLU", CURLOPT_CURLU, CURLOT_OBJECT, 0}, + {"CUSTOMREQUEST", CURLOPT_CUSTOMREQUEST, CURLOT_STRING, 0}, + {"DEBUGDATA", CURLOPT_DEBUGDATA, CURLOT_CBPTR, 0}, + {"DEBUGFUNCTION", CURLOPT_DEBUGFUNCTION, CURLOT_FUNCTION, 0}, + {"DEFAULT_PROTOCOL", CURLOPT_DEFAULT_PROTOCOL, CURLOT_STRING, 0}, + {"DIRLISTONLY", CURLOPT_DIRLISTONLY, CURLOT_LONG, 0}, + {"DISALLOW_USERNAME_IN_URL", CURLOPT_DISALLOW_USERNAME_IN_URL, + CURLOT_LONG, 0}, + {"DNS_CACHE_TIMEOUT", CURLOPT_DNS_CACHE_TIMEOUT, CURLOT_LONG, 0}, + {"DNS_INTERFACE", CURLOPT_DNS_INTERFACE, CURLOT_STRING, 0}, + {"DNS_LOCAL_IP4", CURLOPT_DNS_LOCAL_IP4, CURLOT_STRING, 0}, + {"DNS_LOCAL_IP6", CURLOPT_DNS_LOCAL_IP6, CURLOT_STRING, 0}, + {"DNS_SERVERS", CURLOPT_DNS_SERVERS, CURLOT_STRING, 0}, + {"DNS_SHUFFLE_ADDRESSES", CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOT_LONG, 0}, + {"DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOT_LONG, 0}, + {"DOH_SSL_VERIFYHOST", CURLOPT_DOH_SSL_VERIFYHOST, CURLOT_LONG, 0}, + {"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0}, + {"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0}, + {"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0}, + {"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0}, + {"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS}, + {"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0}, + {"EXPECT_100_TIMEOUT_MS", CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOT_LONG, 0}, + {"FAILONERROR", CURLOPT_FAILONERROR, CURLOT_LONG, 0}, + {"FILE", CURLOPT_WRITEDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, + {"FILETIME", CURLOPT_FILETIME, CURLOT_LONG, 0}, + {"FNMATCH_DATA", CURLOPT_FNMATCH_DATA, CURLOT_CBPTR, 0}, + {"FNMATCH_FUNCTION", CURLOPT_FNMATCH_FUNCTION, CURLOT_FUNCTION, 0}, + {"FOLLOWLOCATION", CURLOPT_FOLLOWLOCATION, CURLOT_LONG, 0}, + {"FORBID_REUSE", CURLOPT_FORBID_REUSE, CURLOT_LONG, 0}, + {"FRESH_CONNECT", CURLOPT_FRESH_CONNECT, CURLOT_LONG, 0}, + {"FTPAPPEND", CURLOPT_APPEND, CURLOT_LONG, CURLOT_FLAG_ALIAS}, + {"FTPLISTONLY", CURLOPT_DIRLISTONLY, CURLOT_LONG, CURLOT_FLAG_ALIAS}, + {"FTPPORT", CURLOPT_FTPPORT, CURLOT_STRING, 0}, + {"FTPSSLAUTH", CURLOPT_FTPSSLAUTH, CURLOT_VALUES, 0}, + {"FTP_ACCOUNT", CURLOPT_FTP_ACCOUNT, CURLOT_STRING, 0}, + {"FTP_ALTERNATIVE_TO_USER", CURLOPT_FTP_ALTERNATIVE_TO_USER, + CURLOT_STRING, 0}, + {"FTP_CREATE_MISSING_DIRS", CURLOPT_FTP_CREATE_MISSING_DIRS, + CURLOT_LONG, 0}, + {"FTP_FILEMETHOD", CURLOPT_FTP_FILEMETHOD, CURLOT_VALUES, 0}, + {"FTP_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT, + CURLOT_LONG, CURLOT_FLAG_ALIAS}, + {"FTP_SKIP_PASV_IP", CURLOPT_FTP_SKIP_PASV_IP, CURLOT_LONG, 0}, + {"FTP_SSL", CURLOPT_USE_SSL, CURLOT_VALUES, CURLOT_FLAG_ALIAS}, + {"FTP_SSL_CCC", CURLOPT_FTP_SSL_CCC, CURLOT_LONG, 0}, + {"FTP_USE_EPRT", CURLOPT_FTP_USE_EPRT, CURLOT_LONG, 0}, + {"FTP_USE_EPSV", CURLOPT_FTP_USE_EPSV, CURLOT_LONG, 0}, + {"FTP_USE_PRET", CURLOPT_FTP_USE_PRET, CURLOT_LONG, 0}, + {"GSSAPI_DELEGATION", CURLOPT_GSSAPI_DELEGATION, CURLOT_VALUES, 0}, + {"HAPPY_EYEBALLS_TIMEOUT_MS", CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, + CURLOT_LONG, 0}, + {"HAPROXYPROTOCOL", CURLOPT_HAPROXYPROTOCOL, CURLOT_LONG, 0}, + {"HAPROXY_CLIENT_IP", CURLOPT_HAPROXY_CLIENT_IP, CURLOT_STRING, 0}, + {"HEADER", CURLOPT_HEADER, CURLOT_LONG, 0}, + {"HEADERDATA", CURLOPT_HEADERDATA, CURLOT_CBPTR, 0}, + {"HEADERFUNCTION", CURLOPT_HEADERFUNCTION, CURLOT_FUNCTION, 0}, + {"HEADEROPT", CURLOPT_HEADEROPT, CURLOT_VALUES, 0}, + {"HSTS", CURLOPT_HSTS, CURLOT_STRING, 0}, + {"HSTSREADDATA", CURLOPT_HSTSREADDATA, CURLOT_CBPTR, 0}, + {"HSTSREADFUNCTION", CURLOPT_HSTSREADFUNCTION, CURLOT_FUNCTION, 0}, + {"HSTSWRITEDATA", CURLOPT_HSTSWRITEDATA, CURLOT_CBPTR, 0}, + {"HSTSWRITEFUNCTION", CURLOPT_HSTSWRITEFUNCTION, CURLOT_FUNCTION, 0}, + {"HSTS_CTRL", CURLOPT_HSTS_CTRL, CURLOT_LONG, 0}, + {"HTTP09_ALLOWED", CURLOPT_HTTP09_ALLOWED, CURLOT_LONG, 0}, + {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0}, + {"HTTPAUTH", CURLOPT_HTTPAUTH, CURLOT_VALUES, 0}, + {"HTTPGET", CURLOPT_HTTPGET, CURLOT_LONG, 0}, + {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0}, + {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0}, + {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0}, + {"HTTP_CONTENT_DECODING", CURLOPT_HTTP_CONTENT_DECODING, CURLOT_LONG, 0}, + {"HTTP_TRANSFER_DECODING", CURLOPT_HTTP_TRANSFER_DECODING, CURLOT_LONG, 0}, + {"HTTP_VERSION", CURLOPT_HTTP_VERSION, CURLOT_VALUES, 0}, + {"IGNORE_CONTENT_LENGTH", CURLOPT_IGNORE_CONTENT_LENGTH, CURLOT_LONG, 0}, + {"INFILE", CURLOPT_READDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, + {"INFILESIZE", CURLOPT_INFILESIZE, CURLOT_LONG, 0}, + {"INFILESIZE_LARGE", CURLOPT_INFILESIZE_LARGE, CURLOT_OFF_T, 0}, + {"INTERFACE", CURLOPT_INTERFACE, CURLOT_STRING, 0}, + {"INTERLEAVEDATA", CURLOPT_INTERLEAVEDATA, CURLOT_CBPTR, 0}, + {"INTERLEAVEFUNCTION", CURLOPT_INTERLEAVEFUNCTION, CURLOT_FUNCTION, 0}, + {"IOCTLDATA", CURLOPT_IOCTLDATA, CURLOT_CBPTR, 0}, + {"IOCTLFUNCTION", CURLOPT_IOCTLFUNCTION, CURLOT_FUNCTION, 0}, + {"IPRESOLVE", CURLOPT_IPRESOLVE, CURLOT_VALUES, 0}, + {"ISSUERCERT", CURLOPT_ISSUERCERT, CURLOT_STRING, 0}, + {"ISSUERCERT_BLOB", CURLOPT_ISSUERCERT_BLOB, CURLOT_BLOB, 0}, + {"KEEP_SENDING_ON_ERROR", CURLOPT_KEEP_SENDING_ON_ERROR, CURLOT_LONG, 0}, + {"KEYPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, 0}, + {"KRB4LEVEL", CURLOPT_KRBLEVEL, CURLOT_STRING, CURLOT_FLAG_ALIAS}, + {"KRBLEVEL", CURLOPT_KRBLEVEL, CURLOT_STRING, 0}, + {"LOCALPORT", CURLOPT_LOCALPORT, CURLOT_LONG, 0}, + {"LOCALPORTRANGE", CURLOPT_LOCALPORTRANGE, CURLOT_LONG, 0}, + {"LOGIN_OPTIONS", CURLOPT_LOGIN_OPTIONS, CURLOT_STRING, 0}, + {"LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT, CURLOT_LONG, 0}, + {"LOW_SPEED_TIME", CURLOPT_LOW_SPEED_TIME, CURLOT_LONG, 0}, + {"MAIL_AUTH", CURLOPT_MAIL_AUTH, CURLOT_STRING, 0}, + {"MAIL_FROM", CURLOPT_MAIL_FROM, CURLOT_STRING, 0}, + {"MAIL_RCPT", CURLOPT_MAIL_RCPT, CURLOT_SLIST, 0}, + {"MAIL_RCPT_ALLLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS, + CURLOT_LONG, CURLOT_FLAG_ALIAS}, + {"MAIL_RCPT_ALLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOT_LONG, 0}, + {"MAXAGE_CONN", CURLOPT_MAXAGE_CONN, CURLOT_LONG, 0}, + {"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0}, + {"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0}, + {"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0}, + {"MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN, CURLOT_LONG, 0}, + {"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0}, + {"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 0}, + {"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0}, + {"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0}, + {"MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CURLOT_LONG, 0}, + {"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0}, + {"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0}, + {"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 0}, + {"NEW_FILE_PERMS", CURLOPT_NEW_FILE_PERMS, CURLOT_LONG, 0}, + {"NOBODY", CURLOPT_NOBODY, CURLOT_LONG, 0}, + {"NOPROGRESS", CURLOPT_NOPROGRESS, CURLOT_LONG, 0}, + {"NOPROXY", CURLOPT_NOPROXY, CURLOT_STRING, 0}, + {"NOSIGNAL", CURLOPT_NOSIGNAL, CURLOT_LONG, 0}, + {"OPENSOCKETDATA", CURLOPT_OPENSOCKETDATA, CURLOT_CBPTR, 0}, + {"OPENSOCKETFUNCTION", CURLOPT_OPENSOCKETFUNCTION, CURLOT_FUNCTION, 0}, + {"PASSWORD", CURLOPT_PASSWORD, CURLOT_STRING, 0}, + {"PATH_AS_IS", CURLOPT_PATH_AS_IS, CURLOT_LONG, 0}, + {"PINNEDPUBLICKEY", CURLOPT_PINNEDPUBLICKEY, CURLOT_STRING, 0}, + {"PIPEWAIT", CURLOPT_PIPEWAIT, CURLOT_LONG, 0}, + {"PORT", CURLOPT_PORT, CURLOT_LONG, 0}, + {"POST", CURLOPT_POST, CURLOT_LONG, 0}, + {"POST301", CURLOPT_POSTREDIR, CURLOT_VALUES, CURLOT_FLAG_ALIAS}, + {"POSTFIELDS", CURLOPT_POSTFIELDS, CURLOT_OBJECT, 0}, + {"POSTFIELDSIZE", CURLOPT_POSTFIELDSIZE, CURLOT_LONG, 0}, + {"POSTFIELDSIZE_LARGE", CURLOPT_POSTFIELDSIZE_LARGE, CURLOT_OFF_T, 0}, + {"POSTQUOTE", CURLOPT_POSTQUOTE, CURLOT_SLIST, 0}, + {"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0}, + {"PREQUOTE", CURLOPT_PREQUOTE, CURLOT_SLIST, 0}, + {"PREREQDATA", CURLOPT_PREREQDATA, CURLOT_CBPTR, 0}, + {"PREREQFUNCTION", CURLOPT_PREREQFUNCTION, CURLOT_FUNCTION, 0}, + {"PRE_PROXY", CURLOPT_PRE_PROXY, CURLOT_STRING, 0}, + {"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0}, + {"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, + {"PROGRESSFUNCTION", CURLOPT_PROGRESSFUNCTION, CURLOT_FUNCTION, 0}, + {"PROTOCOLS", CURLOPT_PROTOCOLS, CURLOT_LONG, 0}, + {"PROTOCOLS_STR", CURLOPT_PROTOCOLS_STR, CURLOT_STRING, 0}, + {"PROXY", CURLOPT_PROXY, CURLOT_STRING, 0}, + {"PROXYAUTH", CURLOPT_PROXYAUTH, CURLOT_VALUES, 0}, + {"PROXYHEADER", CURLOPT_PROXYHEADER, CURLOT_SLIST, 0}, + {"PROXYPASSWORD", CURLOPT_PROXYPASSWORD, CURLOT_STRING, 0}, + {"PROXYPORT", CURLOPT_PROXYPORT, CURLOT_LONG, 0}, + {"PROXYTYPE", CURLOPT_PROXYTYPE, CURLOT_VALUES, 0}, + {"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0}, + {"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0}, + {"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0}, + {"PROXY_CAINFO_BLOB", CURLOPT_PROXY_CAINFO_BLOB, CURLOT_BLOB, 0}, + {"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0}, + {"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0}, + {"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0}, + {"PROXY_ISSUERCERT_BLOB", CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOT_BLOB, 0}, + {"PROXY_KEYPASSWD", CURLOPT_PROXY_KEYPASSWD, CURLOT_STRING, 0}, + {"PROXY_PINNEDPUBLICKEY", CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOT_STRING, 0}, + {"PROXY_SERVICE_NAME", CURLOPT_PROXY_SERVICE_NAME, CURLOT_STRING, 0}, + {"PROXY_SSLCERT", CURLOPT_PROXY_SSLCERT, CURLOT_STRING, 0}, + {"PROXY_SSLCERTTYPE", CURLOPT_PROXY_SSLCERTTYPE, CURLOT_STRING, 0}, + {"PROXY_SSLCERT_BLOB", CURLOPT_PROXY_SSLCERT_BLOB, CURLOT_BLOB, 0}, + {"PROXY_SSLKEY", CURLOPT_PROXY_SSLKEY, CURLOT_STRING, 0}, + {"PROXY_SSLKEYTYPE", CURLOPT_PROXY_SSLKEYTYPE, CURLOT_STRING, 0}, + {"PROXY_SSLKEY_BLOB", CURLOPT_PROXY_SSLKEY_BLOB, CURLOT_BLOB, 0}, + {"PROXY_SSLVERSION", CURLOPT_PROXY_SSLVERSION, CURLOT_VALUES, 0}, + {"PROXY_SSL_CIPHER_LIST", CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOT_STRING, 0}, + {"PROXY_SSL_OPTIONS", CURLOPT_PROXY_SSL_OPTIONS, CURLOT_LONG, 0}, + {"PROXY_SSL_VERIFYHOST", CURLOPT_PROXY_SSL_VERIFYHOST, CURLOT_LONG, 0}, + {"PROXY_SSL_VERIFYPEER", CURLOPT_PROXY_SSL_VERIFYPEER, CURLOT_LONG, 0}, + {"PROXY_TLS13_CIPHERS", CURLOPT_PROXY_TLS13_CIPHERS, CURLOT_STRING, 0}, + {"PROXY_TLSAUTH_PASSWORD", CURLOPT_PROXY_TLSAUTH_PASSWORD, + CURLOT_STRING, 0}, + {"PROXY_TLSAUTH_TYPE", CURLOPT_PROXY_TLSAUTH_TYPE, CURLOT_STRING, 0}, + {"PROXY_TLSAUTH_USERNAME", CURLOPT_PROXY_TLSAUTH_USERNAME, + CURLOT_STRING, 0}, + {"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0}, + {"PUT", CURLOPT_PUT, CURLOT_LONG, 0}, + {"QUICK_EXIT", CURLOPT_QUICK_EXIT, CURLOT_LONG, 0}, + {"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0}, + {"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0}, + {"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0}, + {"READDATA", CURLOPT_READDATA, CURLOT_CBPTR, 0}, + {"READFUNCTION", CURLOPT_READFUNCTION, CURLOT_FUNCTION, 0}, + {"REDIR_PROTOCOLS", CURLOPT_REDIR_PROTOCOLS, CURLOT_LONG, 0}, + {"REDIR_PROTOCOLS_STR", CURLOPT_REDIR_PROTOCOLS_STR, CURLOT_STRING, 0}, + {"REFERER", CURLOPT_REFERER, CURLOT_STRING, 0}, + {"REQUEST_TARGET", CURLOPT_REQUEST_TARGET, CURLOT_STRING, 0}, + {"RESOLVE", CURLOPT_RESOLVE, CURLOT_SLIST, 0}, + {"RESOLVER_START_DATA", CURLOPT_RESOLVER_START_DATA, CURLOT_CBPTR, 0}, + {"RESOLVER_START_FUNCTION", CURLOPT_RESOLVER_START_FUNCTION, + CURLOT_FUNCTION, 0}, + {"RESUME_FROM", CURLOPT_RESUME_FROM, CURLOT_LONG, 0}, + {"RESUME_FROM_LARGE", CURLOPT_RESUME_FROM_LARGE, CURLOT_OFF_T, 0}, + {"RTSPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, CURLOT_FLAG_ALIAS}, + {"RTSP_CLIENT_CSEQ", CURLOPT_RTSP_CLIENT_CSEQ, CURLOT_LONG, 0}, + {"RTSP_REQUEST", CURLOPT_RTSP_REQUEST, CURLOT_VALUES, 0}, + {"RTSP_SERVER_CSEQ", CURLOPT_RTSP_SERVER_CSEQ, CURLOT_LONG, 0}, + {"RTSP_SESSION_ID", CURLOPT_RTSP_SESSION_ID, CURLOT_STRING, 0}, + {"RTSP_STREAM_URI", CURLOPT_RTSP_STREAM_URI, CURLOT_STRING, 0}, + {"RTSP_TRANSPORT", CURLOPT_RTSP_TRANSPORT, CURLOT_STRING, 0}, + {"SASL_AUTHZID", CURLOPT_SASL_AUTHZID, CURLOT_STRING, 0}, + {"SASL_IR", CURLOPT_SASL_IR, CURLOT_LONG, 0}, + {"SEEKDATA", CURLOPT_SEEKDATA, CURLOT_CBPTR, 0}, + {"SEEKFUNCTION", CURLOPT_SEEKFUNCTION, CURLOT_FUNCTION, 0}, + {"SERVER_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT, + CURLOT_LONG, 0}, + {"SERVER_RESPONSE_TIMEOUT_MS", CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, + CURLOT_LONG, 0}, + {"SERVICE_NAME", CURLOPT_SERVICE_NAME, CURLOT_STRING, 0}, + {"SHARE", CURLOPT_SHARE, CURLOT_OBJECT, 0}, + {"SOCKOPTDATA", CURLOPT_SOCKOPTDATA, CURLOT_CBPTR, 0}, + {"SOCKOPTFUNCTION", CURLOPT_SOCKOPTFUNCTION, CURLOT_FUNCTION, 0}, + {"SOCKS5_AUTH", CURLOPT_SOCKS5_AUTH, CURLOT_LONG, 0}, + {"SOCKS5_GSSAPI_NEC", CURLOPT_SOCKS5_GSSAPI_NEC, CURLOT_LONG, 0}, + {"SOCKS5_GSSAPI_SERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOT_STRING, 0}, + {"SSH_AUTH_TYPES", CURLOPT_SSH_AUTH_TYPES, CURLOT_VALUES, 0}, + {"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0}, + {"SSH_HOSTKEYDATA", CURLOPT_SSH_HOSTKEYDATA, CURLOT_CBPTR, 0}, + {"SSH_HOSTKEYFUNCTION", CURLOPT_SSH_HOSTKEYFUNCTION, CURLOT_FUNCTION, 0}, + {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, + CURLOT_STRING, 0}, + {"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, + CURLOT_STRING, 0}, + {"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0}, + {"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0}, + {"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0}, + {"SSH_PRIVATE_KEYFILE", CURLOPT_SSH_PRIVATE_KEYFILE, CURLOT_STRING, 0}, + {"SSH_PUBLIC_KEYFILE", CURLOPT_SSH_PUBLIC_KEYFILE, CURLOT_STRING, 0}, + {"SSLCERT", CURLOPT_SSLCERT, CURLOT_STRING, 0}, + {"SSLCERTPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, CURLOT_FLAG_ALIAS}, + {"SSLCERTTYPE", CURLOPT_SSLCERTTYPE, CURLOT_STRING, 0}, + {"SSLCERT_BLOB", CURLOPT_SSLCERT_BLOB, CURLOT_BLOB, 0}, + {"SSLENGINE", CURLOPT_SSLENGINE, CURLOT_STRING, 0}, + {"SSLENGINE_DEFAULT", CURLOPT_SSLENGINE_DEFAULT, CURLOT_LONG, 0}, + {"SSLKEY", CURLOPT_SSLKEY, CURLOT_STRING, 0}, + {"SSLKEYPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, CURLOT_FLAG_ALIAS}, + {"SSLKEYTYPE", CURLOPT_SSLKEYTYPE, CURLOT_STRING, 0}, + {"SSLKEY_BLOB", CURLOPT_SSLKEY_BLOB, CURLOT_BLOB, 0}, + {"SSLVERSION", CURLOPT_SSLVERSION, CURLOT_VALUES, 0}, + {"SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST, CURLOT_STRING, 0}, + {"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA, CURLOT_CBPTR, 0}, + {"SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, CURLOT_FUNCTION, 0}, + {"SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CURLOT_STRING, 0}, + {"SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN, CURLOT_LONG, 0}, + {"SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN, CURLOT_LONG, 0}, + {"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0}, + {"SSL_OPTIONS", CURLOPT_SSL_OPTIONS, CURLOT_VALUES, 0}, + {"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE, CURLOT_LONG, 0}, + {"SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST, CURLOT_LONG, 0}, + {"SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER, CURLOT_LONG, 0}, + {"SSL_VERIFYSTATUS", CURLOPT_SSL_VERIFYSTATUS, CURLOT_LONG, 0}, + {"STDERR", CURLOPT_STDERR, CURLOT_OBJECT, 0}, + {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0}, + {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0}, + {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0}, + {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS, + CURLOT_LONG, 0}, + {"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0}, + {"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0}, + {"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0}, + {"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0}, + {"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0}, + {"TELNETOPTIONS", CURLOPT_TELNETOPTIONS, CURLOT_SLIST, 0}, + {"TFTP_BLKSIZE", CURLOPT_TFTP_BLKSIZE, CURLOT_LONG, 0}, + {"TFTP_NO_OPTIONS", CURLOPT_TFTP_NO_OPTIONS, CURLOT_LONG, 0}, + {"TIMECONDITION", CURLOPT_TIMECONDITION, CURLOT_VALUES, 0}, + {"TIMEOUT", CURLOPT_TIMEOUT, CURLOT_LONG, 0}, + {"TIMEOUT_MS", CURLOPT_TIMEOUT_MS, CURLOT_LONG, 0}, + {"TIMEVALUE", CURLOPT_TIMEVALUE, CURLOT_LONG, 0}, + {"TIMEVALUE_LARGE", CURLOPT_TIMEVALUE_LARGE, CURLOT_OFF_T, 0}, + {"TLS13_CIPHERS", CURLOPT_TLS13_CIPHERS, CURLOT_STRING, 0}, + {"TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD, CURLOT_STRING, 0}, + {"TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE, CURLOT_STRING, 0}, + {"TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME, CURLOT_STRING, 0}, + {"TRAILERDATA", CURLOPT_TRAILERDATA, CURLOT_CBPTR, 0}, + {"TRAILERFUNCTION", CURLOPT_TRAILERFUNCTION, CURLOT_FUNCTION, 0}, + {"TRANSFERTEXT", CURLOPT_TRANSFERTEXT, CURLOT_LONG, 0}, + {"TRANSFER_ENCODING", CURLOPT_TRANSFER_ENCODING, CURLOT_LONG, 0}, + {"UNIX_SOCKET_PATH", CURLOPT_UNIX_SOCKET_PATH, CURLOT_STRING, 0}, + {"UNRESTRICTED_AUTH", CURLOPT_UNRESTRICTED_AUTH, CURLOT_LONG, 0}, + {"UPKEEP_INTERVAL_MS", CURLOPT_UPKEEP_INTERVAL_MS, CURLOT_LONG, 0}, + {"UPLOAD", CURLOPT_UPLOAD, CURLOT_LONG, 0}, + {"UPLOAD_BUFFERSIZE", CURLOPT_UPLOAD_BUFFERSIZE, CURLOT_LONG, 0}, + {"URL", CURLOPT_URL, CURLOT_STRING, 0}, + {"USERAGENT", CURLOPT_USERAGENT, CURLOT_STRING, 0}, + {"USERNAME", CURLOPT_USERNAME, CURLOT_STRING, 0}, + {"USERPWD", CURLOPT_USERPWD, CURLOT_STRING, 0}, + {"USE_SSL", CURLOPT_USE_SSL, CURLOT_VALUES, 0}, + {"VERBOSE", CURLOPT_VERBOSE, CURLOT_LONG, 0}, + {"WILDCARDMATCH", CURLOPT_WILDCARDMATCH, CURLOT_LONG, 0}, + {"WRITEDATA", CURLOPT_WRITEDATA, CURLOT_CBPTR, 0}, + {"WRITEFUNCTION", CURLOPT_WRITEFUNCTION, CURLOT_FUNCTION, 0}, + {"WRITEHEADER", CURLOPT_HEADERDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, + {"WS_OPTIONS", CURLOPT_WS_OPTIONS, CURLOT_LONG, 0}, + {"XFERINFODATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, 0}, + {"XFERINFOFUNCTION", CURLOPT_XFERINFOFUNCTION, CURLOT_FUNCTION, 0}, + {"XOAUTH2_BEARER", CURLOPT_XOAUTH2_BEARER, CURLOT_STRING, 0}, + {NULL, CURLOPT_LASTENTRY, CURLOT_LONG, 0} /* end of table */ +}; + +#ifdef DEBUGBUILD +/* + * Curl_easyopts_check() is a debug-only function that returns non-zero + * if this source file is not in sync with the options listed in curl/curl.h + */ +int Curl_easyopts_check(void) +{ + return ((CURLOPT_LASTENTRY%10000) != (324 + 1)); +} +#endif diff --git a/lib/easyoptions.h b/lib/easyoptions.h new file mode 100644 index 0000000..24b4cd9 --- /dev/null +++ b/lib/easyoptions.h @@ -0,0 +1,37 @@ +#ifndef HEADER_CURL_EASYOPTIONS_H +#define HEADER_CURL_EASYOPTIONS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* should probably go into the public header */ + +#include + +/* generated table with all easy options */ +extern struct curl_easyoption Curl_easyopts[]; + +#ifdef DEBUGBUILD +int Curl_easyopts_check(void); +#endif +#endif diff --git a/lib/escape.c b/lib/escape.c new file mode 100644 index 0000000..5af00c3 --- /dev/null +++ b/lib/escape.c @@ -0,0 +1,234 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* Escape and unescape URL encoding in strings. The functions return a new + * allocated string or NULL if an error occurred. */ + +#include "curl_setup.h" + +#include + +#include "urldata.h" +#include "warnless.h" +#include "escape.h" +#include "strdup.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* for ABI-compatibility with previous versions */ +char *curl_escape(const char *string, int inlength) +{ + return curl_easy_escape(NULL, string, inlength); +} + +/* for ABI-compatibility with previous versions */ +char *curl_unescape(const char *string, int length) +{ + return curl_easy_unescape(NULL, string, length, NULL); +} + +/* Escapes for URL the given unescaped string of given length. + * 'data' is ignored since 7.82.0. + */ +char *curl_easy_escape(struct Curl_easy *data, const char *string, + int inlength) +{ + size_t length; + struct dynbuf d; + (void)data; + + if(inlength < 0) + return NULL; + + Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH * 3); + + length = (inlength?(size_t)inlength:strlen(string)); + if(!length) + return strdup(""); + + while(length--) { + unsigned char in = *string++; /* treat the characters unsigned */ + + if(ISUNRESERVED(in)) { + /* append this */ + if(Curl_dyn_addn(&d, &in, 1)) + return NULL; + } + else { + /* encode it */ + const char hex[] = "0123456789ABCDEF"; + char out[3]={'%'}; + out[1] = hex[in>>4]; + out[2] = hex[in & 0xf]; + if(Curl_dyn_addn(&d, out, 3)) + return NULL; + } + } + + return Curl_dyn_ptr(&d); +} + +static const unsigned char hextable[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 10, 11, 12, 13, 14, 15 /* 0x60 - 0x66 */ +}; + +/* the input is a single hex digit */ +#define onehex2dec(x) hextable[x - '0'] + +/* + * Curl_urldecode() URL decodes the given string. + * + * Returns a pointer to a malloced string in *ostring with length given in + * *olen. If length == 0, the length is assumed to be strlen(string). + * + * ctrl options: + * - REJECT_NADA: accept everything + * - REJECT_CTRL: rejects control characters (byte codes lower than 32) in + * the data + * - REJECT_ZERO: rejects decoded zero bytes + * + * The values for the enum starts at 2, to make the assert detect legacy + * invokes that used TRUE/FALSE (0 and 1). + */ + +CURLcode Curl_urldecode(const char *string, size_t length, + char **ostring, size_t *olen, + enum urlreject ctrl) +{ + size_t alloc; + char *ns; + + DEBUGASSERT(string); + DEBUGASSERT(ctrl >= REJECT_NADA); /* crash on TRUE/FALSE */ + + alloc = (length?length:strlen(string)); + ns = malloc(alloc + 1); + + if(!ns) + return CURLE_OUT_OF_MEMORY; + + /* store output string */ + *ostring = ns; + + while(alloc) { + unsigned char in = *string; + if(('%' == in) && (alloc > 2) && + ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { + /* this is two hexadecimal digits following a '%' */ + in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]); + + string += 3; + alloc -= 3; + } + else { + string++; + alloc--; + } + + if(((ctrl == REJECT_CTRL) && (in < 0x20)) || + ((ctrl == REJECT_ZERO) && (in == 0))) { + Curl_safefree(*ostring); + return CURLE_URL_MALFORMAT; + } + + *ns++ = in; + } + *ns = 0; /* terminate it */ + + if(olen) + /* store output size */ + *olen = ns - *ostring; + + return CURLE_OK; +} + +/* + * Unescapes the given URL escaped string of given length. Returns a + * pointer to a malloced string with length given in *olen. + * If length == 0, the length is assumed to be strlen(string). + * If olen == NULL, no output length is stored. + * 'data' is ignored since 7.82.0. + */ +char *curl_easy_unescape(struct Curl_easy *data, const char *string, + int length, int *olen) +{ + char *str = NULL; + (void)data; + if(length >= 0) { + size_t inputlen = (size_t)length; + size_t outputlen; + CURLcode res = Curl_urldecode(string, inputlen, &str, &outputlen, + REJECT_NADA); + if(res) + return NULL; + + if(olen) { + if(outputlen <= (size_t) INT_MAX) + *olen = curlx_uztosi(outputlen); + else + /* too large to return in an int, fail! */ + Curl_safefree(str); + } + } + return str; +} + +/* For operating systems/environments that use different malloc/free + systems for the app and for this library, we provide a free that uses + the library's memory system */ +void curl_free(void *p) +{ + free(p); +} + +/* + * Curl_hexencode() + * + * Converts binary input to lowercase hex-encoded ASCII output. + * Null-terminated. + */ +void Curl_hexencode(const unsigned char *src, size_t len, /* input length */ + unsigned char *out, size_t olen) /* output buffer size */ +{ + const char *hex = "0123456789abcdef"; + DEBUGASSERT(src && len && (olen >= 3)); + if(src && len && (olen >= 3)) { + while(len-- && (olen >= 3)) { + /* clang-tidy warns on this line without this comment: */ + /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */ + *out++ = hex[(*src & 0xF0)>>4]; + *out++ = hex[*src & 0x0F]; + ++src; + olen -= 2; + } + *out = 0; + } + else if(olen) + *out = 0; +} diff --git a/lib/escape.h b/lib/escape.h new file mode 100644 index 0000000..690e417 --- /dev/null +++ b/lib/escape.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_ESCAPE_H +#define HEADER_CURL_ESCAPE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* Escape and unescape URL encoding in strings. The functions return a new + * allocated string or NULL if an error occurred. */ + +#include "curl_ctype.h" + +enum urlreject { + REJECT_NADA = 2, + REJECT_CTRL, + REJECT_ZERO +}; + +CURLcode Curl_urldecode(const char *string, size_t length, + char **ostring, size_t *olen, + enum urlreject ctrl); + +void Curl_hexencode(const unsigned char *src, size_t len, /* input length */ + unsigned char *out, size_t olen); /* output buffer size */ + +#endif /* HEADER_CURL_ESCAPE_H */ diff --git a/lib/file.c b/lib/file.c new file mode 100644 index 0000000..b7ce3a8 --- /dev/null +++ b/lib/file.c @@ -0,0 +1,585 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_FILE + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "strtoofft.h" +#include "urldata.h" +#include +#include "progress.h" +#include "sendf.h" +#include "escape.h" +#include "file.h" +#include "speedcheck.h" +#include "getinfo.h" +#include "transfer.h" +#include "url.h" +#include "parsedate.h" /* for the week day and month names */ +#include "warnless.h" +#include "curl_range.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if defined(_WIN32) || defined(MSDOS) || defined(__EMX__) +#define DOS_FILESYSTEM 1 +#elif defined(__amigaos4__) +#define AMIGA_FILESYSTEM 1 +#endif + +#ifdef OPEN_NEEDS_ARG3 +# define open_readonly(p,f) open((p),(f),(0)) +#else +# define open_readonly(p,f) open((p),(f)) +#endif + +/* + * Forward declarations. + */ + +static CURLcode file_do(struct Curl_easy *data, bool *done); +static CURLcode file_done(struct Curl_easy *data, + CURLcode status, bool premature); +static CURLcode file_connect(struct Curl_easy *data, bool *done); +static CURLcode file_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection); +static CURLcode file_setup_connection(struct Curl_easy *data, + struct connectdata *conn); + +/* + * FILE scheme handler. + */ + +const struct Curl_handler Curl_handler_file = { + "FILE", /* scheme */ + file_setup_connection, /* setup_connection */ + file_do, /* do_it */ + file_done, /* done */ + ZERO_NULL, /* do_more */ + file_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + file_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + 0, /* defport */ + CURLPROTO_FILE, /* protocol */ + CURLPROTO_FILE, /* family */ + PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */ +}; + + +static CURLcode file_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + (void)conn; + /* allocate the FILE specific struct */ + data->req.p.file = calloc(1, sizeof(struct FILEPROTO)); + if(!data->req.p.file) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +/* + * file_connect() gets called from Curl_protocol_connect() to allow us to + * do protocol-specific actions at connect-time. We emulate a + * connect-then-transfer protocol and "connect" to the file here + */ +static CURLcode file_connect(struct Curl_easy *data, bool *done) +{ + char *real_path; + struct FILEPROTO *file = data->req.p.file; + int fd; +#ifdef DOS_FILESYSTEM + size_t i; + char *actual_path; +#endif + size_t real_path_len; + CURLcode result; + + if(file->path) { + /* already connected. + * the handler->connect_it() is normally only called once, but + * FILE does a special check on setting up the connection which + * calls this explicitly. */ + *done = TRUE; + return CURLE_OK; + } + + result = Curl_urldecode(data->state.up.path, 0, &real_path, + &real_path_len, REJECT_ZERO); + if(result) + return result; + +#ifdef DOS_FILESYSTEM + /* If the first character is a slash, and there's + something that looks like a drive at the beginning of + the path, skip the slash. If we remove the initial + slash in all cases, paths without drive letters end up + relative to the current directory which isn't how + browsers work. + + Some browsers accept | instead of : as the drive letter + separator, so we do too. + + On other platforms, we need the slash to indicate an + absolute pathname. On Windows, absolute paths start + with a drive letter. + */ + actual_path = real_path; + if((actual_path[0] == '/') && + actual_path[1] && + (actual_path[2] == ':' || actual_path[2] == '|')) { + actual_path[2] = ':'; + actual_path++; + real_path_len--; + } + + /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ + for(i = 0; i < real_path_len; ++i) + if(actual_path[i] == '/') + actual_path[i] = '\\'; + else if(!actual_path[i]) { /* binary zero */ + Curl_safefree(real_path); + return CURLE_URL_MALFORMAT; + } + + fd = open_readonly(actual_path, O_RDONLY|O_BINARY); + file->path = actual_path; +#else + if(memchr(real_path, 0, real_path_len)) { + /* binary zeroes indicate foul play */ + Curl_safefree(real_path); + return CURLE_URL_MALFORMAT; + } + + #ifdef AMIGA_FILESYSTEM + /* + * A leading slash in an AmigaDOS path denotes the parent + * directory, and hence we block this as it is relative. + * Absolute paths start with 'volumename:', so we check for + * this first. Failing that, we treat the path as a real unix + * path, but only if the application was compiled with -lunix. + */ + fd = -1; + file->path = real_path; + + if(real_path[0] == '/') { + extern int __unix_path_semantics; + if(strchr(real_path + 1, ':')) { + /* Amiga absolute path */ + fd = open_readonly(real_path + 1, O_RDONLY); + file->path++; + } + else if(__unix_path_semantics) { + /* -lunix fallback */ + fd = open_readonly(real_path, O_RDONLY); + } + } + #else + fd = open_readonly(real_path, O_RDONLY); + file->path = real_path; + #endif +#endif + Curl_safefree(file->freepath); + file->freepath = real_path; /* free this when done */ + + file->fd = fd; + if(!data->state.upload && (fd == -1)) { + failf(data, "Couldn't open file %s", data->state.up.path); + file_done(data, CURLE_FILE_COULDNT_READ_FILE, FALSE); + return CURLE_FILE_COULDNT_READ_FILE; + } + *done = TRUE; + + return CURLE_OK; +} + +static CURLcode file_done(struct Curl_easy *data, + CURLcode status, bool premature) +{ + struct FILEPROTO *file = data->req.p.file; + (void)status; /* not used */ + (void)premature; /* not used */ + + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } + + return CURLE_OK; +} + +static CURLcode file_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + (void)dead_connection; /* not used */ + (void)conn; + return file_done(data, CURLE_OK, FALSE); +} + +#ifdef DOS_FILESYSTEM +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif + +static CURLcode file_upload(struct Curl_easy *data) +{ + struct FILEPROTO *file = data->req.p.file; + const char *dir = strchr(file->path, DIRSEP); + int fd; + int mode; + CURLcode result = CURLE_OK; + char buffer[8*1024], *uphere_save; + curl_off_t bytecount = 0; + struct_stat file_stat; + const char *sendbuf; + + /* + * Since FILE: doesn't do the full init, we need to provide some extra + * assignments here. + */ + + if(!dir) + return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ + + if(!dir[1]) + return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ + +#ifdef O_BINARY +#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY +#else +#define MODE_DEFAULT O_WRONLY|O_CREAT +#endif + + if(data->state.resume_from) + mode = MODE_DEFAULT|O_APPEND; + else + mode = MODE_DEFAULT|O_TRUNC; + + fd = open(file->path, mode, data->set.new_file_perms); + if(fd < 0) { + failf(data, "Can't open %s for writing", file->path); + return CURLE_WRITE_ERROR; + } + + if(-1 != data->state.infilesize) + /* known size of data to "upload" */ + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* treat the negative resume offset value as the case of "-" */ + if(data->state.resume_from < 0) { + if(fstat(fd, &file_stat)) { + close(fd); + failf(data, "Can't get the size of %s", file->path); + return CURLE_WRITE_ERROR; + } + data->state.resume_from = (curl_off_t)file_stat.st_size; + } + + /* Yikes! Curl_fillreadbuffer uses data->req.upload_fromhere to READ + * client data to! Please, someone fix... */ + uphere_save = data->req.upload_fromhere; + while(!result) { + size_t nread; + ssize_t nwrite; + size_t readcount; + data->req.upload_fromhere = buffer; + result = Curl_fillreadbuffer(data, sizeof(buffer), &readcount); + if(result) + break; + + if(!readcount) + break; + + nread = readcount; + + /* skip bytes before resume point */ + if(data->state.resume_from) { + if((curl_off_t)nread <= data->state.resume_from) { + data->state.resume_from -= nread; + nread = 0; + sendbuf = buffer; + } + else { + sendbuf = buffer + data->state.resume_from; + nread -= (size_t)data->state.resume_from; + data->state.resume_from = 0; + } + } + else + sendbuf = buffer; + + /* write the data to the target */ + nwrite = write(fd, sendbuf, nread); + if((size_t)nwrite != nread) { + result = CURLE_SEND_ERROR; + break; + } + + bytecount += nread; + + Curl_pgrsSetUploadCounter(data, bytecount); + + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, Curl_now()); + } + if(!result && Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + + close(fd); + data->req.upload_fromhere = uphere_save; + + return result; +} + +/* + * file_do() is the protocol-specific function for the do-phase, separated + * from the connect-phase above. Other protocols merely setup the transfer in + * the do-phase, to have it done in the main transfer loop but since some + * platforms we support don't allow select()ing etc on file handles (as + * opposed to sockets) we instead perform the whole do-operation in this + * function. + */ +static CURLcode file_do(struct Curl_easy *data, bool *done) +{ + /* This implementation ignores the host name in conformance with + RFC 1738. Only local files (reachable via the standard file system) + are supported. This means that files on remotely mounted directories + (via NFS, Samba, NT sharing) can be accessed through a file:// URL + */ + CURLcode result = CURLE_OK; + struct_stat statbuf; /* struct_stat instead of struct stat just to allow the + Windows version to have a different struct without + having to redefine the simple word 'stat' */ + curl_off_t expected_size = -1; + bool size_known; + bool fstated = FALSE; + int fd; + struct FILEPROTO *file; + + *done = TRUE; /* unconditionally */ + + if(data->state.upload) + return file_upload(data); + + file = data->req.p.file; + + /* get the fd from the connection phase */ + fd = file->fd; + + /* VMS: This only works reliable for STREAMLF files */ + if(-1 != fstat(fd, &statbuf)) { + if(!S_ISDIR(statbuf.st_mode)) + expected_size = statbuf.st_size; + /* and store the modification time */ + data->info.filetime = statbuf.st_mtime; + fstated = TRUE; + } + + if(fstated && !data->state.range && data->set.timecondition) { + if(!Curl_meets_timecondition(data, data->info.filetime)) { + *done = TRUE; + return CURLE_OK; + } + } + + if(fstated) { + time_t filetime; + struct tm buffer; + const struct tm *tm = &buffer; + char header[80]; + int headerlen; + char accept_ranges[24]= { "Accept-ranges: bytes\r\n" }; + if(expected_size >= 0) { + headerlen = msnprintf(header, sizeof(header), + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", + expected_size); + result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen); + if(result) + return result; + + result = Curl_client_write(data, CLIENTWRITE_HEADER, + accept_ranges, strlen(accept_ranges)); + if(result != CURLE_OK) + return result; + } + + filetime = (time_t)statbuf.st_mtime; + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + headerlen = msnprintf(header, sizeof(header), + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + data->req.no_body ? "": "\r\n"); + result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen); + if(result) + return result; + /* set the file size to make it available post transfer */ + Curl_pgrsSetDownloadSize(data, expected_size); + if(data->req.no_body) + return result; + } + + /* Check whether file range has been specified */ + result = Curl_range(data); + if(result) + return result; + + /* Adjust the start offset in case we want to get the N last bytes + * of the stream if the filesize could be determined */ + if(data->state.resume_from < 0) { + if(!fstated) { + failf(data, "Can't get the size of file."); + return CURLE_READ_ERROR; + } + data->state.resume_from += (curl_off_t)statbuf.st_size; + } + + if(data->state.resume_from > 0) { + /* We check explicitly if we have a start offset, because + * expected_size may be -1 if we don't know how large the file is, + * in which case we should not adjust it. */ + if(data->state.resume_from <= expected_size) + expected_size -= data->state.resume_from; + else { + failf(data, "failed to resume file:// transfer"); + return CURLE_BAD_DOWNLOAD_RESUME; + } + } + + /* A high water mark has been specified so we obey... */ + if(data->req.maxdownload > 0) + expected_size = data->req.maxdownload; + + if(!fstated || (expected_size <= 0)) + size_known = FALSE; + else + size_known = TRUE; + + /* The following is a shortcut implementation of file reading + this is both more efficient than the former call to download() and + it avoids problems with select() and recv() on file descriptors + in Winsock */ + if(size_known) + Curl_pgrsSetDownloadSize(data, expected_size); + + if(data->state.resume_from) { + if(data->state.resume_from != + lseek(fd, data->state.resume_from, SEEK_SET)) + return CURLE_BAD_DOWNLOAD_RESUME; + } + + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + + while(!result) { + char tmpbuf[8*1024]; + ssize_t nread; + /* Don't fill a whole buffer if we want less than all data */ + size_t bytestoread; + + if(size_known) { + bytestoread = (expected_size < (curl_off_t)(sizeof(tmpbuf)-1)) ? + curlx_sotouz(expected_size) : (sizeof(tmpbuf)-1); + } + else + bytestoread = sizeof(tmpbuf)-1; + + nread = read(fd, tmpbuf, bytestoread); + + if(nread > 0) + tmpbuf[nread] = 0; + + if(nread <= 0 || (size_known && (expected_size == 0))) + break; + + if(size_known) + expected_size -= nread; + + result = Curl_client_write(data, CLIENTWRITE_BODY, tmpbuf, nread); + if(result) + return result; + + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, Curl_now()); + } + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + + return result; +} + +#endif diff --git a/lib/file.h b/lib/file.h new file mode 100644 index 0000000..4565525 --- /dev/null +++ b/lib/file.h @@ -0,0 +1,42 @@ +#ifndef HEADER_CURL_FILE_H +#define HEADER_CURL_FILE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + + +/**************************************************************************** + * FILE unique setup + ***************************************************************************/ +struct FILEPROTO { + char *path; /* the path we operate on */ + char *freepath; /* pointer to the allocated block we must free, this might + differ from the 'path' pointer */ + int fd; /* open file descriptor to read from! */ +}; + +#ifndef CURL_DISABLE_FILE +extern const struct Curl_handler Curl_handler_file; +#endif + +#endif /* HEADER_CURL_FILE_H */ diff --git a/lib/fileinfo.c b/lib/fileinfo.c new file mode 100644 index 0000000..2be3b32 --- /dev/null +++ b/lib/fileinfo.c @@ -0,0 +1,46 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#ifndef CURL_DISABLE_FTP +#include "strdup.h" +#include "fileinfo.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +struct fileinfo *Curl_fileinfo_alloc(void) +{ + return calloc(1, sizeof(struct fileinfo)); +} + +void Curl_fileinfo_cleanup(struct fileinfo *finfo) +{ + if(!finfo) + return; + + Curl_dyn_free(&finfo->buf); + free(finfo); +} +#endif diff --git a/lib/fileinfo.h b/lib/fileinfo.h new file mode 100644 index 0000000..ce009da --- /dev/null +++ b/lib/fileinfo.h @@ -0,0 +1,40 @@ +#ifndef HEADER_CURL_FILEINFO_H +#define HEADER_CURL_FILEINFO_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include +#include "llist.h" +#include "dynbuf.h" + +struct fileinfo { + struct curl_fileinfo info; + struct Curl_llist_element list; + struct dynbuf buf; +}; + +struct fileinfo *Curl_fileinfo_alloc(void); +void Curl_fileinfo_cleanup(struct fileinfo *finfo); + +#endif /* HEADER_CURL_FILEINFO_H */ diff --git a/lib/fopen.c b/lib/fopen.c new file mode 100644 index 0000000..851279f --- /dev/null +++ b/lib/fopen.c @@ -0,0 +1,153 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \ + !defined(CURL_DISABLE_HSTS) + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "urldata.h" +#include "rand.h" +#include "fopen.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + The dirslash() function breaks a null-terminated pathname string into + directory and filename components then returns the directory component up + to, *AND INCLUDING*, a final '/'. If there is no directory in the path, + this instead returns a "" string. + + This function returns a pointer to malloc'ed memory. + + The input path to this function is expected to have a file name part. +*/ + +#ifdef _WIN32 +#define PATHSEP "\\" +#define IS_SEP(x) (((x) == '/') || ((x) == '\\')) +#elif defined(MSDOS) || defined(__EMX__) || defined(OS2) +#define PATHSEP "\\" +#define IS_SEP(x) ((x) == '\\') +#else +#define PATHSEP "/" +#define IS_SEP(x) ((x) == '/') +#endif + +static char *dirslash(const char *path) +{ + size_t n; + struct dynbuf out; + DEBUGASSERT(path); + Curl_dyn_init(&out, CURL_MAX_INPUT_LENGTH); + n = strlen(path); + if(n) { + /* find the rightmost path separator, if any */ + while(n && !IS_SEP(path[n-1])) + --n; + /* skip over all the path separators, if any */ + while(n && IS_SEP(path[n-1])) + --n; + } + if(Curl_dyn_addn(&out, path, n)) + return NULL; + /* if there was a directory, append a single trailing slash */ + if(n && Curl_dyn_addn(&out, PATHSEP, 1)) + return NULL; + return Curl_dyn_ptr(&out); +} + +/* + * Curl_fopen() opens a file for writing with a temp name, to be renamed + * to the final name when completed. If there is an existing file using this + * name at the time of the open, this function will clone the mode from that + * file. if 'tempname' is non-NULL, it needs a rename after the file is + * written. + */ +CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, + FILE **fh, char **tempname) +{ + CURLcode result = CURLE_WRITE_ERROR; + unsigned char randbuf[41]; + char *tempstore = NULL; + struct_stat sb; + int fd = -1; + char *dir = NULL; + *tempname = NULL; + + *fh = fopen(filename, FOPEN_WRITETEXT); + if(!*fh) + goto fail; + if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) { + return CURLE_OK; + } + fclose(*fh); + *fh = NULL; + + result = Curl_rand_alnum(data, randbuf, sizeof(randbuf)); + if(result) + goto fail; + + dir = dirslash(filename); + if(dir) { + /* The temp file name should not end up too long for the target file + system */ + tempstore = aprintf("%s%s.tmp", dir, randbuf); + free(dir); + } + + if(!tempstore) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + result = CURLE_WRITE_ERROR; + fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600|sb.st_mode); + if(fd == -1) + goto fail; + + *fh = fdopen(fd, FOPEN_WRITETEXT); + if(!*fh) + goto fail; + + *tempname = tempstore; + return CURLE_OK; + +fail: + if(fd != -1) { + close(fd); + unlink(tempstore); + } + + free(tempstore); + return result; +} + +#endif /* ! disabled */ diff --git a/lib/fopen.h b/lib/fopen.h new file mode 100644 index 0000000..e3a919d --- /dev/null +++ b/lib/fopen.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_FOPEN_H +#define HEADER_CURL_FOPEN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, + FILE **fh, char **tempname); + +#endif diff --git a/lib/formdata.c b/lib/formdata.c new file mode 100644 index 0000000..d6a1697 --- /dev/null +++ b/lib/formdata.c @@ -0,0 +1,958 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "formdata.h" +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API) + +#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) +#include +#endif + +#include "urldata.h" /* for struct Curl_easy */ +#include "mime.h" +#include "vtls/vtls.h" +#include "strcase.h" +#include "sendf.h" +#include "strdup.h" +#include "rand.h" +#include "warnless.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME +#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME +#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS +#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE +#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER +#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK +#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER + +/*************************************************************************** + * + * AddHttpPost() + * + * Adds an HttpPost structure to the list, if parent_post is given becomes + * a subpost of parent_post instead of a direct list element. + * + * Returns newly allocated HttpPost on success and NULL if malloc failed. + * + ***************************************************************************/ +static struct curl_httppost * +AddHttpPost(char *name, size_t namelength, + char *value, curl_off_t contentslength, + char *buffer, size_t bufferlength, + char *contenttype, + long flags, + struct curl_slist *contentHeader, + char *showfilename, char *userp, + struct curl_httppost *parent_post, + struct curl_httppost **httppost, + struct curl_httppost **last_post) +{ + struct curl_httppost *post; + if(!namelength && name) + namelength = strlen(name); + if((bufferlength > LONG_MAX) || (namelength > LONG_MAX)) + /* avoid overflow in typecasts below */ + return NULL; + post = calloc(1, sizeof(struct curl_httppost)); + if(post) { + post->name = name; + post->namelength = (long)namelength; + post->contents = value; + post->contentlen = contentslength; + post->buffer = buffer; + post->bufferlength = (long)bufferlength; + post->contenttype = contenttype; + post->contentheader = contentHeader; + post->showfilename = showfilename; + post->userp = userp; + post->flags = flags | CURL_HTTPPOST_LARGE; + } + else + return NULL; + + if(parent_post) { + /* now, point our 'more' to the original 'more' */ + post->more = parent_post->more; + + /* then move the original 'more' to point to ourselves */ + parent_post->more = post; + } + else { + /* make the previous point to this */ + if(*last_post) + (*last_post)->next = post; + else + (*httppost) = post; + + (*last_post) = post; + } + return post; +} + +/*************************************************************************** + * + * AddFormInfo() + * + * Adds a FormInfo structure to the list presented by parent_form_info. + * + * Returns newly allocated FormInfo on success and NULL if malloc failed/ + * parent_form_info is NULL. + * + ***************************************************************************/ +static struct FormInfo *AddFormInfo(char *value, + char *contenttype, + struct FormInfo *parent_form_info) +{ + struct FormInfo *form_info; + form_info = calloc(1, sizeof(struct FormInfo)); + if(!form_info) + return NULL; + if(value) + form_info->value = value; + if(contenttype) + form_info->contenttype = contenttype; + form_info->flags = HTTPPOST_FILENAME; + + if(parent_form_info) { + /* now, point our 'more' to the original 'more' */ + form_info->more = parent_form_info->more; + + /* then move the original 'more' to point to ourselves */ + parent_form_info->more = form_info; + } + + return form_info; +} + +/*************************************************************************** + * + * FormAdd() + * + * Stores a formpost parameter and builds the appropriate linked list. + * + * Has two principal functionalities: using files and byte arrays as + * post parts. Byte arrays are either copied or just the pointer is stored + * (as the user requests) while for files only the filename and not the + * content is stored. + * + * While you may have only one byte array for each name, multiple filenames + * are allowed (and because of this feature CURLFORM_END is needed after + * using CURLFORM_FILE). + * + * Examples: + * + * Simple name/value pair with copied contents: + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); + * + * name/value pair where only the content pointer is remembered: + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); + * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) + * + * storing a filename (CONTENTTYPE is optional!): + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", + * CURLFORM_END); + * + * storing multiple filenames: + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if an HttpPost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ + +static +CURLFORMcode FormAdd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + va_list params) +{ + struct FormInfo *first_form, *current_form, *form = NULL; + CURLFORMcode return_value = CURL_FORMADD_OK; + const char *prevtype = NULL; + struct curl_httppost *post = NULL; + CURLformoption option; + struct curl_forms *forms = NULL; + char *array_value = NULL; /* value read from an array */ + + /* This is a state variable, that if TRUE means that we're parsing an + array that we got passed to us. If FALSE we're parsing the input + va_list arguments. */ + bool array_state = FALSE; + + /* + * We need to allocate the first struct to fill in. + */ + first_form = calloc(1, sizeof(struct FormInfo)); + if(!first_form) + return CURL_FORMADD_MEMORY; + + current_form = first_form; + + /* + * Loop through all the options set. Break if we have an error to report. + */ + while(return_value == CURL_FORMADD_OK) { + + /* first see if we have more parts of the array param */ + if(array_state && forms) { + /* get the upcoming option from the given array */ + option = forms->option; + array_value = (char *)forms->value; + + forms++; /* advance this to next entry */ + if(CURLFORM_END == option) { + /* end of array state */ + array_state = FALSE; + continue; + } + } + else { + /* This is not array-state, get next option. This gets an 'int' with + va_arg() because CURLformoption might be a smaller type than int and + might cause compiler warnings and wrong behavior. */ + option = (CURLformoption)va_arg(params, int); + if(CURLFORM_END == option) + break; + } + + switch(option) { + case CURLFORM_ARRAY: + if(array_state) + /* we don't support an array from within an array */ + return_value = CURL_FORMADD_ILLEGAL_ARRAY; + else { + forms = va_arg(params, struct curl_forms *); + if(forms) + array_state = TRUE; + else + return_value = CURL_FORMADD_NULL; + } + break; + + /* + * Set the Name property. + */ + case CURLFORM_PTRNAME: + current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ + + FALLTHROUGH(); + case CURLFORM_COPYNAME: + if(current_form->name) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *name = array_state? + array_value:va_arg(params, char *); + if(name) + current_form->name = name; /* store for the moment */ + else + return_value = CURL_FORMADD_NULL; + } + break; + case CURLFORM_NAMELENGTH: + if(current_form->namelength) + return_value = CURL_FORMADD_OPTION_TWICE; + else + current_form->namelength = + array_state?(size_t)array_value:(size_t)va_arg(params, long); + break; + + /* + * Set the contents property. + */ + case CURLFORM_PTRCONTENTS: + current_form->flags |= HTTPPOST_PTRCONTENTS; + FALLTHROUGH(); + case CURLFORM_COPYCONTENTS: + if(current_form->value) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *value = + array_state?array_value:va_arg(params, char *); + if(value) + current_form->value = value; /* store for the moment */ + else + return_value = CURL_FORMADD_NULL; + } + break; + case CURLFORM_CONTENTSLENGTH: + current_form->contentslength = + array_state?(size_t)array_value:(size_t)va_arg(params, long); + break; + + case CURLFORM_CONTENTLEN: + current_form->flags |= CURL_HTTPPOST_LARGE; + current_form->contentslength = + array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t); + break; + + /* Get contents from a given file name */ + case CURLFORM_FILECONTENT: + if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + const char *filename = array_state? + array_value:va_arg(params, char *); + if(filename) { + current_form->value = strdup(filename); + if(!current_form->value) + return_value = CURL_FORMADD_MEMORY; + else { + current_form->flags |= HTTPPOST_READFILE; + current_form->value_alloc = TRUE; + } + } + else + return_value = CURL_FORMADD_NULL; + } + break; + + /* We upload a file */ + case CURLFORM_FILE: + { + const char *filename = array_state?array_value: + va_arg(params, char *); + + if(current_form->value) { + if(current_form->flags & HTTPPOST_FILENAME) { + if(filename) { + char *fname = strdup(filename); + if(!fname) + return_value = CURL_FORMADD_MEMORY; + else { + form = AddFormInfo(fname, NULL, current_form); + if(!form) { + free(fname); + return_value = CURL_FORMADD_MEMORY; + } + else { + form->value_alloc = TRUE; + current_form = form; + form = NULL; + } + } + } + else + return_value = CURL_FORMADD_NULL; + } + else + return_value = CURL_FORMADD_OPTION_TWICE; + } + else { + if(filename) { + current_form->value = strdup(filename); + if(!current_form->value) + return_value = CURL_FORMADD_MEMORY; + else { + current_form->flags |= HTTPPOST_FILENAME; + current_form->value_alloc = TRUE; + } + } + else + return_value = CURL_FORMADD_NULL; + } + break; + } + + case CURLFORM_BUFFERPTR: + current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; + if(current_form->buffer) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *buffer = + array_state?array_value:va_arg(params, char *); + if(buffer) { + current_form->buffer = buffer; /* store for the moment */ + current_form->value = buffer; /* make it non-NULL to be accepted + as fine */ + } + else + return_value = CURL_FORMADD_NULL; + } + break; + + case CURLFORM_BUFFERLENGTH: + if(current_form->bufferlength) + return_value = CURL_FORMADD_OPTION_TWICE; + else + current_form->bufferlength = + array_state?(size_t)array_value:(size_t)va_arg(params, long); + break; + + case CURLFORM_STREAM: + current_form->flags |= HTTPPOST_CALLBACK; + if(current_form->userp) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *userp = + array_state?array_value:va_arg(params, char *); + if(userp) { + current_form->userp = userp; + current_form->value = userp; /* this isn't strictly true but we + derive a value from this later on + and we need this non-NULL to be + accepted as a fine form part */ + } + else + return_value = CURL_FORMADD_NULL; + } + break; + + case CURLFORM_CONTENTTYPE: + { + const char *contenttype = + array_state?array_value:va_arg(params, char *); + if(current_form->contenttype) { + if(current_form->flags & HTTPPOST_FILENAME) { + if(contenttype) { + char *type = strdup(contenttype); + if(!type) + return_value = CURL_FORMADD_MEMORY; + else { + form = AddFormInfo(NULL, type, current_form); + if(!form) { + free(type); + return_value = CURL_FORMADD_MEMORY; + } + else { + form->contenttype_alloc = TRUE; + current_form = form; + form = NULL; + } + } + } + else + return_value = CURL_FORMADD_NULL; + } + else + return_value = CURL_FORMADD_OPTION_TWICE; + } + else { + if(contenttype) { + current_form->contenttype = strdup(contenttype); + if(!current_form->contenttype) + return_value = CURL_FORMADD_MEMORY; + else + current_form->contenttype_alloc = TRUE; + } + else + return_value = CURL_FORMADD_NULL; + } + break; + } + case CURLFORM_CONTENTHEADER: + { + /* this "cast increases required alignment of target type" but + we consider it OK anyway */ + struct curl_slist *list = array_state? + (struct curl_slist *)(void *)array_value: + va_arg(params, struct curl_slist *); + + if(current_form->contentheader) + return_value = CURL_FORMADD_OPTION_TWICE; + else + current_form->contentheader = list; + + break; + } + case CURLFORM_FILENAME: + case CURLFORM_BUFFER: + { + const char *filename = array_state?array_value: + va_arg(params, char *); + if(current_form->showfilename) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + current_form->showfilename = strdup(filename); + if(!current_form->showfilename) + return_value = CURL_FORMADD_MEMORY; + else + current_form->showfilename_alloc = TRUE; + } + break; + } + default: + return_value = CURL_FORMADD_UNKNOWN_OPTION; + break; + } + } + + if(CURL_FORMADD_OK != return_value) { + /* On error, free allocated fields for all nodes of the FormInfo linked + list without deallocating nodes. List nodes are deallocated later on */ + struct FormInfo *ptr; + for(ptr = first_form; ptr != NULL; ptr = ptr->more) { + if(ptr->name_alloc) { + Curl_safefree(ptr->name); + ptr->name_alloc = FALSE; + } + if(ptr->value_alloc) { + Curl_safefree(ptr->value); + ptr->value_alloc = FALSE; + } + if(ptr->contenttype_alloc) { + Curl_safefree(ptr->contenttype); + ptr->contenttype_alloc = FALSE; + } + if(ptr->showfilename_alloc) { + Curl_safefree(ptr->showfilename); + ptr->showfilename_alloc = FALSE; + } + } + } + + if(CURL_FORMADD_OK == return_value) { + /* go through the list, check for completeness and if everything is + * alright add the HttpPost item otherwise set return_value accordingly */ + + post = NULL; + for(form = first_form; + form != NULL; + form = form->more) { + if(((!form->name || !form->value) && !post) || + ( (form->contentslength) && + (form->flags & HTTPPOST_FILENAME) ) || + ( (form->flags & HTTPPOST_FILENAME) && + (form->flags & HTTPPOST_PTRCONTENTS) ) || + + ( (!form->buffer) && + (form->flags & HTTPPOST_BUFFER) && + (form->flags & HTTPPOST_PTRBUFFER) ) || + + ( (form->flags & HTTPPOST_READFILE) && + (form->flags & HTTPPOST_PTRCONTENTS) ) + ) { + return_value = CURL_FORMADD_INCOMPLETE; + break; + } + if(((form->flags & HTTPPOST_FILENAME) || + (form->flags & HTTPPOST_BUFFER)) && + !form->contenttype) { + char *f = (form->flags & HTTPPOST_BUFFER)? + form->showfilename : form->value; + char const *type; + type = Curl_mime_contenttype(f); + if(!type) + type = prevtype; + if(!type) + type = FILE_CONTENTTYPE_DEFAULT; + + /* our contenttype is missing */ + form->contenttype = strdup(type); + if(!form->contenttype) { + return_value = CURL_FORMADD_MEMORY; + break; + } + form->contenttype_alloc = TRUE; + } + if(form->name && form->namelength) { + /* Name should not contain nul bytes. */ + size_t i; + for(i = 0; i < form->namelength; i++) + if(!form->name[i]) { + return_value = CURL_FORMADD_NULL; + break; + } + if(return_value != CURL_FORMADD_OK) + break; + } + if(!(form->flags & HTTPPOST_PTRNAME) && + (form == first_form) ) { + /* Note that there's small risk that form->name is NULL here if the + app passed in a bad combo, so we better check for that first. */ + if(form->name) { + /* copy name (without strdup; possibly not null-terminated) */ + form->name = Curl_memdup0(form->name, form->namelength? + form->namelength: + strlen(form->name)); + } + if(!form->name) { + return_value = CURL_FORMADD_MEMORY; + break; + } + form->name_alloc = TRUE; + } + if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | + HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | + HTTPPOST_CALLBACK)) && form->value) { + /* copy value (without strdup; possibly contains null characters) */ + size_t clen = (size_t) form->contentslength; + if(!clen) + clen = strlen(form->value) + 1; + + form->value = Curl_memdup(form->value, clen); + + if(!form->value) { + return_value = CURL_FORMADD_MEMORY; + break; + } + form->value_alloc = TRUE; + } + post = AddHttpPost(form->name, form->namelength, + form->value, form->contentslength, + form->buffer, form->bufferlength, + form->contenttype, form->flags, + form->contentheader, form->showfilename, + form->userp, + post, httppost, + last_post); + + if(!post) { + return_value = CURL_FORMADD_MEMORY; + break; + } + + if(form->contenttype) + prevtype = form->contenttype; + } + if(CURL_FORMADD_OK != return_value) { + /* On error, free allocated fields for nodes of the FormInfo linked + list which are not already owned by the httppost linked list + without deallocating nodes. List nodes are deallocated later on */ + struct FormInfo *ptr; + for(ptr = form; ptr != NULL; ptr = ptr->more) { + if(ptr->name_alloc) { + Curl_safefree(ptr->name); + ptr->name_alloc = FALSE; + } + if(ptr->value_alloc) { + Curl_safefree(ptr->value); + ptr->value_alloc = FALSE; + } + if(ptr->contenttype_alloc) { + Curl_safefree(ptr->contenttype); + ptr->contenttype_alloc = FALSE; + } + if(ptr->showfilename_alloc) { + Curl_safefree(ptr->showfilename); + ptr->showfilename_alloc = FALSE; + } + } + } + } + + /* Always deallocate FormInfo linked list nodes without touching node + fields given that these have either been deallocated or are owned + now by the httppost linked list */ + while(first_form) { + struct FormInfo *ptr = first_form->more; + free(first_form); + first_form = ptr; + } + + return return_value; +} + +/* + * curl_formadd() is a public API to add a section to the multipart formpost. + * + * @unittest: 1308 + */ + +CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...) +{ + va_list arg; + CURLFORMcode result; + va_start(arg, last_post); + result = FormAdd(httppost, last_post, arg); + va_end(arg); + return result; +} + +/* + * curl_formget() + * Serialize a curl_httppost struct. + * Returns 0 on success. + * + * @unittest: 1308 + */ +int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append) +{ + CURLcode result; + curl_mimepart toppart; + + Curl_mime_initpart(&toppart); /* default form is empty */ + result = Curl_getformdata(NULL, &toppart, form, NULL); + if(!result) + result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data", + NULL, MIMESTRATEGY_FORM); + + while(!result) { + char buffer[8192]; + size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart); + + if(!nread) + break; + + if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) { + result = CURLE_READ_ERROR; + if(nread == CURL_READFUNC_ABORT) + result = CURLE_ABORTED_BY_CALLBACK; + } + } + + Curl_mime_cleanpart(&toppart); + return (int) result; +} + +/* + * curl_formfree() is an external function to free up a whole form post + * chain + */ +void curl_formfree(struct curl_httppost *form) +{ + struct curl_httppost *next; + + if(!form) + /* no form to free, just get out of this */ + return; + + do { + next = form->next; /* the following form line */ + + /* recurse to sub-contents */ + curl_formfree(form->more); + + if(!(form->flags & HTTPPOST_PTRNAME)) + free(form->name); /* free the name */ + if(!(form->flags & + (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) + ) + free(form->contents); /* free the contents */ + free(form->contenttype); /* free the content type */ + free(form->showfilename); /* free the faked file name */ + free(form); /* free the struct */ + form = next; + } while(form); /* continue */ +} + + +/* Set mime part name, taking care of non null-terminated name string. */ +static CURLcode setname(curl_mimepart *part, const char *name, size_t len) +{ + char *zname; + CURLcode res; + + if(!name || !len) + return curl_mime_name(part, name); + zname = Curl_memdup0(name, len); + if(!zname) + return CURLE_OUT_OF_MEMORY; + res = curl_mime_name(part, zname); + free(zname); + return res; +} + +/* wrap call to fseeko so it matches the calling convention of callback */ +static int fseeko_wrapper(void *stream, curl_off_t offset, int whence) +{ +#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO) + return fseeko(stream, (off_t)offset, whence); +#elif defined(HAVE__FSEEKI64) + return _fseeki64(stream, (__int64)offset, whence); +#else + if(offset > LONG_MAX) + return -1; + return fseek(stream, (long)offset, whence); +#endif +} + +/* + * Curl_getformdata() converts a linked list of "meta data" into a mime + * structure. The input list is in 'post', while the output is stored in + * mime part at '*finalform'. + * + * This function will not do a failf() for the potential memory failures but + * should for all other errors it spots. Just note that this function MAY get + * a NULL pointer in the 'data' argument. + */ + +CURLcode Curl_getformdata(struct Curl_easy *data, + curl_mimepart *finalform, + struct curl_httppost *post, + curl_read_callback fread_func) +{ + CURLcode result = CURLE_OK; + curl_mime *form = NULL; + curl_mimepart *part; + struct curl_httppost *file; + + Curl_mime_cleanpart(finalform); /* default form is empty */ + + if(!post) + return result; /* no input => no output! */ + + form = curl_mime_init(data); + if(!form) + result = CURLE_OUT_OF_MEMORY; + + if(!result) + result = curl_mime_subparts(finalform, form); + + /* Process each top part. */ + for(; !result && post; post = post->next) { + /* If we have more than a file here, create a mime subpart and fill it. */ + curl_mime *multipart = form; + if(post->more) { + part = curl_mime_addpart(form); + if(!part) + result = CURLE_OUT_OF_MEMORY; + if(!result) + result = setname(part, post->name, post->namelength); + if(!result) { + multipart = curl_mime_init(data); + if(!multipart) + result = CURLE_OUT_OF_MEMORY; + } + if(!result) + result = curl_mime_subparts(part, multipart); + } + + /* Generate all the part contents. */ + for(file = post; !result && file; file = file->more) { + /* Create the part. */ + part = curl_mime_addpart(multipart); + if(!part) + result = CURLE_OUT_OF_MEMORY; + + /* Set the headers. */ + if(!result) + result = curl_mime_headers(part, file->contentheader, 0); + + /* Set the content type. */ + if(!result && file->contenttype) + result = curl_mime_type(part, file->contenttype); + + /* Set field name. */ + if(!result && !post->more) + result = setname(part, post->name, post->namelength); + + /* Process contents. */ + if(!result) { + curl_off_t clen = post->contentslength; + + if(post->flags & CURL_HTTPPOST_LARGE) + clen = post->contentlen; + + if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) { + if(!strcmp(file->contents, "-")) { + /* There are a few cases where the code below won't work; in + particular, freopen(stdin) by the caller is not guaranteed + to result as expected. This feature has been kept for backward + compatibility: use of "-" pseudo file name should be avoided. */ + result = curl_mime_data_cb(part, (curl_off_t) -1, + (curl_read_callback) fread, + fseeko_wrapper, + NULL, (void *) stdin); + } + else + result = curl_mime_filedata(part, file->contents); + if(!result && (post->flags & HTTPPOST_READFILE)) + result = curl_mime_filename(part, NULL); + } + else if(post->flags & HTTPPOST_BUFFER) + result = curl_mime_data(part, post->buffer, + post->bufferlength? post->bufferlength: -1); + else if(post->flags & HTTPPOST_CALLBACK) { + /* the contents should be read with the callback and the size is set + with the contentslength */ + if(!clen) + clen = -1; + result = curl_mime_data_cb(part, clen, + fread_func, NULL, NULL, post->userp); + } + else { + size_t uclen; + if(!clen) + uclen = CURL_ZERO_TERMINATED; + else + uclen = (size_t)clen; + result = curl_mime_data(part, post->contents, uclen); + } + } + + /* Set fake file name. */ + if(!result && post->showfilename) + if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER | + HTTPPOST_CALLBACK))) + result = curl_mime_filename(part, post->showfilename); + } + } + + if(result) + Curl_mime_cleanpart(finalform); + + return result; +} + +#else +/* if disabled */ +CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...) +{ + (void)httppost; + (void)last_post; + return CURL_FORMADD_DISABLED; +} + +int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append) +{ + (void) form; + (void) arg; + (void) append; + return CURL_FORMADD_DISABLED; +} + +void curl_formfree(struct curl_httppost *form) +{ + (void)form; + /* Nothing to do. */ +} + +#endif /* if disabled */ diff --git a/lib/formdata.h b/lib/formdata.h new file mode 100644 index 0000000..af46624 --- /dev/null +++ b/lib/formdata.h @@ -0,0 +1,59 @@ +#ifndef HEADER_CURL_FORMDATA_H +#define HEADER_CURL_FORMDATA_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_FORM_API + +/* used by FormAdd for temporary storage */ +struct FormInfo { + char *name; + size_t namelength; + char *value; + curl_off_t contentslength; + char *contenttype; + long flags; + char *buffer; /* pointer to existing buffer used for file upload */ + size_t bufferlength; + char *showfilename; /* The file name to show. If not set, the actual + file name will be used */ + char *userp; /* pointer for the read callback */ + struct curl_slist *contentheader; + struct FormInfo *more; + bool name_alloc; + bool value_alloc; + bool contenttype_alloc; + bool showfilename_alloc; +}; + +CURLcode Curl_getformdata(struct Curl_easy *data, + curl_mimepart *, + struct curl_httppost *post, + curl_read_callback fread_func); +#endif /* CURL_DISABLE_FORM_API */ + + +#endif /* HEADER_CURL_FORMDATA_H */ diff --git a/lib/ftp.c b/lib/ftp.c new file mode 100644 index 0000000..f621082 --- /dev/null +++ b/lib/ftp.c @@ -0,0 +1,4437 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_FTP + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "if2ip.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "ftp.h" +#include "fileinfo.h" +#include "ftplistparser.h" +#include "curl_range.h" +#include "curl_krb5.h" +#include "strtoofft.h" +#include "strcase.h" +#include "vtls/vtls.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "connect.h" +#include "strerror.h" +#include "inet_ntop.h" +#include "inet_pton.h" +#include "select.h" +#include "parsedate.h" /* for the week day and month names */ +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "multiif.h" +#include "url.h" +#include "speedcheck.h" +#include "warnless.h" +#include "http_proxy.h" +#include "socks.h" +#include "strdup.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif + +#ifdef CURL_DISABLE_VERBOSE_STRINGS +#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt +#endif + +/* Local API functions */ +#ifndef DEBUGBUILD +static void _ftp_state(struct Curl_easy *data, + ftpstate newstate); +#define ftp_state(x,y) _ftp_state(x,y) +#else +static void _ftp_state(struct Curl_easy *data, + ftpstate newstate, + int lineno); +#define ftp_state(x,y) _ftp_state(x,y,__LINE__) +#endif + +static CURLcode ftp_sendquote(struct Curl_easy *data, + struct connectdata *conn, + struct curl_slist *quote); +static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn); +static CURLcode ftp_parse_url_path(struct Curl_easy *data); +static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done); +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void ftp_pasv_verbose(struct Curl_easy *data, + struct Curl_addrinfo *ai, + char *newhost, /* ascii version */ + int port); +#endif +static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data); +static CURLcode ftp_state_mdtm(struct Curl_easy *data); +static CURLcode ftp_state_quote(struct Curl_easy *data, + bool init, ftpstate instate); +static CURLcode ftp_nb_type(struct Curl_easy *data, + struct connectdata *conn, + bool ascii, ftpstate newstate); +static int ftp_need_type(struct connectdata *conn, + bool ascii); +static CURLcode ftp_do(struct Curl_easy *data, bool *done); +static CURLcode ftp_done(struct Curl_easy *data, + CURLcode, bool premature); +static CURLcode ftp_connect(struct Curl_easy *data, bool *done); +static CURLcode ftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection); +static CURLcode ftp_do_more(struct Curl_easy *data, int *completed); +static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done); +static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks); +static int ftp_domore_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); +static CURLcode ftp_doing(struct Curl_easy *data, + bool *dophase_done); +static CURLcode ftp_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static CURLcode init_wc_data(struct Curl_easy *data); +static CURLcode wc_statemach(struct Curl_easy *data); +static void wc_data_dtor(void *ptr); +static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize); +static CURLcode ftp_readresp(struct Curl_easy *data, + curl_socket_t sockfd, + struct pingpong *pp, + int *ftpcode, + size_t *size); +static CURLcode ftp_dophase_done(struct Curl_easy *data, + bool connected); + +/* + * FTP protocol handler. + */ + +const struct Curl_handler Curl_handler_ftp = { + "FTP", /* scheme */ + ftp_setup_connection, /* setup_connection */ + ftp_do, /* do_it */ + ftp_done, /* done */ + ftp_do_more, /* do_more */ + ftp_connect, /* connect_it */ + ftp_multi_statemach, /* connecting */ + ftp_doing, /* doing */ + ftp_getsock, /* proto_getsock */ + ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ftp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_FTP, /* defport */ + CURLPROTO_FTP, /* protocol */ + CURLPROTO_FTP, /* family */ + PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | + PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP | + PROTOPT_WILDCARD /* flags */ +}; + + +#ifdef USE_SSL +/* + * FTPS protocol handler. + */ + +const struct Curl_handler Curl_handler_ftps = { + "FTPS", /* scheme */ + ftp_setup_connection, /* setup_connection */ + ftp_do, /* do_it */ + ftp_done, /* done */ + ftp_do_more, /* do_more */ + ftp_connect, /* connect_it */ + ftp_multi_statemach, /* connecting */ + ftp_doing, /* doing */ + ftp_getsock, /* proto_getsock */ + ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ftp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_FTPS, /* defport */ + CURLPROTO_FTPS, /* protocol */ + CURLPROTO_FTP, /* family */ + PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | + PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */ +}; +#endif + +static void close_secondarysocket(struct Curl_easy *data, + struct connectdata *conn) +{ + Curl_conn_close(data, SECONDARYSOCKET); + Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET); +} + +/* + * NOTE: back in the old days, we added code in the FTP code that made NOBODY + * requests on files respond with headers passed to the client/stdout that + * looked like HTTP ones. + * + * This approach is not very elegant, it causes confusion and is error-prone. + * It is subject for removal at the next (or at least a future) soname bump. + * Until then you can test the effects of the removal by undefining the + * following define named CURL_FTP_HTTPSTYLE_HEAD. + */ +#define CURL_FTP_HTTPSTYLE_HEAD 1 + +static void freedirs(struct ftp_conn *ftpc) +{ + if(ftpc->dirs) { + int i; + for(i = 0; i < ftpc->dirdepth; i++) { + free(ftpc->dirs[i]); + ftpc->dirs[i] = NULL; + } + free(ftpc->dirs); + ftpc->dirs = NULL; + ftpc->dirdepth = 0; + } + Curl_safefree(ftpc->file); + + /* no longer of any use */ + Curl_safefree(ftpc->newhost); +} + +/*********************************************************************** + * + * AcceptServerConnect() + * + * After connection request is received from the server this function is + * called to accept the connection and close the listening socket + * + */ +static CURLcode AcceptServerConnect(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + curl_socket_t sock = conn->sock[SECONDARYSOCKET]; + curl_socket_t s = CURL_SOCKET_BAD; +#ifdef ENABLE_IPV6 + struct Curl_sockaddr_storage add; +#else + struct sockaddr_in add; +#endif + curl_socklen_t size = (curl_socklen_t) sizeof(add); + CURLcode result; + + if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { + size = sizeof(add); + + s = accept(sock, (struct sockaddr *) &add, &size); + } + + if(CURL_SOCKET_BAD == s) { + failf(data, "Error accept()ing server connect"); + return CURLE_FTP_PORT_FAILED; + } + infof(data, "Connection accepted from server"); + /* when this happens within the DO state it is important that we mark us as + not needing DO_MORE anymore */ + conn->bits.do_more = FALSE; + + (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ + /* Replace any filter on SECONDARY with one listening on this socket */ + result = Curl_conn_tcp_accepted_set(data, conn, SECONDARYSOCKET, &s); + if(result) + return result; + + if(data->set.fsockopt) { + int error = 0; + + /* activate callback for setting socket options */ + Curl_set_in_callback(data, true); + error = data->set.fsockopt(data->set.sockopt_client, + s, + CURLSOCKTYPE_ACCEPT); + Curl_set_in_callback(data, false); + + if(error) { + close_secondarysocket(data, conn); + return CURLE_ABORTED_BY_CALLBACK; + } + } + + return CURLE_OK; + +} + +/* + * ftp_timeleft_accept() returns the amount of milliseconds left allowed for + * waiting server to connect. If the value is negative, the timeout time has + * already elapsed. + * + * The start time is stored in progress.t_acceptdata - as set with + * Curl_pgrsTime(..., TIMER_STARTACCEPT); + * + */ +static timediff_t ftp_timeleft_accept(struct Curl_easy *data) +{ + timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT; + timediff_t other; + struct curltime now; + + if(data->set.accepttimeout > 0) + timeout_ms = data->set.accepttimeout; + + now = Curl_now(); + + /* check if the generic timeout possibly is set shorter */ + other = Curl_timeleft(data, &now, FALSE); + if(other && (other < timeout_ms)) + /* note that this also works fine for when other happens to be negative + due to it already having elapsed */ + timeout_ms = other; + else { + /* subtract elapsed time */ + timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata); + if(!timeout_ms) + /* avoid returning 0 as that means no timeout! */ + return -1; + } + + return timeout_ms; +} + + +/*********************************************************************** + * + * ReceivedServerConnect() + * + * After allowing server to connect to us from data port, this function + * checks both data connection for connection establishment and ctrl + * connection for a negative response regarding a failure in connecting + * + */ +static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received) +{ + struct connectdata *conn = data->conn; + curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; + curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + int socketstate = 0; + timediff_t timeout_ms; + ssize_t nread; + int ftpcode; + bool response = FALSE; + + *received = FALSE; + + timeout_ms = ftp_timeleft_accept(data); + infof(data, "Checking for server connect"); + if(timeout_ms < 0) { + /* if a timeout was already reached, bail out */ + failf(data, "Accept timeout occurred while waiting server connect"); + return CURLE_FTP_ACCEPT_TIMEOUT; + } + + /* First check whether there is a cached response from server */ + if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) { + /* Data connection could not be established, let's return */ + infof(data, "There is negative response in cache while serv connect"); + (void)Curl_GetFTPResponse(data, &nread, &ftpcode); + return CURLE_FTP_ACCEPT_FAILED; + } + + if(pp->overflow) + /* there is pending control data still in the buffer to read */ + response = TRUE; + else + socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); + + /* see if the connection request is already here */ + switch(socketstate) { + case -1: /* error */ + /* let's die here */ + failf(data, "Error while waiting for server connect"); + return CURLE_FTP_ACCEPT_FAILED; + case 0: /* Server connect is not received yet */ + break; /* loop */ + default: + if(socketstate & CURL_CSELECT_IN2) { + infof(data, "Ready to accept data connection from server"); + *received = TRUE; + } + else if(socketstate & CURL_CSELECT_IN) + response = TRUE; + break; + } + if(response) { + infof(data, "Ctrl conn has data while waiting for data conn"); + (void)Curl_GetFTPResponse(data, &nread, &ftpcode); + + if(ftpcode/100 > 3) + return CURLE_FTP_ACCEPT_FAILED; + + return CURLE_WEIRD_SERVER_REPLY; + } + + return CURLE_OK; +} + + +/*********************************************************************** + * + * InitiateTransfer() + * + * After connection from server is accepted this function is called to + * setup transfer parameters and initiate the data transfer. + * + */ +static CURLcode InitiateTransfer(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + bool connected; + + DEBUGF(infof(data, "ftp InitiateTransfer()")); + if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port && + !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) { + result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET); + if(result) + return result; + } + result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected); + if(result || !connected) + return result; + + if(conn->proto.ftpc.state_saved == FTP_STOR) { + /* When we know we're uploading a specified file, we can get the file + size prior to the actual upload. */ + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* set the SO_SNDBUF for the secondary socket for those who need it */ + Curl_sndbufset(conn->sock[SECONDARYSOCKET]); + + Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET); + } + else { + /* FTP download: */ + Curl_setup_transfer(data, SECONDARYSOCKET, + conn->proto.ftpc.retr_size_saved, FALSE, -1); + } + + conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ + ftp_state(data, FTP_STOP); + + return CURLE_OK; +} + +/*********************************************************************** + * + * AllowServerConnect() + * + * When we've issue the PORT command, we have told the server to connect to + * us. This function checks whether data connection is established if so it is + * accepted. + * + */ +static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected) +{ + timediff_t timeout_ms; + CURLcode result = CURLE_OK; + + *connected = FALSE; + infof(data, "Preparing for accepting server on data port"); + + /* Save the time we start accepting server connect */ + Curl_pgrsTime(data, TIMER_STARTACCEPT); + + timeout_ms = ftp_timeleft_accept(data); + if(timeout_ms < 0) { + /* if a timeout was already reached, bail out */ + failf(data, "Accept timeout occurred while waiting server connect"); + result = CURLE_FTP_ACCEPT_TIMEOUT; + goto out; + } + + /* see if the connection request is already here */ + result = ReceivedServerConnect(data, connected); + if(result) + goto out; + + if(*connected) { + result = AcceptServerConnect(data); + if(result) + goto out; + + result = InitiateTransfer(data); + if(result) + goto out; + } + else { + /* Add timeout to multi handle and break out of the loop */ + Curl_expire(data, data->set.accepttimeout ? + data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, + EXPIRE_FTP_ACCEPT); + } + +out: + DEBUGF(infof(data, "ftp AllowServerConnect() -> %d", result)); + return result; +} + +/* macro to check for a three-digit ftp status code at the start of the + given string */ +#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ + ISDIGIT(line[2])) + +/* macro to check for the last line in an FTP server response */ +#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) + +static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn, + char *line, size_t len, int *code) +{ + (void)data; + (void)conn; + + if((len > 3) && LASTLINE(line)) { + *code = curlx_sltosi(strtol(line, NULL, 10)); + return TRUE; + } + + return FALSE; +} + +static CURLcode ftp_readresp(struct Curl_easy *data, + curl_socket_t sockfd, + struct pingpong *pp, + int *ftpcode, /* return the ftp-code if done */ + size_t *size) /* size of the response */ +{ + int code; + CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size); + +#ifdef HAVE_GSSAPI + { + struct connectdata *conn = data->conn; + char * const buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf); + + /* handle the security-oriented responses 6xx ***/ + switch(code) { + case 631: + code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE); + break; + case 632: + code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE); + break; + case 633: + code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL); + break; + default: + /* normal ftp stuff we pass through! */ + break; + } + } +#endif + + /* store the latest code for later retrieval */ + data->info.httpcode = code; + + if(ftpcode) + *ftpcode = code; + + if(421 == code) { + /* 421 means "Service not available, closing control connection." and FTP + * servers use it to signal that idle session timeout has been exceeded. + * If we ignored the response, it could end up hanging in some cases. + * + * This response code can come at any point so having it treated + * generically is a good idea. + */ + infof(data, "We got a 421 - timeout"); + ftp_state(data, FTP_STOP); + return CURLE_OPERATION_TIMEDOUT; + } + + return result; +} + +/* --- parse FTP server responses --- */ + +/* + * Curl_GetFTPResponse() is a BLOCKING function to read the full response + * from a server after a command. + * + */ + +CURLcode Curl_GetFTPResponse(struct Curl_easy *data, + ssize_t *nreadp, /* return number of bytes read */ + int *ftpcode) /* return the ftp-code */ +{ + /* + * We cannot read just one byte per read() and then go back to select() as + * the OpenSSL read() doesn't grok that properly. + * + * Alas, read as much as possible, split up into lines, use the ending + * line in a response or continue reading. */ + + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + size_t nread; + int cache_skip = 0; + int value_to_be_ignored = 0; + + if(ftpcode) + *ftpcode = 0; /* 0 for errors */ + else + /* make the pointer point to something for the rest of this function */ + ftpcode = &value_to_be_ignored; + + *nreadp = 0; + + while(!*ftpcode && !result) { + /* check and reset timeout value every lap */ + timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE); + timediff_t interval_ms; + + if(timeout <= 0) { + failf(data, "FTP response timeout"); + return CURLE_OPERATION_TIMEDOUT; /* already too little time */ + } + + interval_ms = 1000; /* use 1 second timeout intervals */ + if(timeout < interval_ms) + interval_ms = timeout; + + /* + * Since this function is blocking, we need to wait here for input on the + * connection and only then we call the response reading function. We do + * timeout at least every second to make the timeout check run. + * + * A caution here is that the ftp_readresp() function has a cache that may + * contain pieces of a response from the previous invoke and we need to + * make sure we don't just wait for input while there is unhandled data in + * that cache. But also, if the cache is there, we call ftp_readresp() and + * the cache wasn't good enough to continue we must not just busy-loop + * around this function. + * + */ + + if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) { + /* + * There's a cache left since before. We then skipping the wait for + * socket action, unless this is the same cache like the previous round + * as then the cache was deemed not enough to act on and we then need to + * wait for more data anyway. + */ + } + else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) { + switch(SOCKET_READABLE(sockfd, interval_ms)) { + case -1: /* select() error, stop reading */ + failf(data, "FTP response aborted due to select/poll error: %d", + SOCKERRNO); + return CURLE_RECV_ERROR; + + case 0: /* timeout */ + if(Curl_pgrsUpdate(data)) + return CURLE_ABORTED_BY_CALLBACK; + continue; /* just continue in our loop for the timeout duration */ + + default: /* for clarity */ + break; + } + } + result = ftp_readresp(data, sockfd, pp, ftpcode, &nread); + if(result) + break; + + if(!nread && Curl_dyn_len(&pp->recvbuf)) + /* bump cache skip counter as on repeated skips we must wait for more + data */ + cache_skip++; + else + /* when we got data or there is no cache left, we reset the cache skip + counter */ + cache_skip = 0; + + *nreadp += nread; + + } /* while there's buffer left and loop is requested */ + + pp->pending_resp = FALSE; + + return result; +} + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ +static const char * const ftp_state_names[]={ + "STOP", + "WAIT220", + "AUTH", + "USER", + "PASS", + "ACCT", + "PBSZ", + "PROT", + "CCC", + "PWD", + "SYST", + "NAMEFMT", + "QUOTE", + "RETR_PREQUOTE", + "STOR_PREQUOTE", + "POSTQUOTE", + "CWD", + "MKD", + "MDTM", + "TYPE", + "LIST_TYPE", + "RETR_TYPE", + "STOR_TYPE", + "SIZE", + "RETR_SIZE", + "STOR_SIZE", + "REST", + "RETR_REST", + "PORT", + "PRET", + "PASV", + "LIST", + "RETR", + "STOR", + "QUIT" +}; +#endif + +/* This is the ONLY way to change FTP state! */ +static void _ftp_state(struct Curl_easy *data, + ftpstate newstate +#ifdef DEBUGBUILD + , int lineno +#endif + ) +{ + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + +#if defined(DEBUGBUILD) + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) lineno; +#else + if(ftpc->state != newstate) + infof(data, "FTP %p (line %d) state change from %s to %s", + (void *)ftpc, lineno, ftp_state_names[ftpc->state], + ftp_state_names[newstate]); +#endif +#endif + + ftpc->state = newstate; +} + +static CURLcode ftp_state_user(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = Curl_pp_sendf(data, + &conn->proto.ftpc.pp, "USER %s", + conn->user?conn->user:""); + if(!result) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + ftpc->ftp_trying_alternative = FALSE; + ftp_state(data, FTP_USER); + } + return result; +} + +static CURLcode ftp_state_pwd(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD"); + if(!result) + ftp_state(data, FTP_PWD); + + return result; +} + +/* For the FTP "protocol connect" and "doing" phases only */ +static int ftp_getsock(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *socks) +{ + return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks); +} + +/* For the FTP "DO_MORE" phase only */ +static int ftp_domore_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + (void)data; + + /* When in DO_MORE state, we could be either waiting for us to connect to a + * remote site, or we could wait for that site to connect to us. Or just + * handle ordinary commands. + */ + + DEBUGF(infof(data, "ftp_domore_getsock()")); + if(conn->cfilter[SECONDARYSOCKET] + && !Curl_conn_is_connected(conn, SECONDARYSOCKET)) + return 0; + + if(FTP_STOP == ftpc->state) { + int bits = GETSOCK_READSOCK(0); + + /* if stopped and still in this state, then we're also waiting for a + connect on the secondary connection */ + socks[0] = conn->sock[FIRSTSOCKET]; + if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { + socks[1] = conn->sock[SECONDARYSOCKET]; + bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); + } + + return bits; + } + return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks); +} + +/* This is called after the FTP_QUOTE state is passed. + + ftp_state_cwd() sends the range of CWD commands to the server to change to + the correct directory. It may also need to send MKD commands to create + missing ones, if that option is enabled. +*/ +static CURLcode ftp_state_cwd(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(ftpc->cwddone) + /* already done and fine */ + result = ftp_state_mdtm(data); + else { + /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */ + DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) || + !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')); + + ftpc->count2 = 0; /* count2 counts failed CWDs */ + + if(conn->bits.reuse && ftpc->entrypath && + /* no need to go to entrypath when we have an absolute path */ + !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) { + /* This is a reused connection. Since we change directory to where the + transfer is taking place, we must first get back to the original dir + where we ended up after login: */ + ftpc->cwdcount = 0; /* we count this as the first path, then we add one + for all upcoming ones in the ftp->dirs[] array */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath); + if(!result) + ftp_state(data, FTP_CWD); + } + else { + if(ftpc->dirdepth) { + ftpc->cwdcount = 1; + /* issue the first CWD, the rest is sent when the CWD responses are + received... */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount -1]); + if(!result) + ftp_state(data, FTP_CWD); + } + else { + /* No CWD necessary */ + result = ftp_state_mdtm(data); + } + } + } + return result; +} + +typedef enum { + EPRT, + PORT, + DONE +} ftpport; + +static CURLcode ftp_state_use_port(struct Curl_easy *data, + ftpport fcmd) /* start with this */ +{ + CURLcode result = CURLE_FTP_PORT_FAILED; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + curl_socket_t portsock = CURL_SOCKET_BAD; + char myhost[MAX_IPADR_LEN + 1] = ""; + + struct Curl_sockaddr_storage ss; + struct Curl_addrinfo *res, *ai; + curl_socklen_t sslen; + char hbuf[NI_MAXHOST]; + struct sockaddr *sa = (struct sockaddr *)&ss; + struct sockaddr_in * const sa4 = (void *)sa; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 * const sa6 = (void *)sa; +#endif + static const char mode[][5] = { "EPRT", "PORT" }; + enum resolve_t rc; + int error; + char *host = NULL; + char *string_ftpport = data->set.str[STRING_FTPPORT]; + struct Curl_dns_entry *h = NULL; + unsigned short port_min = 0; + unsigned short port_max = 0; + unsigned short port; + bool possibly_non_local = TRUE; + char buffer[STRERROR_LEN]; + char *addr = NULL; + size_t addrlen = 0; + char ipstr[50]; + + /* Step 1, figure out what is requested, + * accepted format : + * (ipv4|ipv6|domain|interface)?(:port(-range)?)? + */ + + if(data->set.str[STRING_FTPPORT] && + (strlen(data->set.str[STRING_FTPPORT]) > 1)) { + char *ip_end = NULL; + +#ifdef ENABLE_IPV6 + if(*string_ftpport == '[') { + /* [ipv6]:port(-range) */ + char *ip_start = string_ftpport + 1; + ip_end = strchr(ip_start, ']'); + if(ip_end) { + addrlen = ip_end - ip_start; + addr = ip_start; + } + } + else +#endif + if(*string_ftpport == ':') { + /* :port */ + ip_end = string_ftpport; + } + else { + ip_end = strchr(string_ftpport, ':'); + addr = string_ftpport; + if(ip_end) { + /* either ipv6 or (ipv4|domain|interface):port(-range) */ + addrlen = ip_end - string_ftpport; +#ifdef ENABLE_IPV6 + if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) { + /* ipv6 */ + port_min = port_max = 0; + ip_end = NULL; /* this got no port ! */ + } +#endif + } + else + /* ipv4|interface */ + addrlen = strlen(string_ftpport); + } + + /* parse the port */ + if(ip_end) { + char *port_sep = NULL; + char *port_start = strchr(ip_end, ':'); + if(port_start) { + port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10)); + port_sep = strchr(port_start, '-'); + if(port_sep) { + port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10)); + } + else + port_max = port_min; + } + } + + /* correct errors like: + * :1234-1230 + * :-4711, in this case port_min is (unsigned)-1, + * therefore port_min > port_max for all cases + * but port_max = (unsigned)-1 + */ + if(port_min > port_max) + port_min = port_max = 0; + + if(addrlen) { + DEBUGASSERT(addr); + if(addrlen >= sizeof(ipstr)) + goto out; + memcpy(ipstr, addr, addrlen); + ipstr[addrlen] = 0; + + /* attempt to get the address of the given interface name */ + switch(Curl_if2ip(conn->remote_addr->family, +#ifdef ENABLE_IPV6 + Curl_ipv6_scope(&conn->remote_addr->sa_addr), + conn->scope_id, +#endif + ipstr, hbuf, sizeof(hbuf))) { + case IF2IP_NOT_FOUND: + /* not an interface, use the given string as host name instead */ + host = ipstr; + break; + case IF2IP_AF_NOT_SUPPORTED: + goto out; + case IF2IP_FOUND: + host = hbuf; /* use the hbuf for host name */ + break; + } + } + else + /* there was only a port(-range) given, default the host */ + host = NULL; + } /* data->set.ftpport */ + + if(!host) { + const char *r; + /* not an interface and not a host name, get default by extracting + the IP from the control connection */ + sslen = sizeof(ss); + if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + goto out; + } + switch(sa->sa_family) { +#ifdef ENABLE_IPV6 + case AF_INET6: + r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); + break; +#endif + default: + r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); + break; + } + if(!r) { + goto out; + } + host = hbuf; /* use this host name */ + possibly_non_local = FALSE; /* we know it is local now */ + } + + /* resolv ip/host to ip */ + rc = Curl_resolv(data, host, 0, FALSE, &h); + if(rc == CURLRESOLV_PENDING) + (void)Curl_resolver_wait_resolv(data, &h); + if(h) { + res = h->addr; + /* when we return from this function, we can forget about this entry + to we can unlock it now already */ + Curl_resolv_unlock(data, h); + } /* (h) */ + else + res = NULL; /* failure! */ + + if(!res) { + failf(data, "failed to resolve the address provided to PORT: %s", host); + goto out; + } + + host = NULL; + + /* step 2, create a socket for the requested address */ + error = 0; + for(ai = res; ai; ai = ai->ai_next) { + if(Curl_socket_open(data, ai, NULL, conn->transport, &portsock)) { + error = SOCKERRNO; + continue; + } + break; + } + if(!ai) { + failf(data, "socket failure: %s", + Curl_strerror(error, buffer, sizeof(buffer))); + goto out; + } + DEBUGF(infof(data, "ftp_state_use_port(), opened socket")); + + /* step 3, bind to a suitable local address */ + + memcpy(sa, ai->ai_addr, ai->ai_addrlen); + sslen = ai->ai_addrlen; + + for(port = port_min; port <= port_max;) { + if(sa->sa_family == AF_INET) + sa4->sin_port = htons(port); +#ifdef ENABLE_IPV6 + else + sa6->sin6_port = htons(port); +#endif + /* Try binding the given address. */ + if(bind(portsock, sa, sslen) ) { + /* It failed. */ + error = SOCKERRNO; + if(possibly_non_local && (error == EADDRNOTAVAIL)) { + /* The requested bind address is not local. Use the address used for + * the control connection instead and restart the port loop + */ + infof(data, "bind(port=%hu) on non-local address failed: %s", port, + Curl_strerror(error, buffer, sizeof(buffer))); + + sslen = sizeof(ss); + if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + goto out; + } + port = port_min; + possibly_non_local = FALSE; /* don't try this again */ + continue; + } + if(error != EADDRINUSE && error != EACCES) { + failf(data, "bind(port=%hu) failed: %s", port, + Curl_strerror(error, buffer, sizeof(buffer))); + goto out; + } + } + else + break; + + port++; + } + + /* maybe all ports were in use already */ + if(port > port_max) { + failf(data, "bind() failed, we ran out of ports"); + goto out; + } + + /* get the name again after the bind() so that we can extract the + port number it uses now */ + sslen = sizeof(ss); + if(getsockname(portsock, sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + goto out; + } + DEBUGF(infof(data, "ftp_state_use_port(), socket bound to port %d", port)); + + /* step 4, listen on the socket */ + + if(listen(portsock, 1)) { + failf(data, "socket failure: %s", + Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + goto out; + } + DEBUGF(infof(data, "ftp_state_use_port(), listening on %d", port)); + + /* step 5, send the proper FTP command */ + + /* get a plain printable version of the numerical address to work with + below */ + Curl_printable_address(ai, myhost, sizeof(myhost)); + +#ifdef ENABLE_IPV6 + if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) + /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the + request and enable EPRT again! */ + conn->bits.ftp_use_eprt = TRUE; +#endif + + for(; fcmd != DONE; fcmd++) { + + if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) + /* if disabled, goto next */ + continue; + + if((PORT == fcmd) && sa->sa_family != AF_INET) + /* PORT is IPv4 only */ + continue; + + switch(sa->sa_family) { + case AF_INET: + port = ntohs(sa4->sin_port); + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + port = ntohs(sa6->sin6_port); + break; +#endif + default: + continue; /* might as well skip this */ + } + + if(EPRT == fcmd) { + /* + * Two fine examples from RFC2428; + * + * EPRT |1|132.235.1.2|6275| + * + * EPRT |2|1080::8:800:200C:417A|5282| + */ + + result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], + sa->sa_family == AF_INET?1:2, + myhost, port); + if(result) { + failf(data, "Failure sending EPRT command: %s", + curl_easy_strerror(result)); + goto out; + } + break; + } + if(PORT == fcmd) { + /* large enough for [IP address],[num],[num] */ + char target[sizeof(myhost) + 20]; + char *source = myhost; + char *dest = target; + + /* translate x.x.x.x to x,x,x,x */ + while(source && *source) { + if(*source == '.') + *dest = ','; + else + *dest = *source; + dest++; + source++; + } + *dest = 0; + msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); + + result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target); + if(result) { + failf(data, "Failure sending PORT command: %s", + curl_easy_strerror(result)); + goto out; + } + break; + } + } + + /* store which command was sent */ + ftpc->count1 = fcmd; + + /* Replace any filter on SECONDARY with one listening on this socket */ + result = Curl_conn_tcp_listen_set(data, conn, SECONDARYSOCKET, &portsock); + if(result) + goto out; + portsock = CURL_SOCKET_BAD; /* now held in filter */ + ftp_state(data, FTP_PORT); + +out: + if(result) { + ftp_state(data, FTP_STOP); + } + if(portsock != CURL_SOCKET_BAD) + Curl_socket_close(data, conn, portsock); + return result; +} + +static CURLcode ftp_state_use_pasv(struct Curl_easy *data, + struct connectdata *conn) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = CURLE_OK; + /* + Here's the executive summary on what to do: + + PASV is RFC959, expect: + 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) + + LPSV is RFC1639, expect: + 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) + + EPSV is RFC2428, expect: + 229 Entering Extended Passive Mode (|||port|) + + */ + + static const char mode[][5] = { "EPSV", "PASV" }; + int modeoff; + +#ifdef PF_INET6 + if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) + /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the + request and enable EPSV again! */ + conn->bits.ftp_use_epsv = TRUE; +#endif + + modeoff = conn->bits.ftp_use_epsv?0:1; + + result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]); + if(!result) { + ftpc->count1 = modeoff; + ftp_state(data, FTP_PASV); + infof(data, "Connect data stream passively"); + } + return result; +} + +/* + * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. + * + * REST is the last command in the chain of commands when a "head"-like + * request is made. Thus, if an actual transfer is to be made this is where we + * take off for real. + */ +static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + + if(ftp->transfer != PPTRANSFER_BODY) { + /* doesn't transfer any data */ + + /* still possibly do PRE QUOTE jobs */ + ftp_state(data, FTP_RETR_PREQUOTE); + result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE); + } + else if(data->set.ftp_use_port) { + /* We have chosen to use the PORT (or similar) command */ + result = ftp_state_use_port(data, EPRT); + } + else { + /* We have chosen (this is default) to use the PASV (or similar) command */ + if(data->set.ftp_use_pret) { + /* The user has requested that we send a PRET command + to prepare the server for the upcoming PASV */ + struct ftp_conn *ftpc = &conn->proto.ftpc; + if(!conn->proto.ftpc.file) + result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s", + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: + (data->state.list_only?"NLST":"LIST")); + else if(data->state.upload) + result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s", + conn->proto.ftpc.file); + else + result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s", + conn->proto.ftpc.file); + if(!result) + ftp_state(data, FTP_PRET); + } + else + result = ftp_state_use_pasv(data, conn); + } + return result; +} + +static CURLcode ftp_state_rest(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) { + /* if a "head"-like request is being made (on a file) */ + + /* Determine if server can respond to REST command and therefore + whether it supports range */ + result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0); + if(!result) + ftp_state(data, FTP_REST); + } + else + result = ftp_state_prepare_transfer(data); + + return result; +} + +static CURLcode ftp_state_size(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) { + /* if a "head"-like request is being made (on a file) */ + + /* we know ftpc->file is a valid pointer to a file name */ + result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); + if(!result) + ftp_state(data, FTP_SIZE); + } + else + result = ftp_state_rest(data, conn); + + return result; +} + +static CURLcode ftp_state_list(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + + /* If this output is to be machine-parsed, the NLST command might be better + to use, since the LIST command output is not specified or standard in any + way. It has turned out that the NLST list output is not the same on all + servers either... */ + + /* + if FTPFILE_NOCWD was specified, we should add the path + as argument for the LIST / NLST / or custom command. + Whether the server will support this, is uncertain. + + The other ftp_filemethods will CWD into dir/dir/ first and + then just do LIST (in that case: nothing to do here) + */ + char *lstArg = NULL; + char *cmd; + + if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) { + /* url-decode before evaluation: e.g. paths starting/ending with %2f */ + const char *slashPos = NULL; + char *rawPath = NULL; + result = Curl_urldecode(ftp->path, 0, &rawPath, NULL, REJECT_CTRL); + if(result) + return result; + + slashPos = strrchr(rawPath, '/'); + if(slashPos) { + /* chop off the file part if format is dir/file otherwise remove + the trailing slash for dir/dir/ except for absolute path / */ + size_t n = slashPos - rawPath; + if(n == 0) + ++n; + + lstArg = rawPath; + lstArg[n] = '\0'; + } + else + free(rawPath); + } + + cmd = aprintf("%s%s%s", + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: + (data->state.list_only?"NLST":"LIST"), + lstArg? " ": "", + lstArg? lstArg: ""); + free(lstArg); + + if(!cmd) + return CURLE_OUT_OF_MEMORY; + + result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", cmd); + free(cmd); + + if(!result) + ftp_state(data, FTP_LIST); + + return result; +} + +static CURLcode ftp_state_retr_prequote(struct Curl_easy *data) +{ + /* We've sent the TYPE, now we must send the list of prequote strings */ + return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE); +} + +static CURLcode ftp_state_stor_prequote(struct Curl_easy *data) +{ + /* We've sent the TYPE, now we must send the list of prequote strings */ + return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE); +} + +static CURLcode ftp_state_type(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + /* If we have selected NOBODY and HEADER, it means that we only want file + information. Which in FTP can't be much more than the file size and + date. */ + if(data->req.no_body && ftpc->file && + ftp_need_type(conn, data->state.prefer_ascii)) { + /* The SIZE command is _not_ RFC 959 specified, and therefore many servers + may not support it! It is however the only way we have to get a file's + size! */ + + ftp->transfer = PPTRANSFER_INFO; + /* this means no actual transfer will be made */ + + /* Some servers return different sizes for different modes, and thus we + must set the proper type before we check the size */ + result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE); + if(result) + return result; + } + else + result = ftp_state_size(data, conn); + + return result; +} + +/* This is called after the CWD commands have been done in the beginning of + the DO phase */ +static CURLcode ftp_state_mdtm(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + /* Requested time of file or time-depended transfer? */ + if((data->set.get_filetime || data->set.timecondition) && ftpc->file) { + + /* we have requested to get the modified-time of the file, this is a white + spot as the MDTM is not mentioned in RFC959 */ + result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file); + + if(!result) + ftp_state(data, FTP_MDTM); + } + else + result = ftp_state_type(data); + + return result; +} + + +/* This is called after the TYPE and possible quote commands have been sent */ +static CURLcode ftp_state_ul_setup(struct Curl_easy *data, + bool sizechecked) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct FTP *ftp = data->req.p.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + bool append = data->set.remote_append; + + if((data->state.resume_from && !sizechecked) || + ((data->state.resume_from > 0) && sizechecked)) { + /* we're about to continue the uploading of a file */ + /* 1. get already existing file's size. We use the SIZE command for this + which may not exist in the server! The SIZE command is not in + RFC959. */ + + /* 2. This used to set REST. But since we can do append, we + don't another ftp command. We just skip the source file + offset and then we APPEND the rest on the file instead */ + + /* 3. pass file-size number of bytes in the source file */ + /* 4. lower the infilesize counter */ + /* => transfer as usual */ + int seekerr = CURL_SEEKFUNC_OK; + + if(data->state.resume_from < 0) { + /* Got no given size to start from, figure it out */ + result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); + if(!result) + ftp_state(data, FTP_STOR_SIZE); + return result; + } + + /* enable append */ + append = TRUE; + + /* Let's read off the proper amount of bytes from the input. */ + if(conn->seek_func) { + Curl_set_in_callback(data, true); + seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, + SEEK_SET); + Curl_set_in_callback(data, false); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed = 0; + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_FTP_COULDNT_USE_REST; + } + /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ + do { + char scratch[4*1024]; + size_t readthisamountnow = + (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : + curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread = + data->state.fread_func(scratch, 1, readthisamountnow, + data->state.in); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); + } + /* now, decrease the size of the read */ + if(data->state.infilesize>0) { + data->state.infilesize -= data->state.resume_from; + + if(data->state.infilesize <= 0) { + infof(data, "File already completely uploaded"); + + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + + /* Set ->transfer so that we won't get any error in + * ftp_done() because we didn't transfer anything! */ + ftp->transfer = PPTRANSFER_NONE; + + ftp_state(data, FTP_STOP); + return CURLE_OK; + } + } + /* we've passed, proceed as normal */ + } /* resume_from */ + + result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s", + ftpc->file); + if(!result) + ftp_state(data, FTP_STOR); + + return result; +} + +static CURLcode ftp_state_quote(struct Curl_easy *data, + bool init, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + bool quote = FALSE; + struct curl_slist *item; + + switch(instate) { + case FTP_QUOTE: + default: + item = data->set.quote; + break; + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + item = data->set.prequote; + break; + case FTP_POSTQUOTE: + item = data->set.postquote; + break; + } + + /* + * This state uses: + * 'count1' to iterate over the commands to send + * 'count2' to store whether to allow commands to fail + */ + + if(init) + ftpc->count1 = 0; + else + ftpc->count1++; + + if(item) { + int i = 0; + + /* Skip count1 items in the linked list */ + while((i< ftpc->count1) && item) { + item = item->next; + i++; + } + if(item) { + char *cmd = item->data; + if(cmd[0] == '*') { + cmd++; + ftpc->count2 = 1; /* the sent command is allowed to fail */ + } + else + ftpc->count2 = 0; /* failure means cancel operation */ + + result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); + if(result) + return result; + ftp_state(data, instate); + quote = TRUE; + } + } + + if(!quote) { + /* No more quote to send, continue to ... */ + switch(instate) { + case FTP_QUOTE: + default: + result = ftp_state_cwd(data, conn); + break; + case FTP_RETR_PREQUOTE: + if(ftp->transfer != PPTRANSFER_BODY) + ftp_state(data, FTP_STOP); + else { + if(ftpc->known_filesize != -1) { + Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); + result = ftp_state_retr(data, ftpc->known_filesize); + } + else { + if(data->set.ignorecl || data->state.prefer_ascii) { + /* 'ignorecl' is used to support download of growing files. It + prevents the state machine from requesting the file size from + the server. With an unknown file size the download continues + until the server terminates it, otherwise the client stops if + the received byte count exceeds the reported file size. Set + option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this + behavior. + + In addition: asking for the size for 'TYPE A' transfers is not + constructive since servers don't report the converted size. So + skip it. + */ + result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); + if(!result) + ftp_state(data, FTP_RETR); + } + else { + result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); + if(!result) + ftp_state(data, FTP_RETR_SIZE); + } + } + } + break; + case FTP_STOR_PREQUOTE: + result = ftp_state_ul_setup(data, FALSE); + break; + case FTP_POSTQUOTE: + break; + } + } + + return result; +} + +/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV + problems */ +static CURLcode ftp_epsv_disable(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if(conn->bits.ipv6 +#ifndef CURL_DISABLE_PROXY + && !(conn->bits.tunnel_proxy || conn->bits.socksproxy) +#endif + ) { + /* We can't disable EPSV when doing IPv6, so this is instead a fail */ + failf(data, "Failed EPSV attempt, exiting"); + return CURLE_WEIRD_SERVER_REPLY; + } + + infof(data, "Failed EPSV attempt. Disabling EPSV"); + /* disable it for next transfer */ + conn->bits.ftp_use_epsv = FALSE; + Curl_conn_close(data, SECONDARYSOCKET); + Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET); + data->state.errorbuf = FALSE; /* allow error message to get + rewritten */ + result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV"); + if(!result) { + conn->proto.ftpc.count1++; + /* remain in/go to the FTP_PASV state */ + ftp_state(data, FTP_PASV); + } + return result; +} + + +static char *control_address(struct connectdata *conn) +{ + /* Returns the control connection IP address. + If a proxy tunnel is used, returns the original host name instead, because + the effective control connection address is the proxy address, + not the ftp host. */ +#ifndef CURL_DISABLE_PROXY + if(conn->bits.tunnel_proxy || conn->bits.socksproxy) + return conn->host.name; +#endif + return conn->primary_ip; +} + +static bool match_pasv_6nums(const char *p, + unsigned int *array) /* 6 numbers */ +{ + int i; + for(i = 0; i < 6; i++) { + unsigned long num; + char *endp; + if(i) { + if(*p != ',') + return FALSE; + p++; + } + if(!ISDIGIT(*p)) + return FALSE; + num = strtoul(p, &endp, 10); + if(num > 255) + return FALSE; + array[i] = (unsigned int)num; + p = endp; + } + return TRUE; +} + +static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, + int ftpcode) +{ + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result; + struct Curl_dns_entry *addr = NULL; + enum resolve_t rc; + unsigned short connectport; /* the local port connect() should use! */ + struct pingpong *pp = &ftpc->pp; + char *str = + Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */ + + /* if we come here again, make sure the former name is cleared */ + Curl_safefree(ftpc->newhost); + + if((ftpc->count1 == 0) && + (ftpcode == 229)) { + /* positive EPSV response */ + char *ptr = strchr(str, '('); + if(ptr) { + char sep; + ptr++; + /* |||12345| */ + sep = ptr[0]; + /* the ISDIGIT() check here is because strtoul() accepts leading minus + etc */ + if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) { + char *endp; + unsigned long num = strtoul(&ptr[3], &endp, 10); + if(*endp != sep) + ptr = NULL; + else if(num > 0xffff) { + failf(data, "Illegal port number in EPSV reply"); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + if(ptr) { + ftpc->newport = (unsigned short)(num & 0xffff); + ftpc->newhost = strdup(control_address(conn)); + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; + } + } + else + ptr = NULL; + } + if(!ptr) { + failf(data, "Weirdly formatted EPSV reply"); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + } + else if((ftpc->count1 == 1) && + (ftpcode == 227)) { + /* positive PASV response */ + unsigned int ip[6]; + + /* + * Scan for a sequence of six comma-separated numbers and use them as + * IP+port indicators. + * + * Found reply-strings include: + * "227 Entering Passive Mode (127,0,0,1,4,51)" + * "227 Data transfer will passively listen to 127,0,0,1,4,51" + * "227 Entering passive mode. 127,0,0,1,4,51" + */ + while(*str) { + if(match_pasv_6nums(str, ip)) + break; + str++; + } + + if(!*str) { + failf(data, "Couldn't interpret the 227-response"); + return CURLE_FTP_WEIRD_227_FORMAT; + } + + /* we got OK from server */ + if(data->set.ftp_skip_ip) { + /* told to ignore the remotely given IP but instead use the host we used + for the control connection */ + infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead", + ip[0], ip[1], ip[2], ip[3], + conn->host.name); + ftpc->newhost = strdup(control_address(conn)); + } + else + ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; + + ftpc->newport = (unsigned short)(((ip[4]<<8) + ip[5]) & 0xffff); + } + else if(ftpc->count1 == 0) { + /* EPSV failed, move on to PASV */ + return ftp_epsv_disable(data, conn); + } + else { + failf(data, "Bad PASV/EPSV response: %03d", ftpcode); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + +#ifndef CURL_DISABLE_PROXY + if(conn->bits.proxy) { + /* + * This connection uses a proxy and we need to connect to the proxy again + * here. We don't want to rely on a former host lookup that might've + * expired now, instead we remake the lookup here and now! + */ + const char * const host_name = conn->bits.socksproxy ? + conn->socks_proxy.host.name : conn->http_proxy.host.name; + rc = Curl_resolv(data, host_name, conn->port, FALSE, &addr); + if(rc == CURLRESOLV_PENDING) + /* BLOCKING, ignores the return code but 'addr' will be NULL in + case of failure */ + (void)Curl_resolver_wait_resolv(data, &addr); + + connectport = + (unsigned short)conn->port; /* we connect to the proxy's port */ + + if(!addr) { + failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport); + return CURLE_COULDNT_RESOLVE_PROXY; + } + } + else +#endif + { + /* normal, direct, ftp connection */ + DEBUGASSERT(ftpc->newhost); + + /* postponed address resolution in case of tcp fastopen */ + if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) { + Curl_conn_ev_update_info(data, conn); + Curl_safefree(ftpc->newhost); + ftpc->newhost = strdup(control_address(conn)); + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; + } + + rc = Curl_resolv(data, ftpc->newhost, ftpc->newport, FALSE, &addr); + if(rc == CURLRESOLV_PENDING) + /* BLOCKING */ + (void)Curl_resolver_wait_resolv(data, &addr); + + connectport = ftpc->newport; /* we connect to the remote port */ + + if(!addr) { + failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport); + return CURLE_FTP_CANT_GET_HOST; + } + } + + result = Curl_conn_setup(data, conn, SECONDARYSOCKET, addr, + conn->bits.ftp_use_data_ssl? + CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE); + + if(result) { + Curl_resolv_unlock(data, addr); /* we're done using this address */ + if(ftpc->count1 == 0 && ftpcode == 229) + return ftp_epsv_disable(data, conn); + + return result; + } + + + /* + * When this is used from the multi interface, this might've returned with + * the 'connected' set to FALSE and thus we are now awaiting a non-blocking + * connect to connect. + */ + + if(data->set.verbose) + /* this just dumps information about this second connection */ + ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport); + + Curl_resolv_unlock(data, addr); /* we're done using this address */ + + Curl_safefree(conn->secondaryhostname); + conn->secondary_port = ftpc->newport; + conn->secondaryhostname = strdup(ftpc->newhost); + if(!conn->secondaryhostname) + return CURLE_OUT_OF_MEMORY; + + conn->bits.do_more = TRUE; + ftp_state(data, FTP_STOP); /* this phase is completed */ + + return result; +} + +static CURLcode ftp_state_port_resp(struct Curl_easy *data, + int ftpcode) +{ + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + ftpport fcmd = (ftpport)ftpc->count1; + CURLcode result = CURLE_OK; + + /* The FTP spec tells a positive response should have code 200. + Be more permissive here to tolerate deviant servers. */ + if(ftpcode / 100 != 2) { + /* the command failed */ + + if(EPRT == fcmd) { + infof(data, "disabling EPRT usage"); + conn->bits.ftp_use_eprt = FALSE; + } + fcmd++; + + if(fcmd == DONE) { + failf(data, "Failed to do PORT"); + result = CURLE_FTP_PORT_FAILED; + } + else + /* try next */ + result = ftp_state_use_port(data, fcmd); + } + else { + infof(data, "Connect data stream actively"); + ftp_state(data, FTP_STOP); /* end of DO phase */ + result = ftp_dophase_done(data, FALSE); + } + + return result; +} + +static int twodigit(const char *p) +{ + return (p[0]-'0') * 10 + (p[1]-'0'); +} + +static bool ftp_213_date(const char *p, int *year, int *month, int *day, + int *hour, int *minute, int *second) +{ + size_t len = strlen(p); + if(len < 14) + return FALSE; + *year = twodigit(&p[0]) * 100 + twodigit(&p[2]); + *month = twodigit(&p[4]); + *day = twodigit(&p[6]); + *hour = twodigit(&p[8]); + *minute = twodigit(&p[10]); + *second = twodigit(&p[12]); + + if((*month > 12) || (*day > 31) || (*hour > 23) || (*minute > 59) || + (*second > 60)) + return FALSE; + return TRUE; +} + +static CURLcode client_write_header(struct Curl_easy *data, + char *buf, size_t blen) +{ + /* Some replies from an FTP server are written to the client + * as CLIENTWRITE_HEADER, formatted as if they came from a + * HTTP conversation. + * In all protocols, CLIENTWRITE_HEADER data is only passed to + * the body write callback when data->set.include_header is set + * via CURLOPT_HEADER. + * For historic reasons, FTP never played this game and expects + * all its HEADERs to do that always. Set that flag during the + * call to Curl_client_write() so it does the right thing. + * + * Notice that we cannot enable this flag for FTP in general, + * as an FTP transfer might involve a HTTP proxy connection and + * headers from CONNECT should not automatically be part of the + * output. */ + CURLcode result; + int save = data->set.include_header; + data->set.include_header = TRUE; + result = Curl_client_write(data, CLIENTWRITE_HEADER, buf, blen); + data->set.include_header = save? TRUE:FALSE; + return result; +} + +static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, + int ftpcode) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + switch(ftpcode) { + case 213: + { + /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the + last .sss part is optional and means fractions of a second */ + int year, month, day, hour, minute, second; + struct pingpong *pp = &ftpc->pp; + char *resp = Curl_dyn_ptr(&pp->recvbuf) + 4; + if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) { + /* we have a time, reformat it */ + char timebuf[24]; + msnprintf(timebuf, sizeof(timebuf), + "%04d%02d%02d %02d:%02d:%02d GMT", + year, month, day, hour, minute, second); + /* now, convert this into a time() value: */ + data->info.filetime = Curl_getdate_capped(timebuf); + } + +#ifdef CURL_FTP_HTTPSTYLE_HEAD + /* If we asked for a time of the file and we actually got one as well, + we "emulate" an HTTP-style header in our output. */ + + if(data->req.no_body && + ftpc->file && + data->set.get_filetime && + (data->info.filetime >= 0) ) { + char headerbuf[128]; + int headerbuflen; + time_t filetime = data->info.filetime; + struct tm buffer; + const struct tm *tm = &buffer; + + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + + /* format: "Tue, 15 Nov 1994 12:45:26" */ + headerbuflen = msnprintf(headerbuf, sizeof(headerbuf), + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + result = client_write_header(data, headerbuf, headerbuflen); + if(result) + return result; + } /* end of a ridiculous amount of conditionals */ +#endif + } + break; + default: + infof(data, "unsupported MDTM reply format"); + break; + case 550: /* 550 is used for several different problems, e.g. + "No such file or directory" or "Permission denied". + It does not mean that the file does not exist at all. */ + infof(data, "MDTM failed: file does not exist or permission problem," + " continuing"); + break; + } + + if(data->set.timecondition) { + if((data->info.filetime > 0) && (data->set.timevalue > 0)) { + switch(data->set.timecondition) { + case CURL_TIMECOND_IFMODSINCE: + default: + if(data->info.filetime <= data->set.timevalue) { + infof(data, "The requested document is not new enough"); + ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ + data->info.timecond = TRUE; + ftp_state(data, FTP_STOP); + return CURLE_OK; + } + break; + case CURL_TIMECOND_IFUNMODSINCE: + if(data->info.filetime > data->set.timevalue) { + infof(data, "The requested document is not old enough"); + ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ + data->info.timecond = TRUE; + ftp_state(data, FTP_STOP); + return CURLE_OK; + } + break; + } /* switch */ + } + else { + infof(data, "Skipping time comparison"); + } + } + + if(!result) + result = ftp_state_type(data); + + return result; +} + +static CURLcode ftp_state_type_resp(struct Curl_easy *data, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + if(ftpcode/100 != 2) { + /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a + successful 'TYPE I'. While that is not as RFC959 says, it is still a + positive response code and we allow that. */ + failf(data, "Couldn't set desired mode"); + return CURLE_FTP_COULDNT_SET_TYPE; + } + if(ftpcode != 200) + infof(data, "Got a %03d response code instead of the assumed 200", + ftpcode); + + if(instate == FTP_TYPE) + result = ftp_state_size(data, conn); + else if(instate == FTP_LIST_TYPE) + result = ftp_state_list(data); + else if(instate == FTP_RETR_TYPE) + result = ftp_state_retr_prequote(data); + else if(instate == FTP_STOR_TYPE) + result = ftp_state_stor_prequote(data); + + return result; +} + +static CURLcode ftp_state_retr(struct Curl_easy *data, + curl_off_t filesize) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + DEBUGF(infof(data, "ftp_state_retr()")); + if(data->set.max_filesize && (filesize > data->set.max_filesize)) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + ftp->downloadsize = filesize; + + if(data->state.resume_from) { + /* We always (attempt to) get the size of downloads, so it is done before + this even when not doing resumes. */ + if(filesize == -1) { + infof(data, "ftp server doesn't support SIZE"); + /* We couldn't get the size and therefore we can't know if there really + is a part of the file left to get, although the server will just + close the connection when we start the connection so it won't cause + us any harm, just not make us exit as nicely. */ + } + else { + /* We got a file size report, so we check that there actually is a + part of the file left to get, or else we go home. */ + if(data->state.resume_from< 0) { + /* We're supposed to download the last abs(from) bytes */ + if(filesize < -data->state.resume_from) { + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* convert to size to download */ + ftp->downloadsize = -data->state.resume_from; + /* download from where? */ + data->state.resume_from = filesize - ftp->downloadsize; + } + else { + if(filesize < data->state.resume_from) { + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* Now store the number of bytes we are expected to download */ + ftp->downloadsize = filesize-data->state.resume_from; + } + } + + if(ftp->downloadsize == 0) { + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + infof(data, "File already completely downloaded"); + + /* Set ->transfer so that we won't get any error in ftp_done() + * because we didn't transfer the any file */ + ftp->transfer = PPTRANSFER_NONE; + ftp_state(data, FTP_STOP); + return CURLE_OK; + } + + /* Set resume file transfer offset */ + infof(data, "Instructs server to resume from offset %" + CURL_FORMAT_CURL_OFF_T, data->state.resume_from); + + result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, + data->state.resume_from); + if(!result) + ftp_state(data, FTP_RETR_REST); + } + else { + /* no resume */ + result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); + if(!result) + ftp_state(data, FTP_RETR); + } + + return result; +} + +static CURLcode ftp_state_size_resp(struct Curl_easy *data, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + curl_off_t filesize = -1; + char *buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf); + size_t len = data->conn->proto.ftpc.pp.nfinal; + + /* get the size from the ascii string: */ + if(ftpcode == 213) { + /* To allow servers to prepend "rubbish" in the response string, we scan + for all the digits at the end of the response and parse only those as a + number. */ + char *start = &buf[4]; + char *fdigit = memchr(start, '\r', len); + if(fdigit) { + fdigit--; + if(*fdigit == '\n') + fdigit--; + while(ISDIGIT(fdigit[-1]) && (fdigit > start)) + fdigit--; + } + else + fdigit = start; + /* ignores parsing errors, which will make the size remain unknown */ + (void)curlx_strtoofft(fdigit, NULL, 10, &filesize); + + } + else if(ftpcode == 550) { /* "No such file or directory" */ + /* allow a SIZE failure for (resumed) uploads, when probing what command + to use */ + if(instate != FTP_STOR_SIZE) { + failf(data, "The file does not exist"); + return CURLE_REMOTE_FILE_NOT_FOUND; + } + } + + if(instate == FTP_SIZE) { +#ifdef CURL_FTP_HTTPSTYLE_HEAD + if(-1 != filesize) { + char clbuf[128]; + int clbuflen = msnprintf(clbuf, sizeof(clbuf), + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); + result = client_write_header(data, clbuf, clbuflen); + if(result) + return result; + } +#endif + Curl_pgrsSetDownloadSize(data, filesize); + result = ftp_state_rest(data, data->conn); + } + else if(instate == FTP_RETR_SIZE) { + Curl_pgrsSetDownloadSize(data, filesize); + result = ftp_state_retr(data, filesize); + } + else if(instate == FTP_STOR_SIZE) { + data->state.resume_from = filesize; + result = ftp_state_ul_setup(data, TRUE); + } + + return result; +} + +static CURLcode ftp_state_rest_resp(struct Curl_easy *data, + struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + switch(instate) { + case FTP_REST: + default: +#ifdef CURL_FTP_HTTPSTYLE_HEAD + if(ftpcode == 350) { + char buffer[24]= { "Accept-ranges: bytes\r\n" }; + result = client_write_header(data, buffer, strlen(buffer)); + if(result) + return result; + } +#endif + result = ftp_state_prepare_transfer(data); + break; + + case FTP_RETR_REST: + if(ftpcode != 350) { + failf(data, "Couldn't use REST"); + result = CURLE_FTP_COULDNT_USE_REST; + } + else { + result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); + if(!result) + ftp_state(data, FTP_RETR); + } + break; + } + + return result; +} + +static CURLcode ftp_state_stor_resp(struct Curl_easy *data, + int ftpcode, ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + if(ftpcode >= 400) { + failf(data, "Failed FTP upload: %0d", ftpcode); + ftp_state(data, FTP_STOP); + /* oops, we never close the sockets! */ + return CURLE_UPLOAD_FAILED; + } + + conn->proto.ftpc.state_saved = instate; + + /* PORT means we are now awaiting the server to connect to us. */ + if(data->set.ftp_use_port) { + bool connected; + + ftp_state(data, FTP_STOP); /* no longer in STOR state */ + + result = AllowServerConnect(data, &connected); + if(result) + return result; + + if(!connected) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + infof(data, "Data conn was not available immediately"); + ftpc->wait_data_conn = TRUE; + } + + return CURLE_OK; + } + return InitiateTransfer(data); +} + +/* for LIST and RETR responses */ +static CURLcode ftp_state_get_resp(struct Curl_easy *data, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + + if((ftpcode == 150) || (ftpcode == 125)) { + + /* + A; + 150 Opening BINARY mode data connection for /etc/passwd (2241 + bytes). (ok, the file is being transferred) + + B: + 150 Opening ASCII mode data connection for /bin/ls + + C: + 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). + + D: + 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes) + + E: + 125 Data connection already open; Transfer starting. */ + + curl_off_t size = -1; /* default unknown size */ + + + /* + * It appears that there are FTP-servers that return size 0 for files when + * SIZE is used on the file while being in BINARY mode. To work around + * that (stupid) behavior, we attempt to parse the RETR response even if + * the SIZE returned size zero. + * + * Debugging help from Salvatore Sorrentino on February 26, 2003. + */ + + if((instate != FTP_LIST) && + !data->state.prefer_ascii && + !data->set.ignorecl && + (ftp->downloadsize < 1)) { + /* + * It seems directory listings either don't show the size or very + * often uses size 0 anyway. ASCII transfers may very well turn out + * that the transferred amount of data is not the same as this line + * tells, why using this number in those cases only confuses us. + * + * Example D above makes this parsing a little tricky */ + char *bytes; + char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf); + bytes = strstr(buf, " bytes"); + if(bytes) { + long in = (long)(--bytes-buf); + /* this is a hint there is size information in there! ;-) */ + while(--in) { + /* scan for the left parenthesis and break there */ + if('(' == *bytes) + break; + /* skip only digits */ + if(!ISDIGIT(*bytes)) { + bytes = NULL; + break; + } + /* one more estep backwards */ + bytes--; + } + /* if we have nothing but digits: */ + if(bytes) { + ++bytes; + /* get the number! */ + (void)curlx_strtoofft(bytes, NULL, 10, &size); + } + } + } + else if(ftp->downloadsize > -1) + size = ftp->downloadsize; + + if(size > data->req.maxdownload && data->req.maxdownload > 0) + size = data->req.size = data->req.maxdownload; + else if((instate != FTP_LIST) && (data->state.prefer_ascii)) + size = -1; /* kludge for servers that understate ASCII mode file size */ + + infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T, + data->req.maxdownload); + + if(instate != FTP_LIST) + infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T, + size); + + /* FTP download: */ + conn->proto.ftpc.state_saved = instate; + conn->proto.ftpc.retr_size_saved = size; + + if(data->set.ftp_use_port) { + bool connected; + + result = AllowServerConnect(data, &connected); + if(result) + return result; + + if(!connected) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + infof(data, "Data conn was not available immediately"); + ftp_state(data, FTP_STOP); + ftpc->wait_data_conn = TRUE; + } + } + else + return InitiateTransfer(data); + } + else { + if((instate == FTP_LIST) && (ftpcode == 450)) { + /* simply no matching files in the dir listing */ + ftp->transfer = PPTRANSFER_NONE; /* don't download anything */ + ftp_state(data, FTP_STOP); /* this phase is over */ + } + else { + failf(data, "RETR response: %03d", ftpcode); + return instate == FTP_RETR && ftpcode == 550? + CURLE_REMOTE_FILE_NOT_FOUND: + CURLE_FTP_COULDNT_RETR_FILE; + } + } + + return result; +} + +/* after USER, PASS and ACCT */ +static CURLcode ftp_state_loggedin(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + if(conn->bits.ftp_use_control_ssl) { + /* PBSZ = PROTECTION BUFFER SIZE. + + The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: + + Specifically, the PROT command MUST be preceded by a PBSZ + command and a PBSZ command MUST be preceded by a successful + security data exchange (the TLS negotiation in this case) + + ... (and on page 8): + + Thus the PBSZ command must still be issued, but must have a + parameter of '0' to indicate that no buffering is taking place + and the data connection should not be encapsulated. + */ + result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0); + if(!result) + ftp_state(data, FTP_PBSZ); + } + else { + result = ftp_state_pwd(data, conn); + } + return result; +} + +/* for USER and PASS responses */ +static CURLcode ftp_state_user_resp(struct Curl_easy *data, + int ftpcode) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + /* some need password anyway, and others just return 2xx ignored */ + if((ftpcode == 331) && (ftpc->state == FTP_USER)) { + /* 331 Password required for ... + (the server requires to send the user's password too) */ + result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", + conn->passwd?conn->passwd:""); + if(!result) + ftp_state(data, FTP_PASS); + } + else if(ftpcode/100 == 2) { + /* 230 User ... logged in. + (the user logged in with or without password) */ + result = ftp_state_loggedin(data); + } + else if(ftpcode == 332) { + if(data->set.str[STRING_FTP_ACCOUNT]) { + result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s", + data->set.str[STRING_FTP_ACCOUNT]); + if(!result) + ftp_state(data, FTP_ACCT); + } + else { + failf(data, "ACCT requested but none available"); + result = CURLE_LOGIN_DENIED; + } + } + else { + /* All other response codes, like: + + 530 User ... access denied + (the server denies to log the specified user) */ + + if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && + !ftpc->ftp_trying_alternative) { + /* Ok, USER failed. Let's try the supplied command. */ + result = + Curl_pp_sendf(data, &ftpc->pp, "%s", + data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); + if(!result) { + ftpc->ftp_trying_alternative = TRUE; + ftp_state(data, FTP_USER); + } + } + else { + failf(data, "Access denied: %03d", ftpcode); + result = CURLE_LOGIN_DENIED; + } + } + return result; +} + +/* for ACCT response */ +static CURLcode ftp_state_acct_resp(struct Curl_easy *data, + int ftpcode) +{ + CURLcode result = CURLE_OK; + if(ftpcode != 230) { + failf(data, "ACCT rejected by server: %03d", ftpcode); + result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ + } + else + result = ftp_state_loggedin(data); + + return result; +} + + +static CURLcode ftp_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int ftpcode; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + static const char * const ftpauth[] = { "SSL", "TLS" }; + size_t nread = 0; + + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + result = ftp_readresp(data, sock, pp, &ftpcode, &nread); + if(result) + return result; + + if(ftpcode) { + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + if(ftpcode == 230) { + /* 230 User logged in - already! Take as 220 if TLS required. */ + if(data->set.use_ssl <= CURLUSESSL_TRY || + conn->bits.ftp_use_control_ssl) + return ftp_state_user_resp(data, ftpcode); + } + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); + return CURLE_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_GSSAPI + if(data->set.krb) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); + + if(Curl_sec_login(data, conn)) { + failf(data, "secure login failed"); + return CURLE_WEIRD_SERVER_REPLY; + } + infof(data, "Authentication successful"); + } +#endif + + if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { + /* We don't have a SSL/TLS control connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3 = 0; + switch(data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", + (int)data->set.ftpsslauth); + return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ + } + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + if(!result) + ftp_state(data, FTP_AUTH); + } + else + result = ftp_state_user(data, conn); + break; + + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + + if(pp->overflow) + return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ + + if((ftpcode == 234) || (ftpcode == 334)) { + /* this was BLOCKING, keep it so for now */ + bool done; + if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { + result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); + if(result) { + /* we failed and bail out */ + return CURLE_USE_SSL_FAILED; + } + } + result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, &done); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ + conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(data, conn); + } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.use_ssl > CURLUSESSL_TRY) + /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ + result = CURLE_USE_SSL_FAILED; + else + /* ignore the failure and continue */ + result = ftp_state_user(data, conn); + } + break; + + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(data, ftpcode); + break; + + case FTP_ACCT: + result = ftp_state_acct_resp(data, ftpcode); + break; + + case FTP_PBSZ: + result = + Curl_pp_sendf(data, &ftpc->pp, "PROT %c", + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + if(!result) + ftp_state(data, FTP_PROT); + break; + + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->bits.ftp_use_data_ssl = + (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.use_ssl > CURLUSESSL_CONTROL) + /* we failed and bails out */ + return CURLE_USE_SSL_FAILED; + + if(data->set.ftp_ccc) { + /* CCC - Clear Command Channel + */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); + if(!result) + ftp_state(data, FTP_CCC); + } + else + result = ftp_state_pwd(data, conn); + break; + + case FTP_CCC: + if(ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET); + + if(result) + failf(data, "Failed to clear the command channel (CCC)"); + } + if(!result) + /* Then continue as normal */ + result = ftp_state_pwd(data, conn); + break; + + case FTP_PWD: + if(ftpcode == 257) { + char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first + letter */ + bool entry_extracted = FALSE; + struct dynbuf out; + Curl_dyn_init(&out, 1000); + + /* Reply format is like + 257[rubbish]"" and the + RFC959 says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + + /* scan for the first double-quote for non-standard responses */ + while(*ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + + if('\"' == *ptr) { + /* it started good */ + for(ptr++; *ptr; ptr++) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + result = Curl_dyn_addn(&out, &ptr[1], 1); + ptr++; + } + else { + /* end of path */ + if(Curl_dyn_len(&out)) + entry_extracted = TRUE; + break; /* get out of this loop */ + } + } + else + result = Curl_dyn_addn(&out, ptr, 1); + if(result) + return result; + } + } + if(entry_extracted) { + /* If the path name does not look like an absolute path (i.e.: it + does not start with a '/'), we probably need some server-dependent + adjustments. For example, this is the case when connecting to + an OS400 FTP server: this server supports two name syntaxes, + the default one being incompatible with standard paths. In + addition, this server switches automatically to the regular path + syntax when one is encountered in a command: this results in + having an entrypath in the wrong syntax when later used in CWD. + The method used here is to check the server OS: we do it only + if the path name looks strange to minimize overhead on other + systems. */ + char *dir = Curl_dyn_ptr(&out); + + if(!ftpc->server_os && dir[0] != '/') { + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + ftp_state(data, FTP_SYST); + break; + } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + } + else { + /* couldn't get the path */ + Curl_dyn_free(&out); + infof(data, "Failed to figure out path"); + } + } + ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_SYST: + if(ftpcode == 215) { + char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first + letter */ + char *os; + char *start; + + /* Reply format is like + 215 + */ + while(*ptr == ' ') + ptr++; + for(start = ptr; *ptr && *ptr != ' '; ptr++) + ; + os = Curl_memdup0(start, ptr - start); + if(!os) + return CURLE_OUT_OF_MEMORY; + + /* Check for special servers here. */ + if(strcasecompare(os, "OS/400")) { + /* Force OS400 name format 1. */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + ftp_state(data, FTP_NAMEFMT); + break; + } + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } + else { + /* Cannot identify server OS. Continue anyway and cross fingers. */ + } + + ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_NAMEFMT: + if(ftpcode == 250) { + /* Name format change successful: reload initial path. */ + ftp_state_pwd(data, conn); + break; + } + + ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + if((ftpcode >= 400) && !ftpc->count2) { + /* failure response code, and not allowed to fail */ + failf(data, "QUOT command failed with %03d", ftpcode); + result = CURLE_QUOTE_ERROR; + } + else + result = ftp_state_quote(data, FALSE, ftpc->state); + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(data->set.ftp_create_missing_dirs && + ftpc->cwdcount && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + + /* count3 is set to allow MKD to fail once per dir. In the case when + CWD fails and then MKD fails (due to another session raced it to + create the dir) this then allows for a second try to CWD to it. */ + ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0; + + result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + if(!result) + ftp_state(data, FTP_MKD); + } + else { + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* don't remember this path as we failed + to enter it */ + result = CURLE_REMOTE_ACCESS_DENIED; + } + } + else { + /* success */ + ftpc->count2 = 0; + if(++ftpc->cwdcount <= ftpc->dirdepth) + /* send next CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + else + result = ftp_state_mdtm(data); + } + break; + + case FTP_MKD: + if((ftpcode/100 != 2) && !ftpc->count3--) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + else { + ftp_state(data, FTP_CWD); + /* send CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + } + break; + + case FTP_MDTM: + result = ftp_state_mdtm_resp(data, ftpcode); + break; + + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + result = ftp_state_type_resp(data, ftpcode, ftpc->state); + break; + + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(data, ftpcode, ftpc->state); + break; + + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state); + break; + + case FTP_PRET: + if(ftpcode != 200) { + /* there only is this one standard OK return code. */ + failf(data, "PRET command not accepted: %03d", ftpcode); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(data, conn); + break; + + case FTP_PASV: + result = ftp_state_pasv_resp(data, ftpcode); + break; + + case FTP_PORT: + result = ftp_state_port_resp(data, ftpcode); + break; + + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(data, ftpcode, ftpc->state); + break; + + case FTP_STOR: + result = ftp_state_stor_resp(data, ftpcode, ftpc->state); + break; + + case FTP_QUIT: + default: + /* internal error */ + ftp_state(data, FTP_STOP); + break; + } + } /* if(ftpcode) */ + + return result; +} + + +/* called repeatedly until done from multi.c */ +static CURLcode ftp_multi_statemach(struct Curl_easy *data, + bool *done) +{ + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE); + + /* Check for the state outside of the Curl_socket_check() return code checks + since at times we are in fact already in this state when this function + gets called. */ + *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; + + return result; +} + +static CURLcode ftp_block_statemach(struct Curl_easy *data, + struct connectdata *conn) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + CURLcode result = CURLE_OK; + + while(ftpc->state != FTP_STOP) { + result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */); + if(result) + break; + } + + return result; +} + +/* + * ftp_connect() should do everything that is to be considered a part of + * the connection phase. + * + * The variable 'done' points to will be TRUE if the protocol-layer connect + * phase is done when this function returns, or FALSE if not. + * + */ +static CURLcode ftp_connect(struct Curl_easy *data, + bool *done) /* see description above */ +{ + CURLcode result; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + + *done = FALSE; /* default to not done yet */ + + /* We always support persistent connections on ftp */ + connkeep(conn, "FTP default"); + + PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp); + + if(conn->handler->flags & PROTOPT_SSL) { + /* BLOCKING */ + result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done); + if(result) + return result; + conn->bits.ftp_use_control_ssl = TRUE; + } + + Curl_pp_init(pp); /* once per transfer */ + + /* When we connect, we start in the state where we await the 220 + response */ + ftp_state(data, FTP_WAIT220); + + result = ftp_multi_statemach(data, done); + + return result; +} + +/*********************************************************************** + * + * ftp_done() + * + * The DONE function. This does what needs to be done after a single DO has + * performed. + * + * Input argument is already checked for validity. + */ +static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + struct connectdata *conn = data->conn; + struct FTP *ftp = data->req.p.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + ssize_t nread; + int ftpcode; + CURLcode result = CURLE_OK; + char *rawPath = NULL; + size_t pathLen = 0; + + if(!ftp) + return CURLE_OK; + + switch(status) { + case CURLE_BAD_DOWNLOAD_RESUME: + case CURLE_FTP_WEIRD_PASV_REPLY: + case CURLE_FTP_PORT_FAILED: + case CURLE_FTP_ACCEPT_FAILED: + case CURLE_FTP_ACCEPT_TIMEOUT: + case CURLE_FTP_COULDNT_SET_TYPE: + case CURLE_FTP_COULDNT_RETR_FILE: + case CURLE_PARTIAL_FILE: + case CURLE_UPLOAD_FAILED: + case CURLE_REMOTE_ACCESS_DENIED: + case CURLE_FILESIZE_EXCEEDED: + case CURLE_REMOTE_FILE_NOT_FOUND: + case CURLE_WRITE_ERROR: + /* the connection stays alive fine even though this happened */ + case CURLE_OK: /* doesn't affect the control connection's status */ + if(!premature) + break; + + /* until we cope better with prematurely ended requests, let them + * fallback as if in complete failure */ + FALLTHROUGH(); + default: /* by default, an error means the control connection is + wedged and should not be used anymore */ + ftpc->ctl_valid = FALSE; + ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the + current path, as this connection is going */ + connclose(conn, "FTP ended with bad error code"); + result = status; /* use the already set error code */ + break; + } + + if(data->state.wildcardmatch) { + if(data->set.chunk_end && ftpc->file) { + Curl_set_in_callback(data, true); + data->set.chunk_end(data->set.wildcardptr); + Curl_set_in_callback(data, false); + } + ftpc->known_filesize = -1; + } + + if(!result) + /* get the url-decoded "raw" path */ + result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, + REJECT_CTRL); + if(result) { + /* We can limp along anyway (and should try to since we may already be in + * the error path) */ + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ + free(ftpc->prevpath); + ftpc->prevpath = NULL; /* no path remembering */ + } + else { /* remember working directory for connection reuse */ + if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) + free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */ + else { + free(ftpc->prevpath); + + if(!ftpc->cwdfail) { + if(data->set.ftp_filemethod == FTPFILE_NOCWD) + pathLen = 0; /* relative path => working directory is FTP home */ + else + pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */ + + rawPath[pathLen] = '\0'; + ftpc->prevpath = rawPath; + } + else { + free(rawPath); + ftpc->prevpath = NULL; /* no path */ + } + } + + if(ftpc->prevpath) + infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath); + } + + /* free the dir tree and file parts */ + freedirs(ftpc); + + /* shut down the socket to inform the server we're done */ + +#ifdef _WIN32_WCE + shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ +#endif + + if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { + if(!result && ftpc->dont_check && data->req.maxdownload > 0) { + /* partial download completed */ + result = Curl_pp_sendf(data, pp, "%s", "ABOR"); + if(result) { + failf(data, "Failure sending ABOR command: %s", + curl_easy_strerror(result)); + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "ABOR command failed"); /* connection closure */ + } + } + + close_secondarysocket(data, conn); + } + + if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid && + pp->pending_resp && !premature) { + /* + * Let's see what the server says about the transfer we just performed, + * but lower the timeout as sometimes this connection has died while the + * data has been transferred. This happens when doing through NATs etc that + * abandon old silent connections. + */ + timediff_t old_time = pp->response_time; + + pp->response_time = 60*1000; /* give it only a minute for now */ + pp->response = Curl_now(); /* timeout relative now */ + + result = Curl_GetFTPResponse(data, &nread, &ftpcode); + + pp->response_time = old_time; /* set this back to previous value */ + + if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { + failf(data, "control connection looks dead"); + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */ + } + + if(result) { + Curl_safefree(ftp->pathalloc); + return result; + } + + if(ftpc->dont_check && data->req.maxdownload > 0) { + /* we have just sent ABOR and there is no reliable way to check if it was + * successful or not; we have to close the connection now */ + infof(data, "partial download completed, closing connection"); + connclose(conn, "Partial download with no ability to check"); + return result; + } + + if(!ftpc->dont_check) { + /* 226 Transfer complete, 250 Requested file action okay, completed. */ + switch(ftpcode) { + case 226: + case 250: + break; + case 552: + failf(data, "Exceeded storage allocation"); + result = CURLE_REMOTE_DISK_FULL; + break; + default: + failf(data, "server did not report OK, got %d", ftpcode); + result = CURLE_PARTIAL_FILE; + break; + } + } + } + + if(result || premature) + /* the response code from the transfer showed an error already so no + use checking further */ + ; + else if(data->state.upload) { + if((-1 != data->state.infilesize) && + (data->state.infilesize != data->req.writebytecount) && + !data->set.crlf && + (ftp->transfer == PPTRANSFER_BODY)) { + failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T + " out of %" CURL_FORMAT_CURL_OFF_T " bytes)", + data->req.writebytecount, data->state.infilesize); + result = CURLE_PARTIAL_FILE; + } + } + else { + if((-1 != data->req.size) && + (data->req.size != data->req.bytecount) && +#ifdef CURL_DO_LINEEND_CONV + /* Most FTP servers don't adjust their file SIZE response for CRLFs, so + * we'll check to see if the discrepancy can be explained by the number + * of CRLFs we've changed to LFs. + */ + ((data->req.size + data->state.crlf_conversions) != + data->req.bytecount) && +#endif /* CURL_DO_LINEEND_CONV */ + (data->req.maxdownload != data->req.bytecount)) { + failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T + " bytes", data->req.bytecount); + result = CURLE_PARTIAL_FILE; + } + else if(!ftpc->dont_check && + !data->req.bytecount && + (data->req.size>0)) { + failf(data, "No data was received"); + result = CURLE_FTP_COULDNT_RETR_FILE; + } + } + + /* clear these for next connection */ + ftp->transfer = PPTRANSFER_BODY; + ftpc->dont_check = FALSE; + + /* Send any post-transfer QUOTE strings? */ + if(!status && !result && !premature && data->set.postquote) + result = ftp_sendquote(data, conn, data->set.postquote); + Curl_safefree(ftp->pathalloc); + return result; +} + +/*********************************************************************** + * + * ftp_sendquote() + * + * Where a 'quote' means a list of custom commands to send to the server. + * The quote list is passed as an argument. + * + * BLOCKING + */ + +static +CURLcode ftp_sendquote(struct Curl_easy *data, + struct connectdata *conn, struct curl_slist *quote) +{ + struct curl_slist *item; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + + item = quote; + while(item) { + if(item->data) { + ssize_t nread; + char *cmd = item->data; + bool acceptfail = FALSE; + CURLcode result; + int ftpcode = 0; + + /* if a command starts with an asterisk, which a legal FTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server responds. */ + + if(cmd[0] == '*') { + cmd++; + acceptfail = TRUE; + } + + result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); + if(!result) { + pp->response = Curl_now(); /* timeout relative now */ + result = Curl_GetFTPResponse(data, &nread, &ftpcode); + } + if(result) + return result; + + if(!acceptfail && (ftpcode >= 400)) { + failf(data, "QUOT string not accepted: %s", cmd); + return CURLE_QUOTE_ERROR; + } + } + + item = item->next; + } + + return CURLE_OK; +} + +/*********************************************************************** + * + * ftp_need_type() + * + * Returns TRUE if we in the current situation should send TYPE + */ +static int ftp_need_type(struct connectdata *conn, + bool ascii_wanted) +{ + return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); +} + +/*********************************************************************** + * + * ftp_nb_type() + * + * Set TYPE. We only deal with ASCII or BINARY so this function + * sets one of them. + * If the transfer type is not sent, simulate on OK response in newstate + */ +static CURLcode ftp_nb_type(struct Curl_easy *data, + struct connectdata *conn, + bool ascii, ftpstate newstate) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result; + char want = (char)(ascii?'A':'I'); + + if(ftpc->transfertype == want) { + ftp_state(data, newstate); + return ftp_state_type_resp(data, 200, newstate); + } + + result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want); + if(!result) { + ftp_state(data, newstate); + + /* keep track of our current transfer type */ + ftpc->transfertype = want; + } + return result; +} + +/*************************************************************************** + * + * ftp_pasv_verbose() + * + * This function only outputs some informationals about this second connection + * when we've issued a PASV command before and thus we have connected to a + * possibly new IP address. + * + */ +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void +ftp_pasv_verbose(struct Curl_easy *data, + struct Curl_addrinfo *ai, + char *newhost, /* ascii version */ + int port) +{ + char buf[256]; + Curl_printable_address(ai, buf, sizeof(buf)); + infof(data, "Connecting to %s (%s) port %d", newhost, buf, port); +} +#endif + +/* + * ftp_do_more() + * + * This function shall be called when the second FTP (data) connection is + * connected. + * + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back + * (which basically is only for when PASV is being sent to retry a failed + * EPSV). + */ + +static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) +{ + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = CURLE_OK; + bool connected = FALSE; + bool complete = FALSE; + + /* the ftp struct is inited in ftp_connect(). If we are connecting to an HTTP + * proxy then the state will not be valid until after that connection is + * complete */ + struct FTP *ftp = NULL; + + /* if the second connection isn't done yet, wait for it to have + * connected to the remote host. When using proxy tunneling, this + * means the tunnel needs to have been establish. However, we + * can not expect the remote host to talk to us in any way yet. + * So, when using ftps: the SSL handshake will not start until we + * tell the remote server that we are there. */ + if(conn->cfilter[SECONDARYSOCKET]) { + result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected); + if(result || !Curl_conn_is_ip_connected(data, SECONDARYSOCKET)) { + if(result && (ftpc->count1 == 0)) { + *completep = -1; /* go back to DOING please */ + /* this is a EPSV connect failing, try PASV instead */ + return ftp_epsv_disable(data, conn); + } + return result; + } + } + + /* Curl_proxy_connect might have moved the protocol state */ + ftp = data->req.p.ftp; + + if(ftpc->state) { + /* already in a state so skip the initial commands. + They are only done to kickstart the do_more state */ + result = ftp_multi_statemach(data, &complete); + + *completep = (int)complete; + + /* if we got an error or if we don't wait for a data connection return + immediately */ + if(result || !ftpc->wait_data_conn) + return result; + + /* if we reach the end of the FTP state machine here, *complete will be + TRUE but so is ftpc->wait_data_conn, which says we need to wait for the + data connection and therefore we're not actually complete */ + *completep = 0; + } + + if(ftp->transfer <= PPTRANSFER_INFO) { + /* a transfer is about to take place, or if not a file name was given + so we'll do a SIZE on it later and then we need the right TYPE first */ + + if(ftpc->wait_data_conn) { + bool serv_conned; + + result = ReceivedServerConnect(data, &serv_conned); + if(result) + return result; /* Failed to accept data connection */ + + if(serv_conned) { + /* It looks data connection is established */ + result = AcceptServerConnect(data); + ftpc->wait_data_conn = FALSE; + if(!result) + result = InitiateTransfer(data); + + if(result) + return result; + + *completep = 1; /* this state is now complete when the server has + connected back to us */ + } + } + else if(data->state.upload) { + result = ftp_nb_type(data, conn, data->state.prefer_ascii, + FTP_STOR_TYPE); + if(result) + return result; + + result = ftp_multi_statemach(data, &complete); + *completep = (int)complete; + } + else { + /* download */ + ftp->downloadsize = -1; /* unknown as of yet */ + + result = Curl_range(data); + + if(result == CURLE_OK && data->req.maxdownload >= 0) { + /* Don't check for successful transfer */ + ftpc->dont_check = TRUE; + } + + if(result) + ; + else if(data->state.list_only || !ftpc->file) { + /* The specified path ends with a slash, and therefore we think this + is a directory that is requested, use LIST. But before that we + need to set ASCII transfer mode. */ + + /* But only if a body transfer was requested. */ + if(ftp->transfer == PPTRANSFER_BODY) { + result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE); + if(result) + return result; + } + /* otherwise just fall through */ + } + else { + result = ftp_nb_type(data, conn, data->state.prefer_ascii, + FTP_RETR_TYPE); + if(result) + return result; + } + + result = ftp_multi_statemach(data, &complete); + *completep = (int)complete; + } + return result; + } + + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + + if(!ftpc->wait_data_conn) { + /* no waiting for the data connection so this is now complete */ + *completep = 1; + DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result)); + } + + return result; +} + + + +/*********************************************************************** + * + * ftp_perform() + * + * This is the actual DO function for FTP. Get a file/directory according to + * the options previously setup. + */ + +static +CURLcode ftp_perform(struct Curl_easy *data, + bool *connected, /* connect status after PASV / PORT */ + bool *dophase_done) +{ + /* this is FTP and no proxy */ + CURLcode result = CURLE_OK; + + DEBUGF(infof(data, "DO phase starts")); + + if(data->req.no_body) { + /* requested no body means no transfer... */ + struct FTP *ftp = data->req.p.ftp; + ftp->transfer = PPTRANSFER_INFO; + } + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + result = ftp_state_quote(data, TRUE, FTP_QUOTE); + if(result) + return result; + + /* run the state-machine */ + result = ftp_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(data->conn, SECONDARYSOCKET); + + infof(data, "ftp_perform ends with SECONDARY: %d", *connected); + + if(*dophase_done) + DEBUGF(infof(data, "DO phase is complete1")); + + return result; +} + +static void wc_data_dtor(void *ptr) +{ + struct ftp_wc *ftpwc = ptr; + if(ftpwc && ftpwc->parser) + Curl_ftp_parselist_data_free(&ftpwc->parser); + free(ftpwc); +} + +static CURLcode init_wc_data(struct Curl_easy *data) +{ + char *last_slash; + struct FTP *ftp = data->req.p.ftp; + char *path = ftp->path; + struct WildcardData *wildcard = data->wildcard; + CURLcode result = CURLE_OK; + struct ftp_wc *ftpwc = NULL; + + last_slash = strrchr(ftp->path, '/'); + if(last_slash) { + last_slash++; + if(last_slash[0] == '\0') { + wildcard->state = CURLWC_CLEAN; + result = ftp_parse_url_path(data); + return result; + } + wildcard->pattern = strdup(last_slash); + if(!wildcard->pattern) + return CURLE_OUT_OF_MEMORY; + last_slash[0] = '\0'; /* cut file from path */ + } + else { /* there is only 'wildcard pattern' or nothing */ + if(path[0]) { + wildcard->pattern = strdup(path); + if(!wildcard->pattern) + return CURLE_OUT_OF_MEMORY; + path[0] = '\0'; + } + else { /* only list */ + wildcard->state = CURLWC_CLEAN; + result = ftp_parse_url_path(data); + return result; + } + } + + /* program continues only if URL is not ending with slash, allocate needed + resources for wildcard transfer */ + + /* allocate ftp protocol specific wildcard data */ + ftpwc = calloc(1, sizeof(struct ftp_wc)); + if(!ftpwc) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + /* INITIALIZE parselist structure */ + ftpwc->parser = Curl_ftp_parselist_data_alloc(); + if(!ftpwc->parser) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */ + wildcard->dtor = wc_data_dtor; + + /* wildcard does not support NOCWD option (assert it?) */ + if(data->set.ftp_filemethod == FTPFILE_NOCWD) + data->set.ftp_filemethod = FTPFILE_MULTICWD; + + /* try to parse ftp url */ + result = ftp_parse_url_path(data); + if(result) { + goto fail; + } + + wildcard->path = strdup(ftp->path); + if(!wildcard->path) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + /* backup old write_function */ + ftpwc->backup.write_function = data->set.fwrite_func; + /* parsing write function */ + data->set.fwrite_func = Curl_ftp_parselist; + /* backup old file descriptor */ + ftpwc->backup.file_descriptor = data->set.out; + /* let the writefunc callback know the transfer */ + data->set.out = data; + + infof(data, "Wildcard - Parsing started"); + return CURLE_OK; + +fail: + if(ftpwc) { + Curl_ftp_parselist_data_free(&ftpwc->parser); + free(ftpwc); + } + Curl_safefree(wildcard->pattern); + wildcard->dtor = ZERO_NULL; + wildcard->ftpwc = NULL; + return result; +} + +static CURLcode wc_statemach(struct Curl_easy *data) +{ + struct WildcardData * const wildcard = data->wildcard; + struct connectdata *conn = data->conn; + CURLcode result = CURLE_OK; + + for(;;) { + switch(wildcard->state) { + case CURLWC_INIT: + result = init_wc_data(data); + if(wildcard->state == CURLWC_CLEAN) + /* only listing! */ + return result; + wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; + return result; + + case CURLWC_MATCHING: { + /* In this state is LIST response successfully parsed, so lets restore + previous WRITEFUNCTION callback and WRITEDATA pointer */ + struct ftp_wc *ftpwc = wildcard->ftpwc; + data->set.fwrite_func = ftpwc->backup.write_function; + data->set.out = ftpwc->backup.file_descriptor; + ftpwc->backup.write_function = ZERO_NULL; + ftpwc->backup.file_descriptor = NULL; + wildcard->state = CURLWC_DOWNLOADING; + + if(Curl_ftp_parselist_geterror(ftpwc->parser)) { + /* error found in LIST parsing */ + wildcard->state = CURLWC_CLEAN; + continue; + } + if(wildcard->filelist.size == 0) { + /* no corresponding file */ + wildcard->state = CURLWC_CLEAN; + return CURLE_REMOTE_FILE_NOT_FOUND; + } + continue; + } + + case CURLWC_DOWNLOADING: { + /* filelist has at least one file, lets get first one */ + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; + struct FTP *ftp = data->req.p.ftp; + + char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); + if(!tmp_path) + return CURLE_OUT_OF_MEMORY; + + /* switch default ftp->path and tmp_path */ + free(ftp->pathalloc); + ftp->pathalloc = ftp->path = tmp_path; + + infof(data, "Wildcard - START of \"%s\"", finfo->filename); + if(data->set.chunk_bgn) { + long userresponse; + Curl_set_in_callback(data, true); + userresponse = data->set.chunk_bgn( + finfo, data->set.wildcardptr, (int)wildcard->filelist.size); + Curl_set_in_callback(data, false); + switch(userresponse) { + case CURL_CHUNK_BGN_FUNC_SKIP: + infof(data, "Wildcard - \"%s\" skipped by user", + finfo->filename); + wildcard->state = CURLWC_SKIP; + continue; + case CURL_CHUNK_BGN_FUNC_FAIL: + return CURLE_CHUNK_FAILED; + } + } + + if(finfo->filetype != CURLFILETYPE_FILE) { + wildcard->state = CURLWC_SKIP; + continue; + } + + if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) + ftpc->known_filesize = finfo->size; + + result = ftp_parse_url_path(data); + if(result) + return result; + + /* we don't need the Curl_fileinfo of first file anymore */ + Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); + + if(wildcard->filelist.size == 0) { /* remains only one file to down. */ + wildcard->state = CURLWC_CLEAN; + /* after that will be ftp_do called once again and no transfer + will be done because of CURLWC_CLEAN state */ + return CURLE_OK; + } + return result; + } + + case CURLWC_SKIP: { + if(data->set.chunk_end) { + Curl_set_in_callback(data, true); + data->set.chunk_end(data->set.wildcardptr); + Curl_set_in_callback(data, false); + } + Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); + wildcard->state = (wildcard->filelist.size == 0) ? + CURLWC_CLEAN : CURLWC_DOWNLOADING; + continue; + } + + case CURLWC_CLEAN: { + struct ftp_wc *ftpwc = wildcard->ftpwc; + result = CURLE_OK; + if(ftpwc) + result = Curl_ftp_parselist_geterror(ftpwc->parser); + + wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; + return result; + } + + case CURLWC_DONE: + case CURLWC_ERROR: + case CURLWC_CLEAR: + if(wildcard->dtor) { + wildcard->dtor(wildcard->ftpwc); + wildcard->ftpwc = NULL; + } + return result; + } + } + /* UNREACHABLE */ +} + +/*********************************************************************** + * + * ftp_do() + * + * This function is registered as 'curl_do' function. It decodes the path + * parts etc as a wrapper to the actual DO function (ftp_perform). + * + * The input argument is already checked for validity. + */ +static CURLcode ftp_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + *done = FALSE; /* default to false */ + ftpc->wait_data_conn = FALSE; /* default to no such wait */ + + if(data->state.wildcardmatch) { + result = wc_statemach(data); + if(data->wildcard->state == CURLWC_SKIP || + data->wildcard->state == CURLWC_DONE) { + /* do not call ftp_regular_transfer */ + return CURLE_OK; + } + if(result) /* error, loop or skipping the file */ + return result; + } + else { /* no wildcard FSM needed */ + result = ftp_parse_url_path(data); + if(result) + return result; + } + + result = ftp_regular_transfer(data, done); + + return result; +} + +/*********************************************************************** + * + * ftp_quit() + * + * This should be called before calling sclose() on an ftp control connection + * (not data connections). We should then wait for the response from the + * server before returning. The calling code should then try to close the + * connection. + * + */ +static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if(conn->proto.ftpc.ctl_valid) { + result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT"); + if(result) { + failf(data, "Failure sending QUIT command: %s", + curl_easy_strerror(result)); + conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "QUIT command failed"); /* mark for connection closure */ + ftp_state(data, FTP_STOP); + return result; + } + + ftp_state(data, FTP_QUIT); + + result = ftp_block_statemach(data, conn); + } + + return result; +} + +/*********************************************************************** + * + * ftp_disconnect() + * + * Disconnect from an FTP server. Cleanup protocol-specific per-connection + * resources. BLOCKING. + */ +static CURLcode ftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. + + ftp_quit() will check the state of ftp->ctl_valid. If it's ok it + will try to send the QUIT command, otherwise it will just return. + */ + if(dead_connection) + ftpc->ctl_valid = FALSE; + + /* The FTP session may or may not have been allocated/setup at this point! */ + (void)ftp_quit(data, conn); /* ignore errors on the QUIT */ + + if(ftpc->entrypath) { + if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { + data->state.most_recent_ftp_entrypath = NULL; + } + Curl_safefree(ftpc->entrypath); + } + + freedirs(ftpc); + Curl_safefree(ftpc->account); + Curl_safefree(ftpc->alternative_to_user); + Curl_safefree(ftpc->prevpath); + Curl_safefree(ftpc->server_os); + Curl_pp_disconnect(pp); + Curl_sec_end(conn); + return CURLE_OK; +} + +#ifdef _MSC_VER +/* warning C4706: assignment within conditional expression */ +#pragma warning(disable:4706) +#endif + +/*********************************************************************** + * + * ftp_parse_url_path() + * + * Parse the URL path into separate path components. + * + */ +static +CURLcode ftp_parse_url_path(struct Curl_easy *data) +{ + /* the ftp struct is already inited in ftp_connect() */ + struct FTP *ftp = data->req.p.ftp; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + const char *slashPos = NULL; + const char *fileName = NULL; + CURLcode result = CURLE_OK; + char *rawPath = NULL; /* url-decoded "raw" path */ + size_t pathLen = 0; + + ftpc->ctl_valid = FALSE; + ftpc->cwdfail = FALSE; + + /* url-decode ftp path before further evaluation */ + result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL); + if(result) { + failf(data, "path contains control characters"); + return result; + } + + switch(data->set.ftp_filemethod) { + case FTPFILE_NOCWD: /* fastest, but less standard-compliant */ + + if((pathLen > 0) && (rawPath[pathLen - 1] != '/')) + fileName = rawPath; /* this is a full file path */ + /* + else: ftpc->file is not used anywhere other than for operations on + a file. In other words, never for directory operations. + So we can safely leave filename as NULL here and use it as a + argument in dir/file decisions. + */ + break; + + case FTPFILE_SINGLECWD: + slashPos = strrchr(rawPath, '/'); + if(slashPos) { + /* get path before last slash, except for / */ + size_t dirlen = slashPos - rawPath; + if(dirlen == 0) + dirlen = 1; + + ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); + if(!ftpc->dirs) { + free(rawPath); + return CURLE_OUT_OF_MEMORY; + } + + ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen); + if(!ftpc->dirs[0]) { + free(rawPath); + return CURLE_OUT_OF_MEMORY; + } + + ftpc->dirdepth = 1; /* we consider it to be a single dir */ + fileName = slashPos + 1; /* rest is file name */ + } + else + fileName = rawPath; /* file name only (or empty) */ + break; + + default: /* allow pretty much anything */ + case FTPFILE_MULTICWD: { + /* current position: begin of next path component */ + const char *curPos = rawPath; + + /* number of entries allocated for the 'dirs' array */ + size_t dirAlloc = 0; + const char *str = rawPath; + for(; *str != 0; ++str) + if(*str == '/') + ++dirAlloc; + + if(dirAlloc) { + ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0])); + if(!ftpc->dirs) { + free(rawPath); + return CURLE_OUT_OF_MEMORY; + } + + /* parse the URL path into separate path components */ + while((slashPos = strchr(curPos, '/'))) { + size_t compLen = slashPos - curPos; + + /* path starts with a slash: add that as a directory */ + if((compLen == 0) && (ftpc->dirdepth == 0)) + ++compLen; + + /* we skip empty path components, like "x//y" since the FTP command + CWD requires a parameter and a non-existent parameter a) doesn't + work on many servers and b) has no effect on the others. */ + if(compLen > 0) { + char *comp = Curl_memdup0(curPos, compLen); + if(!comp) { + free(rawPath); + return CURLE_OUT_OF_MEMORY; + } + ftpc->dirs[ftpc->dirdepth++] = comp; + } + curPos = slashPos + 1; + } + } + DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc); + fileName = curPos; /* the rest is the file name (or empty) */ + } + break; + } /* switch */ + + if(fileName && *fileName) + ftpc->file = strdup(fileName); + else + ftpc->file = NULL; /* instead of point to a zero byte, + we make it a NULL pointer */ + + if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) { + /* We need a file name when uploading. Return error! */ + failf(data, "Uploading to a URL without a file name"); + free(rawPath); + return CURLE_URL_MALFORMAT; + } + + ftpc->cwddone = FALSE; /* default to not done */ + + if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) + ftpc->cwddone = TRUE; /* skip CWD for absolute paths */ + else { /* newly created FTP connections are already in entry path */ + const char *oldPath = conn->bits.reuse ? ftpc->prevpath : ""; + if(oldPath) { + size_t n = pathLen; + if(data->set.ftp_filemethod == FTPFILE_NOCWD) + n = 0; /* CWD to entry for relative paths */ + else + n -= ftpc->file?strlen(ftpc->file):0; + + if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) { + infof(data, "Request has same path as previous transfer"); + ftpc->cwddone = TRUE; + } + } + } + + free(rawPath); + return CURLE_OK; +} + +/* call this when the DO phase has completed */ +static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected) +{ + struct connectdata *conn = data->conn; + struct FTP *ftp = data->req.p.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(connected) { + int completed; + CURLcode result = ftp_do_more(data, &completed); + + if(result) { + close_secondarysocket(data, conn); + return result; + } + } + + if(ftp->transfer != PPTRANSFER_BODY) + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + else if(!connected) + /* since we didn't connect now, we want do_more to get called */ + conn->bits.do_more = TRUE; + + ftpc->ctl_valid = TRUE; /* seems good */ + + return CURLE_OK; +} + +/* called from multi.c while DOing */ +static CURLcode ftp_doing(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = ftp_multi_statemach(data, dophase_done); + + if(result) + DEBUGF(infof(data, "DO phase failed")); + else if(*dophase_done) { + result = ftp_dophase_done(data, FALSE /* not connected */); + + DEBUGF(infof(data, "DO phase is complete2")); + } + return result; +} + +/*********************************************************************** + * + * ftp_regular_transfer() + * + * The input argument is already checked for validity. + * + * Performs all commands done before a regular transfer between a local and a + * remote host. + * + * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the + * ftp_done() function without finding any major problem. + */ +static +CURLcode ftp_regular_transfer(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + bool connected = FALSE; + struct connectdata *conn = data->conn; + struct ftp_conn *ftpc = &conn->proto.ftpc; + data->req.size = -1; /* make sure this is unknown at this point */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + ftpc->ctl_valid = TRUE; /* starts good */ + + result = ftp_perform(data, + &connected, /* have we connected after PASV/PORT */ + dophase_done); /* all commands in the DO-phase done? */ + + if(!result) { + + if(!*dophase_done) + /* the DO phase has not completed yet */ + return CURLE_OK; + + result = ftp_dophase_done(data, connected); + + if(result) + return result; + } + else + freedirs(ftpc); + + return result; +} + +static CURLcode ftp_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + char *type; + struct FTP *ftp; + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + ftp = calloc(1, sizeof(struct FTP)); + if(!ftp) + return CURLE_OUT_OF_MEMORY; + + /* clone connection related data that is FTP specific */ + if(data->set.str[STRING_FTP_ACCOUNT]) { + ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]); + if(!ftpc->account) { + free(ftp); + return CURLE_OUT_OF_MEMORY; + } + } + if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) { + ftpc->alternative_to_user = + strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); + if(!ftpc->alternative_to_user) { + Curl_safefree(ftpc->account); + free(ftp); + return CURLE_OUT_OF_MEMORY; + } + } + data->req.p.ftp = ftp; + + ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ + + /* FTP URLs support an extension like ";type=" that + * we'll try to get now! */ + type = strstr(ftp->path, ";type="); + + if(!type) + type = strstr(conn->host.rawalloc, ";type="); + + if(type) { + char command; + *type = 0; /* it was in the middle of the hostname */ + command = Curl_raw_toupper(type[6]); + + switch(command) { + case 'A': /* ASCII mode */ + data->state.prefer_ascii = TRUE; + break; + + case 'D': /* directory mode */ + data->state.list_only = TRUE; + break; + + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->state.prefer_ascii = FALSE; + break; + } + } + + /* get some initial data into the ftp struct */ + ftp->transfer = PPTRANSFER_BODY; + ftp->downloadsize = 0; + ftpc->known_filesize = -1; /* unknown size for now */ + ftpc->use_ssl = data->set.use_ssl; + ftpc->ccc = data->set.ftp_ccc; + + return result; +} + +#endif /* CURL_DISABLE_FTP */ diff --git a/lib/ftp.h b/lib/ftp.h new file mode 100644 index 0000000..977fc88 --- /dev/null +++ b/lib/ftp.h @@ -0,0 +1,167 @@ +#ifndef HEADER_CURL_FTP_H +#define HEADER_CURL_FTP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "pingpong.h" + +#ifndef CURL_DISABLE_FTP +extern const struct Curl_handler Curl_handler_ftp; + +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_ftps; +#endif + +CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nread, + int *ftpcode); +#endif /* CURL_DISABLE_FTP */ + +/**************************************************************************** + * FTP unique setup + ***************************************************************************/ +enum { + FTP_STOP, /* do nothing state, stops the state machine */ + FTP_WAIT220, /* waiting for the initial 220 response immediately after + a connect */ + FTP_AUTH, + FTP_USER, + FTP_PASS, + FTP_ACCT, + FTP_PBSZ, + FTP_PROT, + FTP_CCC, + FTP_PWD, + FTP_SYST, + FTP_NAMEFMT, + FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ + FTP_RETR_PREQUOTE, + FTP_STOR_PREQUOTE, + FTP_POSTQUOTE, + FTP_CWD, /* change dir */ + FTP_MKD, /* if the dir didn't exist */ + FTP_MDTM, /* to figure out the datestamp */ + FTP_TYPE, /* to set type when doing a head-like request */ + FTP_LIST_TYPE, /* set type when about to do a dir list */ + FTP_RETR_TYPE, /* set type when about to RETR a file */ + FTP_STOR_TYPE, /* set type when about to STOR a file */ + FTP_SIZE, /* get the remote file's size for head-like request */ + FTP_RETR_SIZE, /* get the remote file's size for RETR */ + FTP_STOR_SIZE, /* get the size for STOR */ + FTP_REST, /* when used to check if the server supports it in head-like */ + FTP_RETR_REST, /* when asking for "resume" in for RETR */ + FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */ + FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */ + FTP_PASV, /* generic state for PASV and EPSV, check count1 */ + FTP_LIST, /* generic state for LIST, NLST or a custom list command */ + FTP_RETR, + FTP_STOR, /* generic state for STOR and APPE */ + FTP_QUIT, + FTP_LAST /* never used */ +}; +typedef unsigned char ftpstate; /* use the enum values */ + +struct ftp_parselist_data; /* defined later in ftplistparser.c */ + +struct ftp_wc { + struct ftp_parselist_data *parser; + + struct { + curl_write_callback write_function; + FILE *file_descriptor; + } backup; +}; + +typedef enum { + FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */ + FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */ + FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the + file */ +} curl_ftpfile; + +/* This FTP struct is used in the Curl_easy. All FTP data that is + connection-oriented must be in FTP_conn to properly deal with the fact that + perhaps the Curl_easy is changed between the times the connection is + used. */ +struct FTP { + char *path; /* points to the urlpieces struct field */ + char *pathalloc; /* if non-NULL a pointer to an allocated path */ + + /* transfer a file/body or not, done as a typedefed enum just to make + debuggers display the full symbol and not just the numerical value */ + curl_pp_transfer transfer; + curl_off_t downloadsize; +}; + + +/* ftp_conn is used for struct connection-oriented data in the connectdata + struct */ +struct ftp_conn { + struct pingpong pp; + char *account; + char *alternative_to_user; + char *entrypath; /* the PWD reply when we logged on */ + char *file; /* url-decoded file name (or path) */ + char **dirs; /* realloc()ed array for path components */ + char *newhost; + char *prevpath; /* url-decoded conn->path from the previous transfer */ + char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a + and others (A/I or zero) */ + curl_off_t retr_size_saved; /* Size of retrieved file saved */ + char *server_os; /* The target server operating system. */ + curl_off_t known_filesize; /* file size is different from -1, if wildcard + LIST parsing was done and wc_statemach set + it */ + int dirdepth; /* number of entries used in the 'dirs' array */ + int cwdcount; /* number of CWD commands issued */ + int count1; /* general purpose counter for the state machine */ + int count2; /* general purpose counter for the state machine */ + int count3; /* general purpose counter for the state machine */ + /* newhost is the (allocated) IP addr or host name to connect the data + connection to */ + unsigned short newport; + ftpstate state; /* always use ftp.c:state() to change state! */ + ftpstate state_saved; /* transfer type saved to be reloaded after data + connection is established */ + unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or + IMAP or POP3 or others! (type: curl_usessl)*/ + unsigned char ccc; /* ccc level for this connection */ + BIT(ftp_trying_alternative); + BIT(dont_check); /* Set to TRUE to prevent the final (post-transfer) + file size and 226/250 status check. It should still + read the line, just ignore the result. */ + BIT(ctl_valid); /* Tells Curl_ftp_quit() whether or not to do anything. If + the connection has timed out or been closed, this + should be FALSE when it gets to Curl_ftp_quit() */ + BIT(cwddone); /* if it has been determined that the proper CWD combo + already has been done */ + BIT(cwdfail); /* set TRUE if a CWD command fails, as then we must prevent + caching the current directory */ + BIT(wait_data_conn); /* this is set TRUE if data connection is waited */ +}; + +#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */ + +#endif /* HEADER_CURL_FTP_H */ diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c new file mode 100644 index 0000000..82f1ea0 --- /dev/null +++ b/lib/ftplistparser.c @@ -0,0 +1,1041 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/** + * Now implemented: + * + * 1) Unix version 1 + * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog + * 2) Unix version 2 + * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog + * 3) Unix version 3 + * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog + * 4) Unix symlink + * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000 + * 5) DOS style + * 01-29-97 11:32PM prog + */ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_FTP + +#include + +#include "urldata.h" +#include "fileinfo.h" +#include "llist.h" +#include "strtoofft.h" +#include "ftp.h" +#include "ftplistparser.h" +#include "curl_fnmatch.h" +#include "curl_memory.h" +#include "multiif.h" +/* The last #include file should be: */ +#include "memdebug.h" + +typedef enum { + PL_UNIX_TOTALSIZE = 0, + PL_UNIX_FILETYPE, + PL_UNIX_PERMISSION, + PL_UNIX_HLINKS, + PL_UNIX_USER, + PL_UNIX_GROUP, + PL_UNIX_SIZE, + PL_UNIX_TIME, + PL_UNIX_FILENAME, + PL_UNIX_SYMLINK +} pl_unix_mainstate; + +typedef union { + enum { + PL_UNIX_TOTALSIZE_INIT = 0, + PL_UNIX_TOTALSIZE_READING + } total_dirsize; + + enum { + PL_UNIX_HLINKS_PRESPACE = 0, + PL_UNIX_HLINKS_NUMBER + } hlinks; + + enum { + PL_UNIX_USER_PRESPACE = 0, + PL_UNIX_USER_PARSING + } user; + + enum { + PL_UNIX_GROUP_PRESPACE = 0, + PL_UNIX_GROUP_NAME + } group; + + enum { + PL_UNIX_SIZE_PRESPACE = 0, + PL_UNIX_SIZE_NUMBER + } size; + + enum { + PL_UNIX_TIME_PREPART1 = 0, + PL_UNIX_TIME_PART1, + PL_UNIX_TIME_PREPART2, + PL_UNIX_TIME_PART2, + PL_UNIX_TIME_PREPART3, + PL_UNIX_TIME_PART3 + } time; + + enum { + PL_UNIX_FILENAME_PRESPACE = 0, + PL_UNIX_FILENAME_NAME, + PL_UNIX_FILENAME_WINDOWSEOL + } filename; + + enum { + PL_UNIX_SYMLINK_PRESPACE = 0, + PL_UNIX_SYMLINK_NAME, + PL_UNIX_SYMLINK_PRETARGET1, + PL_UNIX_SYMLINK_PRETARGET2, + PL_UNIX_SYMLINK_PRETARGET3, + PL_UNIX_SYMLINK_PRETARGET4, + PL_UNIX_SYMLINK_TARGET, + PL_UNIX_SYMLINK_WINDOWSEOL + } symlink; +} pl_unix_substate; + +typedef enum { + PL_WINNT_DATE = 0, + PL_WINNT_TIME, + PL_WINNT_DIRORSIZE, + PL_WINNT_FILENAME +} pl_winNT_mainstate; + +typedef union { + enum { + PL_WINNT_TIME_PRESPACE = 0, + PL_WINNT_TIME_TIME + } time; + enum { + PL_WINNT_DIRORSIZE_PRESPACE = 0, + PL_WINNT_DIRORSIZE_CONTENT + } dirorsize; + enum { + PL_WINNT_FILENAME_PRESPACE = 0, + PL_WINNT_FILENAME_CONTENT, + PL_WINNT_FILENAME_WINEOL + } filename; +} pl_winNT_substate; + +/* This struct is used in wildcard downloading - for parsing LIST response */ +struct ftp_parselist_data { + enum { + OS_TYPE_UNKNOWN = 0, + OS_TYPE_UNIX, + OS_TYPE_WIN_NT + } os_type; + + union { + struct { + pl_unix_mainstate main; + pl_unix_substate sub; + } UNIX; + + struct { + pl_winNT_mainstate main; + pl_winNT_substate sub; + } NT; + } state; + + CURLcode error; + struct fileinfo *file_data; + unsigned int item_length; + size_t item_offset; + struct { + size_t filename; + size_t user; + size_t group; + size_t time; + size_t perm; + size_t symlink_target; + } offsets; +}; + +static void fileinfo_dtor(void *user, void *element) +{ + (void)user; + Curl_fileinfo_cleanup(element); +} + +CURLcode Curl_wildcard_init(struct WildcardData *wc) +{ + Curl_llist_init(&wc->filelist, fileinfo_dtor); + wc->state = CURLWC_INIT; + + return CURLE_OK; +} + +void Curl_wildcard_dtor(struct WildcardData **wcp) +{ + struct WildcardData *wc = *wcp; + if(!wc) + return; + + if(wc->dtor) { + wc->dtor(wc->ftpwc); + wc->dtor = ZERO_NULL; + wc->ftpwc = NULL; + } + DEBUGASSERT(wc->ftpwc == NULL); + + Curl_llist_destroy(&wc->filelist, NULL); + free(wc->path); + wc->path = NULL; + free(wc->pattern); + wc->pattern = NULL; + wc->state = CURLWC_INIT; + free(wc); + *wcp = NULL; +} + +struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) +{ + return calloc(1, sizeof(struct ftp_parselist_data)); +} + + +void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp) +{ + struct ftp_parselist_data *parser = *parserp; + if(parser) + Curl_fileinfo_cleanup(parser->file_data); + free(parser); + *parserp = NULL; +} + + +CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data) +{ + return pl_data->error; +} + + +#define FTP_LP_MALFORMATED_PERM 0x01000000 + +static unsigned int ftp_pl_get_permission(const char *str) +{ + unsigned int permissions = 0; + /* USER */ + if(str[0] == 'r') + permissions |= 1 << 8; + else if(str[0] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + if(str[1] == 'w') + permissions |= 1 << 7; + else if(str[1] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + + if(str[2] == 'x') + permissions |= 1 << 6; + else if(str[2] == 's') { + permissions |= 1 << 6; + permissions |= 1 << 11; + } + else if(str[2] == 'S') + permissions |= 1 << 11; + else if(str[2] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + /* GROUP */ + if(str[3] == 'r') + permissions |= 1 << 5; + else if(str[3] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + if(str[4] == 'w') + permissions |= 1 << 4; + else if(str[4] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + if(str[5] == 'x') + permissions |= 1 << 3; + else if(str[5] == 's') { + permissions |= 1 << 3; + permissions |= 1 << 10; + } + else if(str[5] == 'S') + permissions |= 1 << 10; + else if(str[5] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + /* others */ + if(str[6] == 'r') + permissions |= 1 << 2; + else if(str[6] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + if(str[7] == 'w') + permissions |= 1 << 1; + else if(str[7] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + if(str[8] == 'x') + permissions |= 1; + else if(str[8] == 't') { + permissions |= 1; + permissions |= 1 << 9; + } + else if(str[8] == 'T') + permissions |= 1 << 9; + else if(str[8] != '-') + permissions |= FTP_LP_MALFORMATED_PERM; + + return permissions; +} + +static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data, + struct fileinfo *infop) +{ + curl_fnmatch_callback compare; + struct WildcardData *wc = data->wildcard; + struct ftp_wc *ftpwc = wc->ftpwc; + struct Curl_llist *llist = &wc->filelist; + struct ftp_parselist_data *parser = ftpwc->parser; + bool add = TRUE; + struct curl_fileinfo *finfo = &infop->info; + + /* set the finfo pointers */ + char *str = Curl_dyn_ptr(&infop->buf); + finfo->filename = str + parser->offsets.filename; + finfo->strings.group = parser->offsets.group ? + str + parser->offsets.group : NULL; + finfo->strings.perm = parser->offsets.perm ? + str + parser->offsets.perm : NULL; + finfo->strings.target = parser->offsets.symlink_target ? + str + parser->offsets.symlink_target : NULL; + finfo->strings.time = str + parser->offsets.time; + finfo->strings.user = parser->offsets.user ? + str + parser->offsets.user : NULL; + + /* get correct fnmatch callback */ + compare = data->set.fnmatch; + if(!compare) + compare = Curl_fnmatch; + + /* filter pattern-corresponding filenames */ + Curl_set_in_callback(data, true); + if(compare(data->set.fnmatch_data, wc->pattern, + finfo->filename) == 0) { + /* discard symlink which is containing multiple " -> " */ + if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target && + (strstr(finfo->strings.target, " -> "))) { + add = FALSE; + } + } + else { + add = FALSE; + } + Curl_set_in_callback(data, false); + + if(add) { + Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list); + } + else { + Curl_fileinfo_cleanup(infop); + } + + ftpwc->parser->file_data = NULL; + return CURLE_OK; +} + +#define MAX_FTPLIST_BUFFER 10000 /* arbitrarily set */ + +size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, + void *connptr) +{ + size_t bufflen = size*nmemb; + struct Curl_easy *data = (struct Curl_easy *)connptr; + struct ftp_wc *ftpwc = data->wildcard->ftpwc; + struct ftp_parselist_data *parser = ftpwc->parser; + size_t i = 0; + CURLcode result; + size_t retsize = bufflen; + + if(parser->error) { /* error in previous call */ + /* scenario: + * 1. call => OK.. + * 2. call => OUT_OF_MEMORY (or other error) + * 3. (last) call => is skipped RIGHT HERE and the error is handled later + * in wc_statemach() + */ + goto fail; + } + + if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) { + /* considering info about FILE response format */ + parser->os_type = ISDIGIT(buffer[0]) ? OS_TYPE_WIN_NT : OS_TYPE_UNIX; + } + + while(i < bufflen) { /* FSM */ + char *mem; + size_t len; /* number of bytes of data in the dynbuf */ + char c = buffer[i]; + struct fileinfo *infop; + struct curl_fileinfo *finfo; + if(!parser->file_data) { /* tmp file data is not allocated yet */ + parser->file_data = Curl_fileinfo_alloc(); + if(!parser->file_data) { + parser->error = CURLE_OUT_OF_MEMORY; + goto fail; + } + parser->item_offset = 0; + parser->item_length = 0; + Curl_dyn_init(&parser->file_data->buf, MAX_FTPLIST_BUFFER); + } + + infop = parser->file_data; + finfo = &infop->info; + + if(Curl_dyn_addn(&infop->buf, &c, 1)) { + parser->error = CURLE_OUT_OF_MEMORY; + goto fail; + } + len = Curl_dyn_len(&infop->buf); + mem = Curl_dyn_ptr(&infop->buf); + + switch(parser->os_type) { + case OS_TYPE_UNIX: + switch(parser->state.UNIX.main) { + case PL_UNIX_TOTALSIZE: + switch(parser->state.UNIX.sub.total_dirsize) { + case PL_UNIX_TOTALSIZE_INIT: + if(c == 't') { + parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING; + parser->item_length++; + } + else { + parser->state.UNIX.main = PL_UNIX_FILETYPE; + /* start FSM again not considering size of directory */ + Curl_dyn_reset(&infop->buf); + continue; + } + break; + case PL_UNIX_TOTALSIZE_READING: + parser->item_length++; + if(c == '\r') { + parser->item_length--; + Curl_dyn_setlen(&infop->buf, --len); + } + else if(c == '\n') { + mem[parser->item_length - 1] = 0; + if(!strncmp("total ", mem, 6)) { + char *endptr = mem + 6; + /* here we can deal with directory size, pass the leading + whitespace and then the digits */ + while(ISBLANK(*endptr)) + endptr++; + while(ISDIGIT(*endptr)) + endptr++; + if(*endptr) { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + parser->state.UNIX.main = PL_UNIX_FILETYPE; + Curl_dyn_reset(&infop->buf); + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + break; + } + break; + case PL_UNIX_FILETYPE: + switch(c) { + case '-': + finfo->filetype = CURLFILETYPE_FILE; + break; + case 'd': + finfo->filetype = CURLFILETYPE_DIRECTORY; + break; + case 'l': + finfo->filetype = CURLFILETYPE_SYMLINK; + break; + case 'p': + finfo->filetype = CURLFILETYPE_NAMEDPIPE; + break; + case 's': + finfo->filetype = CURLFILETYPE_SOCKET; + break; + case 'c': + finfo->filetype = CURLFILETYPE_DEVICE_CHAR; + break; + case 'b': + finfo->filetype = CURLFILETYPE_DEVICE_BLOCK; + break; + case 'D': + finfo->filetype = CURLFILETYPE_DOOR; + break; + default: + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + parser->state.UNIX.main = PL_UNIX_PERMISSION; + parser->item_length = 0; + parser->item_offset = 1; + break; + case PL_UNIX_PERMISSION: + parser->item_length++; + if(parser->item_length <= 9) { + if(!strchr("rwx-tTsS", c)) { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + else if(parser->item_length == 10) { + unsigned int perm; + if(c != ' ') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + mem[10] = 0; /* terminate permissions */ + perm = ftp_pl_get_permission(mem + parser->item_offset); + if(perm & FTP_LP_MALFORMATED_PERM) { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM; + parser->file_data->info.perm = perm; + parser->offsets.perm = parser->item_offset; + + parser->item_length = 0; + parser->state.UNIX.main = PL_UNIX_HLINKS; + parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE; + } + break; + case PL_UNIX_HLINKS: + switch(parser->state.UNIX.sub.hlinks) { + case PL_UNIX_HLINKS_PRESPACE: + if(c != ' ') { + if(ISDIGIT(c)) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + break; + case PL_UNIX_HLINKS_NUMBER: + parser->item_length ++; + if(c == ' ') { + char *p; + long int hlinks; + mem[parser->item_offset + parser->item_length - 1] = 0; + hlinks = strtol(mem + parser->item_offset, &p, 10); + if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) { + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; + parser->file_data->info.hardlinks = hlinks; + } + parser->item_length = 0; + parser->item_offset = 0; + parser->state.UNIX.main = PL_UNIX_USER; + parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE; + } + else if(!ISDIGIT(c)) { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + } + break; + case PL_UNIX_USER: + switch(parser->state.UNIX.sub.user) { + case PL_UNIX_USER_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING; + } + break; + case PL_UNIX_USER_PARSING: + parser->item_length++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.user = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_GROUP; + parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE; + parser->item_offset = 0; + parser->item_length = 0; + } + break; + } + break; + case PL_UNIX_GROUP: + switch(parser->state.UNIX.sub.group) { + case PL_UNIX_GROUP_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME; + } + break; + case PL_UNIX_GROUP_NAME: + parser->item_length++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.group = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_SIZE; + parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE; + parser->item_offset = 0; + parser->item_length = 0; + } + break; + } + break; + case PL_UNIX_SIZE: + switch(parser->state.UNIX.sub.size) { + case PL_UNIX_SIZE_PRESPACE: + if(c != ' ') { + if(ISDIGIT(c)) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + break; + case PL_UNIX_SIZE_NUMBER: + parser->item_length++; + if(c == ' ') { + char *p; + curl_off_t fsize; + mem[parser->item_offset + parser->item_length - 1] = 0; + if(!curlx_strtoofft(mem + parser->item_offset, + &p, 10, &fsize)) { + if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && + fsize != CURL_OFF_T_MIN) { + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; + parser->file_data->info.size = fsize; + } + parser->item_length = 0; + parser->item_offset = 0; + parser->state.UNIX.main = PL_UNIX_TIME; + parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; + } + } + else if(!ISDIGIT(c)) { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + } + break; + case PL_UNIX_TIME: + switch(parser->state.UNIX.sub.time) { + case PL_UNIX_TIME_PREPART1: + if(c != ' ') { + if(ISALNUM(c)) { + parser->item_offset = len -1; + parser->item_length = 1; + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + break; + case PL_UNIX_TIME_PART1: + parser->item_length++; + if(c == ' ') { + parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2; + } + else if(!ISALNUM(c) && c != '.') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + case PL_UNIX_TIME_PREPART2: + parser->item_length++; + if(c != ' ') { + if(ISALNUM(c)) { + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + break; + case PL_UNIX_TIME_PART2: + parser->item_length++; + if(c == ' ') { + parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3; + } + else if(!ISALNUM(c) && c != '.') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + case PL_UNIX_TIME_PREPART3: + parser->item_length++; + if(c != ' ') { + if(ISALNUM(c)) { + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + break; + case PL_UNIX_TIME_PART3: + parser->item_length++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length -1] = 0; + parser->offsets.time = parser->item_offset; + /* + if(ftp_pl_gettime(parser, finfo->mem + parser->item_offset)) { + parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; + } + */ + if(finfo->filetype == CURLFILETYPE_SYMLINK) { + parser->state.UNIX.main = PL_UNIX_SYMLINK; + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; + } + else { + parser->state.UNIX.main = PL_UNIX_FILENAME; + parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE; + } + } + else if(!ISALNUM(c) && c != '.' && c != ':') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + } + break; + case PL_UNIX_FILENAME: + switch(parser->state.UNIX.sub.filename) { + case PL_UNIX_FILENAME_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME; + } + break; + case PL_UNIX_FILENAME_NAME: + parser->item_length++; + if(c == '\r') { + parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; + } + else if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.filename = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_FILETYPE; + result = ftp_pl_insert_finfo(data, infop); + if(result) { + parser->error = result; + goto fail; + } + } + break; + case PL_UNIX_FILENAME_WINDOWSEOL: + if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.filename = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_FILETYPE; + result = ftp_pl_insert_finfo(data, infop); + if(result) { + parser->error = result; + goto fail; + } + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + } + break; + case PL_UNIX_SYMLINK: + switch(parser->state.UNIX.sub.symlink) { + case PL_UNIX_SYMLINK_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + } + break; + case PL_UNIX_SYMLINK_NAME: + parser->item_length++; + if(c == ' ') { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1; + } + else if(c == '\r' || c == '\n') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + case PL_UNIX_SYMLINK_PRETARGET1: + parser->item_length++; + if(c == '-') { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2; + } + else if(c == '\r' || c == '\n') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + else { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + } + break; + case PL_UNIX_SYMLINK_PRETARGET2: + parser->item_length++; + if(c == '>') { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3; + } + else if(c == '\r' || c == '\n') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + else { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + } + break; + case PL_UNIX_SYMLINK_PRETARGET3: + parser->item_length++; + if(c == ' ') { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4; + /* now place where is symlink following */ + mem[parser->item_offset + parser->item_length - 4] = 0; + parser->offsets.filename = parser->item_offset; + parser->item_length = 0; + parser->item_offset = 0; + } + else if(c == '\r' || c == '\n') { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + else { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + } + break; + case PL_UNIX_SYMLINK_PRETARGET4: + if(c != '\r' && c != '\n') { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET; + parser->item_offset = len - 1; + parser->item_length = 1; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + case PL_UNIX_SYMLINK_TARGET: + parser->item_length++; + if(c == '\r') { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; + } + else if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.symlink_target = parser->item_offset; + result = ftp_pl_insert_finfo(data, infop); + if(result) { + parser->error = result; + goto fail; + } + parser->state.UNIX.main = PL_UNIX_FILETYPE; + } + break; + case PL_UNIX_SYMLINK_WINDOWSEOL: + if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.symlink_target = parser->item_offset; + result = ftp_pl_insert_finfo(data, infop); + if(result) { + parser->error = result; + goto fail; + } + parser->state.UNIX.main = PL_UNIX_FILETYPE; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + } + break; + } + break; + case OS_TYPE_WIN_NT: + switch(parser->state.NT.main) { + case PL_WINNT_DATE: + parser->item_length++; + if(parser->item_length < 9) { + if(!strchr("0123456789-", c)) { /* only simple control */ + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + else if(parser->item_length == 9) { + if(c == ' ') { + parser->state.NT.main = PL_WINNT_TIME; + parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + case PL_WINNT_TIME: + parser->item_length++; + switch(parser->state.NT.sub.time) { + case PL_WINNT_TIME_PRESPACE: + if(!ISBLANK(c)) { + parser->state.NT.sub.time = PL_WINNT_TIME_TIME; + } + break; + case PL_WINNT_TIME_TIME: + if(c == ' ') { + parser->offsets.time = parser->item_offset; + mem[parser->item_offset + parser->item_length -1] = 0; + parser->state.NT.main = PL_WINNT_DIRORSIZE; + parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE; + parser->item_length = 0; + } + else if(!strchr("APM0123456789:", c)) { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + } + break; + case PL_WINNT_DIRORSIZE: + switch(parser->state.NT.sub.dirorsize) { + case PL_WINNT_DIRORSIZE_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT; + } + break; + case PL_WINNT_DIRORSIZE_CONTENT: + parser->item_length ++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length - 1] = 0; + if(strcmp("", mem + parser->item_offset) == 0) { + finfo->filetype = CURLFILETYPE_DIRECTORY; + finfo->size = 0; + } + else { + char *endptr; + if(curlx_strtoofft(mem + + parser->item_offset, + &endptr, 10, &finfo->size)) { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + /* correct file type */ + parser->file_data->info.filetype = CURLFILETYPE_FILE; + } + + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; + parser->item_length = 0; + parser->state.NT.main = PL_WINNT_FILENAME; + parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; + } + break; + } + break; + case PL_WINNT_FILENAME: + switch(parser->state.NT.sub.filename) { + case PL_WINNT_FILENAME_PRESPACE: + if(c != ' ') { + parser->item_offset = len -1; + parser->item_length = 1; + parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT; + } + break; + case PL_WINNT_FILENAME_CONTENT: + parser->item_length++; + if(c == '\r') { + parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL; + mem[len - 1] = 0; + } + else if(c == '\n') { + parser->offsets.filename = parser->item_offset; + mem[len - 1] = 0; + result = ftp_pl_insert_finfo(data, infop); + if(result) { + parser->error = result; + goto fail; + } + parser->state.NT.main = PL_WINNT_DATE; + parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; + } + break; + case PL_WINNT_FILENAME_WINEOL: + if(c == '\n') { + parser->offsets.filename = parser->item_offset; + result = ftp_pl_insert_finfo(data, infop); + if(result) { + parser->error = result; + goto fail; + } + parser->state.NT.main = PL_WINNT_DATE; + parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; + } + else { + parser->error = CURLE_FTP_BAD_FILE_LIST; + goto fail; + } + break; + } + break; + } + break; + default: + retsize = bufflen + 1; + goto fail; + } + + i++; + } + return retsize; + +fail: + + /* Clean up any allocated memory. */ + if(parser->file_data) { + Curl_fileinfo_cleanup(parser->file_data); + parser->file_data = NULL; + } + + return retsize; +} + +#endif /* CURL_DISABLE_FTP */ diff --git a/lib/ftplistparser.h b/lib/ftplistparser.h new file mode 100644 index 0000000..5ba1f6a --- /dev/null +++ b/lib/ftplistparser.h @@ -0,0 +1,77 @@ +#ifndef HEADER_CURL_FTPLISTPARSER_H +#define HEADER_CURL_FTPLISTPARSER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifndef CURL_DISABLE_FTP + +/* WRITEFUNCTION callback for parsing LIST responses */ +size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, + void *connptr); + +struct ftp_parselist_data; /* defined inside ftplibparser.c */ + +CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data); + +struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void); + +void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data); + +/* list of wildcard process states */ +typedef enum { + CURLWC_CLEAR = 0, + CURLWC_INIT = 1, + CURLWC_MATCHING, /* library is trying to get list of addresses for + downloading */ + CURLWC_DOWNLOADING, + CURLWC_CLEAN, /* deallocate resources and reset settings */ + CURLWC_SKIP, /* skip over concrete file */ + CURLWC_ERROR, /* error cases */ + CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop + will end */ +} wildcard_states; + +typedef void (*wildcard_dtor)(void *ptr); + +/* struct keeping information about wildcard download process */ +struct WildcardData { + char *path; /* path to the directory, where we trying wildcard-match */ + char *pattern; /* wildcard pattern */ + struct Curl_llist filelist; /* llist with struct Curl_fileinfo */ + struct ftp_wc *ftpwc; /* pointer to FTP wildcard data */ + wildcard_dtor dtor; + unsigned char state; /* wildcard_states */ +}; + +CURLcode Curl_wildcard_init(struct WildcardData *wc); +void Curl_wildcard_dtor(struct WildcardData **wcp); + +struct Curl_easy; + +#else +/* FTP is disabled */ +#define Curl_wildcard_dtor(x) +#endif /* CURL_DISABLE_FTP */ +#endif /* HEADER_CURL_FTPLISTPARSER_H */ diff --git a/lib/functypes.h b/lib/functypes.h new file mode 100644 index 0000000..ea66d32 --- /dev/null +++ b/lib/functypes.h @@ -0,0 +1,115 @@ +#ifndef HEADER_CURL_FUNCTYPES_H +#define HEADER_CURL_FUNCTYPES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/* defaults: + + ssize_t recv(int, void *, size_t, int); + ssize_t send(int, const void *, size_t, int); + + If other argument or return types are needed: + + 1. For systems that run configure or cmake, the alternatives are provided + here. + 2. For systems with config-*.h files, define them there. +*/ + +#ifdef _WIN32 +/* int recv(SOCKET, char *, int, int) */ +#define RECV_TYPE_ARG1 SOCKET +#define RECV_TYPE_ARG2 char * +#define RECV_TYPE_ARG3 int +#define RECV_TYPE_RETV int + +/* int send(SOCKET, const char *, int, int); */ +#define SEND_TYPE_ARG1 SOCKET +#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_RETV int + +#elif defined(__AMIGA__) /* Any AmigaOS flavour */ + +/* long recv(long, char *, long, long); */ +#define RECV_TYPE_ARG1 long +#define RECV_TYPE_ARG2 char * +#define RECV_TYPE_ARG3 long +#define RECV_TYPE_ARG4 long +#define RECV_TYPE_RETV long + +/* int send(int, const char *, int, int); */ +#define SEND_TYPE_ARG1 int +#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_RETV int +#endif + + +#ifndef RECV_TYPE_ARG1 +#define RECV_TYPE_ARG1 int +#endif + +#ifndef RECV_TYPE_ARG2 +#define RECV_TYPE_ARG2 void * +#endif + +#ifndef RECV_TYPE_ARG3 +#define RECV_TYPE_ARG3 size_t +#endif + +#ifndef RECV_TYPE_ARG4 +#define RECV_TYPE_ARG4 int +#endif + +#ifndef RECV_TYPE_RETV +#define RECV_TYPE_RETV ssize_t +#endif + +#ifndef SEND_QUAL_ARG2 +#define SEND_QUAL_ARG2 const +#endif + +#ifndef SEND_TYPE_ARG1 +#define SEND_TYPE_ARG1 int +#endif + +#ifndef SEND_TYPE_ARG2 +#define SEND_TYPE_ARG2 void * +#endif + +#ifndef SEND_TYPE_ARG3 +#define SEND_TYPE_ARG3 size_t +#endif + +#ifndef SEND_TYPE_ARG4 +#define SEND_TYPE_ARG4 int +#endif + +#ifndef SEND_TYPE_RETV +#define SEND_TYPE_RETV ssize_t +#endif + +#endif /* HEADER_CURL_FUNCTYPES_H */ diff --git a/lib/getenv.c b/lib/getenv.c new file mode 100644 index 0000000..48ee972 --- /dev/null +++ b/lib/getenv.c @@ -0,0 +1,80 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "curl_memory.h" + +#include "memdebug.h" + +static char *GetEnv(const char *variable) +{ +#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) || \ + defined(__ORBIS__) || defined(__PROSPERO__) /* PlayStation 4 and 5 */ + (void)variable; + return NULL; +#elif defined(_WIN32) + /* This uses Windows API instead of C runtime getenv() to get the environment + variable since some changes aren't always visible to the latter. #4774 */ + char *buf = NULL; + char *tmp; + DWORD bufsize; + DWORD rc = 1; + const DWORD max = 32768; /* max env var size from MSCRT source */ + + for(;;) { + tmp = realloc(buf, rc); + if(!tmp) { + free(buf); + return NULL; + } + + buf = tmp; + bufsize = rc; + + /* It's possible for rc to be 0 if the variable was found but empty. + Since getenv doesn't make that distinction we ignore it as well. */ + rc = GetEnvironmentVariableA(variable, buf, bufsize); + if(!rc || rc == bufsize || rc > max) { + free(buf); + return NULL; + } + + /* if rc < bufsize then rc is bytes written not including null */ + if(rc < bufsize) + return buf; + + /* else rc is bytes needed, try again */ + } +#else + char *env = getenv(variable); + return (env && env[0])?strdup(env):NULL; +#endif +} + +char *curl_getenv(const char *v) +{ + return GetEnv(v); +} diff --git a/lib/getinfo.c b/lib/getinfo.c new file mode 100644 index 0000000..2f74629 --- /dev/null +++ b/lib/getinfo.c @@ -0,0 +1,628 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "urldata.h" +#include "getinfo.h" + +#include "vtls/vtls.h" +#include "connect.h" /* Curl_getconnectinfo() */ +#include "progress.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Initialize statistical and informational data. + * + * This function is called in curl_easy_reset, curl_easy_duphandle and at the + * beginning of a perform session. It must reset the session-info variables, + * in particular all variables in struct PureInfo. + */ +CURLcode Curl_initinfo(struct Curl_easy *data) +{ + struct Progress *pro = &data->progress; + struct PureInfo *info = &data->info; + + pro->t_nslookup = 0; + pro->t_connect = 0; + pro->t_appconnect = 0; + pro->t_pretransfer = 0; + pro->t_starttransfer = 0; + pro->timespent = 0; + pro->t_redirect = 0; + pro->is_t_startransfer_set = false; + + info->httpcode = 0; + info->httpproxycode = 0; + info->httpversion = 0; + info->filetime = -1; /* -1 is an illegal time and thus means unknown */ + info->timecond = FALSE; + + info->header_size = 0; + info->request_size = 0; + info->proxyauthavail = 0; + info->httpauthavail = 0; + info->numconnects = 0; + + free(info->contenttype); + info->contenttype = NULL; + + free(info->wouldredirect); + info->wouldredirect = NULL; + + info->conn_primary_ip[0] = '\0'; + info->conn_local_ip[0] = '\0'; + info->conn_primary_port = 0; + info->conn_local_port = 0; + info->retry_after = 0; + + info->conn_scheme = 0; + info->conn_protocol = 0; + +#ifdef USE_SSL + Curl_ssl_free_certinfo(data); +#endif + return CURLE_OK; +} + +static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, + const char **param_charp) +{ + switch(info) { + case CURLINFO_EFFECTIVE_URL: + *param_charp = data->state.url?data->state.url:(char *)""; + break; + case CURLINFO_EFFECTIVE_METHOD: { + const char *m = data->set.str[STRING_CUSTOMREQUEST]; + if(!m) { + if(data->set.opt_no_body) + m = "HEAD"; +#ifndef CURL_DISABLE_HTTP + else { + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + m = "POST"; + break; + case HTTPREQ_PUT: + m = "PUT"; + break; + default: /* this should never happen */ + case HTTPREQ_GET: + m = "GET"; + break; + case HTTPREQ_HEAD: + m = "HEAD"; + break; + } + } +#endif + } + *param_charp = m; + } + break; + case CURLINFO_CONTENT_TYPE: + *param_charp = data->info.contenttype; + break; + case CURLINFO_PRIVATE: + *param_charp = (char *) data->set.private_data; + break; + case CURLINFO_FTP_ENTRY_PATH: + /* Return the entrypath string from the most recent connection. + This pointer was copied from the connectdata structure by FTP. + The actual string may be free()ed by subsequent libcurl calls so + it must be copied to a safer area before the next libcurl call. + Callers must never free it themselves. */ + *param_charp = data->state.most_recent_ftp_entrypath; + break; + case CURLINFO_REDIRECT_URL: + /* Return the URL this request would have been redirected to if that + option had been enabled! */ + *param_charp = data->info.wouldredirect; + break; + case CURLINFO_REFERER: + /* Return the referrer header for this request, or NULL if unset */ + *param_charp = data->state.referer; + break; + case CURLINFO_PRIMARY_IP: + /* Return the ip address of the most recent (primary) connection */ + *param_charp = data->info.conn_primary_ip; + break; + case CURLINFO_LOCAL_IP: + /* Return the source/local ip address of the most recent (primary) + connection */ + *param_charp = data->info.conn_local_ip; + break; + case CURLINFO_RTSP_SESSION_ID: + *param_charp = data->set.str[STRING_RTSP_SESSION_ID]; + break; + case CURLINFO_SCHEME: + *param_charp = data->info.conn_scheme; + break; + case CURLINFO_CAPATH: +#ifdef CURL_CA_PATH + *param_charp = CURL_CA_PATH; +#else + *param_charp = NULL; +#endif + break; + case CURLINFO_CAINFO: +#ifdef CURL_CA_BUNDLE + *param_charp = CURL_CA_BUNDLE; +#else + *param_charp = NULL; +#endif + break; + + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, + long *param_longp) +{ + curl_socket_t sockfd; + + union { + unsigned long *to_ulong; + long *to_long; + } lptr; + +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_LOCAL_PORT: + *param_longp = (long)val; + return CURLE_OK; + default: + break; + } + } + /* use another variable for this to allow different values */ + timestr = getenv("CURL_DEBUG_SIZE"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_HEADER_SIZE: + case CURLINFO_REQUEST_SIZE: + *param_longp = (long)val; + return CURLE_OK; + default: + break; + } + } +#endif + + switch(info) { + case CURLINFO_RESPONSE_CODE: + *param_longp = data->info.httpcode; + break; + case CURLINFO_HTTP_CONNECTCODE: + *param_longp = data->info.httpproxycode; + break; + case CURLINFO_FILETIME: + if(data->info.filetime > LONG_MAX) + *param_longp = LONG_MAX; + else if(data->info.filetime < LONG_MIN) + *param_longp = LONG_MIN; + else + *param_longp = (long)data->info.filetime; + break; + case CURLINFO_HEADER_SIZE: + *param_longp = (long)data->info.header_size; + break; + case CURLINFO_REQUEST_SIZE: + *param_longp = (long)data->info.request_size; + break; + case CURLINFO_SSL_VERIFYRESULT: + *param_longp = data->set.ssl.certverifyresult; + break; +#ifndef CURL_DISABLE_PROXY + case CURLINFO_PROXY_SSL_VERIFYRESULT: + *param_longp = data->set.proxy_ssl.certverifyresult; + break; +#endif + case CURLINFO_REDIRECT_COUNT: + *param_longp = data->state.followlocation; + break; + case CURLINFO_HTTPAUTH_AVAIL: + lptr.to_long = param_longp; + *lptr.to_ulong = data->info.httpauthavail; + break; + case CURLINFO_PROXYAUTH_AVAIL: + lptr.to_long = param_longp; + *lptr.to_ulong = data->info.proxyauthavail; + break; + case CURLINFO_OS_ERRNO: + *param_longp = data->state.os_errno; + break; + case CURLINFO_NUM_CONNECTS: + *param_longp = data->info.numconnects; + break; + case CURLINFO_LASTSOCKET: + sockfd = Curl_getconnectinfo(data, NULL); + + /* note: this is not a good conversion for systems with 64 bit sockets and + 32 bit longs */ + if(sockfd != CURL_SOCKET_BAD) + *param_longp = (long)sockfd; + else + /* this interface is documented to return -1 in case of badness, which + may not be the same as the CURL_SOCKET_BAD value */ + *param_longp = -1; + break; + case CURLINFO_PRIMARY_PORT: + /* Return the (remote) port of the most recent (primary) connection */ + *param_longp = data->info.conn_primary_port; + break; + case CURLINFO_LOCAL_PORT: + /* Return the local port of the most recent (primary) connection */ + *param_longp = data->info.conn_local_port; + break; + case CURLINFO_PROXY_ERROR: + *param_longp = (long)data->info.pxcode; + break; + case CURLINFO_CONDITION_UNMET: + if(data->info.httpcode == 304) + *param_longp = 1L; + else + /* return if the condition prevented the document to get transferred */ + *param_longp = data->info.timecond ? 1L : 0L; + break; +#ifndef CURL_DISABLE_RTSP + case CURLINFO_RTSP_CLIENT_CSEQ: + *param_longp = data->state.rtsp_next_client_CSeq; + break; + case CURLINFO_RTSP_SERVER_CSEQ: + *param_longp = data->state.rtsp_next_server_CSeq; + break; + case CURLINFO_RTSP_CSEQ_RECV: + *param_longp = data->state.rtsp_CSeq_recv; + break; +#endif + case CURLINFO_HTTP_VERSION: + switch(data->info.httpversion) { + case 10: + *param_longp = CURL_HTTP_VERSION_1_0; + break; + case 11: + *param_longp = CURL_HTTP_VERSION_1_1; + break; + case 20: + *param_longp = CURL_HTTP_VERSION_2_0; + break; + case 30: + *param_longp = CURL_HTTP_VERSION_3; + break; + default: + *param_longp = CURL_HTTP_VERSION_NONE; + break; + } + break; + case CURLINFO_PROTOCOL: + *param_longp = data->info.conn_protocol; + break; + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +#define DOUBLE_SECS(x) (double)(x)/1000000 + +static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, + curl_off_t *param_offt) +{ +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_TOTAL_TIME_T: + case CURLINFO_NAMELOOKUP_TIME_T: + case CURLINFO_CONNECT_TIME_T: + case CURLINFO_APPCONNECT_TIME_T: + case CURLINFO_PRETRANSFER_TIME_T: + case CURLINFO_STARTTRANSFER_TIME_T: + case CURLINFO_REDIRECT_TIME_T: + case CURLINFO_SPEED_DOWNLOAD_T: + case CURLINFO_SPEED_UPLOAD_T: + *param_offt = (curl_off_t)val; + return CURLE_OK; + default: + break; + } + } +#endif + switch(info) { + case CURLINFO_FILETIME_T: + *param_offt = (curl_off_t)data->info.filetime; + break; + case CURLINFO_SIZE_UPLOAD_T: + *param_offt = data->progress.uploaded; + break; + case CURLINFO_SIZE_DOWNLOAD_T: + *param_offt = data->progress.downloaded; + break; + case CURLINFO_SPEED_DOWNLOAD_T: + *param_offt = data->progress.dlspeed; + break; + case CURLINFO_SPEED_UPLOAD_T: + *param_offt = data->progress.ulspeed; + break; + case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T: + *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? + data->progress.size_dl:-1; + break; + case CURLINFO_CONTENT_LENGTH_UPLOAD_T: + *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? + data->progress.size_ul:-1; + break; + case CURLINFO_TOTAL_TIME_T: + *param_offt = data->progress.timespent; + break; + case CURLINFO_NAMELOOKUP_TIME_T: + *param_offt = data->progress.t_nslookup; + break; + case CURLINFO_CONNECT_TIME_T: + *param_offt = data->progress.t_connect; + break; + case CURLINFO_APPCONNECT_TIME_T: + *param_offt = data->progress.t_appconnect; + break; + case CURLINFO_PRETRANSFER_TIME_T: + *param_offt = data->progress.t_pretransfer; + break; + case CURLINFO_STARTTRANSFER_TIME_T: + *param_offt = data->progress.t_starttransfer; + break; + case CURLINFO_QUEUE_TIME_T: + *param_offt = data->progress.t_postqueue; + break; + case CURLINFO_REDIRECT_TIME_T: + *param_offt = data->progress.t_redirect; + break; + case CURLINFO_RETRY_AFTER: + *param_offt = data->info.retry_after; + break; + case CURLINFO_XFER_ID: + *param_offt = data->id; + break; + case CURLINFO_CONN_ID: + *param_offt = data->conn? + data->conn->connection_id : data->state.recent_conn_id; + break; + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, + double *param_doublep) +{ +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_TOTAL_TIME: + case CURLINFO_NAMELOOKUP_TIME: + case CURLINFO_CONNECT_TIME: + case CURLINFO_APPCONNECT_TIME: + case CURLINFO_PRETRANSFER_TIME: + case CURLINFO_STARTTRANSFER_TIME: + case CURLINFO_REDIRECT_TIME: + case CURLINFO_SPEED_DOWNLOAD: + case CURLINFO_SPEED_UPLOAD: + *param_doublep = (double)val; + return CURLE_OK; + default: + break; + } + } +#endif + switch(info) { + case CURLINFO_TOTAL_TIME: + *param_doublep = DOUBLE_SECS(data->progress.timespent); + break; + case CURLINFO_NAMELOOKUP_TIME: + *param_doublep = DOUBLE_SECS(data->progress.t_nslookup); + break; + case CURLINFO_CONNECT_TIME: + *param_doublep = DOUBLE_SECS(data->progress.t_connect); + break; + case CURLINFO_APPCONNECT_TIME: + *param_doublep = DOUBLE_SECS(data->progress.t_appconnect); + break; + case CURLINFO_PRETRANSFER_TIME: + *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer); + break; + case CURLINFO_STARTTRANSFER_TIME: + *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer); + break; + case CURLINFO_SIZE_UPLOAD: + *param_doublep = (double)data->progress.uploaded; + break; + case CURLINFO_SIZE_DOWNLOAD: + *param_doublep = (double)data->progress.downloaded; + break; + case CURLINFO_SPEED_DOWNLOAD: + *param_doublep = (double)data->progress.dlspeed; + break; + case CURLINFO_SPEED_UPLOAD: + *param_doublep = (double)data->progress.ulspeed; + break; + case CURLINFO_CONTENT_LENGTH_DOWNLOAD: + *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? + (double)data->progress.size_dl:-1; + break; + case CURLINFO_CONTENT_LENGTH_UPLOAD: + *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? + (double)data->progress.size_ul:-1; + break; + case CURLINFO_REDIRECT_TIME: + *param_doublep = DOUBLE_SECS(data->progress.t_redirect); + break; + + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, + struct curl_slist **param_slistp) +{ + union { + struct curl_certinfo *to_certinfo; + struct curl_slist *to_slist; + } ptr; + + switch(info) { + case CURLINFO_SSL_ENGINES: + *param_slistp = Curl_ssl_engines_list(data); + break; + case CURLINFO_COOKIELIST: + *param_slistp = Curl_cookie_list(data); + break; + case CURLINFO_CERTINFO: + /* Return the a pointer to the certinfo struct. Not really an slist + pointer but we can pretend it is here */ + ptr.to_certinfo = &data->info.certs; + *param_slistp = ptr.to_slist; + break; + case CURLINFO_TLS_SESSION: + case CURLINFO_TLS_SSL_PTR: + { + struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) + param_slistp; + struct curl_tlssessioninfo *tsi = &data->tsi; +#ifdef USE_SSL + struct connectdata *conn = data->conn; +#endif + + *tsip = tsi; + tsi->backend = Curl_ssl_backend(); + tsi->internals = NULL; + +#ifdef USE_SSL + if(conn && tsi->backend != CURLSSLBACKEND_NONE) { + tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0); + } +#endif + } + break; + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info, + curl_socket_t *param_socketp) +{ + switch(info) { + case CURLINFO_ACTIVESOCKET: + *param_socketp = Curl_getconnectinfo(data, NULL); + break; + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) +{ + va_list arg; + long *param_longp = NULL; + double *param_doublep = NULL; + curl_off_t *param_offt = NULL; + const char **param_charp = NULL; + struct curl_slist **param_slistp = NULL; + curl_socket_t *param_socketp = NULL; + int type; + CURLcode result = CURLE_UNKNOWN_OPTION; + + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + va_start(arg, info); + + type = CURLINFO_TYPEMASK & (int)info; + switch(type) { + case CURLINFO_STRING: + param_charp = va_arg(arg, const char **); + if(param_charp) + result = getinfo_char(data, info, param_charp); + break; + case CURLINFO_LONG: + param_longp = va_arg(arg, long *); + if(param_longp) + result = getinfo_long(data, info, param_longp); + break; + case CURLINFO_DOUBLE: + param_doublep = va_arg(arg, double *); + if(param_doublep) + result = getinfo_double(data, info, param_doublep); + break; + case CURLINFO_OFF_T: + param_offt = va_arg(arg, curl_off_t *); + if(param_offt) + result = getinfo_offt(data, info, param_offt); + break; + case CURLINFO_SLIST: + param_slistp = va_arg(arg, struct curl_slist **); + if(param_slistp) + result = getinfo_slist(data, info, param_slistp); + break; + case CURLINFO_SOCKET: + param_socketp = va_arg(arg, curl_socket_t *); + if(param_socketp) + result = getinfo_socket(data, info, param_socketp); + break; + default: + break; + } + + va_end(arg); + + return result; +} diff --git a/lib/getinfo.h b/lib/getinfo.h new file mode 100644 index 0000000..56bb440 --- /dev/null +++ b/lib/getinfo.h @@ -0,0 +1,29 @@ +#ifndef HEADER_CURL_GETINFO_H +#define HEADER_CURL_GETINFO_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...); +CURLcode Curl_initinfo(struct Curl_easy *data); + +#endif /* HEADER_CURL_GETINFO_H */ diff --git a/lib/gopher.c b/lib/gopher.c new file mode 100644 index 0000000..9ca0828 --- /dev/null +++ b/lib/gopher.c @@ -0,0 +1,242 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_GOPHER + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "cfilters.h" +#include "connect.h" +#include "progress.h" +#include "gopher.h" +#include "select.h" +#include "strdup.h" +#include "vtls/vtls.h" +#include "url.h" +#include "escape.h" +#include "warnless.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Forward declarations. + */ + +static CURLcode gopher_do(struct Curl_easy *data, bool *done); +#ifdef USE_SSL +static CURLcode gopher_connect(struct Curl_easy *data, bool *done); +static CURLcode gopher_connecting(struct Curl_easy *data, bool *done); +#endif + +/* + * Gopher protocol handler. + * This is also a nice simple template to build off for simple + * connect-command-download protocols. + */ + +const struct Curl_handler Curl_handler_gopher = { + "GOPHER", /* scheme */ + ZERO_NULL, /* setup_connection */ + gopher_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_GOPHER, /* defport */ + CURLPROTO_GOPHER, /* protocol */ + CURLPROTO_GOPHER, /* family */ + PROTOPT_NONE /* flags */ +}; + +#ifdef USE_SSL +const struct Curl_handler Curl_handler_gophers = { + "GOPHERS", /* scheme */ + ZERO_NULL, /* setup_connection */ + gopher_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + gopher_connect, /* connect_it */ + gopher_connecting, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_GOPHER, /* defport */ + CURLPROTO_GOPHERS, /* protocol */ + CURLPROTO_GOPHER, /* family */ + PROTOPT_SSL /* flags */ +}; + +static CURLcode gopher_connect(struct Curl_easy *data, bool *done) +{ + (void)data; + (void)done; + return CURLE_OK; +} + +static CURLcode gopher_connecting(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + CURLcode result; + + result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done); + if(result) + connclose(conn, "Failed TLS connection"); + *done = TRUE; + return result; +} +#endif + +static CURLcode gopher_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + char *gopherpath; + char *path = data->state.up.path; + char *query = data->state.up.query; + char *sel = NULL; + char *sel_org = NULL; + timediff_t timeout_ms; + ssize_t amount, k; + size_t len; + int what; + + *done = TRUE; /* unconditionally */ + + /* path is guaranteed non-NULL */ + DEBUGASSERT(path); + + if(query) + gopherpath = aprintf("%s?%s", path, query); + else + gopherpath = strdup(path); + + if(!gopherpath) + return CURLE_OUT_OF_MEMORY; + + /* Create selector. Degenerate cases: / and /1 => convert to "" */ + if(strlen(gopherpath) <= 2) { + sel = (char *)""; + len = strlen(sel); + free(gopherpath); + } + else { + char *newp; + + /* Otherwise, drop / and the first character (i.e., item type) ... */ + newp = gopherpath; + newp += 2; + + /* ... and finally unescape */ + result = Curl_urldecode(newp, 0, &sel, &len, REJECT_ZERO); + free(gopherpath); + if(result) + return result; + sel_org = sel; + } + + k = curlx_uztosz(len); + + for(;;) { + /* Break out of the loop if the selector is empty because OpenSSL and/or + LibreSSL fail with errno 0 if this is the case. */ + if(strlen(sel) < 1) + break; + + result = Curl_nwrite(data, FIRSTSOCKET, sel, k, &amount); + if(!result) { /* Which may not have written it all! */ + result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount); + if(result) + break; + + k -= amount; + sel += amount; + if(k < 1) + break; /* but it did write it all */ + } + else + break; + + timeout_ms = Curl_timeleft(data, NULL, FALSE); + if(timeout_ms < 0) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } + if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + + /* Don't busyloop. The entire loop thing is a work-around as it causes a + BLOCKING behavior which is a NO-NO. This function should rather be + split up in a do and a doing piece where the pieces that aren't + possible to send now will be sent in the doing function repeatedly + until the entire request is sent. + */ + what = SOCKET_WRITABLE(sockfd, timeout_ms); + if(what < 0) { + result = CURLE_SEND_ERROR; + break; + } + else if(!what) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } + } + + free(sel_org); + + if(!result) + result = Curl_nwrite(data, FIRSTSOCKET, "\r\n", 2, &amount); + if(result) { + failf(data, "Failed sending Gopher request"); + return result; + } + result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2); + if(result) + return result; + + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + return CURLE_OK; +} +#endif /* CURL_DISABLE_GOPHER */ diff --git a/lib/gopher.h b/lib/gopher.h new file mode 100644 index 0000000..9e3365b --- /dev/null +++ b/lib/gopher.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_GOPHER_H +#define HEADER_CURL_GOPHER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifndef CURL_DISABLE_GOPHER +extern const struct Curl_handler Curl_handler_gopher; +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_gophers; +#endif +#endif + +#endif /* HEADER_CURL_GOPHER_H */ diff --git a/lib/hash.c b/lib/hash.c new file mode 100644 index 0000000..30f28e2 --- /dev/null +++ b/lib/hash.c @@ -0,0 +1,370 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "hash.h" +#include "llist.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +static void +hash_element_dtor(void *user, void *element) +{ + struct Curl_hash *h = (struct Curl_hash *) user; + struct Curl_hash_element *e = (struct Curl_hash_element *) element; + + if(e->ptr) { + h->dtor(e->ptr); + e->ptr = NULL; + } + + e->key_len = 0; + + free(e); +} + +/* Initializes a hash structure. + * Return 1 on error, 0 is fine. + * + * @unittest: 1602 + * @unittest: 1603 + */ +void +Curl_hash_init(struct Curl_hash *h, + int slots, + hash_function hfunc, + comp_function comparator, + Curl_hash_dtor dtor) +{ + DEBUGASSERT(h); + DEBUGASSERT(slots); + DEBUGASSERT(hfunc); + DEBUGASSERT(comparator); + DEBUGASSERT(dtor); + + h->table = NULL; + h->hash_func = hfunc; + h->comp_func = comparator; + h->dtor = dtor; + h->size = 0; + h->slots = slots; +} + +static struct Curl_hash_element * +mk_hash_element(const void *key, size_t key_len, const void *p) +{ + /* allocate the struct plus memory after it to store the key */ + struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) + + key_len); + if(he) { + /* copy the key */ + memcpy(he->key, key, key_len); + he->key_len = key_len; + he->ptr = (void *) p; + } + return he; +} + +#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)] + +/* Insert the data in the hash. If there already was a match in the hash, that + * data is replaced. This function also "lazily" allocates the table if + * needed, as it isn't done in the _init function (anymore). + * + * @unittest: 1305 + * @unittest: 1602 + * @unittest: 1603 + */ +void * +Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p) +{ + struct Curl_hash_element *he; + struct Curl_llist_element *le; + struct Curl_llist *l; + + DEBUGASSERT(h); + DEBUGASSERT(h->slots); + if(!h->table) { + int i; + h->table = malloc(h->slots * sizeof(struct Curl_llist)); + if(!h->table) + return NULL; /* OOM */ + for(i = 0; i < h->slots; ++i) + Curl_llist_init(&h->table[i], hash_element_dtor); + } + + l = FETCH_LIST(h, key, key_len); + + for(le = l->head; le; le = le->next) { + he = (struct Curl_hash_element *) le->ptr; + if(h->comp_func(he->key, he->key_len, key, key_len)) { + Curl_llist_remove(l, le, (void *)h); + --h->size; + break; + } + } + + he = mk_hash_element(key, key_len, p); + if(he) { + Curl_llist_insert_next(l, l->tail, he, &he->list); + ++h->size; + return p; /* return the new entry */ + } + + return NULL; /* failure */ +} + +/* Remove the identified hash entry. + * Returns non-zero on failure. + * + * @unittest: 1603 + */ +int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len) +{ + struct Curl_llist_element *le; + struct Curl_llist *l; + + DEBUGASSERT(h); + DEBUGASSERT(h->slots); + if(h->table) { + l = FETCH_LIST(h, key, key_len); + + for(le = l->head; le; le = le->next) { + struct Curl_hash_element *he = le->ptr; + if(h->comp_func(he->key, he->key_len, key, key_len)) { + Curl_llist_remove(l, le, (void *) h); + --h->size; + return 0; + } + } + } + return 1; +} + +/* Retrieves a hash element. + * + * @unittest: 1603 + */ +void * +Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len) +{ + struct Curl_llist_element *le; + struct Curl_llist *l; + + DEBUGASSERT(h); + if(h->table) { + DEBUGASSERT(h->slots); + l = FETCH_LIST(h, key, key_len); + for(le = l->head; le; le = le->next) { + struct Curl_hash_element *he = le->ptr; + if(h->comp_func(he->key, he->key_len, key, key_len)) { + return he->ptr; + } + } + } + + return NULL; +} + +#if defined(DEBUGBUILD) && defined(AGGRESSIVE_TEST) +void +Curl_hash_apply(Curl_hash *h, void *user, + void (*cb)(void *user, void *ptr)) +{ + struct Curl_llist_element *le; + int i; + + for(i = 0; i < h->slots; ++i) { + for(le = (h->table[i])->head; + le; + le = le->next) { + Curl_hash_element *el = le->ptr; + cb(user, el->ptr); + } + } +} +#endif + +/* Destroys all the entries in the given hash and resets its attributes, + * prepping the given hash for [static|dynamic] deallocation. + * + * @unittest: 1305 + * @unittest: 1602 + * @unittest: 1603 + */ +void +Curl_hash_destroy(struct Curl_hash *h) +{ + if(h->table) { + int i; + for(i = 0; i < h->slots; ++i) { + Curl_llist_destroy(&h->table[i], (void *) h); + } + Curl_safefree(h->table); + } + h->size = 0; + h->slots = 0; +} + +/* Removes all the entries in the given hash. + * + * @unittest: 1602 + */ +void +Curl_hash_clean(struct Curl_hash *h) +{ + Curl_hash_clean_with_criterium(h, NULL, NULL); +} + +/* Cleans all entries that pass the comp function criteria. */ +void +Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user, + int (*comp)(void *, void *)) +{ + struct Curl_llist_element *le; + struct Curl_llist_element *lnext; + struct Curl_llist *list; + int i; + + if(!h || !h->table) + return; + + for(i = 0; i < h->slots; ++i) { + list = &h->table[i]; + le = list->head; /* get first list entry */ + while(le) { + struct Curl_hash_element *he = le->ptr; + lnext = le->next; + /* ask the callback function if we shall remove this entry or not */ + if(!comp || comp(user, he->ptr)) { + Curl_llist_remove(list, le, (void *) h); + --h->size; /* one less entry in the hash now */ + } + le = lnext; + } + } +} + +size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num) +{ + const char *key_str = (const char *) key; + const char *end = key_str + key_length; + size_t h = 5381; + + while(key_str < end) { + h += h << 5; + h ^= *key_str++; + } + + return (h % slots_num); +} + +size_t Curl_str_key_compare(void *k1, size_t key1_len, + void *k2, size_t key2_len) +{ + if((key1_len == key2_len) && !memcmp(k1, k2, key1_len)) + return 1; + + return 0; +} + +void Curl_hash_start_iterate(struct Curl_hash *hash, + struct Curl_hash_iterator *iter) +{ + iter->hash = hash; + iter->slot_index = 0; + iter->current_element = NULL; +} + +struct Curl_hash_element * +Curl_hash_next_element(struct Curl_hash_iterator *iter) +{ + struct Curl_hash *h = iter->hash; + + if(!h->table) + return NULL; /* empty hash, nothing to return */ + + /* Get the next element in the current list, if any */ + if(iter->current_element) + iter->current_element = iter->current_element->next; + + /* If we have reached the end of the list, find the next one */ + if(!iter->current_element) { + int i; + for(i = iter->slot_index; i < h->slots; i++) { + if(h->table[i].head) { + iter->current_element = h->table[i].head; + iter->slot_index = i + 1; + break; + } + } + } + + if(iter->current_element) { + struct Curl_hash_element *he = iter->current_element->ptr; + return he; + } + return NULL; +} + +#if 0 /* useful function for debugging hashes and their contents */ +void Curl_hash_print(struct Curl_hash *h, + void (*func)(void *)) +{ + struct Curl_hash_iterator iter; + struct Curl_hash_element *he; + int last_index = -1; + + if(!h) + return; + + fprintf(stderr, "=Hash dump=\n"); + + Curl_hash_start_iterate(h, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + if(iter.slot_index != last_index) { + fprintf(stderr, "index %d:", iter.slot_index); + if(last_index >= 0) { + fprintf(stderr, "\n"); + } + last_index = iter.slot_index; + } + + if(func) + func(he->ptr); + else + fprintf(stderr, " [%p]", (void *)he->ptr); + + he = Curl_hash_next_element(&iter); + } + fprintf(stderr, "\n"); +} +#endif diff --git a/lib/hash.h b/lib/hash.h new file mode 100644 index 0000000..9cfffc2 --- /dev/null +++ b/lib/hash.h @@ -0,0 +1,102 @@ +#ifndef HEADER_CURL_HASH_H +#define HEADER_CURL_HASH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "llist.h" + +/* Hash function prototype */ +typedef size_t (*hash_function) (void *key, + size_t key_length, + size_t slots_num); + +/* + Comparator function prototype. Compares two keys. +*/ +typedef size_t (*comp_function) (void *key1, + size_t key1_len, + void *key2, + size_t key2_len); + +typedef void (*Curl_hash_dtor)(void *); + +struct Curl_hash { + struct Curl_llist *table; + + /* Hash function to be used for this hash table */ + hash_function hash_func; + + /* Comparator function to compare keys */ + comp_function comp_func; + Curl_hash_dtor dtor; + int slots; + size_t size; +}; + +struct Curl_hash_element { + struct Curl_llist_element list; + void *ptr; + size_t key_len; + char key[1]; /* allocated memory following the struct */ +}; + +struct Curl_hash_iterator { + struct Curl_hash *hash; + int slot_index; + struct Curl_llist_element *current_element; +}; + +void Curl_hash_init(struct Curl_hash *h, + int slots, + hash_function hfunc, + comp_function comparator, + Curl_hash_dtor dtor); + +void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p); +int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len); +void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len); +void Curl_hash_apply(struct Curl_hash *h, void *user, + void (*cb)(void *user, void *ptr)); +#define Curl_hash_count(h) ((h)->size) +void Curl_hash_destroy(struct Curl_hash *h); +void Curl_hash_clean(struct Curl_hash *h); +void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user, + int (*comp)(void *, void *)); +size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num); +size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2, + size_t key2_len); +void Curl_hash_start_iterate(struct Curl_hash *hash, + struct Curl_hash_iterator *iter); +struct Curl_hash_element * +Curl_hash_next_element(struct Curl_hash_iterator *iter); + +void Curl_hash_print(struct Curl_hash *h, + void (*func)(void *)); + + +#endif /* HEADER_CURL_HASH_H */ diff --git a/lib/headers.c b/lib/headers.c new file mode 100644 index 0000000..8a3264a --- /dev/null +++ b/lib/headers.c @@ -0,0 +1,394 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "urldata.h" +#include "strdup.h" +#include "strcase.h" +#include "headers.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) + +/* Generate the curl_header struct for the user. This function MUST assign all + struct fields in the output struct. */ +static void copy_header_external(struct Curl_header_store *hs, + size_t index, + size_t amount, + struct Curl_llist_element *e, + struct curl_header *hout) +{ + struct curl_header *h = hout; + h->name = hs->name; + h->value = hs->value; + h->amount = amount; + h->index = index; + /* this will randomly OR a reserved bit for the sole purpose of making it + impossible for applications to do == comparisons, as that would otherwise + be very tempting and then lead to the reserved bits not being reserved + anymore. */ + h->origin = hs->type | (1<<27); + h->anchor = e; +} + +/* public API */ +CURLHcode curl_easy_header(CURL *easy, + const char *name, + size_t nameindex, + unsigned int type, + int request, + struct curl_header **hout) +{ + struct Curl_llist_element *e; + struct Curl_llist_element *e_pick = NULL; + struct Curl_easy *data = easy; + size_t match = 0; + size_t amount = 0; + struct Curl_header_store *hs = NULL; + struct Curl_header_store *pick = NULL; + if(!name || !hout || !data || + (type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX| + CURLH_PSEUDO)) || !type || (request < -1)) + return CURLHE_BAD_ARGUMENT; + if(!Curl_llist_count(&data->state.httphdrs)) + return CURLHE_NOHEADERS; /* no headers available */ + if(request > data->state.requests) + return CURLHE_NOREQUEST; + if(request == -1) + request = data->state.requests; + + /* we need a first round to count amount of this header */ + for(e = data->state.httphdrs.head; e; e = e->next) { + hs = e->ptr; + if(strcasecompare(hs->name, name) && + (hs->type & type) && + (hs->request == request)) { + amount++; + pick = hs; + e_pick = e; + } + } + if(!amount) + return CURLHE_MISSING; + else if(nameindex >= amount) + return CURLHE_BADINDEX; + + if(nameindex == amount - 1) + /* if the last or only occurrence is what's asked for, then we know it */ + hs = pick; + else { + for(e = data->state.httphdrs.head; e; e = e->next) { + hs = e->ptr; + if(strcasecompare(hs->name, name) && + (hs->type & type) && + (hs->request == request) && + (match++ == nameindex)) { + e_pick = e; + break; + } + } + if(!e) /* this shouldn't happen */ + return CURLHE_MISSING; + } + /* this is the name we want */ + copy_header_external(hs, nameindex, amount, e_pick, + &data->state.headerout[0]); + *hout = &data->state.headerout[0]; + return CURLHE_OK; +} + +/* public API */ +struct curl_header *curl_easy_nextheader(CURL *easy, + unsigned int type, + int request, + struct curl_header *prev) +{ + struct Curl_easy *data = easy; + struct Curl_llist_element *pick; + struct Curl_llist_element *e; + struct Curl_header_store *hs; + size_t amount = 0; + size_t index = 0; + + if(request > data->state.requests) + return NULL; + if(request == -1) + request = data->state.requests; + + if(prev) { + pick = prev->anchor; + if(!pick) + /* something is wrong */ + return NULL; + pick = pick->next; + } + else + pick = data->state.httphdrs.head; + + if(pick) { + /* make sure it is the next header of the desired type */ + do { + hs = pick->ptr; + if((hs->type & type) && (hs->request == request)) + break; + pick = pick->next; + } while(pick); + } + + if(!pick) + /* no more headers available */ + return NULL; + + hs = pick->ptr; + + /* count number of occurrences of this name within the mask and figure out + the index for the currently selected entry */ + for(e = data->state.httphdrs.head; e; e = e->next) { + struct Curl_header_store *check = e->ptr; + if(strcasecompare(hs->name, check->name) && + (check->request == request) && + (check->type & type)) + amount++; + if(e == pick) + index = amount - 1; + } + + copy_header_external(hs, index, amount, pick, + &data->state.headerout[1]); + return &data->state.headerout[1]; +} + +static CURLcode namevalue(char *header, size_t hlen, unsigned int type, + char **name, char **value) +{ + char *end = header + hlen - 1; /* point to the last byte */ + DEBUGASSERT(hlen); + *name = header; + + if(type == CURLH_PSEUDO) { + if(*header != ':') + return CURLE_BAD_FUNCTION_ARGUMENT; + header++; + } + + /* Find the end of the header name */ + while(*header && (*header != ':')) + ++header; + + if(*header) + /* Skip over colon, null it */ + *header++ = 0; + else + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* skip all leading space letters */ + while(*header && ISBLANK(*header)) + header++; + + *value = header; + + /* skip all trailing space letters */ + while((end > header) && ISSPACE(*end)) + *end-- = 0; /* nul terminate */ + return CURLE_OK; +} + +static CURLcode unfold_value(struct Curl_easy *data, const char *value, + size_t vlen) /* length of the incoming header */ +{ + struct Curl_header_store *hs; + struct Curl_header_store *newhs; + size_t olen; /* length of the old value */ + size_t oalloc; /* length of the old name + value + separator */ + size_t offset; + DEBUGASSERT(data->state.prevhead); + hs = data->state.prevhead; + olen = strlen(hs->value); + offset = hs->value - hs->buffer; + oalloc = olen + offset + 1; + + /* skip all trailing space letters */ + while(vlen && ISSPACE(value[vlen - 1])) + vlen--; + + /* save only one leading space */ + while((vlen > 1) && ISBLANK(value[0]) && ISBLANK(value[1])) { + vlen--; + value++; + } + + /* since this header block might move in the realloc below, it needs to + first be unlinked from the list and then re-added again after the + realloc */ + Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL); + + /* new size = struct + new value length + old name+value length */ + newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1); + if(!newhs) + return CURLE_OUT_OF_MEMORY; + /* ->name' and ->value point into ->buffer (to keep the header allocation + in a single memory block), which now potentially have moved. Adjust + them. */ + newhs->name = newhs->buffer; + newhs->value = &newhs->buffer[offset]; + + /* put the data at the end of the previous data, not the newline */ + memcpy(&newhs->value[olen], value, vlen); + newhs->value[olen + vlen] = 0; /* null-terminate at newline */ + + /* insert this node into the list of headers */ + Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail, + newhs, &newhs->node); + data->state.prevhead = newhs; + return CURLE_OK; +} + + +/* + * Curl_headers_push() gets passed a full HTTP header to store. It gets called + * immediately before the header callback. The header is CRLF terminated. + */ +CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, + unsigned char type) +{ + char *value = NULL; + char *name = NULL; + char *end; + size_t hlen; /* length of the incoming header */ + struct Curl_header_store *hs; + CURLcode result = CURLE_OUT_OF_MEMORY; + + if((header[0] == '\r') || (header[0] == '\n')) + /* ignore the body separator */ + return CURLE_OK; + + end = strchr(header, '\r'); + if(!end) { + end = strchr(header, '\n'); + if(!end) + /* neither CR nor LF as terminator is not a valid header */ + return CURLE_WEIRD_SERVER_REPLY; + } + hlen = end - header; + + if((header[0] == ' ') || (header[0] == '\t')) { + if(data->state.prevhead) + /* line folding, append value to the previous header's value */ + return unfold_value(data, header, hlen); + else { + /* Can't unfold without a previous header. Instead of erroring, just + pass the leading blanks. */ + while(hlen && ISBLANK(*header)) { + header++; + hlen--; + } + if(!hlen) + return CURLE_WEIRD_SERVER_REPLY; + } + } + + hs = calloc(1, sizeof(*hs) + hlen); + if(!hs) + return CURLE_OUT_OF_MEMORY; + memcpy(hs->buffer, header, hlen); + hs->buffer[hlen] = 0; /* nul terminate */ + + result = namevalue(hs->buffer, hlen, type, &name, &value); + if(!result) { + hs->name = name; + hs->value = value; + hs->type = type; + hs->request = data->state.requests; + + /* insert this node into the list of headers */ + Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail, + hs, &hs->node); + data->state.prevhead = hs; + } + else + free(hs); + return result; +} + +/* + * Curl_headers_init(). Init the headers subsystem. + */ +static void headers_init(struct Curl_easy *data) +{ + Curl_llist_init(&data->state.httphdrs, NULL); + data->state.prevhead = NULL; +} + +/* + * Curl_headers_cleanup(). Free all stored headers and associated memory. + */ +CURLcode Curl_headers_cleanup(struct Curl_easy *data) +{ + struct Curl_llist_element *e; + struct Curl_llist_element *n; + + for(e = data->state.httphdrs.head; e; e = n) { + struct Curl_header_store *hs = e->ptr; + n = e->next; + free(hs); + } + headers_init(data); + return CURLE_OK; +} + +#else /* HTTP-disabled builds below */ + +CURLHcode curl_easy_header(CURL *easy, + const char *name, + size_t index, + unsigned int origin, + int request, + struct curl_header **hout) +{ + (void)easy; + (void)name; + (void)index; + (void)origin; + (void)request; + (void)hout; + return CURLHE_NOT_BUILT_IN; +} + +struct curl_header *curl_easy_nextheader(CURL *easy, + unsigned int type, + int request, + struct curl_header *prev) +{ + (void)easy; + (void)type; + (void)request; + (void)prev; + return NULL; +} +#endif diff --git a/lib/headers.h b/lib/headers.h new file mode 100644 index 0000000..a5229ea --- /dev/null +++ b/lib/headers.h @@ -0,0 +1,55 @@ +#ifndef HEADER_CURL_HEADER_H +#define HEADER_CURL_HEADER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) + +struct Curl_header_store { + struct Curl_llist_element node; + char *name; /* points into 'buffer' */ + char *value; /* points into 'buffer */ + int request; /* 0 is the first request, then 1.. 2.. */ + unsigned char type; /* CURLH_* defines */ + char buffer[1]; /* this is the raw header blob */ +}; + +/* + * Curl_headers_push() gets passed a full header to store. + */ +CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, + unsigned char type); + +/* + * Curl_headers_cleanup(). Free all stored headers and associated memory. + */ +CURLcode Curl_headers_cleanup(struct Curl_easy *data); + +#else +#define Curl_headers_push(x,y,z) CURLE_OK +#define Curl_headers_cleanup(x) Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_HEADER_H */ diff --git a/lib/hmac.c b/lib/hmac.c new file mode 100644 index 0000000..4019b67 --- /dev/null +++ b/lib/hmac.c @@ -0,0 +1,173 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC2104 Keyed-Hashing for Message Authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ + || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) + +#include + +#include "curl_hmac.h" +#include "curl_memory.h" +#include "warnless.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Generic HMAC algorithm. + * + * This module computes HMAC digests based on any hash function. Parameters + * and computing procedures are set-up dynamically at HMAC computation context + * initialization. + */ + +static const unsigned char hmac_ipad = 0x36; +static const unsigned char hmac_opad = 0x5C; + + + +struct HMAC_context * +Curl_HMAC_init(const struct HMAC_params *hashparams, + const unsigned char *key, + unsigned int keylen) +{ + size_t i; + struct HMAC_context *ctxt; + unsigned char *hkey; + unsigned char b; + + /* Create HMAC context. */ + i = sizeof(*ctxt) + 2 * hashparams->hmac_ctxtsize + + hashparams->hmac_resultlen; + ctxt = malloc(i); + + if(!ctxt) + return ctxt; + + ctxt->hmac_hash = hashparams; + ctxt->hmac_hashctxt1 = (void *) (ctxt + 1); + ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 + + hashparams->hmac_ctxtsize); + + /* If the key is too long, replace it by its hash digest. */ + if(keylen > hashparams->hmac_maxkeylen) { + (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); + (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen); + hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize; + (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1); + key = hkey; + keylen = hashparams->hmac_resultlen; + } + + /* Prime the two hash contexts with the modified key. */ + (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); + (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2); + + for(i = 0; i < keylen; i++) { + b = (unsigned char)(*key ^ hmac_ipad); + (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1); + b = (unsigned char)(*key++ ^ hmac_opad); + (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1); + } + + for(; i < hashparams->hmac_maxkeylen; i++) { + (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1); + (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1); + } + + /* Done, return pointer to HMAC context. */ + return ctxt; +} + +int Curl_HMAC_update(struct HMAC_context *ctxt, + const unsigned char *data, + unsigned int len) +{ + /* Update first hash calculation. */ + (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len); + return 0; +} + + +int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *result) +{ + const struct HMAC_params *hashparams = ctxt->hmac_hash; + + /* Do not get result if called with a null parameter: only release + storage. */ + + if(!result) + result = (unsigned char *) ctxt->hmac_hashctxt2 + + ctxt->hmac_hash->hmac_ctxtsize; + + (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1); + (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, + result, hashparams->hmac_resultlen); + (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2); + free((char *) ctxt); + return 0; +} + +/* + * Curl_hmacit() + * + * This is used to generate a HMAC hash, for the specified input data, given + * the specified hash function and key. + * + * Parameters: + * + * hashparams [in] - The hash function (Curl_HMAC_MD5). + * key [in] - The key to use. + * keylen [in] - The length of the key. + * data [in] - The data to encrypt. + * datalen [in] - The length of the data. + * output [in/out] - The output buffer. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_hmacit(const struct HMAC_params *hashparams, + const unsigned char *key, const size_t keylen, + const unsigned char *data, const size_t datalen, + unsigned char *output) +{ + struct HMAC_context *ctxt = + Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen)); + + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + /* Update the digest with the given challenge */ + Curl_HMAC_update(ctxt, data, curlx_uztoui(datalen)); + + /* Finalise the digest */ + Curl_HMAC_final(ctxt, output); + + return CURLE_OK; +} + +#endif /* Using NTLM (without SSPI) or AWS */ diff --git a/lib/hostasyn.c b/lib/hostasyn.c new file mode 100644 index 0000000..2f6762c --- /dev/null +++ b/lib/hostasyn.c @@ -0,0 +1,123 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/*********************************************************************** + * Only for builds using asynchronous name resolves + **********************************************************************/ +#ifdef CURLRES_ASYNCH + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "url.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread() + * or getaddrinfo_thread() when we got the name resolved (or not!). + * + * If the status argument is CURL_ASYNC_SUCCESS, this function takes + * ownership of the Curl_addrinfo passed, storing the resolved data + * in the DNS cache. + * + * The storage operation locks and unlocks the DNS cache. + */ +CURLcode Curl_addrinfo_callback(struct Curl_easy *data, + int status, + struct Curl_addrinfo *ai) +{ + struct Curl_dns_entry *dns = NULL; + CURLcode result = CURLE_OK; + + data->state.async.status = status; + + if(CURL_ASYNC_SUCCESS == status) { + if(ai) { + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + dns = Curl_cache_addr(data, ai, + data->state.async.hostname, 0, + data->state.async.port); + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + if(!dns) { + /* failed to store, cleanup and return error */ + Curl_freeaddrinfo(ai); + result = CURLE_OUT_OF_MEMORY; + } + } + else { + result = CURLE_OUT_OF_MEMORY; + } + } + + data->state.async.dns = dns; + + /* Set async.done TRUE last in this function since it may be used multi- + threaded and once this is TRUE the other thread may read fields from the + async struct */ + data->state.async.done = TRUE; + + /* IPv4: The input hostent struct will be freed by ares when we return from + this function */ + return result; +} + +/* + * Curl_getaddrinfo() is the generic low-level name resolve API within this + * source file. There are several versions of this function - for different + * name resolve layers (selected at build-time). They all take this same set + * of arguments + */ +struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp) +{ + return Curl_resolver_getaddrinfo(data, hostname, port, waitp); +} + +#endif /* CURLRES_ASYNCH */ diff --git a/lib/hostip.c b/lib/hostip.c new file mode 100644 index 0000000..4f44d34 --- /dev/null +++ b/lib/hostip.c @@ -0,0 +1,1469 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "rand.h" +#include "share.h" +#include "url.h" +#include "inet_ntop.h" +#include "inet_pton.h" +#include "multiif.h" +#include "doh.h" +#include "warnless.h" +#include "strcase.h" +#include "easy_lock.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if defined(CURLRES_SYNCH) && \ + defined(HAVE_ALARM) && \ + defined(SIGALRM) && \ + defined(HAVE_SIGSETJMP) && \ + defined(GLOBAL_INIT_IS_THREADSAFE) +/* alarm-based timeouts can only be used with all the dependencies satisfied */ +#define USE_ALARM_TIMEOUT +#endif + +#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */ + +#define MAX_DNS_CACHE_SIZE 29999 + +/* + * hostip.c explained + * ================== + * + * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c + * source file are these: + * + * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use + * that. The host may not be able to resolve IPv6, but we don't really have to + * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4 + * defined. + * + * CURLRES_ARES - is defined if libcurl is built to use c-ares for + * asynchronous name resolves. This can be Windows or *nix. + * + * CURLRES_THREADED - is defined if libcurl is built to run under (native) + * Windows, and then the name resolve will be done in a new thread, and the + * supported API will be the same as for ares-builds. + * + * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If + * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is + * defined. + * + * The host*.c sources files are split up like this: + * + * hostip.c - method-independent resolver functions and utility functions + * hostasyn.c - functions for asynchronous name resolves + * hostsyn.c - functions for synchronous name resolves + * hostip4.c - IPv4 specific functions + * hostip6.c - IPv6 specific functions + * + * The two asynchronous name resolver backends are implemented in: + * asyn-ares.c - functions for ares-using name resolves + * asyn-thread.c - functions for threaded name resolves + + * The hostip.h is the united header file for all this. It defines the + * CURLRES_* defines based on the config*.h and curl_setup.h defines. + */ + +static void freednsentry(void *freethis); + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void show_resolve_info(struct Curl_easy *data, + struct Curl_dns_entry *dns); +#else +#define show_resolve_info(x,y) Curl_nop_stmt +#endif + +/* + * Curl_printable_address() stores a printable version of the 1st address + * given in the 'ai' argument. The result will be stored in the buf that is + * bufsize bytes big. + * + * If the conversion fails, the target buffer is empty. + */ +void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf, + size_t bufsize) +{ + DEBUGASSERT(bufsize); + buf[0] = 0; + + switch(ai->ai_family) { + case AF_INET: { + const struct sockaddr_in *sa4 = (const void *)ai->ai_addr; + const struct in_addr *ipaddr4 = &sa4->sin_addr; + (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize); + break; + } +#ifdef ENABLE_IPV6 + case AF_INET6: { + const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr; + const struct in6_addr *ipaddr6 = &sa6->sin6_addr; + (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize); + break; + } +#endif + default: + break; + } +} + +/* + * Create a hostcache id string for the provided host + port, to be used by + * the DNS caching. Without alloc. Return length of the id string. + */ +static size_t +create_hostcache_id(const char *name, + size_t nlen, /* 0 or actual name length */ + int port, char *ptr, size_t buflen) +{ + size_t len = nlen ? nlen : strlen(name); + size_t olen = 0; + DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN); + if(len > (buflen - 7)) + len = buflen - 7; + /* store and lower case the name */ + while(len--) { + *ptr++ = Curl_raw_tolower(*name++); + olen++; + } + olen += msnprintf(ptr, 7, ":%u", port); + return olen; +} + +struct hostcache_prune_data { + time_t now; + time_t oldest; /* oldest time in cache not pruned. */ + int cache_timeout; +}; + +/* + * This function is set as a callback to be called for every entry in the DNS + * cache when we want to prune old unused entries. + * + * Returning non-zero means remove the entry, return 0 to keep it in the + * cache. + */ +static int +hostcache_timestamp_remove(void *datap, void *hc) +{ + struct hostcache_prune_data *prune = + (struct hostcache_prune_data *) datap; + struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; + + if(c->timestamp) { + /* age in seconds */ + time_t age = prune->now - c->timestamp; + if(age >= prune->cache_timeout) + return TRUE; + if(age > prune->oldest) + prune->oldest = age; + } + return FALSE; +} + +/* + * Prune the DNS cache. This assumes that a lock has already been taken. + * Returns the 'age' of the oldest still kept entry. + */ +static time_t +hostcache_prune(struct Curl_hash *hostcache, int cache_timeout, + time_t now) +{ + struct hostcache_prune_data user; + + user.cache_timeout = cache_timeout; + user.now = now; + user.oldest = 0; + + Curl_hash_clean_with_criterium(hostcache, + (void *) &user, + hostcache_timestamp_remove); + + return user.oldest; +} + +/* + * Library-wide function for pruning the DNS cache. This function takes and + * returns the appropriate locks. + */ +void Curl_hostcache_prune(struct Curl_easy *data) +{ + time_t now; + /* the timeout may be set -1 (forever) */ + int timeout = data->set.dns_cache_timeout; + + if(!data->dns.hostcache) + /* NULL hostcache means we can't do it */ + return; + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + time(&now); + + do { + /* Remove outdated and unused entries from the hostcache */ + time_t oldest = hostcache_prune(data->dns.hostcache, timeout, now); + + if(oldest < INT_MAX) + timeout = (int)oldest; /* we know it fits */ + else + timeout = INT_MAX - 1; + + /* if the cache size is still too big, use the oldest age as new + prune limit */ + } while(timeout && (data->dns.hostcache->size > MAX_DNS_CACHE_SIZE)); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); +} + +#ifdef USE_ALARM_TIMEOUT +/* Beware this is a global and unique instance. This is used to store the + return address that we can jump back to from inside a signal handler. This + is not thread-safe stuff. */ +static sigjmp_buf curl_jmpenv; +static curl_simple_lock curl_jmpenv_lock; +#endif + +/* lookup address, returns entry if found and not stale */ +static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, + const char *hostname, + int port) +{ + struct Curl_dns_entry *dns = NULL; + char entry_id[MAX_HOSTCACHE_LEN]; + + /* Create an entry id, based upon the hostname and port */ + size_t entry_len = create_hostcache_id(hostname, 0, port, + entry_id, sizeof(entry_id)); + + /* See if its already in our dns cache */ + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); + + /* No entry found in cache, check if we might have a wildcard entry */ + if(!dns && data->state.wildcard_resolve) { + entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id)); + + /* See if it's already in our dns cache */ + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); + } + + if(dns && (data->set.dns_cache_timeout != -1)) { + /* See whether the returned entry is stale. Done before we release lock */ + struct hostcache_prune_data user; + + time(&user.now); + user.cache_timeout = data->set.dns_cache_timeout; + user.oldest = 0; + + if(hostcache_timestamp_remove(&user, dns)) { + infof(data, "Hostname in DNS cache was stale, zapped"); + dns = NULL; /* the memory deallocation is being handled by the hash */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); + } + } + + /* See if the returned entry matches the required resolve mode */ + if(dns && data->conn->ip_version != CURL_IPRESOLVE_WHATEVER) { + int pf = PF_INET; + bool found = false; + struct Curl_addrinfo *addr = dns->addr; + +#ifdef PF_INET6 + if(data->conn->ip_version == CURL_IPRESOLVE_V6) + pf = PF_INET6; +#endif + + while(addr) { + if(addr->ai_family == pf) { + found = true; + break; + } + addr = addr->ai_next; + } + + if(!found) { + infof(data, "Hostname in DNS cache doesn't have needed family, zapped"); + dns = NULL; /* the memory deallocation is being handled by the hash */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); + } + } + return dns; +} + +/* + * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. + * + * Curl_resolv() checks initially and multi_runsingle() checks each time + * it discovers the handle in the state WAITRESOLVE whether the hostname + * has already been resolved and the address has already been stored in + * the DNS cache. This short circuits waiting for a lot of pending + * lookups for the same hostname requested by different handles. + * + * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! + */ +struct Curl_dns_entry * +Curl_fetch_addr(struct Curl_easy *data, + const char *hostname, + int port) +{ + struct Curl_dns_entry *dns = NULL; + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + dns = fetch_addr(data, hostname, port); + + if(dns) + dns->inuse++; /* we use it! */ + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + return dns; +} + +#ifndef CURL_DISABLE_SHUFFLE_DNS +/* + * Return # of addresses in a Curl_addrinfo struct + */ +static int num_addresses(const struct Curl_addrinfo *addr) +{ + int i = 0; + while(addr) { + addr = addr->ai_next; + i++; + } + return i; +} + +UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, + struct Curl_addrinfo **addr); +/* + * Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo' + * struct by re-linking its linked list. + * + * The addr argument should be the address of a pointer to the head node of a + * `Curl_addrinfo` list and it will be modified to point to the new head after + * shuffling. + * + * Not declared static only to make it easy to use in a unit test! + * + * @unittest: 1608 + */ +UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, + struct Curl_addrinfo **addr) +{ + CURLcode result = CURLE_OK; + const int num_addrs = num_addresses(*addr); + + if(num_addrs > 1) { + struct Curl_addrinfo **nodes; + infof(data, "Shuffling %i addresses", num_addrs); + + nodes = malloc(num_addrs*sizeof(*nodes)); + if(nodes) { + int i; + unsigned int *rnd; + const size_t rnd_size = num_addrs * sizeof(*rnd); + + /* build a plain array of Curl_addrinfo pointers */ + nodes[0] = *addr; + for(i = 1; i < num_addrs; i++) { + nodes[i] = nodes[i-1]->ai_next; + } + + rnd = malloc(rnd_size); + if(rnd) { + /* Fisher-Yates shuffle */ + if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) { + struct Curl_addrinfo *swap_tmp; + for(i = num_addrs - 1; i > 0; i--) { + swap_tmp = nodes[rnd[i] % (i + 1)]; + nodes[rnd[i] % (i + 1)] = nodes[i]; + nodes[i] = swap_tmp; + } + + /* relink list in the new order */ + for(i = 1; i < num_addrs; i++) { + nodes[i-1]->ai_next = nodes[i]; + } + + nodes[num_addrs-1]->ai_next = NULL; + *addr = nodes[0]; + } + free(rnd); + } + else + result = CURLE_OUT_OF_MEMORY; + free(nodes); + } + else + result = CURLE_OUT_OF_MEMORY; + } + return result; +} +#endif + +/* + * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. + * + * When calling Curl_resolv() has resulted in a response with a returned + * address, we call this function to store the information in the dns + * cache etc + * + * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. + */ +struct Curl_dns_entry * +Curl_cache_addr(struct Curl_easy *data, + struct Curl_addrinfo *addr, + const char *hostname, + size_t hostlen, /* length or zero */ + int port) +{ + char entry_id[MAX_HOSTCACHE_LEN]; + size_t entry_len; + struct Curl_dns_entry *dns; + struct Curl_dns_entry *dns2; + +#ifndef CURL_DISABLE_SHUFFLE_DNS + /* shuffle addresses if requested */ + if(data->set.dns_shuffle_addresses) { + CURLcode result = Curl_shuffle_addr(data, &addr); + if(result) + return NULL; + } +#endif + if(!hostlen) + hostlen = strlen(hostname); + + /* Create a new cache entry */ + dns = calloc(1, sizeof(struct Curl_dns_entry) + hostlen); + if(!dns) { + return NULL; + } + + /* Create an entry id, based upon the hostname and port */ + entry_len = create_hostcache_id(hostname, hostlen, port, + entry_id, sizeof(entry_id)); + + dns->inuse = 1; /* the cache has the first reference */ + dns->addr = addr; /* this is the address(es) */ + time(&dns->timestamp); + if(dns->timestamp == 0) + dns->timestamp = 1; /* zero indicates permanent CURLOPT_RESOLVE entry */ + dns->hostport = port; + if(hostlen) + memcpy(dns->hostname, hostname, hostlen); + + /* Store the resolved data in our DNS cache. */ + dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1, + (void *)dns); + if(!dns2) { + free(dns); + return NULL; + } + + dns = dns2; + dns->inuse++; /* mark entry as in-use */ + return dns; +} + +#ifdef ENABLE_IPV6 +/* return a static IPv6 ::1 for the name */ +static struct Curl_addrinfo *get_localhost6(int port, const char *name) +{ + struct Curl_addrinfo *ca; + const size_t ss_size = sizeof(struct sockaddr_in6); + const size_t hostlen = strlen(name); + struct sockaddr_in6 sa6; + unsigned char ipv6[16]; + unsigned short port16 = (unsigned short)(port & 0xffff); + ca = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1); + if(!ca) + return NULL; + + sa6.sin6_family = AF_INET6; + sa6.sin6_port = htons(port16); + sa6.sin6_flowinfo = 0; + sa6.sin6_scope_id = 0; + if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1) + return NULL; + memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6)); + + ca->ai_flags = 0; + ca->ai_family = AF_INET6; + ca->ai_socktype = SOCK_STREAM; + ca->ai_protocol = IPPROTO_TCP; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_next = NULL; + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, &sa6, ss_size); + ca->ai_canonname = (char *)ca->ai_addr + ss_size; + strcpy(ca->ai_canonname, name); + return ca; +} +#else +#define get_localhost6(x,y) NULL +#endif + +/* return a static IPv4 127.0.0.1 for the given name */ +static struct Curl_addrinfo *get_localhost(int port, const char *name) +{ + struct Curl_addrinfo *ca; + struct Curl_addrinfo *ca6; + const size_t ss_size = sizeof(struct sockaddr_in); + const size_t hostlen = strlen(name); + struct sockaddr_in sa; + unsigned int ipv4; + unsigned short port16 = (unsigned short)(port & 0xffff); + + /* memset to clear the sa.sin_zero field */ + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(port16); + if(Curl_inet_pton(AF_INET, "127.0.0.1", (char *)&ipv4) < 1) + return NULL; + memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4)); + + ca = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1); + if(!ca) + return NULL; + ca->ai_flags = 0; + ca->ai_family = AF_INET; + ca->ai_socktype = SOCK_STREAM; + ca->ai_protocol = IPPROTO_TCP; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, &sa, ss_size); + ca->ai_canonname = (char *)ca->ai_addr + ss_size; + strcpy(ca->ai_canonname, name); + + ca6 = get_localhost6(port, name); + if(!ca6) + return ca; + ca6->ai_next = ca; + return ca6; +} + +#ifdef ENABLE_IPV6 +/* + * Curl_ipv6works() returns TRUE if IPv6 seems to work. + */ +bool Curl_ipv6works(struct Curl_easy *data) +{ + if(data) { + /* the nature of most system is that IPv6 status doesn't come and go + during a program's lifetime so we only probe the first time and then we + have the info kept for fast reuse */ + DEBUGASSERT(data); + DEBUGASSERT(data->multi); + if(data->multi->ipv6_up == IPV6_UNKNOWN) { + bool works = Curl_ipv6works(NULL); + data->multi->ipv6_up = works ? IPV6_WORKS : IPV6_DEAD; + } + return data->multi->ipv6_up == IPV6_WORKS; + } + else { + int ipv6_works = -1; + /* probe to see if we have a working IPv6 stack */ + curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); + if(s == CURL_SOCKET_BAD) + /* an IPv6 address was requested but we can't get/use one */ + ipv6_works = 0; + else { + ipv6_works = 1; + sclose(s); + } + return (ipv6_works>0)?TRUE:FALSE; + } +} +#endif /* ENABLE_IPV6 */ + +/* + * Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4 + * (or IPv6 if supported) address. + */ +bool Curl_host_is_ipnum(const char *hostname) +{ + struct in_addr in; +#ifdef ENABLE_IPV6 + struct in6_addr in6; +#endif + if(Curl_inet_pton(AF_INET, hostname, &in) > 0 +#ifdef ENABLE_IPV6 + || Curl_inet_pton(AF_INET6, hostname, &in6) > 0 +#endif + ) + return TRUE; + return FALSE; +} + + +/* return TRUE if 'part' is a case insensitive tail of 'full' */ +static bool tailmatch(const char *full, const char *part) +{ + size_t plen = strlen(part); + size_t flen = strlen(full); + if(plen > flen) + return FALSE; + return strncasecompare(part, &full[flen - plen], plen); +} + +/* + * Curl_resolv() is the main name resolve function within libcurl. It resolves + * a name and returns a pointer to the entry in the 'entry' argument (if one + * is provided). This function might return immediately if we're using asynch + * resolves. See the return codes. + * + * The cache entry we return will get its 'inuse' counter increased when this + * function is used. You MUST call Curl_resolv_unlock() later (when you're + * done using this struct) to decrease the counter again. + * + * Return codes: + * + * CURLRESOLV_ERROR (-1) = error, no pointer + * CURLRESOLV_RESOLVED (0) = OK, pointer provided + * CURLRESOLV_PENDING (1) = waiting for response, no pointer + */ + +enum resolve_t Curl_resolv(struct Curl_easy *data, + const char *hostname, + int port, + bool allowDOH, + struct Curl_dns_entry **entry) +{ + struct Curl_dns_entry *dns = NULL; + CURLcode result; + enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */ + struct connectdata *conn = data->conn; + /* We should intentionally error and not resolve .onion TLDs */ + size_t hostname_len = strlen(hostname); + if(hostname_len >= 7 && + (curl_strequal(&hostname[hostname_len - 6], ".onion") || + curl_strequal(&hostname[hostname_len - 7], ".onion."))) { + failf(data, "Not resolving .onion address (RFC 7686)"); + return CURLRESOLV_ERROR; + } + *entry = NULL; +#ifndef CURL_DISABLE_DOH + conn->bits.doh = FALSE; /* default is not */ +#else + (void)allowDOH; +#endif + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + dns = fetch_addr(data, hostname, port); + + if(dns) { + infof(data, "Hostname %s was found in DNS cache", hostname); + dns->inuse++; /* we use it! */ + rc = CURLRESOLV_RESOLVED; + } + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + if(!dns) { + /* The entry was not in the cache. Resolve it to IP address */ + + struct Curl_addrinfo *addr = NULL; + int respwait = 0; +#if !defined(CURL_DISABLE_DOH) || !defined(USE_RESOLVE_ON_IPS) + struct in_addr in; +#endif +#ifndef CURL_DISABLE_DOH +#ifndef USE_RESOLVE_ON_IPS + const +#endif + bool ipnum = FALSE; +#endif + + /* notify the resolver start callback */ + if(data->set.resolver_start) { + int st; + Curl_set_in_callback(data, true); + st = data->set.resolver_start( +#ifdef USE_CURL_ASYNC + data->state.async.resolver, +#else + NULL, +#endif + NULL, + data->set.resolver_start_client); + Curl_set_in_callback(data, false); + if(st) + return CURLRESOLV_ERROR; + } + +#ifndef USE_RESOLVE_ON_IPS + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { + /* This is a dotted IP address 123.123.123.123-style */ + addr = Curl_ip2addr(AF_INET, &in, hostname, port); + if(!addr) + return CURLRESOLV_ERROR; + } +#ifdef ENABLE_IPV6 + else { + struct in6_addr in6; + /* check if this is an IPv6 address string */ + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) { + /* This is an IPv6 address literal */ + addr = Curl_ip2addr(AF_INET6, &in6, hostname, port); + if(!addr) + return CURLRESOLV_ERROR; + } + } +#endif /* ENABLE_IPV6 */ + +#else /* if USE_RESOLVE_ON_IPS */ +#ifndef CURL_DISABLE_DOH + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) + /* This is a dotted IP address 123.123.123.123-style */ + ipnum = TRUE; +#ifdef ENABLE_IPV6 + else { + struct in6_addr in6; + /* check if this is an IPv6 address string */ + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) + /* This is an IPv6 address literal */ + ipnum = TRUE; + } +#endif /* ENABLE_IPV6 */ +#endif /* CURL_DISABLE_DOH */ + +#endif /* !USE_RESOLVE_ON_IPS */ + + if(!addr) { + if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data)) + return CURLRESOLV_ERROR; + + if(strcasecompare(hostname, "localhost") || + tailmatch(hostname, ".localhost")) + addr = get_localhost(port, hostname); +#ifndef CURL_DISABLE_DOH + else if(allowDOH && data->set.doh && !ipnum) + addr = Curl_doh(data, hostname, port, &respwait); +#endif + else { + /* Check what IP specifics the app has requested and if we can provide + * it. If not, bail out. */ + if(!Curl_ipvalid(data, conn)) + return CURLRESOLV_ERROR; + /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a + non-zero value indicating that we need to wait for the response to + the resolve call */ + addr = Curl_getaddrinfo(data, hostname, port, &respwait); + } + } + if(!addr) { + if(respwait) { + /* the response to our resolve call will come asynchronously at + a later time, good or bad */ + /* First, check that we haven't received the info by now */ + result = Curl_resolv_check(data, &dns); + if(result) /* error detected */ + return CURLRESOLV_ERROR; + if(dns) + rc = CURLRESOLV_RESOLVED; /* pointer provided */ + else + rc = CURLRESOLV_PENDING; /* no info yet */ + } + } + else { + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* we got a response, store it in the cache */ + dns = Curl_cache_addr(data, addr, hostname, 0, port); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + if(!dns) + /* returned failure, bail out nicely */ + Curl_freeaddrinfo(addr); + else { + rc = CURLRESOLV_RESOLVED; + show_resolve_info(data, dns); + } + } + } + + *entry = dns; + + return rc; +} + +#ifdef USE_ALARM_TIMEOUT +/* + * This signal handler jumps back into the main libcurl code and continues + * execution. This effectively causes the remainder of the application to run + * within a signal handler which is nonportable and could lead to problems. + */ +CURL_NORETURN static +void alarmfunc(int sig) +{ + (void)sig; + siglongjmp(curl_jmpenv, 1); +} +#endif /* USE_ALARM_TIMEOUT */ + +/* + * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a + * timeout. This function might return immediately if we're using asynch + * resolves. See the return codes. + * + * The cache entry we return will get its 'inuse' counter increased when this + * function is used. You MUST call Curl_resolv_unlock() later (when you're + * done using this struct) to decrease the counter again. + * + * If built with a synchronous resolver and use of signals is not + * disabled by the application, then a nonzero timeout will cause a + * timeout after the specified number of milliseconds. Otherwise, timeout + * is ignored. + * + * Return codes: + * + * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired + * CURLRESOLV_ERROR (-1) = error, no pointer + * CURLRESOLV_RESOLVED (0) = OK, pointer provided + * CURLRESOLV_PENDING (1) = waiting for response, no pointer + */ + +enum resolve_t Curl_resolv_timeout(struct Curl_easy *data, + const char *hostname, + int port, + struct Curl_dns_entry **entry, + timediff_t timeoutms) +{ +#ifdef USE_ALARM_TIMEOUT +#ifdef HAVE_SIGACTION + struct sigaction keep_sigact; /* store the old struct here */ + volatile bool keep_copysig = FALSE; /* whether old sigact has been saved */ + struct sigaction sigact; +#else +#ifdef HAVE_SIGNAL + void (*keep_sigact)(int); /* store the old handler here */ +#endif /* HAVE_SIGNAL */ +#endif /* HAVE_SIGACTION */ + volatile long timeout; + volatile unsigned int prev_alarm = 0; +#endif /* USE_ALARM_TIMEOUT */ + enum resolve_t rc; + + *entry = NULL; + + if(timeoutms < 0) + /* got an already expired timeout */ + return CURLRESOLV_TIMEDOUT; + +#ifdef USE_ALARM_TIMEOUT + if(data->set.no_signal) + /* Ignore the timeout when signals are disabled */ + timeout = 0; + else + timeout = (timeoutms > LONG_MAX) ? LONG_MAX : (long)timeoutms; + + if(!timeout) + /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ + return Curl_resolv(data, hostname, port, TRUE, entry); + + if(timeout < 1000) { + /* The alarm() function only provides integer second resolution, so if + we want to wait less than one second we must bail out already now. */ + failf(data, + "remaining timeout of %ld too small to resolve via SIGALRM method", + timeout); + return CURLRESOLV_TIMEDOUT; + } + /* This allows us to time-out from the name resolver, as the timeout + will generate a signal and we will siglongjmp() from that here. + This technique has problems (see alarmfunc). + This should be the last thing we do before calling Curl_resolv(), + as otherwise we'd have to worry about variables that get modified + before we invoke Curl_resolv() (and thus use "volatile"). */ + curl_simple_lock_lock(&curl_jmpenv_lock); + + if(sigsetjmp(curl_jmpenv, 1)) { + /* this is coming from a siglongjmp() after an alarm signal */ + failf(data, "name lookup timed out"); + rc = CURLRESOLV_ERROR; + goto clean_up; + } + else { + /************************************************************* + * Set signal handler to catch SIGALRM + * Store the old value to be able to set it back later! + *************************************************************/ +#ifdef HAVE_SIGACTION + sigaction(SIGALRM, NULL, &sigact); + keep_sigact = sigact; + keep_copysig = TRUE; /* yes, we have a copy */ + sigact.sa_handler = alarmfunc; +#ifdef SA_RESTART + /* HPUX doesn't have SA_RESTART but defaults to that behavior! */ + sigact.sa_flags &= ~SA_RESTART; +#endif + /* now set the new struct */ + sigaction(SIGALRM, &sigact, NULL); +#else /* HAVE_SIGACTION */ + /* no sigaction(), revert to the much lamer signal() */ +#ifdef HAVE_SIGNAL + keep_sigact = signal(SIGALRM, alarmfunc); +#endif +#endif /* HAVE_SIGACTION */ + + /* alarm() makes a signal get sent when the timeout fires off, and that + will abort system calls */ + prev_alarm = alarm(curlx_sltoui(timeout/1000L)); + } + +#else +#ifndef CURLRES_ASYNCH + if(timeoutms) + infof(data, "timeout on name lookup is not supported"); +#else + (void)timeoutms; /* timeoutms not used with an async resolver */ +#endif +#endif /* USE_ALARM_TIMEOUT */ + + /* Perform the actual name resolution. This might be interrupted by an + * alarm if it takes too long. + */ + rc = Curl_resolv(data, hostname, port, TRUE, entry); + +#ifdef USE_ALARM_TIMEOUT +clean_up: + + if(!prev_alarm) + /* deactivate a possibly active alarm before uninstalling the handler */ + alarm(0); + +#ifdef HAVE_SIGACTION + if(keep_copysig) { + /* we got a struct as it looked before, now put that one back nice + and clean */ + sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */ + } +#else +#ifdef HAVE_SIGNAL + /* restore the previous SIGALRM handler */ + signal(SIGALRM, keep_sigact); +#endif +#endif /* HAVE_SIGACTION */ + + curl_simple_lock_unlock(&curl_jmpenv_lock); + + /* switch back the alarm() to either zero or to what it was before minus + the time we spent until now! */ + if(prev_alarm) { + /* there was an alarm() set before us, now put it back */ + timediff_t elapsed_secs = Curl_timediff(Curl_now(), + data->conn->created) / 1000; + + /* the alarm period is counted in even number of seconds */ + unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs); + + if(!alarm_set || + ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) { + /* if the alarm time-left reached zero or turned "negative" (counted + with unsigned values), we should fire off a SIGALRM here, but we + won't, and zero would be to switch it off so we never set it to + less than 1! */ + alarm(1); + rc = CURLRESOLV_TIMEDOUT; + failf(data, "Previous alarm fired off"); + } + else + alarm((unsigned int)alarm_set); + } +#endif /* USE_ALARM_TIMEOUT */ + + return rc; +} + +/* + * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been + * made, the struct may be destroyed due to pruning. It is important that only + * one unlock is made for each Curl_resolv() call. + * + * May be called with 'data' == NULL for global cache. + */ +void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) +{ + if(data && data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + freednsentry(dns); + + if(data && data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); +} + +/* + * File-internal: release cache dns entry reference, free if inuse drops to 0 + */ +static void freednsentry(void *freethis) +{ + struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis; + DEBUGASSERT(dns && (dns->inuse>0)); + + dns->inuse--; + if(dns->inuse == 0) { + Curl_freeaddrinfo(dns->addr); + free(dns); + } +} + +/* + * Curl_init_dnscache() inits a new DNS cache. + */ +void Curl_init_dnscache(struct Curl_hash *hash, int size) +{ + Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare, + freednsentry); +} + +/* + * Curl_hostcache_clean() + * + * This _can_ be called with 'data' == NULL but then of course no locking + * can be done! + */ + +void Curl_hostcache_clean(struct Curl_easy *data, + struct Curl_hash *hash) +{ + if(data && data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + Curl_hash_clean(hash); + + if(data && data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); +} + + +CURLcode Curl_loadhostpairs(struct Curl_easy *data) +{ + struct curl_slist *hostp; + char *host_end; + + /* Default is no wildcard found */ + data->state.wildcard_resolve = false; + + for(hostp = data->state.resolve; hostp; hostp = hostp->next) { + char entry_id[MAX_HOSTCACHE_LEN]; + if(!hostp->data) + continue; + if(hostp->data[0] == '-') { + unsigned long num = 0; + size_t entry_len; + size_t hlen = 0; + host_end = strchr(&hostp->data[1], ':'); + + if(host_end) { + hlen = host_end - &hostp->data[1]; + num = strtoul(++host_end, NULL, 10); + if(!hlen || (num > 0xffff)) + host_end = NULL; + } + if(!host_end) { + infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'", + hostp->data); + continue; + } + /* Create an entry id, based upon the hostname and port */ + entry_len = create_hostcache_id(&hostp->data[1], hlen, (int)num, + entry_id, sizeof(entry_id)); + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* delete entry, ignore if it didn't exist */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + } + else { + struct Curl_dns_entry *dns; + struct Curl_addrinfo *head = NULL, *tail = NULL; + size_t entry_len; + char address[64]; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + char *addresses = NULL; +#endif + char *addr_begin; + char *addr_end; + char *port_ptr; + int port = 0; + char *end_ptr; + bool permanent = TRUE; + unsigned long tmp_port; + bool error = true; + char *host_begin = hostp->data; + size_t hlen = 0; + + if(host_begin[0] == '+') { + host_begin++; + permanent = FALSE; + } + host_end = strchr(host_begin, ':'); + if(!host_end) + goto err; + hlen = host_end - host_begin; + + port_ptr = host_end + 1; + tmp_port = strtoul(port_ptr, &end_ptr, 10); + if(tmp_port > USHRT_MAX || end_ptr == port_ptr || *end_ptr != ':') + goto err; + + port = (int)tmp_port; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + addresses = end_ptr + 1; +#endif + + while(*end_ptr) { + size_t alen; + struct Curl_addrinfo *ai; + + addr_begin = end_ptr + 1; + addr_end = strchr(addr_begin, ','); + if(!addr_end) + addr_end = addr_begin + strlen(addr_begin); + end_ptr = addr_end; + + /* allow IP(v6) address within [brackets] */ + if(*addr_begin == '[') { + if(addr_end == addr_begin || *(addr_end - 1) != ']') + goto err; + ++addr_begin; + --addr_end; + } + + alen = addr_end - addr_begin; + if(!alen) + continue; + + if(alen >= sizeof(address)) + goto err; + + memcpy(address, addr_begin, alen); + address[alen] = '\0'; + +#ifndef ENABLE_IPV6 + if(strchr(address, ':')) { + infof(data, "Ignoring resolve address '%s', missing IPv6 support.", + address); + continue; + } +#endif + + ai = Curl_str2addr(address, port); + if(!ai) { + infof(data, "Resolve address '%s' found illegal", address); + goto err; + } + + if(tail) { + tail->ai_next = ai; + tail = tail->ai_next; + } + else { + head = tail = ai; + } + } + + if(!head) + goto err; + + error = false; +err: + if(error) { + failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'", + hostp->data); + Curl_freeaddrinfo(head); + return CURLE_SETOPT_OPTION_SYNTAX; + } + + /* Create an entry id, based upon the hostname and port */ + entry_len = create_hostcache_id(host_begin, hlen, port, + entry_id, sizeof(entry_id)); + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* See if it's already in our dns cache */ + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); + + if(dns) { + infof(data, "RESOLVE %.*s:%d - old addresses discarded", + (int)hlen, host_begin, port); + /* delete old entry, there are two reasons for this + 1. old entry may have different addresses. + 2. even if entry with correct addresses is already in the cache, + but if it is close to expire, then by the time next http + request is made, it can get expired and pruned because old + entry is not necessarily marked as permanent. + 3. when adding a non-permanent entry, we want it to remove and + replace an existing permanent entry. + 4. when adding a non-permanent entry, we want it to get a "fresh" + timeout that starts _now_. */ + + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); + } + + /* put this new host in the cache */ + dns = Curl_cache_addr(data, head, host_begin, hlen, port); + if(dns) { + if(permanent) + dns->timestamp = 0; /* mark as permanent */ + /* release the returned reference; the cache itself will keep the + * entry alive: */ + dns->inuse--; + } + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + if(!dns) { + Curl_freeaddrinfo(head); + return CURLE_OUT_OF_MEMORY; + } +#ifndef CURL_DISABLE_VERBOSE_STRINGS + infof(data, "Added %.*s:%d:%s to DNS cache%s", + (int)hlen, host_begin, port, addresses, + permanent ? "" : " (non-permanent)"); +#endif + + /* Wildcard hostname */ + if((hlen == 1) && (host_begin[0] == '*')) { + infof(data, "RESOLVE *:%d using wildcard", port); + data->state.wildcard_resolve = true; + } + } + } + data->state.resolve = NULL; /* dealt with now */ + + return CURLE_OK; +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void show_resolve_info(struct Curl_easy *data, + struct Curl_dns_entry *dns) +{ + struct Curl_addrinfo *a; + CURLcode result = CURLE_OK; +#ifdef CURLRES_IPV6 + struct dynbuf out[2]; +#else + struct dynbuf out[1]; +#endif + DEBUGASSERT(data); + DEBUGASSERT(dns); + + if(!data->set.verbose || + /* ignore no name or numerical IP addresses */ + !dns->hostname[0] || Curl_host_is_ipnum(dns->hostname)) + return; + + a = dns->addr; + + infof(data, "Host %s:%d was resolved.", + (dns->hostname[0] ? dns->hostname : "(none)"), dns->hostport); + + Curl_dyn_init(&out[0], 1024); +#ifdef CURLRES_IPV6 + Curl_dyn_init(&out[1], 1024); +#endif + + while(a) { + if( +#ifdef CURLRES_IPV6 + a->ai_family == PF_INET6 || +#endif + a->ai_family == PF_INET) { + char buf[MAX_IPADR_LEN]; + struct dynbuf *d = &out[(a->ai_family != PF_INET)]; + Curl_printable_address(a, buf, sizeof(buf)); + if(Curl_dyn_len(d)) + result = Curl_dyn_addn(d, ", ", 2); + if(!result) + result = Curl_dyn_add(d, buf); + if(result) { + infof(data, "too many IP, can't show"); + goto fail; + } + } + a = a->ai_next; + } + +#ifdef CURLRES_IPV6 + infof(data, "IPv6: %s", + (Curl_dyn_len(&out[1]) ? Curl_dyn_ptr(&out[1]) : "(none)")); +#endif + infof(data, "IPv4: %s", + (Curl_dyn_len(&out[0]) ? Curl_dyn_ptr(&out[0]) : "(none)")); + +fail: + Curl_dyn_free(&out[0]); +#ifdef CURLRES_IPV6 + Curl_dyn_free(&out[1]); +#endif +} +#endif + +CURLcode Curl_resolv_check(struct Curl_easy *data, + struct Curl_dns_entry **dns) +{ + CURLcode result; +#if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH) + (void)data; + (void)dns; +#endif +#ifndef CURL_DISABLE_DOH + if(data->conn->bits.doh) { + result = Curl_doh_is_resolved(data, dns); + } + else +#endif + result = Curl_resolver_is_resolved(data, dns); + if(*dns) + show_resolve_info(data, *dns); + return result; +} + +int Curl_resolv_getsock(struct Curl_easy *data, + curl_socket_t *socks) +{ +#ifdef CURLRES_ASYNCH +#ifndef CURL_DISABLE_DOH + if(data->conn->bits.doh) + /* nothing to wait for during DoH resolve, those handles have their own + sockets */ + return GETSOCK_BLANK; +#endif + return Curl_resolver_getsock(data, socks); +#else + (void)data; + (void)socks; + return GETSOCK_BLANK; +#endif +} + +/* Call this function after Curl_connect() has returned async=TRUE and + then a successful name resolve has been received. + + Note: this function disconnects and frees the conn data in case of + resolve failure */ +CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done) +{ + CURLcode result; + struct connectdata *conn = data->conn; + +#ifdef USE_CURL_ASYNC + if(data->state.async.dns) { + conn->dns_entry = data->state.async.dns; + data->state.async.dns = NULL; + } +#endif + + result = Curl_setup_conn(data, protocol_done); + + if(result) { + Curl_detach_connection(data); + Curl_conncache_remove_conn(data, conn, TRUE); + Curl_disconnect(data, conn, TRUE); + } + return result; +} + +/* + * Curl_resolver_error() calls failf() with the appropriate message after a + * resolve error + */ + +#ifdef USE_CURL_ASYNC +CURLcode Curl_resolver_error(struct Curl_easy *data) +{ + const char *host_or_proxy; + CURLcode result; + +#ifndef CURL_DISABLE_PROXY + struct connectdata *conn = data->conn; + if(conn->bits.httpproxy) { + host_or_proxy = "proxy"; + result = CURLE_COULDNT_RESOLVE_PROXY; + } + else +#endif + { + host_or_proxy = "host"; + result = CURLE_COULDNT_RESOLVE_HOST; + } + + failf(data, "Could not resolve %s: %s", host_or_proxy, + data->state.async.hostname); + + return result; +} +#endif /* USE_CURL_ASYNC */ diff --git a/lib/hostip.h b/lib/hostip.h new file mode 100644 index 0000000..fb53a57 --- /dev/null +++ b/lib/hostip.h @@ -0,0 +1,229 @@ +#ifndef HEADER_CURL_HOSTIP_H +#define HEADER_CURL_HOSTIP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "hash.h" +#include "curl_addrinfo.h" +#include "timeval.h" /* for timediff_t */ +#include "asyn.h" + +#include + +/* Allocate enough memory to hold the full name information structs and + * everything. OSF1 is known to require at least 8872 bytes. The buffer + * required for storing all possible aliases and IP numbers is according to + * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes! + */ +#define CURL_HOSTENT_SIZE 9000 + +#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this + many seconds for a name resolve */ + +#define CURL_ASYNC_SUCCESS CURLE_OK + +struct addrinfo; +struct hostent; +struct Curl_easy; +struct connectdata; + +/* + * Curl_global_host_cache_init() initializes and sets up a global DNS cache. + * Global DNS cache is general badness. Do not use. This will be removed in + * a future version. Use the share interface instead! + * + * Returns a struct Curl_hash pointer on success, NULL on failure. + */ +struct Curl_hash *Curl_global_host_cache_init(void); + +struct Curl_dns_entry { + struct Curl_addrinfo *addr; + /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */ + time_t timestamp; + /* use-counter, use Curl_resolv_unlock to release reference */ + long inuse; + /* hostname port number that resolved to addr. */ + int hostport; + /* hostname that resolved to addr. may be NULL (unix domain sockets). */ + char hostname[1]; +}; + +bool Curl_host_is_ipnum(const char *hostname); + +/* + * Curl_resolv() returns an entry with the info for the specified host + * and port. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! + */ +/* return codes */ +enum resolve_t { + CURLRESOLV_TIMEDOUT = -2, + CURLRESOLV_ERROR = -1, + CURLRESOLV_RESOLVED = 0, + CURLRESOLV_PENDING = 1 +}; +enum resolve_t Curl_resolv(struct Curl_easy *data, + const char *hostname, + int port, + bool allowDOH, + struct Curl_dns_entry **dnsentry); +enum resolve_t Curl_resolv_timeout(struct Curl_easy *data, + const char *hostname, int port, + struct Curl_dns_entry **dnsentry, + timediff_t timeoutms); + +#ifdef ENABLE_IPV6 +/* + * Curl_ipv6works() returns TRUE if IPv6 seems to work. + */ +bool Curl_ipv6works(struct Curl_easy *data); +#else +#define Curl_ipv6works(x) FALSE +#endif + +/* + * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've + * been set and returns TRUE if they are OK. + */ +bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn); + + +/* + * Curl_getaddrinfo() is the generic low-level name resolve API within this + * source file. There are several versions of this function - for different + * name resolve layers (selected at build-time). They all take this same set + * of arguments + */ +struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp); + + +/* unlock a previously resolved dns entry */ +void Curl_resolv_unlock(struct Curl_easy *data, + struct Curl_dns_entry *dns); + +/* init a new dns cache */ +void Curl_init_dnscache(struct Curl_hash *hash, int hashsize); + +/* prune old entries from the DNS cache */ +void Curl_hostcache_prune(struct Curl_easy *data); + +/* IPv4 threadsafe resolve function used for synch and asynch builds */ +struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port); + +CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_connect); + +/* + * Curl_addrinfo_callback() is used when we build with any asynch specialty. + * Handles end of async request processing. Inserts ai into hostcache when + * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async + * request completed whether successful or failed. + */ +CURLcode Curl_addrinfo_callback(struct Curl_easy *data, + int status, + struct Curl_addrinfo *ai); + +/* + * Curl_printable_address() returns a printable version of the 1st address + * given in the 'ip' argument. The result will be stored in the buf that is + * bufsize bytes big. + */ +void Curl_printable_address(const struct Curl_addrinfo *ip, + char *buf, size_t bufsize); + +/* + * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. + * + * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! + */ +struct Curl_dns_entry * +Curl_fetch_addr(struct Curl_easy *data, + const char *hostname, + int port); + +/* + * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. + * + * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. + */ +struct Curl_dns_entry * +Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, + const char *hostname, size_t hostlen, int port); + +#ifndef INADDR_NONE +#define CURL_INADDR_NONE (in_addr_t) ~0 +#else +#define CURL_INADDR_NONE INADDR_NONE +#endif + +/* + * Function provided by the resolver backend to set DNS servers to use. + */ +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers); + +/* + * Function provided by the resolver backend to set + * outgoing interface to use for DNS requests + */ +CURLcode Curl_set_dns_interface(struct Curl_easy *data, + const char *interf); + +/* + * Function provided by the resolver backend to set + * local IPv4 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, + const char *local_ip4); + +/* + * Function provided by the resolver backend to set + * local IPv6 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, + const char *local_ip6); + +/* + * Clean off entries from the cache + */ +void Curl_hostcache_clean(struct Curl_easy *data, struct Curl_hash *hash); + +/* + * Populate the cache with specified entries from CURLOPT_RESOLVE. + */ +CURLcode Curl_loadhostpairs(struct Curl_easy *data); +CURLcode Curl_resolv_check(struct Curl_easy *data, + struct Curl_dns_entry **dns); +int Curl_resolv_getsock(struct Curl_easy *data, + curl_socket_t *socks); + +CURLcode Curl_resolver_error(struct Curl_easy *data); +#endif /* HEADER_CURL_HOSTIP_H */ diff --git a/lib/hostip4.c b/lib/hostip4.c new file mode 100644 index 0000000..9140180 --- /dev/null +++ b/lib/hostip4.c @@ -0,0 +1,301 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/*********************************************************************** + * Only for plain IPv4 builds + **********************************************************************/ +#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */ + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "url.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've + * been set and returns TRUE if they are OK. + */ +bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn) +{ + (void)data; + if(conn->ip_version == CURL_IPRESOLVE_V6) + /* An IPv6 address was requested and we can't get/use one */ + return FALSE; + + return TRUE; /* OK, proceed */ +} + +#ifdef CURLRES_SYNCH + +/* + * Curl_getaddrinfo() - the IPv4 synchronous version. + * + * The original code to this function was from the Dancer source code, written + * by Bjorn Reese, it has since been patched and modified considerably. + * + * gethostbyname_r() is the thread-safe version of the gethostbyname() + * function. When we build for plain IPv4, we attempt to use this + * function. There are _three_ different gethostbyname_r() versions, and we + * detect which one this platform supports in the configure script and set up + * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or + * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME + * has the corresponding rules. This is primarily on *nix. Note that some unix + * flavours have thread-safe versions of the plain gethostbyname() etc. + * + */ +struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp) +{ + struct Curl_addrinfo *ai = NULL; + +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; +#endif + + *waitp = 0; /* synchronous response only */ + + ai = Curl_ipv4_resolve_r(hostname, port); + if(!ai) + infof(data, "Curl_ipv4_resolve_r failed for %s", hostname); + + return ai; +} +#endif /* CURLRES_SYNCH */ +#endif /* CURLRES_IPV4 */ + +#if defined(CURLRES_IPV4) && \ + !defined(CURLRES_ARES) && !defined(CURLRES_AMIGA) + +/* + * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function. + * + * This is used for both synchronous and asynchronous resolver builds, + * implying that only threadsafe code and function calls may be used. + * + */ +struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, + int port) +{ +#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)) && \ + defined(HAVE_GETHOSTBYNAME_R_3) + int res; +#endif + struct Curl_addrinfo *ai = NULL; + struct hostent *h = NULL; + struct hostent *buf = NULL; + +#if defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE) + struct addrinfo hints; + char sbuf[12]; + char *sbufptr = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + if(port) { + msnprintf(sbuf, sizeof(sbuf), "%d", port); + sbufptr = sbuf; + } + + (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai); + +#elif defined(HAVE_GETHOSTBYNAME_R) + /* + * gethostbyname_r() is the preferred resolve function for many platforms. + * Since there are three different versions of it, the following code is + * somewhat #ifdef-ridden. + */ + int h_errnop; + + buf = calloc(1, CURL_HOSTENT_SIZE); + if(!buf) + return NULL; /* major failure */ + /* + * The clearing of the buffer is a workaround for a gethostbyname_r bug in + * qnx nto and it is also _required_ for some of these functions on some + * platforms. + */ + +#if defined(HAVE_GETHOSTBYNAME_R_5) + /* Solaris, IRIX and more */ + h = gethostbyname_r(hostname, + (struct hostent *)buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h_errnop); + + /* If the buffer is too small, it returns NULL and sets errno to + * ERANGE. The errno is thread safe if this is compiled with + * -D_REENTRANT as then the 'errno' variable is a macro defined to get + * used properly for threads. + */ + + if(h) { + ; + } + else +#elif defined(HAVE_GETHOSTBYNAME_R_6) + /* Linux */ + + (void)gethostbyname_r(hostname, + (struct hostent *)buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h, /* DIFFERENCE */ + &h_errnop); + /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a + * sudden this function returns EAGAIN if the given buffer size is too + * small. Previous versions are known to return ERANGE for the same + * problem. + * + * This wouldn't be such a big problem if older versions wouldn't + * sometimes return EAGAIN on a common failure case. Alas, we can't + * assume that EAGAIN *or* ERANGE means ERANGE for any given version of + * glibc. + * + * For now, we do that and thus we may call the function repeatedly and + * fail for older glibc versions that return EAGAIN, until we run out of + * buffer size (step_size grows beyond CURL_HOSTENT_SIZE). + * + * If anyone has a better fix, please tell us! + * + * ------------------------------------------------------------------- + * + * On October 23rd 2003, Dan C dug up more details on the mysteries of + * gethostbyname_r() in glibc: + * + * In glibc 2.2.5 the interface is different (this has also been + * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't + * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32 + * (shipped/upgraded by Redhat 7.2) don't show this behavior! + * + * In this "buggy" version, the return code is -1 on error and 'errno' + * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a + * thread-safe variable. + */ + + if(!h) /* failure */ +#elif defined(HAVE_GETHOSTBYNAME_R_3) + /* AIX, Digital Unix/Tru64, HPUX 10, more? */ + + /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of + * the plain fact that it does not return unique full buffers on each + * call, but instead several of the pointers in the hostent structs will + * point to the same actual data! This have the unfortunate down-side that + * our caching system breaks down horribly. Luckily for us though, AIX 4.3 + * and more recent versions have a "completely thread-safe"[*] libc where + * all the data is stored in thread-specific memory areas making calls to + * the plain old gethostbyname() work fine even for multi-threaded + * programs. + * + * This AIX 4.3 or later detection is all made in the configure script. + * + * Troels Walsted Hansen helped us work this out on March 3rd, 2003. + * + * [*] = much later we've found out that it isn't at all "completely + * thread-safe", but at least the gethostbyname() function is. + */ + + if(CURL_HOSTENT_SIZE >= + (sizeof(struct hostent) + sizeof(struct hostent_data))) { + + /* August 22nd, 2000: Albert Chin-A-Young brought an updated version + * that should work! September 20: Richard Prescott worked on the buffer + * size dilemma. + */ + + res = gethostbyname_r(hostname, + (struct hostent *)buf, + (struct hostent_data *)((char *)buf + + sizeof(struct hostent))); + h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */ + } + else + res = -1; /* failure, too smallish buffer size */ + + if(!res) { /* success */ + + h = buf; /* result expected in h */ + + /* This is the worst kind of the different gethostbyname_r() interfaces. + * Since we don't know how big buffer this particular lookup required, + * we can't realloc down the huge alloc without doing closer analysis of + * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every + * name lookup. Fixing this would require an extra malloc() and then + * calling Curl_addrinfo_copy() that subsequent realloc()s down the new + * memory area to the actually used amount. + */ + } + else +#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */ + { + h = NULL; /* set return code to NULL */ + free(buf); + } +#else /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) || + HAVE_GETHOSTBYNAME_R */ + /* + * Here is code for platforms that don't have a thread safe + * getaddrinfo() nor gethostbyname_r() function or for which + * gethostbyname() is the preferred one. + */ + h = gethostbyname((void *)hostname); +#endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) || + HAVE_GETHOSTBYNAME_R */ + + if(h) { + ai = Curl_he2ai(h, port); + + if(buf) /* used a *_r() function */ + free(buf); + } + + return ai; +} +#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) && + !defined(CURLRES_AMIGA) */ diff --git a/lib/hostip6.c b/lib/hostip6.c new file mode 100644 index 0000000..18969a7 --- /dev/null +++ b/lib/hostip6.c @@ -0,0 +1,157 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/*********************************************************************** + * Only for IPv6-enabled builds + **********************************************************************/ +#ifdef CURLRES_IPV6 + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "url.h" +#include "inet_pton.h" +#include "connect.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've + * been set and returns TRUE if they are OK. + */ +bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn) +{ + if(conn->ip_version == CURL_IPRESOLVE_V6) + return Curl_ipv6works(data); + + return TRUE; +} + +#if defined(CURLRES_SYNCH) + +#ifdef DEBUG_ADDRINFO +static void dump_addrinfo(const struct Curl_addrinfo *ai) +{ + printf("dump_addrinfo:\n"); + for(; ai; ai = ai->ai_next) { + char buf[INET6_ADDRSTRLEN]; + printf(" fam %2d, CNAME %s, ", + ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); + Curl_printable_address(ai, buf, sizeof(buf)); + printf("%s\n", buf); + } +} +#else +#define dump_addrinfo(x) Curl_nop_stmt +#endif + +/* + * Curl_getaddrinfo() when built IPv6-enabled (non-threading and + * non-ares version). + * + * Returns name information about the given hostname and port number. If + * successful, the 'addrinfo' is returned and the fourth argument will point + * to memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + */ +struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp) +{ + struct addrinfo hints; + struct Curl_addrinfo *res; + int error; + char sbuf[12]; + char *sbufptr = NULL; +#ifndef USE_RESOLVE_ON_IPS + char addrbuf[128]; +#endif + int pf = PF_INET; + + *waitp = 0; /* synchronous response only */ + + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) + /* The stack seems to be IPv6-enabled */ + pf = PF_UNSPEC; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = pf; + hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ? + SOCK_STREAM : SOCK_DGRAM; + +#ifndef USE_RESOLVE_ON_IPS + /* + * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from + * an IPv4 address on iOS and Mac OS X. + */ + if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) || + (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) { + /* the given address is numerical only, prevent a reverse lookup */ + hints.ai_flags = AI_NUMERICHOST; + } +#endif + + if(port) { + msnprintf(sbuf, sizeof(sbuf), "%d", port); + sbufptr = sbuf; + } + + error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res); + if(error) { + infof(data, "getaddrinfo(3) failed for %s:%d", hostname, port); + return NULL; + } + + if(port) { + Curl_addrinfo_set_port(res, port); + } + + dump_addrinfo(res); + + return res; +} +#endif /* CURLRES_SYNCH */ + +#endif /* CURLRES_IPV6 */ diff --git a/lib/hostsyn.c b/lib/hostsyn.c new file mode 100644 index 0000000..ca8b075 --- /dev/null +++ b/lib/hostsyn.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/*********************************************************************** + * Only for builds using synchronous name resolves + **********************************************************************/ +#ifdef CURLRES_SYNCH + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "url.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Function provided by the resolver backend to set DNS servers to use. + */ +CURLcode Curl_set_dns_servers(struct Curl_easy *data, + char *servers) +{ + (void)data; + (void)servers; + return CURLE_NOT_BUILT_IN; + +} + +/* + * Function provided by the resolver backend to set + * outgoing interface to use for DNS requests + */ +CURLcode Curl_set_dns_interface(struct Curl_easy *data, + const char *interf) +{ + (void)data; + (void)interf; + return CURLE_NOT_BUILT_IN; +} + +/* + * Function provided by the resolver backend to set + * local IPv4 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, + const char *local_ip4) +{ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +} + +/* + * Function provided by the resolver backend to set + * local IPv6 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, + const char *local_ip6) +{ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +} + +#endif /* truly sync */ diff --git a/lib/hsts.c b/lib/hsts.c new file mode 100644 index 0000000..8725a35 --- /dev/null +++ b/lib/hsts.c @@ -0,0 +1,585 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + * The Strict-Transport-Security header is defined in RFC 6797: + * https://datatracker.ietf.org/doc/html/rfc6797 + */ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS) +#include +#include "urldata.h" +#include "llist.h" +#include "hsts.h" +#include "curl_get_line.h" +#include "strcase.h" +#include "sendf.h" +#include "strtoofft.h" +#include "parsedate.h" +#include "fopen.h" +#include "rename.h" +#include "share.h" +#include "strdup.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define MAX_HSTS_LINE 4095 +#define MAX_HSTS_HOSTLEN 256 +#define MAX_HSTS_HOSTLENSTR "256" +#define MAX_HSTS_DATELEN 64 +#define MAX_HSTS_DATELENSTR "64" +#define UNLIMITED "unlimited" + +#ifdef DEBUGBUILD +/* to play well with debug builds, we can *set* a fixed time this will + return */ +time_t deltatime; /* allow for "adjustments" for unit test purposes */ +static time_t hsts_debugtime(void *unused) +{ + char *timestr = getenv("CURL_TIME"); + (void)unused; + if(timestr) { + curl_off_t val; + (void)curlx_strtoofft(timestr, NULL, 10, &val); + + val += (curl_off_t)deltatime; + return (time_t)val; + } + return time(NULL); +} +#undef time +#define time(x) hsts_debugtime(x) +#endif + +struct hsts *Curl_hsts_init(void) +{ + struct hsts *h = calloc(1, sizeof(struct hsts)); + if(h) { + Curl_llist_init(&h->list, NULL); + } + return h; +} + +static void hsts_free(struct stsentry *e) +{ + free((char *)e->host); + free(e); +} + +void Curl_hsts_cleanup(struct hsts **hp) +{ + struct hsts *h = *hp; + if(h) { + struct Curl_llist_element *e; + struct Curl_llist_element *n; + for(e = h->list.head; e; e = n) { + struct stsentry *sts = e->ptr; + n = e->next; + hsts_free(sts); + } + free(h->filename); + free(h); + *hp = NULL; + } +} + +static struct stsentry *hsts_entry(void) +{ + return calloc(1, sizeof(struct stsentry)); +} + +static CURLcode hsts_create(struct hsts *h, + const char *hostname, + bool subdomains, + curl_off_t expires) +{ + size_t hlen; + DEBUGASSERT(h); + DEBUGASSERT(hostname); + + hlen = strlen(hostname); + if(hlen && (hostname[hlen - 1] == '.')) + /* strip off any trailing dot */ + --hlen; + if(hlen) { + char *duphost; + struct stsentry *sts = hsts_entry(); + if(!sts) + return CURLE_OUT_OF_MEMORY; + + duphost = Curl_memdup0(hostname, hlen); + if(!duphost) { + free(sts); + return CURLE_OUT_OF_MEMORY; + } + + sts->host = duphost; + sts->expires = expires; + sts->includeSubDomains = subdomains; + Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node); + } + return CURLE_OK; +} + +CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, + const char *header) +{ + const char *p = header; + curl_off_t expires = 0; + bool gotma = FALSE; + bool gotinc = FALSE; + bool subdomains = FALSE; + struct stsentry *sts; + time_t now = time(NULL); + + if(Curl_host_is_ipnum(hostname)) + /* "explicit IP address identification of all forms is excluded." + / RFC 6797 */ + return CURLE_OK; + + do { + while(*p && ISBLANK(*p)) + p++; + if(strncasecompare("max-age=", p, 8)) { + bool quoted = FALSE; + CURLofft offt; + char *endp; + + if(gotma) + return CURLE_BAD_FUNCTION_ARGUMENT; + + p += 8; + while(*p && ISBLANK(*p)) + p++; + if(*p == '\"') { + p++; + quoted = TRUE; + } + offt = curlx_strtoofft(p, &endp, 10, &expires); + if(offt == CURL_OFFT_FLOW) + expires = CURL_OFF_T_MAX; + else if(offt) + /* invalid max-age */ + return CURLE_BAD_FUNCTION_ARGUMENT; + p = endp; + if(quoted) { + if(*p != '\"') + return CURLE_BAD_FUNCTION_ARGUMENT; + p++; + } + gotma = TRUE; + } + else if(strncasecompare("includesubdomains", p, 17)) { + if(gotinc) + return CURLE_BAD_FUNCTION_ARGUMENT; + subdomains = TRUE; + p += 17; + gotinc = TRUE; + } + else { + /* unknown directive, do a lame attempt to skip */ + while(*p && (*p != ';')) + p++; + } + + while(*p && ISBLANK(*p)) + p++; + if(*p == ';') + p++; + } while(*p); + + if(!gotma) + /* max-age is mandatory */ + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(!expires) { + /* remove the entry if present verbatim (without subdomain match) */ + sts = Curl_hsts(h, hostname, FALSE); + if(sts) { + Curl_llist_remove(&h->list, &sts->node, NULL); + hsts_free(sts); + } + return CURLE_OK; + } + + if(CURL_OFF_T_MAX - now < expires) + /* would overflow, use maximum value */ + expires = CURL_OFF_T_MAX; + else + expires += now; + + /* check if it already exists */ + sts = Curl_hsts(h, hostname, FALSE); + if(sts) { + /* just update these fields */ + sts->expires = expires; + sts->includeSubDomains = subdomains; + } + else + return hsts_create(h, hostname, subdomains, expires); + + return CURLE_OK; +} + +/* + * Return TRUE if the given host name is currently an HSTS one. + * + * The 'subdomain' argument tells the function if subdomain matching should be + * attempted. + */ +struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, + bool subdomain) +{ + if(h) { + char buffer[MAX_HSTS_HOSTLEN + 1]; + time_t now = time(NULL); + size_t hlen = strlen(hostname); + struct Curl_llist_element *e; + struct Curl_llist_element *n; + + if((hlen > MAX_HSTS_HOSTLEN) || !hlen) + return NULL; + memcpy(buffer, hostname, hlen); + if(hostname[hlen-1] == '.') + /* remove the trailing dot */ + --hlen; + buffer[hlen] = 0; + hostname = buffer; + + for(e = h->list.head; e; e = n) { + struct stsentry *sts = e->ptr; + n = e->next; + if(sts->expires <= now) { + /* remove expired entries */ + Curl_llist_remove(&h->list, &sts->node, NULL); + hsts_free(sts); + continue; + } + if(subdomain && sts->includeSubDomains) { + size_t ntail = strlen(sts->host); + if(ntail < hlen) { + size_t offs = hlen - ntail; + if((hostname[offs-1] == '.') && + strncasecompare(&hostname[offs], sts->host, ntail)) + return sts; + } + } + if(strcasecompare(hostname, sts->host)) + return sts; + } + } + return NULL; /* no match */ +} + +/* + * Send this HSTS entry to the write callback. + */ +static CURLcode hsts_push(struct Curl_easy *data, + struct curl_index *i, + struct stsentry *sts, + bool *stop) +{ + struct curl_hstsentry e; + CURLSTScode sc; + struct tm stamp; + CURLcode result; + + e.name = (char *)sts->host; + e.namelen = strlen(sts->host); + e.includeSubDomains = sts->includeSubDomains; + + if(sts->expires != TIME_T_MAX) { + result = Curl_gmtime((time_t)sts->expires, &stamp); + if(result) + return result; + + msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d", + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + } + else + strcpy(e.expire, UNLIMITED); + + sc = data->set.hsts_write(data, &e, i, + data->set.hsts_write_userp); + *stop = (sc != CURLSTS_OK); + return sc == CURLSTS_FAIL ? CURLE_BAD_FUNCTION_ARGUMENT : CURLE_OK; +} + +/* + * Write this single hsts entry to a single output line + */ +static CURLcode hsts_out(struct stsentry *sts, FILE *fp) +{ + struct tm stamp; + if(sts->expires != TIME_T_MAX) { + CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp); + if(result) + return result; + fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n", + sts->includeSubDomains ? ".": "", sts->host, + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + } + else + fprintf(fp, "%s%s \"%s\"\n", + sts->includeSubDomains ? ".": "", sts->host, UNLIMITED); + return CURLE_OK; +} + + +/* + * Curl_https_save() writes the HSTS cache to file and callback. + */ +CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, + const char *file) +{ + struct Curl_llist_element *e; + struct Curl_llist_element *n; + CURLcode result = CURLE_OK; + FILE *out; + char *tempstore = NULL; + + if(!h) + /* no cache activated */ + return CURLE_OK; + + /* if no new name is given, use the one we stored from the load */ + if(!file && h->filename) + file = h->filename; + + if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0]) + /* marked as read-only, no file or zero length file name */ + goto skipsave; + + result = Curl_fopen(data, file, &out, &tempstore); + if(!result) { + fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n", + out); + for(e = h->list.head; e; e = n) { + struct stsentry *sts = e->ptr; + n = e->next; + result = hsts_out(sts, out); + if(result) + break; + } + fclose(out); + if(!result && tempstore && Curl_rename(tempstore, file)) + result = CURLE_WRITE_ERROR; + + if(result && tempstore) + unlink(tempstore); + } + free(tempstore); +skipsave: + if(data->set.hsts_write) { + /* if there's a write callback */ + struct curl_index i; /* count */ + i.total = h->list.size; + i.index = 0; + for(e = h->list.head; e; e = n) { + struct stsentry *sts = e->ptr; + bool stop; + n = e->next; + result = hsts_push(data, &i, sts, &stop); + if(result || stop) + break; + i.index++; + } + } + return result; +} + +/* only returns SERIOUS errors */ +static CURLcode hsts_add(struct hsts *h, char *line) +{ + /* Example lines: + example.com "20191231 10:00:00" + .example.net "20191231 10:00:00" + */ + char host[MAX_HSTS_HOSTLEN + 1]; + char date[MAX_HSTS_DATELEN + 1]; + int rc; + + rc = sscanf(line, + "%" MAX_HSTS_HOSTLENSTR "s \"%" MAX_HSTS_DATELENSTR "[^\"]\"", + host, date); + if(2 == rc) { + time_t expires = strcmp(date, UNLIMITED) ? Curl_getdate_capped(date) : + TIME_T_MAX; + CURLcode result = CURLE_OK; + char *p = host; + bool subdomain = FALSE; + struct stsentry *e; + if(p[0] == '.') { + p++; + subdomain = TRUE; + } + /* only add it if not already present */ + e = Curl_hsts(h, p, subdomain); + if(!e) + result = hsts_create(h, p, subdomain, expires); + else { + /* the same host name, use the largest expire time */ + if(expires > e->expires) + e->expires = expires; + } + if(result) + return result; + } + + return CURLE_OK; +} + +/* + * Load HSTS data from callback. + * + */ +static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h) +{ + /* if the HSTS read callback is set, use it */ + if(data->set.hsts_read) { + CURLSTScode sc; + DEBUGASSERT(h); + do { + char buffer[MAX_HSTS_HOSTLEN + 1]; + struct curl_hstsentry e; + e.name = buffer; + e.namelen = sizeof(buffer)-1; + e.includeSubDomains = FALSE; /* default */ + e.expire[0] = 0; + e.name[0] = 0; /* just to make it clean */ + sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp); + if(sc == CURLSTS_OK) { + time_t expires; + CURLcode result; + DEBUGASSERT(e.name[0]); + if(!e.name[0]) + /* bail out if no name was stored */ + return CURLE_BAD_FUNCTION_ARGUMENT; + if(e.expire[0]) + expires = Curl_getdate_capped(e.expire); + else + expires = TIME_T_MAX; /* the end of time */ + result = hsts_create(h, e.name, + /* bitfield to bool conversion: */ + e.includeSubDomains ? TRUE : FALSE, + expires); + if(result) + return result; + } + else if(sc == CURLSTS_FAIL) + return CURLE_ABORTED_BY_CALLBACK; + } while(sc == CURLSTS_OK); + } + return CURLE_OK; +} + +/* + * Load the HSTS cache from the given file. The text based line-oriented file + * format is documented here: https://curl.se/docs/hsts.html + * + * This function only returns error on major problems that prevent hsts + * handling to work completely. It will ignore individual syntactical errors + * etc. + */ +static CURLcode hsts_load(struct hsts *h, const char *file) +{ + CURLcode result = CURLE_OK; + char *line = NULL; + FILE *fp; + + /* we need a private copy of the file name so that the hsts cache file + name survives an easy handle reset */ + free(h->filename); + h->filename = strdup(file); + if(!h->filename) + return CURLE_OUT_OF_MEMORY; + + fp = fopen(file, FOPEN_READTEXT); + if(fp) { + line = malloc(MAX_HSTS_LINE); + if(!line) + goto fail; + while(Curl_get_line(line, MAX_HSTS_LINE, fp)) { + char *lineptr = line; + while(*lineptr && ISBLANK(*lineptr)) + lineptr++; + if(*lineptr == '#') + /* skip commented lines */ + continue; + + hsts_add(h, lineptr); + } + free(line); /* free the line buffer */ + fclose(fp); + } + return result; + +fail: + Curl_safefree(h->filename); + fclose(fp); + return CURLE_OUT_OF_MEMORY; +} + +/* + * Curl_hsts_loadfile() loads HSTS from file + */ +CURLcode Curl_hsts_loadfile(struct Curl_easy *data, + struct hsts *h, const char *file) +{ + DEBUGASSERT(h); + (void)data; + return hsts_load(h, file); +} + +/* + * Curl_hsts_loadcb() loads HSTS from callback + */ +CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h) +{ + if(h) + return hsts_pull(data, h); + return CURLE_OK; +} + +void Curl_hsts_loadfiles(struct Curl_easy *data) +{ + struct curl_slist *l = data->state.hstslist; + if(l) { + Curl_share_lock(data, CURL_LOCK_DATA_HSTS, CURL_LOCK_ACCESS_SINGLE); + + while(l) { + (void)Curl_hsts_loadfile(data, data->hsts, l->data); + l = l->next; + } + Curl_share_unlock(data, CURL_LOCK_DATA_HSTS); + } +} + +#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ diff --git a/lib/hsts.h b/lib/hsts.h new file mode 100644 index 0000000..d3431a5 --- /dev/null +++ b/lib/hsts.h @@ -0,0 +1,69 @@ +#ifndef HEADER_CURL_HSTS_H +#define HEADER_CURL_HSTS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS) +#include +#include "llist.h" + +#ifdef DEBUGBUILD +extern time_t deltatime; +#endif + +struct stsentry { + struct Curl_llist_element node; + const char *host; + bool includeSubDomains; + curl_off_t expires; /* the timestamp of this entry's expiry */ +}; + +/* The HSTS cache. Needs to be able to tailmatch host names. */ +struct hsts { + struct Curl_llist list; + char *filename; + unsigned int flags; +}; + +struct hsts *Curl_hsts_init(void); +void Curl_hsts_cleanup(struct hsts **hp); +CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, + const char *sts); +struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, + bool subdomain); +CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, + const char *file); +CURLcode Curl_hsts_loadfile(struct Curl_easy *data, + struct hsts *h, const char *file); +CURLcode Curl_hsts_loadcb(struct Curl_easy *data, + struct hsts *h); +void Curl_hsts_loadfiles(struct Curl_easy *data); +#else +#define Curl_hsts_cleanup(x) +#define Curl_hsts_loadcb(x,y) CURLE_OK +#define Curl_hsts_save(x,y,z) +#define Curl_hsts_loadfiles(x) +#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ +#endif /* HEADER_CURL_HSTS_H */ diff --git a/lib/http.c b/lib/http.c new file mode 100644 index 0000000..679931e --- /dev/null +++ b/lib/http.c @@ -0,0 +1,4941 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_HTTP + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef USE_HYPER +#include +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "formdata.h" +#include "mime.h" +#include "progress.h" +#include "curl_base64.h" +#include "cookie.h" +#include "vauth/vauth.h" +#include "vtls/vtls.h" +#include "vquic/vquic.h" +#include "http_digest.h" +#include "http_ntlm.h" +#include "curl_ntlm_wb.h" +#include "http_negotiate.h" +#include "http_aws_sigv4.h" +#include "url.h" +#include "share.h" +#include "hostip.h" +#include "dynhds.h" +#include "http.h" +#include "select.h" +#include "parsedate.h" /* for the week day and month names */ +#include "strtoofft.h" +#include "multiif.h" +#include "strcase.h" +#include "content_encoding.h" +#include "http_proxy.h" +#include "warnless.h" +#include "http2.h" +#include "cfilters.h" +#include "connect.h" +#include "strdup.h" +#include "altsvc.h" +#include "hsts.h" +#include "ws.h" +#include "c-hyper.h" +#include "curl_ctype.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Forward declarations. + */ + +static bool http_should_fail(struct Curl_easy *data); + +/* + * HTTP handler interface. + */ +const struct Curl_handler Curl_handler_http = { + "HTTP", /* scheme */ + Curl_http_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + Curl_http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + Curl_http_write_resp, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTP, /* defport */ + CURLPROTO_HTTP, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_CREDSPERREQUEST | /* flags */ + PROTOPT_USERPWDCTRL +}; + +#ifdef USE_SSL +/* + * HTTPS handler interface. + */ +const struct Curl_handler Curl_handler_https = { + "HTTPS", /* scheme */ + Curl_http_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + NULL, /* connecting */ + ZERO_NULL, /* doing */ + NULL, /* proto_getsock */ + Curl_http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + Curl_http_write_resp, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTPS, /* defport */ + CURLPROTO_HTTPS, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN | /* flags */ + PROTOPT_USERPWDCTRL +}; + +#endif + +CURLcode Curl_http_setup_conn(struct Curl_easy *data, + struct connectdata *conn) +{ + /* allocate the HTTP-specific struct for the Curl_easy, only to survive + during this request */ + struct HTTP *http; + DEBUGASSERT(data->req.p.http == NULL); + + http = calloc(1, sizeof(struct HTTP)); + if(!http) + return CURLE_OUT_OF_MEMORY; + + data->req.p.http = http; + connkeep(conn, "HTTP default"); + + if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) { + CURLcode result = Curl_conn_may_http3(data, conn); + if(result) + return result; + } + + return CURLE_OK; +} + +#ifndef CURL_DISABLE_PROXY +/* + * checkProxyHeaders() checks the linked list of custom proxy headers + * if proxy headers are not available, then it will lookup into http header + * link list + * + * It takes a connectdata struct as input to see if this is a proxy request or + * not, as it then might check a different header list. Provide the header + * prefix without colon! + */ +char *Curl_checkProxyheaders(struct Curl_easy *data, + const struct connectdata *conn, + const char *thisheader, + const size_t thislen) +{ + struct curl_slist *head; + + for(head = (conn->bits.proxy && data->set.sep_headers) ? + data->set.proxyheaders : data->set.headers; + head; head = head->next) { + if(strncasecompare(head->data, thisheader, thislen) && + Curl_headersep(head->data[thislen])) + return head->data; + } + + return NULL; +} +#else +/* disabled */ +#define Curl_checkProxyheaders(x,y,z,a) NULL +#endif + +/* + * Strip off leading and trailing whitespace from the value in the + * given HTTP header line and return a strdupped copy. Returns NULL in + * case of allocation failure. Returns an empty string if the header value + * consists entirely of whitespace. + */ +char *Curl_copy_header_value(const char *header) +{ + const char *start; + const char *end; + size_t len; + + /* Find the end of the header name */ + while(*header && (*header != ':')) + ++header; + + if(*header) + /* Skip over colon */ + ++header; + + /* Find the first non-space letter */ + start = header; + while(*start && ISSPACE(*start)) + start++; + + /* data is in the host encoding so + use '\r' and '\n' instead of 0x0d and 0x0a */ + end = strchr(start, '\r'); + if(!end) + end = strchr(start, '\n'); + if(!end) + end = strchr(start, '\0'); + if(!end) + return NULL; + + /* skip all trailing space letters */ + while((end > start) && ISSPACE(*end)) + end--; + + /* get length of the type */ + len = end - start + 1; + + return Curl_memdup0(start, len); +} + +#ifndef CURL_DISABLE_HTTP_AUTH + +#ifndef CURL_DISABLE_BASIC_AUTH +/* + * http_output_basic() sets up an Authorization: header (or the proxy version) + * for HTTP Basic authentication. + * + * Returns CURLcode. + */ +static CURLcode http_output_basic(struct Curl_easy *data, bool proxy) +{ + size_t size = 0; + char *authorization = NULL; + char **userp; + const char *user; + const char *pwd; + CURLcode result; + char *out; + + /* credentials are unique per transfer for HTTP, do not use the ones for the + connection */ + if(proxy) { +#ifndef CURL_DISABLE_PROXY + userp = &data->state.aptr.proxyuserpwd; + user = data->state.aptr.proxyuser; + pwd = data->state.aptr.proxypasswd; +#else + return CURLE_NOT_BUILT_IN; +#endif + } + else { + userp = &data->state.aptr.userpwd; + user = data->state.aptr.user; + pwd = data->state.aptr.passwd; + } + + out = aprintf("%s:%s", user ? user : "", pwd ? pwd : ""); + if(!out) + return CURLE_OUT_OF_MEMORY; + + result = Curl_base64_encode(out, strlen(out), &authorization, &size); + if(result) + goto fail; + + if(!authorization) { + result = CURLE_REMOTE_ACCESS_DENIED; + goto fail; + } + + free(*userp); + *userp = aprintf("%sAuthorization: Basic %s\r\n", + proxy ? "Proxy-" : "", + authorization); + free(authorization); + if(!*userp) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + +fail: + free(out); + return result; +} + +#endif + +#ifndef CURL_DISABLE_BEARER_AUTH +/* + * http_output_bearer() sets up an Authorization: header + * for HTTP Bearer authentication. + * + * Returns CURLcode. + */ +static CURLcode http_output_bearer(struct Curl_easy *data) +{ + char **userp; + CURLcode result = CURLE_OK; + + userp = &data->state.aptr.userpwd; + free(*userp); + *userp = aprintf("Authorization: Bearer %s\r\n", + data->set.str[STRING_BEARER]); + + if(!*userp) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + +fail: + return result; +} + +#endif + +#endif + +/* pickoneauth() selects the most favourable authentication method from the + * ones available and the ones we want. + * + * return TRUE if one was picked + */ +static bool pickoneauth(struct auth *pick, unsigned long mask) +{ + bool picked; + /* only deal with authentication we want */ + unsigned long avail = pick->avail & pick->want & mask; + picked = TRUE; + + /* The order of these checks is highly relevant, as this will be the order + of preference in case of the existence of multiple accepted types. */ + if(avail & CURLAUTH_NEGOTIATE) + pick->picked = CURLAUTH_NEGOTIATE; +#ifndef CURL_DISABLE_BEARER_AUTH + else if(avail & CURLAUTH_BEARER) + pick->picked = CURLAUTH_BEARER; +#endif +#ifndef CURL_DISABLE_DIGEST_AUTH + else if(avail & CURLAUTH_DIGEST) + pick->picked = CURLAUTH_DIGEST; +#endif + else if(avail & CURLAUTH_NTLM) + pick->picked = CURLAUTH_NTLM; + else if(avail & CURLAUTH_NTLM_WB) + pick->picked = CURLAUTH_NTLM_WB; +#ifndef CURL_DISABLE_BASIC_AUTH + else if(avail & CURLAUTH_BASIC) + pick->picked = CURLAUTH_BASIC; +#endif +#ifndef CURL_DISABLE_AWS + else if(avail & CURLAUTH_AWS_SIGV4) + pick->picked = CURLAUTH_AWS_SIGV4; +#endif + else { + pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */ + picked = FALSE; + } + pick->avail = CURLAUTH_NONE; /* clear it here */ + + return picked; +} + +/* + * http_perhapsrewind() + * + * If we are doing POST or PUT { + * If we have more data to send { + * If we are doing NTLM { + * Keep sending since we must not disconnect + * } + * else { + * If there is more than just a little data left to send, close + * the current connection by force. + * } + * } + * If we have sent any data { + * If we don't have track of all the data { + * call app to tell it to rewind + * } + * else { + * rewind internally so that the operation can restart fine + * } + * } + * } + */ +static CURLcode http_perhapsrewind(struct Curl_easy *data, + struct connectdata *conn) +{ + struct HTTP *http = data->req.p.http; + curl_off_t bytessent; + curl_off_t expectsend = -1; /* default is unknown */ + + if(!http) + /* If this is still NULL, we have not reach very far and we can safely + skip this rewinding stuff */ + return CURLE_OK; + + switch(data->state.httpreq) { + case HTTPREQ_GET: + case HTTPREQ_HEAD: + return CURLE_OK; + default: + break; + } + + bytessent = data->req.writebytecount; + + if(conn->bits.authneg) { + /* This is a state where we are known to be negotiating and we don't send + any data then. */ + expectsend = 0; + } + else if(!conn->bits.protoconnstart) { + /* HTTP CONNECT in progress: there is no body */ + expectsend = 0; + } + else { + /* figure out how much data we are expected to send */ + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_PUT: + if(data->state.infilesize != -1) + expectsend = data->state.infilesize; + break; + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + expectsend = http->postsize; + break; + default: + break; + } + } + + data->state.rewindbeforesend = FALSE; /* default */ + + if((expectsend == -1) || (expectsend > bytessent)) { +#if defined(USE_NTLM) + /* There is still data left to send */ + if((data->state.authproxy.picked == CURLAUTH_NTLM) || + (data->state.authhost.picked == CURLAUTH_NTLM) || + (data->state.authproxy.picked == CURLAUTH_NTLM_WB) || + (data->state.authhost.picked == CURLAUTH_NTLM_WB)) { + if(((expectsend - bytessent) < 2000) || + (conn->http_ntlm_state != NTLMSTATE_NONE) || + (conn->proxy_ntlm_state != NTLMSTATE_NONE)) { + /* The NTLM-negotiation has started *OR* there is just a little (<2K) + data left to send, keep on sending. */ + + /* rewind data when completely done sending! */ + if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { + data->state.rewindbeforesend = TRUE; + infof(data, "Rewind stream before next send"); + } + + return CURLE_OK; + } + + if(conn->bits.close) + /* this is already marked to get closed */ + return CURLE_OK; + + infof(data, "NTLM send, close instead of sending %" + CURL_FORMAT_CURL_OFF_T " bytes", + (curl_off_t)(expectsend - bytessent)); + } +#endif +#if defined(USE_SPNEGO) + /* There is still data left to send */ + if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) || + (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) { + if(((expectsend - bytessent) < 2000) || + (conn->http_negotiate_state != GSS_AUTHNONE) || + (conn->proxy_negotiate_state != GSS_AUTHNONE)) { + /* The NEGOTIATE-negotiation has started *OR* + there is just a little (<2K) data left to send, keep on sending. */ + + /* rewind data when completely done sending! */ + if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { + data->state.rewindbeforesend = TRUE; + infof(data, "Rewind stream before next send"); + } + + return CURLE_OK; + } + + if(conn->bits.close) + /* this is already marked to get closed */ + return CURLE_OK; + + infof(data, "NEGOTIATE send, close instead of sending %" + CURL_FORMAT_CURL_OFF_T " bytes", + (curl_off_t)(expectsend - bytessent)); + } +#endif + + /* This is not NEGOTIATE/NTLM or many bytes left to send: close */ + streamclose(conn, "Mid-auth HTTP and much data left to send"); + data->req.size = 0; /* don't download any more than 0 bytes */ + + /* There still is data left to send, but this connection is marked for + closure so we can safely do the rewind right now */ + } + + if(bytessent) { + /* mark for rewind since if we already sent something */ + data->state.rewindbeforesend = TRUE; + infof(data, "Please rewind output before next send"); + } + + return CURLE_OK; +} + +/* + * Curl_http_auth_act() gets called when all HTTP headers have been received + * and it checks what authentication methods that are available and decides + * which one (if any) to use. It will set 'newurl' if an auth method was + * picked. + */ + +CURLcode Curl_http_auth_act(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + bool pickhost = FALSE; + bool pickproxy = FALSE; + CURLcode result = CURLE_OK; + unsigned long authmask = ~0ul; + + if(!data->set.str[STRING_BEARER]) + authmask &= (unsigned long)~CURLAUTH_BEARER; + + if(100 <= data->req.httpcode && data->req.httpcode <= 199) + /* this is a transient response code, ignore */ + return CURLE_OK; + + if(data->state.authproblem) + return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; + + if((data->state.aptr.user || data->set.str[STRING_BEARER]) && + ((data->req.httpcode == 401) || + (conn->bits.authneg && data->req.httpcode < 300))) { + pickhost = pickoneauth(&data->state.authhost, authmask); + if(!pickhost) + data->state.authproblem = TRUE; + if(data->state.authhost.picked == CURLAUTH_NTLM && + conn->httpversion > 11) { + infof(data, "Forcing HTTP/1.1 for NTLM"); + connclose(conn, "Force HTTP/1.1 connection"); + data->state.httpwant = CURL_HTTP_VERSION_1_1; + } + } +#ifndef CURL_DISABLE_PROXY + if(conn->bits.proxy_user_passwd && + ((data->req.httpcode == 407) || + (conn->bits.authneg && data->req.httpcode < 300))) { + pickproxy = pickoneauth(&data->state.authproxy, + authmask & ~CURLAUTH_BEARER); + if(!pickproxy) + data->state.authproblem = TRUE; + } +#endif + + if(pickhost || pickproxy) { + if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD) && + !data->state.rewindbeforesend) { + result = http_perhapsrewind(data, conn); + if(result) + return result; + } + /* In case this is GSS auth, the newurl field is already allocated so + we must make sure to free it before allocating a new one. As figured + out in bug #2284386 */ + Curl_safefree(data->req.newurl); + data->req.newurl = strdup(data->state.url); /* clone URL */ + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + } + else if((data->req.httpcode < 300) && + (!data->state.authhost.done) && + conn->bits.authneg) { + /* no (known) authentication available, + authentication is not "done" yet and + no authentication seems to be required and + we didn't try HEAD or GET */ + if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD)) { + data->req.newurl = strdup(data->state.url); /* clone URL */ + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + data->state.authhost.done = TRUE; + } + } + if(http_should_fail(data)) { + failf(data, "The requested URL returned error: %d", + data->req.httpcode); + result = CURLE_HTTP_RETURNED_ERROR; + } + + return result; +} + +#ifndef CURL_DISABLE_HTTP_AUTH +/* + * Output the correct authentication header depending on the auth type + * and whether or not it is to a proxy. + */ +static CURLcode +output_auth_headers(struct Curl_easy *data, + struct connectdata *conn, + struct auth *authstatus, + const char *request, + const char *path, + bool proxy) +{ + const char *auth = NULL; + CURLcode result = CURLE_OK; + (void)conn; + +#ifdef CURL_DISABLE_DIGEST_AUTH + (void)request; + (void)path; +#endif +#ifndef CURL_DISABLE_AWS + if(authstatus->picked == CURLAUTH_AWS_SIGV4) { + auth = "AWS_SIGV4"; + result = Curl_output_aws_sigv4(data, proxy); + if(result) + return result; + } + else +#endif +#ifdef USE_SPNEGO + if(authstatus->picked == CURLAUTH_NEGOTIATE) { + auth = "Negotiate"; + result = Curl_output_negotiate(data, conn, proxy); + if(result) + return result; + } + else +#endif +#ifdef USE_NTLM + if(authstatus->picked == CURLAUTH_NTLM) { + auth = "NTLM"; + result = Curl_output_ntlm(data, proxy); + if(result) + return result; + } + else +#endif +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + if(authstatus->picked == CURLAUTH_NTLM_WB) { + auth = "NTLM_WB"; + result = Curl_output_ntlm_wb(data, conn, proxy); + if(result) + return result; + } + else +#endif +#ifndef CURL_DISABLE_DIGEST_AUTH + if(authstatus->picked == CURLAUTH_DIGEST) { + auth = "Digest"; + result = Curl_output_digest(data, + proxy, + (const unsigned char *)request, + (const unsigned char *)path); + if(result) + return result; + } + else +#endif +#ifndef CURL_DISABLE_BASIC_AUTH + if(authstatus->picked == CURLAUTH_BASIC) { + /* Basic */ + if( +#ifndef CURL_DISABLE_PROXY + (proxy && conn->bits.proxy_user_passwd && + !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-authorization"))) || +#endif + (!proxy && data->state.aptr.user && + !Curl_checkheaders(data, STRCONST("Authorization")))) { + auth = "Basic"; + result = http_output_basic(data, proxy); + if(result) + return result; + } + + /* NOTE: this function should set 'done' TRUE, as the other auth + functions work that way */ + authstatus->done = TRUE; + } +#endif +#ifndef CURL_DISABLE_BEARER_AUTH + if(authstatus->picked == CURLAUTH_BEARER) { + /* Bearer */ + if((!proxy && data->set.str[STRING_BEARER] && + !Curl_checkheaders(data, STRCONST("Authorization")))) { + auth = "Bearer"; + result = http_output_bearer(data); + if(result) + return result; + } + + /* NOTE: this function should set 'done' TRUE, as the other auth + functions work that way */ + authstatus->done = TRUE; + } +#endif + + if(auth) { +#ifndef CURL_DISABLE_PROXY + infof(data, "%s auth using %s with user '%s'", + proxy ? "Proxy" : "Server", auth, + proxy ? (data->state.aptr.proxyuser ? + data->state.aptr.proxyuser : "") : + (data->state.aptr.user ? + data->state.aptr.user : "")); +#else + (void)proxy; + infof(data, "Server auth using %s with user '%s'", + auth, data->state.aptr.user ? + data->state.aptr.user : ""); +#endif + authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; + } + else + authstatus->multipass = FALSE; + + return result; +} + +/** + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication + * method. data->state.authdone is set to TRUE when authentication is + * done. + * + * @param conn all information about the current connection + * @param request pointer to the request keyword + * @param path pointer to the requested path; should include query part + * @param proxytunnel boolean if this is the request setting up a "proxy + * tunnel" + * + * @returns CURLcode + */ +CURLcode +Curl_http_output_auth(struct Curl_easy *data, + struct connectdata *conn, + const char *request, + Curl_HttpReq httpreq, + const char *path, + bool proxytunnel) /* TRUE if this is the request setting + up the proxy tunnel */ +{ + CURLcode result = CURLE_OK; + struct auth *authhost; + struct auth *authproxy; + + DEBUGASSERT(data); + + authhost = &data->state.authhost; + authproxy = &data->state.authproxy; + + if( +#ifndef CURL_DISABLE_PROXY + (conn->bits.httpproxy && conn->bits.proxy_user_passwd) || +#endif + data->state.aptr.user || +#ifdef USE_SPNEGO + authhost->want & CURLAUTH_NEGOTIATE || + authproxy->want & CURLAUTH_NEGOTIATE || +#endif + data->set.str[STRING_BEARER]) + /* continue please */; + else { + authhost->done = TRUE; + authproxy->done = TRUE; + return CURLE_OK; /* no authentication with no user or password */ + } + + if(authhost->want && !authhost->picked) + /* The app has selected one or more methods, but none has been picked + so far by a server round-trip. Then we set the picked one to the + want one, and if this is one single bit it'll be used instantly. */ + authhost->picked = authhost->want; + + if(authproxy->want && !authproxy->picked) + /* The app has selected one or more methods, but none has been picked so + far by a proxy round-trip. Then we set the picked one to the want one, + and if this is one single bit it'll be used instantly. */ + authproxy->picked = authproxy->want; + +#ifndef CURL_DISABLE_PROXY + /* Send proxy authentication header if needed */ + if(conn->bits.httpproxy && + (conn->bits.tunnel_proxy == (bit)proxytunnel)) { + result = output_auth_headers(data, conn, authproxy, request, path, TRUE); + if(result) + return result; + } + else +#else + (void)proxytunnel; +#endif /* CURL_DISABLE_PROXY */ + /* we have no proxy so let's pretend we're done authenticating + with it */ + authproxy->done = TRUE; + + /* To prevent the user+password to get sent to other than the original host + due to a location-follow */ + if(Curl_auth_allowed_to_host(data) +#ifndef CURL_DISABLE_NETRC + || conn->bits.netrc +#endif + ) + result = output_auth_headers(data, conn, authhost, request, path, FALSE); + else + authhost->done = TRUE; + + if(((authhost->multipass && !authhost->done) || + (authproxy->multipass && !authproxy->done)) && + (httpreq != HTTPREQ_GET) && + (httpreq != HTTPREQ_HEAD)) { + /* Auth is required and we are not authenticated yet. Make a PUT or POST + with content-length zero as a "probe". */ + conn->bits.authneg = TRUE; + } + else + conn->bits.authneg = FALSE; + + return result; +} + +#else +/* when disabled */ +CURLcode +Curl_http_output_auth(struct Curl_easy *data, + struct connectdata *conn, + const char *request, + Curl_HttpReq httpreq, + const char *path, + bool proxytunnel) +{ + (void)data; + (void)conn; + (void)request; + (void)httpreq; + (void)path; + (void)proxytunnel; + return CURLE_OK; +} +#endif + +#if defined(USE_SPNEGO) || defined(USE_NTLM) || \ + !defined(CURL_DISABLE_DIGEST_AUTH) || \ + !defined(CURL_DISABLE_BASIC_AUTH) || \ + !defined(CURL_DISABLE_BEARER_AUTH) +static int is_valid_auth_separator(char ch) +{ + return ch == '\0' || ch == ',' || ISSPACE(ch); +} +#endif + +/* + * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: + * headers. They are dealt with both in the transfer.c main loop and in the + * proxy CONNECT loop. + */ +CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, + const char *auth) /* the first non-space */ +{ + /* + * This resource requires authentication + */ + struct connectdata *conn = data->conn; +#ifdef USE_SPNEGO + curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state : + &conn->http_negotiate_state; +#endif +#if defined(USE_SPNEGO) || \ + defined(USE_NTLM) || \ + !defined(CURL_DISABLE_DIGEST_AUTH) || \ + !defined(CURL_DISABLE_BASIC_AUTH) || \ + !defined(CURL_DISABLE_BEARER_AUTH) + + unsigned long *availp; + struct auth *authp; + + if(proxy) { + availp = &data->info.proxyauthavail; + authp = &data->state.authproxy; + } + else { + availp = &data->info.httpauthavail; + authp = &data->state.authhost; + } +#else + (void) proxy; +#endif + + (void) conn; /* In case conditionals make it unused. */ + + /* + * Here we check if we want the specific single authentication (using ==) and + * if we do, we initiate usage of it. + * + * If the provided authentication is wanted as one out of several accepted + * types (using &), we OR this authentication type to the authavail + * variable. + * + * Note: + * + * ->picked is first set to the 'want' value (one or more bits) before the + * request is sent, and then it is again set _after_ all response 401/407 + * headers have been received but then only to a single preferred method + * (bit). + */ + + while(*auth) { +#ifdef USE_SPNEGO + if(checkprefix("Negotiate", auth) && is_valid_auth_separator(auth[9])) { + if((authp->avail & CURLAUTH_NEGOTIATE) || + Curl_auth_is_spnego_supported()) { + *availp |= CURLAUTH_NEGOTIATE; + authp->avail |= CURLAUTH_NEGOTIATE; + + if(authp->picked == CURLAUTH_NEGOTIATE) { + CURLcode result = Curl_input_negotiate(data, conn, proxy, auth); + if(!result) { + free(data->req.newurl); + data->req.newurl = strdup(data->state.url); + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + data->state.authproblem = FALSE; + /* we received a GSS auth token and we dealt with it fine */ + *negstate = GSS_AUTHRECV; + } + else + data->state.authproblem = TRUE; + } + } + } + else +#endif +#ifdef USE_NTLM + /* NTLM support requires the SSL crypto libs */ + if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) { + if((authp->avail & CURLAUTH_NTLM) || + (authp->avail & CURLAUTH_NTLM_WB) || + Curl_auth_is_ntlm_supported()) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; + + if(authp->picked == CURLAUTH_NTLM || + authp->picked == CURLAUTH_NTLM_WB) { + /* NTLM authentication is picked and activated */ + CURLcode result = Curl_input_ntlm(data, proxy, auth); + if(!result) { + data->state.authproblem = FALSE; +#ifdef NTLM_WB_ENABLED + if(authp->picked == CURLAUTH_NTLM_WB) { + *availp &= ~CURLAUTH_NTLM; + authp->avail &= ~CURLAUTH_NTLM; + *availp |= CURLAUTH_NTLM_WB; + authp->avail |= CURLAUTH_NTLM_WB; + + result = Curl_input_ntlm_wb(data, conn, proxy, auth); + if(result) { + infof(data, "Authentication problem. Ignoring this."); + data->state.authproblem = TRUE; + } + } +#endif + } + else { + infof(data, "Authentication problem. Ignoring this."); + data->state.authproblem = TRUE; + } + } + } + } + else +#endif +#ifndef CURL_DISABLE_DIGEST_AUTH + if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) { + if((authp->avail & CURLAUTH_DIGEST) != 0) + infof(data, "Ignoring duplicate digest auth header."); + else if(Curl_auth_is_digest_supported()) { + CURLcode result; + + *availp |= CURLAUTH_DIGEST; + authp->avail |= CURLAUTH_DIGEST; + + /* We call this function on input Digest headers even if Digest + * authentication isn't activated yet, as we need to store the + * incoming data from this header in case we are going to use + * Digest */ + result = Curl_input_digest(data, proxy, auth); + if(result) { + infof(data, "Authentication problem. Ignoring this."); + data->state.authproblem = TRUE; + } + } + } + else +#endif +#ifndef CURL_DISABLE_BASIC_AUTH + if(checkprefix("Basic", auth) && + is_valid_auth_separator(auth[5])) { + *availp |= CURLAUTH_BASIC; + authp->avail |= CURLAUTH_BASIC; + if(authp->picked == CURLAUTH_BASIC) { + /* We asked for Basic authentication but got a 40X back + anyway, which basically means our name+password isn't + valid. */ + authp->avail = CURLAUTH_NONE; + infof(data, "Authentication problem. Ignoring this."); + data->state.authproblem = TRUE; + } + } + else +#endif +#ifndef CURL_DISABLE_BEARER_AUTH + if(checkprefix("Bearer", auth) && + is_valid_auth_separator(auth[6])) { + *availp |= CURLAUTH_BEARER; + authp->avail |= CURLAUTH_BEARER; + if(authp->picked == CURLAUTH_BEARER) { + /* We asked for Bearer authentication but got a 40X back + anyway, which basically means our token isn't valid. */ + authp->avail = CURLAUTH_NONE; + infof(data, "Authentication problem. Ignoring this."); + data->state.authproblem = TRUE; + } + } +#else + { + /* + * Empty block to terminate the if-else chain correctly. + * + * A semicolon would yield the same result here, but can cause a + * compiler warning when -Wextra is enabled. + */ + } +#endif + + /* there may be multiple methods on one line, so keep reading */ + while(*auth && *auth != ',') /* read up to the next comma */ + auth++; + if(*auth == ',') /* if we're on a comma, skip it */ + auth++; + while(*auth && ISSPACE(*auth)) + auth++; + } + + return CURLE_OK; +} + +/** + * http_should_fail() determines whether an HTTP response has gotten us + * into an error state or not. + * + * @retval FALSE communications should continue + * + * @retval TRUE communications should not continue + */ +static bool http_should_fail(struct Curl_easy *data) +{ + int httpcode; + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + + httpcode = data->req.httpcode; + + /* + ** If we haven't been asked to fail on error, + ** don't fail. + */ + if(!data->set.http_fail_on_error) + return FALSE; + + /* + ** Any code < 400 is never terminal. + */ + if(httpcode < 400) + return FALSE; + + /* + ** A 416 response to a resume request is presumably because the file is + ** already completely downloaded and thus not actually a fail. + */ + if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET && + httpcode == 416) + return FALSE; + + /* + ** Any code >= 400 that's not 401 or 407 is always + ** a terminal error + */ + if((httpcode != 401) && (httpcode != 407)) + return TRUE; + + /* + ** All we have left to deal with is 401 and 407 + */ + DEBUGASSERT((httpcode == 401) || (httpcode == 407)); + + /* + ** Examine the current authentication state to see if this + ** is an error. The idea is for this function to get + ** called after processing all the headers in a response + ** message. So, if we've been to asked to authenticate a + ** particular stage, and we've done it, we're OK. But, if + ** we're already completely authenticated, it's not OK to + ** get another 401 or 407. + ** + ** It is possible for authentication to go stale such that + ** the client needs to reauthenticate. Once that info is + ** available, use it here. + */ + + /* + ** Either we're not authenticating, or we're supposed to + ** be authenticating something else. This is an error. + */ + if((httpcode == 401) && !data->state.aptr.user) + return TRUE; +#ifndef CURL_DISABLE_PROXY + if((httpcode == 407) && !data->conn->bits.proxy_user_passwd) + return TRUE; +#endif + + return data->state.authproblem; +} + +/* + * readmoredata() is a "fread() emulation" to provide POST and/or request + * data. It is used when a huge POST is to be made and the entire chunk wasn't + * sent in the first send(). This function will then be called from the + * transfer.c loop when more data is to be sent to the peer. + * + * Returns the amount of bytes it filled the buffer with. + */ +static size_t readmoredata(char *buffer, + size_t size, + size_t nitems, + void *userp) +{ + struct HTTP *http = (struct HTTP *)userp; + struct Curl_easy *data = http->backup.data; + size_t fullsize = size * nitems; + + if(!http->postsize) + /* nothing to return */ + return 0; + + /* make sure that an HTTP request is never sent away chunked! */ + data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; + + if(data->set.max_send_speed && + (data->set.max_send_speed < (curl_off_t)fullsize) && + (data->set.max_send_speed < http->postsize)) + /* speed limit */ + fullsize = (size_t)data->set.max_send_speed; + + else if(http->postsize <= (curl_off_t)fullsize) { + memcpy(buffer, http->postdata, (size_t)http->postsize); + fullsize = (size_t)http->postsize; + + if(http->backup.postsize) { + /* move backup data into focus and continue on that */ + http->postdata = http->backup.postdata; + http->postsize = http->backup.postsize; + data->state.fread_func = http->backup.fread_func; + data->state.in = http->backup.fread_in; + + http->sending++; /* move one step up */ + + http->backup.postsize = 0; + } + else + http->postsize = 0; + + return fullsize; + } + + memcpy(buffer, http->postdata, fullsize); + http->postdata += fullsize; + http->postsize -= fullsize; + + return fullsize; +} + +/* + * Curl_buffer_send() sends a header buffer and frees all associated + * memory. Body data may be appended to the header data if desired. + * + * Returns CURLcode + */ +CURLcode Curl_buffer_send(struct dynbuf *in, + struct Curl_easy *data, + struct HTTP *http, + /* add the number of sent bytes to this + counter */ + curl_off_t *bytes_written, + /* how much of the buffer contains body data */ + curl_off_t included_body_bytes, + int sockindex) +{ + ssize_t amount; + CURLcode result; + char *ptr; + size_t size; + struct connectdata *conn = data->conn; + size_t sendsize; + size_t headersize; + + DEBUGASSERT(sockindex <= SECONDARYSOCKET && sockindex >= 0); + + /* The looping below is required since we use non-blocking sockets, but due + to the circumstances we will just loop and try again and again etc */ + + ptr = Curl_dyn_ptr(in); + size = Curl_dyn_len(in); + + headersize = size - (size_t)included_body_bytes; /* the initial part that + isn't body is header */ + + DEBUGASSERT(size > (size_t)included_body_bytes); + + if((conn->handler->flags & PROTOPT_SSL +#ifndef CURL_DISABLE_PROXY + || IS_HTTPS_PROXY(conn->http_proxy.proxytype) +#endif + ) + && conn->httpversion < 20) { + /* Make sure this doesn't send more body bytes than what the max send + speed says. The request bytes do not count to the max speed. + */ + if(data->set.max_send_speed && + (included_body_bytes > data->set.max_send_speed)) { + curl_off_t overflow = included_body_bytes - data->set.max_send_speed; + DEBUGASSERT((size_t)overflow < size); + sendsize = size - (size_t)overflow; + } + else + sendsize = size; + + /* OpenSSL is very picky and we must send the SAME buffer pointer to the + library when we attempt to re-send this buffer. Sending the same data + is not enough, we must use the exact same address. For this reason, we + must copy the data to the uploadbuffer first, since that is the buffer + we will be using if this send is retried later. + */ + result = Curl_get_upload_buffer(data); + if(result) { + /* malloc failed, free memory and return to the caller */ + Curl_dyn_free(in); + return result; + } + /* We never send more than upload_buffer_size bytes in one single chunk + when we speak HTTPS, as if only a fraction of it is sent now, this data + needs to fit into the normal read-callback buffer later on and that + buffer is using this size. + */ + if(sendsize > (size_t)data->set.upload_buffer_size) + sendsize = (size_t)data->set.upload_buffer_size; + + memcpy(data->state.ulbuf, ptr, sendsize); + ptr = data->state.ulbuf; + } + else { +#ifdef CURLDEBUG + /* Allow debug builds to override this logic to force short initial + sends + */ + char *p = getenv("CURL_SMALLREQSEND"); + if(p) { + size_t altsize = (size_t)strtoul(p, NULL, 10); + if(altsize) + sendsize = CURLMIN(size, altsize); + else + sendsize = size; + } + else +#endif + { + /* Make sure this doesn't send more body bytes than what the max send + speed says. The request bytes do not count to the max speed. + */ + if(data->set.max_send_speed && + (included_body_bytes > data->set.max_send_speed)) { + curl_off_t overflow = included_body_bytes - data->set.max_send_speed; + DEBUGASSERT((size_t)overflow < size); + sendsize = size - (size_t)overflow; + } + else + sendsize = size; + } + + /* We currently cannot send more that this for http here: + * - if sending blocks, it return 0 as amount + * - we then whisk aside the `in` into the `http` struct + * and install our own `data->state.fread_func` that + * on subsequent calls reads `in` empty. + * - when the whisked away `in` is empty, the `fread_func` + * is restored to its original state. + * The problem is that `fread_func` can only return + * `upload_buffer_size` lengths. If the send we do here + * is larger and blocks, we do re-sending with smaller + * amounts of data and connection filters do not like + * that. + */ + if(http && (sendsize > (size_t)data->set.upload_buffer_size)) + sendsize = (size_t)data->set.upload_buffer_size; + } + + result = Curl_nwrite(data, sockindex, ptr, sendsize, &amount); + + if(!result) { + /* + * Note that we may not send the entire chunk at once, and we have a set + * number of data bytes at the end of the big buffer (out of which we may + * only send away a part). + */ + /* how much of the header that was sent */ + size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount; + size_t bodylen = amount - headlen; + + /* this data _may_ contain binary stuff */ + Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen); + if(bodylen) + /* there was body data sent beyond the initial header part, pass that on + to the debug callback too */ + Curl_debug(data, CURLINFO_DATA_OUT, ptr + headlen, bodylen); + + /* 'amount' can never be a very large value here so typecasting it so a + signed 31 bit value should not cause problems even if ssize_t is + 64bit */ + *bytes_written += (long)amount; + + if(http) { + /* if we sent a piece of the body here, up the byte counter for it + accordingly */ + data->req.writebytecount += bodylen; + Curl_pgrsSetUploadCounter(data, data->req.writebytecount); + + if((size_t)amount != size) { + /* The whole request could not be sent in one system call. We must + queue it up and send it later when we get the chance. We must not + loop here and wait until it might work again. */ + + size -= amount; + + ptr = Curl_dyn_ptr(in) + amount; + + /* backup the currently set pointers */ + http->backup.fread_func = data->state.fread_func; + http->backup.fread_in = data->state.in; + http->backup.postdata = http->postdata; + http->backup.postsize = http->postsize; + http->backup.data = data; + + /* set the new pointers for the request-sending */ + data->state.fread_func = (curl_read_callback)readmoredata; + data->state.in = (void *)http; + http->postdata = ptr; + http->postsize = (curl_off_t)size; + + /* this much data is remaining header: */ + data->req.pendingheader = headersize - headlen; + + http->send_buffer = *in; /* copy the whole struct */ + http->sending = HTTPSEND_REQUEST; + return CURLE_OK; + } + http->sending = HTTPSEND_BODY; + /* the full buffer was sent, clean up and return */ + } + else { + if((size_t)amount != size) + /* We have no continue-send mechanism now, fail. This can only happen + when this function is used from the CONNECT sending function. We + currently (stupidly) assume that the whole request is always sent + away in the first single chunk. + + This needs FIXing. + */ + return CURLE_SEND_ERROR; + } + } + Curl_dyn_free(in); + + /* no remaining header data */ + data->req.pendingheader = 0; + return result; +} + +/* end of the add_buffer functions */ +/* ------------------------------------------------------------------------- */ + + + +/* + * Curl_compareheader() + * + * Returns TRUE if 'headerline' contains the 'header' with given 'content'. + * Pass headers WITH the colon. + */ +bool +Curl_compareheader(const char *headerline, /* line to check */ + const char *header, /* header keyword _with_ colon */ + const size_t hlen, /* len of the keyword in bytes */ + const char *content, /* content string to find */ + const size_t clen) /* len of the content in bytes */ +{ + /* RFC2616, section 4.2 says: "Each header field consists of a name followed + * by a colon (":") and the field value. Field names are case-insensitive. + * The field value MAY be preceded by any amount of LWS, though a single SP + * is preferred." */ + + size_t len; + const char *start; + const char *end; + DEBUGASSERT(hlen); + DEBUGASSERT(clen); + DEBUGASSERT(header); + DEBUGASSERT(content); + + if(!strncasecompare(headerline, header, hlen)) + return FALSE; /* doesn't start with header */ + + /* pass the header */ + start = &headerline[hlen]; + + /* pass all whitespace */ + while(*start && ISSPACE(*start)) + start++; + + /* find the end of the header line */ + end = strchr(start, '\r'); /* lines end with CRLF */ + if(!end) { + /* in case there's a non-standard compliant line here */ + end = strchr(start, '\n'); + + if(!end) + /* hm, there's no line ending here, use the zero byte! */ + end = strchr(start, '\0'); + } + + len = end-start; /* length of the content part of the input line */ + + /* find the content string in the rest of the line */ + for(; len >= clen; len--, start++) { + if(strncasecompare(start, content, clen)) + return TRUE; /* match! */ + } + + return FALSE; /* no match */ +} + +/* + * Curl_http_connect() performs HTTP stuff to do at connect-time, called from + * the generic Curl_connect(). + */ +CURLcode Curl_http_connect(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + + /* We default to persistent connections. We set this already in this connect + function to make the reuse checks properly be able to check this bit. */ + connkeep(conn, "HTTP default"); + + return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done); +} + +/* this returns the socket to wait for in the DO and DOING state for the multi + interface and then we're always _sending_ a request and thus we wait for + the single socket to become writable only */ +int Curl_http_getsock_do(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *socks) +{ + /* write mode */ + (void)conn; + socks[0] = Curl_conn_get_socket(data, FIRSTSOCKET); + return GETSOCK_WRITESOCK(0); +} + +/* + * Curl_http_done() gets called after a single HTTP request has been + * performed. + */ + +CURLcode Curl_http_done(struct Curl_easy *data, + CURLcode status, bool premature) +{ + struct connectdata *conn = data->conn; + struct HTTP *http = data->req.p.http; + + /* Clear multipass flag. If authentication isn't done yet, then it will get + * a chance to be set back to true when we output the next auth header */ + data->state.authhost.multipass = FALSE; + data->state.authproxy.multipass = FALSE; + + /* set the proper values (possibly modified on POST) */ + conn->seek_func = data->set.seek_func; /* restore */ + conn->seek_client = data->set.seek_client; /* restore */ + + if(!http) + return CURLE_OK; + + Curl_dyn_free(&http->send_buffer); + Curl_dyn_reset(&data->state.headerb); + Curl_hyper_done(data); + Curl_ws_done(data); + + if(status) + return status; + + if(!premature && /* this check is pointless when DONE is called before the + entire operation is complete */ + !conn->bits.retry && + !data->set.connect_only && + (data->req.bytecount + + data->req.headerbytecount - + data->req.deductheadercount) <= 0) { + /* If this connection isn't simply closed to be retried, AND nothing was + read from the HTTP server (that counts), this can't be right so we + return an error here */ + failf(data, "Empty reply from server"); + /* Mark it as closed to avoid the "left intact" message */ + streamclose(conn, "Empty reply from server"); + return CURLE_GOT_NOTHING; + } + + return CURLE_OK; +} + +/* + * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons + * to avoid it include: + * + * - if the user specifically requested HTTP 1.0 + * - if the server we are connected to only supports 1.0 + * - if any server previously contacted to handle this request only supports + * 1.0. + */ +bool Curl_use_http_1_1plus(const struct Curl_easy *data, + const struct connectdata *conn) +{ + if((data->state.httpversion == 10) || (conn->httpversion == 10)) + return FALSE; + if((data->state.httpwant == CURL_HTTP_VERSION_1_0) && + (conn->httpversion <= 10)) + return FALSE; + return ((data->state.httpwant == CURL_HTTP_VERSION_NONE) || + (data->state.httpwant >= CURL_HTTP_VERSION_1_1)); +} + +#ifndef USE_HYPER +static const char *get_http_string(const struct Curl_easy *data, + const struct connectdata *conn) +{ + if(Curl_conn_is_http3(data, conn, FIRSTSOCKET)) + return "3"; + if(Curl_conn_is_http2(data, conn, FIRSTSOCKET)) + return "2"; + if(Curl_use_http_1_1plus(data, conn)) + return "1.1"; + + return "1.0"; +} +#endif + +/* check and possibly add an Expect: header */ +static CURLcode expect100(struct Curl_easy *data, + struct connectdata *conn, + struct dynbuf *req) +{ + CURLcode result = CURLE_OK; + if(!data->state.disableexpect && Curl_use_http_1_1plus(data, conn) && + (conn->httpversion < 20)) { + /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an + Expect: 100-continue to the headers which actually speeds up post + operations (as there is one packet coming back from the web server) */ + const char *ptr = Curl_checkheaders(data, STRCONST("Expect")); + if(ptr) { + data->state.expect100header = + Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue")); + } + else { + result = Curl_dyn_addn(req, STRCONST("Expect: 100-continue\r\n")); + if(!result) + data->state.expect100header = TRUE; + } + } + + return result; +} + +enum proxy_use { + HEADER_SERVER, /* direct to server */ + HEADER_PROXY, /* regular request to proxy */ + HEADER_CONNECT /* sending CONNECT to a proxy */ +}; + +/* used to compile the provided trailers into one buffer + will return an error code if one of the headers is + not formatted correctly */ +CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, + struct dynbuf *b, + struct Curl_easy *handle) +{ + char *ptr = NULL; + CURLcode result = CURLE_OK; + const char *endofline_native = NULL; + const char *endofline_network = NULL; + + if( +#ifdef CURL_DO_LINEEND_CONV + (handle->state.prefer_ascii) || +#endif + (handle->set.crlf)) { + /* \n will become \r\n later on */ + endofline_native = "\n"; + endofline_network = "\x0a"; + } + else { + endofline_native = "\r\n"; + endofline_network = "\x0d\x0a"; + } + + while(trailers) { + /* only add correctly formatted trailers */ + ptr = strchr(trailers->data, ':'); + if(ptr && *(ptr + 1) == ' ') { + result = Curl_dyn_add(b, trailers->data); + if(result) + return result; + result = Curl_dyn_add(b, endofline_native); + if(result) + return result; + } + else + infof(handle, "Malformatted trailing header, skipping trailer"); + trailers = trailers->next; + } + result = Curl_dyn_add(b, endofline_network); + return result; +} + +static bool hd_name_eq(const char *n1, size_t n1len, + const char *n2, size_t n2len) +{ + if(n1len == n2len) { + return strncasecompare(n1, n2, n1len); + } + return FALSE; +} + +CURLcode Curl_dynhds_add_custom(struct Curl_easy *data, + bool is_connect, + struct dynhds *hds) +{ + struct connectdata *conn = data->conn; + char *ptr; + struct curl_slist *h[2]; + struct curl_slist *headers; + int numlists = 1; /* by default */ + int i; + +#ifndef CURL_DISABLE_PROXY + enum proxy_use proxy; + + if(is_connect) + proxy = HEADER_CONNECT; + else + proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? + HEADER_PROXY:HEADER_SERVER; + + switch(proxy) { + case HEADER_SERVER: + h[0] = data->set.headers; + break; + case HEADER_PROXY: + h[0] = data->set.headers; + if(data->set.sep_headers) { + h[1] = data->set.proxyheaders; + numlists++; + } + break; + case HEADER_CONNECT: + if(data->set.sep_headers) + h[0] = data->set.proxyheaders; + else + h[0] = data->set.headers; + break; + } +#else + (void)is_connect; + h[0] = data->set.headers; +#endif + + /* loop through one or two lists */ + for(i = 0; i < numlists; i++) { + for(headers = h[i]; headers; headers = headers->next) { + const char *name, *value; + size_t namelen, valuelen; + + /* There are 2 quirks in place for custom headers: + * 1. setting only 'name:' to suppress a header from being sent + * 2. setting only 'name;' to send an empty (illegal) header + */ + ptr = strchr(headers->data, ':'); + if(ptr) { + name = headers->data; + namelen = ptr - headers->data; + ptr++; /* pass the colon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + if(*ptr) { + value = ptr; + valuelen = strlen(value); + } + else { + /* quirk #1, suppress this header */ + continue; + } + } + else { + ptr = strchr(headers->data, ';'); + + if(!ptr) { + /* neither : nor ; in provided header value. We seem + * to ignore this silently */ + continue; + } + + name = headers->data; + namelen = ptr - headers->data; + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + if(!*ptr) { + /* quirk #2, send an empty header */ + value = ""; + valuelen = 0; + } + else { + /* this may be used for something else in the future, + * ignore this for now */ + continue; + } + } + + DEBUGASSERT(name && value); + if(data->state.aptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + hd_name_eq(name, namelen, STRCONST("Host:"))) + ; + else if(data->state.httpreq == HTTPREQ_POST_FORM && + /* this header (extended by formdata.c) is sent later */ + hd_name_eq(name, namelen, STRCONST("Content-Type:"))) + ; + else if(data->state.httpreq == HTTPREQ_POST_MIME && + /* this header is sent later */ + hd_name_eq(name, namelen, STRCONST("Content-Type:"))) + ; + else if(conn->bits.authneg && + /* while doing auth neg, don't allow the custom length since + we will force length zero then */ + hd_name_eq(name, namelen, STRCONST("Content-Length:"))) + ; + else if(data->state.aptr.te && + /* when asking for Transfer-Encoding, don't pass on a custom + Connection: */ + hd_name_eq(name, namelen, STRCONST("Connection:"))) + ; + else if((conn->httpversion >= 20) && + hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:"))) + /* HTTP/2 doesn't support chunked requests */ + ; + else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) || + hd_name_eq(name, namelen, STRCONST("Cookie:"))) && + /* be careful of sending this potentially sensitive header to + other hosts */ + !Curl_auth_allowed_to_host(data)) + ; + else { + CURLcode result; + + result = Curl_dynhds_add(hds, name, namelen, value, valuelen); + if(result) + return result; + } + } + } + + return CURLE_OK; +} + +CURLcode Curl_add_custom_headers(struct Curl_easy *data, + bool is_connect, +#ifndef USE_HYPER + struct dynbuf *req +#else + void *req +#endif + ) +{ + struct connectdata *conn = data->conn; + char *ptr; + struct curl_slist *h[2]; + struct curl_slist *headers; + int numlists = 1; /* by default */ + int i; + +#ifndef CURL_DISABLE_PROXY + enum proxy_use proxy; + + if(is_connect) + proxy = HEADER_CONNECT; + else + proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? + HEADER_PROXY:HEADER_SERVER; + + switch(proxy) { + case HEADER_SERVER: + h[0] = data->set.headers; + break; + case HEADER_PROXY: + h[0] = data->set.headers; + if(data->set.sep_headers) { + h[1] = data->set.proxyheaders; + numlists++; + } + break; + case HEADER_CONNECT: + if(data->set.sep_headers) + h[0] = data->set.proxyheaders; + else + h[0] = data->set.headers; + break; + } +#else + (void)is_connect; + h[0] = data->set.headers; +#endif + + /* loop through one or two lists */ + for(i = 0; i < numlists; i++) { + headers = h[i]; + + while(headers) { + char *semicolonp = NULL; + ptr = strchr(headers->data, ':'); + if(!ptr) { + char *optr; + /* no colon, semicolon? */ + ptr = strchr(headers->data, ';'); + if(ptr) { + optr = ptr; + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* this may be used for something else in the future */ + optr = NULL; + } + else { + if(*(--ptr) == ';') { + /* copy the source */ + semicolonp = strdup(headers->data); + if(!semicolonp) { +#ifndef USE_HYPER + Curl_dyn_free(req); +#endif + return CURLE_OUT_OF_MEMORY; + } + /* put a colon where the semicolon is */ + semicolonp[ptr - headers->data] = ':'; + /* point at the colon */ + optr = &semicolonp [ptr - headers->data]; + } + } + ptr = optr; + } + } + if(ptr && (ptr != headers->data)) { + /* we require a colon for this to be a true header */ + + ptr++; /* pass the colon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr || semicolonp) { + /* only send this if the contents was non-blank or done special */ + CURLcode result = CURLE_OK; + char *compare = semicolonp ? semicolonp : headers->data; + + if(data->state.aptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + checkprefix("Host:", compare)) + ; + else if(data->state.httpreq == HTTPREQ_POST_FORM && + /* this header (extended by formdata.c) is sent later */ + checkprefix("Content-Type:", compare)) + ; + else if(data->state.httpreq == HTTPREQ_POST_MIME && + /* this header is sent later */ + checkprefix("Content-Type:", compare)) + ; + else if(conn->bits.authneg && + /* while doing auth neg, don't allow the custom length since + we will force length zero then */ + checkprefix("Content-Length:", compare)) + ; + else if(data->state.aptr.te && + /* when asking for Transfer-Encoding, don't pass on a custom + Connection: */ + checkprefix("Connection:", compare)) + ; + else if((conn->httpversion >= 20) && + checkprefix("Transfer-Encoding:", compare)) + /* HTTP/2 doesn't support chunked requests */ + ; + else if((checkprefix("Authorization:", compare) || + checkprefix("Cookie:", compare)) && + /* be careful of sending this potentially sensitive header to + other hosts */ + !Curl_auth_allowed_to_host(data)) + ; + else { +#ifdef USE_HYPER + result = Curl_hyper_header(data, req, compare); +#else + result = Curl_dyn_addf(req, "%s\r\n", compare); +#endif + } + if(semicolonp) + free(semicolonp); + if(result) + return result; + } + } + headers = headers->next; + } + } + + return CURLE_OK; +} + +#ifndef CURL_DISABLE_PARSEDATE +CURLcode Curl_add_timecondition(struct Curl_easy *data, +#ifndef USE_HYPER + struct dynbuf *req +#else + void *req +#endif + ) +{ + const struct tm *tm; + struct tm keeptime; + CURLcode result; + char datestr[80]; + const char *condp; + size_t len; + + if(data->set.timecondition == CURL_TIMECOND_NONE) + /* no condition was asked for */ + return CURLE_OK; + + result = Curl_gmtime(data->set.timevalue, &keeptime); + if(result) { + failf(data, "Invalid TIMEVALUE"); + return result; + } + tm = &keeptime; + + switch(data->set.timecondition) { + default: + DEBUGF(infof(data, "invalid time condition")); + return CURLE_BAD_FUNCTION_ARGUMENT; + + case CURL_TIMECOND_IFMODSINCE: + condp = "If-Modified-Since"; + len = 17; + break; + case CURL_TIMECOND_IFUNMODSINCE: + condp = "If-Unmodified-Since"; + len = 19; + break; + case CURL_TIMECOND_LASTMOD: + condp = "Last-Modified"; + len = 13; + break; + } + + if(Curl_checkheaders(data, condp, len)) { + /* A custom header was specified; it will be sent instead. */ + return CURLE_OK; + } + + /* The If-Modified-Since header family should have their times set in + * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be + * represented in Greenwich Mean Time (GMT), without exception. For the + * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal + * Time)." (see page 20 of RFC2616). + */ + + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + msnprintf(datestr, sizeof(datestr), + "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + condp, + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + +#ifndef USE_HYPER + result = Curl_dyn_add(req, datestr); +#else + result = Curl_hyper_header(data, req, datestr); +#endif + + return result; +} +#else +/* disabled */ +CURLcode Curl_add_timecondition(struct Curl_easy *data, + struct dynbuf *req) +{ + (void)data; + (void)req; + return CURLE_OK; +} +#endif + +void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, + const char **method, Curl_HttpReq *reqp) +{ + Curl_HttpReq httpreq = (Curl_HttpReq)data->state.httpreq; + const char *request; + if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && + data->state.upload) + httpreq = HTTPREQ_PUT; + + /* Now set the 'request' pointer to the proper request string */ + if(data->set.str[STRING_CUSTOMREQUEST]) + request = data->set.str[STRING_CUSTOMREQUEST]; + else { + if(data->req.no_body) + request = "HEAD"; + else { + DEBUGASSERT((httpreq >= HTTPREQ_GET) && (httpreq <= HTTPREQ_HEAD)); + switch(httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + request = "POST"; + break; + case HTTPREQ_PUT: + request = "PUT"; + break; + default: /* this should never happen */ + case HTTPREQ_GET: + request = "GET"; + break; + case HTTPREQ_HEAD: + request = "HEAD"; + break; + } + } + } + *method = request; + *reqp = httpreq; +} + +CURLcode Curl_http_useragent(struct Curl_easy *data) +{ + /* The User-Agent string might have been allocated in url.c already, because + it might have been used in the proxy connect, but if we have got a header + with the user-agent string specified, we erase the previously made string + here. */ + if(Curl_checkheaders(data, STRCONST("User-Agent"))) { + free(data->state.aptr.uagent); + data->state.aptr.uagent = NULL; + } + return CURLE_OK; +} + + +CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn) +{ + const char *ptr; + struct dynamically_allocated_data *aptr = &data->state.aptr; + if(!data->state.this_is_a_follow) { + /* Free to avoid leaking memory on multiple requests */ + free(data->state.first_host); + + data->state.first_host = strdup(conn->host.name); + if(!data->state.first_host) + return CURLE_OUT_OF_MEMORY; + + data->state.first_remote_port = conn->remote_port; + data->state.first_remote_protocol = conn->handler->protocol; + } + Curl_safefree(aptr->host); + + ptr = Curl_checkheaders(data, STRCONST("Host")); + if(ptr && (!data->state.this_is_a_follow || + strcasecompare(data->state.first_host, conn->host.name))) { +#if !defined(CURL_DISABLE_COOKIES) + /* If we have a given custom Host: header, we extract the host name in + order to possibly use it for cookie reasons later on. We only allow the + custom Host: header if this is NOT a redirect, as setting Host: in the + redirected request is being out on thin ice. Except if the host name + is the same as the first one! */ + char *cookiehost = Curl_copy_header_value(ptr); + if(!cookiehost) + return CURLE_OUT_OF_MEMORY; + if(!*cookiehost) + /* ignore empty data */ + free(cookiehost); + else { + /* If the host begins with '[', we start searching for the port after + the bracket has been closed */ + if(*cookiehost == '[') { + char *closingbracket; + /* since the 'cookiehost' is an allocated memory area that will be + freed later we cannot simply increment the pointer */ + memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1); + closingbracket = strchr(cookiehost, ']'); + if(closingbracket) + *closingbracket = 0; + } + else { + int startsearch = 0; + char *colon = strchr(cookiehost + startsearch, ':'); + if(colon) + *colon = 0; /* The host must not include an embedded port number */ + } + Curl_safefree(aptr->cookiehost); + aptr->cookiehost = cookiehost; + } +#endif + + if(!strcasecompare("Host:", ptr)) { + aptr->host = aprintf("Host:%s\r\n", &ptr[5]); + if(!aptr->host) + return CURLE_OUT_OF_MEMORY; + } + } + else { + /* When building Host: headers, we must put the host name within + [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ + const char *host = conn->host.name; + + if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) && + (conn->remote_port == PORT_HTTPS)) || + ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) && + (conn->remote_port == PORT_HTTP)) ) + /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include + the port number in the host string */ + aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"", + host, conn->bits.ipv6_ip?"]":""); + else + aptr->host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"", + host, conn->bits.ipv6_ip?"]":"", + conn->remote_port); + + if(!aptr->host) + /* without Host: we can't make a nice request */ + return CURLE_OUT_OF_MEMORY; + } + return CURLE_OK; +} + +/* + * Append the request-target to the HTTP request + */ +CURLcode Curl_http_target(struct Curl_easy *data, + struct connectdata *conn, + struct dynbuf *r) +{ + CURLcode result = CURLE_OK; + const char *path = data->state.up.path; + const char *query = data->state.up.query; + + if(data->set.str[STRING_TARGET]) { + path = data->set.str[STRING_TARGET]; + query = NULL; + } + +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + /* Using a proxy but does not tunnel through it */ + + /* The path sent to the proxy is in fact the entire URL. But if the remote + host is a IDN-name, we must make sure that the request we produce only + uses the encoded host name! */ + + /* and no fragment part */ + CURLUcode uc; + char *url; + CURLU *h = curl_url_dup(data->state.uh); + if(!h) + return CURLE_OUT_OF_MEMORY; + + if(conn->host.dispname != conn->host.name) { + uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0); + if(uc) { + curl_url_cleanup(h); + return CURLE_OUT_OF_MEMORY; + } + } + uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0); + if(uc) { + curl_url_cleanup(h); + return CURLE_OUT_OF_MEMORY; + } + + if(strcasecompare("http", data->state.up.scheme)) { + /* when getting HTTP, we don't want the userinfo the URL */ + uc = curl_url_set(h, CURLUPART_USER, NULL, 0); + if(uc) { + curl_url_cleanup(h); + return CURLE_OUT_OF_MEMORY; + } + uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0); + if(uc) { + curl_url_cleanup(h); + return CURLE_OUT_OF_MEMORY; + } + } + /* Extract the URL to use in the request. */ + uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT); + if(uc) { + curl_url_cleanup(h); + return CURLE_OUT_OF_MEMORY; + } + + curl_url_cleanup(h); + + /* target or url */ + result = Curl_dyn_add(r, data->set.str[STRING_TARGET]? + data->set.str[STRING_TARGET]:url); + free(url); + if(result) + return (result); + + if(strcasecompare("ftp", data->state.up.scheme)) { + if(data->set.proxy_transfer_mode) { + /* when doing ftp, append ;type= if not present */ + char *type = strstr(path, ";type="); + if(type && type[6] && type[7] == 0) { + switch(Curl_raw_toupper(type[6])) { + case 'A': + case 'D': + case 'I': + break; + default: + type = NULL; + } + } + if(!type) { + result = Curl_dyn_addf(r, ";type=%c", + data->state.prefer_ascii ? 'a' : 'i'); + if(result) + return result; + } + } + } + } + + else +#else + (void)conn; /* not used in disabled-proxy builds */ +#endif + { + result = Curl_dyn_add(r, path); + if(result) + return result; + if(query) + result = Curl_dyn_addf(r, "?%s", query); + } + + return result; +} + +CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn, + Curl_HttpReq httpreq, const char **tep) +{ + CURLcode result = CURLE_OK; + const char *ptr; + struct HTTP *http = data->req.p.http; + http->postsize = 0; + + switch(httpreq) { + case HTTPREQ_POST_MIME: + data->state.mimepost = &data->set.mimepost; + break; +#ifndef CURL_DISABLE_FORM_API + case HTTPREQ_POST_FORM: + /* Convert the form structure into a mime structure, then keep + the conversion */ + if(!data->state.formp) { + data->state.formp = calloc(1, sizeof(curl_mimepart)); + if(!data->state.formp) + return CURLE_OUT_OF_MEMORY; + Curl_mime_cleanpart(data->state.formp); + result = Curl_getformdata(data, data->state.formp, data->set.httppost, + data->state.fread_func); + if(result) { + Curl_safefree(data->state.formp); + return result; + } + data->state.mimepost = data->state.formp; + } + break; +#endif + default: + data->state.mimepost = NULL; + } + +#ifndef CURL_DISABLE_MIME + if(data->state.mimepost) { + const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type")); + + /* Read and seek body only. */ + data->state.mimepost->flags |= MIME_BODY_ONLY; + + /* Prepare the mime structure headers & set content type. */ + + if(cthdr) + for(cthdr += 13; *cthdr == ' '; cthdr++) + ; + else if(data->state.mimepost->kind == MIMEKIND_MULTIPART) + cthdr = "multipart/form-data"; + + curl_mime_headers(data->state.mimepost, data->set.headers, 0); + result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr, + NULL, MIMESTRATEGY_FORM); + curl_mime_headers(data->state.mimepost, NULL, 0); + if(!result) + result = Curl_mime_rewind(data->state.mimepost); + if(result) + return result; + http->postsize = Curl_mime_size(data->state.mimepost); + } +#endif + + ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding")); + if(ptr) { + /* Some kind of TE is requested, check if 'chunked' is chosen */ + data->req.upload_chunky = + Curl_compareheader(ptr, + STRCONST("Transfer-Encoding:"), STRCONST("chunked")); + } + else { + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && + http->postsize < 0) || + ((data->state.upload || httpreq == HTTPREQ_POST) && + data->state.infilesize == -1))) { + if(conn->bits.authneg) + /* don't enable chunked during auth neg */ + ; + else if(Curl_use_http_1_1plus(data, conn)) { + if(conn->httpversion < 20) + /* HTTP, upload, unknown file size and not HTTP 1.0 */ + data->req.upload_chunky = TRUE; + } + else { + failf(data, "Chunky upload is not supported by HTTP 1.0"); + return CURLE_UPLOAD_FAILED; + } + } + else { + /* else, no chunky upload */ + data->req.upload_chunky = FALSE; + } + + if(data->req.upload_chunky) + *tep = "Transfer-Encoding: chunked\r\n"; + } + return result; +} + +static CURLcode addexpect(struct Curl_easy *data, struct connectdata *conn, + struct dynbuf *r) +{ + data->state.expect100header = FALSE; + /* Avoid Expect: 100-continue if Upgrade: is used */ + if(data->req.upgr101 == UPGR101_INIT) { + struct HTTP *http = data->req.p.http; + /* For really small puts we don't use Expect: headers at all, and for + the somewhat bigger ones we allow the app to disable it. Just make + sure that the expect100header is always set to the preferred value + here. */ + char *ptr = Curl_checkheaders(data, STRCONST("Expect")); + if(ptr) { + data->state.expect100header = + Curl_compareheader(ptr, STRCONST("Expect:"), + STRCONST("100-continue")); + } + else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) + return expect100(data, conn, r); + } + return CURLE_OK; +} + +CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, + struct dynbuf *r, Curl_HttpReq httpreq) +{ +#ifndef USE_HYPER + /* Hyper always handles the body separately */ + curl_off_t included_body = 0; +#else + /* from this point down, this function should not be used */ +#define Curl_buffer_send(a,b,c,d,e,f) CURLE_OK +#endif + CURLcode result = CURLE_OK; + struct HTTP *http = data->req.p.http; + + switch(httpreq) { + case HTTPREQ_PUT: /* Let's PUT the data to the server! */ + + if(conn->bits.authneg) + http->postsize = 0; + else + http->postsize = data->state.infilesize; + + if((http->postsize != -1) && !data->req.upload_chunky && + (conn->bits.authneg || + !Curl_checkheaders(data, STRCONST("Content-Length")))) { + /* only add Content-Length if not uploading chunked */ + result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", http->postsize); + if(result) + return result; + } + + result = addexpect(data, conn, r); + if(result) + return result; + + /* end of headers */ + result = Curl_dyn_addn(r, STRCONST("\r\n")); + if(result) + return result; + + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, http->postsize); + + /* this sends the buffer and frees all the buffer resources */ + result = Curl_buffer_send(r, data, data->req.p.http, + &data->info.request_size, 0, + FIRSTSOCKET); + if(result) + failf(data, "Failed sending PUT request"); + else + /* prepare for transfer */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, + http->postsize?FIRSTSOCKET:-1); + if(result) + return result; + break; + + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + /* This is form posting using mime data. */ + if(conn->bits.authneg) { + /* nothing to post! */ + result = Curl_dyn_addn(r, STRCONST("Content-Length: 0\r\n\r\n")); + if(result) + return result; + + result = Curl_buffer_send(r, data, data->req.p.http, + &data->info.request_size, 0, + FIRSTSOCKET); + if(result) + failf(data, "Failed sending POST request"); + else + /* setup variables for the upcoming transfer */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); + break; + } + + data->state.infilesize = http->postsize; + + /* We only set Content-Length and allow a custom Content-Length if + we don't upload data chunked, as RFC2616 forbids us to set both + kinds of headers (Transfer-Encoding: chunked and Content-Length) */ + if(http->postsize != -1 && !data->req.upload_chunky && + (!Curl_checkheaders(data, STRCONST("Content-Length")))) { + /* we allow replacing this header if not during auth negotiation, + although it isn't very wise to actually set your own */ + result = Curl_dyn_addf(r, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", http->postsize); + if(result) + return result; + } + +#ifndef CURL_DISABLE_MIME + /* Output mime-generated headers. */ + { + struct curl_slist *hdr; + + for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) { + result = Curl_dyn_addf(r, "%s\r\n", hdr->data); + if(result) + return result; + } + } +#endif + + result = addexpect(data, conn, r); + if(result) + return result; + + /* make the request end in a true CRLF */ + result = Curl_dyn_addn(r, STRCONST("\r\n")); + if(result) + return result; + + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, http->postsize); + + /* Read from mime structure. */ + data->state.fread_func = (curl_read_callback) Curl_mime_read; + data->state.in = (void *) data->state.mimepost; + http->sending = HTTPSEND_BODY; + + /* this sends the buffer and frees all the buffer resources */ + result = Curl_buffer_send(r, data, data->req.p.http, + &data->info.request_size, 0, + FIRSTSOCKET); + if(result) + failf(data, "Failed sending POST request"); + else + /* prepare for transfer */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, + http->postsize?FIRSTSOCKET:-1); + if(result) + return result; + + break; + + case HTTPREQ_POST: + /* this is the simple POST, using x-www-form-urlencoded style */ + + if(conn->bits.authneg) + http->postsize = 0; + else + /* the size of the post body */ + http->postsize = data->state.infilesize; + + /* We only set Content-Length and allow a custom Content-Length if + we don't upload data chunked, as RFC2616 forbids us to set both + kinds of headers (Transfer-Encoding: chunked and Content-Length) */ + if((http->postsize != -1) && !data->req.upload_chunky && + (conn->bits.authneg || + !Curl_checkheaders(data, STRCONST("Content-Length")))) { + /* we allow replacing this header if not during auth negotiation, + although it isn't very wise to actually set your own */ + result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", http->postsize); + if(result) + return result; + } + + if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { + result = Curl_dyn_addn(r, STRCONST("Content-Type: application/" + "x-www-form-urlencoded\r\n")); + if(result) + return result; + } + + result = addexpect(data, conn, r); + if(result) + return result; + +#ifndef USE_HYPER + /* With Hyper the body is always passed on separately */ + if(data->set.postfields) { + if(!data->state.expect100header && + (http->postsize < MAX_INITIAL_POST_SIZE)) { + /* if we don't use expect: 100 AND + postsize is less than MAX_INITIAL_POST_SIZE + + then append the post data to the HTTP request header. This limit + is no magic limit but only set to prevent really huge POSTs to + get the data duplicated with malloc() and family. */ + + /* end of headers! */ + result = Curl_dyn_addn(r, STRCONST("\r\n")); + if(result) + return result; + + if(!data->req.upload_chunky) { + /* We're not sending it 'chunked', append it to the request + already now to reduce the number of send() calls */ + result = Curl_dyn_addn(r, data->set.postfields, + (size_t)http->postsize); + included_body = http->postsize; + } + else { + if(http->postsize) { + char chunk[16]; + /* Append the POST data chunky-style */ + msnprintf(chunk, sizeof(chunk), "%x\r\n", (int)http->postsize); + result = Curl_dyn_add(r, chunk); + if(!result) { + included_body = http->postsize + strlen(chunk); + result = Curl_dyn_addn(r, data->set.postfields, + (size_t)http->postsize); + if(!result) + result = Curl_dyn_addn(r, STRCONST("\r\n")); + included_body += 2; + } + } + if(!result) { + result = Curl_dyn_addn(r, STRCONST("\x30\x0d\x0a\x0d\x0a")); + /* 0 CR LF CR LF */ + included_body += 5; + } + } + if(result) + return result; + /* Make sure the progress information is accurate */ + Curl_pgrsSetUploadSize(data, http->postsize); + } + else { + /* A huge POST coming up, do data separate from the request */ + http->postdata = data->set.postfields; + http->sending = HTTPSEND_BODY; + http->backup.data = data; + data->state.fread_func = (curl_read_callback)readmoredata; + data->state.in = (void *)http; + + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, http->postsize); + + /* end of headers! */ + result = Curl_dyn_addn(r, STRCONST("\r\n")); + if(result) + return result; + } + } + else +#endif + { + /* end of headers! */ + result = Curl_dyn_addn(r, STRCONST("\r\n")); + if(result) + return result; + + if(data->req.upload_chunky && conn->bits.authneg) { + /* Chunky upload is selected and we're negotiating auth still, send + end-of-data only */ + result = Curl_dyn_addn(r, (char *)STRCONST("\x30\x0d\x0a\x0d\x0a")); + /* 0 CR LF CR LF */ + if(result) + return result; + } + + else if(data->state.infilesize) { + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, http->postsize?http->postsize:-1); + + /* set the pointer to mark that we will send the post body using the + read callback, but only if we're not in authenticate negotiation */ + if(!conn->bits.authneg) + http->postdata = (char *)&http->postdata; + } + } + /* issue the request */ + result = Curl_buffer_send(r, data, data->req.p.http, + &data->info.request_size, included_body, + FIRSTSOCKET); + + if(result) + failf(data, "Failed sending HTTP POST request"); + else + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, + http->postdata?FIRSTSOCKET:-1); + break; + + default: + result = Curl_dyn_addn(r, STRCONST("\r\n")); + if(result) + return result; + + /* issue the request */ + result = Curl_buffer_send(r, data, data->req.p.http, + &data->info.request_size, 0, + FIRSTSOCKET); + if(result) + failf(data, "Failed sending HTTP request"); +#ifdef USE_WEBSOCKETS + else if((conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) && + !(data->set.connect_only)) + /* Set up the transfer for two-way since without CONNECT_ONLY set, this + request probably wants to send data too post upgrade */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET); +#endif + else + /* HTTP GET/HEAD download: */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); + } + + return result; +} + +#if !defined(CURL_DISABLE_COOKIES) + +CURLcode Curl_http_cookies(struct Curl_easy *data, + struct connectdata *conn, + struct dynbuf *r) +{ + CURLcode result = CURLE_OK; + char *addcookies = NULL; + bool linecap = FALSE; + if(data->set.str[STRING_COOKIE] && + !Curl_checkheaders(data, STRCONST("Cookie"))) + addcookies = data->set.str[STRING_COOKIE]; + + if(data->cookies || addcookies) { + struct Cookie *co = NULL; /* no cookies from start */ + int count = 0; + + if(data->cookies && data->state.cookie_engine) { + const char *host = data->state.aptr.cookiehost ? + data->state.aptr.cookiehost : conn->host.name; + const bool secure_context = + conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || + strcasecompare("localhost", host) || + !strcmp(host, "127.0.0.1") || + !strcmp(host, "::1") ? TRUE : FALSE; + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path, + secure_context); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + if(co) { + struct Cookie *store = co; + size_t clen = 8; /* hold the size of the generated Cookie: header */ + /* now loop through all cookies that matched */ + while(co) { + if(co->value) { + size_t add; + if(!count) { + result = Curl_dyn_addn(r, STRCONST("Cookie: ")); + if(result) + break; + } + add = strlen(co->name) + strlen(co->value) + 1; + if(clen + add >= MAX_COOKIE_HEADER_LEN) { + infof(data, "Restricted outgoing cookies due to header size, " + "'%s' not sent", co->name); + linecap = TRUE; + break; + } + result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"", + co->name, co->value); + if(result) + break; + clen += add + (count ? 2 : 0); + count++; + } + co = co->next; /* next cookie please */ + } + Curl_cookie_freelist(store); + } + if(addcookies && !result && !linecap) { + if(!count) + result = Curl_dyn_addn(r, STRCONST("Cookie: ")); + if(!result) { + result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies); + count++; + } + } + if(count && !result) + result = Curl_dyn_addn(r, STRCONST("\r\n")); + + if(result) + return result; + } + return result; +} +#endif + +CURLcode Curl_http_range(struct Curl_easy *data, + Curl_HttpReq httpreq) +{ + if(data->state.use_range) { + /* + * A range is selected. We use different headers whether we're downloading + * or uploading and we always let customized headers override our internal + * ones if any such are specified. + */ + if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && + !Curl_checkheaders(data, STRCONST("Range"))) { + /* if a line like this was already allocated, free the previous one */ + free(data->state.aptr.rangeline); + data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n", + data->state.range); + } + else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && + !Curl_checkheaders(data, STRCONST("Content-Range"))) { + + /* if a line like this was already allocated, free the previous one */ + free(data->state.aptr.rangeline); + + if(data->set.set_resume_from < 0) { + /* Upload resume was asked for, but we don't know the size of the + remote part so we tell the server (and act accordingly) that we + upload the whole file (again) */ + data->state.aptr.rangeline = + aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "\r\n", + data->state.infilesize - 1, data->state.infilesize); + + } + else if(data->state.resume_from) { + /* This is because "resume" was selected */ + curl_off_t total_expected_size = + data->state.resume_from + data->state.infilesize; + data->state.aptr.rangeline = + aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "\r\n", + data->state.range, total_expected_size-1, + total_expected_size); + } + else { + /* Range was selected and then we just pass the incoming range and + append total size */ + data->state.aptr.rangeline = + aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", + data->state.range, data->state.infilesize); + } + if(!data->state.aptr.rangeline) + return CURLE_OUT_OF_MEMORY; + } + } + return CURLE_OK; +} + +CURLcode Curl_http_resume(struct Curl_easy *data, + struct connectdata *conn, + Curl_HttpReq httpreq) +{ + if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && + data->state.resume_from) { + /********************************************************************** + * Resuming upload in HTTP means that we PUT or POST and that we have + * got a resume_from value set. The resume value has already created + * a Range: header that will be passed along. We need to "fast forward" + * the file the given number of bytes and decrease the assume upload + * file size before we continue this venture in the dark lands of HTTP. + * Resuming mime/form posting at an offset > 0 has no sense and is ignored. + *********************************************************************/ + + if(data->state.resume_from < 0) { + /* + * This is meant to get the size of the present remote-file by itself. + * We don't support this now. Bail out! + */ + data->state.resume_from = 0; + } + + if(data->state.resume_from && !data->state.followlocation) { + /* only act on the first request */ + + /* Now, let's read off the proper amount of bytes from the + input. */ + int seekerr = CURL_SEEKFUNC_CANTSEEK; + if(conn->seek_func) { + Curl_set_in_callback(data, true); + seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, + SEEK_SET); + Curl_set_in_callback(data, false); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed = 0; + + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_READ_ERROR; + } + /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ + do { + char scratch[4*1024]; + size_t readthisamountnow = + (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : + curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread = + data->state.fread_func(scratch, 1, readthisamountnow, + data->state.in); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T + " bytes from the input", passed); + return CURLE_READ_ERROR; + } + } while(passed < data->state.resume_from); + } + + /* now, decrease the size of the read */ + if(data->state.infilesize>0) { + data->state.infilesize -= data->state.resume_from; + + if(data->state.infilesize <= 0) { + failf(data, "File already completely uploaded"); + return CURLE_PARTIAL_FILE; + } + } + /* we've passed, proceed as normal */ + } + } + return CURLE_OK; +} + +CURLcode Curl_http_firstwrite(struct Curl_easy *data, + struct connectdata *conn, + bool *done) +{ + struct SingleRequest *k = &data->req; + + *done = FALSE; + if(data->req.newurl) { + if(conn->bits.close) { + /* Abort after the headers if "follow Location" is set + and we're set to close anyway. */ + k->keepon &= ~KEEP_RECV; + *done = TRUE; + return CURLE_OK; + } + /* We have a new url to load, but since we want to be able to reuse this + connection properly, we read the full response in "ignore more" */ + k->ignorebody = TRUE; + infof(data, "Ignoring the response-body"); + } + if(data->state.resume_from && !k->content_range && + (data->state.httpreq == HTTPREQ_GET) && + !k->ignorebody) { + + if(k->size == data->state.resume_from) { + /* The resume point is at the end of file, consider this fine even if it + doesn't allow resume from here. */ + infof(data, "The entire document is already downloaded"); + streamclose(conn, "already downloaded"); + /* Abort download */ + k->keepon &= ~KEEP_RECV; + *done = TRUE; + return CURLE_OK; + } + + /* we wanted to resume a download, although the server doesn't seem to + * support this and we did this with a GET (if it wasn't a GET we did a + * POST or PUT resume) */ + failf(data, "HTTP server doesn't seem to support " + "byte ranges. Cannot resume."); + return CURLE_RANGE_ERROR; + } + + if(data->set.timecondition && !data->state.range) { + /* A time condition has been set AND no ranges have been requested. This + seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct + action for an HTTP/1.1 client */ + + if(!Curl_meets_timecondition(data, k->timeofdoc)) { + *done = TRUE; + /* We're simulating an HTTP 304 from server so we return + what should have been returned from the server */ + data->info.httpcode = 304; + infof(data, "Simulate an HTTP 304 response"); + /* we abort the transfer before it is completed == we ruin the + reuse ability. Close the connection */ + streamclose(conn, "Simulated 304 handling"); + return CURLE_OK; + } + } /* we have a time condition */ + + return CURLE_OK; +} + +#ifdef HAVE_LIBZ +CURLcode Curl_transferencode(struct Curl_easy *data) +{ + if(!Curl_checkheaders(data, STRCONST("TE")) && + data->set.http_transfer_encoding) { + /* When we are to insert a TE: header in the request, we must also insert + TE in a Connection: header, so we need to merge the custom provided + Connection: header and prevent the original to get sent. Note that if + the user has inserted his/her own TE: header we don't do this magic + but then assume that the user will handle it all! */ + char *cptr = Curl_checkheaders(data, STRCONST("Connection")); +#define TE_HEADER "TE: gzip\r\n" + + Curl_safefree(data->state.aptr.te); + + if(cptr) { + cptr = Curl_copy_header_value(cptr); + if(!cptr) + return CURLE_OUT_OF_MEMORY; + } + + /* Create the (updated) Connection: header */ + data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, + cptr ? cptr : "", (cptr && *cptr) ? ", ":""); + + free(cptr); + if(!data->state.aptr.te) + return CURLE_OUT_OF_MEMORY; + } + return CURLE_OK; +} +#endif + +#ifndef USE_HYPER +/* + * Curl_http() gets called from the generic multi_do() function when an HTTP + * request is to be performed. This creates and sends a properly constructed + * HTTP request. + */ +CURLcode Curl_http(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + CURLcode result = CURLE_OK; + struct HTTP *http; + Curl_HttpReq httpreq; + const char *te = ""; /* transfer-encoding */ + const char *request; + const char *httpstring; + struct dynbuf req; + char *altused = NULL; + const char *p_accept; /* Accept: string */ + + /* Always consider the DO phase done after this function call, even if there + may be parts of the request that are not yet sent, since we can deal with + the rest of the request in the PERFORM phase. */ + *done = TRUE; + + switch(conn->alpn) { + case CURL_HTTP_VERSION_3: + DEBUGASSERT(Curl_conn_is_http3(data, conn, FIRSTSOCKET)); + break; + case CURL_HTTP_VERSION_2: +#ifndef CURL_DISABLE_PROXY + if(!Curl_conn_is_http2(data, conn, FIRSTSOCKET) && + conn->bits.proxy && !conn->bits.tunnel_proxy + ) { + result = Curl_http2_switch(data, conn, FIRSTSOCKET); + if(result) + goto fail; + } + else +#endif + DEBUGASSERT(Curl_conn_is_http2(data, conn, FIRSTSOCKET)); + break; + case CURL_HTTP_VERSION_1_1: + /* continue with HTTP/1.x when explicitly requested */ + break; + default: + /* Check if user wants to use HTTP/2 with clear TCP */ + if(Curl_http2_may_switch(data, conn, FIRSTSOCKET)) { + DEBUGF(infof(data, "HTTP/2 over clean TCP")); + result = Curl_http2_switch(data, conn, FIRSTSOCKET); + if(result) + goto fail; + } + break; + } + + http = data->req.p.http; + DEBUGASSERT(http); + + result = Curl_http_host(data, conn); + if(result) + goto fail; + + result = Curl_http_useragent(data); + if(result) + goto fail; + + Curl_http_method(data, conn, &request, &httpreq); + + /* setup the authentication headers */ + { + char *pq = NULL; + if(data->state.up.query) { + pq = aprintf("%s?%s", data->state.up.path, data->state.up.query); + if(!pq) + return CURLE_OUT_OF_MEMORY; + } + result = Curl_http_output_auth(data, conn, request, httpreq, + (pq ? pq : data->state.up.path), FALSE); + free(pq); + if(result) + goto fail; + } + + Curl_safefree(data->state.aptr.ref); + if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) { + data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); + if(!data->state.aptr.ref) + return CURLE_OUT_OF_MEMORY; + } + + if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && + data->set.str[STRING_ENCODING]) { + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = + aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); + if(!data->state.aptr.accept_encoding) + return CURLE_OUT_OF_MEMORY; + } + else + Curl_safefree(data->state.aptr.accept_encoding); + +#ifdef HAVE_LIBZ + /* we only consider transfer-encoding magic if libz support is built-in */ + result = Curl_transferencode(data); + if(result) + goto fail; +#endif + + result = Curl_http_body(data, conn, httpreq, &te); + if(result) + goto fail; + + p_accept = Curl_checkheaders(data, + STRCONST("Accept"))?NULL:"Accept: */*\r\n"; + + result = Curl_http_resume(data, conn, httpreq); + if(result) + goto fail; + + result = Curl_http_range(data, httpreq); + if(result) + goto fail; + + httpstring = get_http_string(data, conn); + + /* initialize a dynamic send-buffer */ + Curl_dyn_init(&req, DYN_HTTP_REQUEST); + + /* make sure the header buffer is reset - if there are leftovers from a + previous transfer */ + Curl_dyn_reset(&data->state.headerb); + + /* add the main request stuff */ + /* GET/HEAD/POST/PUT */ + result = Curl_dyn_addf(&req, "%s ", request); + if(!result) + result = Curl_http_target(data, conn, &req); + if(result) { + Curl_dyn_free(&req); + goto fail; + } + +#ifndef CURL_DISABLE_ALTSVC + if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) { + altused = aprintf("Alt-Used: %s:%d\r\n", + conn->conn_to_host.name, conn->conn_to_port); + if(!altused) { + Curl_dyn_free(&req); + return CURLE_OUT_OF_MEMORY; + } + } +#endif + result = + Curl_dyn_addf(&req, + " HTTP/%s\r\n" /* HTTP version */ + "%s" /* host */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* accept */ + "%s" /* TE: */ + "%s" /* accept-encoding */ + "%s" /* referer */ + "%s" /* Proxy-Connection */ + "%s" /* transfer-encoding */ + "%s",/* Alt-Used */ + + httpstring, + (data->state.aptr.host?data->state.aptr.host:""), + data->state.aptr.proxyuserpwd? + data->state.aptr.proxyuserpwd:"", + data->state.aptr.userpwd?data->state.aptr.userpwd:"", + (data->state.use_range && data->state.aptr.rangeline)? + data->state.aptr.rangeline:"", + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && + data->state.aptr.uagent)? + data->state.aptr.uagent:"", + p_accept?p_accept:"", + data->state.aptr.te?data->state.aptr.te:"", + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + data->state.aptr.accept_encoding)? + data->state.aptr.accept_encoding:"", + (data->state.referer && data->state.aptr.ref)? + data->state.aptr.ref:"" /* Referer: */, +#ifndef CURL_DISABLE_PROXY + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkheaders(data, STRCONST("Proxy-Connection")) && + !Curl_checkProxyheaders(data, + conn, + STRCONST("Proxy-Connection")))? + "Proxy-Connection: Keep-Alive\r\n":"", +#else + "", +#endif + te, + altused ? altused : "" + ); + + /* clear userpwd and proxyuserpwd to avoid reusing old credentials + * from reused connections */ + Curl_safefree(data->state.aptr.userpwd); + Curl_safefree(data->state.aptr.proxyuserpwd); + free(altused); + + if(result) { + Curl_dyn_free(&req); + goto fail; + } + + if(!(conn->handler->flags&PROTOPT_SSL) && + conn->httpversion < 20 && + (data->state.httpwant == CURL_HTTP_VERSION_2)) { + /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done + over SSL */ + result = Curl_http2_request_upgrade(&req, data); + if(result) { + Curl_dyn_free(&req); + return result; + } + } + + result = Curl_http_cookies(data, conn, &req); +#ifdef USE_WEBSOCKETS + if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + result = Curl_ws_request(data, &req); +#endif + if(!result) + result = Curl_add_timecondition(data, &req); + if(!result) + result = Curl_add_custom_headers(data, FALSE, &req); + + if(!result) { + http->postdata = NULL; /* nothing to post at this point */ + if((httpreq == HTTPREQ_GET) || + (httpreq == HTTPREQ_HEAD)) + Curl_pgrsSetUploadSize(data, 0); /* nothing */ + + /* bodysend takes ownership of the 'req' memory on success */ + result = Curl_http_bodysend(data, conn, &req, httpreq); + } + if(result) { + Curl_dyn_free(&req); + goto fail; + } + + if((http->postsize > -1) && + (http->postsize <= data->req.writebytecount) && + (http->sending != HTTPSEND_REQUEST)) + data->req.upload_done = TRUE; + + if(data->req.writebytecount) { + /* if a request-body has been sent off, we make sure this progress is noted + properly */ + Curl_pgrsSetUploadCounter(data, data->req.writebytecount); + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + + if(!http->postsize) { + /* already sent the entire request body, mark the "upload" as + complete */ + infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T + " out of %" CURL_FORMAT_CURL_OFF_T " bytes", + data->req.writebytecount, http->postsize); + data->req.upload_done = TRUE; + data->req.keepon &= ~KEEP_SEND; /* we're done writing */ + data->req.exp100 = EXP100_SEND_DATA; /* already sent */ + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + } + } + + if(data->req.upload_done) + Curl_conn_ev_data_done_send(data); + + if((conn->httpversion >= 20) && data->req.upload_chunky) + /* upload_chunky was set above to set up the request in a chunky fashion, + but is disabled here again to avoid that the chunked encoded version is + actually used when sending the request body over h2 */ + data->req.upload_chunky = FALSE; +fail: + if(CURLE_TOO_LARGE == result) + failf(data, "HTTP request too large"); + return result; +} + +#endif /* USE_HYPER */ + +typedef enum { + STATUS_UNKNOWN, /* not enough data to tell yet */ + STATUS_DONE, /* a status line was read */ + STATUS_BAD /* not a status line */ +} statusline; + + +/* Check a string for a prefix. Check no more than 'len' bytes */ +static bool checkprefixmax(const char *prefix, const char *buffer, size_t len) +{ + size_t ch = CURLMIN(strlen(prefix), len); + return curl_strnequal(prefix, buffer, ch); +} + +/* + * checkhttpprefix() + * + * Returns TRUE if member of the list matches prefix of string + */ +static statusline +checkhttpprefix(struct Curl_easy *data, + const char *s, size_t len) +{ + struct curl_slist *head = data->set.http200aliases; + statusline rc = STATUS_BAD; + statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; + + while(head) { + if(checkprefixmax(head->data, s, len)) { + rc = onmatch; + break; + } + head = head->next; + } + + if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len))) + rc = onmatch; + + return rc; +} + +#ifndef CURL_DISABLE_RTSP +static statusline +checkrtspprefix(struct Curl_easy *data, + const char *s, size_t len) +{ + statusline result = STATUS_BAD; + statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; + (void)data; /* unused */ + if(checkprefixmax("RTSP/", s, len)) + result = onmatch; + + return result; +} +#endif /* CURL_DISABLE_RTSP */ + +static statusline +checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, + const char *s, size_t len) +{ +#ifndef CURL_DISABLE_RTSP + if(conn->handler->protocol & CURLPROTO_RTSP) + return checkrtspprefix(data, s, len); +#else + (void)conn; +#endif /* CURL_DISABLE_RTSP */ + + return checkhttpprefix(data, s, len); +} + +/* + * Curl_http_header() parses a single response header. + */ +CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, + char *headp) +{ + CURLcode result; + struct SingleRequest *k = &data->req; + /* Check for Content-Length: header lines to get size */ + if(!k->http_bodyless && + !data->set.ignorecl && checkprefix("Content-Length:", headp)) { + curl_off_t contentlength; + CURLofft offt = curlx_strtoofft(headp + strlen("Content-Length:"), + NULL, 10, &contentlength); + + if(offt == CURL_OFFT_OK) { + k->size = contentlength; + k->maxdownload = k->size; + } + else if(offt == CURL_OFFT_FLOW) { + /* out of range */ + if(data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + streamclose(conn, "overflow content-length"); + infof(data, "Overflow Content-Length: value"); + } + else { + /* negative or just rubbish - bad HTTP */ + failf(data, "Invalid Content-Length: value"); + return CURLE_WEIRD_SERVER_REPLY; + } + } + /* check for Content-Type: header lines to get the MIME-type */ + else if(checkprefix("Content-Type:", headp)) { + char *contenttype = Curl_copy_header_value(headp); + if(!contenttype) + return CURLE_OUT_OF_MEMORY; + if(!*contenttype) + /* ignore empty data */ + free(contenttype); + else { + Curl_safefree(data->info.contenttype); + data->info.contenttype = contenttype; + } + } +#ifndef CURL_DISABLE_PROXY + else if((conn->httpversion == 10) && + conn->bits.httpproxy && + Curl_compareheader(headp, + STRCONST("Proxy-Connection:"), + STRCONST("keep-alive"))) { + /* + * When an HTTP/1.0 reply comes when using a proxy, the + * 'Proxy-Connection: keep-alive' line tells us the + * connection will be kept alive for our pleasure. + * Default action for 1.0 is to close. + */ + connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */ + infof(data, "HTTP/1.0 proxy connection set to keep alive"); + } + else if((conn->httpversion == 11) && + conn->bits.httpproxy && + Curl_compareheader(headp, + STRCONST("Proxy-Connection:"), + STRCONST("close"))) { + /* + * We get an HTTP/1.1 response from a proxy and it says it'll + * close down after this transfer. + */ + connclose(conn, "Proxy-Connection: asked to close after done"); + infof(data, "HTTP/1.1 proxy connection set close"); + } +#endif + else if((conn->httpversion == 10) && + Curl_compareheader(headp, + STRCONST("Connection:"), + STRCONST("keep-alive"))) { + /* + * An HTTP/1.0 reply with the 'Connection: keep-alive' line + * tells us the connection will be kept alive for our + * pleasure. Default action for 1.0 is to close. + * + * [RFC2068, section 19.7.1] */ + connkeep(conn, "Connection keep-alive"); + infof(data, "HTTP/1.0 connection set to keep alive"); + } + else if(Curl_compareheader(headp, + STRCONST("Connection:"), STRCONST("close"))) { + /* + * [RFC 2616, section 8.1.2.1] + * "Connection: close" is HTTP/1.1 language and means that + * the connection will close when this request has been + * served. + */ + streamclose(conn, "Connection: close used"); + } + else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) { + /* One or more encodings. We check for chunked and/or a compression + algorithm. */ + /* + * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding + * means that the server will send a series of "chunks". Each + * chunk starts with line with info (including size of the + * coming block) (terminated with CRLF), then a block of data + * with the previously mentioned size. There can be any amount + * of chunks, and a chunk-data set to zero signals the + * end-of-chunks. */ + + result = Curl_build_unencoding_stack(data, + headp + strlen("Transfer-Encoding:"), + TRUE); + if(result) + return result; + if(!k->chunk && data->set.http_transfer_encoding) { + /* if this isn't chunked, only close can signal the end of this transfer + as Content-Length is said not to be trusted for transfer-encoding! */ + connclose(conn, "HTTP/1.1 transfer-encoding without chunks"); + k->ignore_cl = TRUE; + } + } + else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) && + data->set.str[STRING_ENCODING]) { + /* + * Process Content-Encoding. Look for the values: identity, + * gzip, deflate, compress, x-gzip and x-compress. x-gzip and + * x-compress are the same as gzip and compress. (Sec 3.5 RFC + * 2616). zlib cannot handle compress. However, errors are + * handled further down when the response body is processed + */ + result = Curl_build_unencoding_stack(data, + headp + strlen("Content-Encoding:"), + FALSE); + if(result) + return result; + } + else if(checkprefix("Retry-After:", headp)) { + /* Retry-After = HTTP-date / delay-seconds */ + curl_off_t retry_after = 0; /* zero for unknown or "now" */ + /* Try it as a decimal number, if it works it is not a date */ + (void)curlx_strtoofft(headp + strlen("Retry-After:"), + NULL, 10, &retry_after); + if(!retry_after) { + time_t date = Curl_getdate_capped(headp + strlen("Retry-After:")); + if(-1 != date) + /* convert date to number of seconds into the future */ + retry_after = date - time(NULL); + } + data->info.retry_after = retry_after; /* store it */ + } + else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) { + /* Content-Range: bytes [num]- + Content-Range: bytes: [num]- + Content-Range: [num]- + Content-Range: [asterisk]/[total] + + The second format was added since Sun's webserver + JavaWebServer/1.1.1 obviously sends the header this way! + The third added since some servers use that! + The fourth means the requested range was unsatisfied. + */ + + char *ptr = headp + strlen("Content-Range:"); + + /* Move forward until first digit or asterisk */ + while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') + ptr++; + + /* if it truly stopped on a digit */ + if(ISDIGIT(*ptr)) { + if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { + if(data->state.resume_from == k->offset) + /* we asked for a resume and we got it */ + k->content_range = TRUE; + } + } + else if(k->httpcode < 300) + data->state.resume_from = 0; /* get everything */ + } +#if !defined(CURL_DISABLE_COOKIES) + else if(data->cookies && data->state.cookie_engine && + checkprefix("Set-Cookie:", headp)) { + /* If there is a custom-set Host: name, use it here, or else use real peer + host name. */ + const char *host = data->state.aptr.cookiehost? + data->state.aptr.cookiehost:conn->host.name; + const bool secure_context = + conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || + strcasecompare("localhost", host) || + !strcmp(host, "127.0.0.1") || + !strcmp(host, "::1") ? TRUE : FALSE; + + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, + CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_add(data, data->cookies, TRUE, FALSE, + headp + strlen("Set-Cookie:"), host, + data->state.up.path, secure_context); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } +#endif + else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) && + (data->set.timecondition || data->set.get_filetime) ) { + k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:")); + if(data->set.get_filetime) + data->info.filetime = k->timeofdoc; + } + else if((checkprefix("WWW-Authenticate:", headp) && + (401 == k->httpcode)) || + (checkprefix("Proxy-authenticate:", headp) && + (407 == k->httpcode))) { + + bool proxy = (k->httpcode == 407) ? TRUE : FALSE; + char *auth = Curl_copy_header_value(headp); + if(!auth) + return CURLE_OUT_OF_MEMORY; + + result = Curl_http_input_auth(data, proxy, auth); + + free(auth); + + if(result) + return result; + } +#ifdef USE_SPNEGO + else if(checkprefix("Persistent-Auth:", headp)) { + struct negotiatedata *negdata = &conn->negotiate; + struct auth *authp = &data->state.authhost; + if(authp->picked == CURLAUTH_NEGOTIATE) { + char *persistentauth = Curl_copy_header_value(headp); + if(!persistentauth) + return CURLE_OUT_OF_MEMORY; + negdata->noauthpersist = checkprefix("false", persistentauth)? + TRUE:FALSE; + negdata->havenoauthpersist = TRUE; + infof(data, "Negotiate: noauthpersist -> %d, header part: %s", + negdata->noauthpersist, persistentauth); + free(persistentauth); + } + } +#endif + else if((k->httpcode >= 300 && k->httpcode < 400) && + checkprefix("Location:", headp) && + !data->req.location) { + /* this is the URL that the server advises us to use instead */ + char *location = Curl_copy_header_value(headp); + if(!location) + return CURLE_OUT_OF_MEMORY; + if(!*location) + /* ignore empty data */ + free(location); + else { + data->req.location = location; + + if(data->set.http_follow_location) { + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->req.location); /* clone */ + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + + /* some cases of POST and PUT etc needs to rewind the data + stream at this point */ + result = http_perhapsrewind(data, conn); + if(result) + return result; + + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; + } + } + } + +#ifndef CURL_DISABLE_HSTS + /* If enabled, the header is incoming and this is over HTTPS */ + else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) && + ((conn->handler->flags & PROTOPT_SSL) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_HSTS_HTTP") +#else + 0 +#endif + )) { + CURLcode check = + Curl_hsts_parse(data->hsts, conn->host.name, + headp + strlen("Strict-Transport-Security:")); + if(check) + infof(data, "Illegal STS header skipped"); +#ifdef DEBUGBUILD + else + infof(data, "Parsed STS header fine (%zu entries)", + data->hsts->list.size); +#endif + } +#endif +#ifndef CURL_DISABLE_ALTSVC + /* If enabled, the header is incoming and this is over HTTPS */ + else if(data->asi && checkprefix("Alt-Svc:", headp) && + ((conn->handler->flags & PROTOPT_SSL) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_ALTSVC_HTTP") +#else + 0 +#endif + )) { + /* the ALPN of the current request */ + enum alpnid id = (conn->httpversion == 30)? ALPN_h3 : + (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1; + result = Curl_altsvc_parse(data, data->asi, + headp + strlen("Alt-Svc:"), + id, conn->host.name, + curlx_uitous((unsigned int)conn->remote_port)); + if(result) + return result; + } +#endif + else if(conn->handler->protocol & CURLPROTO_RTSP) { + result = Curl_rtsp_parseheader(data, headp); + if(result) + return result; + } + return CURLE_OK; +} + +/* + * Called after the first HTTP response line (the status line) has been + * received and parsed. + */ + +CURLcode Curl_http_statusline(struct Curl_easy *data, + struct connectdata *conn) +{ + struct SingleRequest *k = &data->req; + data->info.httpcode = k->httpcode; + + data->info.httpversion = conn->httpversion; + if(!data->state.httpversion || + data->state.httpversion > conn->httpversion) + /* store the lowest server version we encounter */ + data->state.httpversion = conn->httpversion; + + /* + * This code executes as part of processing the header. As a + * result, it's not totally clear how to interpret the + * response code yet as that depends on what other headers may + * be present. 401 and 407 may be errors, but may be OK + * depending on how authentication is working. Other codes + * are definitely errors, so give up here. + */ + if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET && + k->httpcode == 416) { + /* "Requested Range Not Satisfiable", just proceed and + pretend this is no error */ + k->ignorebody = TRUE; /* Avoid appending error msg to good data. */ + } + + if(conn->httpversion == 10) { + /* Default action for HTTP/1.0 must be to close, unless + we get one of those fancy headers that tell us the + server keeps it open for us! */ + infof(data, "HTTP 1.0, assume close after body"); + connclose(conn, "HTTP/1.0 close after body"); + } + else if(conn->httpversion == 20 || + (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) { + DEBUGF(infof(data, "HTTP/2 found, allow multiplexing")); + /* HTTP/2 cannot avoid multiplexing since it is a core functionality + of the protocol */ + conn->bundle->multiuse = BUNDLE_MULTIPLEX; + } + else if(conn->httpversion >= 11 && + !conn->bits.close) { + /* If HTTP version is >= 1.1 and connection is persistent */ + DEBUGF(infof(data, + "HTTP 1.1 or later with persistent connection")); + } + + k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200; + switch(k->httpcode) { + case 304: + /* (quote from RFC2616, section 10.3.5): The 304 response + * MUST NOT contain a message-body, and thus is always + * terminated by the first empty line after the header + * fields. */ + if(data->set.timecondition) + data->info.timecond = TRUE; + FALLTHROUGH(); + case 204: + /* (quote from RFC2616, section 10.2.5): The server has + * fulfilled the request but does not need to return an + * entity-body ... The 204 response MUST NOT include a + * message-body, and thus is always terminated by the first + * empty line after the header fields. */ + k->size = 0; + k->maxdownload = 0; + k->http_bodyless = TRUE; + break; + default: + break; + } + return CURLE_OK; +} + +/* Content-Length must be ignored if any Transfer-Encoding is present in the + response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is + figured out here after all headers have been received but before the final + call to the user's header callback, so that a valid content length can be + retrieved by the user in the final call. */ +CURLcode Curl_http_size(struct Curl_easy *data) +{ + struct SingleRequest *k = &data->req; + if(data->req.ignore_cl || k->chunk) { + k->size = k->maxdownload = -1; + } + else if(k->size != -1) { + if(data->set.max_filesize && + k->size > data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + Curl_pgrsSetDownloadSize(data, k->size); + k->maxdownload = k->size; + } + return CURLE_OK; +} + +static CURLcode verify_header(struct Curl_easy *data) +{ + struct SingleRequest *k = &data->req; + const char *header = Curl_dyn_ptr(&data->state.headerb); + size_t hlen = Curl_dyn_len(&data->state.headerb); + char *ptr = memchr(header, 0x00, hlen); + if(ptr) { + /* this is bad, bail out */ + failf(data, "Nul byte in header"); + return CURLE_WEIRD_SERVER_REPLY; + } + if(k->headerline < 2) + /* the first "header" is the status-line and it has no colon */ + return CURLE_OK; + if(((header[0] == ' ') || (header[0] == '\t')) && k->headerline > 2) + /* line folding, can't happen on line 2 */ + ; + else { + ptr = memchr(header, ':', hlen); + if(!ptr) { + /* this is bad, bail out */ + failf(data, "Header without colon"); + return CURLE_WEIRD_SERVER_REPLY; + } + } + return CURLE_OK; +} + +CURLcode Curl_bump_headersize(struct Curl_easy *data, + size_t delta, + bool connect_only) +{ + size_t bad = 0; + unsigned int max = MAX_HTTP_RESP_HEADER_SIZE; + if(delta < MAX_HTTP_RESP_HEADER_SIZE) { + data->info.header_size += (unsigned int)delta; + data->req.allheadercount += (unsigned int)delta; + if(!connect_only) + data->req.headerbytecount += (unsigned int)delta; + if(data->req.allheadercount > max) + bad = data->req.allheadercount; + else if(data->info.header_size > (max * 20)) { + bad = data->info.header_size; + max *= 20; + } + } + else + bad = data->req.allheadercount + delta; + if(bad) { + failf(data, "Too large response headers: %zu > %u", bad, max); + return CURLE_RECV_ERROR; + } + return CURLE_OK; +} + + +/* + * Read any HTTP header lines from the server and pass them to the client app. + */ +static CURLcode http_rw_headers(struct Curl_easy *data, + const char *buf, size_t blen, + size_t *pconsumed) +{ + struct connectdata *conn = data->conn; + CURLcode result = CURLE_OK; + struct SingleRequest *k = &data->req; + char *headp; + char *end_ptr; + bool leftover_body = FALSE; + + /* header line within buffer loop */ + *pconsumed = 0; + do { + size_t line_length; + int writetype; + + /* data is in network encoding so use 0x0a instead of '\n' */ + end_ptr = memchr(buf, 0x0a, blen); + + if(!end_ptr) { + /* Not a complete header line within buffer, append the data to + the end of the headerbuff. */ + result = Curl_dyn_addn(&data->state.headerb, buf, blen); + if(result) + return result; + *pconsumed += blen; + + if(!k->headerline) { + /* check if this looks like a protocol header */ + statusline st = + checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + + if(st == STATUS_BAD) { + /* this is not the beginning of a protocol first header line */ + k->header = FALSE; + streamclose(conn, "bad HTTP: No end-of-message indicator"); + if(!data->set.http09_allowed) { + failf(data, "Received HTTP/0.9 when not allowed"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + leftover_body = TRUE; + goto out; + } + } + goto out; /* read more and try again */ + } + + /* decrease the size of the remaining (supposed) header line */ + line_length = (end_ptr - buf) + 1; + result = Curl_dyn_addn(&data->state.headerb, buf, line_length); + if(result) + return result; + + blen -= line_length; + buf += line_length; + *pconsumed += line_length; + + /**** + * We now have a FULL header line in 'headerb'. + *****/ + + if(!k->headerline) { + /* the first read header */ + statusline st = checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(st == STATUS_BAD) { + streamclose(conn, "bad HTTP: No end-of-message indicator"); + /* this is not the beginning of a protocol first header line */ + if(!data->set.http09_allowed) { + failf(data, "Received HTTP/0.9 when not allowed"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + k->header = FALSE; + leftover_body = TRUE; + goto out; + } + } + + /* headers are in network encoding so use 0x0a and 0x0d instead of '\n' + and '\r' */ + headp = Curl_dyn_ptr(&data->state.headerb); + if((0x0a == *headp) || (0x0d == *headp)) { + size_t headerlen; + bool switch_to_h2 = FALSE; + /* Zero-length header line means end of headers! */ + + if('\r' == *headp) + headp++; /* pass the \r byte */ + if('\n' == *headp) + headp++; /* pass the \n byte */ + + if(100 <= k->httpcode && 199 >= k->httpcode) { + /* "A user agent MAY ignore unexpected 1xx status responses." */ + switch(k->httpcode) { + case 100: + /* + * We have made an HTTP PUT or POST and this is 1.1-lingo + * that tells us that the server is OK with this and ready + * to receive the data. + * However, we'll get more headers now so we must get + * back into the header-parsing state! + */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + + /* if we did wait for this do enable write now! */ + if(k->exp100 > EXP100_SEND_DATA) { + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + } + break; + case 101: + if(conn->httpversion == 11) { + /* Switching Protocols only allowed from HTTP/1.1 */ + if(k->upgr101 == UPGR101_H2) { + /* Switching to HTTP/2 */ + infof(data, "Received 101, Switching to HTTP/2"); + k->upgr101 = UPGR101_RECEIVED; + + /* we'll get more headers (HTTP/2 response) */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + switch_to_h2 = TRUE; + } +#ifdef USE_WEBSOCKETS + else if(k->upgr101 == UPGR101_WS) { + /* verify the response */ + result = Curl_ws_accept(data, buf, blen); + if(result) + return result; + k->header = FALSE; /* no more header to parse! */ + *pconsumed += blen; /* ws accept handled the data */ + blen = 0; + if(data->set.connect_only) + k->keepon &= ~KEEP_RECV; /* read no more content */ + } +#endif + else { + /* Not switching to another protocol */ + k->header = FALSE; /* no more header to parse! */ + } + } + else { + /* invalid for other HTTP versions */ + failf(data, "unexpected 101 response code"); + return CURLE_WEIRD_SERVER_REPLY; + } + break; + default: + /* the status code 1xx indicates a provisional response, so + we'll get another set of headers */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + break; + } + } + else { + if(k->upgr101 == UPGR101_H2) { + /* A requested upgrade was denied, poke the multi handle to possibly + allow a pending pipewait to continue */ + Curl_multi_connchanged(data->multi); + } + k->header = FALSE; /* no more header to parse! */ + + if((k->size == -1) && !k->chunk && !conn->bits.close && + (conn->httpversion == 11) && + !(conn->handler->protocol & CURLPROTO_RTSP) && + data->state.httpreq != HTTPREQ_HEAD) { + /* On HTTP 1.1, when connection is not to get closed, but no + Content-Length nor Transfer-Encoding chunked have been + received, according to RFC2616 section 4.4 point 5, we + assume that the server will close the connection to + signal the end of the document. */ + infof(data, "no chunk, no close, no size. Assume close to " + "signal end"); + streamclose(conn, "HTTP: No end-of-message indicator"); + } + } + + if(!k->header) { + result = Curl_http_size(data); + if(result) + return result; + } + + /* At this point we have some idea about the fate of the connection. + If we are closing the connection it may result auth failure. */ +#if defined(USE_NTLM) + if(conn->bits.close && + (((data->req.httpcode == 401) && + (conn->http_ntlm_state == NTLMSTATE_TYPE2)) || + ((data->req.httpcode == 407) && + (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) { + infof(data, "Connection closure while negotiating auth (HTTP 1.0?)"); + data->state.authproblem = TRUE; + } +#endif +#if defined(USE_SPNEGO) + if(conn->bits.close && + (((data->req.httpcode == 401) && + (conn->http_negotiate_state == GSS_AUTHRECV)) || + ((data->req.httpcode == 407) && + (conn->proxy_negotiate_state == GSS_AUTHRECV)))) { + infof(data, "Connection closure while negotiating auth (HTTP 1.0?)"); + data->state.authproblem = TRUE; + } + if((conn->http_negotiate_state == GSS_AUTHDONE) && + (data->req.httpcode != 401)) { + conn->http_negotiate_state = GSS_AUTHSUCC; + } + if((conn->proxy_negotiate_state == GSS_AUTHDONE) && + (data->req.httpcode != 407)) { + conn->proxy_negotiate_state = GSS_AUTHSUCC; + } +#endif + + /* now, only output this if the header AND body are requested: + */ + writetype = CLIENTWRITE_HEADER | + ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0); + + headerlen = Curl_dyn_len(&data->state.headerb); + result = Curl_client_write(data, writetype, + Curl_dyn_ptr(&data->state.headerb), + headerlen); + if(result) + return result; + + result = Curl_bump_headersize(data, headerlen, FALSE); + if(result) + return result; + + /* + * When all the headers have been parsed, see if we should give + * up and return an error. + */ + if(http_should_fail(data)) { + failf(data, "The requested URL returned error: %d", + k->httpcode); + return CURLE_HTTP_RETURNED_ERROR; + } + +#ifdef USE_WEBSOCKETS + /* All non-101 HTTP status codes are bad when wanting to upgrade to + websockets */ + if(data->req.upgr101 == UPGR101_WS) { + failf(data, "Refused WebSockets upgrade: %d", k->httpcode); + return CURLE_HTTP_RETURNED_ERROR; + } +#endif + + + data->req.deductheadercount = + (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; + + /* Curl_http_auth_act() checks what authentication methods + * that are available and decides which one (if any) to + * use. It will set 'newurl' if an auth method was picked. */ + result = Curl_http_auth_act(data); + + if(result) + return result; + + if(k->httpcode >= 300) { + if((!conn->bits.authneg) && !conn->bits.close && + !data->state.rewindbeforesend) { + /* + * General treatment of errors when about to send data. Including : + * "417 Expectation Failed", while waiting for 100-continue. + * + * The check for close above is done simply because of something + * else has already deemed the connection to get closed then + * something else should've considered the big picture and we + * avoid this check. + * + * rewindbeforesend indicates that something has told libcurl to + * continue sending even if it gets discarded + */ + + switch(data->state.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + /* We got an error response. If this happened before the whole + * request body has been sent we stop sending and mark the + * connection for closure after we've read the entire response. + */ + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + if(!k->upload_done) { + if((k->httpcode == 417) && data->state.expect100header) { + /* 417 Expectation Failed - try again without the Expect + header */ + if(!k->writebytecount && + k->exp100 == EXP100_AWAITING_CONTINUE) { + infof(data, "Got HTTP failure 417 while waiting for a 100"); + } + else { + infof(data, "Got HTTP failure 417 while sending data"); + streamclose(conn, + "Stop sending data before everything sent"); + result = http_perhapsrewind(data, conn); + if(result) + return result; + } + data->state.disableexpect = TRUE; + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->state.url); + Curl_done_sending(data, k); + } + else if(data->set.http_keep_sending_on_error) { + infof(data, "HTTP error before end of send, keep sending"); + if(k->exp100 > EXP100_SEND_DATA) { + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + } + } + else { + infof(data, "HTTP error before end of send, stop sending"); + streamclose(conn, "Stop sending data before everything sent"); + result = Curl_done_sending(data, k); + if(result) + return result; + k->upload_done = TRUE; + if(data->state.expect100header) + k->exp100 = EXP100_FAILED; + } + } + break; + + default: /* default label present to avoid compiler warnings */ + break; + } + } + + if(data->state.rewindbeforesend && + (conn->writesockfd != CURL_SOCKET_BAD)) { + /* We rewind before next send, continue sending now */ + infof(data, "Keep sending data to get tossed away"); + k->keepon |= KEEP_SEND; + } + } + + if(!k->header) { + /* + * really end-of-headers. + * + * If we requested a "no body", this is a good time to get + * out and return home. + */ + if(data->req.no_body) + k->download_done = TRUE; + + /* If max download size is *zero* (nothing) we already have + nothing and can safely return ok now! But for HTTP/2, we'd + like to call http2_handle_stream_close to properly close a + stream. In order to do this, we keep reading until we + close the stream. */ + if(0 == k->maxdownload + && !Curl_conn_is_http2(data, conn, FIRSTSOCKET) + && !Curl_conn_is_http3(data, conn, FIRSTSOCKET)) + k->download_done = TRUE; + + Curl_debug(data, CURLINFO_HEADER_IN, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + goto out; /* exit header line loop */ + } + + /* We continue reading headers, reset the line-based header */ + Curl_dyn_reset(&data->state.headerb); + if(switch_to_h2) { + /* Having handled the headers, we can do the HTTP/2 switch. + * Any remaining `buf` bytes are already HTTP/2 and passed to + * be processed. */ + result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen); + if(result) + return result; + *pconsumed += blen; + blen = 0; + } + + continue; + } + + /* + * Checks for special headers coming up. + */ + + writetype = CLIENTWRITE_HEADER; + if(!k->headerline++) { + /* This is the first header, it MUST be the error code line + or else we consider this to be the body right away! */ + bool fine_statusline = FALSE; + if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + /* + * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2 + * + * The response code is always a three-digit number in HTTP as the spec + * says. We allow any three-digit number here, but we cannot make + * guarantees on future behaviors since it isn't within the protocol. + */ + int httpversion = 0; + char *p = headp; + + while(*p && ISBLANK(*p)) + p++; + if(!strncmp(p, "HTTP/", 5)) { + p += 5; + switch(*p) { + case '1': + p++; + if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) { + if(ISBLANK(p[2])) { + httpversion = 10 + (p[1] - '0'); + p += 3; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(ISSPACE(*p)) + fine_statusline = TRUE; + } + } + } + if(!fine_statusline) { + failf(data, "Unsupported HTTP/1 subversion in response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + break; + case '2': + case '3': + if(!ISBLANK(p[1])) + break; + httpversion = (*p - '0') * 10; + p += 2; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(!ISSPACE(*p)) + break; + fine_statusline = TRUE; + } + break; + default: /* unsupported */ + failf(data, "Unsupported HTTP version in response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + } + + if(fine_statusline) { + if(k->httpcode < 100) { + failf(data, "Unsupported response code in HTTP response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + switch(httpversion) { + case 10: + case 11: +#ifdef USE_HTTP2 + case 20: +#endif +#ifdef ENABLE_QUIC + case 30: +#endif + conn->httpversion = (unsigned char)httpversion; + break; + default: + failf(data, "Unsupported HTTP version (%u.%d) in response", + httpversion/10, httpversion%10); + return CURLE_UNSUPPORTED_PROTOCOL; + } + + if(k->upgr101 == UPGR101_RECEIVED) { + /* supposedly upgraded to http2 now */ + if(conn->httpversion != 20) + infof(data, "Lying server, not serving HTTP/2"); + } + if(conn->httpversion < 20) { + conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; + } + } + else { + /* If user has set option HTTP200ALIASES, + compare header line against list of aliases + */ + statusline check = + checkhttpprefix(data, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(check == STATUS_DONE) { + fine_statusline = TRUE; + k->httpcode = 200; + conn->httpversion = 10; + } + } + } + else if(conn->handler->protocol & CURLPROTO_RTSP) { + char *p = headp; + while(*p && ISBLANK(*p)) + p++; + if(!strncmp(p, "RTSP/", 5)) { + p += 5; + if(ISDIGIT(*p)) { + p++; + if((p[0] == '.') && ISDIGIT(p[1])) { + if(ISBLANK(p[2])) { + p += 3; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(ISSPACE(*p)) { + fine_statusline = TRUE; + conn->httpversion = 11; /* RTSP acts like HTTP 1.1 */ + } + } + } + } + } + if(!fine_statusline) + return CURLE_WEIRD_SERVER_REPLY; + } + } + + if(fine_statusline) { + result = Curl_http_statusline(data, conn); + if(result) + return result; + writetype |= CLIENTWRITE_STATUS; + } + else { + k->header = FALSE; /* this is not a header line */ + break; + } + } + + result = verify_header(data); + if(result) + return result; + + result = Curl_http_header(data, conn, headp); + if(result) + return result; + + /* + * End of header-checks. Write them to the client. + */ + if(k->httpcode/100 == 1) + writetype |= CLIENTWRITE_1XX; + + Curl_debug(data, CURLINFO_HEADER_IN, headp, + Curl_dyn_len(&data->state.headerb)); + + result = Curl_client_write(data, writetype, headp, + Curl_dyn_len(&data->state.headerb)); + if(result) + return result; + + result = Curl_bump_headersize(data, Curl_dyn_len(&data->state.headerb), + FALSE); + if(result) + return result; + + Curl_dyn_reset(&data->state.headerb); + } + while(blen); + + /* We might have reached the end of the header part here, but + there might be a non-header part left in the end of the read + buffer. */ +out: + if(!k->header && !leftover_body) { + Curl_dyn_free(&data->state.headerb); + } + return CURLE_OK; +} + +/* + * HTTP protocol `write_resp` implementation. Will parse headers + * when not done yet and otherwise return without consuming data. + */ +CURLcode Curl_http_write_resp_hds(struct Curl_easy *data, + const char *buf, size_t blen, + size_t *pconsumed, + bool *done) +{ + *done = FALSE; + if(!data->req.header) { + *pconsumed = 0; + return CURLE_OK; + } + else { + CURLcode result; + + result = http_rw_headers(data, buf, blen, pconsumed); + if(!result && !data->req.header) { + /* we have successfully finished parsing the HEADERs */ + result = Curl_http_firstwrite(data, data->conn, done); + + if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) { + /* leftover from parsing something that turned out not + * to be a header, only happens if we allow for + * HTTP/0.9 like responses */ + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + } + Curl_dyn_free(&data->state.headerb); + } + return result; + } +} + +CURLcode Curl_http_write_resp(struct Curl_easy *data, + const char *buf, size_t blen, + bool is_eos, + bool *done) +{ + CURLcode result; + size_t consumed; + int flags; + + *done = FALSE; + result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done); + if(result || *done) + goto out; + + DEBUGASSERT(consumed <= blen); + blen -= consumed; + buf += consumed; + /* either all was consumed in header parsing, or we have data left + * and are done with heders, e.g. it is BODY data */ + DEBUGASSERT(!blen || !data->req.header); + if(!data->req.header && (blen || is_eos)) { + /* BODY data after header been parsed, write and consume */ + flags = CLIENTWRITE_BODY; + if(is_eos) + flags |= CLIENTWRITE_EOS; + result = Curl_client_write(data, flags, (char *)buf, blen); + } +out: + return result; +} + +/* Decode HTTP status code string. */ +CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len) +{ + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + int status = 0; + int i; + + if(len != 3) + goto out; + + for(i = 0; i < 3; ++i) { + char c = s[i]; + + if(c < '0' || c > '9') + goto out; + + status *= 10; + status += c - '0'; + } + result = CURLE_OK; +out: + *pstatus = result? -1 : status; + return result; +} + +CURLcode Curl_http_req_make(struct httpreq **preq, + const char *method, size_t m_len, + const char *scheme, size_t s_len, + const char *authority, size_t a_len, + const char *path, size_t p_len) +{ + struct httpreq *req; + CURLcode result = CURLE_OUT_OF_MEMORY; + + DEBUGASSERT(method); + if(m_len + 1 > sizeof(req->method)) + return CURLE_BAD_FUNCTION_ARGUMENT; + + req = calloc(1, sizeof(*req)); + if(!req) + goto out; + memcpy(req->method, method, m_len); + if(scheme) { + req->scheme = Curl_memdup0(scheme, s_len); + if(!req->scheme) + goto out; + } + if(authority) { + req->authority = Curl_memdup0(authority, a_len); + if(!req->authority) + goto out; + } + if(path) { + req->path = Curl_memdup0(path, p_len); + if(!req->path) + goto out; + } + Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST); + Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST); + result = CURLE_OK; + +out: + if(result && req) + Curl_http_req_free(req); + *preq = result? NULL : req; + return result; +} + +static CURLcode req_assign_url_authority(struct httpreq *req, CURLU *url) +{ + char *user, *pass, *host, *port; + struct dynbuf buf; + CURLUcode uc; + CURLcode result = CURLE_URL_MALFORMAT; + + user = pass = host = port = NULL; + Curl_dyn_init(&buf, DYN_HTTP_REQUEST); + + uc = curl_url_get(url, CURLUPART_HOST, &host, 0); + if(uc && uc != CURLUE_NO_HOST) + goto out; + if(!host) { + req->authority = NULL; + result = CURLE_OK; + goto out; + } + + uc = curl_url_get(url, CURLUPART_PORT, &port, CURLU_NO_DEFAULT_PORT); + if(uc && uc != CURLUE_NO_PORT) + goto out; + uc = curl_url_get(url, CURLUPART_USER, &user, 0); + if(uc && uc != CURLUE_NO_USER) + goto out; + if(user) { + uc = curl_url_get(url, CURLUPART_PASSWORD, &pass, 0); + if(uc && uc != CURLUE_NO_PASSWORD) + goto out; + } + + if(user) { + result = Curl_dyn_add(&buf, user); + if(result) + goto out; + if(pass) { + result = Curl_dyn_addf(&buf, ":%s", pass); + if(result) + goto out; + } + result = Curl_dyn_add(&buf, "@"); + if(result) + goto out; + } + result = Curl_dyn_add(&buf, host); + if(result) + goto out; + if(port) { + result = Curl_dyn_addf(&buf, ":%s", port); + if(result) + goto out; + } + req->authority = strdup(Curl_dyn_ptr(&buf)); + if(!req->authority) + goto out; + result = CURLE_OK; + +out: + free(user); + free(pass); + free(host); + free(port); + Curl_dyn_free(&buf); + return result; +} + +static CURLcode req_assign_url_path(struct httpreq *req, CURLU *url) +{ + char *path, *query; + struct dynbuf buf; + CURLUcode uc; + CURLcode result = CURLE_URL_MALFORMAT; + + path = query = NULL; + Curl_dyn_init(&buf, DYN_HTTP_REQUEST); + + uc = curl_url_get(url, CURLUPART_PATH, &path, CURLU_PATH_AS_IS); + if(uc) + goto out; + uc = curl_url_get(url, CURLUPART_QUERY, &query, 0); + if(uc && uc != CURLUE_NO_QUERY) + goto out; + + if(!path && !query) { + req->path = NULL; + } + else if(path && !query) { + req->path = path; + path = NULL; + } + else { + if(path) { + result = Curl_dyn_add(&buf, path); + if(result) + goto out; + } + if(query) { + result = Curl_dyn_addf(&buf, "?%s", query); + if(result) + goto out; + } + req->path = strdup(Curl_dyn_ptr(&buf)); + if(!req->path) + goto out; + } + result = CURLE_OK; + +out: + free(path); + free(query); + Curl_dyn_free(&buf); + return result; +} + +CURLcode Curl_http_req_make2(struct httpreq **preq, + const char *method, size_t m_len, + CURLU *url, const char *scheme_default) +{ + struct httpreq *req; + CURLcode result = CURLE_OUT_OF_MEMORY; + CURLUcode uc; + + DEBUGASSERT(method); + if(m_len + 1 > sizeof(req->method)) + return CURLE_BAD_FUNCTION_ARGUMENT; + + req = calloc(1, sizeof(*req)); + if(!req) + goto out; + memcpy(req->method, method, m_len); + + uc = curl_url_get(url, CURLUPART_SCHEME, &req->scheme, 0); + if(uc && uc != CURLUE_NO_SCHEME) + goto out; + if(!req->scheme && scheme_default) { + req->scheme = strdup(scheme_default); + if(!req->scheme) + goto out; + } + + result = req_assign_url_authority(req, url); + if(result) + goto out; + result = req_assign_url_path(req, url); + if(result) + goto out; + + Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST); + Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST); + result = CURLE_OK; + +out: + if(result && req) + Curl_http_req_free(req); + *preq = result? NULL : req; + return result; +} + +void Curl_http_req_free(struct httpreq *req) +{ + if(req) { + free(req->scheme); + free(req->authority); + free(req->path); + Curl_dynhds_free(&req->headers); + Curl_dynhds_free(&req->trailers); + free(req); + } +} + +struct name_const { + const char *name; + size_t namelen; +}; + +static struct name_const H2_NON_FIELD[] = { + { STRCONST("Host") }, + { STRCONST("Upgrade") }, + { STRCONST("Connection") }, + { STRCONST("Keep-Alive") }, + { STRCONST("Proxy-Connection") }, + { STRCONST("Transfer-Encoding") }, +}; + +static bool h2_non_field(const char *name, size_t namelen) +{ + size_t i; + for(i = 0; i < sizeof(H2_NON_FIELD)/sizeof(H2_NON_FIELD[0]); ++i) { + if(namelen < H2_NON_FIELD[i].namelen) + return FALSE; + if(namelen == H2_NON_FIELD[i].namelen && + strcasecompare(H2_NON_FIELD[i].name, name)) + return TRUE; + } + return FALSE; +} + +CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, + struct httpreq *req, struct Curl_easy *data) +{ + const char *scheme = NULL, *authority = NULL; + struct dynhds_entry *e; + size_t i; + CURLcode result; + + DEBUGASSERT(req); + DEBUGASSERT(h2_headers); + + if(req->scheme) { + scheme = req->scheme; + } + else if(strcmp("CONNECT", req->method)) { + scheme = Curl_checkheaders(data, STRCONST(HTTP_PSEUDO_SCHEME)); + if(scheme) { + scheme += sizeof(HTTP_PSEUDO_SCHEME); + while(*scheme && ISBLANK(*scheme)) + scheme++; + infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme); + } + else { + scheme = (data->conn && data->conn->handler->flags & PROTOPT_SSL)? + "https" : "http"; + } + } + + if(req->authority) { + authority = req->authority; + } + else { + e = Curl_dynhds_get(&req->headers, STRCONST("Host")); + if(e) + authority = e->value; + } + + Curl_dynhds_reset(h2_headers); + Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE); + result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), + req->method, strlen(req->method)); + if(!result && scheme) { + result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), + scheme, strlen(scheme)); + } + if(!result && authority) { + result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), + authority, strlen(authority)); + } + if(!result && req->path) { + result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), + req->path, strlen(req->path)); + } + for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) { + e = Curl_dynhds_getn(&req->headers, i); + if(!h2_non_field(e->name, e->namelen)) { + result = Curl_dynhds_add(h2_headers, e->name, e->namelen, + e->value, e->valuelen); + } + } + + return result; +} + +CURLcode Curl_http_resp_make(struct http_resp **presp, + int status, + const char *description) +{ + struct http_resp *resp; + CURLcode result = CURLE_OUT_OF_MEMORY; + + resp = calloc(1, sizeof(*resp)); + if(!resp) + goto out; + + resp->status = status; + if(description) { + resp->description = strdup(description); + if(!resp->description) + goto out; + } + Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST); + Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST); + result = CURLE_OK; + +out: + if(result && resp) + Curl_http_resp_free(resp); + *presp = result? NULL : resp; + return result; +} + +void Curl_http_resp_free(struct http_resp *resp) +{ + if(resp) { + free(resp->description); + Curl_dynhds_free(&resp->headers); + Curl_dynhds_free(&resp->trailers); + if(resp->prev) + Curl_http_resp_free(resp->prev); + free(resp); + } +} + +#endif /* CURL_DISABLE_HTTP */ diff --git a/lib/http.h b/lib/http.h new file mode 100644 index 0000000..ad2697c --- /dev/null +++ b/lib/http.h @@ -0,0 +1,333 @@ +#ifndef HEADER_CURL_HTTP_H +#define HEADER_CURL_HTTP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(USE_MSH3) && !defined(_WIN32) +#include +#endif + +#include "bufq.h" +#include "dynhds.h" +#include "ws.h" + +typedef enum { + HTTPREQ_GET, + HTTPREQ_POST, + HTTPREQ_POST_FORM, /* we make a difference internally */ + HTTPREQ_POST_MIME, /* we make a difference internally */ + HTTPREQ_PUT, + HTTPREQ_HEAD +} Curl_HttpReq; + +#ifndef CURL_DISABLE_HTTP + +#if defined(ENABLE_QUIC) +#include +#endif + +extern const struct Curl_handler Curl_handler_http; + +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_https; +#endif + +struct dynhds; + +CURLcode Curl_bump_headersize(struct Curl_easy *data, + size_t delta, + bool connect_only); + +/* Header specific functions */ +bool Curl_compareheader(const char *headerline, /* line to check */ + const char *header, /* header keyword _with_ colon */ + const size_t hlen, /* len of the keyword in bytes */ + const char *content, /* content string to find */ + const size_t clen); /* len of the content in bytes */ + +char *Curl_copy_header_value(const char *header); + +char *Curl_checkProxyheaders(struct Curl_easy *data, + const struct connectdata *conn, + const char *thisheader, + const size_t thislen); +struct HTTP; /* see below */ +CURLcode Curl_buffer_send(struct dynbuf *in, + struct Curl_easy *data, + struct HTTP *http, + curl_off_t *bytes_written, + curl_off_t included_body_bytes, + int socketindex); + +CURLcode Curl_add_timecondition(struct Curl_easy *data, +#ifndef USE_HYPER + struct dynbuf *req +#else + void *headers +#endif + ); +CURLcode Curl_add_custom_headers(struct Curl_easy *data, + bool is_connect, +#ifndef USE_HYPER + struct dynbuf *req +#else + void *headers +#endif + ); +CURLcode Curl_dynhds_add_custom(struct Curl_easy *data, + bool is_connect, + struct dynhds *hds); + +CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, + struct dynbuf *buf, + struct Curl_easy *handle); + +void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, + const char **method, Curl_HttpReq *); +CURLcode Curl_http_useragent(struct Curl_easy *data); +CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn); +CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn, + struct dynbuf *req); +CURLcode Curl_http_statusline(struct Curl_easy *data, + struct connectdata *conn); +CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, + char *headp); +CURLcode Curl_transferencode(struct Curl_easy *data); +CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn, + Curl_HttpReq httpreq, + const char **teep); +CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, + struct dynbuf *r, Curl_HttpReq httpreq); +bool Curl_use_http_1_1plus(const struct Curl_easy *data, + const struct connectdata *conn); +#ifndef CURL_DISABLE_COOKIES +CURLcode Curl_http_cookies(struct Curl_easy *data, + struct connectdata *conn, + struct dynbuf *r); +#else +#define Curl_http_cookies(a,b,c) CURLE_OK +#endif +CURLcode Curl_http_resume(struct Curl_easy *data, + struct connectdata *conn, + Curl_HttpReq httpreq); +CURLcode Curl_http_range(struct Curl_easy *data, + Curl_HttpReq httpreq); +CURLcode Curl_http_firstwrite(struct Curl_easy *data, + struct connectdata *conn, + bool *done); + +/* protocol-specific functions set up to be called by the main engine */ +CURLcode Curl_http_setup_conn(struct Curl_easy *data, + struct connectdata *conn); +CURLcode Curl_http(struct Curl_easy *data, bool *done); +CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature); +CURLcode Curl_http_connect(struct Curl_easy *data, bool *done); +int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks); +CURLcode Curl_http_write_resp(struct Curl_easy *data, + const char *buf, size_t blen, + bool is_eos, + bool *done); + +/* These functions are in http.c */ +CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, + const char *auth); +CURLcode Curl_http_auth_act(struct Curl_easy *data); + +/* If only the PICKNONE bit is set, there has been a round-trip and we + selected to use no auth at all. Ie, we actively select no auth, as opposed + to not having one selected. The other CURLAUTH_* defines are present in the + public curl/curl.h header. */ +#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */ + +/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST + data get included in the initial data chunk sent to the server. If the + data is larger than this, it will automatically get split up in multiple + system calls. + + This value used to be fairly big (100K), but we must take into account that + if the server rejects the POST due for authentication reasons, this data + will always be unconditionally sent and thus it may not be larger than can + always be afforded to send twice. + + It must not be greater than 64K to work on VMS. +*/ +#ifndef MAX_INITIAL_POST_SIZE +#define MAX_INITIAL_POST_SIZE (64*1024) +#endif + +/* EXPECT_100_THRESHOLD is the request body size limit for when libcurl will + * automatically add an "Expect: 100-continue" header in HTTP requests. When + * the size is unknown, it will always add it. + * + */ +#ifndef EXPECT_100_THRESHOLD +#define EXPECT_100_THRESHOLD (1024*1024) +#endif + +/* MAX_HTTP_RESP_HEADER_SIZE is the maximum size of all response headers + combined that libcurl allows for a single HTTP response, any HTTP + version. This count includes CONNECT response headers. */ +#define MAX_HTTP_RESP_HEADER_SIZE (300*1024) + +#endif /* CURL_DISABLE_HTTP */ + +/**************************************************************************** + * HTTP unique setup + ***************************************************************************/ +struct HTTP { + curl_off_t postsize; /* off_t to handle large file sizes */ + const char *postdata; + struct back { + curl_read_callback fread_func; /* backup storage for fread pointer */ + void *fread_in; /* backup storage for fread_in pointer */ + const char *postdata; + curl_off_t postsize; + struct Curl_easy *data; + } backup; + + enum { + HTTPSEND_NADA, /* init */ + HTTPSEND_REQUEST, /* sending a request */ + HTTPSEND_BODY /* sending body */ + } sending; + +#ifndef CURL_DISABLE_HTTP + void *h2_ctx; /* HTTP/2 implementation context */ + void *h3_ctx; /* HTTP/3 implementation context */ + struct dynbuf send_buffer; /* used if the request couldn't be sent in one + chunk, points to an allocated send_buffer + struct */ +#endif +}; + +CURLcode Curl_http_size(struct Curl_easy *data); + +CURLcode Curl_http_write_resp_hds(struct Curl_easy *data, + const char *buf, size_t blen, + size_t *pconsumed, + bool *done); + +/** + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication + * method. data->state.authdone is set to TRUE when authentication is + * done. + * + * @param data all information about the current transfer + * @param conn all information about the current connection + * @param request pointer to the request keyword + * @param httpreq is the request type + * @param path pointer to the requested path + * @param proxytunnel boolean if this is the request setting up a "proxy + * tunnel" + * + * @returns CURLcode + */ +CURLcode +Curl_http_output_auth(struct Curl_easy *data, + struct connectdata *conn, + const char *request, + Curl_HttpReq httpreq, + const char *path, + bool proxytunnel); /* TRUE if this is the request setting + up the proxy tunnel */ + +/* Decode HTTP status code string. */ +CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len); + + +/** + * All about a core HTTP request, excluding body and trailers + */ +struct httpreq { + char method[24]; + char *scheme; + char *authority; + char *path; + struct dynhds headers; + struct dynhds trailers; +}; + +/** + * Create a HTTP request struct. + */ +CURLcode Curl_http_req_make(struct httpreq **preq, + const char *method, size_t m_len, + const char *scheme, size_t s_len, + const char *authority, size_t a_len, + const char *path, size_t p_len); + +CURLcode Curl_http_req_make2(struct httpreq **preq, + const char *method, size_t m_len, + CURLU *url, const char *scheme_default); + +void Curl_http_req_free(struct httpreq *req); + +#define HTTP_PSEUDO_METHOD ":method" +#define HTTP_PSEUDO_SCHEME ":scheme" +#define HTTP_PSEUDO_AUTHORITY ":authority" +#define HTTP_PSEUDO_PATH ":path" +#define HTTP_PSEUDO_STATUS ":status" + +/** + * Create the list of HTTP/2 headers which represent the request, + * using HTTP/2 pseudo headers preceding the `req->headers`. + * + * Applies the following transformations: + * - if `authority` is set, any "Host" header is removed. + * - if `authority` is unset and a "Host" header is present, use + * that as `authority` and remove "Host" + * - removes and Connection header fields as defined in rfc9113 ch. 8.2.2 + * - lower-cases the header field names + * + * @param h2_headers will contain the HTTP/2 headers on success + * @param req the request to transform + * @param data the handle to lookup defaults like ' :scheme' from + */ +CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, + struct httpreq *req, struct Curl_easy *data); + +/** + * All about a core HTTP response, excluding body and trailers + */ +struct http_resp { + int status; + char *description; + struct dynhds headers; + struct dynhds trailers; + struct http_resp *prev; +}; + +/** + * Create a HTTP response struct. + */ +CURLcode Curl_http_resp_make(struct http_resp **presp, + int status, + const char *description); + +void Curl_http_resp_free(struct http_resp *resp); + +#endif /* HEADER_CURL_HTTP_H */ diff --git a/lib/http1.c b/lib/http1.c new file mode 100644 index 0000000..182234c --- /dev/null +++ b/lib/http1.c @@ -0,0 +1,346 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_HTTP + +#include "urldata.h" +#include +#include "http.h" +#include "http1.h" +#include "urlapi-int.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +#define H1_MAX_URL_LEN (8*1024) + +void Curl_h1_req_parse_init(struct h1_req_parser *parser, size_t max_line_len) +{ + memset(parser, 0, sizeof(*parser)); + parser->max_line_len = max_line_len; + Curl_dyn_init(&parser->scratch, max_line_len); +} + +void Curl_h1_req_parse_free(struct h1_req_parser *parser) +{ + if(parser) { + Curl_http_req_free(parser->req); + Curl_dyn_free(&parser->scratch); + parser->req = NULL; + parser->done = FALSE; + } +} + +static CURLcode trim_line(struct h1_req_parser *parser, int options) +{ + DEBUGASSERT(parser->line); + if(parser->line_len) { + if(parser->line[parser->line_len - 1] == '\n') + --parser->line_len; + if(parser->line_len) { + if(parser->line[parser->line_len - 1] == '\r') + --parser->line_len; + else if(options & H1_PARSE_OPT_STRICT) + return CURLE_URL_MALFORMAT; + } + else if(options & H1_PARSE_OPT_STRICT) + return CURLE_URL_MALFORMAT; + } + else if(options & H1_PARSE_OPT_STRICT) + return CURLE_URL_MALFORMAT; + + if(parser->line_len > parser->max_line_len) { + return CURLE_URL_MALFORMAT; + } + return CURLE_OK; +} + +static ssize_t detect_line(struct h1_req_parser *parser, + const char *buf, const size_t buflen, + CURLcode *err) +{ + const char *line_end; + + DEBUGASSERT(!parser->line); + line_end = memchr(buf, '\n', buflen); + if(!line_end) { + *err = CURLE_AGAIN; + return -1; + } + parser->line = buf; + parser->line_len = line_end - buf + 1; + *err = CURLE_OK; + return (ssize_t)parser->line_len; +} + +static ssize_t next_line(struct h1_req_parser *parser, + const char *buf, const size_t buflen, int options, + CURLcode *err) +{ + ssize_t nread = 0; + + if(parser->line) { + parser->line = NULL; + parser->line_len = 0; + Curl_dyn_reset(&parser->scratch); + } + + nread = detect_line(parser, buf, buflen, err); + if(nread >= 0) { + if(Curl_dyn_len(&parser->scratch)) { + /* append detected line to scratch to have the complete line */ + *err = Curl_dyn_addn(&parser->scratch, parser->line, parser->line_len); + if(*err) + return -1; + parser->line = Curl_dyn_ptr(&parser->scratch); + parser->line_len = Curl_dyn_len(&parser->scratch); + } + *err = trim_line(parser, options); + if(*err) + return -1; + } + else if(*err == CURLE_AGAIN) { + /* no line end in `buf`, add it to our scratch */ + *err = Curl_dyn_addn(&parser->scratch, (const unsigned char *)buf, buflen); + nread = (*err)? -1 : (ssize_t)buflen; + } + return nread; +} + +static CURLcode start_req(struct h1_req_parser *parser, + const char *scheme_default, int options) +{ + const char *p, *m, *target, *hv, *scheme, *authority, *path; + size_t m_len, target_len, hv_len, scheme_len, authority_len, path_len; + size_t i; + CURLU *url = NULL; + CURLcode result = CURLE_URL_MALFORMAT; /* Use this as default fail */ + + DEBUGASSERT(!parser->req); + /* line must match: "METHOD TARGET HTTP_VERSION" */ + p = memchr(parser->line, ' ', parser->line_len); + if(!p || p == parser->line) + goto out; + + m = parser->line; + m_len = p - parser->line; + target = p + 1; + target_len = hv_len = 0; + hv = NULL; + + /* URL may contain spaces so scan backwards */ + for(i = parser->line_len; i > m_len; --i) { + if(parser->line[i] == ' ') { + hv = &parser->line[i + 1]; + hv_len = parser->line_len - i; + target_len = (hv - target) - 1; + break; + } + } + /* no SPACE found or empty TARGET or empty HTTP_VERSION */ + if(!target_len || !hv_len) + goto out; + + /* TODO: we do not check HTTP_VERSION for conformity, should + + do that when STRICT option is supplied. */ + (void)hv; + + /* The TARGET can be (rfc 9112, ch. 3.2): + * origin-form: path + optional query + * absolute-form: absolute URI + * authority-form: host+port for CONNECT + * asterisk-form: '*' for OPTIONS + * + * from TARGET, we derive `scheme` `authority` `path` + * origin-form -- -- TARGET + * absolute-form URL* URL* URL* + * authority-form -- TARGET -- + * asterisk-form -- -- TARGET + */ + scheme = authority = path = NULL; + scheme_len = authority_len = path_len = 0; + + if(target_len == 1 && target[0] == '*') { + /* asterisk-form */ + path = target; + path_len = target_len; + } + else if(!strncmp("CONNECT", m, m_len)) { + /* authority-form */ + authority = target; + authority_len = target_len; + } + else if(target[0] == '/') { + /* origin-form */ + path = target; + path_len = target_len; + } + else { + /* origin-form OR absolute-form */ + CURLUcode uc; + char tmp[H1_MAX_URL_LEN]; + + /* default, unless we see an absolute URL */ + path = target; + path_len = target_len; + + /* URL parser wants 0-termination */ + if(target_len >= sizeof(tmp)) + goto out; + memcpy(tmp, target, target_len); + tmp[target_len] = '\0'; + /* See if treating TARGET as an absolute URL makes sense */ + if(Curl_is_absolute_url(tmp, NULL, 0, FALSE)) { + int url_options; + + url = curl_url(); + if(!url) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + url_options = (CURLU_NON_SUPPORT_SCHEME| + CURLU_PATH_AS_IS| + CURLU_NO_DEFAULT_PORT); + if(!(options & H1_PARSE_OPT_STRICT)) + url_options |= CURLU_ALLOW_SPACE; + uc = curl_url_set(url, CURLUPART_URL, tmp, url_options); + if(uc) { + goto out; + } + } + + if(!url && (options & H1_PARSE_OPT_STRICT)) { + /* we should have an absolute URL or have seen `/` earlier */ + goto out; + } + } + + if(url) { + result = Curl_http_req_make2(&parser->req, m, m_len, url, scheme_default); + } + else { + if(!scheme && scheme_default) { + scheme = scheme_default; + scheme_len = strlen(scheme_default); + } + result = Curl_http_req_make(&parser->req, m, m_len, scheme, scheme_len, + authority, authority_len, path, path_len); + } + +out: + curl_url_cleanup(url); + return result; +} + +ssize_t Curl_h1_req_parse_read(struct h1_req_parser *parser, + const char *buf, size_t buflen, + const char *scheme_default, int options, + CURLcode *err) +{ + ssize_t nread = 0, n; + + *err = CURLE_OK; + while(!parser->done) { + n = next_line(parser, buf, buflen, options, err); + if(n < 0) { + if(*err != CURLE_AGAIN) { + nread = -1; + } + *err = CURLE_OK; + goto out; + } + + /* Consume this line */ + nread += (size_t)n; + buf += (size_t)n; + buflen -= (size_t)n; + + if(!parser->line) { + /* consumed bytes, but line not complete */ + if(!buflen) + goto out; + } + else if(!parser->req) { + *err = start_req(parser, scheme_default, options); + if(*err) { + nread = -1; + goto out; + } + } + else if(parser->line_len == 0) { + /* last, empty line, we are finished */ + if(!parser->req) { + *err = CURLE_URL_MALFORMAT; + nread = -1; + goto out; + } + parser->done = TRUE; + Curl_dyn_reset(&parser->scratch); + /* last chance adjustments */ + } + else { + *err = Curl_dynhds_h1_add_line(&parser->req->headers, + parser->line, parser->line_len); + if(*err) { + nread = -1; + goto out; + } + } + } + +out: + return nread; +} + +CURLcode Curl_h1_req_write_head(struct httpreq *req, int http_minor, + struct dynbuf *dbuf) +{ + CURLcode result; + + result = Curl_dyn_addf(dbuf, "%s %s%s%s%s HTTP/1.%d\r\n", + req->method, + req->scheme? req->scheme : "", + req->scheme? "://" : "", + req->authority? req->authority : "", + req->path? req->path : "", + http_minor); + if(result) + goto out; + + result = Curl_dynhds_h1_dprint(&req->headers, dbuf); + if(result) + goto out; + + result = Curl_dyn_addn(dbuf, STRCONST("\r\n")); + +out: + return result; +} + +#endif /* !CURL_DISABLE_HTTP */ diff --git a/lib/http1.h b/lib/http1.h new file mode 100644 index 0000000..2de302f --- /dev/null +++ b/lib/http1.h @@ -0,0 +1,63 @@ +#ifndef HEADER_CURL_HTTP1_H +#define HEADER_CURL_HTTP1_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_HTTP +#include "bufq.h" +#include "http.h" + +#define H1_PARSE_OPT_NONE (0) +#define H1_PARSE_OPT_STRICT (1 << 0) + +#define H1_PARSE_DEFAULT_MAX_LINE_LEN DYN_HTTP_REQUEST + +struct h1_req_parser { + struct httpreq *req; + struct dynbuf scratch; + size_t scratch_skip; + const char *line; + size_t max_line_len; + size_t line_len; + bool done; +}; + +void Curl_h1_req_parse_init(struct h1_req_parser *parser, size_t max_line_len); +void Curl_h1_req_parse_free(struct h1_req_parser *parser); + +ssize_t Curl_h1_req_parse_read(struct h1_req_parser *parser, + const char *buf, size_t buflen, + const char *scheme_default, int options, + CURLcode *err); + +CURLcode Curl_h1_req_dprint(const struct httpreq *req, + struct dynbuf *dbuf); + +CURLcode Curl_h1_req_write_head(struct httpreq *req, int http_minor, + struct dynbuf *dbuf); + +#endif /* !CURL_DISABLE_HTTP */ +#endif /* HEADER_CURL_HTTP1_H */ diff --git a/lib/http2.c b/lib/http2.c new file mode 100644 index 0000000..c3157d1 --- /dev/null +++ b/lib/http2.c @@ -0,0 +1,2849 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_NGHTTP2 +#include +#include +#include "urldata.h" +#include "bufq.h" +#include "http1.h" +#include "http2.h" +#include "http.h" +#include "sendf.h" +#include "select.h" +#include "curl_base64.h" +#include "strcase.h" +#include "multiif.h" +#include "url.h" +#include "urlapi-int.h" +#include "cfilters.h" +#include "connect.h" +#include "rand.h" +#include "strtoofft.h" +#include "strdup.h" +#include "transfer.h" +#include "dynbuf.h" +#include "headers.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if (NGHTTP2_VERSION_NUM < 0x010c00) +#error too old nghttp2 version, upgrade! +#endif + +#ifdef CURL_DISABLE_VERBOSE_STRINGS +#define nghttp2_session_callbacks_set_error_callback(x,y) +#endif + +#if (NGHTTP2_VERSION_NUM >= 0x010c00) +#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 +#endif + + +/* buffer dimensioning: + * use 16K as chunk size, as that fits H2 DATA frames well */ +#define H2_CHUNK_SIZE (16 * 1024) +/* this is how much we want "in flight" for a stream */ +#define H2_STREAM_WINDOW_SIZE (10 * 1024 * 1024) +/* on receiving from TLS, we prep for holding a full stream window */ +#define H2_NW_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) +/* on send into TLS, we just want to accumulate small frames */ +#define H2_NW_SEND_CHUNKS 1 +/* stream recv/send chunks are a result of window / chunk sizes */ +#define H2_STREAM_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) +/* keep smaller stream upload buffer (default h2 window size) to have + * our progress bars and "upload done" reporting closer to reality */ +#define H2_STREAM_SEND_CHUNKS ((64 * 1024) / H2_CHUNK_SIZE) +/* spare chunks we keep for a full window */ +#define H2_STREAM_POOL_SPARES (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) + +/* We need to accommodate the max number of streams with their window + * sizes on the overall connection. Streams might become PAUSED which + * will block their received QUOTA in the connection window. And if we + * run out of space, the server is blocked from sending us any data. + * See #10988 for an issue with this. */ +#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE) + +#define H2_SETTINGS_IV_LEN 3 +#define H2_BINSETTINGS_LEN 80 + +static int populate_settings(nghttp2_settings_entry *iv, + struct Curl_easy *data) +{ + iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; + iv[0].value = Curl_multi_max_concurrent_streams(data->multi); + + iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + iv[1].value = H2_STREAM_WINDOW_SIZE; + + iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + iv[2].value = data->multi->push_cb != NULL; + + return 3; +} + +static ssize_t populate_binsettings(uint8_t *binsettings, + struct Curl_easy *data) +{ + nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN]; + int ivlen; + + ivlen = populate_settings(iv, data); + /* this returns number of bytes it wrote or a negative number on error. */ + return nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, + iv, ivlen); +} + +struct cf_h2_ctx { + nghttp2_session *h2; + uint32_t max_concurrent_streams; + /* The easy handle used in the current filter call, cleared at return */ + struct cf_call_data call_data; + + struct bufq inbufq; /* network input */ + struct bufq outbufq; /* network output */ + struct bufc_pool stream_bufcp; /* spares for stream buffers */ + + size_t drain_total; /* sum of all stream's UrlState drain */ + int32_t goaway_error; + int32_t last_stream_id; + BIT(conn_closed); + BIT(goaway); + BIT(enable_push); + BIT(nw_out_blocked); +}; + +/* How to access `call_data` from a cf_h2 filter */ +#undef CF_CTX_CALL_DATA +#define CF_CTX_CALL_DATA(cf) \ + ((struct cf_h2_ctx *)(cf)->ctx)->call_data + +static void cf_h2_ctx_clear(struct cf_h2_ctx *ctx) +{ + struct cf_call_data save = ctx->call_data; + + if(ctx->h2) { + nghttp2_session_del(ctx->h2); + } + Curl_bufq_free(&ctx->inbufq); + Curl_bufq_free(&ctx->outbufq); + Curl_bufcp_free(&ctx->stream_bufcp); + memset(ctx, 0, sizeof(*ctx)); + ctx->call_data = save; +} + +static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) +{ + if(ctx) { + cf_h2_ctx_clear(ctx); + free(ctx); + } +} + +static CURLcode h2_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data); + +/** + * All about the H3 internals of a stream + */ +struct stream_ctx { + /*********** for HTTP/2 we store stream-local data here *************/ + int32_t id; /* HTTP/2 protocol identifier for stream */ + struct bufq recvbuf; /* response buffer */ + struct bufq sendbuf; /* request buffer */ + struct h1_req_parser h1; /* parsing the request */ + struct dynhds resp_trailers; /* response trailer fields */ + size_t resp_hds_len; /* amount of response header bytes in recvbuf */ + size_t upload_blocked_len; + curl_off_t upload_left; /* number of request bytes left to upload */ + + char **push_headers; /* allocated array */ + size_t push_headers_used; /* number of entries filled in */ + size_t push_headers_alloc; /* number of entries allocated */ + + int status_code; /* HTTP response status code */ + uint32_t error; /* stream error code */ + uint32_t local_window_size; /* the local recv window size */ + bool resp_hds_complete; /* we have a complete, final response */ + bool closed; /* TRUE on stream close */ + bool reset; /* TRUE on stream reset */ + bool close_handled; /* TRUE if stream closure is handled by libcurl */ + bool bodystarted; + bool send_closed; /* transfer is done sending, we might have still + buffered data in stream->sendbuf to upload. */ +}; + +#define H2_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \ + ((struct HTTP *)(d)->req.p.http)->h2_ctx \ + : NULL)) +#define H2_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h2_ctx +#define H2_STREAM_ID(d) (H2_STREAM_CTX(d)? \ + H2_STREAM_CTX(d)->id : -2) + +/* + * Mark this transfer to get "drained". + */ +static void drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct stream_ctx *stream) +{ + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(!stream->send_closed && + (stream->upload_left || stream->upload_blocked_len)) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x", + stream->id, bits); + data->state.select_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +static CURLcode http2_data_setup(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct stream_ctx **pstream) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream; + + (void)cf; + DEBUGASSERT(data); + if(!data->req.p.http) { + failf(data, "initialization failure, transfer not http initialized"); + return CURLE_FAILED_INIT; + } + stream = H2_STREAM_CTX(data); + if(stream) { + *pstream = stream; + return CURLE_OK; + } + + stream = calloc(1, sizeof(*stream)); + if(!stream) + return CURLE_OUT_OF_MEMORY; + + stream->id = -1; + Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, + H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); + Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, + H2_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); + Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); + Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST); + stream->resp_hds_len = 0; + stream->bodystarted = FALSE; + stream->status_code = -1; + stream->closed = FALSE; + stream->close_handled = FALSE; + stream->error = NGHTTP2_NO_ERROR; + stream->local_window_size = H2_STREAM_WINDOW_SIZE; + stream->upload_left = 0; + + H2_STREAM_LCTX(data) = stream; + *pstream = stream; + return CURLE_OK; +} + +static void http2_data_done(struct Curl_cfilter *cf, + struct Curl_easy *data, bool premature) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H2_STREAM_CTX(data); + + DEBUGASSERT(ctx); + (void)premature; + if(!stream) + return; + + if(ctx->h2) { + bool flush_egress = FALSE; + /* returns error if stream not known, which is fine here */ + (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL); + + if(!stream->closed && stream->id > 0) { + /* RST_STREAM */ + CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream", + stream->id); + stream->closed = TRUE; + stream->reset = TRUE; + stream->send_closed = TRUE; + nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, + stream->id, NGHTTP2_STREAM_CLOSED); + flush_egress = TRUE; + } + if(!Curl_bufq_is_empty(&stream->recvbuf)) { + /* Anything in the recvbuf is still being counted + * in stream and connection window flow control. Need + * to free that space or the connection window might get + * exhausted eventually. */ + nghttp2_session_consume(ctx->h2, stream->id, + Curl_bufq_len(&stream->recvbuf)); + /* give WINDOW_UPATE a chance to be sent, but ignore any error */ + flush_egress = TRUE; + } + + if(flush_egress) + nghttp2_session_send(ctx->h2); + } + + Curl_bufq_free(&stream->sendbuf); + Curl_bufq_free(&stream->recvbuf); + Curl_h1_req_parse_free(&stream->h1); + Curl_dynhds_free(&stream->resp_trailers); + if(stream->push_headers) { + /* if they weren't used and then freed before */ + for(; stream->push_headers_used > 0; --stream->push_headers_used) { + free(stream->push_headers[stream->push_headers_used - 1]); + } + free(stream->push_headers); + stream->push_headers = NULL; + } + + free(stream); + H2_STREAM_LCTX(data) = NULL; +} + +static int h2_client_new(struct Curl_cfilter *cf, + nghttp2_session_callbacks *cbs) +{ + struct cf_h2_ctx *ctx = cf->ctx; + nghttp2_option *o; + + int rc = nghttp2_option_new(&o); + if(rc) + return rc; + /* We handle window updates ourself to enforce buffer limits */ + nghttp2_option_set_no_auto_window_update(o, 1); +#if NGHTTP2_VERSION_NUM >= 0x013200 + /* with 1.50.0 */ + /* turn off RFC 9113 leading and trailing white spaces validation against + HTTP field value. */ + nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1); +#endif + rc = nghttp2_session_client_new2(&ctx->h2, cbs, cf, o); + nghttp2_option_del(o); + return rc; +} + +static ssize_t nw_in_reader(void *reader_ctx, + unsigned char *buf, size_t buflen, + CURLcode *err) +{ + struct Curl_cfilter *cf = reader_ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + + return Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err); +} + +static ssize_t nw_out_writer(void *writer_ctx, + const unsigned char *buf, size_t buflen, + CURLcode *err) +{ + struct Curl_cfilter *cf = writer_ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + + if(data) { + ssize_t nwritten = Curl_conn_cf_send(cf->next, data, + (const char *)buf, buflen, err); + if(nwritten > 0) + CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten); + return nwritten; + } + return 0; +} + +static ssize_t send_callback(nghttp2_session *h2, + const uint8_t *mem, size_t length, int flags, + void *userp); +static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, + void *userp); +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, + void *userp); +#endif +static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const uint8_t *mem, size_t len, void *userp); +static int on_stream_close(nghttp2_session *session, int32_t stream_id, + uint32_t error_code, void *userp); +static int on_begin_headers(nghttp2_session *session, + const nghttp2_frame *frame, void *userp); +static int on_header(nghttp2_session *session, const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, + void *userp); +static int error_callback(nghttp2_session *session, const char *msg, + size_t len, void *userp); + +/* + * Initialize the cfilter context + */ +static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool via_h1_upgrade) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream; + CURLcode result = CURLE_OUT_OF_MEMORY; + int rc; + nghttp2_session_callbacks *cbs = NULL; + + DEBUGASSERT(!ctx->h2); + Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES); + Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0); + Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0); + ctx->last_stream_id = 2147483647; + + rc = nghttp2_session_callbacks_new(&cbs); + if(rc) { + failf(data, "Couldn't initialize nghttp2 callbacks"); + goto out; + } + + nghttp2_session_callbacks_set_send_callback(cbs, send_callback); + nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send); +#endif + nghttp2_session_callbacks_set_on_data_chunk_recv_callback( + cbs, on_data_chunk_recv); + nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close); + nghttp2_session_callbacks_set_on_begin_headers_callback( + cbs, on_begin_headers); + nghttp2_session_callbacks_set_on_header_callback(cbs, on_header); + nghttp2_session_callbacks_set_error_callback(cbs, error_callback); + + /* The nghttp2 session is not yet setup, do it */ + rc = h2_client_new(cf, cbs); + if(rc) { + failf(data, "Couldn't initialize nghttp2"); + goto out; + } + ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS; + + if(via_h1_upgrade) { + /* HTTP/1.1 Upgrade issued. H2 Settings have already been submitted + * in the H1 request and we upgrade from there. This stream + * is opened implicitly as #1. */ + uint8_t binsettings[H2_BINSETTINGS_LEN]; + ssize_t binlen; /* length of the binsettings data */ + + binlen = populate_binsettings(binsettings, data); + if(binlen <= 0) { + failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); + result = CURLE_FAILED_INIT; + goto out; + } + + result = http2_data_setup(cf, data, &stream); + if(result) + goto out; + DEBUGASSERT(stream); + stream->id = 1; + /* queue SETTINGS frame (again) */ + rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen, + data->state.httpreq == HTTPREQ_HEAD, + NULL); + if(rc) { + failf(data, "nghttp2_session_upgrade2() failed: %s(%d)", + nghttp2_strerror(rc), rc); + result = CURLE_HTTP2; + goto out; + } + + rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id, + data); + if(rc) { + infof(data, "http/2: failed to set user_data for stream %u", + stream->id); + DEBUGASSERT(0); + } + CURL_TRC_CF(data, cf, "created session via Upgrade"); + } + else { + nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN]; + int ivlen; + + ivlen = populate_settings(iv, data); + rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE, + iv, ivlen); + if(rc) { + failf(data, "nghttp2_submit_settings() failed: %s(%d)", + nghttp2_strerror(rc), rc); + result = CURLE_HTTP2; + goto out; + } + } + + rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0, + HTTP2_HUGE_WINDOW_SIZE); + if(rc) { + failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", + nghttp2_strerror(rc), rc); + result = CURLE_HTTP2; + goto out; + } + + /* all set, traffic will be send on connect */ + result = CURLE_OK; + CURL_TRC_CF(data, cf, "[0] created h2 session%s", + via_h1_upgrade? " (via h1 upgrade)" : ""); + +out: + if(cbs) + nghttp2_session_callbacks_del(cbs); + return result; +} + +/* + * Returns nonzero if current HTTP/2 session should be closed. + */ +static int should_close_session(struct cf_h2_ctx *ctx) +{ + return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) && + !nghttp2_session_want_write(ctx->h2); +} + +/* + * Processes pending input left in network input buffer. + * This function returns 0 if it succeeds, or -1 and error code will + * be assigned to *err. + */ +static int h2_process_pending_input(struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLcode *err) +{ + struct cf_h2_ctx *ctx = cf->ctx; + const unsigned char *buf; + size_t blen; + ssize_t rv; + + while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) { + + rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen); + if(rv < 0) { + failf(data, + "process_pending_input: nghttp2_session_mem_recv() returned " + "%zd:%s", rv, nghttp2_strerror((int)rv)); + *err = CURLE_RECV_ERROR; + return -1; + } + Curl_bufq_skip(&ctx->inbufq, (size_t)rv); + if(Curl_bufq_is_empty(&ctx->inbufq)) { + break; + } + else { + CURL_TRC_CF(data, cf, "process_pending_input: %zu bytes left " + "in connection buffer", Curl_bufq_len(&ctx->inbufq)); + } + } + + if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { + /* No more requests are allowed in the current session, so + the connection may not be reused. This is set when a + GOAWAY frame has been received or when the limit of stream + identifiers has been reached. */ + connclose(cf->conn, "http/2: No new requests allowed"); + } + + return 0; +} + +/* + * The server may send us data at any point (e.g. PING frames). Therefore, + * we cannot assume that an HTTP/2 socket is dead just because it is readable. + * + * Check the lower filters first and, if successful, peek at the socket + * and distinguish between closed and data. + */ +static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data, + bool *input_pending) +{ + struct cf_h2_ctx *ctx = cf->ctx; + bool alive = TRUE; + + *input_pending = FALSE; + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + return FALSE; + + if(*input_pending) { + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + CURLcode result; + ssize_t nread = -1; + + *input_pending = FALSE; + nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); + if(nread != -1) { + CURL_TRC_CF(data, cf, "%zd bytes stray data read before trying " + "h2 connection", nread); + if(h2_process_pending_input(cf, data, &result) < 0) + /* immediate error, considered dead */ + alive = FALSE; + else { + alive = !should_close_session(ctx); + } + } + else if(result != CURLE_AGAIN) { + /* the read failed so let's say this is dead anyway */ + alive = FALSE; + } + } + + return alive; +} + +static CURLcode http2_send_ping(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + int rc; + + rc = nghttp2_submit_ping(ctx->h2, 0, ZERO_NULL); + if(rc) { + failf(data, "nghttp2_submit_ping() failed: %s(%d)", + nghttp2_strerror(rc), rc); + return CURLE_HTTP2; + } + + rc = nghttp2_session_send(ctx->h2); + if(rc) { + failf(data, "nghttp2_session_send() failed: %s(%d)", + nghttp2_strerror(rc), rc); + return CURLE_SEND_ERROR; + } + return CURLE_OK; +} + +/* + * Store nghttp2 version info in this buffer. + */ +void Curl_http2_ver(char *p, size_t len) +{ + nghttp2_info *h2 = nghttp2_version(0); + (void)msnprintf(p, len, "nghttp2/%s", h2->version_str); +} + +static CURLcode nw_out_flush(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + ssize_t nwritten; + CURLcode result; + + (void)data; + if(Curl_bufq_is_empty(&ctx->outbufq)) + return CURLE_OK; + + nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result); + if(nwritten < 0) { + if(result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN", + Curl_bufq_len(&ctx->outbufq)); + ctx->nw_out_blocked = 1; + } + return result; + } + return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN; +} + +/* + * The implementation of nghttp2_send_callback type. Here we write |data| with + * size |length| to the network and return the number of bytes actually + * written. See the documentation of nghttp2_send_callback for the details. + */ +static ssize_t send_callback(nghttp2_session *h2, + const uint8_t *buf, size_t blen, int flags, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result = CURLE_OK; + + (void)h2; + (void)flags; + DEBUGASSERT(data); + + nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, + nw_out_writer, cf, &result); + if(nwritten < 0) { + if(result == CURLE_AGAIN) { + ctx->nw_out_blocked = 1; + return NGHTTP2_ERR_WOULDBLOCK; + } + failf(data, "Failed sending HTTP2 data"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + if(!nwritten) { + ctx->nw_out_blocked = 1; + return NGHTTP2_ERR_WOULDBLOCK; + } + return nwritten; +} + + +/* We pass a pointer to this struct in the push callback, but the contents of + the struct are hidden from the user. */ +struct curl_pushheaders { + struct Curl_easy *data; + const nghttp2_push_promise *frame; +}; + +/* + * push header access function. Only to be used from within the push callback + */ +char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) +{ + /* Verify that we got a good easy handle in the push header struct, mostly to + detect rubbish input fast(er). */ + if(!h || !GOOD_EASY_HANDLE(h->data)) + return NULL; + else { + struct stream_ctx *stream = H2_STREAM_CTX(h->data); + if(stream && num < stream->push_headers_used) + return stream->push_headers[num]; + } + return NULL; +} + +/* + * push header access function. Only to be used from within the push callback + */ +char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) +{ + struct stream_ctx *stream; + size_t len; + size_t i; + /* Verify that we got a good easy handle in the push header struct, + mostly to detect rubbish input fast(er). Also empty header name + is just a rubbish too. We have to allow ":" at the beginning of + the header, but header == ":" must be rejected. If we have ':' in + the middle of header, it could be matched in middle of the value, + this is because we do prefix match.*/ + if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || + !strcmp(header, ":") || strchr(header + 1, ':')) + return NULL; + + stream = H2_STREAM_CTX(h->data); + if(!stream) + return NULL; + + len = strlen(header); + for(i = 0; ipush_headers_used; i++) { + if(!strncmp(header, stream->push_headers[i], len)) { + /* sub-match, make sure that it is followed by a colon */ + if(stream->push_headers[i][len] != ':') + continue; + return &stream->push_headers[i][len + 1]; + } + } + return NULL; +} + +static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct Curl_easy *second = curl_easy_duphandle(data); + if(second) { + /* setup the request struct */ + struct HTTP *http = calloc(1, sizeof(struct HTTP)); + if(!http) { + (void)Curl_close(&second); + } + else { + struct stream_ctx *second_stream; + + second->req.p.http = http; + http2_data_setup(cf, second, &second_stream); + second->state.priority.weight = data->state.priority.weight; + } + } + return second; +} + +static int set_transfer_url(struct Curl_easy *data, + struct curl_pushheaders *hp) +{ + const char *v; + CURLUcode uc; + char *url = NULL; + int rc = 0; + CURLU *u = curl_url(); + + if(!u) + return 5; + + v = curl_pushheader_byname(hp, HTTP_PSEUDO_SCHEME); + if(v) { + uc = curl_url_set(u, CURLUPART_SCHEME, v, 0); + if(uc) { + rc = 1; + goto fail; + } + } + + v = curl_pushheader_byname(hp, HTTP_PSEUDO_AUTHORITY); + if(v) { + uc = Curl_url_set_authority(u, v, CURLU_DISALLOW_USER); + if(uc) { + rc = 2; + goto fail; + } + } + + v = curl_pushheader_byname(hp, HTTP_PSEUDO_PATH); + if(v) { + uc = curl_url_set(u, CURLUPART_PATH, v, 0); + if(uc) { + rc = 3; + goto fail; + } + } + + uc = curl_url_get(u, CURLUPART_URL, &url, 0); + if(uc) + rc = 4; +fail: + curl_url_cleanup(u); + if(rc) + return rc; + + if(data->state.url_alloc) + free(data->state.url); + data->state.url_alloc = TRUE; + data->state.url = url; + return 0; +} + +static void discard_newhandle(struct Curl_cfilter *cf, + struct Curl_easy *newhandle) +{ + if(!newhandle->req.p.http) { + http2_data_done(cf, newhandle, TRUE); + newhandle->req.p.http = NULL; + } + (void)Curl_close(&newhandle); +} + +static int push_promise(struct Curl_cfilter *cf, + struct Curl_easy *data, + const nghttp2_push_promise *frame) +{ + struct cf_h2_ctx *ctx = cf->ctx; + int rv; /* one of the CURL_PUSH_* defines */ + + CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE received", + frame->promised_stream_id); + if(data->multi->push_cb) { + struct stream_ctx *stream; + struct stream_ctx *newstream; + struct curl_pushheaders heads; + CURLMcode rc; + CURLcode result; + size_t i; + /* clone the parent */ + struct Curl_easy *newhandle = h2_duphandle(cf, data); + if(!newhandle) { + infof(data, "failed to duplicate handle"); + rv = CURL_PUSH_DENY; /* FAIL HARD */ + goto fail; + } + + heads.data = data; + heads.frame = frame; + /* ask the application */ + CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ask application"); + + stream = H2_STREAM_CTX(data); + if(!stream) { + failf(data, "Internal NULL stream"); + discard_newhandle(cf, newhandle); + rv = CURL_PUSH_DENY; + goto fail; + } + + rv = set_transfer_url(newhandle, &heads); + if(rv) { + discard_newhandle(cf, newhandle); + rv = CURL_PUSH_DENY; + goto fail; + } + + result = http2_data_setup(cf, newhandle, &newstream); + if(result) { + failf(data, "error setting up stream: %d", result); + discard_newhandle(cf, newhandle); + rv = CURL_PUSH_DENY; + goto fail; + } + DEBUGASSERT(stream); + + Curl_set_in_callback(data, true); + rv = data->multi->push_cb(data, newhandle, + stream->push_headers_used, &heads, + data->multi->push_userp); + Curl_set_in_callback(data, false); + + /* free the headers again */ + for(i = 0; ipush_headers_used; i++) + free(stream->push_headers[i]); + free(stream->push_headers); + stream->push_headers = NULL; + stream->push_headers_used = 0; + + if(rv) { + DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT)); + /* denied, kill off the new handle again */ + discard_newhandle(cf, newhandle); + goto fail; + } + + newstream->id = frame->promised_stream_id; + newhandle->req.maxdownload = -1; + newhandle->req.size = -1; + + /* approved, add to the multi handle and immediately switch to PERFORM + state with the given connection !*/ + rc = Curl_multi_add_perform(data->multi, newhandle, cf->conn); + if(rc) { + infof(data, "failed to add handle to multi"); + discard_newhandle(cf, newhandle); + rv = CURL_PUSH_DENY; + goto fail; + } + + rv = nghttp2_session_set_stream_user_data(ctx->h2, + newstream->id, + newhandle); + if(rv) { + infof(data, "failed to set user_data for stream %u", + newstream->id); + DEBUGASSERT(0); + rv = CURL_PUSH_DENY; + goto fail; + } + } + else { + CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ignore it"); + rv = CURL_PUSH_DENY; + } +fail: + return rv; +} + +static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char *buf, size_t blen) +{ + struct stream_ctx *stream = H2_STREAM_CTX(data); + ssize_t nwritten; + CURLcode result; + + (void)cf; + nwritten = Curl_bufq_write(&stream->recvbuf, + (const unsigned char *)buf, blen, &result); + if(nwritten < 0) + return result; + stream->resp_hds_len += (size_t)nwritten; + DEBUGASSERT((size_t)nwritten == blen); + return CURLE_OK; +} + +static CURLcode on_stream_frame(struct Curl_cfilter *cf, + struct Curl_easy *data, + const nghttp2_frame *frame) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H2_STREAM_CTX(data); + int32_t stream_id = frame->hd.stream_id; + CURLcode result; + size_t rbuflen; + int rv; + + if(!stream) { + CURL_TRC_CF(data, cf, "[%d] No stream_ctx set", stream_id); + return CURLE_FAILED_INIT; + } + + switch(frame->hd.type) { + case NGHTTP2_DATA: + rbuflen = Curl_bufq_len(&stream->recvbuf); + CURL_TRC_CF(data, cf, "[%d] DATA, buffered=%zu, window=%d/%d", + stream_id, rbuflen, + nghttp2_session_get_stream_effective_recv_data_length( + ctx->h2, stream->id), + nghttp2_session_get_stream_effective_local_window_size( + ctx->h2, stream->id)); + /* If !body started on this stream, then receiving DATA is illegal. */ + if(!stream->bodystarted) { + rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, + stream_id, NGHTTP2_PROTOCOL_ERROR); + + if(nghttp2_is_fatal(rv)) { + return CURLE_RECV_ERROR; + } + } + if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + drain_stream(cf, data, stream); + } + else if(rbuflen > stream->local_window_size) { + int32_t wsize = nghttp2_session_get_stream_local_window_size( + ctx->h2, stream->id); + if(wsize > 0 && (uint32_t)wsize != stream->local_window_size) { + /* H2 flow control is not absolute, as the server might not have the + * same view, yet. When we receive more than we want, we enforce + * the local window size again to make nghttp2 send WINDOW_UPATEs + * accordingly. */ + nghttp2_session_set_local_window_size(ctx->h2, + NGHTTP2_FLAG_NONE, + stream->id, + stream->local_window_size); + } + } + break; + case NGHTTP2_HEADERS: + if(stream->bodystarted) { + /* Only valid HEADERS after body started is trailer HEADERS. We + buffer them in on_header callback. */ + break; + } + + /* nghttp2 guarantees that :status is received, and we store it to + stream->status_code. Fuzzing has proven this can still be reached + without status code having been set. */ + if(stream->status_code == -1) + return CURLE_RECV_ERROR; + + /* Only final status code signals the end of header */ + if(stream->status_code / 100 != 1) { + stream->bodystarted = TRUE; + stream->status_code = -1; + } + + result = recvbuf_write_hds(cf, data, STRCONST("\r\n")); + if(result) + return result; + + if(stream->status_code / 100 != 1) { + stream->resp_hds_complete = TRUE; + } + drain_stream(cf, data, stream); + break; + case NGHTTP2_PUSH_PROMISE: + rv = push_promise(cf, data, &frame->push_promise); + if(rv) { /* deny! */ + DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT)); + rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, + frame->push_promise.promised_stream_id, + NGHTTP2_CANCEL); + if(nghttp2_is_fatal(rv)) + return CURLE_SEND_ERROR; + else if(rv == CURL_PUSH_ERROROUT) { + CURL_TRC_CF(data, cf, "[%d] fail in PUSH_PROMISE received", + stream_id); + return CURLE_RECV_ERROR; + } + } + break; + case NGHTTP2_RST_STREAM: + stream->closed = TRUE; + if(frame->rst_stream.error_code) { + stream->reset = TRUE; + } + stream->send_closed = TRUE; + drain_stream(cf, data, stream); + break; + case NGHTTP2_WINDOW_UPDATE: + if(CURL_WANT_SEND(data)) { + drain_stream(cf, data, stream); + } + break; + default: + break; + } + return CURLE_OK; +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen) +{ + switch(frame->hd.type) { + case NGHTTP2_DATA: { + return msnprintf(buffer, blen, + "FRAME[DATA, len=%d, eos=%d, padlen=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), + (int)frame->data.padlen); + } + case NGHTTP2_HEADERS: { + return msnprintf(buffer, blen, + "FRAME[HEADERS, len=%d, hend=%d, eos=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); + } + case NGHTTP2_PRIORITY: { + return msnprintf(buffer, blen, + "FRAME[PRIORITY, len=%d, flags=%d]", + (int)frame->hd.length, frame->hd.flags); + } + case NGHTTP2_RST_STREAM: { + return msnprintf(buffer, blen, + "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]", + (int)frame->hd.length, frame->hd.flags, + frame->rst_stream.error_code); + } + case NGHTTP2_SETTINGS: { + if(frame->hd.flags & NGHTTP2_FLAG_ACK) { + return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]"); + } + return msnprintf(buffer, blen, + "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); + } + case NGHTTP2_PUSH_PROMISE: { + return msnprintf(buffer, blen, + "FRAME[PUSH_PROMISE, len=%d, hend=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); + } + case NGHTTP2_PING: { + return msnprintf(buffer, blen, + "FRAME[PING, len=%d, ack=%d]", + (int)frame->hd.length, + frame->hd.flags&NGHTTP2_FLAG_ACK); + } + case NGHTTP2_GOAWAY: { + char scratch[128]; + size_t s_len = sizeof(scratch)/sizeof(scratch[0]); + size_t len = (frame->goaway.opaque_data_len < s_len)? + frame->goaway.opaque_data_len : s_len-1; + if(len) + memcpy(scratch, frame->goaway.opaque_data, len); + scratch[len] = '\0'; + return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', " + "last_stream=%d]", frame->goaway.error_code, + scratch, frame->goaway.last_stream_id); + } + case NGHTTP2_WINDOW_UPDATE: { + return msnprintf(buffer, blen, + "FRAME[WINDOW_UPDATE, incr=%d]", + frame->window_update.window_size_increment); + } + default: + return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]", + frame->hd.type, (int)frame->hd.length, + frame->hd.flags); + } +} + +static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + + (void)session; + DEBUGASSERT(data); + if(data && Curl_trc_cf_is_verbose(cf, data)) { + char buffer[256]; + int len; + len = fr_print(frame, buffer, sizeof(buffer)-1); + buffer[len] = 0; + CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer); + } + return 0; +} +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ + +static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct cf_h2_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf), *data_s; + int32_t stream_id = frame->hd.stream_id; + + DEBUGASSERT(data); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_cf_is_verbose(cf, data)) { + char buffer[256]; + int len; + len = fr_print(frame, buffer, sizeof(buffer)-1); + buffer[len] = 0; + CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer); + } +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ + + if(!stream_id) { + /* stream ID zero is for connection-oriented stuff */ + DEBUGASSERT(data); + switch(frame->hd.type) { + case NGHTTP2_SETTINGS: { + if(!(frame->hd.flags & NGHTTP2_FLAG_ACK)) { + uint32_t max_conn = ctx->max_concurrent_streams; + ctx->max_concurrent_streams = nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); + ctx->enable_push = nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_ENABLE_PUSH) != 0; + CURL_TRC_CF(data, cf, "[0] MAX_CONCURRENT_STREAMS: %d", + ctx->max_concurrent_streams); + CURL_TRC_CF(data, cf, "[0] ENABLE_PUSH: %s", + ctx->enable_push ? "TRUE" : "false"); + if(data && max_conn != ctx->max_concurrent_streams) { + /* only signal change if the value actually changed */ + CURL_TRC_CF(data, cf, "[0] notify MAX_CONCURRENT_STREAMS: %u", + ctx->max_concurrent_streams); + Curl_multi_connchanged(data->multi); + } + /* Since the initial stream window is 64K, a request might be on HOLD, + * due to exhaustion. The (initial) SETTINGS may announce a much larger + * window and *assume* that we treat this like a WINDOW_UPDATE. Some + * servers send an explicit WINDOW_UPDATE, but not all seem to do that. + * To be safe, we UNHOLD a stream in order not to stall. */ + if(CURL_WANT_SEND(data)) { + struct stream_ctx *stream = H2_STREAM_CTX(data); + if(stream) + drain_stream(cf, data, stream); + } + } + break; + } + case NGHTTP2_GOAWAY: + ctx->goaway = TRUE; + ctx->goaway_error = frame->goaway.error_code; + ctx->last_stream_id = frame->goaway.last_stream_id; + if(data) { + infof(data, "received GOAWAY, error=%d, last_stream=%u", + ctx->goaway_error, ctx->last_stream_id); + Curl_multi_connchanged(data->multi); + } + break; + default: + break; + } + return 0; + } + + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) { + CURL_TRC_CF(data, cf, "[%d] No Curl_easy associated", stream_id); + return 0; + } + + return on_stream_frame(cf, data_s, frame)? NGHTTP2_ERR_CALLBACK_FAILURE : 0; +} + +static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const uint8_t *mem, size_t len, void *userp) +{ + struct Curl_cfilter *cf = userp; + struct stream_ctx *stream; + struct Curl_easy *data_s; + ssize_t nwritten; + CURLcode result; + (void)flags; + + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ + DEBUGASSERT(CF_DATA_CURRENT(cf)); + + /* get the stream from the hash based on Stream ID */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) { + /* Receiving a Stream ID not in the hash should not happen - unless + we have aborted a transfer artificially and there were more data + in the pipeline. Silently ignore. */ + CURL_TRC_CF(CF_DATA_CURRENT(cf), cf, "[%d] Data for unknown", + stream_id); + /* consumed explicitly as no one will read it */ + nghttp2_session_consume(session, stream_id, len); + return 0; + } + + stream = H2_STREAM_CTX(data_s); + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + nwritten = Curl_bufq_write(&stream->recvbuf, mem, len, &result); + if(nwritten < 0) { + if(result != CURLE_AGAIN) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + nwritten = 0; + } + + /* if we receive data for another handle, wake that up */ + drain_stream(cf, data_s, stream); + + DEBUGASSERT((size_t)nwritten == len); + return 0; +} + +static int on_stream_close(nghttp2_session *session, int32_t stream_id, + uint32_t error_code, void *userp) +{ + struct Curl_cfilter *cf = userp; + struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf); + struct stream_ctx *stream; + int rv; + (void)session; + + DEBUGASSERT(call_data); + /* get the stream from the hash based on Stream ID, stream ID zero is for + connection-oriented stuff */ + data_s = stream_id? + nghttp2_session_get_stream_user_data(session, stream_id) : NULL; + if(!data_s) { + CURL_TRC_CF(call_data, cf, + "[%d] on_stream_close, no easy set on stream", stream_id); + return 0; + } + if(!GOOD_EASY_HANDLE(data_s)) { + /* nghttp2 still has an easy registered for the stream which has + * been freed be libcurl. This points to a code path that does not + * trigger DONE or DETACH events as it must. */ + CURL_TRC_CF(call_data, cf, + "[%d] on_stream_close, not a GOOD easy on stream", stream_id); + (void)nghttp2_session_set_stream_user_data(session, stream_id, 0); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + stream = H2_STREAM_CTX(data_s); + if(!stream) { + CURL_TRC_CF(data_s, cf, + "[%d] on_stream_close, GOOD easy but no stream", stream_id); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + stream->closed = TRUE; + stream->error = error_code; + if(stream->error) { + stream->reset = TRUE; + stream->send_closed = TRUE; + } + + if(stream->error) + CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)", + stream_id, nghttp2_http2_strerror(error_code), error_code); + else + CURL_TRC_CF(data_s, cf, "[%d] CLOSED", stream_id); + drain_stream(cf, data_s, stream); + + /* remove `data_s` from the nghttp2 stream */ + rv = nghttp2_session_set_stream_user_data(session, stream_id, 0); + if(rv) { + infof(data_s, "http/2: failed to clear user_data for stream %u", + stream_id); + DEBUGASSERT(0); + } + return 0; +} + +static int on_begin_headers(nghttp2_session *session, + const nghttp2_frame *frame, void *userp) +{ + struct Curl_cfilter *cf = userp; + struct stream_ctx *stream; + struct Curl_easy *data_s = NULL; + + (void)cf; + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(!data_s) { + return 0; + } + + if(frame->hd.type != NGHTTP2_HEADERS) { + return 0; + } + + stream = H2_STREAM_CTX(data_s); + if(!stream || !stream->bodystarted) { + return 0; + } + + return 0; +} + +/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */ +static int on_header(nghttp2_session *session, const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct stream_ctx *stream; + struct Curl_easy *data_s; + int32_t stream_id = frame->hd.stream_id; + CURLcode result; + (void)flags; + + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ + + /* get the stream from the hash based on Stream ID */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream = H2_STREAM_CTX(data_s); + if(!stream) { + failf(data_s, "Internal NULL stream"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + /* Store received PUSH_PROMISE headers to be used when the subsequent + PUSH_PROMISE callback comes */ + if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { + char *h; + + if(!strcmp(HTTP_PSEUDO_AUTHORITY, (const char *)name)) { + /* pseudo headers are lower case */ + int rc = 0; + char *check = aprintf("%s:%d", cf->conn->host.name, + cf->conn->remote_port); + if(!check) + /* no memory */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + if(!strcasecompare(check, (const char *)value) && + ((cf->conn->remote_port != cf->conn->given->defport) || + !strcasecompare(cf->conn->host.name, (const char *)value))) { + /* This is push is not for the same authority that was asked for in + * the URL. RFC 7540 section 8.2 says: "A client MUST treat a + * PUSH_PROMISE for which the server is not authoritative as a stream + * error of type PROTOCOL_ERROR." + */ + (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, + stream_id, NGHTTP2_PROTOCOL_ERROR); + rc = NGHTTP2_ERR_CALLBACK_FAILURE; + } + free(check); + if(rc) + return rc; + } + + if(!stream->push_headers) { + stream->push_headers_alloc = 10; + stream->push_headers = malloc(stream->push_headers_alloc * + sizeof(char *)); + if(!stream->push_headers) + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + stream->push_headers_used = 0; + } + else if(stream->push_headers_used == + stream->push_headers_alloc) { + char **headp; + if(stream->push_headers_alloc > 1000) { + /* this is beyond crazy many headers, bail out */ + failf(data_s, "Too many PUSH_PROMISE headers"); + Curl_safefree(stream->push_headers); + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + stream->push_headers_alloc *= 2; + headp = Curl_saferealloc(stream->push_headers, + stream->push_headers_alloc * sizeof(char *)); + if(!headp) { + stream->push_headers = NULL; + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + stream->push_headers = headp; + } + h = aprintf("%s:%s", name, value); + if(h) + stream->push_headers[stream->push_headers_used++] = h; + return 0; + } + + if(stream->bodystarted) { + /* This is a trailer */ + CURL_TRC_CF(data_s, cf, "[%d] trailer: %.*s: %.*s", + stream->id, (int)namelen, name, (int)valuelen, value); + result = Curl_dynhds_add(&stream->resp_trailers, + (const char *)name, namelen, + (const char *)value, valuelen); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + return 0; + } + + if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 && + memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) { + /* nghttp2 guarantees :status is received first and only once. */ + char buffer[32]; + result = Curl_http_decode_status(&stream->status_code, + (const char *)value, valuelen); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r", + stream->status_code); + result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + result = recvbuf_write_hds(cf, data_s, STRCONST("HTTP/2 ")); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + /* the space character after the status code is mandatory */ + result = recvbuf_write_hds(cf, data_s, STRCONST(" \r\n")); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + /* if we receive data for another handle, wake that up */ + if(CF_DATA_CURRENT(cf) != data_s) + Curl_expire(data_s, 0, EXPIRE_RUN_NOW); + + CURL_TRC_CF(data_s, cf, "[%d] status: HTTP/2 %03d", + stream->id, stream->status_code); + return 0; + } + + /* nghttp2 guarantees that namelen > 0, and :status was already + received, and this is not pseudo-header field . */ + /* convert to an HTTP1-style header */ + result = recvbuf_write_hds(cf, data_s, (const char *)name, namelen); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + result = recvbuf_write_hds(cf, data_s, STRCONST(": ")); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + result = recvbuf_write_hds(cf, data_s, STRCONST("\r\n")); + if(result) + return NGHTTP2_ERR_CALLBACK_FAILURE; + /* if we receive data for another handle, wake that up */ + if(CF_DATA_CURRENT(cf) != data_s) + Curl_expire(data_s, 0, EXPIRE_RUN_NOW); + + CURL_TRC_CF(data_s, cf, "[%d] header: %.*s: %.*s", + stream->id, (int)namelen, name, (int)valuelen, value); + + return 0; /* 0 is successful */ +} + +static ssize_t req_body_read_callback(nghttp2_session *session, + int32_t stream_id, + uint8_t *buf, size_t length, + uint32_t *data_flags, + nghttp2_data_source *source, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct Curl_easy *data_s; + struct stream_ctx *stream = NULL; + CURLcode result; + ssize_t nread; + (void)source; + + (void)cf; + if(stream_id) { + /* get the stream from the hash based on Stream ID, stream ID zero is for + connection-oriented stuff */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream = H2_STREAM_CTX(data_s); + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + else + return NGHTTP2_ERR_INVALID_ARGUMENT; + + nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result); + if(nread < 0) { + if(result != CURLE_AGAIN) + return NGHTTP2_ERR_CALLBACK_FAILURE; + nread = 0; + } + + if(nread > 0 && stream->upload_left != -1) + stream->upload_left -= nread; + + CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) left=%" + CURL_FORMAT_CURL_OFF_T " -> %zd, %d", + stream_id, length, stream->upload_left, nread, result); + + if(stream->upload_left == 0) + *data_flags = NGHTTP2_DATA_FLAG_EOF; + else if(nread == 0) + return NGHTTP2_ERR_DEFERRED; + + return nread; +} + +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +static int error_callback(nghttp2_session *session, + const char *msg, + size_t len, + void *userp) +{ + struct Curl_cfilter *cf = userp; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + (void)session; + failf(data, "%.*s", (int)len, msg); + return 0; +} +#endif + +/* + * Append headers to ask for an HTTP1.1 to HTTP2 upgrade. + */ +CURLcode Curl_http2_request_upgrade(struct dynbuf *req, + struct Curl_easy *data) +{ + CURLcode result; + char *base64; + size_t blen; + struct SingleRequest *k = &data->req; + uint8_t binsettings[H2_BINSETTINGS_LEN]; + ssize_t binlen; /* length of the binsettings data */ + + binlen = populate_binsettings(binsettings, data); + if(binlen <= 0) { + failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); + Curl_dyn_free(req); + return CURLE_FAILED_INIT; + } + + result = Curl_base64url_encode((const char *)binsettings, binlen, + &base64, &blen); + if(result) { + Curl_dyn_free(req); + return result; + } + + result = Curl_dyn_addf(req, + "Connection: Upgrade, HTTP2-Settings\r\n" + "Upgrade: %s\r\n" + "HTTP2-Settings: %s\r\n", + NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); + free(base64); + + k->upgr101 = UPGR101_H2; + + return result; +} + +static CURLcode http2_data_done_send(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct stream_ctx *stream = H2_STREAM_CTX(data); + + if(!ctx || !ctx->h2 || !stream) + goto out; + + CURL_TRC_CF(data, cf, "[%d] data done send", stream->id); + if(!stream->send_closed) { + stream->send_closed = TRUE; + if(stream->upload_left) { + /* we now know that everything that is buffered is all there is. */ + stream->upload_left = Curl_bufq_len(&stream->sendbuf); + /* resume sending here to trigger the callback to get called again so + that it can signal EOF to nghttp2 */ + (void)nghttp2_session_resume_data(ctx->h2, stream->id); + drain_stream(cf, data, stream); + } + } + +out: + return result; +} + +static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct stream_ctx *stream, + CURLcode *err) +{ + ssize_t rv = 0; + + if(stream->error == NGHTTP2_REFUSED_STREAM) { + CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new " + "connection", stream->id); + connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */ + data->state.refused_stream = TRUE; + *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ + return -1; + } + else if(stream->error != NGHTTP2_NO_ERROR) { + failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)", + stream->id, nghttp2_http2_strerror(stream->error), + stream->error); + *err = CURLE_HTTP2_STREAM; + return -1; + } + else if(stream->reset) { + failf(data, "HTTP/2 stream %u was reset", stream->id); + *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; + return -1; + } + + if(!stream->bodystarted) { + failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " + " all response header fields, treated as error", + stream->id); + *err = CURLE_HTTP2_STREAM; + return -1; + } + + if(Curl_dynhds_count(&stream->resp_trailers)) { + struct dynhds_entry *e; + struct dynbuf dbuf; + size_t i; + + *err = CURLE_OK; + Curl_dyn_init(&dbuf, DYN_TRAILERS); + for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) { + e = Curl_dynhds_getn(&stream->resp_trailers, i); + if(!e) + break; + Curl_dyn_reset(&dbuf); + *err = Curl_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a", + (int)e->namelen, e->name, + (int)e->valuelen, e->value); + if(*err) + break; + Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&dbuf), + Curl_dyn_len(&dbuf)); + *err = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER, + Curl_dyn_ptr(&dbuf), Curl_dyn_len(&dbuf)); + if(*err) + break; + } + Curl_dyn_free(&dbuf); + if(*err) + goto out; + } + + stream->close_handled = TRUE; + *err = CURLE_OK; + rv = 0; + +out: + CURL_TRC_CF(data, cf, "handle_stream_close -> %zd, %d", rv, *err); + return rv; +} + +static int sweight_wanted(const struct Curl_easy *data) +{ + /* 0 weight is not set by user and we take the nghttp2 default one */ + return data->set.priority.weight? + data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; +} + +static int sweight_in_effect(const struct Curl_easy *data) +{ + /* 0 weight is not set by user and we take the nghttp2 default one */ + return data->state.priority.weight? + data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT; +} + +/* + * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight + * and dependency to the peer. It also stores the updated values in the state + * struct. + */ + +static void h2_pri_spec(struct Curl_easy *data, + nghttp2_priority_spec *pri_spec) +{ + struct Curl_data_priority *prio = &data->set.priority; + struct stream_ctx *depstream = H2_STREAM_CTX(prio->parent); + int32_t depstream_id = depstream? depstream->id:0; + nghttp2_priority_spec_init(pri_spec, depstream_id, + sweight_wanted(data), + data->set.priority.exclusive); + data->state.priority = *prio; +} + +/* + * Check if there's been an update in the priority / + * dependency settings and if so it submits a PRIORITY frame with the updated + * info. + * Flush any out data pending in the network buffer. + */ +static CURLcode h2_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H2_STREAM_CTX(data); + int rv = 0; + + if(stream && stream->id > 0 && + ((sweight_wanted(data) != sweight_in_effect(data)) || + (data->set.priority.exclusive != data->state.priority.exclusive) || + (data->set.priority.parent != data->state.priority.parent)) ) { + /* send new weight and/or dependency */ + nghttp2_priority_spec pri_spec; + + h2_pri_spec(data, &pri_spec); + CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); + DEBUGASSERT(stream->id != -1); + rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, + stream->id, &pri_spec); + if(rv) + goto out; + } + + ctx->nw_out_blocked = 0; + while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2)) + rv = nghttp2_session_send(ctx->h2); + +out: + if(nghttp2_is_fatal(rv)) { + CURL_TRC_CF(data, cf, "nghttp2_session_send error (%s)%d", + nghttp2_strerror(rv), rv); + return CURLE_SEND_ERROR; + } + return nw_out_flush(cf, data); +} + +static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + struct stream_ctx *stream, + char *buf, size_t len, CURLcode *err) +{ + struct cf_h2_ctx *ctx = cf->ctx; + ssize_t nread = -1; + + *err = CURLE_AGAIN; + if(!Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) + goto out; + DEBUGASSERT(nread > 0); + } + + if(nread < 0) { + if(stream->closed) { + CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id); + nread = http2_handle_stream_close(cf, data, stream, err); + } + else if(stream->reset || + (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || + (ctx->goaway && ctx->last_stream_id < stream->id)) { + CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id); + *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; + nread = -1; + } + } + else if(nread == 0) { + *err = CURLE_AGAIN; + nread = -1; + } + +out: + if(nread < 0 && *err != CURLE_AGAIN) + CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d", + stream->id, len, nread, *err); + return nread; +} + +static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream; + CURLcode result = CURLE_OK; + ssize_t nread; + + /* Process network input buffer fist */ + if(!Curl_bufq_is_empty(&ctx->inbufq)) { + CURL_TRC_CF(data, cf, "Process %zu bytes in connection buffer", + Curl_bufq_len(&ctx->inbufq)); + if(h2_process_pending_input(cf, data, &result) < 0) + return result; + } + + /* Receive data from the "lower" filters, e.g. network until + * it is time to stop due to connection close or us not processing + * all network input */ + while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { + stream = H2_STREAM_CTX(data); + if(stream && (stream->closed || Curl_bufq_is_full(&stream->recvbuf))) { + /* We would like to abort here and stop processing, so that + * the transfer loop can handle the data/close here. However, + * this may leave data in underlying buffers that will not + * be consumed. */ + if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data)) + break; + } + + nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); + if(nread < 0) { + if(result != CURLE_AGAIN) { + failf(data, "Failed receiving HTTP2 data: %d(%s)", result, + curl_easy_strerror(result)); + return result; + } + break; + } + else if(nread == 0) { + CURL_TRC_CF(data, cf, "[0] ingress: connection closed"); + ctx->conn_closed = TRUE; + break; + } + else { + CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", + nread); + } + + if(h2_process_pending_input(cf, data, &result)) + return result; + } + + if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { + connclose(cf->conn, "GOAWAY received"); + } + + return CURLE_OK; +} + +static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H2_STREAM_CTX(data); + ssize_t nread = -1; + CURLcode result; + struct cf_call_data save; + + if(!stream) { + /* Abnormal call sequence: either this transfer has never opened a stream + * (unlikely) or the transfer has been done, cleaned up its resources, but + * a read() is called anyway. It is not clear what the calling sequence + * is for such a case. */ + failf(data, "[%zd-%zd], http/2 recv on a transfer never opened " + "or already cleared", (ssize_t)data->id, + (ssize_t)cf->conn->connection_id); + *err = CURLE_HTTP2; + return -1; + } + + CF_DATA_SAVE(save, cf, data); + + nread = stream_recv(cf, data, stream, buf, len, err); + if(nread < 0 && *err != CURLE_AGAIN) + goto out; + + if(nread < 0) { + *err = h2_progress_ingress(cf, data); + if(*err) + goto out; + + nread = stream_recv(cf, data, stream, buf, len, err); + } + + if(nread > 0) { + size_t data_consumed = (size_t)nread; + /* Now that we transferred this to the upper layer, we report + * the actual amount of DATA consumed to the H2 session, so + * that it adjusts stream flow control */ + if(stream->resp_hds_len >= data_consumed) { + stream->resp_hds_len -= data_consumed; /* no DATA */ + } + else { + if(stream->resp_hds_len) { + data_consumed -= stream->resp_hds_len; + stream->resp_hds_len = 0; + } + if(data_consumed) { + nghttp2_session_consume(ctx->h2, stream->id, data_consumed); + } + } + + if(stream->closed) { + CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id); + drain_stream(cf, data, stream); + } + } + +out: + result = h2_progress_egress(cf, data); + if(result == CURLE_AGAIN) { + /* pending data to send, need to be called again. Ideally, we'd + * monitor the socket for POLLOUT, but we might not be in SENDING + * transfer state any longer and are unable to make this happen. + */ + drain_stream(cf, data, stream); + } + else if(result) { + *err = result; + nread = -1; + } + CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, " + "buffered=%zu, window=%d/%d, connection %d/%d", + stream->id, len, nread, *err, + Curl_bufq_len(&stream->recvbuf), + nghttp2_session_get_stream_effective_recv_data_length( + ctx->h2, stream->id), + nghttp2_session_get_stream_effective_local_window_size( + ctx->h2, stream->id), + nghttp2_session_get_local_window_size(ctx->h2), + HTTP2_HUGE_WINDOW_SIZE); + + CF_DATA_RESTORE(cf, save); + return nread; +} + +static ssize_t h2_submit(struct stream_ctx **pstream, + struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = NULL; + struct dynhds h2_headers; + nghttp2_nv *nva = NULL; + const void *body = NULL; + size_t nheader, bodylen, i; + nghttp2_data_provider data_prd; + int32_t stream_id; + nghttp2_priority_spec pri_spec; + ssize_t nwritten; + + Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); + + *err = http2_data_setup(cf, data, &stream); + if(*err) { + nwritten = -1; + goto out; + } + + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + if(nwritten < 0) + goto out; + if(!stream->h1.done) { + /* need more data */ + goto out; + } + DEBUGASSERT(stream->h1.req); + + *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(*err) { + nwritten = -1; + goto out; + } + /* no longer needed */ + Curl_h1_req_parse_free(&stream->h1); + + nva = Curl_dynhds_to_nva(&h2_headers, &nheader); + if(!nva) { + *err = CURLE_OUT_OF_MEMORY; + nwritten = -1; + goto out; + } + + h2_pri_spec(data, &pri_spec); + if(!nghttp2_session_check_request_allowed(ctx->h2)) + CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)"); + + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + case HTTPREQ_PUT: + if(data->state.infilesize != -1) + stream->upload_left = data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown */ + + data_prd.read_callback = req_body_read_callback; + data_prd.source.ptr = NULL; + stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader, + &data_prd, data); + break; + default: + stream->upload_left = 0; /* no request body */ + stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader, + NULL, data); + } + + if(stream_id < 0) { + CURL_TRC_CF(data, cf, "send: nghttp2_submit_request error (%s)%u", + nghttp2_strerror(stream_id), stream_id); + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + +#define MAX_ACC 60000 /* <64KB to account for some overhead */ + if(Curl_trc_is_verbose(data)) { + size_t acc = 0; + + infof(data, "[HTTP/2] [%d] OPENED stream for %s", + stream_id, data->state.url); + for(i = 0; i < nheader; ++i) { + acc += nva[i].namelen + nva[i].valuelen; + + infof(data, "[HTTP/2] [%d] [%.*s: %.*s]", stream_id, + (int)nva[i].namelen, nva[i].name, + (int)nva[i].valuelen, nva[i].value); + } + + if(acc > MAX_ACC) { + infof(data, "[HTTP/2] Warning: The cumulative length of all " + "headers exceeds %d bytes and that could cause the " + "stream to be rejected.", MAX_ACC); + } + } + + stream->id = stream_id; + stream->local_window_size = H2_STREAM_WINDOW_SIZE; + if(data->set.max_recv_speed) { + /* We are asked to only receive `max_recv_speed` bytes per second. + * Let's limit our stream window size around that, otherwise the server + * will send in large bursts only. We make the window 50% larger to + * allow for data in flight and avoid stalling. */ + curl_off_t n = (((data->set.max_recv_speed - 1) / H2_CHUNK_SIZE) + 1); + n += CURLMAX((n/2), 1); + if(n < (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) && + n < (UINT_MAX / H2_CHUNK_SIZE)) { + stream->local_window_size = (uint32_t)n * H2_CHUNK_SIZE; + } + } + + body = (const char *)buf + nwritten; + bodylen = len - nwritten; + + if(bodylen) { + /* We have request body to send in DATA frame */ + ssize_t n = Curl_bufq_write(&stream->sendbuf, body, bodylen, err); + if(n < 0) { + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + nwritten += n; + } + +out: + CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d", + stream? stream->id : -1, nwritten, *err); + Curl_safefree(nva); + *pstream = stream; + Curl_dynhds_free(&h2_headers); + return nwritten; +} + +static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H2_STREAM_CTX(data); + struct cf_call_data save; + int rv; + ssize_t nwritten; + CURLcode result; + int blocked = 0, was_blocked = 0; + + CF_DATA_SAVE(save, cf, data); + + if(stream && stream->id != -1) { + if(stream->upload_blocked_len) { + /* the data in `buf` has already been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + /* TODO: this assertion triggers in OSSFuzz runs and it is not + * clear why. Disable for now to let OSSFuzz continue its tests. */ + DEBUGASSERT(len >= stream->upload_blocked_len); + if(len < stream->upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happen. We are not prepared to handle that. */ + failf(data, "HTTP/2 send again with decreased length (%zd vs %zd)", + len, stream->upload_blocked_len); + *err = CURLE_HTTP2; + nwritten = -1; + goto out; + } + nwritten = (ssize_t)stream->upload_blocked_len; + stream->upload_blocked_len = 0; + was_blocked = 1; + } + else if(stream->closed) { + if(stream->resp_hds_complete) { + /* Server decided to close the stream after having sent us a findl + * response. This is valid if it is not interested in the request + * body. This happens on 30x or 40x responses. + * We silently discard the data sent, since this is not a transport + * error situation. */ + CURL_TRC_CF(data, cf, "[%d] discarding data" + "on closed stream with response", stream->id); + *err = CURLE_OK; + nwritten = (ssize_t)len; + goto out; + } + infof(data, "stream %u closed", stream->id); + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + else { + /* If stream_id != -1, we have dispatched request HEADERS and + * optionally request body, and now are going to send or sending + * more request body in DATA frame */ + nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err); + if(nwritten < 0 && *err != CURLE_AGAIN) + goto out; + } + + if(!Curl_bufq_is_empty(&stream->sendbuf)) { + /* req body data is buffered, resume the potentially suspended stream */ + rv = nghttp2_session_resume_data(ctx->h2, stream->id); + if(nghttp2_is_fatal(rv)) { + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + } + } + else { + nwritten = h2_submit(&stream, cf, data, buf, len, err); + if(nwritten < 0) { + goto out; + } + DEBUGASSERT(stream); + } + + /* Call the nghttp2 send loop and flush to write ALL buffered data, + * headers and/or request body completely out to the network */ + result = h2_progress_egress(cf, data); + /* if the stream has been closed in egress handling (nghttp2 does that + * when it does not like the headers, for example */ + if(stream && stream->closed && !was_blocked) { + infof(data, "stream %u closed", stream->id); + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + else if(result == CURLE_AGAIN) { + blocked = 1; + } + else if(result) { + *err = result; + nwritten = -1; + goto out; + } + else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) { + /* although we wrote everything that nghttp2 wants to send now, + * there is data left in our stream send buffer unwritten. This may + * be due to the stream's HTTP/2 flow window being exhausted. */ + blocked = 1; + } + + if(stream && blocked && nwritten > 0) { + /* Unable to send all data, due to connection blocked or H2 window + * exhaustion. Data is left in our stream buffer, or nghttp2's internal + * frame buffer or our network out buffer. */ + size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2, + stream->id); + /* Whatever the cause, we need to return CURL_EAGAIN for this call. + * We have unwritten state that needs us being invoked again and EAGAIN + * is the only way to ensure that. */ + stream->upload_blocked_len = nwritten; + CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu " + "blocked_len=%zu", + stream->id, len, + nghttp2_session_get_remote_window_size(ctx->h2), rwin, + nwritten); + *err = CURLE_AGAIN; + nwritten = -1; + goto out; + } + else if(should_close_session(ctx)) { + /* nghttp2 thinks this session is done. If the stream has not been + * closed, this is an error state for out transfer */ + if(stream->closed) { + nwritten = http2_handle_stream_close(cf, data, stream, err); + } + else { + CURL_TRC_CF(data, cf, "send: nothing to do in this session"); + *err = CURLE_HTTP2; + nwritten = -1; + } + } + +out: + if(stream) { + CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, " + "upload_left=%" CURL_FORMAT_CURL_OFF_T ", " + "h2 windows %d-%d (stream-conn), " + "buffers %zu-%zu (stream-conn)", + stream->id, len, nwritten, *err, + stream->upload_left, + nghttp2_session_get_stream_remote_window_size( + ctx->h2, stream->id), + nghttp2_session_get_remote_window_size(ctx->h2), + Curl_bufq_len(&stream->sendbuf), + Curl_bufq_len(&ctx->outbufq)); + } + else { + CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, " + "connection-window=%d, nw_send_buffer(%zu)", + len, nwritten, *err, + nghttp2_session_get_remote_window_size(ctx->h2), + Curl_bufq_len(&ctx->outbufq)); + } + CF_DATA_RESTORE(cf, save); + return nwritten; +} + +static void cf_h2_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_h2_ctx *ctx = cf->ctx; + curl_socket_t sock; + bool want_recv, want_send; + + if(!ctx->h2) + return; + + sock = Curl_conn_cf_get_socket(cf, data); + Curl_pollset_check(data, ps, sock, &want_recv, &want_send); + if(want_recv || want_send) { + struct stream_ctx *stream = H2_STREAM_CTX(data); + struct cf_call_data save; + bool c_exhaust, s_exhaust; + + CF_DATA_SAVE(save, cf, data); + c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2); + s_exhaust = want_send && stream && stream->id >= 0 && + !nghttp2_session_get_stream_remote_window_size(ctx->h2, + stream->id); + want_recv = (want_recv || c_exhaust || s_exhaust); + want_send = (!s_exhaust && want_send) || + (!c_exhaust && nghttp2_session_want_write(ctx->h2)); + + Curl_pollset_set(data, ps, sock, want_recv, want_send); + CF_DATA_RESTORE(cf, save); + } +} + +static CURLcode cf_h2_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_h2_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* Connect the lower filters first */ + if(!cf->next->connected) { + result = Curl_conn_cf_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + } + + *done = FALSE; + + CF_DATA_SAVE(save, cf, data); + if(!ctx->h2) { + result = cf_h2_ctx_init(cf, data, FALSE); + if(result) + goto out; + } + + result = h2_progress_ingress(cf, data); + if(result) + goto out; + + /* Send out our SETTINGS and ACKs and such. If that blocks, we + * have it buffered and can count this filter as being connected */ + result = h2_progress_egress(cf, data); + if(result == CURLE_AGAIN) + result = CURLE_OK; + else if(result) + goto out; + + *done = TRUE; + cf->connected = TRUE; + result = CURLE_OK; + +out: + CURL_TRC_CF(data, cf, "cf_connect() -> %d, %d, ", result, *done); + CF_DATA_RESTORE(cf, save); + return result; +} + +static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + + if(ctx) { + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + cf_h2_ctx_clear(ctx); + CF_DATA_RESTORE(cf, save); + } + if(cf->next) + cf->next->cft->do_close(cf->next, data); +} + +static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + + (void)data; + if(ctx) { + cf_h2_ctx_free(ctx); + cf->ctx = NULL; + } +} + +static CURLcode http2_data_pause(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool pause) +{ +#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H2_STREAM_CTX(data); + + DEBUGASSERT(data); + if(ctx && ctx->h2 && stream) { + uint32_t window = pause? 0 : stream->local_window_size; + + int rv = nghttp2_session_set_local_window_size(ctx->h2, + NGHTTP2_FLAG_NONE, + stream->id, + window); + if(rv) { + failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", + nghttp2_strerror(rv), rv); + return CURLE_HTTP2; + } + + if(!pause) + drain_stream(cf, data, stream); + + /* attempt to send the window update */ + (void)h2_progress_egress(cf, data); + + if(!pause) { + /* Unpausing a h2 transfer, requires it to be run again. The server + * may send new DATA on us increasing the flow window, and it may + * not. We may have already buffered and exhausted the new window + * by operating on things in flight during the handling of other + * transfers. */ + drain_stream(cf, data, stream); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u", + window, stream->id)); + +#ifdef DEBUGBUILD + { + /* read out the stream local window again */ + uint32_t window2 = + nghttp2_session_get_stream_local_window_size(ctx->h2, + stream->id); + DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u", + window2, stream->id)); + } +#endif + } +#endif + return CURLE_OK; +} + +static CURLcode cf_h2_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + CURLcode result = CURLE_OK; + struct cf_call_data save; + + (void)arg2; + + CF_DATA_SAVE(save, cf, data); + switch(event) { + case CF_CTRL_DATA_SETUP: + break; + case CF_CTRL_DATA_PAUSE: + result = http2_data_pause(cf, data, (arg1 != 0)); + break; + case CF_CTRL_DATA_DONE_SEND: + result = http2_data_done_send(cf, data); + break; + case CF_CTRL_DATA_DETACH: + http2_data_done(cf, data, TRUE); + break; + case CF_CTRL_DATA_DONE: + http2_data_done(cf, data, arg1 != 0); + break; + default: + break; + } + CF_DATA_RESTORE(cf, save); + return result; +} + +static bool cf_h2_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H2_STREAM_CTX(data); + + if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq) + || (stream && !Curl_bufq_is_empty(&stream->sendbuf)) + || (stream && !Curl_bufq_is_empty(&stream->recvbuf)))) + return TRUE; + return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE; +} + +static bool cf_h2_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_h2_ctx *ctx = cf->ctx; + CURLcode result; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending)); + CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d", + result, *input_pending); + CF_DATA_RESTORE(cf, save); + return result; +} + +static CURLcode cf_h2_keep_alive(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + result = http2_send_ping(cf, data); + CF_DATA_RESTORE(cf, save); + return result; +} + +static CURLcode cf_h2_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_h2_ctx *ctx = cf->ctx; + struct cf_call_data save; + size_t effective_max; + + switch(query) { + case CF_QUERY_MAX_CONCURRENT: + DEBUGASSERT(pres1); + + CF_DATA_SAVE(save, cf, data); + if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { + /* the limit is what we have in use right now */ + effective_max = CONN_INUSE(cf->conn); + } + else { + effective_max = ctx->max_concurrent_streams; + } + *pres1 = (effective_max > INT_MAX)? INT_MAX : (int)effective_max; + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +struct Curl_cftype Curl_cft_nghttp2 = { + "HTTP/2", + CF_TYPE_MULTIPLEX, + CURL_LOG_LVL_NONE, + cf_h2_destroy, + cf_h2_connect, + cf_h2_close, + Curl_cf_def_get_host, + cf_h2_adjust_pollset, + cf_h2_data_pending, + cf_h2_send, + cf_h2_recv, + cf_h2_cntrl, + cf_h2_is_alive, + cf_h2_keep_alive, + cf_h2_query, +}; + +static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf = NULL; + struct cf_h2_ctx *ctx; + CURLcode result = CURLE_OUT_OF_MEMORY; + + DEBUGASSERT(data->conn); + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) + goto out; + + result = Curl_cf_create(&cf, &Curl_cft_nghttp2, ctx); + if(result) + goto out; + + Curl_conn_cf_add(data, conn, sockindex, cf); + result = CURLE_OK; + +out: + if(result) + cf_h2_ctx_free(ctx); + *pcf = result? NULL : cf; + return result; +} + +static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf_h2 = NULL; + struct cf_h2_ctx *ctx; + CURLcode result = CURLE_OUT_OF_MEMORY; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) + goto out; + + result = Curl_cf_create(&cf_h2, &Curl_cft_nghttp2, ctx); + if(result) + goto out; + + Curl_conn_cf_insert_after(cf, cf_h2); + result = CURLE_OK; + +out: + if(result) + cf_h2_ctx_free(ctx); + return result; +} + +static bool Curl_cf_is_http2(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + (void)data; + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_nghttp2) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; +} + +bool Curl_conn_is_http2(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex) +{ + return conn? Curl_cf_is_http2(conn->cfilter[sockindex], data) : FALSE; +} + +bool Curl_http2_may_switch(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + (void)sockindex; + if(!Curl_conn_is_http2(data, conn, sockindex) && + data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + /* We don't support HTTP/2 proxies yet. Also it's debatable + whether or not this setting should apply to HTTP/2 proxies. */ + infof(data, "Ignoring HTTP/2 prior knowledge due to proxy"); + return FALSE; + } +#endif + return TRUE; + } + return FALSE; +} + +CURLcode Curl_http2_switch(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + struct Curl_cfilter *cf; + CURLcode result; + + DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex)); + DEBUGF(infof(data, "switching to HTTP/2")); + + result = http2_cfilter_add(&cf, data, conn, sockindex); + if(result) + return result; + + result = cf_h2_ctx_init(cf, data, FALSE); + if(result) + return result; + + conn->httpversion = 20; /* we know we're on HTTP/2 now */ + conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + conn->bundle->multiuse = BUNDLE_MULTIPLEX; + Curl_multi_connchanged(data->multi); + + if(cf->next) { + bool done; + return Curl_conn_cf_connect(cf, data, FALSE, &done); + } + return CURLE_OK; +} + +CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct Curl_cfilter *cf_h2; + CURLcode result; + + DEBUGASSERT(!Curl_cf_is_http2(cf, data)); + + result = http2_cfilter_insert_after(cf, data); + if(result) + return result; + + cf_h2 = cf->next; + result = cf_h2_ctx_init(cf_h2, data, FALSE); + if(result) + return result; + + cf->conn->httpversion = 20; /* we know we're on HTTP/2 now */ + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; + Curl_multi_connchanged(data->multi); + + if(cf_h2->next) { + bool done; + return Curl_conn_cf_connect(cf_h2, data, FALSE, &done); + } + return CURLE_OK; +} + +CURLcode Curl_http2_upgrade(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + const char *mem, size_t nread) +{ + struct Curl_cfilter *cf; + struct cf_h2_ctx *ctx; + CURLcode result; + + DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex)); + DEBUGF(infof(data, "upgrading to HTTP/2")); + DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED); + + result = http2_cfilter_add(&cf, data, conn, sockindex); + if(result) + return result; + + DEBUGASSERT(cf->cft == &Curl_cft_nghttp2); + ctx = cf->ctx; + + result = cf_h2_ctx_init(cf, data, TRUE); + if(result) + return result; + + if(nread > 0) { + /* Remaining data from the protocol switch reply is already using + * the switched protocol, ie. HTTP/2. We add that to the network + * inbufq. */ + ssize_t copied; + + copied = Curl_bufq_write(&ctx->inbufq, + (const unsigned char *)mem, nread, &result); + if(copied < 0) { + failf(data, "error on copying HTTP Upgrade response: %d", result); + return CURLE_RECV_ERROR; + } + if((size_t)copied < nread) { + failf(data, "connection buffer size could not take all data " + "from HTTP Upgrade response header: copied=%zd, datalen=%zu", + copied, nread); + return CURLE_HTTP2; + } + infof(data, "Copied HTTP/2 data in stream buffer to connection buffer" + " after upgrade: len=%zu", nread); + } + + conn->httpversion = 20; /* we know we're on HTTP/2 now */ + conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + conn->bundle->multiuse = BUNDLE_MULTIPLEX; + Curl_multi_connchanged(data->multi); + + if(cf->next) { + bool done; + return Curl_conn_cf_connect(cf, data, FALSE, &done); + } + return CURLE_OK; +} + +/* Only call this function for a transfer that already got an HTTP/2 + CURLE_HTTP2_STREAM error! */ +bool Curl_h2_http_1_1_error(struct Curl_easy *data) +{ + struct stream_ctx *stream = H2_STREAM_CTX(data); + return (stream && stream->error == NGHTTP2_HTTP_1_1_REQUIRED); +} + +#else /* !USE_NGHTTP2 */ + +/* Satisfy external references even if http2 is not compiled in. */ +#include + +char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) +{ + (void) h; + (void) num; + return NULL; +} + +char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) +{ + (void) h; + (void) header; + return NULL; +} + +#endif /* USE_NGHTTP2 */ diff --git a/lib/http2.h b/lib/http2.h new file mode 100644 index 0000000..80e1834 --- /dev/null +++ b/lib/http2.h @@ -0,0 +1,77 @@ +#ifndef HEADER_CURL_HTTP2_H +#define HEADER_CURL_HTTP2_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_NGHTTP2 +#include "http.h" + +/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting + from the peer */ +#define DEFAULT_MAX_CONCURRENT_STREAMS 100 + +/* + * Store nghttp2 version info in this buffer. + */ +void Curl_http2_ver(char *p, size_t len); + +CURLcode Curl_http2_request_upgrade(struct dynbuf *req, + struct Curl_easy *data); + +/* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */ +bool Curl_h2_http_1_1_error(struct Curl_easy *data); + +bool Curl_conn_is_http2(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex); +bool Curl_http2_may_switch(struct Curl_easy *data, + struct connectdata *conn, + int sockindex); + +CURLcode Curl_http2_switch(struct Curl_easy *data, + struct connectdata *conn, int sockindex); + +CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data); + +CURLcode Curl_http2_upgrade(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + const char *ptr, size_t nread); + +extern struct Curl_cftype Curl_cft_nghttp2; + +#else /* USE_NGHTTP2 */ + +#define Curl_cf_is_http2(a,b) FALSE +#define Curl_conn_is_http2(a,b,c) FALSE +#define Curl_http2_may_switch(a,b,c) FALSE + +#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_switch(a,b,c) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_upgrade(a,b,c,d,e) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_h2_http_1_1_error(x) 0 +#endif + +#endif /* HEADER_CURL_HTTP2_H */ diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c new file mode 100644 index 0000000..c938291 --- /dev/null +++ b/lib/http_aws_sigv4.c @@ -0,0 +1,817 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) + +#include "urldata.h" +#include "strcase.h" +#include "strdup.h" +#include "http_aws_sigv4.h" +#include "curl_sha256.h" +#include "transfer.h" +#include "parsedate.h" +#include "sendf.h" +#include "escape.h" + +#include + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#include "slist.h" + +#define HMAC_SHA256(k, kl, d, dl, o) \ + do { \ + result = Curl_hmacit(Curl_HMAC_SHA256, \ + (unsigned char *)k, \ + kl, \ + (unsigned char *)d, \ + dl, o); \ + if(result) { \ + goto fail; \ + } \ + } while(0) + +#define TIMESTAMP_SIZE 17 + +/* hex-encoded with trailing null */ +#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1) + +static void sha256_to_hex(char *dst, unsigned char *sha) +{ + Curl_hexencode(sha, SHA256_DIGEST_LENGTH, + (unsigned char *)dst, SHA256_HEX_LENGTH); +} + +static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr) +{ + char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr)); + + if(tmp) + return tmp; + return Curl_checkheaders(data, STRCONST("Date")); +} + +/* remove whitespace, and lowercase all headers */ +static void trim_headers(struct curl_slist *head) +{ + struct curl_slist *l; + for(l = head; l; l = l->next) { + char *value; /* to read from */ + char *store; + size_t colon = strcspn(l->data, ":"); + Curl_strntolower(l->data, l->data, colon); + + value = &l->data[colon]; + if(!*value) + continue; + ++value; + store = value; + + /* skip leading whitespace */ + while(*value && ISBLANK(*value)) + value++; + + while(*value) { + int space = 0; + while(*value && ISBLANK(*value)) { + value++; + space++; + } + if(space) { + /* replace any number of consecutive whitespace with a single space, + unless at the end of the string, then nothing */ + if(*value) + *store++ = ' '; + } + else + *store++ = *value++; + } + *store = 0; /* null terminate */ + } +} + +/* maximum length for the aws sivg4 parts */ +#define MAX_SIGV4_LEN 64 +#define MAX_SIGV4_LEN_TXT "64" + +#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date")) + +#define MAX_HOST_LEN 255 +/* FQDN + host: */ +#define FULL_HOST_LEN (MAX_HOST_LEN + sizeof("host:")) + +/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */ +#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1) + +/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */ +static CURLcode make_headers(struct Curl_easy *data, + const char *hostname, + char *timestamp, + char *provider1, + char **date_header, + char *content_sha256_header, + struct dynbuf *canonical_headers, + struct dynbuf *signed_headers) +{ + char date_hdr_key[DATE_HDR_KEY_LEN]; + char date_full_hdr[DATE_FULL_HDR_LEN]; + struct curl_slist *head = NULL; + struct curl_slist *tmp_head = NULL; + CURLcode ret = CURLE_OUT_OF_MEMORY; + struct curl_slist *l; + int again = 1; + + /* provider1 mid */ + Curl_strntolower(provider1, provider1, strlen(provider1)); + provider1[0] = Curl_raw_toupper(provider1[0]); + + msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1); + + /* provider1 lowercase */ + Curl_strntolower(provider1, provider1, 1); /* first byte only */ + msnprintf(date_full_hdr, DATE_FULL_HDR_LEN, + "x-%s-date:%s", provider1, timestamp); + + if(Curl_checkheaders(data, STRCONST("Host"))) { + head = NULL; + } + else { + char full_host[FULL_HOST_LEN + 1]; + + if(data->state.aptr.host) { + size_t pos; + + if(strlen(data->state.aptr.host) > FULL_HOST_LEN) { + ret = CURLE_URL_MALFORMAT; + goto fail; + } + strcpy(full_host, data->state.aptr.host); + /* remove /r/n as the separator for canonical request must be '\n' */ + pos = strcspn(full_host, "\n\r"); + full_host[pos] = 0; + } + else { + if(strlen(hostname) > MAX_HOST_LEN) { + ret = CURLE_URL_MALFORMAT; + goto fail; + } + msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname); + } + + head = curl_slist_append(NULL, full_host); + if(!head) + goto fail; + } + + + if(*content_sha256_header) { + tmp_head = curl_slist_append(head, content_sha256_header); + if(!tmp_head) + goto fail; + head = tmp_head; + } + + /* copy user headers to our header list. the logic is based on how http.c + handles user headers. + + user headers in format 'name:' with no value are used to signal that an + internal header of that name should be removed. those user headers are not + added to this list. + + user headers in format 'name;' with no value are used to signal that a + header of that name with no value should be sent. those user headers are + added to this list but in the format that they will be sent, ie the + semi-colon is changed to a colon for format 'name:'. + + user headers with a value of whitespace only, or without a colon or + semi-colon, are not added to this list. + */ + for(l = data->set.headers; l; l = l->next) { + char *dupdata, *ptr; + char *sep = strchr(l->data, ':'); + if(!sep) + sep = strchr(l->data, ';'); + if(!sep || (*sep == ':' && !*(sep + 1))) + continue; + for(ptr = sep + 1; ISSPACE(*ptr); ++ptr) + ; + if(!*ptr && ptr != sep + 1) /* a value of whitespace only */ + continue; + dupdata = strdup(l->data); + if(!dupdata) + goto fail; + dupdata[sep - l->data] = ':'; + tmp_head = Curl_slist_append_nodup(head, dupdata); + if(!tmp_head) { + free(dupdata); + goto fail; + } + head = tmp_head; + } + + trim_headers(head); + + *date_header = find_date_hdr(data, date_hdr_key); + if(!*date_header) { + tmp_head = curl_slist_append(head, date_full_hdr); + if(!tmp_head) + goto fail; + head = tmp_head; + *date_header = curl_maprintf("%s: %s\r\n", date_hdr_key, timestamp); + } + else { + char *value; + char *endp; + value = strchr(*date_header, ':'); + if(!value) { + *date_header = NULL; + goto fail; + } + ++value; + while(ISBLANK(*value)) + ++value; + endp = value; + while(*endp && ISALNUM(*endp)) + ++endp; + /* 16 bytes => "19700101T000000Z" */ + if((endp - value) == TIMESTAMP_SIZE - 1) { + memcpy(timestamp, value, TIMESTAMP_SIZE - 1); + timestamp[TIMESTAMP_SIZE - 1] = 0; + } + else + /* bad timestamp length */ + timestamp[0] = 0; + *date_header = NULL; + } + + /* alpha-sort in a case sensitive manner */ + do { + again = 0; + for(l = head; l; l = l->next) { + struct curl_slist *next = l->next; + + if(next && strcmp(l->data, next->data) > 0) { + char *tmp = l->data; + + l->data = next->data; + next->data = tmp; + again = 1; + } + } + } while(again); + + for(l = head; l; l = l->next) { + char *tmp; + + if(Curl_dyn_add(canonical_headers, l->data)) + goto fail; + if(Curl_dyn_add(canonical_headers, "\n")) + goto fail; + + tmp = strchr(l->data, ':'); + if(tmp) + *tmp = 0; + + if(l != head) { + if(Curl_dyn_add(signed_headers, ";")) + goto fail; + } + if(Curl_dyn_add(signed_headers, l->data)) + goto fail; + } + + ret = CURLE_OK; +fail: + curl_slist_free_all(head); + + return ret; +} + +#define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256")) +/* add 2 for ": " between header name and value */ +#define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \ + SHA256_HEX_LENGTH) + +/* try to parse a payload hash from the content-sha256 header */ +static char *parse_content_sha_hdr(struct Curl_easy *data, + const char *provider1, + size_t *value_len) +{ + char key[CONTENT_SHA256_KEY_LEN]; + size_t key_len; + char *value; + size_t len; + + key_len = msnprintf(key, sizeof(key), "x-%s-content-sha256", provider1); + + value = Curl_checkheaders(data, key, key_len); + if(!value) + return NULL; + + value = strchr(value, ':'); + if(!value) + return NULL; + ++value; + + while(*value && ISBLANK(*value)) + ++value; + + len = strlen(value); + while(len > 0 && ISBLANK(value[len-1])) + --len; + + *value_len = len; + return value; +} + +static CURLcode calc_payload_hash(struct Curl_easy *data, + unsigned char *sha_hash, char *sha_hex) +{ + const char *post_data = data->set.postfields; + size_t post_data_len = 0; + CURLcode result; + + if(post_data) { + if(data->set.postfieldsize < 0) + post_data_len = strlen(post_data); + else + post_data_len = (size_t)data->set.postfieldsize; + } + result = Curl_sha256it(sha_hash, (const unsigned char *) post_data, + post_data_len); + if(!result) + sha256_to_hex(sha_hex, sha_hash); + return result; +} + +#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD" + +static CURLcode calc_s3_payload_hash(struct Curl_easy *data, + Curl_HttpReq httpreq, char *provider1, + unsigned char *sha_hash, + char *sha_hex, char *header) +{ + bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD); + /* The request method or filesize indicate no request payload */ + bool empty_payload = (empty_method || data->set.filesize == 0); + /* The POST payload is in memory */ + bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields); + CURLcode ret = CURLE_OUT_OF_MEMORY; + + if(empty_payload || post_payload) { + /* Calculate a real hash when we know the request payload */ + ret = calc_payload_hash(data, sha_hash, sha_hex); + if(ret) + goto fail; + } + else { + /* Fall back to s3's UNSIGNED-PAYLOAD */ + size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1; + DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */ + memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len); + sha_hex[len] = 0; + } + + /* format the required content-sha256 header */ + msnprintf(header, CONTENT_SHA256_HDR_LEN, + "x-%s-content-sha256: %s", provider1, sha_hex); + + ret = CURLE_OK; +fail: + return ret; +} + +struct pair { + const char *p; + size_t len; +}; + +static int compare_func(const void *a, const void *b) +{ + const struct pair *aa = a; + const struct pair *bb = b; + /* If one element is empty, the other is always sorted higher */ + if(aa->len == 0) + return -1; + if(bb->len == 0) + return 1; + return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len); +} + +#define MAX_QUERYPAIRS 64 + +static CURLcode canon_query(struct Curl_easy *data, + const char *query, struct dynbuf *dq) +{ + CURLcode result = CURLE_OK; + int entry = 0; + int i; + const char *p = query; + struct pair array[MAX_QUERYPAIRS]; + struct pair *ap = &array[0]; + if(!query) + return result; + + /* sort the name=value pairs first */ + do { + char *amp; + entry++; + ap->p = p; + amp = strchr(p, '&'); + if(amp) + ap->len = amp - p; /* excluding the ampersand */ + else { + ap->len = strlen(p); + break; + } + ap++; + p = amp + 1; + } while(entry < MAX_QUERYPAIRS); + if(entry == MAX_QUERYPAIRS) { + /* too many query pairs for us */ + failf(data, "aws-sigv4: too many query pairs in URL"); + return CURLE_URL_MALFORMAT; + } + + qsort(&array[0], entry, sizeof(struct pair), compare_func); + + ap = &array[0]; + for(i = 0; !result && (i < entry); i++, ap++) { + size_t len; + const char *q = ap->p; + bool found_equals = false; + if(!ap->len) + continue; + for(len = ap->len; len && !result; q++, len--) { + if(ISALNUM(*q)) + result = Curl_dyn_addn(dq, q, 1); + else { + switch(*q) { + case '-': + case '.': + case '_': + case '~': + /* allowed as-is */ + result = Curl_dyn_addn(dq, q, 1); + break; + case '=': + /* allowed as-is */ + result = Curl_dyn_addn(dq, q, 1); + found_equals = true; + break; + case '%': + /* uppercase the following if hexadecimal */ + if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) { + char tmp[3]="%"; + tmp[1] = Curl_raw_toupper(q[1]); + tmp[2] = Curl_raw_toupper(q[2]); + result = Curl_dyn_addn(dq, tmp, 3); + q += 2; + len -= 2; + } + else + /* '%' without a following two-digit hex, encode it */ + result = Curl_dyn_addn(dq, "%25", 3); + break; + default: { + /* URL encode */ + const char hex[] = "0123456789ABCDEF"; + char out[3]={'%'}; + out[1] = hex[((unsigned char)*q)>>4]; + out[2] = hex[*q & 0xf]; + result = Curl_dyn_addn(dq, out, 3); + break; + } + } + } + } + if(!result && !found_equals) { + /* queries without value still need an equals */ + result = Curl_dyn_addn(dq, "=", 1); + } + if(!result && i < entry - 1) { + /* insert ampersands between query pairs */ + result = Curl_dyn_addn(dq, "&", 1); + } + } + return result; +} + + +CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) +{ + CURLcode result = CURLE_OUT_OF_MEMORY; + struct connectdata *conn = data->conn; + size_t len; + const char *arg; + char provider0[MAX_SIGV4_LEN + 1]=""; + char provider1[MAX_SIGV4_LEN + 1]=""; + char region[MAX_SIGV4_LEN + 1]=""; + char service[MAX_SIGV4_LEN + 1]=""; + bool sign_as_s3 = false; + const char *hostname = conn->host.name; + time_t clock; + struct tm tm; + char timestamp[TIMESTAMP_SIZE]; + char date[9]; + struct dynbuf canonical_headers; + struct dynbuf signed_headers; + struct dynbuf canonical_query; + char *date_header = NULL; + Curl_HttpReq httpreq; + const char *method = NULL; + char *payload_hash = NULL; + size_t payload_hash_len = 0; + unsigned char sha_hash[SHA256_DIGEST_LENGTH]; + char sha_hex[SHA256_HEX_LENGTH]; + char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */ + char *canonical_request = NULL; + char *request_type = NULL; + char *credential_scope = NULL; + char *str_to_sign = NULL; + const char *user = data->state.aptr.user ? data->state.aptr.user : ""; + char *secret = NULL; + unsigned char sign0[SHA256_DIGEST_LENGTH] = {0}; + unsigned char sign1[SHA256_DIGEST_LENGTH] = {0}; + char *auth_headers = NULL; + + DEBUGASSERT(!proxy); + (void)proxy; + + if(Curl_checkheaders(data, STRCONST("Authorization"))) { + /* Authorization already present, Bailing out */ + return CURLE_OK; + } + + /* we init those buffers here, so goto fail will free initialized dynbuf */ + Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER); + Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER); + Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER); + + /* + * Parameters parsing + * Google and Outscale use the same OSC or GOOG, + * but Amazon uses AWS and AMZ for header arguments. + * AWS is the default because most of non-amazon providers + * are still using aws:amz as a prefix. + */ + arg = data->set.str[STRING_AWS_SIGV4] ? + data->set.str[STRING_AWS_SIGV4] : "aws:amz"; + + /* provider1[:provider2[:region[:service]]] + + No string can be longer than N bytes of non-whitespace + */ + (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "s", + provider0, provider1, region, service); + if(!provider0[0]) { + failf(data, "first aws-sigv4 provider can't be empty"); + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto fail; + } + else if(!provider1[0]) + strcpy(provider1, provider0); + + if(!service[0]) { + char *hostdot = strchr(hostname, '.'); + if(!hostdot) { + failf(data, "aws-sigv4: service missing in parameters and hostname"); + result = CURLE_URL_MALFORMAT; + goto fail; + } + len = hostdot - hostname; + if(len > MAX_SIGV4_LEN) { + failf(data, "aws-sigv4: service too long in hostname"); + result = CURLE_URL_MALFORMAT; + goto fail; + } + memcpy(service, hostname, len); + service[len] = '\0'; + + infof(data, "aws_sigv4: picked service %s from host", service); + + if(!region[0]) { + const char *reg = hostdot + 1; + const char *hostreg = strchr(reg, '.'); + if(!hostreg) { + failf(data, "aws-sigv4: region missing in parameters and hostname"); + result = CURLE_URL_MALFORMAT; + goto fail; + } + len = hostreg - reg; + if(len > MAX_SIGV4_LEN) { + failf(data, "aws-sigv4: region too long in hostname"); + result = CURLE_URL_MALFORMAT; + goto fail; + } + memcpy(region, reg, len); + region[len] = '\0'; + infof(data, "aws_sigv4: picked region %s from host", region); + } + } + + Curl_http_method(data, conn, &method, &httpreq); + + /* AWS S3 requires a x-amz-content-sha256 header, and supports special + * values like UNSIGNED-PAYLOAD */ + sign_as_s3 = (strcasecompare(provider0, "aws") && + strcasecompare(service, "s3")); + + payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len); + + if(!payload_hash) { + if(sign_as_s3) + result = calc_s3_payload_hash(data, httpreq, provider1, sha_hash, + sha_hex, content_sha256_hdr); + else + result = calc_payload_hash(data, sha_hash, sha_hex); + if(result) + goto fail; + + payload_hash = sha_hex; + /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */ + payload_hash_len = strlen(sha_hex); + } + +#ifdef DEBUGBUILD + { + char *force_timestamp = getenv("CURL_FORCETIME"); + if(force_timestamp) + clock = 0; + else + time(&clock); + } +#else + time(&clock); +#endif + result = Curl_gmtime(clock, &tm); + if(result) { + goto fail; + } + if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + result = make_headers(data, hostname, timestamp, provider1, + &date_header, content_sha256_hdr, + &canonical_headers, &signed_headers); + if(result) + goto fail; + + if(*content_sha256_hdr) { + /* make_headers() needed this without the \r\n for canonicalization */ + size_t hdrlen = strlen(content_sha256_hdr); + DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr)); + memcpy(content_sha256_hdr + hdrlen, "\r\n", 3); + } + + memcpy(date, timestamp, sizeof(date)); + date[sizeof(date) - 1] = 0; + + result = canon_query(data, data->state.up.query, &canonical_query); + if(result) + goto fail; + result = CURLE_OUT_OF_MEMORY; + + canonical_request = + curl_maprintf("%s\n" /* HTTPRequestMethod */ + "%s\n" /* CanonicalURI */ + "%s\n" /* CanonicalQueryString */ + "%s\n" /* CanonicalHeaders */ + "%s\n" /* SignedHeaders */ + "%.*s", /* HashedRequestPayload in hex */ + method, + data->state.up.path, + Curl_dyn_ptr(&canonical_query) ? + Curl_dyn_ptr(&canonical_query) : "", + Curl_dyn_ptr(&canonical_headers), + Curl_dyn_ptr(&signed_headers), + (int)payload_hash_len, payload_hash); + if(!canonical_request) + goto fail; + + DEBUGF(infof(data, "Canonical request: %s", canonical_request)); + + /* provider 0 lowercase */ + Curl_strntolower(provider0, provider0, strlen(provider0)); + request_type = curl_maprintf("%s4_request", provider0); + if(!request_type) + goto fail; + + credential_scope = curl_maprintf("%s/%s/%s/%s", + date, region, service, request_type); + if(!credential_scope) + goto fail; + + if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request, + strlen(canonical_request))) + goto fail; + + sha256_to_hex(sha_hex, sha_hash); + + /* provider 0 uppercase */ + Curl_strntoupper(provider0, provider0, strlen(provider0)); + + /* + * Google allows using RSA key instead of HMAC, so this code might change + * in the future. For now we only support HMAC. + */ + str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */ + "%s\n" /* RequestDateTime */ + "%s\n" /* CredentialScope */ + "%s", /* HashedCanonicalRequest in hex */ + provider0, + timestamp, + credential_scope, + sha_hex); + if(!str_to_sign) { + goto fail; + } + + /* provider 0 uppercase */ + secret = curl_maprintf("%s4%s", provider0, + data->state.aptr.passwd ? + data->state.aptr.passwd : ""); + if(!secret) + goto fail; + + HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0); + HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1); + HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0); + HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1); + HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0); + + sha256_to_hex(sha_hex, sign0); + + /* provider 0 uppercase */ + auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 " + "Credential=%s/%s, " + "SignedHeaders=%s, " + "Signature=%s\r\n" + /* + * date_header is added here, only if it wasn't + * user-specified (using CURLOPT_HTTPHEADER). + * date_header includes \r\n + */ + "%s" + "%s", /* optional sha256 header includes \r\n */ + provider0, + user, + credential_scope, + Curl_dyn_ptr(&signed_headers), + sha_hex, + date_header ? date_header : "", + content_sha256_hdr); + if(!auth_headers) { + goto fail; + } + + Curl_safefree(data->state.aptr.userpwd); + data->state.aptr.userpwd = auth_headers; + data->state.authhost.done = TRUE; + result = CURLE_OK; + +fail: + Curl_dyn_free(&canonical_query); + Curl_dyn_free(&canonical_headers); + Curl_dyn_free(&signed_headers); + free(canonical_request); + free(request_type); + free(credential_scope); + free(str_to_sign); + free(secret); + free(date_header); + return result; +} + +#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */ diff --git a/lib/http_aws_sigv4.h b/lib/http_aws_sigv4.h new file mode 100644 index 0000000..57cc570 --- /dev/null +++ b/lib/http_aws_sigv4.h @@ -0,0 +1,31 @@ +#ifndef HEADER_CURL_HTTP_AWS_SIGV4_H +#define HEADER_CURL_HTTP_AWS_SIGV4_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +/* this is for creating aws_sigv4 header output */ +CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy); + +#endif /* HEADER_CURL_HTTP_AWS_SIGV4_H */ diff --git a/lib/http_chunks.c b/lib/http_chunks.c new file mode 100644 index 0000000..039c179 --- /dev/null +++ b/lib/http_chunks.c @@ -0,0 +1,455 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_HTTP + +#include "urldata.h" /* it includes http_chunks.h */ +#include "sendf.h" /* for the client write stuff */ +#include "dynbuf.h" +#include "content_encoding.h" +#include "http.h" +#include "strtoofft.h" +#include "warnless.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Chunk format (simplified): + * + * [ chunk extension ] CRLF + * CRLF + * + * Highlights from RFC2616 section 3.6 say: + + The chunked encoding modifies the body of a message in order to + transfer it as a series of chunks, each with its own size indicator, + followed by an OPTIONAL trailer containing entity-header fields. This + allows dynamically produced content to be transferred along with the + information necessary for the recipient to verify that it has + received the full message. + + Chunked-Body = *chunk + last-chunk + trailer + CRLF + + chunk = chunk-size [ chunk-extension ] CRLF + chunk-data CRLF + chunk-size = 1*HEX + last-chunk = 1*("0") [ chunk-extension ] CRLF + + chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) + chunk-ext-name = token + chunk-ext-val = token | quoted-string + chunk-data = chunk-size(OCTET) + trailer = *(entity-header CRLF) + + The chunk-size field is a string of hex digits indicating the size of + the chunk. The chunked encoding is ended by any chunk whose size is + zero, followed by the trailer, which is terminated by an empty line. + + */ + +void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body) +{ + (void)data; + ch->hexindex = 0; /* start at 0 */ + ch->state = CHUNK_HEX; /* we get hex first! */ + ch->last_code = CHUNKE_OK; + Curl_dyn_init(&ch->trailer, DYN_H1_TRAILER); + ch->ignore_body = ignore_body; +} + +void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body) +{ + (void)data; + ch->hexindex = 0; /* start at 0 */ + ch->state = CHUNK_HEX; /* we get hex first! */ + ch->last_code = CHUNKE_OK; + Curl_dyn_reset(&ch->trailer); + ch->ignore_body = ignore_body; +} + +void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch) +{ + (void)data; + Curl_dyn_free(&ch->trailer); +} + +bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch) +{ + (void)data; + return ch->state == CHUNK_DONE; +} + +static CURLcode httpchunk_readwrite(struct Curl_easy *data, + struct Curl_chunker *ch, + struct Curl_cwriter *cw_next, + const char *buf, size_t blen, + size_t *pconsumed) +{ + CURLcode result = CURLE_OK; + size_t piece; + + *pconsumed = 0; /* nothing's written yet */ + /* first check terminal states that will not progress anywhere */ + if(ch->state == CHUNK_DONE) + return CURLE_OK; + if(ch->state == CHUNK_FAILED) + return CURLE_RECV_ERROR; + + /* the original data is written to the client, but we go on with the + chunk read process, to properly calculate the content length */ + if(data->set.http_te_skip && !ch->ignore_body) { + if(cw_next) + result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, buf, blen); + else + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_PASSTHRU_ERROR; + return result; + } + } + + while(blen) { + switch(ch->state) { + case CHUNK_HEX: + if(ISXDIGIT(*buf)) { + if(ch->hexindex >= CHUNK_MAXNUM_LEN) { + failf(data, "chunk hex-length longer than %d", CHUNK_MAXNUM_LEN); + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_TOO_LONG_HEX; /* longer than we support */ + return CURLE_RECV_ERROR; + } + ch->hexbuffer[ch->hexindex++] = *buf; + buf++; + blen--; + } + else { + char *endptr; + if(0 == ch->hexindex) { + /* This is illegal data, we received junk where we expected + a hexadecimal digit. */ + failf(data, "chunk hex-length char not a hex digit: 0x%x", *buf); + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_ILLEGAL_HEX; + return CURLE_RECV_ERROR; + } + + /* blen and buf are unmodified */ + ch->hexbuffer[ch->hexindex] = 0; + if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize)) { + failf(data, "chunk hex-length not valid: '%s'", ch->hexbuffer); + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_ILLEGAL_HEX; + return CURLE_RECV_ERROR; + } + ch->state = CHUNK_LF; /* now wait for the CRLF */ + } + break; + + case CHUNK_LF: + /* waiting for the LF after a chunk size */ + if(*buf == 0x0a) { + /* we're now expecting data to come, unless size was zero! */ + if(0 == ch->datasize) { + ch->state = CHUNK_TRAILER; /* now check for trailers */ + } + else + ch->state = CHUNK_DATA; + } + + buf++; + blen--; + break; + + case CHUNK_DATA: + /* We expect 'datasize' of data. We have 'blen' right now, it can be + more or less than 'datasize'. Get the smallest piece. + */ + piece = blen; + if(ch->datasize < (curl_off_t)blen) + piece = curlx_sotouz(ch->datasize); + + /* Write the data portion available */ + if(!data->set.http_te_skip && !ch->ignore_body) { + if(cw_next) + result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, + buf, piece); + else + result = Curl_client_write(data, CLIENTWRITE_BODY, + (char *)buf, piece); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_PASSTHRU_ERROR; + return result; + } + } + + *pconsumed += piece; + ch->datasize -= piece; /* decrease amount left to expect */ + buf += piece; /* move read pointer forward */ + blen -= piece; /* decrease space left in this round */ + + if(0 == ch->datasize) + /* end of data this round, we now expect a trailing CRLF */ + ch->state = CHUNK_POSTLF; + break; + + case CHUNK_POSTLF: + if(*buf == 0x0a) { + /* The last one before we go back to hex state and start all over. */ + Curl_httpchunk_reset(data, ch, ch->ignore_body); + } + else if(*buf != 0x0d) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_BAD_CHUNK; + return CURLE_RECV_ERROR; + } + buf++; + blen--; + break; + + case CHUNK_TRAILER: + if((*buf == 0x0d) || (*buf == 0x0a)) { + char *tr = Curl_dyn_ptr(&ch->trailer); + /* this is the end of a trailer, but if the trailer was zero bytes + there was no trailer and we move on */ + + if(tr) { + size_t trlen; + result = Curl_dyn_addn(&ch->trailer, (char *)STRCONST("\x0d\x0a")); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_OUT_OF_MEMORY; + return result; + } + tr = Curl_dyn_ptr(&ch->trailer); + trlen = Curl_dyn_len(&ch->trailer); + if(!data->set.http_te_skip) { + if(cw_next) + result = Curl_cwriter_write(data, cw_next, + CLIENTWRITE_HEADER| + CLIENTWRITE_TRAILER, + tr, trlen); + else + result = Curl_client_write(data, + CLIENTWRITE_HEADER| + CLIENTWRITE_TRAILER, + tr, trlen); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_PASSTHRU_ERROR; + return result; + } + } + Curl_dyn_reset(&ch->trailer); + ch->state = CHUNK_TRAILER_CR; + if(*buf == 0x0a) + /* already on the LF */ + break; + } + else { + /* no trailer, we're on the final CRLF pair */ + ch->state = CHUNK_TRAILER_POSTCR; + break; /* don't advance the pointer */ + } + } + else { + result = Curl_dyn_addn(&ch->trailer, buf, 1); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_OUT_OF_MEMORY; + return result; + } + } + buf++; + blen--; + break; + + case CHUNK_TRAILER_CR: + if(*buf == 0x0a) { + ch->state = CHUNK_TRAILER_POSTCR; + buf++; + blen--; + } + else { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_BAD_CHUNK; + return CURLE_RECV_ERROR; + } + break; + + case CHUNK_TRAILER_POSTCR: + /* We enter this state when a CR should arrive so we expect to + have to first pass a CR before we wait for LF */ + if((*buf != 0x0d) && (*buf != 0x0a)) { + /* not a CR then it must be another header in the trailer */ + ch->state = CHUNK_TRAILER; + break; + } + if(*buf == 0x0d) { + /* skip if CR */ + buf++; + blen--; + } + /* now wait for the final LF */ + ch->state = CHUNK_STOP; + break; + + case CHUNK_STOP: + if(*buf == 0x0a) { + blen--; + /* Record the length of any data left in the end of the buffer + even if there's no more chunks to read */ + ch->datasize = blen; + ch->state = CHUNK_DONE; + return CURLE_OK; + } + else { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_BAD_CHUNK; + return CURLE_RECV_ERROR; + } + case CHUNK_DONE: + return CURLE_OK; + + case CHUNK_FAILED: + return CURLE_RECV_ERROR; + } + + } + return CURLE_OK; +} + +static const char *Curl_chunked_strerror(CHUNKcode code) +{ + switch(code) { + default: + return "OK"; + case CHUNKE_TOO_LONG_HEX: + return "Too long hexadecimal number"; + case CHUNKE_ILLEGAL_HEX: + return "Illegal or missing hexadecimal sequence"; + case CHUNKE_BAD_CHUNK: + return "Malformed encoding found"; + case CHUNKE_PASSTHRU_ERROR: + return "Error writing data to client"; + case CHUNKE_BAD_ENCODING: + return "Bad content-encoding found"; + case CHUNKE_OUT_OF_MEMORY: + return "Out of memory"; + } +} + +CURLcode Curl_httpchunk_read(struct Curl_easy *data, + struct Curl_chunker *ch, + char *buf, size_t blen, + size_t *pconsumed) +{ + return httpchunk_readwrite(data, ch, NULL, buf, blen, pconsumed); +} + +struct chunked_writer { + struct Curl_cwriter super; + struct Curl_chunker ch; +}; + +static CURLcode cw_chunked_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct chunked_writer *ctx = (struct chunked_writer *)writer; + + data->req.chunk = TRUE; /* chunks coming our way. */ + Curl_httpchunk_init(data, &ctx->ch, FALSE); + return CURLE_OK; +} + +static void cw_chunked_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct chunked_writer *ctx = (struct chunked_writer *)writer; + Curl_httpchunk_free(data, &ctx->ch); +} + +static CURLcode cw_chunked_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t blen) +{ + struct chunked_writer *ctx = (struct chunked_writer *)writer; + CURLcode result; + size_t consumed; + + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, blen); + + consumed = 0; + result = httpchunk_readwrite(data, &ctx->ch, writer->next, buf, blen, + &consumed); + + if(result) { + if(CHUNKE_PASSTHRU_ERROR == ctx->ch.last_code) { + failf(data, "Failed reading the chunked-encoded stream"); + } + else { + failf(data, "%s in chunked-encoding", + Curl_chunked_strerror(ctx->ch.last_code)); + } + return result; + } + + blen -= consumed; + if(CHUNK_DONE == ctx->ch.state) { + /* chunks read successfully, download is complete */ + data->req.download_done = TRUE; + if(blen) { + infof(data, "Leftovers after chunking: %zu bytes", blen); + } + } + else if((type & CLIENTWRITE_EOS) && !data->req.no_body) { + failf(data, "transfer closed with outstanding read data remaining"); + return CURLE_PARTIAL_FILE; + } + + return CURLE_OK; +} + +/* HTTP chunked Transfer-Encoding decoder */ +const struct Curl_cwtype Curl_httpchunk_unencoder = { + "chunked", + NULL, + cw_chunked_init, + cw_chunked_write, + cw_chunked_close, + sizeof(struct chunked_writer) +}; + +#endif /* CURL_DISABLE_HTTP */ diff --git a/lib/http_chunks.h b/lib/http_chunks.h new file mode 100644 index 0000000..07f2984 --- /dev/null +++ b/lib/http_chunks.h @@ -0,0 +1,138 @@ +#ifndef HEADER_CURL_HTTP_CHUNKS_H +#define HEADER_CURL_HTTP_CHUNKS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifndef CURL_DISABLE_HTTP + +#include "dynbuf.h" + +struct connectdata; + +/* + * The longest possible hexadecimal number we support in a chunked transfer. + * Neither RFC2616 nor the later HTTP specs define a maximum chunk size. + * For 64 bit curl_off_t we support 16 digits. For 32 bit, 8 digits. + */ +#define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2) + +typedef enum { + /* await and buffer all hexadecimal digits until we get one that isn't a + hexadecimal digit. When done, we go CHUNK_LF */ + CHUNK_HEX, + + /* wait for LF, ignore all else */ + CHUNK_LF, + + /* We eat the amount of data specified. When done, we move on to the + POST_CR state. */ + CHUNK_DATA, + + /* POSTLF should get a CR and then a LF and nothing else, then move back to + HEX as the CRLF combination marks the end of a chunk. A missing CR is no + big deal. */ + CHUNK_POSTLF, + + /* Used to mark that we're out of the game. NOTE: that there's a 'datasize' + field in the struct that will tell how many bytes that were not passed to + the client in the end of the last buffer! */ + CHUNK_STOP, + + /* At this point optional trailer headers can be found, unless the next line + is CRLF */ + CHUNK_TRAILER, + + /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. + Next char must be a LF */ + CHUNK_TRAILER_CR, + + /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be + signalled If this is an empty trailer CHUNKE_STOP will be signalled. + Otherwise the trailer will be broadcasted via Curl_client_write() and the + next state will be CHUNK_TRAILER */ + CHUNK_TRAILER_POSTCR, + + /* Successfully de-chunked everything */ + CHUNK_DONE, + + /* Failed on seeing a bad or not correctly terminated chunk */ + CHUNK_FAILED +} ChunkyState; + +typedef enum { + CHUNKE_OK = 0, + CHUNKE_TOO_LONG_HEX = 1, + CHUNKE_ILLEGAL_HEX, + CHUNKE_BAD_CHUNK, + CHUNKE_BAD_ENCODING, + CHUNKE_OUT_OF_MEMORY, + CHUNKE_PASSTHRU_ERROR /* Curl_httpchunk_read() returns a CURLcode to use */ +} CHUNKcode; + +struct Curl_chunker { + curl_off_t datasize; + ChunkyState state; + CHUNKcode last_code; + struct dynbuf trailer; /* for chunked-encoded trailer */ + unsigned char hexindex; + char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */ + BIT(ignore_body); /* never write response body data */ +}; + +/* The following functions are defined in http_chunks.c */ +void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body); +void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch); +void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body); + +/* + * Read BODY bytes in HTTP/1.1 chunked encoding from `buf` and return + * the amount of bytes consumed. The actual response bytes and trailer + * headers are written out to the client. + * On success, this will consume all bytes up to the end of the response, + * e.g. the last chunk, has been processed. + * @param data the transfer involved + * @param ch the chunker instance keeping state across calls + * @param buf the response data + * @param blen amount of bytes in `buf` + * @param pconsumed on successful return, the number of bytes in `buf` + * consumed + * + * This function always uses ASCII hex values to accommodate non-ASCII hosts. + * For example, 0x0d and 0x0a are used instead of '\r' and '\n'. + */ +CURLcode Curl_httpchunk_read(struct Curl_easy *data, struct Curl_chunker *ch, + char *buf, size_t blen, size_t *pconsumed); + +/** + * @return TRUE iff chunked decoded has finished successfully. + */ +bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch); + +extern const struct Curl_cwtype Curl_httpchunk_unencoder; + +#endif /* !CURL_DISABLE_HTTP */ + +#endif /* HEADER_CURL_HTTP_CHUNKS_H */ diff --git a/lib/http_digest.c b/lib/http_digest.c new file mode 100644 index 0000000..2db3125 --- /dev/null +++ b/lib/http_digest.c @@ -0,0 +1,185 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) + +#include "urldata.h" +#include "strcase.h" +#include "vauth/vauth.h" +#include "http_digest.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* Test example headers: + +WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" +Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" + +*/ + +CURLcode Curl_input_digest(struct Curl_easy *data, + bool proxy, + const char *header) /* rest of the *-authenticate: + header */ +{ + /* Point to the correct struct with this */ + struct digestdata *digest; + + if(proxy) { + digest = &data->state.proxydigest; + } + else { + digest = &data->state.digest; + } + + if(!checkprefix("Digest", header) || !ISBLANK(header[6])) + return CURLE_BAD_CONTENT_ENCODING; + + header += strlen("Digest"); + while(*header && ISBLANK(*header)) + header++; + + return Curl_auth_decode_digest_http_message(header, digest); +} + +CURLcode Curl_output_digest(struct Curl_easy *data, + bool proxy, + const unsigned char *request, + const unsigned char *uripath) +{ + CURLcode result; + unsigned char *path = NULL; + char *tmp = NULL; + char *response; + size_t len; + bool have_chlg; + + /* Point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for an HTTP proxy */ + char **allocuserpwd; + + /* Point to the name and password for this */ + const char *userp; + const char *passwdp; + + /* Point to the correct struct with this */ + struct digestdata *digest; + struct auth *authp; + + if(proxy) { +#ifdef CURL_DISABLE_PROXY + return CURLE_NOT_BUILT_IN; +#else + digest = &data->state.proxydigest; + allocuserpwd = &data->state.aptr.proxyuserpwd; + userp = data->state.aptr.proxyuser; + passwdp = data->state.aptr.proxypasswd; + authp = &data->state.authproxy; +#endif + } + else { + digest = &data->state.digest; + allocuserpwd = &data->state.aptr.userpwd; + userp = data->state.aptr.user; + passwdp = data->state.aptr.passwd; + authp = &data->state.authhost; + } + + Curl_safefree(*allocuserpwd); + + /* not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + +#if defined(USE_WINDOWS_SSPI) + have_chlg = digest->input_token ? TRUE : FALSE; +#else + have_chlg = digest->nonce ? TRUE : FALSE; +#endif + + if(!have_chlg) { + authp->done = FALSE; + return CURLE_OK; + } + + /* So IE browsers < v7 cut off the URI part at the query part when they + evaluate the MD5 and some (IIS?) servers work with them so we may need to + do the Digest IE-style. Note that the different ways cause different MD5 + sums to get sent. + + Apache servers can be set to do the Digest IE-style automatically using + the BrowserMatch feature: + https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie + + Further details on Digest implementation differences: + http://www.fngtps.com/2006/09/http-authentication + */ + + if(authp->iestyle) { + tmp = strchr((char *)uripath, '?'); + if(tmp) { + size_t urilen = tmp - (char *)uripath; + /* typecast is fine here since the value is always less than 32 bits */ + path = (unsigned char *) aprintf("%.*s", (int)urilen, uripath); + } + } + if(!tmp) + path = (unsigned char *) strdup((char *) uripath); + + if(!path) + return CURLE_OUT_OF_MEMORY; + + result = Curl_auth_create_digest_http_message(data, userp, passwdp, request, + path, digest, &response, &len); + free(path); + if(result) + return result; + + *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n", + proxy ? "Proxy-" : "", + response); + free(response); + if(!*allocuserpwd) + return CURLE_OUT_OF_MEMORY; + + authp->done = TRUE; + + return CURLE_OK; +} + +void Curl_http_auth_cleanup_digest(struct Curl_easy *data) +{ + Curl_auth_digest_cleanup(&data->state.digest); + Curl_auth_digest_cleanup(&data->state.proxydigest); +} + +#endif diff --git a/lib/http_digest.h b/lib/http_digest.h new file mode 100644 index 0000000..5f79731 --- /dev/null +++ b/lib/http_digest.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_HTTP_DIGEST_H +#define HEADER_CURL_HTTP_DIGEST_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) + +/* this is for digest header input */ +CURLcode Curl_input_digest(struct Curl_easy *data, + bool proxy, const char *header); + +/* this is for creating digest header output */ +CURLcode Curl_output_digest(struct Curl_easy *data, + bool proxy, + const unsigned char *request, + const unsigned char *uripath); + +void Curl_http_auth_cleanup_digest(struct Curl_easy *data); + +#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_DIGEST_AUTH */ + +#endif /* HEADER_CURL_HTTP_DIGEST_H */ diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c new file mode 100644 index 0000000..153e3d4 --- /dev/null +++ b/lib/http_negotiate.c @@ -0,0 +1,224 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) + +#include "urldata.h" +#include "sendf.h" +#include "http_negotiate.h" +#include "vauth/vauth.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, + bool proxy, const char *header) +{ + CURLcode result; + size_t len; + + /* Point to the username, password, service and host */ + const char *userp; + const char *passwdp; + const char *service; + const char *host; + + /* Point to the correct struct with this */ + struct negotiatedata *neg_ctx; + curlnegotiate state; + + if(proxy) { +#ifndef CURL_DISABLE_PROXY + userp = conn->http_proxy.user; + passwdp = conn->http_proxy.passwd; + service = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; + host = conn->http_proxy.host.name; + neg_ctx = &conn->proxyneg; + state = conn->proxy_negotiate_state; +#else + return CURLE_NOT_BUILT_IN; +#endif + } + else { + userp = conn->user; + passwdp = conn->passwd; + service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : "HTTP"; + host = conn->host.name; + neg_ctx = &conn->negotiate; + state = conn->http_negotiate_state; + } + + /* Not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + + /* Obtain the input token, if any */ + header += strlen("Negotiate"); + while(*header && ISBLANK(*header)) + header++; + + len = strlen(header); + neg_ctx->havenegdata = len != 0; + if(!len) { + if(state == GSS_AUTHSUCC) { + infof(data, "Negotiate auth restarted"); + Curl_http_auth_cleanup_negotiate(conn); + } + else if(state != GSS_AUTHNONE) { + /* The server rejected our authentication and hasn't supplied any more + negotiation mechanisms */ + Curl_http_auth_cleanup_negotiate(conn); + return CURLE_LOGIN_DENIED; + } + } + + /* Supports SSL channel binding for Windows ISS extended protection */ +#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS) + neg_ctx->sslContext = conn->sslContext; +#endif + + /* Initialize the security context and decode our challenge */ + result = Curl_auth_decode_spnego_message(data, userp, passwdp, service, + host, header, neg_ctx); + + if(result) + Curl_http_auth_cleanup_negotiate(conn); + + return result; +} + +CURLcode Curl_output_negotiate(struct Curl_easy *data, + struct connectdata *conn, bool proxy) +{ + struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg : + &conn->negotiate; + struct auth *authp = proxy ? &data->state.authproxy : &data->state.authhost; + curlnegotiate *state = proxy ? &conn->proxy_negotiate_state : + &conn->http_negotiate_state; + char *base64 = NULL; + size_t len = 0; + char *userp; + CURLcode result; + + authp->done = FALSE; + + if(*state == GSS_AUTHRECV) { + if(neg_ctx->havenegdata) { + neg_ctx->havemultiplerequests = TRUE; + } + } + else if(*state == GSS_AUTHSUCC) { + if(!neg_ctx->havenoauthpersist) { + neg_ctx->noauthpersist = !neg_ctx->havemultiplerequests; + } + } + + if(neg_ctx->noauthpersist || + (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) { + + if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) { + infof(data, "Curl_output_negotiate, " + "no persistent authentication: cleanup existing context"); + Curl_http_auth_cleanup_negotiate(conn); + } + if(!neg_ctx->context) { + result = Curl_input_negotiate(data, conn, proxy, "Negotiate"); + if(result == CURLE_AUTH_ERROR) { + /* negotiate auth failed, let's continue unauthenticated to stay + * compatible with the behavior before curl-7_64_0-158-g6c6035532 */ + authp->done = TRUE; + return CURLE_OK; + } + else if(result) + return result; + } + + result = Curl_auth_create_spnego_message(neg_ctx, &base64, &len); + if(result) + return result; + + userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", + base64); + + if(proxy) { + Curl_safefree(data->state.aptr.proxyuserpwd); + data->state.aptr.proxyuserpwd = userp; + } + else { + Curl_safefree(data->state.aptr.userpwd); + data->state.aptr.userpwd = userp; + } + + free(base64); + + if(!userp) { + return CURLE_OUT_OF_MEMORY; + } + + *state = GSS_AUTHSENT; + #ifdef HAVE_GSSAPI + if(neg_ctx->status == GSS_S_COMPLETE || + neg_ctx->status == GSS_S_CONTINUE_NEEDED) { + *state = GSS_AUTHDONE; + } + #else + #ifdef USE_WINDOWS_SSPI + if(neg_ctx->status == SEC_E_OK || + neg_ctx->status == SEC_I_CONTINUE_NEEDED) { + *state = GSS_AUTHDONE; + } + #endif + #endif + } + + if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) { + /* connection is already authenticated, + * don't send a header in future requests */ + authp->done = TRUE; + } + + neg_ctx->havenegdata = FALSE; + + return CURLE_OK; +} + +void Curl_http_auth_cleanup_negotiate(struct connectdata *conn) +{ + conn->http_negotiate_state = GSS_AUTHNONE; + conn->proxy_negotiate_state = GSS_AUTHNONE; + + Curl_auth_cleanup_spnego(&conn->negotiate); + Curl_auth_cleanup_spnego(&conn->proxyneg); +} + +#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h new file mode 100644 index 0000000..76d8356 --- /dev/null +++ b/lib/http_negotiate.h @@ -0,0 +1,43 @@ +#ifndef HEADER_CURL_HTTP_NEGOTIATE_H +#define HEADER_CURL_HTTP_NEGOTIATE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) + +/* this is for Negotiate header input */ +CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, + bool proxy, const char *header); + +/* this is for creating Negotiate header output */ +CURLcode Curl_output_negotiate(struct Curl_easy *data, + struct connectdata *conn, bool proxy); + +void Curl_http_auth_cleanup_negotiate(struct connectdata *conn); + +#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */ +#define Curl_http_auth_cleanup_negotiate(x) +#endif + +#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */ diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c new file mode 100644 index 0000000..b845ddf --- /dev/null +++ b/lib/http_ntlm.c @@ -0,0 +1,275 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) + +/* + * NTLM details: + * + * https://davenport.sourceforge.net/ntlm.html + * https://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#include "urldata.h" +#include "sendf.h" +#include "strcase.h" +#include "http_ntlm.h" +#include "curl_ntlm_core.h" +#include "curl_ntlm_wb.h" +#include "curl_base64.h" +#include "vauth/vauth.h" +#include "url.h" + +/* SSL backend-specific #if branches in this file must be kept in the order + documented in curl_ntlm_core. */ +#if defined(USE_WINDOWS_SSPI) +#include "curl_sspi.h" +#endif + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if DEBUG_ME +# define DEBUG_OUT(x) x +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +CURLcode Curl_input_ntlm(struct Curl_easy *data, + bool proxy, /* if proxy or not */ + const char *header) /* rest of the www-authenticate: + header */ +{ + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + curlntlm *state; + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; + state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; + + if(checkprefix("NTLM", header)) { + header += strlen("NTLM"); + + while(*header && ISSPACE(*header)) + header++; + + if(*header) { + unsigned char *hdr; + size_t hdrlen; + + result = Curl_base64_decode(header, &hdr, &hdrlen); + if(!result) { + struct bufref hdrbuf; + + Curl_bufref_init(&hdrbuf); + Curl_bufref_set(&hdrbuf, hdr, hdrlen, curl_free); + result = Curl_auth_decode_ntlm_type2_message(data, &hdrbuf, ntlm); + Curl_bufref_free(&hdrbuf); + } + if(result) + return result; + + *state = NTLMSTATE_TYPE2; /* We got a type-2 message */ + } + else { + if(*state == NTLMSTATE_LAST) { + infof(data, "NTLM auth restarted"); + Curl_http_auth_cleanup_ntlm(conn); + } + else if(*state == NTLMSTATE_TYPE3) { + infof(data, "NTLM handshake rejected"); + Curl_http_auth_cleanup_ntlm(conn); + *state = NTLMSTATE_NONE; + return CURLE_REMOTE_ACCESS_DENIED; + } + else if(*state >= NTLMSTATE_TYPE1) { + infof(data, "NTLM handshake failure (internal error)"); + return CURLE_REMOTE_ACCESS_DENIED; + } + + *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ + } + } + + return result; +} + +/* + * This is for creating ntlm header output + */ +CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) +{ + char *base64 = NULL; + size_t len = 0; + CURLcode result = CURLE_OK; + struct bufref ntlmmsg; + + /* point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for an HTTP proxy */ + char **allocuserpwd; + + /* point to the username, password, service and host */ + const char *userp; + const char *passwdp; + const char *service = NULL; + const char *hostname = NULL; + + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + curlntlm *state; + struct auth *authp; + struct connectdata *conn = data->conn; + + DEBUGASSERT(conn); + DEBUGASSERT(data); + + if(proxy) { +#ifndef CURL_DISABLE_PROXY + allocuserpwd = &data->state.aptr.proxyuserpwd; + userp = data->state.aptr.proxyuser; + passwdp = data->state.aptr.proxypasswd; + service = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; + hostname = conn->http_proxy.host.name; + ntlm = &conn->proxyntlm; + state = &conn->proxy_ntlm_state; + authp = &data->state.authproxy; +#else + return CURLE_NOT_BUILT_IN; +#endif + } + else { + allocuserpwd = &data->state.aptr.userpwd; + userp = data->state.aptr.user; + passwdp = data->state.aptr.passwd; + service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : "HTTP"; + hostname = conn->host.name; + ntlm = &conn->ntlm; + state = &conn->http_ntlm_state; + authp = &data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + +#ifdef USE_WINDOWS_SSPI + if(!s_hSecDll) { + /* not thread safe and leaks - use curl_global_init() to avoid */ + CURLcode err = Curl_sspi_global_init(); + if(!s_hSecDll) + return err; + } +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + ntlm->sslContext = conn->sslContext; +#endif +#endif + + Curl_bufref_init(&ntlmmsg); + + /* connection is already authenticated, don't send a header in future + * requests so go directly to NTLMSTATE_LAST */ + if(*state == NTLMSTATE_TYPE3) + *state = NTLMSTATE_LAST; + + switch(*state) { + case NTLMSTATE_TYPE1: + default: /* for the weird cases we (re)start here */ + /* Create a type-1 message */ + result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, + service, hostname, + ntlm, &ntlmmsg); + if(!result) { + DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0); + result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg), + Curl_bufref_len(&ntlmmsg), &base64, &len); + if(!result) { + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + free(base64); + if(!*allocuserpwd) + result = CURLE_OUT_OF_MEMORY; + } + } + break; + + case NTLMSTATE_TYPE2: + /* We already received the type-2 message, create a type-3 message */ + result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp, + ntlm, &ntlmmsg); + if(!result && Curl_bufref_len(&ntlmmsg)) { + result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg), + Curl_bufref_len(&ntlmmsg), &base64, &len); + if(!result) { + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + free(base64); + if(!*allocuserpwd) + result = CURLE_OUT_OF_MEMORY; + else { + *state = NTLMSTATE_TYPE3; /* we send a type-3 */ + authp->done = TRUE; + } + } + } + break; + + case NTLMSTATE_LAST: + Curl_safefree(*allocuserpwd); + authp->done = TRUE; + break; + } + Curl_bufref_free(&ntlmmsg); + + return result; +} + +void Curl_http_auth_cleanup_ntlm(struct connectdata *conn) +{ + Curl_auth_cleanup_ntlm(&conn->ntlm); + Curl_auth_cleanup_ntlm(&conn->proxyntlm); + +#if defined(NTLM_WB_ENABLED) + Curl_http_auth_cleanup_ntlm_wb(conn); +#endif +} + +#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h new file mode 100644 index 0000000..f37572b --- /dev/null +++ b/lib/http_ntlm.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_HTTP_NTLM_H +#define HEADER_CURL_HTTP_NTLM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) + +/* this is for ntlm header input */ +CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy, + const char *header); + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy); + +void Curl_http_auth_cleanup_ntlm(struct connectdata *conn); + +#else /* !CURL_DISABLE_HTTP && USE_NTLM */ +#define Curl_http_auth_cleanup_ntlm(x) +#endif + +#endif /* HEADER_CURL_HTTP_NTLM_H */ diff --git a/lib/http_proxy.c b/lib/http_proxy.c new file mode 100644 index 0000000..113c43a --- /dev/null +++ b/lib/http_proxy.c @@ -0,0 +1,336 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "http_proxy.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) + +#include +#ifdef USE_HYPER +#include +#endif +#include "sendf.h" +#include "http.h" +#include "url.h" +#include "select.h" +#include "progress.h" +#include "cfilters.h" +#include "cf-h1-proxy.h" +#include "cf-h2-proxy.h" +#include "connect.h" +#include "curlx.h" +#include "vtls/vtls.h" +#include "transfer.h" +#include "multiif.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf, + const char **phostname, + int *pport, bool *pipv6_ip) +{ + DEBUGASSERT(cf); + DEBUGASSERT(cf->conn); + + if(cf->conn->bits.conn_to_host) + *phostname = cf->conn->conn_to_host.name; + else if(cf->sockindex == SECONDARYSOCKET) + *phostname = cf->conn->secondaryhostname; + else + *phostname = cf->conn->host.name; + + if(cf->sockindex == SECONDARYSOCKET) + *pport = cf->conn->secondary_port; + else if(cf->conn->bits.conn_to_port) + *pport = cf->conn->conn_to_port; + else + *pport = cf->conn->remote_port; + + if(*phostname != cf->conn->host.name) + *pipv6_ip = (strchr(*phostname, ':') != NULL); + else + *pipv6_ip = cf->conn->bits.ipv6_ip; + + return CURLE_OK; +} + +CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, + struct Curl_cfilter *cf, + struct Curl_easy *data, + int http_version_major) +{ + const char *hostname = NULL; + char *authority = NULL; + int port; + bool ipv6_ip; + CURLcode result; + struct httpreq *req = NULL; + + result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip); + if(result) + goto out; + + authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, + ipv6_ip?"]":"", port); + if(!authority) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + result = Curl_http_req_make(&req, "CONNECT", sizeof("CONNECT")-1, + NULL, 0, authority, strlen(authority), + NULL, 0); + if(result) + goto out; + + /* Setup the proxy-authorization header, if any */ + result = Curl_http_output_auth(data, cf->conn, req->method, HTTPREQ_GET, + req->authority, TRUE); + if(result) + goto out; + + /* If user is not overriding Host: header, we add for HTTP/1.x */ + if(http_version_major == 1 && + !Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) { + result = Curl_dynhds_cadd(&req->headers, "Host", authority); + if(result) + goto out; + } + + if(data->state.aptr.proxyuserpwd) { + result = Curl_dynhds_h1_cadd_line(&req->headers, + data->state.aptr.proxyuserpwd); + if(result) + goto out; + } + + if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) && + data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) { + result = Curl_dynhds_cadd(&req->headers, "User-Agent", + data->set.str[STRING_USERAGENT]); + if(result) + goto out; + } + + if(http_version_major == 1 && + !Curl_checkProxyheaders(data, cf->conn, STRCONST("Proxy-Connection"))) { + result = Curl_dynhds_cadd(&req->headers, "Proxy-Connection", "Keep-Alive"); + if(result) + goto out; + } + + result = Curl_dynhds_add_custom(data, TRUE, &req->headers); + +out: + if(result && req) { + Curl_http_req_free(req); + req = NULL; + } + free(authority); + *preq = req; + return result; +} + + +struct cf_proxy_ctx { + /* the protocol specific sub-filter we install during connect */ + struct Curl_cfilter *cf_protocol; +}; + +static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_proxy_ctx *ctx = cf->ctx; + CURLcode result; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + CURL_TRC_CF(data, cf, "connect"); +connect_sub: + result = cf->next->cft->do_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + + *done = FALSE; + if(!ctx->cf_protocol) { + struct Curl_cfilter *cf_protocol = NULL; + int alpn = Curl_conn_cf_is_ssl(cf->next)? + cf->conn->proxy_alpn : CURL_HTTP_VERSION_1_1; + + /* First time call after the subchain connected */ + switch(alpn) { + case CURL_HTTP_VERSION_NONE: + case CURL_HTTP_VERSION_1_0: + case CURL_HTTP_VERSION_1_1: + CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.1"); + infof(data, "CONNECT tunnel: HTTP/1.%d negotiated", + (alpn == CURL_HTTP_VERSION_1_0)? 0 : 1); + result = Curl_cf_h1_proxy_insert_after(cf, data); + if(result) + goto out; + cf_protocol = cf->next; + break; +#ifdef USE_NGHTTP2 + case CURL_HTTP_VERSION_2: + CURL_TRC_CF(data, cf, "installing subfilter for HTTP/2"); + infof(data, "CONNECT tunnel: HTTP/2 negotiated"); + result = Curl_cf_h2_proxy_insert_after(cf, data); + if(result) + goto out; + cf_protocol = cf->next; + break; +#endif + default: + infof(data, "CONNECT tunnel: unsupported ALPN(%d) negotiated", alpn); + result = CURLE_COULDNT_CONNECT; + goto out; + } + + ctx->cf_protocol = cf_protocol; + /* after we installed the filter "below" us, we call connect + * on out sub-chain again. + */ + goto connect_sub; + } + else { + /* subchain connected and we had already installed the protocol filter. + * This means the protocol tunnel is established, we are done. + */ + DEBUGASSERT(ctx->cf_protocol); + result = CURLE_OK; + } + +out: + if(!result) { + cf->connected = TRUE; + *done = TRUE; + } + return result; +} + +void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char **phost, + const char **pdisplay_host, + int *pport) +{ + (void)data; + if(!cf->connected) { + *phost = cf->conn->http_proxy.host.name; + *pdisplay_host = cf->conn->http_proxy.host.dispname; + *pport = (int)cf->conn->http_proxy.port; + } + else { + cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport); + } +} + +static void http_proxy_cf_destroy(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_proxy_ctx *ctx = cf->ctx; + + (void)data; + CURL_TRC_CF(data, cf, "destroy"); + free(ctx); +} + +static void http_proxy_cf_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_proxy_ctx *ctx = cf->ctx; + + CURL_TRC_CF(data, cf, "close"); + cf->connected = FALSE; + if(ctx->cf_protocol) { + struct Curl_cfilter *f; + /* if someone already removed it, we assume he also + * took care of destroying it. */ + for(f = cf->next; f; f = f->next) { + if(f == ctx->cf_protocol) { + /* still in our sub-chain */ + Curl_conn_cf_discard_sub(cf, ctx->cf_protocol, data, FALSE); + break; + } + } + ctx->cf_protocol = NULL; + } + if(cf->next) + cf->next->cft->do_close(cf->next, data); +} + + +struct Curl_cftype Curl_cft_http_proxy = { + "HTTP-PROXY", + CF_TYPE_IP_CONNECT, + 0, + http_proxy_cf_destroy, + http_proxy_cf_connect, + http_proxy_cf_close, + Curl_cf_http_proxy_get_host, + Curl_cf_def_adjust_pollset, + Curl_cf_def_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, +}; + +CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + struct cf_proxy_ctx *ctx = NULL; + CURLcode result; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + result = Curl_cf_create(&cf, &Curl_cft_http_proxy, ctx); + if(result) + goto out; + ctx = NULL; + Curl_conn_cf_insert_after(cf_at, cf); + +out: + free(ctx); + return result; +} + +#endif /* ! CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ diff --git a/lib/http_proxy.h b/lib/http_proxy.h new file mode 100644 index 0000000..2b5f7ae --- /dev/null +++ b/lib/http_proxy.h @@ -0,0 +1,61 @@ +#ifndef HEADER_CURL_HTTP_PROXY_H +#define HEADER_CURL_HTTP_PROXY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) + +#include "urldata.h" + +CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf, + const char **phostname, + int *pport, bool *pipv6_ip); + +CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, + struct Curl_cfilter *cf, + struct Curl_easy *data, + int http_version_major); + +/* Default proxy timeout in milliseconds */ +#define PROXY_TIMEOUT (3600*1000) + +void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char **phost, + const char **pdisplay_host, + int *pport); + +CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data); + +extern struct Curl_cftype Curl_cft_http_proxy; + +#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */ + +#define IS_HTTPS_PROXY(t) (((t) == CURLPROXY_HTTPS) || \ + ((t) == CURLPROXY_HTTPS2)) + +#endif /* HEADER_CURL_HTTP_PROXY_H */ diff --git a/lib/idn.c b/lib/idn.c new file mode 100644 index 0000000..81a177f --- /dev/null +++ b/lib/idn.c @@ -0,0 +1,287 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + + /* + * IDN conversions + */ + +#include "curl_setup.h" +#include "urldata.h" +#include "idn.h" +#include "sendf.h" +#include "curl_multibyte.h" +#include "warnless.h" + +#ifdef USE_LIBIDN2 +#include + +#if defined(_WIN32) && defined(UNICODE) +#define IDN2_LOOKUP(name, host, flags) \ + idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags) +#else +#define IDN2_LOOKUP(name, host, flags) \ + idn2_lookup_ul((const char *)name, (char **)host, flags) +#endif +#endif /* USE_LIBIDN2 */ + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef USE_WIN32_IDN +/* using Windows kernel32 and normaliz libraries. */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600 +WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, + const WCHAR *lpUnicodeCharStr, + int cchUnicodeChar, + WCHAR *lpASCIICharStr, + int cchASCIIChar); +WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, + const WCHAR *lpASCIICharStr, + int cchASCIIChar, + WCHAR *lpUnicodeCharStr, + int cchUnicodeChar); +#endif + +#define IDN_MAX_LENGTH 255 + +static CURLcode win32_idn_to_ascii(const char *in, char **out) +{ + wchar_t *in_w = curlx_convert_UTF8_to_wchar(in); + *out = NULL; + if(in_w) { + wchar_t punycode[IDN_MAX_LENGTH]; + int chars = IdnToAscii(0, in_w, (int)(wcslen(in_w) + 1), punycode, + IDN_MAX_LENGTH); + curlx_unicodefree(in_w); + if(chars) { + char *mstr = curlx_convert_wchar_to_UTF8(punycode); + if(mstr) { + *out = strdup(mstr); + curlx_unicodefree(mstr); + if(!*out) + return CURLE_OUT_OF_MEMORY; + } + else + return CURLE_OUT_OF_MEMORY; + } + else + return CURLE_URL_MALFORMAT; + } + else + return CURLE_URL_MALFORMAT; + + return CURLE_OK; +} + +static CURLcode win32_ascii_to_idn(const char *in, char **output) +{ + char *out = NULL; + + wchar_t *in_w = curlx_convert_UTF8_to_wchar(in); + if(in_w) { + WCHAR idn[IDN_MAX_LENGTH]; /* stores a UTF-16 string */ + int chars = IdnToUnicode(0, in_w, (int)(wcslen(in_w) + 1), idn, + IDN_MAX_LENGTH); + if(chars) { + /* 'chars' is "the number of characters retrieved" */ + char *mstr = curlx_convert_wchar_to_UTF8(idn); + if(mstr) { + out = strdup(mstr); + curlx_unicodefree(mstr); + if(!out) + return CURLE_OUT_OF_MEMORY; + } + } + else + return CURLE_URL_MALFORMAT; + } + else + return CURLE_URL_MALFORMAT; + *output = out; + return CURLE_OK; +} + +#endif /* USE_WIN32_IDN */ + +/* + * Helpers for IDNA conversions. + */ +bool Curl_is_ASCII_name(const char *hostname) +{ + /* get an UNSIGNED local version of the pointer */ + const unsigned char *ch = (const unsigned char *)hostname; + + if(!hostname) /* bad input, consider it ASCII! */ + return TRUE; + + while(*ch) { + if(*ch++ & 0x80) + return FALSE; + } + return TRUE; +} + +#ifdef USE_IDN +/* + * Curl_idn_decode() returns an allocated IDN decoded string if it was + * possible. NULL on error. + * + * CURLE_URL_MALFORMAT - the host name could not be converted + * CURLE_OUT_OF_MEMORY - memory problem + * + */ +static CURLcode idn_decode(const char *input, char **output) +{ + char *decoded = NULL; + CURLcode result = CURLE_OK; +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { + int flags = IDN2_NFC_INPUT +#if IDN2_VERSION_NUMBER >= 0x00140000 + /* IDN2_NFC_INPUT: Normalize input string using normalization form C. + IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional + processing. */ + | IDN2_NONTRANSITIONAL +#endif + ; + int rc = IDN2_LOOKUP(input, &decoded, flags); + if(rc != IDN2_OK) + /* fallback to TR46 Transitional mode for better IDNA2003 + compatibility */ + rc = IDN2_LOOKUP(input, &decoded, IDN2_TRANSITIONAL); + if(rc != IDN2_OK) + result = CURLE_URL_MALFORMAT; + } + else + /* a too old libidn2 version */ + result = CURLE_NOT_BUILT_IN; +#elif defined(USE_WIN32_IDN) + result = win32_idn_to_ascii(input, &decoded); +#endif + if(!result) + *output = decoded; + return result; +} + +static CURLcode idn_encode(const char *puny, char **output) +{ + char *enc = NULL; +#ifdef USE_LIBIDN2 + int rc = idn2_to_unicode_8z8z(puny, &enc, 0); + if(rc != IDNA_SUCCESS) + return rc == IDNA_MALLOC_ERROR ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT; +#elif defined(USE_WIN32_IDN) + CURLcode result = win32_ascii_to_idn(puny, &enc); + if(result) + return result; +#endif + *output = enc; + return CURLE_OK; +} + +CURLcode Curl_idn_decode(const char *input, char **output) +{ + char *d = NULL; + CURLcode result = idn_decode(input, &d); +#ifdef USE_LIBIDN2 + if(!result) { + char *c = strdup(d); + idn2_free(d); + if(c) + d = c; + else + result = CURLE_OUT_OF_MEMORY; + } +#endif + if(!result) + *output = d; + return result; +} + +CURLcode Curl_idn_encode(const char *puny, char **output) +{ + char *d = NULL; + CURLcode result = idn_encode(puny, &d); +#ifdef USE_LIBIDN2 + if(!result) { + char *c = strdup(d); + idn2_free(d); + if(c) + d = c; + else + result = CURLE_OUT_OF_MEMORY; + } +#endif + if(!result) + *output = d; + return result; +} + +/* + * Frees data allocated by idnconvert_hostname() + */ +void Curl_free_idnconverted_hostname(struct hostname *host) +{ + if(host->encalloc) { + /* must be freed with idn2_free() if allocated by libidn */ + Curl_idn_free(host->encalloc); + host->encalloc = NULL; + } +} + +#endif /* USE_IDN */ + +/* + * Perform any necessary IDN conversion of hostname + */ +CURLcode Curl_idnconvert_hostname(struct hostname *host) +{ + /* set the name we use to display the host name */ + host->dispname = host->name; + +#ifdef USE_IDN + /* Check name for non-ASCII and convert hostname if we can */ + if(!Curl_is_ASCII_name(host->name)) { + char *decoded; + CURLcode result = idn_decode(host->name, &decoded); + if(!result) { + if(!*decoded) { + /* zero length is a bad host name */ + Curl_idn_free(decoded); + return CURLE_URL_MALFORMAT; + } + /* successful */ + host->encalloc = decoded; + /* change the name pointer to point to the encoded hostname */ + host->name = host->encalloc; + } + else + return result; + } +#endif + return CURLE_OK; +} diff --git a/lib/idn.h b/lib/idn.h new file mode 100644 index 0000000..74bbcaf --- /dev/null +++ b/lib/idn.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_IDN_H +#define HEADER_CURL_IDN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +bool Curl_is_ASCII_name(const char *hostname); +CURLcode Curl_idnconvert_hostname(struct hostname *host); +#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) +#define USE_IDN +void Curl_free_idnconverted_hostname(struct hostname *host); +CURLcode Curl_idn_decode(const char *input, char **output); +CURLcode Curl_idn_encode(const char *input, char **output); +#ifdef USE_LIBIDN2 +#define Curl_idn_free(x) idn2_free(x) +#else +#define Curl_idn_free(x) free(x) +#endif + +#else +#define Curl_free_idnconverted_hostname(x) +#define Curl_idn_decode(x) NULL +#endif +#endif /* HEADER_CURL_IDN_H */ diff --git a/lib/if2ip.c b/lib/if2ip.c new file mode 100644 index 0000000..5249f6c --- /dev/null +++ b/lib/if2ip.c @@ -0,0 +1,260 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_NET_IF_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_SYS_SOCKIO_H +# include +#endif +#ifdef HAVE_IFADDRS_H +# include +#endif +#ifdef HAVE_STROPTS_H +# include +#endif +#ifdef __VMS +# include +#endif + +#include "inet_ntop.h" +#include "strcase.h" +#include "if2ip.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* ------------------------------------------------------------------ */ + +#ifdef ENABLE_IPV6 +/* Return the scope of the given address. */ +unsigned int Curl_ipv6_scope(const struct sockaddr *sa) +{ + if(sa->sa_family == AF_INET6) { + const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa; + const unsigned char *b = sa6->sin6_addr.s6_addr; + unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); + + if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */ + return IPV6_SCOPE_UNIQUELOCAL; + switch(w & 0xFFC0) { + case 0xFE80: + return IPV6_SCOPE_LINKLOCAL; + case 0xFEC0: + return IPV6_SCOPE_SITELOCAL; + case 0x0000: + w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] | + b[10] | b[11] | b[12] | b[13] | b[14]; + if(w || b[15] != 0x01) + break; + return IPV6_SCOPE_NODELOCAL; + default: + break; + } + } + return IPV6_SCOPE_GLOBAL; +} +#endif + +#ifndef CURL_DISABLE_BINDLOCAL + +#if defined(HAVE_GETIFADDRS) + +if2ip_result_t Curl_if2ip(int af, +#ifdef ENABLE_IPV6 + unsigned int remote_scope, + unsigned int local_scope_id, +#endif + const char *interf, + char *buf, int buf_size) +{ + struct ifaddrs *iface, *head; + if2ip_result_t res = IF2IP_NOT_FOUND; + +#if defined(ENABLE_IPV6) && \ + !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) + (void) local_scope_id; +#endif + + if(getifaddrs(&head) >= 0) { + for(iface = head; iface != NULL; iface = iface->ifa_next) { + if(iface->ifa_addr) { + if(iface->ifa_addr->sa_family == af) { + if(strcasecompare(iface->ifa_name, interf)) { + void *addr; + const char *ip; + char scope[12] = ""; + char ipstr[64]; +#ifdef ENABLE_IPV6 + if(af == AF_INET6) { +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + unsigned int scopeid = 0; +#endif + unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); + + if(ifscope != remote_scope) { + /* We are interested only in interface addresses whose scope + matches the remote address we want to connect to: global + for global, link-local for link-local, etc... */ + if(res == IF2IP_NOT_FOUND) + res = IF2IP_AF_NOT_SUPPORTED; + continue; + } + + addr = + &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr; +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + /* Include the scope of this interface as part of the address */ + scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr) + ->sin6_scope_id; + + /* If given, scope id should match. */ + if(local_scope_id && scopeid != local_scope_id) { + if(res == IF2IP_NOT_FOUND) + res = IF2IP_AF_NOT_SUPPORTED; + + continue; + } + + if(scopeid) + msnprintf(scope, sizeof(scope), "%%%u", scopeid); +#endif + } + else +#endif + addr = + &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; + res = IF2IP_FOUND; + ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); + msnprintf(buf, buf_size, "%s%s", ip, scope); + break; + } + } + else if((res == IF2IP_NOT_FOUND) && + strcasecompare(iface->ifa_name, interf)) { + res = IF2IP_AF_NOT_SUPPORTED; + } + } + } + + freeifaddrs(head); + } + + return res; +} + +#elif defined(HAVE_IOCTL_SIOCGIFADDR) + +if2ip_result_t Curl_if2ip(int af, +#ifdef ENABLE_IPV6 + unsigned int remote_scope, + unsigned int local_scope_id, +#endif + const char *interf, + char *buf, int buf_size) +{ + struct ifreq req; + struct in_addr in; + struct sockaddr_in *s; + curl_socket_t dummy; + size_t len; + const char *r; + +#ifdef ENABLE_IPV6 + (void)remote_scope; + (void)local_scope_id; +#endif + + if(!interf || (af != AF_INET)) + return IF2IP_NOT_FOUND; + + len = strlen(interf); + if(len >= sizeof(req.ifr_name)) + return IF2IP_NOT_FOUND; + + dummy = socket(AF_INET, SOCK_STREAM, 0); + if(CURL_SOCKET_BAD == dummy) + return IF2IP_NOT_FOUND; + + memset(&req, 0, sizeof(req)); + memcpy(req.ifr_name, interf, len + 1); + req.ifr_addr.sa_family = AF_INET; + + if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { + sclose(dummy); + /* With SIOCGIFADDR, we cannot tell the difference between an interface + that does not exist and an interface that has no address of the + correct family. Assume the interface does not exist */ + return IF2IP_NOT_FOUND; + } + + s = (struct sockaddr_in *)(void *)&req.ifr_addr; + memcpy(&in, &s->sin_addr, sizeof(in)); + r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size); + + sclose(dummy); + if(!r) + return IF2IP_NOT_FOUND; + return IF2IP_FOUND; +} + +#else + +if2ip_result_t Curl_if2ip(int af, +#ifdef ENABLE_IPV6 + unsigned int remote_scope, + unsigned int local_scope_id, +#endif + const char *interf, + char *buf, int buf_size) +{ + (void) af; +#ifdef ENABLE_IPV6 + (void) remote_scope; + (void) local_scope_id; +#endif + (void) interf; + (void) buf; + (void) buf_size; + return IF2IP_NOT_FOUND; +} + +#endif + +#endif /* CURL_DISABLE_BINDLOCAL */ diff --git a/lib/if2ip.h b/lib/if2ip.h new file mode 100644 index 0000000..1f97350 --- /dev/null +++ b/lib/if2ip.h @@ -0,0 +1,92 @@ +#ifndef HEADER_CURL_IF2IP_H +#define HEADER_CURL_IF2IP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +/* IPv6 address scopes. */ +#define IPV6_SCOPE_GLOBAL 0 /* Global scope. */ +#define IPV6_SCOPE_LINKLOCAL 1 /* Link-local scope. */ +#define IPV6_SCOPE_SITELOCAL 2 /* Site-local scope (deprecated). */ +#define IPV6_SCOPE_UNIQUELOCAL 3 /* Unique local */ +#define IPV6_SCOPE_NODELOCAL 4 /* Loopback. */ + +#ifdef ENABLE_IPV6 +unsigned int Curl_ipv6_scope(const struct sockaddr *sa); +#else +#define Curl_ipv6_scope(x) 0 +#endif + +typedef enum { + IF2IP_NOT_FOUND = 0, /* Interface not found */ + IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */ + IF2IP_FOUND = 2 /* The address has been stored in "buf" */ +} if2ip_result_t; + +if2ip_result_t Curl_if2ip(int af, +#ifdef ENABLE_IPV6 + unsigned int remote_scope, + unsigned int local_scope_id, +#endif + const char *interf, + char *buf, int buf_size); + +#ifdef __INTERIX + +/* Nedelcho Stanev's work-around for SFU 3.0 */ +struct ifreq { +#define IFNAMSIZ 16 +#define IFHWADDRLEN 6 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_metric; + int ifru_mtu; + } ifr_ifru; +}; + +/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the + C code. */ + +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +#define ifr_metric ifr_ifru.ifru_metric /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ + +#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ + +#endif /* __INTERIX */ + +#endif /* HEADER_CURL_IF2IP_H */ diff --git a/lib/imap.c b/lib/imap.c new file mode 100644 index 0000000..f9211d9 --- /dev/null +++ b/lib/imap.c @@ -0,0 +1,2115 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC2195 CRAM-MD5 authentication + * RFC2595 Using TLS with IMAP, POP3 and ACAP + * RFC2831 DIGEST-MD5 authentication + * RFC3501 IMAPv4 protocol + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4616 PLAIN authentication + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * RFC4959 IMAP Extension for SASL Initial Client Response + * RFC5092 IMAP URL Scheme + * RFC6749 OAuth 2.0 Authorization Framework + * RFC8314 Use of TLS for Email Submission and Access + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_IMAP + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "socks.h" +#include "imap.h" +#include "mime.h" +#include "strtoofft.h" +#include "strcase.h" +#include "vtls/vtls.h" +#include "cfilters.h" +#include "connect.h" +#include "select.h" +#include "multiif.h" +#include "url.h" +#include "bufref.h" +#include "curl_sasl.h" +#include "warnless.h" +#include "curl_ctype.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* Local API functions */ +static CURLcode imap_regular_transfer(struct Curl_easy *data, bool *done); +static CURLcode imap_do(struct Curl_easy *data, bool *done); +static CURLcode imap_done(struct Curl_easy *data, CURLcode status, + bool premature); +static CURLcode imap_connect(struct Curl_easy *data, bool *done); +static CURLcode imap_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); +static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done); +static int imap_getsock(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks); +static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done); +static CURLcode imap_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static char *imap_atom(const char *str, bool escape_only); +static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...) + CURL_PRINTF(2, 3); +static CURLcode imap_parse_url_options(struct connectdata *conn); +static CURLcode imap_parse_url_path(struct Curl_easy *data); +static CURLcode imap_parse_custom_request(struct Curl_easy *data); +static CURLcode imap_perform_authenticate(struct Curl_easy *data, + const char *mech, + const struct bufref *initresp); +static CURLcode imap_continue_authenticate(struct Curl_easy *data, + const char *mech, + const struct bufref *resp); +static CURLcode imap_cancel_authenticate(struct Curl_easy *data, + const char *mech); +static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out); + +/* + * IMAP protocol handler. + */ + +const struct Curl_handler Curl_handler_imap = { + "IMAP", /* scheme */ + imap_setup_connection, /* setup_connection */ + imap_do, /* do_it */ + imap_done, /* done */ + ZERO_NULL, /* do_more */ + imap_connect, /* connect_it */ + imap_multi_statemach, /* connecting */ + imap_doing, /* doing */ + imap_getsock, /* proto_getsock */ + imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + imap_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_IMAP, /* defport */ + CURLPROTO_IMAP, /* protocol */ + CURLPROTO_IMAP, /* family */ + PROTOPT_CLOSEACTION| /* flags */ + PROTOPT_URLOPTIONS +}; + +#ifdef USE_SSL +/* + * IMAPS protocol handler. + */ + +const struct Curl_handler Curl_handler_imaps = { + "IMAPS", /* scheme */ + imap_setup_connection, /* setup_connection */ + imap_do, /* do_it */ + imap_done, /* done */ + ZERO_NULL, /* do_more */ + imap_connect, /* connect_it */ + imap_multi_statemach, /* connecting */ + imap_doing, /* doing */ + imap_getsock, /* proto_getsock */ + imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + imap_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_IMAPS, /* defport */ + CURLPROTO_IMAPS, /* protocol */ + CURLPROTO_IMAP, /* family */ + PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */ + PROTOPT_URLOPTIONS +}; +#endif + +#define IMAP_RESP_OK 1 +#define IMAP_RESP_NOT_OK 2 +#define IMAP_RESP_PREAUTH 3 + +/* SASL parameters for the imap protocol */ +static const struct SASLproto saslimap = { + "imap", /* The service name */ + imap_perform_authenticate, /* Send authentication command */ + imap_continue_authenticate, /* Send authentication continuation */ + imap_cancel_authenticate, /* Send authentication cancellation */ + imap_get_message, /* Get SASL response message */ + 0, /* No maximum initial response length */ + '+', /* Code received when continuation is expected */ + IMAP_RESP_OK, /* Code to receive upon authentication success */ + SASL_AUTH_DEFAULT, /* Default mechanisms */ + SASL_FLAG_BASE64 /* Configuration flags */ +}; + + +#ifdef USE_SSL +static void imap_to_imaps(struct connectdata *conn) +{ + /* Change the connection handler */ + conn->handler = &Curl_handler_imaps; + + /* Set the connection's upgraded to TLS flag */ + conn->bits.tls_upgraded = TRUE; +} +#else +#define imap_to_imaps(x) Curl_nop_stmt +#endif + +/*********************************************************************** + * + * imap_matchresp() + * + * Determines whether the untagged response is related to the specified + * command by checking if it is in format "* ..." or + * "* ...". + * + * The "* " marker is assumed to have already been checked by the caller. + */ +static bool imap_matchresp(const char *line, size_t len, const char *cmd) +{ + const char *end = line + len; + size_t cmd_len = strlen(cmd); + + /* Skip the untagged response marker */ + line += 2; + + /* Do we have a number after the marker? */ + if(line < end && ISDIGIT(*line)) { + /* Skip the number */ + do + line++; + while(line < end && ISDIGIT(*line)); + + /* Do we have the space character? */ + if(line == end || *line != ' ') + return FALSE; + + line++; + } + + /* Does the command name match and is it followed by a space character or at + the end of line? */ + if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) && + (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) + return TRUE; + + return FALSE; +} + +/*********************************************************************** + * + * imap_endofresp() + * + * Checks whether the given string is a valid tagged, untagged or continuation + * response which can be processed by the response handler. + */ +static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn, + char *line, size_t len, int *resp) +{ + struct IMAP *imap = data->req.p.imap; + struct imap_conn *imapc = &conn->proto.imapc; + const char *id = imapc->resptag; + size_t id_len = strlen(id); + + /* Do we have a tagged command response? */ + if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') { + line += id_len + 1; + len -= id_len + 1; + + if(len >= 2 && !memcmp(line, "OK", 2)) + *resp = IMAP_RESP_OK; + else if(len >= 7 && !memcmp(line, "PREAUTH", 7)) + *resp = IMAP_RESP_PREAUTH; + else + *resp = IMAP_RESP_NOT_OK; + + return TRUE; + } + + /* Do we have an untagged command response? */ + if(len >= 2 && !memcmp("* ", line, 2)) { + switch(imapc->state) { + /* States which are interested in untagged responses */ + case IMAP_CAPABILITY: + if(!imap_matchresp(line, len, "CAPABILITY")) + return FALSE; + break; + + case IMAP_LIST: + if((!imap->custom && !imap_matchresp(line, len, "LIST")) || + (imap->custom && !imap_matchresp(line, len, imap->custom) && + (!strcasecompare(imap->custom, "STORE") || + !imap_matchresp(line, len, "FETCH")) && + !strcasecompare(imap->custom, "SELECT") && + !strcasecompare(imap->custom, "EXAMINE") && + !strcasecompare(imap->custom, "SEARCH") && + !strcasecompare(imap->custom, "EXPUNGE") && + !strcasecompare(imap->custom, "LSUB") && + !strcasecompare(imap->custom, "UID") && + !strcasecompare(imap->custom, "GETQUOTAROOT") && + !strcasecompare(imap->custom, "NOOP"))) + return FALSE; + break; + + case IMAP_SELECT: + /* SELECT is special in that its untagged responses do not have a + common prefix so accept anything! */ + break; + + case IMAP_FETCH: + if(!imap_matchresp(line, len, "FETCH")) + return FALSE; + break; + + case IMAP_SEARCH: + if(!imap_matchresp(line, len, "SEARCH")) + return FALSE; + break; + + /* Ignore other untagged responses */ + default: + return FALSE; + } + + *resp = '*'; + return TRUE; + } + + /* Do we have a continuation response? This should be a + symbol followed by + a space and optionally some text as per RFC-3501 for the AUTHENTICATE and + APPEND commands and as outlined in Section 4. Examples of RFC-4959 but + some email servers ignore this and only send a single + instead. */ + if(imap && !imap->custom && ((len == 3 && line[0] == '+') || + (len >= 2 && !memcmp("+ ", line, 2)))) { + switch(imapc->state) { + /* States which are interested in continuation responses */ + case IMAP_AUTHENTICATE: + case IMAP_APPEND: + *resp = '+'; + break; + + default: + failf(data, "Unexpected continuation response"); + *resp = -1; + break; + } + + return TRUE; + } + + return FALSE; /* Nothing for us */ +} + +/*********************************************************************** + * + * imap_get_message() + * + * Gets the authentication message from the response buffer. + */ +static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out) +{ + char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); + size_t len = data->conn->proto.imapc.pp.nfinal; + + if(len > 2) { + /* Find the start of the message */ + len -= 2; + for(message += 2; *message == ' ' || *message == '\t'; message++, len--) + ; + + /* Find the end of the message */ + while(len--) + if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && + message[len] != '\t') + break; + + /* Terminate the message */ + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); + } + else + /* junk input => zero length output */ + Curl_bufref_set(out, "", 0, NULL); + + return CURLE_OK; +} + +/*********************************************************************** + * + * imap_state() + * + * This is the ONLY way to change IMAP state! + */ +static void imap_state(struct Curl_easy *data, imapstate newstate) +{ + struct imap_conn *imapc = &data->conn->proto.imapc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[]={ + "STOP", + "SERVERGREET", + "CAPABILITY", + "STARTTLS", + "UPGRADETLS", + "AUTHENTICATE", + "LOGIN", + "LIST", + "SELECT", + "FETCH", + "FETCH_FINAL", + "APPEND", + "APPEND_FINAL", + "SEARCH", + "LOGOUT", + /* LAST */ + }; + + if(imapc->state != newstate) + infof(data, "IMAP %p state change from %s to %s", + (void *)imapc, names[imapc->state], names[newstate]); +#endif + + imapc->state = newstate; +} + +/*********************************************************************** + * + * imap_perform_capability() + * + * Sends the CAPABILITY command in order to obtain a list of server side + * supported capabilities. + */ +static CURLcode imap_perform_capability(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ + imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ + imapc->tls_supported = FALSE; /* Clear the TLS capability */ + + /* Send the CAPABILITY command */ + result = imap_sendf(data, "CAPABILITY"); + + if(!result) + imap_state(data, IMAP_CAPABILITY); + + return result; +} + +/*********************************************************************** + * + * imap_perform_starttls() + * + * Sends the STARTTLS command to start the upgrade to TLS. + */ +static CURLcode imap_perform_starttls(struct Curl_easy *data) +{ + /* Send the STARTTLS command */ + CURLcode result = imap_sendf(data, "STARTTLS"); + + if(!result) + imap_state(data, IMAP_STARTTLS); + + return result; +} + +/*********************************************************************** + * + * imap_perform_upgrade_tls() + * + * Performs the upgrade to TLS. + */ +static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Start the SSL connection */ + struct imap_conn *imapc = &conn->proto.imapc; + CURLcode result; + bool ssldone = FALSE; + + if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { + result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); + if(result) + goto out; + } + + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); + if(!result) { + imapc->ssldone = ssldone; + if(imapc->state != IMAP_UPGRADETLS) + imap_state(data, IMAP_UPGRADETLS); + + if(imapc->ssldone) { + imap_to_imaps(conn); + result = imap_perform_capability(data, conn); + } + } +out: + return result; +} + +/*********************************************************************** + * + * imap_perform_login() + * + * Sends a clear text LOGIN command to authenticate with. + */ +static CURLcode imap_perform_login(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + char *user; + char *passwd; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!data->state.aptr.user) { + imap_state(data, IMAP_STOP); + + return result; + } + + /* Make sure the username and password are in the correct atom format */ + user = imap_atom(conn->user, false); + passwd = imap_atom(conn->passwd, false); + + /* Send the LOGIN command */ + result = imap_sendf(data, "LOGIN %s %s", user ? user : "", + passwd ? passwd : ""); + + free(user); + free(passwd); + + if(!result) + imap_state(data, IMAP_LOGIN); + + return result; +} + +/*********************************************************************** + * + * imap_perform_authenticate() + * + * Sends an AUTHENTICATE command allowing the client to login with the given + * SASL authentication mechanism. + */ +static CURLcode imap_perform_authenticate(struct Curl_easy *data, + const char *mech, + const struct bufref *initresp) +{ + CURLcode result = CURLE_OK; + const char *ir = (const char *) Curl_bufref_ptr(initresp); + + if(ir) { + /* Send the AUTHENTICATE command with the initial response */ + result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir); + } + else { + /* Send the AUTHENTICATE command */ + result = imap_sendf(data, "AUTHENTICATE %s", mech); + } + + return result; +} + +/*********************************************************************** + * + * imap_continue_authenticate() + * + * Sends SASL continuation data. + */ +static CURLcode imap_continue_authenticate(struct Curl_easy *data, + const char *mech, + const struct bufref *resp) +{ + struct imap_conn *imapc = &data->conn->proto.imapc; + + (void)mech; + + return Curl_pp_sendf(data, &imapc->pp, + "%s", (const char *) Curl_bufref_ptr(resp)); +} + +/*********************************************************************** + * + * imap_cancel_authenticate() + * + * Sends SASL cancellation. + */ +static CURLcode imap_cancel_authenticate(struct Curl_easy *data, + const char *mech) +{ + struct imap_conn *imapc = &data->conn->proto.imapc; + + (void)mech; + + return Curl_pp_sendf(data, &imapc->pp, "*"); +} + +/*********************************************************************** + * + * imap_perform_authentication() + * + * Initiates the authentication sequence, with the appropriate SASL + * authentication mechanism, falling back to clear text should a common + * mechanism not be available between the client and server. + */ +static CURLcode imap_perform_authentication(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + saslprogress progress; + + /* Check if already authenticated OR if there is enough data to authenticate + with and end the connect phase if we don't */ + if(imapc->preauth || + !Curl_sasl_can_authenticate(&imapc->sasl, data)) { + imap_state(data, IMAP_STOP); + return result; + } + + /* Calculate the SASL login details */ + result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress); + + if(!result) { + if(progress == SASL_INPROGRESS) + imap_state(data, IMAP_AUTHENTICATE); + else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + /* Perform clear text authentication */ + result = imap_perform_login(data, conn); + else { + /* Other mechanisms not supported */ + infof(data, "No known authentication mechanisms supported"); + result = CURLE_LOGIN_DENIED; + } + } + + return result; +} + +/*********************************************************************** + * + * imap_perform_list() + * + * Sends a LIST command or an alternative custom request. + */ +static CURLcode imap_perform_list(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = data->req.p.imap; + + if(imap->custom) + /* Send the custom request */ + result = imap_sendf(data, "%s%s", imap->custom, + imap->custom_params ? imap->custom_params : ""); + else { + /* Make sure the mailbox is in the correct atom format if necessary */ + char *mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) + : strdup(""); + if(!mailbox) + return CURLE_OUT_OF_MEMORY; + + /* Send the LIST command */ + result = imap_sendf(data, "LIST \"%s\" *", mailbox); + + free(mailbox); + } + + if(!result) + imap_state(data, IMAP_LIST); + + return result; +} + +/*********************************************************************** + * + * imap_perform_select() + * + * Sends a SELECT command to ask the server to change the selected mailbox. + */ +static CURLcode imap_perform_select(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct IMAP *imap = data->req.p.imap; + struct imap_conn *imapc = &conn->proto.imapc; + char *mailbox; + + /* Invalidate old information as we are switching mailboxes */ + Curl_safefree(imapc->mailbox); + Curl_safefree(imapc->mailbox_uidvalidity); + + /* Check we have a mailbox */ + if(!imap->mailbox) { + failf(data, "Cannot SELECT without a mailbox."); + return CURLE_URL_MALFORMAT; + } + + /* Make sure the mailbox is in the correct atom format */ + mailbox = imap_atom(imap->mailbox, false); + if(!mailbox) + return CURLE_OUT_OF_MEMORY; + + /* Send the SELECT command */ + result = imap_sendf(data, "SELECT %s", mailbox); + + free(mailbox); + + if(!result) + imap_state(data, IMAP_SELECT); + + return result; +} + +/*********************************************************************** + * + * imap_perform_fetch() + * + * Sends a FETCH command to initiate the download of a message. + */ +static CURLcode imap_perform_fetch(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = data->req.p.imap; + /* Check we have a UID */ + if(imap->uid) { + + /* Send the FETCH command */ + if(imap->partial) + result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>", + imap->uid, imap->section ? imap->section : "", + imap->partial); + else + result = imap_sendf(data, "UID FETCH %s BODY[%s]", + imap->uid, imap->section ? imap->section : ""); + } + else if(imap->mindex) { + /* Send the FETCH command */ + if(imap->partial) + result = imap_sendf(data, "FETCH %s BODY[%s]<%s>", + imap->mindex, imap->section ? imap->section : "", + imap->partial); + else + result = imap_sendf(data, "FETCH %s BODY[%s]", + imap->mindex, imap->section ? imap->section : ""); + } + else { + failf(data, "Cannot FETCH without a UID."); + return CURLE_URL_MALFORMAT; + } + if(!result) + imap_state(data, IMAP_FETCH); + + return result; +} + +/*********************************************************************** + * + * imap_perform_append() + * + * Sends an APPEND command to initiate the upload of a message. + */ +static CURLcode imap_perform_append(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = data->req.p.imap; + char *mailbox; + + /* Check we have a mailbox */ + if(!imap->mailbox) { + failf(data, "Cannot APPEND without a mailbox."); + return CURLE_URL_MALFORMAT; + } + + /* Prepare the mime data if some. */ + if(data->set.mimepost.kind != MIMEKIND_NONE) { + /* Use the whole structure as data. */ + data->set.mimepost.flags &= ~MIME_BODY_ONLY; + + /* Add external headers and mime version. */ + curl_mime_headers(&data->set.mimepost, data->set.headers, 0); + result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL, + NULL, MIMESTRATEGY_MAIL); + + if(!result) + if(!Curl_checkheaders(data, STRCONST("Mime-Version"))) + result = Curl_mime_add_header(&data->set.mimepost.curlheaders, + "Mime-Version: 1.0"); + + /* Make sure we will read the entire mime structure. */ + if(!result) + result = Curl_mime_rewind(&data->set.mimepost); + + if(result) + return result; + + data->state.infilesize = Curl_mime_size(&data->set.mimepost); + + /* Read from mime structure. */ + data->state.fread_func = (curl_read_callback) Curl_mime_read; + data->state.in = (void *) &data->set.mimepost; + } + + /* Check we know the size of the upload */ + if(data->state.infilesize < 0) { + failf(data, "Cannot APPEND with unknown input file size"); + return CURLE_UPLOAD_FAILED; + } + + /* Make sure the mailbox is in the correct atom format */ + mailbox = imap_atom(imap->mailbox, false); + if(!mailbox) + return CURLE_OUT_OF_MEMORY; + + /* Send the APPEND command */ + result = imap_sendf(data, + "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", + mailbox, data->state.infilesize); + + free(mailbox); + + if(!result) + imap_state(data, IMAP_APPEND); + + return result; +} + +/*********************************************************************** + * + * imap_perform_search() + * + * Sends a SEARCH command. + */ +static CURLcode imap_perform_search(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = data->req.p.imap; + + /* Check we have a query string */ + if(!imap->query) { + failf(data, "Cannot SEARCH without a query string."); + return CURLE_URL_MALFORMAT; + } + + /* Send the SEARCH command */ + result = imap_sendf(data, "SEARCH %s", imap->query); + + if(!result) + imap_state(data, IMAP_SEARCH); + + return result; +} + +/*********************************************************************** + * + * imap_perform_logout() + * + * Performs the logout action prior to sclose() being called. + */ +static CURLcode imap_perform_logout(struct Curl_easy *data) +{ + /* Send the LOGOUT command */ + CURLcode result = imap_sendf(data, "LOGOUT"); + + if(!result) + imap_state(data, IMAP_LOGOUT); + + return result; +} + +/* For the initial server greeting */ +static CURLcode imap_state_servergreet_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + struct connectdata *conn = data->conn; + (void)instate; /* no use for this yet */ + + if(imapcode == IMAP_RESP_PREAUTH) { + /* PREAUTH */ + struct imap_conn *imapc = &conn->proto.imapc; + imapc->preauth = TRUE; + infof(data, "PREAUTH connection, already authenticated"); + } + else if(imapcode != IMAP_RESP_OK) { + failf(data, "Got unexpected imap-server response"); + return CURLE_WEIRD_SERVER_REPLY; + } + + return imap_perform_capability(data, conn); +} + +/* For CAPABILITY responses */ +static CURLcode imap_state_capability_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct imap_conn *imapc = &conn->proto.imapc; + const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf); + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged response? */ + if(imapcode == '*') { + line += 2; + + /* Loop through the data line */ + for(;;) { + size_t wordlen; + while(*line && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + } + + if(!*line) + break; + + /* Extract the word */ + for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Does the server support the STARTTLS capability? */ + if(wordlen == 8 && !memcmp(line, "STARTTLS", 8)) + imapc->tls_supported = TRUE; + + /* Has the server explicitly disabled clear text authentication? */ + else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13)) + imapc->login_disabled = TRUE; + + /* Does the server support the SASL-IR capability? */ + else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7)) + imapc->ir_supported = TRUE; + + /* Do we have a SASL based authentication mechanism? */ + else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { + size_t llen; + unsigned short mechbit; + + line += 5; + wordlen -= 5; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + imapc->sasl.authmechs |= mechbit; + } + + line += wordlen; + } + } + else if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) { + /* PREAUTH is not compatible with STARTTLS. */ + if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) { + /* Switch to TLS connection now */ + result = imap_perform_starttls(data); + } + else if(data->set.use_ssl <= CURLUSESSL_TRY) + result = imap_perform_authentication(data, conn); + else { + failf(data, "STARTTLS not available."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = imap_perform_authentication(data, conn); + + return result; +} + +/* For STARTTLS responses */ +static CURLcode imap_state_starttls_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + (void)instate; /* no use for this yet */ + + /* Pipelining in response is forbidden. */ + if(data->conn->proto.imapc.pp.overflow) + return CURLE_WEIRD_SERVER_REPLY; + + if(imapcode != IMAP_RESP_OK) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); + result = CURLE_USE_SSL_FAILED; + } + else + result = imap_perform_authentication(data, conn); + } + else + result = imap_perform_upgrade_tls(data, conn); + + return result; +} + +/* For SASL authentication responses */ +static CURLcode imap_state_auth_resp(struct Curl_easy *data, + struct connectdata *conn, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + saslprogress progress; + + (void)instate; /* no use for this yet */ + + result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + imap_state(data, IMAP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ + if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + /* Perform clear text authentication */ + result = imap_perform_login(data, conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + } + break; + default: + break; + } + + return result; +} + +/* For LOGIN responses */ +static CURLcode imap_state_login_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(imapcode != IMAP_RESP_OK) { + failf(data, "Access denied. %c", imapcode); + result = CURLE_LOGIN_DENIED; + } + else + /* End of connect phase */ + imap_state(data, IMAP_STOP); + + return result; +} + +/* For LIST and SEARCH responses */ +static CURLcode imap_state_listsearch_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); + size_t len = data->conn->proto.imapc.pp.nfinal; + + (void)instate; /* No use for this yet */ + + if(imapcode == '*') + result = Curl_client_write(data, CLIENTWRITE_BODY, line, len); + else if(imapcode != IMAP_RESP_OK) + result = CURLE_QUOTE_ERROR; + else + /* End of DO phase */ + imap_state(data, IMAP_STOP); + + return result; +} + +/* For SELECT responses */ +static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct IMAP *imap = data->req.p.imap; + struct imap_conn *imapc = &conn->proto.imapc; + const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); + + (void)instate; /* no use for this yet */ + + if(imapcode == '*') { + /* See if this is an UIDVALIDITY response */ + if(checkprefix("OK [UIDVALIDITY ", line + 2)) { + size_t len = 0; + const char *p = &line[2] + strlen("OK [UIDVALIDITY "); + while((len < 20) && p[len] && ISDIGIT(p[len])) + len++; + if(len && (p[len] == ']')) { + struct dynbuf uid; + Curl_dyn_init(&uid, 20); + if(Curl_dyn_addn(&uid, p, len)) + return CURLE_OUT_OF_MEMORY; + Curl_safefree(imapc->mailbox_uidvalidity); + imapc->mailbox_uidvalidity = Curl_dyn_ptr(&uid); + } + } + } + else if(imapcode == IMAP_RESP_OK) { + /* Check if the UIDVALIDITY has been specified and matches */ + if(imap->uidvalidity && imapc->mailbox_uidvalidity && + !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) { + failf(data, "Mailbox UIDVALIDITY has changed"); + result = CURLE_REMOTE_FILE_NOT_FOUND; + } + else { + /* Note the currently opened mailbox on this connection */ + DEBUGASSERT(!imapc->mailbox); + imapc->mailbox = strdup(imap->mailbox); + if(!imapc->mailbox) + return CURLE_OUT_OF_MEMORY; + + if(imap->custom) + result = imap_perform_list(data); + else if(imap->query) + result = imap_perform_search(data); + else + result = imap_perform_fetch(data); + } + } + else { + failf(data, "Select failed"); + result = CURLE_LOGIN_DENIED; + } + + return result; +} + +/* For the (first line of the) FETCH responses */ +static CURLcode imap_state_fetch_resp(struct Curl_easy *data, + struct connectdata *conn, int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + struct pingpong *pp = &imapc->pp; + const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); + size_t len = data->conn->proto.imapc.pp.nfinal; + bool parsed = FALSE; + curl_off_t size = 0; + + (void)instate; /* no use for this yet */ + + if(imapcode != '*') { + Curl_pgrsSetDownloadSize(data, -1); + imap_state(data, IMAP_STOP); + return CURLE_REMOTE_FILE_NOT_FOUND; + } + + /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse + the continuation data contained within the curly brackets */ + ptr = memchr(ptr, '{', len); + if(ptr) { + char *endptr; + if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) && + (endptr - ptr > 1 && *endptr == '}')) + parsed = TRUE; + } + + if(parsed) { + infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download", + size); + Curl_pgrsSetDownloadSize(data, size); + + if(pp->overflow) { + /* At this point there is a data in the receive buffer that is body + content, send it as body and then skip it. Do note that there may + even be additional "headers" after the body. */ + size_t chunk = pp->overflow; + + /* keep only the overflow */ + Curl_dyn_tail(&pp->recvbuf, chunk); + pp->nfinal = 0; /* done */ + + if(chunk > (size_t)size) + /* The conversion from curl_off_t to size_t is always fine here */ + chunk = (size_t)size; + + if(!chunk) { + /* no size, we're done with the data */ + imap_state(data, IMAP_STOP); + return CURLE_OK; + } + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&pp->recvbuf), chunk); + if(result) + return result; + + infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU + " bytes are left for transfer", chunk, size - chunk); + + /* Have we used the entire overflow or just part of it?*/ + if(pp->overflow > chunk) { + /* remember the remaining trailing overflow data */ + pp->overflow -= chunk; + Curl_dyn_tail(&pp->recvbuf, pp->overflow); + } + else { + pp->overflow = 0; /* handled */ + /* Free the cache */ + Curl_dyn_reset(&pp->recvbuf); + } + } + + if(data->req.bytecount == size) + /* The entire data is already transferred! */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + else { + /* IMAP download */ + data->req.maxdownload = size; + /* force a recv/send check of this connection, as the data might've been + read off the socket already */ + data->state.select_bits = CURL_CSELECT_IN; + Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1); + } + } + else { + /* We don't know how to parse this line */ + failf(data, "Failed to parse FETCH response."); + result = CURLE_WEIRD_SERVER_REPLY; + } + + /* End of DO phase */ + imap_state(data, IMAP_STOP); + + return result; +} + +/* For final FETCH responses performed after the download */ +static CURLcode imap_state_fetch_final_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + + (void)instate; /* No use for this yet */ + + if(imapcode != IMAP_RESP_OK) + result = CURLE_WEIRD_SERVER_REPLY; + else + /* End of DONE phase */ + imap_state(data, IMAP_STOP); + + return result; +} + +/* For APPEND responses */ +static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* No use for this yet */ + + if(imapcode != '+') { + result = CURLE_UPLOAD_FAILED; + } + else { + /* Set the progress upload size */ + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* IMAP upload */ + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + + /* End of DO phase */ + imap_state(data, IMAP_STOP); + } + + return result; +} + +/* For final APPEND responses performed after the upload */ +static CURLcode imap_state_append_final_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + + (void)instate; /* No use for this yet */ + + if(imapcode != IMAP_RESP_OK) + result = CURLE_UPLOAD_FAILED; + else + /* End of DONE phase */ + imap_state(data, IMAP_STOP); + + return result; +} + +static CURLcode imap_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int imapcode; + struct imap_conn *imapc = &conn->proto.imapc; + struct pingpong *pp = &imapc->pp; + size_t nread = 0; + (void)data; + + /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */ + if(imapc->state == IMAP_UPGRADETLS) + return imap_perform_upgrade_tls(data, conn); + + /* Flush any data that needs to be sent */ + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + do { + /* Read the response from the server */ + result = Curl_pp_readresp(data, sock, pp, &imapcode, &nread); + if(result) + return result; + + /* Was there an error parsing the response line? */ + if(imapcode == -1) + return CURLE_WEIRD_SERVER_REPLY; + + if(!imapcode) + break; + + /* We have now received a full IMAP server response */ + switch(imapc->state) { + case IMAP_SERVERGREET: + result = imap_state_servergreet_resp(data, imapcode, imapc->state); + break; + + case IMAP_CAPABILITY: + result = imap_state_capability_resp(data, imapcode, imapc->state); + break; + + case IMAP_STARTTLS: + result = imap_state_starttls_resp(data, imapcode, imapc->state); + break; + + case IMAP_AUTHENTICATE: + result = imap_state_auth_resp(data, conn, imapcode, imapc->state); + break; + + case IMAP_LOGIN: + result = imap_state_login_resp(data, imapcode, imapc->state); + break; + + case IMAP_LIST: + case IMAP_SEARCH: + result = imap_state_listsearch_resp(data, imapcode, imapc->state); + break; + + case IMAP_SELECT: + result = imap_state_select_resp(data, imapcode, imapc->state); + break; + + case IMAP_FETCH: + result = imap_state_fetch_resp(data, conn, imapcode, imapc->state); + break; + + case IMAP_FETCH_FINAL: + result = imap_state_fetch_final_resp(data, imapcode, imapc->state); + break; + + case IMAP_APPEND: + result = imap_state_append_resp(data, imapcode, imapc->state); + break; + + case IMAP_APPEND_FINAL: + result = imap_state_append_final_resp(data, imapcode, imapc->state); + break; + + case IMAP_LOGOUT: + default: + /* internal error */ + imap_state(data, IMAP_STOP); + break; + } + } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp)); + + return result; +} + +/* Called repeatedly until done from multi.c */ +static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct imap_conn *imapc = &conn->proto.imapc; + + if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) { + bool ssldone = FALSE; + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); + imapc->ssldone = ssldone; + if(result || !ssldone) + return result; + } + + result = Curl_pp_statemach(data, &imapc->pp, FALSE, FALSE); + *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE; + + return result; +} + +static CURLcode imap_block_statemach(struct Curl_easy *data, + struct connectdata *conn, + bool disconnecting) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + + while(imapc->state != IMAP_STOP && !result) + result = Curl_pp_statemach(data, &imapc->pp, TRUE, disconnecting); + + return result; +} + +/* Allocate and initialize the struct IMAP for the current Curl_easy if + required */ +static CURLcode imap_init(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap; + + imap = data->req.p.imap = calloc(1, sizeof(struct IMAP)); + if(!imap) + result = CURLE_OUT_OF_MEMORY; + + return result; +} + +/* For the IMAP "protocol connect" and "doing" phases only */ +static int imap_getsock(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *socks) +{ + return Curl_pp_getsock(data, &conn->proto.imapc.pp, socks); +} + +/*********************************************************************** + * + * imap_connect() + * + * This function should do everything that is to be considered a part of the + * connection phase. + * + * The variable 'done' points to will be TRUE if the protocol-layer connect + * phase is done when this function returns, or FALSE if not. + */ +static CURLcode imap_connect(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct imap_conn *imapc = &conn->proto.imapc; + struct pingpong *pp = &imapc->pp; + + *done = FALSE; /* default to not done yet */ + + /* We always support persistent connections in IMAP */ + connkeep(conn, "IMAP default"); + + PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp); + + /* Set the default preferred authentication type and mechanism */ + imapc->preftype = IMAP_TYPE_ANY; + Curl_sasl_init(&imapc->sasl, data, &saslimap); + + Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD); + Curl_pp_init(pp); + + /* Parse the URL options */ + result = imap_parse_url_options(conn); + if(result) + return result; + + /* Start off waiting for the server greeting response */ + imap_state(data, IMAP_SERVERGREET); + + /* Start off with an response id of '*' */ + strcpy(imapc->resptag, "*"); + + result = imap_multi_statemach(data, done); + + return result; +} + +/*********************************************************************** + * + * imap_done() + * + * The DONE function. This does what needs to be done after a single DO has + * performed. + * + * Input argument is already checked for validity. + */ +static CURLcode imap_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct IMAP *imap = data->req.p.imap; + + (void)premature; + + if(!imap) + return CURLE_OK; + + if(status) { + connclose(conn, "IMAP done with bad status"); /* marked for closure */ + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && !imap->custom && + (imap->uid || imap->mindex || data->state.upload || + data->set.mimepost.kind != MIMEKIND_NONE)) { + /* Handle responses after FETCH or APPEND transfer has finished */ + + if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE) + imap_state(data, IMAP_FETCH_FINAL); + else { + /* End the APPEND command first by sending an empty line */ + result = Curl_pp_sendf(data, &conn->proto.imapc.pp, "%s", ""); + if(!result) + imap_state(data, IMAP_APPEND_FINAL); + } + + /* Run the state-machine */ + if(!result) + result = imap_block_statemach(data, conn, FALSE); + } + + /* Cleanup our per-request based variables */ + Curl_safefree(imap->mailbox); + Curl_safefree(imap->uidvalidity); + Curl_safefree(imap->uid); + Curl_safefree(imap->mindex); + Curl_safefree(imap->section); + Curl_safefree(imap->partial); + Curl_safefree(imap->query); + Curl_safefree(imap->custom); + Curl_safefree(imap->custom_params); + + /* Clear the transfer mode for the next request */ + imap->transfer = PPTRANSFER_BODY; + + return result; +} + +/*********************************************************************** + * + * imap_perform() + * + * This is the actual DO function for IMAP. Fetch or append a message, or do + * other things according to the options previously setup. + */ +static CURLcode imap_perform(struct Curl_easy *data, bool *connected, + bool *dophase_done) +{ + /* This is IMAP and no proxy */ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct IMAP *imap = data->req.p.imap; + struct imap_conn *imapc = &conn->proto.imapc; + bool selected = FALSE; + + DEBUGF(infof(data, "DO phase starts")); + + if(data->req.no_body) { + /* Requested no body means no transfer */ + imap->transfer = PPTRANSFER_INFO; + } + + *dophase_done = FALSE; /* not done yet */ + + /* Determine if the requested mailbox (with the same UIDVALIDITY if set) + has already been selected on this connection */ + if(imap->mailbox && imapc->mailbox && + strcasecompare(imap->mailbox, imapc->mailbox) && + (!imap->uidvalidity || !imapc->mailbox_uidvalidity || + strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity))) + selected = TRUE; + + /* Start the first command in the DO phase */ + if(data->state.upload || data->set.mimepost.kind != MIMEKIND_NONE) + /* APPEND can be executed directly */ + result = imap_perform_append(data); + else if(imap->custom && (selected || !imap->mailbox)) + /* Custom command using the same mailbox or no mailbox */ + result = imap_perform_list(data); + else if(!imap->custom && selected && (imap->uid || imap->mindex)) + /* FETCH from the same mailbox */ + result = imap_perform_fetch(data); + else if(!imap->custom && selected && imap->query) + /* SEARCH the current mailbox */ + result = imap_perform_search(data); + else if(imap->mailbox && !selected && + (imap->custom || imap->uid || imap->mindex || imap->query)) + /* SELECT the mailbox */ + result = imap_perform_select(data); + else + /* LIST */ + result = imap_perform_list(data); + + if(result) + return result; + + /* Run the state-machine */ + result = imap_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(conn, FIRSTSOCKET); + + if(*dophase_done) + DEBUGF(infof(data, "DO phase is complete")); + + return result; +} + +/*********************************************************************** + * + * imap_do() + * + * This function is registered as 'curl_do' function. It decodes the path + * parts etc as a wrapper to the actual DO function (imap_perform). + * + * The input argument is already checked for validity. + */ +static CURLcode imap_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + *done = FALSE; /* default to false */ + + /* Parse the URL path */ + result = imap_parse_url_path(data); + if(result) + return result; + + /* Parse the custom request */ + result = imap_parse_custom_request(data); + if(result) + return result; + + result = imap_regular_transfer(data, done); + + return result; +} + +/*********************************************************************** + * + * imap_disconnect() + * + * Disconnect from an IMAP server. Cleanup protocol-specific per-connection + * resources. BLOCKING. + */ +static CURLcode imap_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection) +{ + struct imap_conn *imapc = &conn->proto.imapc; + (void)data; + + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. */ + + /* The IMAP session may or may not have been allocated/setup at this + point! */ + if(!dead_connection && conn->bits.protoconnstart) { + if(!imap_perform_logout(data)) + (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */ + } + + /* Disconnect from the server */ + Curl_pp_disconnect(&imapc->pp); + Curl_dyn_free(&imapc->dyn); + + /* Cleanup the SASL module */ + Curl_sasl_cleanup(conn, imapc->sasl.authused); + + /* Cleanup our connection based variables */ + Curl_safefree(imapc->mailbox); + Curl_safefree(imapc->mailbox_uidvalidity); + + return CURLE_OK; +} + +/* Call this when the DO phase has completed */ +static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected) +{ + struct IMAP *imap = data->req.p.imap; + + (void)connected; + + if(imap->transfer != PPTRANSFER_BODY) + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + + return CURLE_OK; +} + +/* Called from multi.c while DOing */ +static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done) +{ + CURLcode result = imap_multi_statemach(data, dophase_done); + + if(result) + DEBUGF(infof(data, "DO phase failed")); + else if(*dophase_done) { + result = imap_dophase_done(data, FALSE /* not connected */); + + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +/*********************************************************************** + * + * imap_regular_transfer() + * + * The input argument is already checked for validity. + * + * Performs all commands done before a regular transfer between a local and a + * remote host. + */ +static CURLcode imap_regular_transfer(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + bool connected = FALSE; + + /* Make sure size is unknown at this point */ + data->req.size = -1; + + /* Set the progress data */ + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + /* Carry out the perform */ + result = imap_perform(data, &connected, dophase_done); + + /* Perform post DO phase operations if necessary */ + if(!result && *dophase_done) + result = imap_dophase_done(data, connected); + + return result; +} + +static CURLcode imap_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Initialise the IMAP layer */ + CURLcode result = imap_init(data); + if(result) + return result; + + /* Clear the TLS upgraded flag */ + conn->bits.tls_upgraded = FALSE; + + return CURLE_OK; +} + +/*********************************************************************** + * + * imap_sendf() + * + * Sends the formatted string as an IMAP command to the server. + * + * Designed to never block. + */ +static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &data->conn->proto.imapc; + + DEBUGASSERT(fmt); + + /* Calculate the tag based on the connection ID and command ID */ + msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", + 'A' + curlx_sltosi((long)(data->conn->connection_id % 26)), + ++imapc->cmdid); + + /* start with a blank buffer */ + Curl_dyn_reset(&imapc->dyn); + + /* append tag + space + fmt */ + result = Curl_dyn_addf(&imapc->dyn, "%s %s", imapc->resptag, fmt); + if(!result) { + va_list ap; + va_start(ap, fmt); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + va_end(ap); + } + return result; +} + +/*********************************************************************** + * + * imap_atom() + * + * Checks the input string for characters that need escaping and returns an + * atom ready for sending to the server. + * + * The returned string needs to be freed. + * + */ +static char *imap_atom(const char *str, bool escape_only) +{ + struct dynbuf line; + size_t nclean; + size_t len; + + if(!str) + return NULL; + + len = strlen(str); + nclean = strcspn(str, "() {%*]\\\""); + if(len == nclean) + /* nothing to escape, return a strdup */ + return strdup(str); + + Curl_dyn_init(&line, 2000); + + if(!escape_only && Curl_dyn_addn(&line, "\"", 1)) + return NULL; + + while(*str) { + if((*str == '\\' || *str == '"') && + Curl_dyn_addn(&line, "\\", 1)) + return NULL; + if(Curl_dyn_addn(&line, str, 1)) + return NULL; + str++; + } + + if(!escape_only && Curl_dyn_addn(&line, "\"", 1)) + return NULL; + + return Curl_dyn_ptr(&line); +} + +/*********************************************************************** + * + * imap_is_bchar() + * + * Portable test of whether the specified char is a "bchar" as defined in the + * grammar of RFC-5092. + */ +static bool imap_is_bchar(char ch) +{ + /* Performing the alnum check with this macro is faster because of ASCII + arithmetic */ + if(ISALNUM(ch)) + return true; + + switch(ch) { + /* bchar */ + case ':': case '@': case '/': + /* bchar -> achar */ + case '&': case '=': + /* bchar -> achar -> uchar -> unreserved (without alphanumeric) */ + case '-': case '.': case '_': case '~': + /* bchar -> achar -> uchar -> sub-delims-sh */ + case '!': case '$': case '\'': case '(': case ')': case '*': + case '+': case ',': + /* bchar -> achar -> uchar -> pct-encoded */ + case '%': /* HEXDIG chars are already included above */ + return true; + + default: + return false; + } +} + +/*********************************************************************** + * + * imap_parse_url_options() + * + * Parse the URL login options. + */ +static CURLcode imap_parse_url_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + const char *ptr = conn->options; + bool prefer_login = false; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(strncasecompare(key, "AUTH=+LOGIN", 11)) { + /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */ + prefer_login = true; + imapc->sasl.prefmech = SASL_AUTH_NONE; + } + else if(strncasecompare(key, "AUTH=", 5)) { + prefer_login = false; + result = Curl_sasl_parse_url_auth_option(&imapc->sasl, + value, ptr - value); + } + else { + prefer_login = false; + result = CURLE_URL_MALFORMAT; + } + + if(*ptr == ';') + ptr++; + } + + if(prefer_login) + imapc->preftype = IMAP_TYPE_CLEARTEXT; + else { + switch(imapc->sasl.prefmech) { + case SASL_AUTH_NONE: + imapc->preftype = IMAP_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + imapc->preftype = IMAP_TYPE_ANY; + break; + default: + imapc->preftype = IMAP_TYPE_SASL; + break; + } + } + + return result; +} + +/*********************************************************************** + * + * imap_parse_url_path() + * + * Parse the URL path into separate path components. + * + */ +static CURLcode imap_parse_url_path(struct Curl_easy *data) +{ + /* The imap struct is already initialised in imap_connect() */ + CURLcode result = CURLE_OK; + struct IMAP *imap = data->req.p.imap; + const char *begin = &data->state.up.path[1]; /* skip leading slash */ + const char *ptr = begin; + + /* See how much of the URL is a valid path and decode it */ + while(imap_is_bchar(*ptr)) + ptr++; + + if(ptr != begin) { + /* Remove the trailing slash if present */ + const char *end = ptr; + if(end > begin && end[-1] == '/') + end--; + + result = Curl_urldecode(begin, end - begin, &imap->mailbox, NULL, + REJECT_CTRL); + if(result) + return result; + } + else + imap->mailbox = NULL; + + /* There can be any number of parameters in the form ";NAME=VALUE" */ + while(*ptr == ';') { + char *name; + char *value; + size_t valuelen; + + /* Find the length of the name parameter */ + begin = ++ptr; + while(*ptr && *ptr != '=') + ptr++; + + if(!*ptr) + return CURLE_URL_MALFORMAT; + + /* Decode the name parameter */ + result = Curl_urldecode(begin, ptr - begin, &name, NULL, + REJECT_CTRL); + if(result) + return result; + + /* Find the length of the value parameter */ + begin = ++ptr; + while(imap_is_bchar(*ptr)) + ptr++; + + /* Decode the value parameter */ + result = Curl_urldecode(begin, ptr - begin, &value, &valuelen, + REJECT_CTRL); + if(result) { + free(name); + return result; + } + + DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'", name, value)); + + /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and + PARTIAL) stripping of the trailing slash character if it is present. + + Note: Unknown parameters trigger a URL_MALFORMAT error. */ + if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->uidvalidity = value; + value = NULL; + } + else if(strcasecompare(name, "UID") && !imap->uid) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->uid = value; + value = NULL; + } + else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->mindex = value; + value = NULL; + } + else if(strcasecompare(name, "SECTION") && !imap->section) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->section = value; + value = NULL; + } + else if(strcasecompare(name, "PARTIAL") && !imap->partial) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->partial = value; + value = NULL; + } + else { + free(name); + free(value); + + return CURLE_URL_MALFORMAT; + } + + free(name); + free(value); + } + + /* Does the URL contain a query parameter? Only valid when we have a mailbox + and no UID as per RFC-5092 */ + if(imap->mailbox && !imap->uid && !imap->mindex) { + /* Get the query parameter, URL decoded */ + (void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query, + CURLU_URLDECODE); + } + + /* Any extra stuff at the end of the URL is an error */ + if(*ptr) + return CURLE_URL_MALFORMAT; + + return CURLE_OK; +} + +/*********************************************************************** + * + * imap_parse_custom_request() + * + * Parse the custom request. + */ +static CURLcode imap_parse_custom_request(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = data->req.p.imap; + const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + + if(custom) { + /* URL decode the custom request */ + result = Curl_urldecode(custom, 0, &imap->custom, NULL, REJECT_CTRL); + + /* Extract the parameters if specified */ + if(!result) { + const char *params = imap->custom; + + while(*params && *params != ' ') + params++; + + if(*params) { + imap->custom_params = strdup(params); + imap->custom[params - imap->custom] = '\0'; + + if(!imap->custom_params) + result = CURLE_OUT_OF_MEMORY; + } + } + } + + return result; +} + +#endif /* CURL_DISABLE_IMAP */ diff --git a/lib/imap.h b/lib/imap.h new file mode 100644 index 0000000..784ee97 --- /dev/null +++ b/lib/imap.h @@ -0,0 +1,101 @@ +#ifndef HEADER_CURL_IMAP_H +#define HEADER_CURL_IMAP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "pingpong.h" +#include "curl_sasl.h" + +/**************************************************************************** + * IMAP unique setup + ***************************************************************************/ +typedef enum { + IMAP_STOP, /* do nothing state, stops the state machine */ + IMAP_SERVERGREET, /* waiting for the initial greeting immediately after + a connect */ + IMAP_CAPABILITY, + IMAP_STARTTLS, + IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS + (multi mode only) */ + IMAP_AUTHENTICATE, + IMAP_LOGIN, + IMAP_LIST, + IMAP_SELECT, + IMAP_FETCH, + IMAP_FETCH_FINAL, + IMAP_APPEND, + IMAP_APPEND_FINAL, + IMAP_SEARCH, + IMAP_LOGOUT, + IMAP_LAST /* never used */ +} imapstate; + +/* This IMAP struct is used in the Curl_easy. All IMAP data that is + connection-oriented must be in imap_conn to properly deal with the fact that + perhaps the Curl_easy is changed between the times the connection is + used. */ +struct IMAP { + curl_pp_transfer transfer; + char *mailbox; /* Mailbox to select */ + char *uidvalidity; /* UIDVALIDITY to check in select */ + char *uid; /* Message UID to fetch */ + char *mindex; /* Index in mail box of mail to fetch */ + char *section; /* Message SECTION to fetch */ + char *partial; /* Message PARTIAL to fetch */ + char *query; /* Query to search for */ + char *custom; /* Custom request */ + char *custom_params; /* Parameters for the custom request */ +}; + +/* imap_conn is used for struct connection-oriented data in the connectdata + struct */ +struct imap_conn { + struct pingpong pp; + struct SASL sasl; /* SASL-related parameters */ + struct dynbuf dyn; /* for the IMAP commands */ + char *mailbox; /* The last selected mailbox */ + char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */ + imapstate state; /* Always use imap.c:state() to change state! */ + char resptag[5]; /* Response tag to wait for */ + unsigned char preftype; /* Preferred authentication type */ + unsigned char cmdid; /* Last used command ID */ + BIT(ssldone); /* Is connect() over SSL done? */ + BIT(preauth); /* Is this connection PREAUTH? */ + BIT(tls_supported); /* StartTLS capability supported by server */ + BIT(login_disabled); /* LOGIN command disabled by server */ + BIT(ir_supported); /* Initial response supported by server */ +}; + +extern const struct Curl_handler Curl_handler_imap; +extern const struct Curl_handler Curl_handler_imaps; + +/* Authentication type flags */ +#define IMAP_TYPE_CLEARTEXT (1 << 0) +#define IMAP_TYPE_SASL (1 << 1) + +/* Authentication type values */ +#define IMAP_TYPE_NONE 0 +#define IMAP_TYPE_ANY (IMAP_TYPE_CLEARTEXT|IMAP_TYPE_SASL) + +#endif /* HEADER_CURL_IMAP_H */ diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c new file mode 100644 index 0000000..c9cee0c --- /dev/null +++ b/lib/inet_ntop.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 1996-2022 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: ISC + */ +/* + * Original code by Paul Vixie. "curlified" by Gisle Vanem. + */ + +#include "curl_setup.h" + +#ifndef HAVE_INET_NTOP + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include "inet_ntop.h" +#include "curl_printf.h" + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +/* + * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make + * sure we have _some_ value for AF_INET6 without polluting our fake value + * everywhere. + */ +#if !defined(ENABLE_IPV6) && !defined(AF_INET6) +#define AF_INET6 (AF_INET + 1) +#endif + +/* + * Format an IPv4 address, more or less like inet_ntop(). + * + * Returns `dst' (as a const) + * Note: + * - uses no statics + * - takes a unsigned char* not an in_addr as input + */ +static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) +{ + char tmp[sizeof("255.255.255.255")]; + size_t len; + + DEBUGASSERT(size >= 16); + + tmp[0] = '\0'; + (void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", + ((int)((unsigned char)src[0])) & 0xff, + ((int)((unsigned char)src[1])) & 0xff, + ((int)((unsigned char)src[2])) & 0xff, + ((int)((unsigned char)src[3])) & 0xff); + + len = strlen(tmp); + if(len == 0 || len >= size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return dst; +} + +/* + * Convert IPv6 binary address into presentation (printable) format. + */ +static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + char *tp; + struct { + int base; + int len; + } best, cur; + unsigned int words[IN6ADDRSZ / INT16SZ]; + int i; + + /* Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof(words)); + for(i = 0; i < IN6ADDRSZ; i++) + words[i/2] |= ((unsigned int)src[i] << ((1 - (i % 2)) << 3)); + + best.base = -1; + cur.base = -1; + best.len = 0; + cur.len = 0; + + for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + if(words[i] == 0) { + if(cur.base == -1) { + cur.base = i; cur.len = 1; + } + else + cur.len++; + } + else if(cur.base != -1) { + if(best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + if((cur.base != -1) && (best.base == -1 || cur.len > best.len)) + best = cur; + if(best.base != -1 && best.len < 2) + best.base = -1; + /* Format the result. */ + tp = tmp; + for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if(best.base != -1 && i >= best.base && i < (best.base + best.len)) { + if(i == best.base) + *tp++ = ':'; + continue; + } + + /* Are we following an initial run of 0x00s or any real hex? + */ + if(i) + *tp++ = ':'; + + /* Is this address an encapsulated IPv4? + */ + if(i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) { + errno = ENOSPC; + return (NULL); + } + tp += strlen(tp); + break; + } + tp += msnprintf(tp, 5, "%x", words[i]); + } + + /* Was it a trailing run of 0x00's? + */ + if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* Check for overflow, copy, and we're done. + */ + if((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return dst; +} + +/* + * Convert a network format address to presentation format. + * + * Returns pointer to presentation format address (`buf'). + * Returns NULL on error and errno set with the specific + * error, EAFNOSUPPORT or ENOSPC. + * + * On Windows we store the error in the thread errno, not + * in the winsock error code. This is to avoid losing the + * actual last winsock error. So when this function returns + * NULL, check errno not SOCKERRNO. + */ +char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) +{ + switch(af) { + case AF_INET: + return inet_ntop4((const unsigned char *)src, buf, size); + case AF_INET6: + return inet_ntop6((const unsigned char *)src, buf, size); + default: + errno = EAFNOSUPPORT; + return NULL; + } +} +#endif /* HAVE_INET_NTOP */ diff --git a/lib/inet_ntop.h b/lib/inet_ntop.h new file mode 100644 index 0000000..7c3ead4 --- /dev/null +++ b/lib/inet_ntop.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_INET_NTOP_H +#define HEADER_CURL_INET_NTOP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); + +#ifdef HAVE_INET_NTOP +#ifdef HAVE_ARPA_INET_H +#include +#endif +#define Curl_inet_ntop(af,addr,buf,size) \ + inet_ntop(af, addr, buf, (curl_socklen_t)size) +#endif + +#endif /* HEADER_CURL_INET_NTOP_H */ diff --git a/lib/inet_pton.c b/lib/inet_pton.c new file mode 100644 index 0000000..176cc95 --- /dev/null +++ b/lib/inet_pton.c @@ -0,0 +1,243 @@ +/* This is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * SPDX-License-Identifier: ISC + */ + +#include "curl_setup.h" + +#ifndef HAVE_INET_PTON + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include "inet_pton.h" + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +/* + * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make + * sure we have _some_ value for AF_INET6 without polluting our fake value + * everywhere. + */ +#if !defined(ENABLE_IPV6) && !defined(AF_INET6) +#define AF_INET6 (AF_INET + 1) +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4(const char *src, unsigned char *dst); +static int inet_pton6(const char *src, unsigned char *dst); + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * notice: + * On Windows we store the error in the thread errno, not + * in the winsock error code. This is to avoid losing the + * actual last winsock error. So when this function returns + * -1, check errno not SOCKERRNO. + * author: + * Paul Vixie, 1996. + */ +int +Curl_inet_pton(int af, const char *src, void *dst) +{ + switch(af) { + case AF_INET: + return (inet_pton4(src, (unsigned char *)dst)); + case AF_INET6: + return (inet_pton6(src, (unsigned char *)dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + tp = tmp; + *tp = 0; + while((ch = *src++) != '\0') { + const char *pch; + + pch = strchr(digits, ch); + if(pch) { + unsigned int val = (unsigned int)(*tp * 10) + + (unsigned int)(pch - digits); + + if(saw_digit && *tp == 0) + return (0); + if(val > 255) + return (0); + *tp = (unsigned char)val; + if(!saw_digit) { + if(++octets > 4) + return (0); + saw_digit = 1; + } + } + else if(ch == '.' && saw_digit) { + if(octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } + else + return (0); + } + if(octets < 4) + return (0); + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(const char *src, unsigned char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *curtok; + int ch, saw_xdigit; + size_t val; + + memset((tp = tmp), 0, IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if(*src == ':') + if(*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while((ch = *src++) != '\0') { + const char *xdigits; + const char *pch; + + pch = strchr((xdigits = xdigits_l), ch); + if(!pch) + pch = strchr((xdigits = xdigits_u), ch); + if(pch) { + val <<= 4; + val |= (pch - xdigits); + if(++saw_xdigit > 4) + return (0); + continue; + } + if(ch == ':') { + curtok = src; + if(!saw_xdigit) { + if(colonp) + return (0); + colonp = tp; + continue; + } + if(tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) ((val >> 8) & 0xff); + *tp++ = (unsigned char) (val & 0xff); + saw_xdigit = 0; + val = 0; + continue; + } + if(ch == '.' && ((tp + INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if(saw_xdigit) { + if(tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) ((val >> 8) & 0xff); + *tp++ = (unsigned char) (val & 0xff); + } + if(colonp) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const ssize_t n = tp - colonp; + ssize_t i; + + if(tp == endp) + return (0); + for(i = 1; i <= n; i++) { + *(endp - i) = *(colonp + n - i); + *(colonp + n - i) = 0; + } + tp = endp; + } + if(tp != endp) + return (0); + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} + +#endif /* HAVE_INET_PTON */ diff --git a/lib/inet_pton.h b/lib/inet_pton.h new file mode 100644 index 0000000..f8562fa --- /dev/null +++ b/lib/inet_pton.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_INET_PTON_H +#define HEADER_CURL_INET_PTON_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +int Curl_inet_pton(int, const char *, void *); + +#ifdef HAVE_INET_PTON +#ifdef HAVE_ARPA_INET_H +#include +#endif +#define Curl_inet_pton(x,y,z) inet_pton(x,y,z) +#endif + +#endif /* HEADER_CURL_INET_PTON_H */ diff --git a/lib/krb5.c b/lib/krb5.c new file mode 100644 index 0000000..4db19fb --- /dev/null +++ b/lib/krb5.c @@ -0,0 +1,913 @@ +/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c + * + * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Copyright (C) Daniel Stenberg + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) + +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include "urldata.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "curl_base64.h" +#include "ftp.h" +#include "curl_gssapi.h" +#include "sendf.h" +#include "curl_krb5.h" +#include "warnless.h" +#include "strcase.h" +#include "strdup.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn, + const char *cmd) +{ + ssize_t bytes_written; +#define SBUF_SIZE 1024 + char s[SBUF_SIZE]; + size_t write_len; + char *sptr = s; + CURLcode result = CURLE_OK; +#ifdef HAVE_GSSAPI + unsigned char data_sec = conn->data_prot; +#endif + + DEBUGASSERT(cmd); + + write_len = strlen(cmd); + if(!write_len || write_len > (sizeof(s) -3)) + return CURLE_BAD_FUNCTION_ARGUMENT; + + memcpy(&s, cmd, write_len); + strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ + write_len += 2; + bytes_written = 0; + + for(;;) { +#ifdef HAVE_GSSAPI + conn->data_prot = PROT_CMD; +#endif + result = Curl_nwrite(data, FIRSTSOCKET, sptr, write_len, + &bytes_written); +#ifdef HAVE_GSSAPI + DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); + conn->data_prot = data_sec; +#endif + + if(result) + break; + + Curl_debug(data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written); + + if(bytes_written != (ssize_t)write_len) { + write_len -= bytes_written; + sptr += bytes_written; + } + else + break; + } + + return result; +} + +static int +krb5_init(void *app_data) +{ + gss_ctx_id_t *context = app_data; + /* Make sure our context is initialized for krb5_end. */ + *context = GSS_C_NO_CONTEXT; + return 0; +} + +static int +krb5_check_prot(void *app_data, int level) +{ + (void)app_data; /* unused */ + if(level == PROT_CONFIDENTIAL) + return -1; + return 0; +} + +static int +krb5_decode(void *app_data, void *buf, int len, + int level UNUSED_PARAM, + struct connectdata *conn UNUSED_PARAM) +{ + gss_ctx_id_t *context = app_data; + OM_uint32 maj, min; + gss_buffer_desc enc, dec; + + (void)level; + (void)conn; + + enc.value = buf; + enc.length = len; + maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); + if(maj != GSS_S_COMPLETE) + return -1; + + memcpy(buf, dec.value, dec.length); + len = curlx_uztosi(dec.length); + gss_release_buffer(&min, &dec); + + return len; +} + +static int +krb5_encode(void *app_data, const void *from, int length, int level, void **to) +{ + gss_ctx_id_t *context = app_data; + gss_buffer_desc dec, enc; + OM_uint32 maj, min; + int state; + int len; + + /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal + * libraries modify the input buffer in gss_wrap() + */ + dec.value = (void *)from; + dec.length = length; + maj = gss_wrap(&min, *context, + level == PROT_PRIVATE, + GSS_C_QOP_DEFAULT, + &dec, &state, &enc); + + if(maj != GSS_S_COMPLETE) + return -1; + + /* malloc a new buffer, in case gss_release_buffer doesn't work as + expected */ + *to = malloc(enc.length); + if(!*to) + return -1; + memcpy(*to, enc.value, enc.length); + len = curlx_uztosi(enc.length); + gss_release_buffer(&min, &enc); + return len; +} + +static int +krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) +{ + int ret = AUTH_OK; + char *p; + const char *host = conn->host.name; + ssize_t nread; + curl_socklen_t l = sizeof(conn->local_addr); + CURLcode result; + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + "ftp"; + const char *srv_host = "host"; + gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp; + OM_uint32 maj, min; + gss_name_t gssname; + gss_ctx_id_t *context = app_data; + struct gss_channel_bindings_struct chan; + size_t base64_sz = 0; + struct sockaddr_in *remote_addr = + (struct sockaddr_in *)(void *)&conn->remote_addr->sa_addr; + char *stringp; + + if(getsockname(conn->sock[FIRSTSOCKET], + (struct sockaddr *)&conn->local_addr, &l) < 0) + perror("getsockname()"); + + chan.initiator_addrtype = GSS_C_AF_INET; + chan.initiator_address.length = l - 4; + chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; + chan.acceptor_addrtype = GSS_C_AF_INET; + chan.acceptor_address.length = l - 4; + chan.acceptor_address.value = &remote_addr->sin_addr.s_addr; + chan.application_data.length = 0; + chan.application_data.value = NULL; + + /* this loop will execute twice (once for service, once for host) */ + for(;;) { + /* this really shouldn't be repeated here, but can't help it */ + if(service == srv_host) { + result = ftpsend(data, conn, "AUTH GSSAPI"); + if(result) + return -2; + + if(Curl_GetFTPResponse(data, &nread, NULL)) + return -1; + else { + struct pingpong *pp = &conn->proto.ftpc.pp; + char *line = Curl_dyn_ptr(&pp->recvbuf); + if(line[0] != '3') + return -1; + } + } + + stringp = aprintf("%s@%s", service, host); + if(!stringp) + return -2; + + input_buffer.value = stringp; + input_buffer.length = strlen(stringp); + maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE, + &gssname); + free(stringp); + if(maj != GSS_S_COMPLETE) { + gss_release_name(&min, &gssname); + if(service == srv_host) { + failf(data, "Error importing service name %s@%s", service, host); + return AUTH_ERROR; + } + service = srv_host; + continue; + } + /* We pass NULL as |output_name_type| to avoid a leak. */ + gss_display_name(&min, gssname, &output_buffer, NULL); + infof(data, "Trying against %s", (char *)output_buffer.value); + gssresp = GSS_C_NO_BUFFER; + *context = GSS_C_NO_CONTEXT; + + do { + /* Release the buffer at each iteration to avoid leaking: the first time + we are releasing the memory from gss_display_name. The last item is + taken care by a final gss_release_buffer. */ + gss_release_buffer(&min, &output_buffer); + ret = AUTH_OK; + maj = Curl_gss_init_sec_context(data, + &min, + context, + gssname, + &Curl_krb5_mech_oid, + &chan, + gssresp, + &output_buffer, + TRUE, + NULL); + + if(gssresp) { + free(_gssresp.value); + gssresp = NULL; + } + + if(GSS_ERROR(maj)) { + infof(data, "Error creating security context"); + ret = AUTH_ERROR; + break; + } + + if(output_buffer.length) { + char *cmd; + + result = Curl_base64_encode((char *)output_buffer.value, + output_buffer.length, &p, &base64_sz); + if(result) { + infof(data, "base64-encoding: %s", curl_easy_strerror(result)); + ret = AUTH_ERROR; + break; + } + + cmd = aprintf("ADAT %s", p); + if(cmd) + result = ftpsend(data, conn, cmd); + else + result = CURLE_OUT_OF_MEMORY; + + free(p); + free(cmd); + + if(result) { + ret = -2; + break; + } + + if(Curl_GetFTPResponse(data, &nread, NULL)) { + ret = -1; + break; + } + else { + struct pingpong *pp = &conn->proto.ftpc.pp; + size_t len = Curl_dyn_len(&pp->recvbuf); + p = Curl_dyn_ptr(&pp->recvbuf); + if((len < 4) || (p[0] != '2' && p[0] != '3')) { + infof(data, "Server didn't accept auth data"); + ret = AUTH_ERROR; + break; + } + } + + _gssresp.value = NULL; /* make sure it is initialized */ + p += 4; /* over '789 ' */ + p = strstr(p, "ADAT="); + if(p) { + result = Curl_base64_decode(p + 5, + (unsigned char **)&_gssresp.value, + &_gssresp.length); + if(result) { + failf(data, "base64-decoding: %s", curl_easy_strerror(result)); + ret = AUTH_CONTINUE; + break; + } + } + + gssresp = &_gssresp; + } + } while(maj == GSS_S_CONTINUE_NEEDED); + + gss_release_name(&min, &gssname); + gss_release_buffer(&min, &output_buffer); + + if(gssresp) + free(_gssresp.value); + + if(ret == AUTH_OK || service == srv_host) + return ret; + + service = srv_host; + } + return ret; +} + +static void krb5_end(void *app_data) +{ + OM_uint32 min; + gss_ctx_id_t *context = app_data; + if(*context != GSS_C_NO_CONTEXT) { + OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER); + (void)maj; + DEBUGASSERT(maj == GSS_S_COMPLETE); + } +} + +static const struct Curl_sec_client_mech Curl_krb5_client_mech = { + "GSSAPI", + sizeof(gss_ctx_id_t), + krb5_init, + krb5_auth, + krb5_end, + krb5_check_prot, + + krb5_encode, + krb5_decode +}; + +static const struct { + unsigned char level; + const char *name; +} level_names[] = { + { PROT_CLEAR, "clear" }, + { PROT_SAFE, "safe" }, + { PROT_CONFIDENTIAL, "confidential" }, + { PROT_PRIVATE, "private" } +}; + +static unsigned char name_to_level(const char *name) +{ + int i; + for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) + if(curl_strequal(name, level_names[i].name)) + return level_names[i].level; + return PROT_NONE; +} + +/* Convert a protocol |level| to its char representation. + We take an int to catch programming mistakes. */ +static char level_to_char(int level) +{ + switch(level) { + case PROT_CLEAR: + return 'C'; + case PROT_SAFE: + return 'S'; + case PROT_CONFIDENTIAL: + return 'E'; + case PROT_PRIVATE: + return 'P'; + case PROT_CMD: + default: + /* Those 2 cases should not be reached! */ + break; + } + DEBUGASSERT(0); + /* Default to the most secure alternative. */ + return 'P'; +} + +/* Send an FTP command defined by |message| and the optional arguments. The + function returns the ftp_code. If an error occurs, -1 is returned. */ +static int ftp_send_command(struct Curl_easy *data, const char *message, ...) + CURL_PRINTF(2, 3); + +static int ftp_send_command(struct Curl_easy *data, const char *message, ...) +{ + int ftp_code; + ssize_t nread = 0; + va_list args; + char print_buffer[50]; + + va_start(args, message); + mvsnprintf(print_buffer, sizeof(print_buffer), message, args); + va_end(args); + + if(ftpsend(data, data->conn, print_buffer)) { + ftp_code = -1; + } + else { + if(Curl_GetFTPResponse(data, &nread, &ftp_code)) + ftp_code = -1; + } + + (void)nread; /* Unused */ + return ftp_code; +} + +/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode + saying whether an error occurred or CURLE_OK if |len| was read. */ +static CURLcode +socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len) +{ + char *to_p = to; + CURLcode result; + ssize_t nread = 0; + + while(len > 0) { + nread = Curl_conn_recv(data, sockindex, to_p, len, &result); + if(nread > 0) { + len -= nread; + to_p += nread; + } + else { + if(result == CURLE_AGAIN) + continue; + return result; + } + } + return CURLE_OK; +} + + +/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a + CURLcode saying whether an error occurred or CURLE_OK if |len| was + written. */ +static CURLcode +socket_write(struct Curl_easy *data, int sockindex, const void *to, + size_t len) +{ + const char *to_p = to; + CURLcode result; + ssize_t written; + + while(len > 0) { + written = Curl_conn_send(data, sockindex, to_p, len, &result); + if(written > 0) { + len -= written; + to_p += written; + } + else { + if(result == CURLE_AGAIN) + continue; + return result; + } + } + return CURLE_OK; +} + +static CURLcode read_data(struct Curl_easy *data, int sockindex, + struct krb5buffer *buf) +{ + struct connectdata *conn = data->conn; + int len; + CURLcode result; + int nread; + + result = socket_read(data, sockindex, &len, sizeof(len)); + if(result) + return result; + + if(len) { + /* only realloc if there was a length */ + len = ntohl(len); + if(len > CURL_MAX_INPUT_LENGTH) + len = 0; + else + buf->data = Curl_saferealloc(buf->data, len); + } + if(!len || !buf->data) + return CURLE_OUT_OF_MEMORY; + + result = socket_read(data, sockindex, buf->data, len); + if(result) + return result; + nread = conn->mech->decode(conn->app_data, buf->data, len, + conn->data_prot, conn); + if(nread < 0) + return CURLE_RECV_ERROR; + buf->size = (size_t)nread; + buf->index = 0; + return CURLE_OK; +} + +static size_t +buffer_read(struct krb5buffer *buf, void *data, size_t len) +{ + if(buf->size - buf->index < len) + len = buf->size - buf->index; + memcpy(data, (char *)buf->data + buf->index, len); + buf->index += len; + return len; +} + +/* Matches Curl_recv signature */ +static ssize_t sec_recv(struct Curl_easy *data, int sockindex, + char *buffer, size_t len, CURLcode *err) +{ + size_t bytes_read; + size_t total_read = 0; + struct connectdata *conn = data->conn; + + *err = CURLE_OK; + + /* Handle clear text response. */ + if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) + return Curl_conn_recv(data, sockindex, buffer, len, err); + + if(conn->in_buffer.eof_flag) { + conn->in_buffer.eof_flag = 0; + return 0; + } + + bytes_read = buffer_read(&conn->in_buffer, buffer, len); + len -= bytes_read; + total_read += bytes_read; + buffer += bytes_read; + + while(len > 0) { + if(read_data(data, sockindex, &conn->in_buffer)) + return -1; + if(conn->in_buffer.size == 0) { + if(bytes_read > 0) + conn->in_buffer.eof_flag = 1; + return bytes_read; + } + bytes_read = buffer_read(&conn->in_buffer, buffer, len); + len -= bytes_read; + total_read += bytes_read; + buffer += bytes_read; + } + return total_read; +} + +/* Send |length| bytes from |from| to the |fd| socket taking care of encoding + and negotiating with the server. |from| can be NULL. */ +static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t fd, const char *from, int length) +{ + int bytes, htonl_bytes; /* 32-bit integers for htonl */ + char *buffer = NULL; + char *cmd_buffer; + size_t cmd_size = 0; + CURLcode error; + enum protection_level prot_level = conn->data_prot; + bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE; + + DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); + + if(iscmd) { + if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5)) + prot_level = PROT_PRIVATE; + else + prot_level = conn->command_prot; + } + bytes = conn->mech->encode(conn->app_data, from, length, prot_level, + (void **)&buffer); + if(!buffer || bytes <= 0) + return; /* error */ + + if(iscmd) { + error = Curl_base64_encode(buffer, curlx_sitouz(bytes), + &cmd_buffer, &cmd_size); + if(error) { + free(buffer); + return; /* error */ + } + if(cmd_size > 0) { + static const char *enc = "ENC "; + static const char *mic = "MIC "; + if(prot_level == PROT_PRIVATE) + socket_write(data, fd, enc, 4); + else + socket_write(data, fd, mic, 4); + + socket_write(data, fd, cmd_buffer, cmd_size); + socket_write(data, fd, "\r\n", 2); + infof(data, "Send: %s%s", prot_level == PROT_PRIVATE?enc:mic, + cmd_buffer); + free(cmd_buffer); + } + } + else { + htonl_bytes = htonl(bytes); + socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes)); + socket_write(data, fd, buffer, curlx_sitouz(bytes)); + } + free(buffer); +} + +static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t fd, const char *buffer, size_t length) +{ + ssize_t tx = 0, len = conn->buffer_size; + + if(len <= 0) + len = length; + while(length) { + if(length < (size_t)len) + len = length; + + do_sec_send(data, conn, fd, buffer, curlx_sztosi(len)); + length -= len; + buffer += len; + tx += len; + } + return tx; +} + +/* Matches Curl_send signature */ +static ssize_t sec_send(struct Curl_easy *data, int sockindex, + const void *buffer, size_t len, CURLcode *err) +{ + struct connectdata *conn = data->conn; + curl_socket_t fd = conn->sock[sockindex]; + *err = CURLE_OK; + return sec_write(data, conn, fd, buffer, len); +} + +int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, + char *buffer, enum protection_level level) +{ + /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an + int */ + int decoded_len; + char *buf; + int ret_code = 0; + size_t decoded_sz = 0; + CURLcode error; + + (void) data; + + if(!conn->mech) + /* not initialized, return error */ + return -1; + + DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); + + error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); + if(error || decoded_sz == 0) + return -1; + + if(decoded_sz > (size_t)INT_MAX) { + free(buf); + return -1; + } + decoded_len = curlx_uztosi(decoded_sz); + + decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, + level, conn); + if(decoded_len <= 0) { + free(buf); + return -1; + } + + { + buf[decoded_len] = '\n'; + Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1); + } + + buf[decoded_len] = '\0'; + if(decoded_len <= 3) + /* suspiciously short */ + return 0; + + if(buf[3] != '-') + ret_code = atoi(buf); + + if(buf[decoded_len - 1] == '\n') + buf[decoded_len - 1] = '\0'; + strcpy(buffer, buf); + free(buf); + return ret_code; +} + +static int sec_set_protection_level(struct Curl_easy *data) +{ + int code; + struct connectdata *conn = data->conn; + unsigned char level = conn->request_data_prot; + + DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); + + if(!conn->sec_complete) { + infof(data, "Trying to change the protection level after the" + " completion of the data exchange."); + return -1; + } + + /* Bail out if we try to set up the same level */ + if(conn->data_prot == level) + return 0; + + if(level) { + char *pbsz; + unsigned int buffer_size = 1 << 20; /* 1048576 */ + struct pingpong *pp = &conn->proto.ftpc.pp; + char *line; + + code = ftp_send_command(data, "PBSZ %u", buffer_size); + if(code < 0) + return -1; + + if(code/100 != 2) { + failf(data, "Failed to set the protection's buffer size."); + return -1; + } + conn->buffer_size = buffer_size; + + line = Curl_dyn_ptr(&pp->recvbuf); + pbsz = strstr(line, "PBSZ="); + if(pbsz) { + /* stick to default value if the check fails */ + if(ISDIGIT(pbsz[5])) + buffer_size = atoi(&pbsz[5]); + if(buffer_size < conn->buffer_size) + conn->buffer_size = buffer_size; + } + } + + /* Now try to negotiate the protection level. */ + code = ftp_send_command(data, "PROT %c", level_to_char(level)); + + if(code < 0) + return -1; + + if(code/100 != 2) { + failf(data, "Failed to set the protection level."); + return -1; + } + + conn->data_prot = level; + if(level == PROT_PRIVATE) + conn->command_prot = level; + + return 0; +} + +int +Curl_sec_request_prot(struct connectdata *conn, const char *level) +{ + unsigned char l = name_to_level(level); + if(l == PROT_NONE) + return -1; + DEBUGASSERT(l > PROT_NONE && l < PROT_LAST); + conn->request_data_prot = l; + return 0; +} + +static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn) +{ + int ret; + void *tmp_allocation; + const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; + + tmp_allocation = realloc(conn->app_data, mech->size); + if(!tmp_allocation) { + failf(data, "Failed realloc of size %zu", mech->size); + mech = NULL; + return CURLE_OUT_OF_MEMORY; + } + conn->app_data = tmp_allocation; + + if(mech->init) { + ret = mech->init(conn->app_data); + if(ret) { + infof(data, "Failed initialization for %s. Skipping it.", + mech->name); + return CURLE_FAILED_INIT; + } + } + + infof(data, "Trying mechanism %s...", mech->name); + ret = ftp_send_command(data, "AUTH %s", mech->name); + if(ret < 0) + return CURLE_COULDNT_CONNECT; + + if(ret/100 != 3) { + switch(ret) { + case 504: + infof(data, "Mechanism %s is not supported by the server (server " + "returned ftp code: 504).", mech->name); + break; + case 534: + infof(data, "Mechanism %s was rejected by the server (server returned " + "ftp code: 534).", mech->name); + break; + default: + if(ret/100 == 5) { + infof(data, "server does not support the security extensions"); + return CURLE_USE_SSL_FAILED; + } + break; + } + return CURLE_LOGIN_DENIED; + } + + /* Authenticate */ + ret = mech->auth(conn->app_data, data, conn); + + if(ret != AUTH_CONTINUE) { + if(ret != AUTH_OK) { + /* Mechanism has dumped the error to stderr, don't error here. */ + return CURLE_USE_SSL_FAILED; + } + DEBUGASSERT(ret == AUTH_OK); + + conn->mech = mech; + conn->sec_complete = 1; + conn->recv[FIRSTSOCKET] = sec_recv; + conn->send[FIRSTSOCKET] = sec_send; + conn->recv[SECONDARYSOCKET] = sec_recv; + conn->send[SECONDARYSOCKET] = sec_send; + conn->command_prot = PROT_SAFE; + /* Set the requested protection level */ + /* BLOCKING */ + (void)sec_set_protection_level(data); + } + + return CURLE_OK; +} + +CURLcode +Curl_sec_login(struct Curl_easy *data, struct connectdata *conn) +{ + return choose_mech(data, conn); +} + + +void +Curl_sec_end(struct connectdata *conn) +{ + if(conn->mech && conn->mech->end) + conn->mech->end(conn->app_data); + free(conn->app_data); + conn->app_data = NULL; + if(conn->in_buffer.data) { + free(conn->in_buffer.data); + conn->in_buffer.data = NULL; + conn->in_buffer.size = 0; + conn->in_buffer.index = 0; + conn->in_buffer.eof_flag = 0; + } + conn->sec_complete = 0; + conn->data_prot = PROT_CLEAR; + conn->mech = NULL; +} + +#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ diff --git a/lib/ldap.c b/lib/ldap.c new file mode 100644 index 0000000..4c04647 --- /dev/null +++ b/lib/ldap.c @@ -0,0 +1,1107 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP) + +/* + * Notice that USE_OPENLDAP is only a source code selection switch. When + * libcurl is built with USE_OPENLDAP defined the libcurl source code that + * gets compiled is the code from openldap.c, otherwise the code that gets + * compiled is the code from ldap.c. + * + * When USE_OPENLDAP is defined a recent version of the OpenLDAP library + * might be required for compilation and runtime. In order to use ancient + * OpenLDAP library versions, USE_OPENLDAP shall not be defined. + */ + +/* Wincrypt must be included before anything that could include OpenSSL. */ +#if defined(USE_WIN32_CRYPTO) +#include +/* Undefine wincrypt conflicting symbols for BoringSSL. */ +#undef X509_NAME +#undef X509_EXTENSIONS +#undef PKCS7_ISSUER_AND_SERIAL +#undef PKCS7_SIGNER_INFO +#undef OCSP_REQUEST +#undef OCSP_RESPONSE +#endif + +#ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4201) +# endif +# include /* for [P]UNICODE_STRING */ +# ifdef _MSC_VER +# pragma warning(pop) +# endif +# include +# ifndef LDAP_VENDOR_NAME +# error Your Platform SDK is NOT sufficient for LDAP support! \ + Update your Platform SDK, or disable LDAP support! +# else +# include +# endif +#else +# define LDAP_DEPRECATED 1 /* Be sure ldap_init() is defined. */ +# ifdef HAVE_LBER_H +# include +# endif +# include +# if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H)) +# include +# endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */ +#endif + +#include "urldata.h" +#include +#include "sendf.h" +#include "escape.h" +#include "progress.h" +#include "transfer.h" +#include "strcase.h" +#include "strtok.h" +#include "curl_ldap.h" +#include "curl_multibyte.h" +#include "curl_base64.h" +#include "connect.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef HAVE_LDAP_URL_PARSE + +/* Use our own implementation. */ + +struct ldap_urldesc { + char *lud_host; + int lud_port; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_dn; + TCHAR **lud_attrs; +#else + char *lud_dn; + char **lud_attrs; +#endif + int lud_scope; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_filter; +#else + char *lud_filter; +#endif + char **lud_exts; + size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the + "real" struct so can only be used in code + without HAVE_LDAP_URL_PARSE defined */ +}; + +#undef LDAPURLDesc +#define LDAPURLDesc struct ldap_urldesc + +static int _ldap_url_parse(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludp); +static void _ldap_free_urldesc(LDAPURLDesc *ludp); + +#undef ldap_free_urldesc +#define ldap_free_urldesc _ldap_free_urldesc +#endif + +#ifdef DEBUG_LDAP + #define LDAP_TRACE(x) do { \ + _ldap_trace("%u: ", __LINE__); \ + _ldap_trace x; \ + } while(0) + + static void _ldap_trace(const char *fmt, ...) CURL_PRINTF(1, 2); +#else + #define LDAP_TRACE(x) Curl_nop_stmt +#endif + +#if defined(USE_WIN32_LDAP) && defined(ldap_err2string) +/* Use ansi error strings in UNICODE builds */ +#undef ldap_err2string +#define ldap_err2string ldap_err2stringA +#endif + +#if defined(USE_WIN32_LDAP) && defined(_MSC_VER) && (_MSC_VER <= 1600) +/* Workaround for warning: + 'type cast' : conversion from 'int' to 'void *' of greater size */ +#undef LDAP_OPT_ON +#undef LDAP_OPT_OFF +#define LDAP_OPT_ON ((void *)(size_t)1) +#define LDAP_OPT_OFF ((void *)(size_t)0) +#endif + +static CURLcode ldap_do(struct Curl_easy *data, bool *done); + +/* + * LDAP protocol handler. + */ + +const struct Curl_handler Curl_handler_ldap = { + "LDAP", /* scheme */ + ZERO_NULL, /* setup_connection */ + ldap_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_LDAP, /* defport */ + CURLPROTO_LDAP, /* protocol */ + CURLPROTO_LDAP, /* family */ + PROTOPT_NONE /* flags */ +}; + +#ifdef HAVE_LDAP_SSL +/* + * LDAPS protocol handler. + */ + +const struct Curl_handler Curl_handler_ldaps = { + "LDAPS", /* scheme */ + ZERO_NULL, /* setup_connection */ + ldap_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_LDAPS, /* defport */ + CURLPROTO_LDAPS, /* protocol */ + CURLPROTO_LDAP, /* family */ + PROTOPT_SSL /* flags */ +}; +#endif + +#if defined(USE_WIN32_LDAP) + +#if defined(USE_WINDOWS_SSPI) +static int ldap_win_bind_auth(LDAP *server, const char *user, + const char *passwd, unsigned long authflags) +{ + ULONG method = 0; + SEC_WINNT_AUTH_IDENTITY cred; + int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; + + memset(&cred, 0, sizeof(cred)); + +#if defined(USE_SPNEGO) + if(authflags & CURLAUTH_NEGOTIATE) { + method = LDAP_AUTH_NEGOTIATE; + } + else +#endif +#if defined(USE_NTLM) + if(authflags & CURLAUTH_NTLM) { + method = LDAP_AUTH_NTLM; + } + else +#endif +#if !defined(CURL_DISABLE_DIGEST_AUTH) + if(authflags & CURLAUTH_DIGEST) { + method = LDAP_AUTH_DIGEST; + } + else +#endif + { + /* required anyway if one of upper preprocessor definitions enabled */ + } + + if(method && user && passwd) { + rc = Curl_create_sspi_identity(user, passwd, &cred); + if(!rc) { + rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method); + Curl_sspi_free_identity(&cred); + } + } + else { + /* proceed with current user credentials */ + method = LDAP_AUTH_NEGOTIATE; + rc = ldap_bind_s(server, NULL, NULL, method); + } + return rc; +} +#endif /* #if defined(USE_WINDOWS_SSPI) */ + +static int ldap_win_bind(struct Curl_easy *data, LDAP *server, + const char *user, const char *passwd) +{ + int rc = LDAP_INVALID_CREDENTIALS; + + PTCHAR inuser = NULL; + PTCHAR inpass = NULL; + + if(user && passwd && (data->set.httpauth & CURLAUTH_BASIC)) { + inuser = curlx_convert_UTF8_to_tchar((char *) user); + inpass = curlx_convert_UTF8_to_tchar((char *) passwd); + + rc = ldap_simple_bind_s(server, inuser, inpass); + + curlx_unicodefree(inuser); + curlx_unicodefree(inpass); + } +#if defined(USE_WINDOWS_SSPI) + else { + rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth); + } +#endif + + return rc; +} +#endif /* #if defined(USE_WIN32_LDAP) */ + +#if defined(USE_WIN32_LDAP) +#define FREE_ON_WINLDAP(x) curlx_unicodefree(x) +#else +#define FREE_ON_WINLDAP(x) +#endif + + +static CURLcode ldap_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + int rc = 0; + LDAP *server = NULL; + LDAPURLDesc *ludp = NULL; + LDAPMessage *ldapmsg = NULL; + LDAPMessage *entryIterator; + int num = 0; + struct connectdata *conn = data->conn; + int ldap_proto = LDAP_VERSION3; + int ldap_ssl = 0; + char *val_b64 = NULL; + size_t val_b64_sz = 0; +#ifdef LDAP_OPT_NETWORK_TIMEOUT + struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ +#endif +#if defined(USE_WIN32_LDAP) + TCHAR *host = NULL; +#else + char *host = NULL; +#endif + char *user = NULL; + char *passwd = NULL; + + *done = TRUE; /* unconditionally */ + infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d", + LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION); + infof(data, "LDAP local: %s", data->state.url); + +#ifdef HAVE_LDAP_URL_PARSE + rc = ldap_url_parse(data->state.url, &ludp); +#else + rc = _ldap_url_parse(data, conn, &ludp); +#endif + if(rc) { + failf(data, "Bad LDAP URL: %s", ldap_err2string(rc)); + result = CURLE_URL_MALFORMAT; + goto quit; + } + + /* Get the URL scheme (either ldap or ldaps) */ + if(conn->given->flags & PROTOPT_SSL) + ldap_ssl = 1; + infof(data, "LDAP local: trying to establish %s connection", + ldap_ssl ? "encrypted" : "cleartext"); + +#if defined(USE_WIN32_LDAP) + host = curlx_convert_UTF8_to_tchar(conn->host.name); + if(!host) { + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + host = conn->host.name; +#endif + + if(data->state.aptr.user) { + user = conn->user; + passwd = conn->passwd; + } + +#ifdef LDAP_OPT_NETWORK_TIMEOUT + ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); +#endif + ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); + + if(ldap_ssl) { +#ifdef HAVE_LDAP_SSL +#ifdef USE_WIN32_LDAP + /* Win32 LDAP SDK doesn't support insecure mode without CA! */ + server = ldap_sslinit(host, conn->port, 1); + ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); +#else + int ldap_option; + char *ldap_ca = conn->ssl_config.CAfile; +#if defined(CURL_HAS_NOVELL_LDAPSDK) + rc = ldapssl_client_init(NULL, NULL); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc)); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + if(conn->ssl_config.verifypeer) { + /* Novell SDK supports DER or BASE64 files. */ + int cert_type = LDAPSSL_CERT_FILETYPE_B64; + if((data->set.ssl.cert_type) && + (strcasecompare(data->set.ssl.cert_type, "DER"))) + cert_type = LDAPSSL_CERT_FILETYPE_DER; + if(!ldap_ca) { + failf(data, "LDAP local: ERROR %s CA cert not set", + (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM")); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + infof(data, "LDAP local: using %s CA cert '%s'", + (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), + ldap_ca); + rc = ldapssl_add_trusted_cert(ldap_ca, cert_type); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ERROR setting %s CA cert: %s", + (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), + ldap_err2string(rc)); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + ldap_option = LDAPSSL_VERIFY_SERVER; + } + else + ldap_option = LDAPSSL_VERIFY_NONE; + rc = ldapssl_set_verify_mode(ldap_option); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ERROR setting cert verify mode: %s", + ldap_err2string(rc)); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + server = ldapssl_init(host, conn->port, 1); + if(!server) { + failf(data, "LDAP local: Cannot connect to %s:%u", + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; + goto quit; + } +#elif defined(LDAP_OPT_X_TLS) + if(conn->ssl_config.verifypeer) { + /* OpenLDAP SDK supports BASE64 files. */ + if((data->set.ssl.cert_type) && + (!strcasecompare(data->set.ssl.cert_type, "PEM"))) { + failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type"); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + if(!ldap_ca) { + failf(data, "LDAP local: ERROR PEM CA cert not set"); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + infof(data, "LDAP local: using PEM CA cert: %s", ldap_ca); + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ERROR setting PEM CA cert: %s", + ldap_err2string(rc)); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + ldap_option = LDAP_OPT_X_TLS_DEMAND; + } + else + ldap_option = LDAP_OPT_X_TLS_NEVER; + + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ERROR setting cert verify mode: %s", + ldap_err2string(rc)); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } + server = ldap_init(host, conn->port); + if(!server) { + failf(data, "LDAP local: Cannot connect to %s:%u", + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; + goto quit; + } + ldap_option = LDAP_OPT_X_TLS_HARD; + rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", + ldap_err2string(rc)); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } +/* + rc = ldap_start_tls_s(server, NULL, NULL); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", + ldap_err2string(rc)); + result = CURLE_SSL_CERTPROBLEM; + goto quit; + } +*/ +#else + /* we should probably never come up to here since configure + should check in first place if we can support LDAP SSL/TLS */ + failf(data, "LDAP local: SSL/TLS not supported with this version " + "of the OpenLDAP toolkit\n"); + result = CURLE_SSL_CERTPROBLEM; + goto quit; +#endif +#endif +#endif /* CURL_LDAP_USE_SSL */ + } + else if(data->set.use_ssl > CURLUSESSL_TRY) { + failf(data, "LDAP local: explicit TLS not supported"); + result = CURLE_NOT_BUILT_IN; + goto quit; + } + else { + server = ldap_init(host, conn->port); + if(!server) { + failf(data, "LDAP local: Cannot connect to %s:%u", + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; + goto quit; + } + } +#ifdef USE_WIN32_LDAP + ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); + rc = ldap_win_bind(data, server, user, passwd); +#else + rc = ldap_simple_bind_s(server, user, passwd); +#endif + if(!ldap_ssl && rc) { + ldap_proto = LDAP_VERSION2; + ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); +#ifdef USE_WIN32_LDAP + rc = ldap_win_bind(data, server, user, passwd); +#else + rc = ldap_simple_bind_s(server, user, passwd); +#endif + } + if(rc) { +#ifdef USE_WIN32_LDAP + failf(data, "LDAP local: bind via ldap_win_bind %s", + ldap_err2string(rc)); +#else + failf(data, "LDAP local: bind via ldap_simple_bind_s %s", + ldap_err2string(rc)); +#endif + result = CURLE_LDAP_CANNOT_BIND; + goto quit; + } + + Curl_pgrsSetDownloadCounter(data, 0); + rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, + ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); + + if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) { + failf(data, "LDAP remote: %s", ldap_err2string(rc)); + result = CURLE_LDAP_SEARCH_FAILED; + goto quit; + } + + for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg); + entryIterator; + entryIterator = ldap_next_entry(server, entryIterator), num++) { + BerElement *ber = NULL; +#if defined(USE_WIN32_LDAP) + TCHAR *attribute; +#else + char *attribute; +#endif + int i; + + /* Get the DN and write it to the client */ + { + char *name; + size_t name_len; +#if defined(USE_WIN32_LDAP) + TCHAR *dn = ldap_get_dn(server, entryIterator); + name = curlx_convert_tchar_to_UTF8(dn); + if(!name) { + ldap_memfree(dn); + + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + char *dn = name = ldap_get_dn(server, entryIterator); +#endif + name_len = strlen(name); + + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4); + if(result) { + FREE_ON_WINLDAP(name); + ldap_memfree(dn); + goto quit; + } + + result = Curl_client_write(data, CLIENTWRITE_BODY, name, name_len); + if(result) { + FREE_ON_WINLDAP(name); + ldap_memfree(dn); + goto quit; + } + + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { + FREE_ON_WINLDAP(name); + ldap_memfree(dn); + + goto quit; + } + + FREE_ON_WINLDAP(name); + ldap_memfree(dn); + } + + /* Get the attributes and write them to the client */ + for(attribute = ldap_first_attribute(server, entryIterator, &ber); + attribute; + attribute = ldap_next_attribute(server, entryIterator, ber)) { + BerValue **vals; + size_t attr_len; +#if defined(USE_WIN32_LDAP) + char *attr = curlx_convert_tchar_to_UTF8(attribute); + if(!attr) { + if(ber) + ber_free(ber, 0); + + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + char *attr = attribute; +#endif + attr_len = strlen(attr); + + vals = ldap_get_values_len(server, entryIterator, attribute); + if(vals) { + for(i = 0; (vals[i] != NULL); i++) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(data, CLIENTWRITE_BODY, attr, attr_len); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + if((attr_len > 7) && + (strcmp(";binary", attr + (attr_len - 7)) == 0)) { + /* Binary attribute, encode to base64. */ + result = Curl_base64_encode(vals[i]->bv_val, vals[i]->bv_len, + &val_b64, &val_b64_sz); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + if(val_b64_sz > 0) { + result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, + val_b64_sz); + free(val_b64); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + } + } + else { + result = Curl_client_write(data, CLIENTWRITE_BODY, vals[i]->bv_val, + vals[i]->bv_len); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + } + + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + } + + /* Free memory used to store values */ + ldap_value_free_len(vals); + } + + /* Free the attribute as we are done with it */ + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) + goto quit; + } + + if(ber) + ber_free(ber, 0); + } + +quit: + if(ldapmsg) { + ldap_msgfree(ldapmsg); + LDAP_TRACE(("Received %d entries\n", num)); + } + if(rc == LDAP_SIZELIMIT_EXCEEDED) + infof(data, "There are more than %d entries", num); + if(ludp) + ldap_free_urldesc(ludp); + if(server) + ldap_unbind_s(server); +#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK) + if(ldap_ssl) + ldapssl_client_deinit(); +#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ + + FREE_ON_WINLDAP(host); + + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + connclose(conn, "LDAP connection always disable reuse"); + + return result; +} + +#ifdef DEBUG_LDAP +static void _ldap_trace(const char *fmt, ...) +{ + static int do_trace = -1; + va_list args; + + if(do_trace == -1) { + const char *env = getenv("CURL_TRACE"); + do_trace = (env && strtol(env, NULL, 10) > 0); + } + if(!do_trace) + return; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} +#endif + +#ifndef HAVE_LDAP_URL_PARSE + +/* + * Return scope-value for a scope-string. + */ +static int str2scope(const char *p) +{ + if(strcasecompare(p, "one")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "onetree")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "base")) + return LDAP_SCOPE_BASE; + if(strcasecompare(p, "sub")) + return LDAP_SCOPE_SUBTREE; + if(strcasecompare(p, "subtree")) + return LDAP_SCOPE_SUBTREE; + return (-1); +} + +/* + * Split 'str' into strings separated by commas. + * Note: out[] points into 'str'. + */ +static bool split_str(char *str, char ***out, size_t *count) +{ + char **res; + char *lasts; + char *s; + size_t i; + size_t items = 1; + + s = strchr(str, ','); + while(s) { + items++; + s = strchr(++s, ','); + } + + res = calloc(items, sizeof(char *)); + if(!res) + return FALSE; + + for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items; + s = strtok_r(NULL, ",", &lasts), i++) + res[i] = s; + + *out = res; + *count = items; + + return TRUE; +} + +/* + * Break apart the pieces of an LDAP URL. + * Syntax: + * ldap://:/???? + * + * already known from 'conn->host.name'. + * already known from 'conn->remote_port'. + * extract the rest from 'data->state.path+1'. All fields are optional. + * e.g. + * ldap://:/??? + * yields ludp->lud_dn = "". + * + * Defined in RFC4516 section 2. + */ +static int _ldap_url_parse2(struct Curl_easy *data, + const struct connectdata *conn, LDAPURLDesc *ludp) +{ + int rc = LDAP_SUCCESS; + char *p; + char *path; + char *q = NULL; + char *query = NULL; + size_t i; + + if(!data || + !data->state.up.path || + data->state.up.path[0] != '/' || + !strncasecompare("LDAP", data->state.up.scheme, 4)) + return LDAP_INVALID_SYNTAX; + + ludp->lud_scope = LDAP_SCOPE_BASE; + ludp->lud_port = conn->remote_port; + ludp->lud_host = conn->host.name; + + /* Duplicate the path */ + p = path = strdup(data->state.up.path + 1); + if(!path) + return LDAP_NO_MEMORY; + + /* Duplicate the query if present */ + if(data->state.up.query) { + q = query = strdup(data->state.up.query); + if(!query) { + free(path); + return LDAP_NO_MEMORY; + } + } + + /* Parse the DN (Distinguished Name) */ + if(*p) { + char *dn = p; + char *unescaped; + CURLcode result; + + LDAP_TRACE(("DN '%s'\n", dn)); + + /* Unescape the DN */ + result = Curl_urldecode(dn, 0, &unescaped, NULL, REJECT_ZERO); + if(result) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + free(unescaped); + + if(!ludp->lud_dn) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_dn = unescaped; +#endif + } + + p = q; + if(!p) + goto quit; + + /* Parse the attributes. skip "??" */ + q = strchr(p, '?'); + if(q) + *q++ = '\0'; + + if(*p) { + char **attributes; + size_t count = 0; + + /* Split the string into an array of attributes */ + if(!split_str(p, &attributes, &count)) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + + /* Allocate our array (+1 for the NULL entry) */ +#if defined(USE_WIN32_LDAP) + ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *)); +#else + ludp->lud_attrs = calloc(count + 1, sizeof(char *)); +#endif + if(!ludp->lud_attrs) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + + for(i = 0; i < count; i++) { + char *unescaped; + CURLcode result; + + LDAP_TRACE(("attr[%zu] '%s'\n", i, attributes[i])); + + /* Unescape the attribute */ + result = Curl_urldecode(attributes[i], 0, &unescaped, NULL, + REJECT_ZERO); + if(result) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + free(unescaped); + + if(!ludp->lud_attrs[i]) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_attrs[i] = unescaped; +#endif + + ludp->lud_attrs_dups++; + } + + free(attributes); + } + + p = q; + if(!p) + goto quit; + + /* Parse the scope. skip "??" */ + q = strchr(p, '?'); + if(q) + *q++ = '\0'; + + if(*p) { + ludp->lud_scope = str2scope(p); + if(ludp->lud_scope == -1) { + rc = LDAP_INVALID_SYNTAX; + + goto quit; + } + LDAP_TRACE(("scope %d\n", ludp->lud_scope)); + } + + p = q; + if(!p) + goto quit; + + /* Parse the filter */ + q = strchr(p, '?'); + if(q) + *q++ = '\0'; + + if(*p) { + char *filter = p; + char *unescaped; + CURLcode result; + + LDAP_TRACE(("filter '%s'\n", filter)); + + /* Unescape the filter */ + result = Curl_urldecode(filter, 0, &unescaped, NULL, REJECT_ZERO); + if(result) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + free(unescaped); + + if(!ludp->lud_filter) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_filter = unescaped; +#endif + } + + p = q; + if(p && !*p) { + rc = LDAP_INVALID_SYNTAX; + + goto quit; + } + +quit: + free(path); + free(query); + + return rc; +} + +static int _ldap_url_parse(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludpp) +{ + LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); + int rc; + + *ludpp = NULL; + if(!ludp) + return LDAP_NO_MEMORY; + + rc = _ldap_url_parse2(data, conn, ludp); + if(rc != LDAP_SUCCESS) { + _ldap_free_urldesc(ludp); + ludp = NULL; + } + *ludpp = ludp; + return (rc); +} + +static void _ldap_free_urldesc(LDAPURLDesc *ludp) +{ + if(!ludp) + return; + +#if defined(USE_WIN32_LDAP) + curlx_unicodefree(ludp->lud_dn); + curlx_unicodefree(ludp->lud_filter); +#else + free(ludp->lud_dn); + free(ludp->lud_filter); +#endif + + if(ludp->lud_attrs) { + size_t i; + for(i = 0; i < ludp->lud_attrs_dups; i++) { +#if defined(USE_WIN32_LDAP) + curlx_unicodefree(ludp->lud_attrs[i]); +#else + free(ludp->lud_attrs[i]); +#endif + } + free(ludp->lud_attrs); + } + + free(ludp); +} +#endif /* !HAVE_LDAP_URL_PARSE */ +#endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */ diff --git a/lib/libcurl.plist b/lib/libcurl.plist new file mode 100644 index 0000000..363e76d --- /dev/null +++ b/lib/libcurl.plist @@ -0,0 +1,35 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundleDevelopmentRegion + English + + CFBundleExecutable + curl + + CFBundleIdentifier + se.curl.libcurl + + CFBundleVersion + 8.6.0 + + CFBundleName + libcurl + + CFBundlePackageType + FMWK + + CFBundleSignature + ???? + + CFBundleShortVersionString + libcurl 8.6.0 + + CFBundleGetInfoString + libcurl.plist 8.6.0 + + diff --git a/lib/libcurl.plist.in b/lib/libcurl.plist.in new file mode 100644 index 0000000..d2e6492 --- /dev/null +++ b/lib/libcurl.plist.in @@ -0,0 +1,35 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundleDevelopmentRegion + English + + CFBundleExecutable + curl + + CFBundleIdentifier + se.curl.libcurl + + CFBundleVersion + @CURL_PLIST_VERSION@ + + CFBundleName + libcurl + + CFBundlePackageType + FMWK + + CFBundleSignature + ???? + + CFBundleShortVersionString + libcurl @CURL_PLIST_VERSION@ + + CFBundleGetInfoString + libcurl.plist @CURL_PLIST_VERSION@ + + diff --git a/lib/libcurl.rc b/lib/libcurl.rc new file mode 100644 index 0000000..daa2d62 --- /dev/null +++ b/lib/libcurl.rc @@ -0,0 +1,65 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include +#include "../include/curl/curlver.h" + +LANGUAGE 0, 0 + +#define RC_VERSION LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RC_VERSION + PRODUCTVERSION RC_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#if defined(DEBUGBUILD) || defined(_DEBUG) + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0L + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "The curl library, https://curl.se/\0" + VALUE "FileDescription", "libcurl Shared Library\0" + VALUE "FileVersion", LIBCURL_VERSION "\0" + VALUE "InternalName", "libcurl\0" + VALUE "OriginalFilename", "libcurl.dll\0" + VALUE "ProductName", "The curl library\0" + VALUE "ProductVersion", LIBCURL_VERSION "\0" + VALUE "LegalCopyright", "Copyright (C) " LIBCURL_COPYRIGHT "\0" + VALUE "License", "https://curl.se/docs/copyright.html\0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/lib/libcurl.vers.in b/lib/libcurl.vers.in new file mode 100644 index 0000000..ae978a4 --- /dev/null +++ b/lib/libcurl.vers.in @@ -0,0 +1,13 @@ +HIDDEN +{ + local: + __*; + _rest*; + _save*; +}; + +CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@4 +{ + global: curl_*; + local: *; +}; diff --git a/lib/llist.c b/lib/llist.c new file mode 100644 index 0000000..5b6b033 --- /dev/null +++ b/lib/llist.c @@ -0,0 +1,146 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "llist.h" +#include "curl_memory.h" + +/* this must be the last include file */ +#include "memdebug.h" + +/* + * @unittest: 1300 + */ +void +Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor) +{ + l->size = 0; + l->dtor = dtor; + l->head = NULL; + l->tail = NULL; +} + +/* + * Curl_llist_insert_next() + * + * Inserts a new list element after the given one 'e'. If the given existing + * entry is NULL and the list already has elements, the new one will be + * inserted first in the list. + * + * The 'ne' argument should be a pointer into the object to store. + * + * @unittest: 1300 + */ +void +Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e, + const void *p, + struct Curl_llist_element *ne) +{ + ne->ptr = (void *) p; + if(list->size == 0) { + list->head = ne; + list->head->prev = NULL; + list->head->next = NULL; + list->tail = ne; + } + else { + /* if 'e' is NULL here, we insert the new element first in the list */ + ne->next = e?e->next:list->head; + ne->prev = e; + if(!e) { + list->head->prev = ne; + list->head = ne; + } + else if(e->next) { + e->next->prev = ne; + } + else { + list->tail = ne; + } + if(e) + e->next = ne; + } + + ++list->size; +} + +/* + * @unittest: 1300 + */ +void +Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e, + void *user) +{ + void *ptr; + if(!e || list->size == 0) + return; + + if(e == list->head) { + list->head = e->next; + + if(!list->head) + list->tail = NULL; + else + e->next->prev = NULL; + } + else { + if(e->prev) + e->prev->next = e->next; + + if(!e->next) + list->tail = e->prev; + else + e->next->prev = e->prev; + } + + ptr = e->ptr; + + e->ptr = NULL; + e->prev = NULL; + e->next = NULL; + + --list->size; + + /* call the dtor() last for when it actually frees the 'e' memory itself */ + if(list->dtor) + list->dtor(user, ptr); +} + +void +Curl_llist_destroy(struct Curl_llist *list, void *user) +{ + if(list) { + while(list->size > 0) + Curl_llist_remove(list, list->tail, user); + } +} + +size_t +Curl_llist_count(struct Curl_llist *list) +{ + return list->size; +} diff --git a/lib/llist.h b/lib/llist.h new file mode 100644 index 0000000..320580e --- /dev/null +++ b/lib/llist.h @@ -0,0 +1,52 @@ +#ifndef HEADER_CURL_LLIST_H +#define HEADER_CURL_LLIST_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include + +typedef void (*Curl_llist_dtor)(void *, void *); + +struct Curl_llist_element { + void *ptr; + struct Curl_llist_element *prev; + struct Curl_llist_element *next; +}; + +struct Curl_llist { + struct Curl_llist_element *head; + struct Curl_llist_element *tail; + Curl_llist_dtor dtor; + size_t size; +}; + +void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor); +void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *, + const void *, struct Curl_llist_element *node); +void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *, + void *); +size_t Curl_llist_count(struct Curl_llist *); +void Curl_llist_destroy(struct Curl_llist *, void *); +#endif /* HEADER_CURL_LLIST_H */ diff --git a/lib/macos.c b/lib/macos.c new file mode 100644 index 0000000..9e8e76e --- /dev/null +++ b/lib/macos.c @@ -0,0 +1,55 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef CURL_MACOS_CALL_COPYPROXIES + +#include + +#include "macos.h" + +#include + +CURLcode Curl_macos_init(void) +{ + { + /* + * The automagic conversion from IPv4 literals to IPv6 literals only + * works if the SCDynamicStoreCopyProxies system function gets called + * first. As Curl currently doesn't support system-wide HTTP proxies, we + * therefore don't use any value this function might return. + * + * This function is only available on macOS and is not needed for + * IPv4-only builds, hence the conditions for defining + * CURL_MACOS_CALL_COPYPROXIES in curl_setup.h. + */ + CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); + if(dict) + CFRelease(dict); + } + return CURLE_OK; +} + +#endif diff --git a/lib/macos.h b/lib/macos.h new file mode 100644 index 0000000..637860e --- /dev/null +++ b/lib/macos.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_MACOS_H +#define HEADER_CURL_MACOS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef CURL_MACOS_CALL_COPYPROXIES + +CURLcode Curl_macos_init(void); + +#else + +#define Curl_macos_init() CURLE_OK + +#endif + +#endif /* HEADER_CURL_MACOS_H */ diff --git a/lib/md4.c b/lib/md4.c new file mode 100644 index 0000000..067c211 --- /dev/null +++ b/lib/md4.c @@ -0,0 +1,524 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_CURL_NTLM_CORE) + +#include + +#include "curl_md4.h" +#include "warnless.h" + +#ifdef USE_OPENSSL +#include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(USE_AMISSL) +/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */ +#define OPENSSL_NO_MD4 +#endif +#endif /* USE_OPENSSL */ + +#ifdef USE_WOLFSSL +#include +#define VOID_MD4_INIT +#ifdef NO_MD4 +#define WOLFSSL_NO_MD4 +#endif +#endif + +#ifdef USE_MBEDTLS +#include +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#include +#else +#include +#endif +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) + #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS +#endif +#endif /* USE_MBEDTLS */ + +#if defined(USE_GNUTLS) +#include +/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */ +#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4) +#include +#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4) +#include +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \ + defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \ + (__MAC_OS_X_VERSION_MIN_REQUIRED < 101500)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000) && \ + defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && \ + (__IPHONE_OS_VERSION_MIN_REQUIRED < 130000)) +#define AN_APPLE_OS +#include +#elif defined(USE_WIN32_CRYPTO) +#include +#elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C)) +#include +#endif + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +#if defined(USE_GNUTLS) + +typedef struct md4_ctx MD4_CTX; + +static int MD4_Init(MD4_CTX *ctx) +{ + md4_init(ctx); + return 1; +} + +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) +{ + md4_update(ctx, size, data); +} + +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) +{ + md4_digest(ctx, MD4_DIGEST_SIZE, result); +} + +#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4) + +#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4) + +#elif defined(AN_APPLE_OS) +typedef CC_MD4_CTX MD4_CTX; + +static int MD4_Init(MD4_CTX *ctx) +{ + return CC_MD4_Init(ctx); +} + +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) +{ + (void)CC_MD4_Update(ctx, data, (CC_LONG)size); +} + +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) +{ + (void)CC_MD4_Final(result, ctx); +} + +#elif defined(USE_WIN32_CRYPTO) + +struct md4_ctx { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; +}; +typedef struct md4_ctx MD4_CTX; + +static int MD4_Init(MD4_CTX *ctx) +{ + ctx->hCryptProv = 0; + ctx->hHash = 0; + + if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return 0; + + if(!CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash)) { + CryptReleaseContext(ctx->hCryptProv, 0); + ctx->hCryptProv = 0; + return 0; + } + + return 1; +} + +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) +{ + CryptHashData(ctx->hHash, (BYTE *)data, (unsigned int) size, 0); +} + +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) +{ + unsigned long length = 0; + + CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); + if(length == MD4_DIGEST_LENGTH) + CryptGetHashParam(ctx->hHash, HP_HASHVAL, result, &length, 0); + + if(ctx->hHash) + CryptDestroyHash(ctx->hHash); + + if(ctx->hCryptProv) + CryptReleaseContext(ctx->hCryptProv, 0); +} + +#elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C)) + +struct md4_ctx { + void *data; + unsigned long size; +}; +typedef struct md4_ctx MD4_CTX; + +static int MD4_Init(MD4_CTX *ctx) +{ + ctx->data = NULL; + ctx->size = 0; + return 1; +} + +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) +{ + if(!ctx->data) { + ctx->data = Curl_memdup(data, size); + if(ctx->data) + ctx->size = size; + } +} + +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) +{ + if(ctx->data) { +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + mbedtls_md4(ctx->data, ctx->size, result); +#else + (void) mbedtls_md4_ret(ctx->data, ctx->size, result); +#endif + + Curl_safefree(ctx->data); + ctx->size = 0; + } +} + +#else +/* When no other crypto library is available, or the crypto library doesn't + * support MD4, we use this code segment this implementation of it + * + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD4 Message-Digest Algorithm (RFC 1320). + * + * Homepage: + https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. In case + * this attempt to disclaim copyright and place the software in the public + * domain is deemed null and void, then the software is Copyright (c) 2001 + * Alexander Peslyak and it is hereby released to the general public under the + * following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD4_u32plus; + +struct md4_ctx { + MD4_u32plus lo, hi; + MD4_u32plus a, b, c, d; + unsigned char buffer[64]; + MD4_u32plus block[16]; +}; +typedef struct md4_ctx MD4_CTX; + +static int MD4_Init(MD4_CTX *ctx); +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size); +static void MD4_Final(unsigned char *result, MD4_CTX *ctx); + +/* + * The basic MD4 functions. + * + * F and G are optimized compared to their RFC 1320 definitions, with the + * optimization for F borrowed from Colin Plumb's MD5 implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The MD4 transformation for all three rounds. + */ +#define STEP(f, a, b, c, d, x, s) \ + (a) += f((b), (c), (d)) + (x); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD4_u32plus *)(void *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD4_u32plus)ptr[(n) * 4] | \ + ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD4_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. + */ +static const void *body(MD4_CTX *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD4_u32plus a, b, c, d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + MD4_u32plus saved_a, saved_b, saved_c, saved_d; + + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 3) + STEP(F, d, a, b, c, SET(1), 7) + STEP(F, c, d, a, b, SET(2), 11) + STEP(F, b, c, d, a, SET(3), 19) + STEP(F, a, b, c, d, SET(4), 3) + STEP(F, d, a, b, c, SET(5), 7) + STEP(F, c, d, a, b, SET(6), 11) + STEP(F, b, c, d, a, SET(7), 19) + STEP(F, a, b, c, d, SET(8), 3) + STEP(F, d, a, b, c, SET(9), 7) + STEP(F, c, d, a, b, SET(10), 11) + STEP(F, b, c, d, a, SET(11), 19) + STEP(F, a, b, c, d, SET(12), 3) + STEP(F, d, a, b, c, SET(13), 7) + STEP(F, c, d, a, b, SET(14), 11) + STEP(F, b, c, d, a, SET(15), 19) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while(size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +static int MD4_Init(MD4_CTX *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; + return 1; +} + +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) +{ + MD4_u32plus saved_lo; + unsigned long used; + + saved_lo = ctx->lo; + ctx->lo = (saved_lo + size) & 0x1fffffff; + if(ctx->lo < saved_lo) + ctx->hi++; + ctx->hi += (MD4_u32plus)size >> 29; + + used = saved_lo & 0x3f; + + if(used) { + unsigned long available = 64 - used; + + if(size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if(size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if(available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); + ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); + ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); + ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff); + ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); + ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); + ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); + ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); + + body(ctx, ctx->buffer, 64); + + result[0] = curlx_ultouc((ctx->a)&0xff); + result[1] = curlx_ultouc((ctx->a >> 8)&0xff); + result[2] = curlx_ultouc((ctx->a >> 16)&0xff); + result[3] = curlx_ultouc(ctx->a >> 24); + result[4] = curlx_ultouc((ctx->b)&0xff); + result[5] = curlx_ultouc((ctx->b >> 8)&0xff); + result[6] = curlx_ultouc((ctx->b >> 16)&0xff); + result[7] = curlx_ultouc(ctx->b >> 24); + result[8] = curlx_ultouc((ctx->c)&0xff); + result[9] = curlx_ultouc((ctx->c >> 8)&0xff); + result[10] = curlx_ultouc((ctx->c >> 16)&0xff); + result[11] = curlx_ultouc(ctx->c >> 24); + result[12] = curlx_ultouc((ctx->d)&0xff); + result[13] = curlx_ultouc((ctx->d >> 8)&0xff); + result[14] = curlx_ultouc((ctx->d >> 16)&0xff); + result[15] = curlx_ultouc(ctx->d >> 24); + + memset(ctx, 0, sizeof(*ctx)); +} + +#endif /* CRYPTO LIBS */ + +CURLcode Curl_md4it(unsigned char *output, const unsigned char *input, + const size_t len) +{ + MD4_CTX ctx; + +#ifdef VOID_MD4_INIT + MD4_Init(&ctx); +#else + if(!MD4_Init(&ctx)) + return CURLE_FAILED_INIT; +#endif + + MD4_Update(&ctx, input, curlx_uztoui(len)); + MD4_Final(output, &ctx); + return CURLE_OK; +} + +#endif /* USE_CURL_NTLM_CORE */ diff --git a/lib/md5.c b/lib/md5.c new file mode 100644 index 0000000..01415af --- /dev/null +++ b/lib/md5.c @@ -0,0 +1,656 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ + || !defined(CURL_DISABLE_DIGEST_AUTH) + +#include +#include + +#include "curl_md5.h" +#include "curl_hmac.h" +#include "warnless.h" + +#ifdef USE_MBEDTLS +#include + +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \ + (MBEDTLS_VERSION_NUMBER < 0x03000000) + #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS +#endif +#endif /* USE_MBEDTLS */ + +#ifdef USE_OPENSSL + #include + #if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_DEPRECATED_3_0) + #define USE_OPENSSL_MD5 + #endif +#endif + +#ifdef USE_WOLFSSL + #include + #ifndef NO_MD5 + #define USE_WOLFSSL_MD5 + #endif +#endif + +#if defined(USE_GNUTLS) +#include +#elif defined(USE_OPENSSL_MD5) +#include +#elif defined(USE_WOLFSSL_MD5) +#include +#elif defined(USE_MBEDTLS) +#include +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \ + defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \ + (__MAC_OS_X_VERSION_MIN_REQUIRED < 101500)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000) && \ + defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && \ + (__IPHONE_OS_VERSION_MIN_REQUIRED < 130000)) +#define AN_APPLE_OS +#include +#elif defined(USE_WIN32_CRYPTO) +#include +#endif + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if defined(USE_GNUTLS) + +typedef struct md5_ctx my_md5_ctx; + +static CURLcode my_md5_init(my_md5_ctx *ctx) +{ + md5_init(ctx); + return CURLE_OK; +} + +static void my_md5_update(my_md5_ctx *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + md5_update(ctx, inputLen, input); +} + +static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx) +{ + md5_digest(ctx, 16, digest); +} + +#elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5) + +typedef MD5_CTX my_md5_ctx; + +static CURLcode my_md5_init(my_md5_ctx *ctx) +{ + if(!MD5_Init(ctx)) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +static void my_md5_update(my_md5_ctx *ctx, + const unsigned char *input, + unsigned int len) +{ + (void)MD5_Update(ctx, input, len); +} + +static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx) +{ + (void)MD5_Final(digest, ctx); +} + +#elif defined(USE_MBEDTLS) + +typedef mbedtls_md5_context my_md5_ctx; + +static CURLcode my_md5_init(my_md5_ctx *ctx) +{ +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + if(mbedtls_md5_starts(ctx)) + return CURLE_OUT_OF_MEMORY; +#elif defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + if(mbedtls_md5_starts_ret(ctx)) + return CURLE_OUT_OF_MEMORY; +#else + (void)mbedtls_md5_starts(ctx); +#endif + return CURLE_OK; +} + +static void my_md5_update(my_md5_ctx *ctx, + const unsigned char *data, + unsigned int length) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_md5_update(ctx, data, length); +#else + (void) mbedtls_md5_update_ret(ctx, data, length); +#endif +} + +static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_md5_finish(ctx, digest); +#else + (void) mbedtls_md5_finish_ret(ctx, digest); +#endif +} + +#elif defined(AN_APPLE_OS) + +/* For Apple operating systems: CommonCrypto has the functions we need. + These functions are available on Tiger and later, as well as iOS 2.0 + and later. If you're building for an older cat, well, sorry. + + Declaring the functions as static like this seems to be a bit more + reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */ +# define my_md5_ctx CC_MD5_CTX + +static CURLcode my_md5_init(my_md5_ctx *ctx) +{ + if(!CC_MD5_Init(ctx)) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +static void my_md5_update(my_md5_ctx *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + CC_MD5_Update(ctx, input, inputLen); +} + +static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx) +{ + CC_MD5_Final(digest, ctx); +} + +#elif defined(USE_WIN32_CRYPTO) + +struct md5_ctx { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; +}; +typedef struct md5_ctx my_md5_ctx; + +static CURLcode my_md5_init(my_md5_ctx *ctx) +{ + if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return CURLE_OUT_OF_MEMORY; + + if(!CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash)) { + CryptReleaseContext(ctx->hCryptProv, 0); + ctx->hCryptProv = 0; + return CURLE_FAILED_INIT; + } + + return CURLE_OK; +} + +static void my_md5_update(my_md5_ctx *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); +} + +static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx) +{ + unsigned long length = 0; + CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); + if(length == 16) + CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); + if(ctx->hHash) + CryptDestroyHash(ctx->hHash); + if(ctx->hCryptProv) + CryptReleaseContext(ctx->hCryptProv, 0); +} + +#else + +/* When no other crypto library is available we use this code segment */ + +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD5_u32plus; + +struct md5_ctx { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + MD5_u32plus block[16]; +}; +typedef struct md5_ctx my_md5_ctx; + +static CURLcode my_md5_init(my_md5_ctx *ctx); +static void my_md5_update(my_md5_ctx *ctx, const void *data, + unsigned long size); +static void my_md5_final(unsigned char *result, my_md5_ctx *ctx); + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD5_u32plus *)(void *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. + */ +static const void *body(my_md5_ctx *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD5_u32plus a, b, c, d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while(size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +static CURLcode my_md5_init(my_md5_ctx *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; + + return CURLE_OK; +} + +static void my_md5_update(my_md5_ctx *ctx, const void *data, + unsigned long size) +{ + MD5_u32plus saved_lo; + unsigned long used; + + saved_lo = ctx->lo; + ctx->lo = (saved_lo + size) & 0x1fffffff; + if(ctx->lo < saved_lo) + ctx->hi++; + ctx->hi += (MD5_u32plus)size >> 29; + + used = saved_lo & 0x3f; + + if(used) { + unsigned long available = 64 - used; + + if(size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if(size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +static void my_md5_final(unsigned char *result, my_md5_ctx *ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if(available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); + ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); + ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); + ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24); + ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); + ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); + ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); + ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); + + body(ctx, ctx->buffer, 64); + + result[0] = curlx_ultouc((ctx->a)&0xff); + result[1] = curlx_ultouc((ctx->a >> 8)&0xff); + result[2] = curlx_ultouc((ctx->a >> 16)&0xff); + result[3] = curlx_ultouc(ctx->a >> 24); + result[4] = curlx_ultouc((ctx->b)&0xff); + result[5] = curlx_ultouc((ctx->b >> 8)&0xff); + result[6] = curlx_ultouc((ctx->b >> 16)&0xff); + result[7] = curlx_ultouc(ctx->b >> 24); + result[8] = curlx_ultouc((ctx->c)&0xff); + result[9] = curlx_ultouc((ctx->c >> 8)&0xff); + result[10] = curlx_ultouc((ctx->c >> 16)&0xff); + result[11] = curlx_ultouc(ctx->c >> 24); + result[12] = curlx_ultouc((ctx->d)&0xff); + result[13] = curlx_ultouc((ctx->d >> 8)&0xff); + result[14] = curlx_ultouc((ctx->d >> 16)&0xff); + result[15] = curlx_ultouc(ctx->d >> 24); + + memset(ctx, 0, sizeof(*ctx)); +} + +#endif /* CRYPTO LIBS */ + +const struct HMAC_params Curl_HMAC_MD5[] = { + { + /* Hash initialization function. */ + CURLX_FUNCTION_CAST(HMAC_hinit_func, my_md5_init), + /* Hash update function. */ + CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_md5_update), + /* Hash computation end function. */ + CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_md5_final), + /* Size of hash context structure. */ + sizeof(my_md5_ctx), + /* Maximum key length. */ + 64, + /* Result size. */ + 16 + } +}; + +const struct MD5_params Curl_DIGEST_MD5[] = { + { + /* Digest initialization function */ + CURLX_FUNCTION_CAST(Curl_MD5_init_func, my_md5_init), + /* Digest update function */ + CURLX_FUNCTION_CAST(Curl_MD5_update_func, my_md5_update), + /* Digest computation end function */ + CURLX_FUNCTION_CAST(Curl_MD5_final_func, my_md5_final), + /* Size of digest context struct */ + sizeof(my_md5_ctx), + /* Result size */ + 16 + } +}; + +/* + * @unittest: 1601 + * Returns CURLE_OK on success. + */ +CURLcode Curl_md5it(unsigned char *outbuffer, const unsigned char *input, + const size_t len) +{ + CURLcode result; + my_md5_ctx ctx; + + result = my_md5_init(&ctx); + if(!result) { + my_md5_update(&ctx, input, curlx_uztoui(len)); + my_md5_final(outbuffer, &ctx); + } + return result; +} + +struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params) +{ + struct MD5_context *ctxt; + + /* Create MD5 context */ + ctxt = malloc(sizeof(*ctxt)); + + if(!ctxt) + return ctxt; + + ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize); + + if(!ctxt->md5_hashctx) { + free(ctxt); + return NULL; + } + + ctxt->md5_hash = md5params; + + if((*md5params->md5_init_func)(ctxt->md5_hashctx)) { + free(ctxt->md5_hashctx); + free(ctxt); + return NULL; + } + + return ctxt; +} + +CURLcode Curl_MD5_update(struct MD5_context *context, + const unsigned char *data, + unsigned int len) +{ + (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len); + + return CURLE_OK; +} + +CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result) +{ + (*context->md5_hash->md5_final_func)(result, context->md5_hashctx); + + free(context->md5_hashctx); + free(context); + + return CURLE_OK; +} + +#endif /* Using NTLM (without SSPI) || Digest */ diff --git a/lib/memdebug.c b/lib/memdebug.c new file mode 100644 index 0000000..fce933a --- /dev/null +++ b/lib/memdebug.c @@ -0,0 +1,463 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef CURLDEBUG + +#include + +#include "urldata.h" + +#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +struct memdebug { + size_t size; + union { + curl_off_t o; + double d; + void *p; + } mem[1]; + /* I'm hoping this is the thing with the strictest alignment + * requirements. That also means we waste some space :-( */ +}; + +/* + * Note that these debug functions are very simple and they are meant to + * remain so. For advanced analysis, record a log file and write perl scripts + * to analyze them! + * + * Don't use these with multithreaded test programs! + */ + +FILE *curl_dbg_logfile = NULL; +static bool registered_cleanup = FALSE; /* atexit registered cleanup */ +static bool memlimit = FALSE; /* enable memory limit */ +static long memsize = 0; /* set number of mallocs allowed */ + +/* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected + on exit so the logfile must be closed explicitly or data could be lost. + Though _exit() does not call atexit handlers such as this, LSAN's call to + _exit() comes after the atexit handlers are called. curl/curl#6620 */ +static void curl_dbg_cleanup(void) +{ + if(curl_dbg_logfile && + curl_dbg_logfile != stderr && + curl_dbg_logfile != stdout) { + fclose(curl_dbg_logfile); + } + curl_dbg_logfile = NULL; +} + +/* this sets the log file name */ +void curl_dbg_memdebug(const char *logname) +{ + if(!curl_dbg_logfile) { + if(logname && *logname) + curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT); + else + curl_dbg_logfile = stderr; +#ifdef MEMDEBUG_LOG_SYNC + /* Flush the log file after every line so the log isn't lost in a crash */ + if(curl_dbg_logfile) + setbuf(curl_dbg_logfile, (char *)NULL); +#endif + } + if(!registered_cleanup) + registered_cleanup = !atexit(curl_dbg_cleanup); +} + +/* This function sets the number of malloc() calls that should return + successfully! */ +void curl_dbg_memlimit(long limit) +{ + if(!memlimit) { + memlimit = TRUE; + memsize = limit; + } +} + +/* returns TRUE if this isn't allowed! */ +static bool countcheck(const char *func, int line, const char *source) +{ + /* if source is NULL, then the call is made internally and this check + should not be made */ + if(memlimit && source) { + if(!memsize) { + /* log to file */ + curl_dbg_log("LIMIT %s:%d %s reached memlimit\n", + source, line, func); + /* log to stderr also */ + fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", + source, line, func); + fflush(curl_dbg_logfile); /* because it might crash now */ + errno = ENOMEM; + return TRUE; /* RETURN ERROR! */ + } + else + memsize--; /* countdown */ + + + } + + return FALSE; /* allow this */ +} + +ALLOC_FUNC void *curl_dbg_malloc(size_t wantedsize, + int line, const char *source) +{ + struct memdebug *mem; + size_t size; + + DEBUGASSERT(wantedsize != 0); + + if(countcheck("malloc", line, source)) + return NULL; + + /* alloc at least 64 bytes */ + size = sizeof(struct memdebug) + wantedsize; + + mem = (Curl_cmalloc)(size); + if(mem) { + mem->size = wantedsize; + } + + if(source) + curl_dbg_log("MEM %s:%d malloc(%zu) = %p\n", + source, line, wantedsize, + mem ? (void *)mem->mem : (void *)0); + + return (mem ? mem->mem : NULL); +} + +ALLOC_FUNC void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size, + int line, const char *source) +{ + struct memdebug *mem; + size_t size, user_size; + + DEBUGASSERT(wanted_elements != 0); + DEBUGASSERT(wanted_size != 0); + + if(countcheck("calloc", line, source)) + return NULL; + + /* alloc at least 64 bytes */ + user_size = wanted_size * wanted_elements; + size = sizeof(struct memdebug) + user_size; + + mem = (Curl_ccalloc)(1, size); + if(mem) + mem->size = user_size; + + if(source) + curl_dbg_log("MEM %s:%d calloc(%zu,%zu) = %p\n", + source, line, wanted_elements, wanted_size, + mem ? (void *)mem->mem : (void *)0); + + return (mem ? mem->mem : NULL); +} + +ALLOC_FUNC char *curl_dbg_strdup(const char *str, + int line, const char *source) +{ + char *mem; + size_t len; + + DEBUGASSERT(str != NULL); + + if(countcheck("strdup", line, source)) + return NULL; + + len = strlen(str) + 1; + + mem = curl_dbg_malloc(len, 0, NULL); /* NULL prevents logging */ + if(mem) + memcpy(mem, str, len); + + if(source) + curl_dbg_log("MEM %s:%d strdup(%p) (%zu) = %p\n", + source, line, (const void *)str, len, (const void *)mem); + + return mem; +} + +#if defined(_WIN32) && defined(UNICODE) +ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str, + int line, const char *source) +{ + wchar_t *mem; + size_t wsiz, bsiz; + + DEBUGASSERT(str != NULL); + + if(countcheck("wcsdup", line, source)) + return NULL; + + wsiz = wcslen(str) + 1; + bsiz = wsiz * sizeof(wchar_t); + + mem = curl_dbg_malloc(bsiz, 0, NULL); /* NULL prevents logging */ + if(mem) + memcpy(mem, str, bsiz); + + if(source) + curl_dbg_log("MEM %s:%d wcsdup(%p) (%zu) = %p\n", + source, line, (void *)str, bsiz, (void *)mem); + + return mem; +} +#endif + +/* We provide a realloc() that accepts a NULL as pointer, which then + performs a malloc(). In order to work with ares. */ +void *curl_dbg_realloc(void *ptr, size_t wantedsize, + int line, const char *source) +{ + struct memdebug *mem = NULL; + + size_t size = sizeof(struct memdebug) + wantedsize; + + DEBUGASSERT(wantedsize != 0); + + if(countcheck("realloc", line, source)) + return NULL; + +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:1684) + /* 1684: conversion from pointer to same-sized integral type */ +#endif + + if(ptr) + mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif + + mem = (Curl_crealloc)(mem, size); + if(source) + curl_dbg_log("MEM %s:%d realloc(%p, %zu) = %p\n", + source, line, (void *)ptr, wantedsize, + mem ? (void *)mem->mem : (void *)0); + + if(mem) { + mem->size = wantedsize; + return mem->mem; + } + + return NULL; +} + +void curl_dbg_free(void *ptr, int line, const char *source) +{ + if(ptr) { + struct memdebug *mem; + +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:1684) + /* 1684: conversion from pointer to same-sized integral type */ +#endif + + mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif + + /* free for real */ + (Curl_cfree)(mem); + } + + if(source && ptr) + curl_dbg_log("MEM %s:%d free(%p)\n", source, line, (void *)ptr); +} + +curl_socket_t curl_dbg_socket(int domain, int type, int protocol, + int line, const char *source) +{ + curl_socket_t sockfd; + + if(countcheck("socket", line, source)) + return CURL_SOCKET_BAD; + + sockfd = socket(domain, type, protocol); + + if(source && (sockfd != CURL_SOCKET_BAD)) + curl_dbg_log("FD %s:%d socket() = %" CURL_FORMAT_SOCKET_T "\n", + source, line, sockfd); + + return sockfd; +} + +SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, + SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, + SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line, + const char *source) +{ + SEND_TYPE_RETV rc; + if(countcheck("send", line, source)) + return -1; + rc = send(sockfd, buf, len, flags); + if(source) + curl_dbg_log("SEND %s:%d send(%lu) = %ld\n", + source, line, (unsigned long)len, (long)rc); + return rc; +} + +RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, + RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line, + const char *source) +{ + RECV_TYPE_RETV rc; + if(countcheck("recv", line, source)) + return -1; + rc = recv(sockfd, buf, len, flags); + if(source) + curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n", + source, line, (unsigned long)len, (long)rc); + return rc; +} + +#ifdef HAVE_SOCKETPAIR +int curl_dbg_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line, const char *source) +{ + int res = socketpair(domain, type, protocol, socket_vector); + + if(source && (0 == res)) + curl_dbg_log("FD %s:%d socketpair() = " + "%" CURL_FORMAT_SOCKET_T " %" CURL_FORMAT_SOCKET_T "\n", + source, line, socket_vector[0], socket_vector[1]); + + return res; +} +#endif + +curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, + int line, const char *source) +{ + struct sockaddr *addr = (struct sockaddr *)saddr; + curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; + + curl_socket_t sockfd = accept(s, addr, addrlen); + + if(source && (sockfd != CURL_SOCKET_BAD)) + curl_dbg_log("FD %s:%d accept() = %" CURL_FORMAT_SOCKET_T "\n", + source, line, sockfd); + + return sockfd; +} + +/* separate function to allow libcurl to mark a "faked" close */ +void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source) +{ + if(source) + curl_dbg_log("FD %s:%d sclose(%" CURL_FORMAT_SOCKET_T ")\n", + source, line, sockfd); +} + +/* this is our own defined way to close sockets on *ALL* platforms */ +int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source) +{ + int res = sclose(sockfd); + curl_dbg_mark_sclose(sockfd, line, source); + return res; +} + +ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode, + int line, const char *source) +{ + FILE *res = fopen(file, mode); + + if(source) + curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", + source, line, file, mode, (void *)res); + + return res; +} + +ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode, + int line, const char *source) +{ + FILE *res = fdopen(filedes, mode); + if(source) + curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", + source, line, filedes, mode, (void *)res); + return res; +} + +int curl_dbg_fclose(FILE *file, int line, const char *source) +{ + int res; + + DEBUGASSERT(file != NULL); + + if(source) + curl_dbg_log("FILE %s:%d fclose(%p)\n", + source, line, (void *)file); + + res = fclose(file); + + return res; +} + +#define LOGLINE_BUFSIZE 1024 + +/* this does the writing to the memory tracking log file */ +void curl_dbg_log(const char *format, ...) +{ + char *buf; + int nchars; + va_list ap; + + if(!curl_dbg_logfile) + return; + + buf = (Curl_cmalloc)(LOGLINE_BUFSIZE); + if(!buf) + return; + + va_start(ap, format); + nchars = mvsnprintf(buf, LOGLINE_BUFSIZE, format, ap); + va_end(ap); + + if(nchars > LOGLINE_BUFSIZE - 1) + nchars = LOGLINE_BUFSIZE - 1; + + if(nchars > 0) + fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile); + + (Curl_cfree)(buf); +} + +#endif /* CURLDEBUG */ diff --git a/lib/memdebug.h b/lib/memdebug.h new file mode 100644 index 0000000..51147cd --- /dev/null +++ b/lib/memdebug.h @@ -0,0 +1,202 @@ +#ifndef HEADER_CURL_MEMDEBUG_H +#define HEADER_CURL_MEMDEBUG_H +#ifdef CURLDEBUG +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * CAUTION: this header is designed to work when included by the app-side + * as well as the library. Do not mix with library internals! + */ + +#include +#include "functypes.h" + +#if defined(__GNUC__) && __GNUC__ >= 3 +# define ALLOC_FUNC __attribute__((malloc)) +# define ALLOC_SIZE(s) __attribute__((alloc_size(s))) +# define ALLOC_SIZE2(n, s) __attribute__((alloc_size(n, s))) +#elif defined(_MSC_VER) +# define ALLOC_FUNC __declspec(restrict) +# define ALLOC_SIZE(s) +# define ALLOC_SIZE2(n, s) +#else +# define ALLOC_FUNC +# define ALLOC_SIZE(s) +# define ALLOC_SIZE2(n, s) +#endif + +#define CURL_MT_LOGFNAME_BUFSIZE 512 + +extern FILE *curl_dbg_logfile; + +/* memory functions */ +CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1) void *curl_dbg_malloc(size_t size, + int line, + const char *source); +CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2) void *curl_dbg_calloc(size_t elements, + size_t size, int line, const char *source); +CURL_EXTERN ALLOC_SIZE(2) void *curl_dbg_realloc(void *ptr, + size_t size, + int line, + const char *source); +CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source); +CURL_EXTERN ALLOC_FUNC char *curl_dbg_strdup(const char *str, int line, + const char *src); +#if defined(_WIN32) && defined(UNICODE) +CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str, + int line, + const char *source); +#endif + +CURL_EXTERN void curl_dbg_memdebug(const char *logname); +CURL_EXTERN void curl_dbg_memlimit(long limit); +CURL_EXTERN void curl_dbg_log(const char *format, ...) CURL_PRINTF(1, 2); + +/* file descriptor manipulators */ +CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol, + int line, const char *source); +CURL_EXTERN void curl_dbg_mark_sclose(curl_socket_t sockfd, + int line, const char *source); +CURL_EXTERN int curl_dbg_sclose(curl_socket_t sockfd, + int line, const char *source); +CURL_EXTERN curl_socket_t curl_dbg_accept(curl_socket_t s, void *a, void *alen, + int line, const char *source); +#ifdef HAVE_SOCKETPAIR +CURL_EXTERN int curl_dbg_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line, const char *source); +#endif + +/* send/receive sockets */ +CURL_EXTERN SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, + SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, + SEND_TYPE_ARG3 len, + SEND_TYPE_ARG4 flags, int line, + const char *source); +CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, + RECV_TYPE_ARG2 buf, + RECV_TYPE_ARG3 len, + RECV_TYPE_ARG4 flags, int line, + const char *source); + +/* FILE functions */ +CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode, + int line, const char *source); +CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode, + int line, const char *source); + +CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source); + +#ifndef MEMDEBUG_NODEFINES + +/* Set this symbol on the command-line, recompile all lib-sources */ +#undef strdup +#define strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) +#define malloc(size) curl_dbg_malloc(size, __LINE__, __FILE__) +#define calloc(nbelem,size) curl_dbg_calloc(nbelem, size, __LINE__, __FILE__) +#define realloc(ptr,size) curl_dbg_realloc(ptr, size, __LINE__, __FILE__) +#define free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__) +#define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__) +#define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) + +#ifdef _WIN32 +# ifdef UNICODE +# undef wcsdup +# define wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) +# undef _wcsdup +# define _wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) +# undef _tcsdup +# define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) +# else +# undef _tcsdup +# define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) +# endif +#endif + +#undef socket +#define socket(domain,type,protocol)\ + curl_dbg_socket(domain, type, protocol, __LINE__, __FILE__) +#undef accept /* for those with accept as a macro */ +#define accept(sock,addr,len)\ + curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) +#ifdef HAVE_SOCKETPAIR +#define socketpair(domain,type,protocol,socket_vector)\ + curl_dbg_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__) +#endif + +#ifdef HAVE_GETADDRINFO +#if defined(getaddrinfo) && defined(__osf__) +/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define + our macro as for other platforms. Instead, we redefine the new name they + define getaddrinfo to become! */ +#define ogetaddrinfo(host,serv,hint,res) \ + curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__) +#else +#undef getaddrinfo +#define getaddrinfo(host,serv,hint,res) \ + curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__) +#endif +#endif /* HAVE_GETADDRINFO */ + +#ifdef HAVE_FREEADDRINFO +#undef freeaddrinfo +#define freeaddrinfo(data) \ + curl_dbg_freeaddrinfo(data, __LINE__, __FILE__) +#endif /* HAVE_FREEADDRINFO */ + +/* sclose is probably already defined, redefine it! */ +#undef sclose +#define sclose(sockfd) curl_dbg_sclose(sockfd,__LINE__,__FILE__) + +#define fake_sclose(sockfd) curl_dbg_mark_sclose(sockfd,__LINE__,__FILE__) + +#undef fopen +#define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) +#undef fdopen +#define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) +#define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) + +#endif /* MEMDEBUG_NODEFINES */ + +#endif /* CURLDEBUG */ + +/* +** Following section applies even when CURLDEBUG is not defined. +*/ + +#ifndef fake_sclose +#define fake_sclose(x) Curl_nop_stmt +#endif + +/* + * Curl_safefree defined as a macro to allow MemoryTracking feature + * to log free() calls at same location where Curl_safefree is used. + * This macro also assigns NULL to given pointer when free'd. + */ + +#define Curl_safefree(ptr) \ + do { free((ptr)); (ptr) = NULL;} while(0) + +#endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/lib/mime.c b/lib/mime.c new file mode 100644 index 0000000..d712331 --- /dev/null +++ b/lib/mime.c @@ -0,0 +1,2022 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "mime.h" +#include "warnless.h" +#include "urldata.h" +#include "sendf.h" +#include "strdup.h" + +#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP)) + +#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) +#include +#endif + +#include "rand.h" +#include "slist.h" +#include "strcase.h" +#include "dynbuf.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef _WIN32 +# ifndef R_OK +# define R_OK 4 +# endif +#endif + + +#define READ_ERROR ((size_t) -1) +#define STOP_FILLING ((size_t) -2) + +static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, + void *instream, bool *hasread); + +/* Encoders. */ +static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part); +static curl_off_t encoder_nop_size(curl_mimepart *part); +static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part); +static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part); +static curl_off_t encoder_base64_size(curl_mimepart *part); +static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part); +static curl_off_t encoder_qp_size(curl_mimepart *part); + +static const struct mime_encoder encoders[] = { + {"binary", encoder_nop_read, encoder_nop_size}, + {"8bit", encoder_nop_read, encoder_nop_size}, + {"7bit", encoder_7bit_read, encoder_nop_size}, + {"base64", encoder_base64_read, encoder_base64_size}, + {"quoted-printable", encoder_qp_read, encoder_qp_size}, + {ZERO_NULL, ZERO_NULL, ZERO_NULL} +}; + +/* Base64 encoding table */ +static const char base64enc[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* Quoted-printable character class table. + * + * We cannot rely on ctype functions since quoted-printable input data + * is assumed to be ascii-compatible, even on non-ascii platforms. */ +#define QP_OK 1 /* Can be represented by itself. */ +#define QP_SP 2 /* Space or tab. */ +#define QP_CR 3 /* Carriage return. */ +#define QP_LF 4 /* Line-feed. */ +static const unsigned char qp_class[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */ + 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */ + QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ +}; + + +/* Binary --> hexadecimal ASCII table. */ +static const char aschex[] = + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46"; + + + +#ifndef __VMS +#define filesize(name, stat_data) (stat_data.st_size) +#define fopen_read fopen + +#else + +#include +/* + * get_vms_file_size does what it takes to get the real size of the file + * + * For fixed files, find out the size of the EOF block and adjust. + * + * For all others, have to read the entire file in, discarding the contents. + * Most posted text files will be small, and binary files like zlib archives + * and CD/DVD images should be either a STREAM_LF format or a fixed format. + * + */ +curl_off_t VmsRealFileSize(const char *name, + const struct_stat *stat_buf) +{ + char buffer[8192]; + curl_off_t count; + int ret_stat; + FILE * file; + + file = fopen(name, FOPEN_READTEXT); /* VMS */ + if(!file) + return 0; + + count = 0; + ret_stat = 1; + while(ret_stat > 0) { + ret_stat = fread(buffer, 1, sizeof(buffer), file); + if(ret_stat) + count += ret_stat; + } + fclose(file); + + return count; +} + +/* + * + * VmsSpecialSize checks to see if the stat st_size can be trusted and + * if not to call a routine to get the correct size. + * + */ +static curl_off_t VmsSpecialSize(const char *name, + const struct_stat *stat_buf) +{ + switch(stat_buf->st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + return VmsRealFileSize(name, stat_buf); + break; + default: + return stat_buf->st_size; + } +} + +#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) + +/* + * vmsfopenread + * + * For upload to work as expected on VMS, different optional + * parameters must be added to the fopen command based on + * record format of the file. + * + */ +static FILE * vmsfopenread(const char *file, const char *mode) +{ + struct_stat statbuf; + int result; + + result = stat(file, &statbuf); + + switch(statbuf.st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + case FAB$C_STMCR: + return fopen(file, FOPEN_READTEXT); /* VMS */ + break; + default: + return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); + } +} + +#define fopen_read vmsfopenread +#endif + + +#ifndef HAVE_BASENAME +/* + (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 + Edition) + + The basename() function shall take the pathname pointed to by path and + return a pointer to the final component of the pathname, deleting any + trailing '/' characters. + + If the string pointed to by path consists entirely of the '/' character, + basename() shall return a pointer to the string "/". If the string pointed + to by path is exactly "//", it is implementation-defined whether '/' or "//" + is returned. + + If path is a null pointer or points to an empty string, basename() shall + return a pointer to the string ".". + + The basename() function may modify the string pointed to by path, and may + return a pointer to static storage that may then be overwritten by a + subsequent call to basename(). + + The basename() function need not be reentrant. A function that is not + required to be reentrant is not required to be thread-safe. + +*/ +static char *Curl_basename(char *path) +{ + /* Ignore all the details above for now and make a quick and simple + implementation here */ + char *s1; + char *s2; + + s1 = strrchr(path, '/'); + s2 = strrchr(path, '\\'); + + if(s1 && s2) { + path = (s1 > s2? s1 : s2) + 1; + } + else if(s1) + path = s1 + 1; + else if(s2) + path = s2 + 1; + + return path; +} + +#define basename(x) Curl_basename((x)) +#endif + + +/* Set readback state. */ +static void mimesetstate(struct mime_state *state, + enum mimestate tok, void *ptr) +{ + state->state = tok; + state->ptr = ptr; + state->offset = 0; +} + + +/* Escape header string into allocated memory. */ +static char *escape_string(struct Curl_easy *data, + const char *src, enum mimestrategy strategy) +{ + CURLcode result; + struct dynbuf db; + const char * const *table; + const char * const *p; + /* replace first character by rest of string. */ + static const char * const mimetable[] = { + "\\\\\\", + "\"\\\"", + NULL + }; + /* WHATWG HTML living standard 4.10.21.8 2 specifies: + For field names and filenames for file fields, the result of the + encoding in the previous bullet point must be escaped by replacing + any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D` + and 0x22 (") with `%22`. + The user agent must not perform any other escapes. */ + static const char * const formtable[] = { + "\"%22", + "\r%0D", + "\n%0A", + NULL + }; + + table = formtable; + /* data can be NULL when this function is called indirectly from + curl_formget(). */ + if(strategy == MIMESTRATEGY_MAIL || (data && (data->set.mime_formescape))) + table = mimetable; + + Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH); + + for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) { + for(p = table; *p && **p != *src; p++) + ; + + if(*p) + result = Curl_dyn_add(&db, *p + 1); + else + result = Curl_dyn_addn(&db, src, 1); + } + + return Curl_dyn_ptr(&db); +} + +/* Check if header matches. */ +static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len) +{ + char *value = NULL; + + if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':') + for(value = hdr->data + len + 1; *value == ' '; value++) + ; + return value; +} + +/* Get a header from an slist. */ +static char *search_header(struct curl_slist *hdrlist, + const char *hdr, size_t len) +{ + char *value = NULL; + + for(; !value && hdrlist; hdrlist = hdrlist->next) + value = match_header(hdrlist, hdr, len); + + return value; +} + +static char *strippath(const char *fullfile) +{ + char *filename; + char *base; + filename = strdup(fullfile); /* duplicate since basename() may ruin the + buffer it works on */ + if(!filename) + return NULL; + base = strdup(basename(filename)); + + free(filename); /* free temporary buffer */ + + return base; /* returns an allocated string or NULL ! */ +} + +/* Initialize data encoder state. */ +static void cleanup_encoder_state(struct mime_encoder_state *p) +{ + p->pos = 0; + p->bufbeg = 0; + p->bufend = 0; +} + + +/* Dummy encoder. This is used for 8bit and binary content encodings. */ +static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, + struct curl_mimepart *part) +{ + struct mime_encoder_state *st = &part->encstate; + size_t insize = st->bufend - st->bufbeg; + + (void) ateof; + + if(!size) + return STOP_FILLING; + + if(size > insize) + size = insize; + + if(size) + memcpy(buffer, st->buf + st->bufbeg, size); + + st->bufbeg += size; + return size; +} + +static curl_off_t encoder_nop_size(curl_mimepart *part) +{ + return part->datasize; +} + + +/* 7bit encoder: the encoder is just a data validity check. */ +static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part) +{ + struct mime_encoder_state *st = &part->encstate; + size_t cursize = st->bufend - st->bufbeg; + + (void) ateof; + + if(!size) + return STOP_FILLING; + + if(size > cursize) + size = cursize; + + for(cursize = 0; cursize < size; cursize++) { + *buffer = st->buf[st->bufbeg]; + if(*buffer++ & 0x80) + return cursize? cursize: READ_ERROR; + st->bufbeg++; + } + + return cursize; +} + + +/* Base64 content encoder. */ +static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part) +{ + struct mime_encoder_state *st = &part->encstate; + size_t cursize = 0; + int i; + char *ptr = buffer; + + while(st->bufbeg < st->bufend) { + /* Line full ? */ + if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) { + /* Yes, we need 2 characters for CRLF. */ + if(size < 2) { + if(!cursize) + return STOP_FILLING; + break; + } + *ptr++ = '\r'; + *ptr++ = '\n'; + st->pos = 0; + cursize += 2; + size -= 2; + } + + /* Be sure there is enough space and input data for a base64 group. */ + if(size < 4) { + if(!cursize) + return STOP_FILLING; + break; + } + if(st->bufend - st->bufbeg < 3) + break; + + /* Encode three bytes as four characters. */ + i = st->buf[st->bufbeg++] & 0xFF; + i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); + i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); + *ptr++ = base64enc[(i >> 18) & 0x3F]; + *ptr++ = base64enc[(i >> 12) & 0x3F]; + *ptr++ = base64enc[(i >> 6) & 0x3F]; + *ptr++ = base64enc[i & 0x3F]; + cursize += 4; + st->pos += 4; + size -= 4; + } + + /* If at eof, we have to flush the buffered data. */ + if(ateof) { + if(size < 4) { + if(!cursize) + return STOP_FILLING; + } + else { + /* Buffered data size can only be 0, 1 or 2. */ + ptr[2] = ptr[3] = '='; + i = 0; + + /* If there is buffered data */ + if(st->bufend != st->bufbeg) { + + if(st->bufend - st->bufbeg == 2) + i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; + + i |= (st->buf[st->bufbeg] & 0xFF) << 16; + ptr[0] = base64enc[(i >> 18) & 0x3F]; + ptr[1] = base64enc[(i >> 12) & 0x3F]; + if(++st->bufbeg != st->bufend) { + ptr[2] = base64enc[(i >> 6) & 0x3F]; + st->bufbeg++; + } + cursize += 4; + st->pos += 4; + } + } + } + + return cursize; +} + +static curl_off_t encoder_base64_size(curl_mimepart *part) +{ + curl_off_t size = part->datasize; + + if(size <= 0) + return size; /* Unknown size or no data. */ + + /* Compute base64 character count. */ + size = 4 * (1 + (size - 1) / 3); + + /* Effective character count must include CRLFs. */ + return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH); +} + + +/* Quoted-printable lookahead. + * + * Check if a CRLF or end of data is in input buffer at current position + n. + * Return -1 if more data needed, 1 if CRLF or end of data, else 0. + */ +static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n) +{ + n += st->bufbeg; + if(n >= st->bufend && ateof) + return 1; + if(n + 2 > st->bufend) + return ateof? 0: -1; + if(qp_class[st->buf[n] & 0xFF] == QP_CR && + qp_class[st->buf[n + 1] & 0xFF] == QP_LF) + return 1; + return 0; +} + +/* Quoted-printable encoder. */ +static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part) +{ + struct mime_encoder_state *st = &part->encstate; + char *ptr = buffer; + size_t cursize = 0; + int softlinebreak; + char buf[4]; + + /* On all platforms, input is supposed to be ASCII compatible: for this + reason, we use hexadecimal ASCII codes in this function rather than + character constants that can be interpreted as non-ascii on some + platforms. Preserve ASCII encoding on output too. */ + while(st->bufbeg < st->bufend) { + size_t len = 1; + size_t consumed = 1; + int i = st->buf[st->bufbeg]; + buf[0] = (char) i; + buf[1] = aschex[(i >> 4) & 0xF]; + buf[2] = aschex[i & 0xF]; + + switch(qp_class[st->buf[st->bufbeg] & 0xFF]) { + case QP_OK: /* Not a special character. */ + break; + case QP_SP: /* Space or tab. */ + /* Spacing must be escaped if followed by CRLF. */ + switch(qp_lookahead_eol(st, ateof, 1)) { + case -1: /* More input data needed. */ + return cursize; + case 0: /* No encoding needed. */ + break; + default: /* CRLF after space or tab. */ + buf[0] = '\x3D'; /* '=' */ + len = 3; + break; + } + break; + case QP_CR: /* Carriage return. */ + /* If followed by a line-feed, output the CRLF pair. + Else escape it. */ + switch(qp_lookahead_eol(st, ateof, 0)) { + case -1: /* Need more data. */ + return cursize; + case 1: /* CRLF found. */ + buf[len++] = '\x0A'; /* Append '\n'. */ + consumed = 2; + break; + default: /* Not followed by LF: escape. */ + buf[0] = '\x3D'; /* '=' */ + len = 3; + break; + } + break; + default: /* Character must be escaped. */ + buf[0] = '\x3D'; /* '=' */ + len = 3; + break; + } + + /* Be sure the encoded character fits within maximum line length. */ + if(buf[len - 1] != '\x0A') { /* '\n' */ + softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH; + if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) { + /* We may use the current line only if end of data or followed by + a CRLF. */ + switch(qp_lookahead_eol(st, ateof, consumed)) { + case -1: /* Need more data. */ + return cursize; + case 0: /* Not followed by a CRLF. */ + softlinebreak = 1; + break; + } + } + if(softlinebreak) { + strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */ + len = 3; + consumed = 0; + } + } + + /* If the output buffer would overflow, do not store. */ + if(len > size) { + if(!cursize) + return STOP_FILLING; + break; + } + + /* Append to output buffer. */ + memcpy(ptr, buf, len); + cursize += len; + ptr += len; + size -= len; + st->pos += len; + if(buf[len - 1] == '\x0A') /* '\n' */ + st->pos = 0; + st->bufbeg += consumed; + } + + return cursize; +} + +static curl_off_t encoder_qp_size(curl_mimepart *part) +{ + /* Determining the size can only be done by reading the data: unless the + data size is 0, we return it as unknown (-1). */ + return part->datasize? -1: 0; +} + + +/* In-memory data callbacks. */ +/* Argument is a pointer to the mime part. */ +static size_t mime_mem_read(char *buffer, size_t size, size_t nitems, + void *instream) +{ + curl_mimepart *part = (curl_mimepart *) instream; + size_t sz = curlx_sotouz(part->datasize - part->state.offset); + (void) size; /* Always 1.*/ + + if(!nitems) + return STOP_FILLING; + + if(sz > nitems) + sz = nitems; + + if(sz) + memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz); + + return sz; +} + +static int mime_mem_seek(void *instream, curl_off_t offset, int whence) +{ + curl_mimepart *part = (curl_mimepart *) instream; + + switch(whence) { + case SEEK_CUR: + offset += part->state.offset; + break; + case SEEK_END: + offset += part->datasize; + break; + } + + if(offset < 0 || offset > part->datasize) + return CURL_SEEKFUNC_FAIL; + + part->state.offset = offset; + return CURL_SEEKFUNC_OK; +} + +static void mime_mem_free(void *ptr) +{ + Curl_safefree(((curl_mimepart *) ptr)->data); +} + + +/* Named file callbacks. */ +/* Argument is a pointer to the mime part. */ +static int mime_open_file(curl_mimepart *part) +{ + /* Open a MIMEKIND_FILE part. */ + + if(part->fp) + return 0; + part->fp = fopen_read(part->data, "rb"); + return part->fp? 0: -1; +} + +static size_t mime_file_read(char *buffer, size_t size, size_t nitems, + void *instream) +{ + curl_mimepart *part = (curl_mimepart *) instream; + + if(!nitems) + return STOP_FILLING; + + if(mime_open_file(part)) + return READ_ERROR; + + return fread(buffer, size, nitems, part->fp); +} + +static int mime_file_seek(void *instream, curl_off_t offset, int whence) +{ + curl_mimepart *part = (curl_mimepart *) instream; + + if(whence == SEEK_SET && !offset && !part->fp) + return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */ + + if(mime_open_file(part)) + return CURL_SEEKFUNC_FAIL; + + return fseek(part->fp, (long) offset, whence)? + CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK; +} + +static void mime_file_free(void *ptr) +{ + curl_mimepart *part = (curl_mimepart *) ptr; + + if(part->fp) { + fclose(part->fp); + part->fp = NULL; + } + Curl_safefree(part->data); +} + + +/* Subparts callbacks. */ +/* Argument is a pointer to the mime structure. */ + +/* Readback a byte string segment. */ +static size_t readback_bytes(struct mime_state *state, + char *buffer, size_t bufsize, + const char *bytes, size_t numbytes, + const char *trail, size_t traillen) +{ + size_t sz; + size_t offset = curlx_sotouz(state->offset); + + if(numbytes > offset) { + sz = numbytes - offset; + bytes += offset; + } + else { + sz = offset - numbytes; + if(sz >= traillen) + return 0; + bytes = trail + sz; + sz = traillen - sz; + } + + if(sz > bufsize) + sz = bufsize; + + memcpy(buffer, bytes, sz); + state->offset += sz; + return sz; +} + +/* Read a non-encoded part content. */ +static size_t read_part_content(curl_mimepart *part, + char *buffer, size_t bufsize, bool *hasread) +{ + size_t sz = 0; + + switch(part->lastreadstatus) { + case 0: + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + return part->lastreadstatus; + default: + break; + } + + /* If we can determine we are at end of part data, spare a read. */ + if(part->datasize != (curl_off_t) -1 && + part->state.offset >= part->datasize) { + /* sz is already zero. */ + } + else { + switch(part->kind) { + case MIMEKIND_MULTIPART: + /* + * Cannot be processed as other kinds since read function requires + * an additional parameter and is highly recursive. + */ + sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread); + break; + case MIMEKIND_FILE: + if(part->fp && feof(part->fp)) + break; /* At EOF. */ + FALLTHROUGH(); + default: + if(part->readfunc) { + if(!(part->flags & MIME_FAST_READ)) { + if(*hasread) + return STOP_FILLING; + *hasread = TRUE; + } + sz = part->readfunc(buffer, 1, bufsize, part->arg); + } + break; + } + } + + switch(sz) { + case STOP_FILLING: + break; + case 0: + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + part->lastreadstatus = sz; + break; + default: + part->state.offset += sz; + part->lastreadstatus = sz; + break; + } + + return sz; +} + +/* Read and encode part content. */ +static size_t read_encoded_part_content(curl_mimepart *part, char *buffer, + size_t bufsize, bool *hasread) +{ + struct mime_encoder_state *st = &part->encstate; + size_t cursize = 0; + size_t sz; + bool ateof = FALSE; + + for(;;) { + if(st->bufbeg < st->bufend || ateof) { + /* Encode buffered data. */ + sz = part->encoder->encodefunc(buffer, bufsize, ateof, part); + switch(sz) { + case 0: + if(ateof) + return cursize; + break; + case READ_ERROR: + case STOP_FILLING: + return cursize? cursize: sz; + default: + cursize += sz; + buffer += sz; + bufsize -= sz; + continue; + } + } + + /* We need more data in input buffer. */ + if(st->bufbeg) { + size_t len = st->bufend - st->bufbeg; + + if(len) + memmove(st->buf, st->buf + st->bufbeg, len); + st->bufbeg = 0; + st->bufend = len; + } + if(st->bufend >= sizeof(st->buf)) + return cursize? cursize: READ_ERROR; /* Buffer full. */ + sz = read_part_content(part, st->buf + st->bufend, + sizeof(st->buf) - st->bufend, hasread); + switch(sz) { + case 0: + ateof = TRUE; + break; + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + case STOP_FILLING: + return cursize? cursize: sz; + default: + st->bufend += sz; + break; + } + } + + /* NOTREACHED */ +} + +/* Readback a mime part. */ +static size_t readback_part(curl_mimepart *part, + char *buffer, size_t bufsize, bool *hasread) +{ + size_t cursize = 0; + + /* Readback from part. */ + + while(bufsize) { + size_t sz = 0; + struct curl_slist *hdr = (struct curl_slist *) part->state.ptr; + switch(part->state.state) { + case MIMESTATE_BEGIN: + mimesetstate(&part->state, + (part->flags & MIME_BODY_ONLY)? + MIMESTATE_BODY: MIMESTATE_CURLHEADERS, + part->curlheaders); + break; + case MIMESTATE_USERHEADERS: + if(!hdr) { + mimesetstate(&part->state, MIMESTATE_EOH, NULL); + break; + } + if(match_header(hdr, "Content-Type", 12)) { + mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next); + break; + } + FALLTHROUGH(); + case MIMESTATE_CURLHEADERS: + if(!hdr) + mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders); + else { + sz = readback_bytes(&part->state, buffer, bufsize, + hdr->data, strlen(hdr->data), STRCONST("\r\n")); + if(!sz) + mimesetstate(&part->state, part->state.state, hdr->next); + } + break; + case MIMESTATE_EOH: + sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"), + STRCONST("")); + if(!sz) + mimesetstate(&part->state, MIMESTATE_BODY, NULL); + break; + case MIMESTATE_BODY: + cleanup_encoder_state(&part->encstate); + mimesetstate(&part->state, MIMESTATE_CONTENT, NULL); + break; + case MIMESTATE_CONTENT: + if(part->encoder) + sz = read_encoded_part_content(part, buffer, bufsize, hasread); + else + sz = read_part_content(part, buffer, bufsize, hasread); + switch(sz) { + case 0: + mimesetstate(&part->state, MIMESTATE_END, NULL); + /* Try sparing open file descriptors. */ + if(part->kind == MIMEKIND_FILE && part->fp) { + fclose(part->fp); + part->fp = NULL; + } + FALLTHROUGH(); + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + case STOP_FILLING: + return cursize? cursize: sz; + } + break; + case MIMESTATE_END: + return cursize; + default: + break; /* Other values not in part state. */ + } + + /* Bump buffer and counters according to read size. */ + cursize += sz; + buffer += sz; + bufsize -= sz; + } + + return cursize; +} + +/* Readback from mime. Warning: not a read callback function. */ +static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, + void *instream, bool *hasread) +{ + curl_mime *mime = (curl_mime *) instream; + size_t cursize = 0; + (void) size; /* Always 1. */ + + while(nitems) { + size_t sz = 0; + curl_mimepart *part = mime->state.ptr; + switch(mime->state.state) { + case MIMESTATE_BEGIN: + case MIMESTATE_BODY: + mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart); + /* The first boundary always follows the header termination empty line, + so is always preceded by a CRLF. We can then spare 2 characters + by skipping the leading CRLF in boundary. */ + mime->state.offset += 2; + break; + case MIMESTATE_BOUNDARY1: + sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"), + STRCONST("")); + if(!sz) + mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part); + break; + case MIMESTATE_BOUNDARY2: + if(part) + sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary, + MIME_BOUNDARY_LEN, STRCONST("\r\n")); + else + sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary, + MIME_BOUNDARY_LEN, STRCONST("--\r\n")); + if(!sz) { + mimesetstate(&mime->state, MIMESTATE_CONTENT, part); + } + break; + case MIMESTATE_CONTENT: + if(!part) { + mimesetstate(&mime->state, MIMESTATE_END, NULL); + break; + } + sz = readback_part(part, buffer, nitems, hasread); + switch(sz) { + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + case STOP_FILLING: + return cursize? cursize: sz; + case 0: + mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart); + break; + } + break; + case MIMESTATE_END: + return cursize; + default: + break; /* other values not used in mime state. */ + } + + /* Bump buffer and counters according to read size. */ + cursize += sz; + buffer += sz; + nitems -= sz; + } + + return cursize; +} + +static int mime_part_rewind(curl_mimepart *part) +{ + int res = CURL_SEEKFUNC_OK; + enum mimestate targetstate = MIMESTATE_BEGIN; + + if(part->flags & MIME_BODY_ONLY) + targetstate = MIMESTATE_BODY; + cleanup_encoder_state(&part->encstate); + if(part->state.state > targetstate) { + res = CURL_SEEKFUNC_CANTSEEK; + if(part->seekfunc) { + res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET); + switch(res) { + case CURL_SEEKFUNC_OK: + case CURL_SEEKFUNC_FAIL: + case CURL_SEEKFUNC_CANTSEEK: + break; + case -1: /* For fseek() error. */ + res = CURL_SEEKFUNC_CANTSEEK; + break; + default: + res = CURL_SEEKFUNC_FAIL; + break; + } + } + } + + if(res == CURL_SEEKFUNC_OK) + mimesetstate(&part->state, targetstate, NULL); + + part->lastreadstatus = 1; /* Successful read status. */ + return res; +} + +static int mime_subparts_seek(void *instream, curl_off_t offset, int whence) +{ + curl_mime *mime = (curl_mime *) instream; + curl_mimepart *part; + int result = CURL_SEEKFUNC_OK; + + if(whence != SEEK_SET || offset) + return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */ + + if(mime->state.state == MIMESTATE_BEGIN) + return CURL_SEEKFUNC_OK; /* Already rewound. */ + + for(part = mime->firstpart; part; part = part->nextpart) { + int res = mime_part_rewind(part); + if(res != CURL_SEEKFUNC_OK) + result = res; + } + + if(result == CURL_SEEKFUNC_OK) + mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); + + return result; +} + +/* Release part content. */ +static void cleanup_part_content(curl_mimepart *part) +{ + if(part->freefunc) + part->freefunc(part->arg); + + part->readfunc = NULL; + part->seekfunc = NULL; + part->freefunc = NULL; + part->arg = (void *) part; /* Defaults to part itself. */ + part->data = NULL; + part->fp = NULL; + part->datasize = (curl_off_t) 0; /* No size yet. */ + cleanup_encoder_state(&part->encstate); + part->kind = MIMEKIND_NONE; + part->flags &= ~MIME_FAST_READ; + part->lastreadstatus = 1; /* Successful read status. */ + part->state.state = MIMESTATE_BEGIN; +} + +static void mime_subparts_free(void *ptr) +{ + curl_mime *mime = (curl_mime *) ptr; + + if(mime && mime->parent) { + mime->parent->freefunc = NULL; /* Be sure we won't be called again. */ + cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */ + } + curl_mime_free(mime); +} + +/* Do not free subparts: unbind them. This is used for the top level only. */ +static void mime_subparts_unbind(void *ptr) +{ + curl_mime *mime = (curl_mime *) ptr; + + if(mime && mime->parent) { + mime->parent->freefunc = NULL; /* Be sure we won't be called again. */ + cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */ + mime->parent = NULL; + } +} + + +void Curl_mime_cleanpart(curl_mimepart *part) +{ + if(part) { + cleanup_part_content(part); + curl_slist_free_all(part->curlheaders); + if(part->flags & MIME_USERHEADERS_OWNER) + curl_slist_free_all(part->userheaders); + Curl_safefree(part->mimetype); + Curl_safefree(part->name); + Curl_safefree(part->filename); + Curl_mime_initpart(part); + } +} + +/* Recursively delete a mime handle and its parts. */ +void curl_mime_free(curl_mime *mime) +{ + curl_mimepart *part; + + if(mime) { + mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */ + while(mime->firstpart) { + part = mime->firstpart; + mime->firstpart = part->nextpart; + Curl_mime_cleanpart(part); + free(part); + } + free(mime); + } +} + +CURLcode Curl_mime_duppart(struct Curl_easy *data, + curl_mimepart *dst, const curl_mimepart *src) +{ + curl_mime *mime; + curl_mimepart *d; + const curl_mimepart *s; + CURLcode res = CURLE_OK; + + DEBUGASSERT(dst); + + /* Duplicate content. */ + switch(src->kind) { + case MIMEKIND_NONE: + break; + case MIMEKIND_DATA: + res = curl_mime_data(dst, src->data, (size_t) src->datasize); + break; + case MIMEKIND_FILE: + res = curl_mime_filedata(dst, src->data); + /* Do not abort duplication if file is not readable. */ + if(res == CURLE_READ_ERROR) + res = CURLE_OK; + break; + case MIMEKIND_CALLBACK: + res = curl_mime_data_cb(dst, src->datasize, src->readfunc, + src->seekfunc, src->freefunc, src->arg); + break; + case MIMEKIND_MULTIPART: + /* No one knows about the cloned subparts, thus always attach ownership + to the part. */ + mime = curl_mime_init(data); + res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY; + + /* Duplicate subparts. */ + for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) { + d = curl_mime_addpart(mime); + res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY; + } + break; + default: /* Invalid kind: should not occur. */ + DEBUGF(infof(data, "invalid MIMEKIND* attempt")); + res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */ + break; + } + + /* Duplicate headers. */ + if(!res && src->userheaders) { + struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders); + + if(!hdrs) + res = CURLE_OUT_OF_MEMORY; + else { + /* No one but this procedure knows about the new header list, + so always take ownership. */ + res = curl_mime_headers(dst, hdrs, TRUE); + if(res) + curl_slist_free_all(hdrs); + } + } + + if(!res) { + /* Duplicate other fields. */ + dst->encoder = src->encoder; + res = curl_mime_type(dst, src->mimetype); + } + if(!res) + res = curl_mime_name(dst, src->name); + if(!res) + res = curl_mime_filename(dst, src->filename); + + /* If an error occurred, rollback. */ + if(res) + Curl_mime_cleanpart(dst); + + return res; +} + +/* + * Mime build functions. + */ + +/* Create a mime handle. */ +curl_mime *curl_mime_init(struct Curl_easy *easy) +{ + curl_mime *mime; + + mime = (curl_mime *) malloc(sizeof(*mime)); + + if(mime) { + mime->parent = NULL; + mime->firstpart = NULL; + mime->lastpart = NULL; + + memset(mime->boundary, '-', MIME_BOUNDARY_DASHES); + if(Curl_rand_alnum(easy, + (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES], + MIME_RAND_BOUNDARY_CHARS + 1)) { + /* failed to get random separator, bail out */ + free(mime); + return NULL; + } + mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); + } + + return mime; +} + +/* Initialize a mime part. */ +void Curl_mime_initpart(curl_mimepart *part) +{ + memset((char *) part, 0, sizeof(*part)); + part->lastreadstatus = 1; /* Successful read status. */ + mimesetstate(&part->state, MIMESTATE_BEGIN, NULL); +} + +/* Create a mime part and append it to a mime handle's part list. */ +curl_mimepart *curl_mime_addpart(curl_mime *mime) +{ + curl_mimepart *part; + + if(!mime) + return NULL; + + part = (curl_mimepart *) malloc(sizeof(*part)); + + if(part) { + Curl_mime_initpart(part); + part->parent = mime; + + if(mime->lastpart) + mime->lastpart->nextpart = part; + else + mime->firstpart = part; + + mime->lastpart = part; + } + + return part; +} + +/* Set mime part name. */ +CURLcode curl_mime_name(curl_mimepart *part, const char *name) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_safefree(part->name); + + if(name) { + part->name = strdup(name); + if(!part->name) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* Set mime part remote file name. */ +CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_safefree(part->filename); + + if(filename) { + part->filename = strdup(filename); + if(!part->filename) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* Set mime part content from memory data. */ +CURLcode curl_mime_data(curl_mimepart *part, + const char *ptr, size_t datasize) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + cleanup_part_content(part); + + if(ptr) { + if(datasize == CURL_ZERO_TERMINATED) + datasize = strlen(ptr); + + part->data = Curl_memdup0(ptr, datasize); + if(!part->data) + return CURLE_OUT_OF_MEMORY; + + part->datasize = datasize; + part->readfunc = mime_mem_read; + part->seekfunc = mime_mem_seek; + part->freefunc = mime_mem_free; + part->flags |= MIME_FAST_READ; + part->kind = MIMEKIND_DATA; + } + + return CURLE_OK; +} + +/* Set mime part content from named local file. */ +CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) +{ + CURLcode result = CURLE_OK; + + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + cleanup_part_content(part); + + if(filename) { + char *base; + struct_stat sbuf; + + if(stat(filename, &sbuf) || access(filename, R_OK)) + result = CURLE_READ_ERROR; + + part->data = strdup(filename); + if(!part->data) + result = CURLE_OUT_OF_MEMORY; + + part->datasize = -1; + if(!result && S_ISREG(sbuf.st_mode)) { + part->datasize = filesize(filename, sbuf); + part->seekfunc = mime_file_seek; + } + + part->readfunc = mime_file_read; + part->freefunc = mime_file_free; + part->kind = MIMEKIND_FILE; + + /* As a side effect, set the filename to the current file's base name. + It is possible to withdraw this by explicitly calling + curl_mime_filename() with a NULL filename argument after the current + call. */ + base = strippath(filename); + if(!base) + result = CURLE_OUT_OF_MEMORY; + else { + CURLcode res = curl_mime_filename(part, base); + + if(res) + result = res; + free(base); + } + } + return result; +} + +/* Set mime part type. */ +CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_safefree(part->mimetype); + + if(mimetype) { + part->mimetype = strdup(mimetype); + if(!part->mimetype) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* Set mime data transfer encoder. */ +CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) +{ + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + const struct mime_encoder *mep; + + if(!part) + return result; + + part->encoder = NULL; + + if(!encoding) + return CURLE_OK; /* Removing current encoder. */ + + for(mep = encoders; mep->name; mep++) + if(strcasecompare(encoding, mep->name)) { + part->encoder = mep; + result = CURLE_OK; + } + + return result; +} + +/* Set mime part headers. */ +CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, int take_ownership) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(part->flags & MIME_USERHEADERS_OWNER) { + if(part->userheaders != headers) /* Allow setting twice the same list. */ + curl_slist_free_all(part->userheaders); + part->flags &= ~MIME_USERHEADERS_OWNER; + } + part->userheaders = headers; + if(headers && take_ownership) + part->flags |= MIME_USERHEADERS_OWNER; + return CURLE_OK; +} + +/* Set mime part content from callback. */ +CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, void *arg) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + cleanup_part_content(part); + + if(readfunc) { + part->readfunc = readfunc; + part->seekfunc = seekfunc; + part->freefunc = freefunc; + part->arg = arg; + part->datasize = datasize; + part->kind = MIMEKIND_CALLBACK; + } + + return CURLE_OK; +} + +/* Set mime part content from subparts. */ +CURLcode Curl_mime_set_subparts(curl_mimepart *part, + curl_mime *subparts, int take_ownership) +{ + curl_mime *root; + + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* Accept setting twice the same subparts. */ + if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts) + return CURLE_OK; + + cleanup_part_content(part); + + if(subparts) { + /* Should not have been attached already. */ + if(subparts->parent) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* Should not be the part's root. */ + root = part->parent; + if(root) { + while(root->parent && root->parent->parent) + root = root->parent->parent; + if(subparts == root) { + /* Can't add as a subpart of itself. */ + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + + subparts->parent = part; + /* Subparts are processed internally: no read callback. */ + part->seekfunc = mime_subparts_seek; + part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind; + part->arg = subparts; + part->datasize = -1; + part->kind = MIMEKIND_MULTIPART; + } + + return CURLE_OK; +} + +CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) +{ + return Curl_mime_set_subparts(part, subparts, TRUE); +} + + +/* Readback from top mime. */ +/* Argument is the dummy top part. */ +size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) +{ + curl_mimepart *part = (curl_mimepart *) instream; + size_t ret; + bool hasread; + + (void) size; /* Always 1. */ + + do { + hasread = FALSE; + ret = readback_part(part, buffer, nitems, &hasread); + /* + * If this is not possible to get some data without calling more than + * one read callback (probably because a content encoder is not able to + * deliver a new bunch for the few data accumulated so far), force another + * read until we get enough data or a special exit code. + */ + } while(ret == STOP_FILLING); + + return ret; +} + +/* Rewind mime stream. */ +CURLcode Curl_mime_rewind(curl_mimepart *part) +{ + return mime_part_rewind(part) == CURL_SEEKFUNC_OK? + CURLE_OK: CURLE_SEND_FAIL_REWIND; +} + +/* Compute header list size. */ +static size_t slist_size(struct curl_slist *s, + size_t overhead, const char *skip, size_t skiplen) +{ + size_t size = 0; + + for(; s; s = s->next) + if(!skip || !match_header(s, skip, skiplen)) + size += strlen(s->data) + overhead; + return size; +} + +/* Get/compute multipart size. */ +static curl_off_t multipart_size(curl_mime *mime) +{ + curl_off_t size; + curl_off_t boundarysize; + curl_mimepart *part; + + if(!mime) + return 0; /* Not present -> empty. */ + + boundarysize = 4 + MIME_BOUNDARY_LEN + 2; + size = boundarysize; /* Final boundary - CRLF after headers. */ + + for(part = mime->firstpart; part; part = part->nextpart) { + curl_off_t sz = Curl_mime_size(part); + + if(sz < 0) + size = sz; + + if(size >= 0) + size += boundarysize + sz; + } + + return size; +} + +/* Get/compute mime size. */ +curl_off_t Curl_mime_size(curl_mimepart *part) +{ + curl_off_t size; + + if(part->kind == MIMEKIND_MULTIPART) + part->datasize = multipart_size(part->arg); + + size = part->datasize; + + if(part->encoder) + size = part->encoder->sizefunc(part); + + if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) { + /* Compute total part size. */ + size += slist_size(part->curlheaders, 2, NULL, 0); + size += slist_size(part->userheaders, 2, STRCONST("Content-Type")); + size += 2; /* CRLF after headers. */ + } + return size; +} + +/* Add a header. */ +/* VARARGS2 */ +CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) +{ + struct curl_slist *hdr = NULL; + char *s = NULL; + va_list ap; + + va_start(ap, fmt); + s = curl_mvaprintf(fmt, ap); + va_end(ap); + + if(s) { + hdr = Curl_slist_append_nodup(*slp, s); + if(hdr) + *slp = hdr; + else + free(s); + } + + return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY; +} + +/* Add a content type header. */ +static CURLcode add_content_type(struct curl_slist **slp, + const char *type, const char *boundary) +{ + return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type, + boundary? "; boundary=": "", + boundary? boundary: ""); +} + +const char *Curl_mime_contenttype(const char *filename) +{ + /* + * If no content type was specified, we scan through a few well-known + * extensions and pick the first we match! + */ + struct ContentType { + const char *extension; + const char *type; + }; + static const struct ContentType ctts[] = { + {".gif", "image/gif"}, + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".png", "image/png"}, + {".svg", "image/svg+xml"}, + {".txt", "text/plain"}, + {".htm", "text/html"}, + {".html", "text/html"}, + {".pdf", "application/pdf"}, + {".xml", "application/xml"} + }; + + if(filename) { + size_t len1 = strlen(filename); + const char *nameend = filename + len1; + unsigned int i; + + for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) { + size_t len2 = strlen(ctts[i].extension); + + if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension)) + return ctts[i].type; + } + } + return NULL; +} + +static bool content_type_match(const char *contenttype, + const char *target, size_t len) +{ + if(contenttype && strncasecompare(contenttype, target, len)) + switch(contenttype[len]) { + case '\0': + case '\t': + case '\r': + case '\n': + case ' ': + case ';': + return TRUE; + } + return FALSE; +} + +CURLcode Curl_mime_prepare_headers(struct Curl_easy *data, + curl_mimepart *part, + const char *contenttype, + const char *disposition, + enum mimestrategy strategy) +{ + curl_mime *mime = NULL; + const char *boundary = NULL; + char *customct; + const char *cte = NULL; + CURLcode ret = CURLE_OK; + + /* Get rid of previously prepared headers. */ + curl_slist_free_all(part->curlheaders); + part->curlheaders = NULL; + + /* Be sure we won't access old headers later. */ + if(part->state.state == MIMESTATE_CURLHEADERS) + mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL); + + /* Check if content type is specified. */ + customct = part->mimetype; + if(!customct) + customct = search_header(part->userheaders, STRCONST("Content-Type")); + if(customct) + contenttype = customct; + + /* If content type is not specified, try to determine it. */ + if(!contenttype) { + switch(part->kind) { + case MIMEKIND_MULTIPART: + contenttype = MULTIPART_CONTENTTYPE_DEFAULT; + break; + case MIMEKIND_FILE: + contenttype = Curl_mime_contenttype(part->filename); + if(!contenttype) + contenttype = Curl_mime_contenttype(part->data); + if(!contenttype && part->filename) + contenttype = FILE_CONTENTTYPE_DEFAULT; + break; + default: + contenttype = Curl_mime_contenttype(part->filename); + break; + } + } + + if(part->kind == MIMEKIND_MULTIPART) { + mime = (curl_mime *) part->arg; + if(mime) + boundary = mime->boundary; + } + else if(contenttype && !customct && + content_type_match(contenttype, STRCONST("text/plain"))) + if(strategy == MIMESTRATEGY_MAIL || !part->filename) + contenttype = NULL; + + /* Issue content-disposition header only if not already set by caller. */ + if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) { + if(!disposition) + if(part->filename || part->name || + (contenttype && !strncasecompare(contenttype, "multipart/", 10))) + disposition = DISPOSITION_DEFAULT; + if(disposition && curl_strequal(disposition, "attachment") && + !part->name && !part->filename) + disposition = NULL; + if(disposition) { + char *name = NULL; + char *filename = NULL; + + if(part->name) { + name = escape_string(data, part->name, strategy); + if(!name) + ret = CURLE_OUT_OF_MEMORY; + } + if(!ret && part->filename) { + filename = escape_string(data, part->filename, strategy); + if(!filename) + ret = CURLE_OUT_OF_MEMORY; + } + if(!ret) + ret = Curl_mime_add_header(&part->curlheaders, + "Content-Disposition: %s%s%s%s%s%s%s", + disposition, + name? "; name=\"": "", + name? name: "", + name? "\"": "", + filename? "; filename=\"": "", + filename? filename: "", + filename? "\"": ""); + Curl_safefree(name); + Curl_safefree(filename); + if(ret) + return ret; + } + } + + /* Issue Content-Type header. */ + if(contenttype) { + ret = add_content_type(&part->curlheaders, contenttype, boundary); + if(ret) + return ret; + } + + /* Content-Transfer-Encoding header. */ + if(!search_header(part->userheaders, + STRCONST("Content-Transfer-Encoding"))) { + if(part->encoder) + cte = part->encoder->name; + else if(contenttype && strategy == MIMESTRATEGY_MAIL && + part->kind != MIMEKIND_MULTIPART) + cte = "8bit"; + if(cte) { + ret = Curl_mime_add_header(&part->curlheaders, + "Content-Transfer-Encoding: %s", cte); + if(ret) + return ret; + } + } + + /* If we were reading curl-generated headers, restart with new ones (this + should not occur). */ + if(part->state.state == MIMESTATE_CURLHEADERS) + mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders); + + /* Process subparts. */ + if(part->kind == MIMEKIND_MULTIPART && mime) { + curl_mimepart *subpart; + + disposition = NULL; + if(content_type_match(contenttype, STRCONST("multipart/form-data"))) + disposition = "form-data"; + for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) { + ret = Curl_mime_prepare_headers(data, subpart, NULL, + disposition, strategy); + if(ret) + return ret; + } + } + return ret; +} + +/* Recursively reset paused status in the given part. */ +void Curl_mime_unpause(curl_mimepart *part) +{ + if(part) { + if(part->lastreadstatus == CURL_READFUNC_PAUSE) + part->lastreadstatus = 1; /* Successful read status. */ + if(part->kind == MIMEKIND_MULTIPART) { + curl_mime *mime = (curl_mime *) part->arg; + + if(mime) { + curl_mimepart *subpart; + + for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) + Curl_mime_unpause(subpart); + } + } + } +} + + +#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP || + !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */ + +/* Mime not compiled in: define stubs for externally-referenced functions. */ +curl_mime *curl_mime_init(CURL *easy) +{ + (void) easy; + return NULL; +} + +void curl_mime_free(curl_mime *mime) +{ + (void) mime; +} + +curl_mimepart *curl_mime_addpart(curl_mime *mime) +{ + (void) mime; + return NULL; +} + +CURLcode curl_mime_name(curl_mimepart *part, const char *name) +{ + (void) part; + (void) name; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) +{ + (void) part; + (void) filename; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) +{ + (void) part; + (void) mimetype; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) +{ + (void) part; + (void) encoding; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize) +{ + (void) part; + (void) data; + (void) datasize; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) +{ + (void) part; + (void) filename; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg) +{ + (void) part; + (void) datasize; + (void) readfunc; + (void) seekfunc; + (void) freefunc; + (void) arg; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) +{ + (void) part; + (void) subparts; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, int take_ownership) +{ + (void) part; + (void) headers; + (void) take_ownership; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) +{ + (void)slp; + (void)fmt; + return CURLE_NOT_BUILT_IN; +} + +#endif /* if disabled */ diff --git a/lib/mime.h b/lib/mime.h new file mode 100644 index 0000000..a64f41d --- /dev/null +++ b/lib/mime.h @@ -0,0 +1,175 @@ +#ifndef HEADER_CURL_MIME_H +#define HEADER_CURL_MIME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#define MIME_BOUNDARY_DASHES 24 /* leading boundary dashes */ +#define MIME_RAND_BOUNDARY_CHARS 22 /* Nb. of random boundary chars. */ +#define MAX_ENCODED_LINE_LENGTH 76 /* Maximum encoded line length. */ +#define ENCODING_BUFFER_SIZE 256 /* Encoding temp buffers size. */ + +/* Part flags. */ +#define MIME_USERHEADERS_OWNER (1 << 0) +#define MIME_BODY_ONLY (1 << 1) +#define MIME_FAST_READ (1 << 2) + +#define FILE_CONTENTTYPE_DEFAULT "application/octet-stream" +#define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed" +#define DISPOSITION_DEFAULT "attachment" + +/* Part source kinds. */ +enum mimekind { + MIMEKIND_NONE = 0, /* Part not set. */ + MIMEKIND_DATA, /* Allocated mime data. */ + MIMEKIND_FILE, /* Data from file. */ + MIMEKIND_CALLBACK, /* Data from `read' callback. */ + MIMEKIND_MULTIPART, /* Data is a mime subpart. */ + MIMEKIND_LAST +}; + +/* Readback state tokens. */ +enum mimestate { + MIMESTATE_BEGIN, /* Readback has not yet started. */ + MIMESTATE_CURLHEADERS, /* In curl-generated headers. */ + MIMESTATE_USERHEADERS, /* In caller's supplied headers. */ + MIMESTATE_EOH, /* End of headers. */ + MIMESTATE_BODY, /* Placeholder. */ + MIMESTATE_BOUNDARY1, /* In boundary prefix. */ + MIMESTATE_BOUNDARY2, /* In boundary. */ + MIMESTATE_CONTENT, /* In content. */ + MIMESTATE_END, /* End of part reached. */ + MIMESTATE_LAST +}; + +/* Mime headers strategies. */ +enum mimestrategy { + MIMESTRATEGY_MAIL, /* Mime mail. */ + MIMESTRATEGY_FORM, /* HTTP post form. */ + MIMESTRATEGY_LAST +}; + +/* Content transfer encoder. */ +struct mime_encoder { + const char * name; /* Encoding name. */ + size_t (*encodefunc)(char *buffer, size_t size, bool ateof, + curl_mimepart *part); /* Encoded read. */ + curl_off_t (*sizefunc)(curl_mimepart *part); /* Encoded size. */ +}; + +/* Content transfer encoder state. */ +struct mime_encoder_state { + size_t pos; /* Position on output line. */ + size_t bufbeg; /* Next data index in input buffer. */ + size_t bufend; /* First unused byte index in input buffer. */ + char buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */ +}; + +/* Mime readback state. */ +struct mime_state { + enum mimestate state; /* Current state token. */ + void *ptr; /* State-dependent pointer. */ + curl_off_t offset; /* State-dependent offset. */ +}; + +/* Boundary string length. */ +#define MIME_BOUNDARY_LEN (MIME_BOUNDARY_DASHES + MIME_RAND_BOUNDARY_CHARS) + +/* A mime multipart. */ +struct curl_mime { + curl_mimepart *parent; /* Parent part. */ + curl_mimepart *firstpart; /* First part. */ + curl_mimepart *lastpart; /* Last part. */ + char boundary[MIME_BOUNDARY_LEN + 1]; /* The part boundary. */ + struct mime_state state; /* Current readback state. */ +}; + +/* A mime part. */ +struct curl_mimepart { + curl_mime *parent; /* Parent mime structure. */ + curl_mimepart *nextpart; /* Forward linked list. */ + enum mimekind kind; /* The part kind. */ + unsigned int flags; /* Flags. */ + char *data; /* Memory data or file name. */ + curl_read_callback readfunc; /* Read function. */ + curl_seek_callback seekfunc; /* Seek function. */ + curl_free_callback freefunc; /* Argument free function. */ + void *arg; /* Argument to callback functions. */ + FILE *fp; /* File pointer. */ + struct curl_slist *curlheaders; /* Part headers. */ + struct curl_slist *userheaders; /* Part headers. */ + char *mimetype; /* Part mime type. */ + char *filename; /* Remote file name. */ + char *name; /* Data name. */ + curl_off_t datasize; /* Expected data size. */ + struct mime_state state; /* Current readback state. */ + const struct mime_encoder *encoder; /* Content data encoder. */ + struct mime_encoder_state encstate; /* Data encoder state. */ + size_t lastreadstatus; /* Last read callback returned status. */ +}; + +CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) + CURL_PRINTF(2, 3); + +#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP)) + +/* Prototypes. */ +void Curl_mime_initpart(struct curl_mimepart *part); +void Curl_mime_cleanpart(struct curl_mimepart *part); +CURLcode Curl_mime_duppart(struct Curl_easy *data, + struct curl_mimepart *dst, + const curl_mimepart *src); +CURLcode Curl_mime_set_subparts(struct curl_mimepart *part, + struct curl_mime *subparts, + int take_ownership); +CURLcode Curl_mime_prepare_headers(struct Curl_easy *data, + struct curl_mimepart *part, + const char *contenttype, + const char *disposition, + enum mimestrategy strategy); +curl_off_t Curl_mime_size(struct curl_mimepart *part); +size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, + void *instream); +CURLcode Curl_mime_rewind(struct curl_mimepart *part); +const char *Curl_mime_contenttype(const char *filename); +void Curl_mime_unpause(struct curl_mimepart *part); + +#else +/* if disabled */ +#define Curl_mime_initpart(x) +#define Curl_mime_cleanpart(x) +#define Curl_mime_duppart(x,y,z) CURLE_OK /* Nothing to duplicate. Succeed */ +#define Curl_mime_set_subparts(a,b,c) CURLE_NOT_BUILT_IN +#define Curl_mime_prepare_headers(a,b,c,d,e) CURLE_NOT_BUILT_IN +#define Curl_mime_size(x) (curl_off_t) -1 +#define Curl_mime_read NULL +#define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN) +#define Curl_mime_unpause(x) +#endif + + +#endif /* HEADER_CURL_MIME_H */ diff --git a/lib/mprintf.c b/lib/mprintf.c new file mode 100644 index 0000000..63f7f24 --- /dev/null +++ b/lib/mprintf.c @@ -0,0 +1,1213 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + */ + +#include "curl_setup.h" +#include "dynbuf.h" +#include "curl_printf.h" +#include + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * If SIZEOF_SIZE_T has not been defined, default to the size of long. + */ + +#ifdef HAVE_LONGLONG +# define LONG_LONG_TYPE long long +# define HAVE_LONG_LONG_TYPE +#else +# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define LONG_LONG_TYPE __int64 +# define HAVE_LONG_LONG_TYPE +# else +# undef LONG_LONG_TYPE +# undef HAVE_LONG_LONG_TYPE +# endif +#endif + +/* + * Non-ANSI integer extensions + */ + +#if (defined(_WIN32_WCE)) || \ + (defined(__MINGW32__)) || \ + (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)) +# define MP_HAVE_INT_EXTENSIONS +#endif + +/* + * Max integer data types that mprintf.c is capable + */ + +#ifdef HAVE_LONG_LONG_TYPE +# define mp_intmax_t LONG_LONG_TYPE +# define mp_uintmax_t unsigned LONG_LONG_TYPE +#else +# define mp_intmax_t long +# define mp_uintmax_t unsigned long +#endif + +#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should + fit negative DBL_MAX (317 letters) */ +#define MAX_PARAMETERS 128 /* number of input arguments */ +#define MAX_SEGMENTS 128 /* number of output segments */ + +#ifdef __AMIGA__ +# undef FORMAT_INT +#endif + +/* Lower-case digits. */ +static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +/* Upper-case digits. */ +static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#define OUTCHAR(x) \ + do { \ + if(!stream(x, userp)) \ + done++; \ + else \ + return done; /* return on failure */ \ + } while(0) + +/* Data type to read from the arglist */ +typedef enum { + FORMAT_STRING, + FORMAT_PTR, + FORMAT_INTPTR, + FORMAT_INT, + FORMAT_LONG, + FORMAT_LONGLONG, + FORMAT_INTU, + FORMAT_LONGU, + FORMAT_LONGLONGU, + FORMAT_DOUBLE, + FORMAT_LONGDOUBLE, + FORMAT_WIDTH, + FORMAT_PRECISION +} FormatType; + +/* conversion and display flags */ +enum { + FLAGS_SPACE = 1<<0, + FLAGS_SHOWSIGN = 1<<1, + FLAGS_LEFT = 1<<2, + FLAGS_ALT = 1<<3, + FLAGS_SHORT = 1<<4, + FLAGS_LONG = 1<<5, + FLAGS_LONGLONG = 1<<6, + FLAGS_LONGDOUBLE = 1<<7, + FLAGS_PAD_NIL = 1<<8, + FLAGS_UNSIGNED = 1<<9, + FLAGS_OCTAL = 1<<10, + FLAGS_HEX = 1<<11, + FLAGS_UPPER = 1<<12, + FLAGS_WIDTH = 1<<13, /* '*' or '*$' used */ + FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ + FLAGS_PREC = 1<<15, /* precision was specified */ + FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ + FLAGS_CHAR = 1<<17, /* %c story */ + FLAGS_FLOATE = 1<<18, /* %e or %E */ + FLAGS_FLOATG = 1<<19, /* %g or %G */ + FLAGS_SUBSTR = 1<<20 /* no input, only substring */ +}; + +enum { + DOLLAR_UNKNOWN, + DOLLAR_NOPE, + DOLLAR_USE +}; + +/* + * Describes an input va_arg type and hold its value. + */ +struct va_input { + FormatType type; /* FormatType */ + union { + char *str; + void *ptr; + mp_intmax_t nums; /* signed */ + mp_uintmax_t numu; /* unsigned */ + double dnum; + } val; +}; + +/* + * Describes an output segment. + */ +struct outsegment { + int width; /* width OR width parameter number */ + int precision; /* precision OR precision parameter number */ + unsigned int flags; + unsigned int input; /* input argument array index */ + char *start; /* format string start to output */ + size_t outlen; /* number of bytes from the format string to output */ +}; + +struct nsprintf { + char *buffer; + size_t length; + size_t max; +}; + +struct asprintf { + struct dynbuf *b; + char merr; +}; + +/* the provided input number is 1-based but this returns the number 0-based. + + returns -1 if no valid number was provided. +*/ +static int dollarstring(char *input, char **end) +{ + if(ISDIGIT(*input)) { + int number = 0; + do { + if(number < MAX_PARAMETERS) { + number *= 10; + number += *input - '0'; + } + input++; + } while(ISDIGIT(*input)); + + if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) { + *end = ++input; + return number - 1; + } + } + return -1; +} + +/* + * Parse the format string. + * + * Create two arrays. One describes the inputs, one describes the outputs. + * + * Returns zero on success. + */ + +#define PFMT_OK 0 +#define PFMT_DOLLAR 1 /* bad dollar for main param */ +#define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */ +#define PFMT_DOLLARPREC 3 /* bad dollar use for precision */ +#define PFMT_MANYARGS 4 /* too many input arguments used */ +#define PFMT_PREC 5 /* precision overflow */ +#define PFMT_PRECMIX 6 /* bad mix of precision specifiers */ +#define PFMT_WIDTH 7 /* width overflow */ +#define PFMT_INPUTGAP 8 /* gap in arguments */ +#define PFMT_WIDTHARG 9 /* attempted to use same arg twice, for width */ +#define PFMT_PRECARG 10 /* attempted to use same arg twice, for prec */ +#define PFMT_MANYSEGS 11 /* maxed out output segments */ + +static int parsefmt(const char *format, + struct outsegment *out, + struct va_input *in, + int *opieces, + int *ipieces, va_list arglist) +{ + char *fmt = (char *)format; + int param_num = 0; + int param; + int width; + int precision; + unsigned int flags; + FormatType type; + int max_param = -1; + int i; + int ocount = 0; + unsigned char usedinput[MAX_PARAMETERS/8]; + size_t outlen = 0; + struct outsegment *optr; + int use_dollar = DOLLAR_UNKNOWN; + char *start = fmt; + + /* clear, set a bit for each used input */ + memset(usedinput, 0, sizeof(usedinput)); + + while(*fmt) { + if(*fmt == '%') { + struct va_input *iptr; + bool loopit = TRUE; + fmt++; + outlen = fmt - start - 1; + if(*fmt == '%') { + /* this means a %% that should be output only as %. Create an output + segment. */ + if(outlen) { + optr = &out[ocount++]; + if(ocount > MAX_SEGMENTS) + return PFMT_MANYSEGS; + optr->input = 0; + optr->flags = FLAGS_SUBSTR; + optr->start = start; + optr->outlen = outlen; + } + start = fmt; + fmt++; + continue; /* while */ + } + + flags = width = precision = 0; + + if(use_dollar != DOLLAR_NOPE) { + param = dollarstring(fmt, &fmt); + if(param < 0) { + if(use_dollar == DOLLAR_USE) + /* illegal combo */ + return PFMT_DOLLAR; + + /* we got no positional, just get the next arg */ + param = -1; + use_dollar = DOLLAR_NOPE; + } + else + use_dollar = DOLLAR_USE; + } + else + param = -1; + + /* Handle the flags */ + while(loopit) { + switch(*fmt++) { + case ' ': + flags |= FLAGS_SPACE; + break; + case '+': + flags |= FLAGS_SHOWSIGN; + break; + case '-': + flags |= FLAGS_LEFT; + flags &= ~FLAGS_PAD_NIL; + break; + case '#': + flags |= FLAGS_ALT; + break; + case '.': + if('*' == *fmt) { + /* The precision is picked from a specified parameter */ + flags |= FLAGS_PRECPARAM; + fmt++; + + if(use_dollar == DOLLAR_USE) { + precision = dollarstring(fmt, &fmt); + if(precision < 0) + /* illegal combo */ + return PFMT_DOLLARPREC; + } + else + /* get it from the next argument */ + precision = -1; + } + else { + bool is_neg = FALSE; + flags |= FLAGS_PREC; + precision = 0; + if('-' == *fmt) { + is_neg = TRUE; + fmt++; + } + while(ISDIGIT(*fmt)) { + if(precision > INT_MAX/10) + return PFMT_PREC; + precision *= 10; + precision += *fmt - '0'; + fmt++; + } + if(is_neg) + precision = -precision; + } + if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) == + (FLAGS_PREC | FLAGS_PRECPARAM)) + /* it is not permitted to use both kinds of precision for the same + argument */ + return PFMT_PRECMIX; + break; + case 'h': + flags |= FLAGS_SHORT; + break; +#if defined(MP_HAVE_INT_EXTENSIONS) + case 'I': + if((fmt[0] == '3') && (fmt[1] == '2')) { + flags |= FLAGS_LONG; + fmt += 2; + } + else if((fmt[0] == '6') && (fmt[1] == '4')) { + flags |= FLAGS_LONGLONG; + fmt += 2; + } + else { +#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + } + break; +#endif + case 'l': + if(flags & FLAGS_LONG) + flags |= FLAGS_LONGLONG; + else + flags |= FLAGS_LONG; + break; + case 'L': + flags |= FLAGS_LONGDOUBLE; + break; + case 'q': + flags |= FLAGS_LONGLONG; + break; + case 'z': + /* the code below generates a warning if -Wunreachable-code is + used */ +#if (SIZEOF_SIZE_T > SIZEOF_LONG) + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; + case 'O': +#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; + case '0': + if(!(flags & FLAGS_LEFT)) + flags |= FLAGS_PAD_NIL; + FALLTHROUGH(); + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + flags |= FLAGS_WIDTH; + width = 0; + fmt--; + do { + if(width > INT_MAX/10) + return PFMT_WIDTH; + width *= 10; + width += *fmt - '0'; + fmt++; + } while(ISDIGIT(*fmt)); + break; + case '*': /* read width from argument list */ + flags |= FLAGS_WIDTHPARAM; + if(use_dollar == DOLLAR_USE) { + width = dollarstring(fmt, &fmt); + if(width < 0) + /* illegal combo */ + return PFMT_DOLLARWIDTH; + } + else + /* pick from the next argument */ + width = -1; + break; + default: + loopit = FALSE; + fmt--; + break; + } /* switch */ + } /* while */ + + switch(*fmt) { + case 'S': + flags |= FLAGS_ALT; + FALLTHROUGH(); + case 's': + type = FORMAT_STRING; + break; + case 'n': + type = FORMAT_INTPTR; + break; + case 'p': + type = FORMAT_PTR; + break; + case 'd': + case 'i': + if(flags & FLAGS_LONGLONG) + type = FORMAT_LONGLONG; + else if(flags & FLAGS_LONG) + type = FORMAT_LONG; + else + type = FORMAT_INT; + break; + case 'u': + if(flags & FLAGS_LONGLONG) + type = FORMAT_LONGLONGU; + else if(flags & FLAGS_LONG) + type = FORMAT_LONGU; + else + type = FORMAT_INTU; + flags |= FLAGS_UNSIGNED; + break; + case 'o': + type = FORMAT_INT; + flags |= FLAGS_OCTAL; + break; + case 'x': + type = FORMAT_INTU; + flags |= FLAGS_HEX|FLAGS_UNSIGNED; + break; + case 'X': + type = FORMAT_INTU; + flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; + break; + case 'c': + type = FORMAT_INT; + flags |= FLAGS_CHAR; + break; + case 'f': + type = FORMAT_DOUBLE; + break; + case 'e': + type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATE; + break; + case 'E': + type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATE|FLAGS_UPPER; + break; + case 'g': + type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATG; + break; + case 'G': + type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATG|FLAGS_UPPER; + break; + default: + /* invalid instruction, disregard and continue */ + continue; + } /* switch */ + + if(flags & FLAGS_WIDTHPARAM) { + if(width < 0) + width = param_num++; + else { + /* if this identifies a parameter already used, this + is illegal */ + if(usedinput[width/8] & (1 << (width&7))) + return PFMT_WIDTHARG; + } + if(width >= MAX_PARAMETERS) + return PFMT_MANYARGS; + if(width >= max_param) + max_param = width; + + in[width].type = FORMAT_WIDTH; + /* mark as used */ + usedinput[width/8] |= (unsigned char)(1 << (width&7)); + } + + if(flags & FLAGS_PRECPARAM) { + if(precision < 0) + precision = param_num++; + else { + /* if this identifies a parameter already used, this + is illegal */ + if(usedinput[precision/8] & (1 << (precision&7))) + return PFMT_PRECARG; + } + if(precision >= MAX_PARAMETERS) + return PFMT_MANYARGS; + if(precision >= max_param) + max_param = precision; + + in[precision].type = FORMAT_PRECISION; + usedinput[precision/8] |= (unsigned char)(1 << (precision&7)); + } + + /* Handle the specifier */ + if(param < 0) + param = param_num++; + if(param >= MAX_PARAMETERS) + return PFMT_MANYARGS; + if(param >= max_param) + max_param = param; + + iptr = &in[param]; + iptr->type = type; + + /* mark this input as used */ + usedinput[param/8] |= (unsigned char)(1 << (param&7)); + + fmt++; + optr = &out[ocount++]; + if(ocount > MAX_SEGMENTS) + return PFMT_MANYSEGS; + optr->input = param; + optr->flags = flags; + optr->width = width; + optr->precision = precision; + optr->start = start; + optr->outlen = outlen; + start = fmt; + } + else + fmt++; + } + + /* is there a trailing piece */ + outlen = fmt - start; + if(outlen) { + optr = &out[ocount++]; + if(ocount > MAX_SEGMENTS) + return PFMT_MANYSEGS; + optr->input = 0; + optr->flags = FLAGS_SUBSTR; + optr->start = start; + optr->outlen = outlen; + } + + /* Read the arg list parameters into our data list */ + for(i = 0; i < max_param + 1; i++) { + struct va_input *iptr = &in[i]; + if(!(usedinput[i/8] & (1 << (i&7)))) + /* bad input */ + return PFMT_INPUTGAP; + + /* based on the type, read the correct argument */ + switch(iptr->type) { + case FORMAT_STRING: + iptr->val.str = va_arg(arglist, char *); + break; + + case FORMAT_INTPTR: + case FORMAT_PTR: + iptr->val.ptr = va_arg(arglist, void *); + break; + + case FORMAT_LONGLONGU: + iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t); + break; + + case FORMAT_LONGLONG: + iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t); + break; + + case FORMAT_LONGU: + iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long); + break; + + case FORMAT_LONG: + iptr->val.nums = (mp_intmax_t)va_arg(arglist, long); + break; + + case FORMAT_INTU: + iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int); + break; + + case FORMAT_INT: + case FORMAT_WIDTH: + case FORMAT_PRECISION: + iptr->val.nums = (mp_intmax_t)va_arg(arglist, int); + break; + + case FORMAT_DOUBLE: + iptr->val.dnum = va_arg(arglist, double); + break; + + default: + DEBUGASSERT(NULL); /* unexpected */ + break; + } + } + *ipieces = max_param + 1; + *opieces = ocount; + + return PFMT_OK; +} + +/* + * formatf() - the general printf function. + * + * It calls parsefmt() to parse the format string. It populates two arrays; + * one that describes the input arguments and one that describes a number of + * output segments. + * + * On success, the input array describes the type of all arguments and their + * values. + * + * The function then iterates over the output sengments and outputs them one + * by one until done. Using the appropriate input arguments (if any). + * + * All output is sent to the 'stream()' callback, one byte at a time. + */ + +static int formatf( + void *userp, /* untouched by format(), just sent to the stream() function in + the second argument */ + /* function pointer called for each output character */ + int (*stream)(unsigned char, void *), + const char *format, /* %-formatted string */ + va_list ap_save) /* list of parameters */ +{ + static const char nilstr[] = "(nil)"; + const char *digits = lower_digits; /* Base-36 digits for numbers. */ + int done = 0; /* number of characters written */ + int i; + int ocount = 0; /* number of output segments */ + int icount = 0; /* number of input arguments */ + + struct outsegment output[MAX_SEGMENTS]; + struct va_input input[MAX_PARAMETERS]; + char work[BUFFSIZE]; + + /* 'workend' points to the final buffer byte position, but with an extra + byte as margin to avoid the (false?) warning Coverity gives us + otherwise */ + char *workend = &work[sizeof(work) - 2]; + + /* Parse the format string */ + if(parsefmt(format, output, input, &ocount, &icount, ap_save)) + return 0; + + for(i = 0; i < ocount; i++) { + struct outsegment *optr = &output[i]; + struct va_input *iptr; + bool is_alt; /* Format spec modifiers. */ + int width; /* Width of a field. */ + int prec; /* Precision of a field. */ + bool is_neg; /* Decimal integer is negative. */ + unsigned long base; /* Base of a number to be written. */ + mp_uintmax_t num; /* Integral values to be written. */ + mp_intmax_t signed_num; /* Used to convert negative in positive. */ + char *w; + size_t outlen = optr->outlen; + int flags = optr->flags; + + if(outlen) { + char *str = optr->start; + for(; outlen && *str; outlen--) + OUTCHAR(*str++); + if(optr->flags & FLAGS_SUBSTR) + /* this is just a substring */ + continue; + } + + /* pick up the specified width */ + if(flags & FLAGS_WIDTHPARAM) { + width = (int)input[optr->width].val.nums; + if(width < 0) { + /* "A negative field width is taken as a '-' flag followed by a + positive field width." */ + if(width == INT_MIN) + width = INT_MAX; + else + width = -width; + flags |= FLAGS_LEFT; + flags &= ~FLAGS_PAD_NIL; + } + } + else + width = optr->width; + + /* pick up the specified precision */ + if(flags & FLAGS_PRECPARAM) { + prec = (int)input[optr->precision].val.nums; + if(prec < 0) + /* "A negative precision is taken as if the precision were + omitted." */ + prec = -1; + } + else if(flags & FLAGS_PREC) + prec = optr->precision; + else + prec = -1; + + is_alt = (flags & FLAGS_ALT) ? 1 : 0; + iptr = &input[optr->input]; + + switch(iptr->type) { + case FORMAT_INTU: + case FORMAT_LONGU: + case FORMAT_LONGLONGU: + flags |= FLAGS_UNSIGNED; + FALLTHROUGH(); + case FORMAT_INT: + case FORMAT_LONG: + case FORMAT_LONGLONG: + num = iptr->val.numu; + if(flags & FLAGS_CHAR) { + /* Character. */ + if(!(flags & FLAGS_LEFT)) + while(--width > 0) + OUTCHAR(' '); + OUTCHAR((char) num); + if(flags & FLAGS_LEFT) + while(--width > 0) + OUTCHAR(' '); + break; + } + if(flags & FLAGS_OCTAL) { + /* Octal unsigned integer */ + base = 8; + is_neg = FALSE; + } + else if(flags & FLAGS_HEX) { + /* Hexadecimal unsigned integer */ + digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits; + base = 16; + is_neg = FALSE; + } + else if(flags & FLAGS_UNSIGNED) { + /* Decimal unsigned integer */ + base = 10; + is_neg = FALSE; + } + else { + /* Decimal integer. */ + base = 10; + + is_neg = (iptr->val.nums < (mp_intmax_t)0); + if(is_neg) { + /* signed_num might fail to hold absolute negative minimum by 1 */ + signed_num = iptr->val.nums + (mp_intmax_t)1; + signed_num = -signed_num; + num = (mp_uintmax_t)signed_num; + num += (mp_uintmax_t)1; + } + } +number: + /* Supply a default precision if none was given. */ + if(prec == -1) + prec = 1; + + /* Put the number in WORK. */ + w = workend; + switch(base) { + case 10: + while(num > 0) { + *w-- = (char)('0' + (num % 10)); + num /= 10; + } + break; + default: + while(num > 0) { + *w-- = digits[num % base]; + num /= base; + } + break; + } + width -= (int)(workend - w); + prec -= (int)(workend - w); + + if(is_alt && base == 8 && prec <= 0) { + *w-- = '0'; + --width; + } + + if(prec > 0) { + width -= prec; + while(prec-- > 0 && w >= work) + *w-- = '0'; + } + + if(is_alt && base == 16) + width -= 2; + + if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) + --width; + + if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL)) + while(width-- > 0) + OUTCHAR(' '); + + if(is_neg) + OUTCHAR('-'); + else if(flags & FLAGS_SHOWSIGN) + OUTCHAR('+'); + else if(flags & FLAGS_SPACE) + OUTCHAR(' '); + + if(is_alt && base == 16) { + OUTCHAR('0'); + if(flags & FLAGS_UPPER) + OUTCHAR('X'); + else + OUTCHAR('x'); + } + + if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL)) + while(width-- > 0) + OUTCHAR('0'); + + /* Write the number. */ + while(++w <= workend) { + OUTCHAR(*w); + } + + if(flags & FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); + break; + + case FORMAT_STRING: { + const char *str; + size_t len; + + str = (char *)iptr->val.str; + if(!str) { + /* Write null string if there's space. */ + if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) { + str = nilstr; + len = sizeof(nilstr) - 1; + /* Disable quotes around (nil) */ + flags &= (~FLAGS_ALT); + } + else { + str = ""; + len = 0; + } + } + else if(prec != -1) + len = (size_t)prec; + else if(*str == '\0') + len = 0; + else + len = strlen(str); + + width -= (len > INT_MAX) ? INT_MAX : (int)len; + + if(flags & FLAGS_ALT) + OUTCHAR('"'); + + if(!(flags&FLAGS_LEFT)) + while(width-- > 0) + OUTCHAR(' '); + + for(; len && *str; len--) + OUTCHAR(*str++); + if(flags&FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); + + if(flags & FLAGS_ALT) + OUTCHAR('"'); + break; + } + + case FORMAT_PTR: + /* Generic pointer. */ + if(iptr->val.ptr) { + /* If the pointer is not NULL, write it as a %#x spec. */ + base = 16; + digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits; + is_alt = TRUE; + num = (size_t) iptr->val.ptr; + is_neg = FALSE; + goto number; + } + else { + /* Write "(nil)" for a nil pointer. */ + const char *point; + + width -= (int)(sizeof(nilstr) - 1); + if(flags & FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); + for(point = nilstr; *point != '\0'; ++point) + OUTCHAR(*point); + if(!(flags & FLAGS_LEFT)) + while(width-- > 0) + OUTCHAR(' '); + } + break; + + case FORMAT_DOUBLE: { + char formatbuf[32]="%"; + char *fptr = &formatbuf[1]; + size_t left = sizeof(formatbuf)-strlen(formatbuf); + int len; + + if(flags & FLAGS_WIDTH) + width = optr->width; + + if(flags & FLAGS_PREC) + prec = optr->precision; + + if(flags & FLAGS_LEFT) + *fptr++ = '-'; + if(flags & FLAGS_SHOWSIGN) + *fptr++ = '+'; + if(flags & FLAGS_SPACE) + *fptr++ = ' '; + if(flags & FLAGS_ALT) + *fptr++ = '#'; + + *fptr = 0; + + if(width >= 0) { + if(width >= (int)sizeof(work)) + width = sizeof(work)-1; + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, "%d", width); + fptr += len; + left -= len; + } + if(prec >= 0) { + /* for each digit in the integer part, we can have one less + precision */ + size_t maxprec = sizeof(work) - 2; + double val = iptr->val.dnum; + if(width > 0 && prec <= width) + maxprec -= width; + while(val >= 10.0) { + val /= 10; + maxprec--; + } + + if(prec > (int)maxprec) + prec = (int)maxprec-1; + if(prec < 0) + prec = 0; + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, ".%d", prec); + fptr += len; + } + if(flags & FLAGS_LONG) + *fptr++ = 'l'; + + if(flags & FLAGS_FLOATE) + *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E':'e'); + else if(flags & FLAGS_FLOATG) + *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g'); + else + *fptr++ = 'f'; + + *fptr = 0; /* and a final null-termination */ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + /* NOTE NOTE NOTE!! Not all sprintf implementations return number of + output characters */ +#ifdef HAVE_SNPRINTF + (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum); +#else + (sprintf)(work, formatbuf, iptr->val.dnum); +#endif +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + DEBUGASSERT(strlen(work) <= sizeof(work)); + for(fptr = work; *fptr; fptr++) + OUTCHAR(*fptr); + break; + } + + case FORMAT_INTPTR: + /* Answer the count of characters written. */ +#ifdef HAVE_LONG_LONG_TYPE + if(flags & FLAGS_LONGLONG) + *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done; + else +#endif + if(flags & FLAGS_LONG) + *(long *) iptr->val.ptr = (long)done; + else if(!(flags & FLAGS_SHORT)) + *(int *) iptr->val.ptr = (int)done; + else + *(short *) iptr->val.ptr = (short)done; + break; + + default: + break; + } + } + return done; +} + +/* fputc() look-alike */ +static int addbyter(unsigned char outc, void *f) +{ + struct nsprintf *infop = f; + if(infop->length < infop->max) { + /* only do this if we haven't reached max length yet */ + *infop->buffer++ = outc; /* store */ + infop->length++; /* we are now one byte larger */ + return 0; /* fputc() returns like this on success */ + } + return 1; +} + +int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, + va_list ap_save) +{ + int retcode; + struct nsprintf info; + + info.buffer = buffer; + info.length = 0; + info.max = maxlength; + + retcode = formatf(&info, addbyter, format, ap_save); + if(info.max) { + /* we terminate this with a zero byte */ + if(info.max == info.length) { + /* we're at maximum, scrap the last letter */ + info.buffer[-1] = 0; + DEBUGASSERT(retcode); + retcode--; /* don't count the nul byte */ + } + else + info.buffer[0] = 0; + } + return retcode; +} + +int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); + va_end(ap_save); + return retcode; +} + +/* fputc() look-alike */ +static int alloc_addbyter(unsigned char outc, void *f) +{ + struct asprintf *infop = f; + CURLcode result = Curl_dyn_addn(infop->b, &outc, 1); + if(result) { + infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM; + return 1 ; /* fail */ + } + return 0; +} + +/* appends the formatted string, returns MERR error code */ +int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save) +{ + struct asprintf info; + info.b = dyn; + info.merr = MERR_OK; + + (void)formatf(&info, alloc_addbyter, format, ap_save); + if(info.merr) { + Curl_dyn_free(info.b); + return info.merr; + } + return 0; +} + +char *curl_mvaprintf(const char *format, va_list ap_save) +{ + struct asprintf info; + struct dynbuf dyn; + info.b = &dyn; + Curl_dyn_init(info.b, DYN_APRINTF); + info.merr = MERR_OK; + + (void)formatf(&info, alloc_addbyter, format, ap_save); + if(info.merr) { + Curl_dyn_free(info.b); + return NULL; + } + if(Curl_dyn_len(info.b)) + return Curl_dyn_ptr(info.b); + return strdup(""); +} + +char *curl_maprintf(const char *format, ...) +{ + va_list ap_save; + char *s; + va_start(ap_save, format); + s = curl_mvaprintf(format, ap_save); + va_end(ap_save); + return s; +} + +static int storebuffer(unsigned char outc, void *f) +{ + char **buffer = f; + **buffer = outc; + (*buffer)++; + return 0; +} + +int curl_msprintf(char *buffer, const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + va_start(ap_save, format); + retcode = formatf(&buffer, storebuffer, format, ap_save); + va_end(ap_save); + *buffer = 0; /* we terminate this with a zero byte */ + return retcode; +} + +static int fputc_wrapper(unsigned char outc, void *f) +{ + int out = outc; + FILE *s = f; + int rc = fputc(out, s); + if(rc == out) + return 0; + return 1; +} + +int curl_mprintf(const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + + retcode = formatf(stdout, fputc_wrapper, format, ap_save); + va_end(ap_save); + return retcode; +} + +int curl_mfprintf(FILE *whereto, const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + retcode = formatf(whereto, fputc_wrapper, format, ap_save); + va_end(ap_save); + return retcode; +} + +int curl_mvsprintf(char *buffer, const char *format, va_list ap_save) +{ + int retcode = formatf(&buffer, storebuffer, format, ap_save); + *buffer = 0; /* we terminate this with a zero byte */ + return retcode; +} + +int curl_mvprintf(const char *format, va_list ap_save) +{ + return formatf(stdout, fputc_wrapper, format, ap_save); +} + +int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) +{ + return formatf(whereto, fputc_wrapper, format, ap_save); +} diff --git a/lib/mqtt.c b/lib/mqtt.c new file mode 100644 index 0000000..5a9d6d0 --- /dev/null +++ b/lib/mqtt.c @@ -0,0 +1,844 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Björn Stenberg, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_MQTT + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "progress.h" +#include "mqtt.h" +#include "select.h" +#include "strdup.h" +#include "url.h" +#include "escape.h" +#include "warnless.h" +#include "curl_printf.h" +#include "curl_memory.h" +#include "multiif.h" +#include "rand.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#define MQTT_MSG_CONNECT 0x10 +#define MQTT_MSG_CONNACK 0x20 +#define MQTT_MSG_PUBLISH 0x30 +#define MQTT_MSG_SUBSCRIBE 0x82 +#define MQTT_MSG_SUBACK 0x90 +#define MQTT_MSG_DISCONNECT 0xe0 + +#define MQTT_CONNACK_LEN 2 +#define MQTT_SUBACK_LEN 3 +#define MQTT_CLIENTID_LEN 12 /* "curl0123abcd" */ + +/* + * Forward declarations. + */ + +static CURLcode mqtt_do(struct Curl_easy *data, bool *done); +static CURLcode mqtt_done(struct Curl_easy *data, + CURLcode status, bool premature); +static CURLcode mqtt_doing(struct Curl_easy *data, bool *done); +static int mqtt_getsock(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *sock); +static CURLcode mqtt_setup_conn(struct Curl_easy *data, + struct connectdata *conn); + +/* + * MQTT protocol handler. + */ + +const struct Curl_handler Curl_handler_mqtt = { + "MQTT", /* scheme */ + mqtt_setup_conn, /* setup_connection */ + mqtt_do, /* do_it */ + mqtt_done, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + mqtt_doing, /* doing */ + ZERO_NULL, /* proto_getsock */ + mqtt_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_MQTT, /* defport */ + CURLPROTO_MQTT, /* protocol */ + CURLPROTO_MQTT, /* family */ + PROTOPT_NONE /* flags */ +}; + +static CURLcode mqtt_setup_conn(struct Curl_easy *data, + struct connectdata *conn) +{ + /* allocate the HTTP-specific struct for the Curl_easy, only to survive + during this request */ + struct MQTT *mq; + (void)conn; + DEBUGASSERT(data->req.p.mqtt == NULL); + + mq = calloc(1, sizeof(struct MQTT)); + if(!mq) + return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&mq->recvbuf, DYN_MQTT_RECV); + data->req.p.mqtt = mq; + return CURLE_OK; +} + +static CURLcode mqtt_send(struct Curl_easy *data, + char *buf, size_t len) +{ + CURLcode result = CURLE_OK; + struct MQTT *mq = data->req.p.mqtt; + ssize_t n; + result = Curl_nwrite(data, FIRSTSOCKET, buf, len, &n); + if(result) + return result; + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n); + if(len != (size_t)n) { + size_t nsend = len - n; + char *sendleftovers = Curl_memdup(&buf[n], nsend); + if(!sendleftovers) + return CURLE_OUT_OF_MEMORY; + mq->sendleftovers = sendleftovers; + mq->nsend = nsend; + } + else { + mq->sendleftovers = NULL; + mq->nsend = 0; + } + return result; +} + +/* Generic function called by the multi interface to figure out what socket(s) + to wait for and for what actions during the DOING and PROTOCONNECT + states */ +static int mqtt_getsock(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *sock) +{ + (void)data; + sock[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(FIRSTSOCKET); +} + +static int mqtt_encode_len(char *buf, size_t len) +{ + unsigned char encoded; + int i; + + for(i = 0; (len > 0) && (i<4); i++) { + encoded = len % 0x80; + len /= 0x80; + if(len) + encoded |= 0x80; + buf[i] = encoded; + } + + return i; +} + +/* add the passwd to the CONNECT packet */ +static int add_passwd(const char *passwd, const size_t plen, + char *pkt, const size_t start, int remain_pos) +{ + /* magic number that need to be set properly */ + const size_t conn_flags_pos = remain_pos + 8; + if(plen > 0xffff) + return 1; + + /* set password flag */ + pkt[conn_flags_pos] |= 0x40; + + /* length of password provided */ + pkt[start] = (char)((plen >> 8) & 0xFF); + pkt[start + 1] = (char)(plen & 0xFF); + memcpy(&pkt[start + 2], passwd, plen); + return 0; +} + +/* add user to the CONNECT packet */ +static int add_user(const char *username, const size_t ulen, + unsigned char *pkt, const size_t start, int remain_pos) +{ + /* magic number that need to be set properly */ + const size_t conn_flags_pos = remain_pos + 8; + if(ulen > 0xffff) + return 1; + + /* set username flag */ + pkt[conn_flags_pos] |= 0x80; + /* length of username provided */ + pkt[start] = (unsigned char)((ulen >> 8) & 0xFF); + pkt[start + 1] = (unsigned char)(ulen & 0xFF); + memcpy(&pkt[start + 2], username, ulen); + return 0; +} + +/* add client ID to the CONNECT packet */ +static int add_client_id(const char *client_id, const size_t client_id_len, + char *pkt, const size_t start) +{ + if(client_id_len != MQTT_CLIENTID_LEN) + return 1; + pkt[start] = 0x00; + pkt[start + 1] = MQTT_CLIENTID_LEN; + memcpy(&pkt[start + 2], client_id, MQTT_CLIENTID_LEN); + return 0; +} + +/* Set initial values of CONNECT packet */ +static int init_connpack(char *packet, char *remain, int remain_pos) +{ + /* Fixed header starts */ + /* packet type */ + packet[0] = MQTT_MSG_CONNECT; + /* remaining length field */ + memcpy(&packet[1], remain, remain_pos); + /* Fixed header ends */ + + /* Variable header starts */ + /* protocol length */ + packet[remain_pos + 1] = 0x00; + packet[remain_pos + 2] = 0x04; + /* protocol name */ + packet[remain_pos + 3] = 'M'; + packet[remain_pos + 4] = 'Q'; + packet[remain_pos + 5] = 'T'; + packet[remain_pos + 6] = 'T'; + /* protocol level */ + packet[remain_pos + 7] = 0x04; + /* CONNECT flag: CleanSession */ + packet[remain_pos + 8] = 0x02; + /* keep-alive 0 = disabled */ + packet[remain_pos + 9] = 0x00; + packet[remain_pos + 10] = 0x3c; + /* end of variable header */ + return remain_pos + 10; +} + +static CURLcode mqtt_connect(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + int pos = 0; + int rc = 0; + /* remain length */ + int remain_pos = 0; + char remain[4] = {0}; + size_t packetlen = 0; + size_t payloadlen = 0; + size_t start_user = 0; + size_t start_pwd = 0; + char client_id[MQTT_CLIENTID_LEN + 1] = "curl"; + const size_t clen = strlen("curl"); + char *packet = NULL; + + /* extracting username from request */ + const char *username = data->state.aptr.user ? + data->state.aptr.user : ""; + const size_t ulen = strlen(username); + /* extracting password from request */ + const char *passwd = data->state.aptr.passwd ? + data->state.aptr.passwd : ""; + const size_t plen = strlen(passwd); + + payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2; + /* The plus 2 are for the MSB and LSB describing the length of the string to + * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */ + if(ulen) + payloadlen += 2; + if(plen) + payloadlen += 2; + + /* getting how much occupy the remain length */ + remain_pos = mqtt_encode_len(remain, payloadlen + 10); + + /* 10 length of variable header and 1 the first byte of the fixed header */ + packetlen = payloadlen + 10 + remain_pos + 1; + + /* allocating packet */ + if(packetlen > 268435455) + return CURLE_WEIRD_SERVER_REPLY; + packet = malloc(packetlen); + if(!packet) + return CURLE_OUT_OF_MEMORY; + memset(packet, 0, packetlen); + + /* set initial values for the CONNECT packet */ + pos = init_connpack(packet, remain, remain_pos); + + result = Curl_rand_alnum(data, (unsigned char *)&client_id[clen], + MQTT_CLIENTID_LEN - clen + 1); + /* add client id */ + rc = add_client_id(client_id, strlen(client_id), packet, pos + 1); + if(rc) { + failf(data, "Client ID length mismatched: [%zu]", strlen(client_id)); + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + infof(data, "Using client id '%s'", client_id); + + /* position where starts the user payload */ + start_user = pos + 3 + MQTT_CLIENTID_LEN; + /* position where starts the password payload */ + start_pwd = start_user + ulen; + /* if user name was provided, add it to the packet */ + if(ulen) { + start_pwd += 2; + + rc = add_user(username, ulen, + (unsigned char *)packet, start_user, remain_pos); + if(rc) { + failf(data, "Username is too large: [%zu]", ulen); + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + } + + /* if passwd was provided, add it to the packet */ + if(plen) { + rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos); + if(rc) { + failf(data, "Password is too large: [%zu]", plen); + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + } + + if(!result) + result = mqtt_send(data, packet, packetlen); + +end: + if(packet) + free(packet); + Curl_safefree(data->state.aptr.user); + Curl_safefree(data->state.aptr.passwd); + return result; +} + +static CURLcode mqtt_disconnect(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct MQTT *mq = data->req.p.mqtt; + result = mqtt_send(data, (char *)"\xe0\x00", 2); + Curl_safefree(mq->sendleftovers); + Curl_dyn_free(&mq->recvbuf); + return result; +} + +static CURLcode mqtt_recv_atleast(struct Curl_easy *data, size_t nbytes) +{ + struct MQTT *mq = data->req.p.mqtt; + size_t rlen = Curl_dyn_len(&mq->recvbuf); + CURLcode result; + + if(rlen < nbytes) { + unsigned char readbuf[1024]; + ssize_t nread; + + DEBUGASSERT(nbytes - rlen < sizeof(readbuf)); + result = Curl_read(data, data->conn->sock[FIRSTSOCKET], + (char *)readbuf, nbytes - rlen, &nread); + if(result) + return result; + DEBUGASSERT(nread >= 0); + if(Curl_dyn_addn(&mq->recvbuf, readbuf, (size_t)nread)) + return CURLE_OUT_OF_MEMORY; + rlen = Curl_dyn_len(&mq->recvbuf); + } + return (rlen >= nbytes)? CURLE_OK : CURLE_AGAIN; +} + +static void mqtt_recv_consume(struct Curl_easy *data, size_t nbytes) +{ + struct MQTT *mq = data->req.p.mqtt; + size_t rlen = Curl_dyn_len(&mq->recvbuf); + if(rlen <= nbytes) + Curl_dyn_reset(&mq->recvbuf); + else + Curl_dyn_tail(&mq->recvbuf, rlen - nbytes); +} + +static CURLcode mqtt_verify_connack(struct Curl_easy *data) +{ + struct MQTT *mq = data->req.p.mqtt; + CURLcode result; + char *ptr; + + result = mqtt_recv_atleast(data, MQTT_CONNACK_LEN); + if(result) + goto fail; + + /* verify CONNACK */ + DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_CONNACK_LEN); + ptr = Curl_dyn_ptr(&mq->recvbuf); + Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_CONNACK_LEN); + + if(ptr[0] != 0x00 || ptr[1] != 0x00) { + failf(data, "Expected %02x%02x but got %02x%02x", + 0x00, 0x00, ptr[0], ptr[1]); + Curl_dyn_reset(&mq->recvbuf); + result = CURLE_WEIRD_SERVER_REPLY; + goto fail; + } + mqtt_recv_consume(data, MQTT_CONNACK_LEN); +fail: + return result; +} + +static CURLcode mqtt_get_topic(struct Curl_easy *data, + char **topic, size_t *topiclen) +{ + char *path = data->state.up.path; + CURLcode result = CURLE_URL_MALFORMAT; + if(strlen(path) > 1) { + result = Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA); + if(!result && (*topiclen > 0xffff)) { + failf(data, "Too long MQTT topic"); + result = CURLE_URL_MALFORMAT; + } + } + else + failf(data, "No MQTT topic found. Forgot to URL encode it?"); + + return result; +} + +static CURLcode mqtt_subscribe(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + char *topic = NULL; + size_t topiclen; + unsigned char *packet = NULL; + size_t packetlen; + char encodedsize[4]; + size_t n; + struct connectdata *conn = data->conn; + + result = mqtt_get_topic(data, &topic, &topiclen); + if(result) + goto fail; + + conn->proto.mqtt.packetid++; + + packetlen = topiclen + 5; /* packetid + topic (has a two byte length field) + + 2 bytes topic length + QoS byte */ + n = mqtt_encode_len((char *)encodedsize, packetlen); + packetlen += n + 1; /* add one for the control packet type byte */ + + packet = malloc(packetlen); + if(!packet) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + packet[0] = MQTT_MSG_SUBSCRIBE; + memcpy(&packet[1], encodedsize, n); + packet[1 + n] = (conn->proto.mqtt.packetid >> 8) & 0xff; + packet[2 + n] = conn->proto.mqtt.packetid & 0xff; + packet[3 + n] = (topiclen >> 8) & 0xff; + packet[4 + n ] = topiclen & 0xff; + memcpy(&packet[5 + n], topic, topiclen); + packet[5 + n + topiclen] = 0; /* QoS zero */ + + result = mqtt_send(data, (char *)packet, packetlen); + +fail: + free(topic); + free(packet); + return result; +} + +/* + * Called when the first byte was already read. + */ +static CURLcode mqtt_verify_suback(struct Curl_easy *data) +{ + struct MQTT *mq = data->req.p.mqtt; + struct connectdata *conn = data->conn; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + CURLcode result; + char *ptr; + + result = mqtt_recv_atleast(data, MQTT_SUBACK_LEN); + if(result) + goto fail; + + /* verify SUBACK */ + DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_SUBACK_LEN); + ptr = Curl_dyn_ptr(&mq->recvbuf); + Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_SUBACK_LEN); + + if(((unsigned char)ptr[0]) != ((mqtt->packetid >> 8) & 0xff) || + ((unsigned char)ptr[1]) != (mqtt->packetid & 0xff) || + ptr[2] != 0x00) { + Curl_dyn_reset(&mq->recvbuf); + result = CURLE_WEIRD_SERVER_REPLY; + goto fail; + } + mqtt_recv_consume(data, MQTT_SUBACK_LEN); +fail: + return result; +} + +static CURLcode mqtt_publish(struct Curl_easy *data) +{ + CURLcode result; + char *payload = data->set.postfields; + size_t payloadlen; + char *topic = NULL; + size_t topiclen; + unsigned char *pkt = NULL; + size_t i = 0; + size_t remaininglength; + size_t encodelen; + char encodedbytes[4]; + curl_off_t postfieldsize = data->set.postfieldsize; + + if(!payload) { + DEBUGF(infof(data, "mqtt_publish without payload, return bad arg")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(postfieldsize < 0) + payloadlen = strlen(payload); + else + payloadlen = (size_t)postfieldsize; + + result = mqtt_get_topic(data, &topic, &topiclen); + if(result) + goto fail; + + remaininglength = payloadlen + 2 + topiclen; + encodelen = mqtt_encode_len(encodedbytes, remaininglength); + + /* add the control byte and the encoded remaining length */ + pkt = malloc(remaininglength + 1 + encodelen); + if(!pkt) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + /* assemble packet */ + pkt[i++] = MQTT_MSG_PUBLISH; + memcpy(&pkt[i], encodedbytes, encodelen); + i += encodelen; + pkt[i++] = (topiclen >> 8) & 0xff; + pkt[i++] = (topiclen & 0xff); + memcpy(&pkt[i], topic, topiclen); + i += topiclen; + memcpy(&pkt[i], payload, payloadlen); + i += payloadlen; + result = mqtt_send(data, (char *)pkt, i); + +fail: + free(pkt); + free(topic); + return result; +} + +static size_t mqtt_decode_len(unsigned char *buf, + size_t buflen, size_t *lenbytes) +{ + size_t len = 0; + size_t mult = 1; + size_t i; + unsigned char encoded = 128; + + for(i = 0; (i < buflen) && (encoded & 128); i++) { + encoded = buf[i]; + len += (encoded & 127) * mult; + mult *= 128; + } + + if(lenbytes) + *lenbytes = i; + + return len; +} + +#ifdef CURLDEBUG +static const char *statenames[]={ + "MQTT_FIRST", + "MQTT_REMAINING_LENGTH", + "MQTT_CONNACK", + "MQTT_SUBACK", + "MQTT_SUBACK_COMING", + "MQTT_PUBWAIT", + "MQTT_PUB_REMAIN", + + "NOT A STATE" +}; +#endif + +/* The only way to change state */ +static void mqstate(struct Curl_easy *data, + enum mqttstate state, + enum mqttstate nextstate) /* used if state == FIRST */ +{ + struct connectdata *conn = data->conn; + struct mqtt_conn *mqtt = &conn->proto.mqtt; +#ifdef CURLDEBUG + infof(data, "%s (from %s) (next is %s)", + statenames[state], + statenames[mqtt->state], + (state == MQTT_FIRST)? statenames[nextstate] : ""); +#endif + mqtt->state = state; + if(state == MQTT_FIRST) + mqtt->nextstate = nextstate; +} + + +static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + ssize_t nread; + size_t remlen; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + struct MQTT *mq = data->req.p.mqtt; + unsigned char packet; + + switch(mqtt->state) { +MQTT_SUBACK_COMING: + case MQTT_SUBACK_COMING: + result = mqtt_verify_suback(data); + if(result) + break; + + mqstate(data, MQTT_FIRST, MQTT_PUBWAIT); + break; + + case MQTT_SUBACK: + case MQTT_PUBWAIT: + /* we are expecting PUBLISH or SUBACK */ + packet = mq->firstbyte & 0xf0; + if(packet == MQTT_MSG_PUBLISH) + mqstate(data, MQTT_PUB_REMAIN, MQTT_NOSTATE); + else if(packet == MQTT_MSG_SUBACK) { + mqstate(data, MQTT_SUBACK_COMING, MQTT_NOSTATE); + goto MQTT_SUBACK_COMING; + } + else if(packet == MQTT_MSG_DISCONNECT) { + infof(data, "Got DISCONNECT"); + *done = TRUE; + goto end; + } + else { + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + + /* -- switched state -- */ + remlen = mq->remaining_length; + infof(data, "Remaining length: %zu bytes", remlen); + if(data->set.max_filesize && + (curl_off_t)remlen > data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + result = CURLE_FILESIZE_EXCEEDED; + goto end; + } + Curl_pgrsSetDownloadSize(data, remlen); + data->req.bytecount = 0; + data->req.size = remlen; + mq->npacket = remlen; /* get this many bytes */ + FALLTHROUGH(); + case MQTT_PUB_REMAIN: { + /* read rest of packet, but no more. Cap to buffer size */ + char buffer[4*1024]; + size_t rest = mq->npacket; + if(rest > sizeof(buffer)) + rest = sizeof(buffer); + result = Curl_read(data, sockfd, buffer, rest, &nread); + if(result) { + if(CURLE_AGAIN == result) { + infof(data, "EEEE AAAAGAIN"); + } + goto end; + } + if(!nread) { + infof(data, "server disconnected"); + result = CURLE_PARTIAL_FILE; + goto end; + } + + /* if QoS is set, message contains packet id */ + result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread); + if(result) + goto end; + + mq->npacket -= nread; + if(!mq->npacket) + /* no more PUBLISH payload, back to subscribe wait state */ + mqstate(data, MQTT_FIRST, MQTT_PUBWAIT); + break; + } + default: + DEBUGASSERT(NULL); /* illegal state */ + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } +end: + return result; +} + +static CURLcode mqtt_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + *done = FALSE; /* unconditionally */ + + result = mqtt_connect(data); + if(result) { + failf(data, "Error %d sending MQTT CONNECT request", result); + return result; + } + mqstate(data, MQTT_FIRST, MQTT_CONNACK); + return CURLE_OK; +} + +static CURLcode mqtt_done(struct Curl_easy *data, + CURLcode status, bool premature) +{ + struct MQTT *mq = data->req.p.mqtt; + (void)status; + (void)premature; + Curl_safefree(mq->sendleftovers); + Curl_dyn_free(&mq->recvbuf); + return CURLE_OK; +} + +static CURLcode mqtt_doing(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + struct MQTT *mq = data->req.p.mqtt; + ssize_t nread; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + unsigned char byte; + + *done = FALSE; + + if(mq->nsend) { + /* send the remainder of an outgoing packet */ + char *ptr = mq->sendleftovers; + result = mqtt_send(data, mq->sendleftovers, mq->nsend); + free(ptr); + if(result) + return result; + } + + infof(data, "mqtt_doing: state [%d]", (int) mqtt->state); + switch(mqtt->state) { + case MQTT_FIRST: + /* Read the initial byte only */ + result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread); + if(result) + break; + else if(!nread) { + failf(data, "Connection disconnected"); + *done = TRUE; + result = CURLE_RECV_ERROR; + break; + } + Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1); + /* remember the first byte */ + mq->npacket = 0; + mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE); + FALLTHROUGH(); + case MQTT_REMAINING_LENGTH: + do { + result = Curl_read(data, sockfd, (char *)&byte, 1, &nread); + if(!nread) + break; + Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1); + mq->pkt_hd[mq->npacket++] = byte; + } while((byte & 0x80) && (mq->npacket < 4)); + if(nread && (byte & 0x80)) + /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 + + 127 * 128^3 bytes. server tried to send more */ + result = CURLE_WEIRD_SERVER_REPLY; + if(result) + break; + mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL); + mq->npacket = 0; + if(mq->remaining_length) { + mqstate(data, mqtt->nextstate, MQTT_NOSTATE); + break; + } + mqstate(data, MQTT_FIRST, MQTT_FIRST); + + if(mq->firstbyte == MQTT_MSG_DISCONNECT) { + infof(data, "Got DISCONNECT"); + *done = TRUE; + } + break; + case MQTT_CONNACK: + result = mqtt_verify_connack(data); + if(result) + break; + + if(data->state.httpreq == HTTPREQ_POST) { + result = mqtt_publish(data); + if(!result) { + result = mqtt_disconnect(data); + *done = TRUE; + } + mqtt->nextstate = MQTT_FIRST; + } + else { + result = mqtt_subscribe(data); + if(!result) { + mqstate(data, MQTT_FIRST, MQTT_SUBACK); + } + } + break; + + case MQTT_SUBACK: + case MQTT_PUBWAIT: + case MQTT_PUB_REMAIN: + result = mqtt_read_publish(data, done); + break; + + default: + failf(data, "State not handled yet"); + *done = TRUE; + break; + } + + if(result == CURLE_AGAIN) + result = CURLE_OK; + return result; +} + +#endif /* CURL_DISABLE_MQTT */ diff --git a/lib/mqtt.h b/lib/mqtt.h new file mode 100644 index 0000000..99ab12a --- /dev/null +++ b/lib/mqtt.h @@ -0,0 +1,63 @@ +#ifndef HEADER_CURL_MQTT_H +#define HEADER_CURL_MQTT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Björn Stenberg, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifndef CURL_DISABLE_MQTT +extern const struct Curl_handler Curl_handler_mqtt; +#endif + +enum mqttstate { + MQTT_FIRST, /* 0 */ + MQTT_REMAINING_LENGTH, /* 1 */ + MQTT_CONNACK, /* 2 */ + MQTT_SUBACK, /* 3 */ + MQTT_SUBACK_COMING, /* 4 - the SUBACK remainder */ + MQTT_PUBWAIT, /* 5 - wait for publish */ + MQTT_PUB_REMAIN, /* 6 - wait for the remainder of the publish */ + + MQTT_NOSTATE /* 7 - never used an actual state */ +}; + +struct mqtt_conn { + enum mqttstate state; + enum mqttstate nextstate; /* switch to this after remaining length is + done */ + unsigned int packetid; +}; + +/* protocol-specific transfer-related data */ +struct MQTT { + char *sendleftovers; + size_t nsend; /* size of sendleftovers */ + + /* when receiving */ + size_t npacket; /* byte counter */ + unsigned char firstbyte; + size_t remaining_length; + struct dynbuf recvbuf; + unsigned char pkt_hd[4]; /* for decoding the arriving packet length */ +}; + +#endif /* HEADER_CURL_MQTT_H */ diff --git a/lib/multi.c b/lib/multi.c new file mode 100644 index 0000000..0926b0d --- /dev/null +++ b/lib/multi.c @@ -0,0 +1,3821 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "urldata.h" +#include "transfer.h" +#include "url.h" +#include "cfilters.h" +#include "connect.h" +#include "progress.h" +#include "easyif.h" +#include "share.h" +#include "psl.h" +#include "multiif.h" +#include "sendf.h" +#include "timeval.h" +#include "http.h" +#include "select.h" +#include "warnless.h" +#include "speedcheck.h" +#include "conncache.h" +#include "multihandle.h" +#include "sigpipe.h" +#include "vtls/vtls.h" +#include "http_proxy.h" +#include "http2.h" +#include "socketpair.h" +#include "socks.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97 + to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every + CURL handle takes 45-50 K memory, therefore this 3K are not significant. +*/ +#ifndef CURL_SOCKET_HASH_TABLE_SIZE +#define CURL_SOCKET_HASH_TABLE_SIZE 911 +#endif + +#ifndef CURL_CONNECTION_HASH_SIZE +#define CURL_CONNECTION_HASH_SIZE 97 +#endif + +#ifndef CURL_DNS_HASH_SIZE +#define CURL_DNS_HASH_SIZE 71 +#endif + +#define CURL_MULTI_HANDLE 0x000bab1e + +#ifdef DEBUGBUILD +/* On a debug build, we want to fail hard on multi handles that + * are not NULL, but no longer have the MAGIC touch. This gives + * us early warning on things only discovered by valgrind otherwise. */ +#define GOOD_MULTI_HANDLE(x) \ + (((x) && (x)->magic == CURL_MULTI_HANDLE)? TRUE: \ + (DEBUGASSERT(!(x)), FALSE)) +#else +#define GOOD_MULTI_HANDLE(x) \ + ((x) && (x)->magic == CURL_MULTI_HANDLE) +#endif + +static CURLMcode singlesocket(struct Curl_multi *multi, + struct Curl_easy *data); +static CURLMcode add_next_timeout(struct curltime now, + struct Curl_multi *multi, + struct Curl_easy *d); +static CURLMcode multi_timeout(struct Curl_multi *multi, + long *timeout_ms); +static void process_pending_handles(struct Curl_multi *multi); + +#ifdef DEBUGBUILD +static const char * const multi_statename[]={ + "INIT", + "PENDING", + "CONNECT", + "RESOLVING", + "CONNECTING", + "TUNNELING", + "PROTOCONNECT", + "PROTOCONNECTING", + "DO", + "DOING", + "DOING_MORE", + "DID", + "PERFORMING", + "RATELIMITING", + "DONE", + "COMPLETED", + "MSGSENT", +}; +#endif + +/* function pointer called once when switching TO a state */ +typedef void (*init_multistate_func)(struct Curl_easy *data); + +/* called in DID state, before PERFORMING state */ +static void before_perform(struct Curl_easy *data) +{ + data->req.chunk = FALSE; + Curl_pgrsTime(data, TIMER_PRETRANSFER); +} + +static void init_completed(struct Curl_easy *data) +{ + /* this is a completed transfer */ + + /* Important: reset the conn pointer so that we don't point to memory + that could be freed anytime */ + Curl_detach_connection(data); + Curl_expire_clear(data); /* stop all timers */ +} + +/* always use this function to change state, to make debugging easier */ +static void mstate(struct Curl_easy *data, CURLMstate state +#ifdef DEBUGBUILD + , int lineno +#endif +) +{ + CURLMstate oldstate = data->mstate; + static const init_multistate_func finit[MSTATE_LAST] = { + NULL, /* INIT */ + NULL, /* PENDING */ + Curl_init_CONNECT, /* CONNECT */ + NULL, /* RESOLVING */ + NULL, /* CONNECTING */ + NULL, /* TUNNELING */ + NULL, /* PROTOCONNECT */ + NULL, /* PROTOCONNECTING */ + NULL, /* DO */ + NULL, /* DOING */ + NULL, /* DOING_MORE */ + before_perform, /* DID */ + NULL, /* PERFORMING */ + NULL, /* RATELIMITING */ + NULL, /* DONE */ + init_completed, /* COMPLETED */ + NULL /* MSGSENT */ + }; + +#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) lineno; +#endif + + if(oldstate == state) + /* don't bother when the new state is the same as the old state */ + return; + + data->mstate = state; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(data->mstate >= MSTATE_PENDING && + data->mstate < MSTATE_COMPLETED) { + infof(data, + "STATE: %s => %s handle %p; line %d", + multi_statename[oldstate], multi_statename[data->mstate], + (void *)data, lineno); + } +#endif + + if(state == MSTATE_COMPLETED) { + /* changing to COMPLETED means there's one less easy handle 'alive' */ + DEBUGASSERT(data->multi->num_alive > 0); + data->multi->num_alive--; + } + + /* if this state has an init-function, run it */ + if(finit[state]) + finit[state](data); +} + +#ifndef DEBUGBUILD +#define multistate(x,y) mstate(x,y) +#else +#define multistate(x,y) mstate(x,y, __LINE__) +#endif + +/* + * We add one of these structs to the sockhash for each socket + */ + +struct Curl_sh_entry { + struct Curl_hash transfers; /* hash of transfers using this socket */ + unsigned int action; /* what combined action READ/WRITE this socket waits + for */ + unsigned int users; /* number of transfers using this */ + void *socketp; /* settable by users with curl_multi_assign() */ + unsigned int readers; /* this many transfers want to read */ + unsigned int writers; /* this many transfers want to write */ +}; + +/* look up a given socket in the socket hash, skip invalid sockets */ +static struct Curl_sh_entry *sh_getentry(struct Curl_hash *sh, + curl_socket_t s) +{ + if(s != CURL_SOCKET_BAD) { + /* only look for proper sockets */ + return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); + } + return NULL; +} + +#define TRHASH_SIZE 13 +static size_t trhash(void *key, size_t key_length, size_t slots_num) +{ + size_t keyval = (size_t)*(struct Curl_easy **)key; + (void) key_length; + + return (keyval % slots_num); +} + +static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) +{ + (void)k1_len; + (void)k2_len; + + return *(struct Curl_easy **)k1 == *(struct Curl_easy **)k2; +} + +static void trhash_dtor(void *nada) +{ + (void)nada; +} + +/* + * The sockhash has its own separate subhash in each entry that need to be + * safely destroyed first. + */ +static void sockhash_destroy(struct Curl_hash *h) +{ + struct Curl_hash_iterator iter; + struct Curl_hash_element *he; + + DEBUGASSERT(h); + Curl_hash_start_iterate(h, &iter); + he = Curl_hash_next_element(&iter); + while(he) { + struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr; + Curl_hash_destroy(&sh->transfers); + he = Curl_hash_next_element(&iter); + } + Curl_hash_destroy(h); +} + + +/* make sure this socket is present in the hash for this handle */ +static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh, + curl_socket_t s) +{ + struct Curl_sh_entry *there = sh_getentry(sh, s); + struct Curl_sh_entry *check; + + if(there) { + /* it is present, return fine */ + return there; + } + + /* not present, add it */ + check = calloc(1, sizeof(struct Curl_sh_entry)); + if(!check) + return NULL; /* major failure */ + + Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare, + trhash_dtor); + + /* make/add new hash entry */ + if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { + Curl_hash_destroy(&check->transfers); + free(check); + return NULL; /* major failure */ + } + + return check; /* things are good in sockhash land */ +} + + +/* delete the given socket + handle from the hash */ +static void sh_delentry(struct Curl_sh_entry *entry, + struct Curl_hash *sh, curl_socket_t s) +{ + Curl_hash_destroy(&entry->transfers); + + /* We remove the hash entry. This will end up in a call to + sh_freeentry(). */ + Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); +} + +/* + * free a sockhash entry + */ +static void sh_freeentry(void *freethis) +{ + struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; + + free(p); +} + +static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) +{ + (void) k1_len; (void) k2_len; + + return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2)); +} + +static size_t hash_fd(void *key, size_t key_length, size_t slots_num) +{ + curl_socket_t fd = *((curl_socket_t *) key); + (void) key_length; + + return (fd % slots_num); +} + +/* + * sh_init() creates a new socket hash and returns the handle for it. + * + * Quote from README.multi_socket: + * + * "Some tests at 7000 and 9000 connections showed that the socket hash lookup + * is somewhat of a bottle neck. Its current implementation may be a bit too + * limiting. It simply has a fixed-size array, and on each entry in the array + * it has a linked list with entries. So the hash only checks which list to + * scan through. The code I had used so for used a list with merely 7 slots + * (as that is what the DNS hash uses) but with 7000 connections that would + * make an average of 1000 nodes in each list to run through. I upped that to + * 97 slots (I believe a prime is suitable) and noticed a significant speed + * increase. I need to reconsider the hash implementation or use a rather + * large default value like this. At 9000 connections I was still below 10us + * per call." + * + */ +static void sh_init(struct Curl_hash *hash, int hashsize) +{ + Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare, + sh_freeentry); +} + +/* + * multi_addmsg() + * + * Called when a transfer is completed. Adds the given msg pointer to + * the list kept in the multi handle. + */ +static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg) +{ + Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg, + &msg->list); +} + +struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ + int chashsize, /* connection hash */ + int dnssize) /* dns hash */ +{ + struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi)); + + if(!multi) + return NULL; + + multi->magic = CURL_MULTI_HANDLE; + + Curl_init_dnscache(&multi->hostcache, dnssize); + + sh_init(&multi->sockhash, hashsize); + + if(Curl_conncache_init(&multi->conn_cache, chashsize)) + goto error; + + Curl_llist_init(&multi->msglist, NULL); + Curl_llist_init(&multi->pending, NULL); + Curl_llist_init(&multi->msgsent, NULL); + + multi->multiplexing = TRUE; + multi->max_concurrent_streams = 100; + +#ifdef USE_WINSOCK + multi->wsa_event = WSACreateEvent(); + if(multi->wsa_event == WSA_INVALID_EVENT) + goto error; +#else +#ifdef ENABLE_WAKEUP + if(wakeup_create(multi->wakeup_pair) < 0) { + multi->wakeup_pair[0] = CURL_SOCKET_BAD; + multi->wakeup_pair[1] = CURL_SOCKET_BAD; + } + else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 || + curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) { + wakeup_close(multi->wakeup_pair[0]); + wakeup_close(multi->wakeup_pair[1]); + multi->wakeup_pair[0] = CURL_SOCKET_BAD; + multi->wakeup_pair[1] = CURL_SOCKET_BAD; + } +#endif +#endif + + return multi; + +error: + + sockhash_destroy(&multi->sockhash); + Curl_hash_destroy(&multi->hostcache); + Curl_conncache_destroy(&multi->conn_cache); + free(multi); + return NULL; +} + +struct Curl_multi *curl_multi_init(void) +{ + return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, + CURL_CONNECTION_HASH_SIZE, + CURL_DNS_HASH_SIZE); +} + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data) +{ + if(!multi->warned) { + infof(data, "!!! WARNING !!!"); + infof(data, "This is a debug build of libcurl, " + "do not use in production."); + multi->warned = true; + } +} +#else +#define multi_warn_debug(x,y) Curl_nop_stmt +#endif + +/* returns TRUE if the easy handle is supposed to be present in the main link + list */ +static bool in_main_list(struct Curl_easy *data) +{ + return ((data->mstate != MSTATE_PENDING) && + (data->mstate != MSTATE_MSGSENT)); +} + +static void link_easy(struct Curl_multi *multi, + struct Curl_easy *data) +{ + /* We add the new easy entry last in the list. */ + data->next = NULL; /* end of the line */ + if(multi->easyp) { + struct Curl_easy *last = multi->easylp; + last->next = data; + data->prev = last; + multi->easylp = data; /* the new last node */ + } + else { + /* first node, make prev NULL! */ + data->prev = NULL; + multi->easylp = multi->easyp = data; /* both first and last */ + } +} + +/* unlink the given easy handle from the linked list of easy handles */ +static void unlink_easy(struct Curl_multi *multi, + struct Curl_easy *data) +{ + /* make the previous node point to our next */ + if(data->prev) + data->prev->next = data->next; + else + multi->easyp = data->next; /* point to first node */ + + /* make our next point to our previous node */ + if(data->next) + data->next->prev = data->prev; + else + multi->easylp = data->prev; /* point to last node */ + + data->prev = data->next = NULL; +} + + +CURLMcode curl_multi_add_handle(struct Curl_multi *multi, + struct Curl_easy *data) +{ + CURLMcode rc; + /* First, make some basic checks that the CURLM handle is a good handle */ + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + /* Verify that we got a somewhat good easy handle too */ + if(!GOOD_EASY_HANDLE(data)) + return CURLM_BAD_EASY_HANDLE; + + /* Prevent users from adding same easy handle more than once and prevent + adding to more than one multi stack */ + if(data->multi) + return CURLM_ADDED_ALREADY; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + if(multi->dead) { + /* a "dead" handle cannot get added transfers while any existing easy + handles are still alive - but if there are none alive anymore, it is + fine to start over and unmark the "deadness" of this handle */ + if(multi->num_alive) + return CURLM_ABORTED_BY_CALLBACK; + multi->dead = FALSE; + } + + /* Initialize timeout list for this handle */ + Curl_llist_init(&data->state.timeoutlist, NULL); + + /* + * No failure allowed in this function beyond this point. And no + * modification of easy nor multi handle allowed before this except for + * potential multi's connection cache growing which won't be undone in this + * function no matter what. + */ + if(data->set.errorbuffer) + data->set.errorbuffer[0] = 0; + + /* make the Curl_easy refer back to this multi handle - before Curl_expire() + is called. */ + data->multi = multi; + + /* Set the timeout for this handle to expire really soon so that it will + be taken care of even when this handle is added in the midst of operation + when only the curl_multi_socket() API is used. During that flow, only + sockets that time-out or have actions will be dealt with. Since this + handle has no action yet, we make sure it times out to get things to + happen. */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + /* A somewhat crude work-around for a little glitch in Curl_update_timer() + that happens if the lastcall time is set to the same time when the handle + is removed as when the next handle is added, as then the check in + Curl_update_timer() that prevents calling the application multiple times + with the same timer info will not trigger and then the new handle's + timeout will not be notified to the app. + + The work-around is thus simply to clear the 'lastcall' variable to force + Curl_update_timer() to always trigger a callback to the app when a new + easy handle is added */ + memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + + rc = Curl_update_timer(multi); + if(rc) + return rc; + + /* set the easy handle */ + multistate(data, MSTATE_INIT); + + /* for multi interface connections, we share DNS cache automatically if the + easy handle's one is currently not set. */ + if(!data->dns.hostcache || + (data->dns.hostcachetype == HCACHE_NONE)) { + data->dns.hostcache = &multi->hostcache; + data->dns.hostcachetype = HCACHE_MULTI; + } + + /* Point to the shared or multi handle connection cache */ + if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT))) + data->state.conn_cache = &data->share->conn_cache; + else + data->state.conn_cache = &multi->conn_cache; + data->state.lastconnect_id = -1; + +#ifdef USE_LIBPSL + /* Do the same for PSL. */ + if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL))) + data->psl = &data->share->psl; + else + data->psl = &multi->psl; +#endif + + link_easy(multi, data); + + /* increase the node-counter */ + multi->num_easy++; + + /* increase the alive-counter */ + multi->num_alive++; + + CONNCACHE_LOCK(data); + /* The closure handle only ever has default timeouts set. To improve the + state somewhat we clone the timeouts from each added handle so that the + closure handle always has the same timeouts as the most recently added + easy handle. */ + data->state.conn_cache->closure_handle->set.timeout = data->set.timeout; + data->state.conn_cache->closure_handle->set.server_response_timeout = + data->set.server_response_timeout; + data->state.conn_cache->closure_handle->set.no_signal = + data->set.no_signal; + data->id = data->state.conn_cache->next_easy_id++; + if(data->state.conn_cache->next_easy_id <= 0) + data->state.conn_cache->next_easy_id = 0; + CONNCACHE_UNLOCK(data); + + multi_warn_debug(multi, data); + + return CURLM_OK; +} + +#if 0 +/* Debug-function, used like this: + * + * Curl_hash_print(&multi->sockhash, debug_print_sock_hash); + * + * Enable the hash print function first by editing hash.c + */ +static void debug_print_sock_hash(void *p) +{ + struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; + + fprintf(stderr, " [readers %u][writers %u]", + sh->readers, sh->writers); +} +#endif + +static CURLcode multi_done(struct Curl_easy *data, + CURLcode status, /* an error if this is called + after an error was detected */ + bool premature) +{ + CURLcode result; + struct connectdata *conn = data->conn; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d", + multi_statename[data->mstate], + (int)status, (int)premature, data->state.done)); +#else + DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d", + (int)status, (int)premature, data->state.done)); +#endif + + if(data->state.done) + /* Stop if multi_done() has already been called */ + return CURLE_OK; + + /* Stop the resolver and free its own resources (but not dns_entry yet). */ + Curl_resolver_kill(data); + + /* Cleanup possible redirect junk */ + Curl_safefree(data->req.newurl); + Curl_safefree(data->req.location); + + switch(status) { + case CURLE_ABORTED_BY_CALLBACK: + case CURLE_READ_ERROR: + case CURLE_WRITE_ERROR: + /* When we're aborted due to a callback return code it basically have to + be counted as premature as there is trouble ahead if we don't. We have + many callbacks and protocols work differently, we could potentially do + this more fine-grained in the future. */ + premature = TRUE; + FALLTHROUGH(); + default: + break; + } + + /* this calls the protocol-specific function pointer previously set */ + if(conn->handler->done) + result = conn->handler->done(data, status, premature); + else + result = status; + + if(CURLE_ABORTED_BY_CALLBACK != result) { + /* avoid this if we already aborted by callback to avoid this calling + another callback */ + int rc = Curl_pgrsDone(data); + if(!result && rc) + result = CURLE_ABORTED_BY_CALLBACK; + } + + /* Inform connection filters that this transfer is done */ + Curl_conn_ev_data_done(data, premature); + + process_pending_handles(data->multi); /* connection / multiplex */ + + Curl_safefree(data->state.ulbuf); + + Curl_client_cleanup(data); + + CONNCACHE_LOCK(data); + Curl_detach_connection(data); + if(CONN_INUSE(conn)) { + /* Stop if still used. */ + CONNCACHE_UNLOCK(data); + DEBUGF(infof(data, "Connection still in use %zu, " + "no more multi_done now!", + conn->easyq.size)); + return CURLE_OK; + } + + data->state.done = TRUE; /* called just now! */ + + if(conn->dns_entry) { + Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ + conn->dns_entry = NULL; + } + Curl_hostcache_prune(data); + + /* if data->set.reuse_forbid is TRUE, it means the libcurl client has + forced us to close this connection. This is ignored for requests taking + place in a NTLM/NEGOTIATE authentication handshake + + if conn->bits.close is TRUE, it means that the connection should be + closed in spite of all our efforts to be nice, due to protocol + restrictions in our or the server's end + + if premature is TRUE, it means this connection was said to be DONE before + the entire request operation is complete and thus we can't know in what + state it is for reusing, so we're forced to close it. In a perfect world + we can add code that keep track of if we really must close it here or not, + but currently we have no such detail knowledge. + */ + + data->state.recent_conn_id = conn->connection_id; + if((data->set.reuse_forbid +#if defined(USE_NTLM) + && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 || + conn->proxy_ntlm_state == NTLMSTATE_TYPE2) +#endif +#if defined(USE_SPNEGO) + && !(conn->http_negotiate_state == GSS_AUTHRECV || + conn->proxy_negotiate_state == GSS_AUTHRECV) +#endif + ) || conn->bits.close + || (premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) { + DEBUGF(infof(data, "multi_done, not reusing connection=%" + CURL_FORMAT_CURL_OFF_T ", forbid=%d" + ", close=%d, premature=%d, conn_multiplex=%d", + conn->connection_id, + data->set.reuse_forbid, conn->bits.close, premature, + Curl_conn_is_multiplex(conn, FIRSTSOCKET))); + connclose(conn, "disconnecting"); + Curl_conncache_remove_conn(data, conn, FALSE); + CONNCACHE_UNLOCK(data); + Curl_disconnect(data, conn, premature); + } + else { + char buffer[256]; + const char *host = +#ifndef CURL_DISABLE_PROXY + conn->bits.socksproxy ? + conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : +#endif + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname; + /* create string before returning the connection */ + curl_off_t connection_id = conn->connection_id; + msnprintf(buffer, sizeof(buffer), + "Connection #%" CURL_FORMAT_CURL_OFF_T " to host %s left intact", + connection_id, host); + /* the connection is no longer in use by this transfer */ + CONNCACHE_UNLOCK(data); + if(Curl_conncache_return_conn(data, conn)) { + /* remember the most recently used connection */ + data->state.lastconnect_id = connection_id; + data->state.recent_conn_id = connection_id; + infof(data, "%s", buffer); + } + else + data->state.lastconnect_id = -1; + } + + Curl_safefree(data->state.buffer); + return result; +} + +static int close_connect_only(struct Curl_easy *data, + struct connectdata *conn, void *param) +{ + (void)param; + if(data->state.lastconnect_id != conn->connection_id) + return 0; + + if(!conn->connect_only) + return 1; + + connclose(conn, "Removing connect-only easy handle"); + + return 1; +} + +CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, + struct Curl_easy *data) +{ + struct Curl_easy *easy = data; + bool premature; + struct Curl_llist_element *e; + CURLMcode rc; + + /* First, make some basic checks that the CURLM handle is a good handle */ + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + /* Verify that we got a somewhat good easy handle too */ + if(!GOOD_EASY_HANDLE(data)) + return CURLM_BAD_EASY_HANDLE; + + /* Prevent users from trying to remove same easy handle more than once */ + if(!data->multi) + return CURLM_OK; /* it is already removed so let's say it is fine! */ + + /* Prevent users from trying to remove an easy handle from the wrong multi */ + if(data->multi != multi) + return CURLM_BAD_EASY_HANDLE; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE; + + /* If the 'state' is not INIT or COMPLETED, we might need to do something + nice to put the easy_handle in a good known state when this returns. */ + if(premature) { + /* this handle is "alive" so we need to count down the total number of + alive connections when this is removed */ + multi->num_alive--; + } + + if(data->conn && + data->mstate > MSTATE_DO && + data->mstate < MSTATE_COMPLETED) { + /* Set connection owner so that the DONE function closes it. We can + safely do this here since connection is killed. */ + streamclose(data->conn, "Removed with partial response"); + } + + if(data->conn) { + /* multi_done() clears the association between the easy handle and the + connection. + + Note that this ignores the return code simply because there's + nothing really useful to do with it anyway! */ + (void)multi_done(data, data->result, premature); + } + + /* The timer must be shut down before data->multi is set to NULL, else the + timenode will remain in the splay tree after curl_easy_cleanup is + called. Do it after multi_done() in case that sets another time! */ + Curl_expire_clear(data); + + if(data->connect_queue.ptr) { + /* the handle is in the pending or msgsent lists, so go ahead and remove + it */ + if(data->mstate == MSTATE_PENDING) + Curl_llist_remove(&multi->pending, &data->connect_queue, NULL); + else + Curl_llist_remove(&multi->msgsent, &data->connect_queue, NULL); + } + if(in_main_list(data)) + unlink_easy(multi, data); + + if(data->dns.hostcachetype == HCACHE_MULTI) { + /* stop using the multi handle's DNS cache, *after* the possible + multi_done() call above */ + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; + } + + Curl_wildcard_dtor(&data->wildcard); + + /* change state without using multistate(), only to make singlesocket() do + what we want */ + data->mstate = MSTATE_COMPLETED; + + /* This ignores the return code even in case of problems because there's + nothing more to do about that, here */ + (void)singlesocket(multi, easy); /* to let the application know what sockets + that vanish with this handle */ + + /* Remove the association between the connection and the handle */ + Curl_detach_connection(data); + + if(data->set.connect_only && !data->multi_easy) { + /* This removes a handle that was part the multi interface that used + CONNECT_ONLY, that connection is now left alive but since this handle + has bits.close set nothing can use that transfer anymore and it is + forbidden from reuse. And this easy handle cannot find the connection + anymore once removed from the multi handle + + Better close the connection here, at once. + */ + struct connectdata *c; + curl_socket_t s; + s = Curl_getconnectinfo(data, &c); + if((s != CURL_SOCKET_BAD) && c) { + Curl_conncache_remove_conn(data, c, TRUE); + Curl_disconnect(data, c, TRUE); + } + } + + if(data->state.lastconnect_id != -1) { + /* Mark any connect-only connection for closure */ + Curl_conncache_foreach(data, data->state.conn_cache, + NULL, close_connect_only); + } + +#ifdef USE_LIBPSL + /* Remove the PSL association. */ + if(data->psl == &multi->psl) + data->psl = NULL; +#endif + + /* as this was using a shared connection cache we clear the pointer to that + since we're not part of that multi handle anymore */ + data->state.conn_cache = NULL; + + data->multi = NULL; /* clear the association to this multi handle */ + + /* make sure there's no pending message in the queue sent from this easy + handle */ + for(e = multi->msglist.head; e; e = e->next) { + struct Curl_message *msg = e->ptr; + + if(msg->extmsg.easy_handle == easy) { + Curl_llist_remove(&multi->msglist, e, NULL); + /* there can only be one from this specific handle */ + break; + } + } + + /* NOTE NOTE NOTE + We do not touch the easy handle here! */ + multi->num_easy--; /* one less to care about now */ + + process_pending_handles(multi); + + rc = Curl_update_timer(multi); + if(rc) + return rc; + return CURLM_OK; +} + +/* Return TRUE if the application asked for multiplexing */ +bool Curl_multiplex_wanted(const struct Curl_multi *multi) +{ + return (multi && (multi->multiplexing)); +} + +/* + * Curl_detach_connection() removes the given transfer from the connection. + * + * This is the only function that should clear data->conn. This will + * occasionally be called with the data->conn pointer already cleared. + */ +void Curl_detach_connection(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + if(conn) { + Curl_conn_ev_data_detach(conn, data); + Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL); + } + data->conn = NULL; +} + +/* + * Curl_attach_connection() attaches this transfer to this connection. + * + * This is the only function that should assign data->conn + */ +void Curl_attach_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + DEBUGASSERT(!data->conn); + DEBUGASSERT(conn); + data->conn = conn; + Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data, + &data->conn_queue); + if(conn->handler && conn->handler->attach) + conn->handler->attach(data, conn); + Curl_conn_ev_data_attach(conn, data); +} + +static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks) +{ + struct connectdata *conn = data->conn; + (void)socks; + /* Not using `conn->sockfd` as `Curl_setup_transfer()` initializes + * that *after* the connect. */ + if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) { + /* Default is to wait to something from the server */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0); + } + return GETSOCK_BLANK; +} + +static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks) +{ + struct connectdata *conn = data->conn; + if(conn && conn->handler->proto_getsock) + return conn->handler->proto_getsock(data, conn, socks); + else if(conn && conn->sockfd != CURL_SOCKET_BAD) { + /* Default is to wait to something from the server */ + socks[0] = conn->sockfd; + return GETSOCK_READSOCK(0); + } + return GETSOCK_BLANK; +} + +static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks) +{ + struct connectdata *conn = data->conn; + if(conn && conn->handler->domore_getsock) + return conn->handler->domore_getsock(data, conn, socks); + else if(conn && conn->sockfd != CURL_SOCKET_BAD) { + /* Default is that we want to send something to the server */ + socks[0] = conn->sockfd; + return GETSOCK_WRITESOCK(0); + } + return GETSOCK_BLANK; +} + +static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks) +{ + struct connectdata *conn = data->conn; + if(conn && conn->handler->doing_getsock) + return conn->handler->doing_getsock(data, conn, socks); + else if(conn && conn->sockfd != CURL_SOCKET_BAD) { + /* Default is that we want to send something to the server */ + socks[0] = conn->sockfd; + return GETSOCK_WRITESOCK(0); + } + return GETSOCK_BLANK; +} + +static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock) +{ + struct connectdata *conn = data->conn; + + if(!conn) + return GETSOCK_BLANK; + else if(conn->handler->perform_getsock) + return conn->handler->perform_getsock(data, conn, sock); + else { + /* Default is to obey the data->req.keepon flags for send/recv */ + int bitmap = GETSOCK_BLANK; + unsigned sockindex = 0; + if(CURL_WANT_RECV(data)) { + DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); + bitmap |= GETSOCK_READSOCK(sockindex); + sock[sockindex] = conn->sockfd; + } + + if(CURL_WANT_SEND(data)) { + if((conn->sockfd != conn->writesockfd) || + bitmap == GETSOCK_BLANK) { + /* only if they are not the same socket and we have a readable + one, we increase index */ + if(bitmap != GETSOCK_BLANK) + sockindex++; /* increase index if we need two entries */ + + DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); + sock[sockindex] = conn->writesockfd; + } + bitmap |= GETSOCK_WRITESOCK(sockindex); + } + return bitmap; + } +} + +/* Initializes `poll_set` with the current socket poll actions needed + * for transfer `data`. */ +static void multi_getsock(struct Curl_easy *data, + struct easy_pollset *ps) +{ + /* The no connection case can happen when this is called from + curl_multi_remove_handle() => singlesocket() => multi_getsock(). + */ + Curl_pollset_reset(data, ps); + if(!data->conn) + return; + + switch(data->mstate) { + case MSTATE_INIT: + case MSTATE_PENDING: + case MSTATE_CONNECT: + /* nothing to poll for yet */ + break; + + case MSTATE_RESOLVING: + Curl_pollset_add_socks(data, ps, Curl_resolv_getsock); + /* connection filters are not involved in this phase */ + break; + + case MSTATE_CONNECTING: + case MSTATE_TUNNELING: + Curl_pollset_add_socks(data, ps, connecting_getsock); + Curl_conn_adjust_pollset(data, ps); + break; + + case MSTATE_PROTOCONNECT: + case MSTATE_PROTOCONNECTING: + Curl_pollset_add_socks(data, ps, protocol_getsock); + Curl_conn_adjust_pollset(data, ps); + break; + + case MSTATE_DO: + case MSTATE_DOING: + Curl_pollset_add_socks(data, ps, doing_getsock); + Curl_conn_adjust_pollset(data, ps); + break; + + case MSTATE_DOING_MORE: + Curl_pollset_add_socks(data, ps, domore_getsock); + Curl_conn_adjust_pollset(data, ps); + break; + + case MSTATE_DID: /* same as PERFORMING in regard to polling */ + case MSTATE_PERFORMING: + Curl_pollset_add_socks(data, ps, perform_getsock); + Curl_conn_adjust_pollset(data, ps); + break; + + case MSTATE_RATELIMITING: + /* we need to let time pass, ignore socket(s) */ + break; + + case MSTATE_DONE: + case MSTATE_COMPLETED: + case MSTATE_MSGSENT: + /* nothing more to poll for */ + break; + + default: + failf(data, "multi_getsock: unexpected multi state %d", data->mstate); + DEBUGASSERT(0); + break; + } +} + +CURLMcode curl_multi_fdset(struct Curl_multi *multi, + fd_set *read_fd_set, fd_set *write_fd_set, + fd_set *exc_fd_set, int *max_fd) +{ + /* Scan through all the easy handles to get the file descriptors set. + Some easy handles may not have connected to the remote host yet, + and then we must make sure that is done. */ + struct Curl_easy *data; + int this_max_fd = -1; + struct easy_pollset ps; + unsigned int i; + (void)exc_fd_set; /* not used */ + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + memset(&ps, 0, sizeof(ps)); + for(data = multi->easyp; data; data = data->next) { + multi_getsock(data, &ps); + + for(i = 0; i < ps.num; i++) { + if(!FDSET_SOCK(ps.sockets[i])) + /* pretend it doesn't exist */ + continue; + if(ps.actions[i] & CURL_POLL_IN) + FD_SET(ps.sockets[i], read_fd_set); + if(ps.actions[i] & CURL_POLL_OUT) + FD_SET(ps.sockets[i], write_fd_set); + if((int)ps.sockets[i] > this_max_fd) + this_max_fd = (int)ps.sockets[i]; + } + } + + *max_fd = this_max_fd; + + return CURLM_OK; +} + +#ifdef USE_WINSOCK +/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets can't + * be reset this way because an empty datagram would be sent. #9203 + * + * "On Windows the internal state of FD_WRITE as returned from + * WSAEnumNetworkEvents is only reset after successful send()." + */ +static void reset_socket_fdwrite(curl_socket_t s) +{ + int t; + int l = (int)sizeof(t); + if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM) + send(s, NULL, 0, 0); +} +#endif + +#define NUM_POLLS_ON_STACK 10 + +static CURLMcode multi_wait(struct Curl_multi *multi, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret, + bool extrawait, /* when no socket, wait */ + bool use_wakeup) +{ + struct Curl_easy *data; + struct easy_pollset ps; + size_t i; + unsigned int nfds = 0; + unsigned int curlfds; + long timeout_internal; + int retcode = 0; + struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; + struct pollfd *ufds = &a_few_on_stack[0]; + bool ufds_malloc = FALSE; +#ifdef USE_WINSOCK + WSANETWORKEVENTS wsa_events; + DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT); +#endif +#ifndef ENABLE_WAKEUP + (void)use_wakeup; +#endif + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + if(timeout_ms < 0) + return CURLM_BAD_FUNCTION_ARGUMENT; + + /* Count up how many fds we have from the multi handle */ + memset(&ps, 0, sizeof(ps)); + for(data = multi->easyp; data; data = data->next) { + multi_getsock(data, &ps); + nfds += ps.num; + } + + /* If the internally desired timeout is actually shorter than requested from + the outside, then use the shorter time! But only if the internal timer + is actually larger than -1! */ + (void)multi_timeout(multi, &timeout_internal); + if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms)) + timeout_ms = (int)timeout_internal; + + curlfds = nfds; /* number of internal file descriptors */ + nfds += extra_nfds; /* add the externally provided ones */ + +#ifdef ENABLE_WAKEUP +#ifdef USE_WINSOCK + if(use_wakeup) { +#else + if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { +#endif + ++nfds; + } +#endif + + if(nfds > NUM_POLLS_ON_STACK) { + /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes + big, so at 2^29 sockets this value might wrap. When a process gets + the capability to actually handle over 500 million sockets this + calculation needs a integer overflow check. */ + ufds = malloc(nfds * sizeof(struct pollfd)); + if(!ufds) + return CURLM_OUT_OF_MEMORY; + ufds_malloc = TRUE; + } + nfds = 0; + + /* only do the second loop if we found descriptors in the first stage run + above */ + + if(curlfds) { + /* Add the curl handles to our pollfds first */ + for(data = multi->easyp; data; data = data->next) { + multi_getsock(data, &ps); + + for(i = 0; i < ps.num; i++) { + struct pollfd *ufd = &ufds[nfds++]; +#ifdef USE_WINSOCK + long mask = 0; +#endif + ufd->fd = ps.sockets[i]; + ufd->events = 0; + if(ps.actions[i] & CURL_POLL_IN) { +#ifdef USE_WINSOCK + mask |= FD_READ|FD_ACCEPT|FD_CLOSE; +#endif + ufd->events |= POLLIN; + } + if(ps.actions[i] & CURL_POLL_OUT) { +#ifdef USE_WINSOCK + mask |= FD_WRITE|FD_CONNECT|FD_CLOSE; + reset_socket_fdwrite(ps.sockets[i]); +#endif + ufd->events |= POLLOUT; + } +#ifdef USE_WINSOCK + if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) { + if(ufds_malloc) + free(ufds); + return CURLM_INTERNAL_ERROR; + } +#endif + } + } + } + + /* Add external file descriptions from poll-like struct curl_waitfd */ + for(i = 0; i < extra_nfds; i++) { +#ifdef USE_WINSOCK + long mask = 0; + if(extra_fds[i].events & CURL_WAIT_POLLIN) + mask |= FD_READ|FD_ACCEPT|FD_CLOSE; + if(extra_fds[i].events & CURL_WAIT_POLLPRI) + mask |= FD_OOB; + if(extra_fds[i].events & CURL_WAIT_POLLOUT) { + mask |= FD_WRITE|FD_CONNECT|FD_CLOSE; + reset_socket_fdwrite(extra_fds[i].fd); + } + if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) { + if(ufds_malloc) + free(ufds); + return CURLM_INTERNAL_ERROR; + } +#endif + ufds[nfds].fd = extra_fds[i].fd; + ufds[nfds].events = 0; + if(extra_fds[i].events & CURL_WAIT_POLLIN) + ufds[nfds].events |= POLLIN; + if(extra_fds[i].events & CURL_WAIT_POLLPRI) + ufds[nfds].events |= POLLPRI; + if(extra_fds[i].events & CURL_WAIT_POLLOUT) + ufds[nfds].events |= POLLOUT; + ++nfds; + } + +#ifdef ENABLE_WAKEUP +#ifndef USE_WINSOCK + if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { + ufds[nfds].fd = multi->wakeup_pair[0]; + ufds[nfds].events = POLLIN; + ++nfds; + } +#endif +#endif + +#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK) + if(nfds || use_wakeup) { +#else + if(nfds) { +#endif + int pollrc; +#ifdef USE_WINSOCK + if(nfds) + pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */ + else + pollrc = 0; +#else + pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */ +#endif + if(pollrc < 0) + return CURLM_UNRECOVERABLE_POLL; + + if(pollrc > 0) { + retcode = pollrc; +#ifdef USE_WINSOCK + } + else { /* now wait... if not ready during the pre-check (pollrc == 0) */ + WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE); + } + /* With WinSock, we have to run the following section unconditionally + to call WSAEventSelect(fd, event, 0) on all the sockets */ + { +#endif + /* copy revents results from the poll to the curl_multi_wait poll + struct, the bit values of the actual underlying poll() implementation + may not be the same as the ones in the public libcurl API! */ + for(i = 0; i < extra_nfds; i++) { + unsigned r = ufds[curlfds + i].revents; + unsigned short mask = 0; +#ifdef USE_WINSOCK + curl_socket_t s = extra_fds[i].fd; + wsa_events.lNetworkEvents = 0; + if(WSAEnumNetworkEvents(s, NULL, &wsa_events) == 0) { + if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE)) + mask |= CURL_WAIT_POLLIN; + if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE)) + mask |= CURL_WAIT_POLLOUT; + if(wsa_events.lNetworkEvents & FD_OOB) + mask |= CURL_WAIT_POLLPRI; + if(ret && !pollrc && wsa_events.lNetworkEvents) + retcode++; + } + WSAEventSelect(s, multi->wsa_event, 0); + if(!pollrc) { + extra_fds[i].revents = mask; + continue; + } +#endif + if(r & POLLIN) + mask |= CURL_WAIT_POLLIN; + if(r & POLLOUT) + mask |= CURL_WAIT_POLLOUT; + if(r & POLLPRI) + mask |= CURL_WAIT_POLLPRI; + extra_fds[i].revents = mask; + } + +#ifdef USE_WINSOCK + /* Count up all our own sockets that had activity, + and remove them from the event. */ + if(curlfds) { + + for(data = multi->easyp; data; data = data->next) { + multi_getsock(data, &ps); + + for(i = 0; i < ps.num; i++) { + wsa_events.lNetworkEvents = 0; + if(WSAEnumNetworkEvents(ps.sockets[i], NULL, + &wsa_events) == 0) { + if(ret && !pollrc && wsa_events.lNetworkEvents) + retcode++; + } + WSAEventSelect(ps.sockets[i], multi->wsa_event, 0); + } + } + } + + WSAResetEvent(multi->wsa_event); +#else +#ifdef ENABLE_WAKEUP + if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { + if(ufds[curlfds + extra_nfds].revents & POLLIN) { + char buf[64]; + ssize_t nread; + while(1) { + /* the reading socket is non-blocking, try to read + data from it until it receives an error (except EINTR). + In normal cases it will get EAGAIN or EWOULDBLOCK + when there is no more data, breaking the loop. */ + nread = wakeup_read(multi->wakeup_pair[0], buf, sizeof(buf)); + if(nread <= 0) { + if(nread < 0 && EINTR == SOCKERRNO) + continue; + break; + } + } + /* do not count the wakeup socket into the returned value */ + retcode--; + } + } +#endif +#endif + } + } + + if(ufds_malloc) + free(ufds); + if(ret) + *ret = retcode; +#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK) + if(extrawait && !nfds && !use_wakeup) { +#else + if(extrawait && !nfds) { +#endif + long sleep_ms = 0; + + /* Avoid busy-looping when there's nothing particular to wait for */ + if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) { + if(sleep_ms > timeout_ms) + sleep_ms = timeout_ms; + /* when there are no easy handles in the multi, this holds a -1 + timeout */ + else if(sleep_ms < 0) + sleep_ms = timeout_ms; + Curl_wait_ms(sleep_ms); + } + } + + return CURLM_OK; +} + +CURLMcode curl_multi_wait(struct Curl_multi *multi, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret) +{ + return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE, + FALSE); +} + +CURLMcode curl_multi_poll(struct Curl_multi *multi, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret) +{ + return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE, + TRUE); +} + +CURLMcode curl_multi_wakeup(struct Curl_multi *multi) +{ + /* this function is usually called from another thread, + it has to be careful only to access parts of the + Curl_multi struct that are constant */ + + /* GOOD_MULTI_HANDLE can be safely called */ + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + +#ifdef ENABLE_WAKEUP +#ifdef USE_WINSOCK + if(WSASetEvent(multi->wsa_event)) + return CURLM_OK; +#else + /* the wakeup_pair variable is only written during init and cleanup, + making it safe to access from another thread after the init part + and before cleanup */ + if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) { + char buf[1]; + buf[0] = 1; + while(1) { + /* swrite() is not thread-safe in general, because concurrent calls + can have their messages interleaved, but in this case the content + of the messages does not matter, which makes it ok to call. + + The write socket is set to non-blocking, this way this function + cannot block, making it safe to call even from the same thread + that will call curl_multi_wait(). If swrite() returns that it + would block, it's considered successful because it means that + previous calls to this function will wake up the poll(). */ + if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) { + int err = SOCKERRNO; + int return_success; +#ifdef USE_WINSOCK + return_success = WSAEWOULDBLOCK == err; +#else + if(EINTR == err) + continue; + return_success = EWOULDBLOCK == err || EAGAIN == err; +#endif + if(!return_success) + return CURLM_WAKEUP_FAILURE; + } + return CURLM_OK; + } + } +#endif +#endif + return CURLM_WAKEUP_FAILURE; +} + +/* + * multi_ischanged() is called + * + * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND + * => CONNECT action. + * + * Set 'clear' to TRUE to have it also clear the state variable. + */ +static bool multi_ischanged(struct Curl_multi *multi, bool clear) +{ + bool retval = multi->recheckstate; + if(clear) + multi->recheckstate = FALSE; + return retval; +} + +/* + * Curl_multi_connchanged() is called to tell that there is a connection in + * this multi handle that has changed state (multiplexing become possible, the + * number of allowed streams changed or similar), and a subsequent use of this + * multi handle should move CONNECT_PEND handles back to CONNECT to have them + * retry. + */ +void Curl_multi_connchanged(struct Curl_multi *multi) +{ + multi->recheckstate = TRUE; +} + +CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, + struct Curl_easy *data, + struct connectdata *conn) +{ + CURLMcode rc; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + rc = curl_multi_add_handle(multi, data); + if(!rc) { + struct SingleRequest *k = &data->req; + + /* pass in NULL for 'conn' here since we don't want to init the + connection, only this transfer */ + Curl_init_do(data, NULL); + + /* take this handle to the perform state right away */ + multistate(data, MSTATE_PERFORMING); + Curl_attach_connection(data, conn); + k->keepon |= KEEP_RECV; /* setup to receive! */ + } + return rc; +} + +static CURLcode multi_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + DEBUGASSERT(conn); + DEBUGASSERT(conn->handler); + + if(conn->handler->do_it) + result = conn->handler->do_it(data, done); + + return result; +} + +/* + * multi_do_more() is called during the DO_MORE multi state. It is basically a + * second stage DO state which (wrongly) was introduced to support FTP's + * second connection. + * + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to + * DOING state there's more work to do! + */ + +static CURLcode multi_do_more(struct Curl_easy *data, int *complete) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + *complete = 0; + + if(conn->handler->do_more) + result = conn->handler->do_more(data, complete); + + return result; +} + +/* + * Check whether a timeout occurred, and handle it if it did + */ +static bool multi_handle_timeout(struct Curl_easy *data, + struct curltime *now, + bool *stream_error, + CURLcode *result, + bool connect_timeout) +{ + timediff_t timeout_ms; + timeout_ms = Curl_timeleft(data, now, connect_timeout); + + if(timeout_ms < 0) { + /* Handle timed out */ + if(data->mstate == MSTATE_RESOLVING) + failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T + " milliseconds", + Curl_timediff(*now, data->progress.t_startsingle)); + else if(data->mstate == MSTATE_CONNECTING) + failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T + " milliseconds", + Curl_timediff(*now, data->progress.t_startsingle)); + else { + struct SingleRequest *k = &data->req; + if(k->size != -1) { + failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T + " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" + CURL_FORMAT_CURL_OFF_T " bytes received", + Curl_timediff(*now, data->progress.t_startsingle), + k->bytecount, k->size); + } + else { + failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T + " milliseconds with %" CURL_FORMAT_CURL_OFF_T + " bytes received", + Curl_timediff(*now, data->progress.t_startsingle), + k->bytecount); + } + } + + /* Force connection closed if the connection has indeed been used */ + if(data->mstate > MSTATE_DO) { + streamclose(data->conn, "Disconnected with pending data"); + *stream_error = TRUE; + } + *result = CURLE_OPERATION_TIMEDOUT; + (void)multi_done(data, *result, TRUE); + } + + return (timeout_ms < 0); +} + +/* + * We are doing protocol-specific connecting and this is being called over and + * over from the multi interface until the connection phase is done on + * protocol layer. + */ + +static CURLcode protocol_connecting(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + if(conn && conn->handler->connecting) { + *done = FALSE; + result = conn->handler->connecting(data, done); + } + else + *done = TRUE; + + return result; +} + +/* + * We are DOING this is being called over and over from the multi interface + * until the DOING phase is done on protocol layer. + */ + +static CURLcode protocol_doing(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + if(conn && conn->handler->doing) { + *done = FALSE; + result = conn->handler->doing(data, done); + } + else + *done = TRUE; + + return result; +} + +/* + * We have discovered that the TCP connection has been successful, we can now + * proceed with some action. + * + */ +static CURLcode protocol_connect(struct Curl_easy *data, + bool *protocol_done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + DEBUGASSERT(conn); + DEBUGASSERT(protocol_done); + + *protocol_done = FALSE; + + if(Curl_conn_is_connected(conn, FIRSTSOCKET) + && conn->bits.protoconnstart) { + /* We already are connected, get back. This may happen when the connect + worked fine in the first call, like when we connect to a local server + or proxy. Note that we don't know if the protocol is actually done. + + Unless this protocol doesn't have any protocol-connect callback, as + then we know we're done. */ + if(!conn->handler->connecting) + *protocol_done = TRUE; + + return CURLE_OK; + } + + if(!conn->bits.protoconnstart) { + if(conn->handler->connect_it) { + /* is there a protocol-specific connect() procedure? */ + + /* Call the protocol-specific connect function */ + result = conn->handler->connect_it(data, protocol_done); + } + else + *protocol_done = TRUE; + + /* it has started, possibly even completed but that knowledge isn't stored + in this bit! */ + if(!result) + conn->bits.protoconnstart = TRUE; + } + + return result; /* pass back status */ +} + +/* + * readrewind() rewinds the read stream. This is typically used for HTTP + * POST/PUT with multi-pass authentication when a sending was denied and a + * resend is necessary. + */ +static CURLcode readrewind(struct Curl_easy *data) +{ + curl_mimepart *mimepart = &data->set.mimepost; + DEBUGASSERT(data->conn); + + data->state.rewindbeforesend = FALSE; /* we rewind now */ + + /* explicitly switch off sending data on this connection now since we are + about to restart a new transfer and thus we want to avoid inadvertently + sending more data on the existing connection until the next transfer + starts */ + data->req.keepon &= ~KEEP_SEND; + + /* We have sent away data. If not using CURLOPT_POSTFIELDS or + CURLOPT_HTTPPOST, call app to rewind + */ +#ifndef CURL_DISABLE_HTTP + if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) { + if(data->state.mimepost) + mimepart = data->state.mimepost; + } +#endif + if(data->set.postfields || + (data->state.httpreq == HTTPREQ_GET) || + (data->state.httpreq == HTTPREQ_HEAD)) + ; /* no need to rewind */ + else if(data->state.httpreq == HTTPREQ_POST_MIME || + data->state.httpreq == HTTPREQ_POST_FORM) { + CURLcode result = Curl_mime_rewind(mimepart); + if(result) { + failf(data, "Cannot rewind mime/post data"); + return result; + } + } + else { + if(data->set.seek_func) { + int err; + + Curl_set_in_callback(data, true); + err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET); + Curl_set_in_callback(data, false); + if(err) { + failf(data, "seek callback returned error %d", (int)err); + return CURLE_SEND_FAIL_REWIND; + } + } + else if(data->set.ioctl_func) { + curlioerr err; + + Curl_set_in_callback(data, true); + err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD, + data->set.ioctl_client); + Curl_set_in_callback(data, false); + infof(data, "the ioctl callback returned %d", (int)err); + + if(err) { + failf(data, "ioctl callback returned error %d", (int)err); + return CURLE_SEND_FAIL_REWIND; + } + } + else { + /* If no CURLOPT_READFUNCTION is used, we know that we operate on a + given FILE * stream and we can actually attempt to rewind that + ourselves with fseek() */ + if(data->state.fread_func == (curl_read_callback)fread) { + if(-1 != fseek(data->state.in, 0, SEEK_SET)) + /* successful rewind */ + return CURLE_OK; + } + + /* no callback set or failure above, makes us fail at once */ + failf(data, "necessary data rewind wasn't possible"); + return CURLE_SEND_FAIL_REWIND; + } + } + return CURLE_OK; +} + +/* + * Curl_preconnect() is called immediately before a connect starts. When a + * redirect is followed, this is then called multiple times during a single + * transfer. + */ +CURLcode Curl_preconnect(struct Curl_easy *data) +{ + if(!data->state.buffer) { + data->state.buffer = malloc(data->set.buffer_size + 1); + if(!data->state.buffer) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +static void set_in_callback(struct Curl_multi *multi, bool value) +{ + multi->in_callback = value; +} + +static CURLMcode multi_runsingle(struct Curl_multi *multi, + struct curltime *nowp, + struct Curl_easy *data) +{ + struct Curl_message *msg = NULL; + bool connected; + bool async; + bool protocol_connected = FALSE; + bool dophase_done = FALSE; + bool done = FALSE; + CURLMcode rc; + CURLcode result = CURLE_OK; + timediff_t recv_timeout_ms; + timediff_t send_timeout_ms; + int control; + + if(!GOOD_EASY_HANDLE(data)) + return CURLM_BAD_EASY_HANDLE; + + if(multi->dead) { + /* a multi-level callback returned error before, meaning every individual + transfer now has failed */ + result = CURLE_ABORTED_BY_CALLBACK; + Curl_posttransfer(data); + multi_done(data, result, FALSE); + multistate(data, MSTATE_COMPLETED); + } + + multi_warn_debug(multi, data); + + do { + /* A "stream" here is a logical stream if the protocol can handle that + (HTTP/2), or the full connection for older protocols */ + bool stream_error = FALSE; + rc = CURLM_OK; + + if(multi_ischanged(multi, TRUE)) { + DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue")); + process_pending_handles(multi); /* multiplexed */ + } + + if(data->mstate > MSTATE_CONNECT && + data->mstate < MSTATE_COMPLETED) { + /* Make sure we set the connection's current owner */ + DEBUGASSERT(data->conn); + if(!data->conn) + return CURLM_INTERNAL_ERROR; + } + + if(data->conn && + (data->mstate >= MSTATE_CONNECT) && + (data->mstate < MSTATE_COMPLETED)) { + /* Check for overall operation timeout here but defer handling the + * connection timeout to later, to allow for a connection to be set up + * in the window since we last checked timeout. This prevents us + * tearing down a completed connection in the case where we were slow + * to check the timeout (e.g. process descheduled during this loop). + * We set connect_timeout=FALSE to do this. */ + + /* we need to wait for the connect state as only then is the start time + stored, but we must not check already completed handles */ + if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) { + /* Skip the statemachine and go directly to error handling section. */ + goto statemachine_end; + } + } + + switch(data->mstate) { + case MSTATE_INIT: + /* init this transfer. */ + result = Curl_pretransfer(data); + + if(!result) { + /* after init, go CONNECT */ + multistate(data, MSTATE_CONNECT); + *nowp = Curl_pgrsTime(data, TIMER_STARTOP); + rc = CURLM_CALL_MULTI_PERFORM; + } + break; + + case MSTATE_CONNECT: + /* Connect. We want to get a connection identifier filled in. */ + /* init this transfer. */ + result = Curl_preconnect(data); + if(result) + break; + + *nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE); + if(data->set.timeout) + Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT); + + if(data->set.connecttimeout) + Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT); + + result = Curl_connect(data, &async, &connected); + if(CURLE_NO_CONNECTION_AVAILABLE == result) { + /* There was no connection available. We will go to the pending + state and wait for an available connection. */ + multistate(data, MSTATE_PENDING); + + /* add this handle to the list of connect-pending handles */ + Curl_llist_insert_next(&multi->pending, multi->pending.tail, data, + &data->connect_queue); + /* unlink from the main list */ + unlink_easy(multi, data); + result = CURLE_OK; + break; + } + else if(data->state.previouslypending) { + /* this transfer comes from the pending queue so try move another */ + infof(data, "Transfer was pending, now try another"); + process_pending_handles(data->multi); + } + + if(!result) { + *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE); + if(async) + /* We're now waiting for an asynchronous name lookup */ + multistate(data, MSTATE_RESOLVING); + else { + /* after the connect has been sent off, go WAITCONNECT unless the + protocol connect is already done and we can go directly to + WAITDO or DO! */ + rc = CURLM_CALL_MULTI_PERFORM; + + if(connected) + multistate(data, MSTATE_PROTOCONNECT); + else { + multistate(data, MSTATE_CONNECTING); + } + } + } + break; + + case MSTATE_RESOLVING: + /* awaiting an asynch name resolve to complete */ + { + struct Curl_dns_entry *dns = NULL; + struct connectdata *conn = data->conn; + const char *hostname; + + DEBUGASSERT(conn); +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; + else +#endif + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(data, hostname, (int)conn->port); + + if(dns) { +#ifdef CURLRES_ASYNCH + data->state.async.dns = dns; + data->state.async.done = TRUE; +#endif + result = CURLE_OK; + infof(data, "Hostname '%s' was found in DNS cache", hostname); + } + + if(!dns) + result = Curl_resolv_check(data, &dns); + + /* Update sockets here, because the socket(s) may have been + closed and the application thus needs to be told, even if it + is likely that the same socket(s) will again be used further + down. If the name has not yet been resolved, it is likely + that new sockets have been opened in an attempt to contact + another resolver. */ + rc = singlesocket(multi, data); + if(rc) + return rc; + + if(dns) { + /* Perform the next step in the connection phase, and then move on + to the WAITCONNECT state */ + result = Curl_once_resolved(data, &connected); + + if(result) + /* if Curl_once_resolved() returns failure, the connection struct + is already freed and gone */ + data->conn = NULL; /* no more connection */ + else { + /* call again please so that we get the next socket setup */ + rc = CURLM_CALL_MULTI_PERFORM; + if(connected) + multistate(data, MSTATE_PROTOCONNECT); + else { + multistate(data, MSTATE_CONNECTING); + } + } + } + + if(result) { + /* failure detected */ + stream_error = TRUE; + break; + } + } + break; + +#ifndef CURL_DISABLE_HTTP + case MSTATE_TUNNELING: + /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ + DEBUGASSERT(data->conn); + result = Curl_http_connect(data, &protocol_connected); +#ifndef CURL_DISABLE_PROXY + if(data->conn->bits.proxy_connect_closed) { + rc = CURLM_CALL_MULTI_PERFORM; + /* connect back to proxy again */ + result = CURLE_OK; + multi_done(data, CURLE_OK, FALSE); + multistate(data, MSTATE_CONNECT); + } + else +#endif + if(!result) { + rc = CURLM_CALL_MULTI_PERFORM; + /* initiate protocol connect phase */ + multistate(data, MSTATE_PROTOCONNECT); + } + else + stream_error = TRUE; + break; +#endif + + case MSTATE_CONNECTING: + /* awaiting a completion of an asynch TCP connect */ + DEBUGASSERT(data->conn); + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected); + if(connected && !result) { + rc = CURLM_CALL_MULTI_PERFORM; + multistate(data, MSTATE_PROTOCONNECT); + } + else if(result) { + /* failure detected */ + Curl_posttransfer(data); + multi_done(data, result, TRUE); + stream_error = TRUE; + break; + } + break; + + case MSTATE_PROTOCONNECT: + if(data->state.rewindbeforesend) + result = readrewind(data); + + if(!result && data->conn->bits.reuse) { + /* ftp seems to hang when protoconnect on reused connection + * since we handle PROTOCONNECT in general inside the filers, it + * seems wrong to restart this on a reused connection. */ + multistate(data, MSTATE_DO); + rc = CURLM_CALL_MULTI_PERFORM; + break; + } + if(!result) + result = protocol_connect(data, &protocol_connected); + if(!result && !protocol_connected) { + /* switch to waiting state */ + multistate(data, MSTATE_PROTOCONNECTING); + rc = CURLM_CALL_MULTI_PERFORM; + } + else if(!result) { + /* protocol connect has completed, go WAITDO or DO */ + multistate(data, MSTATE_DO); + rc = CURLM_CALL_MULTI_PERFORM; + } + else { + /* failure detected */ + Curl_posttransfer(data); + multi_done(data, result, TRUE); + stream_error = TRUE; + } + break; + + case MSTATE_PROTOCONNECTING: + /* protocol-specific connect phase */ + result = protocol_connecting(data, &protocol_connected); + if(!result && protocol_connected) { + /* after the connect has completed, go WAITDO or DO */ + multistate(data, MSTATE_DO); + rc = CURLM_CALL_MULTI_PERFORM; + } + else if(result) { + /* failure detected */ + Curl_posttransfer(data); + multi_done(data, result, TRUE); + stream_error = TRUE; + } + break; + + case MSTATE_DO: + if(data->set.fprereq) { + int prereq_rc; + + /* call the prerequest callback function */ + Curl_set_in_callback(data, true); + prereq_rc = data->set.fprereq(data->set.prereq_userp, + data->info.conn_primary_ip, + data->info.conn_local_ip, + data->info.conn_primary_port, + data->info.conn_local_port); + Curl_set_in_callback(data, false); + if(prereq_rc != CURL_PREREQFUNC_OK) { + failf(data, "operation aborted by pre-request callback"); + /* failure in pre-request callback - don't do any other processing */ + result = CURLE_ABORTED_BY_CALLBACK; + Curl_posttransfer(data); + multi_done(data, result, FALSE); + stream_error = TRUE; + break; + } + } + + if(data->set.connect_only == 1) { + /* keep connection open for application to use the socket */ + connkeep(data->conn, "CONNECT_ONLY"); + multistate(data, MSTATE_DONE); + result = CURLE_OK; + rc = CURLM_CALL_MULTI_PERFORM; + } + else { + /* Perform the protocol's DO action */ + result = multi_do(data, &dophase_done); + + /* When multi_do() returns failure, data->conn might be NULL! */ + + if(!result) { + if(!dophase_done) { +#ifndef CURL_DISABLE_FTP + /* some steps needed for wildcard matching */ + if(data->state.wildcardmatch) { + struct WildcardData *wc = data->wildcard; + if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { + /* skip some states if it is important */ + multi_done(data, CURLE_OK, FALSE); + + /* if there's no connection left, skip the DONE state */ + multistate(data, data->conn ? + MSTATE_DONE : MSTATE_COMPLETED); + rc = CURLM_CALL_MULTI_PERFORM; + break; + } + } +#endif + /* DO was not completed in one function call, we must continue + DOING... */ + multistate(data, MSTATE_DOING); + rc = CURLM_CALL_MULTI_PERFORM; + } + + /* after DO, go DO_DONE... or DO_MORE */ + else if(data->conn->bits.do_more) { + /* we're supposed to do more, but we need to sit down, relax + and wait a little while first */ + multistate(data, MSTATE_DOING_MORE); + rc = CURLM_CALL_MULTI_PERFORM; + } + else { + /* we're done with the DO, now DID */ + multistate(data, MSTATE_DID); + rc = CURLM_CALL_MULTI_PERFORM; + } + } + else if((CURLE_SEND_ERROR == result) && + data->conn->bits.reuse) { + /* + * In this situation, a connection that we were trying to use + * may have unexpectedly died. If possible, send the connection + * back to the CONNECT phase so we can try again. + */ + char *newurl = NULL; + followtype follow = FOLLOW_NONE; + CURLcode drc; + + drc = Curl_retry_request(data, &newurl); + if(drc) { + /* a failure here pretty much implies an out of memory */ + result = drc; + stream_error = TRUE; + } + + Curl_posttransfer(data); + drc = multi_done(data, result, FALSE); + + /* When set to retry the connection, we must go back to the CONNECT + * state */ + if(newurl) { + if(!drc || (drc == CURLE_SEND_ERROR)) { + follow = FOLLOW_RETRY; + drc = Curl_follow(data, newurl, follow); + if(!drc) { + multistate(data, MSTATE_CONNECT); + rc = CURLM_CALL_MULTI_PERFORM; + result = CURLE_OK; + } + else { + /* Follow failed */ + result = drc; + } + } + else { + /* done didn't return OK or SEND_ERROR */ + result = drc; + } + } + else { + /* Have error handler disconnect conn if we can't retry */ + stream_error = TRUE; + } + free(newurl); + } + else { + /* failure detected */ + Curl_posttransfer(data); + if(data->conn) + multi_done(data, result, FALSE); + stream_error = TRUE; + } + } + break; + + case MSTATE_DOING: + /* we continue DOING until the DO phase is complete */ + DEBUGASSERT(data->conn); + result = protocol_doing(data, &dophase_done); + if(!result) { + if(dophase_done) { + /* after DO, go DO_DONE or DO_MORE */ + multistate(data, data->conn->bits.do_more? + MSTATE_DOING_MORE : MSTATE_DID); + rc = CURLM_CALL_MULTI_PERFORM; + } /* dophase_done */ + } + else { + /* failure detected */ + Curl_posttransfer(data); + multi_done(data, result, FALSE); + stream_error = TRUE; + } + break; + + case MSTATE_DOING_MORE: + /* + * When we are connected, DOING MORE and then go DID + */ + DEBUGASSERT(data->conn); + result = multi_do_more(data, &control); + + if(!result) { + if(control) { + /* if positive, advance to DO_DONE + if negative, go back to DOING */ + multistate(data, control == 1? + MSTATE_DID : MSTATE_DOING); + rc = CURLM_CALL_MULTI_PERFORM; + } + /* else + stay in DO_MORE */ + } + else { + /* failure detected */ + Curl_posttransfer(data); + multi_done(data, result, FALSE); + stream_error = TRUE; + } + break; + + case MSTATE_DID: + DEBUGASSERT(data->conn); + if(data->conn->bits.multiplex) + /* Check if we can move pending requests to send pipe */ + process_pending_handles(multi); /* multiplexed */ + + /* Only perform the transfer if there's a good socket to work with. + Having both BAD is a signal to skip immediately to DONE */ + if((data->conn->sockfd != CURL_SOCKET_BAD) || + (data->conn->writesockfd != CURL_SOCKET_BAD)) + multistate(data, MSTATE_PERFORMING); + else { +#ifndef CURL_DISABLE_FTP + if(data->state.wildcardmatch && + ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) { + data->wildcard->state = CURLWC_DONE; + } +#endif + multistate(data, MSTATE_DONE); + } + rc = CURLM_CALL_MULTI_PERFORM; + break; + + case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */ + DEBUGASSERT(data->conn); + /* if both rates are within spec, resume transfer */ + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, *nowp); + + if(result) { + if(!(data->conn->handler->flags & PROTOPT_DUAL) && + result != CURLE_HTTP2_STREAM) + streamclose(data->conn, "Transfer returned error"); + + Curl_posttransfer(data); + multi_done(data, result, TRUE); + } + else { + send_timeout_ms = 0; + if(data->set.max_send_speed) + send_timeout_ms = + Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + *nowp); + + recv_timeout_ms = 0; + if(data->set.max_recv_speed) + recv_timeout_ms = + Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + *nowp); + + if(!send_timeout_ms && !recv_timeout_ms) { + multistate(data, MSTATE_PERFORMING); + Curl_ratelimit(data, *nowp); + } + else if(send_timeout_ms >= recv_timeout_ms) + Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); + else + Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); + } + break; + + case MSTATE_PERFORMING: + { + char *newurl = NULL; + bool retry = FALSE; + DEBUGASSERT(data->state.buffer); + /* check if over send speed */ + send_timeout_ms = 0; + if(data->set.max_send_speed) + send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + *nowp); + + /* check if over recv speed */ + recv_timeout_ms = 0; + if(data->set.max_recv_speed) + recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + *nowp); + + if(send_timeout_ms || recv_timeout_ms) { + Curl_ratelimit(data, *nowp); + multistate(data, MSTATE_RATELIMITING); + if(send_timeout_ms >= recv_timeout_ms) + Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); + else + Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); + break; + } + + /* read/write data if it is ready to do so */ + result = Curl_readwrite(data, &done); + + if(done || (result == CURLE_RECV_ERROR)) { + /* If CURLE_RECV_ERROR happens early enough, we assume it was a race + * condition and the server closed the reused connection exactly when + * we wanted to use it, so figure out if that is indeed the case. + */ + CURLcode ret = Curl_retry_request(data, &newurl); + if(!ret) + retry = (newurl)?TRUE:FALSE; + else if(!result) + result = ret; + + if(retry) { + /* if we are to retry, set the result to OK and consider the + request as done */ + result = CURLE_OK; + done = TRUE; + } + } + else if((CURLE_HTTP2_STREAM == result) && + Curl_h2_http_1_1_error(data)) { + CURLcode ret = Curl_retry_request(data, &newurl); + + if(!ret) { + infof(data, "Downgrades to HTTP/1.1"); + streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1"); + data->state.httpwant = CURL_HTTP_VERSION_1_1; + /* clear the error message bit too as we ignore the one we got */ + data->state.errorbuf = FALSE; + if(!newurl) + /* typically for HTTP_1_1_REQUIRED error on first flight */ + newurl = strdup(data->state.url); + /* if we are to retry, set the result to OK and consider the request + as done */ + retry = TRUE; + result = CURLE_OK; + done = TRUE; + } + else + result = ret; + } + + if(result) { + /* + * The transfer phase returned error, we mark the connection to get + * closed to prevent being reused. This is because we can't possibly + * know if the connection is in a good shape or not now. Unless it is + * a protocol which uses two "channels" like FTP, as then the error + * happened in the data connection. + */ + + if(!(data->conn->handler->flags & PROTOPT_DUAL) && + result != CURLE_HTTP2_STREAM) + streamclose(data->conn, "Transfer returned error"); + + Curl_posttransfer(data); + multi_done(data, result, TRUE); + } + else if(done) { + + /* call this even if the readwrite function returned error */ + Curl_posttransfer(data); + + /* When we follow redirects or is set to retry the connection, we must + to go back to the CONNECT state */ + if(data->req.newurl || retry) { + followtype follow = FOLLOW_NONE; + if(!retry) { + /* if the URL is a follow-location and not just a retried request + then figure out the URL here */ + free(newurl); + newurl = data->req.newurl; + data->req.newurl = NULL; + follow = FOLLOW_REDIR; + } + else + follow = FOLLOW_RETRY; + (void)multi_done(data, CURLE_OK, FALSE); + /* multi_done() might return CURLE_GOT_NOTHING */ + result = Curl_follow(data, newurl, follow); + if(!result) { + multistate(data, MSTATE_CONNECT); + rc = CURLM_CALL_MULTI_PERFORM; + } + free(newurl); + } + else { + /* after the transfer is done, go DONE */ + + /* but first check to see if we got a location info even though we're + not following redirects */ + if(data->req.location) { + free(newurl); + newurl = data->req.location; + data->req.location = NULL; + result = Curl_follow(data, newurl, FOLLOW_FAKE); + free(newurl); + if(result) { + stream_error = TRUE; + result = multi_done(data, result, TRUE); + } + } + + if(!result) { + multistate(data, MSTATE_DONE); + rc = CURLM_CALL_MULTI_PERFORM; + } + } + } + else if(data->state.select_bits) { + /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer + won't get stuck on this transfer at the expense of other concurrent + transfers */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + break; + } + + case MSTATE_DONE: + /* this state is highly transient, so run another loop after this */ + rc = CURLM_CALL_MULTI_PERFORM; + + if(data->conn) { + CURLcode res; + + if(data->conn->bits.multiplex) + /* Check if we can move pending requests to connection */ + process_pending_handles(multi); /* multiplexing */ + + /* post-transfer command */ + res = multi_done(data, result, FALSE); + + /* allow a previously set error code take precedence */ + if(!result) + result = res; + } + +#ifndef CURL_DISABLE_FTP + if(data->state.wildcardmatch) { + if(data->wildcard->state != CURLWC_DONE) { + /* if a wildcard is set and we are not ending -> lets start again + with MSTATE_INIT */ + multistate(data, MSTATE_INIT); + break; + } + } +#endif + /* after we have DONE what we're supposed to do, go COMPLETED, and + it doesn't matter what the multi_done() returned! */ + multistate(data, MSTATE_COMPLETED); + break; + + case MSTATE_COMPLETED: + break; + + case MSTATE_PENDING: + case MSTATE_MSGSENT: + /* handles in these states should NOT be in this list */ + DEBUGASSERT(0); + break; + + default: + return CURLM_INTERNAL_ERROR; + } + + if(data->conn && + data->mstate >= MSTATE_CONNECT && + data->mstate < MSTATE_DO && + rc != CURLM_CALL_MULTI_PERFORM && + !multi_ischanged(multi, false)) { + /* We now handle stream timeouts if and only if this will be the last + * loop iteration. We only check this on the last iteration to ensure + * that if we know we have additional work to do immediately + * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before + * declaring the connection timed out as we may almost have a completed + * connection. */ + multi_handle_timeout(data, nowp, &stream_error, &result, TRUE); + } + +statemachine_end: + + if(data->mstate < MSTATE_COMPLETED) { + if(result) { + /* + * If an error was returned, and we aren't in completed state now, + * then we go to completed and consider this transfer aborted. + */ + + /* NOTE: no attempt to disconnect connections must be made + in the case blocks above - cleanup happens only here */ + + /* Check if we can move pending requests to send pipe */ + process_pending_handles(multi); /* connection */ + + if(data->conn) { + if(stream_error) { + /* Don't attempt to send data over a connection that timed out */ + bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; + struct connectdata *conn = data->conn; + + /* This is where we make sure that the conn pointer is reset. + We don't have to do this in every case block above where a + failure is detected */ + Curl_detach_connection(data); + + /* remove connection from cache */ + Curl_conncache_remove_conn(data, conn, TRUE); + + /* disconnect properly */ + Curl_disconnect(data, conn, dead_connection); + } + } + else if(data->mstate == MSTATE_CONNECT) { + /* Curl_connect() failed */ + (void)Curl_posttransfer(data); + } + + multistate(data, MSTATE_COMPLETED); + rc = CURLM_CALL_MULTI_PERFORM; + } + /* if there's still a connection to use, call the progress function */ + else if(data->conn && Curl_pgrsUpdate(data)) { + /* aborted due to progress callback return code must close the + connection */ + result = CURLE_ABORTED_BY_CALLBACK; + streamclose(data->conn, "Aborted by callback"); + + /* if not yet in DONE state, go there, otherwise COMPLETED */ + multistate(data, (data->mstate < MSTATE_DONE)? + MSTATE_DONE: MSTATE_COMPLETED); + rc = CURLM_CALL_MULTI_PERFORM; + } + } + + if(MSTATE_COMPLETED == data->mstate) { + if(data->set.fmultidone) { + /* signal via callback instead */ + data->set.fmultidone(data, result); + } + else { + /* now fill in the Curl_message with this info */ + msg = &data->msg; + + msg->extmsg.msg = CURLMSG_DONE; + msg->extmsg.easy_handle = data; + msg->extmsg.data.result = result; + + multi_addmsg(multi, msg); + DEBUGASSERT(!data->conn); + } + multistate(data, MSTATE_MSGSENT); + + /* add this handle to the list of msgsent handles */ + Curl_llist_insert_next(&multi->msgsent, multi->msgsent.tail, data, + &data->connect_queue); + /* unlink from the main list */ + unlink_easy(multi, data); + return CURLM_OK; + } + } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE)); + + data->result = result; + return rc; +} + + +CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) +{ + struct Curl_easy *data; + CURLMcode returncode = CURLM_OK; + struct Curl_tree *t; + struct curltime now = Curl_now(); + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + data = multi->easyp; + if(data) { + CURLMcode result; + bool nosig = data->set.no_signal; + SIGPIPE_VARIABLE(pipe_st); + sigpipe_ignore(data, &pipe_st); + /* Do the loop and only alter the signal ignore state if the next handle + has a different NO_SIGNAL state than the previous */ + do { + /* the current node might be unlinked in multi_runsingle(), get the next + pointer now */ + struct Curl_easy *datanext = data->next; + if(data->set.no_signal != nosig) { + sigpipe_restore(&pipe_st); + sigpipe_ignore(data, &pipe_st); + nosig = data->set.no_signal; + } + result = multi_runsingle(multi, &now, data); + if(result) + returncode = result; + data = datanext; /* operate on next handle */ + } while(data); + sigpipe_restore(&pipe_st); + } + + /* + * Simply remove all expired timers from the splay since handles are dealt + * with unconditionally by this function and curl_multi_timeout() requires + * that already passed/handled expire times are removed from the splay. + * + * It is important that the 'now' value is set at the entry of this function + * and not for the current time as it may have ticked a little while since + * then and then we risk this loop to remove timers that actually have not + * been handled! + */ + do { + multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); + if(t) + /* the removed may have another timeout in queue */ + (void)add_next_timeout(now, multi, t->payload); + + } while(t); + + *running_handles = multi->num_alive; + + if(CURLM_OK >= returncode) + returncode = Curl_update_timer(multi); + + return returncode; +} + +/* unlink_all_msgsent_handles() detaches all those easy handles from this + multi handle */ +static void unlink_all_msgsent_handles(struct Curl_multi *multi) +{ + struct Curl_llist_element *e = multi->msgsent.head; + if(e) { + struct Curl_easy *data = e->ptr; + DEBUGASSERT(data->mstate == MSTATE_MSGSENT); + data->multi = NULL; + } +} + +CURLMcode curl_multi_cleanup(struct Curl_multi *multi) +{ + struct Curl_easy *data; + struct Curl_easy *nextdata; + + if(GOOD_MULTI_HANDLE(multi)) { + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + multi->magic = 0; /* not good anymore */ + + unlink_all_msgsent_handles(multi); + process_pending_handles(multi); + /* First remove all remaining easy handles */ + data = multi->easyp; + while(data) { + nextdata = data->next; + if(!data->state.done && data->conn) + /* if DONE was never called for this handle */ + (void)multi_done(data, CURLE_OK, TRUE); + if(data->dns.hostcachetype == HCACHE_MULTI) { + /* clear out the usage of the shared DNS cache */ + Curl_hostcache_clean(data, data->dns.hostcache); + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; + } + + /* Clear the pointer to the connection cache */ + data->state.conn_cache = NULL; + data->multi = NULL; /* clear the association */ + +#ifdef USE_LIBPSL + if(data->psl == &multi->psl) + data->psl = NULL; +#endif + + data = nextdata; + } + + /* Close all the connections in the connection cache */ + Curl_conncache_close_all_connections(&multi->conn_cache); + + sockhash_destroy(&multi->sockhash); + Curl_conncache_destroy(&multi->conn_cache); + Curl_hash_destroy(&multi->hostcache); + Curl_psl_destroy(&multi->psl); + +#ifdef USE_WINSOCK + WSACloseEvent(multi->wsa_event); +#else +#ifdef ENABLE_WAKEUP + wakeup_close(multi->wakeup_pair[0]); + wakeup_close(multi->wakeup_pair[1]); +#endif +#endif + +#ifdef USE_SSL + Curl_free_multi_ssl_backend_data(multi->ssl_backend_data); +#endif + + free(multi); + + return CURLM_OK; + } + return CURLM_BAD_HANDLE; +} + +/* + * curl_multi_info_read() + * + * This function is the primary way for a multi/multi_socket application to + * figure out if a transfer has ended. We MUST make this function as fast as + * possible as it will be polled frequently and we MUST NOT scan any lists in + * here to figure out things. We must scale fine to thousands of handles and + * beyond. The current design is fully O(1). + */ + +CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue) +{ + struct Curl_message *msg; + + *msgs_in_queue = 0; /* default to none */ + + if(GOOD_MULTI_HANDLE(multi) && + !multi->in_callback && + Curl_llist_count(&multi->msglist)) { + /* there is one or more messages in the list */ + struct Curl_llist_element *e; + + /* extract the head of the list to return */ + e = multi->msglist.head; + + msg = e->ptr; + + /* remove the extracted entry */ + Curl_llist_remove(&multi->msglist, e, NULL); + + *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist)); + + return &msg->extmsg; + } + return NULL; +} + +/* + * singlesocket() checks what sockets we deal with and their "action state" + * and if we have a different state in any of those sockets from last time we + * call the callback accordingly. + */ +static CURLMcode singlesocket(struct Curl_multi *multi, + struct Curl_easy *data) +{ + struct easy_pollset cur_poll; + unsigned int i; + struct Curl_sh_entry *entry; + curl_socket_t s; + int rc; + + /* Fill in the 'current' struct with the state as it is now: what sockets to + supervise and for what actions */ + multi_getsock(data, &cur_poll); + + /* We have 0 .. N sockets already and we get to know about the 0 .. M + sockets we should have from now on. Detect the differences, remove no + longer supervised ones and add new ones */ + + /* walk over the sockets we got right now */ + for(i = 0; i < cur_poll.num; i++) { + unsigned char cur_action = cur_poll.actions[i]; + unsigned char last_action = 0; + int comboaction; + + s = cur_poll.sockets[i]; + + /* get it from the hash */ + entry = sh_getentry(&multi->sockhash, s); + if(entry) { + /* check if new for this transfer */ + unsigned int j; + for(j = 0; j< data->last_poll.num; j++) { + if(s == data->last_poll.sockets[j]) { + last_action = data->last_poll.actions[j]; + break; + } + } + } + else { + /* this is a socket we didn't have before, add it to the hash! */ + entry = sh_addentry(&multi->sockhash, s); + if(!entry) + /* fatal */ + return CURLM_OUT_OF_MEMORY; + } + if(last_action && (last_action != cur_action)) { + /* Socket was used already, but different action now */ + if(last_action & CURL_POLL_IN) + entry->readers--; + if(last_action & CURL_POLL_OUT) + entry->writers--; + if(cur_action & CURL_POLL_IN) + entry->readers++; + if(cur_action & CURL_POLL_OUT) + entry->writers++; + } + else if(!last_action) { + /* a new transfer using this socket */ + entry->users++; + if(cur_action & CURL_POLL_IN) + entry->readers++; + if(cur_action & CURL_POLL_OUT) + entry->writers++; + + /* add 'data' to the transfer hash on this socket! */ + if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */ + sizeof(struct Curl_easy *), data)) { + Curl_hash_destroy(&entry->transfers); + return CURLM_OUT_OF_MEMORY; + } + } + + comboaction = (entry->writers ? CURL_POLL_OUT : 0) | + (entry->readers ? CURL_POLL_IN : 0); + + /* socket existed before and has the same action set as before */ + if(last_action && ((int)entry->action == comboaction)) + /* same, continue */ + continue; + + if(multi->socket_cb) { + set_in_callback(multi, TRUE); + rc = multi->socket_cb(data, s, comboaction, multi->socket_userp, + entry->socketp); + + set_in_callback(multi, FALSE); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + } + + entry->action = comboaction; /* store the current action state */ + } + + /* Check for last_poll.sockets that no longer appear in cur_poll.sockets. + * Need to remove the easy handle from the multi->sockhash->transfers and + * remove multi->sockhash entry when this was the last transfer */ + for(i = 0; i< data->last_poll.num; i++) { + unsigned int j; + bool stillused = FALSE; + s = data->last_poll.sockets[i]; + for(j = 0; j < cur_poll.num; j++) { + if(s == cur_poll.sockets[j]) { + /* this is still supervised */ + stillused = TRUE; + break; + } + } + if(stillused) + continue; + + entry = sh_getentry(&multi->sockhash, s); + /* if this is NULL here, the socket has been closed and notified so + already by Curl_multi_closed() */ + if(entry) { + unsigned char oldactions = data->last_poll.actions[i]; + /* this socket has been removed. Decrease user count */ + entry->users--; + if(oldactions & CURL_POLL_OUT) + entry->writers--; + if(oldactions & CURL_POLL_IN) + entry->readers--; + if(!entry->users) { + if(multi->socket_cb) { + set_in_callback(multi, TRUE); + rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, + multi->socket_userp, entry->socketp); + set_in_callback(multi, FALSE); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + } + sh_delentry(entry, &multi->sockhash, s); + } + else { + /* still users, but remove this handle as a user of this socket */ + if(Curl_hash_delete(&entry->transfers, (char *)&data, + sizeof(struct Curl_easy *))) { + DEBUGASSERT(NULL); + } + } + } + } /* for loop over num */ + + /* Remember for next time */ + memcpy(&data->last_poll, &cur_poll, sizeof(data->last_poll)); + return CURLM_OK; +} + +CURLcode Curl_updatesocket(struct Curl_easy *data) +{ + if(singlesocket(data->multi, data)) + return CURLE_ABORTED_BY_CALLBACK; + return CURLE_OK; +} + + +/* + * Curl_multi_closed() + * + * Used by the connect code to tell the multi_socket code that one of the + * sockets we were using is about to be closed. This function will then + * remove it from the sockethash for this handle to make the multi_socket API + * behave properly, especially for the case when libcurl will create another + * socket again and it gets the same file descriptor number. + */ + +void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s) +{ + if(data) { + /* if there's still an easy handle associated with this connection */ + struct Curl_multi *multi = data->multi; + if(multi) { + /* this is set if this connection is part of a handle that is added to + a multi handle, and only then this is necessary */ + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); + + if(entry) { + int rc = 0; + if(multi->socket_cb) { + set_in_callback(multi, TRUE); + rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, + multi->socket_userp, entry->socketp); + set_in_callback(multi, FALSE); + } + + /* now remove it from the socket hash */ + sh_delentry(entry, &multi->sockhash, s); + if(rc == -1) + /* This just marks the multi handle as "dead" without returning an + error code primarily because this function is used from many + places where propagating an error back is tricky. */ + multi->dead = TRUE; + } + } + } +} + +/* + * add_next_timeout() + * + * Each Curl_easy has a list of timeouts. The add_next_timeout() is called + * when it has just been removed from the splay tree because the timeout has + * expired. This function is then to advance in the list to pick the next + * timeout to use (skip the already expired ones) and add this node back to + * the splay tree again. + * + * The splay tree only has each sessionhandle as a single node and the nearest + * timeout is used to sort it on. + */ +static CURLMcode add_next_timeout(struct curltime now, + struct Curl_multi *multi, + struct Curl_easy *d) +{ + struct curltime *tv = &d->state.expiretime; + struct Curl_llist *list = &d->state.timeoutlist; + struct Curl_llist_element *e; + struct time_node *node = NULL; + + /* move over the timeout list for this specific handle and remove all + timeouts that are now passed tense and store the next pending + timeout in *tv */ + for(e = list->head; e;) { + struct Curl_llist_element *n = e->next; + timediff_t diff; + node = (struct time_node *)e->ptr; + diff = Curl_timediff_us(node->time, now); + if(diff <= 0) + /* remove outdated entry */ + Curl_llist_remove(list, e, NULL); + else + /* the list is sorted so get out on the first mismatch */ + break; + e = n; + } + e = list->head; + if(!e) { + /* clear the expire times within the handles that we remove from the + splay tree */ + tv->tv_sec = 0; + tv->tv_usec = 0; + } + else { + /* copy the first entry to 'tv' */ + memcpy(tv, &node->time, sizeof(*tv)); + + /* Insert this node again into the splay. Keep the timer in the list in + case we need to recompute future timers. */ + multi->timetree = Curl_splayinsert(*tv, multi->timetree, + &d->state.timenode); + } + return CURLM_OK; +} + +static CURLMcode multi_socket(struct Curl_multi *multi, + bool checkall, + curl_socket_t s, + int ev_bitmask, + int *running_handles) +{ + CURLMcode result = CURLM_OK; + struct Curl_easy *data = NULL; + struct Curl_tree *t; + struct curltime now = Curl_now(); + bool first = FALSE; + bool nosig = FALSE; + SIGPIPE_VARIABLE(pipe_st); + + if(checkall) { + /* *perform() deals with running_handles on its own */ + result = curl_multi_perform(multi, running_handles); + + /* walk through each easy handle and do the socket state change magic + and callbacks */ + if(result != CURLM_BAD_HANDLE) { + data = multi->easyp; + while(data && !result) { + result = singlesocket(multi, data); + data = data->next; + } + } + + /* or should we fall-through and do the timer-based stuff? */ + return result; + } + if(s != CURL_SOCKET_TIMEOUT) { + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); + + if(!entry) + /* Unmatched socket, we can't act on it but we ignore this fact. In + real-world tests it has been proved that libevent can in fact give + the application actions even though the socket was just previously + asked to get removed, so thus we better survive stray socket actions + and just move on. */ + ; + else { + struct Curl_hash_iterator iter; + struct Curl_hash_element *he; + + /* the socket can be shared by many transfers, iterate */ + Curl_hash_start_iterate(&entry->transfers, &iter); + for(he = Curl_hash_next_element(&iter); he; + he = Curl_hash_next_element(&iter)) { + data = (struct Curl_easy *)he->ptr; + DEBUGASSERT(data); + DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER); + + if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK)) + /* set socket event bitmask if they're not locked */ + data->state.select_bits = (unsigned char)ev_bitmask; + + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + + /* Now we fall-through and do the timer-based stuff, since we don't want + to force the user to have to deal with timeouts as long as at least + one connection in fact has traffic. */ + + data = NULL; /* set data to NULL again to avoid calling + multi_runsingle() in case there's no need to */ + now = Curl_now(); /* get a newer time since the multi_runsingle() loop + may have taken some time */ + } + } + else { + /* Asked to run due to time-out. Clear the 'lastcall' variable to force + Curl_update_timer() to trigger a callback to the app again even if the + same timeout is still the one to run after this call. That handles the + case when the application asks libcurl to run the timeout + prematurely. */ + memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + } + + /* + * The loop following here will go on as long as there are expire-times left + * to process in the splay and 'data' will be re-assigned for every expired + * handle we deal with. + */ + do { + /* the first loop lap 'data' can be NULL */ + if(data) { + if(!first) { + first = TRUE; + nosig = data->set.no_signal; /* initial state */ + sigpipe_ignore(data, &pipe_st); + } + else if(data->set.no_signal != nosig) { + sigpipe_restore(&pipe_st); + sigpipe_ignore(data, &pipe_st); + nosig = data->set.no_signal; /* remember new state */ + } + result = multi_runsingle(multi, &now, data); + + if(CURLM_OK >= result) { + /* get the socket(s) and check if the state has been changed since + last */ + result = singlesocket(multi, data); + if(result) + break; + } + } + + /* Check if there's one (more) expired timer to deal with! This function + extracts a matching node if there is one */ + + multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); + if(t) { + data = t->payload; /* assign this for next loop */ + (void)add_next_timeout(now, multi, t->payload); + } + + } while(t); + if(first) + sigpipe_restore(&pipe_st); + + *running_handles = multi->num_alive; + return result; +} + +#undef curl_multi_setopt +CURLMcode curl_multi_setopt(struct Curl_multi *multi, + CURLMoption option, ...) +{ + CURLMcode res = CURLM_OK; + va_list param; + unsigned long uarg; + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + va_start(param, option); + + switch(option) { + case CURLMOPT_SOCKETFUNCTION: + multi->socket_cb = va_arg(param, curl_socket_callback); + break; + case CURLMOPT_SOCKETDATA: + multi->socket_userp = va_arg(param, void *); + break; + case CURLMOPT_PUSHFUNCTION: + multi->push_cb = va_arg(param, curl_push_callback); + break; + case CURLMOPT_PUSHDATA: + multi->push_userp = va_arg(param, void *); + break; + case CURLMOPT_PIPELINING: + multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX ? 1 : 0; + break; + case CURLMOPT_TIMERFUNCTION: + multi->timer_cb = va_arg(param, curl_multi_timer_callback); + break; + case CURLMOPT_TIMERDATA: + multi->timer_userp = va_arg(param, void *); + break; + case CURLMOPT_MAXCONNECTS: + uarg = va_arg(param, unsigned long); + if(uarg <= UINT_MAX) + multi->maxconnects = (unsigned int)uarg; + break; + case CURLMOPT_MAX_HOST_CONNECTIONS: + multi->max_host_connections = va_arg(param, long); + break; + case CURLMOPT_MAX_TOTAL_CONNECTIONS: + multi->max_total_connections = va_arg(param, long); + break; + /* options formerly used for pipelining */ + case CURLMOPT_MAX_PIPELINE_LENGTH: + break; + case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: + break; + case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: + break; + case CURLMOPT_PIPELINING_SITE_BL: + break; + case CURLMOPT_PIPELINING_SERVER_BL: + break; + case CURLMOPT_MAX_CONCURRENT_STREAMS: + { + long streams = va_arg(param, long); + if((streams < 1) || (streams > INT_MAX)) + streams = 100; + multi->max_concurrent_streams = (unsigned int)streams; + } + break; + default: + res = CURLM_UNKNOWN_OPTION; + break; + } + va_end(param); + return res; +} + +/* we define curl_multi_socket() in the public multi.h header */ +#undef curl_multi_socket + +CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s, + int *running_handles) +{ + CURLMcode result; + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + result = multi_socket(multi, FALSE, s, 0, running_handles); + if(CURLM_OK >= result) + result = Curl_update_timer(multi); + return result; +} + +CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s, + int ev_bitmask, int *running_handles) +{ + CURLMcode result; + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles); + if(CURLM_OK >= result) + result = Curl_update_timer(multi); + return result; +} + +CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) +{ + CURLMcode result; + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles); + if(CURLM_OK >= result) + result = Curl_update_timer(multi); + return result; +} + +static CURLMcode multi_timeout(struct Curl_multi *multi, + long *timeout_ms) +{ + static const struct curltime tv_zero = {0, 0}; + + if(multi->dead) { + *timeout_ms = 0; + return CURLM_OK; + } + + if(multi->timetree) { + /* we have a tree of expire times */ + struct curltime now = Curl_now(); + + /* splay the lowest to the bottom */ + multi->timetree = Curl_splay(tv_zero, multi->timetree); + + if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) { + /* some time left before expiration */ + timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now); + /* this should be safe even on 32 bit archs, as we don't use that + overly long timeouts */ + *timeout_ms = (long)diff; + } + else + /* 0 means immediately */ + *timeout_ms = 0; + } + else + *timeout_ms = -1; + + return CURLM_OK; +} + +CURLMcode curl_multi_timeout(struct Curl_multi *multi, + long *timeout_ms) +{ + /* First, make some basic checks that the CURLM handle is a good handle */ + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + return multi_timeout(multi, timeout_ms); +} + +/* + * Tell the application it should update its timers, if it subscribes to the + * update timer callback. + */ +CURLMcode Curl_update_timer(struct Curl_multi *multi) +{ + long timeout_ms; + int rc; + + if(!multi->timer_cb || multi->dead) + return CURLM_OK; + if(multi_timeout(multi, &timeout_ms)) { + return CURLM_OK; + } + if(timeout_ms < 0) { + static const struct curltime none = {0, 0}; + if(Curl_splaycomparekeys(none, multi->timer_lastcall)) { + multi->timer_lastcall = none; + /* there's no timeout now but there was one previously, tell the app to + disable it */ + set_in_callback(multi, TRUE); + rc = multi->timer_cb(multi, -1, multi->timer_userp); + set_in_callback(multi, FALSE); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + return CURLM_OK; + } + return CURLM_OK; + } + + /* When multi_timeout() is done, multi->timetree points to the node with the + * timeout we got the (relative) time-out time for. We can thus easily check + * if this is the same (fixed) time as we got in a previous call and then + * avoid calling the callback again. */ + if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0) + return CURLM_OK; + + multi->timer_lastcall = multi->timetree->key; + + set_in_callback(multi, TRUE); + rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp); + set_in_callback(multi, FALSE); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + return CURLM_OK; +} + +/* + * multi_deltimeout() + * + * Remove a given timestamp from the list of timeouts. + */ +static void +multi_deltimeout(struct Curl_easy *data, expire_id eid) +{ + struct Curl_llist_element *e; + struct Curl_llist *timeoutlist = &data->state.timeoutlist; + /* find and remove the specific node from the list */ + for(e = timeoutlist->head; e; e = e->next) { + struct time_node *n = (struct time_node *)e->ptr; + if(n->eid == eid) { + Curl_llist_remove(timeoutlist, e, NULL); + return; + } + } +} + +/* + * multi_addtimeout() + * + * Add a timestamp to the list of timeouts. Keep the list sorted so that head + * of list is always the timeout nearest in time. + * + */ +static CURLMcode +multi_addtimeout(struct Curl_easy *data, + struct curltime *stamp, + expire_id eid) +{ + struct Curl_llist_element *e; + struct time_node *node; + struct Curl_llist_element *prev = NULL; + size_t n; + struct Curl_llist *timeoutlist = &data->state.timeoutlist; + + node = &data->state.expires[eid]; + + /* copy the timestamp and id */ + memcpy(&node->time, stamp, sizeof(*stamp)); + node->eid = eid; /* also marks it as in use */ + + n = Curl_llist_count(timeoutlist); + if(n) { + /* find the correct spot in the list */ + for(e = timeoutlist->head; e; e = e->next) { + struct time_node *check = (struct time_node *)e->ptr; + timediff_t diff = Curl_timediff(check->time, node->time); + if(diff > 0) + break; + prev = e; + } + + } + /* else + this is the first timeout on the list */ + + Curl_llist_insert_next(timeoutlist, prev, node, &node->list); + return CURLM_OK; +} + +/* + * Curl_expire() + * + * given a number of milliseconds from now to use to set the 'act before + * this'-time for the transfer, to be extracted by curl_multi_timeout() + * + * The timeout will be added to a queue of timeouts if it defines a moment in + * time that is later than the current head of queue. + * + * Expire replaces a former timeout using the same id if already set. + */ +void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id) +{ + struct Curl_multi *multi = data->multi; + struct curltime *nowp = &data->state.expiretime; + struct curltime set; + + /* this is only interesting while there is still an associated multi struct + remaining! */ + if(!multi) + return; + + DEBUGASSERT(id < EXPIRE_LAST); + + set = Curl_now(); + set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bit conversion */ + set.tv_usec += (unsigned int)(milli%1000)*1000; + + if(set.tv_usec >= 1000000) { + set.tv_sec++; + set.tv_usec -= 1000000; + } + + /* Remove any timer with the same id just in case. */ + multi_deltimeout(data, id); + + /* Add it to the timer list. It must stay in the list until it has expired + in case we need to recompute the minimum timer later. */ + multi_addtimeout(data, &set, id); + + if(nowp->tv_sec || nowp->tv_usec) { + /* This means that the struct is added as a node in the splay tree. + Compare if the new time is earlier, and only remove-old/add-new if it + is. */ + timediff_t diff = Curl_timediff(set, *nowp); + int rc; + + if(diff > 0) { + /* The current splay tree entry is sooner than this new expiry time. + We don't need to update our splay tree entry. */ + return; + } + + /* Since this is an updated time, we must remove the previous entry from + the splay tree first and then re-add the new value */ + rc = Curl_splayremove(multi->timetree, &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error removing splay node = %d", rc); + } + + /* Indicate that we are in the splay tree and insert the new timer expiry + value since it is our local minimum. */ + *nowp = set; + data->state.timenode.payload = data; + multi->timetree = Curl_splayinsert(*nowp, multi->timetree, + &data->state.timenode); +} + +/* + * Curl_expire_done() + * + * Removes the expire timer. Marks it as done. + * + */ +void Curl_expire_done(struct Curl_easy *data, expire_id id) +{ + /* remove the timer, if there */ + multi_deltimeout(data, id); +} + +/* + * Curl_expire_clear() + * + * Clear ALL timeout values for this handle. + */ +void Curl_expire_clear(struct Curl_easy *data) +{ + struct Curl_multi *multi = data->multi; + struct curltime *nowp = &data->state.expiretime; + + /* this is only interesting while there is still an associated multi struct + remaining! */ + if(!multi) + return; + + if(nowp->tv_sec || nowp->tv_usec) { + /* Since this is an cleared time, we must remove the previous entry from + the splay tree */ + struct Curl_llist *list = &data->state.timeoutlist; + int rc; + + rc = Curl_splayremove(multi->timetree, &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error clearing splay node = %d", rc); + + /* flush the timeout list too */ + while(list->size > 0) { + Curl_llist_remove(list, list->tail, NULL); + } + +#ifdef DEBUGBUILD + infof(data, "Expire cleared"); +#endif + nowp->tv_sec = 0; + nowp->tv_usec = 0; + } +} + + + + +CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s, + void *hashp) +{ + struct Curl_sh_entry *there = NULL; + + there = sh_getentry(&multi->sockhash, s); + + if(!there) + return CURLM_BAD_SOCKET; + + there->socketp = hashp; + + return CURLM_OK; +} + +size_t Curl_multi_max_host_connections(struct Curl_multi *multi) +{ + return multi ? multi->max_host_connections : 0; +} + +size_t Curl_multi_max_total_connections(struct Curl_multi *multi) +{ + return multi ? multi->max_total_connections : 0; +} + +/* + * When information about a connection has appeared, call this! + */ + +void Curl_multiuse_state(struct Curl_easy *data, + int bundlestate) /* use BUNDLE_* defines */ +{ + struct connectdata *conn; + DEBUGASSERT(data); + DEBUGASSERT(data->multi); + conn = data->conn; + DEBUGASSERT(conn); + DEBUGASSERT(conn->bundle); + + conn->bundle->multiuse = bundlestate; + process_pending_handles(data->multi); +} + +/* process_pending_handles() moves all handles from PENDING + back into the main list and change state to CONNECT */ +static void process_pending_handles(struct Curl_multi *multi) +{ + struct Curl_llist_element *e = multi->pending.head; + if(e) { + struct Curl_easy *data = e->ptr; + + DEBUGASSERT(data->mstate == MSTATE_PENDING); + + /* put it back into the main list */ + link_easy(multi, data); + + multistate(data, MSTATE_CONNECT); + + /* Remove this node from the list */ + Curl_llist_remove(&multi->pending, e, NULL); + + /* Make sure that the handle will be processed soonish. */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + /* mark this as having been in the pending queue */ + data->state.previouslypending = TRUE; + } +} + +void Curl_set_in_callback(struct Curl_easy *data, bool value) +{ + /* might get called when there is no data pointer! */ + if(data) { + if(data->multi_easy) + data->multi_easy->in_callback = value; + else if(data->multi) + data->multi->in_callback = value; + } +} + +bool Curl_is_in_callback(struct Curl_easy *easy) +{ + return ((easy->multi && easy->multi->in_callback) || + (easy->multi_easy && easy->multi_easy->in_callback)); +} + +unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi) +{ + DEBUGASSERT(multi); + return multi->max_concurrent_streams; +} + +struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi) +{ + struct Curl_easy **a = malloc(sizeof(struct Curl_easy *) * + (multi->num_easy + 1)); + if(a) { + unsigned int i = 0; + struct Curl_easy *e = multi->easyp; + while(e) { + DEBUGASSERT(i < multi->num_easy); + if(!e->state.internal) + a[i++] = e; + e = e->next; + } + a[i] = NULL; /* last entry is a NULL */ + } + return a; +} diff --git a/lib/multihandle.h b/lib/multihandle.h new file mode 100644 index 0000000..e03e382 --- /dev/null +++ b/lib/multihandle.h @@ -0,0 +1,179 @@ +#ifndef HEADER_CURL_MULTIHANDLE_H +#define HEADER_CURL_MULTIHANDLE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "llist.h" +#include "hash.h" +#include "conncache.h" +#include "psl.h" +#include "socketpair.h" + +struct connectdata; + +struct Curl_message { + struct Curl_llist_element list; + /* the 'CURLMsg' is the part that is visible to the external user */ + struct CURLMsg extmsg; +}; + +/* NOTE: if you add a state here, add the name to the statename[] array as + well! +*/ +typedef enum { + MSTATE_INIT, /* 0 - start in this state */ + MSTATE_PENDING, /* 1 - no connections, waiting for one */ + MSTATE_CONNECT, /* 2 - resolve/connect has been sent off */ + MSTATE_RESOLVING, /* 3 - awaiting the resolve to finalize */ + MSTATE_CONNECTING, /* 4 - awaiting the TCP connect to finalize */ + MSTATE_TUNNELING, /* 5 - awaiting HTTPS proxy SSL initialization to + complete and/or proxy CONNECT to finalize */ + MSTATE_PROTOCONNECT, /* 6 - initiate protocol connect procedure */ + MSTATE_PROTOCONNECTING, /* 7 - completing the protocol-specific connect + phase */ + MSTATE_DO, /* 8 - start send off the request (part 1) */ + MSTATE_DOING, /* 9 - sending off the request (part 1) */ + MSTATE_DOING_MORE, /* 10 - send off the request (part 2) */ + MSTATE_DID, /* 11 - done sending off request */ + MSTATE_PERFORMING, /* 12 - transfer data */ + MSTATE_RATELIMITING, /* 13 - wait because limit-rate exceeded */ + MSTATE_DONE, /* 14 - post data transfer operation */ + MSTATE_COMPLETED, /* 15 - operation complete */ + MSTATE_MSGSENT, /* 16 - the operation complete message is sent */ + MSTATE_LAST /* 17 - not a true state, never use this */ +} CURLMstate; + +/* we support N sockets per easy handle. Set the corresponding bit to what + action we should wait for */ +#define MAX_SOCKSPEREASYHANDLE 5 +#define GETSOCK_READABLE (0x00ff) +#define GETSOCK_WRITABLE (0xff00) + +#define CURLPIPE_ANY (CURLPIPE_MULTIPLEX) + +#if !defined(CURL_DISABLE_SOCKETPAIR) +#define ENABLE_WAKEUP +#endif + +/* value for MAXIMUM CONCURRENT STREAMS upper limit */ +#define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1) + +/* Curl_multi SSL backend-specific data; declared differently by each SSL + backend */ +struct multi_ssl_backend_data; + +/* This is the struct known as CURLM on the outside */ +struct Curl_multi { + /* First a simple identifier to easier detect if a user mix up + this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ + unsigned int magic; + + /* We have a doubly-linked list with easy handles */ + struct Curl_easy *easyp; + struct Curl_easy *easylp; /* last node */ + + unsigned int num_easy; /* amount of entries in the linked list above. */ + unsigned int num_alive; /* amount of easy handles that are added but have + not yet reached COMPLETE state */ + + struct Curl_llist msglist; /* a list of messages from completed transfers */ + + struct Curl_llist pending; /* Curl_easys that are in the + MSTATE_PENDING state */ + struct Curl_llist msgsent; /* Curl_easys that are in the + MSTATE_MSGSENT state */ + + /* callback function and user data pointer for the *socket() API */ + curl_socket_callback socket_cb; + void *socket_userp; + + /* callback function and user data pointer for server push */ + curl_push_callback push_cb; + void *push_userp; + + /* Hostname cache */ + struct Curl_hash hostcache; + +#ifdef USE_LIBPSL + /* PSL cache. */ + struct PslCache psl; +#endif + + /* timetree points to the splay-tree of time nodes to figure out expire + times of all currently set timers */ + struct Curl_tree *timetree; + +#if defined(USE_SSL) + struct multi_ssl_backend_data *ssl_backend_data; +#endif + + /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note + the pluralis form, there can be more than one easy handle waiting on the + same actual socket) */ + struct Curl_hash sockhash; + + /* Shared connection cache (bundles)*/ + struct conncache conn_cache; + + long max_host_connections; /* if >0, a fixed limit of the maximum number + of connections per host */ + + long max_total_connections; /* if >0, a fixed limit of the maximum number + of connections in total */ + + /* timer callback and user data pointer for the *socket() API */ + curl_multi_timer_callback timer_cb; + void *timer_userp; + struct curltime timer_lastcall; /* the fixed time for the timeout for the + previous callback */ +#ifdef USE_WINSOCK + WSAEVENT wsa_event; /* winsock event used for waits */ +#else +#ifdef ENABLE_WAKEUP + curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup + 0 is used for read, 1 is used for write */ +#endif +#endif + unsigned int max_concurrent_streams; + unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of + entries we're allowed to grow the connection + cache to */ +#define IPV6_UNKNOWN 0 +#define IPV6_DEAD 1 +#define IPV6_WORKS 2 + unsigned char ipv6_up; /* IPV6_* defined */ + BIT(multiplexing); /* multiplexing wanted */ + BIT(recheckstate); /* see Curl_multi_connchanged */ + BIT(in_callback); /* true while executing a callback */ +#ifdef USE_OPENSSL + BIT(ssl_seeded); +#endif + BIT(dead); /* a callback returned error, everything needs to crash and + burn */ +#ifdef DEBUGBUILD + BIT(warned); /* true after user warned of DEBUGBUILD */ +#endif +}; + +#endif /* HEADER_CURL_MULTIHANDLE_H */ diff --git a/lib/multiif.h b/lib/multiif.h new file mode 100644 index 0000000..7a344fa --- /dev/null +++ b/lib/multiif.h @@ -0,0 +1,97 @@ +#ifndef HEADER_CURL_MULTIIF_H +#define HEADER_CURL_MULTIIF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Prototypes for library-wide functions provided by multi.c + */ + +CURLcode Curl_updatesocket(struct Curl_easy *data); +void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id); +void Curl_expire_clear(struct Curl_easy *data); +void Curl_expire_done(struct Curl_easy *data, expire_id id); +CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT; +void Curl_attach_connection(struct Curl_easy *data, + struct connectdata *conn); +void Curl_detach_connection(struct Curl_easy *data); +bool Curl_multiplex_wanted(const struct Curl_multi *multi); +void Curl_set_in_callback(struct Curl_easy *data, bool value); +bool Curl_is_in_callback(struct Curl_easy *easy); +CURLcode Curl_preconnect(struct Curl_easy *data); + +void Curl_multi_connchanged(struct Curl_multi *multi); + +/* Internal version of curl_multi_init() accepts size parameters for the + socket, connection and dns hashes */ +struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize, + int dnssize); + +/* the write bits start at bit 16 for the *getsock() bitmap */ +#define GETSOCK_WRITEBITSTART 16 + +#define GETSOCK_BLANK 0 /* no bits set */ + +/* set the bit for the given sock number to make the bitmap for writable */ +#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x))) + +/* set the bit for the given sock number to make the bitmap for readable */ +#define GETSOCK_READSOCK(x) (1 << (x)) + +/* mask for checking if read and/or write is set for index x */ +#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x)) + +/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */ +size_t Curl_multi_max_host_connections(struct Curl_multi *multi); + +/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */ +size_t Curl_multi_max_total_connections(struct Curl_multi *multi); + +void Curl_multiuse_state(struct Curl_easy *data, + int bundlestate); /* use BUNDLE_* defines */ + +/* + * Curl_multi_closed() + * + * Used by the connect code to tell the multi_socket code that one of the + * sockets we were using is about to be closed. This function will then + * remove it from the sockethash for this handle to make the multi_socket API + * behave properly, especially for the case when libcurl will create another + * socket again and it gets the same file descriptor number. + */ + +void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s); + +/* + * Add a handle and move it into PERFORM state at once. For pushed streams. + */ +CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, + struct Curl_easy *data, + struct connectdata *conn); + + +/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */ +unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi); + +#endif /* HEADER_CURL_MULTIIF_H */ diff --git a/lib/netrc.c b/lib/netrc.c new file mode 100644 index 0000000..038c6dc --- /dev/null +++ b/lib/netrc.c @@ -0,0 +1,349 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#ifndef CURL_DISABLE_NETRC + +#ifdef HAVE_PWD_H +#include +#endif + +#include +#include "netrc.h" +#include "strtok.h" +#include "strcase.h" +#include "curl_get_line.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* Get user and password from .netrc when given a machine name */ + +enum host_lookup_state { + NOTHING, + HOSTFOUND, /* the 'machine' keyword was found */ + HOSTVALID, /* this is "our" machine! */ + MACDEF +}; + +#define NETRC_FILE_MISSING 1 +#define NETRC_FAILED -1 +#define NETRC_SUCCESS 0 + +/* + * Returns zero on success. + */ +static int parsenetrc(const char *host, + char **loginp, + char **passwordp, + char *netrcfile) +{ + FILE *file; + int retcode = NETRC_FILE_MISSING; + char *login = *loginp; + char *password = *passwordp; + bool specific_login = (login && *login != 0); + bool login_alloc = FALSE; + bool password_alloc = FALSE; + enum host_lookup_state state = NOTHING; + + char state_login = 0; /* Found a login keyword */ + char state_password = 0; /* Found a password keyword */ + int state_our_login = TRUE; /* With specific_login, found *our* login + name (or login-less line) */ + + DEBUGASSERT(netrcfile); + + file = fopen(netrcfile, FOPEN_READTEXT); + if(file) { + bool done = FALSE; + char netrcbuffer[4096]; + int netrcbuffsize = (int)sizeof(netrcbuffer); + + while(!done && Curl_get_line(netrcbuffer, netrcbuffsize, file)) { + char *tok; + char *tok_end; + bool quoted; + if(state == MACDEF) { + if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r')) + state = NOTHING; + else + continue; + } + tok = netrcbuffer; + while(tok) { + while(ISBLANK(*tok)) + tok++; + /* tok is first non-space letter */ + if(!*tok || (*tok == '#')) + /* end of line or the rest is a comment */ + break; + + /* leading double-quote means quoted string */ + quoted = (*tok == '\"'); + + tok_end = tok; + if(!quoted) { + while(!ISSPACE(*tok_end)) + tok_end++; + *tok_end = 0; + } + else { + bool escape = FALSE; + bool endquote = FALSE; + char *store = tok; + tok_end++; /* pass the leading quote */ + while(*tok_end) { + char s = *tok_end; + if(escape) { + escape = FALSE; + switch(s) { + case 'n': + s = '\n'; + break; + case 'r': + s = '\r'; + break; + case 't': + s = '\t'; + break; + } + } + else if(s == '\\') { + escape = TRUE; + tok_end++; + continue; + } + else if(s == '\"') { + tok_end++; /* pass the ending quote */ + endquote = TRUE; + break; + } + *store++ = s; + tok_end++; + } + *store = 0; + if(escape || !endquote) { + /* bad syntax, get out */ + retcode = NETRC_FAILED; + goto out; + } + } + + if((login && *login) && (password && *password)) { + done = TRUE; + break; + } + + switch(state) { + case NOTHING: + if(strcasecompare("macdef", tok)) { + /* Define a macro. A macro is defined with the specified name; its + contents begin with the next .netrc line and continue until a + null line (consecutive new-line characters) is encountered. */ + state = MACDEF; + } + else if(strcasecompare("machine", tok)) { + /* the next tok is the machine name, this is in itself the + delimiter that starts the stuff entered for this machine, + after this we need to search for 'login' and + 'password'. */ + state = HOSTFOUND; + } + else if(strcasecompare("default", tok)) { + state = HOSTVALID; + retcode = NETRC_SUCCESS; /* we did find our host */ + } + break; + case MACDEF: + if(!strlen(tok)) { + state = NOTHING; + } + break; + case HOSTFOUND: + if(strcasecompare(host, tok)) { + /* and yes, this is our host! */ + state = HOSTVALID; + retcode = NETRC_SUCCESS; /* we did find our host */ + } + else + /* not our host */ + state = NOTHING; + break; + case HOSTVALID: + /* we are now parsing sub-keywords concerning "our" host */ + if(state_login) { + if(specific_login) { + state_our_login = !Curl_timestrcmp(login, tok); + } + else if(!login || Curl_timestrcmp(login, tok)) { + if(login_alloc) { + free(login); + login_alloc = FALSE; + } + login = strdup(tok); + if(!login) { + retcode = NETRC_FAILED; /* allocation failed */ + goto out; + } + login_alloc = TRUE; + } + state_login = 0; + } + else if(state_password) { + if((state_our_login || !specific_login) + && (!password || Curl_timestrcmp(password, tok))) { + if(password_alloc) { + free(password); + password_alloc = FALSE; + } + password = strdup(tok); + if(!password) { + retcode = NETRC_FAILED; /* allocation failed */ + goto out; + } + password_alloc = TRUE; + } + state_password = 0; + } + else if(strcasecompare("login", tok)) + state_login = 1; + else if(strcasecompare("password", tok)) + state_password = 1; + else if(strcasecompare("machine", tok)) { + /* ok, there's machine here go => */ + state = HOSTFOUND; + state_our_login = FALSE; + } + break; + } /* switch (state) */ + tok = ++tok_end; + } + } /* while Curl_get_line() */ + +out: + if(!retcode) { + /* success */ + if(login_alloc) { + if(*loginp) + free(*loginp); + *loginp = login; + } + if(password_alloc) { + if(*passwordp) + free(*passwordp); + *passwordp = password; + } + } + else { + if(login_alloc) + free(login); + if(password_alloc) + free(password); + } + fclose(file); + } + + return retcode; +} + +/* + * @unittest: 1304 + * + * *loginp and *passwordp MUST be allocated if they aren't NULL when passed + * in. + */ +int Curl_parsenetrc(const char *host, char **loginp, char **passwordp, + char *netrcfile) +{ + int retcode = 1; + char *filealloc = NULL; + + if(!netrcfile) { +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + char pwbuf[1024]; +#endif + char *home = NULL; + char *homea = curl_getenv("HOME"); /* portable environment reader */ + if(homea) { + home = homea; +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + } + else { + struct passwd pw, *pw_res; + if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) + && pw_res) { + home = pw.pw_dir; + } +#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) + } + else { + struct passwd *pw; + pw = getpwuid(geteuid()); + if(pw) { + home = pw->pw_dir; + } +#elif defined(_WIN32) + } + else { + homea = curl_getenv("USERPROFILE"); + if(homea) { + home = homea; + } +#endif + } + + if(!home) + return retcode; /* no home directory found (or possibly out of + memory) */ + + filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR); + if(!filealloc) { + free(homea); + return -1; + } + retcode = parsenetrc(host, loginp, passwordp, filealloc); + free(filealloc); +#ifdef _WIN32 + if(retcode == NETRC_FILE_MISSING) { + /* fallback to the old-style "_netrc" file */ + filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR); + if(!filealloc) { + free(homea); + return -1; + } + retcode = parsenetrc(host, loginp, passwordp, filealloc); + free(filealloc); + } +#endif + free(homea); + } + else + retcode = parsenetrc(host, loginp, passwordp, netrcfile); + return retcode; +} + +#endif diff --git a/lib/netrc.h b/lib/netrc.h new file mode 100644 index 0000000..9f2815f --- /dev/null +++ b/lib/netrc.h @@ -0,0 +1,43 @@ +#ifndef HEADER_CURL_NETRC_H +#define HEADER_CURL_NETRC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#ifndef CURL_DISABLE_NETRC + +/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ +int Curl_parsenetrc(const char *host, char **loginp, + char **passwordp, char *filename); + /* Assume: (*passwordp)[0]=0, host[0] != 0. + * If (*loginp)[0] = 0, search for login and password within a machine + * section in the netrc. + * If (*loginp)[0] != 0, search for password within machine and login. + */ +#else +/* disabled */ +#define Curl_parsenetrc(a,b,c,d,e,f) 1 +#endif + +#endif /* HEADER_CURL_NETRC_H */ diff --git a/lib/nonblock.c b/lib/nonblock.c new file mode 100644 index 0000000..f4eb656 --- /dev/null +++ b/lib/nonblock.c @@ -0,0 +1,84 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef __VMS +#include +#include +#endif + +#include "nonblock.h" + +/* + * curlx_nonblock() set the given socket to either blocking or non-blocking + * mode based on the 'nonblock' boolean argument. This function is highly + * portable. + */ +int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ + int nonblock /* TRUE or FALSE */) +{ +#if defined(HAVE_FCNTL_O_NONBLOCK) + /* most recent unix versions */ + int flags; + flags = sfcntl(sockfd, F_GETFL, 0); + if(nonblock) + return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); + +#elif defined(HAVE_IOCTL_FIONBIO) + + /* older unix versions */ + int flags = nonblock ? 1 : 0; + return ioctl(sockfd, FIONBIO, &flags); + +#elif defined(HAVE_IOCTLSOCKET_FIONBIO) + + /* Windows */ + unsigned long flags = nonblock ? 1UL : 0UL; + return ioctlsocket(sockfd, FIONBIO, &flags); + +#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) + + /* Amiga */ + long flags = nonblock ? 1L : 0L; + return IoctlSocket(sockfd, FIONBIO, (char *)&flags); + +#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) + + /* Orbis OS */ + long b = nonblock ? 1L : 0L; + return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); + +#else +# error "no non-blocking method was found/used/set" +#endif +} diff --git a/lib/nonblock.h b/lib/nonblock.h new file mode 100644 index 0000000..4a1a615 --- /dev/null +++ b/lib/nonblock.h @@ -0,0 +1,32 @@ +#ifndef HEADER_CURL_NONBLOCK_H +#define HEADER_CURL_NONBLOCK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include /* for curl_socket_t */ + +int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ + int nonblock /* TRUE or FALSE */); + +#endif /* HEADER_CURL_NONBLOCK_H */ diff --git a/lib/noproxy.c b/lib/noproxy.c new file mode 100644 index 0000000..5241640 --- /dev/null +++ b/lib/noproxy.c @@ -0,0 +1,265 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_PROXY + +#include "inet_pton.h" +#include "strcase.h" +#include "noproxy.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +/* + * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the + * specified CIDR address range. + */ +UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ + const char *network, /* 1.2.3.4 address */ + unsigned int bits) +{ + unsigned int address = 0; + unsigned int check = 0; + + if(bits > 32) + /* strange input */ + return FALSE; + + if(1 != Curl_inet_pton(AF_INET, ipv4, &address)) + return FALSE; + if(1 != Curl_inet_pton(AF_INET, network, &check)) + return FALSE; + + if(bits && (bits != 32)) { + unsigned int mask = 0xffffffff << (32 - bits); + unsigned int haddr = htonl(address); + unsigned int hcheck = htonl(check); +#if 0 + fprintf(stderr, "Host %s (%x) network %s (%x) bits %u mask %x => %x\n", + ipv4, haddr, network, hcheck, bits, mask, + (haddr ^ hcheck) & mask); +#endif + if((haddr ^ hcheck) & mask) + return FALSE; + return TRUE; + } + return (address == check); +} + +UNITTEST bool Curl_cidr6_match(const char *ipv6, + const char *network, + unsigned int bits) +{ +#ifdef ENABLE_IPV6 + int bytes; + int rest; + unsigned char address[16]; + unsigned char check[16]; + + if(!bits) + bits = 128; + + bytes = bits/8; + rest = bits & 0x07; + if(1 != Curl_inet_pton(AF_INET6, ipv6, address)) + return FALSE; + if(1 != Curl_inet_pton(AF_INET6, network, check)) + return FALSE; + if((bytes > 16) || ((bytes == 16) && rest)) + return FALSE; + if(bytes && memcmp(address, check, bytes)) + return FALSE; + if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest)))) + return FALSE; + + return TRUE; +#else + (void)ipv6; + (void)network; + (void)bits; + return FALSE; +#endif +} + +enum nametype { + TYPE_HOST, + TYPE_IPV4, + TYPE_IPV6 +}; + +/**************************************************************** +* Checks if the host is in the noproxy list. returns TRUE if it matches and +* therefore the proxy should NOT be used. +****************************************************************/ +bool Curl_check_noproxy(const char *name, const char *no_proxy, + bool *spacesep) +{ + char hostip[128]; + *spacesep = FALSE; + /* + * If we don't have a hostname at all, like for example with a FILE + * transfer, we have nothing to interrogate the noproxy list with. + */ + if(!name || name[0] == '\0') + return FALSE; + + /* no_proxy=domain1.dom,host.domain2.dom + * (a comma-separated list of hosts which should + * not be proxied, or an asterisk to override + * all proxy variables) + */ + if(no_proxy && no_proxy[0]) { + const char *p = no_proxy; + size_t namelen; + enum nametype type = TYPE_HOST; + if(!strcmp("*", no_proxy)) + return TRUE; + + /* NO_PROXY was specified and it wasn't just an asterisk */ + + if(name[0] == '[') { + char *endptr; + /* IPv6 numerical address */ + endptr = strchr(name, ']'); + if(!endptr) + return FALSE; + name++; + namelen = endptr - name; + if(namelen >= sizeof(hostip)) + return FALSE; + memcpy(hostip, name, namelen); + hostip[namelen] = 0; + name = hostip; + type = TYPE_IPV6; + } + else { + unsigned int address; + namelen = strlen(name); + if(1 == Curl_inet_pton(AF_INET, name, &address)) + type = TYPE_IPV4; + else { + /* ignore trailing dots in the host name */ + if(name[namelen - 1] == '.') + namelen--; + } + } + + while(*p) { + const char *token; + size_t tokenlen = 0; + bool match = FALSE; + + /* pass blanks */ + while(*p && ISBLANK(*p)) + p++; + + token = p; + /* pass over the pattern */ + while(*p && !ISBLANK(*p) && (*p != ',')) { + p++; + tokenlen++; + } + + if(tokenlen) { + switch(type) { + case TYPE_HOST: + /* ignore trailing dots in the token to check */ + if(token[tokenlen - 1] == '.') + tokenlen--; + + if(tokenlen && (*token == '.')) { + /* ignore leading token dot as well */ + token++; + tokenlen--; + } + /* A: example.com matches 'example.com' + B: www.example.com matches 'example.com' + C: nonexample.com DOES NOT match 'example.com' + */ + if(tokenlen == namelen) + /* case A, exact match */ + match = strncasecompare(token, name, namelen); + else if(tokenlen < namelen) { + /* case B, tailmatch domain */ + match = (name[namelen - tokenlen - 1] == '.') && + strncasecompare(token, name + (namelen - tokenlen), + tokenlen); + } + /* case C passes through, not a match */ + break; + case TYPE_IPV4: + case TYPE_IPV6: { + const char *check = token; + char *slash; + unsigned int bits = 0; + char checkip[128]; + if(tokenlen >= sizeof(checkip)) + /* this cannot match */ + break; + /* copy the check name to a temp buffer */ + memcpy(checkip, check, tokenlen); + checkip[tokenlen] = 0; + check = checkip; + + slash = strchr(check, '/'); + /* if the slash is part of this token, use it */ + if(slash) { + bits = atoi(slash + 1); + *slash = 0; /* null terminate there */ + } + if(type == TYPE_IPV6) + match = Curl_cidr6_match(name, check, bits); + else + match = Curl_cidr4_match(name, check, bits); + break; + } + } + if(match) + return TRUE; + } /* if(tokenlen) */ + /* pass blanks after pattern */ + while(ISBLANK(*p)) + p++; + /* if not a comma! */ + if(*p && (*p != ',')) { + *spacesep = TRUE; + continue; + } + /* pass any number of commas */ + while(*p == ',') + p++; + } /* while(*p) */ + } /* NO_PROXY was specified and it wasn't just an asterisk */ + + return FALSE; +} + +#endif /* CURL_DISABLE_PROXY */ diff --git a/lib/noproxy.h b/lib/noproxy.h new file mode 100644 index 0000000..a3a6807 --- /dev/null +++ b/lib/noproxy.h @@ -0,0 +1,45 @@ +#ifndef HEADER_CURL_NOPROXY_H +#define HEADER_CURL_NOPROXY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifndef CURL_DISABLE_PROXY + +#ifdef DEBUGBUILD + +UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ + const char *network, /* 1.2.3.4 address */ + unsigned int bits); +UNITTEST bool Curl_cidr6_match(const char *ipv6, + const char *network, + unsigned int bits); +#endif + +bool Curl_check_noproxy(const char *name, const char *no_proxy, + bool *spacesep); + +#endif + +#endif /* HEADER_CURL_NOPROXY_H */ diff --git a/lib/openldap.c b/lib/openldap.c new file mode 100644 index 0000000..1e60ff7 --- /dev/null +++ b/lib/openldap.c @@ -0,0 +1,1219 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Howard Chu, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP) + +/* + * Notice that USE_OPENLDAP is only a source code selection switch. When + * libcurl is built with USE_OPENLDAP defined the libcurl source code that + * gets compiled is the code from openldap.c, otherwise the code that gets + * compiled is the code from ldap.c. + * + * When USE_OPENLDAP is defined a recent version of the OpenLDAP library + * might be required for compilation and runtime. In order to use ancient + * OpenLDAP library versions, USE_OPENLDAP shall not be defined. + */ + +#include + +#include "urldata.h" +#include +#include "sendf.h" +#include "vtls/vtls.h" +#include "transfer.h" +#include "curl_ldap.h" +#include "curl_base64.h" +#include "cfilters.h" +#include "connect.h" +#include "curl_sasl.h" +#include "strcase.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Uncommenting this will enable the built-in debug logging of the openldap + * library. The debug log level can be set using the CURL_OPENLDAP_TRACE + * environment variable. The debug output is written to stderr. + * + * The library supports the following debug flags: + * LDAP_DEBUG_NONE 0x0000 + * LDAP_DEBUG_TRACE 0x0001 + * LDAP_DEBUG_CONSTRUCT 0x0002 + * LDAP_DEBUG_DESTROY 0x0004 + * LDAP_DEBUG_PARAMETER 0x0008 + * LDAP_DEBUG_ANY 0xffff + * + * For example, use CURL_OPENLDAP_TRACE=0 for no debug, + * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only, + * CURL_OPENLDAP_TRACE=65535 for all debug message levels. + */ +/* #define CURL_OPENLDAP_DEBUG */ + +/* Machine states. */ +typedef enum { + OLDAP_STOP, /* Do nothing state, stops the state machine */ + OLDAP_SSL, /* Performing SSL handshake. */ + OLDAP_STARTTLS, /* STARTTLS request sent. */ + OLDAP_TLS, /* Performing TLS handshake. */ + OLDAP_MECHS, /* Get SASL authentication mechanisms. */ + OLDAP_SASL, /* SASL binding reply. */ + OLDAP_BIND, /* Simple bind reply. */ + OLDAP_BINDV2, /* Simple bind reply in protocol version 2. */ + OLDAP_LAST /* Never used */ +} ldapstate; + +#ifndef _LDAP_PVT_H +extern int ldap_pvt_url_scheme2proto(const char *); +extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, + LDAP **ld); +#endif + +static CURLcode oldap_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static CURLcode oldap_do(struct Curl_easy *data, bool *done); +static CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool); +static CURLcode oldap_connect(struct Curl_easy *data, bool *done); +static CURLcode oldap_connecting(struct Curl_easy *data, bool *done); +static CURLcode oldap_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); + +static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out); + +static Curl_recv oldap_recv; + +/* + * LDAP protocol handler. + */ + +const struct Curl_handler Curl_handler_ldap = { + "LDAP", /* scheme */ + oldap_setup_connection, /* setup_connection */ + oldap_do, /* do_it */ + oldap_done, /* done */ + ZERO_NULL, /* do_more */ + oldap_connect, /* connect_it */ + oldap_connecting, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + oldap_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_LDAP, /* defport */ + CURLPROTO_LDAP, /* protocol */ + CURLPROTO_LDAP, /* family */ + PROTOPT_NONE /* flags */ +}; + +#ifdef USE_SSL +/* + * LDAPS protocol handler. + */ + +const struct Curl_handler Curl_handler_ldaps = { + "LDAPS", /* scheme */ + oldap_setup_connection, /* setup_connection */ + oldap_do, /* do_it */ + oldap_done, /* done */ + ZERO_NULL, /* do_more */ + oldap_connect, /* connect_it */ + oldap_connecting, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + oldap_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_LDAPS, /* defport */ + CURLPROTO_LDAPS, /* protocol */ + CURLPROTO_LDAP, /* family */ + PROTOPT_SSL /* flags */ +}; +#endif + +/* SASL parameters for the ldap protocol */ +static const struct SASLproto saslldap = { + "ldap", /* The service name */ + oldap_perform_auth, /* Send authentication command */ + oldap_continue_auth, /* Send authentication continuation */ + oldap_cancel_auth, /* Send authentication cancellation */ + oldap_get_message, /* Get SASL response message */ + 0, /* Maximum initial response length (no max) */ + LDAP_SASL_BIND_IN_PROGRESS, /* Code received when continuation is expected */ + LDAP_SUCCESS, /* Code to receive upon authentication success */ + SASL_AUTH_NONE, /* Default mechanisms */ + 0 /* Configuration flags */ +}; + +struct ldapconninfo { + struct SASL sasl; /* SASL-related parameters */ + LDAP *ld; /* Openldap connection handle. */ + Curl_recv *recv; /* For stacking SSL handler */ + Curl_send *send; + struct berval *servercred; /* SASL data from server. */ + ldapstate state; /* Current machine state. */ + int proto; /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */ + int msgid; /* Current message id. */ +}; + +struct ldapreqinfo { + int msgid; + int nument; +}; + +/* + * oldap_state() + * + * This is the ONLY way to change LDAP state! + */ +static void oldap_state(struct Curl_easy *data, ldapstate newstate) +{ + struct ldapconninfo *ldapc = data->conn->proto.ldapc; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[] = { + "STOP", + "SSL", + "STARTTLS", + "TLS", + "MECHS", + "SASL", + "BIND", + "BINDV2", + /* LAST */ + }; + + if(ldapc->state != newstate) + infof(data, "LDAP %p state change from %s to %s", + (void *)ldapc, names[ldapc->state], names[newstate]); +#endif + + ldapc->state = newstate; +} + +/* Map some particular LDAP error codes to CURLcode values. */ +static CURLcode oldap_map_error(int rc, CURLcode result) +{ + switch(rc) { + case LDAP_NO_MEMORY: + result = CURLE_OUT_OF_MEMORY; + break; + case LDAP_INVALID_CREDENTIALS: + result = CURLE_LOGIN_DENIED; + break; + case LDAP_PROTOCOL_ERROR: + result = CURLE_UNSUPPORTED_PROTOCOL; + break; + case LDAP_INSUFFICIENT_ACCESS: + result = CURLE_REMOTE_ACCESS_DENIED; + break; + } + return result; +} + +static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp) +{ + CURLcode result = CURLE_OK; + int rc = LDAP_URL_ERR_BADURL; + static const char * const url_errs[] = { + "success", + "out of memory", + "bad parameter", + "unrecognized scheme", + "unbalanced delimiter", + "bad URL", + "bad host or port", + "bad or missing attributes", + "bad or missing scope", + "bad or missing filter", + "bad or missing extensions" + }; + + *ludp = NULL; + if(!data->state.up.user && !data->state.up.password && + !data->state.up.options) + rc = ldap_url_parse(data->state.url, ludp); + if(rc != LDAP_URL_SUCCESS) { + const char *msg = "url parsing problem"; + + result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT; + rc -= LDAP_URL_SUCCESS; + if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0])) + msg = url_errs[rc]; + failf(data, "LDAP local: %s", msg); + } + return result; +} + +/* Parse the login options. */ +static CURLcode oldap_parse_login_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct ldapconninfo *li = conn->proto.ldapc; + const char *ptr = conn->options; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(checkprefix("AUTH=", key)) + result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value); + else + result = CURLE_SETOPT_OPTION_SYNTAX; + + if(*ptr == ';') + ptr++; + } + + return result == CURLE_URL_MALFORMAT? CURLE_SETOPT_OPTION_SYNTAX: result; +} + +static CURLcode oldap_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + LDAPURLDesc *lud; + (void)conn; + + /* Early URL syntax check. */ + result = oldap_url_parse(data, &lud); + ldap_free_urldesc(lud); + + return result; +} + +/* + * Get the SASL authentication challenge from the server credential buffer. + */ +static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out) +{ + struct berval *servercred = data->conn->proto.ldapc->servercred; + + if(!servercred || !servercred->bv_val) + return CURLE_WEIRD_SERVER_REPLY; + Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL); + return CURLE_OK; +} + +/* + * Sends an initial SASL bind request to the server. + */ +static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode result = CURLE_OK; + struct berval cred; + struct berval *pcred = &cred; + int rc; + + cred.bv_val = (char *) Curl_bufref_ptr(initresp); + cred.bv_len = Curl_bufref_len(initresp); + if(!cred.bv_val) + pcred = NULL; + rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid); + if(rc != LDAP_SUCCESS) + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); + return result; +} + +/* + * Sends SASL continuation. + */ +static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode result = CURLE_OK; + struct berval cred; + struct berval *pcred = &cred; + int rc; + + cred.bv_val = (char *) Curl_bufref_ptr(resp); + cred.bv_len = Curl_bufref_len(resp); + if(!cred.bv_val) + pcred = NULL; + rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid); + if(rc != LDAP_SUCCESS) + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); + return result; +} + +/* + * Sends SASL bind cancellation. + */ +static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech) +{ + struct ldapconninfo *li = data->conn->proto.ldapc; + CURLcode result = CURLE_OK; + int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL, + &li->msgid); + + (void)mech; + if(rc != LDAP_SUCCESS) + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); + return result; +} + +/* Starts LDAP simple bind. */ +static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + char *binddn = NULL; + struct berval passwd; + int rc; + + passwd.bv_val = NULL; + passwd.bv_len = 0; + + if(data->state.aptr.user) { + binddn = conn->user; + passwd.bv_val = conn->passwd; + passwd.bv_len = strlen(passwd.bv_val); + } + + rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, + NULL, NULL, &li->msgid); + if(rc == LDAP_SUCCESS) + oldap_state(data, newstate); + else + result = oldap_map_error(rc, + data->state.aptr.user? + CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND); + return result; +} + +/* Query the supported SASL authentication mechanisms. */ +static CURLcode oldap_perform_mechs(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct ldapconninfo *li = data->conn->proto.ldapc; + int rc; + static const char * const supportedSASLMechanisms[] = { + "supportedSASLMechanisms", + NULL + }; + + rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", + (char **) supportedSASLMechanisms, 0, + NULL, NULL, NULL, 0, &li->msgid); + if(rc == LDAP_SUCCESS) + oldap_state(data, OLDAP_MECHS); + else + result = oldap_map_error(rc, CURLE_LOGIN_DENIED); + return result; +} + +/* Starts SASL bind. */ +static CURLcode oldap_perform_sasl(struct Curl_easy *data) +{ + saslprogress progress = SASL_IDLE; + struct ldapconninfo *li = data->conn->proto.ldapc; + CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress); + + oldap_state(data, OLDAP_SASL); + if(!result && progress != SASL_INPROGRESS) + result = CURLE_LOGIN_DENIED; + return result; +} + +#ifdef USE_SSL +static Sockbuf_IO ldapsb_tls; + +static bool ssl_installed(struct connectdata *conn) +{ + return conn->proto.ldapc->recv != NULL; +} + +static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + bool ssldone = 0; + + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); + if(!result) { + oldap_state(data, newstate); + + if(ssldone) { + Sockbuf *sb; + + /* Install the libcurl SSL handlers into the sockbuf. */ + ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); + li->recv = conn->recv[FIRSTSOCKET]; + li->send = conn->send[FIRSTSOCKET]; + } + } + + return result; +} + +/* Send the STARTTLS request */ +static CURLcode oldap_perform_starttls(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct ldapconninfo *li = data->conn->proto.ldapc; + int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid); + + if(rc == LDAP_SUCCESS) + oldap_state(data, OLDAP_STARTTLS); + else + result = oldap_map_error(rc, CURLE_USE_SSL_FAILED); + return result; +} +#endif + +static CURLcode oldap_connect(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li; + static const int version = LDAP_VERSION3; + int rc; + char *hosturl; +#ifdef CURL_OPENLDAP_DEBUG + static int do_trace = -1; +#endif + + (void)done; + + DEBUGASSERT(!conn->proto.ldapc); + li = calloc(1, sizeof(struct ldapconninfo)); + if(!li) + return CURLE_OUT_OF_MEMORY; + else { + CURLcode result; + li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme); + conn->proto.ldapc = li; + + /* Initialize the SASL storage */ + Curl_sasl_init(&li->sasl, data, &saslldap); + + /* Clear the TLS upgraded flag */ + conn->bits.tls_upgraded = FALSE; + + result = oldap_parse_login_options(conn); + if(result) + return result; + } + + hosturl = aprintf("ldap%s://%s:%d", + conn->handler->flags & PROTOPT_SSL? "s": "", + conn->host.name, conn->remote_port); + if(!hosturl) + return CURLE_OUT_OF_MEMORY; + + rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld); + if(rc) { + failf(data, "LDAP local: Cannot connect to %s, %s", + hosturl, ldap_err2string(rc)); + free(hosturl); + return CURLE_COULDNT_CONNECT; + } + + free(hosturl); + +#ifdef CURL_OPENLDAP_DEBUG + if(do_trace < 0) { + const char *env = getenv("CURL_OPENLDAP_TRACE"); + do_trace = (env && strtol(env, NULL, 10) > 0); + } + if(do_trace) + ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace); +#endif + + /* Try version 3 first. */ + ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version); + + /* Do not chase referrals. */ + ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); + +#ifdef USE_SSL + if(conn->handler->flags & PROTOPT_SSL) + return oldap_ssl_connect(data, OLDAP_SSL); + + if(data->set.use_ssl) { + CURLcode result = oldap_perform_starttls(data); + + if(!result || data->set.use_ssl != CURLUSESSL_TRY) + return result; + } +#endif + + if(li->sasl.prefmech != SASL_AUTH_NONE) + return oldap_perform_mechs(data); + + /* Force bind even if anonymous bind is not needed in protocol version 3 + to detect missing version 3 support. */ + return oldap_perform_bind(data, OLDAP_BIND); +} + +/* Handle the supported SASL mechanisms query response */ +static CURLcode oldap_state_mechs_resp(struct Curl_easy *data, + LDAPMessage *msg, int code) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + int rc; + BerElement *ber = NULL; + CURLcode result = CURLE_OK; + struct berval bv, *bvals; + + switch(ldap_msgtype(msg)) { + case LDAP_RES_SEARCH_ENTRY: + /* Got a list of supported SASL mechanisms. */ + if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED) + return CURLE_LOGIN_DENIED; + + rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv); + if(rc < 0) + return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING); + for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) { + int i; + + if(!bv.bv_val) + break; + + if(bvals) { + for(i = 0; bvals[i].bv_val; i++) { + size_t llen; + unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val, + bvals[i].bv_len, &llen); + if(bvals[i].bv_len == llen) + li->sasl.authmechs |= mech; + } + ber_memfree(bvals); + } + } + ber_free(ber, 0); + break; + + case LDAP_RES_SEARCH_RESULT: + switch(code) { + case LDAP_SIZELIMIT_EXCEEDED: + infof(data, "Too many authentication mechanisms\n"); + FALLTHROUGH(); + case LDAP_SUCCESS: + case LDAP_NO_RESULTS_RETURNED: + if(Curl_sasl_can_authenticate(&li->sasl, data)) + result = oldap_perform_sasl(data); + else + result = CURLE_LOGIN_DENIED; + break; + default: + result = oldap_map_error(code, CURLE_LOGIN_DENIED); + break; + } + break; + default: + break; + } + return result; +} + +/* Handle a SASL bind response. */ +static CURLcode oldap_state_sasl_resp(struct Curl_easy *data, + LDAPMessage *msg, int code) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode result = CURLE_OK; + saslprogress progress; + int rc; + + li->servercred = NULL; + rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc)); + result = oldap_map_error(rc, CURLE_LOGIN_DENIED); + } + else { + result = Curl_sasl_continue(&li->sasl, data, code, &progress); + if(!result && progress != SASL_INPROGRESS) + oldap_state(data, OLDAP_STOP); + } + + if(li->servercred) + ber_bvfree(li->servercred); + return result; +} + +/* Handle a simple bind response. */ +static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg, + int code) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode result = CURLE_OK; + struct berval *bv = NULL; + int rc; + + if(code != LDAP_SUCCESS) + return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND); + + rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s", + ldap_err2string(rc)); + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); + } + else + oldap_state(data, OLDAP_STOP); + + if(bv) + ber_bvfree(bv); + return result; +} + +static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + LDAPMessage *msg = NULL; + struct timeval tv = {0, 0}; + int code = LDAP_SUCCESS; + int rc; + + if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) { + /* Get response to last command. */ + rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg); + switch(rc) { + case 0: /* Timed out. */ + return CURLE_OK; + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_SEARCH_REFERENCE: + break; + default: + li->msgid = 0; /* Nothing to abandon upon error. */ + if(rc < 0) { + failf(data, "LDAP local: connecting ldap_result %s", + ldap_err2string(rc)); + return oldap_map_error(rc, CURLE_COULDNT_CONNECT); + } + break; + } + + /* Get error code from message. */ + rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0); + if(rc) + code = rc; + else { + /* store the latest code for later retrieval */ + data->info.httpcode = code; + } + + /* If protocol version 3 is not supported, fallback to version 2. */ + if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 && +#ifdef USE_SSL + (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) && +#endif + li->sasl.prefmech == SASL_AUTH_NONE) { + static const int version = LDAP_VERSION2; + + ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version); + ldap_msgfree(msg); + return oldap_perform_bind(data, OLDAP_BINDV2); + } + } + + /* Handle response message according to current state. */ + switch(li->state) { + +#ifdef USE_SSL + case OLDAP_SSL: + result = oldap_ssl_connect(data, OLDAP_SSL); + if(!result && ssl_installed(conn)) { + if(li->sasl.prefmech != SASL_AUTH_NONE) + result = oldap_perform_mechs(data); + else + result = oldap_perform_bind(data, OLDAP_BIND); + } + break; + case OLDAP_STARTTLS: + if(code != LDAP_SUCCESS) { + if(data->set.use_ssl != CURLUSESSL_TRY) + result = oldap_map_error(code, CURLE_USE_SSL_FAILED); + else if(li->sasl.prefmech != SASL_AUTH_NONE) + result = oldap_perform_mechs(data); + else + result = oldap_perform_bind(data, OLDAP_BIND); + break; + } + result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); + if(result) + break; + FALLTHROUGH(); + case OLDAP_TLS: + result = oldap_ssl_connect(data, OLDAP_TLS); + if(result) + result = oldap_map_error(code, CURLE_USE_SSL_FAILED); + else if(ssl_installed(conn)) { + conn->bits.tls_upgraded = TRUE; + if(li->sasl.prefmech != SASL_AUTH_NONE) + result = oldap_perform_mechs(data); + else if(data->state.aptr.user) + result = oldap_perform_bind(data, OLDAP_BIND); + else { + /* Version 3 supported: no bind required */ + oldap_state(data, OLDAP_STOP); + result = CURLE_OK; + } + } + break; +#endif + + case OLDAP_MECHS: + result = oldap_state_mechs_resp(data, msg, code); + break; + case OLDAP_SASL: + result = oldap_state_sasl_resp(data, msg, code); + break; + case OLDAP_BIND: + case OLDAP_BINDV2: + result = oldap_state_bind_resp(data, msg, code); + break; + default: + /* internal error */ + result = CURLE_COULDNT_CONNECT; + break; + } + + ldap_msgfree(msg); + + *done = li->state == OLDAP_STOP; + if(*done) + conn->recv[FIRSTSOCKET] = oldap_recv; + + if(result && li->msgid) { + ldap_abandon_ext(li->ld, li->msgid, NULL, NULL); + li->msgid = 0; + } + return result; +} + +static CURLcode oldap_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + struct ldapconninfo *li = conn->proto.ldapc; + (void) dead_connection; +#ifndef USE_SSL + (void)data; +#endif + + if(li) { + if(li->ld) { +#ifdef USE_SSL + if(ssl_installed(conn)) { + Sockbuf *sb; + ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); + } +#endif + ldap_unbind_ext(li->ld, NULL, NULL); + li->ld = NULL; + } + Curl_sasl_cleanup(conn, li->sasl.authused); + conn->proto.ldapc = NULL; + free(li); + } + return CURLE_OK; +} + +static CURLcode oldap_do(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + struct ldapreqinfo *lr; + CURLcode result; + int rc; + LDAPURLDesc *lud; + int msgid; + + connkeep(conn, "OpenLDAP do"); + + infof(data, "LDAP local: %s", data->state.url); + + result = oldap_url_parse(data, &lud); + if(!result) { +#ifdef USE_SSL + if(ssl_installed(conn)) { + Sockbuf *sb; + /* re-install the libcurl SSL handlers into the sockbuf. */ + ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); + } +#endif + + rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope, + lud->lud_filter, lud->lud_attrs, 0, + NULL, NULL, NULL, 0, &msgid); + ldap_free_urldesc(lud); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); + result = CURLE_LDAP_SEARCH_FAILED; + } + else { + lr = calloc(1, sizeof(struct ldapreqinfo)); + if(!lr) { + ldap_abandon_ext(li->ld, msgid, NULL, NULL); + result = CURLE_OUT_OF_MEMORY; + } + else { + lr->msgid = msgid; + data->req.p.ldap = lr; + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + *done = TRUE; + } + } + } + return result; +} + +static CURLcode oldap_done(struct Curl_easy *data, CURLcode res, + bool premature) +{ + struct connectdata *conn = data->conn; + struct ldapreqinfo *lr = data->req.p.ldap; + + (void)res; + (void)premature; + + if(lr) { + /* if there was a search in progress, abandon it */ + if(lr->msgid) { + struct ldapconninfo *li = conn->proto.ldapc; + ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL); + lr->msgid = 0; + } + data->req.p.ldap = NULL; + free(lr); + } + + return CURLE_OK; +} + +static CURLcode client_write(struct Curl_easy *data, + const char *prefix, size_t plen, + const char *value, size_t len, + const char *suffix, size_t slen) +{ + CURLcode result = CURLE_OK; + + if(prefix) { + /* If we have a zero-length value and the prefix ends with a space + separator, drop the latter. */ + if(!len && plen && prefix[plen - 1] == ' ') + plen--; + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen); + } + if(!result && value) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len); + } + if(!result && suffix) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen); + } + return result; +} + +static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, + size_t len, CURLcode *err) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + struct ldapreqinfo *lr = data->req.p.ldap; + int rc; + LDAPMessage *msg = NULL; + BerElement *ber = NULL; + struct timeval tv = {0, 0}; + struct berval bv, *bvals; + int binary = 0; + CURLcode result = CURLE_AGAIN; + int code; + char *info = NULL; + + (void)len; + (void)buf; + (void)sockindex; + + rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg); + if(rc < 0) { + failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc)); + result = CURLE_RECV_ERROR; + } + + *err = result; + + /* error or timed out */ + if(!msg) + return -1; + + result = CURLE_OK; + + switch(ldap_msgtype(msg)) { + case LDAP_RES_SEARCH_RESULT: + lr->msgid = 0; + rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0); + if(rc) { + failf(data, "LDAP local: search ldap_parse_result %s", + ldap_err2string(rc)); + result = CURLE_LDAP_SEARCH_FAILED; + break; + } + + /* store the latest code for later retrieval */ + data->info.httpcode = code; + + switch(code) { + case LDAP_SIZELIMIT_EXCEEDED: + infof(data, "There are more than %d entries", lr->nument); + FALLTHROUGH(); + case LDAP_SUCCESS: + data->req.size = data->req.bytecount; + break; + default: + failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code), + info ? info : ""); + result = CURLE_LDAP_SEARCH_FAILED; + break; + } + if(info) + ldap_memfree(info); + break; + case LDAP_RES_SEARCH_ENTRY: + lr->nument++; + rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv); + if(rc < 0) { + result = CURLE_RECV_ERROR; + break; + } + + result = client_write(data, STRCONST("DN: "), bv.bv_val, bv.bv_len, + STRCONST("\n")); + if(result) + break; + + for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) { + int i; + + if(!bv.bv_val) + break; + + if(!bvals) { + result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len, + STRCONST(":\n")); + if(result) + break; + continue; + } + + binary = bv.bv_len > 7 && + !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7); + + for(i = 0; bvals[i].bv_val != NULL; i++) { + int binval = 0; + + result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len, + STRCONST(":")); + if(result) + break; + + if(!binary) { + /* check for leading or trailing whitespace */ + if(ISBLANK(bvals[i].bv_val[0]) || + ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1])) + binval = 1; + else { + /* check for unprintable characters */ + unsigned int j; + for(j = 0; j < bvals[i].bv_len; j++) + if(!ISPRINT(bvals[i].bv_val[j])) { + binval = 1; + break; + } + } + } + if(binary || binval) { + char *val_b64 = NULL; + size_t val_b64_sz = 0; + + /* Binary value, encode to base64. */ + if(bvals[i].bv_len) + result = Curl_base64_encode(bvals[i].bv_val, bvals[i].bv_len, + &val_b64, &val_b64_sz); + if(!result) + result = client_write(data, STRCONST(": "), val_b64, val_b64_sz, + STRCONST("\n")); + free(val_b64); + } + else + result = client_write(data, STRCONST(" "), + bvals[i].bv_val, bvals[i].bv_len, + STRCONST("\n")); + if(result) + break; + } + + ber_memfree(bvals); + bvals = NULL; + if(!result) + result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0); + if(result) + break; + } + + ber_free(ber, 0); + + if(!result) + result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0); + if(!result) + result = CURLE_AGAIN; + break; + } + + ldap_msgfree(msg); + *err = result; + return result? -1: 0; +} + +#ifdef USE_SSL +static int +ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg) +{ + sbiod->sbiod_pvt = arg; + return 0; +} + +static int +ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod) +{ + sbiod->sbiod_pvt = NULL; + return 0; +} + +/* We don't need to do anything because libcurl does it already */ +static int +ldapsb_tls_close(Sockbuf_IO_Desc *sbiod) +{ + (void)sbiod; + return 0; +} + +static int +ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg) +{ + (void)arg; + if(opt == LBER_SB_OPT_DATA_READY) { + struct Curl_easy *data = sbiod->sbiod_pvt; + return Curl_conn_data_pending(data, FIRSTSOCKET); + } + return 0; +} + +static ber_slen_t +ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct Curl_easy *data = sbiod->sbiod_pvt; + ber_slen_t ret = 0; + if(data) { + struct connectdata *conn = data->conn; + if(conn) { + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode err = CURLE_RECV_ERROR; + + ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err); + if(ret < 0 && err == CURLE_AGAIN) { + SET_SOCKERRNO(EWOULDBLOCK); + } + } + } + return ret; +} + +static ber_slen_t +ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct Curl_easy *data = sbiod->sbiod_pvt; + ber_slen_t ret = 0; + if(data) { + struct connectdata *conn = data->conn; + if(conn) { + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode err = CURLE_SEND_ERROR; + ret = (li->send)(data, FIRSTSOCKET, buf, len, &err); + if(ret < 0 && err == CURLE_AGAIN) { + SET_SOCKERRNO(EWOULDBLOCK); + } + } + } + return ret; +} + +static Sockbuf_IO ldapsb_tls = +{ + ldapsb_tls_setup, + ldapsb_tls_remove, + ldapsb_tls_ctrl, + ldapsb_tls_read, + ldapsb_tls_write, + ldapsb_tls_close +}; +#endif /* USE_SSL */ + +#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */ diff --git a/lib/parsedate.c b/lib/parsedate.c new file mode 100644 index 0000000..1a7195b --- /dev/null +++ b/lib/parsedate.c @@ -0,0 +1,644 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* + A brief summary of the date string formats this parser groks: + + RFC 2616 3.3.1 + + Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + + we support dates without week day name: + + 06 Nov 1994 08:49:37 GMT + 06-Nov-94 08:49:37 GMT + Nov 6 08:49:37 1994 + + without the time zone: + + 06 Nov 1994 08:49:37 + 06-Nov-94 08:49:37 + + weird order: + + 1994 Nov 6 08:49:37 (GNU date fails) + GMT 08:49:37 06-Nov-94 Sunday + 94 6 Nov 08:49:37 (GNU date fails) + + time left out: + + 1994 Nov 6 + 06-Nov-94 + Sun Nov 6 94 + + unusual separators: + + 1994.Nov.6 + Sun/Nov/6/94/GMT + + commonly used time zone names: + + Sun, 06 Nov 1994 08:49:37 CET + 06 Nov 1994 08:49:37 EST + + time zones specified using RFC822 style: + + Sun, 12 Sep 2004 15:05:58 -0700 + Sat, 11 Sep 2004 21:32:11 +0200 + + compact numerical date strings: + + 20040912 15:05:58 -0700 + 20040911 +0200 + +*/ + +#include "curl_setup.h" + +#include + +#include +#include "strcase.h" +#include "warnless.h" +#include "parsedate.h" + +/* + * parsedate() + * + * Returns: + * + * PARSEDATE_OK - a fine conversion + * PARSEDATE_FAIL - failed to convert + * PARSEDATE_LATER - time overflow at the far end of time_t + * PARSEDATE_SOONER - time underflow at the low end of time_t + */ + +static int parsedate(const char *date, time_t *output); + +#define PARSEDATE_OK 0 +#define PARSEDATE_FAIL -1 +#define PARSEDATE_LATER 1 +#define PARSEDATE_SOONER 2 + +#if !defined(CURL_DISABLE_PARSEDATE) || !defined(CURL_DISABLE_FTP) || \ + !defined(CURL_DISABLE_FILE) +/* These names are also used by FTP and FILE code */ +const char * const Curl_wkday[] = +{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; +const char * const Curl_month[]= +{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +#endif + +#ifndef CURL_DISABLE_PARSEDATE +static const char * const weekday[] = +{ "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday", "Sunday" }; + +struct tzinfo { + char name[5]; + int offset; /* +/- in minutes */ +}; + +/* Here's a bunch of frequently used time zone names. These were supported + by the old getdate parser. */ +#define tDAYZONE -60 /* offset for daylight savings time */ +static const struct tzinfo tz[]= { + {"GMT", 0}, /* Greenwich Mean */ + {"UT", 0}, /* Universal Time */ + {"UTC", 0}, /* Universal (Coordinated) */ + {"WET", 0}, /* Western European */ + {"BST", 0 tDAYZONE}, /* British Summer */ + {"WAT", 60}, /* West Africa */ + {"AST", 240}, /* Atlantic Standard */ + {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */ + {"EST", 300}, /* Eastern Standard */ + {"EDT", 300 tDAYZONE}, /* Eastern Daylight */ + {"CST", 360}, /* Central Standard */ + {"CDT", 360 tDAYZONE}, /* Central Daylight */ + {"MST", 420}, /* Mountain Standard */ + {"MDT", 420 tDAYZONE}, /* Mountain Daylight */ + {"PST", 480}, /* Pacific Standard */ + {"PDT", 480 tDAYZONE}, /* Pacific Daylight */ + {"YST", 540}, /* Yukon Standard */ + {"YDT", 540 tDAYZONE}, /* Yukon Daylight */ + {"HST", 600}, /* Hawaii Standard */ + {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */ + {"CAT", 600}, /* Central Alaska */ + {"AHST", 600}, /* Alaska-Hawaii Standard */ + {"NT", 660}, /* Nome */ + {"IDLW", 720}, /* International Date Line West */ + {"CET", -60}, /* Central European */ + {"MET", -60}, /* Middle European */ + {"MEWT", -60}, /* Middle European Winter */ + {"MEST", -60 tDAYZONE}, /* Middle European Summer */ + {"CEST", -60 tDAYZONE}, /* Central European Summer */ + {"MESZ", -60 tDAYZONE}, /* Middle European Summer */ + {"FWT", -60}, /* French Winter */ + {"FST", -60 tDAYZONE}, /* French Summer */ + {"EET", -120}, /* Eastern Europe, USSR Zone 1 */ + {"WAST", -420}, /* West Australian Standard */ + {"WADT", -420 tDAYZONE}, /* West Australian Daylight */ + {"CCT", -480}, /* China Coast, USSR Zone 7 */ + {"JST", -540}, /* Japan Standard, USSR Zone 8 */ + {"EAST", -600}, /* Eastern Australian Standard */ + {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */ + {"GST", -600}, /* Guam Standard, USSR Zone 9 */ + {"NZT", -720}, /* New Zealand */ + {"NZST", -720}, /* New Zealand Standard */ + {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */ + {"IDLE", -720}, /* International Date Line East */ + /* Next up: Military timezone names. RFC822 allowed these, but (as noted in + RFC 1123) had their signs wrong. Here we use the correct signs to match + actual military usage. + */ + {"A", 1 * 60}, /* Alpha */ + {"B", 2 * 60}, /* Bravo */ + {"C", 3 * 60}, /* Charlie */ + {"D", 4 * 60}, /* Delta */ + {"E", 5 * 60}, /* Echo */ + {"F", 6 * 60}, /* Foxtrot */ + {"G", 7 * 60}, /* Golf */ + {"H", 8 * 60}, /* Hotel */ + {"I", 9 * 60}, /* India */ + /* "J", Juliet is not used as a timezone, to indicate the observer's local + time */ + {"K", 10 * 60}, /* Kilo */ + {"L", 11 * 60}, /* Lima */ + {"M", 12 * 60}, /* Mike */ + {"N", -1 * 60}, /* November */ + {"O", -2 * 60}, /* Oscar */ + {"P", -3 * 60}, /* Papa */ + {"Q", -4 * 60}, /* Quebec */ + {"R", -5 * 60}, /* Romeo */ + {"S", -6 * 60}, /* Sierra */ + {"T", -7 * 60}, /* Tango */ + {"U", -8 * 60}, /* Uniform */ + {"V", -9 * 60}, /* Victor */ + {"W", -10 * 60}, /* Whiskey */ + {"X", -11 * 60}, /* X-ray */ + {"Y", -12 * 60}, /* Yankee */ + {"Z", 0}, /* Zulu, zero meridian, a.k.a. UTC */ +}; + +/* returns: + -1 no day + 0 monday - 6 sunday +*/ + +static int checkday(const char *check, size_t len) +{ + int i; + const char * const *what; + if(len > 3) + what = &weekday[0]; + else if(len == 3) + what = &Curl_wkday[0]; + else + return -1; /* too short */ + for(i = 0; i<7; i++) { + size_t ilen = strlen(what[0]); + if((ilen == len) && + strncasecompare(check, what[0], len)) + return i; + what++; + } + return -1; +} + +static int checkmonth(const char *check, size_t len) +{ + int i; + const char * const *what = &Curl_month[0]; + if(len != 3) + return -1; /* not a month */ + + for(i = 0; i<12; i++) { + if(strncasecompare(check, what[0], 3)) + return i; + what++; + } + return -1; /* return the offset or -1, no real offset is -1 */ +} + +/* return the time zone offset between GMT and the input one, in number + of seconds or -1 if the timezone wasn't found/legal */ + +static int checktz(const char *check, size_t len) +{ + unsigned int i; + const struct tzinfo *what = tz; + if(len > 4) /* longer than any valid timezone */ + return -1; + + for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) { + size_t ilen = strlen(what->name); + if((ilen == len) && + strncasecompare(check, what->name, len)) + return what->offset*60; + what++; + } + return -1; +} + +static void skip(const char **date) +{ + /* skip everything that aren't letters or digits */ + while(**date && !ISALNUM(**date)) + (*date)++; +} + +enum assume { + DATE_MDAY, + DATE_YEAR, + DATE_TIME +}; + +/* + * time2epoch: time stamp to seconds since epoch in GMT time zone. Similar to + * mktime but for GMT only. + */ +static time_t time2epoch(int sec, int min, int hour, + int mday, int mon, int year) +{ + static const int month_days_cumulative [12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int leap_days = year - (mon <= 1); + leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400) + - (1969 / 4) + (1969 / 100) - (1969 / 400)); + return ((((time_t) (year - 1970) * 365 + + leap_days + month_days_cumulative[mon] + mday - 1) * 24 + + hour) * 60 + min) * 60 + sec; +} + +/* Returns the value of a single-digit or two-digit decimal number, return + then pointer to after the number. The 'date' pointer is known to point to a + digit. */ +static int oneortwodigit(const char *date, const char **endp) +{ + int num = date[0] - '0'; + if(ISDIGIT(date[1])) { + *endp = &date[2]; + return num*10 + (date[1] - '0'); + } + *endp = &date[1]; + return num; +} + + +/* HH:MM:SS or HH:MM and accept single-digits too */ +static bool match_time(const char *date, + int *h, int *m, int *s, char **endp) +{ + const char *p; + int hh, mm, ss = 0; + hh = oneortwodigit(date, &p); + if((hh < 24) && (*p == ':') && ISDIGIT(p[1])) { + mm = oneortwodigit(&p[1], &p); + if(mm < 60) { + if((*p == ':') && ISDIGIT(p[1])) { + ss = oneortwodigit(&p[1], &p); + if(ss <= 60) { + /* valid HH:MM:SS */ + goto match; + } + } + else { + /* valid HH:MM */ + goto match; + } + } + } + return FALSE; /* not a time string */ +match: + *h = hh; + *m = mm; + *s = ss; + *endp = (char *)p; + return TRUE; +} + +/* + * parsedate() + * + * Returns: + * + * PARSEDATE_OK - a fine conversion + * PARSEDATE_FAIL - failed to convert + * PARSEDATE_LATER - time overflow at the far end of time_t + * PARSEDATE_SOONER - time underflow at the low end of time_t + */ + +/* Wednesday is the longest name this parser knows about */ +#define NAME_LEN 12 + +static int parsedate(const char *date, time_t *output) +{ + time_t t = 0; + int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */ + int monnum = -1; /* month of the year number, 0-11 */ + int mdaynum = -1; /* day of month, 1 - 31 */ + int hournum = -1; + int minnum = -1; + int secnum = -1; + int yearnum = -1; + int tzoff = -1; + enum assume dignext = DATE_MDAY; + const char *indate = date; /* save the original pointer */ + int part = 0; /* max 6 parts */ + + while(*date && (part < 6)) { + bool found = FALSE; + + skip(&date); + + if(ISALPHA(*date)) { + /* a name coming up */ + size_t len = 0; + const char *p = date; + while(ISALPHA(*p) && (len < NAME_LEN)) { + p++; + len++; + } + + if(len != NAME_LEN) { + if(wdaynum == -1) { + wdaynum = checkday(date, len); + if(wdaynum != -1) + found = TRUE; + } + if(!found && (monnum == -1)) { + monnum = checkmonth(date, len); + if(monnum != -1) + found = TRUE; + } + + if(!found && (tzoff == -1)) { + /* this just must be a time zone string */ + tzoff = checktz(date, len); + if(tzoff != -1) + found = TRUE; + } + } + if(!found) + return PARSEDATE_FAIL; /* bad string */ + + date += len; + } + else if(ISDIGIT(*date)) { + /* a digit */ + int val; + char *end; + if((secnum == -1) && + match_time(date, &hournum, &minnum, &secnum, &end)) { + /* time stamp */ + date = end; + } + else { + long lval; + int error; + int old_errno; + + old_errno = errno; + errno = 0; + lval = strtol(date, &end, 10); + error = errno; + if(errno != old_errno) + errno = old_errno; + + if(error) + return PARSEDATE_FAIL; + +#if LONG_MAX != INT_MAX + if((lval > (long)INT_MAX) || (lval < (long)INT_MIN)) + return PARSEDATE_FAIL; +#endif + + val = curlx_sltosi(lval); + + if((tzoff == -1) && + ((end - date) == 4) && + (val <= 1400) && + (indate< date) && + ((date[-1] == '+' || date[-1] == '-'))) { + /* four digits and a value less than or equal to 1400 (to take into + account all sorts of funny time zone diffs) and it is preceded + with a plus or minus. This is a time zone indication. 1400 is + picked since +1300 is frequently used and +1400 is mentioned as + an edge number in the document "ISO C 200X Proposal: Timezone + Functions" at http://david.tribble.com/text/c0xtimezone.html If + anyone has a more authoritative source for the exact maximum time + zone offsets, please speak up! */ + found = TRUE; + tzoff = (val/100 * 60 + val%100)*60; + + /* the + and - prefix indicates the local time compared to GMT, + this we need their reversed math to get what we want */ + tzoff = date[-1]=='+'?-tzoff:tzoff; + } + + if(((end - date) == 8) && + (yearnum == -1) && + (monnum == -1) && + (mdaynum == -1)) { + /* 8 digits, no year, month or day yet. This is YYYYMMDD */ + found = TRUE; + yearnum = val/10000; + monnum = (val%10000)/100-1; /* month is 0 - 11 */ + mdaynum = val%100; + } + + if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { + if((val > 0) && (val<32)) { + mdaynum = val; + found = TRUE; + } + dignext = DATE_YEAR; + } + + if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { + yearnum = val; + found = TRUE; + if(yearnum < 100) { + if(yearnum > 70) + yearnum += 1900; + else + yearnum += 2000; + } + if(mdaynum == -1) + dignext = DATE_MDAY; + } + + if(!found) + return PARSEDATE_FAIL; + + date = end; + } + } + + part++; + } + + if(-1 == secnum) + secnum = minnum = hournum = 0; /* no time, make it zero */ + + if((-1 == mdaynum) || + (-1 == monnum) || + (-1 == yearnum)) + /* lacks vital info, fail */ + return PARSEDATE_FAIL; + +#ifdef HAVE_TIME_T_UNSIGNED + if(yearnum < 1970) { + /* only positive numbers cannot return earlier */ + *output = TIME_T_MIN; + return PARSEDATE_SOONER; + } +#endif + +#if (SIZEOF_TIME_T < 5) + +#ifdef HAVE_TIME_T_UNSIGNED + /* an unsigned 32 bit time_t can only hold dates to 2106 */ + if(yearnum > 2105) { + *output = TIME_T_MAX; + return PARSEDATE_LATER; + } +#else + /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */ + if(yearnum > 2037) { + *output = TIME_T_MAX; + return PARSEDATE_LATER; + } + if(yearnum < 1903) { + *output = TIME_T_MIN; + return PARSEDATE_SOONER; + } +#endif + +#else + /* The Gregorian calendar was introduced 1582 */ + if(yearnum < 1583) + return PARSEDATE_FAIL; +#endif + + if((mdaynum > 31) || (monnum > 11) || + (hournum > 23) || (minnum > 59) || (secnum > 60)) + return PARSEDATE_FAIL; /* clearly an illegal date */ + + /* time2epoch() returns a time_t. time_t is often 32 bits, sometimes even on + architectures that feature 64 bit 'long' but ultimately time_t is the + correct data type to use. + */ + t = time2epoch(secnum, minnum, hournum, mdaynum, monnum, yearnum); + + /* Add the time zone diff between local time zone and GMT. */ + if(tzoff == -1) + tzoff = 0; + + if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) { + *output = TIME_T_MAX; + return PARSEDATE_LATER; /* time_t overflow */ + } + + t += tzoff; + + *output = t; + + return PARSEDATE_OK; +} +#else +/* disabled */ +static int parsedate(const char *date, time_t *output) +{ + (void)date; + *output = 0; + return PARSEDATE_OK; /* a lie */ +} +#endif + +time_t curl_getdate(const char *p, const time_t *now) +{ + time_t parsed = -1; + int rc = parsedate(p, &parsed); + (void)now; /* legacy argument from the past that we ignore */ + + if(rc == PARSEDATE_OK) { + if(parsed == -1) + /* avoid returning -1 for a working scenario */ + parsed++; + return parsed; + } + /* everything else is fail */ + return -1; +} + +/* Curl_getdate_capped() differs from curl_getdate() in that this will return + TIME_T_MAX in case the parsed time value was too big, instead of an + error. */ + +time_t Curl_getdate_capped(const char *p) +{ + time_t parsed = -1; + int rc = parsedate(p, &parsed); + + switch(rc) { + case PARSEDATE_OK: + if(parsed == -1) + /* avoid returning -1 for a working scenario */ + parsed++; + return parsed; + case PARSEDATE_LATER: + /* this returns the maximum time value */ + return parsed; + default: + return -1; /* everything else is fail */ + } + /* UNREACHABLE */ +} + +/* + * Curl_gmtime() is a gmtime() replacement for portability. Do not use the + * gmtime_r() or gmtime() functions anywhere else but here. + * + */ + +CURLcode Curl_gmtime(time_t intime, struct tm *store) +{ + const struct tm *tm; +#ifdef HAVE_GMTIME_R + /* thread-safe version */ + tm = (struct tm *)gmtime_r(&intime, store); +#else + /* !checksrc! disable BANNEDFUNC 1 */ + tm = gmtime(&intime); + if(tm) + *store = *tm; /* copy the pointed struct to the local copy */ +#endif + + if(!tm) + return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_OK; +} diff --git a/lib/parsedate.h b/lib/parsedate.h new file mode 100644 index 0000000..84c37f1 --- /dev/null +++ b/lib/parsedate.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_PARSEDATE_H +#define HEADER_CURL_PARSEDATE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +extern const char * const Curl_wkday[7]; +extern const char * const Curl_month[12]; + +CURLcode Curl_gmtime(time_t intime, struct tm *store); + +/* Curl_getdate_capped() differs from curl_getdate() in that this will return + TIME_T_MAX in case the parsed time value was too big, instead of an + error. */ + +time_t Curl_getdate_capped(const char *p); + +#endif /* HEADER_CURL_PARSEDATE_H */ diff --git a/lib/pingpong.c b/lib/pingpong.c new file mode 100644 index 0000000..b976ffb --- /dev/null +++ b/lib/pingpong.c @@ -0,0 +1,429 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * 'pingpong' is for generic back-and-forth support functions used by FTP, + * IMAP, POP3, SMTP and whatever more that likes them. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "urldata.h" +#include "cfilters.h" +#include "sendf.h" +#include "select.h" +#include "progress.h" +#include "speedcheck.h" +#include "pingpong.h" +#include "multiif.h" +#include "vtls/vtls.h" +#include "strdup.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef USE_PINGPONG + +/* Returns timeout in ms. 0 or negative number means the timeout has already + triggered */ +timediff_t Curl_pp_state_timeout(struct Curl_easy *data, + struct pingpong *pp, bool disconnecting) +{ + struct connectdata *conn = data->conn; + timediff_t timeout_ms; /* in milliseconds */ + timediff_t response_time = (data->set.server_response_timeout)? + data->set.server_response_timeout: pp->response_time; + + /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine + remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is + supposed to govern the response for any given server response, not for + the time from connect to the given server response. */ + + /* Without a requested timeout, we only wait 'response_time' seconds for the + full response to arrive before we bail out */ + timeout_ms = response_time - + Curl_timediff(Curl_now(), pp->response); /* spent time */ + + if(data->set.timeout && !disconnecting) { + /* if timeout is requested, find out how much remaining time we have */ + timediff_t timeout2_ms = data->set.timeout - /* timeout time */ + Curl_timediff(Curl_now(), conn->now); /* spent time */ + + /* pick the lowest number */ + timeout_ms = CURLMIN(timeout_ms, timeout2_ms); + } + + return timeout_ms; +} + +/* + * Curl_pp_statemach() + */ +CURLcode Curl_pp_statemach(struct Curl_easy *data, + struct pingpong *pp, bool block, + bool disconnecting) +{ + struct connectdata *conn = data->conn; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc; + timediff_t interval_ms; + timediff_t timeout_ms = Curl_pp_state_timeout(data, pp, disconnecting); + CURLcode result = CURLE_OK; + + if(timeout_ms <= 0) { + failf(data, "server response timeout"); + return CURLE_OPERATION_TIMEDOUT; /* already too little time */ + } + + if(block) { + interval_ms = 1000; /* use 1 second timeout intervals */ + if(timeout_ms < interval_ms) + interval_ms = timeout_ms; + } + else + interval_ms = 0; /* immediate */ + + if(Curl_conn_data_pending(data, FIRSTSOCKET)) + rc = 1; + else if(pp->overflow) + /* We are receiving and there is data in the cache so just read it */ + rc = 1; + else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET)) + /* We are receiving and there is data ready in the SSL library */ + rc = 1; + else + rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + CURL_SOCKET_BAD, + pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ + interval_ms); + + if(block) { + /* if we didn't wait, we don't have to spend time on this now */ + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, Curl_now()); + + if(result) + return result; + } + + if(rc == -1) { + failf(data, "select/poll error"); + result = CURLE_OUT_OF_MEMORY; + } + else if(rc) + result = pp->statemachine(data, data->conn); + + return result; +} + +/* initialize stuff to prepare for reading a fresh new response */ +void Curl_pp_init(struct pingpong *pp) +{ + pp->nread_resp = 0; + pp->response = Curl_now(); /* start response time-out now! */ + pp->pending_resp = TRUE; + Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD); + Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD); +} + +/*********************************************************************** + * + * Curl_pp_vsendf() + * + * Send the formatted string as a command to a pingpong server. Note that + * the string should not have any CRLF appended, as this function will + * append the necessary things itself. + * + * made to never block + */ +CURLcode Curl_pp_vsendf(struct Curl_easy *data, + struct pingpong *pp, + const char *fmt, + va_list args) +{ + ssize_t bytes_written = 0; + size_t write_len; + char *s; + CURLcode result; + struct connectdata *conn = data->conn; + +#ifdef HAVE_GSSAPI + enum protection_level data_sec; +#endif + + DEBUGASSERT(pp->sendleft == 0); + DEBUGASSERT(pp->sendsize == 0); + DEBUGASSERT(pp->sendthis == NULL); + + if(!conn) + /* can't send without a connection! */ + return CURLE_SEND_ERROR; + + Curl_dyn_reset(&pp->sendbuf); + result = Curl_dyn_vaddf(&pp->sendbuf, fmt, args); + if(result) + return result; + + /* append CRLF */ + result = Curl_dyn_addn(&pp->sendbuf, "\r\n", 2); + if(result) + return result; + + pp->pending_resp = TRUE; + write_len = Curl_dyn_len(&pp->sendbuf); + s = Curl_dyn_ptr(&pp->sendbuf); + +#ifdef HAVE_GSSAPI + conn->data_prot = PROT_CMD; +#endif + result = Curl_nwrite(data, FIRSTSOCKET, s, write_len, &bytes_written); + if(result) + return result; +#ifdef HAVE_GSSAPI + data_sec = conn->data_prot; + DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); + conn->data_prot = (unsigned char)data_sec; +#endif + + Curl_debug(data, CURLINFO_HEADER_OUT, s, (size_t)bytes_written); + + if(bytes_written != (ssize_t)write_len) { + /* the whole chunk was not sent, keep it around and adjust sizes */ + pp->sendthis = s; + pp->sendsize = write_len; + pp->sendleft = write_len - bytes_written; + } + else { + pp->sendthis = NULL; + pp->sendleft = pp->sendsize = 0; + pp->response = Curl_now(); + } + + return CURLE_OK; +} + + +/*********************************************************************** + * + * Curl_pp_sendf() + * + * Send the formatted string as a command to a pingpong server. Note that + * the string should not have any CRLF appended, as this function will + * append the necessary things itself. + * + * made to never block + */ +CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp, + const char *fmt, ...) +{ + CURLcode result; + va_list ap; + va_start(ap, fmt); + + result = Curl_pp_vsendf(data, pp, fmt, ap); + + va_end(ap); + + return result; +} + +static CURLcode pingpong_read(struct Curl_easy *data, + curl_socket_t sockfd, + char *buffer, + size_t buflen, + ssize_t *nread) +{ + CURLcode result; +#ifdef HAVE_GSSAPI + enum protection_level prot = data->conn->data_prot; + data->conn->data_prot = PROT_CLEAR; +#endif + result = Curl_read(data, sockfd, buffer, buflen, nread); +#ifdef HAVE_GSSAPI + DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); + data->conn->data_prot = (unsigned char)prot; +#endif + return result; +} + +/* + * Curl_pp_readresp() + * + * Reads a piece of a server response. + */ +CURLcode Curl_pp_readresp(struct Curl_easy *data, + curl_socket_t sockfd, + struct pingpong *pp, + int *code, /* return the server code if done */ + size_t *size) /* size of the response */ +{ + struct connectdata *conn = data->conn; + CURLcode result = CURLE_OK; + + *code = 0; /* 0 for errors or not done */ + *size = 0; + + if(pp->nfinal) { + /* a previous call left this many bytes in the beginning of the buffer as + that was the final line; now ditch that */ + size_t full = Curl_dyn_len(&pp->recvbuf); + + /* trim off the "final" leading part */ + Curl_dyn_tail(&pp->recvbuf, full - pp->nfinal); + + pp->nfinal = 0; /* now gone */ + } + if(!pp->overflow) { + ssize_t gotbytes = 0; + char buffer[900]; + + result = pingpong_read(data, sockfd, buffer, sizeof(buffer), &gotbytes); + if(result == CURLE_AGAIN) + return CURLE_OK; + + if(result) + return result; + + if(gotbytes <= 0) { + failf(data, "response reading failed (errno: %d)", SOCKERRNO); + return CURLE_RECV_ERROR; + } + + result = Curl_dyn_addn(&pp->recvbuf, buffer, gotbytes); + if(result) + return result; + + data->req.headerbytecount += (unsigned int)gotbytes; + + pp->nread_resp += gotbytes; + } + + do { + char *line = Curl_dyn_ptr(&pp->recvbuf); + char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf)); + if(nl) { + /* a newline is CRLF in pp-talk, so the CR is ignored as + the line isn't really terminated until the LF comes */ + size_t length = nl - line + 1; + + /* output debug output if that is requested */ +#ifdef HAVE_GSSAPI + if(!conn->sec_complete) +#endif + Curl_debug(data, CURLINFO_HEADER_IN, line, length); + + /* + * Pass all response-lines to the callback function registered for + * "headers". The response lines can be seen as a kind of headers. + */ + result = Curl_client_write(data, CLIENTWRITE_INFO, line, length); + if(result) + return result; + + if(pp->endofresp(data, conn, line, length, code)) { + /* When at "end of response", keep the endofresp line first in the + buffer since it will be accessed outside (by pingpong + parsers). Store the overflow counter to inform about additional + data in this buffer after the endofresp line. */ + pp->nfinal = length; + if(Curl_dyn_len(&pp->recvbuf) > length) + pp->overflow = Curl_dyn_len(&pp->recvbuf) - length; + else + pp->overflow = 0; + *size = pp->nread_resp; /* size of the response */ + pp->nread_resp = 0; /* restart */ + break; + } + if(Curl_dyn_len(&pp->recvbuf) > length) + /* keep the remaining piece */ + Curl_dyn_tail((&pp->recvbuf), Curl_dyn_len(&pp->recvbuf) - length); + else + Curl_dyn_reset(&pp->recvbuf); + } + else { + /* without a newline, there is no overflow */ + pp->overflow = 0; + break; + } + + } while(1); /* while there's buffer left to scan */ + + pp->pending_resp = FALSE; + + return result; +} + +int Curl_pp_getsock(struct Curl_easy *data, + struct pingpong *pp, curl_socket_t *socks) +{ + struct connectdata *conn = data->conn; + socks[0] = conn->sock[FIRSTSOCKET]; + + if(pp->sendleft) { + /* write mode */ + return GETSOCK_WRITESOCK(0); + } + + /* read mode */ + return GETSOCK_READSOCK(0); +} + +CURLcode Curl_pp_flushsend(struct Curl_easy *data, + struct pingpong *pp) +{ + /* we have a piece of a command still left to send */ + ssize_t written; + CURLcode result = Curl_nwrite(data, FIRSTSOCKET, + pp->sendthis + pp->sendsize - pp->sendleft, + pp->sendleft, &written); + if(result) + return result; + + if(written != (ssize_t)pp->sendleft) { + /* only a fraction was sent */ + pp->sendleft -= written; + } + else { + pp->sendthis = NULL; + pp->sendleft = pp->sendsize = 0; + pp->response = Curl_now(); + } + return CURLE_OK; +} + +CURLcode Curl_pp_disconnect(struct pingpong *pp) +{ + Curl_dyn_free(&pp->sendbuf); + Curl_dyn_free(&pp->recvbuf); + return CURLE_OK; +} + +bool Curl_pp_moredata(struct pingpong *pp) +{ + return (!pp->sendleft && Curl_dyn_len(&pp->recvbuf)); +} + +#endif diff --git a/lib/pingpong.h b/lib/pingpong.h new file mode 100644 index 0000000..006b9c5 --- /dev/null +++ b/lib/pingpong.h @@ -0,0 +1,160 @@ +#ifndef HEADER_CURL_PINGPONG_H +#define HEADER_CURL_PINGPONG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \ + !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP) +#define USE_PINGPONG +#endif + +/* forward-declaration, this is defined in urldata.h */ +struct connectdata; + +typedef enum { + PPTRANSFER_BODY, /* yes do transfer a body */ + PPTRANSFER_INFO, /* do still go through to get info/headers */ + PPTRANSFER_NONE /* don't get anything and don't get info */ +} curl_pp_transfer; + +/* + * 'pingpong' is the generic struct used for protocols doing server<->client + * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc. + * + * It holds response cache and non-blocking sending data. + */ +struct pingpong { + size_t nread_resp; /* number of bytes currently read of a server response */ + bool pending_resp; /* set TRUE when a server response is pending or in + progress, and is cleared once the last response is + read */ + char *sendthis; /* pointer to a buffer that is to be sent to the server */ + size_t sendleft; /* number of bytes left to send from the sendthis buffer */ + size_t sendsize; /* total size of the sendthis buffer */ + struct curltime response; /* set to Curl_now() when a command has been sent + off, used to time-out response reading */ + timediff_t response_time; /* When no timeout is given, this is the amount of + milliseconds we await for a server response. */ + struct dynbuf sendbuf; + struct dynbuf recvbuf; + size_t overflow; /* number of bytes left after a final response line */ + size_t nfinal; /* number of bytes in the final response line, which + after a match is first in the receice buffer */ + + /* Function pointers the protocols MUST implement and provide for the + pingpong layer to function */ + + CURLcode (*statemachine)(struct Curl_easy *data, struct connectdata *conn); + bool (*endofresp)(struct Curl_easy *data, struct connectdata *conn, + char *ptr, size_t len, int *code); +}; + +#define PINGPONG_SETUP(pp,s,e) \ + do { \ + pp->response_time = RESP_TIMEOUT; \ + pp->statemachine = s; \ + pp->endofresp = e; \ + } while(0) + +/* + * Curl_pp_statemach() + * + * called repeatedly until done. Set 'wait' to make it wait a while on the + * socket if there's no traffic. + */ +CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp, + bool block, bool disconnecting); + +/* initialize stuff to prepare for reading a fresh new response */ +void Curl_pp_init(struct pingpong *pp); + +/* Returns timeout in ms. 0 or negative number means the timeout has already + triggered */ +timediff_t Curl_pp_state_timeout(struct Curl_easy *data, + struct pingpong *pp, bool disconnecting); + + +/*********************************************************************** + * + * Curl_pp_sendf() + * + * Send the formatted string as a command to a pingpong server. Note that + * the string should not have any CRLF appended, as this function will + * append the necessary things itself. + * + * made to never block + */ +CURLcode Curl_pp_sendf(struct Curl_easy *data, + struct pingpong *pp, + const char *fmt, ...) CURL_PRINTF(3, 4); + +/*********************************************************************** + * + * Curl_pp_vsendf() + * + * Send the formatted string as a command to a pingpong server. Note that + * the string should not have any CRLF appended, as this function will + * append the necessary things itself. + * + * made to never block + */ +CURLcode Curl_pp_vsendf(struct Curl_easy *data, + struct pingpong *pp, + const char *fmt, + va_list args) CURL_PRINTF(3, 0); + +/* + * Curl_pp_readresp() + * + * Reads a piece of a server response. + */ +CURLcode Curl_pp_readresp(struct Curl_easy *data, + curl_socket_t sockfd, + struct pingpong *pp, + int *code, /* return the server code if done */ + size_t *size); /* size of the response */ + + +CURLcode Curl_pp_flushsend(struct Curl_easy *data, + struct pingpong *pp); + +/* call this when a pingpong connection is disconnected */ +CURLcode Curl_pp_disconnect(struct pingpong *pp); + +int Curl_pp_getsock(struct Curl_easy *data, struct pingpong *pp, + curl_socket_t *socks); + + +/*********************************************************************** + * + * Curl_pp_moredata() + * + * Returns whether there are still more data in the cache and so a call + * to Curl_pp_readresp() will not block. + */ +bool Curl_pp_moredata(struct pingpong *pp); + +#endif /* HEADER_CURL_PINGPONG_H */ diff --git a/lib/pop3.c b/lib/pop3.c new file mode 100644 index 0000000..cf25192 --- /dev/null +++ b/lib/pop3.c @@ -0,0 +1,1583 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC1734 POP3 Authentication + * RFC1939 POP3 protocol + * RFC2195 CRAM-MD5 authentication + * RFC2384 POP URL Scheme + * RFC2449 POP3 Extension Mechanism + * RFC2595 Using TLS with IMAP, POP3 and ACAP + * RFC2831 DIGEST-MD5 authentication + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4616 PLAIN authentication + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * RFC5034 POP3 SASL Authentication Mechanism + * RFC6749 OAuth 2.0 Authorization Framework + * RFC8314 Use of TLS for Email Submission and Access + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_POP3 + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "socks.h" +#include "pop3.h" +#include "strtoofft.h" +#include "strcase.h" +#include "vtls/vtls.h" +#include "cfilters.h" +#include "connect.h" +#include "select.h" +#include "multiif.h" +#include "url.h" +#include "bufref.h" +#include "curl_sasl.h" +#include "curl_md5.h" +#include "warnless.h" +#include "strdup.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* Local API functions */ +static CURLcode pop3_regular_transfer(struct Curl_easy *data, bool *done); +static CURLcode pop3_do(struct Curl_easy *data, bool *done); +static CURLcode pop3_done(struct Curl_easy *data, CURLcode status, + bool premature); +static CURLcode pop3_connect(struct Curl_easy *data, bool *done); +static CURLcode pop3_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); +static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done); +static int pop3_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); +static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done); +static CURLcode pop3_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static CURLcode pop3_parse_url_options(struct connectdata *conn); +static CURLcode pop3_parse_url_path(struct Curl_easy *data); +static CURLcode pop3_parse_custom_request(struct Curl_easy *data); +static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out); + +/* + * POP3 protocol handler. + */ + +const struct Curl_handler Curl_handler_pop3 = { + "POP3", /* scheme */ + pop3_setup_connection, /* setup_connection */ + pop3_do, /* do_it */ + pop3_done, /* done */ + ZERO_NULL, /* do_more */ + pop3_connect, /* connect_it */ + pop3_multi_statemach, /* connecting */ + pop3_doing, /* doing */ + pop3_getsock, /* proto_getsock */ + pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + pop3_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_POP3, /* defport */ + CURLPROTO_POP3, /* protocol */ + CURLPROTO_POP3, /* family */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ + PROTOPT_URLOPTIONS +}; + +#ifdef USE_SSL +/* + * POP3S protocol handler. + */ + +const struct Curl_handler Curl_handler_pop3s = { + "POP3S", /* scheme */ + pop3_setup_connection, /* setup_connection */ + pop3_do, /* do_it */ + pop3_done, /* done */ + ZERO_NULL, /* do_more */ + pop3_connect, /* connect_it */ + pop3_multi_statemach, /* connecting */ + pop3_doing, /* doing */ + pop3_getsock, /* proto_getsock */ + pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + pop3_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_POP3S, /* defport */ + CURLPROTO_POP3S, /* protocol */ + CURLPROTO_POP3, /* family */ + PROTOPT_CLOSEACTION | PROTOPT_SSL + | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ +}; +#endif + +/* SASL parameters for the pop3 protocol */ +static const struct SASLproto saslpop3 = { + "pop", /* The service name */ + pop3_perform_auth, /* Send authentication command */ + pop3_continue_auth, /* Send authentication continuation */ + pop3_cancel_auth, /* Send authentication cancellation */ + pop3_get_message, /* Get SASL response message */ + 255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */ + '*', /* Code received when continuation is expected */ + '+', /* Code to receive upon authentication success */ + SASL_AUTH_DEFAULT, /* Default mechanisms */ + SASL_FLAG_BASE64 /* Configuration flags */ +}; + +#ifdef USE_SSL +static void pop3_to_pop3s(struct connectdata *conn) +{ + /* Change the connection handler */ + conn->handler = &Curl_handler_pop3s; + + /* Set the connection's upgraded to TLS flag */ + conn->bits.tls_upgraded = TRUE; +} +#else +#define pop3_to_pop3s(x) Curl_nop_stmt +#endif + +/*********************************************************************** + * + * pop3_endofresp() + * + * Checks for an ending POP3 status code at the start of the given string, but + * also detects the APOP timestamp from the server greeting and various + * capabilities from the CAPA response including the supported authentication + * types and allowed SASL mechanisms. + */ +static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn, + char *line, size_t len, int *resp) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + (void)data; + + /* Do we have an error response? */ + if(len >= 4 && !memcmp("-ERR", line, 4)) { + *resp = '-'; + + return TRUE; + } + + /* Are we processing CAPA command responses? */ + if(pop3c->state == POP3_CAPA) { + /* Do we have the terminating line? */ + if(len >= 1 && line[0] == '.') + /* Treat the response as a success */ + *resp = '+'; + else + /* Treat the response as an untagged continuation */ + *resp = '*'; + + return TRUE; + } + + /* Do we have a success response? */ + if(len >= 3 && !memcmp("+OK", line, 3)) { + *resp = '+'; + + return TRUE; + } + + /* Do we have a continuation response? */ + if(len >= 1 && line[0] == '+') { + *resp = '*'; + + return TRUE; + } + + return FALSE; /* Nothing for us */ +} + +/*********************************************************************** + * + * pop3_get_message() + * + * Gets the authentication message from the response buffer. + */ +static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out) +{ + char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); + size_t len = data->conn->proto.pop3c.pp.nfinal; + + if(len > 2) { + /* Find the start of the message */ + len -= 2; + for(message += 2; *message == ' ' || *message == '\t'; message++, len--) + ; + + /* Find the end of the message */ + while(len--) + if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && + message[len] != '\t') + break; + + /* Terminate the message */ + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); + } + else + /* junk input => zero length output */ + Curl_bufref_set(out, "", 0, NULL); + + return CURLE_OK; +} + +/*********************************************************************** + * + * pop3_state() + * + * This is the ONLY way to change POP3 state! + */ +static void pop3_state(struct Curl_easy *data, pop3state newstate) +{ + struct pop3_conn *pop3c = &data->conn->proto.pop3c; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[] = { + "STOP", + "SERVERGREET", + "CAPA", + "STARTTLS", + "UPGRADETLS", + "AUTH", + "APOP", + "USER", + "PASS", + "COMMAND", + "QUIT", + /* LAST */ + }; + + if(pop3c->state != newstate) + infof(data, "POP3 %p state change from %s to %s", + (void *)pop3c, names[pop3c->state], names[newstate]); +#endif + + pop3c->state = newstate; +} + +/*********************************************************************** + * + * pop3_perform_capa() + * + * Sends the CAPA command in order to obtain a list of server side supported + * capabilities. + */ +static CURLcode pop3_perform_capa(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ + pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ + pop3c->tls_supported = FALSE; /* Clear the TLS capability */ + + /* Send the CAPA command */ + result = Curl_pp_sendf(data, &pop3c->pp, "%s", "CAPA"); + + if(!result) + pop3_state(data, POP3_CAPA); + + return result; +} + +/*********************************************************************** + * + * pop3_perform_starttls() + * + * Sends the STLS command to start the upgrade to TLS. + */ +static CURLcode pop3_perform_starttls(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Send the STLS command */ + CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "STLS"); + + if(!result) + pop3_state(data, POP3_STARTTLS); + + return result; +} + +/*********************************************************************** + * + * pop3_perform_upgrade_tls() + * + * Performs the upgrade to TLS. + */ +static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Start the SSL connection */ + struct pop3_conn *pop3c = &conn->proto.pop3c; + CURLcode result; + bool ssldone = FALSE; + + if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { + result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); + if(result) + goto out; + } + + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); + + if(!result) { + pop3c->ssldone = ssldone; + if(pop3c->state != POP3_UPGRADETLS) + pop3_state(data, POP3_UPGRADETLS); + + if(pop3c->ssldone) { + pop3_to_pop3s(conn); + result = pop3_perform_capa(data, conn); + } + } +out: + return result; +} + +/*********************************************************************** + * + * pop3_perform_user() + * + * Sends a clear text USER command to authenticate with. + */ +static CURLcode pop3_perform_user(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!data->state.aptr.user) { + pop3_state(data, POP3_STOP); + + return result; + } + + /* Send the USER command */ + result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "USER %s", + conn->user ? conn->user : ""); + if(!result) + pop3_state(data, POP3_USER); + + return result; +} + +#ifndef CURL_DISABLE_DIGEST_AUTH +/*********************************************************************** + * + * pop3_perform_apop() + * + * Sends an APOP command to authenticate with. + */ +static CURLcode pop3_perform_apop(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + size_t i; + struct MD5_context *ctxt; + unsigned char digest[MD5_DIGEST_LEN]; + char secret[2 * MD5_DIGEST_LEN + 1]; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!data->state.aptr.user) { + pop3_state(data, POP3_STOP); + + return result; + } + + /* Create the digest */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp, + curlx_uztoui(strlen(pop3c->apoptimestamp))); + + Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd, + curlx_uztoui(strlen(conn->passwd))); + + /* Finalise the digest */ + Curl_MD5_final(ctxt, digest); + + /* Convert the calculated 16 octet digest into a 32 byte hex string */ + for(i = 0; i < MD5_DIGEST_LEN; i++) + msnprintf(&secret[2 * i], 3, "%02x", digest[i]); + + result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret); + + if(!result) + pop3_state(data, POP3_APOP); + + return result; +} +#endif + +/*********************************************************************** + * + * pop3_perform_auth() + * + * Sends an AUTH command allowing the client to login with the given SASL + * authentication mechanism. + */ +static CURLcode pop3_perform_auth(struct Curl_easy *data, + const char *mech, + const struct bufref *initresp) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &data->conn->proto.pop3c; + const char *ir = (const char *) Curl_bufref_ptr(initresp); + + if(ir) { /* AUTH ... */ + /* Send the AUTH command with the initial response */ + result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir); + } + else { + /* Send the AUTH command */ + result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s", mech); + } + + return result; +} + +/*********************************************************************** + * + * pop3_continue_auth() + * + * Sends SASL continuation data. + */ +static CURLcode pop3_continue_auth(struct Curl_easy *data, + const char *mech, + const struct bufref *resp) +{ + struct pop3_conn *pop3c = &data->conn->proto.pop3c; + + (void)mech; + + return Curl_pp_sendf(data, &pop3c->pp, + "%s", (const char *) Curl_bufref_ptr(resp)); +} + +/*********************************************************************** + * + * pop3_cancel_auth() + * + * Sends SASL cancellation. + */ +static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech) +{ + struct pop3_conn *pop3c = &data->conn->proto.pop3c; + + (void)mech; + + return Curl_pp_sendf(data, &pop3c->pp, "*"); +} + +/*********************************************************************** + * + * pop3_perform_authentication() + * + * Initiates the authentication sequence, with the appropriate SASL + * authentication mechanism, falling back to APOP and clear text should a + * common mechanism not be available between the client and server. + */ +static CURLcode pop3_perform_authentication(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + saslprogress progress = SASL_IDLE; + + /* Check we have enough data to authenticate with and end the + connect phase if we don't */ + if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) { + pop3_state(data, POP3_STOP); + return result; + } + + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { + /* Calculate the SASL login details */ + result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress); + + if(!result) + if(progress == SASL_INPROGRESS) + pop3_state(data, POP3_AUTH); + } + + if(!result && progress == SASL_IDLE) { +#ifndef CURL_DISABLE_DIGEST_AUTH + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) + /* Perform APOP authentication */ + result = pop3_perform_apop(data, conn); + else +#endif + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) + /* Perform clear text authentication */ + result = pop3_perform_user(data, conn); + else { + /* Other mechanisms not supported */ + infof(data, "No known authentication mechanisms supported"); + result = CURLE_LOGIN_DENIED; + } + } + + return result; +} + +/*********************************************************************** + * + * pop3_perform_command() + * + * Sends a POP3 based command. + */ +static CURLcode pop3_perform_command(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct POP3 *pop3 = data->req.p.pop3; + const char *command = NULL; + + /* Calculate the default command */ + if(pop3->id[0] == '\0' || data->set.list_only) { + command = "LIST"; + + if(pop3->id[0] != '\0') + /* Message specific LIST so skip the BODY transfer */ + pop3->transfer = PPTRANSFER_INFO; + } + else + command = "RETR"; + + /* Send the command */ + if(pop3->id[0] != '\0') + result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s %s", + (pop3->custom && pop3->custom[0] != '\0' ? + pop3->custom : command), pop3->id); + else + result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", + (pop3->custom && pop3->custom[0] != '\0' ? + pop3->custom : command)); + + if(!result) + pop3_state(data, POP3_COMMAND); + + return result; +} + +/*********************************************************************** + * + * pop3_perform_quit() + * + * Performs the quit action prior to sclose() be called. + */ +static CURLcode pop3_perform_quit(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Send the QUIT command */ + CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "QUIT"); + + if(!result) + pop3_state(data, POP3_QUIT); + + return result; +} + +/* For the initial server greeting */ +static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); + size_t len = data->conn->proto.pop3c.pp.nfinal; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Got unexpected pop3-server response"); + result = CURLE_WEIRD_SERVER_REPLY; + } + else if(len > 3) { + /* Does the server support APOP authentication? */ + char *lt; + char *gt = NULL; + + /* Look for the APOP timestamp */ + lt = memchr(line, '<', len); + if(lt) + /* search the remainder for '>' */ + gt = memchr(lt, '>', len - (lt - line)); + if(gt) { + /* the length of the timestamp, including the brackets */ + size_t timestamplen = gt - lt + 1; + char *at = memchr(lt, '@', timestamplen); + /* If the timestamp does not contain '@' it is not (as required by + RFC-1939) conformant to the RFC-822 message id syntax, and we + therefore do not use APOP authentication. */ + if(at) { + /* dupe the timestamp */ + pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen); + if(!pop3c->apoptimestamp) + return CURLE_OUT_OF_MEMORY; + /* Store the APOP capability */ + pop3c->authtypes |= POP3_TYPE_APOP; + } + } + + if(!result) + result = pop3_perform_capa(data, conn); + } + + return result; +} + +/* For CAPA responses */ +static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); + size_t len = data->conn->proto.pop3c.pp.nfinal; + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged continuation response? */ + if(pop3code == '*') { + /* Does the server support the STLS capability? */ + if(len >= 4 && !memcmp(line, "STLS", 4)) + pop3c->tls_supported = TRUE; + + /* Does the server support clear text authentication? */ + else if(len >= 4 && !memcmp(line, "USER", 4)) + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + /* Does the server support SASL based authentication? */ + else if(len >= 5 && !memcmp(line, "SASL ", 5)) { + pop3c->authtypes |= POP3_TYPE_SASL; + + /* Advance past the SASL keyword */ + line += 5; + len -= 5; + + /* Loop through the data line */ + for(;;) { + size_t llen; + size_t wordlen; + unsigned short mechbit; + + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + len--; + } + + if(!len) + break; + + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + pop3c->sasl.authmechs |= mechbit; + + line += wordlen; + len -= wordlen; + } + } + } + else { + /* Clear text is supported when CAPA isn't recognised */ + if(pop3code != '+') + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + if(!data->set.use_ssl || Curl_conn_is_ssl(conn, FIRSTSOCKET)) + result = pop3_perform_authentication(data, conn); + else if(pop3code == '+' && pop3c->tls_supported) + /* Switch to TLS connection now */ + result = pop3_perform_starttls(data, conn); + else if(data->set.use_ssl <= CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = pop3_perform_authentication(data, conn); + else { + failf(data, "STLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + + return result; +} + +/* For STARTTLS responses */ +static CURLcode pop3_state_starttls_resp(struct Curl_easy *data, + struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + /* Pipelining in response is forbidden. */ + if(data->conn->proto.pop3c.pp.overflow) + return CURLE_WEIRD_SERVER_REPLY; + + if(pop3code != '+') { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); + result = CURLE_USE_SSL_FAILED; + } + else + result = pop3_perform_authentication(data, conn); + } + else + result = pop3_perform_upgrade_tls(data, conn); + + return result; +} + +/* For SASL authentication responses */ +static CURLcode pop3_state_auth_resp(struct Curl_easy *data, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + saslprogress progress; + + (void)instate; /* no use for this yet */ + + result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + pop3_state(data, POP3_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ +#ifndef CURL_DISABLE_DIGEST_AUTH + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) + /* Perform APOP authentication */ + result = pop3_perform_apop(data, conn); + else +#endif + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) + /* Perform clear text authentication */ + result = pop3_perform_user(data, conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + } + break; + default: + break; + } + + return result; +} + +#ifndef CURL_DISABLE_DIGEST_AUTH +/* For APOP responses */ +static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Authentication failed: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } + else + /* End of connect phase */ + pop3_state(data, POP3_STOP); + + return result; +} +#endif + +/* For USER responses */ +static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied. %c", pop3code); + result = CURLE_LOGIN_DENIED; + } + else + /* Send the PASS command */ + result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "PASS %s", + conn->passwd ? conn->passwd : ""); + if(!result) + pop3_state(data, POP3_PASS); + + return result; +} + +/* For PASS responses */ +static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied. %c", pop3code); + result = CURLE_LOGIN_DENIED; + } + else + /* End of connect phase */ + pop3_state(data, POP3_STOP); + + return result; +} + +/* For command responses */ +static CURLcode pop3_state_command_resp(struct Curl_easy *data, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct POP3 *pop3 = data->req.p.pop3; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + pop3_state(data, POP3_STOP); + return CURLE_WEIRD_SERVER_REPLY; + } + + /* This 'OK' line ends with a CR LF pair which is the two first bytes of the + EOB string so count this is two matching bytes. This is necessary to make + the code detect the EOB if the only data than comes now is %2e CR LF like + when there is no body to return. */ + pop3c->eob = 2; + + /* But since this initial CR LF pair is not part of the actual body, we set + the strip counter here so that these bytes won't be delivered. */ + pop3c->strip = 2; + + if(pop3->transfer == PPTRANSFER_BODY) { + /* POP3 download */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + + if(pp->overflow) { + /* The recv buffer contains data that is actually body content so send + it as such. Note that there may even be additional "headers" after + the body */ + + /* keep only the overflow */ + Curl_dyn_tail(&pp->recvbuf, pp->overflow); + pp->nfinal = 0; /* done */ + + if(!data->req.no_body) { + result = Curl_pop3_write(data, Curl_dyn_ptr(&pp->recvbuf), + Curl_dyn_len(&pp->recvbuf)); + if(result) + return result; + } + + /* reset the buffer */ + Curl_dyn_reset(&pp->recvbuf); + pp->overflow = 0; + } + } + else + pp->overflow = 0; + + /* End of DO phase */ + pop3_state(data, POP3_STOP); + + return result; +} + +static CURLcode pop3_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int pop3code; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + size_t nread = 0; + (void)data; + + /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */ + if(pop3c->state == POP3_UPGRADETLS) + return pop3_perform_upgrade_tls(data, conn); + + /* Flush any data that needs to be sent */ + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + do { + /* Read the response from the server */ + result = Curl_pp_readresp(data, sock, pp, &pop3code, &nread); + if(result) + return result; + + if(!pop3code) + break; + + /* We have now received a full POP3 server response */ + switch(pop3c->state) { + case POP3_SERVERGREET: + result = pop3_state_servergreet_resp(data, pop3code, pop3c->state); + break; + + case POP3_CAPA: + result = pop3_state_capa_resp(data, pop3code, pop3c->state); + break; + + case POP3_STARTTLS: + result = pop3_state_starttls_resp(data, conn, pop3code, pop3c->state); + break; + + case POP3_AUTH: + result = pop3_state_auth_resp(data, pop3code, pop3c->state); + break; + +#ifndef CURL_DISABLE_DIGEST_AUTH + case POP3_APOP: + result = pop3_state_apop_resp(data, pop3code, pop3c->state); + break; +#endif + + case POP3_USER: + result = pop3_state_user_resp(data, pop3code, pop3c->state); + break; + + case POP3_PASS: + result = pop3_state_pass_resp(data, pop3code, pop3c->state); + break; + + case POP3_COMMAND: + result = pop3_state_command_resp(data, pop3code, pop3c->state); + break; + + case POP3_QUIT: + pop3_state(data, POP3_STOP); + break; + + default: + /* internal error */ + pop3_state(data, POP3_STOP); + break; + } + } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); + + return result; +} + +/* Called repeatedly until done from multi.c */ +static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) { + bool ssldone = FALSE; + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); + pop3c->ssldone = ssldone; + if(result || !pop3c->ssldone) + return result; + } + + result = Curl_pp_statemach(data, &pop3c->pp, FALSE, FALSE); + *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; + + return result; +} + +static CURLcode pop3_block_statemach(struct Curl_easy *data, + struct connectdata *conn, + bool disconnecting) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + while(pop3c->state != POP3_STOP && !result) + result = Curl_pp_statemach(data, &pop3c->pp, TRUE, disconnecting); + + return result; +} + +/* Allocate and initialize the POP3 struct for the current Curl_easy if + required */ +static CURLcode pop3_init(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct POP3 *pop3; + + pop3 = data->req.p.pop3 = calloc(1, sizeof(struct POP3)); + if(!pop3) + result = CURLE_OUT_OF_MEMORY; + + return result; +} + +/* For the POP3 "protocol connect" and "doing" phases only */ +static int pop3_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks) +{ + return Curl_pp_getsock(data, &conn->proto.pop3c.pp, socks); +} + +/*********************************************************************** + * + * pop3_connect() + * + * This function should do everything that is to be considered a part of the + * connection phase. + * + * The variable 'done' points to will be TRUE if the protocol-layer connect + * phase is done when this function returns, or FALSE if not. + */ +static CURLcode pop3_connect(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + + *done = FALSE; /* default to not done yet */ + + /* We always support persistent connections in POP3 */ + connkeep(conn, "POP3 default"); + + PINGPONG_SETUP(pp, pop3_statemachine, pop3_endofresp); + + /* Set the default preferred authentication type and mechanism */ + pop3c->preftype = POP3_TYPE_ANY; + Curl_sasl_init(&pop3c->sasl, data, &saslpop3); + + /* Initialise the pingpong layer */ + Curl_pp_init(pp); + + /* Parse the URL options */ + result = pop3_parse_url_options(conn); + if(result) + return result; + + /* Start off waiting for the server greeting response */ + pop3_state(data, POP3_SERVERGREET); + + result = pop3_multi_statemach(data, done); + + return result; +} + +/*********************************************************************** + * + * pop3_done() + * + * The DONE function. This does what needs to be done after a single DO has + * performed. + * + * Input argument is already checked for validity. + */ +static CURLcode pop3_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + CURLcode result = CURLE_OK; + struct POP3 *pop3 = data->req.p.pop3; + + (void)premature; + + if(!pop3) + return CURLE_OK; + + if(status) { + connclose(data->conn, "POP3 done with bad status"); + result = status; /* use the already set error code */ + } + + /* Cleanup our per-request based variables */ + Curl_safefree(pop3->id); + Curl_safefree(pop3->custom); + + /* Clear the transfer mode for the next request */ + pop3->transfer = PPTRANSFER_BODY; + + return result; +} + +/*********************************************************************** + * + * pop3_perform() + * + * This is the actual DO function for POP3. Get a message/listing according to + * the options previously setup. + */ +static CURLcode pop3_perform(struct Curl_easy *data, bool *connected, + bool *dophase_done) +{ + /* This is POP3 and no proxy */ + CURLcode result = CURLE_OK; + struct POP3 *pop3 = data->req.p.pop3; + + DEBUGF(infof(data, "DO phase starts")); + + if(data->req.no_body) { + /* Requested no body means no transfer */ + pop3->transfer = PPTRANSFER_INFO; + } + + *dophase_done = FALSE; /* not done yet */ + + /* Start the first command in the DO phase */ + result = pop3_perform_command(data); + if(result) + return result; + + /* Run the state-machine */ + result = pop3_multi_statemach(data, dophase_done); + *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); + + if(*dophase_done) + DEBUGF(infof(data, "DO phase is complete")); + + return result; +} + +/*********************************************************************** + * + * pop3_do() + * + * This function is registered as 'curl_do' function. It decodes the path + * parts etc as a wrapper to the actual DO function (pop3_perform). + * + * The input argument is already checked for validity. + */ +static CURLcode pop3_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + *done = FALSE; /* default to false */ + + /* Parse the URL path */ + result = pop3_parse_url_path(data); + if(result) + return result; + + /* Parse the custom request */ + result = pop3_parse_custom_request(data); + if(result) + return result; + + result = pop3_regular_transfer(data, done); + + return result; +} + +/*********************************************************************** + * + * pop3_disconnect() + * + * Disconnect from an POP3 server. Cleanup protocol-specific per-connection + * resources. BLOCKING. + */ +static CURLcode pop3_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + (void)data; + + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. */ + + if(!dead_connection && conn->bits.protoconnstart) { + if(!pop3_perform_quit(data, conn)) + (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */ + } + + /* Disconnect from the server */ + Curl_pp_disconnect(&pop3c->pp); + + /* Cleanup the SASL module */ + Curl_sasl_cleanup(conn, pop3c->sasl.authused); + + /* Cleanup our connection based variables */ + Curl_safefree(pop3c->apoptimestamp); + + return CURLE_OK; +} + +/* Call this when the DO phase has completed */ +static CURLcode pop3_dophase_done(struct Curl_easy *data, bool connected) +{ + (void)data; + (void)connected; + + return CURLE_OK; +} + +/* Called from multi.c while DOing */ +static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done) +{ + CURLcode result = pop3_multi_statemach(data, dophase_done); + + if(result) + DEBUGF(infof(data, "DO phase failed")); + else if(*dophase_done) { + result = pop3_dophase_done(data, FALSE /* not connected */); + + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +/*********************************************************************** + * + * pop3_regular_transfer() + * + * The input argument is already checked for validity. + * + * Performs all commands done before a regular transfer between a local and a + * remote host. + */ +static CURLcode pop3_regular_transfer(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + bool connected = FALSE; + + /* Make sure size is unknown at this point */ + data->req.size = -1; + + /* Set the progress data */ + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + /* Carry out the perform */ + result = pop3_perform(data, &connected, dophase_done); + + /* Perform post DO phase operations if necessary */ + if(!result && *dophase_done) + result = pop3_dophase_done(data, connected); + + return result; +} + +static CURLcode pop3_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Initialise the POP3 layer */ + CURLcode result = pop3_init(data); + if(result) + return result; + + /* Clear the TLS upgraded flag */ + conn->bits.tls_upgraded = FALSE; + + return CURLE_OK; +} + +/*********************************************************************** + * + * pop3_parse_url_options() + * + * Parse the URL login options. + */ +static CURLcode pop3_parse_url_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *ptr = conn->options; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(strncasecompare(key, "AUTH=", 5)) { + result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, + value, ptr - value); + + if(result && strncasecompare(value, "+APOP", ptr - value)) { + pop3c->preftype = POP3_TYPE_APOP; + pop3c->sasl.prefmech = SASL_AUTH_NONE; + result = CURLE_OK; + } + } + else + result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; + } + + if(pop3c->preftype != POP3_TYPE_APOP) + switch(pop3c->sasl.prefmech) { + case SASL_AUTH_NONE: + pop3c->preftype = POP3_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + pop3c->preftype = POP3_TYPE_ANY; + break; + default: + pop3c->preftype = POP3_TYPE_SASL; + break; + } + + return result; +} + +/*********************************************************************** + * + * pop3_parse_url_path() + * + * Parse the URL path into separate path components. + */ +static CURLcode pop3_parse_url_path(struct Curl_easy *data) +{ + /* The POP3 struct is already initialised in pop3_connect() */ + struct POP3 *pop3 = data->req.p.pop3; + const char *path = &data->state.up.path[1]; /* skip leading path */ + + /* URL decode the path for the message ID */ + return Curl_urldecode(path, 0, &pop3->id, NULL, REJECT_CTRL); +} + +/*********************************************************************** + * + * pop3_parse_custom_request() + * + * Parse the custom request. + */ +static CURLcode pop3_parse_custom_request(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct POP3 *pop3 = data->req.p.pop3; + const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + + /* URL decode the custom request */ + if(custom) + result = Curl_urldecode(custom, 0, &pop3->custom, NULL, REJECT_CTRL); + + return result; +} + +/*********************************************************************** + * + * Curl_pop3_write() + * + * This function scans the body after the end-of-body and writes everything + * until the end is found. + */ +CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread) +{ + /* This code could be made into a special function in the handler struct */ + CURLcode result = CURLE_OK; + struct SingleRequest *k = &data->req; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + bool strip_dot = FALSE; + size_t last = 0; + size_t i; + + /* Search through the buffer looking for the end-of-body marker which is + 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches + the eob so the server will have prefixed it with an extra dot which we + need to strip out. Additionally the marker could of course be spread out + over 5 different data chunks. */ + for(i = 0; i < nread; i++) { + size_t prev = pop3c->eob; + + switch(str[i]) { + case 0x0d: + if(pop3c->eob == 0) { + pop3c->eob++; + + if(i) { + /* Write out the body part that didn't match */ + result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last], + i - last); + + if(result) + return result; + + last = i; + } + } + else if(pop3c->eob == 3) + pop3c->eob++; + else + /* If the character match wasn't at position 0 or 3 then restart the + pattern matching */ + pop3c->eob = 1; + break; + + case 0x0a: + if(pop3c->eob == 1 || pop3c->eob == 4) + pop3c->eob++; + else + /* If the character match wasn't at position 1 or 4 then start the + search again */ + pop3c->eob = 0; + break; + + case 0x2e: + if(pop3c->eob == 2) + pop3c->eob++; + else if(pop3c->eob == 3) { + /* We have an extra dot after the CRLF which we need to strip off */ + strip_dot = TRUE; + pop3c->eob = 0; + } + else + /* If the character match wasn't at position 2 then start the search + again */ + pop3c->eob = 0; + break; + + default: + pop3c->eob = 0; + break; + } + + /* Did we have a partial match which has subsequently failed? */ + if(prev && prev >= pop3c->eob) { + /* Strip can only be non-zero for the very first mismatch after CRLF + and then both prev and strip are equal and nothing will be output + below */ + while(prev && pop3c->strip) { + prev--; + pop3c->strip--; + } + + if(prev) { + /* If the partial match was the CRLF and dot then only write the CRLF + as the server would have inserted the dot */ + if(strip_dot && prev - 1 > 0) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, + prev - 1); + } + else if(!strip_dot) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, + prev); + } + else { + result = CURLE_OK; + } + + if(result) + return result; + + last = i; + strip_dot = FALSE; + } + } + } + + if(pop3c->eob == POP3_EOB_LEN) { + /* We have a full match so the transfer is done, however we must transfer + the CRLF at the start of the EOB as this is considered to be part of the + message as per RFC-1939, sect. 3 */ + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 2); + + k->keepon &= ~KEEP_RECV; + pop3c->eob = 0; + + return result; + } + + if(pop3c->eob) + /* While EOB is matching nothing should be output */ + return CURLE_OK; + + if(nread - last) { + result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last], + nread - last); + } + + return result; +} + +#endif /* CURL_DISABLE_POP3 */ diff --git a/lib/pop3.h b/lib/pop3.h new file mode 100644 index 0000000..83f0f83 --- /dev/null +++ b/lib/pop3.h @@ -0,0 +1,97 @@ +#ifndef HEADER_CURL_POP3_H +#define HEADER_CURL_POP3_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "pingpong.h" +#include "curl_sasl.h" + +/**************************************************************************** + * POP3 unique setup + ***************************************************************************/ +typedef enum { + POP3_STOP, /* do nothing state, stops the state machine */ + POP3_SERVERGREET, /* waiting for the initial greeting immediately after + a connect */ + POP3_CAPA, + POP3_STARTTLS, + POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS + (multi mode only) */ + POP3_AUTH, + POP3_APOP, + POP3_USER, + POP3_PASS, + POP3_COMMAND, + POP3_QUIT, + POP3_LAST /* never used */ +} pop3state; + +/* This POP3 struct is used in the Curl_easy. All POP3 data that is + connection-oriented must be in pop3_conn to properly deal with the fact that + perhaps the Curl_easy is changed between the times the connection is + used. */ +struct POP3 { + curl_pp_transfer transfer; + char *id; /* Message ID */ + char *custom; /* Custom Request */ +}; + +/* pop3_conn is used for struct connection-oriented data in the connectdata + struct */ +struct pop3_conn { + struct pingpong pp; + pop3state state; /* Always use pop3.c:state() to change state! */ + size_t eob; /* Number of bytes of the EOB (End Of Body) that + have been received so far */ + size_t strip; /* Number of bytes from the start to ignore as + non-body */ + struct SASL sasl; /* SASL-related storage */ + char *apoptimestamp; /* APOP timestamp from the server greeting */ + unsigned char authtypes; /* Accepted authentication types */ + unsigned char preftype; /* Preferred authentication type */ + BIT(ssldone); /* Is connect() over SSL done? */ + BIT(tls_supported); /* StartTLS capability supported by server */ +}; + +extern const struct Curl_handler Curl_handler_pop3; +extern const struct Curl_handler Curl_handler_pop3s; + +/* Authentication type flags */ +#define POP3_TYPE_CLEARTEXT (1 << 0) +#define POP3_TYPE_APOP (1 << 1) +#define POP3_TYPE_SASL (1 << 2) + +/* Authentication type values */ +#define POP3_TYPE_NONE 0 +#define POP3_TYPE_ANY (POP3_TYPE_CLEARTEXT|POP3_TYPE_APOP|POP3_TYPE_SASL) + +/* This is the 5-bytes End-Of-Body marker for POP3 */ +#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" +#define POP3_EOB_LEN 5 + +/* This function scans the body after the end-of-body and writes everything + * until the end is found */ +CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread); + +#endif /* HEADER_CURL_POP3_H */ diff --git a/lib/progress.c b/lib/progress.c new file mode 100644 index 0000000..d05fcc3 --- /dev/null +++ b/lib/progress.c @@ -0,0 +1,633 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "urldata.h" +#include "sendf.h" +#include "multiif.h" +#include "progress.h" +#include "timeval.h" +#include "curl_printf.h" + +/* check rate limits within this many recent milliseconds, at minimum. */ +#define MIN_RATE_LIMIT_PERIOD 3000 + +#ifndef CURL_DISABLE_PROGRESS_METER +/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero + byte) */ +static void time2str(char *r, curl_off_t seconds) +{ + curl_off_t h; + if(seconds <= 0) { + strcpy(r, "--:--:--"); + return; + } + h = seconds / CURL_OFF_T_C(3600); + if(h <= CURL_OFF_T_C(99)) { + curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); + curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); + msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T + ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); + } + else { + /* this equals to more than 99 hours, switch to a more suitable output + format to fit within the limits. */ + curl_off_t d = seconds / CURL_OFF_T_C(86400); + h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); + if(d <= CURL_OFF_T_C(999)) + msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T + "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); + else + msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); + } +} + +/* The point of this function would be to return a string of the input data, + but never longer than 5 columns (+ one zero byte). + Add suffix k, M, G when suitable... */ +static char *max5data(curl_off_t bytes, char *max5) +{ +#define ONE_KILOBYTE CURL_OFF_T_C(1024) +#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE) +#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE) +#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE) +#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) + + if(bytes < CURL_OFF_T_C(100000)) + msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + + else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); + + else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) + /* 'XX.XM' is good as long as we're less than 100 megs */ + msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, + (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); + + else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) + /* 'XXXXM' is good until we're at 10000MB or above */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); + + else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) + /* 10000 MB - 100 GB, we show it as XX.XG */ + msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, + (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); + + else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) + /* up to 10000GB, display without decimal: XXXXG */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); + + else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) + /* up to 10000TB, display without decimal: XXXXT */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); + + else + /* up to 10000PB, display without decimal: XXXXP */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); + + /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can + hold, but our data type is signed so 8192PB will be the maximum. */ + + return max5; +} +#endif + +/* + + New proposed interface, 9th of February 2000: + + pgrsStartNow() - sets start time + pgrsSetDownloadSize(x) - known expected download size + pgrsSetUploadSize(x) - known expected upload size + pgrsSetDownloadCounter() - amount of data currently downloaded + pgrsSetUploadCounter() - amount of data currently uploaded + pgrsUpdate() - show progress + pgrsDone() - transfer complete + +*/ + +int Curl_pgrsDone(struct Curl_easy *data) +{ + int rc; + data->progress.lastshow = 0; + rc = Curl_pgrsUpdate(data); /* the final (forced) update */ + if(rc) + return rc; + + if(!(data->progress.flags & PGRS_HIDE) && + !data->progress.callback) + /* only output if we don't use a progress callback and we're not + * hidden */ + fprintf(data->set.err, "\n"); + + data->progress.speeder_c = 0; /* reset the progress meter display */ + return 0; +} + +/* reset the known transfer sizes */ +void Curl_pgrsResetTransferSizes(struct Curl_easy *data) +{ + Curl_pgrsSetDownloadSize(data, -1); + Curl_pgrsSetUploadSize(data, -1); +} + +/* + * + * Curl_pgrsTimeWas(). Store the timestamp time at the given label. + */ +void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer, + struct curltime timestamp) +{ + timediff_t *delta = NULL; + + switch(timer) { + default: + case TIMER_NONE: + /* mistake filter */ + break; + case TIMER_STARTOP: + /* This is set at the start of a transfer */ + data->progress.t_startop = timestamp; + break; + case TIMER_STARTSINGLE: + /* This is set at the start of each single transfer */ + data->progress.t_startsingle = timestamp; + data->progress.is_t_startransfer_set = false; + break; + case TIMER_POSTQUEUE: + /* Set when the transfer starts (after potentially having been brought + back from the waiting queue). It needs to count from t_startop and not + t_startsingle since the latter is reset when a connection is brought + back from the pending queue. */ + data->progress.t_postqueue = + Curl_timediff_us(timestamp, data->progress.t_startop); + break; + case TIMER_STARTACCEPT: + data->progress.t_acceptdata = timestamp; + break; + case TIMER_NAMELOOKUP: + delta = &data->progress.t_nslookup; + break; + case TIMER_CONNECT: + delta = &data->progress.t_connect; + break; + case TIMER_APPCONNECT: + delta = &data->progress.t_appconnect; + break; + case TIMER_PRETRANSFER: + delta = &data->progress.t_pretransfer; + break; + case TIMER_STARTTRANSFER: + delta = &data->progress.t_starttransfer; + /* prevent updating t_starttransfer unless: + * 1) this is the first time we're setting t_starttransfer + * 2) a redirect has occurred since the last time t_starttransfer was set + * This prevents repeated invocations of the function from incorrectly + * changing the t_starttransfer time. + */ + if(data->progress.is_t_startransfer_set) { + return; + } + else { + data->progress.is_t_startransfer_set = true; + break; + } + case TIMER_POSTRANSFER: + /* this is the normal end-of-transfer thing */ + break; + case TIMER_REDIRECT: + data->progress.t_redirect = Curl_timediff_us(timestamp, + data->progress.start); + break; + } + if(delta) { + timediff_t us = Curl_timediff_us(timestamp, data->progress.t_startsingle); + if(us < 1) + us = 1; /* make sure at least one microsecond passed */ + *delta += us; + } +} + +/* + * + * Curl_pgrsTime(). Store the current time at the given label. This fetches a + * fresh "now" and returns it. + * + * @unittest: 1399 + */ +struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer) +{ + struct curltime now = Curl_now(); + + Curl_pgrsTimeWas(data, timer, now); + return now; +} + +void Curl_pgrsStartNow(struct Curl_easy *data) +{ + data->progress.speeder_c = 0; /* reset the progress meter display */ + data->progress.start = Curl_now(); + data->progress.is_t_startransfer_set = false; + data->progress.ul_limit_start = data->progress.start; + data->progress.dl_limit_start = data->progress.start; + data->progress.ul_limit_size = 0; + data->progress.dl_limit_size = 0; + data->progress.downloaded = 0; + data->progress.uploaded = 0; + /* clear all bits except HIDE and HEADERS_OUT */ + data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; + Curl_ratelimit(data, data->progress.start); +} + +/* + * This is used to handle speed limits, calculating how many milliseconds to + * wait until we're back under the speed limit, if needed. + * + * The way it works is by having a "starting point" (time & amount of data + * transferred by then) used in the speed computation, to be used instead of + * the start of the transfer. This starting point is regularly moved as + * transfer goes on, to keep getting accurate values (instead of average over + * the entire transfer). + * + * This function takes the current amount of data transferred, the amount at + * the starting point, the limit (in bytes/s), the time of the starting point + * and the current time. + * + * Returns 0 if no waiting is needed or when no waiting is needed but the + * starting point should be reset (to current); or the number of milliseconds + * to wait to get back under the speed limit. + */ +timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct curltime start, + struct curltime now) +{ + curl_off_t size = cursize - startsize; + timediff_t minimum; + timediff_t actual; + + if(!limit || !size) + return 0; + + /* + * 'minimum' is the number of milliseconds 'size' should take to download to + * stay below 'limit'. + */ + if(size < CURL_OFF_T_MAX/1000) + minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / limit); + else { + minimum = (timediff_t) (size / limit); + if(minimum < TIMEDIFF_T_MAX/1000) + minimum *= 1000; + else + minimum = TIMEDIFF_T_MAX; + } + + /* + * 'actual' is the time in milliseconds it took to actually download the + * last 'size' bytes. + */ + actual = Curl_timediff_ceil(now, start); + if(actual < minimum) { + /* if it downloaded the data faster than the limit, make it wait the + difference */ + return (minimum - actual); + } + + return 0; +} + +/* + * Set the number of downloaded bytes so far. + */ +CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) +{ + data->progress.downloaded = size; + return CURLE_OK; +} + +/* + * Update the timestamp and sizestamp to use for rate limit calculations. + */ +void Curl_ratelimit(struct Curl_easy *data, struct curltime now) +{ + /* don't set a new stamp unless the time since last update is long enough */ + if(data->set.max_recv_speed) { + if(Curl_timediff(now, data->progress.dl_limit_start) >= + MIN_RATE_LIMIT_PERIOD) { + data->progress.dl_limit_start = now; + data->progress.dl_limit_size = data->progress.downloaded; + } + } + if(data->set.max_send_speed) { + if(Curl_timediff(now, data->progress.ul_limit_start) >= + MIN_RATE_LIMIT_PERIOD) { + data->progress.ul_limit_start = now; + data->progress.ul_limit_size = data->progress.uploaded; + } + } +} + +/* + * Set the number of uploaded bytes so far. + */ +void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) +{ + data->progress.uploaded = size; +} + +void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size) +{ + if(size >= 0) { + data->progress.size_dl = size; + data->progress.flags |= PGRS_DL_SIZE_KNOWN; + } + else { + data->progress.size_dl = 0; + data->progress.flags &= ~PGRS_DL_SIZE_KNOWN; + } +} + +void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size) +{ + if(size >= 0) { + data->progress.size_ul = size; + data->progress.flags |= PGRS_UL_SIZE_KNOWN; + } + else { + data->progress.size_ul = 0; + data->progress.flags &= ~PGRS_UL_SIZE_KNOWN; + } +} + +/* returns the average speed in bytes / second */ +static curl_off_t trspeed(curl_off_t size, /* number of bytes */ + curl_off_t us) /* microseconds */ +{ + if(us < 1) + return size * 1000000; + else if(size < CURL_OFF_T_MAX/1000000) + return (size * 1000000) / us; + else if(us >= 1000000) + return size / (us / 1000000); + else + return CURL_OFF_T_MAX; +} + +/* returns TRUE if it's time to show the progress meter */ +static bool progress_calc(struct Curl_easy *data, struct curltime now) +{ + bool timetoshow = FALSE; + struct Progress * const p = &data->progress; + + /* The time spent so far (from the start) in microseconds */ + p->timespent = Curl_timediff_us(now, p->start); + p->dlspeed = trspeed(p->downloaded, p->timespent); + p->ulspeed = trspeed(p->uploaded, p->timespent); + + /* Calculations done at most once a second, unless end is reached */ + if(p->lastshow != now.tv_sec) { + int countindex; /* amount of seconds stored in the speeder array */ + int nowindex = p->speeder_c% CURR_TIME; + p->lastshow = now.tv_sec; + timetoshow = TRUE; + + /* Let's do the "current speed" thing, with the dl + ul speeds + combined. Store the speed at entry 'nowindex'. */ + p->speeder[ nowindex ] = p->downloaded + p->uploaded; + + /* remember the exact time for this moment */ + p->speeder_time [ nowindex ] = now; + + /* advance our speeder_c counter, which is increased every time we get + here and we expect it to never wrap as 2^32 is a lot of seconds! */ + p->speeder_c++; + + /* figure out how many index entries of data we have stored in our speeder + array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of + transfer. Imagine, after one second we have filled in two entries, + after two seconds we've filled in three entries etc. */ + countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1; + + /* first of all, we don't do this if there's no counted seconds yet */ + if(countindex) { + int checkindex; + timediff_t span_ms; + curl_off_t amount; + + /* Get the index position to compare with the 'nowindex' position. + Get the oldest entry possible. While we have less than CURR_TIME + entries, the first entry will remain the oldest. */ + checkindex = (p->speeder_c >= CURR_TIME)? p->speeder_c%CURR_TIME:0; + + /* Figure out the exact time for the time span */ + span_ms = Curl_timediff(now, p->speeder_time[checkindex]); + if(0 == span_ms) + span_ms = 1; /* at least one millisecond MUST have passed */ + + /* Calculate the average speed the last 'span_ms' milliseconds */ + amount = p->speeder[nowindex]- p->speeder[checkindex]; + + if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */) + /* the 'amount' value is bigger than would fit in 32 bits if + multiplied with 1000, so we use the double math for this */ + p->current_speed = (curl_off_t) + ((double)amount/((double)span_ms/1000.0)); + else + /* the 'amount' value is small enough to fit within 32 bits even + when multiplied with 1000 */ + p->current_speed = amount*CURL_OFF_T_C(1000)/span_ms; + } + else + /* the first second we use the average */ + p->current_speed = p->ulspeed + p->dlspeed; + + } /* Calculations end */ + return timetoshow; +} + +#ifndef CURL_DISABLE_PROGRESS_METER +static void progress_meter(struct Curl_easy *data) +{ + char max5[6][10]; + curl_off_t dlpercen = 0; + curl_off_t ulpercen = 0; + curl_off_t total_percen = 0; + curl_off_t total_transfer; + curl_off_t total_expected_transfer; + char time_left[10]; + char time_total[10]; + char time_spent[10]; + curl_off_t ulestimate = 0; + curl_off_t dlestimate = 0; + curl_off_t total_estimate; + curl_off_t timespent = + (curl_off_t)data->progress.timespent/1000000; /* seconds */ + + if(!(data->progress.flags & PGRS_HEADERS_OUT)) { + if(data->state.resume_from) { + fprintf(data->set.err, + "** Resuming transfer from byte position %" + CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); + } + fprintf(data->set.err, + " %% Total %% Received %% Xferd Average Speed " + "Time Time Time Current\n" + " Dload Upload " + "Total Spent Left Speed\n"); + data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */ + } + + /* Figure out the estimated time of arrival for the upload */ + if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && + (data->progress.ulspeed > CURL_OFF_T_C(0))) { + ulestimate = data->progress.size_ul / data->progress.ulspeed; + + if(data->progress.size_ul > CURL_OFF_T_C(10000)) + ulpercen = data->progress.uploaded / + (data->progress.size_ul/CURL_OFF_T_C(100)); + else if(data->progress.size_ul > CURL_OFF_T_C(0)) + ulpercen = (data->progress.uploaded*100) / + data->progress.size_ul; + } + + /* ... and the download */ + if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && + (data->progress.dlspeed > CURL_OFF_T_C(0))) { + dlestimate = data->progress.size_dl / data->progress.dlspeed; + + if(data->progress.size_dl > CURL_OFF_T_C(10000)) + dlpercen = data->progress.downloaded / + (data->progress.size_dl/CURL_OFF_T_C(100)); + else if(data->progress.size_dl > CURL_OFF_T_C(0)) + dlpercen = (data->progress.downloaded*100) / + data->progress.size_dl; + } + + /* Now figure out which of them is slower and use that one for the + total estimate! */ + total_estimate = ulestimate>dlestimate?ulestimate:dlestimate; + + /* create the three time strings */ + time2str(time_left, total_estimate > 0?(total_estimate - timespent):0); + time2str(time_total, total_estimate); + time2str(time_spent, timespent); + + /* Get the total amount of data expected to get transferred */ + total_expected_transfer = + ((data->progress.flags & PGRS_UL_SIZE_KNOWN)? + data->progress.size_ul:data->progress.uploaded)+ + ((data->progress.flags & PGRS_DL_SIZE_KNOWN)? + data->progress.size_dl:data->progress.downloaded); + + /* We have transferred this much so far */ + total_transfer = data->progress.downloaded + data->progress.uploaded; + + /* Get the percentage of data transferred so far */ + if(total_expected_transfer > CURL_OFF_T_C(10000)) + total_percen = total_transfer / + (total_expected_transfer/CURL_OFF_T_C(100)); + else if(total_expected_transfer > CURL_OFF_T_C(0)) + total_percen = (total_transfer*100) / total_expected_transfer; + + fprintf(data->set.err, + "\r" + "%3" CURL_FORMAT_CURL_OFF_T " %s " + "%3" CURL_FORMAT_CURL_OFF_T " %s " + "%3" CURL_FORMAT_CURL_OFF_T " %s %s %s %s %s %s %s", + total_percen, /* 3 letters */ /* total % */ + max5data(total_expected_transfer, max5[2]), /* total size */ + dlpercen, /* 3 letters */ /* rcvd % */ + max5data(data->progress.downloaded, max5[0]), /* rcvd size */ + ulpercen, /* 3 letters */ /* xfer % */ + max5data(data->progress.uploaded, max5[1]), /* xfer size */ + max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */ + max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */ + time_total, /* 8 letters */ /* total time */ + time_spent, /* 8 letters */ /* time spent */ + time_left, /* 8 letters */ /* time left */ + max5data(data->progress.current_speed, max5[5]) + ); + + /* we flush the output stream to make it appear as soon as possible */ + fflush(data->set.err); +} +#else + /* progress bar disabled */ +#define progress_meter(x) Curl_nop_stmt +#endif + + +/* + * Curl_pgrsUpdate() returns 0 for success or the value returned by the + * progress callback! + */ +int Curl_pgrsUpdate(struct Curl_easy *data) +{ + struct curltime now = Curl_now(); /* what time is it */ + bool showprogress = progress_calc(data, now); + if(!(data->progress.flags & PGRS_HIDE)) { + if(data->set.fxferinfo) { + int result; + /* There's a callback set, call that */ + Curl_set_in_callback(data, true); + result = data->set.fxferinfo(data->set.progress_client, + data->progress.size_dl, + data->progress.downloaded, + data->progress.size_ul, + data->progress.uploaded); + Curl_set_in_callback(data, false); + if(result != CURL_PROGRESSFUNC_CONTINUE) { + if(result) + failf(data, "Callback aborted"); + return result; + } + } + else if(data->set.fprogress) { + int result; + /* The older deprecated callback is set, call that */ + Curl_set_in_callback(data, true); + result = data->set.fprogress(data->set.progress_client, + (double)data->progress.size_dl, + (double)data->progress.downloaded, + (double)data->progress.size_ul, + (double)data->progress.uploaded); + Curl_set_in_callback(data, false); + if(result != CURL_PROGRESSFUNC_CONTINUE) { + if(result) + failf(data, "Callback aborted"); + return result; + } + } + + if(showprogress) + progress_meter(data); + } + + return 0; +} diff --git a/lib/progress.h b/lib/progress.h new file mode 100644 index 0000000..7374941 --- /dev/null +++ b/lib/progress.h @@ -0,0 +1,77 @@ +#ifndef HEADER_CURL_PROGRESS_H +#define HEADER_CURL_PROGRESS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "timeval.h" + + +typedef enum { + TIMER_NONE, + TIMER_STARTOP, + TIMER_STARTSINGLE, /* start of transfer, might get queued */ + TIMER_POSTQUEUE, /* start, immediately after dequeue */ + TIMER_NAMELOOKUP, + TIMER_CONNECT, + TIMER_APPCONNECT, + TIMER_PRETRANSFER, + TIMER_STARTTRANSFER, + TIMER_POSTRANSFER, + TIMER_STARTACCEPT, + TIMER_REDIRECT, + TIMER_LAST /* must be last */ +} timerid; + +int Curl_pgrsDone(struct Curl_easy *data); +void Curl_pgrsStartNow(struct Curl_easy *data); +void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size); +void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); + +/* It is fine to not check the return code if 'size' is set to 0 */ +CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); + +void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); +void Curl_ratelimit(struct Curl_easy *data, struct curltime now); +int Curl_pgrsUpdate(struct Curl_easy *data); +void Curl_pgrsResetTransferSizes(struct Curl_easy *data); +struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer); +timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct curltime start, + struct curltime now); +/** + * Update progress timer with the elapsed time from its start to `timestamp`. + * This allows updating timers later and is used by happy eyeballing, where + * we only want to record the winner's times. + */ +void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer, + struct curltime timestamp); + +#define PGRS_HIDE (1<<4) +#define PGRS_UL_SIZE_KNOWN (1<<5) +#define PGRS_DL_SIZE_KNOWN (1<<6) +#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */ + +#endif /* HEADER_CURL_PROGRESS_H */ diff --git a/lib/psl.c b/lib/psl.c new file mode 100644 index 0000000..626a203 --- /dev/null +++ b/lib/psl.c @@ -0,0 +1,113 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#ifdef USE_LIBPSL + +#include "psl.h" +#include "share.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +void Curl_psl_destroy(struct PslCache *pslcache) +{ + if(pslcache->psl) { + if(pslcache->dynamic) + psl_free((psl_ctx_t *) pslcache->psl); + pslcache->psl = NULL; + pslcache->dynamic = FALSE; + } +} + +static time_t now_seconds(void) +{ + struct curltime now = Curl_now(); + + return now.tv_sec; +} + +const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy) +{ + struct PslCache *pslcache = easy->psl; + const psl_ctx_t *psl; + time_t now; + + if(!pslcache) + return NULL; + + Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED); + now = now_seconds(); + if(!pslcache->psl || pslcache->expires <= now) { + /* Let a chance to other threads to do the job: avoids deadlock. */ + Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); + + /* Update cache: this needs an exclusive lock. */ + Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SINGLE); + + /* Recheck in case another thread did the job. */ + now = now_seconds(); + if(!pslcache->psl || pslcache->expires <= now) { + bool dynamic = FALSE; + time_t expires = TIME_T_MAX; + +#if defined(PSL_VERSION_NUMBER) && PSL_VERSION_NUMBER >= 0x001000 + psl = psl_latest(NULL); + dynamic = psl != NULL; + /* Take care of possible time computation overflow. */ + expires = now < TIME_T_MAX - PSL_TTL? now + PSL_TTL: TIME_T_MAX; + + /* Only get the built-in PSL if we do not already have the "latest". */ + if(!psl && !pslcache->dynamic) +#endif + + psl = psl_builtin(); + + if(psl) { + Curl_psl_destroy(pslcache); + pslcache->psl = psl; + pslcache->dynamic = dynamic; + pslcache->expires = expires; + } + } + Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); /* Release exclusive lock. */ + Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED); + } + psl = pslcache->psl; + if(!psl) + Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); + return psl; +} + +void Curl_psl_release(struct Curl_easy *easy) +{ + Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); +} + +#endif /* USE_LIBPSL */ diff --git a/lib/psl.h b/lib/psl.h new file mode 100644 index 0000000..23cfa92 --- /dev/null +++ b/lib/psl.h @@ -0,0 +1,49 @@ +#ifndef HEADER_PSL_H +#define HEADER_PSL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifdef USE_LIBPSL +#include + +#define PSL_TTL (72 * 3600) /* PSL time to live before a refresh. */ + +struct PslCache { + const psl_ctx_t *psl; /* The PSL. */ + time_t expires; /* Time this PSL life expires. */ + bool dynamic; /* PSL should be released when no longer needed. */ +}; + +const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy); +void Curl_psl_release(struct Curl_easy *easy); +void Curl_psl_destroy(struct PslCache *pslcache); + +#else + +#define Curl_psl_use(easy) NULL +#define Curl_psl_release(easy) +#define Curl_psl_destroy(pslcache) + +#endif /* USE_LIBPSL */ +#endif /* HEADER_PSL_H */ diff --git a/lib/rand.c b/lib/rand.c new file mode 100644 index 0000000..c62b1a4 --- /dev/null +++ b/lib/rand.c @@ -0,0 +1,291 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include +#include "urldata.h" +#include "vtls/vtls.h" +#include "sendf.h" +#include "timeval.h" +#include "rand.h" +#include "escape.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef _WIN32 + +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 +# define HAVE_WIN_BCRYPTGENRANDOM +# include +# ifdef _MSC_VER +# pragma comment(lib, "bcrypt.lib") +# endif +# ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG +# define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002 +# endif +# ifndef STATUS_SUCCESS +# define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +# endif +#elif defined(USE_WIN32_CRYPTO) +# include +# ifdef _MSC_VER +# pragma comment(lib, "advapi32.lib") +# endif +#endif + +CURLcode Curl_win32_random(unsigned char *entropy, size_t length) +{ + memset(entropy, 0, length); + +#if defined(HAVE_WIN_BCRYPTGENRANDOM) + if(BCryptGenRandom(NULL, entropy, (ULONG)length, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS) + return CURLE_FAILED_INIT; + + return CURLE_OK; +#elif defined(USE_WIN32_CRYPTO) + { + HCRYPTPROV hCryptProv = 0; + + if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return CURLE_FAILED_INIT; + + if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { + CryptReleaseContext(hCryptProv, 0UL); + return CURLE_FAILED_INIT; + } + + CryptReleaseContext(hCryptProv, 0UL); + } + return CURLE_OK; +#else + return CURLE_NOT_BUILT_IN; +#endif +} +#endif + +static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) +{ + CURLcode result = CURLE_OK; + static unsigned int randseed; + static bool seeded = FALSE; + +#ifdef CURLDEBUG + char *force_entropy = getenv("CURL_ENTROPY"); + if(force_entropy) { + if(!seeded) { + unsigned int seed = 0; + size_t elen = strlen(force_entropy); + size_t clen = sizeof(seed); + size_t min = elen < clen ? elen : clen; + memcpy((char *)&seed, force_entropy, min); + randseed = ntohl(seed); + seeded = TRUE; + } + else + randseed++; + *rnd = randseed; + return CURLE_OK; + } +#endif + + /* data may be NULL! */ + result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); + if(result != CURLE_NOT_BUILT_IN) + /* only if there is no random function in the TLS backend do the non crypto + version, otherwise return result */ + return result; + + /* ---- non-cryptographic version following ---- */ + +#ifdef _WIN32 + if(!seeded) { + result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd)); + if(result != CURLE_NOT_BUILT_IN) + return result; + } +#endif + +#if defined(HAVE_ARC4RANDOM) && !defined(USE_OPENSSL) + if(!seeded) { + *rnd = (unsigned int)arc4random(); + return CURLE_OK; + } +#endif + +#if defined(RANDOM_FILE) && !defined(_WIN32) + if(!seeded) { + /* if there's a random file to read a seed from, use it */ + int fd = open(RANDOM_FILE, O_RDONLY); + if(fd > -1) { + /* read random data into the randseed variable */ + ssize_t nread = read(fd, &randseed, sizeof(randseed)); + if(nread == sizeof(randseed)) + seeded = TRUE; + close(fd); + } + } +#endif + + if(!seeded) { + struct curltime now = Curl_now(); + infof(data, "WARNING: using weak random seed"); + randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + seeded = TRUE; + } + + { + unsigned int r; + /* Return an unsigned 32-bit pseudo-random number. */ + r = randseed = randseed * 1103515245 + 12345; + *rnd = (r << 16) | ((r >> 16) & 0xFFFF); + } + return CURLE_OK; +} + +/* + * Curl_rand() stores 'num' number of random unsigned characters in the buffer + * 'rnd' points to. + * + * If libcurl is built without TLS support or with a TLS backend that lacks a + * proper random API (rustls or mbedTLS), this function will use "weak" + * random. + * + * When built *with* TLS support and a backend that offers strong random, it + * will return error if it cannot provide strong random values. + * + * NOTE: 'data' may be passed in as NULL when coming from external API without + * easy handle! + * + */ + +CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num) +{ + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + + DEBUGASSERT(num); + + while(num) { + unsigned int r; + size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int); + + result = randit(data, &r); + if(result) + return result; + + while(left) { + *rnd++ = (unsigned char)(r & 0xFF); + r >>= 8; + --num; + --left; + } + } + + return result; +} + +/* + * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random + * hexadecimal digits PLUS a null-terminating byte. It must be an odd number + * size. + */ + +CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, + size_t num) +{ + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + unsigned char buffer[128]; + DEBUGASSERT(num > 1); + +#ifdef __clang_analyzer__ + /* This silences a scan-build warning about accessing this buffer with + uninitialized memory. */ + memset(buffer, 0, sizeof(buffer)); +#endif + + if((num/2 >= sizeof(buffer)) || !(num&1)) { + /* make sure it fits in the local buffer and that it is an odd number! */ + DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + num--; /* save one for null-termination */ + + result = Curl_rand(data, buffer, num/2); + if(result) + return result; + + Curl_hexencode(buffer, num/2, rnd, num + 1); + return result; +} + +/* + * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random + * alphanumerical chars PLUS a null-terminating byte. + */ + +static const char alnum[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd, + size_t num) +{ + CURLcode result = CURLE_OK; + const int alnumspace = sizeof(alnum) - 1; + unsigned int r; + DEBUGASSERT(num > 1); + + num--; /* save one for null-termination */ + + while(num) { + do { + result = randit(data, &r); + if(result) + return result; + } while(r >= (UINT_MAX - UINT_MAX % alnumspace)); + + *rnd++ = alnum[r % alnumspace]; + num--; + } + *rnd = 0; + + return result; +} diff --git a/lib/rand.h b/lib/rand.h new file mode 100644 index 0000000..bc05239 --- /dev/null +++ b/lib/rand.h @@ -0,0 +1,50 @@ +#ifndef HEADER_CURL_RAND_H +#define HEADER_CURL_RAND_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num); + +/* + * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random + * hexadecimal digits PLUS a null-terminating byte. It must be an odd number + * size. + */ +CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, + size_t num); + +/* + * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random + * alphanumerical chars PLUS a null-terminating byte. + */ +CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd, + size_t num); + +#ifdef _WIN32 +/* Random generator shared between the Schannel vtls and Curl_rand*() + functions */ +CURLcode Curl_win32_random(unsigned char *entropy, size_t length); +#endif + +#endif /* HEADER_CURL_RAND_H */ diff --git a/lib/rename.c b/lib/rename.c new file mode 100644 index 0000000..4c88698 --- /dev/null +++ b/lib/rename.c @@ -0,0 +1,73 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "rename.h" + +#include "curl_setup.h" + +#if (!defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_COOKIES)) || \ + !defined(CURL_DISABLE_ALTSVC) + +#include "curl_multibyte.h" +#include "timeval.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* return 0 on success, 1 on error */ +int Curl_rename(const char *oldpath, const char *newpath) +{ +#ifdef _WIN32 + /* rename() on Windows doesn't overwrite, so we can't use it here. + MoveFileEx() will overwrite and is usually atomic, however it fails + when there are open handles to the file. */ + const int max_wait_ms = 1000; + struct curltime start = Curl_now(); + TCHAR *tchar_oldpath = curlx_convert_UTF8_to_tchar((char *)oldpath); + TCHAR *tchar_newpath = curlx_convert_UTF8_to_tchar((char *)newpath); + for(;;) { + timediff_t diff; + if(MoveFileEx(tchar_oldpath, tchar_newpath, MOVEFILE_REPLACE_EXISTING)) { + curlx_unicodefree(tchar_oldpath); + curlx_unicodefree(tchar_newpath); + break; + } + diff = Curl_timediff(Curl_now(), start); + if(diff < 0 || diff > max_wait_ms) { + curlx_unicodefree(tchar_oldpath); + curlx_unicodefree(tchar_newpath); + return 1; + } + Sleep(1); + } +#else + if(rename(oldpath, newpath)) + return 1; +#endif + return 0; +} + +#endif diff --git a/lib/rename.h b/lib/rename.h new file mode 100644 index 0000000..0444082 --- /dev/null +++ b/lib/rename.h @@ -0,0 +1,29 @@ +#ifndef HEADER_CURL_RENAME_H +#define HEADER_CURL_RENAME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +int Curl_rename(const char *oldpath, const char *newpath); + +#endif /* HEADER_CURL_RENAME_H */ diff --git a/lib/rtsp.c b/lib/rtsp.c new file mode 100644 index 0000000..26f4735 --- /dev/null +++ b/lib/rtsp.c @@ -0,0 +1,1032 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_RTSP) && !defined(USE_HYPER) + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "multiif.h" +#include "http.h" +#include "url.h" +#include "progress.h" +#include "rtsp.h" +#include "strcase.h" +#include "select.h" +#include "connect.h" +#include "cfilters.h" +#include "strdup.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define RTP_PKT_LENGTH(p) ((((unsigned int)((unsigned char)((p)[2]))) << 8) | \ + ((unsigned int)((unsigned char)((p)[3])))) + +/* protocol-specific functions set up to be called by the main engine */ +static CURLcode rtsp_do(struct Curl_easy *data, bool *done); +static CURLcode rtsp_done(struct Curl_easy *data, CURLcode, bool premature); +static CURLcode rtsp_connect(struct Curl_easy *data, bool *done); +static CURLcode rtsp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); +static int rtsp_getsock_do(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); + +/* + * Parse and write out an RTSP response. + * @param data the transfer + * @param conn the connection + * @param buf data read from connection + * @param blen amount of data in buf + * @param is_eos TRUE iff this is the last write + * @param readmore out, TRUE iff complete buf was consumed and more data + * is needed + */ +static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos, + bool *done); + +static CURLcode rtsp_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static unsigned int rtsp_conncheck(struct Curl_easy *data, + struct connectdata *check, + unsigned int checks_to_perform); + +/* this returns the socket to wait for in the DO and DOING state for the multi + interface and then we're always _sending_ a request and thus we wait for + the single socket to become writable only */ +static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks) +{ + /* write mode */ + (void)data; + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_WRITESOCK(0); +} + +static +CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len); +static +CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport); + + +/* + * RTSP handler interface. + */ +const struct Curl_handler Curl_handler_rtsp = { + "RTSP", /* scheme */ + rtsp_setup_connection, /* setup_connection */ + rtsp_do, /* do_it */ + rtsp_done, /* done */ + ZERO_NULL, /* do_more */ + rtsp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + rtsp_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + rtsp_disconnect, /* disconnect */ + rtsp_rtp_write_resp, /* write_resp */ + rtsp_conncheck, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_RTSP, /* defport */ + CURLPROTO_RTSP, /* protocol */ + CURLPROTO_RTSP, /* family */ + PROTOPT_NONE /* flags */ +}; + +#define MAX_RTP_BUFFERSIZE 1000000 /* arbitrary */ + +static CURLcode rtsp_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + struct RTSP *rtsp; + (void)conn; + + data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP)); + if(!rtsp) + return CURLE_OUT_OF_MEMORY; + + Curl_dyn_init(&conn->proto.rtspc.buf, MAX_RTP_BUFFERSIZE); + return CURLE_OK; +} + + +/* + * Function to check on various aspects of a connection. + */ +static unsigned int rtsp_conncheck(struct Curl_easy *data, + struct connectdata *conn, + unsigned int checks_to_perform) +{ + unsigned int ret_val = CONNRESULT_NONE; + (void)data; + + if(checks_to_perform & CONNCHECK_ISDEAD) { + bool input_pending; + if(!Curl_conn_is_alive(data, conn, &input_pending)) + ret_val |= CONNRESULT_DEAD; + } + + return ret_val; +} + + +static CURLcode rtsp_connect(struct Curl_easy *data, bool *done) +{ + CURLcode httpStatus; + + httpStatus = Curl_http_connect(data, done); + + /* Initialize the CSeq if not already done */ + if(data->state.rtsp_next_client_CSeq == 0) + data->state.rtsp_next_client_CSeq = 1; + if(data->state.rtsp_next_server_CSeq == 0) + data->state.rtsp_next_server_CSeq = 1; + + data->conn->proto.rtspc.rtp_channel = -1; + + return httpStatus; +} + +static CURLcode rtsp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead) +{ + (void) dead; + (void) data; + Curl_dyn_free(&conn->proto.rtspc.buf); + return CURLE_OK; +} + + +static CURLcode rtsp_done(struct Curl_easy *data, + CURLcode status, bool premature) +{ + struct RTSP *rtsp = data->req.p.rtsp; + CURLcode httpStatus; + + /* Bypass HTTP empty-reply checks on receive */ + if(data->set.rtspreq == RTSPREQ_RECEIVE) + premature = TRUE; + + httpStatus = Curl_http_done(data, status, premature); + + if(rtsp && !status && !httpStatus) { + /* Check the sequence numbers */ + long CSeq_sent = rtsp->CSeq_sent; + long CSeq_recv = rtsp->CSeq_recv; + if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) { + failf(data, + "The CSeq of this request %ld did not match the response %ld", + CSeq_sent, CSeq_recv); + return CURLE_RTSP_CSEQ_ERROR; + } + if(data->set.rtspreq == RTSPREQ_RECEIVE && + (data->conn->proto.rtspc.rtp_channel == -1)) { + infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv); + } + } + + return httpStatus; +} + +static CURLcode rtsp_do(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + CURLcode result = CURLE_OK; + Curl_RtspReq rtspreq = data->set.rtspreq; + struct RTSP *rtsp = data->req.p.rtsp; + struct dynbuf req_buffer; + curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ + curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */ + + const char *p_request = NULL; + const char *p_session_id = NULL; + const char *p_accept = NULL; + const char *p_accept_encoding = NULL; + const char *p_range = NULL; + const char *p_referrer = NULL; + const char *p_stream_uri = NULL; + const char *p_transport = NULL; + const char *p_uagent = NULL; + const char *p_proxyuserpwd = NULL; + const char *p_userpwd = NULL; + + *done = TRUE; + + rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq; + rtsp->CSeq_recv = 0; + + /* Setup the first_* fields to allow auth details get sent + to this origin */ + + if(!data->state.first_host) { + data->state.first_host = strdup(conn->host.name); + if(!data->state.first_host) + return CURLE_OUT_OF_MEMORY; + + data->state.first_remote_port = conn->remote_port; + data->state.first_remote_protocol = conn->handler->protocol; + } + + /* Setup the 'p_request' pointer to the proper p_request string + * Since all RTSP requests are included here, there is no need to + * support custom requests like HTTP. + **/ + data->req.no_body = TRUE; /* most requests don't contain a body */ + switch(rtspreq) { + default: + failf(data, "Got invalid RTSP request"); + return CURLE_BAD_FUNCTION_ARGUMENT; + case RTSPREQ_OPTIONS: + p_request = "OPTIONS"; + break; + case RTSPREQ_DESCRIBE: + p_request = "DESCRIBE"; + data->req.no_body = FALSE; + break; + case RTSPREQ_ANNOUNCE: + p_request = "ANNOUNCE"; + break; + case RTSPREQ_SETUP: + p_request = "SETUP"; + break; + case RTSPREQ_PLAY: + p_request = "PLAY"; + break; + case RTSPREQ_PAUSE: + p_request = "PAUSE"; + break; + case RTSPREQ_TEARDOWN: + p_request = "TEARDOWN"; + break; + case RTSPREQ_GET_PARAMETER: + /* GET_PARAMETER's no_body status is determined later */ + p_request = "GET_PARAMETER"; + data->req.no_body = FALSE; + break; + case RTSPREQ_SET_PARAMETER: + p_request = "SET_PARAMETER"; + break; + case RTSPREQ_RECORD: + p_request = "RECORD"; + break; + case RTSPREQ_RECEIVE: + p_request = ""; + /* Treat interleaved RTP as body */ + data->req.no_body = FALSE; + break; + case RTSPREQ_LAST: + failf(data, "Got invalid RTSP request: RTSPREQ_LAST"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + if(rtspreq == RTSPREQ_RECEIVE) { + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); + + return result; + } + + p_session_id = data->set.str[STRING_RTSP_SESSION_ID]; + if(!p_session_id && + (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) { + failf(data, "Refusing to issue an RTSP request [%s] without a session ID.", + p_request); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + /* Stream URI. Default to server '*' if not specified */ + if(data->set.str[STRING_RTSP_STREAM_URI]) { + p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI]; + } + else { + p_stream_uri = "*"; + } + + /* Transport Header for SETUP requests */ + p_transport = Curl_checkheaders(data, STRCONST("Transport")); + if(rtspreq == RTSPREQ_SETUP && !p_transport) { + /* New Transport: setting? */ + if(data->set.str[STRING_RTSP_TRANSPORT]) { + Curl_safefree(data->state.aptr.rtsp_transport); + + data->state.aptr.rtsp_transport = + aprintf("Transport: %s\r\n", + data->set.str[STRING_RTSP_TRANSPORT]); + if(!data->state.aptr.rtsp_transport) + return CURLE_OUT_OF_MEMORY; + } + else { + failf(data, + "Refusing to issue an RTSP SETUP without a Transport: header."); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + p_transport = data->state.aptr.rtsp_transport; + } + + /* Accept Headers for DESCRIBE requests */ + if(rtspreq == RTSPREQ_DESCRIBE) { + /* Accept Header */ + p_accept = Curl_checkheaders(data, STRCONST("Accept"))? + NULL:"Accept: application/sdp\r\n"; + + /* Accept-Encoding header */ + if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && + data->set.str[STRING_ENCODING]) { + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = + aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); + + if(!data->state.aptr.accept_encoding) + return CURLE_OUT_OF_MEMORY; + + p_accept_encoding = data->state.aptr.accept_encoding; + } + } + + /* The User-Agent string might have been allocated in url.c already, because + it might have been used in the proxy connect, but if we have got a header + with the user-agent string specified, we erase the previously made string + here. */ + if(Curl_checkheaders(data, STRCONST("User-Agent")) && + data->state.aptr.uagent) { + Curl_safefree(data->state.aptr.uagent); + } + else if(!Curl_checkheaders(data, STRCONST("User-Agent")) && + data->set.str[STRING_USERAGENT]) { + p_uagent = data->state.aptr.uagent; + } + + /* setup the authentication headers */ + result = Curl_http_output_auth(data, conn, p_request, HTTPREQ_GET, + p_stream_uri, FALSE); + if(result) + return result; + + p_proxyuserpwd = data->state.aptr.proxyuserpwd; + p_userpwd = data->state.aptr.userpwd; + + /* Referrer */ + Curl_safefree(data->state.aptr.ref); + if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) + data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); + + p_referrer = data->state.aptr.ref; + + /* + * Range Header + * Only applies to PLAY, PAUSE, RECORD + * + * Go ahead and use the Range stuff supplied for HTTP + */ + if(data->state.use_range && + (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { + + /* Check to see if there is a range set in the custom headers */ + if(!Curl_checkheaders(data, STRCONST("Range")) && data->state.range) { + Curl_safefree(data->state.aptr.rangeline); + data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range); + p_range = data->state.aptr.rangeline; + } + } + + /* + * Sanity check the custom headers + */ + if(Curl_checkheaders(data, STRCONST("CSeq"))) { + failf(data, "CSeq cannot be set as a custom header."); + return CURLE_RTSP_CSEQ_ERROR; + } + if(Curl_checkheaders(data, STRCONST("Session"))) { + failf(data, "Session ID cannot be set as a custom header."); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + /* Initialize a dynamic send buffer */ + Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER); + + result = + Curl_dyn_addf(&req_buffer, + "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ + "CSeq: %ld\r\n", /* CSeq */ + p_request, p_stream_uri, rtsp->CSeq_sent); + if(result) + return result; + + /* + * Rather than do a normal alloc line, keep the session_id unformatted + * to make comparison easier + */ + if(p_session_id) { + result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id); + if(result) + return result; + } + + /* + * Shared HTTP-like options + */ + result = Curl_dyn_addf(&req_buffer, + "%s" /* transport */ + "%s" /* accept */ + "%s" /* accept-encoding */ + "%s" /* range */ + "%s" /* referrer */ + "%s" /* user-agent */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + , + p_transport ? p_transport : "", + p_accept ? p_accept : "", + p_accept_encoding ? p_accept_encoding : "", + p_range ? p_range : "", + p_referrer ? p_referrer : "", + p_uagent ? p_uagent : "", + p_proxyuserpwd ? p_proxyuserpwd : "", + p_userpwd ? p_userpwd : ""); + + /* + * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM + * with basic and digest, it will be freed anyway by the next request + */ + Curl_safefree(data->state.aptr.userpwd); + + if(result) + return result; + + if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) { + result = Curl_add_timecondition(data, &req_buffer); + if(result) + return result; + } + + result = Curl_add_custom_headers(data, FALSE, &req_buffer); + if(result) + return result; + + if(rtspreq == RTSPREQ_ANNOUNCE || + rtspreq == RTSPREQ_SET_PARAMETER || + rtspreq == RTSPREQ_GET_PARAMETER) { + + if(data->state.upload) { + putsize = data->state.infilesize; + data->state.httpreq = HTTPREQ_PUT; + + } + else { + postsize = (data->state.infilesize != -1)? + data->state.infilesize: + (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); + data->state.httpreq = HTTPREQ_POST; + } + + if(putsize > 0 || postsize > 0) { + /* As stated in the http comments, it is probably not wise to + * actually set a custom Content-Length in the headers */ + if(!Curl_checkheaders(data, STRCONST("Content-Length"))) { + result = + Curl_dyn_addf(&req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", + (data->state.upload ? putsize : postsize)); + if(result) + return result; + } + + if(rtspreq == RTSPREQ_SET_PARAMETER || + rtspreq == RTSPREQ_GET_PARAMETER) { + if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { + result = Curl_dyn_addn(&req_buffer, + STRCONST("Content-Type: " + "text/parameters\r\n")); + if(result) + return result; + } + } + + if(rtspreq == RTSPREQ_ANNOUNCE) { + if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { + result = Curl_dyn_addn(&req_buffer, + STRCONST("Content-Type: " + "application/sdp\r\n")); + if(result) + return result; + } + } + + data->state.expect100header = FALSE; /* RTSP posts are simple/small */ + } + else if(rtspreq == RTSPREQ_GET_PARAMETER) { + /* Check for an empty GET_PARAMETER (heartbeat) request */ + data->state.httpreq = HTTPREQ_HEAD; + data->req.no_body = TRUE; + } + } + + /* RTSP never allows chunked transfer */ + data->req.forbidchunk = TRUE; + /* Finish the request buffer */ + result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n")); + if(result) + return result; + + if(postsize > 0) { + result = Curl_dyn_addn(&req_buffer, data->set.postfields, + (size_t)postsize); + if(result) + return result; + } + + /* issue the request */ + result = Curl_buffer_send(&req_buffer, data, data->req.p.http, + &data->info.request_size, 0, FIRSTSOCKET); + if(result) { + failf(data, "Failed sending RTSP request"); + return result; + } + + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1); + + /* Increment the CSeq on success */ + data->state.rtsp_next_client_CSeq++; + + if(data->req.writebytecount) { + /* if a request-body has been sent off, we make sure this progress is + noted properly */ + Curl_pgrsSetUploadCounter(data, data->req.writebytecount); + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + } + + return result; +} + +/** + * write any BODY bytes missing to the client, ignore the rest. + */ +static CURLcode rtp_write_body_junk(struct Curl_easy *data, + const char *buf, + size_t blen) +{ + struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); + curl_off_t body_remain; + bool in_body; + + in_body = (data->req.headerline && !rtspc->in_header) && + (data->req.size >= 0) && + (data->req.bytecount < data->req.size); + body_remain = in_body? (data->req.size - data->req.bytecount) : 0; + DEBUGASSERT(body_remain >= 0); + if(body_remain) { + if((curl_off_t)blen > body_remain) + blen = (size_t)body_remain; + return Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen); + } + return CURLE_OK; +} + +static CURLcode rtsp_filter_rtp(struct Curl_easy *data, + const char *buf, + size_t blen, + size_t *pconsumed) +{ + struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); + CURLcode result = CURLE_OK; + size_t skip_len = 0; + + *pconsumed = 0; + while(blen) { + bool in_body = (data->req.headerline && !rtspc->in_header) && + (data->req.size >= 0) && + (data->req.bytecount < data->req.size); + switch(rtspc->state) { + + case RTP_PARSE_SKIP: { + DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 0); + while(blen && buf[0] != '$') { + if(!in_body && buf[0] == 'R' && + data->set.rtspreq != RTSPREQ_RECEIVE) { + if(strncmp(buf, "RTSP/", (blen < 5) ? blen : 5) == 0) { + /* This could be the next response, no consume and return */ + if(*pconsumed) { + DEBUGF(infof(data, "RTP rtsp_filter_rtp[SKIP] RTSP/ prefix, " + "skipping %zd bytes of junk", *pconsumed)); + } + rtspc->state = RTP_PARSE_SKIP; + rtspc->in_header = TRUE; + goto out; + } + } + /* junk/BODY, consume without buffering */ + *pconsumed += 1; + ++buf; + --blen; + ++skip_len; + } + if(blen && buf[0] == '$') { + /* possible start of an RTP message, buffer */ + if(skip_len) { + /* end of junk/BODY bytes, flush */ + result = rtp_write_body_junk(data, + (char *)(buf - skip_len), skip_len); + skip_len = 0; + if(result) + goto out; + } + if(Curl_dyn_addn(&rtspc->buf, buf, 1)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + *pconsumed += 1; + ++buf; + --blen; + rtspc->state = RTP_PARSE_CHANNEL; + } + break; + } + + case RTP_PARSE_CHANNEL: { + int idx = ((unsigned char)buf[0]) / 8; + int off = ((unsigned char)buf[0]) % 8; + DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 1); + if(!(data->state.rtp_channel_mask[idx] & (1 << off))) { + /* invalid channel number, junk or BODY data */ + rtspc->state = RTP_PARSE_SKIP; + DEBUGASSERT(skip_len == 0); + /* we do not consume this byte, it is BODY data */ + DEBUGF(infof(data, "RTSP: invalid RTP channel %d, skipping", idx)); + if(*pconsumed == 0) { + /* We did not consume the initial '$' in our buffer, but had + * it from an earlier call. We cannot un-consume it and have + * to write it directly as BODY data */ + result = rtp_write_body_junk(data, Curl_dyn_ptr(&rtspc->buf), 1); + if(result) + goto out; + } + else { + /* count the '$' as skip and continue */ + skip_len = 1; + } + Curl_dyn_free(&rtspc->buf); + break; + } + /* a valid channel, so we expect this to be a real RTP message */ + rtspc->rtp_channel = (unsigned char)buf[0]; + if(Curl_dyn_addn(&rtspc->buf, buf, 1)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + *pconsumed += 1; + ++buf; + --blen; + rtspc->state = RTP_PARSE_LEN; + break; + } + + case RTP_PARSE_LEN: { + size_t rtp_len = Curl_dyn_len(&rtspc->buf); + const char *rtp_buf; + DEBUGASSERT(rtp_len >= 2 && rtp_len < 4); + if(Curl_dyn_addn(&rtspc->buf, buf, 1)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + *pconsumed += 1; + ++buf; + --blen; + if(rtp_len == 2) + break; + rtp_buf = Curl_dyn_ptr(&rtspc->buf); + rtspc->rtp_len = RTP_PKT_LENGTH(rtp_buf) + 4; + rtspc->state = RTP_PARSE_DATA; + break; + } + + case RTP_PARSE_DATA: { + size_t rtp_len = Curl_dyn_len(&rtspc->buf); + size_t needed; + DEBUGASSERT(rtp_len < rtspc->rtp_len); + needed = rtspc->rtp_len - rtp_len; + if(needed <= blen) { + if(Curl_dyn_addn(&rtspc->buf, buf, needed)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + *pconsumed += needed; + buf += needed; + blen -= needed; + /* complete RTP message in buffer */ + DEBUGF(infof(data, "RTP write channel %d rtp_len %zu", + rtspc->rtp_channel, rtspc->rtp_len)); + result = rtp_client_write(data, Curl_dyn_ptr(&rtspc->buf), + rtspc->rtp_len); + Curl_dyn_free(&rtspc->buf); + rtspc->state = RTP_PARSE_SKIP; + if(result) + goto out; + } + else { + if(Curl_dyn_addn(&rtspc->buf, buf, blen)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + *pconsumed += blen; + buf += blen; + blen = 0; + } + break; + } + + default: + DEBUGASSERT(0); + return CURLE_RECV_ERROR; + } + } +out: + if(!result && skip_len) + result = rtp_write_body_junk(data, (char *)(buf - skip_len), skip_len); + return result; +} + +static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos, + bool *done) +{ + struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); + CURLcode result = CURLE_OK; + size_t consumed = 0; + + if(!data->req.header) + rtspc->in_header = FALSE; + *done = FALSE; + if(!blen) { + goto out; + } + + DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, eos=%d)", + blen, rtspc->in_header, is_eos)); + + /* If header parsing is not onging, extract RTP messages */ + if(!rtspc->in_header) { + result = rtsp_filter_rtp(data, buf, blen, &consumed); + if(result) + goto out; + buf += consumed; + blen -= consumed; + /* either we consumed all or are at the start of header parsing */ + if(blen && !data->req.header) + DEBUGF(infof(data, "RTSP: %zu bytes, possibly excess in response body", + blen)); + } + + /* we want to parse headers, do so */ + if(data->req.header && blen) { + rtspc->in_header = TRUE; + result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done); + if(result) + goto out; + + buf += consumed; + blen -= consumed; + + if(!data->req.header) + rtspc->in_header = FALSE; + + if(!rtspc->in_header) { + /* If header parsing is done, extract interleaved RTP messages */ + if(data->req.size <= -1) { + /* Respect section 4.4 of rfc2326: If the Content-Length header is + absent, a length 0 must be assumed. */ + data->req.size = 0; + data->req.download_done = TRUE; + } + result = rtsp_filter_rtp(data, buf, blen, &consumed); + if(result) + goto out; + blen -= consumed; + } + } + + if(rtspc->state != RTP_PARSE_SKIP) + *done = FALSE; + /* we SHOULD have consumed all bytes, unless the response is borked. + * In which case we write out the left over bytes, letting the client + * writer deal with it (it will report EXCESS and fail the transfer). */ + DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d " + " rtspc->state=%d, req.size=%" CURL_FORMAT_CURL_OFF_T ")", + blen, rtspc->in_header, *done, rtspc->state, data->req.size)); + if(!result && (is_eos || blen)) { + result = Curl_client_write(data, CLIENTWRITE_BODY| + (is_eos? CLIENTWRITE_EOS:0), + (char *)buf, blen); + } + +out: + if((data->set.rtspreq == RTSPREQ_RECEIVE) && + (rtspc->state == RTP_PARSE_SKIP)) { + /* In special mode RECEIVE, we just process one chunk of network + * data, so we stop the transfer here, if we have no incomplete + * RTP message pending. */ + data->req.download_done = TRUE; + } + return result; +} + +static +CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len) +{ + size_t wrote; + curl_write_callback writeit; + void *user_ptr; + + if(len == 0) { + failf(data, "Cannot write a 0 size RTP packet."); + return CURLE_WRITE_ERROR; + } + + /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that + function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP + data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA + pointer to write out the RTP data. */ + if(data->set.fwrite_rtp) { + writeit = data->set.fwrite_rtp; + user_ptr = data->set.rtp_out; + } + else { + writeit = data->set.fwrite_func; + user_ptr = data->set.out; + } + + Curl_set_in_callback(data, true); + wrote = writeit((char *)ptr, 1, len, user_ptr); + Curl_set_in_callback(data, false); + + if(CURL_WRITEFUNC_PAUSE == wrote) { + failf(data, "Cannot pause RTP"); + return CURLE_WRITE_ERROR; + } + + if(wrote != len) { + failf(data, "Failed writing RTP data"); + return CURLE_WRITE_ERROR; + } + + return CURLE_OK; +} + +CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) +{ + if(checkprefix("CSeq:", header)) { + long CSeq = 0; + char *endp; + char *p = &header[5]; + while(ISBLANK(*p)) + p++; + CSeq = strtol(p, &endp, 10); + if(p != endp) { + struct RTSP *rtsp = data->req.p.rtsp; + rtsp->CSeq_recv = CSeq; /* mark the request */ + data->state.rtsp_CSeq_recv = CSeq; /* update the handle */ + } + else { + failf(data, "Unable to read the CSeq header: [%s]", header); + return CURLE_RTSP_CSEQ_ERROR; + } + } + else if(checkprefix("Session:", header)) { + char *start; + char *end; + size_t idlen; + + /* Find the first non-space letter */ + start = header + 8; + while(*start && ISBLANK(*start)) + start++; + + if(!*start) { + failf(data, "Got a blank Session ID"); + return CURLE_RTSP_SESSION_ERROR; + } + + /* Find the end of Session ID + * + * Allow any non whitespace content, up to the field separator or end of + * line. RFC 2326 isn't 100% clear on the session ID and for example + * gstreamer does url-encoded session ID's not covered by the standard. + */ + end = start; + while(*end && *end != ';' && !ISSPACE(*end)) + end++; + idlen = end - start; + + if(data->set.str[STRING_RTSP_SESSION_ID]) { + + /* If the Session ID is set, then compare */ + if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen || + strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen)) { + failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]", + start, data->set.str[STRING_RTSP_SESSION_ID]); + return CURLE_RTSP_SESSION_ERROR; + } + } + else { + /* If the Session ID is not set, and we find it in a response, then set + * it. + */ + + /* Copy the id substring into a new buffer */ + data->set.str[STRING_RTSP_SESSION_ID] = Curl_memdup0(start, idlen); + if(!data->set.str[STRING_RTSP_SESSION_ID]) + return CURLE_OUT_OF_MEMORY; + } + } + else if(checkprefix("Transport:", header)) { + CURLcode result; + result = rtsp_parse_transport(data, header + 10); + if(result) + return result; + } + return CURLE_OK; +} + +static +CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport) +{ + /* If we receive multiple Transport response-headers, the linterleaved + channels of each response header is recorded and used together for + subsequent data validity checks.*/ + /* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */ + char *start; + char *end; + start = transport; + while(start && *start) { + while(*start && ISBLANK(*start) ) + start++; + end = strchr(start, ';'); + if(checkprefix("interleaved=", start)) { + long chan1, chan2, chan; + char *endp; + char *p = start + 12; + chan1 = strtol(p, &endp, 10); + if(p != endp && chan1 >= 0 && chan1 <= 255) { + unsigned char *rtp_channel_mask = data->state.rtp_channel_mask; + chan2 = chan1; + if(*endp == '-') { + p = endp + 1; + chan2 = strtol(p, &endp, 10); + if(p == endp || chan2 < 0 || chan2 > 255) { + infof(data, "Unable to read the interleaved parameter from " + "Transport header: [%s]", transport); + chan2 = chan1; + } + } + for(chan = chan1; chan <= chan2; chan++) { + long idx = chan / 8; + long off = chan % 8; + rtp_channel_mask[idx] |= (unsigned char)(1 << off); + } + } + else { + infof(data, "Unable to read the interleaved parameter from " + "Transport header: [%s]", transport); + } + break; + } + /* skip to next parameter */ + start = (!end) ? end : (end + 1); + } + return CURLE_OK; +} + + +#endif /* CURL_DISABLE_RTSP or using Hyper */ diff --git a/lib/rtsp.h b/lib/rtsp.h new file mode 100644 index 0000000..237b80f --- /dev/null +++ b/lib/rtsp.h @@ -0,0 +1,80 @@ +#ifndef HEADER_CURL_RTSP_H +#define HEADER_CURL_RTSP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifdef USE_HYPER +#define CURL_DISABLE_RTSP 1 +#endif + +#ifndef CURL_DISABLE_RTSP + +extern const struct Curl_handler Curl_handler_rtsp; + +CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header); + +#else +/* disabled */ +#define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN + +#endif /* CURL_DISABLE_RTSP */ + +typedef enum { + RTP_PARSE_SKIP, + RTP_PARSE_CHANNEL, + RTP_PARSE_LEN, + RTP_PARSE_DATA +} rtp_parse_st; +/* + * RTSP Connection data + * + * Currently, only used for tracking incomplete RTP data reads + */ +struct rtsp_conn { + struct dynbuf buf; + int rtp_channel; + size_t rtp_len; + rtp_parse_st state; + BIT(in_header); +}; + +/**************************************************************************** + * RTSP unique setup + ***************************************************************************/ +struct RTSP { + /* + * http_wrapper MUST be the first element of this structure for the wrap + * logic to work. In this way, we get a cheap polymorphism because + * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec + * + * HTTP functions can safely treat this as an HTTP struct, but RTSP aware + * functions can also index into the later elements. + */ + struct HTTP http_wrapper; /* wrap HTTP to do the heavy lifting */ + + long CSeq_sent; /* CSeq of this request */ + long CSeq_recv; /* CSeq received */ +}; + + +#endif /* HEADER_CURL_RTSP_H */ diff --git a/lib/select.c b/lib/select.c new file mode 100644 index 0000000..d92e745 --- /dev/null +++ b/lib/select.c @@ -0,0 +1,403 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif + +#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) +#error "We can't compile without select() or poll() support." +#endif + +#ifdef MSDOS +#include /* delay() */ +#endif + +#include + +#include "urldata.h" +#include "connect.h" +#include "select.h" +#include "timediff.h" +#include "warnless.h" + +/* + * Internal function used for waiting a specific amount of ms + * in Curl_socket_check() and Curl_poll() when no file descriptor + * is provided to wait on, just being used to delay execution. + * WinSock select() and poll() timeout mechanisms need a valid + * socket descriptor in a not null file descriptor set to work. + * Waiting indefinitely with this function is not allowed, a + * zero or negative timeout value will return immediately. + * Timeout resolution, accuracy, as well as maximum supported + * value is system dependent, neither factor is a critical issue + * for the intended use of this function in the library. + * + * Return values: + * -1 = system call error, or invalid timeout value + * 0 = specified timeout has elapsed, or interrupted + */ +int Curl_wait_ms(timediff_t timeout_ms) +{ + int r = 0; + + if(!timeout_ms) + return 0; + if(timeout_ms < 0) { + SET_SOCKERRNO(EINVAL); + return -1; + } +#if defined(MSDOS) + delay(timeout_ms); +#elif defined(_WIN32) + /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */ +#if TIMEDIFF_T_MAX >= ULONG_MAX + if(timeout_ms >= ULONG_MAX) + timeout_ms = ULONG_MAX-1; + /* don't use ULONG_MAX, because that is equal to INFINITE */ +#endif + Sleep((ULONG)timeout_ms); +#else +#if defined(HAVE_POLL_FINE) + /* prevent overflow, timeout_ms is typecast to int. */ +#if TIMEDIFF_T_MAX > INT_MAX + if(timeout_ms > INT_MAX) + timeout_ms = INT_MAX; +#endif + r = poll(NULL, 0, (int)timeout_ms); +#else + { + struct timeval pending_tv; + r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms)); + } +#endif /* HAVE_POLL_FINE */ +#endif /* USE_WINSOCK */ + if(r) { + if((r == -1) && (SOCKERRNO == EINTR)) + /* make EINTR from select or poll not a "lethal" error */ + r = 0; + else + r = -1; + } + return r; +} + +#ifndef HAVE_POLL_FINE +/* + * This is a wrapper around select() to aid in Windows compatibility. + * A negative timeout value makes this function wait indefinitely, + * unless no valid file descriptor is given, when this happens the + * negative timeout is ignored and the function times out immediately. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * N = number of signalled file descriptors + */ +static int our_select(curl_socket_t maxfd, /* highest socket number */ + fd_set *fds_read, /* sockets ready for reading */ + fd_set *fds_write, /* sockets ready for writing */ + fd_set *fds_err, /* sockets with errors */ + timediff_t timeout_ms) /* milliseconds to wait */ +{ + struct timeval pending_tv; + struct timeval *ptimeout; + +#ifdef USE_WINSOCK + /* WinSock select() can't handle zero events. See the comment below. */ + if((!fds_read || fds_read->fd_count == 0) && + (!fds_write || fds_write->fd_count == 0) && + (!fds_err || fds_err->fd_count == 0)) { + /* no sockets, just wait */ + return Curl_wait_ms(timeout_ms); + } +#endif + + ptimeout = curlx_mstotv(&pending_tv, timeout_ms); + +#ifdef USE_WINSOCK + /* WinSock select() must not be called with an fd_set that contains zero + fd flags, or it will return WSAEINVAL. But, it also can't be called + with no fd_sets at all! From the documentation: + + Any two of the parameters, readfds, writefds, or exceptfds, can be + given as null. At least one must be non-null, and any non-null + descriptor set must contain at least one handle to a socket. + + It is unclear why WinSock doesn't just handle this for us instead of + calling this an error. Luckily, with WinSock, we can _also_ ask how + many bits are set on an fd_set. So, let's just check it beforehand. + */ + return select((int)maxfd + 1, + fds_read && fds_read->fd_count ? fds_read : NULL, + fds_write && fds_write->fd_count ? fds_write : NULL, + fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout); +#else + return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout); +#endif +} + +#endif + +/* + * Wait for read or write events on a set of file descriptors. It uses poll() + * when a fine poll() is available, in order to avoid limits with FD_SETSIZE, + * otherwise select() is used. An error is returned if select() is being used + * and a file descriptor is too large for FD_SETSIZE. + * + * A negative timeout value makes this function wait indefinitely, + * unless no valid file descriptor is given, when this happens the + * negative timeout is ignored and the function times out immediately. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * [bitmask] = action as described below + * + * CURL_CSELECT_IN - first socket is readable + * CURL_CSELECT_IN2 - second socket is readable + * CURL_CSELECT_OUT - write socket is writable + * CURL_CSELECT_ERR - an error condition occurred + */ +int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ + curl_socket_t readfd1, + curl_socket_t writefd, /* socket to write to */ + timediff_t timeout_ms) /* milliseconds to wait */ +{ + struct pollfd pfd[3]; + int num; + int r; + + if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && + (writefd == CURL_SOCKET_BAD)) { + /* no sockets, just wait */ + return Curl_wait_ms(timeout_ms); + } + + /* Avoid initial timestamp, avoid Curl_now() call, when elapsed + time in this function does not need to be measured. This happens + when function is called with a zero timeout or a negative timeout + value indicating a blocking call should be performed. */ + + num = 0; + if(readfd0 != CURL_SOCKET_BAD) { + pfd[num].fd = readfd0; + pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[num].revents = 0; + num++; + } + if(readfd1 != CURL_SOCKET_BAD) { + pfd[num].fd = readfd1; + pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[num].revents = 0; + num++; + } + if(writefd != CURL_SOCKET_BAD) { + pfd[num].fd = writefd; + pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI; + pfd[num].revents = 0; + num++; + } + + r = Curl_poll(pfd, num, timeout_ms); + if(r <= 0) + return r; + + r = 0; + num = 0; + if(readfd0 != CURL_SOCKET_BAD) { + if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) + r |= CURL_CSELECT_IN; + if(pfd[num].revents & (POLLPRI|POLLNVAL)) + r |= CURL_CSELECT_ERR; + num++; + } + if(readfd1 != CURL_SOCKET_BAD) { + if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) + r |= CURL_CSELECT_IN2; + if(pfd[num].revents & (POLLPRI|POLLNVAL)) + r |= CURL_CSELECT_ERR; + num++; + } + if(writefd != CURL_SOCKET_BAD) { + if(pfd[num].revents & (POLLWRNORM|POLLOUT)) + r |= CURL_CSELECT_OUT; + if(pfd[num].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) + r |= CURL_CSELECT_ERR; + } + + return r; +} + +/* + * This is a wrapper around poll(). If poll() does not exist, then + * select() is used instead. An error is returned if select() is + * being used and a file descriptor is too large for FD_SETSIZE. + * A negative timeout value makes this function wait indefinitely, + * unless no valid file descriptor is given, when this happens the + * negative timeout is ignored and the function times out immediately. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * N = number of structures with non zero revent fields + */ +int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms) +{ +#ifdef HAVE_POLL_FINE + int pending_ms; +#else + fd_set fds_read; + fd_set fds_write; + fd_set fds_err; + curl_socket_t maxfd; +#endif + bool fds_none = TRUE; + unsigned int i; + int r; + + if(ufds) { + for(i = 0; i < nfds; i++) { + if(ufds[i].fd != CURL_SOCKET_BAD) { + fds_none = FALSE; + break; + } + } + } + if(fds_none) { + /* no sockets, just wait */ + return Curl_wait_ms(timeout_ms); + } + + /* Avoid initial timestamp, avoid Curl_now() call, when elapsed + time in this function does not need to be measured. This happens + when function is called with a zero timeout or a negative timeout + value indicating a blocking call should be performed. */ + +#ifdef HAVE_POLL_FINE + + /* prevent overflow, timeout_ms is typecast to int. */ +#if TIMEDIFF_T_MAX > INT_MAX + if(timeout_ms > INT_MAX) + timeout_ms = INT_MAX; +#endif + if(timeout_ms > 0) + pending_ms = (int)timeout_ms; + else if(timeout_ms < 0) + pending_ms = -1; + else + pending_ms = 0; + r = poll(ufds, nfds, pending_ms); + if(r <= 0) { + if((r == -1) && (SOCKERRNO == EINTR)) + /* make EINTR from select or poll not a "lethal" error */ + r = 0; + return r; + } + + for(i = 0; i < nfds; i++) { + if(ufds[i].fd == CURL_SOCKET_BAD) + continue; + if(ufds[i].revents & POLLHUP) + ufds[i].revents |= POLLIN; + if(ufds[i].revents & POLLERR) + ufds[i].revents |= POLLIN|POLLOUT; + } + +#else /* HAVE_POLL_FINE */ + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_ZERO(&fds_err); + maxfd = (curl_socket_t)-1; + + for(i = 0; i < nfds; i++) { + ufds[i].revents = 0; + if(ufds[i].fd == CURL_SOCKET_BAD) + continue; + VERIFY_SOCK(ufds[i].fd); + if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI| + POLLRDNORM|POLLWRNORM|POLLRDBAND)) { + if(ufds[i].fd > maxfd) + maxfd = ufds[i].fd; + if(ufds[i].events & (POLLRDNORM|POLLIN)) + FD_SET(ufds[i].fd, &fds_read); + if(ufds[i].events & (POLLWRNORM|POLLOUT)) + FD_SET(ufds[i].fd, &fds_write); + if(ufds[i].events & (POLLRDBAND|POLLPRI)) + FD_SET(ufds[i].fd, &fds_err); + } + } + + /* + Note also that WinSock ignores the first argument, so we don't worry + about the fact that maxfd is computed incorrectly with WinSock (since + curl_socket_t is unsigned in such cases and thus -1 is the largest + value). + */ + r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms); + if(r <= 0) { + if((r == -1) && (SOCKERRNO == EINTR)) + /* make EINTR from select or poll not a "lethal" error */ + r = 0; + return r; + } + + r = 0; + for(i = 0; i < nfds; i++) { + ufds[i].revents = 0; + if(ufds[i].fd == CURL_SOCKET_BAD) + continue; + if(FD_ISSET(ufds[i].fd, &fds_read)) { + if(ufds[i].events & POLLRDNORM) + ufds[i].revents |= POLLRDNORM; + if(ufds[i].events & POLLIN) + ufds[i].revents |= POLLIN; + } + if(FD_ISSET(ufds[i].fd, &fds_write)) { + if(ufds[i].events & POLLWRNORM) + ufds[i].revents |= POLLWRNORM; + if(ufds[i].events & POLLOUT) + ufds[i].revents |= POLLOUT; + } + if(FD_ISSET(ufds[i].fd, &fds_err)) { + if(ufds[i].events & POLLRDBAND) + ufds[i].revents |= POLLRDBAND; + if(ufds[i].events & POLLPRI) + ufds[i].revents |= POLLPRI; + } + if(ufds[i].revents) + r++; + } + +#endif /* HAVE_POLL_FINE */ + + return r; +} diff --git a/lib/select.h b/lib/select.h new file mode 100644 index 0000000..5b1ca23 --- /dev/null +++ b/lib/select.h @@ -0,0 +1,114 @@ +#ifndef HEADER_CURL_SELECT_H +#define HEADER_CURL_SELECT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_POLL_H +#include +#elif defined(HAVE_SYS_POLL_H) +#include +#endif + +/* + * Definition of pollfd struct and constants for platforms lacking them. + */ + +#if !defined(HAVE_SYS_POLL_H) && \ + !defined(HAVE_POLL_H) && \ + !defined(POLLIN) + +#define POLLIN 0x01 +#define POLLPRI 0x02 +#define POLLOUT 0x04 +#define POLLERR 0x08 +#define POLLHUP 0x10 +#define POLLNVAL 0x20 + +struct pollfd +{ + curl_socket_t fd; + short events; + short revents; +}; + +#endif + +#ifndef POLLRDNORM +#define POLLRDNORM POLLIN +#endif + +#ifndef POLLWRNORM +#define POLLWRNORM POLLOUT +#endif + +#ifndef POLLRDBAND +#define POLLRDBAND POLLPRI +#endif + +/* there are three CSELECT defines that are defined in the public header that + are exposed to users, but this *IN2 bit is only ever used internally and + therefore defined here */ +#define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1) + +int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, + curl_socket_t writefd, + timediff_t timeout_ms); +#define SOCKET_READABLE(x,z) \ + Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z) +#define SOCKET_WRITABLE(x,z) \ + Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) + +int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms); +int Curl_wait_ms(timediff_t timeout_ms); + +/* + With Winsock the valid range is [0..INVALID_SOCKET-1] according to + https://docs.microsoft.com/en-us/windows/win32/winsock/socket-data-type-2 +*/ +#ifdef USE_WINSOCK +#define VALID_SOCK(s) ((s) < INVALID_SOCKET) +#define FDSET_SOCK(x) 1 +#define VERIFY_SOCK(x) do { \ + if(!VALID_SOCK(x)) { \ + SET_SOCKERRNO(WSAEINVAL); \ + return -1; \ + } \ +} while(0) +#else +#define VALID_SOCK(s) ((s) >= 0) + +/* If the socket is small enough to get set or read from an fdset */ +#define FDSET_SOCK(s) ((s) < FD_SETSIZE) + +#define VERIFY_SOCK(x) do { \ + if(!VALID_SOCK(x) || !FDSET_SOCK(x)) { \ + SET_SOCKERRNO(EINVAL); \ + return -1; \ + } \ + } while(0) +#endif + +#endif /* HEADER_CURL_SELECT_H */ diff --git a/lib/sendf.c b/lib/sendf.c new file mode 100644 index 0000000..db3189a --- /dev/null +++ b/lib/sendf.c @@ -0,0 +1,821 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_LINUX_TCP_H +#include +#elif defined(HAVE_NETINET_TCP_H) +#include +#endif + +#include + +#include "urldata.h" +#include "sendf.h" +#include "cfilters.h" +#include "connect.h" +#include "content_encoding.h" +#include "vtls/vtls.h" +#include "vssh/ssh.h" +#include "easyif.h" +#include "multiif.h" +#include "strerror.h" +#include "select.h" +#include "strdup.h" +#include "http2.h" +#include "headers.h" +#include "progress.h" +#include "ws.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +static CURLcode do_init_stack(struct Curl_easy *data); + +#if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP) +/* + * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF + * (\n), with special processing for CRLF sequences that are split between two + * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new + * size of the data is returned. + */ +static size_t convert_lineends(struct Curl_easy *data, + char *startPtr, size_t size) +{ + char *inPtr, *outPtr; + + /* sanity check */ + if(!startPtr || (size < 1)) { + return size; + } + + if(data->state.prev_block_had_trailing_cr) { + /* The previous block of incoming data + had a trailing CR, which was turned into a LF. */ + if(*startPtr == '\n') { + /* This block of incoming data starts with the + previous block's LF so get rid of it */ + memmove(startPtr, startPtr + 1, size-1); + size--; + /* and it wasn't a bare CR but a CRLF conversion instead */ + data->state.crlf_conversions++; + } + data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */ + } + + /* find 1st CR, if any */ + inPtr = outPtr = memchr(startPtr, '\r', size); + if(inPtr) { + /* at least one CR, now look for CRLF */ + while(inPtr < (startPtr + size-1)) { + /* note that it's size-1, so we'll never look past the last byte */ + if(memcmp(inPtr, "\r\n", 2) == 0) { + /* CRLF found, bump past the CR and copy the NL */ + inPtr++; + *outPtr = *inPtr; + /* keep track of how many CRLFs we converted */ + data->state.crlf_conversions++; + } + else { + if(*inPtr == '\r') { + /* lone CR, move LF instead */ + *outPtr = '\n'; + } + else { + /* not a CRLF nor a CR, just copy whatever it is */ + *outPtr = *inPtr; + } + } + outPtr++; + inPtr++; + } /* end of while loop */ + + if(inPtr < startPtr + size) { + /* handle last byte */ + if(*inPtr == '\r') { + /* deal with a CR at the end of the buffer */ + *outPtr = '\n'; /* copy a NL instead */ + /* note that a CRLF might be split across two blocks */ + data->state.prev_block_had_trailing_cr = TRUE; + } + else { + /* copy last byte */ + *outPtr = *inPtr; + } + outPtr++; + } + if(outPtr < startPtr + size) + /* tidy up by null terminating the now shorter data */ + *outPtr = '\0'; + + return (outPtr - startPtr); + } + return size; +} +#endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */ + +/* + * Curl_nwrite() is an internal write function that sends data to the + * server. Works with a socket index for the connection. + * + * If the write would block (CURLE_AGAIN), it returns CURLE_OK and + * (*nwritten == 0). Otherwise we return regular CURLcode value. + */ +CURLcode Curl_nwrite(struct Curl_easy *data, + int sockindex, + const void *buf, + size_t blen, + ssize_t *pnwritten) +{ + ssize_t nwritten; + CURLcode result = CURLE_OK; + struct connectdata *conn; + + DEBUGASSERT(sockindex >= 0 && sockindex < 2); + DEBUGASSERT(pnwritten); + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + conn = data->conn; +#ifdef CURLDEBUG + { + /* Allow debug builds to override this logic to force short sends + */ + char *p = getenv("CURL_SMALLSENDS"); + if(p) { + size_t altsize = (size_t)strtoul(p, NULL, 10); + if(altsize) + blen = CURLMIN(blen, altsize); + } + } +#endif + nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result); + if(result == CURLE_AGAIN) { + nwritten = 0; + result = CURLE_OK; + } + else if(result) { + nwritten = -1; /* make sure */ + } + else { + DEBUGASSERT(nwritten >= 0); + } + + *pnwritten = nwritten; + return result; +} + +/* + * Curl_write() is an internal write function that sends data to the + * server. Works with plain sockets, SCP, SSL or kerberos. + * + * If the write would block (CURLE_AGAIN), we return CURLE_OK and + * (*written == 0). Otherwise we return regular CURLcode value. + */ +CURLcode Curl_write(struct Curl_easy *data, + curl_socket_t sockfd, + const void *mem, + size_t len, + ssize_t *written) +{ + struct connectdata *conn; + int num; + + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + conn = data->conn; + num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]); + return Curl_nwrite(data, num, mem, len, written); +} + +static CURLcode pausewrite(struct Curl_easy *data, + int type, /* what type of data */ + bool paused_body, + const char *ptr, + size_t len) +{ + /* signalled to pause sending on this connection, but since we have data + we want to send we need to dup it to save a copy for when the sending + is again enabled */ + struct SingleRequest *k = &data->req; + struct UrlState *s = &data->state; + unsigned int i; + bool newtype = TRUE; + + Curl_conn_ev_data_pause(data, TRUE); + + if(s->tempcount) { + for(i = 0; i< s->tempcount; i++) { + if(s->tempwrite[i].type == type && + !!s->tempwrite[i].paused_body == !!paused_body) { + /* data for this type exists */ + newtype = FALSE; + break; + } + } + DEBUGASSERT(i < 3); + if(i >= 3) + /* There are more types to store than what fits: very bad */ + return CURLE_OUT_OF_MEMORY; + } + else + i = 0; + + if(newtype) { + /* store this information in the state struct for later use */ + Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER); + s->tempwrite[i].type = type; + s->tempwrite[i].paused_body = paused_body; + s->tempcount++; + } + + if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len)) + return CURLE_OUT_OF_MEMORY; + + /* mark the connection as RECV paused */ + k->keepon |= KEEP_RECV_PAUSE; + + return CURLE_OK; +} + + +/* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via + * client write callback(s) and takes care of pause requests from the + * callbacks. + */ +static CURLcode chop_write(struct Curl_easy *data, + int type, + bool skip_body_write, + char *optr, + size_t olen) +{ + struct connectdata *conn = data->conn; + curl_write_callback writeheader = NULL; + curl_write_callback writebody = NULL; + char *ptr = optr; + size_t len = olen; + void *writebody_ptr = data->set.out; + + if(!len) + return CURLE_OK; + + /* If reading is paused, append this data to the already held data for this + type. */ + if(data->req.keepon & KEEP_RECV_PAUSE) + return pausewrite(data, type, !skip_body_write, ptr, len); + + /* Determine the callback(s) to use. */ + if(!skip_body_write && + ((type & CLIENTWRITE_BODY) || + ((type & CLIENTWRITE_HEADER) && data->set.include_header))) { + writebody = data->set.fwrite_func; + } + if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) && + (data->set.fwrite_header || data->set.writeheader)) { + /* + * Write headers to the same callback or to the especially setup + * header callback function (added after version 7.7.1). + */ + writeheader = + data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func; + } + + /* Chop data, write chunks. */ + while(len) { + size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE; + + if(writebody) { + size_t wrote; + Curl_set_in_callback(data, true); + wrote = writebody(ptr, 1, chunklen, writebody_ptr); + Curl_set_in_callback(data, false); + + if(CURL_WRITEFUNC_PAUSE == wrote) { + if(conn->handler->flags & PROTOPT_NONETWORK) { + /* Protocols that work without network cannot be paused. This is + actually only FILE:// just now, and it can't pause since the + transfer isn't done using the "normal" procedure. */ + failf(data, "Write callback asked for PAUSE when not supported"); + return CURLE_WRITE_ERROR; + } + return pausewrite(data, type, TRUE, ptr, len); + } + if(wrote != chunklen) { + failf(data, "Failure writing output to destination"); + return CURLE_WRITE_ERROR; + } + } + + ptr += chunklen; + len -= chunklen; + } + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) + /* HTTP header, but not status-line */ + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) { + unsigned char htype = (unsigned char) + (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT : + (type & CLIENTWRITE_1XX ? CURLH_1XX : + (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER : + CURLH_HEADER))); + CURLcode result = Curl_headers_push(data, optr, htype); + if(result) + return result; + } +#endif + + if(writeheader) { + size_t wrote; + + Curl_set_in_callback(data, true); + wrote = writeheader(optr, 1, olen, data->set.writeheader); + Curl_set_in_callback(data, false); + + if(CURL_WRITEFUNC_PAUSE == wrote) + return pausewrite(data, type, FALSE, optr, olen); + if(wrote != olen) { + failf(data, "Failed writing header"); + return CURLE_WRITE_ERROR; + } + } + + return CURLE_OK; +} + + +/* Curl_client_write() sends data to the write callback(s) + + The bit pattern defines to what "streams" to write to. Body and/or header. + The defines are in sendf.h of course. + + If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the + local character encoding. This is a problem and should be changed in + the future to leave the original data alone. + */ +CURLcode Curl_client_write(struct Curl_easy *data, + int type, char *buf, size_t blen) +{ + CURLcode result; + +#if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV) + /* FTP data may need conversion. */ + if((type & CLIENTWRITE_BODY) && + (data->conn->handler->protocol & PROTO_FAMILY_FTP) && + data->conn->proto.ftpc.transfertype == 'A') { + /* convert end-of-line markers */ + blen = convert_lineends(data, buf, blen); + } +#endif + /* it is one of those, at least */ + DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO)); + /* BODY is only BODY (with optional EOS) */ + DEBUGASSERT(!(type & CLIENTWRITE_BODY) || + ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0)); + /* INFO is only INFO (with optional EOS) */ + DEBUGASSERT(!(type & CLIENTWRITE_INFO) || + ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0)); + + if(!data->req.writer_stack) { + result = do_init_stack(data); + if(result) + return result; + DEBUGASSERT(data->req.writer_stack); + } + + return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen); +} + +CURLcode Curl_client_unpause(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + + if(data->state.tempcount) { + /* there are buffers for sending that can be delivered as the receive + pausing is lifted! */ + unsigned int i; + unsigned int count = data->state.tempcount; + struct tempbuf writebuf[3]; /* there can only be three */ + + /* copy the structs to allow for immediate re-pausing */ + for(i = 0; i < data->state.tempcount; i++) { + writebuf[i] = data->state.tempwrite[i]; + Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER); + } + data->state.tempcount = 0; + + for(i = 0; i < count; i++) { + /* even if one function returns error, this loops through and frees + all buffers */ + if(!result) + result = chop_write(data, writebuf[i].type, + !writebuf[i].paused_body, + Curl_dyn_ptr(&writebuf[i].b), + Curl_dyn_len(&writebuf[i].b)); + Curl_dyn_free(&writebuf[i].b); + } + } + return result; +} + +void Curl_client_cleanup(struct Curl_easy *data) +{ + struct Curl_cwriter *writer = data->req.writer_stack; + size_t i; + + while(writer) { + data->req.writer_stack = writer->next; + writer->cwt->do_close(data, writer); + free(writer); + writer = data->req.writer_stack; + } + + for(i = 0; i < data->state.tempcount; i++) { + Curl_dyn_free(&data->state.tempwrite[i].b); + } + data->state.tempcount = 0; + data->req.bytecount = 0; + data->req.headerline = 0; +} + +/* Write data using an unencoding writer stack. "nbytes" is not + allowed to be 0. */ +CURLcode Curl_cwriter_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + if(!writer) + return CURLE_WRITE_ERROR; + return writer->cwt->do_write(data, writer, type, buf, nbytes); +} + +CURLcode Curl_cwriter_def_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + (void)data; + (void)writer; + return CURLE_OK; +} + +CURLcode Curl_cwriter_def_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); +} + +void Curl_cwriter_def_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + (void) data; + (void) writer; +} + +/* Real client writer to installed callbacks. */ +static CURLcode cw_client_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + (void)writer; + if(!nbytes) + return CURLE_OK; + return chop_write(data, type, FALSE, (char *)buf, nbytes); +} + +static const struct Curl_cwtype cw_client = { + "client", + NULL, + Curl_cwriter_def_init, + cw_client_write, + Curl_cwriter_def_close, + sizeof(struct Curl_cwriter) +}; + +static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit) +{ + if(limit != -1) { + /* How much more are we allowed to write? */ + curl_off_t remain_diff; + remain_diff = limit - data->req.bytecount; + if(remain_diff < 0) { + /* already written too much! */ + return 0; + } +#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T + else if(remain_diff > SSIZE_T_MAX) { + return SIZE_T_MAX; + } +#endif + else { + return (size_t)remain_diff; + } + } + return SIZE_T_MAX; +} + +/* Download client writer in phase CURL_CW_PROTOCOL that + * sees the "real" download body data. */ +static CURLcode cw_download_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + CURLcode result; + size_t nwrite, excess_len = 0; + + if(!(type & CLIENTWRITE_BODY)) { + if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers) + return CURLE_OK; + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + } + + if(!data->req.bytecount) { + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + if(data->req.exp100 > EXP100_SEND_DATA) + /* set time stamp to compare with when waiting for the 100 */ + data->req.start100 = Curl_now(); + } + + /* Here, we deal with REAL BODY bytes. All filtering and transfer + * encodings have been applied and only the true content, e.g. BODY, + * bytes are passed here. + * This allows us to check sizes, update stats, etc. independent + * from the protocol in play. */ + + if(data->req.no_body && nbytes > 0) { + /* BODY arrives although we want none, bail out */ + streamclose(data->conn, "ignoring body"); + DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes", + nbytes)); + data->req.download_done = TRUE; + return CURLE_WEIRD_SERVER_REPLY; + } + + /* Determine if we see any bytes in excess to what is allowed. + * We write the allowed bytes and handle excess further below. + * This gives deterministic BODY writes on varying buffer receive + * lengths. */ + nwrite = nbytes; + if(-1 != data->req.maxdownload) { + size_t wmax = get_max_body_write_len(data, data->req.maxdownload); + if(nwrite > wmax) { + excess_len = nbytes - wmax; + nwrite = wmax; + } + + if(nwrite == wmax) { + data->req.download_done = TRUE; + } + } + + /* Error on too large filesize is handled below, after writing + * the permitted bytes */ + if(data->set.max_filesize) { + size_t wmax = get_max_body_write_len(data, data->set.max_filesize); + if(nwrite > wmax) { + nwrite = wmax; + } + } + + /* Update stats, write and report progress */ + data->req.bytecount += nwrite; + ++data->req.bodywrites; + if(!data->req.ignorebody && nwrite) { + result = Curl_cwriter_write(data, writer->next, type, buf, nwrite); + if(result) + return result; + } + result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + if(result) + return result; + + if(excess_len) { + if(!data->req.ignorebody) { + infof(data, + "Excess found writing body:" + " excess = %zu" + ", size = %" CURL_FORMAT_CURL_OFF_T + ", maxdownload = %" CURL_FORMAT_CURL_OFF_T + ", bytecount = %" CURL_FORMAT_CURL_OFF_T, + excess_len, data->req.size, data->req.maxdownload, + data->req.bytecount); + connclose(data->conn, "excess found in a read"); + } + } + else if(nwrite < nbytes) { + failf(data, "Exceeded the maximum allowed file size " + "(%" CURL_FORMAT_CURL_OFF_T ") with %" + CURL_FORMAT_CURL_OFF_T " bytes", + data->set.max_filesize, data->req.bytecount); + return CURLE_FILESIZE_EXCEEDED; + } + + return CURLE_OK; +} + +static const struct Curl_cwtype cw_download = { + "download", + NULL, + Curl_cwriter_def_init, + cw_download_write, + Curl_cwriter_def_close, + sizeof(struct Curl_cwriter) +}; + +/* RAW client writer in phase CURL_CW_RAW that + * enabled tracing of raw data. */ +static CURLcode cw_raw_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) { + Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes); + } + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); +} + +static const struct Curl_cwtype cw_raw = { + "raw", + NULL, + Curl_cwriter_def_init, + cw_raw_write, + Curl_cwriter_def_close, + sizeof(struct Curl_cwriter) +}; + +/* Create an unencoding writer stage using the given handler. */ +CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter, + struct Curl_easy *data, + const struct Curl_cwtype *cwt, + Curl_cwriter_phase phase) +{ + struct Curl_cwriter *writer; + CURLcode result = CURLE_OUT_OF_MEMORY; + + DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter)); + writer = (struct Curl_cwriter *) calloc(1, cwt->cwriter_size); + if(!writer) + goto out; + + writer->cwt = cwt; + writer->phase = phase; + result = cwt->do_init(data, writer); + +out: + *pwriter = result? NULL : writer; + if(result) + free(writer); + return result; +} + +void Curl_cwriter_free(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + if(writer) { + writer->cwt->do_close(data, writer); + free(writer); + } +} + +size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase) +{ + struct Curl_cwriter *w; + size_t n = 0; + + for(w = data->req.writer_stack; w; w = w->next) { + if(w->phase == phase) + ++n; + } + return n; +} + +static CURLcode do_init_stack(struct Curl_easy *data) +{ + struct Curl_cwriter *writer; + CURLcode result; + + DEBUGASSERT(!data->req.writer_stack); + result = Curl_cwriter_create(&data->req.writer_stack, + data, &cw_client, CURL_CW_CLIENT); + if(result) + return result; + + result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL); + if(result) + return result; + result = Curl_cwriter_add(data, writer); + if(result) { + Curl_cwriter_free(data, writer); + } + + result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW); + if(result) + return result; + result = Curl_cwriter_add(data, writer); + if(result) { + Curl_cwriter_free(data, writer); + } + return result; +} + +CURLcode Curl_cwriter_add(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + CURLcode result; + struct Curl_cwriter **anchor = &data->req.writer_stack; + + if(!*anchor) { + result = do_init_stack(data); + if(result) + return result; + } + + /* Insert the writer as first in its phase. + * Skip existing writers of lower phases. */ + while(*anchor && (*anchor)->phase < writer->phase) + anchor = &((*anchor)->next); + writer->next = *anchor; + *anchor = writer; + return CURLE_OK; +} + +void Curl_cwriter_remove_by_name(struct Curl_easy *data, + const char *name) +{ + struct Curl_cwriter **anchor = &data->req.writer_stack; + + while(*anchor) { + if(!strcmp(name, (*anchor)->cwt->name)) { + struct Curl_cwriter *w = (*anchor); + *anchor = w->next; + Curl_cwriter_free(data, w); + continue; + } + anchor = &((*anchor)->next); + } +} + +/* + * Internal read-from-socket function. This is meant to deal with plain + * sockets, SSL sockets and kerberos sockets. + * + * Returns a regular CURLcode value. + */ +CURLcode Curl_read(struct Curl_easy *data, /* transfer */ + curl_socket_t sockfd, /* read from this socket */ + char *buf, /* store read data here */ + size_t sizerequested, /* max amount to read */ + ssize_t *n) /* amount bytes read */ +{ + CURLcode result = CURLE_RECV_ERROR; + ssize_t nread = 0; + size_t bytesfromsocket = 0; + char *buffertofill = NULL; + struct connectdata *conn = data->conn; + + /* Set 'num' to 0 or 1, depending on which socket that has been sent here. + If it is the second socket, we set num to 1. Otherwise to 0. This lets + us use the correct ssl handle. */ + int num = (sockfd == conn->sock[SECONDARYSOCKET]); + + *n = 0; /* reset amount to zero */ + + bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size); + buffertofill = buf; + + nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result); + if(nread < 0) + goto out; + + *n += nread; + result = CURLE_OK; +out: + return result; +} diff --git a/lib/sendf.h b/lib/sendf.h new file mode 100644 index 0000000..7deae2a --- /dev/null +++ b/lib/sendf.h @@ -0,0 +1,193 @@ +#ifndef HEADER_CURL_SENDF_H +#define HEADER_CURL_SENDF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "curl_trc.h" + +/** + * Type of data that is being written to the client (application) + * - data written can be either BODY or META data + * - META data is either INFO or HEADER + * - INFO is meta information, e.g. not BODY, that cannot be interpreted + * as headers of a response. Example FTP/IMAP pingpong answers. + * - HEADER can have additional bits set (more than one) + * - STATUS special "header", e.g. response status line in HTTP + * - CONNECT header was received during proxying the connection + * - 1XX header is part of an intermediate response, e.g. HTTP 1xx code + * - TRAILER header is trailing response data, e.g. HTTP trailers + * BODY, INFO and HEADER should not be mixed, as this would lead to + * confusion on how to interpret/format/convert the data. + */ +#define CLIENTWRITE_BODY (1<<0) /* non-meta information, BODY */ +#define CLIENTWRITE_INFO (1<<1) /* meta information, not a HEADER */ +#define CLIENTWRITE_HEADER (1<<2) /* meta information, HEADER */ +#define CLIENTWRITE_STATUS (1<<3) /* a special status HEADER */ +#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */ +#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */ +#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */ +#define CLIENTWRITE_EOS (1<<7) /* End Of transfer download Stream */ + +/** + * Write `len` bytes at `prt` to the client. `type` indicates what + * kind of data is being written. + */ +CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr, + size_t len) WARN_UNUSED_RESULT; + +/** + * For a paused transfer, there might be buffered data held back. + * Attempt to flush this data to the client. This *may* trigger + * another pause of the transfer. + */ +CURLcode Curl_client_unpause(struct Curl_easy *data); + +/** + * Free all resources related to client writing. + */ +void Curl_client_cleanup(struct Curl_easy *data); + +/** + * Client Writers - a chain passing transfer BODY data to the client. + * Main application: HTTP and related protocols + * Other uses: monitoring of download progress + * + * Writers in the chain are order by their `phase`. First come all + * writers in CURL_CW_RAW, followed by any in CURL_CW_TRANSFER_DECODE, + * followed by any in CURL_CW_PROTOCOL, etc. + * + * When adding a writer, it is inserted as first in its phase. This means + * the order of adding writers of the same phase matters, but writers for + * different phases may be added in any order. + * + * Writers which do modify the BODY data written are expected to be of + * phases TRANSFER_DECODE or CONTENT_DECODE. The other phases are intended + * for monitoring writers. Which do *not* modify the data but gather + * statistics or update progress reporting. + */ + +/* Phase a writer operates at. */ +typedef enum { + CURL_CW_RAW, /* raw data written, before any decoding */ + CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */ + CURL_CW_PROTOCOL, /* after transfer, but before content decoding */ + CURL_CW_CONTENT_DECODE, /* remove content-encodings */ + CURL_CW_CLIENT /* data written to client */ +} Curl_cwriter_phase; + +/* Client Writer Type, provides the implementation */ +struct Curl_cwtype { + const char *name; /* writer name. */ + const char *alias; /* writer name alias, maybe NULL. */ + CURLcode (*do_init)(struct Curl_easy *data, + struct Curl_cwriter *writer); + CURLcode (*do_write)(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes); + void (*do_close)(struct Curl_easy *data, + struct Curl_cwriter *writer); + size_t cwriter_size; /* sizeof() allocated struct Curl_cwriter */ +}; + +/* Client writer instance */ +struct Curl_cwriter { + const struct Curl_cwtype *cwt; /* type implementation */ + struct Curl_cwriter *next; /* Downstream writer. */ + Curl_cwriter_phase phase; /* phase at which it operates */ +}; + +/** + * Create a new cwriter instance with given type and phase. Is not + * inserted into the writer chain by this call. + * Invokes `writer->do_init()`. + */ +CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter, + struct Curl_easy *data, + const struct Curl_cwtype *ce_handler, + Curl_cwriter_phase phase); + +/** + * Free a cwriter instance. + * Invokes `writer->do_close()`. + */ +void Curl_cwriter_free(struct Curl_easy *data, + struct Curl_cwriter *writer); + +/** + * Count the number of writers installed of the given phase. + */ +size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase); + +/** + * Adds a writer to the transfer's writer chain. + * The writers `phase` determines where in the chain it is inserted. + */ +CURLcode Curl_cwriter_add(struct Curl_easy *data, + struct Curl_cwriter *writer); + +void Curl_cwriter_remove_by_name(struct Curl_easy *data, + const char *name); + +/** + * Convenience method for calling `writer->do_write()` that + * checks for NULL writer. + */ +CURLcode Curl_cwriter_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes); + +/** + * Default implementations for do_init, do_write, do_close that + * do nothing and pass the data through. + */ +CURLcode Curl_cwriter_def_init(struct Curl_easy *data, + struct Curl_cwriter *writer); +CURLcode Curl_cwriter_def_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes); +void Curl_cwriter_def_close(struct Curl_easy *data, + struct Curl_cwriter *writer); + + +/* internal read-function, does plain socket, SSL and krb4 */ +CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd, + char *buf, size_t buffersize, + ssize_t *n); + +/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */ +CURLcode Curl_write(struct Curl_easy *data, + curl_socket_t sockfd, + const void *mem, size_t len, + ssize_t *written); + +/* internal write-function, using sockindex for connection destination */ +CURLcode Curl_nwrite(struct Curl_easy *data, + int sockindex, + const void *buf, + size_t blen, + ssize_t *pnwritten); + +#endif /* HEADER_CURL_SENDF_H */ diff --git a/lib/setopt.c b/lib/setopt.c new file mode 100644 index 0000000..a527077 --- /dev/null +++ b/lib/setopt.c @@ -0,0 +1,3179 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_LINUX_TCP_H +#include +#elif defined(HAVE_NETINET_TCP_H) +#include +#endif + +#include "urldata.h" +#include "url.h" +#include "progress.h" +#include "content_encoding.h" +#include "strcase.h" +#include "share.h" +#include "vtls/vtls.h" +#include "warnless.h" +#include "sendf.h" +#include "http2.h" +#include "setopt.h" +#include "multiif.h" +#include "altsvc.h" +#include "hsts.h" +#include "tftp.h" +#include "strdup.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +CURLcode Curl_setstropt(char **charp, const char *s) +{ + /* Release the previous storage at `charp' and replace by a dynamic storage + copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ + + Curl_safefree(*charp); + + if(s) { + if(strlen(s) > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + + *charp = strdup(s); + if(!*charp) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +CURLcode Curl_setblobopt(struct curl_blob **blobp, + const struct curl_blob *blob) +{ + /* free the previous storage at `blobp' and replace by a dynamic storage + copy of blob. If CURL_BLOB_COPY is set, the data is copied. */ + + Curl_safefree(*blobp); + + if(blob) { + struct curl_blob *nblob; + if(blob->len > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + nblob = (struct curl_blob *) + malloc(sizeof(struct curl_blob) + + ((blob->flags & CURL_BLOB_COPY) ? blob->len : 0)); + if(!nblob) + return CURLE_OUT_OF_MEMORY; + *nblob = *blob; + if(blob->flags & CURL_BLOB_COPY) { + /* put the data after the blob struct in memory */ + nblob->data = (char *)nblob + sizeof(struct curl_blob); + memcpy(nblob->data, blob->data, blob->len); + } + + *blobp = nblob; + return CURLE_OK; + } + + return CURLE_OK; +} + +static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) +{ + CURLcode result = CURLE_OK; + char *user = NULL; + char *passwd = NULL; + + /* Parse the login details if specified. It not then we treat NULL as a hint + to clear the existing data */ + if(option) { + size_t len = strlen(option); + if(len > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + + result = Curl_parse_login_details(option, len, + (userp ? &user : NULL), + (passwdp ? &passwd : NULL), + NULL); + } + + if(!result) { + /* Store the username part of option if required */ + if(userp) { + if(!user && option && option[0] == ':') { + /* Allocate an empty string instead of returning NULL as user name */ + user = strdup(""); + if(!user) + result = CURLE_OUT_OF_MEMORY; + } + + Curl_safefree(*userp); + *userp = user; + } + + /* Store the password part of option if required */ + if(passwdp) { + Curl_safefree(*passwdp); + *passwdp = passwd; + } + } + + return result; +} + +#define C_SSLVERSION_VALUE(x) (x & 0xffff) +#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000) + +static CURLcode protocol2num(const char *str, curl_prot_t *val) +{ + if(!str) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(curl_strequal(str, "all")) { + *val = ~(curl_prot_t) 0; + return CURLE_OK; + } + + *val = 0; + + do { + const char *token = str; + size_t tlen; + + str = strchr(str, ','); + tlen = str? (size_t) (str - token): strlen(token); + if(tlen) { + const struct Curl_handler *h = Curl_getn_scheme_handler(token, tlen); + + if(!h) + return CURLE_UNSUPPORTED_PROTOCOL; + + *val |= h->protocol; + } + } while(str && str++); + + if(!*val) + /* no protocol listed */ + return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_OK; +} + +/* + * Do not make Curl_vsetopt() static: it is called from + * packages/OS400/ccsidcurl.c. + */ +CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +{ + char *argptr; + CURLcode result = CURLE_OK; + long arg; + unsigned long uarg; + curl_off_t bigsize; + + switch(option) { + case CURLOPT_DNS_CACHE_TIMEOUT: + arg = va_arg(param, long); + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(arg > INT_MAX) + arg = INT_MAX; + + data->set.dns_cache_timeout = (int)arg; + break; + case CURLOPT_CA_CACHE_TIMEOUT: + arg = va_arg(param, long); + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(arg > INT_MAX) + arg = INT_MAX; + + data->set.general_ssl.ca_cache_timeout = (int)arg; + break; + case CURLOPT_DNS_USE_GLOBAL_CACHE: + /* deprecated */ + break; + case CURLOPT_SSL_CIPHER_LIST: + /* set a list of cipher we want to use in the SSL connection */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSL_CIPHER_LIST: + /* set a list of cipher we want to use in the SSL connection for proxy */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], + va_arg(param, char *)); + break; +#endif + case CURLOPT_TLS13_CIPHERS: + if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) { + /* set preferred list of TLS 1.3 cipher suites */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST], + va_arg(param, char *)); + } + else + return CURLE_NOT_BUILT_IN; + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_TLS13_CIPHERS: + if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) { + /* set preferred list of TLS 1.3 cipher suites for proxy */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY], + va_arg(param, char *)); + } + else + return CURLE_NOT_BUILT_IN; + break; +#endif + case CURLOPT_RANDOM_FILE: + break; + case CURLOPT_EGDSOCKET: + break; + case CURLOPT_MAXCONNECTS: + /* + * Set the absolute number of maximum simultaneous alive connection that + * libcurl is allowed to have. + */ + uarg = va_arg(param, unsigned long); + if(uarg > UINT_MAX) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.maxconnects = (unsigned int)uarg; + break; + case CURLOPT_FORBID_REUSE: + /* + * When this transfer is done, it must not be left to be reused by a + * subsequent transfer but shall be closed immediately. + */ + data->set.reuse_forbid = (0 != va_arg(param, long)); + break; + case CURLOPT_FRESH_CONNECT: + /* + * This transfer shall not use a previously cached connection but + * should be made with a fresh new connect! + */ + data->set.reuse_fresh = (0 != va_arg(param, long)); + break; + case CURLOPT_VERBOSE: + /* + * Verbose means infof() calls that give a lot of information about + * the connection and transfer procedures as well as internal choices. + */ + data->set.verbose = (0 != va_arg(param, long)); + break; + case CURLOPT_HEADER: + /* + * Set to include the header in the general data output stream. + */ + data->set.include_header = (0 != va_arg(param, long)); + break; + case CURLOPT_NOPROGRESS: + /* + * Shut off the internal supported progress meter + */ + data->set.hide_progress = (0 != va_arg(param, long)); + if(data->set.hide_progress) + data->progress.flags |= PGRS_HIDE; + else + data->progress.flags &= ~PGRS_HIDE; + break; + case CURLOPT_NOBODY: + /* + * Do not include the body part in the output data stream. + */ + data->set.opt_no_body = (0 != va_arg(param, long)); +#ifndef CURL_DISABLE_HTTP + if(data->set.opt_no_body) + /* in HTTP lingo, no body means using the HEAD request... */ + data->set.method = HTTPREQ_HEAD; + else if(data->set.method == HTTPREQ_HEAD) + data->set.method = HTTPREQ_GET; +#endif + break; + case CURLOPT_FAILONERROR: + /* + * Don't output the >=400 error code HTML-page, but instead only + * return error. + */ + data->set.http_fail_on_error = (0 != va_arg(param, long)); + break; + case CURLOPT_KEEP_SENDING_ON_ERROR: + data->set.http_keep_sending_on_error = (0 != va_arg(param, long)); + break; + case CURLOPT_UPLOAD: + case CURLOPT_PUT: + /* + * We want to sent data to the remote host. If this is HTTP, that equals + * using the PUT request. + */ + arg = va_arg(param, long); + if(arg) { + /* If this is HTTP, PUT is what's needed to "upload" */ + data->set.method = HTTPREQ_PUT; + data->set.opt_no_body = FALSE; /* this is implied */ + } + else + /* In HTTP, the opposite of upload is GET (unless NOBODY is true as + then this can be changed to HEAD later on) */ + data->set.method = HTTPREQ_GET; + break; + case CURLOPT_REQUEST_TARGET: + result = Curl_setstropt(&data->set.str[STRING_TARGET], + va_arg(param, char *)); + break; + case CURLOPT_FILETIME: + /* + * Try to get the file time of the remote document. The time will + * later (possibly) become available using curl_easy_getinfo(). + */ + data->set.get_filetime = (0 != va_arg(param, long)); + break; + case CURLOPT_SERVER_RESPONSE_TIMEOUT: + /* + * Option that specifies how quickly a server response must be obtained + * before it is considered failure. For pingpong protocols. + */ + arg = va_arg(param, long); + if((arg >= 0) && (arg <= (INT_MAX/1000))) + data->set.server_response_timeout = (unsigned int)arg * 1000; + else + return CURLE_BAD_FUNCTION_ARGUMENT; + break; + case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: + /* + * Option that specifies how quickly a server response must be obtained + * before it is considered failure. For pingpong protocols. + */ + arg = va_arg(param, long); + if((arg >= 0) && (arg <= INT_MAX)) + data->set.server_response_timeout = (unsigned int)arg; + else + return CURLE_BAD_FUNCTION_ARGUMENT; + break; +#ifndef CURL_DISABLE_TFTP + case CURLOPT_TFTP_NO_OPTIONS: + /* + * Option that prevents libcurl from sending TFTP option requests to the + * server. + */ + data->set.tftp_no_options = va_arg(param, long) != 0; + break; + case CURLOPT_TFTP_BLKSIZE: + /* + * TFTP option that specifies the block size to use for data transmission. + */ + arg = va_arg(param, long); + if(arg > TFTP_BLKSIZE_MAX || arg < TFTP_BLKSIZE_MIN) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.tftp_blksize = arg; + break; +#endif +#ifndef CURL_DISABLE_NETRC + case CURLOPT_NETRC: + /* + * Parse the $HOME/.netrc file + */ + arg = va_arg(param, long); + if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.use_netrc = (unsigned char)arg; + break; + case CURLOPT_NETRC_FILE: + /* + * Use this file instead of the $HOME/.netrc file + */ + result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE], + va_arg(param, char *)); + break; +#endif + case CURLOPT_TRANSFERTEXT: + /* + * This option was previously named 'FTPASCII'. Renamed to work with + * more protocols than merely FTP. + * + * Transfer using ASCII (instead of BINARY). + */ + data->set.prefer_ascii = (0 != va_arg(param, long)); + break; + case CURLOPT_TIMECONDITION: + /* + * Set HTTP time condition. This must be one of the defines in the + * curl/curl.h header file. + */ + arg = va_arg(param, long); + if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.timecondition = (unsigned char)(curl_TimeCond)arg; + break; + case CURLOPT_TIMEVALUE: + /* + * This is the value to compare with the remote document with the + * method set with CURLOPT_TIMECONDITION + */ + data->set.timevalue = (time_t)va_arg(param, long); + break; + + case CURLOPT_TIMEVALUE_LARGE: + /* + * This is the value to compare with the remote document with the + * method set with CURLOPT_TIMECONDITION + */ + data->set.timevalue = (time_t)va_arg(param, curl_off_t); + break; + + case CURLOPT_SSLVERSION: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLVERSION: +#endif + /* + * Set explicit SSL version to try to connect with, as some SSL + * implementations are lame. + */ +#ifdef USE_SSL + { + long version, version_max; + struct ssl_primary_config *primary = &data->set.ssl.primary; +#ifndef CURL_DISABLE_PROXY + if(option != CURLOPT_SSLVERSION) + primary = &data->set.proxy_ssl.primary; +#endif + + arg = va_arg(param, long); + + version = C_SSLVERSION_VALUE(arg); + version_max = C_SSLVERSION_MAX_VALUE(arg); + + if(version < CURL_SSLVERSION_DEFAULT || + version == CURL_SSLVERSION_SSLv2 || + version == CURL_SSLVERSION_SSLv3 || + version >= CURL_SSLVERSION_LAST || + version_max < CURL_SSLVERSION_MAX_NONE || + version_max >= CURL_SSLVERSION_MAX_LAST) + return CURLE_BAD_FUNCTION_ARGUMENT; + + primary->version = (unsigned char)version; + primary->version_max = (unsigned int)version_max; + } +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; + + /* MQTT "borrows" some of the HTTP options */ +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT) + case CURLOPT_COPYPOSTFIELDS: + /* + * A string with POST data. Makes curl HTTP POST. Even if it is NULL. + * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to + * CURLOPT_COPYPOSTFIELDS and not altered later. + */ + argptr = va_arg(param, char *); + + if(!argptr || data->set.postfieldsize == -1) + result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr); + else { + /* + * Check that requested length does not overflow the size_t type. + */ + + if((data->set.postfieldsize < 0) || + ((sizeof(curl_off_t) != sizeof(size_t)) && + (data->set.postfieldsize > (curl_off_t)((size_t)-1)))) + result = CURLE_OUT_OF_MEMORY; + else { + /* Allocate even when size == 0. This satisfies the need of possible + later address compare to detect the COPYPOSTFIELDS mode, and to + mark that postfields is used rather than read function or form + data. + */ + char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize); + (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); + if(!p) + result = CURLE_OUT_OF_MEMORY; + else + data->set.str[STRING_COPYPOSTFIELDS] = p; + } + } + + data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS]; + data->set.method = HTTPREQ_POST; + break; + + case CURLOPT_POSTFIELDS: + /* + * Like above, but use static data instead of copying it. + */ + data->set.postfields = va_arg(param, void *); + /* Release old copied data. */ + (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); + data->set.method = HTTPREQ_POST; + break; + + case CURLOPT_POSTFIELDSIZE: + /* + * The size of the POSTFIELD data to prevent libcurl to do strlen() to + * figure it out. Enables binary posts. + */ + bigsize = va_arg(param, long); + if(bigsize < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(data->set.postfieldsize < bigsize && + data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { + /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ + (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); + data->set.postfields = NULL; + } + + data->set.postfieldsize = bigsize; + break; + + case CURLOPT_POSTFIELDSIZE_LARGE: + /* + * The size of the POSTFIELD data to prevent libcurl to do strlen() to + * figure it out. Enables binary posts. + */ + bigsize = va_arg(param, curl_off_t); + if(bigsize < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(data->set.postfieldsize < bigsize && + data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { + /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ + (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); + data->set.postfields = NULL; + } + + data->set.postfieldsize = bigsize; + break; +#endif +#ifndef CURL_DISABLE_HTTP + case CURLOPT_AUTOREFERER: + /* + * Switch on automatic referer that gets set if curl follows locations. + */ + data->set.http_auto_referer = (0 != va_arg(param, long)); + break; + + case CURLOPT_ACCEPT_ENCODING: + /* + * String to use at the value of Accept-Encoding header. + * + * If the encoding is set to "" we use an Accept-Encoding header that + * encompasses all the encodings we support. + * If the encoding is set to NULL we don't send an Accept-Encoding header + * and ignore an received Content-Encoding header. + * + */ + argptr = va_arg(param, char *); + if(argptr && !*argptr) { + char all[256]; + Curl_all_content_encodings(all, sizeof(all)); + result = Curl_setstropt(&data->set.str[STRING_ENCODING], all); + } + else + result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr); + break; + + case CURLOPT_TRANSFER_ENCODING: + data->set.http_transfer_encoding = (0 != va_arg(param, long)); + break; + + case CURLOPT_FOLLOWLOCATION: + /* + * Follow Location: header hints on an HTTP-server. + */ + data->set.http_follow_location = (0 != va_arg(param, long)); + break; + + case CURLOPT_UNRESTRICTED_AUTH: + /* + * Send authentication (user+password) when following locations, even when + * hostname changed. + */ + data->set.allow_auth_to_other_hosts = (0 != va_arg(param, long)); + break; + + case CURLOPT_MAXREDIRS: + /* + * The maximum amount of hops you allow curl to follow Location: + * headers. This should mostly be used to detect never-ending loops. + */ + arg = va_arg(param, long); + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.maxredirs = arg; + break; + + case CURLOPT_POSTREDIR: + /* + * Set the behavior of POST when redirecting + * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302 + * CURL_REDIR_POST_301 - POST is kept as POST after 301 + * CURL_REDIR_POST_302 - POST is kept as POST after 302 + * CURL_REDIR_POST_303 - POST is kept as POST after 303 + * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303 + * other - POST is kept as POST after 301 and 302 + */ + arg = va_arg(param, long); + if(arg < CURL_REDIR_GET_ALL) + /* no return error on too high numbers since the bitmask could be + extended in a future */ + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.keep_post = arg & CURL_REDIR_POST_ALL; + break; + + case CURLOPT_POST: + /* Does this option serve a purpose anymore? Yes it does, when + CURLOPT_POSTFIELDS isn't used and the POST data is read off the + callback! */ + if(va_arg(param, long)) { + data->set.method = HTTPREQ_POST; + data->set.opt_no_body = FALSE; /* this is implied */ + } + else + data->set.method = HTTPREQ_GET; + break; + +#ifndef CURL_DISABLE_FORM_API + case CURLOPT_HTTPPOST: + /* + * Set to make us do HTTP POST. Legacy API-style. + */ + data->set.httppost = va_arg(param, struct curl_httppost *); + data->set.method = HTTPREQ_POST_FORM; + data->set.opt_no_body = FALSE; /* this is implied */ + Curl_mime_cleanpart(data->state.formp); + Curl_safefree(data->state.formp); + data->state.mimepost = NULL; + break; +#endif + +#if !defined(CURL_DISABLE_AWS) + case CURLOPT_AWS_SIGV4: + /* + * String that is merged to some authentication + * parameters are used by the algorithm. + */ + result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4], + va_arg(param, char *)); + /* + * Basic been set by default it need to be unset here + */ + if(data->set.str[STRING_AWS_SIGV4]) + data->set.httpauth = CURLAUTH_AWS_SIGV4; + break; +#endif + + case CURLOPT_REFERER: + /* + * String to set in the HTTP Referer: field. + */ + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + result = Curl_setstropt(&data->set.str[STRING_SET_REFERER], + va_arg(param, char *)); + data->state.referer = data->set.str[STRING_SET_REFERER]; + break; + + case CURLOPT_USERAGENT: + /* + * String to use in the HTTP User-Agent field + */ + result = Curl_setstropt(&data->set.str[STRING_USERAGENT], + va_arg(param, char *)); + break; + +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXYHEADER: + /* + * Set a list with proxy headers to use (or replace internals with) + * + * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a + * long time we remain doing it this way until CURLOPT_PROXYHEADER is + * used. As soon as this option has been used, if set to anything but + * NULL, custom headers for proxies are only picked from this list. + * + * Set this option to NULL to restore the previous behavior. + */ + data->set.proxyheaders = va_arg(param, struct curl_slist *); + break; +#endif + case CURLOPT_HEADEROPT: + /* + * Set header option. + */ + arg = va_arg(param, long); + data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE); + break; + +#if !defined(CURL_DISABLE_COOKIES) + case CURLOPT_COOKIE: + /* + * Cookie string to send to the remote server in the request. + */ + result = Curl_setstropt(&data->set.str[STRING_COOKIE], + va_arg(param, char *)); + break; + + case CURLOPT_COOKIEFILE: + /* + * Set cookie file to read and parse. Can be used multiple times. + */ + argptr = (char *)va_arg(param, void *); + if(argptr) { + struct curl_slist *cl; + /* general protection against mistakes and abuse */ + if(strlen(argptr) > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + /* append the cookie file name to the list of file names, and deal with + them later */ + cl = curl_slist_append(data->state.cookielist, argptr); + if(!cl) { + curl_slist_free_all(data->state.cookielist); + data->state.cookielist = NULL; + return CURLE_OUT_OF_MEMORY; + } + data->state.cookielist = cl; /* store the list for later use */ + } + else { + /* clear the list of cookie files */ + curl_slist_free_all(data->state.cookielist); + data->state.cookielist = NULL; + + if(!data->share || !data->share->cookies) { + /* throw away all existing cookies if this isn't a shared cookie + container */ + Curl_cookie_clearall(data->cookies); + Curl_cookie_cleanup(data->cookies); + } + /* disable the cookie engine */ + data->cookies = NULL; + } + break; + + case CURLOPT_COOKIEJAR: + /* + * Set cookie file name to dump all cookies to when we're done. + */ + { + struct CookieInfo *newcookies; + result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR], + va_arg(param, char *)); + + /* + * Activate the cookie parser. This may or may not already + * have been made. + */ + newcookies = Curl_cookie_init(data, NULL, data->cookies, + data->set.cookiesession); + if(!newcookies) + result = CURLE_OUT_OF_MEMORY; + data->cookies = newcookies; + } + break; + + case CURLOPT_COOKIESESSION: + /* + * Set this option to TRUE to start a new "cookie session". It will + * prevent the forthcoming read-cookies-from-file actions to accept + * cookies that are marked as being session cookies, as they belong to a + * previous session. + */ + data->set.cookiesession = (0 != va_arg(param, long)); + break; + + case CURLOPT_COOKIELIST: + argptr = va_arg(param, char *); + + if(!argptr) + break; + + if(strcasecompare(argptr, "ALL")) { + /* clear all cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_clearall(data->cookies); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + else if(strcasecompare(argptr, "SESS")) { + /* clear session cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_clearsess(data->cookies); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + else if(strcasecompare(argptr, "FLUSH")) { + /* flush cookies to file, takes care of the locking */ + Curl_flush_cookies(data, FALSE); + } + else if(strcasecompare(argptr, "RELOAD")) { + /* reload cookies from file */ + Curl_cookie_loadfiles(data); + break; + } + else { + if(!data->cookies) + /* if cookie engine was not running, activate it */ + data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); + + /* general protection against mistakes and abuse */ + if(strlen(argptr) > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + argptr = strdup(argptr); + if(!argptr || !data->cookies) { + result = CURLE_OUT_OF_MEMORY; + free(argptr); + } + else { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + + if(checkprefix("Set-Cookie:", argptr)) + /* HTTP Header format line */ + Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL, + NULL, TRUE); + + else + /* Netscape format line */ + Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL, + NULL, TRUE); + + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + free(argptr); + } + } + + break; +#endif /* !CURL_DISABLE_COOKIES */ + + case CURLOPT_HTTPGET: + /* + * Set to force us do HTTP GET + */ + if(va_arg(param, long)) { + data->set.method = HTTPREQ_GET; + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; + + case CURLOPT_HTTP_VERSION: + /* + * This sets a requested HTTP version to be used. The value is one of + * the listed enums in curl/curl.h. + */ + arg = va_arg(param, long); + switch(arg) { + case CURL_HTTP_VERSION_NONE: +#ifdef USE_HTTP2 + /* TODO: this seems an undesirable quirk to force a behaviour on + * lower implementations that they should recognize independently? */ + arg = CURL_HTTP_VERSION_2TLS; +#endif + /* accepted */ + break; + case CURL_HTTP_VERSION_1_0: + case CURL_HTTP_VERSION_1_1: + /* accepted */ + break; +#ifdef USE_HTTP2 + case CURL_HTTP_VERSION_2_0: + case CURL_HTTP_VERSION_2TLS: + case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE: + /* accepted */ + break; +#endif +#ifdef ENABLE_QUIC + case CURL_HTTP_VERSION_3: + case CURL_HTTP_VERSION_3ONLY: + /* accepted */ + break; +#endif + default: + /* not accepted */ + if(arg < CURL_HTTP_VERSION_NONE) + return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_UNSUPPORTED_PROTOCOL; + } + data->set.httpwant = (unsigned char)arg; + break; + + case CURLOPT_EXPECT_100_TIMEOUT_MS: + /* + * Time to wait for a response to an HTTP request containing an + * Expect: 100-continue header before sending the data anyway. + */ + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.expect_100_timeout = arg; + break; + + case CURLOPT_HTTP09_ALLOWED: + arg = va_arg(param, unsigned long); + if(arg > 1L) + return CURLE_BAD_FUNCTION_ARGUMENT; +#ifdef USE_HYPER + /* Hyper does not support HTTP/0.9 */ + if(arg) + return CURLE_BAD_FUNCTION_ARGUMENT; +#else + data->set.http09_allowed = !!arg; +#endif + break; + + case CURLOPT_HTTP200ALIASES: + /* + * Set a list of aliases for HTTP 200 in response header + */ + data->set.http200aliases = va_arg(param, struct curl_slist *); + break; +#endif /* CURL_DISABLE_HTTP */ + +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) +# if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME) + case CURLOPT_HTTPHEADER: + /* + * Set a list with HTTP headers to use (or replace internals with) + */ + data->set.headers = va_arg(param, struct curl_slist *); + break; +# endif + +# ifndef CURL_DISABLE_MIME + case CURLOPT_MIMEPOST: + /* + * Set to make us do MIME POST + */ + result = Curl_mime_set_subparts(&data->set.mimepost, + va_arg(param, curl_mime *), FALSE); + if(!result) { + data->set.method = HTTPREQ_POST_MIME; + data->set.opt_no_body = FALSE; /* this is implied */ +#ifndef CURL_DISABLE_FORM_API + Curl_mime_cleanpart(data->state.formp); + Curl_safefree(data->state.formp); + data->state.mimepost = NULL; +#endif + } + break; + + case CURLOPT_MIME_OPTIONS: + arg = va_arg(param, long); + data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE); + break; +# endif +#endif + + case CURLOPT_HTTPAUTH: + /* + * Set HTTP Authentication type BITMASK. + */ + { + int bitcheck; + bool authbits; + unsigned long auth = va_arg(param, unsigned long); + + if(auth == CURLAUTH_NONE) { + data->set.httpauth = auth; + break; + } + + /* the DIGEST_IE bit is only used to set a special marker, for all the + rest we need to handle it as normal DIGEST */ + data->state.authhost.iestyle = !!(auth & CURLAUTH_DIGEST_IE); + + if(auth & CURLAUTH_DIGEST_IE) { + auth |= CURLAUTH_DIGEST; /* set standard digest bit */ + auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */ + } + + /* switch off bits we can't support */ +#ifndef USE_NTLM + auth &= ~CURLAUTH_NTLM; /* no NTLM support */ + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#elif !defined(NTLM_WB_ENABLED) + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#endif +#ifndef USE_SPNEGO + auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without + GSS-API or SSPI */ +#endif + + /* check if any auth bit lower than CURLAUTH_ONLY is still set */ + bitcheck = 0; + authbits = FALSE; + while(bitcheck < 31) { + if(auth & (1UL << bitcheck++)) { + authbits = TRUE; + break; + } + } + if(!authbits) + return CURLE_NOT_BUILT_IN; /* no supported types left! */ + + data->set.httpauth = auth; + } + break; + + case CURLOPT_CUSTOMREQUEST: + /* + * Set a custom string to use as request + */ + result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST], + va_arg(param, char *)); + + /* we don't set + data->set.method = HTTPREQ_CUSTOM; + here, we continue as if we were using the already set type + and this just changes the actual request keyword */ + break; + +#ifndef CURL_DISABLE_PROXY + case CURLOPT_HTTPPROXYTUNNEL: + /* + * Tunnel operations through the proxy instead of normal proxy use + */ + data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)); + break; + + case CURLOPT_PROXYPORT: + /* + * Explicitly set HTTP proxy port number. + */ + arg = va_arg(param, long); + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.proxyport = (unsigned short)arg; + break; + + case CURLOPT_PROXYAUTH: + /* + * Set HTTP Authentication type BITMASK. + */ + { + int bitcheck; + bool authbits; + unsigned long auth = va_arg(param, unsigned long); + + if(auth == CURLAUTH_NONE) { + data->set.proxyauth = auth; + break; + } + + /* the DIGEST_IE bit is only used to set a special marker, for all the + rest we need to handle it as normal DIGEST */ + data->state.authproxy.iestyle = !!(auth & CURLAUTH_DIGEST_IE); + + if(auth & CURLAUTH_DIGEST_IE) { + auth |= CURLAUTH_DIGEST; /* set standard digest bit */ + auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */ + } + /* switch off bits we can't support */ +#ifndef USE_NTLM + auth &= ~CURLAUTH_NTLM; /* no NTLM support */ + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#elif !defined(NTLM_WB_ENABLED) + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#endif +#ifndef USE_SPNEGO + auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without + GSS-API or SSPI */ +#endif + + /* check if any auth bit lower than CURLAUTH_ONLY is still set */ + bitcheck = 0; + authbits = FALSE; + while(bitcheck < 31) { + if(auth & (1UL << bitcheck++)) { + authbits = TRUE; + break; + } + } + if(!authbits) + return CURLE_NOT_BUILT_IN; /* no supported types left! */ + + data->set.proxyauth = auth; + } + break; + + case CURLOPT_PROXY: + /* + * Set proxy server:port to use as proxy. + * + * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL) + * we explicitly say that we don't want to use a proxy + * (even though there might be environment variables saying so). + * + * Setting it to NULL, means no proxy but allows the environment variables + * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). + */ + result = Curl_setstropt(&data->set.str[STRING_PROXY], + va_arg(param, char *)); + break; + + case CURLOPT_PRE_PROXY: + /* + * Set proxy server:port to use as SOCKS proxy. + * + * If the proxy is set to "" or NULL we explicitly say that we don't want + * to use the socks proxy. + */ + result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY], + va_arg(param, char *)); + break; + + case CURLOPT_PROXYTYPE: + /* + * Set proxy type. + */ + arg = va_arg(param, long); + if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.proxytype = (unsigned char)(curl_proxytype)arg; + break; + + case CURLOPT_PROXY_TRANSFER_MODE: + /* + * set transfer mode (;type=) when doing FTP via an HTTP proxy + */ + switch(va_arg(param, long)) { + case 0: + data->set.proxy_transfer_mode = FALSE; + break; + case 1: + data->set.proxy_transfer_mode = TRUE; + break; + default: + /* reserve other values for future use */ + result = CURLE_BAD_FUNCTION_ARGUMENT; + break; + } + break; + + case CURLOPT_SOCKS5_AUTH: + data->set.socks5auth = (unsigned char)va_arg(param, unsigned long); + if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + result = CURLE_NOT_BUILT_IN; + break; +#endif /* CURL_DISABLE_PROXY */ + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CURLOPT_SOCKS5_GSSAPI_NEC: + /* + * Set flag for NEC SOCK5 support + */ + data->set.socks5_gssapi_nec = (0 != va_arg(param, long)); + break; +#endif +#ifndef CURL_DISABLE_PROXY + case CURLOPT_SOCKS5_GSSAPI_SERVICE: + case CURLOPT_PROXY_SERVICE_NAME: + /* + * Set proxy authentication service name for Kerberos 5 and SPNEGO + */ + result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], + va_arg(param, char *)); + break; +#endif + case CURLOPT_SERVICE_NAME: + /* + * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO + */ + result = Curl_setstropt(&data->set.str[STRING_SERVICE_NAME], + va_arg(param, char *)); + break; + + case CURLOPT_HEADERDATA: + /* + * Custom pointer to pass the header write callback function + */ + data->set.writeheader = (void *)va_arg(param, void *); + break; + case CURLOPT_ERRORBUFFER: + /* + * Error buffer provided by the caller to get the human readable + * error string in. + */ + data->set.errorbuffer = va_arg(param, char *); + break; + case CURLOPT_WRITEDATA: + /* + * FILE pointer to write to. Or possibly + * used as argument to the write callback. + */ + data->set.out = va_arg(param, void *); + break; + +#ifdef CURL_LIST_ONLY_PROTOCOL + case CURLOPT_DIRLISTONLY: + /* + * An option that changes the command to one that asks for a list only, no + * file info details. Used for FTP, POP3 and SFTP. + */ + data->set.list_only = (0 != va_arg(param, long)); + break; +#endif + case CURLOPT_APPEND: + /* + * We want to upload and append to an existing file. Used for FTP and + * SFTP. + */ + data->set.remote_append = (0 != va_arg(param, long)); + break; + +#ifndef CURL_DISABLE_FTP + case CURLOPT_FTP_FILEMETHOD: + /* + * How do access files over FTP. + */ + arg = va_arg(param, long); + if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ftp_filemethod = (unsigned char)arg; + break; + case CURLOPT_FTPPORT: + /* + * Use FTP PORT, this also specifies which IP address to use + */ + result = Curl_setstropt(&data->set.str[STRING_FTPPORT], + va_arg(param, char *)); + data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]); + break; + + case CURLOPT_FTP_USE_EPRT: + data->set.ftp_use_eprt = (0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_USE_EPSV: + data->set.ftp_use_epsv = (0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_USE_PRET: + data->set.ftp_use_pret = (0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_SSL_CCC: + arg = va_arg(param, long); + if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ftp_ccc = (unsigned char)arg; + break; + + case CURLOPT_FTP_SKIP_PASV_IP: + /* + * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the + * bypass of the IP address in PASV responses. + */ + data->set.ftp_skip_ip = (0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_ACCOUNT: + result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT], + va_arg(param, char *)); + break; + + case CURLOPT_FTP_ALTERNATIVE_TO_USER: + result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], + va_arg(param, char *)); + break; + + case CURLOPT_FTPSSLAUTH: + /* + * Set a specific auth for FTP-SSL transfers. + */ + arg = va_arg(param, long); + if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg; + break; + case CURLOPT_KRBLEVEL: + /* + * A string that defines the kerberos security level. + */ + result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL], + va_arg(param, char *)); + data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]); + break; +#endif +#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) + case CURLOPT_FTP_CREATE_MISSING_DIRS: + /* + * An FTP/SFTP option that modifies an upload to create missing + * directories on the server. + */ + arg = va_arg(param, long); + /* reserve other values for future use */ + if((arg < CURLFTP_CREATE_DIR_NONE) || + (arg > CURLFTP_CREATE_DIR_RETRY)) + result = CURLE_BAD_FUNCTION_ARGUMENT; + else + data->set.ftp_create_missing_dirs = (unsigned char)arg; + break; + + case CURLOPT_POSTQUOTE: + /* + * List of RAW FTP commands to use after a transfer + */ + data->set.postquote = va_arg(param, struct curl_slist *); + break; + case CURLOPT_PREQUOTE: + /* + * List of RAW FTP commands to use prior to RETR (Wesley Laxton) + */ + data->set.prequote = va_arg(param, struct curl_slist *); + break; + case CURLOPT_QUOTE: + /* + * List of RAW FTP commands to use before a transfer + */ + data->set.quote = va_arg(param, struct curl_slist *); + break; +#endif + case CURLOPT_READDATA: + /* + * FILE pointer to read the file to be uploaded from. Or possibly + * used as argument to the read callback. + */ + data->set.in_set = va_arg(param, void *); + break; + case CURLOPT_INFILESIZE: + /* + * If known, this should inform curl about the file size of the + * to-be-uploaded file. + */ + arg = va_arg(param, long); + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.filesize = arg; + break; + case CURLOPT_INFILESIZE_LARGE: + /* + * If known, this should inform curl about the file size of the + * to-be-uploaded file. + */ + bigsize = va_arg(param, curl_off_t); + if(bigsize < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.filesize = bigsize; + break; + case CURLOPT_LOW_SPEED_LIMIT: + /* + * The low speed limit that if transfers are below this for + * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. + */ + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.low_speed_limit = arg; + break; + case CURLOPT_MAX_SEND_SPEED_LARGE: + /* + * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE + * bytes per second the transfer is throttled.. + */ + bigsize = va_arg(param, curl_off_t); + if(bigsize < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.max_send_speed = bigsize; + break; + case CURLOPT_MAX_RECV_SPEED_LARGE: + /* + * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per + * second the transfer is throttled.. + */ + bigsize = va_arg(param, curl_off_t); + if(bigsize < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.max_recv_speed = bigsize; + break; + case CURLOPT_LOW_SPEED_TIME: + /* + * The low speed time that if transfers are below the set + * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. + */ + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.low_speed_time = arg; + break; + case CURLOPT_CURLU: + /* + * pass CURLU to set URL + */ + data->set.uh = va_arg(param, CURLU *); + break; + case CURLOPT_URL: + /* + * The URL to fetch. + */ + if(data->state.url_alloc) { + /* the already set URL is allocated, free it first! */ + Curl_safefree(data->state.url); + data->state.url_alloc = FALSE; + } + result = Curl_setstropt(&data->set.str[STRING_SET_URL], + va_arg(param, char *)); + data->state.url = data->set.str[STRING_SET_URL]; + break; + case CURLOPT_PORT: + /* + * The port number to use when getting the URL. 0 disables it. + */ + arg = va_arg(param, long); + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.use_port = (unsigned short)arg; + break; + case CURLOPT_TIMEOUT: + /* + * The maximum time you allow curl to use for a single transfer + * operation. + */ + arg = va_arg(param, long); + if((arg >= 0) && (arg <= (INT_MAX/1000))) + data->set.timeout = (unsigned int)arg * 1000; + else + return CURLE_BAD_FUNCTION_ARGUMENT; + break; + + case CURLOPT_TIMEOUT_MS: + uarg = va_arg(param, unsigned long); + if(uarg > UINT_MAX) + uarg = UINT_MAX; + data->set.timeout = (unsigned int)uarg; + break; + + case CURLOPT_CONNECTTIMEOUT: + /* + * The maximum time you allow curl to use to connect. + */ + arg = va_arg(param, long); + if((arg >= 0) && (arg <= (INT_MAX/1000))) + data->set.connecttimeout = (unsigned int)arg * 1000; + else + return CURLE_BAD_FUNCTION_ARGUMENT; + break; + + case CURLOPT_CONNECTTIMEOUT_MS: + uarg = va_arg(param, unsigned long); + if(uarg > UINT_MAX) + uarg = UINT_MAX; + data->set.connecttimeout = (unsigned int)uarg; + break; + +#ifndef CURL_DISABLE_FTP + case CURLOPT_ACCEPTTIMEOUT_MS: + /* + * The maximum time for curl to wait for FTP server connect + */ + uarg = va_arg(param, unsigned long); + if(uarg > UINT_MAX) + uarg = UINT_MAX; + data->set.accepttimeout = (unsigned int)uarg; + break; +#endif + + case CURLOPT_USERPWD: + /* + * user:password to use in the operation + */ + result = setstropt_userpwd(va_arg(param, char *), + &data->set.str[STRING_USERNAME], + &data->set.str[STRING_PASSWORD]); + break; + + case CURLOPT_USERNAME: + /* + * authentication user name to use in the operation + */ + result = Curl_setstropt(&data->set.str[STRING_USERNAME], + va_arg(param, char *)); + break; + case CURLOPT_PASSWORD: + /* + * authentication password to use in the operation + */ + result = Curl_setstropt(&data->set.str[STRING_PASSWORD], + va_arg(param, char *)); + break; + + case CURLOPT_LOGIN_OPTIONS: + /* + * authentication options to use in the operation + */ + result = Curl_setstropt(&data->set.str[STRING_OPTIONS], + va_arg(param, char *)); + break; + + case CURLOPT_XOAUTH2_BEARER: + /* + * OAuth 2.0 bearer token to use in the operation + */ + result = Curl_setstropt(&data->set.str[STRING_BEARER], + va_arg(param, char *)); + break; + + case CURLOPT_RESOLVE: + /* + * List of HOST:PORT:[addresses] strings to populate the DNS cache with + * Entries added this way will remain in the cache until explicitly + * removed or the handle is cleaned up. + * + * Prefix the HOST with plus sign (+) to have the entry expire just like + * automatically added entries. + * + * Prefix the HOST with dash (-) to _remove_ the entry from the cache. + * + * This API can remove any entry from the DNS cache, but only entries + * that aren't actually in use right now will be pruned immediately. + */ + data->set.resolve = va_arg(param, struct curl_slist *); + data->state.resolve = data->set.resolve; + break; + case CURLOPT_PROGRESSFUNCTION: + /* + * Progress callback function + */ + data->set.fprogress = va_arg(param, curl_progress_callback); + if(data->set.fprogress) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ + break; + + case CURLOPT_XFERINFOFUNCTION: + /* + * Transfer info callback function + */ + data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); + if(data->set.fxferinfo) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ + + break; + + case CURLOPT_PROGRESSDATA: + /* + * Custom client data to pass to the progress callback + */ + data->set.progress_client = va_arg(param, void *); + break; + +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXYUSERPWD: + /* + * user:password needed to use the proxy + */ + result = setstropt_userpwd(va_arg(param, char *), + &data->set.str[STRING_PROXYUSERNAME], + &data->set.str[STRING_PROXYPASSWORD]); + break; + case CURLOPT_PROXYUSERNAME: + /* + * authentication user name to use in the operation + */ + result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME], + va_arg(param, char *)); + break; + case CURLOPT_PROXYPASSWORD: + /* + * authentication password to use in the operation + */ + result = Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD], + va_arg(param, char *)); + break; + case CURLOPT_NOPROXY: + /* + * proxy exception list + */ + result = Curl_setstropt(&data->set.str[STRING_NOPROXY], + va_arg(param, char *)); + break; +#endif + + case CURLOPT_RANGE: + /* + * What range of the file you want to transfer + */ + result = Curl_setstropt(&data->set.str[STRING_SET_RANGE], + va_arg(param, char *)); + break; + case CURLOPT_RESUME_FROM: + /* + * Resume transfer at the given file position + */ + arg = va_arg(param, long); + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.set_resume_from = arg; + break; + case CURLOPT_RESUME_FROM_LARGE: + /* + * Resume transfer at the given file position + */ + bigsize = va_arg(param, curl_off_t); + if(bigsize < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.set_resume_from = bigsize; + break; + case CURLOPT_DEBUGFUNCTION: + /* + * stderr write callback. + */ + data->set.fdebug = va_arg(param, curl_debug_callback); + /* + * if the callback provided is NULL, it'll use the default callback + */ + break; + case CURLOPT_DEBUGDATA: + /* + * Set to a void * that should receive all error writes. This + * defaults to CURLOPT_STDERR for normal operations. + */ + data->set.debugdata = va_arg(param, void *); + break; + case CURLOPT_STDERR: + /* + * Set to a FILE * that should receive all error writes. This + * defaults to stderr for normal operations. + */ + data->set.err = va_arg(param, FILE *); + if(!data->set.err) + data->set.err = stderr; + break; + case CURLOPT_HEADERFUNCTION: + /* + * Set header write callback + */ + data->set.fwrite_header = va_arg(param, curl_write_callback); + break; + case CURLOPT_WRITEFUNCTION: + /* + * Set data write callback + */ + data->set.fwrite_func = va_arg(param, curl_write_callback); + if(!data->set.fwrite_func) + /* When set to NULL, reset to our internal default function */ + data->set.fwrite_func = (curl_write_callback)fwrite; + break; + case CURLOPT_READFUNCTION: + /* + * Read data callback + */ + data->set.fread_func_set = va_arg(param, curl_read_callback); + if(!data->set.fread_func_set) { + data->set.is_fread_set = 0; + /* When set to NULL, reset to our internal default function */ + data->set.fread_func_set = (curl_read_callback)fread; + } + else + data->set.is_fread_set = 1; + break; + case CURLOPT_SEEKFUNCTION: + /* + * Seek callback. Might be NULL. + */ + data->set.seek_func = va_arg(param, curl_seek_callback); + break; + case CURLOPT_SEEKDATA: + /* + * Seek control callback. Might be NULL. + */ + data->set.seek_client = va_arg(param, void *); + break; + case CURLOPT_IOCTLFUNCTION: + /* + * I/O control callback. Might be NULL. + */ + data->set.ioctl_func = va_arg(param, curl_ioctl_callback); + break; + case CURLOPT_IOCTLDATA: + /* + * I/O control data pointer. Might be NULL. + */ + data->set.ioctl_client = va_arg(param, void *); + break; + case CURLOPT_SSLCERT: + /* + * String that holds file name of the SSL certificate to use + */ + result = Curl_setstropt(&data->set.str[STRING_CERT], + va_arg(param, char *)); + break; + case CURLOPT_SSLCERT_BLOB: + /* + * Blob that holds file content of the SSL certificate to use + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_CERT], + va_arg(param, struct curl_blob *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLCERT: + /* + * String that holds file name of the SSL certificate to use for proxy + */ + result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLCERT_BLOB: + /* + * Blob that holds file content of the SSL certificate to use for proxy + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY], + va_arg(param, struct curl_blob *)); + break; +#endif + case CURLOPT_SSLCERTTYPE: + /* + * String that holds file type of the SSL certificate to use + */ + result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLCERTTYPE: + /* + * String that holds file type of the SSL certificate to use for proxy + */ + result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], + va_arg(param, char *)); + break; +#endif + case CURLOPT_SSLKEY: + /* + * String that holds file name of the SSL key to use + */ + result = Curl_setstropt(&data->set.str[STRING_KEY], + va_arg(param, char *)); + break; + case CURLOPT_SSLKEY_BLOB: + /* + * Blob that holds file content of the SSL key to use + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_KEY], + va_arg(param, struct curl_blob *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLKEY: + /* + * String that holds file name of the SSL key to use for proxy + */ + result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLKEY_BLOB: + /* + * Blob that holds file content of the SSL key to use for proxy + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY], + va_arg(param, struct curl_blob *)); + break; +#endif + case CURLOPT_SSLKEYTYPE: + /* + * String that holds file type of the SSL key to use + */ + result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLKEYTYPE: + /* + * String that holds file type of the SSL key to use for proxy + */ + result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], + va_arg(param, char *)); + break; +#endif + case CURLOPT_KEYPASSWD: + /* + * String that holds the SSL or SSH private key password. + */ + result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_KEYPASSWD: + /* + * String that holds the SSL private key password for proxy. + */ + result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], + va_arg(param, char *)); + break; +#endif + case CURLOPT_SSLENGINE: + /* + * String that holds the SSL crypto engine. + */ + argptr = va_arg(param, char *); + if(argptr && argptr[0]) { + result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], argptr); + if(!result) { + result = Curl_ssl_set_engine(data, argptr); + } + } + break; + + case CURLOPT_SSLENGINE_DEFAULT: + /* + * flag to set engine as default. + */ + Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], NULL); + result = Curl_ssl_set_engine_default(data); + break; + case CURLOPT_CRLF: + /* + * Kludgy option to enable CRLF conversions. Subject for removal. + */ + data->set.crlf = (0 != va_arg(param, long)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_HAPROXYPROTOCOL: + /* + * Set to send the HAProxy Proxy Protocol header + */ + data->set.haproxyprotocol = (0 != va_arg(param, long)); + break; + case CURLOPT_HAPROXY_CLIENT_IP: + /* + * Set the client IP to send through HAProxy PROXY protocol + */ + result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP], + va_arg(param, char *)); + /* We enable implicitly the HAProxy protocol if we use this flag. */ + data->set.haproxyprotocol = TRUE; + break; +#endif + case CURLOPT_INTERFACE: + /* + * Set what interface or address/hostname to bind the socket to when + * performing an operation and thus what from-IP your connection will use. + */ + result = Curl_setstropt(&data->set.str[STRING_DEVICE], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_BINDLOCAL + case CURLOPT_LOCALPORT: + /* + * Set what local port to bind the socket to when performing an operation. + */ + arg = va_arg(param, long); + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.localport = curlx_sltous(arg); + break; + case CURLOPT_LOCALPORTRANGE: + /* + * Set number of local ports to try, starting with CURLOPT_LOCALPORT. + */ + arg = va_arg(param, long); + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.localportrange = curlx_sltous(arg); + break; +#endif + case CURLOPT_GSSAPI_DELEGATION: + /* + * GSS-API credential delegation bitmask + */ + uarg = va_arg(param, unsigned long); + data->set.gssapi_delegation = (unsigned char)uarg& + (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG); + break; + case CURLOPT_SSL_VERIFYPEER: + /* + * Enable peer SSL verifying. + */ + data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)); + + /* Update the current connection ssl_config. */ + Curl_ssl_conn_config_update(data, FALSE); + break; +#ifndef CURL_DISABLE_DOH + case CURLOPT_DOH_SSL_VERIFYPEER: + /* + * Enable peer SSL verifying for DoH. + */ + data->set.doh_verifypeer = (0 != va_arg(param, long)); + break; +#endif +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSL_VERIFYPEER: + /* + * Enable peer SSL verifying for proxy. + */ + data->set.proxy_ssl.primary.verifypeer = + (0 != va_arg(param, long))?TRUE:FALSE; + + /* Update the current connection proxy_ssl_config. */ + Curl_ssl_conn_config_update(data, TRUE); + break; +#endif + case CURLOPT_SSL_VERIFYHOST: + /* + * Enable verification of the host name in the peer certificate + */ + arg = va_arg(param, long); + + /* Obviously people are not reading documentation and too many thought + this argument took a boolean when it wasn't and misused it. + Treat 1 and 2 the same */ + data->set.ssl.primary.verifyhost = !!(arg & 3); + + /* Update the current connection ssl_config. */ + Curl_ssl_conn_config_update(data, FALSE); + break; +#ifndef CURL_DISABLE_DOH + case CURLOPT_DOH_SSL_VERIFYHOST: + /* + * Enable verification of the host name in the peer certificate for DoH + */ + arg = va_arg(param, long); + + /* Treat both 1 and 2 as TRUE */ + data->set.doh_verifyhost = !!(arg & 3); + break; +#endif +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSL_VERIFYHOST: + /* + * Enable verification of the host name in the peer certificate for proxy + */ + arg = va_arg(param, long); + + /* Treat both 1 and 2 as TRUE */ + data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE); + /* Update the current connection proxy_ssl_config. */ + Curl_ssl_conn_config_update(data, TRUE); + break; +#endif + case CURLOPT_SSL_VERIFYSTATUS: + /* + * Enable certificate status verifying. + */ + if(!Curl_ssl_cert_status_request()) { + result = CURLE_NOT_BUILT_IN; + break; + } + + data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)); + + /* Update the current connection ssl_config. */ + Curl_ssl_conn_config_update(data, FALSE); + break; +#ifndef CURL_DISABLE_DOH + case CURLOPT_DOH_SSL_VERIFYSTATUS: + /* + * Enable certificate status verifying for DoH. + */ + if(!Curl_ssl_cert_status_request()) { + result = CURLE_NOT_BUILT_IN; + break; + } + + data->set.doh_verifystatus = (0 != va_arg(param, long)); + break; +#endif + case CURLOPT_SSL_CTX_FUNCTION: + /* + * Set a SSL_CTX callback + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) + data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); + else +#endif + result = CURLE_NOT_BUILT_IN; + break; + case CURLOPT_SSL_CTX_DATA: + /* + * Set a SSL_CTX callback parameter pointer + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) + data->set.ssl.fsslctxp = va_arg(param, void *); + else +#endif + result = CURLE_NOT_BUILT_IN; + break; + case CURLOPT_SSL_FALSESTART: + /* + * Enable TLS false start. + */ + if(!Curl_ssl_false_start(data)) { + result = CURLE_NOT_BUILT_IN; + break; + } + + data->set.ssl.falsestart = (0 != va_arg(param, long)); + break; + case CURLOPT_CERTINFO: +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CERTINFO)) + data->set.ssl.certinfo = (0 != va_arg(param, long)); + else +#endif + result = CURLE_NOT_BUILT_IN; + break; + case CURLOPT_PINNEDPUBLICKEY: + /* + * Set pinned public key for SSL connection. + * Specify file name of the public key in DER format. + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) + result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], + va_arg(param, char *)); + else +#endif + result = CURLE_NOT_BUILT_IN; + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_PINNEDPUBLICKEY: + /* + * Set pinned public key for SSL connection. + * Specify file name of the public key in DER format. + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) + result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], + va_arg(param, char *)); + else +#endif + result = CURLE_NOT_BUILT_IN; + break; +#endif + case CURLOPT_CAINFO: + /* + * Set CA info for SSL connection. Specify file name of the CA certificate + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], + va_arg(param, char *)); + break; + case CURLOPT_CAINFO_BLOB: + /* + * Blob that holds CA info for SSL connection. + * Specify entire PEM of the CA certificate + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) { + result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO], + va_arg(param, struct curl_blob *)); + break; + } + else +#endif + return CURLE_NOT_BUILT_IN; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_CAINFO: + /* + * Set CA info SSL connection for proxy. Specify file name of the + * CA certificate + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_CAINFO_BLOB: + /* + * Blob that holds CA info for SSL connection proxy. + * Specify entire PEM of the CA certificate + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) { + result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY], + va_arg(param, struct curl_blob *)); + break; + } + else +#endif + return CURLE_NOT_BUILT_IN; +#endif + case CURLOPT_CAPATH: + /* + * Set CA path info for SSL connection. Specify directory name of the CA + * certificates which have been prepared using openssl c_rehash utility. + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) + /* This does not work on windows. */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH], + va_arg(param, char *)); + else +#endif + result = CURLE_NOT_BUILT_IN; + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_CAPATH: + /* + * Set CA path info for SSL connection proxy. Specify directory name of the + * CA certificates which have been prepared using openssl c_rehash utility. + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) + /* This does not work on windows. */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], + va_arg(param, char *)); + else +#endif + result = CURLE_NOT_BUILT_IN; + break; +#endif + case CURLOPT_CRLFILE: + /* + * Set CRL file info for SSL connection. Specify file name of the CRL + * to check certificates revocation + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_CRLFILE: + /* + * Set CRL file info for SSL connection for proxy. Specify file name of the + * CRL to check certificates revocation + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], + va_arg(param, char *)); + break; +#endif + case CURLOPT_ISSUERCERT: + /* + * Set Issuer certificate file + * to check certificates issuer + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT], + va_arg(param, char *)); + break; + case CURLOPT_ISSUERCERT_BLOB: + /* + * Blob that holds Issuer certificate to check certificates issuer + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT], + va_arg(param, struct curl_blob *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_ISSUERCERT: + /* + * Set Issuer certificate file + * to check certificates issuer + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_ISSUERCERT_BLOB: + /* + * Blob that holds Issuer certificate to check certificates issuer + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY], + va_arg(param, struct curl_blob *)); + break; +#endif +#ifndef CURL_DISABLE_TELNET + case CURLOPT_TELNETOPTIONS: + /* + * Set a linked list of telnet options + */ + data->set.telnet_options = va_arg(param, struct curl_slist *); + break; +#endif + case CURLOPT_BUFFERSIZE: + /* + * The application kindly asks for a differently sized receive buffer. + * If it seems reasonable, we'll use it. + */ + if(data->state.buffer) + return CURLE_BAD_FUNCTION_ARGUMENT; + + arg = va_arg(param, long); + + if(arg > READBUFFER_MAX) + arg = READBUFFER_MAX; + else if(arg < 1) + arg = READBUFFER_SIZE; + else if(arg < READBUFFER_MIN) + arg = READBUFFER_MIN; + + data->set.buffer_size = (unsigned int)arg; + break; + + case CURLOPT_UPLOAD_BUFFERSIZE: + /* + * The application kindly asks for a differently sized upload buffer. + * Cap it to sensible. + */ + arg = va_arg(param, long); + + if(arg > UPLOADBUFFER_MAX) + arg = UPLOADBUFFER_MAX; + else if(arg < UPLOADBUFFER_MIN) + arg = UPLOADBUFFER_MIN; + + data->set.upload_buffer_size = (unsigned int)arg; + Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */ + break; + + case CURLOPT_NOSIGNAL: + /* + * The application asks not to set any signal() or alarm() handlers, + * even when using a timeout. + */ + data->set.no_signal = (0 != va_arg(param, long)); + break; + + case CURLOPT_SHARE: + { + struct Curl_share *set; + set = va_arg(param, struct Curl_share *); + + /* disconnect from old share, if any */ + if(data->share) { + Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + + if(data->dns.hostcachetype == HCACHE_SHARED) { + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; + } + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(data->share->cookies == data->cookies) + data->cookies = NULL; +#endif + +#ifndef CURL_DISABLE_HSTS + if(data->share->hsts == data->hsts) + data->hsts = NULL; +#endif +#ifdef USE_SSL + if(data->share->sslsession == data->state.session) + data->state.session = NULL; +#endif +#ifdef USE_LIBPSL + if(data->psl == &data->share->psl) + data->psl = data->multi? &data->multi->psl: NULL; +#endif + + data->share->dirty--; + + Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); + data->share = NULL; + } + + if(GOOD_SHARE_HANDLE(set)) + /* use new share if it set */ + data->share = set; + if(data->share) { + + Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + + data->share->dirty++; + + if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) { + /* use shared host cache */ + data->dns.hostcache = &data->share->hostcache; + data->dns.hostcachetype = HCACHE_SHARED; + } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(data->share->cookies) { + /* use shared cookie list, first free own one if any */ + Curl_cookie_cleanup(data->cookies); + /* enable cookies since we now use a share that uses cookies! */ + data->cookies = data->share->cookies; + } +#endif /* CURL_DISABLE_HTTP */ +#ifndef CURL_DISABLE_HSTS + if(data->share->hsts) { + /* first free the private one if any */ + Curl_hsts_cleanup(&data->hsts); + data->hsts = data->share->hsts; + } +#endif /* CURL_DISABLE_HTTP */ +#ifdef USE_SSL + if(data->share->sslsession) { + data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; + data->state.session = data->share->sslsession; + } +#endif +#ifdef USE_LIBPSL + if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL)) + data->psl = &data->share->psl; +#endif + + Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); + } + /* check for host cache not needed, + * it will be done by curl_easy_perform */ + } + break; + + case CURLOPT_PRIVATE: + /* + * Set private data pointer. + */ + data->set.private_data = va_arg(param, void *); + break; + + case CURLOPT_MAXFILESIZE: + /* + * Set the maximum size of a file to download. + */ + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.max_filesize = arg; + break; + +#ifdef USE_SSL + case CURLOPT_USE_SSL: + /* + * Make transfers attempt to use SSL/TLS. + */ + arg = va_arg(param, long); + if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.use_ssl = (unsigned char)arg; + break; + + case CURLOPT_SSL_OPTIONS: + arg = va_arg(param, long); + data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); + data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); + data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); + data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT); + /* If a setting is added here it should also be added in dohprobe() + which sets its own CURLOPT_SSL_OPTIONS based on these settings. */ + break; + +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSL_OPTIONS: + arg = va_arg(param, long); + data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); + data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.proxy_ssl.revoke_best_effort = + !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); + data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); + data->set.proxy_ssl.auto_client_cert = + !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT); + break; +#endif + + case CURLOPT_SSL_EC_CURVES: + /* + * Set accepted curves in SSL connection setup. + * Specify colon-delimited list of curve algorithm names. + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], + va_arg(param, char *)); + break; +#endif + case CURLOPT_IPRESOLVE: + arg = va_arg(param, long); + if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ipver = (unsigned char) arg; + break; + + case CURLOPT_MAXFILESIZE_LARGE: + /* + * Set the maximum size of a file to download. + */ + bigsize = va_arg(param, curl_off_t); + if(bigsize < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.max_filesize = bigsize; + break; + + case CURLOPT_TCP_NODELAY: + /* + * Enable or disable TCP_NODELAY, which will disable/enable the Nagle + * algorithm + */ + data->set.tcp_nodelay = (0 != va_arg(param, long)); + break; + + case CURLOPT_IGNORE_CONTENT_LENGTH: + data->set.ignorecl = (0 != va_arg(param, long)); + break; + + case CURLOPT_CONNECT_ONLY: + /* + * No data transfer. + * (1) - only do connection + * (2) - do first get request but get no content + */ + arg = va_arg(param, long); + if(arg > 2) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.connect_only = (unsigned char)arg; + break; + + case CURLOPT_SOCKOPTFUNCTION: + /* + * socket callback function: called after socket() but before connect() + */ + data->set.fsockopt = va_arg(param, curl_sockopt_callback); + break; + + case CURLOPT_SOCKOPTDATA: + /* + * socket callback data pointer. Might be NULL. + */ + data->set.sockopt_client = va_arg(param, void *); + break; + + case CURLOPT_OPENSOCKETFUNCTION: + /* + * open/create socket callback function: called instead of socket(), + * before connect() + */ + data->set.fopensocket = va_arg(param, curl_opensocket_callback); + break; + + case CURLOPT_OPENSOCKETDATA: + /* + * socket callback data pointer. Might be NULL. + */ + data->set.opensocket_client = va_arg(param, void *); + break; + + case CURLOPT_CLOSESOCKETFUNCTION: + /* + * close socket callback function: called instead of close() + * when shutting down a connection + */ + data->set.fclosesocket = va_arg(param, curl_closesocket_callback); + break; + + case CURLOPT_RESOLVER_START_FUNCTION: + /* + * resolver start callback function: called before a new resolver request + * is started + */ + data->set.resolver_start = va_arg(param, curl_resolver_start_callback); + break; + + case CURLOPT_RESOLVER_START_DATA: + /* + * resolver start callback data pointer. Might be NULL. + */ + data->set.resolver_start_client = va_arg(param, void *); + break; + + case CURLOPT_CLOSESOCKETDATA: + /* + * socket callback data pointer. Might be NULL. + */ + data->set.closesocket_client = va_arg(param, void *); + break; + + case CURLOPT_SSL_SESSIONID_CACHE: + data->set.ssl.primary.sessionid = (0 != va_arg(param, long)); +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid; +#endif + break; + +#ifdef USE_SSH + /* we only include SSH options if explicitly built to support SSH */ + case CURLOPT_SSH_AUTH_TYPES: + data->set.ssh_auth_types = (unsigned int)va_arg(param, long); + break; + + case CURLOPT_SSH_PUBLIC_KEYFILE: + /* + * Use this file instead of the $HOME/.ssh/id_dsa.pub file + */ + result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], + va_arg(param, char *)); + break; + + case CURLOPT_SSH_PRIVATE_KEYFILE: + /* + * Use this file instead of the $HOME/.ssh/id_dsa file + */ + result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], + va_arg(param, char *)); + break; + case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: + /* + * Option to allow for the MD5 of the host public key to be checked + * for validation purposes. + */ + result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], + va_arg(param, char *)); + break; + + case CURLOPT_SSH_KNOWNHOSTS: + /* + * Store the file name to read known hosts from. + */ + result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], + va_arg(param, char *)); + break; +#ifdef USE_LIBSSH2 + case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256: + /* + * Option to allow for the SHA256 of the host public key to be checked + * for validation purposes. + */ + result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256], + va_arg(param, char *)); + break; + + case CURLOPT_SSH_HOSTKEYFUNCTION: + /* the callback to check the hostkey without the knownhost file */ + data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback); + break; + + case CURLOPT_SSH_HOSTKEYDATA: + /* + * Custom client data to pass to the SSH keyfunc callback + */ + data->set.ssh_hostkeyfunc_userp = va_arg(param, void *); + break; +#endif + + case CURLOPT_SSH_KEYFUNCTION: + /* setting to NULL is fine since the ssh.c functions themselves will + then revert to use the internal default */ + data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback); + break; + + case CURLOPT_SSH_KEYDATA: + /* + * Custom client data to pass to the SSH keyfunc callback + */ + data->set.ssh_keyfunc_userp = va_arg(param, void *); + break; + + case CURLOPT_SSH_COMPRESSION: + data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE; + break; +#endif /* USE_SSH */ + + case CURLOPT_HTTP_TRANSFER_DECODING: + /* + * disable libcurl transfer encoding is used + */ +#ifndef USE_HYPER + data->set.http_te_skip = (0 == va_arg(param, long)); + break; +#else + return CURLE_NOT_BUILT_IN; /* hyper doesn't support */ +#endif + + case CURLOPT_HTTP_CONTENT_DECODING: + /* + * raw data passed to the application when content encoding is used + */ + data->set.http_ce_skip = (0 == va_arg(param, long)); + break; + +#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) + case CURLOPT_NEW_FILE_PERMS: + /* + * Uses these permissions instead of 0644 + */ + arg = va_arg(param, long); + if((arg < 0) || (arg > 0777)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.new_file_perms = (unsigned int)arg; + break; +#endif +#ifdef USE_SSH + case CURLOPT_NEW_DIRECTORY_PERMS: + /* + * Uses these permissions instead of 0755 + */ + arg = va_arg(param, long); + if((arg < 0) || (arg > 0777)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.new_directory_perms = (unsigned int)arg; + break; +#endif + +#ifdef ENABLE_IPV6 + case CURLOPT_ADDRESS_SCOPE: + /* + * Use this scope id when using IPv6 + * We always get longs when passed plain numericals so we should check + * that the value fits into an unsigned 32 bit integer. + */ + uarg = va_arg(param, unsigned long); +#if SIZEOF_LONG > 4 + if(uarg > UINT_MAX) + return CURLE_BAD_FUNCTION_ARGUMENT; +#endif + data->set.scope_id = (unsigned int)uarg; + break; +#endif + + case CURLOPT_PROTOCOLS: + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + data->set.allowed_protocols = (curl_prot_t)va_arg(param, long); + break; + + case CURLOPT_REDIR_PROTOCOLS: + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. */ + data->set.redir_protocols = (curl_prot_t)va_arg(param, long); + break; + + case CURLOPT_PROTOCOLS_STR: { + curl_prot_t prot; + argptr = va_arg(param, char *); + result = protocol2num(argptr, &prot); + if(result) + return result; + data->set.allowed_protocols = prot; + break; + } + + case CURLOPT_REDIR_PROTOCOLS_STR: { + curl_prot_t prot; + argptr = va_arg(param, char *); + result = protocol2num(argptr, &prot); + if(result) + return result; + data->set.redir_protocols = prot; + break; + } + + case CURLOPT_DEFAULT_PROTOCOL: + /* Set the protocol to use when the URL doesn't include any protocol */ + result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_SMTP + case CURLOPT_MAIL_FROM: + /* Set the SMTP mail originator */ + result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM], + va_arg(param, char *)); + break; + + case CURLOPT_MAIL_AUTH: + /* Set the SMTP auth originator */ + result = Curl_setstropt(&data->set.str[STRING_MAIL_AUTH], + va_arg(param, char *)); + break; + + case CURLOPT_MAIL_RCPT: + /* Set the list of mail recipients */ + data->set.mail_rcpt = va_arg(param, struct curl_slist *); + break; + case CURLOPT_MAIL_RCPT_ALLOWFAILS: + /* allow RCPT TO command to fail for some recipients */ + data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)); + break; +#endif + + case CURLOPT_SASL_AUTHZID: + /* Authorization identity (identity to act as) */ + result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], + va_arg(param, char *)); + break; + + case CURLOPT_SASL_IR: + /* Enable/disable SASL initial response */ + data->set.sasl_ir = (0 != va_arg(param, long)); + break; +#ifndef CURL_DISABLE_RTSP + case CURLOPT_RTSP_REQUEST: + { + /* + * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...) + * Would this be better if the RTSPREQ_* were just moved into here? + */ + long in_rtspreq = va_arg(param, long); + Curl_RtspReq rtspreq = RTSPREQ_NONE; + switch(in_rtspreq) { + case CURL_RTSPREQ_OPTIONS: + rtspreq = RTSPREQ_OPTIONS; + break; + + case CURL_RTSPREQ_DESCRIBE: + rtspreq = RTSPREQ_DESCRIBE; + break; + + case CURL_RTSPREQ_ANNOUNCE: + rtspreq = RTSPREQ_ANNOUNCE; + break; + + case CURL_RTSPREQ_SETUP: + rtspreq = RTSPREQ_SETUP; + break; + + case CURL_RTSPREQ_PLAY: + rtspreq = RTSPREQ_PLAY; + break; + + case CURL_RTSPREQ_PAUSE: + rtspreq = RTSPREQ_PAUSE; + break; + + case CURL_RTSPREQ_TEARDOWN: + rtspreq = RTSPREQ_TEARDOWN; + break; + + case CURL_RTSPREQ_GET_PARAMETER: + rtspreq = RTSPREQ_GET_PARAMETER; + break; + + case CURL_RTSPREQ_SET_PARAMETER: + rtspreq = RTSPREQ_SET_PARAMETER; + break; + + case CURL_RTSPREQ_RECORD: + rtspreq = RTSPREQ_RECORD; + break; + + case CURL_RTSPREQ_RECEIVE: + rtspreq = RTSPREQ_RECEIVE; + break; + default: + rtspreq = RTSPREQ_NONE; + } + + data->set.rtspreq = rtspreq; + break; + } + + + case CURLOPT_RTSP_SESSION_ID: + /* + * Set the RTSP Session ID manually. Useful if the application is + * resuming a previously established RTSP session + */ + result = Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID], + va_arg(param, char *)); + break; + + case CURLOPT_RTSP_STREAM_URI: + /* + * Set the Stream URI for the RTSP request. Unless the request is + * for generic server options, the application will need to set this. + */ + result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI], + va_arg(param, char *)); + break; + + case CURLOPT_RTSP_TRANSPORT: + /* + * The content of the Transport: header for the RTSP request + */ + result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], + va_arg(param, char *)); + break; + + case CURLOPT_RTSP_CLIENT_CSEQ: + /* + * Set the CSEQ number to issue for the next RTSP request. Useful if the + * application is resuming a previously broken connection. The CSEQ + * will increment from this new number henceforth. + */ + data->state.rtsp_next_client_CSeq = va_arg(param, long); + break; + + case CURLOPT_RTSP_SERVER_CSEQ: + /* Same as the above, but for server-initiated requests */ + data->state.rtsp_next_server_CSeq = va_arg(param, long); + break; + + case CURLOPT_INTERLEAVEDATA: + data->set.rtp_out = va_arg(param, void *); + break; + case CURLOPT_INTERLEAVEFUNCTION: + /* Set the user defined RTP write function */ + data->set.fwrite_rtp = va_arg(param, curl_write_callback); + break; +#endif +#ifndef CURL_DISABLE_FTP + case CURLOPT_WILDCARDMATCH: + data->set.wildcard_enabled = (0 != va_arg(param, long)); + break; + case CURLOPT_CHUNK_BGN_FUNCTION: + data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); + break; + case CURLOPT_CHUNK_END_FUNCTION: + data->set.chunk_end = va_arg(param, curl_chunk_end_callback); + break; + case CURLOPT_FNMATCH_FUNCTION: + data->set.fnmatch = va_arg(param, curl_fnmatch_callback); + break; + case CURLOPT_CHUNK_DATA: + data->set.wildcardptr = va_arg(param, void *); + break; + case CURLOPT_FNMATCH_DATA: + data->set.fnmatch_data = va_arg(param, void *); + break; +#endif +#ifdef USE_TLS_SRP + case CURLOPT_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], + va_arg(param, char *)); + break; +#endif + case CURLOPT_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], + va_arg(param, char *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], + va_arg(param, char *)); + break; +#endif + case CURLOPT_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(argptr && !strncasecompare(argptr, "SRP", strlen("SRP"))) + return CURLE_BAD_FUNCTION_ARGUMENT; + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(argptr || !strncasecompare(argptr, "SRP", strlen("SRP"))) + return CURLE_BAD_FUNCTION_ARGUMENT; + break; +#endif +#endif +#ifdef USE_ARES + case CURLOPT_DNS_SERVERS: + result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]); + break; + case CURLOPT_DNS_INTERFACE: + result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]); + break; + case CURLOPT_DNS_LOCAL_IP4: + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]); + break; + case CURLOPT_DNS_LOCAL_IP6: + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]); + break; +#endif + case CURLOPT_TCP_KEEPALIVE: + data->set.tcp_keepalive = (0 != va_arg(param, long)); + break; + case CURLOPT_TCP_KEEPIDLE: + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(arg > INT_MAX) + arg = INT_MAX; + data->set.tcp_keepidle = (int)arg; + break; + case CURLOPT_TCP_KEEPINTVL: + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(arg > INT_MAX) + arg = INT_MAX; + data->set.tcp_keepintvl = (int)arg; + break; + case CURLOPT_TCP_FASTOPEN: +#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ + defined(TCP_FASTOPEN_CONNECT) + data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE; +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; + case CURLOPT_SSL_ENABLE_NPN: + break; + case CURLOPT_SSL_ENABLE_ALPN: + data->set.ssl_enable_alpn = (0 != va_arg(param, long)); + break; +#ifdef USE_UNIX_SOCKETS + case CURLOPT_UNIX_SOCKET_PATH: + data->set.abstract_unix_socket = FALSE; + result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], + va_arg(param, char *)); + break; + case CURLOPT_ABSTRACT_UNIX_SOCKET: + data->set.abstract_unix_socket = TRUE; + result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], + va_arg(param, char *)); + break; +#endif + + case CURLOPT_PATH_AS_IS: + data->set.path_as_is = (0 != va_arg(param, long)); + break; + case CURLOPT_PIPEWAIT: + data->set.pipewait = (0 != va_arg(param, long)); + break; + case CURLOPT_STREAM_WEIGHT: +#if defined(USE_HTTP2) || defined(USE_HTTP3) + arg = va_arg(param, long); + if((arg >= 1) && (arg <= 256)) + data->set.priority.weight = (int)arg; + break; +#else + return CURLE_NOT_BUILT_IN; +#endif + case CURLOPT_STREAM_DEPENDS: + case CURLOPT_STREAM_DEPENDS_E: + { + struct Curl_easy *dep = va_arg(param, struct Curl_easy *); + if(!dep || GOOD_EASY_HANDLE(dep)) { + return Curl_data_priority_add_child(dep, data, + option == CURLOPT_STREAM_DEPENDS_E); + } + break; + } + case CURLOPT_CONNECT_TO: + data->set.connect_to = va_arg(param, struct curl_slist *); + break; + case CURLOPT_SUPPRESS_CONNECT_HEADERS: + data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE; + break; + case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS: + uarg = va_arg(param, unsigned long); + if(uarg > UINT_MAX) + uarg = UINT_MAX; + data->set.happy_eyeballs_timeout = (unsigned int)uarg; + break; +#ifndef CURL_DISABLE_SHUFFLE_DNS + case CURLOPT_DNS_SHUFFLE_ADDRESSES: + data->set.dns_shuffle_addresses = (0 != va_arg(param, long)); + break; +#endif + case CURLOPT_DISALLOW_USERNAME_IN_URL: + data->set.disallow_username_in_url = (0 != va_arg(param, long)); + break; +#ifndef CURL_DISABLE_DOH + case CURLOPT_DOH_URL: + result = Curl_setstropt(&data->set.str[STRING_DOH], + va_arg(param, char *)); + data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE; + break; +#endif + case CURLOPT_UPKEEP_INTERVAL_MS: + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.upkeep_interval_ms = arg; + break; + case CURLOPT_MAXAGE_CONN: + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.maxage_conn = arg; + break; + case CURLOPT_MAXLIFETIME_CONN: + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.maxlifetime_conn = arg; + break; + case CURLOPT_TRAILERFUNCTION: +#ifndef CURL_DISABLE_HTTP + data->set.trailer_callback = va_arg(param, curl_trailer_callback); +#endif + break; + case CURLOPT_TRAILERDATA: +#ifndef CURL_DISABLE_HTTP + data->set.trailer_data = va_arg(param, void *); +#endif + break; +#ifndef CURL_DISABLE_HSTS + case CURLOPT_HSTSREADFUNCTION: + data->set.hsts_read = va_arg(param, curl_hstsread_callback); + break; + case CURLOPT_HSTSREADDATA: + data->set.hsts_read_userp = va_arg(param, void *); + break; + case CURLOPT_HSTSWRITEFUNCTION: + data->set.hsts_write = va_arg(param, curl_hstswrite_callback); + break; + case CURLOPT_HSTSWRITEDATA: + data->set.hsts_write_userp = va_arg(param, void *); + break; + case CURLOPT_HSTS: { + struct curl_slist *h; + if(!data->hsts) { + data->hsts = Curl_hsts_init(); + if(!data->hsts) + return CURLE_OUT_OF_MEMORY; + } + argptr = va_arg(param, char *); + if(argptr) { + result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr); + if(result) + return result; + /* this needs to build a list of file names to read from, so that it can + read them later, as we might get a shared HSTS handle to load them + into */ + h = curl_slist_append(data->state.hstslist, argptr); + if(!h) { + curl_slist_free_all(data->state.hstslist); + data->state.hstslist = NULL; + return CURLE_OUT_OF_MEMORY; + } + data->state.hstslist = h; /* store the list for later use */ + } + else { + /* clear the list of HSTS files */ + curl_slist_free_all(data->state.hstslist); + data->state.hstslist = NULL; + if(!data->share || !data->share->hsts) + /* throw away the HSTS cache unless shared */ + Curl_hsts_cleanup(&data->hsts); + } + break; + } + case CURLOPT_HSTS_CTRL: + arg = va_arg(param, long); + if(arg & CURLHSTS_ENABLE) { + if(!data->hsts) { + data->hsts = Curl_hsts_init(); + if(!data->hsts) + return CURLE_OUT_OF_MEMORY; + } + } + else + Curl_hsts_cleanup(&data->hsts); + break; +#endif +#ifndef CURL_DISABLE_ALTSVC + case CURLOPT_ALTSVC: + if(!data->asi) { + data->asi = Curl_altsvc_init(); + if(!data->asi) + return CURLE_OUT_OF_MEMORY; + } + argptr = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_ALTSVC], argptr); + if(result) + return result; + if(argptr) + (void)Curl_altsvc_load(data->asi, argptr); + break; + case CURLOPT_ALTSVC_CTRL: + if(!data->asi) { + data->asi = Curl_altsvc_init(); + if(!data->asi) + return CURLE_OUT_OF_MEMORY; + } + arg = va_arg(param, long); + if(!arg) { + DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + result = Curl_altsvc_ctrl(data->asi, arg); + if(result) + return result; + break; +#endif + case CURLOPT_PREREQFUNCTION: + data->set.fprereq = va_arg(param, curl_prereq_callback); + break; + case CURLOPT_PREREQDATA: + data->set.prereq_userp = va_arg(param, void *); + break; +#ifdef USE_WEBSOCKETS + case CURLOPT_WS_OPTIONS: { + bool raw; + arg = va_arg(param, long); + raw = (arg & CURLWS_RAW_MODE); + data->set.ws_raw_mode = raw; + break; + } +#endif + case CURLOPT_QUICK_EXIT: + data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L; + break; + default: + /* unknown tag and its companion, just ignore: */ + result = CURLE_UNKNOWN_OPTION; + break; + } + + return result; +} + +/* + * curl_easy_setopt() is the external interface for setting options on an + * easy handle. + * + * NOTE: This is one of few API functions that are allowed to be called from + * within a callback. + */ + +#undef curl_easy_setopt +CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...) +{ + va_list arg; + CURLcode result; + + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + va_start(arg, tag); + + result = Curl_vsetopt(data, tag, arg); + + va_end(arg); +#ifdef DEBUGBUILD + if(result == CURLE_BAD_FUNCTION_ARGUMENT) + infof(data, "setopt arg 0x%x returned CURLE_BAD_FUNCTION_ARGUMENT", tag); +#endif + return result; +} diff --git a/lib/setopt.h b/lib/setopt.h new file mode 100644 index 0000000..3c14a05 --- /dev/null +++ b/lib/setopt.h @@ -0,0 +1,32 @@ +#ifndef HEADER_CURL_SETOPT_H +#define HEADER_CURL_SETOPT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +CURLcode Curl_setstropt(char **charp, const char *s); +CURLcode Curl_setblobopt(struct curl_blob **blobp, + const struct curl_blob *blob); +CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg); + +#endif /* HEADER_CURL_SETOPT_H */ diff --git a/lib/setup-os400.h b/lib/setup-os400.h new file mode 100644 index 0000000..53e9177 --- /dev/null +++ b/lib/setup-os400.h @@ -0,0 +1,144 @@ +#ifndef HEADER_CURL_SETUP_OS400_H +#define HEADER_CURL_SETUP_OS400_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + + +/* OS/400 netdb.h does not define NI_MAXHOST. */ +#define NI_MAXHOST 1025 + +/* OS/400 netdb.h does not define NI_MAXSERV. */ +#define NI_MAXSERV 32 + +/* No OS/400 header file defines u_int32_t. */ +typedef unsigned long u_int32_t; + +/* OS/400 has no idea of a tty! */ +#define isatty(fd) 0 + + +/* System API wrapper prototypes & definitions to support ASCII parameters. */ + +#include +#include +#include +#include +#include + +extern int Curl_getaddrinfo_a(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); +#define getaddrinfo Curl_getaddrinfo_a + +/* Note socklen_t must be used as this is declared before curl_socklen_t */ +extern int Curl_getnameinfo_a(const struct sockaddr *sa, + socklen_t salen, + char *nodename, socklen_t nodenamelen, + char *servname, socklen_t servnamelen, + int flags); +#define getnameinfo Curl_getnameinfo_a + +/* GSSAPI wrappers. */ + +extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status, + gss_buffer_t in_name, + gss_OID in_name_type, + gss_name_t * out_name); +#define gss_import_name Curl_gss_import_name_a + + +extern OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status, + OM_uint32 status_value, + int status_type, gss_OID mech_type, + gss_msg_ctx_t * message_context, + gss_buffer_t status_string); +#define gss_display_status Curl_gss_display_status_a + + +extern OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status, + gss_cred_id_t cred_handle, + gss_ctx_id_t * context_handle, + gss_name_t target_name, + gss_OID mech_type, + gss_flags_t req_flags, + OM_uint32 time_req, + gss_channel_bindings_t + input_chan_bindings, + gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + gss_flags_t * ret_flags, + OM_uint32 * time_rec); +#define gss_init_sec_context Curl_gss_init_sec_context_a + + +extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t output_token); +#define gss_delete_sec_context Curl_gss_delete_sec_context_a + + +/* LDAP wrappers. */ + +#define BerValue struct berval + +#define ldap_url_parse ldap_url_parse_utf8 +#define ldap_init Curl_ldap_init_a +#define ldap_simple_bind_s Curl_ldap_simple_bind_s_a +#define ldap_search_s Curl_ldap_search_s_a +#define ldap_get_values_len Curl_ldap_get_values_len_a +#define ldap_err2string Curl_ldap_err2string_a +#define ldap_get_dn Curl_ldap_get_dn_a +#define ldap_first_attribute Curl_ldap_first_attribute_a +#define ldap_next_attribute Curl_ldap_next_attribute_a + +/* Some socket functions must be wrapped to process textual addresses + like AF_UNIX. */ + +extern int Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen); +extern int Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen); +extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags, + const struct sockaddr *dstaddr, int addrlen); +extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags, + struct sockaddr *fromaddr, int *addrlen); +extern int Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen); +extern int Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen); + +#define connect Curl_os400_connect +#define bind Curl_os400_bind +#define sendto Curl_os400_sendto +#define recvfrom Curl_os400_recvfrom +#define getpeername Curl_os400_getpeername +#define getsockname Curl_os400_getsockname + +#ifdef HAVE_LIBZ +#define zlibVersion Curl_os400_zlibVersion +#define inflateInit_ Curl_os400_inflateInit_ +#define inflateInit2_ Curl_os400_inflateInit2_ +#define inflate Curl_os400_inflate +#define inflateEnd Curl_os400_inflateEnd +#endif + +#endif /* HEADER_CURL_SETUP_OS400_H */ diff --git a/lib/setup-vms.h b/lib/setup-vms.h new file mode 100644 index 0000000..645cc1a --- /dev/null +++ b/lib/setup-vms.h @@ -0,0 +1,444 @@ +#ifndef HEADER_CURL_SETUP_VMS_H +#define HEADER_CURL_SETUP_VMS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* */ +/* JEM, 12/30/12, VMS now generates config.h, so only define wrappers for */ +/* getenv(), getpwuid() and provide is_vms_shell() */ +/* Also need upper case symbols for system services, and */ +/* OpenSSL, and some Kerberos image */ + +#ifdef __DECC +#pragma message save +#pragma message disable dollarid +#endif + +/* Hide the stuff we are overriding */ +#define getenv decc_getenv +#ifdef __DECC +# if __INITIAL_POINTER_SIZE != 64 +# define getpwuid decc_getpwuid +# endif +#endif +#include +char *decc$getenv(const char *__name); +#include + +#include +#include + +#undef getenv +#undef getpwuid +#define getenv vms_getenv +#define getpwuid vms_getpwuid + +/* VAX needs these in upper case when compiling exact case */ +#define sys$assign SYS$ASSIGN +#define sys$dassgn SYS$DASSGN +#define sys$qiow SYS$QIOW + +#ifdef __DECC +# if __INITIAL_POINTER_SIZE +# pragma __pointer_size __save +# endif +#endif + +#if __USE_LONG_GID_T +# define decc_getpwuid DECC$__LONG_GID_GETPWUID +#else +# if __INITIAL_POINTER_SIZE +# define decc_getpwuid decc$__32_getpwuid +# else +# define decc_getpwuid decc$getpwuid +# endif +#endif + + struct passwd *decc_getpwuid(uid_t uid); + +#ifdef __DECC +# if __INITIAL_POINTER_SIZE == 32 +/* Translate the path, but only if the path is a VMS file specification */ +/* The translation is usually only needed for older versions of VMS */ +static char *vms_translate_path(const char *path) +{ + char *unix_path; + char *test_str; + + /* See if the result is in VMS format, if not, we are done */ + /* Assume that this is a PATH, not just some data */ + test_str = strpbrk(path, ":[<^"); + if(!test_str) { + return (char *)path; + } + + unix_path = decc$translate_vms(path); + + if((int)unix_path <= 0) { + /* We can not translate it, so return the original string */ + return (char *)path; + } +} +# else + /* VMS translate path is actually not needed on the current 64 bit */ + /* VMS platforms, so instead of figuring out the pointer settings */ + /* Change it to a noop */ +# define vms_translate_path(__path) __path +# endif +#endif + +#ifdef __DECC +# if __INITIAL_POINTER_SIZE +# pragma __pointer_size __restore +# endif +#endif + +static char *vms_getenv(const char *envvar) +{ + char *result; + char *vms_path; + + /* first use the DECC getenv() function */ + result = decc$getenv(envvar); + if(!result) { + return result; + } + + vms_path = result; + result = vms_translate_path(vms_path); + + /* note that if you backport this to use VAX C RTL, that the VAX C RTL */ + /* may do a malloc(2048) for each call to getenv(), so you will need */ + /* to add a free(vms_path) */ + /* Do not do a free() for DEC C RTL builds, which should be used for */ + /* VMS 5.5-2 and later, even if using GCC */ + + return result; +} + + +static struct passwd vms_passwd_cache; + +static struct passwd *vms_getpwuid(uid_t uid) +{ + struct passwd *my_passwd; + +/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */ +#ifdef __DECC +# if __INITIAL_POINTER_SIZE + __char_ptr32 unix_path; +# else + char *unix_path; +# endif +#else + char *unix_path; +#endif + + my_passwd = decc_getpwuid(uid); + if(!my_passwd) { + return my_passwd; + } + + unix_path = vms_translate_path(my_passwd->pw_dir); + + if((long)unix_path <= 0) { + /* We can not translate it, so return the original string */ + return my_passwd; + } + + /* If no changes needed just return it */ + if(unix_path == my_passwd->pw_dir) { + return my_passwd; + } + + /* Need to copy the structure returned */ + /* Since curl is only using pw_dir, no need to fix up */ + /* the pw_shell when running under Bash */ + vms_passwd_cache.pw_name = my_passwd->pw_name; + vms_passwd_cache.pw_uid = my_passwd->pw_uid; + vms_passwd_cache.pw_gid = my_passwd->pw_uid; + vms_passwd_cache.pw_dir = unix_path; + vms_passwd_cache.pw_shell = my_passwd->pw_shell; + + return &vms_passwd_cache; +} + +#ifdef __DECC +#pragma message restore +#endif + +/* Bug - VMS OpenSSL and Kerberos universal symbols are in uppercase only */ +/* VMS libraries should have universal symbols in exact and uppercase */ + +#define ASN1_INTEGER_get ASN1_INTEGER_GET +#define ASN1_STRING_data ASN1_STRING_DATA +#define ASN1_STRING_length ASN1_STRING_LENGTH +#define ASN1_STRING_print ASN1_STRING_PRINT +#define ASN1_STRING_to_UTF8 ASN1_STRING_TO_UTF8 +#define ASN1_STRING_type ASN1_STRING_TYPE +#define BIO_ctrl BIO_CTRL +#define BIO_free BIO_FREE +#define BIO_new BIO_NEW +#define BIO_s_mem BIO_S_MEM +#define BN_bn2bin BN_BN2BIN +#define BN_num_bits BN_NUM_BITS +#define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA +#define CRYPTO_free CRYPTO_FREE +#define CRYPTO_malloc CRYPTO_MALLOC +#define CONF_modules_load_file CONF_MODULES_LOAD_FILE +#ifdef __VAX +# ifdef VMS_OLD_SSL + /* Ancient OpenSSL on VAX/VMS missing this constant */ +# define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10 +# undef CONF_modules_load_file + static int CONF_modules_load_file(const char *filename, + const char *appname, + unsigned long flags) { + return 1; + } +# endif +#endif +#define DES_ecb_encrypt DES_ECB_ENCRYPT +#define DES_set_key DES_SET_KEY +#define DES_set_odd_parity DES_SET_ODD_PARITY +#define ENGINE_ctrl ENGINE_CTRL +#define ENGINE_ctrl_cmd ENGINE_CTRL_CMD +#define ENGINE_finish ENGINE_FINISH +#define ENGINE_free ENGINE_FREE +#define ENGINE_get_first ENGINE_GET_FIRST +#define ENGINE_get_id ENGINE_GET_ID +#define ENGINE_get_next ENGINE_GET_NEXT +#define ENGINE_init ENGINE_INIT +#define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES +#define ENGINE_load_private_key ENGINE_LOAD_PRIVATE_KEY +#define ENGINE_set_default ENGINE_SET_DEFAULT +#define ERR_clear_error ERR_CLEAR_ERROR +#define ERR_error_string ERR_ERROR_STRING +#define ERR_error_string_n ERR_ERROR_STRING_N +#define ERR_free_strings ERR_FREE_STRINGS +#define ERR_get_error ERR_GET_ERROR +#define ERR_peek_error ERR_PEEK_ERROR +#define ERR_remove_state ERR_REMOVE_STATE +#define EVP_PKEY_copy_parameters EVP_PKEY_COPY_PARAMETERS +#define EVP_PKEY_free EVP_PKEY_FREE +#define EVP_cleanup EVP_CLEANUP +#define GENERAL_NAMES_free GENERAL_NAMES_FREE +#define i2d_X509_PUBKEY I2D_X509_PUBKEY +#define MD4_Final MD4_FINAL +#define MD4_Init MD4_INIT +#define MD4_Update MD4_UPDATE +#define MD5_Final MD5_FINAL +#define MD5_Init MD5_INIT +#define MD5_Update MD5_UPDATE +#define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF +#ifndef __VAX +#define OPENSSL_load_builtin_modules OPENSSL_LOAD_BUILTIN_MODULES +#endif +#define PEM_read_X509 PEM_READ_X509 +#define PEM_write_bio_X509 PEM_WRITE_BIO_X509 +#define PKCS12_PBE_add PKCS12_PBE_ADD +#define PKCS12_free PKCS12_FREE +#define PKCS12_parse PKCS12_PARSE +#define RAND_add RAND_ADD +#define RAND_bytes RAND_BYTES +#define RAND_file_name RAND_FILE_NAME +#define RAND_load_file RAND_LOAD_FILE +#define RAND_status RAND_STATUS +#define SSL_CIPHER_get_name SSL_CIPHER_GET_NAME +#define SSL_CTX_add_client_CA SSL_CTX_ADD_CLIENT_CA +#define SSL_CTX_callback_ctrl SSL_CTX_CALLBACK_CTRL +#define SSL_CTX_check_private_key SSL_CTX_CHECK_PRIVATE_KEY +#define SSL_CTX_ctrl SSL_CTX_CTRL +#define SSL_CTX_free SSL_CTX_FREE +#define SSL_CTX_get_cert_store SSL_CTX_GET_CERT_STORE +#define SSL_CTX_load_verify_locations SSL_CTX_LOAD_VERIFY_LOCATIONS +#define SSL_CTX_new SSL_CTX_NEW +#define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST +#define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD +#define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB +#define SSL_CTX_set_msg_callback SSL_CTX_SET_MSG_CALLBACK +#define SSL_CTX_set_verify SSL_CTX_SET_VERIFY +#define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY +#define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE +#define SSL_CTX_use_cert_chain_file SSL_CTX_USE_CERT_CHAIN_FILE +#define SSL_CTX_use_certificate SSL_CTX_USE_CERTIFICATE +#define SSL_CTX_use_certificate_file SSL_CTX_USE_CERTIFICATE_FILE +#define SSL_SESSION_free SSL_SESSION_FREE +#define SSL_connect SSL_CONNECT +#define SSL_free SSL_FREE +#define SSL_get1_session SSL_GET1_SESSION +#define SSL_get_certificate SSL_GET_CERTIFICATE +#define SSL_get_current_cipher SSL_GET_CURRENT_CIPHER +#define SSL_get_error SSL_GET_ERROR +#define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN +#define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE +#define SSL_get_privatekey SSL_GET_PRIVATEKEY +#define SSL_get_session SSL_GET_SESSION +#define SSL_get_shutdown SSL_GET_SHUTDOWN +#define SSL_get_verify_result SSL_GET_VERIFY_RESULT +#define SSL_library_init SSL_LIBRARY_INIT +#define SSL_load_error_strings SSL_LOAD_ERROR_STRINGS +#define SSL_new SSL_NEW +#define SSL_peek SSL_PEEK +#define SSL_pending SSL_PENDING +#define SSL_read SSL_READ +#define SSL_set_connect_state SSL_SET_CONNECT_STATE +#define SSL_set_fd SSL_SET_FD +#define SSL_set_session SSL_SET_SESSION +#define SSL_shutdown SSL_SHUTDOWN +#define SSL_version SSL_VERSION +#define SSL_write SSL_WRITE +#define SSLeay SSLEAY +#define SSLv23_client_method SSLV23_CLIENT_METHOD +#define SSLv3_client_method SSLV3_CLIENT_METHOD +#define TLSv1_client_method TLSV1_CLIENT_METHOD +#define UI_create_method UI_CREATE_METHOD +#define UI_destroy_method UI_DESTROY_METHOD +#define UI_get0_user_data UI_GET0_USER_DATA +#define UI_get_input_flags UI_GET_INPUT_FLAGS +#define UI_get_string_type UI_GET_STRING_TYPE +#define UI_create_method UI_CREATE_METHOD +#define UI_destroy_method UI_DESTROY_METHOD +#define UI_method_get_closer UI_METHOD_GET_CLOSER +#define UI_method_get_opener UI_METHOD_GET_OPENER +#define UI_method_get_reader UI_METHOD_GET_READER +#define UI_method_get_writer UI_METHOD_GET_WRITER +#define UI_method_set_closer UI_METHOD_SET_CLOSER +#define UI_method_set_opener UI_METHOD_SET_OPENER +#define UI_method_set_reader UI_METHOD_SET_READER +#define UI_method_set_writer UI_METHOD_SET_WRITER +#define UI_OpenSSL UI_OPENSSL +#define UI_set_result UI_SET_RESULT +#define X509V3_EXT_print X509V3_EXT_PRINT +#define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL +#define X509_EXTENSION_get_data X509_EXTENSION_GET_DATA +#define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT +#define X509_LOOKUP_file X509_LOOKUP_FILE +#define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA +#define X509_NAME_get_entry X509_NAME_GET_ENTRY +#define X509_NAME_get_index_by_NID X509_NAME_GET_INDEX_BY_NID +#define X509_NAME_print_ex X509_NAME_PRINT_EX +#define X509_STORE_CTX_get_current_cert X509_STORE_CTX_GET_CURRENT_CERT +#define X509_STORE_add_lookup X509_STORE_ADD_LOOKUP +#define X509_STORE_set_flags X509_STORE_SET_FLAGS +#define X509_check_issued X509_CHECK_ISSUED +#define X509_free X509_FREE +#define X509_get_ext_d2i X509_GET_EXT_D2I +#define X509_get_issuer_name X509_GET_ISSUER_NAME +#define X509_get_pubkey X509_GET_PUBKEY +#define X509_get_serialNumber X509_GET_SERIALNUMBER +#define X509_get_subject_name X509_GET_SUBJECT_NAME +#define X509_load_crl_file X509_LOAD_CRL_FILE +#define X509_verify_cert_error_string X509_VERIFY_CERT_ERROR_STRING +#define d2i_PKCS12_fp D2I_PKCS12_FP +#define i2t_ASN1_OBJECT I2T_ASN1_OBJECT +#define sk_num SK_NUM +#define sk_pop SK_POP +#define sk_pop_free SK_POP_FREE +#define sk_value SK_VALUE +#ifdef __VAX +#define OPENSSL_NO_SHA256 +#endif +#define SHA256_Final SHA256_FINAL +#define SHA256_Init SHA256_INIT +#define SHA256_Update SHA256_UPDATE + +#define USE_UPPERCASE_GSSAPI 1 +#define gss_seal GSS_SEAL +#define gss_unseal GSS_UNSEAL + +#define USE_UPPERCASE_KRBAPI 1 + +/* AI_NUMERICHOST needed for IP V6 support in Curl */ +#ifdef HAVE_NETDB_H +#include +#ifndef AI_NUMERICHOST +#ifdef ENABLE_IPV6 +#undef ENABLE_IPV6 +#endif +#endif +#endif + +/* VAX symbols are always in uppercase */ +#ifdef __VAX +#define inflate INFLATE +#define inflateEnd INFLATEEND +#define inflateInit2_ INFLATEINIT2_ +#define inflateInit_ INFLATEINIT_ +#define zlibVersion ZLIBVERSION +#endif + +/* Older VAX OpenSSL port defines these as Macros */ +/* Need to include the headers first and then redefine */ +/* that way a newer port will also work if some one has one */ +#ifdef __VAX + +# if (OPENSSL_VERSION_NUMBER < 0x00907001L) +# define des_set_odd_parity DES_SET_ODD_PARITY +# define des_set_key DES_SET_KEY +# define des_ecb_encrypt DES_ECB_ENCRYPT + +# endif +# include +# ifndef OpenSSL_add_all_algorithms +# define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS + void OPENSSL_ADD_ALL_ALGORITHMS(void); +# endif + + /* Curl defines these to lower case and VAX needs them in upper case */ + /* So we need static routines */ +# if (OPENSSL_VERSION_NUMBER < 0x00907001L) + +# undef des_set_odd_parity +# undef DES_set_odd_parity +# undef des_set_key +# undef DES_set_key +# undef des_ecb_encrypt +# undef DES_ecb_encrypt + + static void des_set_odd_parity(des_cblock *key) { + DES_SET_ODD_PARITY(key); + } + + static int des_set_key(const_des_cblock *key, + des_key_schedule schedule) { + return DES_SET_KEY(key, schedule); + } + + static void des_ecb_encrypt(const_des_cblock *input, + des_cblock *output, + des_key_schedule ks, int enc) { + DES_ECB_ENCRYPT(input, output, ks, enc); + } +#endif +/* Need this to stop a macro redefinition error */ +#if OPENSSL_VERSION_NUMBER < 0x00907000L +# ifdef X509_STORE_set_flags +# undef X509_STORE_set_flags +# define X509_STORE_set_flags(x,y) Curl_nop_stmt +# endif +#endif +#endif + +#endif /* HEADER_CURL_SETUP_VMS_H */ diff --git a/lib/setup-win32.h b/lib/setup-win32.h new file mode 100644 index 0000000..d7e2e6b --- /dev/null +++ b/lib/setup-win32.h @@ -0,0 +1,138 @@ +#ifndef HEADER_CURL_SETUP_WIN32_H +#define HEADER_CURL_SETUP_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#undef USE_WINSOCK +/* ---------------------------------------------------------------- */ +/* Watt-32 TCP/IP SPECIFIC */ +/* ---------------------------------------------------------------- */ +#ifdef USE_WATT32 +# include +# undef byte +# undef word +# define HAVE_SYS_IOCTL_H +# define HAVE_SYS_SOCKET_H +# define HAVE_NETINET_IN_H +# define HAVE_NETDB_H +# define HAVE_ARPA_INET_H +# define SOCKET int +/* ---------------------------------------------------------------- */ +/* BSD-style lwIP TCP/IP stack SPECIFIC */ +/* ---------------------------------------------------------------- */ +#elif defined(USE_LWIPSOCK) + /* Define to use BSD-style lwIP TCP/IP stack. */ + /* #define USE_LWIPSOCK 1 */ +# undef HAVE_GETHOSTNAME +# undef LWIP_POSIX_SOCKETS_IO_NAMES +# undef RECV_TYPE_ARG1 +# undef RECV_TYPE_ARG3 +# undef SEND_TYPE_ARG1 +# undef SEND_TYPE_ARG3 +# define HAVE_GETHOSTBYNAME_R +# define HAVE_GETHOSTBYNAME_R_6 +# define LWIP_POSIX_SOCKETS_IO_NAMES 0 +# define RECV_TYPE_ARG1 int +# define RECV_TYPE_ARG3 size_t +# define SEND_TYPE_ARG1 int +# define SEND_TYPE_ARG3 size_t +#elif defined(_WIN32) +# define USE_WINSOCK 2 +#endif + +/* + * Include header files for windows builds before redefining anything. + * Use this preprocessor block only to include or exclude windows.h, + * winsock2.h or ws2tcpip.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. + */ + +#ifdef _WIN32 +# if defined(UNICODE) && !defined(_UNICODE) +# error "UNICODE is defined but _UNICODE is not defined" +# endif +# if defined(_UNICODE) && !defined(UNICODE) +# error "_UNICODE is defined but UNICODE is not defined" +# endif +/* + * Don't include unneeded stuff in Windows headers to avoid compiler + * warnings and macro clashes. + * Make sure to define this macro before including any Windows headers. + */ +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOGDI +# define NOGDI +# endif +# include +# include +# include +# include +# include +# ifdef UNICODE + typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); +# endif +#endif + +/* + * Define _WIN32_WINNT_[OS] symbols because not all Windows build systems have + * those symbols to compare against, and even those that do may be missing + * newer symbols. + */ + +#ifndef _WIN32_WINNT_NT4 +#define _WIN32_WINNT_NT4 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT_WIN2K +#define _WIN32_WINNT_WIN2K 0x0500 /* Windows 2000 */ +#endif +#ifndef _WIN32_WINNT_WINXP +#define _WIN32_WINNT_WINXP 0x0501 /* Windows XP */ +#endif +#ifndef _WIN32_WINNT_WS03 +#define _WIN32_WINNT_WS03 0x0502 /* Windows Server 2003 */ +#endif +#ifndef _WIN32_WINNT_VISTA +#define _WIN32_WINNT_VISTA 0x0600 /* Windows Vista */ +#endif +#ifndef _WIN32_WINNT_WS08 +#define _WIN32_WINNT_WS08 0x0600 /* Windows Server 2008 */ +#endif +#ifndef _WIN32_WINNT_WIN7 +#define _WIN32_WINNT_WIN7 0x0601 /* Windows 7 */ +#endif +#ifndef _WIN32_WINNT_WIN8 +#define _WIN32_WINNT_WIN8 0x0602 /* Windows 8 */ +#endif +#ifndef _WIN32_WINNT_WINBLUE +#define _WIN32_WINNT_WINBLUE 0x0603 /* Windows 8.1 */ +#endif +#ifndef _WIN32_WINNT_WIN10 +#define _WIN32_WINNT_WIN10 0x0A00 /* Windows 10 */ +#endif + +#endif /* HEADER_CURL_SETUP_WIN32_H */ diff --git a/lib/sha256.c b/lib/sha256.c new file mode 100644 index 0000000..4a02045 --- /dev/null +++ b/lib/sha256.c @@ -0,0 +1,545 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Florin Petriuc, + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \ + || defined(USE_LIBSSH2) + +#include "warnless.h" +#include "curl_sha256.h" +#include "curl_hmac.h" + +#ifdef USE_WOLFSSL +#include +#ifndef NO_SHA256 +#define USE_OPENSSL_SHA256 +#endif +#endif + +#if defined(USE_OPENSSL) + +#include + +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) +#define USE_OPENSSL_SHA256 +#endif + +#endif /* USE_OPENSSL */ + +#ifdef USE_MBEDTLS +#include + +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \ + (MBEDTLS_VERSION_NUMBER < 0x03000000) + #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS +#endif +#endif /* USE_MBEDTLS */ + +#if defined(USE_OPENSSL_SHA256) + +/* When OpenSSL or wolfSSL is available we use their SHA256-functions. */ +#if defined(USE_OPENSSL) +#include +#elif defined(USE_WOLFSSL) +#include +#endif + +#elif defined(USE_GNUTLS) +#include +#elif defined(USE_MBEDTLS) +#include +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) +#include +#define AN_APPLE_OS +#elif defined(USE_WIN32_CRYPTO) +#include +#endif + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* Please keep the SSL backend-specific #if branches in this order: + * + * 1. USE_OPENSSL + * 2. USE_GNUTLS + * 3. USE_MBEDTLS + * 4. USE_COMMON_CRYPTO + * 5. USE_WIN32_CRYPTO + * + * This ensures that the same SSL branch gets activated throughout this source + * file even if multiple backends are enabled at the same time. + */ + +#if defined(USE_OPENSSL_SHA256) + +struct sha256_ctx { + EVP_MD_CTX *openssl_ctx; +}; +typedef struct sha256_ctx my_sha256_ctx; + +static CURLcode my_sha256_init(my_sha256_ctx *ctx) +{ + ctx->openssl_ctx = EVP_MD_CTX_create(); + if(!ctx->openssl_ctx) + return CURLE_OUT_OF_MEMORY; + + if(!EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL)) { + EVP_MD_CTX_destroy(ctx->openssl_ctx); + return CURLE_FAILED_INIT; + } + return CURLE_OK; +} + +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) +{ + EVP_DigestUpdate(ctx->openssl_ctx, data, length); +} + +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) +{ + EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL); + EVP_MD_CTX_destroy(ctx->openssl_ctx); +} + +#elif defined(USE_GNUTLS) + +typedef struct sha256_ctx my_sha256_ctx; + +static CURLcode my_sha256_init(my_sha256_ctx *ctx) +{ + sha256_init(ctx); + return CURLE_OK; +} + +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) +{ + sha256_update(ctx, length, data); +} + +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) +{ + sha256_digest(ctx, SHA256_DIGEST_SIZE, digest); +} + +#elif defined(USE_MBEDTLS) + +typedef mbedtls_sha256_context my_sha256_ctx; + +static CURLcode my_sha256_init(my_sha256_ctx *ctx) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_sha256_starts(ctx, 0); +#else + (void) mbedtls_sha256_starts_ret(ctx, 0); +#endif + return CURLE_OK; +} + +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_sha256_update(ctx, data, length); +#else + (void) mbedtls_sha256_update_ret(ctx, data, length); +#endif +} + +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_sha256_finish(ctx, digest); +#else + (void) mbedtls_sha256_finish_ret(ctx, digest); +#endif +} + +#elif defined(AN_APPLE_OS) +typedef CC_SHA256_CTX my_sha256_ctx; + +static CURLcode my_sha256_init(my_sha256_ctx *ctx) +{ + (void) CC_SHA256_Init(ctx); + return CURLE_OK; +} + +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) +{ + (void) CC_SHA256_Update(ctx, data, length); +} + +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) +{ + (void) CC_SHA256_Final(digest, ctx); +} + +#elif defined(USE_WIN32_CRYPTO) + +struct sha256_ctx { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; +}; +typedef struct sha256_ctx my_sha256_ctx; + +#if !defined(CALG_SHA_256) +#define CALG_SHA_256 0x0000800c +#endif + +static CURLcode my_sha256_init(my_sha256_ctx *ctx) +{ + if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return CURLE_OUT_OF_MEMORY; + + if(!CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash)) { + CryptReleaseContext(ctx->hCryptProv, 0); + ctx->hCryptProv = 0; + return CURLE_FAILED_INIT; + } + + return CURLE_OK; +} + +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) +{ + CryptHashData(ctx->hHash, (unsigned char *) data, length, 0); +} + +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) +{ + unsigned long length = 0; + + CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); + if(length == SHA256_DIGEST_LENGTH) + CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); + + if(ctx->hHash) + CryptDestroyHash(ctx->hHash); + + if(ctx->hCryptProv) + CryptReleaseContext(ctx->hCryptProv, 0); +} + +#else + +/* When no other crypto library is available we use this code segment */ + +/* This is based on SHA256 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. */ + +#define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \ + (((unsigned long)(a)[1]) << 16) | \ + (((unsigned long)(a)[2]) << 8) | \ + ((unsigned long)(a)[3])) +#define WPA_PUT_BE32(a, val) \ +do { \ + (a)[0] = (unsigned char)((((unsigned long) (val)) >> 24) & 0xff); \ + (a)[1] = (unsigned char)((((unsigned long) (val)) >> 16) & 0xff); \ + (a)[2] = (unsigned char)((((unsigned long) (val)) >> 8) & 0xff); \ + (a)[3] = (unsigned char)(((unsigned long) (val)) & 0xff); \ +} while(0) + +#ifdef HAVE_LONGLONG +#define WPA_PUT_BE64(a, val) \ +do { \ + (a)[0] = (unsigned char)(((unsigned long long)(val)) >> 56); \ + (a)[1] = (unsigned char)(((unsigned long long)(val)) >> 48); \ + (a)[2] = (unsigned char)(((unsigned long long)(val)) >> 40); \ + (a)[3] = (unsigned char)(((unsigned long long)(val)) >> 32); \ + (a)[4] = (unsigned char)(((unsigned long long)(val)) >> 24); \ + (a)[5] = (unsigned char)(((unsigned long long)(val)) >> 16); \ + (a)[6] = (unsigned char)(((unsigned long long)(val)) >> 8); \ + (a)[7] = (unsigned char)(((unsigned long long)(val)) & 0xff); \ +} while(0) +#else +#define WPA_PUT_BE64(a, val) \ +do { \ + (a)[0] = (unsigned char)(((unsigned __int64)(val)) >> 56); \ + (a)[1] = (unsigned char)(((unsigned __int64)(val)) >> 48); \ + (a)[2] = (unsigned char)(((unsigned __int64)(val)) >> 40); \ + (a)[3] = (unsigned char)(((unsigned __int64)(val)) >> 32); \ + (a)[4] = (unsigned char)(((unsigned __int64)(val)) >> 24); \ + (a)[5] = (unsigned char)(((unsigned __int64)(val)) >> 16); \ + (a)[6] = (unsigned char)(((unsigned __int64)(val)) >> 8); \ + (a)[7] = (unsigned char)(((unsigned __int64)(val)) & 0xff); \ +} while(0) +#endif + +struct sha256_state { +#ifdef HAVE_LONGLONG + unsigned long long length; +#else + unsigned __int64 length; +#endif + unsigned long state[8], curlen; + unsigned char buf[64]; +}; +typedef struct sha256_state my_sha256_ctx; + +/* The K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Various logical functions */ +#define RORc(x, y) \ +(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \ + ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x), (n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +/* Compress 512-bits */ +static int sha256_compress(struct sha256_state *md, + unsigned char *buf) +{ + unsigned long S[8], W[64]; + int i; + + /* Copy state into S */ + for(i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + /* copy the state into 512-bits into W[0..15] */ + for(i = 0; i < 16; i++) + W[i] = WPA_GET_BE32(buf + (4 * i)); + /* fill W[16..63] */ + for(i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + + W[i - 16]; + } + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i) \ + do { \ + unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + unsigned long t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; \ + } while(0) + + for(i = 0; i < 64; ++i) { + unsigned long t; + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* Feedback */ + for(i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + + return 0; +} + +/* Initialize the hash state */ +static CURLcode my_sha256_init(struct sha256_state *md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; + + return CURLE_OK; +} + +/* + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return 0 if successful +*/ +static int my_sha256_update(struct sha256_state *md, + const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; + +#define block_size 64 + if(md->curlen > sizeof(md->buf)) + return -1; + while(inlen > 0) { + if(md->curlen == 0 && inlen >= block_size) { + if(sha256_compress(md, (unsigned char *)in) < 0) + return -1; + md->length += block_size * 8; + in += block_size; + inlen -= block_size; + } + else { + n = CURLMIN(inlen, (block_size - md->curlen)); + memcpy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if(md->curlen == block_size) { + if(sha256_compress(md, md->buf) < 0) + return -1; + md->length += 8 * block_size; + md->curlen = 0; + } + } + } + + return 0; +} + +/* + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return 0 if successful +*/ +static int my_sha256_final(unsigned char *out, + struct sha256_state *md) +{ + int i; + + if(md->curlen >= sizeof(md->buf)) + return -1; + + /* Increase the length of the message */ + md->length += md->curlen * 8; + + /* Append the '1' bit */ + md->buf[md->curlen++] = (unsigned char)0x80; + + /* If the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if(md->curlen > 56) { + while(md->curlen < 64) { + md->buf[md->curlen++] = (unsigned char)0; + } + sha256_compress(md, md->buf); + md->curlen = 0; + } + + /* Pad up to 56 bytes of zeroes */ + while(md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char)0; + } + + /* Store length */ + WPA_PUT_BE64(md->buf + 56, md->length); + sha256_compress(md, md->buf); + + /* Copy output */ + for(i = 0; i < 8; i++) + WPA_PUT_BE32(out + (4 * i), md->state[i]); + + return 0; +} + +#endif /* CRYPTO LIBS */ + +/* + * Curl_sha256it() + * + * Generates a SHA256 hash for the given input data. + * + * Parameters: + * + * output [in/out] - The output buffer. + * input [in] - The input data. + * length [in] - The input length. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sha256it(unsigned char *output, const unsigned char *input, + const size_t length) +{ + CURLcode result; + my_sha256_ctx ctx; + + result = my_sha256_init(&ctx); + if(!result) { + my_sha256_update(&ctx, input, curlx_uztoui(length)); + my_sha256_final(output, &ctx); + } + return result; +} + + +const struct HMAC_params Curl_HMAC_SHA256[] = { + { + /* Hash initialization function. */ + CURLX_FUNCTION_CAST(HMAC_hinit_func, my_sha256_init), + /* Hash update function. */ + CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_sha256_update), + /* Hash computation end function. */ + CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_sha256_final), + /* Size of hash context structure. */ + sizeof(my_sha256_ctx), + /* Maximum key length. */ + 64, + /* Result size. */ + 32 + } +}; + + +#endif /* AWS, DIGEST, or libSSH2 */ diff --git a/lib/share.c b/lib/share.c new file mode 100644 index 0000000..8fa5cda --- /dev/null +++ b/lib/share.c @@ -0,0 +1,290 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "urldata.h" +#include "share.h" +#include "psl.h" +#include "vtls/vtls.h" +#include "hsts.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +struct Curl_share * +curl_share_init(void) +{ + struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); + if(share) { + share->magic = CURL_GOOD_SHARE; + share->specifier |= (1<hostcache, 23); + } + + return share; +} + +#undef curl_share_setopt +CURLSHcode +curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) +{ + va_list param; + int type; + curl_lock_function lockfunc; + curl_unlock_function unlockfunc; + void *ptr; + CURLSHcode res = CURLSHE_OK; + + if(!GOOD_SHARE_HANDLE(share)) + return CURLSHE_INVALID; + + if(share->dirty) + /* don't allow setting options while one or more handles are already + using this share */ + return CURLSHE_IN_USE; + + va_start(param, option); + + switch(option) { + case CURLSHOPT_SHARE: + /* this is a type this share will share */ + type = va_arg(param, int); + + switch(type) { + case CURL_LOCK_DATA_DNS: + break; + + case CURL_LOCK_DATA_COOKIE: +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(!share->cookies) { + share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE); + if(!share->cookies) + res = CURLSHE_NOMEM; + } +#else /* CURL_DISABLE_HTTP */ + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + case CURL_LOCK_DATA_HSTS: +#ifndef CURL_DISABLE_HSTS + if(!share->hsts) { + share->hsts = Curl_hsts_init(); + if(!share->hsts) + res = CURLSHE_NOMEM; + } +#else /* CURL_DISABLE_HSTS */ + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + if(!share->sslsession) { + share->max_ssl_sessions = 8; + share->sslsession = calloc(share->max_ssl_sessions, + sizeof(struct Curl_ssl_session)); + share->sessionage = 0; + if(!share->sslsession) + res = CURLSHE_NOMEM; + } +#else + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + case CURL_LOCK_DATA_CONNECT: + if(Curl_conncache_init(&share->conn_cache, 103)) + res = CURLSHE_NOMEM; + break; + + case CURL_LOCK_DATA_PSL: +#ifndef USE_LIBPSL + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + default: + res = CURLSHE_BAD_OPTION; + } + if(!res) + share->specifier |= (unsigned int)(1<specifier &= ~(unsigned int)(1<cookies) { + Curl_cookie_cleanup(share->cookies); + share->cookies = NULL; + } +#else /* CURL_DISABLE_HTTP */ + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + case CURL_LOCK_DATA_HSTS: +#ifndef CURL_DISABLE_HSTS + if(share->hsts) { + Curl_hsts_cleanup(&share->hsts); + } +#else /* CURL_DISABLE_HSTS */ + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + Curl_safefree(share->sslsession); +#else + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + case CURL_LOCK_DATA_CONNECT: + break; + + default: + res = CURLSHE_BAD_OPTION; + break; + } + break; + + case CURLSHOPT_LOCKFUNC: + lockfunc = va_arg(param, curl_lock_function); + share->lockfunc = lockfunc; + break; + + case CURLSHOPT_UNLOCKFUNC: + unlockfunc = va_arg(param, curl_unlock_function); + share->unlockfunc = unlockfunc; + break; + + case CURLSHOPT_USERDATA: + ptr = va_arg(param, void *); + share->clientdata = ptr; + break; + + default: + res = CURLSHE_BAD_OPTION; + break; + } + + va_end(param); + + return res; +} + +CURLSHcode +curl_share_cleanup(struct Curl_share *share) +{ + if(!GOOD_SHARE_HANDLE(share)) + return CURLSHE_INVALID; + + if(share->lockfunc) + share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE, + share->clientdata); + + if(share->dirty) { + if(share->unlockfunc) + share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); + return CURLSHE_IN_USE; + } + + Curl_conncache_close_all_connections(&share->conn_cache); + Curl_conncache_destroy(&share->conn_cache); + Curl_hash_destroy(&share->hostcache); + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + Curl_cookie_cleanup(share->cookies); +#endif + +#ifndef CURL_DISABLE_HSTS + Curl_hsts_cleanup(&share->hsts); +#endif + +#ifdef USE_SSL + if(share->sslsession) { + size_t i; + for(i = 0; i < share->max_ssl_sessions; i++) + Curl_ssl_kill_session(&(share->sslsession[i])); + free(share->sslsession); + } +#endif + + Curl_psl_destroy(&share->psl); + + if(share->unlockfunc) + share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); + share->magic = 0; + free(share); + + return CURLSHE_OK; +} + + +CURLSHcode +Curl_share_lock(struct Curl_easy *data, curl_lock_data type, + curl_lock_access accesstype) +{ + struct Curl_share *share = data->share; + + if(!share) + return CURLSHE_INVALID; + + if(share->specifier & (unsigned int)(1<lockfunc) /* only call this if set! */ + share->lockfunc(data, type, accesstype, share->clientdata); + } + /* else if we don't share this, pretend successful lock */ + + return CURLSHE_OK; +} + +CURLSHcode +Curl_share_unlock(struct Curl_easy *data, curl_lock_data type) +{ + struct Curl_share *share = data->share; + + if(!share) + return CURLSHE_INVALID; + + if(share->specifier & (unsigned int)(1<unlockfunc) /* only call this if set! */ + share->unlockfunc (data, type, share->clientdata); + } + + return CURLSHE_OK; +} diff --git a/lib/share.h b/lib/share.h new file mode 100644 index 0000000..632d919 --- /dev/null +++ b/lib/share.h @@ -0,0 +1,68 @@ +#ifndef HEADER_CURL_SHARE_H +#define HEADER_CURL_SHARE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include +#include "cookie.h" +#include "psl.h" +#include "urldata.h" +#include "conncache.h" + +#define CURL_GOOD_SHARE 0x7e117a1e +#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE) + +/* this struct is libcurl-private, don't export details */ +struct Curl_share { + unsigned int magic; /* CURL_GOOD_SHARE */ + unsigned int specifier; + volatile unsigned int dirty; + + curl_lock_function lockfunc; + curl_unlock_function unlockfunc; + void *clientdata; + struct conncache conn_cache; + struct Curl_hash hostcache; +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + struct CookieInfo *cookies; +#endif +#ifdef USE_LIBPSL + struct PslCache psl; +#endif +#ifndef CURL_DISABLE_HSTS + struct hsts *hsts; +#endif +#ifdef USE_SSL + struct Curl_ssl_session *sslsession; + size_t max_ssl_sessions; + long sessionage; +#endif +}; + +CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data, + curl_lock_access); +CURLSHcode Curl_share_unlock(struct Curl_easy *, curl_lock_data); + +#endif /* HEADER_CURL_SHARE_H */ diff --git a/lib/sigpipe.h b/lib/sigpipe.h new file mode 100644 index 0000000..9b29403 --- /dev/null +++ b/lib/sigpipe.h @@ -0,0 +1,80 @@ +#ifndef HEADER_CURL_SIGPIPE_H +#define HEADER_CURL_SIGPIPE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(HAVE_SIGACTION) && \ + (defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL)) +#include + +struct sigpipe_ignore { + struct sigaction old_pipe_act; + bool no_signal; +}; + +#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x + +/* + * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl + * internals, and then sigpipe_restore() will restore the situation when we + * return from libcurl again. + */ +static void sigpipe_ignore(struct Curl_easy *data, + struct sigpipe_ignore *ig) +{ + /* get a local copy of no_signal because the Curl_easy might not be + around when we restore */ + ig->no_signal = data->set.no_signal; + if(!data->set.no_signal) { + struct sigaction action; + /* first, extract the existing situation */ + sigaction(SIGPIPE, NULL, &ig->old_pipe_act); + action = ig->old_pipe_act; + /* ignore this signal */ + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + } +} + +/* + * sigpipe_restore() puts back the outside world's opinion of signal handler + * and SIGPIPE handling. It MUST only be called after a corresponding + * sigpipe_ignore() was used. + */ +static void sigpipe_restore(struct sigpipe_ignore *ig) +{ + if(!ig->no_signal) + /* restore the outside state */ + sigaction(SIGPIPE, &ig->old_pipe_act, NULL); +} + +#else +/* for systems without sigaction */ +#define sigpipe_ignore(x,y) Curl_nop_stmt +#define sigpipe_restore(x) Curl_nop_stmt +#define SIGPIPE_VARIABLE(x) +#endif + +#endif /* HEADER_CURL_SIGPIPE_H */ diff --git a/lib/slist.c b/lib/slist.c new file mode 100644 index 0000000..366b247 --- /dev/null +++ b/lib/slist.c @@ -0,0 +1,146 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "slist.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* returns last node in linked list */ +static struct curl_slist *slist_get_last(struct curl_slist *list) +{ + struct curl_slist *item; + + /* if caller passed us a NULL, return now */ + if(!list) + return NULL; + + /* loop through to find the last item */ + item = list; + while(item->next) { + item = item->next; + } + return item; +} + +/* + * Curl_slist_append_nodup() appends a string to the linked list. Rather than + * copying the string in dynamic storage, it takes its ownership. The string + * should have been malloc()ated. Curl_slist_append_nodup always returns + * the address of the first record, so that you can use this function as an + * initialization function as well as an append function. + * If an error occurs, NULL is returned and the string argument is NOT + * released. + */ +struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data) +{ + struct curl_slist *last; + struct curl_slist *new_item; + + DEBUGASSERT(data); + + new_item = malloc(sizeof(struct curl_slist)); + if(!new_item) + return NULL; + + new_item->next = NULL; + new_item->data = data; + + /* if this is the first item, then new_item *is* the list */ + if(!list) + return new_item; + + last = slist_get_last(list); + last->next = new_item; + return list; +} + +/* + * curl_slist_append() appends a string to the linked list. It always returns + * the address of the first record, so that you can use this function as an + * initialization function as well as an append function. If you find this + * bothersome, then simply create a separate _init function and call it + * appropriately from within the program. + */ +struct curl_slist *curl_slist_append(struct curl_slist *list, + const char *data) +{ + char *dupdata = strdup(data); + + if(!dupdata) + return NULL; + + list = Curl_slist_append_nodup(list, dupdata); + if(!list) + free(dupdata); + + return list; +} + +/* + * Curl_slist_duplicate() duplicates a linked list. It always returns the + * address of the first record of the cloned list or NULL in case of an + * error (or if the input list was NULL). + */ +struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist) +{ + struct curl_slist *outlist = NULL; + struct curl_slist *tmp; + + while(inlist) { + tmp = curl_slist_append(outlist, inlist->data); + + if(!tmp) { + curl_slist_free_all(outlist); + return NULL; + } + + outlist = tmp; + inlist = inlist->next; + } + return outlist; +} + +/* be nice and clean up resources */ +void curl_slist_free_all(struct curl_slist *list) +{ + struct curl_slist *next; + struct curl_slist *item; + + if(!list) + return; + + item = list; + do { + next = item->next; + Curl_safefree(item->data); + free(item); + item = next; + } while(next); +} diff --git a/lib/slist.h b/lib/slist.h new file mode 100644 index 0000000..9561fd0 --- /dev/null +++ b/lib/slist.h @@ -0,0 +1,41 @@ +#ifndef HEADER_CURL_SLIST_H +#define HEADER_CURL_SLIST_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Curl_slist_duplicate() duplicates a linked list. It always returns the + * address of the first record of the cloned list or NULL in case of an + * error (or if the input list was NULL). + */ +struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist); + +/* + * Curl_slist_append_nodup() takes ownership of the given string and appends + * it to the list. + */ +struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, + char *data); + +#endif /* HEADER_CURL_SLIST_H */ diff --git a/lib/smb.c b/lib/smb.c new file mode 100644 index 0000000..1d1867c --- /dev/null +++ b/lib/smb.c @@ -0,0 +1,1203 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Bill Nagel , Exacq Technologies + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) + +#ifdef _WIN32 +#define getpid GetCurrentProcessId +#endif + +#include "smb.h" +#include "urldata.h" +#include "sendf.h" +#include "multiif.h" +#include "cfilters.h" +#include "connect.h" +#include "progress.h" +#include "transfer.h" +#include "vtls/vtls.h" +#include "curl_ntlm_core.h" +#include "escape.h" +#include "curl_endian.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Definitions for SMB protocol data structures + */ +#if defined(_MSC_VER) || defined(__ILEC400__) +# define PACK +# pragma pack(push) +# pragma pack(1) +#elif defined(__GNUC__) +# define PACK __attribute__((packed)) +#else +# define PACK +#endif + +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_READ_ANDX 0x2e +#define SMB_COM_WRITE_ANDX 0x2f +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SETUP_ANDX 0x73 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_NT_CREATE_ANDX 0xa2 +#define SMB_COM_NO_ANDX_COMMAND 0xff + +#define SMB_WC_CLOSE 0x03 +#define SMB_WC_READ_ANDX 0x0c +#define SMB_WC_WRITE_ANDX 0x0e +#define SMB_WC_SETUP_ANDX 0x0d +#define SMB_WC_TREE_CONNECT_ANDX 0x04 +#define SMB_WC_NT_CREATE_ANDX 0x18 + +#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 +#define SMB_FLAGS_CASELESS_PATHNAMES 0x08 +#define SMB_FLAGS2_UNICODE_STRINGS 0x8000 +#define SMB_FLAGS2_IS_LONG_NAME 0x0040 +#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 + +#define SMB_CAP_LARGE_FILES 0x08 +#define SMB_GENERIC_WRITE 0x40000000 +#define SMB_GENERIC_READ 0x80000000 +#define SMB_FILE_SHARE_ALL 0x07 +#define SMB_FILE_OPEN 0x01 +#define SMB_FILE_OVERWRITE_IF 0x05 + +#define SMB_ERR_NOACCESS 0x00050001 + +struct smb_header { + unsigned char nbt_type; + unsigned char nbt_flags; + unsigned short nbt_length; + unsigned char magic[4]; + unsigned char command; + unsigned int status; + unsigned char flags; + unsigned short flags2; + unsigned short pid_high; + unsigned char signature[8]; + unsigned short pad; + unsigned short tid; + unsigned short pid; + unsigned short uid; + unsigned short mid; +} PACK; + +struct smb_negotiate_response { + struct smb_header h; + unsigned char word_count; + unsigned short dialect_index; + unsigned char security_mode; + unsigned short max_mpx_count; + unsigned short max_number_vcs; + unsigned int max_buffer_size; + unsigned int max_raw_size; + unsigned int session_key; + unsigned int capabilities; + unsigned int system_time_low; + unsigned int system_time_high; + unsigned short server_time_zone; + unsigned char encryption_key_length; + unsigned short byte_count; + char bytes[1]; +} PACK; + +struct andx { + unsigned char command; + unsigned char pad; + unsigned short offset; +} PACK; + +struct smb_setup { + unsigned char word_count; + struct andx andx; + unsigned short max_buffer_size; + unsigned short max_mpx_count; + unsigned short vc_number; + unsigned int session_key; + unsigned short lengths[2]; + unsigned int pad; + unsigned int capabilities; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_tree_connect { + unsigned char word_count; + struct andx andx; + unsigned short flags; + unsigned short pw_len; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create { + unsigned char word_count; + struct andx andx; + unsigned char pad; + unsigned short name_length; + unsigned int flags; + unsigned int root_fid; + unsigned int access; + curl_off_t allocation_size; + unsigned int ext_file_attributes; + unsigned int share_access; + unsigned int create_disposition; + unsigned int create_options; + unsigned int impersonation_level; + unsigned char security_flags; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create_response { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned char op_lock_level; + unsigned short fid; + unsigned int create_disposition; + + curl_off_t create_time; + curl_off_t last_access_time; + curl_off_t last_write_time; + curl_off_t last_change_time; + unsigned int ext_file_attributes; + curl_off_t allocation_size; + curl_off_t end_of_file; +} PACK; + +struct smb_read { + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned short max_bytes; + unsigned short min_bytes; + unsigned int timeout; + unsigned short remaining; + unsigned int offset_high; + unsigned short byte_count; +} PACK; + +struct smb_write { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned int timeout; + unsigned short write_mode; + unsigned short remaining; + unsigned short pad; + unsigned short data_length; + unsigned short data_offset; + unsigned int offset_high; + unsigned short byte_count; + unsigned char pad2; +} PACK; + +struct smb_close { + unsigned char word_count; + unsigned short fid; + unsigned int last_mtime; + unsigned short byte_count; +} PACK; + +struct smb_tree_disconnect { + unsigned char word_count; + unsigned short byte_count; +} PACK; + +#if defined(_MSC_VER) || defined(__ILEC400__) +# pragma pack(pop) +#endif + +/* Local API functions */ +static CURLcode smb_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static CURLcode smb_connect(struct Curl_easy *data, bool *done); +static CURLcode smb_connection_state(struct Curl_easy *data, bool *done); +static CURLcode smb_do(struct Curl_easy *data, bool *done); +static CURLcode smb_request_state(struct Curl_easy *data, bool *done); +static CURLcode smb_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); +static int smb_getsock(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks); +static CURLcode smb_parse_url_path(struct Curl_easy *data, + struct connectdata *conn); + +/* + * SMB handler interface + */ +const struct Curl_handler Curl_handler_smb = { + "SMB", /* scheme */ + smb_setup_connection, /* setup_connection */ + smb_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ + smb_request_state, /* doing */ + smb_getsock, /* proto_getsock */ + smb_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smb_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SMB, /* defport */ + CURLPROTO_SMB, /* protocol */ + CURLPROTO_SMB, /* family */ + PROTOPT_NONE /* flags */ +}; + +#ifdef USE_SSL +/* + * SMBS handler interface + */ +const struct Curl_handler Curl_handler_smbs = { + "SMBS", /* scheme */ + smb_setup_connection, /* setup_connection */ + smb_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ + smb_request_state, /* doing */ + smb_getsock, /* proto_getsock */ + smb_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smb_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SMBS, /* defport */ + CURLPROTO_SMBS, /* protocol */ + CURLPROTO_SMB, /* family */ + PROTOPT_SSL /* flags */ +}; +#endif + +#define MAX_PAYLOAD_SIZE 0x8000 +#define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) +#define CLIENTNAME "curl" +#define SERVICENAME "?????" + +/* Append a string to an SMB message */ +#define MSGCAT(str) \ + do { \ + strcpy(p, (str)); \ + p += strlen(str); \ + } while(0) + +/* Append a null-terminated string to an SMB message */ +#define MSGCATNULL(str) \ + do { \ + strcpy(p, (str)); \ + p += strlen(str) + 1; \ + } while(0) + +/* SMB is mostly little endian */ +#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ + defined(__OS400__) +static unsigned short smb_swap16(unsigned short x) +{ + return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); +} + +static unsigned int smb_swap32(unsigned int x) +{ + return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | + ((x >> 24) & 0xff); +} + +static curl_off_t smb_swap64(curl_off_t x) +{ + return ((curl_off_t) smb_swap32((unsigned int) x) << 32) | + smb_swap32((unsigned int) (x >> 32)); +} + +#else +# define smb_swap16(x) (x) +# define smb_swap32(x) (x) +# define smb_swap64(x) (x) +#endif + +/* SMB request state */ +enum smb_req_state { + SMB_REQUESTING, + SMB_TREE_CONNECT, + SMB_OPEN, + SMB_DOWNLOAD, + SMB_UPLOAD, + SMB_CLOSE, + SMB_TREE_DISCONNECT, + SMB_DONE +}; + +/* SMB request data */ +struct smb_request { + enum smb_req_state state; + char *path; + unsigned short tid; /* Even if we connect to the same tree as another */ + unsigned short fid; /* request, the tid will be different */ + CURLcode result; +}; + +static void conn_state(struct Curl_easy *data, enum smb_conn_state newstate) +{ + struct smb_conn *smbc = &data->conn->proto.smbc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* For debug purposes */ + static const char * const names[] = { + "SMB_NOT_CONNECTED", + "SMB_CONNECTING", + "SMB_NEGOTIATE", + "SMB_SETUP", + "SMB_CONNECTED", + /* LAST */ + }; + + if(smbc->state != newstate) + infof(data, "SMB conn %p state change from %s to %s", + (void *)smbc, names[smbc->state], names[newstate]); +#endif + + smbc->state = newstate; +} + +static void request_state(struct Curl_easy *data, + enum smb_req_state newstate) +{ + struct smb_request *req = data->req.p.smb; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* For debug purposes */ + static const char * const names[] = { + "SMB_REQUESTING", + "SMB_TREE_CONNECT", + "SMB_OPEN", + "SMB_DOWNLOAD", + "SMB_UPLOAD", + "SMB_CLOSE", + "SMB_TREE_DISCONNECT", + "SMB_DONE", + /* LAST */ + }; + + if(req->state != newstate) + infof(data, "SMB request %p state change from %s to %s", + (void *)req, names[req->state], names[newstate]); +#endif + + req->state = newstate; +} + +/* this should setup things in the connection, not in the easy + handle */ +static CURLcode smb_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + struct smb_request *req; + + /* Initialize the request state */ + data->req.p.smb = req = calloc(1, sizeof(struct smb_request)); + if(!req) + return CURLE_OUT_OF_MEMORY; + + /* Parse the URL path */ + return smb_parse_url_path(data, conn); +} + +static CURLcode smb_connect(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + char *slash; + + (void) done; + + /* Check we have a username and password to authenticate with */ + if(!data->state.aptr.user) + return CURLE_LOGIN_DENIED; + + /* Initialize the connection state */ + smbc->state = SMB_CONNECTING; + smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); + if(!smbc->recv_buf) + return CURLE_OUT_OF_MEMORY; + + /* Multiple requests are allowed with this connection */ + connkeep(conn, "SMB default"); + + /* Parse the username, domain, and password */ + slash = strchr(conn->user, '/'); + if(!slash) + slash = strchr(conn->user, '\\'); + + if(slash) { + smbc->user = slash + 1; + smbc->domain = strdup(conn->user); + if(!smbc->domain) + return CURLE_OUT_OF_MEMORY; + smbc->domain[slash - conn->user] = 0; + } + else { + smbc->user = conn->user; + smbc->domain = strdup(conn->host.name); + if(!smbc->domain) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +static CURLcode smb_recv_message(struct Curl_easy *data, void **msg) +{ + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + struct smb_conn *smbc = &conn->proto.smbc; + char *buf = smbc->recv_buf; + ssize_t bytes_read; + size_t nbt_size; + size_t msg_size; + size_t len = MAX_MESSAGE_SIZE - smbc->got; + CURLcode result; + + result = Curl_read(data, sockfd, buf + smbc->got, len, &bytes_read); + if(result) + return result; + + if(!bytes_read) + return CURLE_OK; + + smbc->got += bytes_read; + + /* Check for a 32-bit nbt header */ + if(smbc->got < sizeof(unsigned int)) + return CURLE_OK; + + nbt_size = Curl_read16_be((const unsigned char *) + (buf + sizeof(unsigned short))) + + sizeof(unsigned int); + if(smbc->got < nbt_size) + return CURLE_OK; + + msg_size = sizeof(struct smb_header); + if(nbt_size >= msg_size + 1) { + /* Add the word count */ + msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); + if(nbt_size >= msg_size + sizeof(unsigned short)) { + /* Add the byte count */ + msg_size += sizeof(unsigned short) + + Curl_read16_le((const unsigned char *)&buf[msg_size]); + if(nbt_size < msg_size) + return CURLE_READ_ERROR; + } + } + + *msg = buf; + + return CURLE_OK; +} + +static void smb_pop_message(struct connectdata *conn) +{ + struct smb_conn *smbc = &conn->proto.smbc; + + smbc->got = 0; +} + +static void smb_format_message(struct Curl_easy *data, struct smb_header *h, + unsigned char cmd, size_t len) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_request *req = data->req.p.smb; + unsigned int pid; + + memset(h, 0, sizeof(*h)); + h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + + len)); + memcpy((char *)h->magic, "\xffSMB", 4); + h->command = cmd; + h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; + h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); + h->uid = smb_swap16(smbc->uid); + h->tid = smb_swap16(req->tid); + pid = getpid(); + h->pid_high = smb_swap16((unsigned short)(pid >> 16)); + h->pid = smb_swap16((unsigned short) pid); +} + +static CURLcode smb_send(struct Curl_easy *data, ssize_t len, + size_t upload_size) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + ssize_t bytes_written; + CURLcode result; + + result = Curl_nwrite(data, FIRSTSOCKET, data->state.ulbuf, + len, &bytes_written); + if(result) + return result; + + if(bytes_written != len) { + smbc->send_size = len; + smbc->sent = bytes_written; + } + + smbc->upload_size = upload_size; + + return CURLE_OK; +} + +static CURLcode smb_flush(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + ssize_t bytes_written; + ssize_t len = smbc->send_size - smbc->sent; + CURLcode result; + + if(!smbc->send_size) + return CURLE_OK; + + result = Curl_nwrite(data, FIRSTSOCKET, + data->state.ulbuf + smbc->sent, + len, &bytes_written); + if(result) + return result; + + if(bytes_written != len) + smbc->sent += bytes_written; + else + smbc->send_size = 0; + + return CURLE_OK; +} + +static CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd, + const void *msg, size_t msg_len) +{ + CURLcode result = Curl_get_upload_buffer(data); + if(result) + return result; + smb_format_message(data, (struct smb_header *)data->state.ulbuf, + cmd, msg_len); + memcpy(data->state.ulbuf + sizeof(struct smb_header), + msg, msg_len); + + return smb_send(data, sizeof(struct smb_header) + msg_len, 0); +} + +static CURLcode smb_send_negotiate(struct Curl_easy *data) +{ + const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; + + return smb_send_message(data, SMB_COM_NEGOTIATE, msg, 15); +} + +static CURLcode smb_send_setup(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_setup msg; + char *p = msg.bytes; + unsigned char lm_hash[21]; + unsigned char lm[24]; + unsigned char nt_hash[21]; + unsigned char nt[24]; + + size_t byte_count = sizeof(lm) + sizeof(nt); + byte_count += strlen(smbc->user) + strlen(smbc->domain); + byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ + if(byte_count > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + Curl_ntlm_core_mk_lm_hash(conn->passwd, lm_hash); + Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); + Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash); + Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_SETUP_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); + msg.max_mpx_count = smb_swap16(1); + msg.vc_number = smb_swap16(1); + msg.session_key = smb_swap32(smbc->session_key); + msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); + msg.lengths[0] = smb_swap16(sizeof(lm)); + msg.lengths[1] = smb_swap16(sizeof(nt)); + memcpy(p, lm, sizeof(lm)); + p += sizeof(lm); + memcpy(p, nt, sizeof(nt)); + p += sizeof(nt); + MSGCATNULL(smbc->user); + MSGCATNULL(smbc->domain); + MSGCATNULL(OS); + MSGCATNULL(CLIENTNAME); + byte_count = p - msg.bytes; + msg.byte_count = smb_swap16((unsigned short)byte_count); + + return smb_send_message(data, SMB_COM_SETUP_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_tree_connect(struct Curl_easy *data) +{ + struct smb_tree_connect msg; + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + char *p = msg.bytes; + + size_t byte_count = strlen(conn->host.name) + strlen(smbc->share); + byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ + if(byte_count > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_TREE_CONNECT_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.pw_len = 0; + MSGCAT("\\\\"); + MSGCAT(conn->host.name); + MSGCAT("\\"); + MSGCATNULL(smbc->share); + MSGCATNULL(SERVICENAME); /* Match any type of service */ + byte_count = p - msg.bytes; + msg.byte_count = smb_swap16((unsigned short)byte_count); + + return smb_send_message(data, SMB_COM_TREE_CONNECT_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_open(struct Curl_easy *data) +{ + struct smb_request *req = data->req.p.smb; + struct smb_nt_create msg; + size_t byte_count; + + if((strlen(req->path) + 1) > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_NT_CREATE_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + byte_count = strlen(req->path); + msg.name_length = smb_swap16((unsigned short)byte_count); + msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); + if(data->state.upload) { + msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); + msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); + } + else { + msg.access = smb_swap32(SMB_GENERIC_READ); + msg.create_disposition = smb_swap32(SMB_FILE_OPEN); + } + msg.byte_count = smb_swap16((unsigned short) ++byte_count); + strcpy(msg.bytes, req->path); + + return smb_send_message(data, SMB_COM_NT_CREATE_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_close(struct Curl_easy *data) +{ + struct smb_request *req = data->req.p.smb; + struct smb_close msg; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_CLOSE; + msg.fid = smb_swap16(req->fid); + + return smb_send_message(data, SMB_COM_CLOSE, &msg, sizeof(msg)); +} + +static CURLcode smb_send_tree_disconnect(struct Curl_easy *data) +{ + struct smb_tree_disconnect msg; + + memset(&msg, 0, sizeof(msg)); + + return smb_send_message(data, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg)); +} + +static CURLcode smb_send_read(struct Curl_easy *data) +{ + struct smb_request *req = data->req.p.smb; + curl_off_t offset = data->req.offset; + struct smb_read msg; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_READ_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.fid = smb_swap16(req->fid); + msg.offset = smb_swap32((unsigned int) offset); + msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); + msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); + msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); + + return smb_send_message(data, SMB_COM_READ_ANDX, &msg, sizeof(msg)); +} + +static CURLcode smb_send_write(struct Curl_easy *data) +{ + struct smb_write *msg; + struct smb_request *req = data->req.p.smb; + curl_off_t offset = data->req.offset; + curl_off_t upload_size = data->req.size - data->req.bytecount; + CURLcode result = Curl_get_upload_buffer(data); + if(result) + return result; + msg = (struct smb_write *)data->state.ulbuf; + + if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ + upload_size = MAX_PAYLOAD_SIZE - 1; + + memset(msg, 0, sizeof(*msg)); + msg->word_count = SMB_WC_WRITE_ANDX; + msg->andx.command = SMB_COM_NO_ANDX_COMMAND; + msg->fid = smb_swap16(req->fid); + msg->offset = smb_swap32((unsigned int) offset); + msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); + msg->data_length = smb_swap16((unsigned short) upload_size); + msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); + msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); + + smb_format_message(data, &msg->h, SMB_COM_WRITE_ANDX, + sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); + + return smb_send(data, sizeof(*msg), (size_t) upload_size); +} + +static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + CURLcode result; + *msg = NULL; /* if it returns early */ + + /* Check if there is data in the transfer buffer */ + if(!smbc->send_size && smbc->upload_size) { + size_t nread = smbc->upload_size > (size_t)data->set.upload_buffer_size ? + (size_t)data->set.upload_buffer_size : smbc->upload_size; + data->req.upload_fromhere = data->state.ulbuf; + result = Curl_fillreadbuffer(data, nread, &nread); + if(result && result != CURLE_AGAIN) + return result; + if(!nread) + return CURLE_OK; + + smbc->upload_size -= nread; + smbc->send_size = nread; + smbc->sent = 0; + } + + /* Check if there is data to send */ + if(smbc->send_size) { + result = smb_flush(data); + if(result) + return result; + } + + /* Check if there is still data to be sent */ + if(smbc->send_size || smbc->upload_size) + return CURLE_AGAIN; + + return smb_recv_message(data, msg); +} + +static CURLcode smb_connection_state(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_negotiate_response *nrsp; + struct smb_header *h; + CURLcode result; + void *msg = NULL; + + if(smbc->state == SMB_CONNECTING) { +#ifdef USE_SSL + if((conn->handler->flags & PROTOPT_SSL)) { + bool ssl_done = FALSE; + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssl_done); + if(result && result != CURLE_AGAIN) + return result; + if(!ssl_done) + return CURLE_OK; + } +#endif + + result = smb_send_negotiate(data); + if(result) { + connclose(conn, "SMB: failed to send negotiate message"); + return result; + } + + conn_state(data, SMB_NEGOTIATE); + } + + /* Send the previous message and check for a response */ + result = smb_send_and_recv(data, &msg); + if(result && result != CURLE_AGAIN) { + connclose(conn, "SMB: failed to communicate"); + return result; + } + + if(!msg) + return CURLE_OK; + + h = msg; + + switch(smbc->state) { + case SMB_NEGOTIATE: + if((smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) || + h->status) { + connclose(conn, "SMB: negotiation failed"); + return CURLE_COULDNT_CONNECT; + } + nrsp = msg; + memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); + smbc->session_key = smb_swap32(nrsp->session_key); + result = smb_send_setup(data); + if(result) { + connclose(conn, "SMB: failed to send setup message"); + return result; + } + conn_state(data, SMB_SETUP); + break; + + case SMB_SETUP: + if(h->status) { + connclose(conn, "SMB: authentication failed"); + return CURLE_LOGIN_DENIED; + } + smbc->uid = smb_swap16(h->uid); + conn_state(data, SMB_CONNECTED); + *done = true; + break; + + default: + smb_pop_message(conn); + return CURLE_OK; /* ignore */ + } + + smb_pop_message(conn); + + return CURLE_OK; +} + +/* + * Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601) + * to Posix time. Cap the output to fit within a time_t. + */ +static void get_posix_time(time_t *out, curl_off_t timestamp) +{ + timestamp -= 116444736000000000; + timestamp /= 10000000; +#if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T + if(timestamp > TIME_T_MAX) + *out = TIME_T_MAX; + else if(timestamp < TIME_T_MIN) + *out = TIME_T_MIN; + else +#endif + *out = (time_t) timestamp; +} + +static CURLcode smb_request_state(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct smb_request *req = data->req.p.smb; + struct smb_header *h; + struct smb_conn *smbc = &conn->proto.smbc; + enum smb_req_state next_state = SMB_DONE; + unsigned short len; + unsigned short off; + CURLcode result; + void *msg = NULL; + const struct smb_nt_create_response *smb_m; + + if(data->state.upload && (data->state.infilesize < 0)) { + failf(data, "SMB upload needs to know the size up front"); + return CURLE_SEND_ERROR; + } + + /* Start the request */ + if(req->state == SMB_REQUESTING) { + result = smb_send_tree_connect(data); + if(result) { + connclose(conn, "SMB: failed to send tree connect message"); + return result; + } + + request_state(data, SMB_TREE_CONNECT); + } + + /* Send the previous message and check for a response */ + result = smb_send_and_recv(data, &msg); + if(result && result != CURLE_AGAIN) { + connclose(conn, "SMB: failed to communicate"); + return result; + } + + if(!msg) + return CURLE_OK; + + h = msg; + + switch(req->state) { + case SMB_TREE_CONNECT: + if(h->status) { + req->result = CURLE_REMOTE_FILE_NOT_FOUND; + if(h->status == smb_swap32(SMB_ERR_NOACCESS)) + req->result = CURLE_REMOTE_ACCESS_DENIED; + break; + } + req->tid = smb_swap16(h->tid); + next_state = SMB_OPEN; + break; + + case SMB_OPEN: + if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { + req->result = CURLE_REMOTE_FILE_NOT_FOUND; + if(h->status == smb_swap32(SMB_ERR_NOACCESS)) + req->result = CURLE_REMOTE_ACCESS_DENIED; + next_state = SMB_TREE_DISCONNECT; + break; + } + smb_m = (const struct smb_nt_create_response*) msg; + req->fid = smb_swap16(smb_m->fid); + data->req.offset = 0; + if(data->state.upload) { + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->req.size); + next_state = SMB_UPLOAD; + } + else { + data->req.size = smb_swap64(smb_m->end_of_file); + if(data->req.size < 0) { + req->result = CURLE_WEIRD_SERVER_REPLY; + next_state = SMB_CLOSE; + } + else { + Curl_pgrsSetDownloadSize(data, data->req.size); + if(data->set.get_filetime) + get_posix_time(&data->info.filetime, smb_m->last_change_time); + next_state = SMB_DOWNLOAD; + } + } + break; + + case SMB_DOWNLOAD: + if(h->status || smbc->got < sizeof(struct smb_header) + 14) { + req->result = CURLE_RECV_ERROR; + next_state = SMB_CLOSE; + break; + } + len = Curl_read16_le(((const unsigned char *) msg) + + sizeof(struct smb_header) + 11); + off = Curl_read16_le(((const unsigned char *) msg) + + sizeof(struct smb_header) + 13); + if(len > 0) { + if(off + sizeof(unsigned int) + len > smbc->got) { + failf(data, "Invalid input packet"); + result = CURLE_RECV_ERROR; + } + else + result = Curl_client_write(data, CLIENTWRITE_BODY, + (char *)msg + off + sizeof(unsigned int), + len); + if(result) { + req->result = result; + next_state = SMB_CLOSE; + break; + } + } + data->req.offset += len; + next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; + break; + + case SMB_UPLOAD: + if(h->status || smbc->got < sizeof(struct smb_header) + 6) { + req->result = CURLE_UPLOAD_FAILED; + next_state = SMB_CLOSE; + break; + } + len = Curl_read16_le(((const unsigned char *) msg) + + sizeof(struct smb_header) + 5); + data->req.bytecount += len; + data->req.offset += len; + Curl_pgrsSetUploadCounter(data, data->req.bytecount); + if(data->req.bytecount >= data->req.size) + next_state = SMB_CLOSE; + else + next_state = SMB_UPLOAD; + break; + + case SMB_CLOSE: + /* We don't care if the close failed, proceed to tree disconnect anyway */ + next_state = SMB_TREE_DISCONNECT; + break; + + case SMB_TREE_DISCONNECT: + next_state = SMB_DONE; + break; + + default: + smb_pop_message(conn); + return CURLE_OK; /* ignore */ + } + + smb_pop_message(conn); + + switch(next_state) { + case SMB_OPEN: + result = smb_send_open(data); + break; + + case SMB_DOWNLOAD: + result = smb_send_read(data); + break; + + case SMB_UPLOAD: + result = smb_send_write(data); + break; + + case SMB_CLOSE: + result = smb_send_close(data); + break; + + case SMB_TREE_DISCONNECT: + result = smb_send_tree_disconnect(data); + break; + + case SMB_DONE: + result = req->result; + *done = true; + break; + + default: + break; + } + + if(result) { + connclose(conn, "SMB: failed to send message"); + return result; + } + + request_state(data, next_state); + + return CURLE_OK; +} + +static CURLcode smb_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead) +{ + struct smb_conn *smbc = &conn->proto.smbc; + (void) dead; + (void) data; + Curl_safefree(smbc->share); + Curl_safefree(smbc->domain); + Curl_safefree(smbc->recv_buf); + return CURLE_OK; +} + +static int smb_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks) +{ + (void)data; + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0); +} + +static CURLcode smb_do(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct smb_conn *smbc = &conn->proto.smbc; + + *done = FALSE; + if(smbc->share) { + return CURLE_OK; + } + return CURLE_URL_MALFORMAT; +} + +static CURLcode smb_parse_url_path(struct Curl_easy *data, + struct connectdata *conn) +{ + struct smb_request *req = data->req.p.smb; + struct smb_conn *smbc = &conn->proto.smbc; + char *path; + char *slash; + + /* URL decode the path */ + CURLcode result = Curl_urldecode(data->state.up.path, 0, &path, NULL, + REJECT_CTRL); + if(result) + return result; + + /* Parse the path for the share */ + smbc->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); + free(path); + if(!smbc->share) + return CURLE_OUT_OF_MEMORY; + + slash = strchr(smbc->share, '/'); + if(!slash) + slash = strchr(smbc->share, '\\'); + + /* The share must be present */ + if(!slash) { + Curl_safefree(smbc->share); + failf(data, "missing share in URL path for SMB"); + return CURLE_URL_MALFORMAT; + } + + /* Parse the path for the file path converting any forward slashes into + backslashes */ + *slash++ = 0; + req->path = slash; + + for(; *slash; slash++) { + if(*slash == '/') + *slash = '\\'; + } + return CURLE_OK; +} + +#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && + SIZEOF_CURL_OFF_T > 4 */ diff --git a/lib/smb.h b/lib/smb.h new file mode 100644 index 0000000..437f4a5 --- /dev/null +++ b/lib/smb.h @@ -0,0 +1,60 @@ +#ifndef HEADER_CURL_SMB_H +#define HEADER_CURL_SMB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Bill Nagel , Exacq Technologies + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +enum smb_conn_state { + SMB_NOT_CONNECTED = 0, + SMB_CONNECTING, + SMB_NEGOTIATE, + SMB_SETUP, + SMB_CONNECTED +}; + +struct smb_conn { + enum smb_conn_state state; + char *user; + char *domain; + char *share; + unsigned char challenge[8]; + unsigned int session_key; + unsigned short uid; + char *recv_buf; + size_t upload_size; + size_t send_size; + size_t sent; + size_t got; +}; + +#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \ + (SIZEOF_CURL_OFF_T > 4) + +extern const struct Curl_handler Curl_handler_smb; +extern const struct Curl_handler Curl_handler_smbs; + +#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && + SIZEOF_CURL_OFF_T > 4 */ + +#endif /* HEADER_CURL_SMB_H */ diff --git a/lib/smtp.c b/lib/smtp.c new file mode 100644 index 0000000..bfe7b8f --- /dev/null +++ b/lib/smtp.c @@ -0,0 +1,1925 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC1870 SMTP Service Extension for Message Size + * RFC2195 CRAM-MD5 authentication + * RFC2831 DIGEST-MD5 authentication + * RFC3207 SMTP over TLS + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4616 PLAIN authentication + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * RFC4954 SMTP Authentication + * RFC5321 SMTP protocol + * RFC5890 Internationalized Domain Names for Applications (IDNA) + * RFC6531 SMTP Extension for Internationalized Email + * RFC6532 Internationalized Email Headers + * RFC6749 OAuth 2.0 Authorization Framework + * RFC8314 Use of TLS for Email Submission and Access + * Draft SMTP URL Interface + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_SMTP + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "mime.h" +#include "socks.h" +#include "smtp.h" +#include "strtoofft.h" +#include "strcase.h" +#include "vtls/vtls.h" +#include "cfilters.h" +#include "connect.h" +#include "select.h" +#include "multiif.h" +#include "url.h" +#include "curl_gethostname.h" +#include "bufref.h" +#include "curl_sasl.h" +#include "warnless.h" +#include "idn.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* Local API functions */ +static CURLcode smtp_regular_transfer(struct Curl_easy *data, bool *done); +static CURLcode smtp_do(struct Curl_easy *data, bool *done); +static CURLcode smtp_done(struct Curl_easy *data, CURLcode status, + bool premature); +static CURLcode smtp_connect(struct Curl_easy *data, bool *done); +static CURLcode smtp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); +static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done); +static int smtp_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); +static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done); +static CURLcode smtp_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static CURLcode smtp_parse_url_options(struct connectdata *conn); +static CURLcode smtp_parse_url_path(struct Curl_easy *data); +static CURLcode smtp_parse_custom_request(struct Curl_easy *data); +static CURLcode smtp_parse_address(const char *fqma, + char **address, struct hostname *host); +static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out); + +/* + * SMTP protocol handler. + */ + +const struct Curl_handler Curl_handler_smtp = { + "SMTP", /* scheme */ + smtp_setup_connection, /* setup_connection */ + smtp_do, /* do_it */ + smtp_done, /* done */ + ZERO_NULL, /* do_more */ + smtp_connect, /* connect_it */ + smtp_multi_statemach, /* connecting */ + smtp_doing, /* doing */ + smtp_getsock, /* proto_getsock */ + smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smtp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SMTP, /* defport */ + CURLPROTO_SMTP, /* protocol */ + CURLPROTO_SMTP, /* family */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ + PROTOPT_URLOPTIONS +}; + +#ifdef USE_SSL +/* + * SMTPS protocol handler. + */ + +const struct Curl_handler Curl_handler_smtps = { + "SMTPS", /* scheme */ + smtp_setup_connection, /* setup_connection */ + smtp_do, /* do_it */ + smtp_done, /* done */ + ZERO_NULL, /* do_more */ + smtp_connect, /* connect_it */ + smtp_multi_statemach, /* connecting */ + smtp_doing, /* doing */ + smtp_getsock, /* proto_getsock */ + smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smtp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SMTPS, /* defport */ + CURLPROTO_SMTPS, /* protocol */ + CURLPROTO_SMTP, /* family */ + PROTOPT_CLOSEACTION | PROTOPT_SSL + | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ +}; +#endif + +/* SASL parameters for the smtp protocol */ +static const struct SASLproto saslsmtp = { + "smtp", /* The service name */ + smtp_perform_auth, /* Send authentication command */ + smtp_continue_auth, /* Send authentication continuation */ + smtp_cancel_auth, /* Cancel authentication */ + smtp_get_message, /* Get SASL response message */ + 512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */ + 334, /* Code received when continuation is expected */ + 235, /* Code to receive upon authentication success */ + SASL_AUTH_DEFAULT, /* Default mechanisms */ + SASL_FLAG_BASE64 /* Configuration flags */ +}; + +#ifdef USE_SSL +static void smtp_to_smtps(struct connectdata *conn) +{ + /* Change the connection handler */ + conn->handler = &Curl_handler_smtps; + + /* Set the connection's upgraded to TLS flag */ + conn->bits.tls_upgraded = TRUE; +} +#else +#define smtp_to_smtps(x) Curl_nop_stmt +#endif + +/*********************************************************************** + * + * smtp_endofresp() + * + * Checks for an ending SMTP status code at the start of the given string, but + * also detects various capabilities from the EHLO response including the + * supported authentication mechanisms. + */ +static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn, + char *line, size_t len, int *resp) +{ + struct smtp_conn *smtpc = &conn->proto.smtpc; + bool result = FALSE; + (void)data; + + /* Nothing for us */ + if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2])) + return FALSE; + + /* Do we have a command response? This should be the response code followed + by a space and optionally some text as per RFC-5321 and as outlined in + Section 4. Examples of RFC-4954 but some email servers ignore this and + only send the response code instead as per Section 4.2. */ + if(line[3] == ' ' || len == 5) { + char tmpline[6]; + + result = TRUE; + memset(tmpline, '\0', sizeof(tmpline)); + memcpy(tmpline, line, (len == 5 ? 5 : 3)); + *resp = curlx_sltosi(strtol(tmpline, NULL, 10)); + + /* Make sure real server never sends internal value */ + if(*resp == 1) + *resp = 0; + } + /* Do we have a multiline (continuation) response? */ + else if(line[3] == '-' && + (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) { + result = TRUE; + *resp = 1; /* Internal response code */ + } + + return result; +} + +/*********************************************************************** + * + * smtp_get_message() + * + * Gets the authentication message from the response buffer. + */ +static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out) +{ + char *message = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf); + size_t len = data->conn->proto.smtpc.pp.nfinal; + + if(len > 4) { + /* Find the start of the message */ + len -= 4; + for(message += 4; *message == ' ' || *message == '\t'; message++, len--) + ; + + /* Find the end of the message */ + while(len--) + if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && + message[len] != '\t') + break; + + /* Terminate the message */ + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); + } + else + /* junk input => zero length output */ + Curl_bufref_set(out, "", 0, NULL); + + return CURLE_OK; +} + +/*********************************************************************** + * + * smtp_state() + * + * This is the ONLY way to change SMTP state! + */ +static void smtp_state(struct Curl_easy *data, smtpstate newstate) +{ + struct smtp_conn *smtpc = &data->conn->proto.smtpc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[] = { + "STOP", + "SERVERGREET", + "EHLO", + "HELO", + "STARTTLS", + "UPGRADETLS", + "AUTH", + "COMMAND", + "MAIL", + "RCPT", + "DATA", + "POSTDATA", + "QUIT", + /* LAST */ + }; + + if(smtpc->state != newstate) + infof(data, "SMTP %p state change from %s to %s", + (void *)smtpc, names[smtpc->state], names[newstate]); +#endif + + smtpc->state = newstate; +} + +/*********************************************************************** + * + * smtp_perform_ehlo() + * + * Sends the EHLO command to not only initialise communication with the ESMTP + * server but to also obtain a list of server side supported capabilities. + */ +static CURLcode smtp_perform_ehlo(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct smtp_conn *smtpc = &conn->proto.smtpc; + + smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */ + smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism + used for esmtp connections */ + smtpc->tls_supported = FALSE; /* Clear the TLS capability */ + smtpc->auth_supported = FALSE; /* Clear the AUTH capability */ + + /* Send the EHLO command */ + result = Curl_pp_sendf(data, &smtpc->pp, "EHLO %s", smtpc->domain); + + if(!result) + smtp_state(data, SMTP_EHLO); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_helo() + * + * Sends the HELO command to initialise communication with the SMTP server. + */ +static CURLcode smtp_perform_helo(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + + smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used + in smtp connections */ + + /* Send the HELO command */ + result = Curl_pp_sendf(data, &smtpc->pp, "HELO %s", smtpc->domain); + + if(!result) + smtp_state(data, SMTP_HELO); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_starttls() + * + * Sends the STLS command to start the upgrade to TLS. + */ +static CURLcode smtp_perform_starttls(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Send the STARTTLS command */ + CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, + "%s", "STARTTLS"); + + if(!result) + smtp_state(data, SMTP_STARTTLS); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_upgrade_tls() + * + * Performs the upgrade to TLS. + */ +static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data) +{ + /* Start the SSL connection */ + struct connectdata *conn = data->conn; + struct smtp_conn *smtpc = &conn->proto.smtpc; + CURLcode result; + bool ssldone = FALSE; + + if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { + result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); + if(result) + goto out; + } + + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); + if(!result) { + smtpc->ssldone = ssldone; + if(smtpc->state != SMTP_UPGRADETLS) + smtp_state(data, SMTP_UPGRADETLS); + + if(smtpc->ssldone) { + smtp_to_smtps(conn); + result = smtp_perform_ehlo(data); + } + } +out: + return result; +} + +/*********************************************************************** + * + * smtp_perform_auth() + * + * Sends an AUTH command allowing the client to login with the given SASL + * authentication mechanism. + */ +static CURLcode smtp_perform_auth(struct Curl_easy *data, + const char *mech, + const struct bufref *initresp) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &data->conn->proto.smtpc; + const char *ir = (const char *) Curl_bufref_ptr(initresp); + + if(ir) { /* AUTH ... */ + /* Send the AUTH command with the initial response */ + result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, ir); + } + else { + /* Send the AUTH command */ + result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s", mech); + } + + return result; +} + +/*********************************************************************** + * + * smtp_continue_auth() + * + * Sends SASL continuation data. + */ +static CURLcode smtp_continue_auth(struct Curl_easy *data, + const char *mech, + const struct bufref *resp) +{ + struct smtp_conn *smtpc = &data->conn->proto.smtpc; + + (void)mech; + + return Curl_pp_sendf(data, &smtpc->pp, + "%s", (const char *) Curl_bufref_ptr(resp)); +} + +/*********************************************************************** + * + * smtp_cancel_auth() + * + * Sends SASL cancellation. + */ +static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech) +{ + struct smtp_conn *smtpc = &data->conn->proto.smtpc; + + (void)mech; + + return Curl_pp_sendf(data, &smtpc->pp, "*"); +} + +/*********************************************************************** + * + * smtp_perform_authentication() + * + * Initiates the authentication sequence, with the appropriate SASL + * authentication mechanism. + */ +static CURLcode smtp_perform_authentication(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct smtp_conn *smtpc = &conn->proto.smtpc; + saslprogress progress; + + /* Check we have enough data to authenticate with, and the + server supports authentication, and end the connect phase if not */ + if(!smtpc->auth_supported || + !Curl_sasl_can_authenticate(&smtpc->sasl, data)) { + smtp_state(data, SMTP_STOP); + return result; + } + + /* Calculate the SASL login details */ + result = Curl_sasl_start(&smtpc->sasl, data, FALSE, &progress); + + if(!result) { + if(progress == SASL_INPROGRESS) + smtp_state(data, SMTP_AUTH); + else { + /* Other mechanisms not supported */ + infof(data, "No known authentication mechanisms supported"); + result = CURLE_LOGIN_DENIED; + } + } + + return result; +} + +/*********************************************************************** + * + * smtp_perform_command() + * + * Sends a SMTP based command. + */ +static CURLcode smtp_perform_command(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct SMTP *smtp = data->req.p.smtp; + + if(smtp->rcpt) { + /* We notify the server we are sending UTF-8 data if a) it supports the + SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in + either the local address or host name parts. This is regardless of + whether the host name is encoded using IDN ACE */ + bool utf8 = FALSE; + + if((!smtp->custom) || (!smtp->custom[0])) { + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the mailbox to verify into the local address and host name + parts, converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(smtp->rcpt->data, + &address, &host); + if(result) + return result; + + /* Establish whether we should report SMTPUTF8 to the server for this + mailbox as per RFC-6531 sect. 3.1 point 6 */ + utf8 = (conn->proto.smtpc.utf8_supported) && + ((host.encalloc) || (!Curl_is_ASCII_name(address)) || + (!Curl_is_ASCII_name(host.name))); + + /* Send the VRFY command (Note: The host name part may be absent when the + host is a local system) */ + result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "VRFY %s%s%s%s", + address, + host.name ? "@" : "", + host.name ? host.name : "", + utf8 ? " SMTPUTF8" : ""); + + Curl_free_idnconverted_hostname(&host); + free(address); + } + else { + /* Establish whether we should report that we support SMTPUTF8 for EXPN + commands to the server as per RFC-6531 sect. 3.1 point 6 */ + utf8 = (conn->proto.smtpc.utf8_supported) && + (!strcmp(smtp->custom, "EXPN")); + + /* Send the custom recipient based command such as the EXPN command */ + result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, + "%s %s%s", smtp->custom, + smtp->rcpt->data, + utf8 ? " SMTPUTF8" : ""); + } + } + else + /* Send the non-recipient based command such as HELP */ + result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", + smtp->custom && smtp->custom[0] != '\0' ? + smtp->custom : "HELP"); + + if(!result) + smtp_state(data, SMTP_COMMAND); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_mail() + * + * Sends an MAIL command to initiate the upload of a message. + */ +static CURLcode smtp_perform_mail(struct Curl_easy *data) +{ + char *from = NULL; + char *auth = NULL; + char *size = NULL; + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + /* We notify the server we are sending UTF-8 data if a) it supports the + SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in + either the local address or host name parts. This is regardless of + whether the host name is encoded using IDN ACE */ + bool utf8 = FALSE; + + /* Calculate the FROM parameter */ + if(data->set.str[STRING_MAIL_FROM]) { + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the FROM mailbox into the local address and host name parts, + converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(data->set.str[STRING_MAIL_FROM], + &address, &host); + if(result) + return result; + + /* Establish whether we should report SMTPUTF8 to the server for this + mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */ + utf8 = (conn->proto.smtpc.utf8_supported) && + ((host.encalloc) || (!Curl_is_ASCII_name(address)) || + (!Curl_is_ASCII_name(host.name))); + + if(host.name) { + from = aprintf("<%s@%s>", address, host.name); + + Curl_free_idnconverted_hostname(&host); + } + else + /* An invalid mailbox was provided but we'll simply let the server worry + about that and reply with a 501 error */ + from = aprintf("<%s>", address); + + free(address); + } + else + /* Null reverse-path, RFC-5321, sect. 3.6.3 */ + from = strdup("<>"); + + if(!from) + return CURLE_OUT_OF_MEMORY; + + /* Calculate the optional AUTH parameter */ + if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) { + if(data->set.str[STRING_MAIL_AUTH][0] != '\0') { + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the AUTH mailbox into the local address and host name parts, + converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH], + &address, &host); + if(result) { + free(from); + return result; + } + + /* Establish whether we should report SMTPUTF8 to the server for this + mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */ + if((!utf8) && (conn->proto.smtpc.utf8_supported) && + ((host.encalloc) || (!Curl_is_ASCII_name(address)) || + (!Curl_is_ASCII_name(host.name)))) + utf8 = TRUE; + + if(host.name) { + auth = aprintf("<%s@%s>", address, host.name); + + Curl_free_idnconverted_hostname(&host); + } + else + /* An invalid mailbox was provided but we'll simply let the server + worry about it */ + auth = aprintf("<%s>", address); + + free(address); + } + else + /* Empty AUTH, RFC-2554, sect. 5 */ + auth = strdup("<>"); + + if(!auth) { + free(from); + + return CURLE_OUT_OF_MEMORY; + } + } + + /* Prepare the mime data if some. */ + if(data->set.mimepost.kind != MIMEKIND_NONE) { + /* Use the whole structure as data. */ + data->set.mimepost.flags &= ~MIME_BODY_ONLY; + + /* Add external headers and mime version. */ + curl_mime_headers(&data->set.mimepost, data->set.headers, 0); + result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL, + NULL, MIMESTRATEGY_MAIL); + + if(!result) + if(!Curl_checkheaders(data, STRCONST("Mime-Version"))) + result = Curl_mime_add_header(&data->set.mimepost.curlheaders, + "Mime-Version: 1.0"); + + /* Make sure we will read the entire mime structure. */ + if(!result) + result = Curl_mime_rewind(&data->set.mimepost); + + if(result) { + free(from); + free(auth); + + return result; + } + + data->state.infilesize = Curl_mime_size(&data->set.mimepost); + + /* Read from mime structure. */ + data->state.fread_func = (curl_read_callback) Curl_mime_read; + data->state.in = (void *) &data->set.mimepost; + } + + /* Calculate the optional SIZE parameter */ + if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) { + size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); + + if(!size) { + free(from); + free(auth); + + return CURLE_OUT_OF_MEMORY; + } + } + + /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8 + based address then quickly scan through the recipient list and check if + any there do, as we need to correctly identify our support for SMTPUTF8 + in the envelope, as per RFC-6531 sect. 3.4 */ + if(conn->proto.smtpc.utf8_supported && !utf8) { + struct SMTP *smtp = data->req.p.smtp; + struct curl_slist *rcpt = smtp->rcpt; + + while(rcpt && !utf8) { + /* Does the host name contain non-ASCII characters? */ + if(!Curl_is_ASCII_name(rcpt->data)) + utf8 = TRUE; + + rcpt = rcpt->next; + } + } + + /* Send the MAIL command */ + result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, + "MAIL FROM:%s%s%s%s%s%s", + from, /* Mandatory */ + auth ? " AUTH=" : "", /* Optional on AUTH support */ + auth ? auth : "", /* */ + size ? " SIZE=" : "", /* Optional on SIZE support */ + size ? size : "", /* */ + utf8 ? " SMTPUTF8" /* Internationalised mailbox */ + : ""); /* included in our envelope */ + + free(from); + free(auth); + free(size); + + if(!result) + smtp_state(data, SMTP_MAIL); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_rcpt_to() + * + * Sends a RCPT TO command for a given recipient as part of the message upload + * process. + */ +static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct SMTP *smtp = data->req.p.smtp; + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the recipient mailbox into the local address and host name parts, + converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(smtp->rcpt->data, + &address, &host); + if(result) + return result; + + /* Send the RCPT TO command */ + if(host.name) + result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s@%s>", + address, host.name); + else + /* An invalid mailbox was provided but we'll simply let the server worry + about that and reply with a 501 error */ + result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s>", + address); + + Curl_free_idnconverted_hostname(&host); + free(address); + + if(!result) + smtp_state(data, SMTP_RCPT); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_quit() + * + * Performs the quit action prior to sclose() being called. + */ +static CURLcode smtp_perform_quit(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Send the QUIT command */ + CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "QUIT"); + + if(!result) + smtp_state(data, SMTP_QUIT); + + return result; +} + +/* For the initial server greeting */ +static CURLcode smtp_state_servergreet_resp(struct Curl_easy *data, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2) { + failf(data, "Got unexpected smtp-server response: %d", smtpcode); + result = CURLE_WEIRD_SERVER_REPLY; + } + else + result = smtp_perform_ehlo(data); + + return result; +} + +/* For STARTTLS responses */ +static CURLcode smtp_state_starttls_resp(struct Curl_easy *data, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + /* Pipelining in response is forbidden. */ + if(data->conn->proto.smtpc.pp.overflow) + return CURLE_WEIRD_SERVER_REPLY; + + if(smtpcode != 220) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied, code %d", smtpcode); + result = CURLE_USE_SSL_FAILED; + } + else + result = smtp_perform_authentication(data); + } + else + result = smtp_perform_upgrade_tls(data); + + return result; +} + +/* For EHLO responses */ +static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data, + struct connectdata *conn, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + const char *line = Curl_dyn_ptr(&smtpc->pp.recvbuf); + size_t len = smtpc->pp.nfinal; + + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2 && smtpcode != 1) { + if(data->set.use_ssl <= CURLUSESSL_TRY + || Curl_conn_is_ssl(conn, FIRSTSOCKET)) + result = smtp_perform_helo(data, conn); + else { + failf(data, "Remote access denied: %d", smtpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + } + else if(len >= 4) { + line += 4; + len -= 4; + + /* Does the server support the STARTTLS capability? */ + if(len >= 8 && !memcmp(line, "STARTTLS", 8)) + smtpc->tls_supported = TRUE; + + /* Does the server support the SIZE capability? */ + else if(len >= 4 && !memcmp(line, "SIZE", 4)) + smtpc->size_supported = TRUE; + + /* Does the server support the UTF-8 capability? */ + else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8)) + smtpc->utf8_supported = TRUE; + + /* Does the server support authentication? */ + else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { + smtpc->auth_supported = TRUE; + + /* Advance past the AUTH keyword */ + line += 5; + len -= 5; + + /* Loop through the data line */ + for(;;) { + size_t llen; + size_t wordlen; + unsigned short mechbit; + + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + len--; + } + + if(!len) + break; + + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + smtpc->sasl.authmechs |= mechbit; + + line += wordlen; + len -= wordlen; + } + } + + if(smtpcode != 1) { + if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) { + /* We don't have a SSL/TLS connection yet, but SSL is requested */ + if(smtpc->tls_supported) + /* Switch to TLS connection now */ + result = smtp_perform_starttls(data, conn); + else if(data->set.use_ssl == CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = smtp_perform_authentication(data); + else { + failf(data, "STARTTLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = smtp_perform_authentication(data); + } + } + else { + failf(data, "Unexpectedly short EHLO response"); + result = CURLE_WEIRD_SERVER_REPLY; + } + + return result; +} + +/* For HELO responses */ +static CURLcode smtp_state_helo_resp(struct Curl_easy *data, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2) { + failf(data, "Remote access denied: %d", smtpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + else + /* End of connect phase */ + smtp_state(data, SMTP_STOP); + + return result; +} + +/* For SASL authentication responses */ +static CURLcode smtp_state_auth_resp(struct Curl_easy *data, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct smtp_conn *smtpc = &conn->proto.smtpc; + saslprogress progress; + + (void)instate; /* no use for this yet */ + + result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + smtp_state(data, SMTP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + break; + default: + break; + } + + return result; +} + +/* For command responses */ +static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SMTP *smtp = data->req.p.smtp; + char *line = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf); + size_t len = data->conn->proto.smtpc.pp.nfinal; + + (void)instate; /* no use for this yet */ + + if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) || + (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) { + failf(data, "Command failed: %d", smtpcode); + result = CURLE_WEIRD_SERVER_REPLY; + } + else { + if(!data->req.no_body) + result = Curl_client_write(data, CLIENTWRITE_BODY, line, len); + + if(smtpcode != 1) { + if(smtp->rcpt) { + smtp->rcpt = smtp->rcpt->next; + + if(smtp->rcpt) { + /* Send the next command */ + result = smtp_perform_command(data); + } + else + /* End of DO phase */ + smtp_state(data, SMTP_STOP); + } + else + /* End of DO phase */ + smtp_state(data, SMTP_STOP); + } + } + + return result; +} + +/* For MAIL responses */ +static CURLcode smtp_state_mail_resp(struct Curl_easy *data, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2) { + failf(data, "MAIL failed: %d", smtpcode); + result = CURLE_SEND_ERROR; + } + else + /* Start the RCPT TO command */ + result = smtp_perform_rcpt_to(data); + + return result; +} + +/* For RCPT responses */ +static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data, + struct connectdata *conn, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SMTP *smtp = data->req.p.smtp; + bool is_smtp_err = FALSE; + bool is_smtp_blocking_err = FALSE; + + (void)instate; /* no use for this yet */ + + is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE; + + /* If there's multiple RCPT TO to be issued, it's possible to ignore errors + and proceed with only the valid addresses. */ + is_smtp_blocking_err = + (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE; + + if(is_smtp_err) { + /* Remembering the last failure which we can report if all "RCPT TO" have + failed and we cannot proceed. */ + smtp->rcpt_last_error = smtpcode; + + if(is_smtp_blocking_err) { + failf(data, "RCPT failed: %d", smtpcode); + result = CURLE_SEND_ERROR; + } + } + else { + /* Some RCPT TO commands have succeeded. */ + smtp->rcpt_had_ok = TRUE; + } + + if(!is_smtp_blocking_err) { + smtp->rcpt = smtp->rcpt->next; + + if(smtp->rcpt) + /* Send the next RCPT TO command */ + result = smtp_perform_rcpt_to(data); + else { + /* We weren't able to issue a successful RCPT TO command while going + over recipients (potentially multiple). Sending back last error. */ + if(!smtp->rcpt_had_ok) { + failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error); + result = CURLE_SEND_ERROR; + } + else { + /* Send the DATA command */ + result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "DATA"); + + if(!result) + smtp_state(data, SMTP_DATA); + } + } + } + + return result; +} + +/* For DATA response */ +static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(smtpcode != 354) { + failf(data, "DATA failed: %d", smtpcode); + result = CURLE_SEND_ERROR; + } + else { + /* Set the progress upload size */ + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* SMTP upload */ + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + + /* End of DO phase */ + smtp_state(data, SMTP_STOP); + } + + return result; +} + +/* For POSTDATA responses, which are received after the entire DATA + part has been sent to the server */ +static CURLcode smtp_state_postdata_resp(struct Curl_easy *data, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + + (void)instate; /* no use for this yet */ + + if(smtpcode != 250) + result = CURLE_WEIRD_SERVER_REPLY; + + /* End of DONE phase */ + smtp_state(data, SMTP_STOP); + + return result; +} + +static CURLcode smtp_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int smtpcode; + struct smtp_conn *smtpc = &conn->proto.smtpc; + struct pingpong *pp = &smtpc->pp; + size_t nread = 0; + + /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */ + if(smtpc->state == SMTP_UPGRADETLS) + return smtp_perform_upgrade_tls(data); + + /* Flush any data that needs to be sent */ + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + do { + /* Read the response from the server */ + result = Curl_pp_readresp(data, sock, pp, &smtpcode, &nread); + if(result) + return result; + + /* Store the latest response for later retrieval if necessary */ + if(smtpc->state != SMTP_QUIT && smtpcode != 1) + data->info.httpcode = smtpcode; + + if(!smtpcode) + break; + + /* We have now received a full SMTP server response */ + switch(smtpc->state) { + case SMTP_SERVERGREET: + result = smtp_state_servergreet_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_EHLO: + result = smtp_state_ehlo_resp(data, conn, smtpcode, smtpc->state); + break; + + case SMTP_HELO: + result = smtp_state_helo_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_STARTTLS: + result = smtp_state_starttls_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_AUTH: + result = smtp_state_auth_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_COMMAND: + result = smtp_state_command_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_MAIL: + result = smtp_state_mail_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_RCPT: + result = smtp_state_rcpt_resp(data, conn, smtpcode, smtpc->state); + break; + + case SMTP_DATA: + result = smtp_state_data_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_POSTDATA: + result = smtp_state_postdata_resp(data, smtpcode, smtpc->state); + break; + + case SMTP_QUIT: + default: + /* internal error */ + smtp_state(data, SMTP_STOP); + break; + } + } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp)); + + return result; +} + +/* Called repeatedly until done from multi.c */ +static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct smtp_conn *smtpc = &conn->proto.smtpc; + + if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) { + bool ssldone = FALSE; + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); + smtpc->ssldone = ssldone; + if(result || !smtpc->ssldone) + return result; + } + + result = Curl_pp_statemach(data, &smtpc->pp, FALSE, FALSE); + *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; + + return result; +} + +static CURLcode smtp_block_statemach(struct Curl_easy *data, + struct connectdata *conn, + bool disconnecting) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + + while(smtpc->state != SMTP_STOP && !result) + result = Curl_pp_statemach(data, &smtpc->pp, TRUE, disconnecting); + + return result; +} + +/* Allocate and initialize the SMTP struct for the current Curl_easy if + required */ +static CURLcode smtp_init(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct SMTP *smtp; + + smtp = data->req.p.smtp = calloc(1, sizeof(struct SMTP)); + if(!smtp) + result = CURLE_OUT_OF_MEMORY; + + return result; +} + +/* For the SMTP "protocol connect" and "doing" phases only */ +static int smtp_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks) +{ + return Curl_pp_getsock(data, &conn->proto.smtpc.pp, socks); +} + +/*********************************************************************** + * + * smtp_connect() + * + * This function should do everything that is to be considered a part of + * the connection phase. + * + * The variable pointed to by 'done' will be TRUE if the protocol-layer + * connect phase is done when this function returns, or FALSE if not. + */ +static CURLcode smtp_connect(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct smtp_conn *smtpc = &conn->proto.smtpc; + struct pingpong *pp = &smtpc->pp; + + *done = FALSE; /* default to not done yet */ + + /* We always support persistent connections in SMTP */ + connkeep(conn, "SMTP default"); + + PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp); + + /* Initialize the SASL storage */ + Curl_sasl_init(&smtpc->sasl, data, &saslsmtp); + + /* Initialise the pingpong layer */ + Curl_pp_init(pp); + + /* Parse the URL options */ + result = smtp_parse_url_options(conn); + if(result) + return result; + + /* Parse the URL path */ + result = smtp_parse_url_path(data); + if(result) + return result; + + /* Start off waiting for the server greeting response */ + smtp_state(data, SMTP_SERVERGREET); + + result = smtp_multi_statemach(data, done); + + return result; +} + +/*********************************************************************** + * + * smtp_done() + * + * The DONE function. This does what needs to be done after a single DO has + * performed. + * + * Input argument is already checked for validity. + */ +static CURLcode smtp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct SMTP *smtp = data->req.p.smtp; + struct pingpong *pp = &conn->proto.smtpc.pp; + char *eob; + ssize_t len; + ssize_t bytes_written; + + (void)premature; + + if(!smtp) + return CURLE_OK; + + /* Cleanup our per-request based variables */ + Curl_safefree(smtp->custom); + + if(status) { + connclose(conn, "SMTP done with bad status"); /* marked for closure */ + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && data->set.mail_rcpt && + (data->state.upload || data->set.mimepost.kind)) { + /* Calculate the EOB taking into account any terminating CRLF from the + previous line of the email or the CRLF of the DATA command when there + is "no mail data". RFC-5321, sect. 4.1.1.4. + + Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to + fail when using a different pointer following a previous write, that + returned CURLE_AGAIN, we duplicate the EOB now rather than when the + bytes written doesn't equal len. */ + if(smtp->trailing_crlf || !data->state.infilesize) { + eob = strdup(&SMTP_EOB[2]); + len = SMTP_EOB_LEN - 2; + } + else { + eob = strdup(SMTP_EOB); + len = SMTP_EOB_LEN; + } + + if(!eob) + return CURLE_OUT_OF_MEMORY; + + /* Send the end of block data */ + result = Curl_write(data, conn->writesockfd, eob, len, &bytes_written); + if(result) { + free(eob); + return result; + } + + if(bytes_written != len) { + /* The whole chunk was not sent so keep it around and adjust the + pingpong structure accordingly */ + pp->sendthis = eob; + pp->sendsize = len; + pp->sendleft = len - bytes_written; + } + else { + /* Successfully sent so adjust the response timeout relative to now */ + pp->response = Curl_now(); + + free(eob); + } + + smtp_state(data, SMTP_POSTDATA); + + /* Run the state-machine */ + result = smtp_block_statemach(data, conn, FALSE); + } + + /* Clear the transfer mode for the next request */ + smtp->transfer = PPTRANSFER_BODY; + + return result; +} + +/*********************************************************************** + * + * smtp_perform() + * + * This is the actual DO function for SMTP. Transfer a mail, send a command + * or get some data according to the options previously setup. + */ +static CURLcode smtp_perform(struct Curl_easy *data, bool *connected, + bool *dophase_done) +{ + /* This is SMTP and no proxy */ + CURLcode result = CURLE_OK; + struct SMTP *smtp = data->req.p.smtp; + + DEBUGF(infof(data, "DO phase starts")); + + if(data->req.no_body) { + /* Requested no body means no transfer */ + smtp->transfer = PPTRANSFER_INFO; + } + + *dophase_done = FALSE; /* not done yet */ + + /* Store the first recipient (or NULL if not specified) */ + smtp->rcpt = data->set.mail_rcpt; + + /* Track of whether we've successfully sent at least one RCPT TO command */ + smtp->rcpt_had_ok = FALSE; + + /* Track of the last error we've received by sending RCPT TO command */ + smtp->rcpt_last_error = 0; + + /* Initial data character is the first character in line: it is implicitly + preceded by a virtual CRLF. */ + smtp->trailing_crlf = TRUE; + smtp->eob = 2; + + /* Start the first command in the DO phase */ + if((data->state.upload || data->set.mimepost.kind) && data->set.mail_rcpt) + /* MAIL transfer */ + result = smtp_perform_mail(data); + else + /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */ + result = smtp_perform_command(data); + + if(result) + return result; + + /* Run the state-machine */ + result = smtp_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); + + if(*dophase_done) + DEBUGF(infof(data, "DO phase is complete")); + + return result; +} + +/*********************************************************************** + * + * smtp_do() + * + * This function is registered as 'curl_do' function. It decodes the path + * parts etc as a wrapper to the actual DO function (smtp_perform). + * + * The input argument is already checked for validity. + */ +static CURLcode smtp_do(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + *done = FALSE; /* default to false */ + + /* Parse the custom request */ + result = smtp_parse_custom_request(data); + if(result) + return result; + + result = smtp_regular_transfer(data, done); + + return result; +} + +/*********************************************************************** + * + * smtp_disconnect() + * + * Disconnect from an SMTP server. Cleanup protocol-specific per-connection + * resources. BLOCKING. + */ +static CURLcode smtp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + struct smtp_conn *smtpc = &conn->proto.smtpc; + (void)data; + + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. */ + + if(!dead_connection && conn->bits.protoconnstart) { + if(!smtp_perform_quit(data, conn)) + (void)smtp_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */ + } + + /* Disconnect from the server */ + Curl_pp_disconnect(&smtpc->pp); + + /* Cleanup the SASL module */ + Curl_sasl_cleanup(conn, smtpc->sasl.authused); + + /* Cleanup our connection based variables */ + Curl_safefree(smtpc->domain); + + return CURLE_OK; +} + +/* Call this when the DO phase has completed */ +static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected) +{ + struct SMTP *smtp = data->req.p.smtp; + + (void)connected; + + if(smtp->transfer != PPTRANSFER_BODY) + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + + return CURLE_OK; +} + +/* Called from multi.c while DOing */ +static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done) +{ + CURLcode result = smtp_multi_statemach(data, dophase_done); + + if(result) + DEBUGF(infof(data, "DO phase failed")); + else if(*dophase_done) { + result = smtp_dophase_done(data, FALSE /* not connected */); + + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +/*********************************************************************** + * + * smtp_regular_transfer() + * + * The input argument is already checked for validity. + * + * Performs all commands done before a regular transfer between a local and a + * remote host. + */ +static CURLcode smtp_regular_transfer(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + bool connected = FALSE; + + /* Make sure size is unknown at this point */ + data->req.size = -1; + + /* Set the progress data */ + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + /* Carry out the perform */ + result = smtp_perform(data, &connected, dophase_done); + + /* Perform post DO phase operations if necessary */ + if(!result && *dophase_done) + result = smtp_dophase_done(data, connected); + + return result; +} + +static CURLcode smtp_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + + /* Clear the TLS upgraded flag */ + conn->bits.tls_upgraded = FALSE; + + /* Initialise the SMTP layer */ + result = smtp_init(data); + if(result) + return result; + + return CURLE_OK; +} + +/*********************************************************************** + * + * smtp_parse_url_options() + * + * Parse the URL login options. + */ +static CURLcode smtp_parse_url_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + const char *ptr = conn->options; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(strncasecompare(key, "AUTH=", 5)) + result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, + value, ptr - value); + else + result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; + } + + return result; +} + +/*********************************************************************** + * + * smtp_parse_url_path() + * + * Parse the URL path into separate path components. + */ +static CURLcode smtp_parse_url_path(struct Curl_easy *data) +{ + /* The SMTP struct is already initialised in smtp_connect() */ + struct connectdata *conn = data->conn; + struct smtp_conn *smtpc = &conn->proto.smtpc; + const char *path = &data->state.up.path[1]; /* skip leading path */ + char localhost[HOSTNAME_MAX + 1]; + + /* Calculate the path if necessary */ + if(!*path) { + if(!Curl_gethostname(localhost, sizeof(localhost))) + path = localhost; + else + path = "localhost"; + } + + /* URL decode the path and use it as the domain in our EHLO */ + return Curl_urldecode(path, 0, &smtpc->domain, NULL, REJECT_CTRL); +} + +/*********************************************************************** + * + * smtp_parse_custom_request() + * + * Parse the custom request. + */ +static CURLcode smtp_parse_custom_request(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct SMTP *smtp = data->req.p.smtp; + const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + + /* URL decode the custom request */ + if(custom) + result = Curl_urldecode(custom, 0, &smtp->custom, NULL, REJECT_CTRL); + + return result; +} + +/*********************************************************************** + * + * smtp_parse_address() + * + * Parse the fully qualified mailbox address into a local address part and the + * host name, converting the host name to an IDN A-label, as per RFC-5890, if + * necessary. + * + * Parameters: + * + * conn [in] - The connection handle. + * fqma [in] - The fully qualified mailbox address (which may or + * may not contain UTF-8 characters). + * address [in/out] - A new allocated buffer which holds the local + * address part of the mailbox. This buffer must be + * free'ed by the caller. + * host [in/out] - The host name structure that holds the original, + * and optionally encoded, host name. + * Curl_free_idnconverted_hostname() must be called + * once the caller has finished with the structure. + * + * Returns CURLE_OK on success. + * + * Notes: + * + * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor + * that conversion then we shall return success. This allow the caller to send + * the data to the server as a U-label (as per RFC-6531 sect. 3.2). + * + * If an mailbox '@' separator cannot be located then the mailbox is considered + * to be either a local mailbox or an invalid mailbox (depending on what the + * calling function deems it to be) then the input will simply be returned in + * the address part with the host name being NULL. + */ +static CURLcode smtp_parse_address(const char *fqma, char **address, + struct hostname *host) +{ + CURLcode result = CURLE_OK; + size_t length; + + /* Duplicate the fully qualified email address so we can manipulate it, + ensuring it doesn't contain the delimiters if specified */ + char *dup = strdup(fqma[0] == '<' ? fqma + 1 : fqma); + if(!dup) + return CURLE_OUT_OF_MEMORY; + + length = strlen(dup); + if(length) { + if(dup[length - 1] == '>') + dup[length - 1] = '\0'; + } + + /* Extract the host name from the address (if we can) */ + host->name = strpbrk(dup, "@"); + if(host->name) { + *host->name = '\0'; + host->name = host->name + 1; + + /* Attempt to convert the host name to IDN ACE */ + (void) Curl_idnconvert_hostname(host); + + /* If Curl_idnconvert_hostname() fails then we shall attempt to continue + and send the host name using UTF-8 rather than as 7-bit ACE (which is + our preference) */ + } + + /* Extract the local address from the mailbox */ + *address = dup; + + return result; +} + +CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, + const ssize_t nread, + const ssize_t offset) +{ + /* When sending a SMTP payload we must detect CRLF. sequences making sure + they are sent as CRLF.. instead, as a . on the beginning of a line will + be deleted by the server when not part of an EOB terminator and a + genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of + data by the server + */ + ssize_t i; + ssize_t si; + struct SMTP *smtp = data->req.p.smtp; + char *scratch = data->state.scratch; + char *newscratch = NULL; + char *oldscratch = NULL; + size_t eob_sent; + + /* Do we need to allocate a scratch buffer? */ + if(!scratch || data->set.crlf) { + oldscratch = scratch; + + scratch = newscratch = malloc(2 * data->set.upload_buffer_size); + if(!newscratch) { + failf(data, "Failed to alloc scratch buffer"); + + return CURLE_OUT_OF_MEMORY; + } + } + DEBUGASSERT((size_t)data->set.upload_buffer_size >= (size_t)nread); + + /* Have we already sent part of the EOB? */ + eob_sent = smtp->eob; + + /* This loop can be improved by some kind of Boyer-Moore style of + approach but that is saved for later... */ + if(offset) + memcpy(scratch, data->req.upload_fromhere, offset); + for(i = offset, si = offset; i < nread; i++) { + if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) { + smtp->eob++; + + /* Is the EOB potentially the terminating CRLF? */ + if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob) + smtp->trailing_crlf = TRUE; + else + smtp->trailing_crlf = FALSE; + } + else if(smtp->eob) { + /* A previous substring matched so output that first */ + memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); + si += smtp->eob - eob_sent; + + /* Then compare the first byte */ + if(SMTP_EOB[0] == data->req.upload_fromhere[i]) + smtp->eob = 1; + else + smtp->eob = 0; + + eob_sent = 0; + + /* Reset the trailing CRLF flag as there was more data */ + smtp->trailing_crlf = FALSE; + } + + /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */ + if(SMTP_EOB_FIND_LEN == smtp->eob) { + /* Copy the replacement data to the target buffer */ + memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent], + SMTP_EOB_REPL_LEN - eob_sent); + si += SMTP_EOB_REPL_LEN - eob_sent; + smtp->eob = 0; + eob_sent = 0; + } + else if(!smtp->eob) + scratch[si++] = data->req.upload_fromhere[i]; + } + + if(smtp->eob - eob_sent) { + /* A substring matched before processing ended so output that now */ + memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); + si += smtp->eob - eob_sent; + } + + /* Only use the new buffer if we replaced something */ + if(si != nread) { + /* Upload from the new (replaced) buffer instead */ + data->req.upload_fromhere = scratch; + + /* Save the buffer so it can be freed later */ + data->state.scratch = scratch; + + /* Free the old scratch buffer */ + free(oldscratch); + + /* Set the new amount too */ + data->req.upload_present = si; + } + else + free(newscratch); + + return CURLE_OK; +} + +#endif /* CURL_DISABLE_SMTP */ diff --git a/lib/smtp.h b/lib/smtp.h new file mode 100644 index 0000000..7a04c21 --- /dev/null +++ b/lib/smtp.h @@ -0,0 +1,100 @@ +#ifndef HEADER_CURL_SMTP_H +#define HEADER_CURL_SMTP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "pingpong.h" +#include "curl_sasl.h" + +/**************************************************************************** + * SMTP unique setup + ***************************************************************************/ +typedef enum { + SMTP_STOP, /* do nothing state, stops the state machine */ + SMTP_SERVERGREET, /* waiting for the initial greeting immediately after + a connect */ + SMTP_EHLO, + SMTP_HELO, + SMTP_STARTTLS, + SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS + (multi mode only) */ + SMTP_AUTH, + SMTP_COMMAND, /* VRFY, EXPN, NOOP, RSET and HELP */ + SMTP_MAIL, /* MAIL FROM */ + SMTP_RCPT, /* RCPT TO */ + SMTP_DATA, + SMTP_POSTDATA, + SMTP_QUIT, + SMTP_LAST /* never used */ +} smtpstate; + +/* This SMTP struct is used in the Curl_easy. All SMTP data that is + connection-oriented must be in smtp_conn to properly deal with the fact that + perhaps the Curl_easy is changed between the times the connection is + used. */ +struct SMTP { + curl_pp_transfer transfer; + char *custom; /* Custom Request */ + struct curl_slist *rcpt; /* Recipient list */ + int rcpt_last_error; /* The last error received for RCPT TO command */ + size_t eob; /* Number of bytes of the EOB (End Of Body) that + have been received so far */ + BIT(rcpt_had_ok); /* Whether any of RCPT TO commands (depends on + total number of recipients) succeeded so far */ + BIT(trailing_crlf); /* Specifies if the trailing CRLF is present */ +}; + +/* smtp_conn is used for struct connection-oriented data in the connectdata + struct */ +struct smtp_conn { + struct pingpong pp; + struct SASL sasl; /* SASL-related storage */ + smtpstate state; /* Always use smtp.c:state() to change state! */ + char *domain; /* Client address/name to send in the EHLO */ + BIT(ssldone); /* Is connect() over SSL done? */ + BIT(tls_supported); /* StartTLS capability supported by server */ + BIT(size_supported); /* If server supports SIZE extension according to + RFC 1870 */ + BIT(utf8_supported); /* If server supports SMTPUTF8 extension according + to RFC 6531 */ + BIT(auth_supported); /* AUTH capability supported by server */ +}; + +extern const struct Curl_handler Curl_handler_smtp; +extern const struct Curl_handler Curl_handler_smtps; + +/* this is the 5-bytes End-Of-Body marker for SMTP */ +#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a" +#define SMTP_EOB_LEN 5 +#define SMTP_EOB_FIND_LEN 3 + +/* if found in data, replace it with this string instead */ +#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e" +#define SMTP_EOB_REPL_LEN 4 + +CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, + const ssize_t nread, + const ssize_t offset); + +#endif /* HEADER_CURL_SMTP_H */ diff --git a/lib/sockaddr.h b/lib/sockaddr.h new file mode 100644 index 0000000..5a6bb20 --- /dev/null +++ b/lib/sockaddr.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_SOCKADDR_H +#define HEADER_CURL_SOCKADDR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +struct Curl_sockaddr_storage { + union { + struct sockaddr sa; + struct sockaddr_in sa_in; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 sa_in6; +#endif +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE + struct sockaddr_storage sa_stor; +#else + char cbuf[256]; /* this should be big enough to fit a lot */ +#endif + } buffer; +}; + +#endif /* HEADER_CURL_SOCKADDR_H */ diff --git a/lib/socketpair.c b/lib/socketpair.c new file mode 100644 index 0000000..d01b255 --- /dev/null +++ b/lib/socketpair.c @@ -0,0 +1,190 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "socketpair.h" +#include "urldata.h" +#include "rand.h" + +#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR) +#ifdef _WIN32 +/* + * This is a socketpair() implementation for Windows. + */ +#include +#include +#else +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include /* IPPROTO_TCP */ +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001 +#endif /* !INADDR_LOOPBACK */ +#endif /* !_WIN32 */ + +#include "nonblock.h" /* for curlx_nonblock */ +#include "timeval.h" /* needed before select.h */ +#include "select.h" /* for Curl_poll */ + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +int Curl_socketpair(int domain, int type, int protocol, + curl_socket_t socks[2]) +{ + union { + struct sockaddr_in inaddr; + struct sockaddr addr; + } a; + curl_socket_t listener; + curl_socklen_t addrlen = sizeof(a.inaddr); + int reuse = 1; + struct pollfd pfd[1]; + (void)domain; + (void)type; + (void)protocol; + + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(listener == CURL_SOCKET_BAD) + return -1; + + memset(&a, 0, sizeof(a)); + a.inaddr.sin_family = AF_INET; + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_port = 0; + + socks[0] = socks[1] = CURL_SOCKET_BAD; + +#if defined(_WIN32) || defined(__CYGWIN__) + /* don't set SO_REUSEADDR on Windows */ + (void)reuse; +#ifdef SO_EXCLUSIVEADDRUSE + { + int exclusive = 1; + if(setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, + (char *)&exclusive, (curl_socklen_t)sizeof(exclusive)) == -1) + goto error; + } +#endif +#else + if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse, (curl_socklen_t)sizeof(reuse)) == -1) + goto error; +#endif + if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1) + goto error; + if(getsockname(listener, &a.addr, &addrlen) == -1 || + addrlen < (int)sizeof(a.inaddr)) + goto error; + if(listen(listener, 1) == -1) + goto error; + socks[0] = socket(AF_INET, SOCK_STREAM, 0); + if(socks[0] == CURL_SOCKET_BAD) + goto error; + if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1) + goto error; + + /* use non-blocking accept to make sure we don't block forever */ + if(curlx_nonblock(listener, TRUE) < 0) + goto error; + pfd[0].fd = listener; + pfd[0].events = POLLIN; + pfd[0].revents = 0; + (void)Curl_poll(pfd, 1, 1000); /* one second */ + socks[1] = accept(listener, NULL, NULL); + if(socks[1] == CURL_SOCKET_BAD) + goto error; + else { + struct curltime start = Curl_now(); + char rnd[9]; + char check[sizeof(rnd)]; + char *p = &check[0]; + size_t s = sizeof(check); + + if(Curl_rand(NULL, (unsigned char *)rnd, sizeof(rnd))) + goto error; + + /* write data to the socket */ + swrite(socks[0], rnd, sizeof(rnd)); + /* verify that we read the correct data */ + do { + ssize_t nread; + + pfd[0].fd = socks[1]; + pfd[0].events = POLLIN; + pfd[0].revents = 0; + (void)Curl_poll(pfd, 1, 1000); /* one second */ + + nread = sread(socks[1], p, s); + if(nread == -1) { + int sockerr = SOCKERRNO; + /* Don't block forever */ + if(Curl_timediff(Curl_now(), start) > (60 * 1000)) + goto error; + if( +#ifdef WSAEWOULDBLOCK + /* This is how Windows does it */ + (WSAEWOULDBLOCK == sockerr) +#else + /* errno may be EWOULDBLOCK or on some systems EAGAIN when it + returned due to its inability to send off data without + blocking. We therefore treat both error codes the same here */ + (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || + (EINTR == sockerr) || (EINPROGRESS == sockerr) +#endif + ) { + continue; + } + goto error; + } + s -= nread; + if(s) { + p += nread; + continue; + } + if(memcmp(rnd, check, sizeof(check))) + goto error; + break; + } while(1); + } + + sclose(listener); + return 0; + +error: + sclose(listener); + sclose(socks[0]); + sclose(socks[1]); + return -1; +} + +#endif /* ! HAVE_SOCKETPAIR */ diff --git a/lib/socketpair.h b/lib/socketpair.h new file mode 100644 index 0000000..bd499ab --- /dev/null +++ b/lib/socketpair.h @@ -0,0 +1,54 @@ +#ifndef HEADER_CURL_SOCKETPAIR_H +#define HEADER_CURL_SOCKETPAIR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_PIPE + +#define wakeup_write write +#define wakeup_read read +#define wakeup_close close +#define wakeup_create pipe + +#else /* HAVE_PIPE */ + +#define wakeup_write swrite +#define wakeup_read sread +#define wakeup_close sclose +#define wakeup_create(p) Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, p) + +#endif /* HAVE_PIPE */ + +#ifndef HAVE_SOCKETPAIR +#include + +int Curl_socketpair(int domain, int type, int protocol, + curl_socket_t socks[2]); +#else +#define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d) +#endif + +#endif /* HEADER_CURL_SOCKETPAIR_H */ diff --git a/lib/socks.c b/lib/socks.c new file mode 100644 index 0000000..ecd2f7e --- /dev/null +++ b/lib/socks.c @@ -0,0 +1,1276 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_PROXY) + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "select.h" +#include "cfilters.h" +#include "connect.h" +#include "timeval.h" +#include "socks.h" +#include "multiif.h" /* for getsock macros */ +#include "inet_pton.h" +#include "url.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* for the (SOCKS) connect state machine */ +enum connect_t { + CONNECT_INIT, + CONNECT_SOCKS_INIT, /* 1 */ + CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */ + CONNECT_SOCKS_READ_INIT, /* 3 set up read */ + CONNECT_SOCKS_READ, /* 4 read server response */ + CONNECT_GSSAPI_INIT, /* 5 */ + CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */ + CONNECT_AUTH_SEND, /* 7 send auth */ + CONNECT_AUTH_READ, /* 8 read auth response */ + CONNECT_REQ_INIT, /* 9 init SOCKS "request" */ + CONNECT_RESOLVING, /* 10 */ + CONNECT_RESOLVED, /* 11 */ + CONNECT_RESOLVE_REMOTE, /* 12 */ + CONNECT_REQ_SEND, /* 13 */ + CONNECT_REQ_SENDING, /* 14 */ + CONNECT_REQ_READ, /* 15 */ + CONNECT_REQ_READ_MORE, /* 16 */ + CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */ +}; + +#define CURL_SOCKS_BUF_SIZE 600 + +/* make sure we configure it not too low */ +#if CURL_SOCKS_BUF_SIZE < 600 +#error CURL_SOCKS_BUF_SIZE must be at least 600 +#endif + + +struct socks_state { + enum connect_t state; + ssize_t outstanding; /* send this many bytes more */ + unsigned char buffer[CURL_SOCKS_BUF_SIZE]; + unsigned char *outp; /* send from this pointer */ + + const char *hostname; + int remote_port; + const char *proxy_user; + const char *proxy_password; +}; + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) +/* + * Helper read-from-socket functions. Does the same as Curl_read() but it + * blocks until all bytes amount of buffersize will be read. No more, no less. + * + * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions. + */ +int Curl_blockread_all(struct Curl_cfilter *cf, + struct Curl_easy *data, /* transfer */ + char *buf, /* store read data here */ + ssize_t buffersize, /* max amount to read */ + ssize_t *n) /* amount bytes read */ +{ + ssize_t nread = 0; + ssize_t allread = 0; + int result; + CURLcode err = CURLE_OK; + + *n = 0; + for(;;) { + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + if(timeout_ms < 0) { + /* we already got the timeout */ + result = CURLE_OPERATION_TIMEDOUT; + break; + } + if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) { + result = ~CURLE_OK; + break; + } + nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err); + if(nread <= 0) { + result = err; + if(CURLE_AGAIN == err) + continue; + if(err) { + break; + } + } + + if(buffersize == nread) { + allread += nread; + *n = allread; + result = CURLE_OK; + break; + } + if(!nread) { + result = ~CURLE_OK; + break; + } + + buffersize -= nread; + buf += nread; + allread += nread; + } + return result; +} +#endif + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +#define DEBUG_AND_VERBOSE +#define sxstate(x,d,y) socksstate(x,d,y, __LINE__) +#else +#define sxstate(x,d,y) socksstate(x,d,y) +#endif + +/* always use this function to change state, to make debugging easier */ +static void socksstate(struct socks_state *sx, struct Curl_easy *data, + enum connect_t state +#ifdef DEBUG_AND_VERBOSE + , int lineno +#endif +) +{ + enum connect_t oldstate = sx->state; +#ifdef DEBUG_AND_VERBOSE + /* synced with the state list in urldata.h */ + static const char * const socks_statename[] = { + "INIT", + "SOCKS_INIT", + "SOCKS_SEND", + "SOCKS_READ_INIT", + "SOCKS_READ", + "GSSAPI_INIT", + "AUTH_INIT", + "AUTH_SEND", + "AUTH_READ", + "REQ_INIT", + "RESOLVING", + "RESOLVED", + "RESOLVE_REMOTE", + "REQ_SEND", + "REQ_SENDING", + "REQ_READ", + "REQ_READ_MORE", + "DONE" + }; +#endif + + (void)data; + if(oldstate == state) + /* don't bother when the new state is the same as the old state */ + return; + + sx->state = state; + +#ifdef DEBUG_AND_VERBOSE + infof(data, + "SXSTATE: %s => %s; line %d", + socks_statename[oldstate], socks_statename[sx->state], + lineno); +#endif +} + +static CURLproxycode socks_state_send(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data, + CURLproxycode failcode, + const char *description) +{ + ssize_t nwritten; + CURLcode result; + + nwritten = Curl_conn_cf_send(cf->next, data, (char *)sx->outp, + sx->outstanding, &result); + if(nwritten <= 0) { + if(CURLE_AGAIN == result) { + return CURLPX_OK; + } + else if(CURLE_OK == result) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLPX_CLOSED; + } + failf(data, "Failed to send %s: %s", description, + curl_easy_strerror(result)); + return failcode; + } + DEBUGASSERT(sx->outstanding >= nwritten); + /* not done, remain in state */ + sx->outstanding -= nwritten; + sx->outp += nwritten; + return CURLPX_OK; +} + +static CURLproxycode socks_state_recv(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data, + CURLproxycode failcode, + const char *description) +{ + ssize_t nread; + CURLcode result; + + nread = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp, + sx->outstanding, &result); + if(nread <= 0) { + if(CURLE_AGAIN == result) { + return CURLPX_OK; + } + else if(CURLE_OK == result) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLPX_CLOSED; + } + failf(data, "SOCKS: Failed receiving %s: %s", description, + curl_easy_strerror(result)); + return failcode; + } + /* remain in reading state */ + DEBUGASSERT(sx->outstanding >= nread); + sx->outstanding -= nread; + sx->outp += nread; + return CURLPX_OK; +} + +/* +* This function logs in to a SOCKS4 proxy and sends the specifics to the final +* destination server. +* +* Reference : +* https://www.openssh.com/txt/socks4.protocol +* +* Note : +* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" +* Nonsupport "Identification Protocol (RFC1413)" +*/ +static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + struct connectdata *conn = cf->conn; + const bool protocol4a = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE; + unsigned char *socksreq = sx->buffer; + CURLcode result; + CURLproxycode presult; + struct Curl_dns_entry *dns = NULL; + + switch(sx->state) { + case CONNECT_SOCKS_INIT: + /* SOCKS4 can only do IPv4, insist! */ + conn->ip_version = CURL_IPRESOLVE_V4; + if(conn->bits.httpproxy) + infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d", + protocol4a ? "a" : "", sx->hostname, sx->remote_port); + + infof(data, "SOCKS4 communication to %s:%d", + sx->hostname, sx->remote_port); + + /* + * Compose socks4 request + * + * Request format + * + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * | VN | CD | DSTPORT | DSTIP | USERID |NULL| + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * # of bytes: 1 1 2 4 variable 1 + */ + + socksreq[0] = 4; /* version (SOCKS4) */ + socksreq[1] = 1; /* connect */ + socksreq[2] = (unsigned char)((sx->remote_port >> 8) & 0xff); /* MSB */ + socksreq[3] = (unsigned char)(sx->remote_port & 0xff); /* LSB */ + + /* DNS resolve only for SOCKS4, not SOCKS4a */ + if(!protocol4a) { + enum resolve_t rc = + Curl_resolv(data, sx->hostname, sx->remote_port, TRUE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLPX_RESOLVE_HOST; + else if(rc == CURLRESOLV_PENDING) { + sxstate(sx, data, CONNECT_RESOLVING); + infof(data, "SOCKS4 non-blocking resolve of %s", sx->hostname); + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; + } + + /* socks4a doesn't resolve anything locally */ + sxstate(sx, data, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; + + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(data, sx->hostname, (int)conn->port); + + if(dns) { +#ifdef CURLRES_ASYNCH + data->state.async.dns = dns; + data->state.async.done = TRUE; +#endif + infof(data, "Hostname '%s' was found", sx->hostname); + sxstate(sx, data, CONNECT_RESOLVED); + } + else { + result = Curl_resolv_check(data, &dns); + if(!dns) { + if(result) + return CURLPX_RESOLVE_HOST; + return CURLPX_OK; + } + } + FALLTHROUGH(); + case CONNECT_RESOLVED: +CONNECT_RESOLVED: + { + struct Curl_addrinfo *hp = NULL; + /* + * We cannot use 'hostent' as a struct that Curl_resolv() returns. It + * returns a Curl_addrinfo pointer that may not always look the same. + */ + if(dns) { + hp = dns->addr; + + /* scan for the first IPv4 address */ + while(hp && (hp->ai_family != AF_INET)) + hp = hp->ai_next; + + if(hp) { + struct sockaddr_in *saddr_in; + char buf[64]; + Curl_printable_address(hp, buf, sizeof(buf)); + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0]; + socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1]; + socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2]; + socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3]; + + infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf); + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + } + else + failf(data, "SOCKS4 connection to %s not supported", sx->hostname); + } + else + failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", + sx->hostname); + + if(!hp) + return CURLPX_RESOLVE_HOST; + } + FALLTHROUGH(); + case CONNECT_REQ_INIT: +CONNECT_REQ_INIT: + /* + * This is currently not supporting "Identification Protocol (RFC1413)". + */ + socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ + if(sx->proxy_user) { + size_t plen = strlen(sx->proxy_user); + if(plen > 255) { + /* there is no real size limit to this field in the protocol, but + SOCKS5 limits the proxy user field to 255 bytes and it seems likely + that a longer field is either a mistake or malicious input */ + failf(data, "Too long SOCKS proxy user name"); + return CURLPX_LONG_USER; + } + /* copy the proxy name WITH trailing zero */ + memcpy(socksreq + 8, sx->proxy_user, plen + 1); + } + + /* + * Make connection + */ + { + size_t packetsize = 9 + + strlen((char *)socksreq + 8); /* size including NUL */ + + /* If SOCKS4a, set special invalid IP address 0.0.0.x */ + if(protocol4a) { + size_t hostnamelen = 0; + socksreq[4] = 0; + socksreq[5] = 0; + socksreq[6] = 0; + socksreq[7] = 1; + /* append hostname */ + hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */ + if((hostnamelen <= 255) && + (packetsize + hostnamelen < sizeof(sx->buffer))) + strcpy((char *)socksreq + packetsize, sx->hostname); + else { + failf(data, "SOCKS4: too long host name"); + return CURLPX_LONG_HOSTNAME; + } + packetsize += hostnamelen; + } + sx->outp = socksreq; + DEBUGASSERT(packetsize <= sizeof(sx->buffer)); + sx->outstanding = packetsize; + sxstate(sx, data, CONNECT_REQ_SENDING); + } + FALLTHROUGH(); + case CONNECT_REQ_SENDING: + /* Send request */ + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "SOCKS4 connect request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + /* done sending! */ + sx->outstanding = 8; /* receive data size */ + sx->outp = socksreq; + sxstate(sx, data, CONNECT_SOCKS_READ); + + FALLTHROUGH(); + case CONNECT_SOCKS_READ: + /* Receive response */ + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, + "connect request ack"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_DONE); + break; + default: /* lots of unused states in SOCKS4 */ + break; + } + + /* + * Response format + * + * +----+----+----+----+----+----+----+----+ + * | VN | CD | DSTPORT | DSTIP | + * +----+----+----+----+----+----+----+----+ + * # of bytes: 1 1 2 4 + * + * VN is the version of the reply code and should be 0. CD is the result + * code with one of the following values: + * + * 90: request granted + * 91: request rejected or failed + * 92: request rejected because SOCKS server cannot connect to + * identd on the client + * 93: request rejected because the client program and identd + * report different user-ids + */ + + /* wrong version ? */ + if(socksreq[0]) { + failf(data, + "SOCKS4 reply has wrong version, version should be 0."); + return CURLPX_BAD_VERSION; + } + + /* Result */ + switch(socksreq[1]) { + case 90: + infof(data, "SOCKS4%s request granted.", protocol4a?"a":""); + break; + case 91: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected or failed.", + socksreq[4], socksreq[5], socksreq[6], socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLPX_REQUEST_FAILED; + case 92: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected because SOCKS server cannot connect to " + "identd on the client.", + socksreq[4], socksreq[5], socksreq[6], socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLPX_IDENTD; + case 93: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected because the client program and identd " + "report different user-ids.", + socksreq[4], socksreq[5], socksreq[6], socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLPX_IDENTD_DIFFER; + default: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", Unknown.", + socksreq[4], socksreq[5], socksreq[6], socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLPX_UNKNOWN_FAIL; + } + + return CURLPX_OK; /* Proxy was successful! */ +} + +/* + * This function logs in to a SOCKS5 proxy and sends the specifics to the final + * destination server. + */ +static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + /* + According to the RFC1928, section "6. Replies". This is what a SOCK5 + replies: + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + Where: + + o VER protocol version: X'05' + o REP Reply field: + o X'00' succeeded + */ + struct connectdata *conn = cf->conn; + unsigned char *socksreq = sx->buffer; + size_t idx; + CURLcode result; + CURLproxycode presult; + bool socks5_resolve_local = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; + const size_t hostname_len = strlen(sx->hostname); + size_t len = 0; + const unsigned char auth = data->set.socks5auth; + bool allow_gssapi = FALSE; + struct Curl_dns_entry *dns = NULL; + + DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI)); + switch(sx->state) { + case CONNECT_SOCKS_INIT: + if(conn->bits.httpproxy) + infof(data, "SOCKS5: connecting to HTTP proxy %s port %d", + sx->hostname, sx->remote_port); + + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ + if(!socks5_resolve_local && hostname_len > 255) { + failf(data, "SOCKS5: the destination hostname is too long to be " + "resolved remotely by the proxy."); + return CURLPX_LONG_HOSTNAME; + } + + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(data, + "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u", + auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + sx->proxy_user = NULL; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; +#endif + + idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ + if(allow_gssapi) + socksreq[idx++] = 1; /* GSS-API */ + if(sx->proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + + sx->outp = socksreq; + DEBUGASSERT(idx <= sizeof(sx->buffer)); + sx->outstanding = idx; + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_SOCKS_READ); + goto CONNECT_SOCKS_READ_INIT; + case CONNECT_SOCKS_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + FALLTHROUGH(); + case CONNECT_SOCKS_READ_INIT: +CONNECT_SOCKS_READ_INIT: + sx->outstanding = 2; /* expect two bytes */ + sx->outp = socksreq; /* store it here */ + FALLTHROUGH(); + case CONNECT_SOCKS_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, + "initial SOCKS5 response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1] == 0) { + /* DONE! No authentication needed. Send request. */ + sxstate(sx, data, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; + } + else if(socksreq[1] == 2) { + /* regular name + password authentication */ + sxstate(sx, data, CONNECT_AUTH_INIT); + goto CONNECT_AUTH_INIT; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else if(allow_gssapi && (socksreq[1] == 1)) { + sxstate(sx, data, CONNECT_GSSAPI_INIT); + result = Curl_SOCKS5_gssapi_negotiate(cf, data); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLPX_GSSAPI; + } + } +#endif + else { + /* error */ + if(!allow_gssapi && (socksreq[1] == 1)) { + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return CURLPX_GSSAPI_PERMSG; + } + else if(socksreq[1] == 255) { + failf(data, "No authentication method was acceptable."); + return CURLPX_NO_AUTH; + } + } + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return CURLPX_UNKNOWN_MODE; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CONNECT_GSSAPI_INIT: + /* GSSAPI stuff done non-blocking */ + break; +#endif + + default: /* do nothing! */ + break; + +CONNECT_AUTH_INIT: + case CONNECT_AUTH_INIT: { + /* Needs user name and password */ + size_t proxy_user_len, proxy_password_len; + if(sx->proxy_user && sx->proxy_password) { + proxy_user_len = strlen(sx->proxy_user); + proxy_password_len = strlen(sx->proxy_password); + } + else { + proxy_user_len = 0; + proxy_password_len = 0; + } + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + len = 0; + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (unsigned char) proxy_user_len; + if(sx->proxy_user && proxy_user_len) { + /* the length must fit in a single byte */ + if(proxy_user_len > 255) { + failf(data, "Excessive user name length for proxy auth"); + return CURLPX_LONG_USER; + } + memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + } + len += proxy_user_len; + socksreq[len++] = (unsigned char) proxy_password_len; + if(sx->proxy_password && proxy_password_len) { + /* the length must fit in a single byte */ + if(proxy_password_len > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } + memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + } + len += proxy_password_len; + sxstate(sx, data, CONNECT_AUTH_SEND); + DEBUGASSERT(len <= sizeof(sx->buffer)); + sx->outstanding = len; + sx->outp = socksreq; + } + FALLTHROUGH(); + case CONNECT_AUTH_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, + "SOCKS5 sub-negotiation request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sx->outp = socksreq; + sx->outstanding = 2; + sxstate(sx, data, CONNECT_AUTH_READ); + FALLTHROUGH(); + case CONNECT_AUTH_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, + "SOCKS5 sub-negotiation response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + /* ignore the first (VER) byte */ + else if(socksreq[1]) { /* status */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + return CURLPX_USER_REJECTED; + } + + /* Everything is good so far, user was authenticated! */ + sxstate(sx, data, CONNECT_REQ_INIT); + FALLTHROUGH(); + case CONNECT_REQ_INIT: +CONNECT_REQ_INIT: + if(socks5_resolve_local) { + enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port, + TRUE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLPX_RESOLVE_HOST; + + if(rc == CURLRESOLV_PENDING) { + sxstate(sx, data, CONNECT_RESOLVING); + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; + } + goto CONNECT_RESOLVE_REMOTE; + + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port); + + if(dns) { +#ifdef CURLRES_ASYNCH + data->state.async.dns = dns; + data->state.async.done = TRUE; +#endif + infof(data, "SOCKS5: hostname '%s' found", sx->hostname); + } + + if(!dns) { + result = Curl_resolv_check(data, &dns); + if(!dns) { + if(result) + return CURLPX_RESOLVE_HOST; + return CURLPX_OK; + } + } + FALLTHROUGH(); + case CONNECT_RESOLVED: +CONNECT_RESOLVED: + { + char dest[MAX_IPADR_LEN]; /* printable address */ + struct Curl_addrinfo *hp = NULL; + if(dns) + hp = dns->addr; +#ifdef ENABLE_IPV6 + if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) { + int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ? + AF_INET : AF_INET6; + /* scan for the first proper address */ + while(hp && (hp->ai_family != wanted_family)) + hp = hp->ai_next; + } +#endif + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + return CURLPX_RESOLVE_HOST; + } + + Curl_printable_address(hp, dest, sizeof(dest)); + + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + if(hp->ai_family == AF_INET) { + int i; + struct sockaddr_in *saddr_in; + socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + for(i = 0; i < 4; i++) { + socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; + } + + infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest, + sx->remote_port); + } +#ifdef ENABLE_IPV6 + else if(hp->ai_family == AF_INET6) { + int i; + struct sockaddr_in6 *saddr_in6; + socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ + + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + for(i = 0; i < 16; i++) { + socksreq[len++] = + ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; + } + + infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest, + sx->remote_port); + } +#endif + else { + hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported", dest); + } + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + goto CONNECT_REQ_SEND; + } +CONNECT_RESOLVE_REMOTE: + case CONNECT_RESOLVE_REMOTE: + /* Authentication is complete, now specify destination to the proxy */ + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + + if(!socks5_resolve_local) { + /* ATYP: domain name = 3, + IPv6 == 4, + IPv4 == 1 */ + unsigned char ip4[4]; +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip) { + char ip6[16]; + if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6)) + return CURLPX_BAD_ADDRESS_TYPE; + socksreq[len++] = 4; + memcpy(&socksreq[len], ip6, sizeof(ip6)); + len += sizeof(ip6); + } + else +#endif + if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) { + socksreq[len++] = 1; + memcpy(&socksreq[len], ip4, sizeof(ip4)); + len += sizeof(ip4); + } + else { + socksreq[len++] = 3; + socksreq[len++] = (unsigned char) hostname_len; /* one byte length */ + memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ + len += hostname_len; + } + infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); + } + FALLTHROUGH(); + + case CONNECT_REQ_SEND: +CONNECT_REQ_SEND: + /* PORT MSB */ + socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); + /* PORT LSB */ + socksreq[len++] = (unsigned char)(sx->remote_port & 0xff); + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outp = socksreq; + DEBUGASSERT(len <= sizeof(sx->buffer)); + sx->outstanding = len; + sxstate(sx, data, CONNECT_REQ_SENDING); + FALLTHROUGH(); + case CONNECT_REQ_SENDING: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, + "SOCKS5 connect request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in send state */ + return CURLPX_OK; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outstanding = 10; /* minimum packet size is 10 */ + sx->outp = socksreq; + sxstate(sx, data, CONNECT_REQ_READ); + FALLTHROUGH(); + case CONNECT_REQ_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, + "SOCKS5 connect request ack"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { /* version */ + failf(data, + "SOCKS5 reply has wrong version, version should be 5."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1]) { /* Anything besides 0 is an error */ + CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; + int code = socksreq[1]; + failf(data, "Can't complete SOCKS5 connection to %s. (%d)", + sx->hostname, (unsigned char)socksreq[1]); + if(code < 9) { + /* RFC 1928 section 6 lists: */ + static const CURLproxycode lookup[] = { + CURLPX_OK, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + }; + rc = lookup[code]; + } + return rc; + } + + /* Fix: in general, returned BND.ADDR is variable length parameter by RFC + 1928, so the reply packet should be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + + /* Calculate real packet size */ + if(socksreq[3] == 3) { + /* domain name */ + int addrlen = (int) socksreq[4]; + len = 5 + addrlen + 2; + } + else if(socksreq[3] == 4) { + /* IPv6 */ + len = 4 + 16 + 2; + } + else if(socksreq[3] == 1) { + len = 4 + 4 + 2; + } + else { + failf(data, "SOCKS5 reply has wrong address type."); + return CURLPX_BAD_ADDRESS_TYPE; + } + + /* At this point we already read first 10 bytes */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(!conn->socks5_gssapi_enctype) { + /* decrypt_gssapi_blockread already read the whole packet */ +#endif + if(len > 10) { + DEBUGASSERT(len <= sizeof(sx->buffer)); + sx->outstanding = len - 10; /* get the rest */ + sx->outp = &socksreq[10]; + sxstate(sx, data, CONNECT_REQ_READ_MORE); + } + else { + sxstate(sx, data, CONNECT_DONE); + break; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + } +#endif + FALLTHROUGH(); + case CONNECT_REQ_READ_MORE: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, + "SOCKS5 connect request address"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_DONE); + } + infof(data, "SOCKS5 request granted."); + + return CURLPX_OK; /* Proxy was successful! */ +} + +static CURLcode connect_SOCKS(struct Curl_cfilter *cf, + struct socks_state *sxstate, + struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + CURLproxycode pxresult = CURLPX_OK; + struct connectdata *conn = cf->conn; + + switch(conn->socks_proxy.proxytype) { + case CURLPROXY_SOCKS5: + case CURLPROXY_SOCKS5_HOSTNAME: + pxresult = do_SOCKS5(cf, sxstate, data); + break; + + case CURLPROXY_SOCKS4: + case CURLPROXY_SOCKS4A: + pxresult = do_SOCKS4(cf, sxstate, data); + break; + + default: + failf(data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + } /* switch proxytype */ + if(pxresult) { + result = CURLE_PROXY; + data->info.pxcode = pxresult; + } + + return result; +} + +static void socks_proxy_cf_free(struct Curl_cfilter *cf) +{ + struct socks_state *sxstate = cf->ctx; + if(sxstate) { + free(sxstate); + cf->ctx = NULL; + } +} + +/* After a TCP connection to the proxy has been verified, this function does + the next magic steps. If 'done' isn't set TRUE, it is not done yet and + must be called again. + + Note: this function's sub-functions call failf() + +*/ +static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + CURLcode result; + struct connectdata *conn = cf->conn; + int sockindex = cf->sockindex; + struct socks_state *sx = cf->ctx; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + result = cf->next->cft->do_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + + if(!sx) { + sx = calloc(1, sizeof(*sx)); + if(!sx) + return CURLE_OUT_OF_MEMORY; + cf->ctx = sx; + } + + if(sx->state == CONNECT_INIT) { + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + sxstate(sx, data, CONNECT_SOCKS_INIT); + sx->hostname = + conn->bits.httpproxy ? + conn->http_proxy.host.name : + conn->bits.conn_to_host ? + conn->conn_to_host.name : + sockindex == SECONDARYSOCKET ? + conn->secondaryhostname : conn->host.name; + sx->remote_port = + conn->bits.httpproxy ? (int)conn->http_proxy.port : + sockindex == SECONDARYSOCKET ? conn->secondary_port : + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; + sx->proxy_user = conn->socks_proxy.user; + sx->proxy_password = conn->socks_proxy.passwd; + } + + result = connect_SOCKS(cf, sx, data); + if(!result && sx->state == CONNECT_DONE) { + cf->connected = TRUE; + Curl_verboseconnect(data, conn); + socks_proxy_cf_free(cf); + } + + *done = cf->connected; + return result; +} + +static void socks_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct socks_state *sx = cf->ctx; + + if(!cf->connected && sx) { + /* If we are not connected, the filter below is and has nothing + * to wait on, we determine what to wait for. */ + curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); + switch(sx->state) { + case CONNECT_RESOLVING: + case CONNECT_SOCKS_READ: + case CONNECT_AUTH_READ: + case CONNECT_REQ_READ: + case CONNECT_REQ_READ_MORE: + Curl_pollset_set_in_only(data, ps, sock); + break; + default: + Curl_pollset_set_out_only(data, ps, sock); + break; + } + } +} + +static void socks_proxy_cf_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + + DEBUGASSERT(cf->next); + cf->connected = FALSE; + socks_proxy_cf_free(cf); + cf->next->cft->do_close(cf->next, data); +} + +static void socks_proxy_cf_destroy(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + (void)data; + socks_proxy_cf_free(cf); +} + +static void socks_cf_get_host(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char **phost, + const char **pdisplay_host, + int *pport) +{ + (void)data; + if(!cf->connected) { + *phost = cf->conn->socks_proxy.host.name; + *pdisplay_host = cf->conn->http_proxy.host.dispname; + *pport = (int)cf->conn->socks_proxy.port; + } + else { + cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport); + } +} + +struct Curl_cftype Curl_cft_socks_proxy = { + "SOCKS-PROXYY", + CF_TYPE_IP_CONNECT, + 0, + socks_proxy_cf_destroy, + socks_proxy_cf_connect, + socks_proxy_cf_close, + socks_cf_get_host, + socks_cf_adjust_pollset, + Curl_cf_def_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, +}; + +CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + CURLcode result; + + (void)data; + result = Curl_cf_create(&cf, &Curl_cft_socks_proxy, NULL); + if(!result) + Curl_conn_cf_insert_after(cf_at, cf); + return result; +} + +#endif /* CURL_DISABLE_PROXY */ diff --git a/lib/socks.h b/lib/socks.h new file mode 100644 index 0000000..a3adcc6 --- /dev/null +++ b/lib/socks.h @@ -0,0 +1,61 @@ +#ifndef HEADER_CURL_SOCKS_H +#define HEADER_CURL_SOCKS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef CURL_DISABLE_PROXY +#define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN +#define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN +#define Curl_SOCKS_getsock(x,y,z) 0 +#else +/* + * Helper read-from-socket functions. Does the same as Curl_read() but it + * blocks until all bytes amount of buffersize will be read. No more, no less. + * + * This is STUPID BLOCKING behavior + */ +int Curl_blockread_all(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, + ssize_t buffersize, + ssize_t *n); + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) +/* + * This function handles the SOCKS5 GSS-API negotiation and initialization + */ +CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, + struct Curl_easy *data); +#endif + +CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data); + +extern struct Curl_cftype Curl_cft_socks_proxy; + +#endif /* CURL_DISABLE_PROXY */ + +#endif /* HEADER_CURL_SOCKS_H */ diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c new file mode 100644 index 0000000..2437150 --- /dev/null +++ b/lib/socks_gssapi.c @@ -0,0 +1,535 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Markus Moeller, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY) + +#include "curl_gssapi.h" +#include "urldata.h" +#include "sendf.h" +#include "cfilters.h" +#include "connect.h" +#include "timeval.h" +#include "socks.h" +#include "warnless.h" +#include "strdup.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; + +/* + * Helper GSS-API error functions. + */ +static int check_gss_err(struct Curl_easy *data, + OM_uint32 major_status, + OM_uint32 minor_status, + const char *function) +{ + if(GSS_ERROR(major_status)) { + OM_uint32 maj_stat, min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER; + char buf[1024]; + size_t len; + + len = 0; + msg_ctx = 0; + while(!msg_ctx) { + /* convert major status code (GSS-API error) to text */ + maj_stat = gss_display_status(&min_stat, major_status, + GSS_C_GSS_CODE, + GSS_C_NULL_OID, + &msg_ctx, &status_string); + if(maj_stat == GSS_S_COMPLETE) { + if(sizeof(buf) > len + status_string.length + 1) { + strcpy(buf + len, (char *) status_string.value); + len += status_string.length; + } + gss_release_buffer(&min_stat, &status_string); + break; + } + gss_release_buffer(&min_stat, &status_string); + } + if(sizeof(buf) > len + 3) { + strcpy(buf + len, ".\n"); + len += 2; + } + msg_ctx = 0; + while(!msg_ctx) { + /* convert minor status code (underlying routine error) to text */ + maj_stat = gss_display_status(&min_stat, minor_status, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, &status_string); + if(maj_stat == GSS_S_COMPLETE) { + if(sizeof(buf) > len + status_string.length) + strcpy(buf + len, (char *) status_string.value); + gss_release_buffer(&min_stat, &status_string); + break; + } + gss_release_buffer(&min_stat, &status_string); + } + failf(data, "GSS-API error: %s failed: %s", function, buf); + return 1; + } + + return 0; +} + +CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct connectdata *conn = cf->conn; + curl_socket_t sock = conn->sock[cf->sockindex]; + CURLcode code; + ssize_t actualread; + ssize_t nwritten; + int result; + OM_uint32 gss_major_status, gss_minor_status, gss_status; + OM_uint32 gss_ret_flags; + int gss_conf_state, gss_enc; + gss_buffer_desc service = GSS_C_EMPTY_BUFFER; + gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc *gss_token = GSS_C_NO_BUFFER; + gss_name_t server = GSS_C_NO_NAME; + gss_name_t gss_client_name = GSS_C_NO_NAME; + unsigned short us_length; + char *user = NULL; + unsigned char socksreq[4]; /* room for GSS-API exchange header only */ + const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + const size_t serviceptr_length = strlen(serviceptr); + + /* GSS-API request looks like + * +----+------+-----+----------------+ + * |VER | MTYP | LEN | TOKEN | + * +----+------+----------------------+ + * | 1 | 1 | 2 | up to 2^16 - 1 | + * +----+------+-----+----------------+ + */ + + /* prepare service name */ + if(strchr(serviceptr, '/')) { + service.length = serviceptr_length; + service.value = Curl_memdup(serviceptr, service.length); + if(!service.value) + return CURLE_OUT_OF_MEMORY; + + gss_major_status = gss_import_name(&gss_minor_status, &service, + (gss_OID) GSS_C_NULL_OID, &server); + } + else { + service.value = malloc(serviceptr_length + + strlen(conn->socks_proxy.host.name) + 2); + if(!service.value) + return CURLE_OUT_OF_MEMORY; + service.length = serviceptr_length + + strlen(conn->socks_proxy.host.name) + 1; + msnprintf(service.value, service.length + 1, "%s@%s", + serviceptr, conn->socks_proxy.host.name); + + gss_major_status = gss_import_name(&gss_minor_status, &service, + GSS_C_NT_HOSTBASED_SERVICE, &server); + } + + gss_release_buffer(&gss_status, &service); /* clear allocated memory */ + + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_import_name()")) { + failf(data, "Failed to create service name."); + gss_release_name(&gss_status, &server); + return CURLE_COULDNT_CONNECT; + } + + (void)curlx_nonblock(sock, FALSE); + + /* As long as we need to keep sending some context info, and there's no */ + /* errors, keep sending it... */ + for(;;) { + gss_major_status = Curl_gss_init_sec_context(data, + &gss_minor_status, + &gss_context, + server, + &Curl_krb5_mech_oid, + NULL, + gss_token, + &gss_send_token, + TRUE, + &gss_ret_flags); + + if(gss_token != GSS_C_NO_BUFFER) + gss_release_buffer(&gss_status, &gss_recv_token); + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_init_sec_context")) { + gss_release_name(&gss_status, &server); + gss_release_buffer(&gss_status, &gss_recv_token); + gss_release_buffer(&gss_status, &gss_send_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + failf(data, "Failed to initial GSS-API token."); + return CURLE_COULDNT_CONNECT; + } + + if(gss_send_token.length) { + socksreq[0] = 1; /* GSS-API subnegotiation version */ + socksreq[1] = 1; /* authentication message type */ + us_length = htons((short)gss_send_token.length); + memcpy(socksreq + 2, &us_length, sizeof(short)); + + nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); + if(code || (4 != nwritten)) { + failf(data, "Failed to send GSS-API authentication request."); + gss_release_name(&gss_status, &server); + gss_release_buffer(&gss_status, &gss_recv_token); + gss_release_buffer(&gss_status, &gss_send_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + nwritten = Curl_conn_cf_send(cf->next, data, + (char *)gss_send_token.value, + gss_send_token.length, &code); + if(code || ((ssize_t)gss_send_token.length != nwritten)) { + failf(data, "Failed to send GSS-API authentication token."); + gss_release_name(&gss_status, &server); + gss_release_buffer(&gss_status, &gss_recv_token); + gss_release_buffer(&gss_status, &gss_send_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + } + + gss_release_buffer(&gss_status, &gss_send_token); + gss_release_buffer(&gss_status, &gss_recv_token); + if(gss_major_status != GSS_S_CONTINUE_NEEDED) + break; + + /* analyse response */ + + /* GSS-API response looks like + * +----+------+-----+----------------+ + * |VER | MTYP | LEN | TOKEN | + * +----+------+----------------------+ + * | 1 | 1 | 2 | up to 2^16 - 1 | + * +----+------+-----+----------------+ + */ + + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { + failf(data, "Failed to receive GSS-API authentication response."); + gss_release_name(&gss_status, &server); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + /* ignore the first (VER) byte */ + if(socksreq[1] == 255) { /* status / message type */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + gss_release_name(&gss_status, &server); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + if(socksreq[1] != 1) { /* status / message type */ + failf(data, "Invalid GSS-API authentication response type (%d %d).", + socksreq[0], socksreq[1]); + gss_release_name(&gss_status, &server); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + memcpy(&us_length, socksreq + 2, sizeof(short)); + us_length = ntohs(us_length); + + gss_recv_token.length = us_length; + gss_recv_token.value = malloc(us_length); + if(!gss_recv_token.value) { + failf(data, + "Could not allocate memory for GSS-API authentication " + "response token."); + gss_release_name(&gss_status, &server); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_OUT_OF_MEMORY; + } + + result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value, + gss_recv_token.length, &actualread); + + if(result || (actualread != us_length)) { + failf(data, "Failed to receive GSS-API authentication token."); + gss_release_name(&gss_status, &server); + gss_release_buffer(&gss_status, &gss_recv_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + gss_token = &gss_recv_token; + } + + gss_release_name(&gss_status, &server); + + /* Everything is good so far, user was authenticated! */ + gss_major_status = gss_inquire_context(&gss_minor_status, gss_context, + &gss_client_name, NULL, NULL, NULL, + NULL, NULL, NULL); + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_inquire_context")) { + gss_delete_sec_context(&gss_status, &gss_context, NULL); + gss_release_name(&gss_status, &gss_client_name); + failf(data, "Failed to determine user name."); + return CURLE_COULDNT_CONNECT; + } + gss_major_status = gss_display_name(&gss_minor_status, gss_client_name, + &gss_send_token, NULL); + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_display_name")) { + gss_delete_sec_context(&gss_status, &gss_context, NULL); + gss_release_name(&gss_status, &gss_client_name); + gss_release_buffer(&gss_status, &gss_send_token); + failf(data, "Failed to determine user name."); + return CURLE_COULDNT_CONNECT; + } + user = malloc(gss_send_token.length + 1); + if(!user) { + gss_delete_sec_context(&gss_status, &gss_context, NULL); + gss_release_name(&gss_status, &gss_client_name); + gss_release_buffer(&gss_status, &gss_send_token); + return CURLE_OUT_OF_MEMORY; + } + + memcpy(user, gss_send_token.value, gss_send_token.length); + user[gss_send_token.length] = '\0'; + gss_release_name(&gss_status, &gss_client_name); + gss_release_buffer(&gss_status, &gss_send_token); + infof(data, "SOCKS5 server authenticated user %s with GSS-API.",user); + free(user); + user = NULL; + + /* Do encryption */ + socksreq[0] = 1; /* GSS-API subnegotiation version */ + socksreq[1] = 2; /* encryption message type */ + + gss_enc = 0; /* no data protection */ + /* do confidentiality protection if supported */ + if(gss_ret_flags & GSS_C_CONF_FLAG) + gss_enc = 2; + /* else do integrity protection */ + else if(gss_ret_flags & GSS_C_INTEG_FLAG) + gss_enc = 1; + + infof(data, "SOCKS5 server supports GSS-API %s data protection.", + (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality")); + /* force for the moment to no data protection */ + gss_enc = 0; + /* + * Sending the encryption type in clear seems wrong. It should be + * protected with gss_seal()/gss_wrap(). See RFC1961 extract below + * The NEC reference implementations on which this is based is + * therefore at fault + * + * +------+------+------+.......................+ + * + ver | mtyp | len | token | + * +------+------+------+.......................+ + * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | + * +------+------+------+.......................+ + * + * Where: + * + * - "ver" is the protocol version number, here 1 to represent the + * first version of the SOCKS/GSS-API protocol + * + * - "mtyp" is the message type, here 2 to represent a protection + * -level negotiation message + * + * - "len" is the length of the "token" field in octets + * + * - "token" is the GSS-API encapsulated protection level + * + * The token is produced by encapsulating an octet containing the + * required protection level using gss_seal()/gss_wrap() with conf_req + * set to FALSE. The token is verified using gss_unseal()/ + * gss_unwrap(). + * + */ + if(data->set.socks5_gssapi_nec) { + us_length = htons((short)1); + memcpy(socksreq + 2, &us_length, sizeof(short)); + } + else { + gss_send_token.length = 1; + gss_send_token.value = Curl_memdup(&gss_enc, 1); + if(!gss_send_token.value) { + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_OUT_OF_MEMORY; + } + + gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0, + GSS_C_QOP_DEFAULT, &gss_send_token, + &gss_conf_state, &gss_w_token); + + if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) { + gss_release_buffer(&gss_status, &gss_send_token); + gss_release_buffer(&gss_status, &gss_w_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + failf(data, "Failed to wrap GSS-API encryption value into token."); + return CURLE_COULDNT_CONNECT; + } + gss_release_buffer(&gss_status, &gss_send_token); + + us_length = htons((short)gss_w_token.length); + memcpy(socksreq + 2, &us_length, sizeof(short)); + } + + nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); + if(code || (4 != nwritten)) { + failf(data, "Failed to send GSS-API encryption request."); + gss_release_buffer(&gss_status, &gss_w_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + if(data->set.socks5_gssapi_nec) { + memcpy(socksreq, &gss_enc, 1); + nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code); + if(code || ( 1 != nwritten)) { + failf(data, "Failed to send GSS-API encryption type."); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + } + else { + nwritten = Curl_conn_cf_send(cf->next, data, + (char *)gss_w_token.value, + gss_w_token.length, &code); + if(code || ((ssize_t)gss_w_token.length != nwritten)) { + failf(data, "Failed to send GSS-API encryption type."); + gss_release_buffer(&gss_status, &gss_w_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + gss_release_buffer(&gss_status, &gss_w_token); + } + + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { + failf(data, "Failed to receive GSS-API encryption response."); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + /* ignore the first (VER) byte */ + if(socksreq[1] == 255) { /* status / message type */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + if(socksreq[1] != 2) { /* status / message type */ + failf(data, "Invalid GSS-API encryption response type (%d %d).", + socksreq[0], socksreq[1]); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + memcpy(&us_length, socksreq + 2, sizeof(short)); + us_length = ntohs(us_length); + + gss_recv_token.length = us_length; + gss_recv_token.value = malloc(gss_recv_token.length); + if(!gss_recv_token.value) { + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_OUT_OF_MEMORY; + } + result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value, + gss_recv_token.length, &actualread); + + if(result || (actualread != us_length)) { + failf(data, "Failed to receive GSS-API encryptrion type."); + gss_release_buffer(&gss_status, &gss_recv_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + if(!data->set.socks5_gssapi_nec) { + gss_major_status = gss_unwrap(&gss_minor_status, gss_context, + &gss_recv_token, &gss_w_token, + 0, GSS_C_QOP_DEFAULT); + + if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) { + gss_release_buffer(&gss_status, &gss_recv_token); + gss_release_buffer(&gss_status, &gss_w_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + failf(data, "Failed to unwrap GSS-API encryption value into token."); + return CURLE_COULDNT_CONNECT; + } + gss_release_buffer(&gss_status, &gss_recv_token); + + if(gss_w_token.length != 1) { + failf(data, "Invalid GSS-API encryption response length (%zu).", + gss_w_token.length); + gss_release_buffer(&gss_status, &gss_w_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + memcpy(socksreq, gss_w_token.value, gss_w_token.length); + gss_release_buffer(&gss_status, &gss_w_token); + } + else { + if(gss_recv_token.length != 1) { + failf(data, "Invalid GSS-API encryption response length (%zu).", + gss_recv_token.length); + gss_release_buffer(&gss_status, &gss_recv_token); + gss_delete_sec_context(&gss_status, &gss_context, NULL); + return CURLE_COULDNT_CONNECT; + } + + memcpy(socksreq, gss_recv_token.value, gss_recv_token.length); + gss_release_buffer(&gss_status, &gss_recv_token); + } + + (void)curlx_nonblock(sock, TRUE); + + infof(data, "SOCKS5 access with%s protection granted.", + (socksreq[0] == 0)?"out GSS-API data": + ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); + + conn->socks5_gssapi_enctype = socksreq[0]; + if(socksreq[0] == 0) + gss_delete_sec_context(&gss_status, &gss_context, NULL); + + return CURLE_OK; +} + +#endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */ diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c new file mode 100644 index 0000000..2baae2c --- /dev/null +++ b/lib/socks_sspi.c @@ -0,0 +1,620 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Markus Moeller, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY) + +#include "urldata.h" +#include "sendf.h" +#include "cfilters.h" +#include "connect.h" +#include "strerror.h" +#include "timeval.h" +#include "socks.h" +#include "curl_sspi.h" +#include "curl_multibyte.h" +#include "warnless.h" +#include "strdup.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Helper sspi error functions. + */ +static int check_sspi_err(struct Curl_easy *data, + SECURITY_STATUS status, + const char *function) +{ + if(status != SEC_E_OK && + status != SEC_I_COMPLETE_AND_CONTINUE && + status != SEC_I_COMPLETE_NEEDED && + status != SEC_I_CONTINUE_NEEDED) { + char buffer[STRERROR_LEN]; + failf(data, "SSPI error: %s failed: %s", function, + Curl_sspi_strerror(status, buffer, sizeof(buffer))); + return 1; + } + return 0; +} + +/* This is the SSPI-using version of this function */ +CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct connectdata *conn = cf->conn; + curl_socket_t sock = conn->sock[cf->sockindex]; + CURLcode code; + ssize_t actualread; + ssize_t written; + int result; + /* Needs GSS-API authentication */ + SECURITY_STATUS status; + unsigned long sspi_ret_flags = 0; + unsigned char gss_enc; + SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; + SecBufferDesc input_desc, output_desc, wrap_desc; + SecPkgContext_Sizes sspi_sizes; + CredHandle cred_handle; + CtxtHandle sspi_context; + PCtxtHandle context_handle = NULL; + SecPkgCredentials_Names names; + TimeStamp expiry; + char *service_name = NULL; + unsigned short us_length; + unsigned long qop; + unsigned char socksreq[4]; /* room for GSS-API exchange header only */ + const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + const size_t service_length = strlen(service); + + /* GSS-API request looks like + * +----+------+-----+----------------+ + * |VER | MTYP | LEN | TOKEN | + * +----+------+----------------------+ + * | 1 | 1 | 2 | up to 2^16 - 1 | + * +----+------+-----+----------------+ + */ + + /* prepare service name */ + if(strchr(service, '/')) { + service_name = strdup(service); + if(!service_name) + return CURLE_OUT_OF_MEMORY; + } + else { + service_name = malloc(service_length + + strlen(conn->socks_proxy.host.name) + 2); + if(!service_name) + return CURLE_OUT_OF_MEMORY; + msnprintf(service_name, service_length + + strlen(conn->socks_proxy.host.name) + 2, "%s/%s", + service, conn->socks_proxy.host.name); + } + + input_desc.cBuffers = 1; + input_desc.pBuffers = &sspi_recv_token; + input_desc.ulVersion = SECBUFFER_VERSION; + + sspi_recv_token.BufferType = SECBUFFER_TOKEN; + sspi_recv_token.cbBuffer = 0; + sspi_recv_token.pvBuffer = NULL; + + output_desc.cBuffers = 1; + output_desc.pBuffers = &sspi_send_token; + output_desc.ulVersion = SECBUFFER_VERSION; + + sspi_send_token.BufferType = SECBUFFER_TOKEN; + sspi_send_token.cbBuffer = 0; + sspi_send_token.pvBuffer = NULL; + + wrap_desc.cBuffers = 3; + wrap_desc.pBuffers = sspi_w_token; + wrap_desc.ulVersion = SECBUFFER_VERSION; + + cred_handle.dwLower = 0; + cred_handle.dwUpper = 0; + + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT("Kerberos"), + SECPKG_CRED_OUTBOUND, + NULL, + NULL, + NULL, + NULL, + &cred_handle, + &expiry); + + if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { + failf(data, "Failed to acquire credentials."); + free(service_name); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + return CURLE_COULDNT_CONNECT; + } + + (void)curlx_nonblock(sock, FALSE); + + /* As long as we need to keep sending some context info, and there's no */ + /* errors, keep sending it... */ + for(;;) { + TCHAR *sname; + + sname = curlx_convert_UTF8_to_tchar(service_name); + if(!sname) + return CURLE_OUT_OF_MEMORY; + + status = s_pSecFn->InitializeSecurityContext(&cred_handle, + context_handle, + sname, + ISC_REQ_MUTUAL_AUTH | + ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT, + 0, + SECURITY_NATIVE_DREP, + &input_desc, + 0, + &sspi_context, + &output_desc, + &sspi_ret_flags, + &expiry); + + curlx_unicodefree(sname); + + if(sspi_recv_token.pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + sspi_recv_token.pvBuffer = NULL; + sspi_recv_token.cbBuffer = 0; + } + + if(check_sspi_err(data, status, "InitializeSecurityContext")) { + free(service_name); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + failf(data, "Failed to initialise security context."); + return CURLE_COULDNT_CONNECT; + } + + if(sspi_send_token.cbBuffer) { + socksreq[0] = 1; /* GSS-API subnegotiation version */ + socksreq[1] = 1; /* authentication message type */ + us_length = htons((short)sspi_send_token.cbBuffer); + memcpy(socksreq + 2, &us_length, sizeof(short)); + + written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); + if(code || (4 != written)) { + failf(data, "Failed to send SSPI authentication request."); + free(service_name); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + written = Curl_conn_cf_send(cf->next, data, + (char *)sspi_send_token.pvBuffer, + sspi_send_token.cbBuffer, &code); + if(code || (sspi_send_token.cbBuffer != (size_t)written)) { + failf(data, "Failed to send SSPI authentication token."); + free(service_name); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + } + + if(sspi_send_token.pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + sspi_send_token.pvBuffer = NULL; + } + sspi_send_token.cbBuffer = 0; + + if(sspi_recv_token.pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + sspi_recv_token.pvBuffer = NULL; + } + sspi_recv_token.cbBuffer = 0; + + if(status != SEC_I_CONTINUE_NEEDED) + break; + + /* analyse response */ + + /* GSS-API response looks like + * +----+------+-----+----------------+ + * |VER | MTYP | LEN | TOKEN | + * +----+------+----------------------+ + * | 1 | 1 | 2 | up to 2^16 - 1 | + * +----+------+-----+----------------+ + */ + + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { + failf(data, "Failed to receive SSPI authentication response."); + free(service_name); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + /* ignore the first (VER) byte */ + if(socksreq[1] == 255) { /* status / message type */ + failf(data, "User was rejected by the SOCKS5 server (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); + free(service_name); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + if(socksreq[1] != 1) { /* status / message type */ + failf(data, "Invalid SSPI authentication response type (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); + free(service_name); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + memcpy(&us_length, socksreq + 2, sizeof(short)); + us_length = ntohs(us_length); + + sspi_recv_token.cbBuffer = us_length; + sspi_recv_token.pvBuffer = malloc(us_length); + + if(!sspi_recv_token.pvBuffer) { + free(service_name); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_OUT_OF_MEMORY; + } + result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, + sspi_recv_token.cbBuffer, &actualread); + + if(result || (actualread != us_length)) { + failf(data, "Failed to receive SSPI authentication token."); + free(service_name); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + context_handle = &sspi_context; + } + + free(service_name); + + /* Everything is good so far, user was authenticated! */ + status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, + SECPKG_CRED_ATTR_NAMES, + &names); + s_pSecFn->FreeCredentialsHandle(&cred_handle); + if(check_sspi_err(data, status, "QueryCredentialAttributes")) { + s_pSecFn->DeleteSecurityContext(&sspi_context); + s_pSecFn->FreeContextBuffer(names.sUserName); + failf(data, "Failed to determine user name."); + return CURLE_COULDNT_CONNECT; + } + else { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName); + infof(data, "SOCKS5 server authenticated user %s with GSS-API.", + (user_utf8 ? user_utf8 : "(unknown)")); + curlx_unicodefree(user_utf8); +#endif + s_pSecFn->FreeContextBuffer(names.sUserName); + } + + /* Do encryption */ + socksreq[0] = 1; /* GSS-API subnegotiation version */ + socksreq[1] = 2; /* encryption message type */ + + gss_enc = 0; /* no data protection */ + /* do confidentiality protection if supported */ + if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) + gss_enc = 2; + /* else do integrity protection */ + else if(sspi_ret_flags & ISC_REQ_INTEGRITY) + gss_enc = 1; + + infof(data, "SOCKS5 server supports GSS-API %s data protection.", + (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") ); + /* force to no data protection, avoid encryption/decryption for now */ + gss_enc = 0; + /* + * Sending the encryption type in clear seems wrong. It should be + * protected with gss_seal()/gss_wrap(). See RFC1961 extract below + * The NEC reference implementations on which this is based is + * therefore at fault + * + * +------+------+------+.......................+ + * + ver | mtyp | len | token | + * +------+------+------+.......................+ + * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | + * +------+------+------+.......................+ + * + * Where: + * + * - "ver" is the protocol version number, here 1 to represent the + * first version of the SOCKS/GSS-API protocol + * + * - "mtyp" is the message type, here 2 to represent a protection + * -level negotiation message + * + * - "len" is the length of the "token" field in octets + * + * - "token" is the GSS-API encapsulated protection level + * + * The token is produced by encapsulating an octet containing the + * required protection level using gss_seal()/gss_wrap() with conf_req + * set to FALSE. The token is verified using gss_unseal()/ + * gss_unwrap(). + * + */ + + if(data->set.socks5_gssapi_nec) { + us_length = htons((short)1); + memcpy(socksreq + 2, &us_length, sizeof(short)); + } + else { + status = s_pSecFn->QueryContextAttributes(&sspi_context, + SECPKG_ATTR_SIZES, + &sspi_sizes); + if(check_sspi_err(data, status, "QueryContextAttributes")) { + s_pSecFn->DeleteSecurityContext(&sspi_context); + failf(data, "Failed to query security context attributes."); + return CURLE_COULDNT_CONNECT; + } + + sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; + sspi_w_token[0].BufferType = SECBUFFER_TOKEN; + sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); + + if(!sspi_w_token[0].pvBuffer) { + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_OUT_OF_MEMORY; + } + + sspi_w_token[1].cbBuffer = 1; + sspi_w_token[1].pvBuffer = malloc(1); + if(!sspi_w_token[1].pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_OUT_OF_MEMORY; + } + + memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); + sspi_w_token[2].BufferType = SECBUFFER_PADDING; + sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; + sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); + if(!sspi_w_token[2].pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_OUT_OF_MEMORY; + } + status = s_pSecFn->EncryptMessage(&sspi_context, + KERB_WRAP_NO_ENCRYPT, + &wrap_desc, + 0); + if(check_sspi_err(data, status, "EncryptMessage")) { + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + failf(data, "Failed to query security context attributes."); + return CURLE_COULDNT_CONNECT; + } + sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer + + sspi_w_token[1].cbBuffer + + sspi_w_token[2].cbBuffer; + sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); + if(!sspi_send_token.pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_OUT_OF_MEMORY; + } + + memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, + sspi_w_token[0].cbBuffer); + memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, + sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); + memcpy((PUCHAR) sspi_send_token.pvBuffer + + sspi_w_token[0].cbBuffer + + sspi_w_token[1].cbBuffer, + sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); + + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + sspi_w_token[0].pvBuffer = NULL; + sspi_w_token[0].cbBuffer = 0; + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + sspi_w_token[1].pvBuffer = NULL; + sspi_w_token[1].cbBuffer = 0; + s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); + sspi_w_token[2].pvBuffer = NULL; + sspi_w_token[2].cbBuffer = 0; + + us_length = htons((short)sspi_send_token.cbBuffer); + memcpy(socksreq + 2, &us_length, sizeof(short)); + } + + written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); + if(code || (4 != written)) { + failf(data, "Failed to send SSPI encryption request."); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + if(data->set.socks5_gssapi_nec) { + memcpy(socksreq, &gss_enc, 1); + written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code); + if(code || (1 != written)) { + failf(data, "Failed to send SSPI encryption type."); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + } + else { + written = Curl_conn_cf_send(cf->next, data, + (char *)sspi_send_token.pvBuffer, + sspi_send_token.cbBuffer, &code); + if(code || (sspi_send_token.cbBuffer != (size_t)written)) { + failf(data, "Failed to send SSPI encryption type."); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + } + + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { + failf(data, "Failed to receive SSPI encryption response."); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + /* ignore the first (VER) byte */ + if(socksreq[1] == 255) { /* status / message type */ + failf(data, "User was rejected by the SOCKS5 server (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + if(socksreq[1] != 2) { /* status / message type */ + failf(data, "Invalid SSPI encryption response type (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + memcpy(&us_length, socksreq + 2, sizeof(short)); + us_length = ntohs(us_length); + + sspi_w_token[0].cbBuffer = us_length; + sspi_w_token[0].pvBuffer = malloc(us_length); + if(!sspi_w_token[0].pvBuffer) { + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_OUT_OF_MEMORY; + } + + result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, + sspi_w_token[0].cbBuffer, &actualread); + + if(result || (actualread != us_length)) { + failf(data, "Failed to receive SSPI encryption type."); + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + + if(!data->set.socks5_gssapi_nec) { + wrap_desc.cBuffers = 2; + sspi_w_token[0].BufferType = SECBUFFER_STREAM; + sspi_w_token[1].BufferType = SECBUFFER_DATA; + sspi_w_token[1].cbBuffer = 0; + sspi_w_token[1].pvBuffer = NULL; + + status = s_pSecFn->DecryptMessage(&sspi_context, + &wrap_desc, + 0, + &qop); + + if(check_sspi_err(data, status, "DecryptMessage")) { + if(sspi_w_token[0].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + if(sspi_w_token[1].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + failf(data, "Failed to query security context attributes."); + return CURLE_COULDNT_CONNECT; + } + + if(sspi_w_token[1].cbBuffer != 1) { + failf(data, "Invalid SSPI encryption response length (%lu).", + (unsigned long)sspi_w_token[1].cbBuffer); + if(sspi_w_token[0].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + if(sspi_w_token[1].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + + memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + } + else { + if(sspi_w_token[0].cbBuffer != 1) { + failf(data, "Invalid SSPI encryption response length (%lu).", + (unsigned long)sspi_w_token[0].cbBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + s_pSecFn->DeleteSecurityContext(&sspi_context); + return CURLE_COULDNT_CONNECT; + } + memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + } + (void)curlx_nonblock(sock, TRUE); + + infof(data, "SOCKS5 access with%s protection granted.", + (socksreq[0] == 0)?"out GSS-API data": + ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); + + /* For later use if encryption is required + conn->socks5_gssapi_enctype = socksreq[0]; + if(socksreq[0] != 0) + conn->socks5_sspi_context = sspi_context; + else { + s_pSecFn->DeleteSecurityContext(&sspi_context); + conn->socks5_sspi_context = sspi_context; + } + */ + return CURLE_OK; +} +#endif diff --git a/lib/speedcheck.c b/lib/speedcheck.c new file mode 100644 index 0000000..580efbd --- /dev/null +++ b/lib/speedcheck.c @@ -0,0 +1,79 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "urldata.h" +#include "sendf.h" +#include "multiif.h" +#include "speedcheck.h" + +void Curl_speedinit(struct Curl_easy *data) +{ + memset(&data->state.keeps_speed, 0, sizeof(struct curltime)); +} + +/* + * @unittest: 1606 + */ +CURLcode Curl_speedcheck(struct Curl_easy *data, + struct curltime now) +{ + if(data->req.keepon & KEEP_RECV_PAUSE) + /* A paused transfer is not qualified for speed checks */ + return CURLE_OK; + + if((data->progress.current_speed >= 0) && data->set.low_speed_time) { + if(data->progress.current_speed < data->set.low_speed_limit) { + if(!data->state.keeps_speed.tv_sec) + /* under the limit at this very moment */ + data->state.keeps_speed = now; + else { + /* how long has it been under the limit */ + timediff_t howlong = Curl_timediff(now, data->state.keeps_speed); + + if(howlong >= data->set.low_speed_time * 1000) { + /* too long */ + failf(data, + "Operation too slow. " + "Less than %ld bytes/sec transferred the last %ld seconds", + data->set.low_speed_limit, + data->set.low_speed_time); + return CURLE_OPERATION_TIMEDOUT; + } + } + } + else + /* faster right now */ + data->state.keeps_speed.tv_sec = 0; + } + + if(data->set.low_speed_limit) + /* if low speed limit is enabled, set the expire timer to make this + connection's speed get checked again in a second */ + Curl_expire(data, 1000, EXPIRE_SPEEDCHECK); + + return CURLE_OK; +} diff --git a/lib/speedcheck.h b/lib/speedcheck.h new file mode 100644 index 0000000..bff2f32 --- /dev/null +++ b/lib/speedcheck.h @@ -0,0 +1,35 @@ +#ifndef HEADER_CURL_SPEEDCHECK_H +#define HEADER_CURL_SPEEDCHECK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "timeval.h" + +void Curl_speedinit(struct Curl_easy *data); +CURLcode Curl_speedcheck(struct Curl_easy *data, + struct curltime now); + +#endif /* HEADER_CURL_SPEEDCHECK_H */ diff --git a/lib/splay.c b/lib/splay.c new file mode 100644 index 0000000..48e079b --- /dev/null +++ b/lib/splay.c @@ -0,0 +1,278 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "splay.h" + +/* + * This macro compares two node keys i and j and returns: + * + * negative value: when i is smaller than j + * zero : when i is equal to j + * positive when : when i is larger than j + */ +#define compare(i,j) Curl_splaycomparekeys((i),(j)) + +/* + * Splay using the key i (which may or may not be in the tree.) The starting + * root is t. + */ +struct Curl_tree *Curl_splay(struct curltime i, + struct Curl_tree *t) +{ + struct Curl_tree N, *l, *r, *y; + + if(!t) + return t; + N.smaller = N.larger = NULL; + l = r = &N; + + for(;;) { + long comp = compare(i, t->key); + if(comp < 0) { + if(!t->smaller) + break; + if(compare(i, t->smaller->key) < 0) { + y = t->smaller; /* rotate smaller */ + t->smaller = y->larger; + y->larger = t; + t = y; + if(!t->smaller) + break; + } + r->smaller = t; /* link smaller */ + r = t; + t = t->smaller; + } + else if(comp > 0) { + if(!t->larger) + break; + if(compare(i, t->larger->key) > 0) { + y = t->larger; /* rotate larger */ + t->larger = y->smaller; + y->smaller = t; + t = y; + if(!t->larger) + break; + } + l->larger = t; /* link larger */ + l = t; + t = t->larger; + } + else + break; + } + + l->larger = t->smaller; /* assemble */ + r->smaller = t->larger; + t->smaller = N.larger; + t->larger = N.smaller; + + return t; +} + +/* Insert key i into the tree t. Return a pointer to the resulting tree or + * NULL if something went wrong. + * + * @unittest: 1309 + */ +struct Curl_tree *Curl_splayinsert(struct curltime i, + struct Curl_tree *t, + struct Curl_tree *node) +{ + static const struct curltime KEY_NOTUSED = { + ~0, -1 + }; /* will *NEVER* appear */ + + if(!node) + return t; + + if(t) { + t = Curl_splay(i, t); + if(compare(i, t->key) == 0) { + /* There already exists a node in the tree with the very same key. Build + a doubly-linked circular list of nodes. We add the new 'node' struct + to the end of this list. */ + + node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED + to quickly identify this node as a subnode */ + node->samen = t; + node->samep = t->samep; + t->samep->samen = node; + t->samep = node; + + return t; /* the root node always stays the same */ + } + } + + if(!t) { + node->smaller = node->larger = NULL; + } + else if(compare(i, t->key) < 0) { + node->smaller = t->smaller; + node->larger = t; + t->smaller = NULL; + + } + else { + node->larger = t->larger; + node->smaller = t; + t->larger = NULL; + } + node->key = i; + + /* no identical nodes (yet), we are the only one in the list of nodes */ + node->samen = node; + node->samep = node; + return node; +} + +/* Finds and deletes the best-fit node from the tree. Return a pointer to the + resulting tree. best-fit means the smallest node if it is not larger than + the key */ +struct Curl_tree *Curl_splaygetbest(struct curltime i, + struct Curl_tree *t, + struct Curl_tree **removed) +{ + static const struct curltime tv_zero = {0, 0}; + struct Curl_tree *x; + + if(!t) { + *removed = NULL; /* none removed since there was no root */ + return NULL; + } + + /* find smallest */ + t = Curl_splay(tv_zero, t); + if(compare(i, t->key) < 0) { + /* even the smallest is too big */ + *removed = NULL; + return t; + } + + /* FIRST! Check if there is a list with identical keys */ + x = t->samen; + if(x != t) { + /* there is, pick one from the list */ + + /* 'x' is the new root node */ + + x->key = t->key; + x->larger = t->larger; + x->smaller = t->smaller; + x->samep = t->samep; + t->samep->samen = x; + + *removed = t; + return x; /* new root */ + } + + /* we splayed the tree to the smallest element, there is no smaller */ + x = t->larger; + *removed = t; + + return x; +} + + +/* Deletes the very node we point out from the tree if it's there. Stores a + * pointer to the new resulting tree in 'newroot'. + * + * Returns zero on success and non-zero on errors! + * When returning error, it does not touch the 'newroot' pointer. + * + * NOTE: when the last node of the tree is removed, there's no tree left so + * 'newroot' will be made to point to NULL. + * + * @unittest: 1309 + */ +int Curl_splayremove(struct Curl_tree *t, + struct Curl_tree *removenode, + struct Curl_tree **newroot) +{ + static const struct curltime KEY_NOTUSED = { + ~0, -1 + }; /* will *NEVER* appear */ + struct Curl_tree *x; + + if(!t || !removenode) + return 1; + + if(compare(KEY_NOTUSED, removenode->key) == 0) { + /* Key set to NOTUSED means it is a subnode within a 'same' linked list + and thus we can unlink it easily. */ + if(removenode->samen == removenode) + /* A non-subnode should never be set to KEY_NOTUSED */ + return 3; + + removenode->samep->samen = removenode->samen; + removenode->samen->samep = removenode->samep; + + /* Ensures that double-remove gets caught. */ + removenode->samen = removenode; + + *newroot = t; /* return the same root */ + return 0; + } + + t = Curl_splay(removenode->key, t); + + /* First make sure that we got the same root node as the one we want + to remove, as otherwise we might be trying to remove a node that + isn't actually in the tree. + + We cannot just compare the keys here as a double remove in quick + succession of a node with key != KEY_NOTUSED && same != NULL + could return the same key but a different node. */ + if(t != removenode) + return 2; + + /* Check if there is a list with identical sizes, as then we're trying to + remove the root node of a list of nodes with identical keys. */ + x = t->samen; + if(x != t) { + /* 'x' is the new root node, we just make it use the root node's + smaller/larger links */ + + x->key = t->key; + x->larger = t->larger; + x->smaller = t->smaller; + x->samep = t->samep; + t->samep->samen = x; + } + else { + /* Remove the root node */ + if(!t->smaller) + x = t->larger; + else { + x = Curl_splay(removenode->key, t->smaller); + x->larger = t->larger; + } + } + + *newroot = x; /* store new root pointer */ + + return 0; +} diff --git a/lib/splay.h b/lib/splay.h new file mode 100644 index 0000000..dd1d07a --- /dev/null +++ b/lib/splay.h @@ -0,0 +1,58 @@ +#ifndef HEADER_CURL_SPLAY_H +#define HEADER_CURL_SPLAY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" +#include "timeval.h" + +struct Curl_tree { + struct Curl_tree *smaller; /* smaller node */ + struct Curl_tree *larger; /* larger node */ + struct Curl_tree *samen; /* points to the next node with identical key */ + struct Curl_tree *samep; /* points to the prev node with identical key */ + struct curltime key; /* this node's "sort" key */ + void *payload; /* data the splay code doesn't care about */ +}; + +struct Curl_tree *Curl_splay(struct curltime i, + struct Curl_tree *t); + +struct Curl_tree *Curl_splayinsert(struct curltime key, + struct Curl_tree *t, + struct Curl_tree *newnode); + +struct Curl_tree *Curl_splaygetbest(struct curltime key, + struct Curl_tree *t, + struct Curl_tree **removed); + +int Curl_splayremove(struct Curl_tree *t, + struct Curl_tree *removenode, + struct Curl_tree **newroot); + +#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \ + ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \ + ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \ + ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0)))) + +#endif /* HEADER_CURL_SPLAY_H */ diff --git a/lib/strcase.c b/lib/strcase.c new file mode 100644 index 0000000..7c0b4ef --- /dev/null +++ b/lib/strcase.c @@ -0,0 +1,204 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "strcase.h" + +/* Mapping table to go from lowercase to uppercase for plain ASCII.*/ +static const unsigned char touppermap[256] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, +22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, +41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, +60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, +79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, +66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, +85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, +134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, +150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, +166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, +182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, +198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, +214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, +230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, +246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +}; + +/* Mapping table to go from uppercase to lowercase for plain ASCII.*/ +static const unsigned char tolowermap[256] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, +22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, +42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, +62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, +111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, +96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, +112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, +128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, +144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, +160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, +176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, +192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, +208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, +224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, +240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +}; + + +/* Portable, consistent toupper. Do not use toupper() because its behavior is + altered by the current locale. */ +char Curl_raw_toupper(char in) +{ + return touppermap[(unsigned char) in]; +} + + +/* Portable, consistent tolower. Do not use tolower() because its behavior is + altered by the current locale. */ +char Curl_raw_tolower(char in) +{ + return tolowermap[(unsigned char) in]; +} + +/* + * curl_strequal() is for doing "raw" case insensitive strings. This is meant + * to be locale independent and only compare strings we know are safe for + * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for + * further explanations as to why this function is necessary. + */ + +static int casecompare(const char *first, const char *second) +{ + while(*first && *second) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) + /* get out of the loop as soon as they don't match */ + return 0; + first++; + second++; + } + /* If we're here either the strings are the same or the length is different. + We can just test if the "current" character is non-zero for one and zero + for the other. Note that the characters may not be exactly the same even + if they match, we only want to compare zero-ness. */ + return !*first == !*second; +} + +/* --- public function --- */ +int curl_strequal(const char *first, const char *second) +{ + if(first && second) + /* both pointers point to something then compare them */ + return casecompare(first, second); + + /* if both pointers are NULL then treat them as equal */ + return (NULL == first && NULL == second); +} + +static int ncasecompare(const char *first, const char *second, size_t max) +{ + while(*first && *second && max) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) + return 0; + max--; + first++; + second++; + } + if(0 == max) + return 1; /* they are equal this far */ + + return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); +} + +/* --- public function --- */ +int curl_strnequal(const char *first, const char *second, size_t max) +{ + if(first && second) + /* both pointers point to something then compare them */ + return ncasecompare(first, second, max); + + /* if both pointers are NULL then treat them as equal if max is non-zero */ + return (NULL == first && NULL == second && max); +} +/* Copy an upper case version of the string from src to dest. The + * strings may overlap. No more than n characters of the string are copied + * (including any NUL) and the destination string will NOT be + * NUL-terminated if that limit is reached. + */ +void Curl_strntoupper(char *dest, const char *src, size_t n) +{ + if(n < 1) + return; + + do { + *dest++ = Curl_raw_toupper(*src); + } while(*src++ && --n); +} + +/* Copy a lower case version of the string from src to dest. The + * strings may overlap. No more than n characters of the string are copied + * (including any NUL) and the destination string will NOT be + * NUL-terminated if that limit is reached. + */ +void Curl_strntolower(char *dest, const char *src, size_t n) +{ + if(n < 1) + return; + + do { + *dest++ = Curl_raw_tolower(*src); + } while(*src++ && --n); +} + +/* Compare case-sensitive NUL-terminated strings, taking care of possible + * null pointers. Return true if arguments match. + */ +bool Curl_safecmp(char *a, char *b) +{ + if(a && b) + return !strcmp(a, b); + return !a && !b; +} + +/* + * Curl_timestrcmp() returns 0 if the two strings are identical. The time this + * function spends is a function of the shortest string, not of the contents. + */ +int Curl_timestrcmp(const char *a, const char *b) +{ + int match = 0; + int i = 0; + + if(a && b) { + while(1) { + match |= a[i]^b[i]; + if(!a[i] || !b[i]) + break; + i++; + } + } + else + return a || b; + return match; +} diff --git a/lib/strcase.h b/lib/strcase.h new file mode 100644 index 0000000..8c50bbc --- /dev/null +++ b/lib/strcase.h @@ -0,0 +1,54 @@ +#ifndef HEADER_CURL_STRCASE_H +#define HEADER_CURL_STRCASE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +/* + * Only "raw" case insensitive strings. This is meant to be locale independent + * and only compare strings we know are safe for this. + * + * The function is capable of comparing a-z case insensitively. + * + * Result is 1 if text matches and 0 if not. + */ + +#define strcasecompare(a,b) curl_strequal(a,b) +#define strncasecompare(a,b,c) curl_strnequal(a,b,c) + +char Curl_raw_toupper(char in); +char Curl_raw_tolower(char in); + +/* checkprefix() is a shorter version of the above, used when the first + argument is the string literal */ +#define checkprefix(a,b) curl_strnequal(b, STRCONST(a)) + +void Curl_strntoupper(char *dest, const char *src, size_t n); +void Curl_strntolower(char *dest, const char *src, size_t n); + +bool Curl_safecmp(char *a, char *b); +int Curl_timestrcmp(const char *first, const char *second); + +#endif /* HEADER_CURL_STRCASE_H */ diff --git a/lib/strdup.c b/lib/strdup.c new file mode 100644 index 0000000..299c9cc --- /dev/null +++ b/lib/strdup.c @@ -0,0 +1,143 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#ifdef _WIN32 +#include +#endif + +#include "strdup.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#ifndef HAVE_STRDUP +char *Curl_strdup(const char *str) +{ + size_t len; + char *newstr; + + if(!str) + return (char *)NULL; + + len = strlen(str) + 1; + + newstr = malloc(len); + if(!newstr) + return (char *)NULL; + + memcpy(newstr, str, len); + return newstr; +} +#endif + +#ifdef _WIN32 +/*************************************************************************** + * + * Curl_wcsdup(source) + * + * Copies the 'source' wchar string to a newly allocated buffer (that is + * returned). + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +wchar_t *Curl_wcsdup(const wchar_t *src) +{ + size_t length = wcslen(src); + + if(length > (SIZE_T_MAX / sizeof(wchar_t)) - 1) + return (wchar_t *)NULL; /* integer overflow */ + + return (wchar_t *)Curl_memdup(src, (length + 1) * sizeof(wchar_t)); +} +#endif + +/*************************************************************************** + * + * Curl_memdup(source, length) + * + * Copies the 'source' data to a newly allocated buffer (that is + * returned). Copies 'length' bytes. + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +void *Curl_memdup(const void *src, size_t length) +{ + void *buffer = malloc(length); + if(!buffer) + return NULL; /* fail */ + + memcpy(buffer, src, length); + + return buffer; +} + +/*************************************************************************** + * + * Curl_memdup0(source, length) + * + * Copies the 'source' string to a newly allocated buffer (that is returned). + * Copies 'length' bytes then adds a null terminator. + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +void *Curl_memdup0(const char *src, size_t length) +{ + char *buf = malloc(length + 1); + if(!buf) + return NULL; + memcpy(buf, src, length); + buf[length] = 0; + return buf; +} + +/*************************************************************************** + * + * Curl_saferealloc(ptr, size) + * + * Does a normal realloc(), but will free the data pointer if the realloc + * fails. If 'size' is non-zero, it will free the data and return a failure. + * + * This convenience function is provided and used to help us avoid a common + * mistake pattern when we could pass in a zero, catch the NULL return and end + * up free'ing the memory twice. + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +void *Curl_saferealloc(void *ptr, size_t size) +{ + void *datap = realloc(ptr, size); + if(size && !datap) + /* only free 'ptr' if size was non-zero */ + free(ptr); + return datap; +} diff --git a/lib/strdup.h b/lib/strdup.h new file mode 100644 index 0000000..238a261 --- /dev/null +++ b/lib/strdup.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_STRDUP_H +#define HEADER_CURL_STRDUP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifndef HAVE_STRDUP +char *Curl_strdup(const char *str); +#endif +#ifdef _WIN32 +wchar_t* Curl_wcsdup(const wchar_t* src); +#endif +void *Curl_memdup(const void *src, size_t buffer_length); +void *Curl_saferealloc(void *ptr, size_t size); +void *Curl_memdup0(const char *src, size_t length); + +#endif /* HEADER_CURL_STRDUP_H */ diff --git a/lib/strerror.c b/lib/strerror.c new file mode 100644 index 0000000..a900e78 --- /dev/null +++ b/lib/strerror.c @@ -0,0 +1,1114 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_STRERROR_R +# if (!defined(HAVE_POSIX_STRERROR_R) && \ + !defined(HAVE_GLIBC_STRERROR_R)) || \ + (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) +# error "strerror_r MUST be either POSIX, glibc style" +# endif +#endif + +#include + +#ifdef USE_LIBIDN2 +#include +#endif + +#ifdef USE_WINDOWS_SSPI +#include "curl_sspi.h" +#endif + +#include "strerror.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if defined(_WIN32) || defined(_WIN32_WCE) +#define PRESERVE_WINDOWS_ERROR_CODE +#endif + +const char * +curl_easy_strerror(CURLcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch(error) { + case CURLE_OK: + return "No error"; + + case CURLE_UNSUPPORTED_PROTOCOL: + return "Unsupported protocol"; + + case CURLE_FAILED_INIT: + return "Failed initialization"; + + case CURLE_URL_MALFORMAT: + return "URL using bad/illegal format or missing URL"; + + case CURLE_NOT_BUILT_IN: + return "A requested feature, protocol or option was not found built-in in" + " this libcurl due to a build-time decision."; + + case CURLE_COULDNT_RESOLVE_PROXY: + return "Couldn't resolve proxy name"; + + case CURLE_COULDNT_RESOLVE_HOST: + return "Couldn't resolve host name"; + + case CURLE_COULDNT_CONNECT: + return "Couldn't connect to server"; + + case CURLE_WEIRD_SERVER_REPLY: + return "Weird server reply"; + + case CURLE_REMOTE_ACCESS_DENIED: + return "Access denied to remote resource"; + + case CURLE_FTP_ACCEPT_FAILED: + return "FTP: The server failed to connect to data port"; + + case CURLE_FTP_ACCEPT_TIMEOUT: + return "FTP: Accepting server connect has timed out"; + + case CURLE_FTP_PRET_FAILED: + return "FTP: The server did not accept the PRET command."; + + case CURLE_FTP_WEIRD_PASS_REPLY: + return "FTP: unknown PASS reply"; + + case CURLE_FTP_WEIRD_PASV_REPLY: + return "FTP: unknown PASV reply"; + + case CURLE_FTP_WEIRD_227_FORMAT: + return "FTP: unknown 227 response format"; + + case CURLE_FTP_CANT_GET_HOST: + return "FTP: can't figure out the host in the PASV response"; + + case CURLE_HTTP2: + return "Error in the HTTP2 framing layer"; + + case CURLE_FTP_COULDNT_SET_TYPE: + return "FTP: couldn't set file type"; + + case CURLE_PARTIAL_FILE: + return "Transferred a partial file"; + + case CURLE_FTP_COULDNT_RETR_FILE: + return "FTP: couldn't retrieve (RETR failed) the specified file"; + + case CURLE_QUOTE_ERROR: + return "Quote command returned error"; + + case CURLE_HTTP_RETURNED_ERROR: + return "HTTP response code said error"; + + case CURLE_WRITE_ERROR: + return "Failed writing received data to disk/application"; + + case CURLE_UPLOAD_FAILED: + return "Upload failed (at start/before it took off)"; + + case CURLE_READ_ERROR: + return "Failed to open/read local data from file/application"; + + case CURLE_OUT_OF_MEMORY: + return "Out of memory"; + + case CURLE_OPERATION_TIMEDOUT: + return "Timeout was reached"; + + case CURLE_FTP_PORT_FAILED: + return "FTP: command PORT failed"; + + case CURLE_FTP_COULDNT_USE_REST: + return "FTP: command REST failed"; + + case CURLE_RANGE_ERROR: + return "Requested range was not delivered by the server"; + + case CURLE_HTTP_POST_ERROR: + return "Internal problem setting up the POST"; + + case CURLE_SSL_CONNECT_ERROR: + return "SSL connect error"; + + case CURLE_BAD_DOWNLOAD_RESUME: + return "Couldn't resume download"; + + case CURLE_FILE_COULDNT_READ_FILE: + return "Couldn't read a file:// file"; + + case CURLE_LDAP_CANNOT_BIND: + return "LDAP: cannot bind"; + + case CURLE_LDAP_SEARCH_FAILED: + return "LDAP: search failed"; + + case CURLE_FUNCTION_NOT_FOUND: + return "A required function in the library was not found"; + + case CURLE_ABORTED_BY_CALLBACK: + return "Operation was aborted by an application callback"; + + case CURLE_BAD_FUNCTION_ARGUMENT: + return "A libcurl function was given a bad argument"; + + case CURLE_INTERFACE_FAILED: + return "Failed binding local connection end"; + + case CURLE_TOO_MANY_REDIRECTS: + return "Number of redirects hit maximum amount"; + + case CURLE_UNKNOWN_OPTION: + return "An unknown option was passed in to libcurl"; + + case CURLE_SETOPT_OPTION_SYNTAX: + return "Malformed option provided in a setopt"; + + case CURLE_GOT_NOTHING: + return "Server returned nothing (no headers, no data)"; + + case CURLE_SSL_ENGINE_NOTFOUND: + return "SSL crypto engine not found"; + + case CURLE_SSL_ENGINE_SETFAILED: + return "Can not set SSL crypto engine as default"; + + case CURLE_SSL_ENGINE_INITFAILED: + return "Failed to initialise SSL crypto engine"; + + case CURLE_SEND_ERROR: + return "Failed sending data to the peer"; + + case CURLE_RECV_ERROR: + return "Failure when receiving data from the peer"; + + case CURLE_SSL_CERTPROBLEM: + return "Problem with the local SSL certificate"; + + case CURLE_SSL_CIPHER: + return "Couldn't use specified SSL cipher"; + + case CURLE_PEER_FAILED_VERIFICATION: + return "SSL peer certificate or SSH remote key was not OK"; + + case CURLE_SSL_CACERT_BADFILE: + return "Problem with the SSL CA cert (path? access rights?)"; + + case CURLE_BAD_CONTENT_ENCODING: + return "Unrecognized or bad HTTP Content or Transfer-Encoding"; + + case CURLE_FILESIZE_EXCEEDED: + return "Maximum file size exceeded"; + + case CURLE_USE_SSL_FAILED: + return "Requested SSL level failed"; + + case CURLE_SSL_SHUTDOWN_FAILED: + return "Failed to shut down the SSL connection"; + + case CURLE_SSL_CRL_BADFILE: + return "Failed to load CRL file (path? access rights?, format?)"; + + case CURLE_SSL_ISSUER_ERROR: + return "Issuer check against peer certificate failed"; + + case CURLE_SEND_FAIL_REWIND: + return "Send failed since rewinding of the data stream failed"; + + case CURLE_LOGIN_DENIED: + return "Login denied"; + + case CURLE_TFTP_NOTFOUND: + return "TFTP: File Not Found"; + + case CURLE_TFTP_PERM: + return "TFTP: Access Violation"; + + case CURLE_REMOTE_DISK_FULL: + return "Disk full or allocation exceeded"; + + case CURLE_TFTP_ILLEGAL: + return "TFTP: Illegal operation"; + + case CURLE_TFTP_UNKNOWNID: + return "TFTP: Unknown transfer ID"; + + case CURLE_REMOTE_FILE_EXISTS: + return "Remote file already exists"; + + case CURLE_TFTP_NOSUCHUSER: + return "TFTP: No such user"; + + case CURLE_REMOTE_FILE_NOT_FOUND: + return "Remote file not found"; + + case CURLE_SSH: + return "Error in the SSH layer"; + + case CURLE_AGAIN: + return "Socket not ready for send/recv"; + + case CURLE_RTSP_CSEQ_ERROR: + return "RTSP CSeq mismatch or invalid CSeq"; + + case CURLE_RTSP_SESSION_ERROR: + return "RTSP session error"; + + case CURLE_FTP_BAD_FILE_LIST: + return "Unable to parse FTP file list"; + + case CURLE_CHUNK_FAILED: + return "Chunk callback failed"; + + case CURLE_NO_CONNECTION_AVAILABLE: + return "The max connection limit is reached"; + + case CURLE_SSL_PINNEDPUBKEYNOTMATCH: + return "SSL public key does not match pinned public key"; + + case CURLE_SSL_INVALIDCERTSTATUS: + return "SSL server certificate status verification FAILED"; + + case CURLE_HTTP2_STREAM: + return "Stream error in the HTTP/2 framing layer"; + + case CURLE_RECURSIVE_API_CALL: + return "API function called from within callback"; + + case CURLE_AUTH_ERROR: + return "An authentication function returned an error"; + + case CURLE_HTTP3: + return "HTTP/3 error"; + + case CURLE_QUIC_CONNECT_ERROR: + return "QUIC connection error"; + + case CURLE_PROXY: + return "proxy handshake error"; + + case CURLE_SSL_CLIENTCERT: + return "SSL Client Certificate required"; + + case CURLE_UNRECOVERABLE_POLL: + return "Unrecoverable error in select/poll"; + + case CURLE_TOO_LARGE: + return "A value or data field grew larger than allowed"; + + /* error codes not used by current libcurl */ + case CURLE_OBSOLETE20: + case CURLE_OBSOLETE24: + case CURLE_OBSOLETE29: + case CURLE_OBSOLETE32: + case CURLE_OBSOLETE40: + case CURLE_OBSOLETE44: + case CURLE_OBSOLETE46: + case CURLE_OBSOLETE50: + case CURLE_OBSOLETE51: + case CURLE_OBSOLETE57: + case CURLE_OBSOLETE62: + case CURLE_OBSOLETE75: + case CURLE_OBSOLETE76: + case CURL_LAST: + break; + } + /* + * By using a switch, gcc -Wall will complain about enum values + * which do not appear, helping keep this function up-to-date. + * By using gcc -Wall -Werror, you can't forget. + * + * A table would not have the same benefit. Most compilers will + * generate code very similar to a table in any case, so there + * is little performance gain from a table. And something is broken + * for the user's application, anyways, so does it matter how fast + * it _doesn't_ work? + * + * The line number for the error will be near this comment, which + * is why it is here, and not at the start of the switch. + */ + return "Unknown error"; +#else + if(!error) + return "No error"; + else + return "Error"; +#endif +} + +const char * +curl_multi_strerror(CURLMcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch(error) { + case CURLM_CALL_MULTI_PERFORM: + return "Please call curl_multi_perform() soon"; + + case CURLM_OK: + return "No error"; + + case CURLM_BAD_HANDLE: + return "Invalid multi handle"; + + case CURLM_BAD_EASY_HANDLE: + return "Invalid easy handle"; + + case CURLM_OUT_OF_MEMORY: + return "Out of memory"; + + case CURLM_INTERNAL_ERROR: + return "Internal error"; + + case CURLM_BAD_SOCKET: + return "Invalid socket argument"; + + case CURLM_UNKNOWN_OPTION: + return "Unknown option"; + + case CURLM_ADDED_ALREADY: + return "The easy handle is already added to a multi handle"; + + case CURLM_RECURSIVE_API_CALL: + return "API function called from within callback"; + + case CURLM_WAKEUP_FAILURE: + return "Wakeup is unavailable or failed"; + + case CURLM_BAD_FUNCTION_ARGUMENT: + return "A libcurl function was given a bad argument"; + + case CURLM_ABORTED_BY_CALLBACK: + return "Operation was aborted by an application callback"; + + case CURLM_UNRECOVERABLE_POLL: + return "Unrecoverable error in select/poll"; + + case CURLM_LAST: + break; + } + + return "Unknown error"; +#else + if(error == CURLM_OK) + return "No error"; + else + return "Error"; +#endif +} + +const char * +curl_share_strerror(CURLSHcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch(error) { + case CURLSHE_OK: + return "No error"; + + case CURLSHE_BAD_OPTION: + return "Unknown share option"; + + case CURLSHE_IN_USE: + return "Share currently in use"; + + case CURLSHE_INVALID: + return "Invalid share handle"; + + case CURLSHE_NOMEM: + return "Out of memory"; + + case CURLSHE_NOT_BUILT_IN: + return "Feature not enabled in this library"; + + case CURLSHE_LAST: + break; + } + + return "CURLSHcode unknown"; +#else + if(error == CURLSHE_OK) + return "No error"; + else + return "Error"; +#endif +} + +const char * +curl_url_strerror(CURLUcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch(error) { + case CURLUE_OK: + return "No error"; + + case CURLUE_BAD_HANDLE: + return "An invalid CURLU pointer was passed as argument"; + + case CURLUE_BAD_PARTPOINTER: + return "An invalid 'part' argument was passed as argument"; + + case CURLUE_MALFORMED_INPUT: + return "Malformed input to a URL function"; + + case CURLUE_BAD_PORT_NUMBER: + return "Port number was not a decimal number between 0 and 65535"; + + case CURLUE_UNSUPPORTED_SCHEME: + return "Unsupported URL scheme"; + + case CURLUE_URLDECODE: + return "URL decode error, most likely because of rubbish in the input"; + + case CURLUE_OUT_OF_MEMORY: + return "A memory function failed"; + + case CURLUE_USER_NOT_ALLOWED: + return "Credentials was passed in the URL when prohibited"; + + case CURLUE_UNKNOWN_PART: + return "An unknown part ID was passed to a URL API function"; + + case CURLUE_NO_SCHEME: + return "No scheme part in the URL"; + + case CURLUE_NO_USER: + return "No user part in the URL"; + + case CURLUE_NO_PASSWORD: + return "No password part in the URL"; + + case CURLUE_NO_OPTIONS: + return "No options part in the URL"; + + case CURLUE_NO_HOST: + return "No host part in the URL"; + + case CURLUE_NO_PORT: + return "No port part in the URL"; + + case CURLUE_NO_QUERY: + return "No query part in the URL"; + + case CURLUE_NO_FRAGMENT: + return "No fragment part in the URL"; + + case CURLUE_NO_ZONEID: + return "No zoneid part in the URL"; + + case CURLUE_BAD_LOGIN: + return "Bad login part"; + + case CURLUE_BAD_IPV6: + return "Bad IPv6 address"; + + case CURLUE_BAD_HOSTNAME: + return "Bad hostname"; + + case CURLUE_BAD_FILE_URL: + return "Bad file:// URL"; + + case CURLUE_BAD_SLASHES: + return "Unsupported number of slashes following scheme"; + + case CURLUE_BAD_SCHEME: + return "Bad scheme"; + + case CURLUE_BAD_PATH: + return "Bad path"; + + case CURLUE_BAD_FRAGMENT: + return "Bad fragment"; + + case CURLUE_BAD_QUERY: + return "Bad query"; + + case CURLUE_BAD_PASSWORD: + return "Bad password"; + + case CURLUE_BAD_USER: + return "Bad user"; + + case CURLUE_LACKS_IDN: + return "libcurl lacks IDN support"; + + case CURLUE_TOO_LARGE: + return "A value or data field is larger than allowed"; + + case CURLUE_LAST: + break; + } + + return "CURLUcode unknown"; +#else + if(error == CURLUE_OK) + return "No error"; + else + return "Error"; +#endif +} + +#ifdef USE_WINSOCK +/* This is a helper function for Curl_strerror that converts Winsock error + * codes (WSAGetLastError) to error messages. + * Returns NULL if no error message was found for error code. + */ +static const char * +get_winsock_error(int err, char *buf, size_t len) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const char *p; + size_t alen; +#endif + + if(!len) + return NULL; + + *buf = '\0'; + +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)err; + return NULL; +#else + switch(err) { + case WSAEINTR: + p = "Call interrupted"; + break; + case WSAEBADF: + p = "Bad file"; + break; + case WSAEACCES: + p = "Bad access"; + break; + case WSAEFAULT: + p = "Bad argument"; + break; + case WSAEINVAL: + p = "Invalid arguments"; + break; + case WSAEMFILE: + p = "Out of file descriptors"; + break; + case WSAEWOULDBLOCK: + p = "Call would block"; + break; + case WSAEINPROGRESS: + case WSAEALREADY: + p = "Blocking call in progress"; + break; + case WSAENOTSOCK: + p = "Descriptor is not a socket"; + break; + case WSAEDESTADDRREQ: + p = "Need destination address"; + break; + case WSAEMSGSIZE: + p = "Bad message size"; + break; + case WSAEPROTOTYPE: + p = "Bad protocol"; + break; + case WSAENOPROTOOPT: + p = "Protocol option is unsupported"; + break; + case WSAEPROTONOSUPPORT: + p = "Protocol is unsupported"; + break; + case WSAESOCKTNOSUPPORT: + p = "Socket is unsupported"; + break; + case WSAEOPNOTSUPP: + p = "Operation not supported"; + break; + case WSAEAFNOSUPPORT: + p = "Address family not supported"; + break; + case WSAEPFNOSUPPORT: + p = "Protocol family not supported"; + break; + case WSAEADDRINUSE: + p = "Address already in use"; + break; + case WSAEADDRNOTAVAIL: + p = "Address not available"; + break; + case WSAENETDOWN: + p = "Network down"; + break; + case WSAENETUNREACH: + p = "Network unreachable"; + break; + case WSAENETRESET: + p = "Network has been reset"; + break; + case WSAECONNABORTED: + p = "Connection was aborted"; + break; + case WSAECONNRESET: + p = "Connection was reset"; + break; + case WSAENOBUFS: + p = "No buffer space"; + break; + case WSAEISCONN: + p = "Socket is already connected"; + break; + case WSAENOTCONN: + p = "Socket is not connected"; + break; + case WSAESHUTDOWN: + p = "Socket has been shut down"; + break; + case WSAETOOMANYREFS: + p = "Too many references"; + break; + case WSAETIMEDOUT: + p = "Timed out"; + break; + case WSAECONNREFUSED: + p = "Connection refused"; + break; + case WSAELOOP: + p = "Loop??"; + break; + case WSAENAMETOOLONG: + p = "Name too long"; + break; + case WSAEHOSTDOWN: + p = "Host down"; + break; + case WSAEHOSTUNREACH: + p = "Host unreachable"; + break; + case WSAENOTEMPTY: + p = "Not empty"; + break; + case WSAEPROCLIM: + p = "Process limit reached"; + break; + case WSAEUSERS: + p = "Too many users"; + break; + case WSAEDQUOT: + p = "Bad quota"; + break; + case WSAESTALE: + p = "Something is stale"; + break; + case WSAEREMOTE: + p = "Remote error"; + break; +#ifdef WSAEDISCON /* missing in SalfordC! */ + case WSAEDISCON: + p = "Disconnected"; + break; +#endif + /* Extended Winsock errors */ + case WSASYSNOTREADY: + p = "Winsock library is not ready"; + break; + case WSANOTINITIALISED: + p = "Winsock library not initialised"; + break; + case WSAVERNOTSUPPORTED: + p = "Winsock version not supported"; + break; + + /* getXbyY() errors (already handled in herrmsg): + * Authoritative Answer: Host not found */ + case WSAHOST_NOT_FOUND: + p = "Host not found"; + break; + + /* Non-Authoritative: Host not found, or SERVERFAIL */ + case WSATRY_AGAIN: + p = "Host not found, try again"; + break; + + /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ + case WSANO_RECOVERY: + p = "Unrecoverable error in call to nameserver"; + break; + + /* Valid name, no data record of requested type */ + case WSANO_DATA: + p = "No data record of requested type"; + break; + + default: + return NULL; + } + alen = strlen(p); + if(alen < len) + strcpy(buf, p); + return buf; +#endif +} +#endif /* USE_WINSOCK */ + +#if defined(_WIN32) || defined(_WIN32_WCE) +/* This is a helper function for Curl_strerror that converts Windows API error + * codes (GetLastError) to error messages. + * Returns NULL if no error message was found for error code. + */ +static const char * +get_winapi_error(int err, char *buf, size_t buflen) +{ + char *p; + wchar_t wbuf[256]; + + if(!buflen) + return NULL; + + *buf = '\0'; + *wbuf = L'\0'; + + /* We return the local codepage version of the error string because if it is + output to the user's terminal it will likely be with functions which + expect the local codepage (eg fprintf, failf, infof). + FormatMessageW -> wcstombs is used for Windows CE compatibility. */ + if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err, + LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) { + size_t written = wcstombs(buf, wbuf, buflen - 1); + if(written != (size_t)-1) + buf[written] = '\0'; + else + *buf = '\0'; + } + + /* Truncate multiple lines */ + p = strchr(buf, '\n'); + if(p) { + if(p > buf && *(p-1) == '\r') + *(p-1) = '\0'; + else + *p = '\0'; + } + + return (*buf ? buf : NULL); +} +#endif /* _WIN32 || _WIN32_WCE */ + +/* + * Our thread-safe and smart strerror() replacement. + * + * The 'err' argument passed in to this function MUST be a true errno number + * as reported on this system. We do no range checking on the number before + * we pass it to the "number-to-message" conversion function and there might + * be systems that don't do proper range checking in there themselves. + * + * We don't do range checking (on systems other than Windows) since there is + * no good reliable and portable way to do it. + * + * On Windows different types of error codes overlap. This function has an + * order of preference when trying to match error codes: + * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError). + * + * It may be more correct to call one of the variant functions instead: + * Call Curl_sspi_strerror if the error code is definitely Windows SSPI. + * Call Curl_winapi_strerror if the error code is definitely Windows API. + */ +const char *Curl_strerror(int err, char *buf, size_t buflen) +{ +#ifdef PRESERVE_WINDOWS_ERROR_CODE + DWORD old_win_err = GetLastError(); +#endif + int old_errno = errno; + char *p; + + if(!buflen) + return NULL; + +#ifndef _WIN32 + DEBUGASSERT(err >= 0); +#endif + + *buf = '\0'; + +#if defined(_WIN32) || defined(_WIN32_WCE) +#if defined(_WIN32) + /* 'sys_nerr' is the maximum errno number, it is not widely portable */ + if(err >= 0 && err < sys_nerr) + msnprintf(buf, buflen, "%s", sys_errlist[err]); + else +#endif + { + if( +#ifdef USE_WINSOCK + !get_winsock_error(err, buf, buflen) && +#endif + !get_winapi_error((DWORD)err, buf, buflen)) + msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err); + } +#else /* not Windows coming up */ + +#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R) + /* + * The POSIX-style strerror_r() may set errno to ERANGE if insufficient + * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated + * message string, or EINVAL if 'errnum' is not a valid error number. + */ + if(0 != strerror_r(err, buf, buflen)) { + if('\0' == buf[0]) + msnprintf(buf, buflen, "Unknown error %d", err); + } +#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) + /* + * The glibc-style strerror_r() only *might* use the buffer we pass to + * the function, but it always returns the error message as a pointer, + * so we must copy that string unconditionally (if non-NULL). + */ + { + char buffer[256]; + char *msg = strerror_r(err, buffer, sizeof(buffer)); + if(msg) + msnprintf(buf, buflen, "%s", msg); + else + msnprintf(buf, buflen, "Unknown error %d", err); + } +#else + { + /* !checksrc! disable STRERROR 1 */ + const char *msg = strerror(err); + if(msg) + msnprintf(buf, buflen, "%s", msg); + else + msnprintf(buf, buflen, "Unknown error %d", err); + } +#endif + +#endif /* end of not Windows */ + + /* strip trailing '\r\n' or '\n'. */ + p = strrchr(buf, '\n'); + if(p && (p - buf) >= 2) + *p = '\0'; + p = strrchr(buf, '\r'); + if(p && (p - buf) >= 1) + *p = '\0'; + + if(errno != old_errno) + errno = old_errno; + +#ifdef PRESERVE_WINDOWS_ERROR_CODE + if(old_win_err != GetLastError()) + SetLastError(old_win_err); +#endif + + return buf; +} + +/* + * Curl_winapi_strerror: + * Variant of Curl_strerror if the error code is definitely Windows API. + */ +#if defined(_WIN32) || defined(_WIN32_WCE) +const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen) +{ +#ifdef PRESERVE_WINDOWS_ERROR_CODE + DWORD old_win_err = GetLastError(); +#endif + int old_errno = errno; + + if(!buflen) + return NULL; + + *buf = '\0'; + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(!get_winapi_error(err, buf, buflen)) { + msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err); + } +#else + { + const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error"; + if(strlen(txt) < buflen) + strcpy(buf, txt); + } +#endif + + if(errno != old_errno) + errno = old_errno; + +#ifdef PRESERVE_WINDOWS_ERROR_CODE + if(old_win_err != GetLastError()) + SetLastError(old_win_err); +#endif + + return buf; +} +#endif /* _WIN32 || _WIN32_WCE */ + +#ifdef USE_WINDOWS_SSPI +/* + * Curl_sspi_strerror: + * Variant of Curl_strerror if the error code is definitely Windows SSPI. + */ +const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) +{ +#ifdef PRESERVE_WINDOWS_ERROR_CODE + DWORD old_win_err = GetLastError(); +#endif + int old_errno = errno; + const char *txt; + + if(!buflen) + return NULL; + + *buf = '\0'; + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + + switch(err) { + case SEC_E_OK: + txt = "No error"; + break; +#define SEC2TXT(sec) case sec: txt = #sec; break + SEC2TXT(CRYPT_E_REVOKED); + SEC2TXT(CRYPT_E_NO_REVOCATION_DLL); + SEC2TXT(CRYPT_E_NO_REVOCATION_CHECK); + SEC2TXT(CRYPT_E_REVOCATION_OFFLINE); + SEC2TXT(CRYPT_E_NOT_IN_REVOCATION_DATABASE); + SEC2TXT(SEC_E_ALGORITHM_MISMATCH); + SEC2TXT(SEC_E_BAD_BINDINGS); + SEC2TXT(SEC_E_BAD_PKGID); + SEC2TXT(SEC_E_BUFFER_TOO_SMALL); + SEC2TXT(SEC_E_CANNOT_INSTALL); + SEC2TXT(SEC_E_CANNOT_PACK); + SEC2TXT(SEC_E_CERT_EXPIRED); + SEC2TXT(SEC_E_CERT_UNKNOWN); + SEC2TXT(SEC_E_CERT_WRONG_USAGE); + SEC2TXT(SEC_E_CONTEXT_EXPIRED); + SEC2TXT(SEC_E_CROSSREALM_DELEGATION_FAILURE); + SEC2TXT(SEC_E_CRYPTO_SYSTEM_INVALID); + SEC2TXT(SEC_E_DECRYPT_FAILURE); + SEC2TXT(SEC_E_DELEGATION_POLICY); + SEC2TXT(SEC_E_DELEGATION_REQUIRED); + SEC2TXT(SEC_E_DOWNGRADE_DETECTED); + SEC2TXT(SEC_E_ENCRYPT_FAILURE); + SEC2TXT(SEC_E_ILLEGAL_MESSAGE); + SEC2TXT(SEC_E_INCOMPLETE_CREDENTIALS); + SEC2TXT(SEC_E_INCOMPLETE_MESSAGE); + SEC2TXT(SEC_E_INSUFFICIENT_MEMORY); + SEC2TXT(SEC_E_INTERNAL_ERROR); + SEC2TXT(SEC_E_INVALID_HANDLE); + SEC2TXT(SEC_E_INVALID_PARAMETER); + SEC2TXT(SEC_E_INVALID_TOKEN); + SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED); + SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED_KDC); + SEC2TXT(SEC_E_KDC_CERT_EXPIRED); + SEC2TXT(SEC_E_KDC_CERT_REVOKED); + SEC2TXT(SEC_E_KDC_INVALID_REQUEST); + SEC2TXT(SEC_E_KDC_UNABLE_TO_REFER); + SEC2TXT(SEC_E_KDC_UNKNOWN_ETYPE); + SEC2TXT(SEC_E_LOGON_DENIED); + SEC2TXT(SEC_E_MAX_REFERRALS_EXCEEDED); + SEC2TXT(SEC_E_MESSAGE_ALTERED); + SEC2TXT(SEC_E_MULTIPLE_ACCOUNTS); + SEC2TXT(SEC_E_MUST_BE_KDC); + SEC2TXT(SEC_E_NOT_OWNER); + SEC2TXT(SEC_E_NO_AUTHENTICATING_AUTHORITY); + SEC2TXT(SEC_E_NO_CREDENTIALS); + SEC2TXT(SEC_E_NO_IMPERSONATION); + SEC2TXT(SEC_E_NO_IP_ADDRESSES); + SEC2TXT(SEC_E_NO_KERB_KEY); + SEC2TXT(SEC_E_NO_PA_DATA); + SEC2TXT(SEC_E_NO_S4U_PROT_SUPPORT); + SEC2TXT(SEC_E_NO_TGT_REPLY); + SEC2TXT(SEC_E_OUT_OF_SEQUENCE); + SEC2TXT(SEC_E_PKINIT_CLIENT_FAILURE); + SEC2TXT(SEC_E_PKINIT_NAME_MISMATCH); + SEC2TXT(SEC_E_POLICY_NLTM_ONLY); + SEC2TXT(SEC_E_QOP_NOT_SUPPORTED); + SEC2TXT(SEC_E_REVOCATION_OFFLINE_C); + SEC2TXT(SEC_E_REVOCATION_OFFLINE_KDC); + SEC2TXT(SEC_E_SECPKG_NOT_FOUND); + SEC2TXT(SEC_E_SECURITY_QOS_FAILED); + SEC2TXT(SEC_E_SHUTDOWN_IN_PROGRESS); + SEC2TXT(SEC_E_SMARTCARD_CERT_EXPIRED); + SEC2TXT(SEC_E_SMARTCARD_CERT_REVOKED); + SEC2TXT(SEC_E_SMARTCARD_LOGON_REQUIRED); + SEC2TXT(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED); + SEC2TXT(SEC_E_TARGET_UNKNOWN); + SEC2TXT(SEC_E_TIME_SKEW); + SEC2TXT(SEC_E_TOO_MANY_PRINCIPALS); + SEC2TXT(SEC_E_UNFINISHED_CONTEXT_DELETED); + SEC2TXT(SEC_E_UNKNOWN_CREDENTIALS); + SEC2TXT(SEC_E_UNSUPPORTED_FUNCTION); + SEC2TXT(SEC_E_UNSUPPORTED_PREAUTH); + SEC2TXT(SEC_E_UNTRUSTED_ROOT); + SEC2TXT(SEC_E_WRONG_CREDENTIAL_HANDLE); + SEC2TXT(SEC_E_WRONG_PRINCIPAL); + SEC2TXT(SEC_I_COMPLETE_AND_CONTINUE); + SEC2TXT(SEC_I_COMPLETE_NEEDED); + SEC2TXT(SEC_I_CONTEXT_EXPIRED); + SEC2TXT(SEC_I_CONTINUE_NEEDED); + SEC2TXT(SEC_I_INCOMPLETE_CREDENTIALS); + SEC2TXT(SEC_I_LOCAL_LOGON); + SEC2TXT(SEC_I_NO_LSA_CONTEXT); + SEC2TXT(SEC_I_RENEGOTIATE); + SEC2TXT(SEC_I_SIGNATURE_NEEDED); + default: + txt = "Unknown error"; + } + + if(err == SEC_E_ILLEGAL_MESSAGE) { + msnprintf(buf, buflen, + "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " + "when a fatal SSL/TLS alert is received (e.g. handshake failed)." + " More detail may be available in the Windows System event log.", + err); + } + else { + char msgbuf[256]; + if(get_winapi_error(err, msgbuf, sizeof(msgbuf))) + msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf); + else + msnprintf(buf, buflen, "%s (0x%08X)", txt, err); + } + +#else + if(err == SEC_E_OK) + txt = "No error"; + else + txt = "Error"; + if(buflen > strlen(txt)) + strcpy(buf, txt); +#endif + + if(errno != old_errno) + errno = old_errno; + +#ifdef PRESERVE_WINDOWS_ERROR_CODE + if(old_win_err != GetLastError()) + SetLastError(old_win_err); +#endif + + return buf; +} +#endif /* USE_WINDOWS_SSPI */ diff --git a/lib/strerror.h b/lib/strerror.h new file mode 100644 index 0000000..6806867 --- /dev/null +++ b/lib/strerror.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_STRERROR_H +#define HEADER_CURL_STRERROR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "urldata.h" + +#define STRERROR_LEN 256 /* a suitable length */ + +const char *Curl_strerror(int err, char *buf, size_t buflen); +#if defined(_WIN32) || defined(_WIN32_WCE) +const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen); +#endif +#ifdef USE_WINDOWS_SSPI +const char *Curl_sspi_strerror(int err, char *buf, size_t buflen); +#endif + +#endif /* HEADER_CURL_STRERROR_H */ diff --git a/lib/strtok.c b/lib/strtok.c new file mode 100644 index 0000000..d8e1e81 --- /dev/null +++ b/lib/strtok.c @@ -0,0 +1,68 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef HAVE_STRTOK_R +#include + +#include "strtok.h" + +char * +Curl_strtok_r(char *ptr, const char *sep, char **end) +{ + if(!ptr) + /* we got NULL input so then we get our last position instead */ + ptr = *end; + + /* pass all letters that are including in the separator string */ + while(*ptr && strchr(sep, *ptr)) + ++ptr; + + if(*ptr) { + /* so this is where the next piece of string starts */ + char *start = ptr; + + /* set the end pointer to the first byte after the start */ + *end = start + 1; + + /* scan through the string to find where it ends, it ends on a + null byte or a character that exists in the separator string */ + while(**end && !strchr(sep, **end)) + ++*end; + + if(**end) { + /* the end is not a null byte */ + **end = '\0'; /* null-terminate it! */ + ++*end; /* advance the last pointer to beyond the null byte */ + } + + return start; /* return the position where the string starts */ + } + + /* we ended up on a null byte, there are no more strings to find! */ + return NULL; +} + +#endif /* this was only compiled if strtok_r wasn't present */ diff --git a/lib/strtok.h b/lib/strtok.h new file mode 100644 index 0000000..321cba2 --- /dev/null +++ b/lib/strtok.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_STRTOK_H +#define HEADER_CURL_STRTOK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" +#include + +#ifndef HAVE_STRTOK_R +char *Curl_strtok_r(char *s, const char *delim, char **last); +#define strtok_r Curl_strtok_r +#else +#include +#endif + +#endif /* HEADER_CURL_STRTOK_H */ diff --git a/lib/strtoofft.c b/lib/strtoofft.c new file mode 100644 index 0000000..077b257 --- /dev/null +++ b/lib/strtoofft.c @@ -0,0 +1,245 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include +#include "curl_setup.h" + +#include "strtoofft.h" + +/* + * NOTE: + * + * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we + * could use in case strtoll() doesn't exist... See + * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html + */ + +#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) +# ifdef HAVE_STRTOLL +# define strtooff strtoll +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) +# if defined(_SAL_VERSION) + _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( + _In_z_ const char *_String, + _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); +# else + _CRTIMP __int64 __cdecl _strtoi64(const char *_String, + char **_EndPtr, int _Radix); +# endif +# define strtooff _strtoi64 +# else +# define PRIVATE_STRTOOFF 1 +# endif +# endif +#else +# define strtooff strtol +#endif + +#ifdef PRIVATE_STRTOOFF + +/* Range tests can be used for alphanum decoding if characters are consecutive, + like in ASCII. Else an array is scanned. Determine this condition now. */ + +#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25 + +#define NO_RANGE_TEST + +static const char valchars[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +#endif + +static int get_char(char c, int base); + +/** + * Custom version of the strtooff function. This extracts a curl_off_t + * value from the given input string and returns it. + */ +static curl_off_t strtooff(const char *nptr, char **endptr, int base) +{ + char *end; + int is_negative = 0; + int overflow; + int i; + curl_off_t value = 0; + curl_off_t newval; + + /* Skip leading whitespace. */ + end = (char *)nptr; + while(ISBLANK(end[0])) { + end++; + } + + /* Handle the sign, if any. */ + if(end[0] == '-') { + is_negative = 1; + end++; + } + else if(end[0] == '+') { + end++; + } + else if(end[0] == '\0') { + /* We had nothing but perhaps some whitespace -- there was no number. */ + if(endptr) { + *endptr = end; + } + return 0; + } + + /* Handle special beginnings, if present and allowed. */ + if(end[0] == '0' && end[1] == 'x') { + if(base == 16 || base == 0) { + end += 2; + base = 16; + } + } + else if(end[0] == '0') { + if(base == 8 || base == 0) { + end++; + base = 8; + } + } + + /* Matching strtol, if the base is 0 and it doesn't look like + * the number is octal or hex, we assume it's base 10. + */ + if(base == 0) { + base = 10; + } + + /* Loop handling digits. */ + value = 0; + overflow = 0; + for(i = get_char(end[0], base); + i != -1; + end++, i = get_char(end[0], base)) { + newval = base * value + i; + if(newval < value) { + /* We've overflowed. */ + overflow = 1; + break; + } + else + value = newval; + } + + if(!overflow) { + if(is_negative) { + /* Fix the sign. */ + value *= -1; + } + } + else { + if(is_negative) + value = CURL_OFF_T_MIN; + else + value = CURL_OFF_T_MAX; + + errno = ERANGE; + } + + if(endptr) + *endptr = end; + + return value; +} + +/** + * Returns the value of c in the given base, or -1 if c cannot + * be interpreted properly in that base (i.e., is out of range, + * is a null, etc.). + * + * @param c the character to interpret according to base + * @param base the base in which to interpret c + * + * @return the value of c in base, or -1 if c isn't in range + */ +static int get_char(char c, int base) +{ +#ifndef NO_RANGE_TEST + int value = -1; + if(c <= '9' && c >= '0') { + value = c - '0'; + } + else if(c <= 'Z' && c >= 'A') { + value = c - 'A' + 10; + } + else if(c <= 'z' && c >= 'a') { + value = c - 'a' + 10; + } +#else + const char *cp; + int value; + + cp = memchr(valchars, c, 10 + 26 + 26); + + if(!cp) + return -1; + + value = cp - valchars; + + if(value >= 10 + 26) + value -= 26; /* Lowercase. */ +#endif + + if(value >= base) { + value = -1; + } + + return value; +} +#endif /* Only present if we need strtoll, but don't have it. */ + +/* + * Parse a *positive* up to 64 bit number written in ascii. + */ +CURLofft curlx_strtoofft(const char *str, char **endp, int base, + curl_off_t *num) +{ + char *end; + curl_off_t number; + errno = 0; + *num = 0; /* clear by default */ + DEBUGASSERT(base); /* starting now, avoid base zero */ + + while(*str && ISBLANK(*str)) + str++; + if(('-' == *str) || (ISSPACE(*str))) { + if(endp) + *endp = (char *)str; /* didn't actually move */ + return CURL_OFFT_INVAL; /* nothing parsed */ + } + number = strtooff(str, &end, base); + if(endp) + *endp = end; + if(errno == ERANGE) + /* overflow/underflow */ + return CURL_OFFT_FLOW; + else if(str == end) + /* nothing parsed */ + return CURL_OFFT_INVAL; + + *num = number; + return CURL_OFFT_OK; +} diff --git a/lib/strtoofft.h b/lib/strtoofft.h new file mode 100644 index 0000000..34d293b --- /dev/null +++ b/lib/strtoofft.h @@ -0,0 +1,54 @@ +#ifndef HEADER_CURL_STRTOOFFT_H +#define HEADER_CURL_STRTOOFFT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/* + * Determine which string to integral data type conversion function we use + * to implement string conversion to our curl_off_t integral data type. + * + * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use + * an underlying data type which might be 'long', 'int64_t', 'long long' or + * '__int64' and more remotely other data types. + * + * On systems where the size of curl_off_t is greater than the size of 'long' + * the conversion function to use is strtoll() if it is available, otherwise, + * we emulate its functionality with our own clone. + * + * On systems where the size of curl_off_t is smaller or equal than the size + * of 'long' the conversion function to use is strtol(). + */ + +typedef enum { + CURL_OFFT_OK, /* parsed fine */ + CURL_OFFT_FLOW, /* over or underflow */ + CURL_OFFT_INVAL /* nothing was parsed */ +} CURLofft; + +CURLofft curlx_strtoofft(const char *str, char **endp, int base, + curl_off_t *num); + +#endif /* HEADER_CURL_STRTOOFFT_H */ diff --git a/lib/system_win32.c b/lib/system_win32.c new file mode 100644 index 0000000..d2862de --- /dev/null +++ b/lib/system_win32.c @@ -0,0 +1,270 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(_WIN32) + +#include +#include "system_win32.h" +#include "version_win32.h" +#include "curl_sspi.h" +#include "warnless.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +LARGE_INTEGER Curl_freq; +bool Curl_isVistaOrGreater; +bool Curl_isWindows8OrGreater; + +/* Handle of iphlpapp.dll */ +static HMODULE s_hIpHlpApiDll = NULL; + +/* Function pointers */ +IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL; +FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW = NULL; +GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel = NULL; +GETADDRINFOEXW_FN Curl_GetAddrInfoExW = NULL; + +/* Curl_win32_init() performs win32 global initialization */ +CURLcode Curl_win32_init(long flags) +{ +#ifdef USE_WINSOCK + HMODULE ws2_32Dll; +#endif + /* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which + is just for Winsock at the moment. Any required win32 initialization + should take place after this block. */ + if(flags & CURL_GLOBAL_WIN32) { +#ifdef USE_WINSOCK + WORD wVersionRequested; + WSADATA wsaData; + int res; + + wVersionRequested = MAKEWORD(2, 2); + res = WSAStartup(wVersionRequested, &wsaData); + + if(res) + /* Tell the user that we couldn't find a usable */ + /* winsock.dll. */ + return CURLE_FAILED_INIT; + + /* Confirm that the Windows Sockets DLL supports what we need.*/ + /* Note that if the DLL supports versions greater */ + /* than wVersionRequested, it will still return */ + /* wVersionRequested in wVersion. wHighVersion contains the */ + /* highest supported version. */ + + if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || + HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) { + /* Tell the user that we couldn't find a usable */ + + /* winsock.dll. */ + WSACleanup(); + return CURLE_FAILED_INIT; + } + /* The Windows Sockets DLL is acceptable. Proceed. */ +#elif defined(USE_LWIPSOCK) + lwip_init(); +#endif + } /* CURL_GLOBAL_WIN32 */ + +#ifdef USE_WINDOWS_SSPI + { + CURLcode result = Curl_sspi_global_init(); + if(result) + return result; + } +#endif + + s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll")); + if(s_hIpHlpApiDll) { + /* Get the address of the if_nametoindex function */ + IF_NAMETOINDEX_FN pIfNameToIndex = + CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN, + (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex"))); + + if(pIfNameToIndex) + Curl_if_nametoindex = pIfNameToIndex; + } + +#ifdef USE_WINSOCK + ws2_32Dll = GetModuleHandleA("ws2_32"); + if(ws2_32Dll) { + Curl_FreeAddrInfoExW = CURLX_FUNCTION_CAST(FREEADDRINFOEXW_FN, + GetProcAddress(ws2_32Dll, "FreeAddrInfoExW")); + Curl_GetAddrInfoExCancel = CURLX_FUNCTION_CAST(GETADDRINFOEXCANCEL_FN, + GetProcAddress(ws2_32Dll, "GetAddrInfoExCancel")); + Curl_GetAddrInfoExW = CURLX_FUNCTION_CAST(GETADDRINFOEXW_FN, + GetProcAddress(ws2_32Dll, "GetAddrInfoExW")); + } +#endif + + /* curlx_verify_windows_version must be called during init at least once + because it has its own initialization routine. */ + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + Curl_isVistaOrGreater = TRUE; + } + else + Curl_isVistaOrGreater = FALSE; + + if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + Curl_isWindows8OrGreater = TRUE; + } + else + Curl_isWindows8OrGreater = FALSE; + + QueryPerformanceFrequency(&Curl_freq); + return CURLE_OK; +} + +/* Curl_win32_cleanup() is the opposite of Curl_win32_init() */ +void Curl_win32_cleanup(long init_flags) +{ + Curl_FreeAddrInfoExW = NULL; + Curl_GetAddrInfoExCancel = NULL; + Curl_GetAddrInfoExW = NULL; + if(s_hIpHlpApiDll) { + FreeLibrary(s_hIpHlpApiDll); + s_hIpHlpApiDll = NULL; + Curl_if_nametoindex = NULL; + } + +#ifdef USE_WINDOWS_SSPI + Curl_sspi_global_cleanup(); +#endif + + if(init_flags & CURL_GLOBAL_WIN32) { +#ifdef USE_WINSOCK + WSACleanup(); +#endif + } +} + +#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH) +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 +#endif + +#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif + +/* We use our own typedef here since some headers might lack these */ +typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); + +/* See function definitions in winbase.h */ +#ifdef UNICODE +# ifdef _WIN32_WCE +# define LOADLIBARYEX L"LoadLibraryExW" +# else +# define LOADLIBARYEX "LoadLibraryExW" +# endif +#else +# define LOADLIBARYEX "LoadLibraryExA" +#endif + +/* + * Curl_load_library() + * + * This is used to dynamically load DLLs using the most secure method available + * for the version of Windows that we are running on. + * + * Parameters: + * + * filename [in] - The filename or full path of the DLL to load. If only the + * filename is passed then the DLL will be loaded from the + * Windows system directory. + * + * Returns the handle of the module on success; otherwise NULL. + */ +HMODULE Curl_load_library(LPCTSTR filename) +{ +#ifndef CURL_WINDOWS_APP + HMODULE hModule = NULL; + LOADLIBRARYEX_FN pLoadLibraryEx = NULL; + + /* Get a handle to kernel32 so we can access it's functions at runtime */ + HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32")); + if(!hKernel32) + return NULL; + + /* Attempt to find LoadLibraryEx() which is only available on Windows 2000 + and above */ + pLoadLibraryEx = + CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN, + (GetProcAddress(hKernel32, LOADLIBARYEX))); + + /* Detect if there's already a path in the filename and load the library if + there is. Note: Both back slashes and forward slashes have been supported + since the earlier days of DOS at an API level although they are not + supported by command prompt */ + if(_tcspbrk(filename, TEXT("\\/"))) { + /** !checksrc! disable BANNEDFUNC 1 **/ + hModule = pLoadLibraryEx ? + pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : + LoadLibrary(filename); + } + /* Detect if KB2533623 is installed, as LOAD_LIBRARY_SEARCH_SYSTEM32 is only + supported on Windows Vista, Windows Server 2008, Windows 7 and Windows + Server 2008 R2 with this patch or natively on Windows 8 and above */ + else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) { + /* Load the DLL from the Windows system directory */ + hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + } + else { + /* Attempt to get the Windows system path */ + UINT systemdirlen = GetSystemDirectory(NULL, 0); + if(systemdirlen) { + /* Allocate space for the full DLL path (Room for the null terminator + is included in systemdirlen) */ + size_t filenamelen = _tcslen(filename); + TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen)); + if(path && GetSystemDirectory(path, systemdirlen)) { + /* Calculate the full DLL path */ + _tcscpy(path + _tcslen(path), TEXT("\\")); + _tcscpy(path + _tcslen(path), filename); + + /* Load the DLL from the Windows system directory */ + /** !checksrc! disable BANNEDFUNC 1 **/ + hModule = pLoadLibraryEx ? + pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : + LoadLibrary(path); + + } + free(path); + } + } + return hModule; +#else + /* the Universal Windows Platform (UWP) can't do this */ + (void)filename; + return NULL; +#endif +} + +#endif /* _WIN32 */ diff --git a/lib/system_win32.h b/lib/system_win32.h new file mode 100644 index 0000000..bd490ca --- /dev/null +++ b/lib/system_win32.h @@ -0,0 +1,77 @@ +#ifndef HEADER_CURL_SYSTEM_WIN32_H +#define HEADER_CURL_SYSTEM_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef _WIN32 + +extern LARGE_INTEGER Curl_freq; +extern bool Curl_isVistaOrGreater; +extern bool Curl_isWindows8OrGreater; + +CURLcode Curl_win32_init(long flags); +void Curl_win32_cleanup(long init_flags); + +/* We use our own typedef here since some headers might lack this */ +typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *); + +/* This is used instead of if_nametoindex if available on Windows */ +extern IF_NAMETOINDEX_FN Curl_if_nametoindex; + +/* Identical copy of addrinfoexW/ADDRINFOEXW */ +typedef struct addrinfoexW_ +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + PWSTR ai_canonname; + struct sockaddr *ai_addr; + void *ai_blob; + size_t ai_bloblen; + LPGUID ai_provider; + struct addrinfoexW_ *ai_next; +} ADDRINFOEXW_; + +typedef void (CALLBACK *LOOKUP_COMPLETION_FN)(DWORD, DWORD, LPWSAOVERLAPPED); +typedef void (WSAAPI *FREEADDRINFOEXW_FN)(ADDRINFOEXW_*); +typedef int (WSAAPI *GETADDRINFOEXCANCEL_FN)(LPHANDLE); +typedef int (WSAAPI *GETADDRINFOEXW_FN)(PCWSTR, PCWSTR, DWORD, LPGUID, + const ADDRINFOEXW_*, ADDRINFOEXW_**, struct timeval*, LPOVERLAPPED, + LOOKUP_COMPLETION_FN, LPHANDLE); + +extern FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW; +extern GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel; +extern GETADDRINFOEXW_FN Curl_GetAddrInfoExW; + +/* This is used to dynamically load DLLs */ +HMODULE Curl_load_library(LPCTSTR filename); +#else /* _WIN32 */ +#define Curl_win32_init(x) CURLE_OK +#endif /* !_WIN32 */ + +#endif /* HEADER_CURL_SYSTEM_WIN32_H */ diff --git a/lib/telnet.c b/lib/telnet.c new file mode 100644 index 0000000..34dc5e8 --- /dev/null +++ b/lib/telnet.c @@ -0,0 +1,1642 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_TELNET + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "telnet.h" +#include "connect.h" +#include "progress.h" +#include "system_win32.h" +#include "arpa_telnet.h" +#include "select.h" +#include "strcase.h" +#include "warnless.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define SUBBUFSIZE 512 + +#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer +#define CURL_SB_TERM(x) \ + do { \ + x->subend = x->subpointer; \ + CURL_SB_CLEAR(x); \ + } while(0) +#define CURL_SB_ACCUM(x,c) \ + do { \ + if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer))) \ + *x->subpointer++ = (c); \ + } while(0) + +#define CURL_SB_GET(x) ((*x->subpointer++)&0xff) +#define CURL_SB_LEN(x) (x->subend - x->subpointer) + +/* For posterity: +#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) +#define CURL_SB_EOF(x) (x->subpointer >= x->subend) */ + +#ifdef CURL_DISABLE_VERBOSE_STRINGS +#define printoption(a,b,c,d) Curl_nop_stmt +#endif + +static +CURLcode telrcv(struct Curl_easy *data, + const unsigned char *inbuf, /* Data received from socket */ + ssize_t count); /* Number of bytes received */ + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void printoption(struct Curl_easy *data, + const char *direction, + int cmd, int option); +#endif + +static void negotiate(struct Curl_easy *data); +static void send_negotiation(struct Curl_easy *data, int cmd, int option); +static void set_local_option(struct Curl_easy *data, + int option, int newstate); +static void set_remote_option(struct Curl_easy *data, + int option, int newstate); + +static void printsub(struct Curl_easy *data, + int direction, unsigned char *pointer, + size_t length); +static void suboption(struct Curl_easy *data); +static void sendsuboption(struct Curl_easy *data, int option); + +static CURLcode telnet_do(struct Curl_easy *data, bool *done); +static CURLcode telnet_done(struct Curl_easy *data, + CURLcode, bool premature); +static CURLcode send_telnet_data(struct Curl_easy *data, + char *buffer, ssize_t nread); + +/* For negotiation compliant to RFC 1143 */ +#define CURL_NO 0 +#define CURL_YES 1 +#define CURL_WANTYES 2 +#define CURL_WANTNO 3 + +#define CURL_EMPTY 0 +#define CURL_OPPOSITE 1 + +/* + * Telnet receiver states for fsm + */ +typedef enum +{ + CURL_TS_DATA = 0, + CURL_TS_IAC, + CURL_TS_WILL, + CURL_TS_WONT, + CURL_TS_DO, + CURL_TS_DONT, + CURL_TS_CR, + CURL_TS_SB, /* sub-option collection */ + CURL_TS_SE /* looking for sub-option end */ +} TelnetReceive; + +struct TELNET { + int please_negotiate; + int already_negotiated; + int us[256]; + int usq[256]; + int us_preferred[256]; + int him[256]; + int himq[256]; + int him_preferred[256]; + int subnegotiation[256]; + char subopt_ttype[32]; /* Set with suboption TTYPE */ + char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ + unsigned short subopt_wsx; /* Set with suboption NAWS */ + unsigned short subopt_wsy; /* Set with suboption NAWS */ + TelnetReceive telrcv_state; + struct curl_slist *telnet_vars; /* Environment variables */ + struct dynbuf out; /* output buffer */ + + /* suboptions */ + unsigned char subbuffer[SUBBUFSIZE]; + unsigned char *subpointer, *subend; /* buffer for sub-options */ +}; + + +/* + * TELNET protocol handler. + */ + +const struct Curl_handler Curl_handler_telnet = { + "TELNET", /* scheme */ + ZERO_NULL, /* setup_connection */ + telnet_do, /* do_it */ + telnet_done, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_TELNET, /* defport */ + CURLPROTO_TELNET, /* protocol */ + CURLPROTO_TELNET, /* family */ + PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ +}; + + +static +CURLcode init_telnet(struct Curl_easy *data) +{ + struct TELNET *tn; + + tn = calloc(1, sizeof(struct TELNET)); + if(!tn) + return CURLE_OUT_OF_MEMORY; + + Curl_dyn_init(&tn->out, 0xffff); + data->req.p.telnet = tn; /* make us known */ + + tn->telrcv_state = CURL_TS_DATA; + + /* Init suboptions */ + CURL_SB_CLEAR(tn); + + /* Set the options we want by default */ + tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; + tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; + + /* To be compliant with previous releases of libcurl + we enable this option by default. This behavior + can be changed thanks to the "BINARY" option in + CURLOPT_TELNETOPTIONS + */ + tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; + tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; + + /* We must allow the server to echo what we sent + but it is not necessary to request the server + to do so (it might forces the server to close + the connection). Hence, we ignore ECHO in the + negotiate function + */ + tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES; + + /* Set the subnegotiation fields to send information + just after negotiation passed (do/will) + + Default values are (0,0) initialized by calloc. + According to the RFC1013 it is valid: + A value equal to zero is acceptable for the width (or height), + and means that no character width (or height) is being sent. + In this case, the width (or height) that will be assumed by the + Telnet server is operating system specific (it will probably be + based upon the terminal type information that may have been sent + using the TERMINAL TYPE Telnet option). */ + tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES; + return CURLE_OK; +} + +static void negotiate(struct Curl_easy *data) +{ + int i; + struct TELNET *tn = data->req.p.telnet; + + for(i = 0; i < CURL_NTELOPTS; i++) { + if(i == CURL_TELOPT_ECHO) + continue; + + if(tn->us_preferred[i] == CURL_YES) + set_local_option(data, i, CURL_YES); + + if(tn->him_preferred[i] == CURL_YES) + set_remote_option(data, i, CURL_YES); + } +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void printoption(struct Curl_easy *data, + const char *direction, int cmd, int option) +{ + if(data->set.verbose) { + if(cmd == CURL_IAC) { + if(CURL_TELCMD_OK(option)) + infof(data, "%s IAC %s", direction, CURL_TELCMD(option)); + else + infof(data, "%s IAC %d", direction, option); + } + else { + const char *fmt = (cmd == CURL_WILL) ? "WILL" : + (cmd == CURL_WONT) ? "WONT" : + (cmd == CURL_DO) ? "DO" : + (cmd == CURL_DONT) ? "DONT" : 0; + if(fmt) { + const char *opt; + if(CURL_TELOPT_OK(option)) + opt = CURL_TELOPT(option); + else if(option == CURL_TELOPT_EXOPL) + opt = "EXOPL"; + else + opt = NULL; + + if(opt) + infof(data, "%s %s %s", direction, fmt, opt); + else + infof(data, "%s %s %d", direction, fmt, option); + } + else + infof(data, "%s %d %d", direction, cmd, option); + } + } +} +#endif + +static void send_negotiation(struct Curl_easy *data, int cmd, int option) +{ + unsigned char buf[3]; + ssize_t bytes_written; + struct connectdata *conn = data->conn; + + buf[0] = CURL_IAC; + buf[1] = (unsigned char)cmd; + buf[2] = (unsigned char)option; + + bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); + if(bytes_written < 0) { + int err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + + printoption(data, "SENT", cmd, option); +} + +static +void set_remote_option(struct Curl_easy *data, int option, int newstate) +{ + struct TELNET *tn = data->req.p.telnet; + if(newstate == CURL_YES) { + switch(tn->him[option]) { + case CURL_NO: + tn->him[option] = CURL_WANTYES; + send_negotiation(data, CURL_DO, option); + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Already negotiating for CURL_YES, queue the request */ + tn->himq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Error: already negotiating for enable */ + break; + case CURL_OPPOSITE: + tn->himq[option] = CURL_EMPTY; + break; + } + break; + } + } + else { /* NO */ + switch(tn->him[option]) { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->him[option] = CURL_WANTNO; + send_negotiation(data, CURL_DONT, option); + break; + + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Already negotiating for NO */ + break; + case CURL_OPPOSITE: + tn->himq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->himq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + break; + } + break; + } + } +} + +static +void rec_will(struct Curl_easy *data, int option) +{ + struct TELNET *tn = data->req.p.telnet; + switch(tn->him[option]) { + case CURL_NO: + if(tn->him_preferred[option] == CURL_YES) { + tn->him[option] = CURL_YES; + send_negotiation(data, CURL_DO, option); + } + else + send_negotiation(data, CURL_DONT, option); + + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Error: DONT answered by WILL */ + tn->him[option] = CURL_NO; + break; + case CURL_OPPOSITE: + /* Error: DONT answered by WILL */ + tn->him[option] = CURL_YES; + tn->himq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->him[option] = CURL_YES; + break; + case CURL_OPPOSITE: + tn->him[option] = CURL_WANTNO; + tn->himq[option] = CURL_EMPTY; + send_negotiation(data, CURL_DONT, option); + break; + } + break; + } +} + +static +void rec_wont(struct Curl_easy *data, int option) +{ + struct TELNET *tn = data->req.p.telnet; + switch(tn->him[option]) { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->him[option] = CURL_NO; + send_negotiation(data, CURL_DONT, option); + break; + + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->him[option] = CURL_NO; + break; + + case CURL_OPPOSITE: + tn->him[option] = CURL_WANTYES; + tn->himq[option] = CURL_EMPTY; + send_negotiation(data, CURL_DO, option); + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->him[option] = CURL_NO; + break; + case CURL_OPPOSITE: + tn->him[option] = CURL_NO; + tn->himq[option] = CURL_EMPTY; + break; + } + break; + } +} + +static void +set_local_option(struct Curl_easy *data, int option, int newstate) +{ + struct TELNET *tn = data->req.p.telnet; + if(newstate == CURL_YES) { + switch(tn->us[option]) { + case CURL_NO: + tn->us[option] = CURL_WANTYES; + send_negotiation(data, CURL_WILL, option); + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Already negotiating for CURL_YES, queue the request */ + tn->usq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Error: already negotiating for enable */ + break; + case CURL_OPPOSITE: + tn->usq[option] = CURL_EMPTY; + break; + } + break; + } + } + else { /* NO */ + switch(tn->us[option]) { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->us[option] = CURL_WANTNO; + send_negotiation(data, CURL_WONT, option); + break; + + case CURL_WANTNO: + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Already negotiating for NO */ + break; + case CURL_OPPOSITE: + tn->usq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) { + case CURL_EMPTY: + tn->usq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + break; + } + break; + } + } +} + +static +void rec_do(struct Curl_easy *data, int option) +{ + struct TELNET *tn = data->req.p.telnet; + switch(tn->us[option]) { + case CURL_NO: + if(tn->us_preferred[option] == CURL_YES) { + tn->us[option] = CURL_YES; + send_negotiation(data, CURL_WILL, option); + if(tn->subnegotiation[option] == CURL_YES) + /* transmission of data option */ + sendsuboption(data, option); + } + else if(tn->subnegotiation[option] == CURL_YES) { + /* send information to achieve this option */ + tn->us[option] = CURL_YES; + send_negotiation(data, CURL_WILL, option); + sendsuboption(data, option); + } + else + send_negotiation(data, CURL_WONT, option); + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Error: DONT answered by WILL */ + tn->us[option] = CURL_NO; + break; + case CURL_OPPOSITE: + /* Error: DONT answered by WILL */ + tn->us[option] = CURL_YES; + tn->usq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) { + case CURL_EMPTY: + tn->us[option] = CURL_YES; + if(tn->subnegotiation[option] == CURL_YES) { + /* transmission of data option */ + sendsuboption(data, option); + } + break; + case CURL_OPPOSITE: + tn->us[option] = CURL_WANTNO; + tn->himq[option] = CURL_EMPTY; + send_negotiation(data, CURL_WONT, option); + break; + } + break; + } +} + +static +void rec_dont(struct Curl_easy *data, int option) +{ + struct TELNET *tn = data->req.p.telnet; + switch(tn->us[option]) { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->us[option] = CURL_NO; + send_negotiation(data, CURL_WONT, option); + break; + + case CURL_WANTNO: + switch(tn->usq[option]) { + case CURL_EMPTY: + tn->us[option] = CURL_NO; + break; + + case CURL_OPPOSITE: + tn->us[option] = CURL_WANTYES; + tn->usq[option] = CURL_EMPTY; + send_negotiation(data, CURL_WILL, option); + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) { + case CURL_EMPTY: + tn->us[option] = CURL_NO; + break; + case CURL_OPPOSITE: + tn->us[option] = CURL_NO; + tn->usq[option] = CURL_EMPTY; + break; + } + break; + } +} + + +static void printsub(struct Curl_easy *data, + int direction, /* '<' or '>' */ + unsigned char *pointer, /* where suboption data is */ + size_t length) /* length of suboption data */ +{ + if(data->set.verbose) { + unsigned int i = 0; + if(direction) { + infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); + if(length >= 3) { + int j; + + i = pointer[length-2]; + j = pointer[length-1]; + + if(i != CURL_IAC || j != CURL_SE) { + infof(data, "(terminated by "); + if(CURL_TELOPT_OK(i)) + infof(data, "%s ", CURL_TELOPT(i)); + else if(CURL_TELCMD_OK(i)) + infof(data, "%s ", CURL_TELCMD(i)); + else + infof(data, "%u ", i); + if(CURL_TELOPT_OK(j)) + infof(data, "%s", CURL_TELOPT(j)); + else if(CURL_TELCMD_OK(j)) + infof(data, "%s", CURL_TELCMD(j)); + else + infof(data, "%d", j); + infof(data, ", not IAC SE) "); + } + } + length -= 2; + } + if(length < 1) { + infof(data, "(Empty suboption?)"); + return; + } + + if(CURL_TELOPT_OK(pointer[0])) { + switch(pointer[0]) { + case CURL_TELOPT_TTYPE: + case CURL_TELOPT_XDISPLOC: + case CURL_TELOPT_NEW_ENVIRON: + case CURL_TELOPT_NAWS: + infof(data, "%s", CURL_TELOPT(pointer[0])); + break; + default: + infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); + break; + } + } + else + infof(data, "%d (unknown)", pointer[i]); + + switch(pointer[0]) { + case CURL_TELOPT_NAWS: + if(length > 4) + infof(data, "Width: %d ; Height: %d", (pointer[1]<<8) | pointer[2], + (pointer[3]<<8) | pointer[4]); + break; + default: + switch(pointer[1]) { + case CURL_TELQUAL_IS: + infof(data, " IS"); + break; + case CURL_TELQUAL_SEND: + infof(data, " SEND"); + break; + case CURL_TELQUAL_INFO: + infof(data, " INFO/REPLY"); + break; + case CURL_TELQUAL_NAME: + infof(data, " NAME"); + break; + } + + switch(pointer[0]) { + case CURL_TELOPT_TTYPE: + case CURL_TELOPT_XDISPLOC: + pointer[length] = 0; + infof(data, " \"%s\"", &pointer[2]); + break; + case CURL_TELOPT_NEW_ENVIRON: + if(pointer[1] == CURL_TELQUAL_IS) { + infof(data, " "); + for(i = 3; i < length; i++) { + switch(pointer[i]) { + case CURL_NEW_ENV_VAR: + infof(data, ", "); + break; + case CURL_NEW_ENV_VALUE: + infof(data, " = "); + break; + default: + infof(data, "%c", pointer[i]); + break; + } + } + } + break; + default: + for(i = 2; i < length; i++) + infof(data, " %.2x", pointer[i]); + break; + } + } + } +} + +#ifdef _MSC_VER +#pragma warning(push) +/* warning C4706: assignment within conditional expression */ +#pragma warning(disable:4706) +#endif +static bool str_is_nonascii(const char *str) +{ + char c; + while((c = *str++)) + if(c & 0x80) + return TRUE; + + return FALSE; +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static CURLcode check_telnet_options(struct Curl_easy *data) +{ + struct curl_slist *head; + struct curl_slist *beg; + struct TELNET *tn = data->req.p.telnet; + CURLcode result = CURLE_OK; + + /* Add the user name as an environment variable if it + was given on the command line */ + if(data->state.aptr.user) { + char buffer[256]; + if(str_is_nonascii(data->conn->user)) { + DEBUGF(infof(data, "set a non ASCII user name in telnet")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); + beg = curl_slist_append(tn->telnet_vars, buffer); + if(!beg) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + return CURLE_OUT_OF_MEMORY; + } + tn->telnet_vars = beg; + tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; + } + + for(head = data->set.telnet_options; head && !result; head = head->next) { + size_t olen; + char *option = head->data; + char *arg; + char *sep = strchr(option, '='); + if(sep) { + olen = sep - option; + arg = ++sep; + if(str_is_nonascii(arg)) + continue; + switch(olen) { + case 5: + /* Terminal type */ + if(strncasecompare(option, "TTYPE", 5)) { + size_t l = strlen(arg); + if(l < sizeof(tn->subopt_ttype)) { + strcpy(tn->subopt_ttype, arg); + tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; + break; + } + } + result = CURLE_UNKNOWN_OPTION; + break; + + case 8: + /* Display variable */ + if(strncasecompare(option, "XDISPLOC", 8)) { + size_t l = strlen(arg); + if(l < sizeof(tn->subopt_xdisploc)) { + strcpy(tn->subopt_xdisploc, arg); + tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; + break; + } + } + result = CURLE_UNKNOWN_OPTION; + break; + + case 7: + /* Environment variable */ + if(strncasecompare(option, "NEW_ENV", 7)) { + beg = curl_slist_append(tn->telnet_vars, arg); + if(!beg) { + result = CURLE_OUT_OF_MEMORY; + break; + } + tn->telnet_vars = beg; + tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; + } + else + result = CURLE_UNKNOWN_OPTION; + break; + + case 2: + /* Window Size */ + if(strncasecompare(option, "WS", 2)) { + char *p; + unsigned long x = strtoul(arg, &p, 10); + unsigned long y = 0; + if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') { + p++; + y = strtoul(p, NULL, 10); + if(y && (y <= 0xffff)) { + tn->subopt_wsx = (unsigned short)x; + tn->subopt_wsy = (unsigned short)y; + tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; + } + } + if(!y) { + failf(data, "Syntax error in telnet option: %s", head->data); + result = CURLE_SETOPT_OPTION_SYNTAX; + } + } + else + result = CURLE_UNKNOWN_OPTION; + break; + + case 6: + /* To take care or not of the 8th bit in data exchange */ + if(strncasecompare(option, "BINARY", 6)) { + int binary_option = atoi(arg); + if(binary_option != 1) { + tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; + tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; + } + } + else + result = CURLE_UNKNOWN_OPTION; + break; + default: + failf(data, "Unknown telnet option %s", head->data); + result = CURLE_UNKNOWN_OPTION; + break; + } + } + else { + failf(data, "Syntax error in telnet option: %s", head->data); + result = CURLE_SETOPT_OPTION_SYNTAX; + } + } + + if(result) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + } + + return result; +} + +/* + * suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + */ + +static void suboption(struct Curl_easy *data) +{ + struct curl_slist *v; + unsigned char temp[2048]; + ssize_t bytes_written; + size_t len; + int err; + struct TELNET *tn = data->req.p.telnet; + struct connectdata *conn = data->conn; + + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); + switch(CURL_SB_GET(tn)) { + case CURL_TELOPT_TTYPE: + len = strlen(tn->subopt_ttype) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_XDISPLOC: + len = strlen(tn->subopt_xdisploc) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_NEW_ENVIRON: + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); + len = 4; + + for(v = tn->telnet_vars; v; v = v->next) { + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { + char *s = strchr(v->data, ','); + if(!s) + len += msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s", CURL_NEW_ENV_VAR, v->data); + else { + size_t vlen = s - v->data; + len += msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%.*s%c%s", CURL_NEW_ENV_VAR, + (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s); + } + } + } + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); + len += 2; + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + } + return; +} + + +/* + * sendsuboption() + * + * Send suboption information to the server side. + */ + +static void sendsuboption(struct Curl_easy *data, int option) +{ + ssize_t bytes_written; + int err; + unsigned short x, y; + unsigned char *uc1, *uc2; + struct TELNET *tn = data->req.p.telnet; + struct connectdata *conn = data->conn; + + switch(option) { + case CURL_TELOPT_NAWS: + /* We prepare data to be sent */ + CURL_SB_CLEAR(tn); + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, CURL_SB); + CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); + /* We must deal either with little or big endian processors */ + /* Window size must be sent according to the 'network order' */ + x = htons(tn->subopt_wsx); + y = htons(tn->subopt_wsy); + uc1 = (unsigned char *)&x; + uc2 = (unsigned char *)&y; + CURL_SB_ACCUM(tn, uc1[0]); + CURL_SB_ACCUM(tn, uc1[1]); + CURL_SB_ACCUM(tn, uc2[0]); + CURL_SB_ACCUM(tn, uc2[1]); + + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, CURL_SE); + CURL_SB_TERM(tn); + /* data suboption is now ready */ + + printsub(data, '>', (unsigned char *)tn->subbuffer + 2, + CURL_SB_LEN(tn)-2); + + /* we send the header of the suboption... */ + bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data, "Sending data failed (%d)", err); + } + /* ... then the window size with the send_telnet_data() function + to deal with 0xFF cases ... */ + send_telnet_data(data, (char *)tn->subbuffer + 3, 4); + /* ... and the footer */ + bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data, "Sending data failed (%d)", err); + } + break; + } +} + + +static +CURLcode telrcv(struct Curl_easy *data, + const unsigned char *inbuf, /* Data received from socket */ + ssize_t count) /* Number of bytes received */ +{ + unsigned char c; + CURLcode result; + int in = 0; + int startwrite = -1; + struct TELNET *tn = data->req.p.telnet; + +#define startskipping() \ + if(startwrite >= 0) { \ + result = Curl_client_write(data, \ + CLIENTWRITE_BODY, \ + (char *)&inbuf[startwrite], \ + in-startwrite); \ + if(result) \ + return result; \ + } \ + startwrite = -1 + +#define writebyte() \ + if(startwrite < 0) \ + startwrite = in + +#define bufferflush() startskipping() + + while(count--) { + c = inbuf[in]; + + switch(tn->telrcv_state) { + case CURL_TS_CR: + tn->telrcv_state = CURL_TS_DATA; + if(c == '\0') { + startskipping(); + break; /* Ignore \0 after CR */ + } + writebyte(); + break; + + case CURL_TS_DATA: + if(c == CURL_IAC) { + tn->telrcv_state = CURL_TS_IAC; + startskipping(); + break; + } + else if(c == '\r') + tn->telrcv_state = CURL_TS_CR; + writebyte(); + break; + + case CURL_TS_IAC: +process_iac: + DEBUGASSERT(startwrite < 0); + switch(c) { + case CURL_WILL: + tn->telrcv_state = CURL_TS_WILL; + break; + case CURL_WONT: + tn->telrcv_state = CURL_TS_WONT; + break; + case CURL_DO: + tn->telrcv_state = CURL_TS_DO; + break; + case CURL_DONT: + tn->telrcv_state = CURL_TS_DONT; + break; + case CURL_SB: + CURL_SB_CLEAR(tn); + tn->telrcv_state = CURL_TS_SB; + break; + case CURL_IAC: + tn->telrcv_state = CURL_TS_DATA; + writebyte(); + break; + case CURL_DM: + case CURL_NOP: + case CURL_GA: + default: + tn->telrcv_state = CURL_TS_DATA; + printoption(data, "RCVD", CURL_IAC, c); + break; + } + break; + + case CURL_TS_WILL: + printoption(data, "RCVD", CURL_WILL, c); + tn->please_negotiate = 1; + rec_will(data, c); + tn->telrcv_state = CURL_TS_DATA; + break; + + case CURL_TS_WONT: + printoption(data, "RCVD", CURL_WONT, c); + tn->please_negotiate = 1; + rec_wont(data, c); + tn->telrcv_state = CURL_TS_DATA; + break; + + case CURL_TS_DO: + printoption(data, "RCVD", CURL_DO, c); + tn->please_negotiate = 1; + rec_do(data, c); + tn->telrcv_state = CURL_TS_DATA; + break; + + case CURL_TS_DONT: + printoption(data, "RCVD", CURL_DONT, c); + tn->please_negotiate = 1; + rec_dont(data, c); + tn->telrcv_state = CURL_TS_DATA; + break; + + case CURL_TS_SB: + if(c == CURL_IAC) + tn->telrcv_state = CURL_TS_SE; + else + CURL_SB_ACCUM(tn, c); + break; + + case CURL_TS_SE: + if(c != CURL_SE) { + if(c != CURL_IAC) { + /* + * This is an error. We only expect to get "IAC IAC" or "IAC SE". + * Several things may have happened. An IAC was not doubled, the + * IAC SE was left off, or another option got inserted into the + * suboption are all possibilities. If we assume that the IAC was + * not doubled, and really the IAC SE was left off, we could get + * into an infinite loop here. So, instead, we terminate the + * suboption, and process the partial suboption if we can. + */ + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, c); + tn->subpointer -= 2; + CURL_SB_TERM(tn); + + printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); + suboption(data); /* handle sub-option */ + tn->telrcv_state = CURL_TS_IAC; + goto process_iac; + } + CURL_SB_ACCUM(tn, c); + tn->telrcv_state = CURL_TS_SB; + } + else { + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, CURL_SE); + tn->subpointer -= 2; + CURL_SB_TERM(tn); + suboption(data); /* handle sub-option */ + tn->telrcv_state = CURL_TS_DATA; + } + break; + } + ++in; + } + bufferflush(); + return CURLE_OK; +} + +/* Escape and send a telnet data block */ +static CURLcode send_telnet_data(struct Curl_easy *data, + char *buffer, ssize_t nread) +{ + ssize_t i, outlen; + unsigned char *outbuf; + CURLcode result = CURLE_OK; + ssize_t bytes_written, total_written = 0; + struct connectdata *conn = data->conn; + struct TELNET *tn = data->req.p.telnet; + + DEBUGASSERT(tn); + + if(memchr(buffer, CURL_IAC, nread)) { + /* only use the escape buffer when necessary */ + Curl_dyn_reset(&tn->out); + + for(i = 0; i < nread && !result; i++) { + result = Curl_dyn_addn(&tn->out, &buffer[i], 1); + if(!result && ((unsigned char)buffer[i] == CURL_IAC)) + /* IAC is FF in hex */ + result = Curl_dyn_addn(&tn->out, "\xff", 1); + } + + outlen = Curl_dyn_len(&tn->out); + outbuf = Curl_dyn_uptr(&tn->out); + } + else { + outlen = nread; + outbuf = (unsigned char *)buffer; + } + while(!result && total_written < outlen) { + /* Make sure socket is writable to avoid EWOULDBLOCK condition */ + struct pollfd pfd[1]; + pfd[0].fd = conn->sock[FIRSTSOCKET]; + pfd[0].events = POLLOUT; + switch(Curl_poll(pfd, 1, -1)) { + case -1: /* error, abort writing */ + case 0: /* timeout (will never happen) */ + result = CURLE_SEND_ERROR; + break; + default: /* write! */ + bytes_written = 0; + result = Curl_nwrite(data, FIRSTSOCKET, outbuf + total_written, + outlen - total_written, &bytes_written); + total_written += bytes_written; + break; + } + } + + return result; +} + +static CURLcode telnet_done(struct Curl_easy *data, + CURLcode status, bool premature) +{ + struct TELNET *tn = data->req.p.telnet; + (void)status; /* unused */ + (void)premature; /* not used */ + + if(!tn) + return CURLE_OK; + + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + Curl_dyn_free(&tn->out); + return CURLE_OK; +} + +static CURLcode telnet_do(struct Curl_easy *data, bool *done) +{ + CURLcode result; + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; +#ifdef USE_WINSOCK + WSAEVENT event_handle; + WSANETWORKEVENTS events; + HANDLE stdin_handle; + HANDLE objs[2]; + DWORD obj_count; + DWORD wait_timeout; + DWORD readfile_read; + int err; +#else + timediff_t interval_ms; + struct pollfd pfd[2]; + int poll_cnt; + curl_off_t total_dl = 0; + curl_off_t total_ul = 0; +#endif + ssize_t nread; + struct curltime now; + bool keepon = TRUE; + char buffer[4*1024]; + struct TELNET *tn; + + *done = TRUE; /* unconditionally */ + + result = init_telnet(data); + if(result) + return result; + + tn = data->req.p.telnet; + + result = check_telnet_options(data); + if(result) + return result; + +#ifdef USE_WINSOCK + /* We want to wait for both stdin and the socket. Since + ** the select() function in winsock only works on sockets + ** we have to use the WaitForMultipleObjects() call. + */ + + /* First, create a sockets event object */ + event_handle = WSACreateEvent(); + if(event_handle == WSA_INVALID_EVENT) { + failf(data, "WSACreateEvent failed (%d)", SOCKERRNO); + return CURLE_FAILED_INIT; + } + + /* Tell winsock what events we want to listen to */ + if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { + WSACloseEvent(event_handle); + return CURLE_OK; + } + + /* The get the Windows file handle for stdin */ + stdin_handle = GetStdHandle(STD_INPUT_HANDLE); + + /* Create the list of objects to wait for */ + objs[0] = event_handle; + objs[1] = stdin_handle; + + /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, + else use the old WaitForMultipleObjects() way */ + if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || + data->set.is_fread_set) { + /* Don't wait for stdin_handle, just wait for event_handle */ + obj_count = 1; + /* Check stdin_handle per 100 milliseconds */ + wait_timeout = 100; + } + else { + obj_count = 2; + wait_timeout = 1000; + } + + /* Keep on listening and act on events */ + while(keepon) { + const DWORD buf_size = (DWORD)sizeof(buffer); + DWORD waitret = WaitForMultipleObjects(obj_count, objs, + FALSE, wait_timeout); + switch(waitret) { + + case WAIT_TIMEOUT: + { + for(;;) { + if(data->set.is_fread_set) { + size_t n; + /* read from user-supplied method */ + n = data->state.fread_func(buffer, 1, buf_size, data->state.in); + if(n == CURL_READFUNC_ABORT) { + keepon = FALSE; + result = CURLE_READ_ERROR; + break; + } + + if(n == CURL_READFUNC_PAUSE) + break; + + if(n == 0) /* no bytes */ + break; + + /* fall through with number of bytes read */ + readfile_read = (DWORD)n; + } + else { + /* read from stdin */ + if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, + &readfile_read, NULL)) { + keepon = FALSE; + result = CURLE_READ_ERROR; + break; + } + + if(!readfile_read) + break; + + if(!ReadFile(stdin_handle, buffer, buf_size, + &readfile_read, NULL)) { + keepon = FALSE; + result = CURLE_READ_ERROR; + break; + } + } + + result = send_telnet_data(data, buffer, readfile_read); + if(result) { + keepon = FALSE; + break; + } + } + } + break; + + case WAIT_OBJECT_0 + 1: + { + if(!ReadFile(stdin_handle, buffer, buf_size, + &readfile_read, NULL)) { + keepon = FALSE; + result = CURLE_READ_ERROR; + break; + } + + result = send_telnet_data(data, buffer, readfile_read); + if(result) { + keepon = FALSE; + break; + } + } + break; + + case WAIT_OBJECT_0: + { + events.lNetworkEvents = 0; + if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) { + err = SOCKERRNO; + if(err != EINPROGRESS) { + infof(data, "WSAEnumNetworkEvents failed (%d)", err); + keepon = FALSE; + result = CURLE_READ_ERROR; + } + break; + } + if(events.lNetworkEvents & FD_READ) { + /* read data from network */ + result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread); + /* read would've blocked. Loop again */ + if(result == CURLE_AGAIN) + break; + /* returned not-zero, this an error */ + else if(result) { + keepon = FALSE; + break; + } + /* returned zero but actually received 0 or less here, + the server closed the connection and we bail out */ + else if(nread <= 0) { + keepon = FALSE; + break; + } + + result = telrcv(data, (unsigned char *) buffer, nread); + if(result) { + keepon = FALSE; + break; + } + + /* Negotiate if the peer has started negotiating, + otherwise don't. We don't want to speak telnet with + non-telnet servers, like POP or SMTP. */ + if(tn->please_negotiate && !tn->already_negotiated) { + negotiate(data); + tn->already_negotiated = 1; + } + } + if(events.lNetworkEvents & FD_CLOSE) { + keepon = FALSE; + } + } + break; + + } + + if(data->set.timeout) { + now = Curl_now(); + if(Curl_timediff(now, conn->created) >= data->set.timeout) { + failf(data, "Time-out"); + result = CURLE_OPERATION_TIMEDOUT; + keepon = FALSE; + } + } + } + + /* We called WSACreateEvent, so call WSACloseEvent */ + if(!WSACloseEvent(event_handle)) { + infof(data, "WSACloseEvent failed (%d)", SOCKERRNO); + } +#else + pfd[0].fd = sockfd; + pfd[0].events = POLLIN; + + if(data->set.is_fread_set) { + poll_cnt = 1; + interval_ms = 100; /* poll user-supplied read function */ + } + else { + /* really using fread, so infile is a FILE* */ + pfd[1].fd = fileno((FILE *)data->state.in); + pfd[1].events = POLLIN; + poll_cnt = 2; + interval_ms = 1 * 1000; + } + + while(keepon) { + DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt)); + switch(Curl_poll(pfd, poll_cnt, interval_ms)) { + case -1: /* error, stop reading */ + keepon = FALSE; + continue; + case 0: /* timeout */ + pfd[0].revents = 0; + pfd[1].revents = 0; + FALLTHROUGH(); + default: /* read! */ + if(pfd[0].revents & POLLIN) { + /* read data from network */ + result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread); + /* read would've blocked. Loop again */ + if(result == CURLE_AGAIN) + break; + /* returned not-zero, this an error */ + if(result) { + keepon = FALSE; + /* TODO: in test 1452, macOS sees a ECONNRESET sometimes? + * Is this the telnet test server not shutting down the socket + * in a clean way? Seems to be timing related, happens more + * on slow debug build */ + if(data->state.os_errno == ECONNRESET) { + DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv")); + } + break; + } + /* returned zero but actually received 0 or less here, + the server closed the connection and we bail out */ + else if(nread <= 0) { + keepon = FALSE; + break; + } + + total_dl += nread; + result = Curl_pgrsSetDownloadCounter(data, total_dl); + if(!result) + result = telrcv(data, (unsigned char *)buffer, nread); + if(result) { + keepon = FALSE; + break; + } + + /* Negotiate if the peer has started negotiating, + otherwise don't. We don't want to speak telnet with + non-telnet servers, like POP or SMTP. */ + if(tn->please_negotiate && !tn->already_negotiated) { + negotiate(data); + tn->already_negotiated = 1; + } + } + + nread = 0; + if(poll_cnt == 2) { + if(pfd[1].revents & POLLIN) { /* read from in file */ + nread = read(pfd[1].fd, buffer, sizeof(buffer)); + } + } + else { + /* read from user-supplied method */ + nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer), + data->state.in); + if(nread == CURL_READFUNC_ABORT) { + keepon = FALSE; + break; + } + if(nread == CURL_READFUNC_PAUSE) + break; + } + + if(nread > 0) { + result = send_telnet_data(data, buffer, nread); + if(result) { + keepon = FALSE; + break; + } + total_ul += nread; + Curl_pgrsSetUploadCounter(data, total_ul); + } + else if(nread < 0) + keepon = FALSE; + + break; + } /* poll switch statement */ + + if(data->set.timeout) { + now = Curl_now(); + if(Curl_timediff(now, conn->created) >= data->set.timeout) { + failf(data, "Time-out"); + result = CURLE_OPERATION_TIMEDOUT; + keepon = FALSE; + } + } + + if(Curl_pgrsUpdate(data)) { + result = CURLE_ABORTED_BY_CALLBACK; + break; + } + } +#endif + /* mark this as "no further transfer wanted" */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + + return result; +} +#endif diff --git a/lib/telnet.h b/lib/telnet.h new file mode 100644 index 0000000..30782d8 --- /dev/null +++ b/lib/telnet.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_TELNET_H +#define HEADER_CURL_TELNET_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifndef CURL_DISABLE_TELNET +extern const struct Curl_handler Curl_handler_telnet; +#endif + +#endif /* HEADER_CURL_TELNET_H */ diff --git a/lib/tftp.c b/lib/tftp.c new file mode 100644 index 0000000..4288110 --- /dev/null +++ b/lib/tftp.c @@ -0,0 +1,1405 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_TFTP + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#include "urldata.h" +#include +#include "cf-socket.h" +#include "transfer.h" +#include "sendf.h" +#include "tftp.h" +#include "progress.h" +#include "connect.h" +#include "strerror.h" +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "multiif.h" +#include "url.h" +#include "strcase.h" +#include "speedcheck.h" +#include "select.h" +#include "escape.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* RFC2348 allows the block size to be negotiated */ +#define TFTP_BLKSIZE_DEFAULT 512 +#define TFTP_OPTION_BLKSIZE "blksize" + +/* from RFC2349: */ +#define TFTP_OPTION_TSIZE "tsize" +#define TFTP_OPTION_INTERVAL "timeout" + +typedef enum { + TFTP_MODE_NETASCII = 0, + TFTP_MODE_OCTET +} tftp_mode_t; + +typedef enum { + TFTP_STATE_START = 0, + TFTP_STATE_RX, + TFTP_STATE_TX, + TFTP_STATE_FIN +} tftp_state_t; + +typedef enum { + TFTP_EVENT_NONE = -1, + TFTP_EVENT_INIT = 0, + TFTP_EVENT_RRQ = 1, + TFTP_EVENT_WRQ = 2, + TFTP_EVENT_DATA = 3, + TFTP_EVENT_ACK = 4, + TFTP_EVENT_ERROR = 5, + TFTP_EVENT_OACK = 6, + TFTP_EVENT_TIMEOUT +} tftp_event_t; + +typedef enum { + TFTP_ERR_UNDEF = 0, + TFTP_ERR_NOTFOUND, + TFTP_ERR_PERM, + TFTP_ERR_DISKFULL, + TFTP_ERR_ILLEGAL, + TFTP_ERR_UNKNOWNID, + TFTP_ERR_EXISTS, + TFTP_ERR_NOSUCHUSER, /* This will never be triggered by this code */ + + /* The remaining error codes are internal to curl */ + TFTP_ERR_NONE = -100, + TFTP_ERR_TIMEOUT, + TFTP_ERR_NORESPONSE +} tftp_error_t; + +struct tftp_packet { + unsigned char *data; +}; + +struct tftp_state_data { + tftp_state_t state; + tftp_mode_t mode; + tftp_error_t error; + tftp_event_t event; + struct Curl_easy *data; + curl_socket_t sockfd; + int retries; + int retry_time; + int retry_max; + time_t rx_time; + struct Curl_sockaddr_storage local_addr; + struct Curl_sockaddr_storage remote_addr; + curl_socklen_t remote_addrlen; + int rbytes; + int sbytes; + int blksize; + int requested_blksize; + unsigned short block; + struct tftp_packet rpacket; + struct tftp_packet spacket; +}; + + +/* Forward declarations */ +static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event); +static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event); +static CURLcode tftp_connect(struct Curl_easy *data, bool *done); +static CURLcode tftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection); +static CURLcode tftp_do(struct Curl_easy *data, bool *done); +static CURLcode tftp_done(struct Curl_easy *data, + CURLcode, bool premature); +static CURLcode tftp_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done); +static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done); +static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks); +static CURLcode tftp_translate_code(tftp_error_t error); + + +/* + * TFTP protocol handler. + */ + +const struct Curl_handler Curl_handler_tftp = { + "TFTP", /* scheme */ + tftp_setup_connection, /* setup_connection */ + tftp_do, /* do_it */ + tftp_done, /* done */ + ZERO_NULL, /* do_more */ + tftp_connect, /* connect_it */ + tftp_multi_statemach, /* connecting */ + tftp_doing, /* doing */ + tftp_getsock, /* proto_getsock */ + tftp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + tftp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_TFTP, /* defport */ + CURLPROTO_TFTP, /* protocol */ + CURLPROTO_TFTP, /* family */ + PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */ +}; + +/********************************************************** + * + * tftp_set_timeouts - + * + * Set timeouts based on state machine state. + * Use user provided connect timeouts until DATA or ACK + * packet is received, then use user-provided transfer timeouts + * + * + **********************************************************/ +static CURLcode tftp_set_timeouts(struct tftp_state_data *state) +{ + time_t maxtime, timeout; + timediff_t timeout_ms; + bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; + + /* Compute drop-dead time */ + timeout_ms = Curl_timeleft(state->data, NULL, start); + + if(timeout_ms < 0) { + /* time-out, bail out, go home */ + failf(state->data, "Connection time-out"); + return CURLE_OPERATION_TIMEDOUT; + } + + if(timeout_ms > 0) + maxtime = (time_t)(timeout_ms + 500) / 1000; + else + maxtime = 3600; /* use for calculating block timeouts */ + + /* Set per-block timeout to total */ + timeout = maxtime; + + /* Average reposting an ACK after 5 seconds */ + state->retry_max = (int)timeout/5; + + /* But bound the total number */ + if(state->retry_max<3) + state->retry_max = 3; + + if(state->retry_max>50) + state->retry_max = 50; + + /* Compute the re-ACK interval to suit the timeout */ + state->retry_time = (int)(timeout/state->retry_max); + if(state->retry_time<1) + state->retry_time = 1; + + infof(state->data, + "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T + ", retry %d maxtry %d", + (int)state->state, timeout_ms, state->retry_time, state->retry_max); + + /* init RX time */ + time(&state->rx_time); + + return CURLE_OK; +} + +/********************************************************** + * + * tftp_set_send_first + * + * Event handler for the START state + * + **********************************************************/ + +static void setpacketevent(struct tftp_packet *packet, unsigned short num) +{ + packet->data[0] = (unsigned char)(num >> 8); + packet->data[1] = (unsigned char)(num & 0xff); +} + + +static void setpacketblock(struct tftp_packet *packet, unsigned short num) +{ + packet->data[2] = (unsigned char)(num >> 8); + packet->data[3] = (unsigned char)(num & 0xff); +} + +static unsigned short getrpacketevent(const struct tftp_packet *packet) +{ + return (unsigned short)((packet->data[0] << 8) | packet->data[1]); +} + +static unsigned short getrpacketblock(const struct tftp_packet *packet) +{ + return (unsigned short)((packet->data[2] << 8) | packet->data[3]); +} + +static size_t tftp_strnlen(const char *string, size_t maxlen) +{ + const char *end = memchr(string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} + +static const char *tftp_option_get(const char *buf, size_t len, + const char **option, const char **value) +{ + size_t loc; + + loc = tftp_strnlen(buf, len); + loc++; /* NULL term */ + + if(loc >= len) + return NULL; + *option = buf; + + loc += tftp_strnlen(buf + loc, len-loc); + loc++; /* NULL term */ + + if(loc > len) + return NULL; + *value = &buf[strlen(*option) + 1]; + + return &buf[loc]; +} + +static CURLcode tftp_parse_option_ack(struct tftp_state_data *state, + const char *ptr, int len) +{ + const char *tmp = ptr; + struct Curl_easy *data = state->data; + + /* if OACK doesn't contain blksize option, the default (512) must be used */ + state->blksize = TFTP_BLKSIZE_DEFAULT; + + while(tmp < ptr + len) { + const char *option, *value; + + tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value); + if(!tmp) { + failf(data, "Malformed ACK packet, rejecting"); + return CURLE_TFTP_ILLEGAL; + } + + infof(data, "got option=(%s) value=(%s)", option, value); + + if(checkprefix(TFTP_OPTION_BLKSIZE, option)) { + long blksize; + + blksize = strtol(value, NULL, 10); + + if(!blksize) { + failf(data, "invalid blocksize value in OACK packet"); + return CURLE_TFTP_ILLEGAL; + } + if(blksize > TFTP_BLKSIZE_MAX) { + failf(data, "%s (%d)", "blksize is larger than max supported", + TFTP_BLKSIZE_MAX); + return CURLE_TFTP_ILLEGAL; + } + else if(blksize < TFTP_BLKSIZE_MIN) { + failf(data, "%s (%d)", "blksize is smaller than min supported", + TFTP_BLKSIZE_MIN); + return CURLE_TFTP_ILLEGAL; + } + else if(blksize > state->requested_blksize) { + /* could realloc pkt buffers here, but the spec doesn't call out + * support for the server requesting a bigger blksize than the client + * requests */ + failf(data, "%s (%ld)", + "server requested blksize larger than allocated", blksize); + return CURLE_TFTP_ILLEGAL; + } + + state->blksize = (int)blksize; + infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK", + state->blksize, "requested", state->requested_blksize); + } + else if(checkprefix(TFTP_OPTION_TSIZE, option)) { + long tsize = 0; + + tsize = strtol(value, NULL, 10); + infof(data, "%s (%ld)", "tsize parsed from OACK", tsize); + + /* tsize should be ignored on upload: Who cares about the size of the + remote file? */ + if(!data->state.upload) { + if(!tsize) { + failf(data, "invalid tsize -:%s:- value in OACK packet", value); + return CURLE_TFTP_ILLEGAL; + } + Curl_pgrsSetDownloadSize(data, tsize); + } + } + } + + return CURLE_OK; +} + +static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize, + char *buf, const char *option) +{ + if(( strlen(option) + *csize + 1) > (size_t)state->blksize) + return CURLE_TFTP_ILLEGAL; + strcpy(buf, option); + *csize += strlen(option) + 1; + return CURLE_OK; +} + +static CURLcode tftp_connect_for_tx(struct tftp_state_data *state, + tftp_event_t event) +{ + CURLcode result; +#ifndef CURL_DISABLE_VERBOSE_STRINGS + struct Curl_easy *data = state->data; + + infof(data, "%s", "Connected for transmit"); +#endif + state->state = TFTP_STATE_TX; + result = tftp_set_timeouts(state); + if(result) + return result; + return tftp_tx(state, event); +} + +static CURLcode tftp_connect_for_rx(struct tftp_state_data *state, + tftp_event_t event) +{ + CURLcode result; +#ifndef CURL_DISABLE_VERBOSE_STRINGS + struct Curl_easy *data = state->data; + + infof(data, "%s", "Connected for receive"); +#endif + state->state = TFTP_STATE_RX; + result = tftp_set_timeouts(state); + if(result) + return result; + return tftp_rx(state, event); +} + +static CURLcode tftp_send_first(struct tftp_state_data *state, + tftp_event_t event) +{ + size_t sbytes; + ssize_t senddata; + const char *mode = "octet"; + char *filename; + struct Curl_easy *data = state->data; + CURLcode result = CURLE_OK; + + /* Set ascii mode if -B flag was used */ + if(data->state.prefer_ascii) + mode = "netascii"; + + switch(event) { + + case TFTP_EVENT_INIT: /* Send the first packet out */ + case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */ + /* Increment the retry counter, quit if over the limit */ + state->retries++; + if(state->retries>state->retry_max) { + state->error = TFTP_ERR_NORESPONSE; + state->state = TFTP_STATE_FIN; + return result; + } + + if(data->state.upload) { + /* If we are uploading, send an WRQ */ + setpacketevent(&state->spacket, TFTP_EVENT_WRQ); + state->data->req.upload_fromhere = + (char *)state->spacket.data + 4; + if(data->state.infilesize != -1) + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + else { + /* If we are downloading, send an RRQ */ + setpacketevent(&state->spacket, TFTP_EVENT_RRQ); + } + /* As RFC3617 describes the separator slash is not actually part of the + file name so we skip the always-present first letter of the path + string. */ + result = Curl_urldecode(&state->data->state.up.path[1], 0, + &filename, NULL, REJECT_ZERO); + if(result) + return result; + + if(strlen(filename) > (state->blksize - strlen(mode) - 4)) { + failf(data, "TFTP file name too long"); + free(filename); + return CURLE_TFTP_ILLEGAL; /* too long file name field */ + } + + msnprintf((char *)state->spacket.data + 2, + state->blksize, + "%s%c%s%c", filename, '\0', mode, '\0'); + sbytes = 4 + strlen(filename) + strlen(mode); + + /* optional addition of TFTP options */ + if(!data->set.tftp_no_options) { + char buf[64]; + /* add tsize option */ + if(data->state.upload && (data->state.infilesize != -1)) + msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); + else + strcpy(buf, "0"); /* the destination is large enough */ + + result = tftp_option_add(state, &sbytes, + (char *)state->spacket.data + sbytes, + TFTP_OPTION_TSIZE); + if(result == CURLE_OK) + result = tftp_option_add(state, &sbytes, + (char *)state->spacket.data + sbytes, buf); + + /* add blksize option */ + msnprintf(buf, sizeof(buf), "%d", state->requested_blksize); + if(result == CURLE_OK) + result = tftp_option_add(state, &sbytes, + (char *)state->spacket.data + sbytes, + TFTP_OPTION_BLKSIZE); + if(result == CURLE_OK) + result = tftp_option_add(state, &sbytes, + (char *)state->spacket.data + sbytes, buf); + + /* add timeout option */ + msnprintf(buf, sizeof(buf), "%d", state->retry_time); + if(result == CURLE_OK) + result = tftp_option_add(state, &sbytes, + (char *)state->spacket.data + sbytes, + TFTP_OPTION_INTERVAL); + if(result == CURLE_OK) + result = tftp_option_add(state, &sbytes, + (char *)state->spacket.data + sbytes, buf); + + if(result != CURLE_OK) { + failf(data, "TFTP buffer too small for options"); + free(filename); + return CURLE_TFTP_ILLEGAL; + } + } + + /* the typecase for the 3rd argument is mostly for systems that do + not have a size_t argument, like older unixes that want an 'int' */ + senddata = sendto(state->sockfd, (void *)state->spacket.data, + (SEND_TYPE_ARG3)sbytes, 0, + &data->conn->remote_addr->sa_addr, + data->conn->remote_addr->addrlen); + if(senddata != (ssize_t)sbytes) { + char buffer[STRERROR_LEN]; + failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + } + free(filename); + break; + + case TFTP_EVENT_OACK: + if(data->state.upload) { + result = tftp_connect_for_tx(state, event); + } + else { + result = tftp_connect_for_rx(state, event); + } + break; + + case TFTP_EVENT_ACK: /* Connected for transmit */ + result = tftp_connect_for_tx(state, event); + break; + + case TFTP_EVENT_DATA: /* Connected for receive */ + result = tftp_connect_for_rx(state, event); + break; + + case TFTP_EVENT_ERROR: + state->state = TFTP_STATE_FIN; + break; + + default: + failf(state->data, "tftp_send_first: internal error"); + break; + } + + return result; +} + +/* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit + boundary */ +#define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff) + +/********************************************************** + * + * tftp_rx + * + * Event handler for the RX state + * + **********************************************************/ +static CURLcode tftp_rx(struct tftp_state_data *state, + tftp_event_t event) +{ + ssize_t sbytes; + int rblock; + struct Curl_easy *data = state->data; + char buffer[STRERROR_LEN]; + + switch(event) { + + case TFTP_EVENT_DATA: + /* Is this the block we expect? */ + rblock = getrpacketblock(&state->rpacket); + if(NEXT_BLOCKNUM(state->block) == rblock) { + /* This is the expected block. Reset counters and ACK it. */ + state->retries = 0; + } + else if(state->block == rblock) { + /* This is the last recently received block again. Log it and ACK it + again. */ + infof(data, "Received last DATA packet block %d again.", rblock); + } + else { + /* totally unexpected, just log it */ + infof(data, + "Received unexpected DATA packet block %d, expecting block %d", + rblock, NEXT_BLOCKNUM(state->block)); + break; + } + + /* ACK this block. */ + state->block = (unsigned short)rblock; + setpacketevent(&state->spacket, TFTP_EVENT_ACK); + setpacketblock(&state->spacket, state->block); + sbytes = sendto(state->sockfd, (void *)state->spacket.data, + 4, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + if(sbytes < 0) { + failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; + } + + /* Check if completed (That is, a less than full packet is received) */ + if(state->rbytes < (ssize_t)state->blksize + 4) { + state->state = TFTP_STATE_FIN; + } + else { + state->state = TFTP_STATE_RX; + } + time(&state->rx_time); + break; + + case TFTP_EVENT_OACK: + /* ACK option acknowledgement so we can move on to data */ + state->block = 0; + state->retries = 0; + setpacketevent(&state->spacket, TFTP_EVENT_ACK); + setpacketblock(&state->spacket, state->block); + sbytes = sendto(state->sockfd, (void *)state->spacket.data, + 4, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + if(sbytes < 0) { + failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; + } + + /* we're ready to RX data */ + state->state = TFTP_STATE_RX; + time(&state->rx_time); + break; + + case TFTP_EVENT_TIMEOUT: + /* Increment the retry count and fail if over the limit */ + state->retries++; + infof(data, + "Timeout waiting for block %d ACK. Retries = %d", + NEXT_BLOCKNUM(state->block), state->retries); + if(state->retries > state->retry_max) { + state->error = TFTP_ERR_TIMEOUT; + state->state = TFTP_STATE_FIN; + } + else { + /* Resend the previous ACK */ + sbytes = sendto(state->sockfd, (void *)state->spacket.data, + 4, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + if(sbytes<0) { + failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; + } + } + break; + + case TFTP_EVENT_ERROR: + setpacketevent(&state->spacket, TFTP_EVENT_ERROR); + setpacketblock(&state->spacket, state->block); + (void)sendto(state->sockfd, (void *)state->spacket.data, + 4, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* don't bother with the return code, but if the socket is still up we + * should be a good TFTP client and let the server know we're done */ + state->state = TFTP_STATE_FIN; + break; + + default: + failf(data, "%s", "tftp_rx: internal error"); + return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for + this */ + } + return CURLE_OK; +} + +/********************************************************** + * + * tftp_tx + * + * Event handler for the TX state + * + **********************************************************/ +static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event) +{ + struct Curl_easy *data = state->data; + ssize_t sbytes; + CURLcode result = CURLE_OK; + struct SingleRequest *k = &data->req; + size_t cb; /* Bytes currently read */ + char buffer[STRERROR_LEN]; + + switch(event) { + + case TFTP_EVENT_ACK: + case TFTP_EVENT_OACK: + if(event == TFTP_EVENT_ACK) { + /* Ack the packet */ + int rblock = getrpacketblock(&state->rpacket); + + if(rblock != state->block && + /* There's a bug in tftpd-hpa that causes it to send us an ack for + * 65535 when the block number wraps to 0. So when we're expecting + * 0, also accept 65535. See + * https://www.syslinux.org/archives/2010-September/015612.html + * */ + !(state->block == 0 && rblock == 65535)) { + /* This isn't the expected block. Log it and up the retry counter */ + infof(data, "Received ACK for block %d, expecting %d", + rblock, state->block); + state->retries++; + /* Bail out if over the maximum */ + if(state->retries>state->retry_max) { + failf(data, "tftp_tx: giving up waiting for block %d ack", + state->block); + result = CURLE_SEND_ERROR; + } + else { + /* Re-send the data packet */ + sbytes = sendto(state->sockfd, (void *)state->spacket.data, + 4 + state->sbytes, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* Check all sbytes were sent */ + if(sbytes<0) { + failf(data, "%s", Curl_strerror(SOCKERRNO, + buffer, sizeof(buffer))); + result = CURLE_SEND_ERROR; + } + } + + return result; + } + /* This is the expected packet. Reset the counters and send the next + block */ + time(&state->rx_time); + state->block++; + } + else + state->block = 1; /* first data block is 1 when using OACK */ + + state->retries = 0; + setpacketevent(&state->spacket, TFTP_EVENT_DATA); + setpacketblock(&state->spacket, state->block); + if(state->block > 1 && state->sbytes < state->blksize) { + state->state = TFTP_STATE_FIN; + return CURLE_OK; + } + + /* TFTP considers data block size < 512 bytes as an end of session. So + * in some cases we must wait for additional data to build full (512 bytes) + * data block. + * */ + state->sbytes = 0; + state->data->req.upload_fromhere = (char *)state->spacket.data + 4; + do { + result = Curl_fillreadbuffer(data, state->blksize - state->sbytes, &cb); + if(result) + return result; + state->sbytes += (int)cb; + state->data->req.upload_fromhere += cb; + } while(state->sbytes < state->blksize && cb); + + sbytes = sendto(state->sockfd, (void *) state->spacket.data, + 4 + state->sbytes, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* Check all sbytes were sent */ + if(sbytes<0) { + failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; + } + /* Update the progress meter */ + k->writebytecount += state->sbytes; + Curl_pgrsSetUploadCounter(data, k->writebytecount); + break; + + case TFTP_EVENT_TIMEOUT: + /* Increment the retry counter and log the timeout */ + state->retries++; + infof(data, "Timeout waiting for block %d ACK. " + " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries); + /* Decide if we've had enough */ + if(state->retries > state->retry_max) { + state->error = TFTP_ERR_TIMEOUT; + state->state = TFTP_STATE_FIN; + } + else { + /* Re-send the data packet */ + sbytes = sendto(state->sockfd, (void *)state->spacket.data, + 4 + state->sbytes, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* Check all sbytes were sent */ + if(sbytes<0) { + failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; + } + /* since this was a re-send, we remain at the still byte position */ + Curl_pgrsSetUploadCounter(data, k->writebytecount); + } + break; + + case TFTP_EVENT_ERROR: + state->state = TFTP_STATE_FIN; + setpacketevent(&state->spacket, TFTP_EVENT_ERROR); + setpacketblock(&state->spacket, state->block); + (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* don't bother with the return code, but if the socket is still up we + * should be a good TFTP client and let the server know we're done */ + state->state = TFTP_STATE_FIN; + break; + + default: + failf(data, "tftp_tx: internal error, event: %i", (int)(event)); + break; + } + + return result; +} + +/********************************************************** + * + * tftp_translate_code + * + * Translate internal error codes to CURL error codes + * + **********************************************************/ +static CURLcode tftp_translate_code(tftp_error_t error) +{ + CURLcode result = CURLE_OK; + + if(error != TFTP_ERR_NONE) { + switch(error) { + case TFTP_ERR_NOTFOUND: + result = CURLE_TFTP_NOTFOUND; + break; + case TFTP_ERR_PERM: + result = CURLE_TFTP_PERM; + break; + case TFTP_ERR_DISKFULL: + result = CURLE_REMOTE_DISK_FULL; + break; + case TFTP_ERR_UNDEF: + case TFTP_ERR_ILLEGAL: + result = CURLE_TFTP_ILLEGAL; + break; + case TFTP_ERR_UNKNOWNID: + result = CURLE_TFTP_UNKNOWNID; + break; + case TFTP_ERR_EXISTS: + result = CURLE_REMOTE_FILE_EXISTS; + break; + case TFTP_ERR_NOSUCHUSER: + result = CURLE_TFTP_NOSUCHUSER; + break; + case TFTP_ERR_TIMEOUT: + result = CURLE_OPERATION_TIMEDOUT; + break; + case TFTP_ERR_NORESPONSE: + result = CURLE_COULDNT_CONNECT; + break; + default: + result = CURLE_ABORTED_BY_CALLBACK; + break; + } + } + else + result = CURLE_OK; + + return result; +} + +/********************************************************** + * + * tftp_state_machine + * + * The tftp state machine event dispatcher + * + **********************************************************/ +static CURLcode tftp_state_machine(struct tftp_state_data *state, + tftp_event_t event) +{ + CURLcode result = CURLE_OK; + struct Curl_easy *data = state->data; + + switch(state->state) { + case TFTP_STATE_START: + DEBUGF(infof(data, "TFTP_STATE_START")); + result = tftp_send_first(state, event); + break; + case TFTP_STATE_RX: + DEBUGF(infof(data, "TFTP_STATE_RX")); + result = tftp_rx(state, event); + break; + case TFTP_STATE_TX: + DEBUGF(infof(data, "TFTP_STATE_TX")); + result = tftp_tx(state, event); + break; + case TFTP_STATE_FIN: + infof(data, "%s", "TFTP finished"); + break; + default: + DEBUGF(infof(data, "STATE: %d", state->state)); + failf(data, "%s", "Internal state machine error"); + result = CURLE_TFTP_ILLEGAL; + break; + } + + return result; +} + +/********************************************************** + * + * tftp_disconnect + * + * The disconnect callback + * + **********************************************************/ +static CURLcode tftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection) +{ + struct tftp_state_data *state = conn->proto.tftpc; + (void) data; + (void) dead_connection; + + /* done, free dynamically allocated pkt buffers */ + if(state) { + Curl_safefree(state->rpacket.data); + Curl_safefree(state->spacket.data); + free(state); + } + + return CURLE_OK; +} + +/********************************************************** + * + * tftp_connect + * + * The connect callback + * + **********************************************************/ +static CURLcode tftp_connect(struct Curl_easy *data, bool *done) +{ + struct tftp_state_data *state; + int blksize; + int need_blksize; + struct connectdata *conn = data->conn; + + blksize = TFTP_BLKSIZE_DEFAULT; + + state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data)); + if(!state) + return CURLE_OUT_OF_MEMORY; + + /* alloc pkt buffers based on specified blksize */ + if(data->set.tftp_blksize) + /* range checked when set */ + blksize = (int)data->set.tftp_blksize; + + need_blksize = blksize; + /* default size is the fallback when no OACK is received */ + if(need_blksize < TFTP_BLKSIZE_DEFAULT) + need_blksize = TFTP_BLKSIZE_DEFAULT; + + if(!state->rpacket.data) { + state->rpacket.data = calloc(1, need_blksize + 2 + 2); + + if(!state->rpacket.data) + return CURLE_OUT_OF_MEMORY; + } + + if(!state->spacket.data) { + state->spacket.data = calloc(1, need_blksize + 2 + 2); + + if(!state->spacket.data) + return CURLE_OUT_OF_MEMORY; + } + + /* we don't keep TFTP connections up basically because there's none or very + * little gain for UDP */ + connclose(conn, "TFTP"); + + state->data = data; + state->sockfd = conn->sock[FIRSTSOCKET]; + state->state = TFTP_STATE_START; + state->error = TFTP_ERR_NONE; + state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */ + state->requested_blksize = blksize; + + ((struct sockaddr *)&state->local_addr)->sa_family = + (CURL_SA_FAMILY_T)(conn->remote_addr->family); + + tftp_set_timeouts(state); + + if(!conn->bits.bound) { + /* If not already bound, bind to any interface, random UDP port. If it is + * reused or a custom local port was desired, this has already been done! + * + * We once used the size of the local_addr struct as the third argument + * for bind() to better work with IPv6 or whatever size the struct could + * have, but we learned that at least Tru64, AIX and IRIX *requires* the + * size of that argument to match the exact size of a 'sockaddr_in' struct + * when running IPv4-only. + * + * Therefore we use the size from the address we connected to, which we + * assume uses the same IP version and thus hopefully this works for both + * IPv4 and IPv6... + */ + int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, + conn->remote_addr->addrlen); + if(rc) { + char buffer[STRERROR_LEN]; + failf(data, "bind() failed; %s", + Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_COULDNT_CONNECT; + } + conn->bits.bound = TRUE; + } + + Curl_pgrsStartNow(data); + + *done = TRUE; + + return CURLE_OK; +} + +/********************************************************** + * + * tftp_done + * + * The done callback + * + **********************************************************/ +static CURLcode tftp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct tftp_state_data *state = conn->proto.tftpc; + + (void)status; /* unused */ + (void)premature; /* not used */ + + if(Curl_pgrsDone(data)) + return CURLE_ABORTED_BY_CALLBACK; + + /* If we have encountered an error */ + if(state) + result = tftp_translate_code(state->error); + + return result; +} + +/********************************************************** + * + * tftp_getsock + * + * The getsock callback + * + **********************************************************/ +static int tftp_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks) +{ + (void)data; + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0); +} + +/********************************************************** + * + * tftp_receive_packet + * + * Called once select fires and data is ready on the socket + * + **********************************************************/ +static CURLcode tftp_receive_packet(struct Curl_easy *data) +{ + struct Curl_sockaddr_storage fromaddr; + curl_socklen_t fromlen; + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct tftp_state_data *state = conn->proto.tftpc; + + /* Receive the packet */ + fromlen = sizeof(fromaddr); + state->rbytes = (int)recvfrom(state->sockfd, + (void *)state->rpacket.data, + state->blksize + 4, + 0, + (struct sockaddr *)&fromaddr, + &fromlen); + if(state->remote_addrlen == 0) { + memcpy(&state->remote_addr, &fromaddr, fromlen); + state->remote_addrlen = fromlen; + } + + /* Sanity check packet length */ + if(state->rbytes < 4) { + failf(data, "Received too short packet"); + /* Not a timeout, but how best to handle it? */ + state->event = TFTP_EVENT_TIMEOUT; + } + else { + /* The event is given by the TFTP packet time */ + unsigned short event = getrpacketevent(&state->rpacket); + state->event = (tftp_event_t)event; + + switch(state->event) { + case TFTP_EVENT_DATA: + /* Don't pass to the client empty or retransmitted packets */ + if(state->rbytes > 4 && + (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) { + result = Curl_client_write(data, CLIENTWRITE_BODY, + (char *)state->rpacket.data + 4, + state->rbytes-4); + if(result) { + tftp_state_machine(state, TFTP_EVENT_ERROR); + return result; + } + } + break; + case TFTP_EVENT_ERROR: + { + unsigned short error = getrpacketblock(&state->rpacket); + char *str = (char *)state->rpacket.data + 4; + size_t strn = state->rbytes - 4; + state->error = (tftp_error_t)error; + if(tftp_strnlen(str, strn) < strn) + infof(data, "TFTP error: %s", str); + break; + } + case TFTP_EVENT_ACK: + break; + case TFTP_EVENT_OACK: + result = tftp_parse_option_ack(state, + (const char *)state->rpacket.data + 2, + state->rbytes-2); + if(result) + return result; + break; + case TFTP_EVENT_RRQ: + case TFTP_EVENT_WRQ: + default: + failf(data, "%s", "Internal error: Unexpected packet"); + break; + } + + /* Update the progress meter */ + if(Curl_pgrsUpdate(data)) { + tftp_state_machine(state, TFTP_EVENT_ERROR); + return CURLE_ABORTED_BY_CALLBACK; + } + } + return result; +} + +/********************************************************** + * + * tftp_state_timeout + * + * Check if timeouts have been reached + * + **********************************************************/ +static timediff_t tftp_state_timeout(struct Curl_easy *data, + tftp_event_t *event) +{ + time_t current; + struct connectdata *conn = data->conn; + struct tftp_state_data *state = conn->proto.tftpc; + timediff_t timeout_ms; + + if(event) + *event = TFTP_EVENT_NONE; + + timeout_ms = Curl_timeleft(state->data, NULL, + (state->state == TFTP_STATE_START)); + if(timeout_ms < 0) { + state->error = TFTP_ERR_TIMEOUT; + state->state = TFTP_STATE_FIN; + return 0; + } + time(¤t); + if(current > state->rx_time + state->retry_time) { + if(event) + *event = TFTP_EVENT_TIMEOUT; + time(&state->rx_time); /* update even though we received nothing */ + } + + return timeout_ms; +} + +/********************************************************** + * + * tftp_multi_statemach + * + * Handle single RX socket event and return + * + **********************************************************/ +static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done) +{ + tftp_event_t event; + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct tftp_state_data *state = conn->proto.tftpc; + timediff_t timeout_ms = tftp_state_timeout(data, &event); + + *done = FALSE; + + if(timeout_ms < 0) { + failf(data, "TFTP response timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + if(event != TFTP_EVENT_NONE) { + result = tftp_state_machine(state, event); + if(result) + return result; + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; + if(*done) + /* Tell curl we're done */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + } + else { + /* no timeouts to handle, check our socket */ + int rc = SOCKET_READABLE(state->sockfd, 0); + + if(rc == -1) { + /* bail out */ + int error = SOCKERRNO; + char buffer[STRERROR_LEN]; + failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer))); + state->event = TFTP_EVENT_ERROR; + } + else if(rc) { + result = tftp_receive_packet(data); + if(result) + return result; + result = tftp_state_machine(state, state->event); + if(result) + return result; + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; + if(*done) + /* Tell curl we're done */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + } + /* if rc == 0, then select() timed out */ + } + + return result; +} + +/********************************************************** + * + * tftp_doing + * + * Called from multi.c while DOing + * + **********************************************************/ +static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done) +{ + CURLcode result; + result = tftp_multi_statemach(data, dophase_done); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + else if(!result) { + /* The multi code doesn't have this logic for the DOING state so we + provide it for TFTP since it may do the entire transfer in this + state. */ + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, Curl_now()); + } + return result; +} + +/********************************************************** + * + * tftp_perform + * + * Entry point for transfer from tftp_do, starts state mach + * + **********************************************************/ +static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct tftp_state_data *state = conn->proto.tftpc; + + *dophase_done = FALSE; + + result = tftp_state_machine(state, TFTP_EVENT_INIT); + + if((state->state == TFTP_STATE_FIN) || result) + return result; + + tftp_multi_statemach(data, dophase_done); + + if(*dophase_done) + DEBUGF(infof(data, "DO phase is complete")); + + return result; +} + + +/********************************************************** + * + * tftp_do + * + * The do callback + * + * This callback initiates the TFTP transfer + * + **********************************************************/ + +static CURLcode tftp_do(struct Curl_easy *data, bool *done) +{ + struct tftp_state_data *state; + CURLcode result; + struct connectdata *conn = data->conn; + + *done = FALSE; + + if(!conn->proto.tftpc) { + result = tftp_connect(data, done); + if(result) + return result; + } + + state = conn->proto.tftpc; + if(!state) + return CURLE_TFTP_ILLEGAL; + + result = tftp_perform(data, done); + + /* If tftp_perform() returned an error, use that for return code. If it + was OK, see if tftp_translate_code() has an error. */ + if(!result) + /* If we have encountered an internal tftp error, translate it. */ + result = tftp_translate_code(state->error); + + return result; +} + +static CURLcode tftp_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + char *type; + + conn->transport = TRNSPRT_UDP; + + /* TFTP URLs support an extension like ";mode=" that + * we'll try to get now! */ + type = strstr(data->state.up.path, ";mode="); + + if(!type) + type = strstr(conn->host.rawalloc, ";mode="); + + if(type) { + char command; + *type = 0; /* it was in the middle of the hostname */ + command = Curl_raw_toupper(type[6]); + + switch(command) { + case 'A': /* ASCII mode */ + case 'N': /* NETASCII mode */ + data->state.prefer_ascii = TRUE; + break; + + case 'O': /* octet mode */ + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->state.prefer_ascii = FALSE; + break; + } + } + + return CURLE_OK; +} +#endif diff --git a/lib/tftp.h b/lib/tftp.h new file mode 100644 index 0000000..12404bf --- /dev/null +++ b/lib/tftp.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_TFTP_H +#define HEADER_CURL_TFTP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifndef CURL_DISABLE_TFTP +extern const struct Curl_handler Curl_handler_tftp; + +#define TFTP_BLKSIZE_MIN 8 +#define TFTP_BLKSIZE_MAX 65464 +#endif + +#endif /* HEADER_CURL_TFTP_H */ diff --git a/lib/timediff.c b/lib/timediff.c new file mode 100644 index 0000000..d0824d1 --- /dev/null +++ b/lib/timediff.c @@ -0,0 +1,88 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "timediff.h" + +#include + +/* + * Converts number of milliseconds into a timeval structure. + * + * Return values: + * NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select) + * tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select) + * tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select) + */ +struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms) +{ + if(!tv) + return NULL; + + if(ms < 0) + return NULL; + + if(ms > 0) { + timediff_t tv_sec = ms / 1000; + timediff_t tv_usec = (ms % 1000) * 1000; /* max=999999 */ +#ifdef HAVE_SUSECONDS_T +#if TIMEDIFF_T_MAX > TIME_T_MAX + /* tv_sec overflow check in case time_t is signed */ + if(tv_sec > TIME_T_MAX) + tv_sec = TIME_T_MAX; +#endif + tv->tv_sec = (time_t)tv_sec; + tv->tv_usec = (suseconds_t)tv_usec; +#elif defined(_WIN32) /* maybe also others in the future */ +#if TIMEDIFF_T_MAX > LONG_MAX + /* tv_sec overflow check on Windows there we know it is long */ + if(tv_sec > LONG_MAX) + tv_sec = LONG_MAX; +#endif + tv->tv_sec = (long)tv_sec; + tv->tv_usec = (long)tv_usec; +#else +#if TIMEDIFF_T_MAX > INT_MAX + /* tv_sec overflow check in case time_t is signed */ + if(tv_sec > INT_MAX) + tv_sec = INT_MAX; +#endif + tv->tv_sec = (int)tv_sec; + tv->tv_usec = (int)tv_usec; +#endif + } + else { + tv->tv_sec = 0; + tv->tv_usec = 0; + } + + return tv; +} + +/* + * Converts a timeval structure into number of milliseconds. + */ +timediff_t curlx_tvtoms(struct timeval *tv) +{ + return (tv->tv_sec*1000) + (timediff_t)(((double)tv->tv_usec)/1000.0); +} diff --git a/lib/timediff.h b/lib/timediff.h new file mode 100644 index 0000000..fb318d4 --- /dev/null +++ b/lib/timediff.h @@ -0,0 +1,52 @@ +#ifndef HEADER_CURL_TIMEDIFF_H +#define HEADER_CURL_TIMEDIFF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/* Use a larger type even for 32 bit time_t systems so that we can keep + microsecond accuracy in it */ +typedef curl_off_t timediff_t; +#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T + +#define TIMEDIFF_T_MAX CURL_OFF_T_MAX +#define TIMEDIFF_T_MIN CURL_OFF_T_MIN + +/* + * Converts number of milliseconds into a timeval structure. + * + * Return values: + * NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select) + * tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select) + * tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select) + */ +struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms); + +/* + * Converts a timeval structure into number of milliseconds. + */ +timediff_t curlx_tvtoms(struct timeval *tv); + +#endif /* HEADER_CURL_TIMEDIFF_H */ diff --git a/lib/timeval.c b/lib/timeval.c new file mode 100644 index 0000000..5a6727c --- /dev/null +++ b/lib/timeval.c @@ -0,0 +1,237 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "timeval.h" + +#if defined(_WIN32) + +#include +#include "system_win32.h" + +/* In case of bug fix this function has a counterpart in tool_util.c */ +struct curltime Curl_now(void) +{ + struct curltime now; + if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */ + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart); + now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 / + Curl_freq.QuadPart); + } + else { + /* Disable /analyze warning that GetTickCount64 is preferred */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:28159) +#endif + DWORD milliseconds = GetTickCount(); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + now.tv_sec = milliseconds / 1000; + now.tv_usec = (milliseconds % 1000) * 1000; + } + return now; +} + +#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) || \ + defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) + +struct curltime Curl_now(void) +{ + /* + ** clock_gettime() is granted to be increased monotonically when the + ** monotonic clock is queried. Time starting point is unspecified, it + ** could be the system start-up time, the Epoch, or something else, + ** in any case the time starting point does not change once that the + ** system has started up. + */ +#ifdef HAVE_GETTIMEOFDAY + struct timeval now; +#endif + struct curltime cnow; + struct timespec tsnow; + + /* + ** clock_gettime() may be defined by Apple's SDK as weak symbol thus + ** code compiles but fails during run-time if clock_gettime() is + ** called on unsupported OS version. + */ +#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ + (HAVE_BUILTIN_AVAILABLE == 1) + bool have_clock_gettime = FALSE; + if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) + have_clock_gettime = TRUE; +#endif + +#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW + if( +#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ + (HAVE_BUILTIN_AVAILABLE == 1) + have_clock_gettime && +#endif + (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) { + cnow.tv_sec = tsnow.tv_sec; + cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); + } + else +#endif + + if( +#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ + (HAVE_BUILTIN_AVAILABLE == 1) + have_clock_gettime && +#endif + (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) { + cnow.tv_sec = tsnow.tv_sec; + cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); + } + /* + ** Even when the configure process has truly detected monotonic clock + ** availability, it might happen that it is not actually available at + ** run-time. When this occurs simply fallback to other time source. + */ +#ifdef HAVE_GETTIMEOFDAY + else { + (void)gettimeofday(&now, NULL); + cnow.tv_sec = now.tv_sec; + cnow.tv_usec = (unsigned int)now.tv_usec; + } +#else + else { + cnow.tv_sec = time(NULL); + cnow.tv_usec = 0; + } +#endif + return cnow; +} + +#elif defined(HAVE_MACH_ABSOLUTE_TIME) + +#include +#include + +struct curltime Curl_now(void) +{ + /* + ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which + ** returns time in Mach "absolute time units," which are platform-dependent. + ** To convert to nanoseconds, one must use conversion factors specified by + ** mach_timebase_info(). + */ + static mach_timebase_info_data_t timebase; + struct curltime cnow; + uint64_t usecs; + + if(0 == timebase.denom) + (void) mach_timebase_info(&timebase); + + usecs = mach_absolute_time(); + usecs *= timebase.numer; + usecs /= timebase.denom; + usecs /= 1000; + + cnow.tv_sec = usecs / 1000000; + cnow.tv_usec = (int)(usecs % 1000000); + + return cnow; +} + +#elif defined(HAVE_GETTIMEOFDAY) + +struct curltime Curl_now(void) +{ + /* + ** gettimeofday() is not granted to be increased monotonically, due to + ** clock drifting and external source time synchronization it can jump + ** forward or backward in time. + */ + struct timeval now; + struct curltime ret; + (void)gettimeofday(&now, NULL); + ret.tv_sec = now.tv_sec; + ret.tv_usec = (int)now.tv_usec; + return ret; +} + +#else + +struct curltime Curl_now(void) +{ + /* + ** time() returns the value of time in seconds since the Epoch. + */ + struct curltime now; + now.tv_sec = time(NULL); + now.tv_usec = 0; + return now; +} + +#endif + +/* + * Returns: time difference in number of milliseconds. For too large diffs it + * returns max value. + * + * @unittest: 1323 + */ +timediff_t Curl_timediff(struct curltime newer, struct curltime older) +{ + timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; + if(diff >= (TIMEDIFF_T_MAX/1000)) + return TIMEDIFF_T_MAX; + else if(diff <= (TIMEDIFF_T_MIN/1000)) + return TIMEDIFF_T_MIN; + return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000; +} + +/* + * Returns: time difference in number of milliseconds, rounded up. + * For too large diffs it returns max value. + */ +timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older) +{ + timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; + if(diff >= (TIMEDIFF_T_MAX/1000)) + return TIMEDIFF_T_MAX; + else if(diff <= (TIMEDIFF_T_MIN/1000)) + return TIMEDIFF_T_MIN; + return diff * 1000 + (newer.tv_usec - older.tv_usec + 999)/1000; +} + +/* + * Returns: time difference in number of microseconds. For too large diffs it + * returns max value. + */ +timediff_t Curl_timediff_us(struct curltime newer, struct curltime older) +{ + timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; + if(diff >= (TIMEDIFF_T_MAX/1000000)) + return TIMEDIFF_T_MAX; + else if(diff <= (TIMEDIFF_T_MIN/1000000)) + return TIMEDIFF_T_MIN; + return diff * 1000000 + newer.tv_usec-older.tv_usec; +} diff --git a/lib/timeval.h b/lib/timeval.h new file mode 100644 index 0000000..33dfb5b --- /dev/null +++ b/lib/timeval.h @@ -0,0 +1,62 @@ +#ifndef HEADER_CURL_TIMEVAL_H +#define HEADER_CURL_TIMEVAL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "timediff.h" + +struct curltime { + time_t tv_sec; /* seconds */ + int tv_usec; /* microseconds */ +}; + +struct curltime Curl_now(void); + +/* + * Make sure that the first argument (newer) is the more recent time and older + * is the older time, as otherwise you get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds. + */ +timediff_t Curl_timediff(struct curltime newer, struct curltime older); + +/* + * Make sure that the first argument (newer) is the more recent time and older + * is the older time, as otherwise you get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds, rounded up. + */ +timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older); + +/* + * Make sure that the first argument (newer) is the more recent time and older + * is the older time, as otherwise you get a weird negative time-diff back... + * + * Returns: the time difference in number of microseconds. + */ +timediff_t Curl_timediff_us(struct curltime newer, struct curltime older); + +#endif /* HEADER_CURL_TIMEVAL_H */ diff --git a/lib/transfer.c b/lib/transfer.c new file mode 100644 index 0000000..3ae4b61 --- /dev/null +++ b/lib/transfer.c @@ -0,0 +1,1718 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "strtoofft.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif + +#ifndef HAVE_SOCKET +#error "We can't compile without socket() support!" +#endif + +#include "urldata.h" +#include +#include "netrc.h" + +#include "content_encoding.h" +#include "hostip.h" +#include "cfilters.h" +#include "transfer.h" +#include "sendf.h" +#include "speedcheck.h" +#include "progress.h" +#include "http.h" +#include "url.h" +#include "getinfo.h" +#include "vtls/vtls.h" +#include "vquic/vquic.h" +#include "select.h" +#include "multiif.h" +#include "connect.h" +#include "http2.h" +#include "mime.h" +#include "strcase.h" +#include "urlapi-int.h" +#include "hsts.h" +#include "setopt.h" +#include "headers.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) +/* + * checkheaders() checks the linked list of custom headers for a + * particular header (prefix). Provide the prefix without colon! + * + * Returns a pointer to the first matching header or NULL if none matched. + */ +char *Curl_checkheaders(const struct Curl_easy *data, + const char *thisheader, + const size_t thislen) +{ + struct curl_slist *head; + DEBUGASSERT(thislen); + DEBUGASSERT(thisheader[thislen-1] != ':'); + + for(head = data->set.headers; head; head = head->next) { + if(strncasecompare(head->data, thisheader, thislen) && + Curl_headersep(head->data[thislen]) ) + return head->data; + } + + return NULL; +} +#endif + +CURLcode Curl_get_upload_buffer(struct Curl_easy *data) +{ + if(!data->state.ulbuf) { + data->state.ulbuf = malloc(data->set.upload_buffer_size); + if(!data->state.ulbuf) + return CURLE_OUT_OF_MEMORY; + } + return CURLE_OK; +} + +#ifndef CURL_DISABLE_HTTP +/* + * This function will be called to loop through the trailers buffer + * until no more data is available for sending. + */ +static size_t trailers_read(char *buffer, size_t size, size_t nitems, + void *raw) +{ + struct Curl_easy *data = (struct Curl_easy *)raw; + struct dynbuf *trailers_buf = &data->state.trailers_buf; + size_t bytes_left = Curl_dyn_len(trailers_buf) - + data->state.trailers_bytes_sent; + size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left; + if(to_copy) { + memcpy(buffer, + Curl_dyn_ptr(trailers_buf) + data->state.trailers_bytes_sent, + to_copy); + data->state.trailers_bytes_sent += to_copy; + } + return to_copy; +} + +static size_t trailers_left(void *raw) +{ + struct Curl_easy *data = (struct Curl_easy *)raw; + struct dynbuf *trailers_buf = &data->state.trailers_buf; + return Curl_dyn_len(trailers_buf) - data->state.trailers_bytes_sent; +} +#endif + +/* + * This function will call the read callback to fill our buffer with data + * to upload. + */ +CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, + size_t *nreadp) +{ + size_t buffersize = bytes; + size_t nread; + curl_read_callback readfunc = NULL; + void *extra_data = NULL; + int eof_index = 0; + +#ifndef CURL_DISABLE_HTTP + if(data->state.trailers_state == TRAILERS_INITIALIZED) { + struct curl_slist *trailers = NULL; + CURLcode result; + int trailers_ret_code; + + /* at this point we already verified that the callback exists + so we compile and store the trailers buffer, then proceed */ + infof(data, + "Moving trailers state machine from initialized to sending."); + data->state.trailers_state = TRAILERS_SENDING; + Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS); + + data->state.trailers_bytes_sent = 0; + Curl_set_in_callback(data, true); + trailers_ret_code = data->set.trailer_callback(&trailers, + data->set.trailer_data); + Curl_set_in_callback(data, false); + if(trailers_ret_code == CURL_TRAILERFUNC_OK) { + result = Curl_http_compile_trailers(trailers, &data->state.trailers_buf, + data); + } + else { + failf(data, "operation aborted by trailing headers callback"); + *nreadp = 0; + result = CURLE_ABORTED_BY_CALLBACK; + } + if(result) { + Curl_dyn_free(&data->state.trailers_buf); + curl_slist_free_all(trailers); + return result; + } + infof(data, "Successfully compiled trailers."); + curl_slist_free_all(trailers); + } +#endif + +#ifndef CURL_DISABLE_HTTP + /* if we are transmitting trailing data, we don't need to write + a chunk size so we skip this */ + if(data->req.upload_chunky && + data->state.trailers_state == TRAILERS_NONE) { + /* if chunked Transfer-Encoding */ + buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */ + data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */ + } + + if(data->state.trailers_state == TRAILERS_SENDING) { + /* if we're here then that means that we already sent the last empty chunk + but we didn't send a final CR LF, so we sent 0 CR LF. We then start + pulling trailing data until we have no more at which point we + simply return to the previous point in the state machine as if + nothing happened. + */ + readfunc = trailers_read; + extra_data = (void *)data; + eof_index = 1; + } + else +#endif + { + readfunc = data->state.fread_func; + extra_data = data->state.in; + } + + if(!data->req.fread_eof[eof_index]) { + Curl_set_in_callback(data, true); + nread = readfunc(data->req.upload_fromhere, 1, buffersize, extra_data); + Curl_set_in_callback(data, false); + /* make sure the callback is not called again after EOF */ + data->req.fread_eof[eof_index] = !nread; + } + else + nread = 0; + + if(nread == CURL_READFUNC_ABORT) { + failf(data, "operation aborted by callback"); + *nreadp = 0; + return CURLE_ABORTED_BY_CALLBACK; + } + if(nread == CURL_READFUNC_PAUSE) { + struct SingleRequest *k = &data->req; + + if(data->conn->handler->flags & PROTOPT_NONETWORK) { + /* protocols that work without network cannot be paused. This is + actually only FILE:// just now, and it can't pause since the transfer + isn't done using the "normal" procedure. */ + failf(data, "Read callback asked for PAUSE when not supported"); + return CURLE_READ_ERROR; + } + + /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ + k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ + if(data->req.upload_chunky) { + /* Back out the preallocation done above */ + data->req.upload_fromhere -= (8 + 2); + } + *nreadp = 0; + + return CURLE_OK; /* nothing was read */ + } + else if(nread > buffersize) { + /* the read function returned a too large value */ + *nreadp = 0; + failf(data, "read function returned funny value"); + return CURLE_READ_ERROR; + } + +#ifndef CURL_DISABLE_HTTP + if(!data->req.forbidchunk && data->req.upload_chunky) { + /* if chunked Transfer-Encoding + * build chunk: + * + * CRLF + * CRLF + */ + /* On non-ASCII platforms the may or may not be + translated based on state.prefer_ascii while the protocol + portion must always be translated to the network encoding. + To further complicate matters, line end conversion might be + done later on, so we need to prevent CRLFs from becoming + CRCRLFs if that's the case. To do this we use bare LFs + here, knowing they'll become CRLFs later on. + */ + + bool added_crlf = FALSE; + int hexlen = 0; + const char *endofline_native; + const char *endofline_network; + + if( +#ifdef CURL_DO_LINEEND_CONV + (data->state.prefer_ascii) || +#endif + (data->set.crlf)) { + /* \n will become \r\n later on */ + endofline_native = "\n"; + endofline_network = "\x0a"; + } + else { + endofline_native = "\r\n"; + endofline_network = "\x0d\x0a"; + } + + /* if we're not handling trailing data, proceed as usual */ + if(data->state.trailers_state != TRAILERS_SENDING) { + char hexbuffer[11] = ""; + hexlen = msnprintf(hexbuffer, sizeof(hexbuffer), + "%zx%s", nread, endofline_native); + + /* move buffer pointer */ + data->req.upload_fromhere -= hexlen; + nread += hexlen; + + /* copy the prefix to the buffer, leaving out the NUL */ + memcpy(data->req.upload_fromhere, hexbuffer, hexlen); + + /* always append ASCII CRLF to the data unless + we have a valid trailer callback */ + if((nread-hexlen) == 0 && + data->set.trailer_callback != NULL && + data->state.trailers_state == TRAILERS_NONE) { + data->state.trailers_state = TRAILERS_INITIALIZED; + } + else { + memcpy(data->req.upload_fromhere + nread, + endofline_network, + strlen(endofline_network)); + added_crlf = TRUE; + } + } + + if(data->state.trailers_state == TRAILERS_SENDING && + !trailers_left(data)) { + Curl_dyn_free(&data->state.trailers_buf); + data->state.trailers_state = TRAILERS_DONE; + data->set.trailer_data = NULL; + data->set.trailer_callback = NULL; + /* mark the transfer as done */ + data->req.upload_done = TRUE; + infof(data, "Signaling end of chunked upload after trailers."); + } + else + if((nread - hexlen) == 0 && + data->state.trailers_state != TRAILERS_INITIALIZED) { + /* mark this as done once this chunk is transferred */ + data->req.upload_done = TRUE; + infof(data, + "Signaling end of chunked upload via terminating chunk."); + } + + if(added_crlf) + nread += strlen(endofline_network); /* for the added end of line */ + } +#endif + + *nreadp = nread; + + return CURLE_OK; +} + +static int data_pending(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + + if(conn->handler->protocol&PROTO_FAMILY_FTP) + return Curl_conn_data_pending(data, SECONDARYSOCKET); + + /* in the case of libssh2, we can never be really sure that we have emptied + its internal buffers so we MUST always try until we get EAGAIN back */ + return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) || + Curl_conn_data_pending(data, FIRSTSOCKET); +} + +/* + * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the + * remote document with the time provided by CURLOPT_TIMEVAL + */ +bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) +{ + if((timeofdoc == 0) || (data->set.timevalue == 0)) + return TRUE; + + switch(data->set.timecondition) { + case CURL_TIMECOND_IFMODSINCE: + default: + if(timeofdoc <= data->set.timevalue) { + infof(data, + "The requested document is not new enough"); + data->info.timecond = TRUE; + return FALSE; + } + break; + case CURL_TIMECOND_IFUNMODSINCE: + if(timeofdoc >= data->set.timevalue) { + infof(data, + "The requested document is not old enough"); + data->info.timecond = TRUE; + return FALSE; + } + break; + } + + return TRUE; +} + +/** + * Receive raw response data for the transfer. + * @param data the transfer + * @param buf buffer to keep response data received + * @param blen length of `buf` + * @param eos_reliable if EOS detection in underlying connection is reliable + * @param err error code in case of -1 return + * @return number of bytes read or -1 for error + */ +static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data, + char *buf, size_t blen, + bool eos_reliable, + CURLcode *err) +{ + ssize_t nread; + + DEBUGASSERT(blen > 0); + /* If we are reading BODY data and the connection does NOT handle EOF + * and we know the size of the BODY data, limit the read amount */ + if(!eos_reliable && !data->req.header && data->req.size != -1) { + curl_off_t totalleft = data->req.size - data->req.bytecount; + if(totalleft <= 0) + blen = 0; + else if(totalleft < (curl_off_t)blen) + blen = (size_t)totalleft; + } + + if(!blen) { + /* want nothing - continue as if read nothing. */ + DEBUGF(infof(data, "readwrite_data: we're done")); + *err = CURLE_OK; + return 0; + } + + *err = Curl_read(data, data->conn->sockfd, buf, blen, &nread); + if(*err) + return -1; + DEBUGASSERT(nread >= 0); + *err = CURLE_OK; + return nread; +} + +/* + * Go ahead and do a read if we have a readable socket or if + * the stream was rewound (in which case we have data in a + * buffer) + */ +static CURLcode readwrite_data(struct Curl_easy *data, + struct SingleRequest *k, + int *didwhat, bool *done) +{ + struct connectdata *conn = data->conn; + CURLcode result = CURLE_OK; + char *buf; + size_t blen; + int maxloops = 10; + curl_off_t total_received = 0; + bool is_multiplex = FALSE; + + DEBUGASSERT(data->state.buffer); + *done = FALSE; + + /* This is where we loop until we have read everything there is to + read or we get a CURLE_AGAIN */ + do { + bool is_eos = FALSE; + size_t bytestoread; + ssize_t nread; + + if(!is_multiplex) { + /* Multiplexed connection have inherent handling of EOF and we do not + * have to carefully restrict the amount we try to read. + * Multiplexed changes only in one direction. */ + is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET); + } + + buf = data->state.buffer; + bytestoread = data->set.buffer_size; + + /* Observe any imposed speed limit */ + if(bytestoread && data->set.max_recv_speed) { + curl_off_t net_limit = data->set.max_recv_speed - total_received; + if(net_limit <= 0) + break; + if((size_t)net_limit < bytestoread) + bytestoread = (size_t)net_limit; + } + + nread = Curl_xfer_recv_resp(data, buf, bytestoread, + is_multiplex, &result); + if(nread < 0) { + if(CURLE_AGAIN == result) { + result = CURLE_OK; + break; /* get out of loop */ + } + goto out; /* real error */ + } + + /* We only get a 0-length read on EndOfStream */ + blen = (size_t)nread; + is_eos = (blen == 0); + *didwhat |= KEEP_RECV; + + if(!blen) { + /* if we receive 0 or less here, either the data transfer is done or the + server closed the connection and we bail out from this! */ + if(is_multiplex) + DEBUGF(infof(data, "nread == 0, stream closed, bailing")); + else + DEBUGF(infof(data, "nread <= 0, server closed connection, bailing")); + if(k->eos_written) { /* already did write this to client, leave */ + k->keepon = 0; /* stop sending as well */ + break; + } + } + total_received += blen; + + result = Curl_xfer_write_resp(data, buf, blen, is_eos, done); + if(result || *done) + goto out; + + /* if we are done, we stop receiving. On multiplexed connections, + * we should read the EOS. Which may arrive as meta data after + * the bytes. Not taking it in might lead to RST of streams. */ + if((!is_multiplex && data->req.download_done) || is_eos) { + data->req.keepon &= ~KEEP_RECV; + } + /* if we are PAUSEd or stopped receiving, leave the loop */ + if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV)) + break; + + } while(maxloops-- && data_pending(data)); + + if(maxloops <= 0) { + /* did not read until EAGAIN, mark read-again-please */ + data->state.select_bits = CURL_CSELECT_IN; + if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) + data->state.select_bits |= CURL_CSELECT_OUT; + } + + if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && + (conn->bits.close || is_multiplex)) { + /* When we've read the entire thing and the close bit is set, the server + may now close the connection. If there's now any kind of sending going + on from our side, we need to stop that immediately. */ + infof(data, "we are done reading and this is set to close, stop send"); + k->keepon &= ~KEEP_SEND; /* no writing anymore either */ + k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */ + } + +out: + if(result) + DEBUGF(infof(data, "readwrite_data() -> %d", result)); + return result; +} + +CURLcode Curl_done_sending(struct Curl_easy *data, + struct SingleRequest *k) +{ + k->keepon &= ~KEEP_SEND; /* we're done writing */ + + /* These functions should be moved into the handler struct! */ + Curl_conn_ev_data_done_send(data); + + return CURLE_OK; +} + +#if defined(_WIN32) && defined(USE_WINSOCK) +#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY +#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B +#endif + +static void win_update_buffer_size(curl_socket_t sockfd) +{ + int result; + ULONG ideal; + DWORD ideallen; + result = WSAIoctl(sockfd, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0, + &ideal, sizeof(ideal), &ideallen, 0, 0); + if(result == 0) { + setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, + (const char *)&ideal, sizeof(ideal)); + } +} +#else +#define win_update_buffer_size(x) +#endif + +#define curl_upload_refill_watermark(data) \ + ((ssize_t)((data)->set.upload_buffer_size >> 5)) + +/* + * Send data to upload to the server, when the socket is writable. + */ +static CURLcode readwrite_upload(struct Curl_easy *data, + struct connectdata *conn, + int *didwhat) +{ + ssize_t i, si; + ssize_t bytes_written; + CURLcode result; + ssize_t nread; /* number of bytes read */ + bool sending_http_headers = FALSE; + struct SingleRequest *k = &data->req; + + *didwhat |= KEEP_SEND; + + do { + curl_off_t nbody; + ssize_t offset = 0; + + if(0 != k->upload_present && + k->upload_present < curl_upload_refill_watermark(data) && + !k->upload_chunky &&/*(variable sized chunked header; append not safe)*/ + !k->upload_done && /*!(k->upload_done once k->upload_present sent)*/ + !(k->writebytecount + k->upload_present - k->pendingheader == + data->state.infilesize)) { + offset = k->upload_present; + } + + /* only read more data if there's no upload data already + present in the upload buffer, or if appending to upload buffer */ + if(0 == k->upload_present || offset) { + result = Curl_get_upload_buffer(data); + if(result) + return result; + if(offset && k->upload_fromhere != data->state.ulbuf) + memmove(data->state.ulbuf, k->upload_fromhere, offset); + /* init the "upload from here" pointer */ + k->upload_fromhere = data->state.ulbuf; + + if(!k->upload_done) { + /* HTTP pollution, this should be written nicer to become more + protocol agnostic. */ + size_t fillcount; + struct HTTP *http = k->p.http; + + if((k->exp100 == EXP100_SENDING_REQUEST) && + (http->sending == HTTPSEND_BODY)) { + /* If this call is to send body data, we must take some action: + We have sent off the full HTTP 1.1 request, and we shall now + go into the Expect: 100 state and await such a header */ + k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */ + k->keepon &= ~KEEP_SEND; /* disable writing */ + k->start100 = Curl_now(); /* timeout count starts now */ + *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */ + /* set a timeout for the multi interface */ + Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); + break; + } + + if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { + if(http->sending == HTTPSEND_REQUEST) + /* We're sending the HTTP request headers, not the data. + Remember that so we don't change the line endings. */ + sending_http_headers = TRUE; + else + sending_http_headers = FALSE; + } + + k->upload_fromhere += offset; + result = Curl_fillreadbuffer(data, data->set.upload_buffer_size-offset, + &fillcount); + k->upload_fromhere -= offset; + if(result) + return result; + + nread = offset + fillcount; + } + else + nread = 0; /* we're done uploading/reading */ + + if(!nread && (k->keepon & KEEP_SEND_PAUSE)) { + /* this is a paused transfer */ + break; + } + if(nread <= 0) { + result = Curl_done_sending(data, k); + if(result) + return result; + break; + } + + /* store number of bytes available for upload */ + k->upload_present = nread; + + /* convert LF to CRLF if so asked */ + if((!sending_http_headers) && ( +#ifdef CURL_DO_LINEEND_CONV + /* always convert if we're FTPing in ASCII mode */ + (data->state.prefer_ascii) || +#endif + (data->set.crlf))) { + /* Do we need to allocate a scratch buffer? */ + if(!data->state.scratch) { + data->state.scratch = malloc(2 * data->set.upload_buffer_size); + if(!data->state.scratch) { + failf(data, "Failed to alloc scratch buffer"); + + return CURLE_OUT_OF_MEMORY; + } + } + + /* + * ASCII/EBCDIC Note: This is presumably a text (not binary) + * transfer so the data should already be in ASCII. + * That means the hex values for ASCII CR (0x0d) & LF (0x0a) + * must be used instead of the escape sequences \r & \n. + */ + if(offset) + memcpy(data->state.scratch, k->upload_fromhere, offset); + for(i = offset, si = offset; i < nread; i++, si++) { + if(k->upload_fromhere[i] == 0x0a) { + data->state.scratch[si++] = 0x0d; + data->state.scratch[si] = 0x0a; + if(!data->set.crlf) { + /* we're here only because FTP is in ASCII mode... + bump infilesize for the LF we just added */ + if(data->state.infilesize != -1) + data->state.infilesize++; + } + } + else + data->state.scratch[si] = k->upload_fromhere[i]; + } + + if(si != nread) { + /* only perform the special operation if we really did replace + anything */ + nread = si; + + /* upload from the new (replaced) buffer instead */ + k->upload_fromhere = data->state.scratch; + + /* set the new amount too */ + k->upload_present = nread; + } + } + +#ifndef CURL_DISABLE_SMTP + if(conn->handler->protocol & PROTO_FAMILY_SMTP) { + result = Curl_smtp_escape_eob(data, nread, offset); + if(result) + return result; + } +#endif /* CURL_DISABLE_SMTP */ + } /* if 0 == k->upload_present or appended to upload buffer */ + else { + /* We have a partial buffer left from a previous "round". Use + that instead of reading more data */ + } + + /* write to socket (send away data) */ + result = Curl_write(data, + conn->writesockfd, /* socket to send to */ + k->upload_fromhere, /* buffer pointer */ + k->upload_present, /* buffer size */ + &bytes_written); /* actually sent */ + if(result) + return result; + +#if defined(_WIN32) && defined(USE_WINSOCK) + { + struct curltime n = Curl_now(); + if(Curl_timediff(n, k->last_sndbuf_update) > 1000) { + win_update_buffer_size(conn->writesockfd); + k->last_sndbuf_update = n; + } + } +#endif + + if(k->pendingheader) { + /* parts of what was sent was header */ + curl_off_t n = CURLMIN(k->pendingheader, bytes_written); + /* show the data before we change the pointer upload_fromhere */ + Curl_debug(data, CURLINFO_HEADER_OUT, k->upload_fromhere, (size_t)n); + k->pendingheader -= n; + nbody = bytes_written - n; /* size of the written body part */ + } + else + nbody = bytes_written; + + if(nbody) { + /* show the data before we change the pointer upload_fromhere */ + Curl_debug(data, CURLINFO_DATA_OUT, + &k->upload_fromhere[bytes_written - nbody], + (size_t)nbody); + + k->writebytecount += nbody; + Curl_pgrsSetUploadCounter(data, k->writebytecount); + } + + if((!k->upload_chunky || k->forbidchunk) && + (k->writebytecount == data->state.infilesize)) { + /* we have sent all data we were supposed to */ + k->upload_done = TRUE; + infof(data, "We are completely uploaded and fine"); + } + + if(k->upload_present != bytes_written) { + /* we only wrote a part of the buffer (if anything), deal with it! */ + + /* store the amount of bytes left in the buffer to write */ + k->upload_present -= bytes_written; + + /* advance the pointer where to find the buffer when the next send + is to happen */ + k->upload_fromhere += bytes_written; + } + else { + /* we've uploaded that buffer now */ + result = Curl_get_upload_buffer(data); + if(result) + return result; + k->upload_fromhere = data->state.ulbuf; + k->upload_present = 0; /* no more bytes left */ + + if(k->upload_done) { + result = Curl_done_sending(data, k); + if(result) + return result; + } + } + + + } while(0); /* just to break out from! */ + + return CURLE_OK; +} + +static int select_bits_paused(struct Curl_easy *data, int select_bits) +{ + /* See issue #11982: we really need to be careful not to progress + * a transfer direction when that direction is paused. Not all parts + * of our state machine are handling PAUSED transfers correctly. So, we + * do not want to go there. + * NOTE: we are only interested in PAUSE, not HOLD. */ + + /* if there is data in a direction not paused, return false */ + if(((select_bits & CURL_CSELECT_IN) && + !(data->req.keepon & KEEP_RECV_PAUSE)) || + ((select_bits & CURL_CSELECT_OUT) && + !(data->req.keepon & KEEP_SEND_PAUSE))) + return FALSE; + + return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)); +} + +/* + * Curl_readwrite() is the low-level function to be called when data is to + * be read and written to/from the connection. + */ +CURLcode Curl_readwrite(struct Curl_easy *data, + bool *done) +{ + struct connectdata *conn = data->conn; + struct SingleRequest *k = &data->req; + CURLcode result; + struct curltime now; + int didwhat = 0; + int select_bits; + + if(data->state.select_bits) { + if(select_bits_paused(data, data->state.select_bits)) { + /* leave the bits unchanged, so they'll tell us what to do when + * this transfer gets unpaused. */ + DEBUGF(infof(data, "readwrite, select_bits, early return on PAUSED")); + result = CURLE_OK; + goto out; + } + select_bits = data->state.select_bits; + data->state.select_bits = 0; + } + else { + curl_socket_t fd_read; + curl_socket_t fd_write; + /* only use the proper socket if the *_HOLD bit is not set simultaneously + as then we are in rate limiting state in that transfer direction */ + if((k->keepon & KEEP_RECVBITS) == KEEP_RECV) + fd_read = conn->sockfd; + else + fd_read = CURL_SOCKET_BAD; + + if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) + fd_write = conn->writesockfd; + else + fd_write = CURL_SOCKET_BAD; + + select_bits = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0); + } + + if(select_bits == CURL_CSELECT_ERR) { + failf(data, "select/poll returned error"); + result = CURLE_SEND_ERROR; + goto out; + } + +#ifdef USE_HYPER + if(conn->datastream) { + result = conn->datastream(data, conn, &didwhat, done, select_bits); + if(result || *done) + goto out; + } + else { +#endif + /* We go ahead and do a read if we have a readable socket or if + the stream was rewound (in which case we have data in a + buffer) */ + if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) { + result = readwrite_data(data, k, &didwhat, done); + if(result || *done) + goto out; + } + + /* If we still have writing to do, we check if we have a writable socket. */ + if((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) { + /* write */ + + result = readwrite_upload(data, conn, &didwhat); + if(result) + goto out; + } +#ifdef USE_HYPER + } +#endif + + now = Curl_now(); + if(!didwhat) { + /* no read no write, this is a timeout? */ + if(k->exp100 == EXP100_AWAITING_CONTINUE) { + /* This should allow some time for the header to arrive, but only a + very short time as otherwise it'll be too much wasted time too + often. */ + + /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status": + + Therefore, when a client sends this header field to an origin server + (possibly via a proxy) from which it has never seen a 100 (Continue) + status, the client SHOULD NOT wait for an indefinite period before + sending the request body. + + */ + + timediff_t ms = Curl_timediff(now, k->start100); + if(ms >= data->set.expect_100_timeout) { + /* we've waited long enough, continue anyway */ + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + infof(data, "Done waiting for 100-continue"); + } + } + + result = Curl_conn_ev_data_idle(data); + if(result) + goto out; + } + + if(Curl_pgrsUpdate(data)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, now); + if(result) + goto out; + + if(k->keepon) { + if(0 > Curl_timeleft(data, &now, FALSE)) { + if(k->size != -1) { + failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T + " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" + CURL_FORMAT_CURL_OFF_T " bytes received", + Curl_timediff(now, data->progress.t_startsingle), + k->bytecount, k->size); + } + else { + failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T + " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received", + Curl_timediff(now, data->progress.t_startsingle), + k->bytecount); + } + result = CURLE_OPERATION_TIMEDOUT; + goto out; + } + } + else { + /* + * The transfer has been performed. Just make some general checks before + * returning. + */ + + if(!(data->req.no_body) && (k->size != -1) && + (k->bytecount != k->size) && +#ifdef CURL_DO_LINEEND_CONV + /* Most FTP servers don't adjust their file SIZE response for CRLFs, + so we'll check to see if the discrepancy can be explained + by the number of CRLFs we've changed to LFs. + */ + (k->bytecount != (k->size + data->state.crlf_conversions)) && +#endif /* CURL_DO_LINEEND_CONV */ + !k->newurl) { + failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T + " bytes remaining to read", k->size - k->bytecount); + result = CURLE_PARTIAL_FILE; + goto out; + } + if(Curl_pgrsUpdate(data)) { + result = CURLE_ABORTED_BY_CALLBACK; + goto out; + } + } + + /* Now update the "done" boolean we return */ + *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE; +out: + if(result) + DEBUGF(infof(data, "Curl_readwrite() -> %d", result)); + return result; +} + +/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT + which means this gets called once for each subsequent redirect etc */ +void Curl_init_CONNECT(struct Curl_easy *data) +{ + data->state.fread_func = data->set.fread_func_set; + data->state.in = data->set.in_set; + data->state.upload = (data->state.httpreq == HTTPREQ_PUT); +} + +/* + * Curl_pretransfer() is called immediately before a transfer starts, and only + * once for one transfer no matter if it has redirects or do multi-pass + * authentication etc. + */ +CURLcode Curl_pretransfer(struct Curl_easy *data) +{ + CURLcode result; + + if(!data->state.url && !data->set.uh) { + /* we can't do anything without URL */ + failf(data, "No URL set"); + return CURLE_URL_MALFORMAT; + } + + /* since the URL may have been redirected in a previous use of this handle */ + if(data->state.url_alloc) { + /* the already set URL is allocated, free it first! */ + Curl_safefree(data->state.url); + data->state.url_alloc = FALSE; + } + + if(!data->state.url && data->set.uh) { + CURLUcode uc; + free(data->set.str[STRING_SET_URL]); + uc = curl_url_get(data->set.uh, + CURLUPART_URL, &data->set.str[STRING_SET_URL], 0); + if(uc) { + failf(data, "No URL set"); + return CURLE_URL_MALFORMAT; + } + } + + if(data->set.postfields && data->set.set_resume_from) { + /* we can't */ + failf(data, "cannot mix POSTFIELDS with RESUME_FROM"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + data->state.prefer_ascii = data->set.prefer_ascii; +#ifdef CURL_LIST_ONLY_PROTOCOL + data->state.list_only = data->set.list_only; +#endif + data->state.httpreq = data->set.method; + data->state.url = data->set.str[STRING_SET_URL]; + + /* Init the SSL session ID cache here. We do it here since we want to do it + after the *_setopt() calls (that could specify the size of the cache) but + before any transfer takes place. */ + result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions); + if(result) + return result; + + data->state.requests = 0; + data->state.followlocation = 0; /* reset the location-follow counter */ + data->state.this_is_a_follow = FALSE; /* reset this */ + data->state.errorbuf = FALSE; /* no error has occurred */ + data->state.httpwant = data->set.httpwant; + data->state.httpversion = 0; + data->state.authproblem = FALSE; + data->state.authhost.want = data->set.httpauth; + data->state.authproxy.want = data->set.proxyauth; + Curl_safefree(data->info.wouldredirect); + Curl_data_priority_clear_state(data); + + if(data->state.httpreq == HTTPREQ_PUT) + data->state.infilesize = data->set.filesize; + else if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD)) { + data->state.infilesize = data->set.postfieldsize; + if(data->set.postfields && (data->state.infilesize == -1)) + data->state.infilesize = (curl_off_t)strlen(data->set.postfields); + } + else + data->state.infilesize = 0; + + /* If there is a list of cookie files to read, do it now! */ + Curl_cookie_loadfiles(data); + + /* If there is a list of host pairs to deal with */ + if(data->state.resolve) + result = Curl_loadhostpairs(data); + + /* If there is a list of hsts files to read */ + Curl_hsts_loadfiles(data); + + if(!result) { + /* Allow data->set.use_port to set which port to use. This needs to be + * disabled for example when we follow Location: headers to URLs using + * different ports! */ + data->state.allow_port = TRUE; + +#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) + /************************************************************* + * Tell signal handler to ignore SIGPIPE + *************************************************************/ + if(!data->set.no_signal) + data->state.prev_signal = signal(SIGPIPE, SIG_IGN); +#endif + + Curl_initinfo(data); /* reset session-specific information "variables" */ + Curl_pgrsResetTransferSizes(data); + Curl_pgrsStartNow(data); + + /* In case the handle is reused and an authentication method was picked + in the session we need to make sure we only use the one(s) we now + consider to be fine */ + data->state.authhost.picked &= data->state.authhost.want; + data->state.authproxy.picked &= data->state.authproxy.want; + +#ifndef CURL_DISABLE_FTP + data->state.wildcardmatch = data->set.wildcard_enabled; + if(data->state.wildcardmatch) { + struct WildcardData *wc; + if(!data->wildcard) { + data->wildcard = calloc(1, sizeof(struct WildcardData)); + if(!data->wildcard) + return CURLE_OUT_OF_MEMORY; + } + wc = data->wildcard; + if(wc->state < CURLWC_INIT) { + if(wc->ftpwc) + wc->dtor(wc->ftpwc); + Curl_safefree(wc->pattern); + Curl_safefree(wc->path); + result = Curl_wildcard_init(wc); /* init wildcard structures */ + if(result) + return CURLE_OUT_OF_MEMORY; + } + } +#endif + result = Curl_hsts_loadcb(data, data->hsts); + } + + /* + * Set user-agent. Used for HTTP, but since we can attempt to tunnel + * basically anything through an HTTP proxy we can't limit this based on + * protocol. + */ + if(data->set.str[STRING_USERAGENT]) { + Curl_safefree(data->state.aptr.uagent); + data->state.aptr.uagent = + aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); + if(!data->state.aptr.uagent) + return CURLE_OUT_OF_MEMORY; + } + + if(!result) + result = Curl_setstropt(&data->state.aptr.user, + data->set.str[STRING_USERNAME]); + if(!result) + result = Curl_setstropt(&data->state.aptr.passwd, + data->set.str[STRING_PASSWORD]); + if(!result) + result = Curl_setstropt(&data->state.aptr.proxyuser, + data->set.str[STRING_PROXYUSERNAME]); + if(!result) + result = Curl_setstropt(&data->state.aptr.proxypasswd, + data->set.str[STRING_PROXYPASSWORD]); + + data->req.headerbytecount = 0; + Curl_headers_cleanup(data); + return result; +} + +/* + * Curl_posttransfer() is called immediately after a transfer ends + */ +CURLcode Curl_posttransfer(struct Curl_easy *data) +{ +#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) + /* restore the signal handler for SIGPIPE before we get back */ + if(!data->set.no_signal) + signal(SIGPIPE, data->state.prev_signal); +#else + (void)data; /* unused parameter */ +#endif + + return CURLE_OK; +} + +/* + * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string + * as given by the remote server and set up the new URL to request. + * + * This function DOES NOT FREE the given url. + */ +CURLcode Curl_follow(struct Curl_easy *data, + char *newurl, /* the Location: string */ + followtype type) /* see transfer.h */ +{ +#ifdef CURL_DISABLE_HTTP + (void)data; + (void)newurl; + (void)type; + /* Location: following will not happen when HTTP is disabled */ + return CURLE_TOO_MANY_REDIRECTS; +#else + + /* Location: redirect */ + bool disallowport = FALSE; + bool reachedmax = FALSE; + CURLUcode uc; + + DEBUGASSERT(type != FOLLOW_NONE); + + if(type != FOLLOW_FAKE) + data->state.requests++; /* count all real follows */ + if(type == FOLLOW_REDIR) { + if((data->set.maxredirs != -1) && + (data->state.followlocation >= data->set.maxredirs)) { + reachedmax = TRUE; + type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected + to URL */ + } + else { + data->state.followlocation++; /* count redirect-followings, including + auth reloads */ + + if(data->set.http_auto_referer) { + CURLU *u; + char *referer = NULL; + + /* We are asked to automatically set the previous URL as the referer + when we get the next URL. We pick the ->url field, which may or may + not be 100% correct */ + + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + + /* Make a copy of the URL without credentials and fragment */ + u = curl_url(); + if(!u) + return CURLE_OUT_OF_MEMORY; + + uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_USER, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); + if(!uc) + uc = curl_url_get(u, CURLUPART_URL, &referer, 0); + + curl_url_cleanup(u); + + if(uc || !referer) + return CURLE_OUT_OF_MEMORY; + + data->state.referer = referer; + data->state.referer_alloc = TRUE; /* yes, free this later */ + } + } + } + + if((type != FOLLOW_RETRY) && + (data->req.httpcode != 401) && (data->req.httpcode != 407) && + Curl_is_absolute_url(newurl, NULL, 0, FALSE)) { + /* If this is not redirect due to a 401 or 407 response and an absolute + URL: don't allow a custom port number */ + disallowport = TRUE; + } + + DEBUGASSERT(data->state.uh); + uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, + (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : + ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) | + CURLU_ALLOW_SPACE | + (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); + if(uc) { + if(type != FOLLOW_FAKE) { + failf(data, "The redirect target URL could not be parsed: %s", + curl_url_strerror(uc)); + return Curl_uc_to_curlcode(uc); + } + + /* the URL could not be parsed for some reason, but since this is FAKE + mode, just duplicate the field as-is */ + newurl = strdup(newurl); + if(!newurl) + return CURLE_OUT_OF_MEMORY; + } + else { + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + + /* Clear auth if this redirects to a different port number or protocol, + unless permitted */ + if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) { + char *portnum; + int port; + bool clear = FALSE; + + if(data->set.use_port && data->state.allow_port) + /* a custom port is used */ + port = (int)data->set.use_port; + else { + uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum, + CURLU_DEFAULT_PORT); + if(uc) { + free(newurl); + return Curl_uc_to_curlcode(uc); + } + port = atoi(portnum); + free(portnum); + } + if(port != data->info.conn_remote_port) { + infof(data, "Clear auth, redirects to port from %u to %u", + data->info.conn_remote_port, port); + clear = TRUE; + } + else { + char *scheme; + const struct Curl_handler *p; + uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0); + if(uc) { + free(newurl); + return Curl_uc_to_curlcode(uc); + } + + p = Curl_get_scheme_handler(scheme); + if(p && (p->protocol != data->info.conn_protocol)) { + infof(data, "Clear auth, redirects scheme from %s to %s", + data->info.conn_scheme, scheme); + clear = TRUE; + } + free(scheme); + } + if(clear) { + Curl_safefree(data->state.aptr.user); + Curl_safefree(data->state.aptr.passwd); + } + } + } + + if(type == FOLLOW_FAKE) { + /* we're only figuring out the new url if we would've followed locations + but now we're done so we can get out! */ + data->info.wouldredirect = newurl; + + if(reachedmax) { + failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); + return CURLE_TOO_MANY_REDIRECTS; + } + return CURLE_OK; + } + + if(disallowport) + data->state.allow_port = FALSE; + + if(data->state.url_alloc) + Curl_safefree(data->state.url); + + data->state.url = newurl; + data->state.url_alloc = TRUE; + + infof(data, "Issue another request to this URL: '%s'", data->state.url); + + /* + * We get here when the HTTP code is 300-399 (and 401). We need to perform + * differently based on exactly what return code there was. + * + * News from 7.10.6: we can also get here on a 401 or 407, in case we act on + * an HTTP (proxy-) authentication scheme other than Basic. + */ + switch(data->info.httpcode) { + /* 401 - Act on a WWW-Authenticate, we keep on moving and do the + Authorization: XXXX header in the HTTP request code snippet */ + /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the + Proxy-Authorization: XXXX header in the HTTP request code snippet */ + /* 300 - Multiple Choices */ + /* 306 - Not used */ + /* 307 - Temporary Redirect */ + default: /* for all above (and the unknown ones) */ + /* Some codes are explicitly mentioned since I've checked RFC2616 and they + * seem to be OK to POST to. + */ + break; + case 301: /* Moved Permanently */ + /* (quote from RFC7231, section 6.4.2) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_301)) { + infof(data, "Switch from POST to GET"); + data->state.httpreq = HTTPREQ_GET; + } + break; + case 302: /* Found */ + /* (quote from RFC7231, section 6.4.3) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_302)) { + infof(data, "Switch from POST to GET"); + data->state.httpreq = HTTPREQ_GET; + } + break; + + case 303: /* See Other */ + /* 'See Other' location is not the resource but a substitute for the + * resource. In this case we switch the method to GET/HEAD, unless the + * method is POST and the user specified to keep it as POST. + * https://github.com/curl/curl/issues/5237#issuecomment-614641049 + */ + if(data->state.httpreq != HTTPREQ_GET && + ((data->state.httpreq != HTTPREQ_POST && + data->state.httpreq != HTTPREQ_POST_FORM && + data->state.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->state.httpreq = HTTPREQ_GET; + infof(data, "Switch to %s", + data->req.no_body?"HEAD":"GET"); + } + break; + case 304: /* Not Modified */ + /* 304 means we did a conditional request and it was "Not modified". + * We shouldn't get any Location: header in this response! + */ + break; + case 305: /* Use Proxy */ + /* (quote from RFC2616, section 10.3.6): + * "The requested resource MUST be accessed through the proxy given + * by the Location field. The Location field gives the URI of the + * proxy. The recipient is expected to repeat this single request + * via the proxy. 305 responses MUST only be generated by origin + * servers." + */ + break; + } + Curl_pgrsTime(data, TIMER_REDIRECT); + Curl_pgrsResetTransferSizes(data); + + return CURLE_OK; +#endif /* CURL_DISABLE_HTTP */ +} + +/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted. + + NOTE: that the *url is malloc()ed. */ +CURLcode Curl_retry_request(struct Curl_easy *data, char **url) +{ + struct connectdata *conn = data->conn; + bool retry = FALSE; + *url = NULL; + + /* if we're talking upload, we can't do the checks below, unless the protocol + is HTTP as when uploading over HTTP we will still get a response */ + if(data->state.upload && + !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) + return CURLE_OK; + + if((data->req.bytecount + data->req.headerbytecount == 0) && + conn->bits.reuse && + (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP)) +#ifndef CURL_DISABLE_RTSP + && (data->set.rtspreq != RTSPREQ_RECEIVE) +#endif + ) + /* We got no data, we attempted to reuse a connection. For HTTP this + can be a retry so we try again regardless if we expected a body. + For other protocols we only try again only if we expected a body. + + This might happen if the connection was left alive when we were + done using it before, but that was closed when we wanted to read from + it again. Bad luck. Retry the same request on a fresh connect! */ + retry = TRUE; + else if(data->state.refused_stream && + (data->req.bytecount + data->req.headerbytecount == 0) ) { + /* This was sent on a refused stream, safe to rerun. A refused stream + error can typically only happen on HTTP/2 level if the stream is safe + to issue again, but the nghttp2 API can deliver the message to other + streams as well, which is why this adds the check the data counters + too. */ + infof(data, "REFUSED_STREAM, retrying a fresh connect"); + data->state.refused_stream = FALSE; /* clear again */ + retry = TRUE; + } + if(retry) { +#define CONN_MAX_RETRIES 5 + if(data->state.retrycount++ >= CONN_MAX_RETRIES) { + failf(data, "Connection died, tried %d times before giving up", + CONN_MAX_RETRIES); + data->state.retrycount = 0; + return CURLE_SEND_ERROR; + } + infof(data, "Connection died, retrying a fresh connect (retry count: %d)", + data->state.retrycount); + *url = strdup(data->state.url); + if(!*url) + return CURLE_OUT_OF_MEMORY; + + connclose(conn, "retry"); /* close this connection */ + conn->bits.retry = TRUE; /* mark this as a connection we're about + to retry. Marking it this way should + prevent i.e HTTP transfers to return + error just because nothing has been + transferred! */ + + + if((conn->handler->protocol&PROTO_FAMILY_HTTP) && + data->req.writebytecount) { + data->state.rewindbeforesend = TRUE; + infof(data, "state.rewindbeforesend = TRUE"); + } + } + return CURLE_OK; +} + +/* + * Curl_setup_transfer() is called to setup some basic properties for the + * upcoming transfer. + */ +void +Curl_setup_transfer( + struct Curl_easy *data, /* transfer */ + int sockindex, /* socket index to read from or -1 */ + curl_off_t size, /* -1 if unknown at this point */ + bool getheader, /* TRUE if header parsing is wanted */ + int writesockindex /* socket index to write to, it may very well be + the same we read from. -1 disables */ + ) +{ + struct SingleRequest *k = &data->req; + struct connectdata *conn = data->conn; + struct HTTP *http = data->req.p.http; + bool httpsending; + + DEBUGASSERT(conn != NULL); + DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); + + httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_REQUEST)); + + if(conn->bits.multiplex || conn->httpversion >= 20 || httpsending) { + /* when multiplexing, the read/write sockets need to be the same! */ + conn->sockfd = sockindex == -1 ? + ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : + conn->sock[sockindex]; + conn->writesockfd = conn->sockfd; + if(httpsending) + /* special and very HTTP-specific */ + writesockindex = FIRSTSOCKET; + } + else { + conn->sockfd = sockindex == -1 ? + CURL_SOCKET_BAD : conn->sock[sockindex]; + conn->writesockfd = writesockindex == -1 ? + CURL_SOCKET_BAD:conn->sock[writesockindex]; + } + k->getheader = getheader; + + k->size = size; + + /* The code sequence below is placed in this function just because all + necessary input is not always known in do_complete() as this function may + be called after that */ + + if(!k->getheader) { + k->header = FALSE; + if(size > 0) + Curl_pgrsSetDownloadSize(data, size); + } + /* we want header and/or body, if neither then don't do this! */ + if(k->getheader || !data->req.no_body) { + + if(sockindex != -1) + k->keepon |= KEEP_RECV; + + if(writesockindex != -1) { + /* HTTP 1.1 magic: + + Even if we require a 100-return code before uploading data, we might + need to write data before that since the REQUEST may not have been + finished sent off just yet. + + Thus, we must check if the request has been sent before we set the + state info where we wait for the 100-return code + */ + if((data->state.expect100header) && + (conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_BODY)) { + /* wait with write until we either got 100-continue or a timeout */ + k->exp100 = EXP100_AWAITING_CONTINUE; + k->start100 = Curl_now(); + + /* Set a timeout for the multi interface. Add the inaccuracy margin so + that we don't fire slightly too early and get denied to run. */ + Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); + } + else { + if(data->state.expect100header) + /* when we've sent off the rest of the headers, we must await a + 100-continue but first finish sending the request */ + k->exp100 = EXP100_SENDING_REQUEST; + + /* enable the write bit when we're not waiting for continue */ + k->keepon |= KEEP_SEND; + } + } /* if(writesockindex != -1) */ + } /* if(k->getheader || !data->req.no_body) */ + +} + +CURLcode Curl_xfer_write_resp(struct Curl_easy *data, + char *buf, size_t blen, + bool is_eos, bool *done) +{ + CURLcode result = CURLE_OK; + + if(data->conn->handler->write_resp) { + /* protocol handlers offering this function take full responsibility + * for writing all received download data to the client. */ + result = data->conn->handler->write_resp(data, buf, blen, is_eos, done); + } + else { + /* No special handling by protocol handler, write all received data + * as BODY to the client. */ + if(blen || is_eos) { + int cwtype = CLIENTWRITE_BODY; + if(is_eos) + cwtype |= CLIENTWRITE_EOS; + +#ifndef CURL_DISABLE_POP3 + if(blen && data->conn->handler->protocol & PROTO_FAMILY_POP3) { + result = data->req.ignorebody? CURLE_OK : + Curl_pop3_write(data, buf, blen); + } + else +#endif /* CURL_DISABLE_POP3 */ + result = Curl_client_write(data, cwtype, buf, blen); + } + } + + if(!result && is_eos) { + /* If we wrote the EOS, we are definitely done */ + data->req.eos_written = TRUE; + data->req.download_done = TRUE; + } + return result; +} diff --git a/lib/transfer.h b/lib/transfer.h new file mode 100644 index 0000000..0507f1a --- /dev/null +++ b/lib/transfer.h @@ -0,0 +1,88 @@ +#ifndef HEADER_CURL_TRANSFER_H +#define HEADER_CURL_TRANSFER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#define Curl_headersep(x) ((((x)==':') || ((x)==';'))) +char *Curl_checkheaders(const struct Curl_easy *data, + const char *thisheader, + const size_t thislen); + +void Curl_init_CONNECT(struct Curl_easy *data); + +CURLcode Curl_pretransfer(struct Curl_easy *data); +CURLcode Curl_posttransfer(struct Curl_easy *data); + +typedef enum { + FOLLOW_NONE, /* not used within the function, just a placeholder to + allow initing to this */ + FOLLOW_FAKE, /* only records stuff, not actually following */ + FOLLOW_RETRY, /* set if this is a request retry as opposed to a real + redirect following */ + FOLLOW_REDIR /* a full true redirect */ +} followtype; + +CURLcode Curl_follow(struct Curl_easy *data, char *newurl, + followtype type); +CURLcode Curl_readwrite(struct Curl_easy *data, bool *done); +int Curl_single_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); +CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, + size_t *nreadp); +CURLcode Curl_retry_request(struct Curl_easy *data, char **url); +bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc); +CURLcode Curl_get_upload_buffer(struct Curl_easy *data); + +CURLcode Curl_done_sending(struct Curl_easy *data, + struct SingleRequest *k); + +/** + * Write the transfer raw response bytes, as received from the connection. + * Will handle all passed bytes or return an error. By default, this will + * write the bytes as BODY to the client. Protocols may provide a + * "write_resp" callback in their handler to add specific treatment. E.g. + * HTTP parses response headers and passes them differently to the client. + * @param data the transfer + * @param buf the raw response bytes + * @param blen the amount of bytes in `buf` + * @param is_eos TRUE iff the connection indicates this to be the last + * bytes of the response + * @param done on returnm, TRUE iff the response is complete + */ +CURLcode Curl_xfer_write_resp(struct Curl_easy *data, + char *buf, size_t blen, + bool is_eos, bool *done); + +/* This sets up a forthcoming transfer */ +void +Curl_setup_transfer (struct Curl_easy *data, + int sockindex, /* socket index to read from or -1 */ + curl_off_t size, /* -1 if unknown at this point */ + bool getheader, /* TRUE if header parsing is wanted */ + int writesockindex /* socket index to write to. May be + the same we read from. -1 + disables */ + ); + +#endif /* HEADER_CURL_TRANSFER_H */ diff --git a/lib/url.c b/lib/url.c new file mode 100644 index 0000000..36395a1 --- /dev/null +++ b/lib/url.c @@ -0,0 +1,4046 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_IPHLPAPI_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef __VMS +#include +#include +#endif + +#ifdef HAVE_SYS_UN_H +#include +#endif + +#ifndef HAVE_SOCKET +#error "We can't compile without socket() support!" +#endif + +#include + +#include "doh.h" +#include "urldata.h" +#include "netrc.h" +#include "formdata.h" +#include "mime.h" +#include "vtls/vtls.h" +#include "hostip.h" +#include "transfer.h" +#include "sendf.h" +#include "progress.h" +#include "cookie.h" +#include "strcase.h" +#include "strerror.h" +#include "escape.h" +#include "strtok.h" +#include "share.h" +#include "content_encoding.h" +#include "http_digest.h" +#include "http_negotiate.h" +#include "select.h" +#include "multiif.h" +#include "easyif.h" +#include "speedcheck.h" +#include "warnless.h" +#include "getinfo.h" +#include "urlapi-int.h" +#include "system_win32.h" +#include "hsts.h" +#include "noproxy.h" +#include "cfilters.h" +#include "idn.h" + +/* And now for the protocols */ +#include "ftp.h" +#include "dict.h" +#include "telnet.h" +#include "tftp.h" +#include "http.h" +#include "http2.h" +#include "file.h" +#include "curl_ldap.h" +#include "vssh/ssh.h" +#include "imap.h" +#include "url.h" +#include "connect.h" +#include "inet_ntop.h" +#include "http_ntlm.h" +#include "curl_rtmp.h" +#include "gopher.h" +#include "mqtt.h" +#include "http_proxy.h" +#include "conncache.h" +#include "multihandle.h" +#include "strdup.h" +#include "setopt.h" +#include "altsvc.h" +#include "dynbuf.h" +#include "headers.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#ifdef USE_NGHTTP2 +static void data_priority_cleanup(struct Curl_easy *data); +#else +#define data_priority_cleanup(x) +#endif + +/* Some parts of the code (e.g. chunked encoding) assume this buffer has at + * more than just a few bytes to play with. Don't let it become too small or + * bad things will happen. + */ +#if READBUFFER_SIZE < READBUFFER_MIN +# error READBUFFER_SIZE is too small +#endif + +#ifdef USE_UNIX_SOCKETS +#define UNIX_SOCKET_PREFIX "localhost" +#endif + +/* Reject URLs exceeding this length */ +#define MAX_URL_LEN 0xffff + +/* +* get_protocol_family() +* +* This is used to return the protocol family for a given protocol. +* +* Parameters: +* +* 'h' [in] - struct Curl_handler pointer. +* +* Returns the family as a single bit protocol identifier. +*/ +static curl_prot_t get_protocol_family(const struct Curl_handler *h) +{ + DEBUGASSERT(h); + DEBUGASSERT(h->family); + return h->family; +} + +void Curl_freeset(struct Curl_easy *data) +{ + /* Free all dynamic strings stored in the data->set substructure. */ + enum dupstring i; + enum dupblob j; + + for(i = (enum dupstring)0; i < STRING_LAST; i++) { + Curl_safefree(data->set.str[i]); + } + + for(j = (enum dupblob)0; j < BLOB_LAST; j++) { + Curl_safefree(data->set.blobs[j]); + } + + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + data->state.referer = NULL; + if(data->state.url_alloc) { + Curl_safefree(data->state.url); + data->state.url_alloc = FALSE; + } + data->state.url = NULL; + + Curl_mime_cleanpart(&data->set.mimepost); + +#ifndef CURL_DISABLE_COOKIES + curl_slist_free_all(data->state.cookielist); + data->state.cookielist = NULL; +#endif +} + +/* free the URL pieces */ +static void up_free(struct Curl_easy *data) +{ + struct urlpieces *up = &data->state.up; + Curl_safefree(up->scheme); + Curl_safefree(up->hostname); + Curl_safefree(up->port); + Curl_safefree(up->user); + Curl_safefree(up->password); + Curl_safefree(up->options); + Curl_safefree(up->path); + Curl_safefree(up->query); + curl_url_cleanup(data->state.uh); + data->state.uh = NULL; +} + +/* + * This is the internal function curl_easy_cleanup() calls. This should + * cleanup and free all resources associated with this sessionhandle. + * + * We ignore SIGPIPE when this is called from curl_easy_cleanup. + */ + +CURLcode Curl_close(struct Curl_easy **datap) +{ + struct Curl_easy *data; + + if(!datap || !*datap) + return CURLE_OK; + + data = *datap; + *datap = NULL; + + Curl_expire_clear(data); /* shut off timers */ + + /* Detach connection if any is left. This should not be normal, but can be + the case for example with CONNECT_ONLY + recv/send (test 556) */ + Curl_detach_connection(data); + if(!data->state.internal) { + if(data->multi) + /* This handle is still part of a multi handle, take care of this first + and detach this handle from there. */ + curl_multi_remove_handle(data->multi, data); + + if(data->multi_easy) { + /* when curl_easy_perform() is used, it creates its own multi handle to + use and this is the one */ + curl_multi_cleanup(data->multi_easy); + data->multi_easy = NULL; + } + } + + data->magic = 0; /* force a clear AFTER the possibly enforced removal from + the multi handle, since that function uses the magic + field! */ + + if(data->state.rangestringalloc) + free(data->state.range); + + /* freed here just in case DONE wasn't called */ + Curl_free_request_state(data); + + /* Close down all open SSL info and sessions */ + Curl_ssl_close_all(data); + Curl_safefree(data->state.first_host); + Curl_safefree(data->state.scratch); + Curl_ssl_free_certinfo(data); + + /* Cleanup possible redirect junk */ + free(data->req.newurl); + data->req.newurl = NULL; + + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + data->state.referer = NULL; + + up_free(data); + Curl_safefree(data->state.buffer); + Curl_dyn_free(&data->state.headerb); + Curl_safefree(data->state.ulbuf); + Curl_flush_cookies(data, TRUE); + Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); + Curl_altsvc_cleanup(&data->asi); + Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]); +#ifndef CURL_DISABLE_HSTS + if(!data->share || !data->share->hsts) + Curl_hsts_cleanup(&data->hsts); + curl_slist_free_all(data->state.hstslist); /* clean up list */ +#endif +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) + Curl_http_auth_cleanup_digest(data); +#endif + Curl_safefree(data->info.contenttype); + Curl_safefree(data->info.wouldredirect); + + /* this destroys the channel and we cannot use it anymore after this */ + Curl_resolver_cancel(data); + Curl_resolver_cleanup(data->state.async.resolver); + + data_priority_cleanup(data); + + /* No longer a dirty share, if it exists */ + if(data->share) { + Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + data->share->dirty--; + Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); + } + + Curl_safefree(data->state.aptr.proxyuserpwd); + Curl_safefree(data->state.aptr.uagent); + Curl_safefree(data->state.aptr.userpwd); + Curl_safefree(data->state.aptr.accept_encoding); + Curl_safefree(data->state.aptr.te); + Curl_safefree(data->state.aptr.rangeline); + Curl_safefree(data->state.aptr.ref); + Curl_safefree(data->state.aptr.host); + Curl_safefree(data->state.aptr.cookiehost); + Curl_safefree(data->state.aptr.rtsp_transport); + Curl_safefree(data->state.aptr.user); + Curl_safefree(data->state.aptr.passwd); + Curl_safefree(data->state.aptr.proxyuser); + Curl_safefree(data->state.aptr.proxypasswd); + +#ifndef CURL_DISABLE_DOH + if(data->req.doh) { + Curl_dyn_free(&data->req.doh->probe[0].serverdoh); + Curl_dyn_free(&data->req.doh->probe[1].serverdoh); + curl_slist_free_all(data->req.doh->headers); + Curl_safefree(data->req.doh); + } +#endif + +#ifndef CURL_DISABLE_HTTP + Curl_mime_cleanpart(data->state.formp); + Curl_safefree(data->state.formp); +#endif + + /* destruct wildcard structures if it is needed */ + Curl_wildcard_dtor(&data->wildcard); + Curl_freeset(data); + Curl_headers_cleanup(data); + free(data); + return CURLE_OK; +} + +/* + * Initialize the UserDefined fields within a Curl_easy. + * This may be safely called on a new or existing Curl_easy. + */ +CURLcode Curl_init_userdefined(struct Curl_easy *data) +{ + struct UserDefined *set = &data->set; + CURLcode result = CURLE_OK; + + set->out = stdout; /* default output to stdout */ + set->in_set = stdin; /* default input from stdin */ + set->err = stderr; /* default stderr to stderr */ + + /* use fwrite as default function to store output */ + set->fwrite_func = (curl_write_callback)fwrite; + + /* use fread as default function to read input */ + set->fread_func_set = (curl_read_callback)fread; + set->is_fread_set = 0; + + set->seek_func = ZERO_NULL; + set->seek_client = ZERO_NULL; + + set->filesize = -1; /* we don't know the size */ + set->postfieldsize = -1; /* unknown size */ + set->maxredirs = 30; /* sensible default */ + + set->method = HTTPREQ_GET; /* Default HTTP request */ +#ifndef CURL_DISABLE_RTSP + set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ +#endif +#ifndef CURL_DISABLE_FTP + set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ + set->ftp_filemethod = FTPFILE_MULTICWD; + set->ftp_skip_ip = TRUE; /* skip PASV IP by default */ +#endif + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + + /* Set the default size of the SSL session ID cache */ + set->general_ssl.max_ssl_sessions = 5; + /* Timeout every 24 hours by default */ + set->general_ssl.ca_cache_timeout = 24 * 60 * 60; + + set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ + +#ifndef CURL_DISABLE_PROXY + set->proxyport = 0; + set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + /* SOCKS5 proxy auth defaults to username/password + GSS-API */ + set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; +#endif + + /* make libcurl quiet by default: */ + set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ + + Curl_mime_initpart(&set->mimepost); + + Curl_ssl_easy_config_init(data); +#ifndef CURL_DISABLE_DOH + set->doh_verifyhost = TRUE; + set->doh_verifypeer = TRUE; +#endif +#ifdef USE_SSH + /* defaults to any auth type */ + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; + set->new_directory_perms = 0755; /* Default permissions */ +#endif + + set->new_file_perms = 0644; /* Default permissions */ + set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL; + set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | + CURLPROTO_FTPS; + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + /* + * disallow unprotected protection negotiation NEC reference implementation + * seem not to follow rfc1961 section 4.3/4.4 + */ + set->socks5_gssapi_nec = FALSE; +#endif + + /* Set the default CA cert bundle/path detected/specified at build time. + * + * If Schannel or SecureTransport is the selected SSL backend then these + * locations are ignored. We allow setting CA location for schannel and + * securetransport when explicitly specified by the user via + * CURLOPT_CAINFO / --cacert. + */ + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL && + Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) { +#if defined(CURL_CA_BUNDLE) + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], + CURL_CA_BUNDLE); + if(result) + return result; +#endif +#if defined(CURL_CA_PATH) + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); + if(result) + return result; +#endif + } + +#ifndef CURL_DISABLE_FTP + set->wildcard_enabled = FALSE; + set->chunk_bgn = ZERO_NULL; + set->chunk_end = ZERO_NULL; + set->fnmatch = ZERO_NULL; +#endif + set->tcp_keepalive = FALSE; + set->tcp_keepintvl = 60; + set->tcp_keepidle = 60; + set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; + set->ssl_enable_alpn = TRUE; + set->expect_100_timeout = 1000L; /* Wait for a second by default. */ + set->sep_headers = TRUE; /* separated header lists by default */ + set->buffer_size = READBUFFER_SIZE; + set->upload_buffer_size = UPLOADBUFFER_DEFAULT; + set->happy_eyeballs_timeout = CURL_HET_DEFAULT; + set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; + set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ + set->maxage_conn = 118; + set->maxlifetime_conn = 0; + set->http09_allowed = FALSE; +#ifdef USE_HTTP2 + set->httpwant = CURL_HTTP_VERSION_2TLS +#else + set->httpwant = CURL_HTTP_VERSION_1_1 +#endif + ; +#if defined(USE_HTTP2) || defined(USE_HTTP3) + memset(&set->priority, 0, sizeof(set->priority)); +#endif + set->quick_exit = 0L; + return result; +} + +/** + * Curl_open() + * + * @param curl is a pointer to a sessionhandle pointer that gets set by this + * function. + * @return CURLcode + */ + +CURLcode Curl_open(struct Curl_easy **curl) +{ + CURLcode result; + struct Curl_easy *data; + + /* Very simple start-up: alloc the struct, init it with zeroes and return */ + data = calloc(1, sizeof(struct Curl_easy)); + if(!data) { + /* this is a very serious error */ + DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); + return CURLE_OUT_OF_MEMORY; + } + + data->magic = CURLEASY_MAGIC_NUMBER; + + result = Curl_resolver_init(data, &data->state.async.resolver); + if(result) { + DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); + free(data); + return result; + } + + result = Curl_init_userdefined(data); + if(!result) { + Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); + Curl_initinfo(data); + + /* most recent connection is not yet defined */ + data->state.lastconnect_id = -1; + data->state.recent_conn_id = -1; + /* and not assigned an id yet */ + data->id = -1; + + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ + } + + if(result) { + Curl_resolver_cleanup(data->state.async.resolver); + Curl_dyn_free(&data->state.headerb); + Curl_freeset(data); + free(data); + data = NULL; + } + else + *curl = data; + + return result; +} + +static void conn_shutdown(struct Curl_easy *data) +{ + DEBUGASSERT(data); + infof(data, "Closing connection"); + + /* possible left-overs from the async name resolvers */ + Curl_resolver_cancel(data); + + Curl_conn_close(data, SECONDARYSOCKET); + Curl_conn_close(data, FIRSTSOCKET); +} + +static void conn_free(struct Curl_easy *data, struct connectdata *conn) +{ + size_t i; + + DEBUGASSERT(conn); + + for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) { + Curl_conn_cf_discard_all(data, conn, (int)i); + } + + Curl_free_idnconverted_hostname(&conn->host); + Curl_free_idnconverted_hostname(&conn->conn_to_host); +#ifndef CURL_DISABLE_PROXY + Curl_free_idnconverted_hostname(&conn->http_proxy.host); + Curl_free_idnconverted_hostname(&conn->socks_proxy.host); + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); + Curl_safefree(conn->http_proxy.passwd); + Curl_safefree(conn->socks_proxy.passwd); + Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ + Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ +#endif + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); + Curl_safefree(conn->sasl_authzid); + Curl_safefree(conn->options); + Curl_safefree(conn->oauth_bearer); + Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ + Curl_safefree(conn->hostname_resolve); + Curl_safefree(conn->secondaryhostname); + Curl_safefree(conn->localdev); + Curl_ssl_conn_config_cleanup(conn); + +#ifdef USE_UNIX_SOCKETS + Curl_safefree(conn->unix_domain_socket); +#endif + + free(conn); /* free all the connection oriented data */ +} + +/* + * Disconnects the given connection. Note the connection may not be the + * primary connection, like when freeing room in the connection cache or + * killing of a dead old connection. + * + * A connection needs an easy handle when closing down. We support this passed + * in separately since the connection to get closed here is often already + * disassociated from an easy handle. + * + * This function MUST NOT reset state in the Curl_easy struct if that + * isn't strictly bound to the life-time of *this* particular connection. + * + */ + +void Curl_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection) +{ + /* there must be a connection to close */ + DEBUGASSERT(conn); + + /* it must be removed from the connection cache */ + DEBUGASSERT(!conn->bundle); + + /* there must be an associated transfer */ + DEBUGASSERT(data); + + /* the transfer must be detached from the connection */ + DEBUGASSERT(!data->conn); + + DEBUGF(infof(data, "Curl_disconnect(conn #%" + CURL_FORMAT_CURL_OFF_T ", dead=%d)", + conn->connection_id, dead_connection)); + /* + * If this connection isn't marked to force-close, leave it open if there + * are other users of it + */ + if(CONN_INUSE(conn) && !dead_connection) { + DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn))); + return; + } + + if(conn->dns_entry) { + Curl_resolv_unlock(data, conn->dns_entry); + conn->dns_entry = NULL; + } + + /* Cleanup NTLM connection-related data */ + Curl_http_auth_cleanup_ntlm(conn); + + /* Cleanup NEGOTIATE connection-related data */ + Curl_http_auth_cleanup_negotiate(conn); + + if(conn->connect_only) + /* treat the connection as dead in CONNECT_ONLY situations */ + dead_connection = TRUE; + + /* temporarily attach the connection to this transfer handle for the + disconnect and shutdown */ + Curl_attach_connection(data, conn); + + if(conn->handler && conn->handler->disconnect) + /* This is set if protocol-specific cleanups should be made */ + conn->handler->disconnect(data, conn, dead_connection); + + conn_shutdown(data); + + /* detach it again */ + Curl_detach_connection(data); + + conn_free(data, conn); +} + +/* + * IsMultiplexingPossible() + * + * Return a bitmask with the available multiplexing options for the given + * requested connection. + */ +static int IsMultiplexingPossible(const struct Curl_easy *handle, + const struct connectdata *conn) +{ + int avail = 0; + + /* If an HTTP protocol and multiplexing is enabled */ + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (!conn->bits.protoconnstart || !conn->bits.close)) { + + if(Curl_multiplex_wanted(handle->multi) && + (handle->state.httpwant >= CURL_HTTP_VERSION_2)) + /* allows HTTP/2 */ + avail |= CURLPIPE_MULTIPLEX; + } + return avail; +} + +#ifndef CURL_DISABLE_PROXY +static bool +proxy_info_matches(const struct proxy_info *data, + const struct proxy_info *needle) +{ + if((data->proxytype == needle->proxytype) && + (data->port == needle->port) && + strcasecompare(data->host.name, needle->host.name)) + return TRUE; + + return FALSE; +} + +static bool +socks_proxy_info_matches(const struct proxy_info *data, + const struct proxy_info *needle) +{ + if(!proxy_info_matches(data, needle)) + return FALSE; + + /* the user information is case-sensitive + or at least it is not defined as case-insensitive + see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */ + + /* curl_strequal does a case insensitive comparison, + so do not use it here! */ + if(Curl_timestrcmp(data->user, needle->user) || + Curl_timestrcmp(data->passwd, needle->passwd)) + return FALSE; + return TRUE; +} +#else +/* disabled, won't get called */ +#define proxy_info_matches(x,y) FALSE +#define socks_proxy_info_matches(x,y) FALSE +#endif + +/* A connection has to have been idle for a shorter time than 'maxage_conn' + (the success rate is just too low after this), or created less than + 'maxlifetime_conn' ago, to be subject for reuse. */ + +static bool conn_maxage(struct Curl_easy *data, + struct connectdata *conn, + struct curltime now) +{ + timediff_t idletime, lifetime; + + idletime = Curl_timediff(now, conn->lastused); + idletime /= 1000; /* integer seconds is fine */ + + if(idletime > data->set.maxage_conn) { + infof(data, "Too old connection (%" CURL_FORMAT_TIMEDIFF_T + " seconds idle), disconnect it", idletime); + return TRUE; + } + + lifetime = Curl_timediff(now, conn->created); + lifetime /= 1000; /* integer seconds is fine */ + + if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) { + infof(data, + "Too old connection (%" CURL_FORMAT_TIMEDIFF_T + " seconds since creation), disconnect it", lifetime); + return TRUE; + } + + + return FALSE; +} + +/* + * This function checks if the given connection is dead and extracts it from + * the connection cache if so. + * + * When this is called as a Curl_conncache_foreach() callback, the connection + * cache lock is held! + * + * Returns TRUE if the connection was dead and extracted. + */ +static bool extract_if_dead(struct connectdata *conn, + struct Curl_easy *data) +{ + if(!CONN_INUSE(conn)) { + /* The check for a dead socket makes sense only if the connection isn't in + use */ + bool dead; + struct curltime now = Curl_now(); + if(conn_maxage(data, conn, now)) { + /* avoid check if already too old */ + dead = TRUE; + } + else if(conn->handler->connection_check) { + /* The protocol has a special method for checking the state of the + connection. Use it to check if the connection is dead. */ + unsigned int state; + + /* briefly attach the connection to this transfer for the purpose of + checking it */ + Curl_attach_connection(data, conn); + + state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD); + dead = (state & CONNRESULT_DEAD); + /* detach the connection again */ + Curl_detach_connection(data); + + } + else { + bool input_pending; + + 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. The 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. + */ + dead = TRUE; + } + Curl_detach_connection(data); + } + + if(dead) { + infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead", + conn->connection_id); + Curl_conncache_remove_conn(data, conn, FALSE); + return TRUE; + } + } + return FALSE; +} + +struct prunedead { + struct Curl_easy *data; + struct connectdata *extracted; +}; + +/* + * Wrapper to use extract_if_dead() function in Curl_conncache_foreach() + * + */ +static int call_extract_if_dead(struct Curl_easy *data, + struct connectdata *conn, void *param) +{ + struct prunedead *p = (struct prunedead *)param; + if(extract_if_dead(conn, data)) { + /* stop the iteration here, pass back the connection that was extracted */ + p->extracted = conn; + return 1; + } + return 0; /* continue iteration */ +} + +/* + * This function scans the connection cache for half-open/dead connections, + * closes and removes them. The cleanup is done at most once per second. + * + * When called, this transfer has no connection attached. + */ +static void prune_dead_connections(struct Curl_easy *data) +{ + struct curltime now = Curl_now(); + timediff_t elapsed; + + DEBUGASSERT(!data->conn); /* no connection */ + CONNCACHE_LOCK(data); + elapsed = + Curl_timediff(now, data->state.conn_cache->last_cleanup); + CONNCACHE_UNLOCK(data); + + if(elapsed >= 1000L) { + struct prunedead prune; + prune.data = data; + prune.extracted = NULL; + while(Curl_conncache_foreach(data, data->state.conn_cache, &prune, + call_extract_if_dead)) { + /* unlocked */ + + /* remove connection from cache */ + Curl_conncache_remove_conn(data, prune.extracted, TRUE); + + /* disconnect it */ + Curl_disconnect(data, prune.extracted, TRUE); + } + CONNCACHE_LOCK(data); + data->state.conn_cache->last_cleanup = now; + CONNCACHE_UNLOCK(data); + } +} + +#ifdef USE_SSH +static bool ssh_config_matches(struct connectdata *one, + struct connectdata *two) +{ + return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) && + Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub)); +} +#else +#define ssh_config_matches(x,y) FALSE +#endif + +/* + * Given one filled in connection struct (named needle), this function should + * detect if there already is one that has all the significant details + * exactly the same and thus should be used instead. + * + * If there is a match, this function returns TRUE - and has marked the + * connection as 'in-use'. It must later be called with ConnectionDone() to + * return back to 'idle' (unused) state. + * + * The force_reuse flag is set if the connection must be used. + */ +static bool +ConnectionExists(struct Curl_easy *data, + struct connectdata *needle, + struct connectdata **usethis, + bool *force_reuse, + bool *waitpipe) +{ + struct connectdata *chosen = NULL; + bool foundPendingCandidate = FALSE; + bool canmultiplex = FALSE; + struct connectbundle *bundle; + struct Curl_llist_element *curr; + +#ifdef USE_NTLM + bool wantNTLMhttp = ((data->state.authhost.want & + (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + (needle->handler->protocol & PROTO_FAMILY_HTTP)); +#ifndef CURL_DISABLE_PROXY + bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd && + ((data->state.authproxy.want & + (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + (needle->handler->protocol & PROTO_FAMILY_HTTP))); +#else + bool wantProxyNTLMhttp = FALSE; +#endif +#endif + /* plain HTTP with upgrade */ + bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) && + (needle->handler->protocol & CURLPROTO_HTTP); + + *usethis = NULL; + *force_reuse = FALSE; + *waitpipe = FALSE; + + /* Look up the bundle with all the connections to this particular host. + Locks the connection cache, beware of early returns! */ + bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache); + if(!bundle) { + CONNCACHE_UNLOCK(data); + return FALSE; + } + infof(data, "Found bundle for host: %p [%s]", + (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ? + "can multiplex" : "serially")); + + /* We can only multiplex iff the transfer allows it AND we know + * that the server we want to talk to supports it as well. */ + canmultiplex = FALSE; + if(IsMultiplexingPossible(data, needle)) { + if(bundle->multiuse == BUNDLE_UNKNOWN) { + if(data->set.pipewait) { + infof(data, "Server doesn't support multiplex yet, wait"); + *waitpipe = TRUE; + CONNCACHE_UNLOCK(data); + return FALSE; /* no reuse */ + } + infof(data, "Server doesn't support multiplex (yet)"); + } + else if(bundle->multiuse == BUNDLE_MULTIPLEX) { + if(Curl_multiplex_wanted(data->multi)) + canmultiplex = TRUE; + else + infof(data, "Could multiplex, but not asked to"); + } + else if(bundle->multiuse == BUNDLE_NO_MULTIUSE) { + infof(data, "Can not multiplex, even if we wanted to"); + } + } + + curr = bundle->conn_list.head; + while(curr) { + struct connectdata *check = curr->ptr; + /* Get next node now. We might remove a dead `check` connection which + * would invalidate `curr` as well. */ + curr = curr->next; + + /* Note that if we use an HTTP proxy in normal mode (no tunneling), we + * check connections to that proxy and not to the actual remote server. + */ + if(check->connect_only || check->bits.close) + /* connect-only or to-be-closed connections will not be reused */ + continue; + + if(data->set.ipver != CURL_IPRESOLVE_WHATEVER + && data->set.ipver != check->ip_version) { + /* skip because the connection is not via the requested IP version */ + continue; + } + + if(!canmultiplex) { + if(Curl_resolver_asynch() && + /* primary_ip[0] is NUL only if the resolving of the name hasn't + completed yet and until then we don't reuse this connection */ + !check->primary_ip[0]) + continue; + } + + if(CONN_INUSE(check)) { + if(!canmultiplex) { + /* transfer can't be multiplexed and check is in use */ + continue; + } + else { + /* Could multiplex, but not when check belongs to another multi */ + struct Curl_llist_element *e = check->easyq.head; + struct Curl_easy *entry = e->ptr; + if(entry->multi != data->multi) + continue; + } + } + + if(!Curl_conn_is_connected(check, FIRSTSOCKET)) { + foundPendingCandidate = TRUE; + /* Don't pick a connection that hasn't connected yet */ + infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T + " isn't open enough, can't reuse", check->connection_id); + continue; + } + + /* `check` is connected. if it is in use and does not support multiplex, + * we cannot use it. */ + if(!check->bits.multiplex && CONN_INUSE(check)) + continue; + +#ifdef USE_UNIX_SOCKETS + if(needle->unix_domain_socket) { + if(!check->unix_domain_socket) + continue; + if(strcmp(needle->unix_domain_socket, check->unix_domain_socket)) + continue; + if(needle->bits.abstract_unix_socket != + check->bits.abstract_unix_socket) + continue; + } + else if(check->unix_domain_socket) + continue; +#endif + + if((needle->handler->flags&PROTOPT_SSL) != + (check->handler->flags&PROTOPT_SSL)) + /* don't do mixed SSL and non-SSL connections */ + if(get_protocol_family(check->handler) != + needle->handler->protocol || !check->bits.tls_upgraded) + /* except protocols that have been upgraded via TLS */ + continue; + + if(needle->bits.conn_to_host != check->bits.conn_to_host) + /* don't mix connections that use the "connect to host" feature and + * connections that don't use this feature */ + continue; + + if(needle->bits.conn_to_port != check->bits.conn_to_port) + /* don't mix connections that use the "connect to port" feature and + * connections that don't use this feature */ + continue; + +#ifndef CURL_DISABLE_PROXY + if(needle->bits.httpproxy != check->bits.httpproxy || + needle->bits.socksproxy != check->bits.socksproxy) + continue; + + if(needle->bits.socksproxy && + !socks_proxy_info_matches(&needle->socks_proxy, + &check->socks_proxy)) + continue; + + if(needle->bits.httpproxy) { + if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy) + continue; + + if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy)) + continue; + + if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) { + /* https proxies come in different types, http/1.1, h2, ... */ + if(needle->http_proxy.proxytype != check->http_proxy.proxytype) + continue; + /* match SSL config to proxy */ + if(!Curl_ssl_conn_config_match(data, check, TRUE)) { + DEBUGF(infof(data, + "Connection #%" CURL_FORMAT_CURL_OFF_T + " has different SSL proxy parameters, can't reuse", + check->connection_id)); + continue; + } + /* the SSL config to the server, which may apply here is checked + * further below */ + } + } +#endif + + if(h2upgrade && !check->httpversion && canmultiplex) { + if(data->set.pipewait) { + infof(data, "Server upgrade doesn't support multiplex yet, wait"); + *waitpipe = TRUE; + CONNCACHE_UNLOCK(data); + return FALSE; /* no reuse */ + } + infof(data, "Server upgrade cannot be used"); + continue; /* can't be used atm */ + } + + if(needle->localdev || needle->localport) { + /* If we are bound to a specific local end (IP+port), we must not + reuse a random other one, although if we didn't ask for a + particular one we can reuse one that was bound. + + This comparison is a bit rough and too strict. Since the input + parameters can be specified in numerous ways and still end up the + same it would take a lot of processing to make it really accurate. + Instead, this matching will assume that reuses of bound connections + will most likely also reuse the exact same binding parameters and + missing out a few edge cases shouldn't hurt anyone very much. + */ + if((check->localport != needle->localport) || + (check->localportrange != needle->localportrange) || + (needle->localdev && + (!check->localdev || strcmp(check->localdev, needle->localdev)))) + continue; + } + + if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { + /* This protocol requires credentials per connection, + so verify that we're using the same name and password as well */ + if(Curl_timestrcmp(needle->user, check->user) || + Curl_timestrcmp(needle->passwd, check->passwd) || + Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) || + Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) { + /* one of them was different */ + continue; + } + } + + /* GSS delegation differences do not actually affect every connection + and auth method, but this check takes precaution before efficiency */ + if(needle->gssapi_delegation != check->gssapi_delegation) + continue; + + /* If looking for HTTP and the HTTP version we want is less + * than the HTTP version of the check connection, continue looking */ + if((needle->handler->protocol & PROTO_FAMILY_HTTP) && + (((check->httpversion >= 20) && + (data->state.httpwant < CURL_HTTP_VERSION_2_0)) + || ((check->httpversion >= 30) && + (data->state.httpwant < CURL_HTTP_VERSION_3)))) + continue; +#ifdef USE_SSH + else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) { + if(!ssh_config_matches(needle, check)) + continue; + } +#endif +#ifndef CURL_DISABLE_FTP + else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) { + /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */ + if(Curl_timestrcmp(needle->proto.ftpc.account, + check->proto.ftpc.account) || + Curl_timestrcmp(needle->proto.ftpc.alternative_to_user, + check->proto.ftpc.alternative_to_user) || + (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) || + (needle->proto.ftpc.ccc != check->proto.ftpc.ccc)) + continue; + } +#endif + + /* Additional match requirements if talking TLS OR + * not talking to a HTTP proxy OR using a tunnel through a proxy */ + if((needle->handler->flags&PROTOPT_SSL) +#ifndef CURL_DISABLE_PROXY + || !needle->bits.httpproxy || needle->bits.tunnel_proxy +#endif + ) { + /* Talking the same protocol scheme or a TLS upgraded protocol in the + * same protocol family? */ + if(!strcasecompare(needle->handler->scheme, check->handler->scheme) && + (get_protocol_family(check->handler) != + needle->handler->protocol || !check->bits.tls_upgraded)) + continue; + + /* If needle has "conn_to_*" set, check must match this */ + if((needle->bits.conn_to_host && !strcasecompare( + needle->conn_to_host.name, check->conn_to_host.name)) || + (needle->bits.conn_to_port && + needle->conn_to_port != check->conn_to_port)) + continue; + + /* hostname and port must match */ + if(!strcasecompare(needle->host.name, check->host.name) || + needle->remote_port != check->remote_port) + continue; + + /* If talking TLS, check needs to use the same SSL options. */ + if((needle->handler->flags & PROTOPT_SSL) && + !Curl_ssl_conn_config_match(data, check, FALSE)) { + DEBUGF(infof(data, + "Connection #%" CURL_FORMAT_CURL_OFF_T + " has different SSL parameters, can't reuse", + check->connection_id)); + continue; + } + } + +#if defined(USE_NTLM) + /* If we are looking for an HTTP+NTLM connection, check if this is + already authenticating with the right credentials. If not, keep + looking so that we can reuse NTLM connections if + possible. (Especially we must not reuse the same connection if + partway through a handshake!) */ + if(wantNTLMhttp) { + if(Curl_timestrcmp(needle->user, check->user) || + Curl_timestrcmp(needle->passwd, check->passwd)) { + + /* we prefer a credential match, but this is at least a connection + that can be reused and "upgraded" to NTLM */ + if(check->http_ntlm_state == NTLMSTATE_NONE) + chosen = check; + continue; + } + } + else if(check->http_ntlm_state != NTLMSTATE_NONE) { + /* Connection is using NTLM auth but we don't want NTLM */ + continue; + } + +#ifndef CURL_DISABLE_PROXY + /* Same for Proxy NTLM authentication */ + if(wantProxyNTLMhttp) { + /* Both check->http_proxy.user and check->http_proxy.passwd can be + * NULL */ + if(!check->http_proxy.user || !check->http_proxy.passwd) + continue; + + if(Curl_timestrcmp(needle->http_proxy.user, + check->http_proxy.user) || + Curl_timestrcmp(needle->http_proxy.passwd, + check->http_proxy.passwd)) + continue; + } + else if(check->proxy_ntlm_state != NTLMSTATE_NONE) { + /* Proxy connection is using NTLM auth but we don't want NTLM */ + continue; + } +#endif + if(wantNTLMhttp || wantProxyNTLMhttp) { + /* Credentials are already checked, we may use this connection. + * With NTLM being weird as it is, we MUST use a + * connection where it has already been fully negotiated. + * If it has not, we keep on looking for a better one. */ + chosen = check; + + if((wantNTLMhttp && + (check->http_ntlm_state != NTLMSTATE_NONE)) || + (wantProxyNTLMhttp && + (check->proxy_ntlm_state != NTLMSTATE_NONE))) { + /* We must use this connection, no other */ + *force_reuse = TRUE; + break; + } + /* Continue look up for a better connection */ + continue; + } +#endif + + if(CONN_INUSE(check)) { + DEBUGASSERT(canmultiplex); + DEBUGASSERT(check->bits.multiplex); + /* If multiplexed, make sure we don't go over concurrency limit */ + if(CONN_INUSE(check) >= + Curl_multi_max_concurrent_streams(data->multi)) { + infof(data, "client side MAX_CONCURRENT_STREAMS reached" + ", skip (%zu)", CONN_INUSE(check)); + continue; + } + if(CONN_INUSE(check) >= + Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) { + infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)", + CONN_INUSE(check)); + continue; + } + /* When not multiplexed, we have a match here! */ + infof(data, "Multiplexed connection found"); + } + else if(extract_if_dead(check, data)) { + /* disconnect it */ + Curl_disconnect(data, check, TRUE); + continue; + } + + /* We have found a connection. Let's stop searching. */ + chosen = check; + break; + } /* loop over connection bundle */ + + if(chosen) { + /* mark it as used before releasing the lock */ + Curl_attach_connection(data, chosen); + CONNCACHE_UNLOCK(data); + *usethis = chosen; + return TRUE; /* yes, we found one to use! */ + } + CONNCACHE_UNLOCK(data); + + if(foundPendingCandidate && data->set.pipewait) { + infof(data, + "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set"); + *waitpipe = TRUE; + } + + return FALSE; /* no matching connecting exists */ +} + +/* + * verboseconnect() displays verbose information after a connect + */ +#ifndef CURL_DISABLE_VERBOSE_STRINGS +void Curl_verboseconnect(struct Curl_easy *data, + struct connectdata *conn) +{ + if(data->set.verbose) + infof(data, "Connected to %s (%s) port %u", + CURL_CONN_HOST_DISPNAME(conn), conn->primary_ip, conn->port); +} +#endif + +/* + * Allocate and initialize a new connectdata object. + */ +static struct connectdata *allocate_conn(struct Curl_easy *data) +{ + struct connectdata *conn = calloc(1, sizeof(struct connectdata)); + if(!conn) + return NULL; + + /* and we setup a few fields in case we end up actually using this struct */ + + conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ + conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ + conn->sockfd = CURL_SOCKET_BAD; + conn->writesockfd = CURL_SOCKET_BAD; + conn->connection_id = -1; /* no ID */ + conn->port = -1; /* unknown at this point */ + conn->remote_port = -1; /* unknown at this point */ + + /* Default protocol-independent behavior doesn't support persistent + connections, so we set this to force-close. Protocols that support + this need to set this to FALSE in their "curl_do" functions. */ + connclose(conn, "Default to force-close"); + + /* Store creation time to help future close decision making */ + conn->created = Curl_now(); + + /* Store current time to give a baseline to keepalive connection times. */ + conn->keepalive = conn->created; + +#ifndef CURL_DISABLE_PROXY + conn->http_proxy.proxytype = data->set.proxytype; + conn->socks_proxy.proxytype = CURLPROXY_SOCKS4; + + /* note that these two proxy bits are now just on what looks to be + requested, they may be altered down the road */ + conn->bits.proxy = (data->set.str[STRING_PROXY] && + *data->set.str[STRING_PROXY]) ? TRUE : FALSE; + conn->bits.httpproxy = (conn->bits.proxy && + (conn->http_proxy.proxytype == CURLPROXY_HTTP || + conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 || + IS_HTTPS_PROXY(conn->http_proxy.proxytype))) ? + TRUE : FALSE; + conn->bits.socksproxy = (conn->bits.proxy && + !conn->bits.httpproxy) ? TRUE : FALSE; + + if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) { + conn->bits.proxy = TRUE; + conn->bits.socksproxy = TRUE; + } + + conn->bits.proxy_user_passwd = + (data->state.aptr.proxyuser) ? TRUE : FALSE; + conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; +#endif /* CURL_DISABLE_PROXY */ + +#ifndef CURL_DISABLE_FTP + conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; + conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; +#endif + conn->ip_version = data->set.ipver; + conn->connect_only = data->set.connect_only; + conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; +#endif + + /* Initialize the easy handle list */ + Curl_llist_init(&conn->easyq, NULL); + +#ifdef HAVE_GSSAPI + conn->data_prot = PROT_CLEAR; +#endif + + /* Store the local bind parameters that will be used for this connection */ + if(data->set.str[STRING_DEVICE]) { + conn->localdev = strdup(data->set.str[STRING_DEVICE]); + if(!conn->localdev) + goto error; + } +#ifndef CURL_DISABLE_BINDLOCAL + conn->localportrange = data->set.localportrange; + conn->localport = data->set.localport; +#endif + + /* the close socket stuff needs to be copied to the connection struct as + it may live on without (this specific) Curl_easy */ + conn->fclosesocket = data->set.fclosesocket; + conn->closesocket_client = data->set.closesocket_client; + conn->lastused = conn->created; + conn->gssapi_delegation = data->set.gssapi_delegation; + + return conn; +error: + + free(conn->localdev); + free(conn); + return NULL; +} + +const struct Curl_handler *Curl_get_scheme_handler(const char *scheme) +{ + return Curl_getn_scheme_handler(scheme, strlen(scheme)); +} + +/* returns the handler if the given scheme is built-in */ +const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, + size_t len) +{ + /* table generated by schemetable.c: + 1. gcc schemetable.c && ./a.out + 2. check how small the table gets + 3. tweak the hash algorithm, then rerun from 1 + 4. when the table is good enough + 5. copy the table into this source code + 6. make sure this function uses the same hash function that worked for + schemetable.c + 7. if needed, adjust the #ifdefs in schemetable.c and rerun + */ + static const struct Curl_handler * const protocols[67] = { +#ifndef CURL_DISABLE_FILE + &Curl_handler_file, +#else + NULL, +#endif + NULL, NULL, +#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER) + &Curl_handler_gophers, +#else + NULL, +#endif + NULL, +#ifdef USE_LIBRTMP + &Curl_handler_rtmpe, +#else + NULL, +#endif +#ifndef CURL_DISABLE_SMTP + &Curl_handler_smtp, +#else + NULL, +#endif +#if defined(USE_SSH) + &Curl_handler_sftp, +#else + NULL, +#endif +#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \ + (SIZEOF_CURL_OFF_T > 4) + &Curl_handler_smb, +#else + NULL, +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP) + &Curl_handler_smtps, +#else + NULL, +#endif +#ifndef CURL_DISABLE_TELNET + &Curl_handler_telnet, +#else + NULL, +#endif +#ifndef CURL_DISABLE_GOPHER + &Curl_handler_gopher, +#else + NULL, +#endif +#ifndef CURL_DISABLE_TFTP + &Curl_handler_tftp, +#else + NULL, +#endif + NULL, NULL, NULL, +#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) + &Curl_handler_ftps, +#else + NULL, +#endif +#ifndef CURL_DISABLE_HTTP + &Curl_handler_http, +#else + NULL, +#endif +#ifndef CURL_DISABLE_IMAP + &Curl_handler_imap, +#else + NULL, +#endif +#ifdef USE_LIBRTMP + &Curl_handler_rtmps, +#else + NULL, +#endif +#ifdef USE_LIBRTMP + &Curl_handler_rtmpt, +#else + NULL, +#endif + NULL, NULL, NULL, +#if !defined(CURL_DISABLE_LDAP) && \ + !defined(CURL_DISABLE_LDAPS) && \ + ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ + (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) + &Curl_handler_ldaps, +#else + NULL, +#endif +#if defined(USE_WEBSOCKETS) && \ + defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + &Curl_handler_wss, +#else + NULL, +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + &Curl_handler_https, +#else + NULL, +#endif + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#ifndef CURL_DISABLE_RTSP + &Curl_handler_rtsp, +#else + NULL, +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \ + defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4) + &Curl_handler_smbs, +#else + NULL, +#endif +#if defined(USE_SSH) && !defined(USE_WOLFSSH) + &Curl_handler_scp, +#else + NULL, +#endif + NULL, NULL, NULL, +#ifndef CURL_DISABLE_POP3 + &Curl_handler_pop3, +#else + NULL, +#endif + NULL, NULL, +#ifdef USE_LIBRTMP + &Curl_handler_rtmp, +#else + NULL, +#endif + NULL, NULL, NULL, +#ifdef USE_LIBRTMP + &Curl_handler_rtmpte, +#else + NULL, +#endif + NULL, NULL, NULL, +#ifndef CURL_DISABLE_DICT + &Curl_handler_dict, +#else + NULL, +#endif + NULL, NULL, NULL, +#ifndef CURL_DISABLE_MQTT + &Curl_handler_mqtt, +#else + NULL, +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3) + &Curl_handler_pop3s, +#else + NULL, +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP) + &Curl_handler_imaps, +#else + NULL, +#endif + NULL, +#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) + &Curl_handler_ws, +#else + NULL, +#endif + NULL, +#ifdef USE_LIBRTMP + &Curl_handler_rtmpts, +#else + NULL, +#endif +#ifndef CURL_DISABLE_LDAP + &Curl_handler_ldap, +#else + NULL, +#endif + NULL, NULL, +#ifndef CURL_DISABLE_FTP + &Curl_handler_ftp, +#else + NULL, +#endif + }; + + if(len && (len <= 7)) { + const char *s = scheme; + size_t l = len; + const struct Curl_handler *h; + unsigned int c = 978; + while(l) { + c <<= 5; + c += Curl_raw_tolower(*s); + s++; + l--; + } + + h = protocols[c % 67]; + if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len]) + return h; + } + return NULL; +} + +static CURLcode findprotocol(struct Curl_easy *data, + struct connectdata *conn, + const char *protostr) +{ + const struct Curl_handler *p = Curl_get_scheme_handler(protostr); + + if(p && /* Protocol found in table. Check if allowed */ + (data->set.allowed_protocols & p->protocol)) { + + /* it is allowed for "normal" request, now do an extra check if this is + the result of a redirect */ + if(data->state.this_is_a_follow && + !(data->set.redir_protocols & p->protocol)) + /* nope, get out */ + ; + else { + /* Perform setup complement if some. */ + conn->handler = conn->given = p; + /* 'port' and 'remote_port' are set in setup_connection_internals() */ + return CURLE_OK; + } + } + + /* The protocol was not found in the table, but we don't have to assign it + to anything since it is already assigned to a dummy-struct in the + create_conn() function when the connectdata struct is allocated. */ + failf(data, "Protocol \"%s\" %s%s", protostr, + p ? "disabled" : "not supported", + data->state.this_is_a_follow ? " (in redirect)":""); + + return CURLE_UNSUPPORTED_PROTOCOL; +} + + +CURLcode Curl_uc_to_curlcode(CURLUcode uc) +{ + switch(uc) { + default: + return CURLE_URL_MALFORMAT; + case CURLUE_UNSUPPORTED_SCHEME: + return CURLE_UNSUPPORTED_PROTOCOL; + case CURLUE_OUT_OF_MEMORY: + return CURLE_OUT_OF_MEMORY; + case CURLUE_USER_NOT_ALLOWED: + return CURLE_LOGIN_DENIED; + } +} + +#ifdef ENABLE_IPV6 +/* + * If the URL was set with an IPv6 numerical address with a zone id part, set + * the scope_id based on that! + */ + +static void zonefrom_url(CURLU *uh, struct Curl_easy *data, + struct connectdata *conn) +{ + char *zoneid; + CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0); +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; +#endif + + if(!uc && zoneid) { + char *endp; + unsigned long scope = strtoul(zoneid, &endp, 10); + if(!*endp && (scope < UINT_MAX)) + /* A plain number, use it directly as a scope id. */ + conn->scope_id = (unsigned int)scope; +#if defined(HAVE_IF_NAMETOINDEX) + else { +#elif defined(_WIN32) + else if(Curl_if_nametoindex) { +#endif + +#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32) + /* Zone identifier is not numeric */ + unsigned int scopeidx = 0; +#if defined(_WIN32) + scopeidx = Curl_if_nametoindex(zoneid); +#else + scopeidx = if_nametoindex(zoneid); +#endif + if(!scopeidx) { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + char buffer[STRERROR_LEN]; + infof(data, "Invalid zoneid: %s; %s", zoneid, + Curl_strerror(errno, buffer, sizeof(buffer))); +#endif + } + else + conn->scope_id = scopeidx; + } +#endif /* HAVE_IF_NAMETOINDEX || _WIN32 */ + + free(zoneid); + } +} +#else +#define zonefrom_url(a,b,c) Curl_nop_stmt +#endif + +/* + * Parse URL and fill in the relevant members of the connection struct. + */ +static CURLcode parseurlandfillconn(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + CURLU *uh; + CURLUcode uc; + char *hostname; + bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow); + + up_free(data); /* cleanup previous leftovers first */ + + /* parse the URL */ + if(use_set_uh) { + uh = data->state.uh = curl_url_dup(data->set.uh); + } + else { + uh = data->state.uh = curl_url(); + } + + if(!uh) + return CURLE_OUT_OF_MEMORY; + + if(data->set.str[STRING_DEFAULT_PROTOCOL] && + !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) { + char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL], + data->state.url); + if(!url) + return CURLE_OUT_OF_MEMORY; + if(data->state.url_alloc) + free(data->state.url); + data->state.url = url; + data->state.url_alloc = TRUE; + } + + if(!use_set_uh) { + char *newurl; + uc = curl_url_set(uh, CURLUPART_URL, data->state.url, + CURLU_GUESS_SCHEME | + CURLU_NON_SUPPORT_SCHEME | + (data->set.disallow_username_in_url ? + CURLU_DISALLOW_USER : 0) | + (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); + if(uc) { + failf(data, "URL rejected: %s", curl_url_strerror(uc)); + return Curl_uc_to_curlcode(uc); + } + + /* after it was parsed, get the generated normalized version */ + uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + if(data->state.url_alloc) + free(data->state.url); + data->state.url = newurl; + data->state.url_alloc = TRUE; + } + + uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + + uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0); + if(uc) { + if(!strcasecompare("file", data->state.up.scheme)) + return CURLE_OUT_OF_MEMORY; + } + else if(strlen(data->state.up.hostname) > MAX_URL_LEN) { + failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN); + return CURLE_URL_MALFORMAT; + } + hostname = data->state.up.hostname; + + if(hostname && hostname[0] == '[') { + /* This looks like an IPv6 address literal. See if there is an address + scope. */ + size_t hlen; + conn->bits.ipv6_ip = TRUE; + /* cut off the brackets! */ + hostname++; + hlen = strlen(hostname); + hostname[hlen - 1] = 0; + + zonefrom_url(uh, data, conn); + } + + /* make sure the connect struct gets its own copy of the host name */ + conn->host.rawalloc = strdup(hostname ? hostname : ""); + if(!conn->host.rawalloc) + return CURLE_OUT_OF_MEMORY; + conn->host.name = conn->host.rawalloc; + + /************************************************************* + * IDN-convert the hostnames + *************************************************************/ + result = Curl_idnconvert_hostname(&conn->host); + if(result) + return result; + +#ifndef CURL_DISABLE_HSTS + /* HSTS upgrade */ + if(data->hsts && strcasecompare("http", data->state.up.scheme)) { + /* This MUST use the IDN decoded name */ + if(Curl_hsts(data->hsts, conn->host.name, TRUE)) { + char *url; + Curl_safefree(data->state.up.scheme); + uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0); + if(uc) + return Curl_uc_to_curlcode(uc); + if(data->state.url_alloc) + Curl_safefree(data->state.url); + /* after update, get the updated version */ + uc = curl_url_get(uh, CURLUPART_URL, &url, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0); + if(uc) { + free(url); + return Curl_uc_to_curlcode(uc); + } + data->state.url = url; + data->state.url_alloc = TRUE; + infof(data, "Switched from HTTP to HTTPS due to HSTS => %s", + data->state.url); + } + } +#endif + + result = findprotocol(data, conn, data->state.up.scheme); + if(result) + return result; + + /* + * User name and password set with their own options override the + * credentials possibly set in the URL. + */ + if(!data->set.str[STRING_PASSWORD]) { + uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0); + if(!uc) { + char *decoded; + result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL, + conn->handler->flags&PROTOPT_USERPWDCTRL ? + REJECT_ZERO : REJECT_CTRL); + if(result) + return result; + conn->passwd = decoded; + result = Curl_setstropt(&data->state.aptr.passwd, decoded); + if(result) + return result; + } + else if(uc != CURLUE_NO_PASSWORD) + return Curl_uc_to_curlcode(uc); + } + + if(!data->set.str[STRING_USERNAME]) { + /* we don't use the URL API's URL decoder option here since it rejects + control codes and we want to allow them for some schemes in the user + and password fields */ + uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0); + if(!uc) { + char *decoded; + result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL, + conn->handler->flags&PROTOPT_USERPWDCTRL ? + REJECT_ZERO : REJECT_CTRL); + if(result) + return result; + conn->user = decoded; + result = Curl_setstropt(&data->state.aptr.user, decoded); + } + else if(uc != CURLUE_NO_USER) + return Curl_uc_to_curlcode(uc); + else if(data->state.aptr.passwd) { + /* no user was set but a password, set a blank user */ + result = Curl_setstropt(&data->state.aptr.user, ""); + } + if(result) + return result; + } + + uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options, + CURLU_URLDECODE); + if(!uc) { + conn->options = strdup(data->state.up.options); + if(!conn->options) + return CURLE_OUT_OF_MEMORY; + } + else if(uc != CURLUE_NO_OPTIONS) + return Curl_uc_to_curlcode(uc); + + uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, + CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + + uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port, + CURLU_DEFAULT_PORT); + if(uc) { + if(!strcasecompare("file", data->state.up.scheme)) + return CURLE_OUT_OF_MEMORY; + } + else { + unsigned long port = strtoul(data->state.up.port, NULL, 10); + conn->port = conn->remote_port = + (data->set.use_port && data->state.allow_port) ? + data->set.use_port : curlx_ultous(port); + } + + (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0); + +#ifdef ENABLE_IPV6 + if(data->set.scope_id) + /* Override any scope that was set above. */ + conn->scope_id = data->set.scope_id; +#endif + + return CURLE_OK; +} + + +/* + * If we're doing a resumed transfer, we need to setup our stuff + * properly. + */ +static CURLcode setup_range(struct Curl_easy *data) +{ + struct UrlState *s = &data->state; + s->resume_from = data->set.set_resume_from; + if(s->resume_from || data->set.str[STRING_SET_RANGE]) { + if(s->rangestringalloc) + free(s->range); + + if(s->resume_from) + s->range = aprintf("%" CURL_FORMAT_CURL_OFF_T "-", s->resume_from); + else + s->range = strdup(data->set.str[STRING_SET_RANGE]); + + s->rangestringalloc = (s->range) ? TRUE : FALSE; + + if(!s->range) + return CURLE_OUT_OF_MEMORY; + + /* tell ourselves to fetch this range */ + s->use_range = TRUE; /* enable range download */ + } + else + s->use_range = FALSE; /* disable range download */ + + return CURLE_OK; +} + + +/* + * setup_connection_internals() - + * + * Setup connection internals specific to the requested protocol in the + * Curl_easy. This is inited and setup before the connection is made but + * is about the particular protocol that is to be used. + * + * This MUST get called after proxy magic has been figured out. + */ +static CURLcode setup_connection_internals(struct Curl_easy *data, + struct connectdata *conn) +{ + const struct Curl_handler *p; + CURLcode result; + + /* Perform setup complement if some. */ + p = conn->handler; + + if(p->setup_connection) { + result = (*p->setup_connection)(data, conn); + + if(result) + return result; + + p = conn->handler; /* May have changed. */ + } + + if(conn->port < 0) + /* we check for -1 here since if proxy was detected already, this + was very likely already set to the proxy port */ + conn->port = p->defport; + + return CURLE_OK; +} + +/* + * Curl_free_request_state() should free temp data that was allocated in the + * Curl_easy for this single request. + */ + +void Curl_free_request_state(struct Curl_easy *data) +{ + Curl_safefree(data->req.p.http); + Curl_safefree(data->req.newurl); +#ifndef CURL_DISABLE_DOH + if(data->req.doh) { + Curl_close(&data->req.doh->probe[0].easy); + Curl_close(&data->req.doh->probe[1].easy); + } +#endif + Curl_client_cleanup(data); +} + + +#ifndef CURL_DISABLE_PROXY + +#ifndef CURL_DISABLE_HTTP +/**************************************************************** +* Detect what (if any) proxy to use. Remember that this selects a host +* name and is not limited to HTTP proxies only. +* The returned pointer must be freed by the caller (unless NULL) +****************************************************************/ +static char *detect_proxy(struct Curl_easy *data, + struct connectdata *conn) +{ + char *proxy = NULL; + + /* If proxy was not specified, we check for default proxy environment + * variables, to enable i.e Lynx compliance: + * + * http_proxy=http://some.server.dom:port/ + * https_proxy=http://some.server.dom:port/ + * ftp_proxy=http://some.server.dom:port/ + * no_proxy=domain1.dom,host.domain2.dom + * (a comma-separated list of hosts which should + * not be proxied, or an asterisk to override + * all proxy variables) + * all_proxy=http://some.server.dom:port/ + * (seems to exist for the CERN www lib. Probably + * the first to check for.) + * + * For compatibility, the all-uppercase versions of these variables are + * checked if the lowercase versions don't exist. + */ + char proxy_env[128]; + const char *protop = conn->handler->scheme; + char *envp = proxy_env; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; +#endif + + /* Now, build _proxy and check for such a one to use */ + while(*protop) + *envp++ = Curl_raw_tolower(*protop++); + + /* append _proxy */ + strcpy(envp, "_proxy"); + + /* read the protocol proxy: */ + proxy = curl_getenv(proxy_env); + + /* + * We don't try the uppercase version of HTTP_PROXY because of + * security reasons: + * + * When curl is used in a webserver application + * environment (cgi or php), this environment variable can + * be controlled by the web server user by setting the + * http header 'Proxy:' to some value. + * + * This can cause 'internal' http/ftp requests to be + * arbitrarily redirected by any external attacker. + */ + if(!proxy && !strcasecompare("http_proxy", proxy_env)) { + /* There was no lowercase variable, try the uppercase version: */ + Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); + proxy = curl_getenv(proxy_env); + } + + envp = proxy_env; + if(!proxy) { +#ifdef USE_WEBSOCKETS + /* websocket proxy fallbacks */ + if(strcasecompare("ws_proxy", proxy_env)) { + proxy = curl_getenv("http_proxy"); + } + else if(strcasecompare("wss_proxy", proxy_env)) { + proxy = curl_getenv("https_proxy"); + if(!proxy) + proxy = curl_getenv("HTTPS_PROXY"); + } + if(!proxy) { +#endif + envp = (char *)"all_proxy"; + proxy = curl_getenv(envp); /* default proxy to use */ + if(!proxy) { + envp = (char *)"ALL_PROXY"; + proxy = curl_getenv(envp); + } +#ifdef USE_WEBSOCKETS + } +#endif + } + if(proxy) + infof(data, "Uses proxy env variable %s == '%s'", envp, proxy); + + return proxy; +} +#endif /* CURL_DISABLE_HTTP */ + +/* + * If this is supposed to use a proxy, we need to figure out the proxy + * host name, so that we can reuse an existing connection + * that may exist registered to the same proxy host. + */ +static CURLcode parse_proxy(struct Curl_easy *data, + struct connectdata *conn, char *proxy, + curl_proxytype proxytype) +{ + char *portptr = NULL; + int port = -1; + char *proxyuser = NULL; + char *proxypasswd = NULL; + char *host = NULL; + bool sockstype; + CURLUcode uc; + struct proxy_info *proxyinfo; + CURLU *uhp = curl_url(); + CURLcode result = CURLE_OK; + char *scheme = NULL; +#ifdef USE_UNIX_SOCKETS + char *path = NULL; + bool is_unix_proxy = FALSE; +#endif + + + if(!uhp) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + /* When parsing the proxy, allowing non-supported schemes since we have + these made up ones for proxies. Guess scheme for URLs without it. */ + uc = curl_url_set(uhp, CURLUPART_URL, proxy, + CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME); + if(!uc) { + /* parsed okay as a URL */ + uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0); + if(uc) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + if(strcasecompare("https", scheme)) { + if(proxytype != CURLPROXY_HTTPS2) + proxytype = CURLPROXY_HTTPS; + else + proxytype = CURLPROXY_HTTPS2; + } + else if(strcasecompare("socks5h", scheme)) + proxytype = CURLPROXY_SOCKS5_HOSTNAME; + else if(strcasecompare("socks5", scheme)) + proxytype = CURLPROXY_SOCKS5; + else if(strcasecompare("socks4a", scheme)) + proxytype = CURLPROXY_SOCKS4A; + else if(strcasecompare("socks4", scheme) || + strcasecompare("socks", scheme)) + proxytype = CURLPROXY_SOCKS4; + else if(strcasecompare("http", scheme)) + ; /* leave it as HTTP or HTTP/1.0 */ + else { + /* Any other xxx:// reject! */ + failf(data, "Unsupported proxy scheme for \'%s\'", proxy); + result = CURLE_COULDNT_CONNECT; + goto error; + } + } + else { + failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy, + curl_url_strerror(uc)); + result = CURLE_COULDNT_RESOLVE_PROXY; + goto error; + } + +#ifdef USE_SSL + if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY)) +#endif + if(IS_HTTPS_PROXY(proxytype)) { + failf(data, "Unsupported proxy \'%s\', libcurl is built without the " + "HTTPS-proxy support.", proxy); + result = CURLE_NOT_BUILT_IN; + goto error; + } + + sockstype = + proxytype == CURLPROXY_SOCKS5_HOSTNAME || + proxytype == CURLPROXY_SOCKS5 || + proxytype == CURLPROXY_SOCKS4A || + proxytype == CURLPROXY_SOCKS4; + + proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy; + proxyinfo->proxytype = (unsigned char)proxytype; + + /* Is there a username and password given in this proxy url? */ + uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE); + if(uc && (uc != CURLUE_NO_USER)) + goto error; + uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE); + if(uc && (uc != CURLUE_NO_PASSWORD)) + goto error; + + if(proxyuser || proxypasswd) { + Curl_safefree(proxyinfo->user); + proxyinfo->user = proxyuser; + result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser); + proxyuser = NULL; + if(result) + goto error; + Curl_safefree(proxyinfo->passwd); + if(!proxypasswd) { + proxypasswd = strdup(""); + if(!proxypasswd) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + } + proxyinfo->passwd = proxypasswd; + result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd); + proxypasswd = NULL; + if(result) + goto error; + conn->bits.proxy_user_passwd = TRUE; /* enable it */ + } + + (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0); + + if(portptr) { + port = (int)strtol(portptr, NULL, 10); + free(portptr); + } + else { + if(data->set.proxyport) + /* None given in the proxy string, then get the default one if it is + given */ + port = (int)data->set.proxyport; + else { + if(IS_HTTPS_PROXY(proxytype)) + port = CURL_DEFAULT_HTTPS_PROXY_PORT; + else + port = CURL_DEFAULT_PROXY_PORT; + } + } + if(port >= 0) { + proxyinfo->port = port; + if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc) + conn->port = port; + } + + /* now, clone the proxy host name */ + uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE); + if(uc) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } +#ifdef USE_UNIX_SOCKETS + if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) { + uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE); + if(uc) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + /* path will be "/", if no path was found */ + if(strcmp("/", path)) { + is_unix_proxy = TRUE; + free(host); + host = aprintf(UNIX_SOCKET_PREFIX"%s", path); + if(!host) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + Curl_safefree(proxyinfo->host.rawalloc); + proxyinfo->host.rawalloc = host; + proxyinfo->host.name = host; + host = NULL; + } + } + + if(!is_unix_proxy) { +#endif + Curl_safefree(proxyinfo->host.rawalloc); + proxyinfo->host.rawalloc = host; + if(host[0] == '[') { + /* this is a numerical IPv6, strip off the brackets */ + size_t len = strlen(host); + host[len-1] = 0; /* clear the trailing bracket */ + host++; + zonefrom_url(uhp, data, conn); + } + proxyinfo->host.name = host; + host = NULL; +#ifdef USE_UNIX_SOCKETS + } +#endif + +error: + free(proxyuser); + free(proxypasswd); + free(host); + free(scheme); +#ifdef USE_UNIX_SOCKETS + free(path); +#endif + curl_url_cleanup(uhp); + return result; +} + +/* + * Extract the user and password from the authentication string + */ +static CURLcode parse_proxy_auth(struct Curl_easy *data, + struct connectdata *conn) +{ + const char *proxyuser = data->state.aptr.proxyuser ? + data->state.aptr.proxyuser : ""; + const char *proxypasswd = data->state.aptr.proxypasswd ? + data->state.aptr.proxypasswd : ""; + CURLcode result = Curl_urldecode(proxyuser, 0, &conn->http_proxy.user, NULL, + REJECT_ZERO); + if(!result) + result = Curl_setstropt(&data->state.aptr.proxyuser, + conn->http_proxy.user); + if(!result) + result = Curl_urldecode(proxypasswd, 0, &conn->http_proxy.passwd, + NULL, REJECT_ZERO); + if(!result) + result = Curl_setstropt(&data->state.aptr.proxypasswd, + conn->http_proxy.passwd); + return result; +} + +/* create_conn helper to parse and init proxy values. to be called after unix + socket init but before any proxy vars are evaluated. */ +static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data, + struct connectdata *conn) +{ + char *proxy = NULL; + char *socksproxy = NULL; + char *no_proxy = NULL; + CURLcode result = CURLE_OK; + bool spacesep = FALSE; + + /************************************************************* + * Extract the user and password from the authentication string + *************************************************************/ + if(conn->bits.proxy_user_passwd) { + result = parse_proxy_auth(data, conn); + if(result) + goto out; + } + + /************************************************************* + * Detect what (if any) proxy to use + *************************************************************/ + if(data->set.str[STRING_PROXY]) { + proxy = strdup(data->set.str[STRING_PROXY]); + /* if global proxy is set, this is it */ + if(!proxy) { + failf(data, "memory shortage"); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + + if(data->set.str[STRING_PRE_PROXY]) { + socksproxy = strdup(data->set.str[STRING_PRE_PROXY]); + /* if global socks proxy is set, this is it */ + if(!socksproxy) { + failf(data, "memory shortage"); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + + if(!data->set.str[STRING_NOPROXY]) { + const char *p = "no_proxy"; + no_proxy = curl_getenv(p); + if(!no_proxy) { + p = "NO_PROXY"; + no_proxy = curl_getenv(p); + } + if(no_proxy) { + infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy); + } + } + + if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? + data->set.str[STRING_NOPROXY] : no_proxy, + &spacesep)) { + Curl_safefree(proxy); + Curl_safefree(socksproxy); + } +#ifndef CURL_DISABLE_HTTP + else if(!proxy && !socksproxy) + /* if the host is not in the noproxy list, detect proxy. */ + proxy = detect_proxy(data, conn); +#endif /* CURL_DISABLE_HTTP */ + if(spacesep) + infof(data, "space-separated NOPROXY patterns are deprecated"); + + Curl_safefree(no_proxy); + +#ifdef USE_UNIX_SOCKETS + /* For the time being do not mix proxy and unix domain sockets. See #1274 */ + if(proxy && conn->unix_domain_socket) { + free(proxy); + proxy = NULL; + } +#endif + + if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { + free(proxy); /* Don't bother with an empty proxy string or if the + protocol doesn't work with network */ + proxy = NULL; + } + if(socksproxy && (!*socksproxy || + (conn->handler->flags & PROTOPT_NONETWORK))) { + free(socksproxy); /* Don't bother with an empty socks proxy string or if + the protocol doesn't work with network */ + socksproxy = NULL; + } + + /*********************************************************************** + * If this is supposed to use a proxy, we need to figure out the proxy host + * name, proxy type and port number, so that we can reuse an existing + * connection that may exist registered to the same proxy host. + ***********************************************************************/ + if(proxy || socksproxy) { + curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype; + if(proxy) { + result = parse_proxy(data, conn, proxy, ptype); + Curl_safefree(proxy); /* parse_proxy copies the proxy string */ + if(result) + goto out; + } + + if(socksproxy) { + result = parse_proxy(data, conn, socksproxy, ptype); + /* parse_proxy copies the socks proxy string */ + Curl_safefree(socksproxy); + if(result) + goto out; + } + + if(conn->http_proxy.host.rawalloc) { +#ifdef CURL_DISABLE_HTTP + /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */ + result = CURLE_UNSUPPORTED_PROTOCOL; + goto out; +#else + /* force this connection's protocol to become HTTP if compatible */ + if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) { + if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) && + !conn->bits.tunnel_proxy) + conn->handler = &Curl_handler_http; + else + /* if not converting to HTTP over the proxy, enforce tunneling */ + conn->bits.tunnel_proxy = TRUE; + } + conn->bits.httpproxy = TRUE; +#endif + } + else { + conn->bits.httpproxy = FALSE; /* not an HTTP proxy */ + conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ + } + + if(conn->socks_proxy.host.rawalloc) { + if(!conn->http_proxy.host.rawalloc) { + /* once a socks proxy */ + if(!conn->socks_proxy.user) { + conn->socks_proxy.user = conn->http_proxy.user; + conn->http_proxy.user = NULL; + Curl_safefree(conn->socks_proxy.passwd); + conn->socks_proxy.passwd = conn->http_proxy.passwd; + conn->http_proxy.passwd = NULL; + } + } + conn->bits.socksproxy = TRUE; + } + else + conn->bits.socksproxy = FALSE; /* not a socks proxy */ + } + else { + conn->bits.socksproxy = FALSE; + conn->bits.httpproxy = FALSE; + } + conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy; + + if(!conn->bits.proxy) { + /* we aren't using the proxy after all... */ + conn->bits.proxy = FALSE; + conn->bits.httpproxy = FALSE; + conn->bits.socksproxy = FALSE; + conn->bits.proxy_user_passwd = FALSE; + conn->bits.tunnel_proxy = FALSE; + /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need + to signal that CURLPROXY_HTTPS is not used for this connection */ + conn->http_proxy.proxytype = CURLPROXY_HTTP; + } + +out: + + free(socksproxy); + free(proxy); + return result; +} +#endif /* CURL_DISABLE_PROXY */ + +/* + * Curl_parse_login_details() + * + * This is used to parse a login string for user name, password and options in + * the following formats: + * + * user + * user:password + * user:password;options + * user;options + * user;options:password + * :password + * :password;options + * ;options + * ;options:password + * + * Parameters: + * + * login [in] - The login string. + * len [in] - The length of the login string. + * userp [in/out] - The address where a pointer to newly allocated memory + * holding the user will be stored upon completion. + * passwdp [in/out] - The address where a pointer to newly allocated memory + * holding the password will be stored upon completion. + * optionsp [in/out] - The address where a pointer to newly allocated memory + * holding the options will be stored upon completion. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_parse_login_details(const char *login, const size_t len, + char **userp, char **passwdp, + char **optionsp) +{ + CURLcode result = CURLE_OK; + char *ubuf = NULL; + char *pbuf = NULL; + char *obuf = NULL; + const char *psep = NULL; + const char *osep = NULL; + size_t ulen; + size_t plen; + size_t olen; + + /* Attempt to find the password separator */ + if(passwdp) + psep = memchr(login, ':', len); + + /* Attempt to find the options separator */ + if(optionsp) + osep = memchr(login, ';', len); + + /* Calculate the portion lengths */ + ulen = (psep ? + (size_t)(osep && psep > osep ? osep - login : psep - login) : + (osep ? (size_t)(osep - login) : len)); + plen = (psep ? + (osep && osep > psep ? (size_t)(osep - psep) : + (size_t)(login + len - psep)) - 1 : 0); + olen = (osep ? + (psep && psep > osep ? (size_t)(psep - osep) : + (size_t)(login + len - osep)) - 1 : 0); + + /* Allocate the user portion buffer, which can be zero length */ + if(userp) { + ubuf = malloc(ulen + 1); + if(!ubuf) + result = CURLE_OUT_OF_MEMORY; + } + + /* Allocate the password portion buffer */ + if(!result && passwdp && psep) { + pbuf = malloc(plen + 1); + if(!pbuf) { + free(ubuf); + result = CURLE_OUT_OF_MEMORY; + } + } + + /* Allocate the options portion buffer */ + if(!result && optionsp && olen) { + obuf = malloc(olen + 1); + if(!obuf) { + free(pbuf); + free(ubuf); + result = CURLE_OUT_OF_MEMORY; + } + } + + if(!result) { + /* Store the user portion if necessary */ + if(ubuf) { + memcpy(ubuf, login, ulen); + ubuf[ulen] = '\0'; + Curl_safefree(*userp); + *userp = ubuf; + } + + /* Store the password portion if necessary */ + if(pbuf) { + memcpy(pbuf, psep + 1, plen); + pbuf[plen] = '\0'; + Curl_safefree(*passwdp); + *passwdp = pbuf; + } + + /* Store the options portion if necessary */ + if(obuf) { + memcpy(obuf, osep + 1, olen); + obuf[olen] = '\0'; + Curl_safefree(*optionsp); + *optionsp = obuf; + } + } + + return result; +} + +/************************************************************* + * Figure out the remote port number and fix it in the URL + * + * No matter if we use a proxy or not, we have to figure out the remote + * port number of various reasons. + * + * The port number embedded in the URL is replaced, if necessary. + *************************************************************/ +static CURLcode parse_remote_port(struct Curl_easy *data, + struct connectdata *conn) +{ + + if(data->set.use_port && data->state.allow_port) { + /* if set, we use this instead of the port possibly given in the URL */ + char portbuf[16]; + CURLUcode uc; + conn->remote_port = data->set.use_port; + msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port); + uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0); + if(uc) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* + * Override the login details from the URL with that in the CURLOPT_USERPWD + * option or a .netrc file, if applicable. + */ +static CURLcode override_login(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLUcode uc; + char **userp = &conn->user; + char **passwdp = &conn->passwd; + char **optionsp = &conn->options; + + if(data->set.str[STRING_OPTIONS]) { + free(*optionsp); + *optionsp = strdup(data->set.str[STRING_OPTIONS]); + if(!*optionsp) + return CURLE_OUT_OF_MEMORY; + } + +#ifndef CURL_DISABLE_NETRC + if(data->set.use_netrc == CURL_NETRC_REQUIRED) { + Curl_safefree(*userp); + Curl_safefree(*passwdp); + } + conn->bits.netrc = FALSE; + if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) { + int ret; + bool url_provided = FALSE; + + if(data->state.aptr.user) { + /* there was a user name in the URL. Use the URL decoded version */ + userp = &data->state.aptr.user; + url_provided = TRUE; + } + + ret = Curl_parsenetrc(conn->host.name, + userp, passwdp, + data->set.str[STRING_NETRC_FILE]); + if(ret > 0) { + infof(data, "Couldn't find host %s in the %s file; using defaults", + conn->host.name, + (data->set.str[STRING_NETRC_FILE] ? + data->set.str[STRING_NETRC_FILE] : ".netrc")); + } + else if(ret < 0) { + failf(data, ".netrc parser error"); + return CURLE_READ_ERROR; + } + else { + /* set bits.netrc TRUE to remember that we got the name from a .netrc + file, so that it is safe to use even if we followed a Location: to a + different host or similar. */ + conn->bits.netrc = TRUE; + } + if(url_provided) { + Curl_safefree(conn->user); + conn->user = strdup(*userp); + if(!conn->user) + return CURLE_OUT_OF_MEMORY; + } + /* no user was set but a password, set a blank user */ + if(!*userp && *passwdp) { + *userp = strdup(""); + if(!*userp) + return CURLE_OUT_OF_MEMORY; + } + } +#endif + + /* for updated strings, we update them in the URL */ + if(*userp) { + CURLcode result; + if(data->state.aptr.user != *userp) { + /* nothing to do then */ + result = Curl_setstropt(&data->state.aptr.user, *userp); + if(result) + return result; + } + } + if(data->state.aptr.user) { + uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user, + CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + if(!*userp) { + *userp = strdup(data->state.aptr.user); + if(!*userp) + return CURLE_OUT_OF_MEMORY; + } + } + if(*passwdp) { + CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp); + if(result) + return result; + } + if(data->state.aptr.passwd) { + uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, + data->state.aptr.passwd, CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + if(!*passwdp) { + *passwdp = strdup(data->state.aptr.passwd); + if(!*passwdp) + return CURLE_OUT_OF_MEMORY; + } + } + + return CURLE_OK; +} + +/* + * Set the login details so they're available in the connection + */ +static CURLcode set_login(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + const char *setuser = CURL_DEFAULT_USER; + const char *setpasswd = CURL_DEFAULT_PASSWORD; + + /* If our protocol needs a password and we have none, use the defaults */ + if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user) + ; + else { + setuser = ""; + setpasswd = ""; + } + /* Store the default user */ + if(!conn->user) { + conn->user = strdup(setuser); + if(!conn->user) + return CURLE_OUT_OF_MEMORY; + } + + /* Store the default password */ + if(!conn->passwd) { + conn->passwd = strdup(setpasswd); + if(!conn->passwd) + result = CURLE_OUT_OF_MEMORY; + } + + return result; +} + +/* + * Parses a "host:port" string to connect to. + * The hostname and the port may be empty; in this case, NULL is returned for + * the hostname and -1 for the port. + */ +static CURLcode parse_connect_to_host_port(struct Curl_easy *data, + const char *host, + char **hostname_result, + int *port_result) +{ + char *host_dup; + char *hostptr; + char *host_portno; + char *portptr; + int port = -1; + CURLcode result = CURLE_OK; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + *hostname_result = NULL; + *port_result = -1; + + if(!host || !*host) + return CURLE_OK; + + host_dup = strdup(host); + if(!host_dup) + return CURLE_OUT_OF_MEMORY; + + hostptr = host_dup; + + /* start scanning for port number at this point */ + portptr = hostptr; + + /* detect and extract RFC6874-style IPv6-addresses */ + if(*hostptr == '[') { +#ifdef ENABLE_IPV6 + char *ptr = ++hostptr; /* advance beyond the initial bracket */ + while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) + ptr++; + if(*ptr == '%') { + /* There might be a zone identifier */ + if(strncmp("%25", ptr, 3)) + infof(data, "Please URL encode %% as %%25, see RFC 6874."); + ptr++; + /* Allow unreserved characters as defined in RFC 3986 */ + while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || + (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) + ptr++; + } + if(*ptr == ']') + /* yeps, it ended nicely with a bracket as well */ + *ptr++ = '\0'; + else + infof(data, "Invalid IPv6 address format"); + portptr = ptr; + /* Note that if this didn't end with a bracket, we still advanced the + * hostptr first, but I can't see anything wrong with that as no host + * name nor a numeric can legally start with a bracket. + */ +#else + failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in"); + result = CURLE_NOT_BUILT_IN; + goto error; +#endif + } + + /* Get port number off server.com:1080 */ + host_portno = strchr(portptr, ':'); + if(host_portno) { + char *endp = NULL; + *host_portno = '\0'; /* cut off number from host name */ + host_portno++; + if(*host_portno) { + long portparse = strtol(host_portno, &endp, 10); + if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { + failf(data, "No valid port number in connect to host string (%s)", + host_portno); + result = CURLE_SETOPT_OPTION_SYNTAX; + goto error; + } + else + port = (int)portparse; /* we know it will fit */ + } + } + + /* now, clone the cleaned host name */ + DEBUGASSERT(hostptr); + *hostname_result = strdup(hostptr); + if(!*hostname_result) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + *port_result = port; + +error: + free(host_dup); + return result; +} + +/* + * Parses one "connect to" string in the form: + * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". + */ +static CURLcode parse_connect_to_string(struct Curl_easy *data, + struct connectdata *conn, + const char *conn_to_host, + char **host_result, + int *port_result) +{ + CURLcode result = CURLE_OK; + const char *ptr = conn_to_host; + int host_match = FALSE; + int port_match = FALSE; + + *host_result = NULL; + *port_result = -1; + + if(*ptr == ':') { + /* an empty hostname always matches */ + host_match = TRUE; + ptr++; + } + else { + /* check whether the URL's hostname matches */ + size_t hostname_to_match_len; + char *hostname_to_match = aprintf("%s%s%s", + conn->bits.ipv6_ip ? "[" : "", + conn->host.name, + conn->bits.ipv6_ip ? "]" : ""); + if(!hostname_to_match) + return CURLE_OUT_OF_MEMORY; + hostname_to_match_len = strlen(hostname_to_match); + host_match = strncasecompare(ptr, hostname_to_match, + hostname_to_match_len); + free(hostname_to_match); + ptr += hostname_to_match_len; + + host_match = host_match && *ptr == ':'; + ptr++; + } + + if(host_match) { + if(*ptr == ':') { + /* an empty port always matches */ + port_match = TRUE; + ptr++; + } + else { + /* check whether the URL's port matches */ + char *ptr_next = strchr(ptr, ':'); + if(ptr_next) { + char *endp = NULL; + long port_to_match = strtol(ptr, &endp, 10); + if((endp == ptr_next) && (port_to_match == conn->remote_port)) { + port_match = TRUE; + ptr = ptr_next + 1; + } + } + } + } + + if(host_match && port_match) { + /* parse the hostname and port to connect to */ + result = parse_connect_to_host_port(data, ptr, host_result, port_result); + } + + return result; +} + +/* + * Processes all strings in the "connect to" slist, and uses the "connect + * to host" and "connect to port" of the first string that matches. + */ +static CURLcode parse_connect_to_slist(struct Curl_easy *data, + struct connectdata *conn, + struct curl_slist *conn_to_host) +{ + CURLcode result = CURLE_OK; + char *host = NULL; + int port = -1; + + while(conn_to_host && !host && port == -1) { + result = parse_connect_to_string(data, conn, conn_to_host->data, + &host, &port); + if(result) + return result; + + if(host && *host) { + conn->conn_to_host.rawalloc = host; + conn->conn_to_host.name = host; + conn->bits.conn_to_host = TRUE; + + infof(data, "Connecting to hostname: %s", host); + } + else { + /* no "connect to host" */ + conn->bits.conn_to_host = FALSE; + Curl_safefree(host); + } + + if(port >= 0) { + conn->conn_to_port = port; + conn->bits.conn_to_port = TRUE; + infof(data, "Connecting to port: %d", port); + } + else { + /* no "connect to port" */ + conn->bits.conn_to_port = FALSE; + port = -1; + } + + conn_to_host = conn_to_host->next; + } + +#ifndef CURL_DISABLE_ALTSVC + if(data->asi && !host && (port == -1) && + ((conn->handler->protocol == CURLPROTO_HTTPS) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_ALTSVC_HTTP") +#else + 0 +#endif + )) { + /* no connect_to match, try alt-svc! */ + enum alpnid srcalpnid; + bool hit; + struct altsvc *as; + const int allowed_versions = ( ALPN_h1 +#ifdef USE_HTTP2 + | ALPN_h2 +#endif +#ifdef ENABLE_QUIC + | ALPN_h3 +#endif + ) & data->asi->flags; + + host = conn->host.rawalloc; +#ifdef USE_HTTP2 + /* with h2 support, check that first */ + srcalpnid = ALPN_h2; + hit = Curl_altsvc_lookup(data->asi, + srcalpnid, host, conn->remote_port, /* from */ + &as /* to */, + allowed_versions); + if(!hit) +#endif + { + srcalpnid = ALPN_h1; + hit = Curl_altsvc_lookup(data->asi, + srcalpnid, host, conn->remote_port, /* from */ + &as /* to */, + allowed_versions); + } + if(hit) { + char *hostd = strdup((char *)as->dst.host); + if(!hostd) + return CURLE_OUT_OF_MEMORY; + conn->conn_to_host.rawalloc = hostd; + conn->conn_to_host.name = hostd; + conn->bits.conn_to_host = TRUE; + conn->conn_to_port = as->dst.port; + conn->bits.conn_to_port = TRUE; + conn->bits.altused = TRUE; + infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d", + Curl_alpnid2str(srcalpnid), host, conn->remote_port, + Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port); + if(srcalpnid != as->dst.alpnid) { + /* protocol version switch */ + switch(as->dst.alpnid) { + case ALPN_h1: + conn->httpversion = 11; + break; + case ALPN_h2: + conn->httpversion = 20; + break; + case ALPN_h3: + conn->transport = TRNSPRT_QUIC; + conn->httpversion = 30; + break; + default: /* shouldn't be possible */ + break; + } + } + } + } +#endif + + return result; +} + +#ifdef USE_UNIX_SOCKETS +static CURLcode resolve_unix(struct Curl_easy *data, + struct connectdata *conn, + char *unix_path) +{ + struct Curl_dns_entry *hostaddr = NULL; + bool longpath = FALSE; + + DEBUGASSERT(unix_path); + DEBUGASSERT(conn->dns_entry == NULL); + + /* Unix domain sockets are local. The host gets ignored, just use the + * specified domain socket address. Do not cache "DNS entries". There is + * no DNS involved and we already have the filesystem path available. */ + hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); + if(!hostaddr) + return CURLE_OUT_OF_MEMORY; + + hostaddr->addr = Curl_unix2addr(unix_path, &longpath, + conn->bits.abstract_unix_socket); + if(!hostaddr->addr) { + if(longpath) + /* Long paths are not supported for now */ + failf(data, "Unix socket path too long: '%s'", unix_path); + free(hostaddr); + return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY; + } + + hostaddr->inuse++; + conn->dns_entry = hostaddr; + return CURLE_OK; +} +#endif + +#ifndef CURL_DISABLE_PROXY +static CURLcode resolve_proxy(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + struct Curl_dns_entry *hostaddr = NULL; + struct hostname *host; + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + int rc; + + DEBUGASSERT(conn->dns_entry == NULL); + + host = conn->bits.socksproxy ? &conn->socks_proxy.host : + &conn->http_proxy.host; + + conn->hostname_resolve = strdup(host->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + + rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, + &hostaddr, timeout_ms); + conn->dns_entry = hostaddr; + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + else if(rc == CURLRESOLV_TIMEDOUT) + return CURLE_OPERATION_TIMEDOUT; + else if(!hostaddr) { + failf(data, "Couldn't resolve proxy '%s'", host->dispname); + return CURLE_COULDNT_RESOLVE_PROXY; + } + + return CURLE_OK; +} +#endif + +static CURLcode resolve_host(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + struct Curl_dns_entry *hostaddr = NULL; + struct hostname *connhost; + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + int rc; + + DEBUGASSERT(conn->dns_entry == NULL); + + connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; + + /* If not connecting via a proxy, extract the port from the URL, if it is + * there, thus overriding any defaults that might have been set above. */ + conn->port = conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; + + /* Resolve target host right on */ + conn->hostname_resolve = strdup(connhost->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + + rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, + &hostaddr, timeout_ms); + conn->dns_entry = hostaddr; + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + else if(rc == CURLRESOLV_TIMEDOUT) { + failf(data, "Failed to resolve host '%s' with timeout after %" + CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname, + Curl_timediff(Curl_now(), data->progress.t_startsingle)); + return CURLE_OPERATION_TIMEDOUT; + } + else if(!hostaddr) { + failf(data, "Could not resolve host: %s", connhost->dispname); + return CURLE_COULDNT_RESOLVE_HOST; + } + + return CURLE_OK; +} + +/* Perform a fresh resolve */ +static CURLcode resolve_fresh(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ +#ifdef USE_UNIX_SOCKETS + char *unix_path = conn->unix_domain_socket; + +#ifndef CURL_DISABLE_PROXY + if(!unix_path && conn->socks_proxy.host.name && + !strncmp(UNIX_SOCKET_PREFIX"/", + conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) + unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; +#endif + + if(unix_path) { + conn->transport = TRNSPRT_UNIX; + return resolve_unix(data, conn, unix_path); + } +#endif + +#ifndef CURL_DISABLE_PROXY + if(CONN_IS_PROXIED(conn)) + return resolve_proxy(data, conn, async); +#endif + + return resolve_host(data, conn, async); +} + +/************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ +static CURLcode resolve_server(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + DEBUGASSERT(conn); + DEBUGASSERT(data); + + /* Resolve the name of the server or proxy */ + if(conn->bits.reuse) { + /* We're reusing the connection - no need to resolve anything, and + idnconvert_hostname() was called already in create_conn() for the reuse + case. */ + *async = FALSE; + return CURLE_OK; + } + + return resolve_fresh(data, conn, async); +} + +/* + * Cleanup the connection `temp`, just allocated for `data`, before using the + * previously `existing` one for `data`. All relevant info is copied over + * and `temp` is freed. + */ +static void reuse_conn(struct Curl_easy *data, + struct connectdata *temp, + struct connectdata *existing) +{ + /* get the user+password information from the temp struct since it may + * be new for this request even when we reuse an existing connection */ + if(temp->user) { + /* use the new user name and password though */ + Curl_safefree(existing->user); + Curl_safefree(existing->passwd); + existing->user = temp->user; + existing->passwd = temp->passwd; + temp->user = NULL; + temp->passwd = NULL; + } + +#ifndef CURL_DISABLE_PROXY + existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd; + if(existing->bits.proxy_user_passwd) { + /* use the new proxy user name and proxy password though */ + Curl_safefree(existing->http_proxy.user); + Curl_safefree(existing->socks_proxy.user); + Curl_safefree(existing->http_proxy.passwd); + Curl_safefree(existing->socks_proxy.passwd); + existing->http_proxy.user = temp->http_proxy.user; + existing->socks_proxy.user = temp->socks_proxy.user; + existing->http_proxy.passwd = temp->http_proxy.passwd; + existing->socks_proxy.passwd = temp->socks_proxy.passwd; + temp->http_proxy.user = NULL; + temp->socks_proxy.user = NULL; + temp->http_proxy.passwd = NULL; + temp->socks_proxy.passwd = NULL; + } +#endif + + /* Finding a connection for reuse in the cache matches, among other + * things on the "remote-relevant" hostname. This is not necessarily + * the authority of the URL, e.g. conn->host. For example: + * - we use a proxy (not tunneling). we want to send all requests + * that use the same proxy on this connection. + * - we have a "connect-to" setting that may redirect the hostname of + * a new request to the same remote endpoint of an existing conn. + * We want to reuse an existing conn to the remote endpoint. + * Since connection reuse does not match on conn->host necessarily, we + * switch `existing` conn to `temp` conn's host settings. + * TODO: is this correct in the case of TLS connections that have + * used the original hostname in SNI to negotiate? Do we send + * requests for another host through the different SNI? + */ + Curl_free_idnconverted_hostname(&existing->host); + Curl_free_idnconverted_hostname(&existing->conn_to_host); + Curl_safefree(existing->host.rawalloc); + Curl_safefree(existing->conn_to_host.rawalloc); + existing->host = temp->host; + temp->host.rawalloc = NULL; + temp->host.encalloc = NULL; + existing->conn_to_host = temp->conn_to_host; + temp->conn_to_host.rawalloc = NULL; + existing->conn_to_port = temp->conn_to_port; + existing->remote_port = temp->remote_port; + Curl_safefree(existing->hostname_resolve); + + existing->hostname_resolve = temp->hostname_resolve; + temp->hostname_resolve = NULL; + + /* reuse init */ + existing->bits.reuse = TRUE; /* yes, we're reusing here */ + + conn_free(data, temp); +} + +/** + * create_conn() sets up a new connectdata struct, or reuses an already + * existing one, and resolves host name. + * + * if this function returns CURLE_OK and *async is set to TRUE, the resolve + * response will be coming asynchronously. If *async is FALSE, the name is + * already resolved. + * + * @param data The sessionhandle pointer + * @param in_connect is set to the next connection data pointer + * @param async is set TRUE when an async DNS resolution is pending + * @see Curl_setup_conn() + * + */ + +static CURLcode create_conn(struct Curl_easy *data, + struct connectdata **in_connect, + bool *async) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn; + struct connectdata *existing = NULL; + bool reuse; + bool connections_available = TRUE; + bool force_reuse = FALSE; + bool waitpipe = FALSE; + size_t max_host_connections = Curl_multi_max_host_connections(data->multi); + size_t max_total_connections = Curl_multi_max_total_connections(data->multi); + + *async = FALSE; + *in_connect = NULL; + + /************************************************************* + * Check input data + *************************************************************/ + if(!data->state.url) { + result = CURLE_URL_MALFORMAT; + goto out; + } + + /* First, split up the current URL in parts so that we can use the + parts for checking against the already present connections. In order + to not have to modify everything at once, we allocate a temporary + connection data struct and fill in for comparison purposes. */ + conn = allocate_conn(data); + + if(!conn) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + /* We must set the return variable as soon as possible, so that our + parent can cleanup any possible allocs we may have done before + any failure */ + *in_connect = conn; + + result = parseurlandfillconn(data, conn); + if(result) + goto out; + + if(data->set.str[STRING_SASL_AUTHZID]) { + conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]); + if(!conn->sasl_authzid) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + + if(data->set.str[STRING_BEARER]) { + conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); + if(!conn->oauth_bearer) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + +#ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); + if(!conn->unix_domain_socket) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + conn->bits.abstract_unix_socket = data->set.abstract_unix_socket; + } +#endif + + /* After the unix socket init but before the proxy vars are used, parse and + initialize the proxy vars */ +#ifndef CURL_DISABLE_PROXY + result = create_conn_helper_init_proxy(data, conn); + if(result) + goto out; + + /************************************************************* + * If the protocol is using SSL and HTTP proxy is used, we set + * the tunnel_proxy bit. + *************************************************************/ + if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Figure out the remote port number and fix it in the URL + *************************************************************/ + result = parse_remote_port(data, conn); + if(result) + goto out; + + /* Check for overridden login details and set them accordingly so that + they are known when protocol->setup_connection is called! */ + result = override_login(data, conn); + if(result) + goto out; + + result = set_login(data, conn); /* default credentials */ + if(result) + goto out; + + /************************************************************* + * Process the "connect to" linked list of hostname/port mappings. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + result = parse_connect_to_slist(data, conn, data->set.connect_to); + if(result) + goto out; + + /************************************************************* + * IDN-convert the proxy hostnames + *************************************************************/ +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) { + result = Curl_idnconvert_hostname(&conn->http_proxy.host); + if(result) + return result; + } + if(conn->bits.socksproxy) { + result = Curl_idnconvert_hostname(&conn->socks_proxy.host); + if(result) + return result; + } +#endif + if(conn->bits.conn_to_host) { + result = Curl_idnconvert_hostname(&conn->conn_to_host); + if(result) + return result; + } + + /************************************************************* + * Check whether the host and the "connect to host" are equal. + * Do this after the hostnames have been IDN-converted. + *************************************************************/ + if(conn->bits.conn_to_host && + strcasecompare(conn->conn_to_host.name, conn->host.name)) { + conn->bits.conn_to_host = FALSE; + } + + /************************************************************* + * Check whether the port and the "connect to port" are equal. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { + conn->bits.conn_to_port = FALSE; + } + +#ifndef CURL_DISABLE_PROXY + /************************************************************* + * If the "connect to" feature is used with an HTTP proxy, + * we set the tunnel_proxy bit. + *************************************************************/ + if((conn->bits.conn_to_host || conn->bits.conn_to_port) && + conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Setup internals depending on protocol. Needs to be done after + * we figured out what/if proxy to use. + *************************************************************/ + result = setup_connection_internals(data, conn); + if(result) + goto out; + + /*********************************************************************** + * file: is a special case in that it doesn't need a network connection + ***********************************************************************/ +#ifndef CURL_DISABLE_FILE + if(conn->handler->flags & PROTOPT_NONETWORK) { + bool done; + /* this is supposed to be the connect function so we better at least check + that the file is present here! */ + DEBUGASSERT(conn->handler->connect_it); + Curl_persistconninfo(data, conn, NULL, -1); + result = conn->handler->connect_it(data, &done); + + /* Setup a "faked" transfer that'll do nothing */ + if(!result) { + Curl_attach_connection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) { + DEBUGASSERT(conn->handler->done); + /* we ignore the return code for the protocol-specific DONE */ + (void)conn->handler->done(data, result, FALSE); + goto out; + } + Curl_setup_transfer(data, -1, -1, FALSE, -1); + } + + /* since we skip do_init() */ + Curl_init_do(data, conn); + + goto out; + } +#endif + + /* Setup filter for network connections */ + conn->recv[FIRSTSOCKET] = Curl_conn_recv; + conn->send[FIRSTSOCKET] = Curl_conn_send; + conn->recv[SECONDARYSOCKET] = Curl_conn_recv; + conn->send[SECONDARYSOCKET] = Curl_conn_send; + conn->bits.tcp_fastopen = data->set.tcp_fastopen; + + /* Complete the easy's SSL configuration for connection cache matching */ + result = Curl_ssl_easy_config_complete(data); + if(result) + goto out; + + prune_dead_connections(data); + + /************************************************************* + * Check the current list of connections to see if we can + * reuse an already existing one or if we have to create a + * new one. + *************************************************************/ + + DEBUGASSERT(conn->user); + DEBUGASSERT(conn->passwd); + + /* reuse_fresh is TRUE if we are told to use a new connection by force, but + we only acknowledge this option if this is not a reused connection + already (which happens due to follow-location or during an HTTP + authentication phase). CONNECT_ONLY transfers also refuse reuse. */ + if((data->set.reuse_fresh && !data->state.followlocation) || + data->set.connect_only) + reuse = FALSE; + else + reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe); + + if(reuse) { + /* + * We already have a connection for this, we got the former connection in + * `existing` and thus we need to cleanup the one we just + * allocated before we can move along and use `existing`. + */ + reuse_conn(data, conn, existing); + conn = existing; + *in_connect = conn; + +#ifndef CURL_DISABLE_PROXY + infof(data, "Re-using existing connection with %s %s", + conn->bits.proxy?"proxy":"host", + conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : + conn->http_proxy.host.name ? conn->http_proxy.host.dispname : + conn->host.dispname); +#else + infof(data, "Re-using existing connection with host %s", + conn->host.dispname); +#endif + } + else { + /* We have decided that we want a new connection. However, we may not + be able to do that if we have reached the limit of how many + connections we are allowed to open. */ + + if(conn->handler->flags & PROTOPT_ALPN) { + /* The protocol wants it, so set the bits if enabled in the easy handle + (default) */ + if(data->set.ssl_enable_alpn) + conn->bits.tls_enable_alpn = TRUE; + } + + if(waitpipe) + /* There is a connection that *might* become usable for multiplexing + "soon", and we wait for that */ + connections_available = FALSE; + else { + /* this gets a lock on the conncache */ + struct connectbundle *bundle = + Curl_conncache_find_bundle(data, conn, data->state.conn_cache); + + if(max_host_connections > 0 && bundle && + (bundle->num_connections >= max_host_connections)) { + struct connectdata *conn_candidate; + + /* The bundle is full. Extract the oldest connection. */ + conn_candidate = Curl_conncache_extract_bundle(data, bundle); + CONNCACHE_UNLOCK(data); + + if(conn_candidate) + Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No more connections allowed to host: %zu", + max_host_connections); + connections_available = FALSE; + } + } + else + CONNCACHE_UNLOCK(data); + + } + + if(connections_available && + (max_total_connections > 0) && + (Curl_conncache_size(data) >= max_total_connections)) { + struct connectdata *conn_candidate; + + /* The cache is full. Let's see if we can kill a connection. */ + conn_candidate = Curl_conncache_extract_oldest(data); + if(conn_candidate) + Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No connections available in cache"); + connections_available = FALSE; + } + } + + if(!connections_available) { + infof(data, "No connections available."); + + conn_free(data, conn); + *in_connect = NULL; + + result = CURLE_NO_CONNECTION_AVAILABLE; + goto out; + } + else { + /* + * This is a brand new connection, so let's store it in the connection + * cache of ours! + */ + result = Curl_ssl_conn_config_init(data, conn); + if(result) { + DEBUGF(fprintf(stderr, "Error: init connection ssl config\n")); + goto out; + } + + Curl_attach_connection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + } + +#if defined(USE_NTLM) + /* If NTLM is requested in a part of this connection, make sure we don't + assume the state is fine as this is a fresh connection and NTLM is + connection based. */ + if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authhost.done) { + infof(data, "NTLM picked AND auth done set, clear picked"); + data->state.authhost.picked = CURLAUTH_NONE; + data->state.authhost.done = FALSE; + } + + if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authproxy.done) { + infof(data, "NTLM-proxy picked AND auth done set, clear picked"); + data->state.authproxy.picked = CURLAUTH_NONE; + data->state.authproxy.done = FALSE; + } +#endif + } + + /* Setup and init stuff before DO starts, in preparing for the transfer. */ + Curl_init_do(data, conn); + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) + goto out; + + /* Continue connectdata initialization here. */ + + /* + * Inherit the proper values from the urldata struct AFTER we have arranged + * the persistent connection stuff + */ + conn->seek_func = data->set.seek_func; + conn->seek_client = data->set.seek_client; + + /************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ + result = resolve_server(data, conn, async); + if(result) + goto out; + + /* Everything general done, inform filters that they need + * to prepare for a data transfer. + */ + result = Curl_conn_ev_data_setup(data); + +out: + return result; +} + +/* Curl_setup_conn() is called after the name resolve initiated in + * create_conn() is all done. + * + * Curl_setup_conn() also handles reused connections + */ +CURLcode Curl_setup_conn(struct Curl_easy *data, + bool *protocol_done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + Curl_pgrsTime(data, TIMER_NAMELOOKUP); + + if(conn->handler->flags & PROTOPT_NONETWORK) { + /* nothing to setup when not using a network */ + *protocol_done = TRUE; + return result; + } + +#ifndef CURL_DISABLE_PROXY + /* set proxy_connect_closed to false unconditionally already here since it + is used strictly to provide extra information to a parent function in the + case of proxy CONNECT failures and we must make sure we don't have it + lingering set from a previous invoke */ + conn->bits.proxy_connect_closed = FALSE; +#endif + +#ifdef CURL_DO_LINEEND_CONV + data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ +#endif /* CURL_DO_LINEEND_CONV */ + + /* set start time here for timeout purposes in the connect procedure, it + is later set again for the progress meter purpose */ + conn->now = Curl_now(); + if(!conn->bits.reuse) + result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry, + CURL_CF_SSL_DEFAULT); + /* not sure we need this flag to be passed around any more */ + *protocol_done = FALSE; + return result; +} + +CURLcode Curl_connect(struct Curl_easy *data, + bool *asyncp, + bool *protocol_done) +{ + CURLcode result; + struct connectdata *conn; + + *asyncp = FALSE; /* assume synchronous resolves by default */ + + /* init the single-transfer specific data */ + Curl_free_request_state(data); + memset(&data->req, 0, sizeof(struct SingleRequest)); + data->req.size = data->req.maxdownload = -1; + data->req.no_body = data->set.opt_no_body; + + /* call the stuff that needs to be called */ + result = create_conn(data, &conn, asyncp); + + if(!result) { + if(CONN_INUSE(conn) > 1) + /* multiplexed */ + *protocol_done = TRUE; + else if(!*asyncp) { + /* DNS resolution is done: that's either because this is a reused + connection, in which case DNS was unnecessary, or because DNS + really did finish already (synch resolver/fast async resolve) */ + result = Curl_setup_conn(data, protocol_done); + } + } + + if(result == CURLE_NO_CONNECTION_AVAILABLE) { + return result; + } + else if(result && conn) { + /* We're not allowed to return failure with memory left allocated in the + connectdata struct, free those here */ + Curl_detach_connection(data); + Curl_conncache_remove_conn(data, conn, TRUE); + Curl_disconnect(data, conn, TRUE); + } + + return result; +} + +/* + * Curl_init_do() inits the readwrite session. This is inited each time (in + * the DO function before the protocol-specific DO functions are invoked) for + * a transfer, sometimes multiple times on the same Curl_easy. Make sure + * nothing in here depends on stuff that are setup dynamically for the + * transfer. + * + * Allow this function to get called with 'conn' set to NULL. + */ + +CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) +{ + struct SingleRequest *k = &data->req; + + /* if this is a pushed stream, we need this: */ + CURLcode result = Curl_preconnect(data); + if(result) + return result; + + if(conn) { + conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to + use */ + /* if the protocol used doesn't support wildcards, switch it off */ + if(data->state.wildcardmatch && + !(conn->handler->flags & PROTOPT_WILDCARD)) + data->state.wildcardmatch = FALSE; + } + + data->state.done = FALSE; /* *_done() is not called yet */ + data->state.expect100header = FALSE; + + if(data->req.no_body) + /* in HTTP lingo, no body means using the HEAD request... */ + data->state.httpreq = HTTPREQ_HEAD; + + k->start = Curl_now(); /* start time */ + k->header = TRUE; /* assume header */ + k->bytecount = 0; + k->ignorebody = FALSE; + + Curl_client_cleanup(data); + Curl_speedinit(data); + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + + return CURLE_OK; +} + +#if defined(USE_HTTP2) || defined(USE_HTTP3) + +#ifdef USE_NGHTTP2 + +static void priority_remove_child(struct Curl_easy *parent, + struct Curl_easy *child) +{ + struct Curl_data_prio_node **pnext = &parent->set.priority.children; + struct Curl_data_prio_node *pnode = parent->set.priority.children; + + DEBUGASSERT(child->set.priority.parent == parent); + while(pnode && pnode->data != child) { + pnext = &pnode->next; + pnode = pnode->next; + } + + DEBUGASSERT(pnode); + if(pnode) { + *pnext = pnode->next; + free(pnode); + } + + child->set.priority.parent = 0; + child->set.priority.exclusive = FALSE; +} + +CURLcode Curl_data_priority_add_child(struct Curl_easy *parent, + struct Curl_easy *child, + bool exclusive) +{ + if(child->set.priority.parent) { + priority_remove_child(child->set.priority.parent, child); + } + + if(parent) { + struct Curl_data_prio_node **tail; + struct Curl_data_prio_node *pnode; + + pnode = calloc(1, sizeof(*pnode)); + if(!pnode) + return CURLE_OUT_OF_MEMORY; + pnode->data = child; + + if(parent->set.priority.children && exclusive) { + /* exclusive: move all existing children underneath the new child */ + struct Curl_data_prio_node *node = parent->set.priority.children; + while(node) { + node->data->set.priority.parent = child; + node = node->next; + } + + tail = &child->set.priority.children; + while(*tail) + tail = &(*tail)->next; + + DEBUGASSERT(!*tail); + *tail = parent->set.priority.children; + parent->set.priority.children = 0; + } + + tail = &parent->set.priority.children; + while(*tail) { + (*tail)->data->set.priority.exclusive = FALSE; + tail = &(*tail)->next; + } + + DEBUGASSERT(!*tail); + *tail = pnode; + } + + child->set.priority.parent = parent; + child->set.priority.exclusive = exclusive; + return CURLE_OK; +} + +#endif /* USE_NGHTTP2 */ + +#ifdef USE_NGHTTP2 +static void data_priority_cleanup(struct Curl_easy *data) +{ + while(data->set.priority.children) { + struct Curl_easy *tmp = data->set.priority.children->data; + priority_remove_child(data, tmp); + if(data->set.priority.parent) + Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE); + } + + if(data->set.priority.parent) + priority_remove_child(data->set.priority.parent, data); +} +#endif + +void Curl_data_priority_clear_state(struct Curl_easy *data) +{ + memset(&data->state.priority, 0, sizeof(data->state.priority)); +} + +#endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */ diff --git a/lib/url.h b/lib/url.h new file mode 100644 index 0000000..7c1a29b --- /dev/null +++ b/lib/url.h @@ -0,0 +1,81 @@ +#ifndef HEADER_CURL_URL_H +#define HEADER_CURL_URL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +/* + * Prototypes for library-wide functions provided by url.c + */ + +CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn); +CURLcode Curl_open(struct Curl_easy **curl); +CURLcode Curl_init_userdefined(struct Curl_easy *data); + +void Curl_freeset(struct Curl_easy *data); +CURLcode Curl_uc_to_curlcode(CURLUcode uc); +CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */ +CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect); +void Curl_disconnect(struct Curl_easy *data, + struct connectdata *, bool dead_connection); +CURLcode Curl_setup_conn(struct Curl_easy *data, + bool *protocol_done); +void Curl_free_request_state(struct Curl_easy *data); +CURLcode Curl_parse_login_details(const char *login, const size_t len, + char **userptr, char **passwdptr, + char **optionsptr); + +/* Get protocol handler for a URI scheme + * @param scheme URI scheme, case-insensitive + * @return NULL of handler not found + */ +const struct Curl_handler *Curl_get_scheme_handler(const char *scheme); +const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, + size_t len); + +#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ +#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless + specified */ + +#ifdef CURL_DISABLE_VERBOSE_STRINGS +#define Curl_verboseconnect(x,y) Curl_nop_stmt +#else +void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn); +#endif + +#if defined(USE_HTTP2) || defined(USE_HTTP3) +void Curl_data_priority_clear_state(struct Curl_easy *data); +#else +#define Curl_data_priority_clear_state(x) +#endif /* !(defined(USE_HTTP2) || defined(USE_HTTP3)) */ + +#ifdef USE_NGHTTP2 +CURLcode Curl_data_priority_add_child(struct Curl_easy *parent, + struct Curl_easy *child, + bool exclusive); +#else +#define Curl_data_priority_add_child(x, y, z) CURLE_NOT_BUILT_IN +#endif + +#endif /* HEADER_CURL_URL_H */ diff --git a/lib/urlapi-int.h b/lib/urlapi-int.h new file mode 100644 index 0000000..d6e240a --- /dev/null +++ b/lib/urlapi-int.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_URLAPI_INT_H +#define HEADER_CURL_URLAPI_INT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, + bool guess_scheme); + +CURLUcode Curl_url_set_authority(CURLU *u, const char *authority, + unsigned int flags); + +#ifdef DEBUGBUILD +CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, + bool has_scheme); +#endif + +#endif /* HEADER_CURL_URLAPI_INT_H */ diff --git a/lib/urlapi.c b/lib/urlapi.c new file mode 100644 index 0000000..3cd0362 --- /dev/null +++ b/lib/urlapi.c @@ -0,0 +1,1974 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "urldata.h" +#include "urlapi-int.h" +#include "strcase.h" +#include "url.h" +#include "escape.h" +#include "curl_ctype.h" +#include "inet_pton.h" +#include "inet_ntop.h" +#include "strdup.h" +#include "idn.h" +#include "curl_memrchr.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + /* MSDOS/Windows style drive prefix, eg c: in c:foo */ +#define STARTS_WITH_DRIVE_PREFIX(str) \ + ((('a' <= str[0] && str[0] <= 'z') || \ + ('A' <= str[0] && str[0] <= 'Z')) && \ + (str[1] == ':')) + + /* MSDOS/Windows style drive prefix, optionally with + * a '|' instead of ':', followed by a slash or NUL */ +#define STARTS_WITH_URL_DRIVE_PREFIX(str) \ + ((('a' <= (str)[0] && (str)[0] <= 'z') || \ + ('A' <= (str)[0] && (str)[0] <= 'Z')) && \ + ((str)[1] == ':' || (str)[1] == '|') && \ + ((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0)) + +/* scheme is not URL encoded, the longest libcurl supported ones are... */ +#define MAX_SCHEME_LEN 40 + +/* + * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make + * sure we have _some_ value for AF_INET6 without polluting our fake value + * everywhere. + */ +#if !defined(ENABLE_IPV6) && !defined(AF_INET6) +#define AF_INET6 (AF_INET + 1) +#endif + +/* Internal representation of CURLU. Point to URL-encoded strings. */ +struct Curl_URL { + char *scheme; + char *user; + char *password; + char *options; /* IMAP only? */ + char *host; + char *zoneid; /* for numerical IPv6 addresses */ + char *port; + char *path; + char *query; + char *fragment; + long portnum; /* the numerical version */ +}; + +#define DEFAULT_SCHEME "https" + +static void free_urlhandle(struct Curl_URL *u) +{ + free(u->scheme); + free(u->user); + free(u->password); + free(u->options); + free(u->host); + free(u->zoneid); + free(u->port); + free(u->path); + free(u->query); + free(u->fragment); +} + +/* + * Find the separator at the end of the host name, or the '?' in cases like + * http://www.example.com?id=2380 + */ +static const char *find_host_sep(const char *url) +{ + const char *sep; + const char *query; + + /* Find the start of the hostname */ + sep = strstr(url, "//"); + if(!sep) + sep = url; + else + sep += 2; + + query = strchr(sep, '?'); + sep = strchr(sep, '/'); + + if(!sep) + sep = url + strlen(url); + + if(!query) + query = url + strlen(url); + + return sep < query ? sep : query; +} + +/* convert CURLcode to CURLUcode */ +#define cc2cu(x) ((x) == CURLE_TOO_LARGE ? CURLUE_TOO_LARGE : \ + CURLUE_OUT_OF_MEMORY) +/* + * Decide whether a character in a URL must be escaped. + */ +#define urlchar_needs_escaping(c) (!(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c))) + +static const char hexdigits[] = "0123456789abcdef"; +/* urlencode_str() writes data into an output dynbuf and URL-encodes the + * spaces in the source URL accordingly. + * + * URL encoding should be skipped for host names, otherwise IDN resolution + * will fail. + */ +static CURLUcode urlencode_str(struct dynbuf *o, const char *url, + size_t len, bool relative, + bool query) +{ + /* we must add this with whitespace-replacing */ + bool left = !query; + const unsigned char *iptr; + const unsigned char *host_sep = (const unsigned char *) url; + CURLcode result; + + if(!relative) + host_sep = (const unsigned char *) find_host_sep(url); + + for(iptr = (unsigned char *)url; /* read from here */ + len; iptr++, len--) { + + if(iptr < host_sep) { + result = Curl_dyn_addn(o, iptr, 1); + if(result) + return cc2cu(result); + continue; + } + + if(*iptr == ' ') { + if(left) + result = Curl_dyn_addn(o, "%20", 3); + else + result = Curl_dyn_addn(o, "+", 1); + if(result) + return cc2cu(result); + continue; + } + + if(*iptr == '?') + left = FALSE; + + if(urlchar_needs_escaping(*iptr)) { + char out[3]={'%'}; + out[1] = hexdigits[*iptr>>4]; + out[2] = hexdigits[*iptr & 0xf]; + result = Curl_dyn_addn(o, out, 3); + } + else + result = Curl_dyn_addn(o, iptr, 1); + if(result) + return cc2cu(result); + } + + return CURLUE_OK; +} + +/* + * Returns the length of the scheme if the given URL is absolute (as opposed + * to relative). Stores the scheme in the buffer if TRUE and 'buf' is + * non-NULL. The buflen must be larger than MAX_SCHEME_LEN if buf is set. + * + * If 'guess_scheme' is TRUE, it means the URL might be provided without + * scheme. + */ +size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, + bool guess_scheme) +{ + int i = 0; + DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN)); + (void)buflen; /* only used in debug-builds */ + if(buf) + buf[0] = 0; /* always leave a defined value in buf */ +#ifdef _WIN32 + if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url)) + return 0; +#endif + if(ISALPHA(url[0])) + for(i = 1; i < MAX_SCHEME_LEN; ++i) { + char s = url[i]; + if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) { + /* RFC 3986 3.1 explains: + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + */ + } + else { + break; + } + } + if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) { + /* If this does not guess scheme, the scheme always ends with the colon so + that this also detects data: URLs etc. In guessing mode, data: could + be the host name "data" with a specified port number. */ + + /* the length of the scheme is the name part only */ + size_t len = i; + if(buf) { + buf[i] = 0; + while(i--) { + buf[i] = Curl_raw_tolower(url[i]); + } + } + return len; + } + return 0; +} + +/* + * Concatenate a relative URL to a base URL making it absolute. + * URL-encodes any spaces. + * The returned pointer must be freed by the caller unless NULL + * (returns NULL on out of memory). + * + * Note that this function destroys the 'base' string. + */ +static CURLcode concat_url(char *base, const char *relurl, char **newurl) +{ + /*** + TRY to append this new path to the old URL + to the right of the host part. Oh crap, this is doomed to cause + problems in the future... + */ + struct dynbuf newest; + char *protsep; + char *pathsep; + bool host_changed = FALSE; + const char *useurl = relurl; + CURLcode result = CURLE_OK; + CURLUcode uc; + *newurl = NULL; + + /* protsep points to the start of the host name */ + protsep = strstr(base, "//"); + if(!protsep) + protsep = base; + else + protsep += 2; /* pass the slashes */ + + if('/' != relurl[0]) { + int level = 0; + + /* First we need to find out if there's a ?-letter in the URL, + and cut it and the right-side of that off */ + pathsep = strchr(protsep, '?'); + if(pathsep) + *pathsep = 0; + + /* we have a relative path to append to the last slash if there's one + available, or if the new URL is just a query string (starts with a + '?') we append the new one at the end of the entire currently worked + out URL */ + if(useurl[0] != '?') { + pathsep = strrchr(protsep, '/'); + if(pathsep) + *pathsep = 0; + } + + /* Check if there's any slash after the host name, and if so, remember + that position instead */ + pathsep = strchr(protsep, '/'); + if(pathsep) + protsep = pathsep + 1; + else + protsep = NULL; + + /* now deal with one "./" or any amount of "../" in the newurl + and act accordingly */ + + if((useurl[0] == '.') && (useurl[1] == '/')) + useurl += 2; /* just skip the "./" */ + + while((useurl[0] == '.') && + (useurl[1] == '.') && + (useurl[2] == '/')) { + level++; + useurl += 3; /* pass the "../" */ + } + + if(protsep) { + while(level--) { + /* cut off one more level from the right of the original URL */ + pathsep = strrchr(protsep, '/'); + if(pathsep) + *pathsep = 0; + else { + *protsep = 0; + break; + } + } + } + } + else { + /* We got a new absolute path for this server */ + + if(relurl[1] == '/') { + /* the new URL starts with //, just keep the protocol part from the + original one */ + *protsep = 0; + useurl = &relurl[2]; /* we keep the slashes from the original, so we + skip the new ones */ + host_changed = TRUE; + } + else { + /* cut off the original URL from the first slash, or deal with URLs + without slash */ + pathsep = strchr(protsep, '/'); + if(pathsep) { + /* When people use badly formatted URLs, such as + "http://www.example.com?dir=/home/daniel" we must not use the first + slash, if there's a ?-letter before it! */ + char *sep = strchr(protsep, '?'); + if(sep && (sep < pathsep)) + pathsep = sep; + *pathsep = 0; + } + else { + /* There was no slash. Now, since we might be operating on a badly + formatted URL, such as "http://www.example.com?id=2380" which + doesn't use a slash separator as it is supposed to, we need to check + for a ?-letter as well! */ + pathsep = strchr(protsep, '?'); + if(pathsep) + *pathsep = 0; + } + } + } + + Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH); + + /* copy over the root url part */ + result = Curl_dyn_add(&newest, base); + if(result) + return result; + + /* check if we need to append a slash */ + if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0])) + ; + else { + result = Curl_dyn_addn(&newest, "/", 1); + if(result) + return result; + } + + /* then append the new piece on the right side */ + uc = urlencode_str(&newest, useurl, strlen(useurl), !host_changed, + FALSE); + if(uc) + return (uc == CURLUE_TOO_LARGE) ? CURLE_TOO_LARGE : CURLE_OUT_OF_MEMORY; + + *newurl = Curl_dyn_ptr(&newest); + return CURLE_OK; +} + +/* scan for byte values <= 31, 127 and sometimes space */ +static CURLUcode junkscan(const char *url, size_t *urllen, unsigned int flags) +{ + static const char badbytes[]={ + /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x7f, 0x00 /* null-terminate */ + }; + size_t n = strlen(url); + size_t nfine; + + if(n > CURL_MAX_INPUT_LENGTH) + /* excessive input length */ + return CURLUE_MALFORMED_INPUT; + + nfine = strcspn(url, badbytes); + if((nfine != n) || + (!(flags & CURLU_ALLOW_SPACE) && strchr(url, ' '))) + return CURLUE_MALFORMED_INPUT; + + *urllen = n; + return CURLUE_OK; +} + +/* + * parse_hostname_login() + * + * Parse the login details (user name, password and options) from the URL and + * strip them out of the host name + * + */ +static CURLUcode parse_hostname_login(struct Curl_URL *u, + const char *login, + size_t len, + unsigned int flags, + size_t *offset) /* to the host name */ +{ + CURLUcode result = CURLUE_OK; + CURLcode ccode; + char *userp = NULL; + char *passwdp = NULL; + char *optionsp = NULL; + const struct Curl_handler *h = NULL; + + /* At this point, we assume all the other special cases have been taken + * care of, so the host is at most + * + * [user[:password][;options]]@]hostname + * + * We need somewhere to put the embedded details, so do that first. + */ + char *ptr; + + DEBUGASSERT(login); + + *offset = 0; + ptr = memchr(login, '@', len); + if(!ptr) + goto out; + + /* We will now try to extract the + * possible login information in a string like: + * ftp://user:password@ftp.my.site:8021/README */ + ptr++; + + /* if this is a known scheme, get some details */ + if(u->scheme) + h = Curl_get_scheme_handler(u->scheme); + + /* We could use the login information in the URL so extract it. Only parse + options if the handler says we should. Note that 'h' might be NULL! */ + ccode = Curl_parse_login_details(login, ptr - login - 1, + &userp, &passwdp, + (h && (h->flags & PROTOPT_URLOPTIONS)) ? + &optionsp:NULL); + if(ccode) { + result = CURLUE_BAD_LOGIN; + goto out; + } + + if(userp) { + if(flags & CURLU_DISALLOW_USER) { + /* Option DISALLOW_USER is set and url contains username. */ + result = CURLUE_USER_NOT_ALLOWED; + goto out; + } + free(u->user); + u->user = userp; + } + + if(passwdp) { + free(u->password); + u->password = passwdp; + } + + if(optionsp) { + free(u->options); + u->options = optionsp; + } + + /* the host name starts at this offset */ + *offset = ptr - login; + return CURLUE_OK; + +out: + + free(userp); + free(passwdp); + free(optionsp); + u->user = NULL; + u->password = NULL; + u->options = NULL; + + return result; +} + +UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, + bool has_scheme) +{ + char *portptr; + char *hostname = Curl_dyn_ptr(host); + /* + * Find the end of an IPv6 address on the ']' ending bracket. + */ + if(hostname[0] == '[') { + portptr = strchr(hostname, ']'); + if(!portptr) + return CURLUE_BAD_IPV6; + portptr++; + /* this is a RFC2732-style specified IP-address */ + if(*portptr) { + if(*portptr != ':') + return CURLUE_BAD_PORT_NUMBER; + } + else + portptr = NULL; + } + else + portptr = strchr(hostname, ':'); + + if(portptr) { + char *rest; + long port; + size_t keep = portptr - hostname; + + /* Browser behavior adaptation. If there's a colon with no digits after, + just cut off the name there which makes us ignore the colon and just + use the default port. Firefox, Chrome and Safari all do that. + + Don't do it if the URL has no scheme, to make something that looks like + a scheme not work! + */ + Curl_dyn_setlen(host, keep); + portptr++; + if(!*portptr) + return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER; + + if(!ISDIGIT(*portptr)) + return CURLUE_BAD_PORT_NUMBER; + + port = strtol(portptr, &rest, 10); /* Port number must be decimal */ + + if(port > 0xffff) + return CURLUE_BAD_PORT_NUMBER; + + if(rest[0]) + return CURLUE_BAD_PORT_NUMBER; + + u->portnum = port; + /* generate a new port number string to get rid of leading zeroes etc */ + free(u->port); + u->port = aprintf("%ld", port); + if(!u->port) + return CURLUE_OUT_OF_MEMORY; + } + + return CURLUE_OK; +} + +/* this assumes 'hostname' now starts with [ */ +static CURLUcode ipv6_parse(struct Curl_URL *u, char *hostname, + size_t hlen) /* length of hostname */ +{ + size_t len; + DEBUGASSERT(*hostname == '['); + if(hlen < 4) /* '[::]' is the shortest possible valid string */ + return CURLUE_BAD_IPV6; + hostname++; + hlen -= 2; + + /* only valid IPv6 letters are ok */ + len = strspn(hostname, "0123456789abcdefABCDEF:."); + + if(hlen != len) { + hlen = len; + if(hostname[len] == '%') { + /* this could now be '%[zone id]' */ + char zoneid[16]; + int i = 0; + char *h = &hostname[len + 1]; + /* pass '25' if present and is a url encoded percent sign */ + if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']')) + h += 2; + while(*h && (*h != ']') && (i < 15)) + zoneid[i++] = *h++; + if(!i || (']' != *h)) + return CURLUE_BAD_IPV6; + zoneid[i] = 0; + u->zoneid = strdup(zoneid); + if(!u->zoneid) + return CURLUE_OUT_OF_MEMORY; + hostname[len] = ']'; /* insert end bracket */ + hostname[len + 1] = 0; /* terminate the hostname */ + } + else + return CURLUE_BAD_IPV6; + /* hostname is fine */ + } + + /* Check the IPv6 address. */ + { + char dest[16]; /* fits a binary IPv6 address */ + char norm[MAX_IPADR_LEN]; + hostname[hlen] = 0; /* end the address there */ + if(1 != Curl_inet_pton(AF_INET6, hostname, dest)) + return CURLUE_BAD_IPV6; + + /* check if it can be done shorter */ + if(Curl_inet_ntop(AF_INET6, dest, norm, sizeof(norm)) && + (strlen(norm) < hlen)) { + strcpy(hostname, norm); + hlen = strlen(norm); + hostname[hlen + 1] = 0; + } + hostname[hlen] = ']'; /* restore ending bracket */ + } + return CURLUE_OK; +} + +static CURLUcode hostname_check(struct Curl_URL *u, char *hostname, + size_t hlen) /* length of hostname */ +{ + size_t len; + DEBUGASSERT(hostname); + + if(!hlen) + return CURLUE_NO_HOST; + else if(hostname[0] == '[') + return ipv6_parse(u, hostname, hlen); + else { + /* letters from the second string are not ok */ + len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()%"); + if(hlen != len) + /* hostname with bad content */ + return CURLUE_BAD_HOSTNAME; + } + return CURLUE_OK; +} + +/* + * Handle partial IPv4 numerical addresses and different bases, like + * '16843009', '0x7f', '0x7f.1' '0177.1.1.1' etc. + * + * If the given input string is syntactically wrong IPv4 or any part for + * example is too big, this function returns HOST_NAME. + * + * Output the "normalized" version of that input string in plain quad decimal + * integers. + * + * Returns the host type. + */ + +#define HOST_ERROR -1 /* out of memory */ +#define HOST_BAD -2 /* bad IPv4 address */ + +#define HOST_NAME 1 +#define HOST_IPV4 2 +#define HOST_IPV6 3 + +static int ipv4_normalize(struct dynbuf *host) +{ + bool done = FALSE; + int n = 0; + const char *c = Curl_dyn_ptr(host); + unsigned long parts[4] = {0, 0, 0, 0}; + CURLcode result = CURLE_OK; + + if(*c == '[') + return HOST_IPV6; + + while(!done) { + char *endp; + unsigned long l; + if(!ISDIGIT(*c)) + /* most importantly this doesn't allow a leading plus or minus */ + return HOST_NAME; + l = strtoul(c, &endp, 0); + + parts[n] = l; + c = endp; + + switch(*c) { + case '.': + if(n == 3) + return HOST_NAME; + n++; + c++; + break; + + case '\0': + done = TRUE; + break; + + default: + return HOST_NAME; + } + + /* overflow */ + if((l == ULONG_MAX) && (errno == ERANGE)) + return HOST_NAME; + +#if SIZEOF_LONG > 4 + /* a value larger than 32 bits */ + if(l > UINT_MAX) + return HOST_NAME; +#endif + } + + switch(n) { + case 0: /* a -- 32 bits */ + Curl_dyn_reset(host); + + result = Curl_dyn_addf(host, "%u.%u.%u.%u", + (unsigned int)(parts[0] >> 24), + (unsigned int)((parts[0] >> 16) & 0xff), + (unsigned int)((parts[0] >> 8) & 0xff), + (unsigned int)(parts[0] & 0xff)); + break; + case 1: /* a.b -- 8.24 bits */ + if((parts[0] > 0xff) || (parts[1] > 0xffffff)) + return HOST_NAME; + Curl_dyn_reset(host); + result = Curl_dyn_addf(host, "%u.%u.%u.%u", + (unsigned int)(parts[0]), + (unsigned int)((parts[1] >> 16) & 0xff), + (unsigned int)((parts[1] >> 8) & 0xff), + (unsigned int)(parts[1] & 0xff)); + break; + case 2: /* a.b.c -- 8.8.16 bits */ + if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff)) + return HOST_NAME; + Curl_dyn_reset(host); + result = Curl_dyn_addf(host, "%u.%u.%u.%u", + (unsigned int)(parts[0]), + (unsigned int)(parts[1]), + (unsigned int)((parts[2] >> 8) & 0xff), + (unsigned int)(parts[2] & 0xff)); + break; + case 3: /* a.b.c.d -- 8.8.8.8 bits */ + if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) || + (parts[3] > 0xff)) + return HOST_NAME; + Curl_dyn_reset(host); + result = Curl_dyn_addf(host, "%u.%u.%u.%u", + (unsigned int)(parts[0]), + (unsigned int)(parts[1]), + (unsigned int)(parts[2]), + (unsigned int)(parts[3])); + break; + } + if(result) + return HOST_ERROR; + return HOST_IPV4; +} + +/* if necessary, replace the host content with a URL decoded version */ +static CURLUcode urldecode_host(struct dynbuf *host) +{ + char *per = NULL; + const char *hostname = Curl_dyn_ptr(host); + per = strchr(hostname, '%'); + if(!per) + /* nothing to decode */ + return CURLUE_OK; + else { + /* encoded */ + size_t dlen; + char *decoded; + CURLcode result = Curl_urldecode(hostname, 0, &decoded, &dlen, + REJECT_CTRL); + if(result) + return CURLUE_BAD_HOSTNAME; + Curl_dyn_reset(host); + result = Curl_dyn_addn(host, decoded, dlen); + free(decoded); + if(result) + return cc2cu(result); + } + + return CURLUE_OK; +} + +static CURLUcode parse_authority(struct Curl_URL *u, + const char *auth, size_t authlen, + unsigned int flags, + struct dynbuf *host, + bool has_scheme) +{ + size_t offset; + CURLUcode uc; + CURLcode result; + + /* + * Parse the login details and strip them out of the host name. + */ + uc = parse_hostname_login(u, auth, authlen, flags, &offset); + if(uc) + goto out; + + result = Curl_dyn_addn(host, auth + offset, authlen - offset); + if(result) { + uc = cc2cu(result); + goto out; + } + + uc = Curl_parse_port(u, host, has_scheme); + if(uc) + goto out; + + if(!Curl_dyn_len(host)) + return CURLUE_NO_HOST; + + switch(ipv4_normalize(host)) { + case HOST_IPV4: + break; + case HOST_IPV6: + uc = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host)); + break; + case HOST_NAME: + uc = urldecode_host(host); + if(!uc) + uc = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host)); + break; + case HOST_ERROR: + uc = CURLUE_OUT_OF_MEMORY; + break; + case HOST_BAD: + default: + uc = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */ + break; + } + +out: + return uc; +} + +CURLUcode Curl_url_set_authority(CURLU *u, const char *authority, + unsigned int flags) +{ + CURLUcode result; + struct dynbuf host; + + DEBUGASSERT(authority); + Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH); + + result = parse_authority(u, authority, strlen(authority), flags, + &host, !!u->scheme); + if(result) + Curl_dyn_free(&host); + else { + free(u->host); + u->host = Curl_dyn_ptr(&host); + } + return result; +} + +/* + * "Remove Dot Segments" + * https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 + */ + +/* + * dedotdotify() + * @unittest: 1395 + * + * This function gets a null-terminated path with dot and dotdot sequences + * passed in and strips them off according to the rules in RFC 3986 section + * 5.2.4. + * + * The function handles a query part ('?' + stuff) appended but it expects + * that fragments ('#' + stuff) have already been cut off. + * + * RETURNS + * + * Zero for success and 'out' set to an allocated dedotdotified string. + */ +UNITTEST int dedotdotify(const char *input, size_t clen, char **outp); +UNITTEST int dedotdotify(const char *input, size_t clen, char **outp) +{ + char *outptr; + const char *endp = &input[clen]; + char *out; + + *outp = NULL; + /* the path always starts with a slash, and a slash has not dot */ + if((clen < 2) || !memchr(input, '.', clen)) + return 0; + + out = malloc(clen + 1); + if(!out) + return 1; /* out of memory */ + + *out = 0; /* null-terminates, for inputs like "./" */ + outptr = out; + + do { + bool dotdot = TRUE; + if(*input == '.') { + /* A. If the input buffer begins with a prefix of "../" or "./", then + remove that prefix from the input buffer; otherwise, */ + + if(!strncmp("./", input, 2)) { + input += 2; + clen -= 2; + } + else if(!strncmp("../", input, 3)) { + input += 3; + clen -= 3; + } + /* D. if the input buffer consists only of "." or "..", then remove + that from the input buffer; otherwise, */ + + else if(!strcmp(".", input) || !strcmp("..", input) || + !strncmp(".?", input, 2) || !strncmp("..?", input, 3)) { + *out = 0; + break; + } + else + dotdot = FALSE; + } + else if(*input == '/') { + /* B. if the input buffer begins with a prefix of "/./" or "/.", where + "." is a complete path segment, then replace that prefix with "/" in + the input buffer; otherwise, */ + if(!strncmp("/./", input, 3)) { + input += 2; + clen -= 2; + } + else if(!strcmp("/.", input) || !strncmp("/.?", input, 3)) { + *outptr++ = '/'; + *outptr = 0; + break; + } + + /* C. if the input buffer begins with a prefix of "/../" or "/..", + where ".." is a complete path segment, then replace that prefix with + "/" in the input buffer and remove the last segment and its + preceding "/" (if any) from the output buffer; otherwise, */ + + else if(!strncmp("/../", input, 4)) { + input += 3; + clen -= 3; + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr = 0; /* null-terminate where it stops */ + } + else if(!strcmp("/..", input) || !strncmp("/..?", input, 4)) { + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr++ = '/'; + *outptr = 0; /* null-terminate where it stops */ + break; + } + else + dotdot = FALSE; + } + else + dotdot = FALSE; + + if(!dotdot) { + /* E. move the first path segment in the input buffer to the end of + the output buffer, including the initial "/" character (if any) and + any subsequent characters up to, but not including, the next "/" + character or the end of the input buffer. */ + + do { + *outptr++ = *input++; + clen--; + } while(*input && (*input != '/') && (*input != '?')); + *outptr = 0; + } + + /* continue until end of path */ + } while(input < endp); + + *outp = out; + return 0; /* success */ +} + +static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) +{ + const char *path; + size_t pathlen; + char *query = NULL; + char *fragment = NULL; + char schemebuf[MAX_SCHEME_LEN + 1]; + size_t schemelen = 0; + size_t urllen; + CURLUcode result = CURLUE_OK; + size_t fraglen = 0; + struct dynbuf host; + + DEBUGASSERT(url); + + Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH); + + result = junkscan(url, &urllen, flags); + if(result) + goto fail; + + schemelen = Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf), + flags & (CURLU_GUESS_SCHEME| + CURLU_DEFAULT_SCHEME)); + + /* handle the file: scheme */ + if(schemelen && !strcmp(schemebuf, "file")) { + bool uncpath = FALSE; + if(urllen <= 6) { + /* file:/ is not enough to actually be a complete file: URL */ + result = CURLUE_BAD_FILE_URL; + goto fail; + } + + /* path has been allocated large enough to hold this */ + path = (char *)&url[5]; + pathlen = urllen - 5; + + u->scheme = strdup("file"); + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + + /* Extra handling URLs with an authority component (i.e. that start with + * "file://") + * + * We allow omitted hostname (e.g. file:/) -- valid according to + * RFC 8089, but not the (current) WHAT-WG URL spec. + */ + if(path[0] == '/' && path[1] == '/') { + /* swallow the two slashes */ + const char *ptr = &path[2]; + + /* + * According to RFC 8089, a file: URL can be reliably dereferenced if: + * + * o it has no/blank hostname, or + * + * o the hostname matches "localhost" (case-insensitively), or + * + * o the hostname is a FQDN that resolves to this machine, or + * + * o it is an UNC String transformed to an URI (Windows only, RFC 8089 + * Appendix E.3). + * + * For brevity, we only consider URLs with empty, "localhost", or + * "127.0.0.1" hostnames as local, otherwise as an UNC String. + * + * Additionally, there is an exception for URLs with a Windows drive + * letter in the authority (which was accidentally omitted from RFC 8089 + * Appendix E, but believe me, it was meant to be there. --MK) + */ + if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) { + /* the URL includes a host name, it must match "localhost" or + "127.0.0.1" to be valid */ + if(checkprefix("localhost/", ptr) || + checkprefix("127.0.0.1/", ptr)) { + ptr += 9; /* now points to the slash after the host */ + } + else { +#if defined(_WIN32) + size_t len; + + /* the host name, NetBIOS computer name, can not contain disallowed + chars, and the delimiting slash character must be appended to the + host name */ + path = strpbrk(ptr, "/\\:*?\"<>|"); + if(!path || *path != '/') { + result = CURLUE_BAD_FILE_URL; + goto fail; + } + + len = path - ptr; + if(len) { + CURLcode code = Curl_dyn_addn(&host, ptr, len); + if(code) { + result = cc2cu(code); + goto fail; + } + uncpath = TRUE; + } + + ptr -= 2; /* now points to the // before the host in UNC */ +#else + /* Invalid file://hostname/, expected localhost or 127.0.0.1 or + none */ + result = CURLUE_BAD_FILE_URL; + goto fail; +#endif + } + } + + path = ptr; + pathlen = urllen - (ptr - url); + } + + if(!uncpath) + /* no host for file: URLs by default */ + Curl_dyn_reset(&host); + +#if !defined(_WIN32) && !defined(MSDOS) && !defined(__CYGWIN__) + /* Don't allow Windows drive letters when not in Windows. + * This catches both "file:/c:" and "file:c:" */ + if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) || + STARTS_WITH_URL_DRIVE_PREFIX(path)) { + /* File drive letters are only accepted in MSDOS/Windows */ + result = CURLUE_BAD_FILE_URL; + goto fail; + } +#else + /* If the path starts with a slash and a drive letter, ditch the slash */ + if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) { + /* This cannot be done with strcpy, as the memory chunks overlap! */ + path++; + pathlen--; + } +#endif + + } + else { + /* clear path */ + const char *schemep = NULL; + const char *hostp; + size_t hostlen; + + if(schemelen) { + int i = 0; + const char *p = &url[schemelen + 1]; + while((*p == '/') && (i < 4)) { + p++; + i++; + } + + schemep = schemebuf; + if(!Curl_get_scheme_handler(schemep) && + !(flags & CURLU_NON_SUPPORT_SCHEME)) { + result = CURLUE_UNSUPPORTED_SCHEME; + goto fail; + } + + if((i < 1) || (i > 3)) { + /* less than one or more than three slashes */ + result = CURLUE_BAD_SLASHES; + goto fail; + } + hostp = p; /* host name starts here */ + } + else { + /* no scheme! */ + + if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) { + result = CURLUE_BAD_SCHEME; + goto fail; + } + if(flags & CURLU_DEFAULT_SCHEME) + schemep = DEFAULT_SCHEME; + + /* + * The URL was badly formatted, let's try without scheme specified. + */ + hostp = url; + } + + if(schemep) { + u->scheme = strdup(schemep); + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + + /* find the end of the host name + port number */ + hostlen = strcspn(hostp, "/?#"); + path = &hostp[hostlen]; + + /* this pathlen also contains the query and the fragment */ + pathlen = urllen - (path - url); + if(hostlen) { + + result = parse_authority(u, hostp, hostlen, flags, &host, schemelen); + if(result) + goto fail; + + if((flags & CURLU_GUESS_SCHEME) && !schemep) { + const char *hostname = Curl_dyn_ptr(&host); + /* legacy curl-style guess based on host name */ + if(checkprefix("ftp.", hostname)) + schemep = "ftp"; + else if(checkprefix("dict.", hostname)) + schemep = "dict"; + else if(checkprefix("ldap.", hostname)) + schemep = "ldap"; + else if(checkprefix("imap.", hostname)) + schemep = "imap"; + else if(checkprefix("smtp.", hostname)) + schemep = "smtp"; + else if(checkprefix("pop3.", hostname)) + schemep = "pop3"; + else + schemep = "http"; + + u->scheme = strdup(schemep); + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + else if(flags & CURLU_NO_AUTHORITY) { + /* allowed to be empty. */ + if(Curl_dyn_add(&host, "")) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + else { + result = CURLUE_NO_HOST; + goto fail; + } + } + + fragment = strchr(path, '#'); + if(fragment) { + fraglen = pathlen - (fragment - path); + if(fraglen > 1) { + /* skip the leading '#' in the copy but include the terminating null */ + if(flags & CURLU_URLENCODE) { + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + result = urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE); + if(result) + goto fail; + u->fragment = Curl_dyn_ptr(&enc); + } + else { + u->fragment = Curl_memdup0(fragment + 1, fraglen - 1); + if(!u->fragment) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + /* after this, pathlen still contains the query */ + pathlen -= fraglen; + } + + query = memchr(path, '?', pathlen); + if(query) { + size_t qlen = fragment ? (size_t)(fragment - query) : + pathlen - (query - path); + pathlen -= qlen; + if(qlen > 1) { + if(flags & CURLU_URLENCODE) { + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + /* skip the leading question mark */ + result = urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE); + if(result) + goto fail; + u->query = Curl_dyn_ptr(&enc); + } + else { + u->query = Curl_memdup0(query + 1, qlen - 1); + if(!u->query) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + else { + /* single byte query */ + u->query = strdup(""); + if(!u->query) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + + if(pathlen && (flags & CURLU_URLENCODE)) { + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + result = urlencode_str(&enc, path, pathlen, TRUE, FALSE); + if(result) + goto fail; + pathlen = Curl_dyn_len(&enc); + path = u->path = Curl_dyn_ptr(&enc); + } + + if(pathlen <= 1) { + /* there is no path left or just the slash, unset */ + path = NULL; + } + else { + if(!u->path) { + u->path = Curl_memdup0(path, pathlen); + if(!u->path) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + path = u->path; + } + else if(flags & CURLU_URLENCODE) + /* it might have encoded more than just the path so cut it */ + u->path[pathlen] = 0; + + if(!(flags & CURLU_PATH_AS_IS)) { + /* remove ../ and ./ sequences according to RFC3986 */ + char *dedot; + int err = dedotdotify((char *)path, pathlen, &dedot); + if(err) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + if(dedot) { + free(u->path); + u->path = dedot; + } + } + } + + u->host = Curl_dyn_ptr(&host); + + return result; +fail: + Curl_dyn_free(&host); + free_urlhandle(u); + return result; +} + +/* + * Parse the URL and, if successful, replace everything in the Curl_URL struct. + */ +static CURLUcode parseurl_and_replace(const char *url, CURLU *u, + unsigned int flags) +{ + CURLUcode result; + CURLU tmpurl; + memset(&tmpurl, 0, sizeof(tmpurl)); + result = parseurl(url, &tmpurl, flags); + if(!result) { + free_urlhandle(u); + *u = tmpurl; + } + return result; +} + +/* + */ +CURLU *curl_url(void) +{ + return calloc(1, sizeof(struct Curl_URL)); +} + +void curl_url_cleanup(CURLU *u) +{ + if(u) { + free_urlhandle(u); + free(u); + } +} + +#define DUP(dest, src, name) \ + do { \ + if(src->name) { \ + dest->name = strdup(src->name); \ + if(!dest->name) \ + goto fail; \ + } \ + } while(0) + +CURLU *curl_url_dup(const CURLU *in) +{ + struct Curl_URL *u = calloc(1, sizeof(struct Curl_URL)); + if(u) { + DUP(u, in, scheme); + DUP(u, in, user); + DUP(u, in, password); + DUP(u, in, options); + DUP(u, in, host); + DUP(u, in, port); + DUP(u, in, path); + DUP(u, in, query); + DUP(u, in, fragment); + DUP(u, in, zoneid); + u->portnum = in->portnum; + } + return u; +fail: + curl_url_cleanup(u); + return NULL; +} + +CURLUcode curl_url_get(const CURLU *u, CURLUPart what, + char **part, unsigned int flags) +{ + const char *ptr; + CURLUcode ifmissing = CURLUE_UNKNOWN_PART; + char portbuf[7]; + bool urldecode = (flags & CURLU_URLDECODE)?1:0; + bool urlencode = (flags & CURLU_URLENCODE)?1:0; + bool punycode = FALSE; + bool depunyfy = FALSE; + bool plusdecode = FALSE; + (void)flags; + if(!u) + return CURLUE_BAD_HANDLE; + if(!part) + return CURLUE_BAD_PARTPOINTER; + *part = NULL; + + switch(what) { + case CURLUPART_SCHEME: + ptr = u->scheme; + ifmissing = CURLUE_NO_SCHEME; + urldecode = FALSE; /* never for schemes */ + break; + case CURLUPART_USER: + ptr = u->user; + ifmissing = CURLUE_NO_USER; + break; + case CURLUPART_PASSWORD: + ptr = u->password; + ifmissing = CURLUE_NO_PASSWORD; + break; + case CURLUPART_OPTIONS: + ptr = u->options; + ifmissing = CURLUE_NO_OPTIONS; + break; + case CURLUPART_HOST: + ptr = u->host; + ifmissing = CURLUE_NO_HOST; + punycode = (flags & CURLU_PUNYCODE)?1:0; + depunyfy = (flags & CURLU_PUNY2IDN)?1:0; + break; + case CURLUPART_ZONEID: + ptr = u->zoneid; + ifmissing = CURLUE_NO_ZONEID; + break; + case CURLUPART_PORT: + ptr = u->port; + ifmissing = CURLUE_NO_PORT; + urldecode = FALSE; /* never for port */ + if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) { + /* there's no stored port number, but asked to deliver + a default one for the scheme */ + const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme); + if(h) { + msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); + ptr = portbuf; + } + } + else if(ptr && u->scheme) { + /* there is a stored port number, but ask to inhibit if + it matches the default one for the scheme */ + const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme); + if(h && (h->defport == u->portnum) && + (flags & CURLU_NO_DEFAULT_PORT)) + ptr = NULL; + } + break; + case CURLUPART_PATH: + ptr = u->path; + if(!ptr) + ptr = "/"; + break; + case CURLUPART_QUERY: + ptr = u->query; + ifmissing = CURLUE_NO_QUERY; + plusdecode = urldecode; + break; + case CURLUPART_FRAGMENT: + ptr = u->fragment; + ifmissing = CURLUE_NO_FRAGMENT; + break; + case CURLUPART_URL: { + char *url; + char *scheme; + char *options = u->options; + char *port = u->port; + char *allochost = NULL; + punycode = (flags & CURLU_PUNYCODE)?1:0; + depunyfy = (flags & CURLU_PUNY2IDN)?1:0; + if(u->scheme && strcasecompare("file", u->scheme)) { + url = aprintf("file://%s%s%s", + u->path, + u->fragment? "#": "", + u->fragment? u->fragment : ""); + } + else if(!u->host) + return CURLUE_NO_HOST; + else { + const struct Curl_handler *h = NULL; + if(u->scheme) + scheme = u->scheme; + else if(flags & CURLU_DEFAULT_SCHEME) + scheme = (char *) DEFAULT_SCHEME; + else + return CURLUE_NO_SCHEME; + + h = Curl_get_scheme_handler(scheme); + if(!port && (flags & CURLU_DEFAULT_PORT)) { + /* there's no stored port number, but asked to deliver + a default one for the scheme */ + if(h) { + msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); + port = portbuf; + } + } + else if(port) { + /* there is a stored port number, but asked to inhibit if it matches + the default one for the scheme */ + if(h && (h->defport == u->portnum) && + (flags & CURLU_NO_DEFAULT_PORT)) + port = NULL; + } + + if(h && !(h->flags & PROTOPT_URLOPTIONS)) + options = NULL; + + if(u->host[0] == '[') { + if(u->zoneid) { + /* make it '[ host %25 zoneid ]' */ + struct dynbuf enc; + size_t hostlen = strlen(u->host); + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + if(Curl_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host, + u->zoneid)) + return CURLUE_OUT_OF_MEMORY; + allochost = Curl_dyn_ptr(&enc); + } + } + else if(urlencode) { + allochost = curl_easy_escape(NULL, u->host, 0); + if(!allochost) + return CURLUE_OUT_OF_MEMORY; + } + else if(punycode) { + if(!Curl_is_ASCII_name(u->host)) { +#ifndef USE_IDN + return CURLUE_LACKS_IDN; +#else + CURLcode result = Curl_idn_decode(u->host, &allochost); + if(result) + return (result == CURLE_OUT_OF_MEMORY) ? + CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; +#endif + } + } + else if(depunyfy) { + if(Curl_is_ASCII_name(u->host) && !strncmp("xn--", u->host, 4)) { +#ifndef USE_IDN + return CURLUE_LACKS_IDN; +#else + CURLcode result = Curl_idn_encode(u->host, &allochost); + if(result) + /* this is the most likely error */ + return (result == CURLE_OUT_OF_MEMORY) ? + CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; +#endif + } + } + + url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + scheme, + u->user ? u->user : "", + u->password ? ":": "", + u->password ? u->password : "", + options ? ";" : "", + options ? options : "", + (u->user || u->password || options) ? "@": "", + allochost ? allochost : u->host, + port ? ":": "", + port ? port : "", + u->path ? u->path : "/", + (u->query && u->query[0]) ? "?": "", + (u->query && u->query[0]) ? u->query : "", + u->fragment? "#": "", + u->fragment? u->fragment : ""); + free(allochost); + } + if(!url) + return CURLUE_OUT_OF_MEMORY; + *part = url; + return CURLUE_OK; + } + default: + ptr = NULL; + break; + } + if(ptr) { + size_t partlen = strlen(ptr); + size_t i = 0; + *part = Curl_memdup0(ptr, partlen); + if(!*part) + return CURLUE_OUT_OF_MEMORY; + if(plusdecode) { + /* convert + to space */ + char *plus = *part; + for(i = 0; i < partlen; ++plus, i++) { + if(*plus == '+') + *plus = ' '; + } + } + if(urldecode) { + char *decoded; + size_t dlen; + /* this unconditional rejection of control bytes is documented + API behavior */ + CURLcode res = Curl_urldecode(*part, 0, &decoded, &dlen, REJECT_CTRL); + free(*part); + if(res) { + *part = NULL; + return CURLUE_URLDECODE; + } + *part = decoded; + partlen = dlen; + } + if(urlencode) { + struct dynbuf enc; + CURLUcode uc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY); + if(uc) + return uc; + free(*part); + *part = Curl_dyn_ptr(&enc); + } + else if(punycode) { + if(!Curl_is_ASCII_name(u->host)) { +#ifndef USE_IDN + return CURLUE_LACKS_IDN; +#else + char *allochost; + CURLcode result = Curl_idn_decode(*part, &allochost); + if(result) + return (result == CURLE_OUT_OF_MEMORY) ? + CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; + free(*part); + *part = allochost; +#endif + } + } + else if(depunyfy) { + if(Curl_is_ASCII_name(u->host) && !strncmp("xn--", u->host, 4)) { +#ifndef USE_IDN + return CURLUE_LACKS_IDN; +#else + char *allochost; + CURLcode result = Curl_idn_encode(*part, &allochost); + if(result) + return (result == CURLE_OUT_OF_MEMORY) ? + CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; + free(*part); + *part = allochost; +#endif + } + } + + return CURLUE_OK; + } + else + return ifmissing; +} + +CURLUcode curl_url_set(CURLU *u, CURLUPart what, + const char *part, unsigned int flags) +{ + char **storep = NULL; + long port = 0; + bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0; + bool plusencode = FALSE; + bool urlskipslash = FALSE; + bool leadingslash = FALSE; + bool appendquery = FALSE; + bool equalsencode = FALSE; + size_t nalloc; + + if(!u) + return CURLUE_BAD_HANDLE; + if(!part) { + /* setting a part to NULL clears it */ + switch(what) { + case CURLUPART_URL: + break; + case CURLUPART_SCHEME: + storep = &u->scheme; + break; + case CURLUPART_USER: + storep = &u->user; + break; + case CURLUPART_PASSWORD: + storep = &u->password; + break; + case CURLUPART_OPTIONS: + storep = &u->options; + break; + case CURLUPART_HOST: + storep = &u->host; + break; + case CURLUPART_ZONEID: + storep = &u->zoneid; + break; + case CURLUPART_PORT: + u->portnum = 0; + storep = &u->port; + break; + case CURLUPART_PATH: + storep = &u->path; + break; + case CURLUPART_QUERY: + storep = &u->query; + break; + case CURLUPART_FRAGMENT: + storep = &u->fragment; + break; + default: + return CURLUE_UNKNOWN_PART; + } + if(storep && *storep) { + Curl_safefree(*storep); + } + else if(!storep) { + free_urlhandle(u); + memset(u, 0, sizeof(struct Curl_URL)); + } + return CURLUE_OK; + } + + nalloc = strlen(part); + if(nalloc > CURL_MAX_INPUT_LENGTH) + /* excessive input length */ + return CURLUE_MALFORMED_INPUT; + + switch(what) { + case CURLUPART_SCHEME: { + size_t plen = strlen(part); + const char *s = part; + if((plen > MAX_SCHEME_LEN) || (plen < 1)) + /* too long or too short */ + return CURLUE_BAD_SCHEME; + /* verify that it is a fine scheme */ + if(!(flags & CURLU_NON_SUPPORT_SCHEME) && !Curl_get_scheme_handler(part)) + return CURLUE_UNSUPPORTED_SCHEME; + storep = &u->scheme; + urlencode = FALSE; /* never */ + if(ISALPHA(*s)) { + /* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ + while(--plen) { + if(ISALNUM(*s) || (*s == '+') || (*s == '-') || (*s == '.')) + s++; /* fine */ + else + return CURLUE_BAD_SCHEME; + } + } + else + return CURLUE_BAD_SCHEME; + break; + } + case CURLUPART_USER: + storep = &u->user; + break; + case CURLUPART_PASSWORD: + storep = &u->password; + break; + case CURLUPART_OPTIONS: + storep = &u->options; + break; + case CURLUPART_HOST: + storep = &u->host; + Curl_safefree(u->zoneid); + break; + case CURLUPART_ZONEID: + storep = &u->zoneid; + break; + case CURLUPART_PORT: + { + char *endp; + urlencode = FALSE; /* never */ + port = strtol(part, &endp, 10); /* Port number must be decimal */ + if((port <= 0) || (port > 0xffff)) + return CURLUE_BAD_PORT_NUMBER; + if(*endp) + /* weirdly provided number, not good! */ + return CURLUE_BAD_PORT_NUMBER; + storep = &u->port; + } + break; + case CURLUPART_PATH: + urlskipslash = TRUE; + leadingslash = TRUE; /* enforce */ + storep = &u->path; + break; + case CURLUPART_QUERY: + plusencode = urlencode; + appendquery = (flags & CURLU_APPENDQUERY)?1:0; + equalsencode = appendquery; + storep = &u->query; + break; + case CURLUPART_FRAGMENT: + storep = &u->fragment; + break; + case CURLUPART_URL: { + /* + * Allow a new URL to replace the existing (if any) contents. + * + * If the existing contents is enough for a URL, allow a relative URL to + * replace it. + */ + CURLcode result; + CURLUcode uc; + char *oldurl; + char *redired_url; + + if(!nalloc) + /* a blank URL is not a valid URL */ + return CURLUE_MALFORMED_INPUT; + + /* if the new thing is absolute or the old one is not + * (we could not get an absolute url in 'oldurl'), + * then replace the existing with the new. */ + if(Curl_is_absolute_url(part, NULL, 0, + flags & (CURLU_GUESS_SCHEME| + CURLU_DEFAULT_SCHEME)) + || curl_url_get(u, CURLUPART_URL, &oldurl, flags)) { + return parseurl_and_replace(part, u, flags); + } + + /* apply the relative part to create a new URL + * and replace the existing one with it. */ + result = concat_url(oldurl, part, &redired_url); + free(oldurl); + if(result) + return cc2cu(result); + + uc = parseurl_and_replace(redired_url, u, flags); + free(redired_url); + return uc; + } + default: + return CURLUE_UNKNOWN_PART; + } + DEBUGASSERT(storep); + { + const char *newp; + struct dynbuf enc; + Curl_dyn_init(&enc, nalloc * 3 + 1 + leadingslash); + + if(leadingslash && (part[0] != '/')) { + CURLcode result = Curl_dyn_addn(&enc, "/", 1); + if(result) + return cc2cu(result); + } + if(urlencode) { + const unsigned char *i; + + for(i = (const unsigned char *)part; *i; i++) { + CURLcode result; + if((*i == ' ') && plusencode) { + result = Curl_dyn_addn(&enc, "+", 1); + if(result) + return CURLUE_OUT_OF_MEMORY; + } + else if(ISUNRESERVED(*i) || + ((*i == '/') && urlskipslash) || + ((*i == '=') && equalsencode)) { + if((*i == '=') && equalsencode) + /* only skip the first equals sign */ + equalsencode = FALSE; + result = Curl_dyn_addn(&enc, i, 1); + if(result) + return cc2cu(result); + } + else { + char out[3]={'%'}; + out[1] = hexdigits[*i>>4]; + out[2] = hexdigits[*i & 0xf]; + result = Curl_dyn_addn(&enc, out, 3); + if(result) + return cc2cu(result); + } + } + } + else { + char *p; + CURLcode result = Curl_dyn_add(&enc, part); + if(result) + return cc2cu(result); + p = Curl_dyn_ptr(&enc); + while(*p) { + /* make sure percent encoded are lower case */ + if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) && + (ISUPPER(p[1]) || ISUPPER(p[2]))) { + p[1] = Curl_raw_tolower(p[1]); + p[2] = Curl_raw_tolower(p[2]); + p += 3; + } + else + p++; + } + } + newp = Curl_dyn_ptr(&enc); + + if(appendquery && newp) { + /* Append the 'newp' string onto the old query. Add a '&' separator if + none is present at the end of the existing query already */ + + size_t querylen = u->query ? strlen(u->query) : 0; + bool addamperand = querylen && (u->query[querylen -1] != '&'); + if(querylen) { + struct dynbuf qbuf; + Curl_dyn_init(&qbuf, CURL_MAX_INPUT_LENGTH); + + if(Curl_dyn_addn(&qbuf, u->query, querylen)) /* add original query */ + goto nomem; + + if(addamperand) { + if(Curl_dyn_addn(&qbuf, "&", 1)) + goto nomem; + } + if(Curl_dyn_add(&qbuf, newp)) + goto nomem; + Curl_dyn_free(&enc); + free(*storep); + *storep = Curl_dyn_ptr(&qbuf); + return CURLUE_OK; +nomem: + Curl_dyn_free(&enc); + return CURLUE_OUT_OF_MEMORY; + } + } + + else if(what == CURLUPART_HOST) { + size_t n = Curl_dyn_len(&enc); + if(!n && (flags & CURLU_NO_AUTHORITY)) { + /* Skip hostname check, it's allowed to be empty. */ + } + else { + if(!n || hostname_check(u, (char *)newp, n)) { + Curl_dyn_free(&enc); + return CURLUE_BAD_HOSTNAME; + } + } + } + + free(*storep); + *storep = (char *)newp; + } + /* set after the string, to make it not assigned if the allocation above + fails */ + if(port) + u->portnum = port; + return CURLUE_OK; +} diff --git a/lib/urldata.h b/lib/urldata.h new file mode 100644 index 0000000..9dcccc7 --- /dev/null +++ b/lib/urldata.h @@ -0,0 +1,2028 @@ +#ifndef HEADER_CURL_URLDATA_H +#define HEADER_CURL_URLDATA_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* This file is for lib internal stuff */ + +#include "curl_setup.h" + +#define PORT_FTP 21 +#define PORT_FTPS 990 +#define PORT_TELNET 23 +#define PORT_HTTP 80 +#define PORT_HTTPS 443 +#define PORT_DICT 2628 +#define PORT_LDAP 389 +#define PORT_LDAPS 636 +#define PORT_TFTP 69 +#define PORT_SSH 22 +#define PORT_IMAP 143 +#define PORT_IMAPS 993 +#define PORT_POP3 110 +#define PORT_POP3S 995 +#define PORT_SMB 445 +#define PORT_SMBS 445 +#define PORT_SMTP 25 +#define PORT_SMTPS 465 /* sometimes called SSMTP */ +#define PORT_RTSP 554 +#define PORT_RTMP 1935 +#define PORT_RTMPT PORT_HTTP +#define PORT_RTMPS PORT_HTTPS +#define PORT_GOPHER 70 +#define PORT_MQTT 1883 + +#ifdef USE_WEBSOCKETS +/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number, + * the rest are internal information. If we use higher bits we only do this on + * platforms that have a >= 64 bit type and then we use such a type for the + * protocol fields in the protocol handler. + */ +#define CURLPROTO_WS (1<<30) +#define CURLPROTO_WSS ((curl_prot_t)1<<31) +#else +#define CURLPROTO_WS 0 +#define CURLPROTO_WSS 0 +#endif + +/* This should be undefined once we need bit 32 or higher */ +#define PROTO_TYPE_SMALL + +#ifndef PROTO_TYPE_SMALL +typedef curl_off_t curl_prot_t; +#else +typedef unsigned int curl_prot_t; +#endif + +/* This mask is for all the old protocols that are provided and defined in the + public header and shall exclude protocols added since which are not exposed + in the API */ +#define CURLPROTO_MASK (0x3ffffff) + +#define DICT_MATCH "/MATCH:" +#define DICT_MATCH2 "/M:" +#define DICT_MATCH3 "/FIND:" +#define DICT_DEFINE "/DEFINE:" +#define DICT_DEFINE2 "/D:" +#define DICT_DEFINE3 "/LOOKUP:" + +#define CURL_DEFAULT_USER "anonymous" +#define CURL_DEFAULT_PASSWORD "ftp@example.com" + +/* Convenience defines for checking protocols or their SSL based version. Each + protocol handler should only ever have a single CURLPROTO_ in its protocol + field. */ +#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_WS| \ + CURLPROTO_WSS) +#define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS) +#define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S) +#define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS) +#define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS) +#define PROTO_FAMILY_SSH (CURLPROTO_SCP|CURLPROTO_SFTP) + +#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) || \ + !defined(CURL_DISABLE_POP3) +/* these protocols support CURLOPT_DIRLISTONLY */ +#define CURL_LIST_ONLY_PROTOCOL 1 +#endif + +#define DEFAULT_CONNCACHE_SIZE 5 + +/* length of longest IPv6 address string including the trailing null */ +#define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + +/* Default FTP/IMAP etc response timeout in milliseconds */ +#define RESP_TIMEOUT (120*1000) + +/* Max string input length is a precaution against abuse and to detect junk + input easier and better. */ +#define CURL_MAX_INPUT_LENGTH 8000000 + + +#include "cookie.h" +#include "psl.h" +#include "formdata.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif + +#include "timeval.h" + +#include + +#include "http_chunks.h" /* for the structs and enum stuff */ +#include "hostip.h" +#include "hash.h" +#include "splay.h" +#include "dynbuf.h" +#include "dynhds.h" + +/* return the count of bytes sent, or -1 on error */ +typedef ssize_t (Curl_send)(struct Curl_easy *data, /* transfer */ + int sockindex, /* socketindex */ + const void *buf, /* data to write */ + size_t len, /* max amount to write */ + CURLcode *err); /* error to return */ + +/* return the count of bytes read, or -1 on error */ +typedef ssize_t (Curl_recv)(struct Curl_easy *data, /* transfer */ + int sockindex, /* socketindex */ + char *buf, /* store data here */ + size_t len, /* max amount to read */ + CURLcode *err); /* error to return */ + +#ifdef USE_HYPER +typedef CURLcode (*Curl_datastream)(struct Curl_easy *data, + struct connectdata *conn, + int *didwhat, + bool *done, + int select_res); +#endif + +#include "mime.h" +#include "imap.h" +#include "pop3.h" +#include "smtp.h" +#include "ftp.h" +#include "file.h" +#include "vssh/ssh.h" +#include "http.h" +#include "rtsp.h" +#include "smb.h" +#include "mqtt.h" +#include "ftplistparser.h" +#include "multihandle.h" +#include "c-hyper.h" +#include "cf-socket.h" + +#ifdef HAVE_GSSAPI +# ifdef HAVE_GSSGNU +# include +# elif defined HAVE_GSSAPI_GSSAPI_H +# include +# else +# include +# endif +# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H +# include +# endif +#endif + +#ifdef USE_LIBSSH2 +#include +#include +#endif /* USE_LIBSSH2 */ + +#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE +#define READBUFFER_MAX CURL_MAX_READ_SIZE +#define READBUFFER_MIN 1024 + +/* The default upload buffer size, should not be smaller than + CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in + a write callback. + + The size was 16KB for many years but was bumped to 64KB because it makes + libcurl able to do significantly faster uploads in some circumstances. Even + larger buffers can help further, but this is deemed a fair memory/speed + compromise. */ +#define UPLOADBUFFER_DEFAULT 65536 +#define UPLOADBUFFER_MAX (2*1024*1024) +#define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE + +#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU +#ifdef DEBUGBUILD +/* On a debug build, we want to fail hard on easy handles that + * are not NULL, but no longer have the MAGIC touch. This gives + * us early warning on things only discovered by valgrind otherwise. */ +#define GOOD_EASY_HANDLE(x) \ + (((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))? TRUE: \ + (DEBUGASSERT(!(x)), FALSE)) +#else +#define GOOD_EASY_HANDLE(x) \ + ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) +#endif + +#ifdef HAVE_GSSAPI +/* Types needed for krb5-ftp connections */ +struct krb5buffer { + void *data; + size_t size; + size_t index; + BIT(eof_flag); +}; + +enum protection_level { + PROT_NONE, /* first in list */ + PROT_CLEAR, + PROT_SAFE, + PROT_CONFIDENTIAL, + PROT_PRIVATE, + PROT_CMD, + PROT_LAST /* last in list */ +}; +#endif + +/* enum for the nonblocking SSL connection state machine */ +typedef enum { + ssl_connect_1, + ssl_connect_2, + ssl_connect_2_reading, + ssl_connect_2_writing, + ssl_connect_3, + ssl_connect_done +} ssl_connect_state; + +typedef enum { + ssl_connection_none, + ssl_connection_negotiating, + ssl_connection_complete +} ssl_connection_state; + +/* SSL backend-specific data; declared differently by each SSL backend */ +struct ssl_backend_data; + +struct ssl_peer { + char *hostname; /* hostname for verification */ + char *dispname; /* display version of hostname */ + char *sni; /* SNI version of hostname or NULL if not usable */ + BIT(is_ip_address); /* if hostname is an IPv4|6 address */ +}; + +struct ssl_primary_config { + char *CApath; /* certificate dir (doesn't work on windows) */ + char *CAfile; /* certificate to verify peer against */ + char *issuercert; /* optional issuer certificate filename */ + char *clientcert; + char *cipher_list; /* list of ciphers to use */ + char *cipher_list13; /* list of TLS 1.3 cipher suites to use */ + char *pinned_key; + char *CRLfile; /* CRL to check certificate revocation */ + struct curl_blob *cert_blob; + struct curl_blob *ca_info_blob; + struct curl_blob *issuercert_blob; +#ifdef USE_TLS_SRP + char *username; /* TLS username (for, e.g., SRP) */ + char *password; /* TLS password (for, e.g., SRP) */ +#endif + char *curves; /* list of curves to use */ + unsigned char ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */ + unsigned int version_max; /* max supported version the client wants to use */ + unsigned char version; /* what version the client wants to use */ + BIT(verifypeer); /* set TRUE if this is desired */ + BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ + BIT(verifystatus); /* set TRUE if certificate status must be checked */ + BIT(sessionid); /* cache session IDs or not */ +}; + +struct ssl_config_data { + struct ssl_primary_config primary; + long certverifyresult; /* result from the certificate verification */ + curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ + void *fsslctxp; /* parameter for call back */ + char *cert_type; /* format for certificate (default: PEM)*/ + char *key; /* private key file name */ + struct curl_blob *key_blob; + char *key_type; /* format for private key (default: PEM) */ + char *key_passwd; /* plain text private key password */ + BIT(certinfo); /* gather lots of certificate info */ + BIT(falsestart); + BIT(enable_beast); /* allow this flaw for interoperability's sake */ + BIT(no_revoke); /* disable SSL certificate revocation checks */ + BIT(no_partialchain); /* don't accept partial certificate chains */ + BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation + list errors */ + BIT(native_ca_store); /* use the native ca store of operating system */ + BIT(auto_client_cert); /* automatically locate and use a client + certificate for authentication (Schannel) */ +}; + +struct ssl_general_config { + size_t max_ssl_sessions; /* SSL session id cache size */ + int ca_cache_timeout; /* Certificate store cache timeout (seconds) */ +}; + +/* information stored about one single SSL session */ +struct Curl_ssl_session { + char *name; /* host name for which this ID was used */ + char *conn_to_host; /* host name for the connection (may be NULL) */ + const char *scheme; /* protocol scheme used */ + void *sessionid; /* as returned from the SSL layer */ + size_t idsize; /* if known, otherwise 0 */ + long age; /* just a number, the higher the more recent */ + int remote_port; /* remote port */ + int conn_to_port; /* remote port for the connection (may be -1) */ + struct ssl_primary_config ssl_config; /* setup for this session */ +}; + +#ifdef USE_WINDOWS_SSPI +#include "curl_sspi.h" +#endif + +#ifndef CURL_DISABLE_DIGEST_AUTH +/* Struct used for Digest challenge-response authentication */ +struct digestdata { +#if defined(USE_WINDOWS_SSPI) + BYTE *input_token; + size_t input_token_len; + CtxtHandle *http_context; + /* copy of user/passwd used to make the identity for http_context. + either may be NULL. */ + char *user; + char *passwd; +#else + char *nonce; + char *cnonce; + char *realm; + char *opaque; + char *qop; + char *algorithm; + int nc; /* nonce count */ + unsigned char algo; + BIT(stale); /* set true for re-negotiation */ + BIT(userhash); +#endif +}; +#endif + +typedef enum { + NTLMSTATE_NONE, + NTLMSTATE_TYPE1, + NTLMSTATE_TYPE2, + NTLMSTATE_TYPE3, + NTLMSTATE_LAST +} curlntlm; + +typedef enum { + GSS_AUTHNONE, + GSS_AUTHRECV, + GSS_AUTHSENT, + GSS_AUTHDONE, + GSS_AUTHSUCC +} curlnegotiate; + +/* Struct used for GSSAPI (Kerberos V5) authentication */ +#if defined(USE_KERBEROS5) +struct kerberos5data { +#if defined(USE_WINDOWS_SSPI) + CredHandle *credentials; + CtxtHandle *context; + TCHAR *spn; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + size_t token_max; + BYTE *output_token; +#else + gss_ctx_id_t context; + gss_name_t spn; +#endif +}; +#endif + +/* Struct used for SCRAM-SHA-1 authentication */ +#ifdef USE_GSASL +#include +struct gsasldata { + Gsasl *ctx; + Gsasl_session *client; +}; +#endif + +/* Struct used for NTLM challenge-response authentication */ +#if defined(USE_NTLM) +struct ntlmdata { +#ifdef USE_WINDOWS_SSPI +/* The sslContext is used for the Schannel bindings. The + * api is available on the Windows 7 SDK and later. + */ +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + CtxtHandle *sslContext; +#endif + CredHandle *credentials; + CtxtHandle *context; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + size_t token_max; + BYTE *output_token; + BYTE *input_token; + size_t input_token_len; + TCHAR *spn; +#else + unsigned int flags; + unsigned char nonce[8]; + unsigned int target_info_len; + void *target_info; /* TargetInfo received in the ntlm type-2 message */ + +#if defined(NTLM_WB_ENABLED) + /* used for communication with Samba's winbind daemon helper ntlm_auth */ + curl_socket_t ntlm_auth_hlpr_socket; + pid_t ntlm_auth_hlpr_pid; + char *challenge; /* The received base64 encoded ntlm type-2 message */ + char *response; /* The generated base64 ntlm type-1/type-3 message */ +#endif +#endif +}; +#endif + +/* Struct used for Negotiate (SPNEGO) authentication */ +#ifdef USE_SPNEGO +struct negotiatedata { +#ifdef HAVE_GSSAPI + OM_uint32 status; + gss_ctx_id_t context; + gss_name_t spn; + gss_buffer_desc output_token; +#else +#ifdef USE_WINDOWS_SSPI +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + CtxtHandle *sslContext; +#endif + DWORD status; + CredHandle *credentials; + CtxtHandle *context; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + TCHAR *spn; + size_t token_max; + BYTE *output_token; + size_t output_token_length; +#endif +#endif + BIT(noauthpersist); + BIT(havenoauthpersist); + BIT(havenegdata); + BIT(havemultiplerequests); +}; +#endif + +#ifdef CURL_DISABLE_PROXY +#define CONN_IS_PROXIED(x) 0 +#else +#define CONN_IS_PROXIED(x) x->bits.proxy +#endif + +/* + * Boolean values that concerns this connection. + */ +struct ConnectBits { +#ifndef CURL_DISABLE_PROXY + BIT(httpproxy); /* if set, this transfer is done through an HTTP proxy */ + BIT(socksproxy); /* if set, this transfer is done through a socks proxy */ + BIT(proxy_user_passwd); /* user+password for the proxy? */ + BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy. + This is implicit when SSL-protocols are used through + proxies, but can also be enabled explicitly by + apps */ + BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection + in a CONNECT request with auth, so that + libcurl should reconnect and continue. */ + BIT(proxy); /* if set, this transfer is done through a proxy - any type */ +#endif + /* always modify bits.close with the connclose() and connkeep() macros! */ + BIT(close); /* if set, we close the connection after this request */ + BIT(reuse); /* if set, this is a reused connection */ + BIT(altused); /* this is an alt-svc "redirect" */ + BIT(conn_to_host); /* if set, this connection has a "connect to host" + that overrides the host in the URL */ + BIT(conn_to_port); /* if set, this connection has a "connect to port" + that overrides the port in the URL (remote port) */ + BIT(ipv6_ip); /* we communicate with a remote site specified with pure IPv6 + IP address */ + BIT(ipv6); /* we communicate with a site using an IPv6 address */ + BIT(do_more); /* this is set TRUE if the ->curl_do_more() function is + supposed to be called, after ->curl_do() */ + BIT(protoconnstart);/* the protocol layer has STARTED its operation after + the TCP layer connect */ + BIT(retry); /* this connection is about to get closed and then + re-attempted at another connection. */ + BIT(authneg); /* TRUE when the auth phase has started, which means + that we are creating a request with an auth header, + but it is not the final request in the auth + negotiation. */ +#ifndef CURL_DISABLE_FTP + BIT(ftp_use_epsv); /* As set with CURLOPT_FTP_USE_EPSV, but if we find out + EPSV doesn't work we disable it for the forthcoming + requests */ + BIT(ftp_use_eprt); /* As set with CURLOPT_FTP_USE_EPRT, but if we find out + EPRT doesn't work we disable it for the forthcoming + requests */ + BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */ + BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */ +#endif +#ifndef CURL_DISABLE_NETRC + BIT(netrc); /* name+password provided by netrc */ +#endif + BIT(bound); /* set true if bind() has already been done on this socket/ + connection */ + BIT(multiplex); /* connection is multiplexed */ + BIT(tcp_fastopen); /* use TCP Fast Open */ + BIT(tls_enable_alpn); /* TLS ALPN extension? */ +#ifndef CURL_DISABLE_DOH + BIT(doh); +#endif +#ifdef USE_UNIX_SOCKETS + BIT(abstract_unix_socket); +#endif + BIT(tls_upgraded); + BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with + accept() */ + BIT(parallel_connect); /* set TRUE when a parallel connect attempt has + started (happy eyeballs) */ +}; + +struct hostname { + char *rawalloc; /* allocated "raw" version of the name */ + char *encalloc; /* allocated IDN-encoded version of the name */ + char *name; /* name to use internally, might be encoded, might be raw */ + const char *dispname; /* name to display, as 'name' might be encoded */ +}; + +/* + * Flags on the keepon member of the Curl_transfer_keeper + */ + +#define KEEP_NONE 0 +#define KEEP_RECV (1<<0) /* there is or may be data to read */ +#define KEEP_SEND (1<<1) /* there is or may be data to write */ +#define KEEP_RECV_HOLD (1<<2) /* when set, no reading should be done but there + might still be data to read */ +#define KEEP_SEND_HOLD (1<<3) /* when set, no writing should be done but there + might still be data to write */ +#define KEEP_RECV_PAUSE (1<<4) /* reading is paused */ +#define KEEP_SEND_PAUSE (1<<5) /* writing is paused */ + +#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE) +#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE) + +/* transfer wants to send is not PAUSE or HOLD */ +#define CURL_WANT_SEND(data) \ + (((data)->req.keepon & KEEP_SENDBITS) == KEEP_SEND) +/* transfer receive is not on PAUSE or HOLD */ +#define CURL_WANT_RECV(data) \ + (((data)->req.keepon & KEEP_RECVBITS) == KEEP_RECV) + +#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH) +#define USE_CURL_ASYNC +struct Curl_async { + char *hostname; + struct Curl_dns_entry *dns; + struct thread_data *tdata; + void *resolver; /* resolver state, if it is used in the URL state - + ares_channel e.g. */ + int port; + int status; /* if done is TRUE, this is the status from the callback */ + BIT(done); /* set TRUE when the lookup is complete */ +}; + +#endif + +#define FIRSTSOCKET 0 +#define SECONDARYSOCKET 1 + +/* Polling requested by an easy handle. + * `action` is CURL_POLL_IN, CURL_POLL_OUT or CURL_POLL_INOUT. + */ +struct easy_pollset { + curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; + unsigned int num; + unsigned char actions[MAX_SOCKSPEREASYHANDLE]; +}; + +enum expect100 { + EXP100_SEND_DATA, /* enough waiting, just send the body now */ + EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */ + EXP100_SENDING_REQUEST, /* still sending the request but will wait for + the 100 header once done with the request */ + EXP100_FAILED /* used on 417 Expectation Failed */ +}; + +enum upgrade101 { + UPGR101_INIT, /* default state */ + UPGR101_WS, /* upgrade to WebSockets requested */ + UPGR101_H2, /* upgrade to HTTP/2 requested */ + UPGR101_RECEIVED, /* 101 response received */ + UPGR101_WORKING /* talking upgraded protocol */ +}; + +enum doh_slots { + /* Explicit values for first two symbols so as to match hard-coded + * constants in existing code + */ + DOH_PROBE_SLOT_IPADDR_V4 = 0, /* make 'V4' stand out for readability */ + DOH_PROBE_SLOT_IPADDR_V6 = 1, /* 'V6' likewise */ + + /* Space here for (possibly build-specific) additional slot definitions */ + + /* for example */ + /* #ifdef WANT_DOH_FOOBAR_TXT */ + /* DOH_PROBE_SLOT_FOOBAR_TXT, */ + /* #endif */ + + /* AFTER all slot definitions, establish how many we have */ + DOH_PROBE_SLOTS +}; + +/* + * Request specific data in the easy handle (Curl_easy). Previously, + * these members were on the connectdata struct but since a conn struct may + * now be shared between different Curl_easys, we store connection-specific + * data here. This struct only keeps stuff that's interesting for *this* + * request, as it will be cleared between multiple ones + */ +struct SingleRequest { + curl_off_t size; /* -1 if unknown at this point */ + curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, + -1 means unlimited */ + curl_off_t bytecount; /* total number of bytes read */ + curl_off_t writebytecount; /* number of bytes written */ + + curl_off_t pendingheader; /* this many bytes left to send is actually + header and not body */ + struct curltime start; /* transfer started at this time */ + unsigned int headerbytecount; /* received server headers (not CONNECT + headers) */ + unsigned int allheadercount; /* all received headers (server + CONNECT) */ + unsigned int deductheadercount; /* this amount of bytes doesn't count when + we check if anything has been transferred + at the end of a connection. We use this + counter to make only a 100 reply (without + a following second response code) result + in a CURLE_GOT_NOTHING error code */ + int headerline; /* counts header lines to better track the + first one */ + curl_off_t offset; /* possible resume offset read from the + Content-Range: header */ + int httpcode; /* error code from the 'HTTP/1.? XXX' or + 'RTSP/1.? XXX' line */ + int keepon; + struct curltime start100; /* time stamp to wait for the 100 code from */ + enum expect100 exp100; /* expect 100 continue state */ + enum upgrade101 upgr101; /* 101 upgrade state */ + + /* Client Writer stack, handles trasnfer- and content-encodings, protocol + * checks, pausing by client callbacks. */ + struct Curl_cwriter *writer_stack; + time_t timeofdoc; + long bodywrites; + char *location; /* This points to an allocated version of the Location: + header data */ + char *newurl; /* Set to the new URL to use when a redirect or a retry is + wanted */ + + /* 'upload_present' is used to keep a byte counter of how much data there is + still left in the buffer, aimed for upload. */ + ssize_t upload_present; + + /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a + buffer, so the next read should read from where this pointer points to, + and the 'upload_present' contains the number of bytes available at this + position */ + char *upload_fromhere; + + /* Allocated protocol-specific data. Each protocol handler makes sure this + points to data it needs. */ + union { + struct FILEPROTO *file; + struct FTP *ftp; + struct HTTP *http; + struct IMAP *imap; + struct ldapreqinfo *ldap; + struct MQTT *mqtt; + struct POP3 *pop3; + struct RTSP *rtsp; + struct smb_request *smb; + struct SMTP *smtp; + struct SSHPROTO *ssh; + struct TELNET *telnet; + } p; +#ifndef CURL_DISABLE_DOH + struct dohdata *doh; /* DoH specific data for this request */ +#endif +#if defined(_WIN32) && defined(USE_WINSOCK) + struct curltime last_sndbuf_update; /* last time readwrite_upload called + win_update_buffer_size */ +#endif + char fread_eof[2]; /* the body read callback (index 0) returned EOF or + the trailer read callback (index 1) returned EOF */ +#ifndef CURL_DISABLE_COOKIES + unsigned char setcookies; +#endif + BIT(header); /* incoming data has HTTP header */ + BIT(content_range); /* set TRUE if Content-Range: was found */ + BIT(download_done); /* set to TRUE when download is complete */ + BIT(eos_written); /* iff EOS has been written to client */ + BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding + upload and we're uploading the last chunk */ + BIT(ignorebody); /* we read a response-body but we ignore it! */ + BIT(http_bodyless); /* HTTP response status code is between 100 and 199, + 204 or 304 */ + BIT(chunk); /* if set, this is a chunked transfer-encoding */ + BIT(ignore_cl); /* ignore content-length */ + BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding + on upload */ + BIT(getheader); /* TRUE if header parsing is wanted */ + BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for + specific upload buffers. See readmoredata() in http.c + for details. */ + BIT(no_body); /* the response has no body */ +}; + +/* + * Specific protocol handler. + */ + +struct Curl_handler { + const char *scheme; /* URL scheme name. */ + + /* Complement to setup_connection_internals(). This is done before the + transfer "owns" the connection. */ + CURLcode (*setup_connection)(struct Curl_easy *data, + struct connectdata *conn); + + /* These two functions MUST be set to be protocol dependent */ + CURLcode (*do_it)(struct Curl_easy *data, bool *done); + CURLcode (*done)(struct Curl_easy *, CURLcode, bool); + + /* If the curl_do() function is better made in two halves, this + * curl_do_more() function will be called afterwards, if set. For example + * for doing the FTP stuff after the PASV/PORT command. + */ + CURLcode (*do_more)(struct Curl_easy *, int *); + + /* This function *MAY* be set to a protocol-dependent function that is run + * after the connect() and everything is done, as a step in the connection. + * The 'done' pointer points to a bool that should be set to TRUE if the + * function completes before return. If it doesn't complete, the caller + * should call the ->connecting() function until it is. + */ + CURLcode (*connect_it)(struct Curl_easy *data, bool *done); + + /* See above. */ + CURLcode (*connecting)(struct Curl_easy *data, bool *done); + CURLcode (*doing)(struct Curl_easy *data, bool *done); + + /* Called from the multi interface during the PROTOCONNECT phase, and it + should then return a proper fd set */ + int (*proto_getsock)(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); + + /* Called from the multi interface during the DOING phase, and it should + then return a proper fd set */ + int (*doing_getsock)(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); + + /* Called from the multi interface during the DO_MORE phase, and it should + then return a proper fd set */ + int (*domore_getsock)(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); + + /* Called from the multi interface during the DO_DONE, PERFORM and + WAITPERFORM phases, and it should then return a proper fd set. Not setting + this will make libcurl use the generic default one. */ + int (*perform_getsock)(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *socks); + + /* This function *MAY* be set to a protocol-dependent function that is run + * by the curl_disconnect(), as a step in the disconnection. If the handler + * is called because the connection has been considered dead, + * dead_connection is set to TRUE. The connection is (again) associated with + * the transfer here. + */ + CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *, + bool dead_connection); + + /* If used, this function gets called from transfer.c:readwrite_data() to + allow the protocol to do extra handling in writing response to + the client. */ + CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen, + bool is_eos, bool *done); + + /* This function can perform various checks on the connection. See + CONNCHECK_* for more information about the checks that can be performed, + and CONNRESULT_* for the results that can be returned. */ + unsigned int (*connection_check)(struct Curl_easy *data, + struct connectdata *conn, + unsigned int checks_to_perform); + + /* attach() attaches this transfer to this connection */ + void (*attach)(struct Curl_easy *data, struct connectdata *conn); + + int defport; /* Default port. */ + curl_prot_t protocol; /* See CURLPROTO_* - this needs to be the single + specific protocol bit */ + curl_prot_t family; /* single bit for protocol family; basically the + non-TLS name of the protocol this is */ + unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */ + +}; + +#define PROTOPT_NONE 0 /* nothing extra */ +#define PROTOPT_SSL (1<<0) /* uses SSL */ +#define PROTOPT_DUAL (1<<1) /* this protocol uses two connections */ +#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */ +/* some protocols will have to call the underlying functions without regard to + what exact state the socket signals. IE even if the socket says "readable", + the send function might need to be called while uploading, or vice versa. +*/ +#define PROTOPT_DIRLOCK (1<<3) +#define PROTOPT_NONETWORK (1<<4) /* protocol doesn't use the network! */ +#define PROTOPT_NEEDSPWD (1<<5) /* needs a password, and if none is set it + gets a default */ +#define PROTOPT_NOURLQUERY (1<<6) /* protocol can't handle + url query strings (?foo=bar) ! */ +#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per + request instead of per connection */ +#define PROTOPT_ALPN (1<<8) /* set ALPN for this */ +/* (1<<9) was PROTOPT_STREAM, now free */ +#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field + of the URL */ +#define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a + HTTP proxy as HTTP proxies may know + this protocol and act as a gateway */ +#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */ +#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in + user name and password */ +#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol can't proxy over TCP */ + +#define CONNCHECK_NONE 0 /* No checks */ +#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */ +#define CONNCHECK_KEEPALIVE (1<<1) /* Perform any keepalive function. */ + +#define CONNRESULT_NONE 0 /* No extra information. */ +#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */ + +struct proxy_info { + struct hostname host; + int port; + unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in + use */ + char *user; /* proxy user name string, allocated */ + char *passwd; /* proxy password string, allocated */ +}; + +struct ldapconninfo; + +#define TRNSPRT_TCP 3 +#define TRNSPRT_UDP 4 +#define TRNSPRT_QUIC 5 +#define TRNSPRT_UNIX 6 + +/* + * The connectdata struct contains all fields and variables that should be + * unique for an entire connection. + */ +struct connectdata { + struct Curl_llist_element bundle_node; /* conncache */ + + curl_closesocket_callback fclosesocket; /* function closing the socket(s) */ + void *closesocket_client; + + /* This is used by the connection cache logic. If this returns TRUE, this + handle is still used by one or more easy handles and can only used by any + other easy handle without careful consideration (== only for + multiplexing) and it cannot be used by another multi handle! */ +#define CONN_INUSE(c) ((c)->easyq.size) + + /**** Fields set when inited and not modified again */ + curl_off_t connection_id; /* Contains a unique number to make it easier to + track the connections in the log output */ + + /* 'dns_entry' is the particular host we use. This points to an entry in the + DNS cache and it will not get pruned while locked. It gets unlocked in + multi_done(). This entry will be NULL if the connection is reused as then + there is no name resolve done. */ + struct Curl_dns_entry *dns_entry; + + /* 'remote_addr' is the particular IP we connected to. it is owned, set + * and NULLed by the connected socket filter (if there is one). */ + const struct Curl_sockaddr_ex *remote_addr; + + struct hostname host; + char *hostname_resolve; /* host name to resolve to address, allocated */ + char *secondaryhostname; /* secondary socket host name (ftp) */ + struct hostname conn_to_host; /* the host to connect to. valid only if + bits.conn_to_host is set */ +#ifndef CURL_DISABLE_PROXY + struct proxy_info socks_proxy; + struct proxy_info http_proxy; +#endif + /* 'primary_ip' and 'primary_port' get filled with peer's numerical + ip address and port number whenever an outgoing connection is + *attempted* from the primary socket to a remote address. When more + than one address is tried for a connection these will hold data + for the last attempt. When the connection is actually established + these are updated with data which comes directly from the socket. */ + + char primary_ip[MAX_IPADR_LEN]; + char *user; /* user name string, allocated */ + char *passwd; /* password string, allocated */ + char *options; /* options string, allocated */ + char *sasl_authzid; /* authorization identity string, allocated */ + char *oauth_bearer; /* OAUTH2 bearer, allocated */ + struct curltime now; /* "current" time */ + struct curltime created; /* creation time */ + struct curltime lastused; /* when returned to the connection cache */ + curl_socket_t sock[2]; /* two sockets, the second is used for the data + transfer when doing FTP */ + Curl_recv *recv[2]; + Curl_send *send[2]; + struct Curl_cfilter *cfilter[2]; /* connection filters */ + + struct ssl_primary_config ssl_config; +#ifndef CURL_DISABLE_PROXY + struct ssl_primary_config proxy_ssl_config; +#endif + struct ConnectBits bits; /* various state-flags for this connection */ + + const struct Curl_handler *handler; /* Connection's protocol handler */ + const struct Curl_handler *given; /* The protocol first given */ + + /* Protocols can use a custom keepalive mechanism to keep connections alive. + This allows those protocols to track the last time the keepalive mechanism + was used on this connection. */ + struct curltime keepalive; + + /**** curl_get() phase fields */ + + curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */ + curl_socket_t writesockfd; /* socket to write to, it may very + well be the same we read from. + CURL_SOCKET_BAD disables */ + +#ifdef HAVE_GSSAPI + BIT(sec_complete); /* if Kerberos is enabled for this connection */ + unsigned char command_prot; /* enum protection_level */ + unsigned char data_prot; /* enum protection_level */ + unsigned char request_data_prot; /* enum protection_level */ + size_t buffer_size; + struct krb5buffer in_buffer; + void *app_data; + const struct Curl_sec_client_mech *mech; + struct sockaddr_in local_addr; +#endif + +#if defined(USE_KERBEROS5) /* Consider moving some of the above GSS-API */ + struct kerberos5data krb5; /* variables into the structure definition, */ +#endif /* however, some of them are ftp specific. */ + + struct Curl_llist easyq; /* List of easy handles using this connection */ + curl_seek_callback seek_func; /* function that seeks the input */ + void *seek_client; /* pointer to pass to the seek() above */ + + /*************** Request - specific items ************/ +#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS) + CtxtHandle *sslContext; +#endif + +#ifdef USE_GSASL + struct gsasldata gsasl; +#endif + +#if defined(USE_NTLM) + curlntlm http_ntlm_state; + curlntlm proxy_ntlm_state; + + struct ntlmdata ntlm; /* NTLM differs from other authentication schemes + because it authenticates connections, not + single requests! */ + struct ntlmdata proxyntlm; /* NTLM data for proxy */ +#endif + +#ifdef USE_SPNEGO + curlnegotiate http_negotiate_state; + curlnegotiate proxy_negotiate_state; + + struct negotiatedata negotiate; /* state data for host Negotiate auth */ + struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */ +#endif + + union { +#ifndef CURL_DISABLE_FTP + struct ftp_conn ftpc; +#endif +#ifdef USE_SSH + struct ssh_conn sshc; +#endif +#ifndef CURL_DISABLE_TFTP + struct tftp_state_data *tftpc; +#endif +#ifndef CURL_DISABLE_IMAP + struct imap_conn imapc; +#endif +#ifndef CURL_DISABLE_POP3 + struct pop3_conn pop3c; +#endif +#ifndef CURL_DISABLE_SMTP + struct smtp_conn smtpc; +#endif +#ifndef CURL_DISABLE_RTSP + struct rtsp_conn rtspc; +#endif +#ifndef CURL_DISABLE_SMB + struct smb_conn smbc; +#endif +#ifdef USE_LIBRTMP + void *rtmp; +#endif +#ifdef USE_OPENLDAP + struct ldapconninfo *ldapc; +#endif +#ifndef CURL_DISABLE_MQTT + struct mqtt_conn mqtt; +#endif +#ifdef USE_WEBSOCKETS + struct websocket *ws; +#endif + unsigned int unused:1; /* avoids empty union */ + } proto; + + struct connectbundle *bundle; /* The bundle we are member of */ +#ifdef USE_UNIX_SOCKETS + char *unix_domain_socket; +#endif +#ifdef USE_HYPER + /* if set, an alternative data transfer function */ + Curl_datastream datastream; +#endif + /* When this connection is created, store the conditions for the local end + bind. This is stored before the actual bind and before any connection is + made and will serve the purpose of being used for comparison reasons so + that subsequent bound-requested connections aren't accidentally reusing + wrong connections. */ + char *localdev; + unsigned short localportrange; + int waitfor; /* current READ/WRITE bits to wait for */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + int socks5_gssapi_enctype; +#endif + /* The field below gets set in connect.c:connecthost() */ + int port; /* which port to use locally - to connect to */ + int remote_port; /* the remote port, not the proxy port! */ + int conn_to_port; /* the remote port to connect to. valid only if + bits.conn_to_port is set */ +#ifdef ENABLE_IPV6 + unsigned int scope_id; /* Scope id for IPv6 */ +#endif + unsigned short localport; + unsigned short secondary_port; /* secondary socket remote port to connect to + (ftp) */ + unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION* + value */ +#ifndef CURL_DISABLE_PROXY + unsigned char proxy_alpn; /* APLN of proxy tunnel, CURL_HTTP_VERSION* */ +#endif + unsigned char transport; /* one of the TRNSPRT_* defines */ + unsigned char ip_version; /* copied from the Curl_easy at creation time */ + unsigned char httpversion; /* the HTTP version*10 reported by the server */ + unsigned char connect_only; + unsigned char gssapi_delegation; /* inherited from set.gssapi_delegation */ +}; + +#ifndef CURL_DISABLE_PROXY +#define CURL_CONN_HOST_DISPNAME(c) \ + ((c)->bits.socksproxy ? (c)->socks_proxy.host.dispname : \ + (c)->bits.httpproxy ? (c)->http_proxy.host.dispname : \ + (c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \ + (c)->host.dispname) +#else +#define CURL_CONN_HOST_DISPNAME(c) \ + (c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \ + (c)->host.dispname +#endif + +/* The end of connectdata. */ + +/* + * Struct to keep statistical and informational data. + * All variables in this struct must be initialized/reset in Curl_initinfo(). + */ +struct PureInfo { + int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ + int httpproxycode; /* response code from proxy when received separate */ + int httpversion; /* the http version number X.Y = X*10+Y */ + time_t filetime; /* If requested, this is might get set. Set to -1 if the + time was unretrievable. */ + curl_off_t request_size; /* the amount of bytes sent in the request(s) */ + unsigned long proxyauthavail; /* what proxy auth types were announced */ + unsigned long httpauthavail; /* what host auth types were announced */ + long numconnects; /* how many new connection did libcurl created */ + char *contenttype; /* the content type of the object */ + char *wouldredirect; /* URL this would've been redirected to if asked to */ + curl_off_t retry_after; /* info from Retry-After: header */ + unsigned int header_size; /* size of read header(s) in bytes */ + + /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip' + and, 'conn_local_port' are copied over from the connectdata struct in + order to allow curl_easy_getinfo() to return this information even when + the session handle is no longer associated with a connection, and also + allow curl_easy_reset() to clear this information from the session handle + without disturbing information which is still alive, and that might be + reused, in the connection cache. */ + + char conn_primary_ip[MAX_IPADR_LEN]; + int conn_primary_port; /* this is the destination port to the connection, + which might have been a proxy */ + int conn_remote_port; /* this is the "remote port", which is the port + number of the used URL, independent of proxy or + not */ + char conn_local_ip[MAX_IPADR_LEN]; + int conn_local_port; + const char *conn_scheme; + unsigned int conn_protocol; + struct curl_certinfo certs; /* info about the certs. Asked for with + CURLOPT_CERTINFO / CURLINFO_CERTINFO */ + CURLproxycode pxcode; + BIT(timecond); /* set to TRUE if the time condition didn't match, which + thus made the document NOT get fetched */ +}; + + +struct Progress { + time_t lastshow; /* time() of the last displayed progress meter or NULL to + force redraw at next call */ + curl_off_t size_dl; /* total expected size */ + curl_off_t size_ul; /* total expected size */ + curl_off_t downloaded; /* transferred so far */ + curl_off_t uploaded; /* transferred so far */ + + curl_off_t current_speed; /* uses the currently fastest transfer */ + + int width; /* screen width at download start */ + int flags; /* see progress.h */ + + timediff_t timespent; + + curl_off_t dlspeed; + curl_off_t ulspeed; + + timediff_t t_postqueue; + timediff_t t_nslookup; + timediff_t t_connect; + timediff_t t_appconnect; + timediff_t t_pretransfer; + timediff_t t_starttransfer; + timediff_t t_redirect; + + struct curltime start; + struct curltime t_startsingle; + struct curltime t_startop; + struct curltime t_acceptdata; + + + /* upload speed limit */ + struct curltime ul_limit_start; + curl_off_t ul_limit_size; + /* download speed limit */ + struct curltime dl_limit_start; + curl_off_t dl_limit_size; + +#define CURR_TIME (5 + 1) /* 6 entries for 5 seconds */ + + curl_off_t speeder[ CURR_TIME ]; + struct curltime speeder_time[ CURR_TIME ]; + int speeder_c; + BIT(callback); /* set when progress callback is used */ + BIT(is_t_startransfer_set); +}; + +typedef enum { + RTSPREQ_NONE, /* first in list */ + RTSPREQ_OPTIONS, + RTSPREQ_DESCRIBE, + RTSPREQ_ANNOUNCE, + RTSPREQ_SETUP, + RTSPREQ_PLAY, + RTSPREQ_PAUSE, + RTSPREQ_TEARDOWN, + RTSPREQ_GET_PARAMETER, + RTSPREQ_SET_PARAMETER, + RTSPREQ_RECORD, + RTSPREQ_RECEIVE, + RTSPREQ_LAST /* last in list */ +} Curl_RtspReq; + +struct auth { + unsigned long want; /* Bitmask set to the authentication methods wanted by + app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ + unsigned long picked; + unsigned long avail; /* Bitmask for what the server reports to support for + this resource */ + BIT(done); /* TRUE when the auth phase is done and ready to do the + actual request */ + BIT(multipass); /* TRUE if this is not yet authenticated but within the + auth multipass negotiation */ + BIT(iestyle); /* TRUE if digest should be done IE-style or FALSE if it + should be RFC compliant */ +}; + +#ifdef USE_NGHTTP2 +struct Curl_data_prio_node { + struct Curl_data_prio_node *next; + struct Curl_easy *data; +}; +#endif + +/** + * Priority information for an easy handle in relation to others + * on the same connection. + * TODO: we need to adapt it to the new priority scheme as defined in RFC 9218 + */ +struct Curl_data_priority { +#ifdef USE_NGHTTP2 + /* tree like dependencies only implemented in nghttp2 */ + struct Curl_easy *parent; + struct Curl_data_prio_node *children; +#endif + int weight; +#ifdef USE_NGHTTP2 + BIT(exclusive); +#endif +}; + +/* + * This struct is for holding data that was attempted to get sent to the user's + * callback but is held due to pausing. One instance per type (BOTH, HEADER, + * BODY). + */ +struct tempbuf { + struct dynbuf b; + int type; /* type of the 'tempwrite' buffer as a bitmask that is used with + Curl_client_write() */ + BIT(paused_body); /* if PAUSE happened before/during BODY write */ +}; + +/* Timers */ +typedef enum { + EXPIRE_100_TIMEOUT, + EXPIRE_ASYNC_NAME, + EXPIRE_CONNECTTIMEOUT, + EXPIRE_DNS_PER_NAME, /* family1 */ + EXPIRE_DNS_PER_NAME2, /* family2 */ + EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */ + EXPIRE_HAPPY_EYEBALLS, + EXPIRE_MULTI_PENDING, + EXPIRE_RUN_NOW, + EXPIRE_SPEEDCHECK, + EXPIRE_TIMEOUT, + EXPIRE_TOOFAST, + EXPIRE_QUIC, + EXPIRE_FTP_ACCEPT, + EXPIRE_ALPN_EYEBALLS, + EXPIRE_LAST /* not an actual timer, used as a marker only */ +} expire_id; + + +typedef enum { + TRAILERS_NONE, + TRAILERS_INITIALIZED, + TRAILERS_SENDING, + TRAILERS_DONE +} trailers_state; + + +/* + * One instance for each timeout an easy handle can set. + */ +struct time_node { + struct Curl_llist_element list; + struct curltime time; + expire_id eid; +}; + +/* individual pieces of the URL */ +struct urlpieces { + char *scheme; + char *hostname; + char *port; + char *user; + char *password; + char *options; + char *path; + char *query; +}; + +struct UrlState { + /* Points to the connection cache */ + struct conncache *conn_cache; + /* buffers to store authentication data in, as parsed from input options */ + struct curltime keeps_speed; /* for the progress meter really */ + + curl_off_t lastconnect_id; /* The last connection, -1 if undefined */ + curl_off_t recent_conn_id; /* The most recent connection used, might no + * longer exist */ + struct dynbuf headerb; /* buffer to store headers in */ + struct curl_slist *hstslist; /* list of HSTS files set by + curl_easy_setopt(HSTS) calls */ + char *buffer; /* download buffer */ + char *ulbuf; /* allocated upload buffer or NULL */ + curl_off_t current_speed; /* the ProgressShow() function sets this, + bytes / second */ + + /* host name, port number and protocol of the first (not followed) request. + if set, this should be the host name that we will sent authorization to, + no else. Used to make Location: following not keep sending user+password. + This is strdup()ed data. */ + char *first_host; + int first_remote_port; + curl_prot_t first_remote_protocol; + + int retrycount; /* number of retries on a new connection */ + struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ + long sessionage; /* number of the most recent session */ + struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */ + unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */ + int os_errno; /* filled in with errno whenever an error occurs */ + char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */ + long followlocation; /* redirect counter */ + int requests; /* request counter: redirects + authentication retakes */ +#ifdef HAVE_SIGNAL + /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ + void (*prev_signal)(int sig); +#endif +#ifndef CURL_DISABLE_DIGEST_AUTH + struct digestdata digest; /* state data for host Digest auth */ + struct digestdata proxydigest; /* state data for proxy Digest auth */ +#endif + struct auth authhost; /* auth details for host */ + struct auth authproxy; /* auth details for proxy */ +#ifdef USE_CURL_ASYNC + struct Curl_async async; /* asynchronous name resolver data */ +#endif + +#if defined(USE_OPENSSL) + /* void instead of ENGINE to avoid bleeding OpenSSL into this header */ + void *engine; +#endif /* USE_OPENSSL */ + struct curltime expiretime; /* set this with Curl_expire() only */ + struct Curl_tree timenode; /* for the splay stuff */ + struct Curl_llist timeoutlist; /* list of pending timeouts */ + struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */ + + /* a place to store the most recently set (S)FTP entrypath */ + char *most_recent_ftp_entrypath; +#if !defined(_WIN32) && !defined(MSDOS) && !defined(__EMX__) +/* do FTP line-end conversions on most platforms */ +#define CURL_DO_LINEEND_CONV + /* for FTP downloads: track CRLF sequences that span blocks */ + BIT(prev_block_had_trailing_cr); + /* for FTP downloads: how many CRLFs did we converted to LFs? */ + curl_off_t crlf_conversions; +#endif + char *range; /* range, if used. See README for detailed specification on + this syntax. */ + curl_off_t resume_from; /* continue [ftp] transfer from here */ + +#ifndef CURL_DISABLE_RTSP + /* This RTSP state information survives requests and connections */ + long rtsp_next_client_CSeq; /* the session's next client CSeq */ + long rtsp_next_server_CSeq; /* the session's next server CSeq */ + long rtsp_CSeq_recv; /* most recent CSeq received */ + + unsigned char rtp_channel_mask[32]; /* for the correctness checking of the + interleaved data */ +#endif + + curl_off_t infilesize; /* size of file to upload, -1 means unknown. + Copied from set.filesize at start of operation */ +#if defined(USE_HTTP2) || defined(USE_HTTP3) + struct Curl_data_priority priority; /* shallow copy of data->set */ +#endif + + curl_read_callback fread_func; /* read callback/function */ + void *in; /* CURLOPT_READDATA */ + CURLU *uh; /* URL handle for the current parsed URL */ + struct urlpieces up; + char *url; /* work URL, copied from UserDefined */ + char *referer; /* referer string */ + struct curl_slist *resolve; /* set to point to the set.resolve list when + this should be dealt with in pretransfer */ +#ifndef CURL_DISABLE_HTTP + curl_mimepart *mimepost; + curl_mimepart *formp; /* storage for old API form-posting, allocated on + demand */ + size_t trailers_bytes_sent; + struct dynbuf trailers_buf; /* a buffer containing the compiled trailing + headers */ + struct Curl_llist httphdrs; /* received headers */ + struct curl_header headerout[2]; /* for external purposes */ + struct Curl_header_store *prevhead; /* the latest added header */ + trailers_state trailers_state; /* whether we are sending trailers + and what stage are we at */ +#endif +#ifndef CURL_DISABLE_COOKIES + struct curl_slist *cookielist; /* list of cookie files set by + curl_easy_setopt(COOKIEFILE) calls */ +#endif +#ifdef USE_HYPER + bool hconnect; /* set if a CONNECT request */ + CURLcode hresult; /* used to pass return codes back from hyper callbacks */ +#endif + + /* Dynamically allocated strings, MUST be freed before this struct is + killed. */ + struct dynamically_allocated_data { + char *proxyuserpwd; + char *uagent; + char *accept_encoding; + char *userpwd; + char *rangeline; + char *ref; + char *host; + char *cookiehost; + char *rtsp_transport; + char *te; /* TE: request header */ + + /* transfer credentials */ + char *user; + char *passwd; + char *proxyuser; + char *proxypasswd; + } aptr; + + unsigned char httpwant; /* when non-zero, a specific HTTP version requested + to be used in the library's request(s) */ + unsigned char httpversion; /* the lowest HTTP version*10 reported by any + server involved in this request */ + unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) + is this */ + unsigned char select_bits; /* != 0 -> bitmask of socket events for this + transfer overriding anything the socket may + report */ +#ifdef CURLDEBUG + BIT(conncache_lock); +#endif + /* when curl_easy_perform() is called, the multi handle is "owned" by + the easy handle so curl_easy_cleanup() on such an easy handle will + also close the multi handle! */ + BIT(multi_owned_by_easy); + + BIT(this_is_a_follow); /* this is a followed Location: request */ + BIT(refused_stream); /* this was refused, try again */ + BIT(errorbuf); /* Set to TRUE if the error buffer is already filled in. + This must be set to FALSE every time _easy_perform() is + called. */ + BIT(allow_port); /* Is set.use_port allowed to take effect or not. This + is always set TRUE when curl_easy_perform() is called. */ + BIT(authproblem); /* TRUE if there's some problem authenticating */ + /* set after initial USER failure, to prevent an authentication loop */ + BIT(wildcardmatch); /* enable wildcard matching */ + BIT(expect100header); /* TRUE if we added Expect: 100-continue */ + BIT(disableexpect); /* TRUE if Expect: is disabled due to a previous + 417 response */ + BIT(use_range); + BIT(rangestringalloc); /* the range string is malloc()'ed */ + BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE + when multi_done() is called, to prevent multi_done() to get + invoked twice when the multi interface is used. */ + BIT(previouslypending); /* this transfer WAS in the multi->pending queue */ +#ifndef CURL_DISABLE_COOKIES + BIT(cookie_engine); +#endif + BIT(prefer_ascii); /* ASCII rather than binary */ +#ifdef CURL_LIST_ONLY_PROTOCOL + BIT(list_only); /* list directory contents */ +#endif + BIT(url_alloc); /* URL string is malloc()'ed */ + BIT(referer_alloc); /* referer string is malloc()ed */ + BIT(wildcard_resolve); /* Set to true if any resolve change is a wildcard */ + BIT(rewindbeforesend);/* TRUE when the sending couldn't be stopped even + though it will be discarded. We must call the data + rewind callback before trying to send again. */ + BIT(upload); /* upload request */ + BIT(internal); /* internal: true if this easy handle was created for + internal use and the user does not have ownership of the + handle. */ +}; + +/* + * This 'UserDefined' struct must only contain data that is set once to go + * for many (perhaps) independent connections. Values that are generated or + * calculated internally for the "session handle" MUST be defined within the + * 'struct UrlState' instead. The only exceptions MUST note the changes in + * the 'DynamicStatic' struct. + * Character pointer fields point to dynamic storage, unless otherwise stated. + */ + +struct Curl_multi; /* declared in multihandle.c */ + +/* + * This enumeration MUST not use conditional directives (#ifdefs), new + * null terminated strings MUST be added to the enumeration immediately + * before STRING_LASTZEROTERMINATED, binary fields immediately before + * STRING_LAST. When doing so, ensure that the packages/OS400/chkstring.c + * test is updated and applicable changes for EBCDIC to ASCII conversion + * are catered for in curl_easy_setopt_ccsid() + */ +enum dupstring { + STRING_CERT, /* client certificate file name */ + STRING_CERT_PROXY, /* client certificate file name */ + STRING_CERT_TYPE, /* format for certificate (default: PEM)*/ + STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/ + STRING_COOKIE, /* HTTP cookie string to send */ + STRING_COOKIEJAR, /* dump all cookies to this file */ + STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ + STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */ + STRING_DEVICE, /* local network interface/address to use */ + STRING_ENCODING, /* Accept-Encoding string */ + STRING_FTP_ACCOUNT, /* ftp account data */ + STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ + STRING_FTPPORT, /* port to send with the FTP PORT command */ + STRING_KEY, /* private key file name */ + STRING_KEY_PROXY, /* private key file name */ + STRING_KEY_PASSWD, /* plain text private key password */ + STRING_KEY_PASSWD_PROXY, /* plain text private key password */ + STRING_KEY_TYPE, /* format for private key (default: PEM) */ + STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */ + STRING_KRB_LEVEL, /* krb security level */ + STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find + $HOME/.netrc */ + STRING_PROXY, /* proxy to use */ + STRING_PRE_PROXY, /* pre socks proxy to use */ + STRING_SET_RANGE, /* range, if used */ + STRING_SET_REFERER, /* custom string for the HTTP referer field */ + STRING_SET_URL, /* what original URL to work on */ + STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAFILE, /* certificate file to verify peer against */ + STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */ + STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */ + STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */ + STRING_SSL_CIPHER_LIST, /* list of ciphers to use */ + STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */ + STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */ + STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */ + STRING_USERAGENT, /* User-Agent string */ + STRING_SSL_CRLFILE, /* crl file to check certificate */ + STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */ + STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */ + STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */ + STRING_SSL_ENGINE, /* name of ssl engine */ + STRING_USERNAME, /* , if used */ + STRING_PASSWORD, /* , if used */ + STRING_OPTIONS, /* , if used */ + STRING_PROXYUSERNAME, /* Proxy , if used */ + STRING_PROXYPASSWORD, /* Proxy , if used */ + STRING_NOPROXY, /* List of hosts which should not use the proxy, if + used */ + STRING_RTSP_SESSION_ID, /* Session ID to use */ + STRING_RTSP_STREAM_URI, /* Stream URI for this request */ + STRING_RTSP_TRANSPORT, /* Transport for this session */ + STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */ + STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */ + STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */ + STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */ + STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ + STRING_PROXY_SERVICE_NAME, /* Proxy service name */ + STRING_SERVICE_NAME, /* Service name */ + STRING_MAIL_FROM, + STRING_MAIL_AUTH, + STRING_TLSAUTH_USERNAME, /* TLS auth */ + STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth */ + STRING_TLSAUTH_PASSWORD, /* TLS auth */ + STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth */ + STRING_BEARER, /* , if used */ + STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */ + STRING_TARGET, /* CURLOPT_REQUEST_TARGET */ + STRING_DOH, /* CURLOPT_DOH_URL */ + STRING_ALTSVC, /* CURLOPT_ALTSVC */ + STRING_HSTS, /* CURLOPT_HSTS */ + STRING_SASL_AUTHZID, /* CURLOPT_SASL_AUTHZID */ + STRING_DNS_SERVERS, + STRING_DNS_INTERFACE, + STRING_DNS_LOCAL_IP4, + STRING_DNS_LOCAL_IP6, + STRING_SSL_EC_CURVES, + STRING_AWS_SIGV4, /* Parameters for V4 signature */ + STRING_HAPROXY_CLIENT_IP, /* CURLOPT_HAPROXY_CLIENT_IP */ + + /* -- end of null-terminated strings -- */ + + STRING_LASTZEROTERMINATED, + + /* -- below this are pointers to binary data that cannot be strdup'ed. --- */ + + STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ + + STRING_LAST /* not used, just an end-of-list marker */ +}; + +enum dupblob { + BLOB_CERT, + BLOB_CERT_PROXY, + BLOB_KEY, + BLOB_KEY_PROXY, + BLOB_SSL_ISSUERCERT, + BLOB_SSL_ISSUERCERT_PROXY, + BLOB_CAINFO, + BLOB_CAINFO_PROXY, + BLOB_LAST +}; + +/* callback that gets called when this easy handle is completed within a multi + handle. Only used for internally created transfers, like for example + DoH. */ +typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result); + +struct UserDefined { + FILE *err; /* the stderr user data goes here */ + void *debugdata; /* the data that will be passed to fdebug */ + char *errorbuffer; /* (Static) store failure messages in here */ + void *out; /* CURLOPT_WRITEDATA */ + void *in_set; /* CURLOPT_READDATA */ + void *writeheader; /* write the header to this if non-NULL */ + unsigned short use_port; /* which port to use (when not using default) */ + unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ + unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ + long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 + for infinity */ + + void *postfields; /* if POST, set the fields' values here */ + curl_seek_callback seek_func; /* function that seeks the input */ + curl_off_t postfieldsize; /* if POST, this might have a size to use instead + of strlen(), and then the data *may* be binary + (contain zero bytes) */ +#ifndef CURL_DISABLE_BINDLOCAL + unsigned short localport; /* local port number to bind to */ + unsigned short localportrange; /* number of additional port numbers to test + in case the 'localport' one can't be + bind()ed */ +#endif + curl_write_callback fwrite_func; /* function that stores the output */ + curl_write_callback fwrite_header; /* function that stores headers */ + curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */ + curl_read_callback fread_func_set; /* function that reads the input */ + curl_progress_callback fprogress; /* OLD and deprecated progress callback */ + curl_xferinfo_callback fxferinfo; /* progress callback */ + curl_debug_callback fdebug; /* function that write informational data */ + curl_ioctl_callback ioctl_func; /* function for I/O control */ + curl_sockopt_callback fsockopt; /* function for setting socket options */ + void *sockopt_client; /* pointer to pass to the socket options callback */ + curl_opensocket_callback fopensocket; /* function for checking/translating + the address and opening the + socket */ + void *opensocket_client; + curl_closesocket_callback fclosesocket; /* function for closing the + socket */ + void *closesocket_client; + curl_prereq_callback fprereq; /* pre-initial request callback */ + void *prereq_userp; /* pre-initial request user data */ + + void *seek_client; /* pointer to pass to the seek callback */ +#ifndef CURL_DISABLE_HSTS + curl_hstsread_callback hsts_read; + void *hsts_read_userp; + curl_hstswrite_callback hsts_write; + void *hsts_write_userp; +#endif + void *progress_client; /* pointer to pass to the progress callback */ + void *ioctl_client; /* pointer to pass to the ioctl callback */ + unsigned int timeout; /* ms, 0 means no timeout */ + unsigned int connecttimeout; /* ms, 0 means no timeout */ + unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */ + unsigned int server_response_timeout; /* ms, 0 means no timeout */ + long maxage_conn; /* in seconds, max idle time to allow a connection that + is to be reused */ + long maxlifetime_conn; /* in seconds, max time since creation to allow a + connection that is to be reused */ +#ifndef CURL_DISABLE_TFTP + long tftp_blksize; /* in bytes, 0 means use default */ +#endif + curl_off_t filesize; /* size of file to upload, -1 means unknown */ + long low_speed_limit; /* bytes/second */ + long low_speed_time; /* number of seconds */ + curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ + curl_off_t max_recv_speed; /* high speed limit in bytes/second for + download */ + curl_off_t set_resume_from; /* continue [ftp] transfer from here */ + struct curl_slist *headers; /* linked list of extra headers */ + struct curl_httppost *httppost; /* linked list of old POST data */ + curl_mimepart mimepost; /* MIME/POST data. */ +#ifndef CURL_DISABLE_TELNET + struct curl_slist *telnet_options; /* linked list of telnet options */ +#endif + struct curl_slist *resolve; /* list of names to add/remove from + DNS cache */ + struct curl_slist *connect_to; /* list of host:port mappings to override + the hostname and port to connect to */ + time_t timevalue; /* what time to compare with */ + unsigned char timecondition; /* kind of time comparison: curl_TimeCond */ + unsigned char method; /* what kind of HTTP request: Curl_HttpReq */ + unsigned char httpwant; /* when non-zero, a specific HTTP version requested + to be used in the library's request(s) */ + struct ssl_config_data ssl; /* user defined SSL stuff */ +#ifndef CURL_DISABLE_PROXY + struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ + struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */ + unsigned short proxyport; /* If non-zero, use this port number by + default. If the proxy string features a + ":[port]" that one will override this. */ + unsigned char proxytype; /* what kind of proxy: curl_proxytype */ + unsigned char socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */ +#endif + struct ssl_general_config general_ssl; /* general user defined SSL stuff */ + int dns_cache_timeout; /* DNS cache timeout (seconds) */ + unsigned int buffer_size; /* size of receive buffer to use */ + unsigned int upload_buffer_size; /* size of upload buffer to use, + keep it >= CURL_MAX_WRITE_SIZE */ + void *private_data; /* application-private data */ +#ifndef CURL_DISABLE_HTTP + struct curl_slist *http200aliases; /* linked list of aliases for http200 */ +#endif + unsigned char ipver; /* the CURL_IPRESOLVE_* defines in the public header + file 0 - whatever, 1 - v2, 2 - v6 */ + curl_off_t max_filesize; /* Maximum file size to download */ +#ifndef CURL_DISABLE_FTP + unsigned char ftp_filemethod; /* how to get to a file: curl_ftpfile */ + unsigned char ftpsslauth; /* what AUTH XXX to try: curl_ftpauth */ + unsigned char ftp_ccc; /* FTP CCC options: curl_ftpccc */ + unsigned int accepttimeout; /* in milliseconds, 0 means no timeout */ +#endif +#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) + struct curl_slist *quote; /* after connection is established */ + struct curl_slist *postquote; /* after the transfer */ + struct curl_slist *prequote; /* before the transfer, after type */ + /* Despite the name, ftp_create_missing_dirs is for FTP(S) and SFTP + 1 - create directories that don't exist + 2 - the same but also allow MKD to fail once + */ + unsigned char ftp_create_missing_dirs; +#endif +#ifdef USE_LIBSSH2 + curl_sshhostkeycallback ssh_hostkeyfunc; /* hostkey check callback */ + void *ssh_hostkeyfunc_userp; /* custom pointer to callback */ +#endif +#ifdef USE_SSH + curl_sshkeycallback ssh_keyfunc; /* key matching callback */ + void *ssh_keyfunc_userp; /* custom pointer to callback */ + int ssh_auth_types; /* allowed SSH auth types */ + unsigned int new_directory_perms; /* when creating remote dirs */ +#endif +#ifndef CURL_DISABLE_NETRC + unsigned char use_netrc; /* enum CURL_NETRC_OPTION values */ +#endif + unsigned int new_file_perms; /* when creating remote files */ + char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ + struct curl_blob *blobs[BLOB_LAST]; +#ifdef ENABLE_IPV6 + unsigned int scope_id; /* Scope id for IPv6 */ +#endif + curl_prot_t allowed_protocols; + curl_prot_t redir_protocols; +#ifndef CURL_DISABLE_RTSP + void *rtp_out; /* write RTP to this if non-NULL */ + /* Common RTSP header options */ + Curl_RtspReq rtspreq; /* RTSP request type */ +#endif +#ifndef CURL_DISABLE_FTP + curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer + starts */ + curl_chunk_end_callback chunk_end; /* called after part transferring + stopped */ + curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds + to pattern (e.g. if WILDCARDMATCH is on) */ + void *fnmatch_data; + void *wildcardptr; +#endif + /* GSS-API credential delegation, see the documentation of + CURLOPT_GSSAPI_DELEGATION */ + unsigned char gssapi_delegation; + + int tcp_keepidle; /* seconds in idle before sending keepalive probe */ + int tcp_keepintvl; /* seconds between TCP keepalive probes */ + + long expect_100_timeout; /* in milliseconds */ +#if defined(USE_HTTP2) || defined(USE_HTTP3) + struct Curl_data_priority priority; +#endif + curl_resolver_start_callback resolver_start; /* optional callback called + before resolver start */ + void *resolver_start_client; /* pointer to pass to resolver start callback */ + long upkeep_interval_ms; /* Time between calls for connection upkeep. */ + multidone_func fmultidone; +#ifndef CURL_DISABLE_DOH + struct Curl_easy *dohfor; /* this is a DoH request for that transfer */ +#endif + CURLU *uh; /* URL handle for the current parsed URL */ +#ifndef CURL_DISABLE_HTTP + void *trailer_data; /* pointer to pass to trailer data callback */ + curl_trailer_callback trailer_callback; /* trailing data callback */ +#endif + char keep_post; /* keep POSTs as POSTs after a 30x request; each + bit represents a request, from 301 to 303 */ +#ifndef CURL_DISABLE_SMTP + struct curl_slist *mail_rcpt; /* linked list of mail recipients */ + BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some + recipients */ +#endif + unsigned int maxconnects; /* Max idle connections in the connection cache */ + unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or + IMAP or POP3 or others! (type: curl_usessl)*/ + unsigned char connect_only; /* make connection/request, then let + application use the socket */ +#ifndef CURL_DISABLE_MIME + BIT(mime_formescape); +#endif + BIT(is_fread_set); /* has read callback been set to non-NULL? */ +#ifndef CURL_DISABLE_TFTP + BIT(tftp_no_options); /* do not send TFTP options requests */ +#endif + BIT(sep_headers); /* handle host and proxy headers separately */ +#ifndef CURL_DISABLE_COOKIES + BIT(cookiesession); /* new cookie session? */ +#endif + BIT(crlf); /* convert crlf on ftp upload(?) */ + BIT(ssh_compression); /* enable SSH compression */ + +/* Here follows boolean settings that define how to behave during + this session. They are STATIC, set by libcurl users or at least initially + and they don't change during operations. */ + BIT(quick_exit); /* set 1L when it is okay to leak things (like + threads), as we're about to exit() anyway and + don't want lengthy cleanups to delay termination, + e.g. after a DNS timeout */ + BIT(get_filetime); /* get the time and get of the remote file */ + BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */ + BIT(prefer_ascii); /* ASCII rather than binary */ + BIT(remote_append); /* append, not overwrite, on upload */ +#ifdef CURL_LIST_ONLY_PROTOCOL + BIT(list_only); /* list directory */ +#endif +#ifndef CURL_DISABLE_FTP + BIT(ftp_use_port); /* use the FTP PORT command */ + BIT(ftp_use_epsv); /* if EPSV is to be attempted or not */ + BIT(ftp_use_eprt); /* if EPRT is to be attempted or not */ + BIT(ftp_use_pret); /* if PRET is to be used before PASV or not */ + BIT(ftp_skip_ip); /* skip the IP address the FTP server passes on to + us */ + BIT(wildcard_enabled); /* enable wildcard matching */ +#endif + BIT(hide_progress); /* don't use the progress meter */ + BIT(http_fail_on_error); /* fail on HTTP error codes >= 400 */ + BIT(http_keep_sending_on_error); /* for HTTP status codes >= 300 */ + BIT(http_follow_location); /* follow HTTP redirects */ + BIT(http_transfer_encoding); /* request compressed HTTP transfer-encoding */ + BIT(allow_auth_to_other_hosts); + BIT(include_header); /* include received protocol headers in data output */ + BIT(http_set_referer); /* is a custom referer used */ + BIT(http_auto_referer); /* set "correct" referer when following + location: */ + BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ + BIT(verbose); /* output verbosity */ + BIT(krb); /* Kerberos connection requested */ + BIT(reuse_forbid); /* forbidden to be reused, close after use */ + BIT(reuse_fresh); /* do not reuse an existing connection */ + BIT(no_signal); /* do not use any signal/alarm handler */ + BIT(tcp_nodelay); /* whether to enable TCP_NODELAY or not */ + BIT(ignorecl); /* ignore content length */ + BIT(http_te_skip); /* pass the raw body data to the user, even when + transfer-encoded (chunked, compressed) */ + BIT(http_ce_skip); /* pass the raw body data to the user, even when + content-encoded (chunked, compressed) */ + BIT(proxy_transfer_mode); /* set transfer mode (;type=) when doing + FTP via an HTTP proxy */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + BIT(socks5_gssapi_nec); /* Flag to support NEC SOCKS5 server */ +#endif + BIT(sasl_ir); /* Enable/disable SASL initial response */ + BIT(tcp_keepalive); /* use TCP keepalives */ + BIT(tcp_fastopen); /* use TCP Fast Open */ + BIT(ssl_enable_alpn);/* TLS ALPN extension? */ + BIT(path_as_is); /* allow dotdots? */ + BIT(pipewait); /* wait for multiplex status before starting a new + connection */ + BIT(suppress_connect_headers); /* suppress proxy CONNECT response headers + from user callbacks */ + BIT(dns_shuffle_addresses); /* whether to shuffle addresses before use */ + BIT(haproxyprotocol); /* whether to send HAProxy PROXY protocol v1 + header */ + BIT(abstract_unix_socket); + BIT(disallow_username_in_url); /* disallow username in url */ +#ifndef CURL_DISABLE_DOH + BIT(doh); /* DNS-over-HTTPS enabled */ + BIT(doh_verifypeer); /* DoH certificate peer verification */ + BIT(doh_verifyhost); /* DoH certificate hostname verification */ + BIT(doh_verifystatus); /* DoH certificate status verification */ +#endif + BIT(http09_allowed); /* allow HTTP/0.9 responses */ +#ifdef USE_WEBSOCKETS + BIT(ws_raw_mode); +#endif +}; + +struct Names { + struct Curl_hash *hostcache; + enum { + HCACHE_NONE, /* not pointing to anything */ + HCACHE_MULTI, /* points to a shared one in the multi handle */ + HCACHE_SHARED /* points to a shared one in a shared object */ + } hostcachetype; +}; + +/* + * The 'connectdata' struct MUST have all the connection oriented stuff as we + * may have several simultaneous connections and connection structs in memory. + * + * The 'struct UserDefined' must only contain data that is set once to go for + * many (perhaps) independent connections. Values that are generated or + * calculated internally for the "session handle" must be defined within the + * 'struct UrlState' instead. + */ + +struct Curl_easy { + /* First a simple identifier to easier detect if a user mix up this easy + handle with a multi handle. Set this to CURLEASY_MAGIC_NUMBER */ + unsigned int magic; + /* once an easy handle is tied to a connection cache + a non-negative number to distinguish this transfer from + other using the same cache. For easier tracking + in log output. + This may wrap around after LONG_MAX to 0 again, so it + has no uniqueness guarantee for very large processings. */ + curl_off_t id; + + /* first, two fields for the linked list of these */ + struct Curl_easy *next; + struct Curl_easy *prev; + + struct connectdata *conn; + struct Curl_llist_element connect_queue; /* for the pending and msgsent + lists */ + struct Curl_llist_element conn_queue; /* list per connectdata */ + + CURLMstate mstate; /* the handle's state */ + CURLcode result; /* previous result */ + + struct Curl_message msg; /* A single posted message. */ + + /* Array with the plain socket numbers this handle takes care of, in no + particular order. Note that all sockets are added to the sockhash, where + the state etc are also kept. This array is mostly used to detect when a + socket is to be removed from the hash. See singlesocket(). */ + struct easy_pollset last_poll; + + struct Names dns; + struct Curl_multi *multi; /* if non-NULL, points to the multi handle + struct to which this "belongs" when used by + the multi interface */ + struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle + struct to which this "belongs" when used + by the easy interface */ + struct Curl_share *share; /* Share, handles global variable mutexing */ +#ifdef USE_LIBPSL + struct PslCache *psl; /* The associated PSL cache. */ +#endif + struct SingleRequest req; /* Request-specific data */ + struct UserDefined set; /* values set by the libcurl user */ +#ifndef CURL_DISABLE_COOKIES + struct CookieInfo *cookies; /* the cookies, read from files and servers. + NOTE that the 'cookie' field in the + UserDefined struct defines if the "engine" + is to be used or not. */ +#endif +#ifndef CURL_DISABLE_HSTS + struct hsts *hsts; +#endif +#ifndef CURL_DISABLE_ALTSVC + struct altsvcinfo *asi; /* the alt-svc cache */ +#endif + struct Progress progress; /* for all the progress meter data */ + struct UrlState state; /* struct for fields used for state info and + other dynamic purposes */ +#ifndef CURL_DISABLE_FTP + struct WildcardData *wildcard; /* wildcard download state info */ +#endif + struct PureInfo info; /* stats, reports and info data */ + struct curl_tlssessioninfo tsi; /* Information about the TLS session, only + valid after a client has asked for it */ +#ifdef USE_HYPER + struct hyptransfer hyp; +#endif +}; + +#define LIBCURL_NAME "libcurl" + +#endif /* HEADER_CURL_URLDATA_H */ diff --git a/lib/vauth/cleartext.c b/lib/vauth/cleartext.c new file mode 100644 index 0000000..972a874 --- /dev/null +++ b/lib/vauth/cleartext.c @@ -0,0 +1,138 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC4616 PLAIN authentication + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_POP3) || \ + (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)) + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "warnless.h" +#include "strtok.h" +#include "sendf.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_plain_message() + * + * This is used to generate an already encoded PLAIN message ready + * for sending to the recipient. + * + * Parameters: + * + * authzid [in] - The authorization identity. + * authcid [in] - The authentication identity. + * passwd [in] - The password. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_plain_message(const char *authzid, + const char *authcid, + const char *passwd, + struct bufref *out) +{ + char *plainauth; + size_t plainlen; + size_t zlen; + size_t clen; + size_t plen; + + zlen = (authzid == NULL ? 0 : strlen(authzid)); + clen = strlen(authcid); + plen = strlen(passwd); + + /* Compute binary message length. Check for overflows. */ + if((zlen > SIZE_T_MAX/4) || (clen > SIZE_T_MAX/4) || + (plen > (SIZE_T_MAX/2 - 2))) + return CURLE_OUT_OF_MEMORY; + plainlen = zlen + clen + plen + 2; + + plainauth = malloc(plainlen + 1); + if(!plainauth) + return CURLE_OUT_OF_MEMORY; + + /* Calculate the reply */ + if(zlen) + memcpy(plainauth, authzid, zlen); + plainauth[zlen] = '\0'; + memcpy(plainauth + zlen + 1, authcid, clen); + plainauth[zlen + clen + 1] = '\0'; + memcpy(plainauth + zlen + clen + 2, passwd, plen); + plainauth[plainlen] = '\0'; + Curl_bufref_set(out, plainauth, plainlen, curl_free); + return CURLE_OK; +} + +/* + * Curl_auth_create_login_message() + * + * This is used to generate an already encoded LOGIN message containing the + * user name or password ready for sending to the recipient. + * + * Parameters: + * + * valuep [in] - The user name or user's password. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_login_message(const char *valuep, struct bufref *out) +{ + Curl_bufref_set(out, valuep, strlen(valuep), NULL); + return CURLE_OK; +} + +/* + * Curl_auth_create_external_message() + * + * This is used to generate an already encoded EXTERNAL message containing + * the user name ready for sending to the recipient. + * + * Parameters: + * + * user [in] - The user name. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_external_message(const char *user, + struct bufref *out) +{ + /* This is the same formatting as the login message */ + return Curl_auth_create_login_message(user, out); +} + +#endif /* if no users */ diff --git a/lib/vauth/cram.c b/lib/vauth/cram.c new file mode 100644 index 0000000..91fb261 --- /dev/null +++ b/lib/vauth/cram.c @@ -0,0 +1,97 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC2195 CRAM-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_DIGEST_AUTH + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "curl_hmac.h" +#include "curl_md5.h" +#include "warnless.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + + +/* + * Curl_auth_create_cram_md5_message() + * + * This is used to generate a CRAM-MD5 response message ready for sending to + * the recipient. + * + * Parameters: + * + * chlg [in] - The challenge. + * userp [in] - The user name. + * passwdp [in] - The user's password. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg, + const char *userp, + const char *passwdp, + struct bufref *out) +{ + struct HMAC_context *ctxt; + unsigned char digest[MD5_DIGEST_LEN]; + char *response; + + /* Compute the digest using the password as the key */ + ctxt = Curl_HMAC_init(Curl_HMAC_MD5, + (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + /* Update the digest with the given challenge */ + if(Curl_bufref_len(chlg)) + Curl_HMAC_update(ctxt, Curl_bufref_ptr(chlg), + curlx_uztoui(Curl_bufref_len(chlg))); + + /* Finalise the digest */ + Curl_HMAC_final(ctxt, digest); + + /* Generate the response */ + response = aprintf( + "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + userp, digest[0], digest[1], digest[2], digest[3], digest[4], + digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], + digest[11], digest[12], digest[13], digest[14], digest[15]); + if(!response) + return CURLE_OUT_OF_MEMORY; + + Curl_bufref_set(out, response, strlen(response), curl_free); + return CURLE_OK; +} + +#endif /* !CURL_DISABLE_DIGEST_AUTH */ diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c new file mode 100644 index 0000000..416da0f --- /dev/null +++ b/lib/vauth/digest.c @@ -0,0 +1,994 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC2831 DIGEST-MD5 authentication + * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_DIGEST_AUTH + +#include + +#include "vauth/vauth.h" +#include "vauth/digest.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_hmac.h" +#include "curl_md5.h" +#include "curl_sha256.h" +#include "vtls/vtls.h" +#include "warnless.h" +#include "strtok.h" +#include "strcase.h" +#include "curl_printf.h" +#include "rand.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#define SESSION_ALGO 1 /* for algos with this bit set */ + +#define ALGO_MD5 0 +#define ALGO_MD5SESS (ALGO_MD5 | SESSION_ALGO) +#define ALGO_SHA256 2 +#define ALGO_SHA256SESS (ALGO_SHA256 | SESSION_ALGO) +#define ALGO_SHA512_256 4 +#define ALGO_SHA512_256SESS (ALGO_SHA512_256 | SESSION_ALGO) + +#if !defined(USE_WINDOWS_SSPI) +#define DIGEST_QOP_VALUE_AUTH (1 << 0) +#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) +#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) + +#define DIGEST_QOP_VALUE_STRING_AUTH "auth" +#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" +#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" +#endif + +bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, + const char **endptr) +{ + int c; + bool starts_with_quote = FALSE; + bool escape = FALSE; + + for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);) + *value++ = *str++; + *value = 0; + + if('=' != *str++) + /* eek, no match */ + return FALSE; + + if('\"' == *str) { + /* This starts with a quote so it must end with one as well! */ + str++; + starts_with_quote = TRUE; + } + + for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { + if(!escape) { + switch(*str) { + case '\\': + if(starts_with_quote) { + /* the start of an escaped quote */ + escape = TRUE; + continue; + } + break; + + case ',': + if(!starts_with_quote) { + /* This signals the end of the content if we didn't get a starting + quote and then we do "sloppy" parsing */ + c = 0; /* the end */ + continue; + } + break; + + case '\r': + case '\n': + /* end of string */ + if(starts_with_quote) + return FALSE; /* No closing quote */ + c = 0; + continue; + + case '\"': + if(starts_with_quote) { + /* end of string */ + c = 0; + continue; + } + else + return FALSE; + } + } + + escape = FALSE; + *content++ = *str; + } + if(escape) + return FALSE; /* No character after backslash */ + + *content = 0; + *endptr = str; + + return TRUE; +} + +#if !defined(USE_WINDOWS_SSPI) +/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string */ +static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ + unsigned char *dest) /* 33 bytes */ +{ + int i; + for(i = 0; i < 16; i++) + msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); +} + +/* Convert sha256 chunk to RFC7616 -suitable ascii string */ +static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */ + unsigned char *dest) /* 65 bytes */ +{ + int i; + for(i = 0; i < 32; i++) + msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); +} + +/* Perform quoted-string escaping as described in RFC2616 and its errata */ +static char *auth_digest_string_quoted(const char *source) +{ + char *dest; + const char *s = source; + size_t n = 1; /* null terminator */ + + /* Calculate size needed */ + while(*s) { + ++n; + if(*s == '"' || *s == '\\') { + ++n; + } + ++s; + } + + dest = malloc(n); + if(dest) { + char *d = dest; + s = source; + while(*s) { + if(*s == '"' || *s == '\\') { + *d++ = '\\'; + } + *d++ = *s++; + } + *d = '\0'; + } + + return dest; +} + +/* Retrieves the value for a corresponding key from the challenge string + * returns TRUE if the key could be found, FALSE if it does not exists + */ +static bool auth_digest_get_key_value(const char *chlg, + const char *key, + char *value, + size_t max_val_len, + char end_char) +{ + char *find_pos; + size_t i; + + find_pos = strstr(chlg, key); + if(!find_pos) + return FALSE; + + find_pos += strlen(key); + + for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) + value[i] = *find_pos++; + value[i] = '\0'; + + return TRUE; +} + +static CURLcode auth_digest_get_qop_values(const char *options, int *value) +{ + char *tmp; + char *token; + char *tok_buf = NULL; + + /* Initialise the output */ + *value = 0; + + /* Tokenise the list of qop values. Use a temporary clone of the buffer since + strtok_r() ruins it. */ + tmp = strdup(options); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token) { + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) + *value |= DIGEST_QOP_VALUE_AUTH; + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) + *value |= DIGEST_QOP_VALUE_AUTH_INT; + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) + *value |= DIGEST_QOP_VALUE_AUTH_CONF; + + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + return CURLE_OK; +} + +/* + * auth_decode_digest_md5_message() + * + * This is used internally to decode an already encoded DIGEST-MD5 challenge + * message into the separate attributes. + * + * Parameters: + * + * chlgref [in] - The challenge message. + * nonce [in/out] - The buffer where the nonce will be stored. + * nlen [in] - The length of the nonce buffer. + * realm [in/out] - The buffer where the realm will be stored. + * rlen [in] - The length of the realm buffer. + * alg [in/out] - The buffer where the algorithm will be stored. + * alen [in] - The length of the algorithm buffer. + * qop [in/out] - The buffer where the qop-options will be stored. + * qlen [in] - The length of the qop buffer. + * + * Returns CURLE_OK on success. + */ +static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref, + char *nonce, size_t nlen, + char *realm, size_t rlen, + char *alg, size_t alen, + char *qop, size_t qlen) +{ + const char *chlg = (const char *) Curl_bufref_ptr(chlgref); + + /* Ensure we have a valid challenge message */ + if(!Curl_bufref_len(chlgref)) + return CURLE_BAD_CONTENT_ENCODING; + + /* Retrieve nonce string from the challenge */ + if(!auth_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"')) + return CURLE_BAD_CONTENT_ENCODING; + + /* Retrieve realm string from the challenge */ + if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) { + /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ + strcpy(realm, ""); + } + + /* Retrieve algorithm string from the challenge */ + if(!auth_digest_get_key_value(chlg, "algorithm=", alg, alen, ',')) + return CURLE_BAD_CONTENT_ENCODING; + + /* Retrieve qop-options string from the challenge */ + if(!auth_digest_get_key_value(chlg, "qop=\"", qop, qlen, '\"')) + return CURLE_BAD_CONTENT_ENCODING; + + return CURLE_OK; +} + +/* + * Curl_auth_is_digest_supported() + * + * This is used to evaluate if DIGEST is supported. + * + * Parameters: None + * + * Returns TRUE as DIGEST as handled by libcurl. + */ +bool Curl_auth_is_digest_supported(void) +{ + return TRUE; +} + +/* + * Curl_auth_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg [in] - The challenge message. + * userp [in] - The user name. + * passwdp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, + const struct bufref *chlg, + const char *userp, + const char *passwdp, + const char *service, + struct bufref *out) +{ + size_t i; + struct MD5_context *ctxt; + char *response = NULL; + unsigned char digest[MD5_DIGEST_LEN]; + char HA1_hex[2 * MD5_DIGEST_LEN + 1]; + char HA2_hex[2 * MD5_DIGEST_LEN + 1]; + char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; + char nonce[64]; + char realm[128]; + char algorithm[64]; + char qop_options[64]; + int qop_values; + char cnonce[33]; + char nonceCount[] = "00000001"; + char method[] = "AUTHENTICATE"; + char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; + char *spn = NULL; + + /* Decode the challenge message */ + CURLcode result = auth_decode_digest_md5_message(chlg, + nonce, sizeof(nonce), + realm, sizeof(realm), + algorithm, + sizeof(algorithm), + qop_options, + sizeof(qop_options)); + if(result) + return result; + + /* We only support md5 sessions */ + if(strcmp(algorithm, "md5-sess") != 0) + return CURLE_BAD_CONTENT_ENCODING; + + /* Get the qop-values from the qop-options */ + result = auth_digest_get_qop_values(qop_options, &qop_values); + if(result) + return result; + + /* We only support auth quality-of-protection */ + if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) + return CURLE_BAD_CONTENT_ENCODING; + + /* Generate 32 random hex chars, 32 bytes + 1 null-termination */ + result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce)); + if(result) + return result; + + /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) userp, + curlx_uztoui(strlen(userp))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) realm, + curlx_uztoui(strlen(realm))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + Curl_MD5_final(ctxt, digest); + + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_final(ctxt, digest); + + /* Convert calculated 16 octet hex into 32 bytes string */ + for(i = 0; i < MD5_DIGEST_LEN; i++) + msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate our SPN */ + spn = Curl_auth_build_spn(service, data->conn->host.name, NULL); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Calculate H(A2) */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) method, + curlx_uztoui(strlen(method))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) spn, + curlx_uztoui(strlen(spn))); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); + + /* Now calculate the response hash */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, + curlx_uztoui(strlen(nonceCount))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) qop, + curlx_uztoui(strlen(qop))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate the response */ + response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," + "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," + "qop=%s", + userp, realm, nonce, + cnonce, nonceCount, spn, resp_hash_hex, qop); + free(spn); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Return the response. */ + Curl_bufref_set(out, response, strlen(response), curl_free); + return result; +} + +/* + * Curl_auth_decode_digest_http_message() + * + * This is used to decode an HTTP DIGEST challenge message into the separate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + bool before = FALSE; /* got a nonce before */ + bool foundAuth = FALSE; + bool foundAuthInt = FALSE; + char *token = NULL; + char *tmp = NULL; + + /* If we already have received a nonce, keep that in mind */ + if(digest->nonce) + before = TRUE; + + /* Clean up any former leftovers and initialise to defaults */ + Curl_auth_digest_cleanup(digest); + + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISBLANK(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { + if(strcasecompare(value, "nonce")) { + free(digest->nonce); + digest->nonce = strdup(content); + if(!digest->nonce) + return CURLE_OUT_OF_MEMORY; + } + else if(strcasecompare(value, "stale")) { + if(strcasecompare(content, "true")) { + digest->stale = TRUE; + digest->nc = 1; /* we make a new nonce now */ + } + } + else if(strcasecompare(value, "realm")) { + free(digest->realm); + digest->realm = strdup(content); + if(!digest->realm) + return CURLE_OUT_OF_MEMORY; + } + else if(strcasecompare(value, "opaque")) { + free(digest->opaque); + digest->opaque = strdup(content); + if(!digest->opaque) + return CURLE_OUT_OF_MEMORY; + } + else if(strcasecompare(value, "qop")) { + char *tok_buf = NULL; + /* Tokenize the list and choose auth if possible, use a temporary + clone of the buffer since strtok_r() ruins it */ + tmp = strdup(content); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token) { + /* Pass additional spaces here */ + while(*token && ISBLANK(*token)) + token++; + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + foundAuth = TRUE; + } + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + foundAuthInt = TRUE; + } + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + /* Select only auth or auth-int. Otherwise, ignore */ + if(foundAuth) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + else if(foundAuthInt) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + } + else if(strcasecompare(value, "algorithm")) { + free(digest->algorithm); + digest->algorithm = strdup(content); + if(!digest->algorithm) + return CURLE_OUT_OF_MEMORY; + + if(strcasecompare(content, "MD5-sess")) + digest->algo = ALGO_MD5SESS; + else if(strcasecompare(content, "MD5")) + digest->algo = ALGO_MD5; + else if(strcasecompare(content, "SHA-256")) + digest->algo = ALGO_SHA256; + else if(strcasecompare(content, "SHA-256-SESS")) + digest->algo = ALGO_SHA256SESS; + else if(strcasecompare(content, "SHA-512-256")) + digest->algo = ALGO_SHA512_256; + else if(strcasecompare(content, "SHA-512-256-SESS")) + digest->algo = ALGO_SHA512_256SESS; + else + return CURLE_BAD_CONTENT_ENCODING; + } + else if(strcasecompare(value, "userhash")) { + if(strcasecompare(content, "true")) { + digest->userhash = TRUE; + } + } + else { + /* Unknown specifier, ignore it! */ + } + } + else + break; /* We're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISBLANK(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + + /* We had a nonce since before, and we got another one now without + 'stale=true'. This means we provided bad credentials in the previous + request */ + if(before && !digest->stale) + return CURLE_BAD_CONTENT_ENCODING; + + /* We got this header without a nonce, that's a bad Digest line! */ + if(!digest->nonce) + return CURLE_BAD_CONTENT_ENCODING; + + /* "-sess" protocol versions require "auth" or "auth-int" qop */ + if(!digest->qop && (digest->algo & SESSION_ALGO)) + return CURLE_BAD_CONTENT_ENCODING; + + return CURLE_OK; +} + +/* + * auth_create_digest_http_message() + * + * This is used to generate an HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passwdp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode auth_create_digest_http_message( + struct Curl_easy *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen, + void (*convert_to_ascii)(unsigned char *, unsigned char *), + CURLcode (*hash)(unsigned char *, const unsigned char *, + const size_t)) +{ + CURLcode result; + unsigned char hashbuf[32]; /* 32 bytes/256 bits */ + unsigned char request_digest[65]; + unsigned char ha1[65]; /* 64 digits and 1 zero byte */ + unsigned char ha2[65]; /* 64 digits and 1 zero byte */ + char userh[65]; + char *cnonce = NULL; + size_t cnonce_sz = 0; + char *userp_quoted; + char *realm_quoted; + char *nonce_quoted; + char *response = NULL; + char *hashthis = NULL; + char *tmp = NULL; + + memset(hashbuf, 0, sizeof(hashbuf)); + if(!digest->nc) + digest->nc = 1; + + if(!digest->cnonce) { + char cnoncebuf[33]; + result = Curl_rand_hex(data, (unsigned char *)cnoncebuf, + sizeof(cnoncebuf)); + if(result) + return result; + + result = Curl_base64_encode(cnoncebuf, strlen(cnoncebuf), + &cnonce, &cnonce_sz); + if(result) + return result; + + digest->cnonce = cnonce; + } + + if(digest->userhash) { + hashthis = aprintf("%s:%s", userp, digest->realm ? digest->realm : ""); + if(!hashthis) + return CURLE_OUT_OF_MEMORY; + + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); + free(hashthis); + convert_to_ascii(hashbuf, (unsigned char *)userh); + } + + /* + If the algorithm is "MD5" or unspecified (which then defaults to MD5): + + A1 = unq(username-value) ":" unq(realm-value) ":" passwd + + If the algorithm is "MD5-sess" then: + + A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":" + unq(nonce-value) ":" unq(cnonce-value) + */ + + hashthis = aprintf("%s:%s:%s", userp, digest->realm ? digest->realm : "", + passwdp); + if(!hashthis) + return CURLE_OUT_OF_MEMORY; + + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); + free(hashthis); + convert_to_ascii(hashbuf, ha1); + + if(digest->algo & SESSION_ALGO) { + /* nonce and cnonce are OUTSIDE the hash */ + tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + hash(hashbuf, (unsigned char *) tmp, strlen(tmp)); + free(tmp); + convert_to_ascii(hashbuf, ha1); + } + + /* + If the "qop" directive's value is "auth" or is unspecified, then A2 is: + + A2 = Method ":" digest-uri-value + + If the "qop" value is "auth-int", then A2 is: + + A2 = Method ":" digest-uri-value ":" H(entity-body) + + (The "Method" value is the HTTP request method as specified in section + 5.1.1 of RFC 2616) + */ + + hashthis = aprintf("%s:%s", request, uripath); + if(!hashthis) + return CURLE_OUT_OF_MEMORY; + + if(digest->qop && strcasecompare(digest->qop, "auth-int")) { + /* We don't support auth-int for PUT or POST */ + char hashed[65]; + char *hashthis2; + + hash(hashbuf, (const unsigned char *)"", 0); + convert_to_ascii(hashbuf, (unsigned char *)hashed); + + hashthis2 = aprintf("%s:%s", hashthis, hashed); + free(hashthis); + hashthis = hashthis2; + } + + if(!hashthis) + return CURLE_OUT_OF_MEMORY; + + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); + free(hashthis); + convert_to_ascii(hashbuf, ha2); + + if(digest->qop) { + hashthis = aprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, digest->nc, + digest->cnonce, digest->qop, ha2); + } + else { + hashthis = aprintf("%s:%s:%s", ha1, digest->nonce, ha2); + } + + if(!hashthis) + return CURLE_OUT_OF_MEMORY; + + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); + free(hashthis); + convert_to_ascii(hashbuf, request_digest); + + /* For test case 64 (snooped from a Mozilla 1.3a request) + + Authorization: Digest username="testuser", realm="testrealm", \ + nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" + + Digest parameters are all quoted strings. Username which is provided by + the user will need double quotes and backslashes within it escaped. + realm, nonce, and opaque will need backslashes as well as they were + de-escaped when copied from request header. cnonce is generated with + web-safe characters. uri is already percent encoded. nc is 8 hex + characters. algorithm and qop with standard values only contain web-safe + characters. + */ + userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp); + if(!userp_quoted) + return CURLE_OUT_OF_MEMORY; + if(digest->realm) + realm_quoted = auth_digest_string_quoted(digest->realm); + else { + realm_quoted = malloc(1); + if(realm_quoted) + realm_quoted[0] = 0; + } + if(!realm_quoted) { + free(userp_quoted); + return CURLE_OUT_OF_MEMORY; + } + nonce_quoted = auth_digest_string_quoted(digest->nonce); + if(!nonce_quoted) { + free(realm_quoted); + free(userp_quoted); + return CURLE_OUT_OF_MEMORY; + } + + if(digest->qop) { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "cnonce=\"%s\", " + "nc=%08x, " + "qop=%s, " + "response=\"%s\"", + userp_quoted, + realm_quoted, + nonce_quoted, + uripath, + digest->cnonce, + digest->nc, + digest->qop, + request_digest); + + /* Increment nonce-count to use another nc value for the next request */ + digest->nc++; + } + else { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"", + userp_quoted, + realm_quoted, + nonce_quoted, + uripath, + request_digest); + } + free(nonce_quoted); + free(realm_quoted); + free(userp_quoted); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Add the optional fields */ + if(digest->opaque) { + char *opaque_quoted; + /* Append the opaque */ + opaque_quoted = auth_digest_string_quoted(digest->opaque); + if(!opaque_quoted) { + free(response); + return CURLE_OUT_OF_MEMORY; + } + tmp = aprintf("%s, opaque=\"%s\"", response, opaque_quoted); + free(response); + free(opaque_quoted); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + if(digest->algorithm) { + /* Append the algorithm */ + tmp = aprintf("%s, algorithm=%s", response, digest->algorithm); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + if(digest->userhash) { + /* Append the userhash */ + tmp = aprintf("%s, userhash=true", response); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + /* Return the output */ + *outptr = response; + *outlen = strlen(response); + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_http_message() + * + * This is used to generate an HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passwdp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + if(digest->algo <= ALGO_MD5SESS) + return auth_create_digest_http_message(data, userp, passwdp, + request, uripath, digest, + outptr, outlen, + auth_digest_md5_to_ascii, + Curl_md5it); + DEBUGASSERT(digest->algo <= ALGO_SHA512_256SESS); + return auth_create_digest_http_message(data, userp, passwdp, + request, uripath, digest, + outptr, outlen, + auth_digest_sha256_to_ascii, + Curl_sha256it); +} + +/* + * Curl_auth_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_auth_digest_cleanup(struct digestdata *digest) +{ + Curl_safefree(digest->nonce); + Curl_safefree(digest->cnonce); + Curl_safefree(digest->realm); + Curl_safefree(digest->opaque); + Curl_safefree(digest->qop); + Curl_safefree(digest->algorithm); + + digest->nc = 0; + digest->algo = ALGO_MD5; /* default algorithm */ + digest->stale = FALSE; /* default means normal, not stale */ + digest->userhash = FALSE; +} +#endif /* !USE_WINDOWS_SSPI */ + +#endif /* !CURL_DISABLE_DIGEST_AUTH */ diff --git a/lib/vauth/digest.h b/lib/vauth/digest.h new file mode 100644 index 0000000..99ce1f9 --- /dev/null +++ b/lib/vauth/digest.h @@ -0,0 +1,40 @@ +#ifndef HEADER_CURL_DIGEST_H +#define HEADER_CURL_DIGEST_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +#ifndef CURL_DISABLE_DIGEST_AUTH + +#define DIGEST_MAX_VALUE_LENGTH 256 +#define DIGEST_MAX_CONTENT_LENGTH 1024 + +/* This is used to extract the realm from a challenge message */ +bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, + const char **endptr); + +#endif + +#endif /* HEADER_CURL_DIGEST_H */ diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c new file mode 100644 index 0000000..4696f29 --- /dev/null +++ b/lib/vauth/digest_sspi.c @@ -0,0 +1,672 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC2831 DIGEST-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_DIGEST_AUTH) + +#include + +#include "vauth/vauth.h" +#include "vauth/digest.h" +#include "urldata.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" +#include "strdup.h" +#include "strcase.h" +#include "strerror.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* +* Curl_auth_is_digest_supported() +* +* This is used to evaluate if DIGEST is supported. +* +* Parameters: None +* +* Returns TRUE if DIGEST is supported by Windows SSPI. +*/ +bool Curl_auth_is_digest_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Digest */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + + /* Release the package buffer as it is not required anymore */ + if(status == SEC_E_OK) { + s_pSecFn->FreeContextBuffer(SecurityPackage); + } + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* + * Curl_auth_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg [in] - The challenge message. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, + const struct bufref *chlg, + const char *userp, + const char *passwdp, + const char *service, + struct bufref *out) +{ + CURLcode result = CURLE_OK; + TCHAR *spn = NULL; + size_t token_max = 0; + unsigned char *output_token = NULL; + CredHandle credentials; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Ensure we have a valid challenge message */ + if(!Curl_bufref_len(chlg)) { + infof(data, "DIGEST-MD5 handshake failure (empty challenge message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info"); + return CURLE_AUTH_ERROR; + } + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + output_token = malloc(token_max); + if(!output_token) + return CURLE_OUT_OF_MEMORY; + + /* Generate our SPN */ + spn = Curl_auth_build_spn(service, data->conn->host.name, NULL); + if(!spn) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } + + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &identity); + if(result) { + free(spn); + free(output_token); + return result; + } + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg); + chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg)); + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + /* Generate our response message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, + 0, 0, 0, &chlg_desc, 0, + &context, &resp_desc, &attrs, + &expiry); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + char buffer[STRERROR_LEN]; +#endif + + s_pSecFn->FreeCredentialsHandle(&credentials); + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + + if(status == SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "schannel: InitializeSecurityContext failed: %s", + Curl_sspi_strerror(status, buffer, sizeof(buffer))); +#endif + + return CURLE_AUTH_ERROR; + } + + /* Return the response. */ + Curl_bufref_set(out, output_token, resp_buf.cbBuffer, curl_free); + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the SPN */ + free(spn); + + return result; +} + +/* + * Curl_override_sspi_http_realm() + * + * This is used to populate the domain in a SSPI identity structure + * The realm is extracted from the challenge message and used as the + * domain if it is not already explicitly set. + * + * Parameters: + * + * chlg [in] - The challenge message. + * identity [in/out] - The identity structure. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *identity) +{ + xcharp_u domain, dup_domain; + + /* If domain is blank or unset, check challenge message for realm */ + if(!identity->Domain || !identity->DomainLength) { + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISBLANK(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { + if(strcasecompare(value, "realm")) { + + /* Setup identity's domain and length */ + domain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *) content); + if(!domain.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + + dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); + if(!dup_domain.tchar_ptr) { + curlx_unicodefree(domain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + + free(identity->Domain); + identity->Domain = dup_domain.tbyte_ptr; + identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); + dup_domain.tchar_ptr = NULL; + + curlx_unicodefree(domain.tchar_ptr); + } + else { + /* Unknown specifier, ignore it! */ + } + } + else + break; /* We're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISBLANK(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + } + + return CURLE_OK; +} + +/* + * Curl_auth_decode_digest_http_message() + * + * This is used to decode an HTTP DIGEST challenge message into the separate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + size_t chlglen = strlen(chlg); + + /* We had an input token before so if there's another one now that means we + provided bad credentials in the previous request or it's stale. */ + if(digest->input_token) { + bool stale = false; + const char *p = chlg; + + /* Check for the 'stale' directive */ + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + while(*p && ISBLANK(*p)) + p++; + + if(!Curl_auth_digest_get_pair(p, value, content, &p)) + break; + + if(strcasecompare(value, "stale") && + strcasecompare(content, "true")) { + stale = true; + break; + } + + while(*p && ISBLANK(*p)) + p++; + + if(',' == *p) + p++; + } + + if(stale) + Curl_auth_digest_cleanup(digest); + else + return CURLE_LOGIN_DENIED; + } + + /* Store the challenge for use later */ + digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); + if(!digest->input_token) + return CURLE_OUT_OF_MEMORY; + + digest->input_token_len = chlglen; + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_http_message() + * + * This is used to generate an HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + size_t token_max; + char *resp; + BYTE *output_token; + size_t output_token_len = 0; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf[5]; + SecBufferDesc chlg_desc; + SECURITY_STATUS status; + + (void) data; + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info"); + return CURLE_AUTH_ERROR; + } + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate the output buffer according to the max token size as indicated + by the security package */ + output_token = malloc(token_max); + if(!output_token) { + return CURLE_OUT_OF_MEMORY; + } + + /* If the user/passwd that was used to make the identity for http_context + has changed then delete that context. */ + if((userp && !digest->user) || (!userp && digest->user) || + (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || + (userp && digest->user && Curl_timestrcmp(userp, digest->user)) || + (passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) { + if(digest->http_context) { + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } + Curl_safefree(digest->user); + Curl_safefree(digest->passwd); + } + + if(digest->http_context) { + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 5; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = NULL; + chlg_buf[0].cbBuffer = 0; + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = (void *) uripath; + chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath)); + chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[3].pvBuffer = NULL; + chlg_buf[3].cbBuffer = 0; + chlg_buf[4].BufferType = SECBUFFER_PADDING; + chlg_buf[4].pvBuffer = output_token; + chlg_buf[4].cbBuffer = curlx_uztoul(token_max); + + status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0); + if(status == SEC_E_OK) + output_token_len = chlg_buf[4].cbBuffer; + else { /* delete the context so a new one can be made */ + infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx", + (long)status); + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } + } + + if(!digest->http_context) { + CredHandle credentials; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer resp_buf; + SecBufferDesc resp_desc; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + TCHAR *spn; + + /* free the copy of user/passwd used to make the previous identity */ + Curl_safefree(digest->user); + Curl_safefree(digest->passwd); + + if(userp && *userp) { + /* Populate our identity structure */ + if(Curl_create_sspi_identity(userp, passwdp, &identity)) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } + + /* Populate our identity domain */ + if(Curl_override_sspi_http_realm((const char *) digest->input_token, + &identity)) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + if(userp) { + digest->user = strdup(userp); + + if(!digest->user) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } + } + + if(passwdp) { + digest->passwd = strdup(passwdp); + + if(!digest->passwd) { + free(output_token); + Curl_safefree(digest->user); + return CURLE_OUT_OF_MEMORY; + } + } + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer if present */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 3; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = digest->input_token; + chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = NULL; + chlg_buf[2].cbBuffer = 0; + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + spn = curlx_convert_UTF8_to_tchar((char *) uripath); + if(!spn) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate our new context handle */ + digest->http_context = calloc(1, sizeof(CtxtHandle)); + if(!digest->http_context) + return CURLE_OUT_OF_MEMORY; + + /* Generate our response message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, + digest->http_context, + &resp_desc, &attrs, &expiry); + curlx_unicodefree(spn); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + char buffer[STRERROR_LEN]; +#endif + + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + Curl_safefree(digest->http_context); + + if(status == SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "schannel: InitializeSecurityContext failed: %s", + Curl_sspi_strerror(status, buffer, sizeof(buffer))); +#endif + + return CURLE_AUTH_ERROR; + } + + output_token_len = resp_buf.cbBuffer; + + s_pSecFn->FreeCredentialsHandle(&credentials); + Curl_sspi_free_identity(p_identity); + } + + resp = malloc(output_token_len + 1); + if(!resp) { + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Copy the generated response */ + memcpy(resp, output_token, output_token_len); + resp[output_token_len] = 0; + + /* Return the response */ + *outptr = resp; + *outlen = output_token_len; + + /* Free the response buffer */ + free(output_token); + + return CURLE_OK; +} + +/* + * Curl_auth_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_auth_digest_cleanup(struct digestdata *digest) +{ + /* Free the input token */ + Curl_safefree(digest->input_token); + + /* Reset any variables */ + digest->input_token_len = 0; + + /* Delete security context */ + if(digest->http_context) { + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } + + /* Free the copy of user/passwd used to make the identity for http_context */ + Curl_safefree(digest->user); + Curl_safefree(digest->passwd); +} + +#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_DIGEST_AUTH */ diff --git a/lib/vauth/gsasl.c b/lib/vauth/gsasl.c new file mode 100644 index 0000000..c7d0a8d --- /dev/null +++ b/lib/vauth/gsasl.c @@ -0,0 +1,127 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Simon Josefsson, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC5802 SCRAM-SHA-1 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_GSASL + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "sendf.h" + +#include + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +bool Curl_auth_gsasl_is_supported(struct Curl_easy *data, + const char *mech, + struct gsasldata *gsasl) +{ + int res; + + res = gsasl_init(&gsasl->ctx); + if(res != GSASL_OK) { + failf(data, "gsasl init: %s\n", gsasl_strerror(res)); + return FALSE; + } + + res = gsasl_client_start(gsasl->ctx, mech, &gsasl->client); + if(res != GSASL_OK) { + gsasl_done(gsasl->ctx); + return FALSE; + } + + return true; +} + +CURLcode Curl_auth_gsasl_start(struct Curl_easy *data, + const char *userp, + const char *passwdp, + struct gsasldata *gsasl) +{ +#if GSASL_VERSION_NUMBER >= 0x010b00 + int res; + res = +#endif + gsasl_property_set(gsasl->client, GSASL_AUTHID, userp); +#if GSASL_VERSION_NUMBER >= 0x010b00 + if(res != GSASL_OK) { + failf(data, "setting AUTHID failed: %s\n", gsasl_strerror(res)); + return CURLE_OUT_OF_MEMORY; + } +#endif + +#if GSASL_VERSION_NUMBER >= 0x010b00 + res = +#endif + gsasl_property_set(gsasl->client, GSASL_PASSWORD, passwdp); +#if GSASL_VERSION_NUMBER >= 0x010b00 + if(res != GSASL_OK) { + failf(data, "setting PASSWORD failed: %s\n", gsasl_strerror(res)); + return CURLE_OUT_OF_MEMORY; + } +#endif + + (void)data; + + return CURLE_OK; +} + +CURLcode Curl_auth_gsasl_token(struct Curl_easy *data, + const struct bufref *chlg, + struct gsasldata *gsasl, + struct bufref *out) +{ + int res; + char *response; + size_t outlen; + + res = gsasl_step(gsasl->client, + (const char *) Curl_bufref_ptr(chlg), Curl_bufref_len(chlg), + &response, &outlen); + if(res != GSASL_OK && res != GSASL_NEEDS_MORE) { + failf(data, "GSASL step: %s\n", gsasl_strerror(res)); + return CURLE_BAD_CONTENT_ENCODING; + } + + Curl_bufref_set(out, response, outlen, gsasl_free); + return CURLE_OK; +} + +void Curl_auth_gsasl_cleanup(struct gsasldata *gsasl) +{ + gsasl_finish(gsasl->client); + gsasl->client = NULL; + + gsasl_done(gsasl->ctx); + gsasl->ctx = NULL; +} +#endif diff --git a/lib/vauth/krb5_gssapi.c b/lib/vauth/krb5_gssapi.c new file mode 100644 index 0000000..16b6e40 --- /dev/null +++ b/lib/vauth/krb5_gssapi.c @@ -0,0 +1,324 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5) + +#include + +#include "vauth/vauth.h" +#include "curl_sasl.h" +#include "urldata.h" +#include "curl_gssapi.h" +#include "sendf.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by the GSS-API library. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + return TRUE; +} + +/* + * Curl_auth_create_gssapi_user_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) user token + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passwdp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in[ - The host name. + * mutual_auth [in] - Flag specifying whether or not mutual authentication + * is enabled. + * chlg [in] - Optional challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + const bool mutual_auth, + const struct bufref *chlg, + struct kerberos5data *krb5, + struct bufref *out) +{ + CURLcode result = CURLE_OK; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + (void) userp; + (void) passwdp; + + if(!krb5->spn) { + /* Generate our SPN */ + char *spn = Curl_auth_build_spn(service, NULL, host); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_import_name() failed: ", + major_status, minor_status); + + free(spn); + + return CURLE_AUTH_ERROR; + } + + free(spn); + } + + if(chlg) { + if(!Curl_bufref_len(chlg)) { + infof(data, "GSSAPI handshake failure (empty challenge message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + input_token.value = (void *) Curl_bufref_ptr(chlg); + input_token.length = Curl_bufref_len(chlg); + } + + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &krb5->context, + krb5->spn, + &Curl_krb5_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + mutual_auth, + NULL); + + if(GSS_ERROR(major_status)) { + if(output_token.value) + gss_release_buffer(&unused_status, &output_token); + + Curl_gss_log_error(data, "gss_init_sec_context() failed: ", + major_status, minor_status); + + return CURLE_AUTH_ERROR; + } + + if(output_token.value && output_token.length) { + result = Curl_bufref_memdup(out, output_token.value, output_token.length); + gss_release_buffer(&unused_status, &output_token); + } + else + Curl_bufref_set(out, mutual_auth? "": NULL, 0, NULL); + + return result; +} + +/* + * Curl_auth_create_gssapi_security_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) security + * token message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * authzid [in] - The authorization identity if some. + * chlg [in] - Optional challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *authzid, + const struct bufref *chlg, + struct kerberos5data *krb5, + struct bufref *out) +{ + CURLcode result = CURLE_OK; + size_t messagelen = 0; + unsigned char *message = NULL; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + unsigned char *indata; + gss_qop_t qop = GSS_C_QOP_DEFAULT; + unsigned int sec_layer = 0; + unsigned int max_size = 0; + + /* Ensure we have a valid challenge message */ + if(!Curl_bufref_len(chlg)) { + infof(data, "GSSAPI handshake failure (empty security message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = (void *) Curl_bufref_ptr(chlg); + input_token.length = Curl_bufref_len(chlg); + + /* Decrypt the inbound challenge and obtain the qop */ + major_status = gss_unwrap(&minor_status, krb5->context, &input_token, + &output_token, NULL, &qop); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_unwrap() failed: ", + major_status, minor_status); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(output_token.length != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Extract the security layer and the maximum message size */ + indata = output_token.value; + sec_layer = indata[0]; + max_size = ((unsigned int)indata[1] << 16) | + ((unsigned int)indata[2] << 8) | indata[3]; + + /* Free the challenge as it is not required anymore */ + gss_release_buffer(&unused_status, &output_token); + + /* Process the security layer */ + if(!(sec_layer & GSSAUTH_P_NONE)) { + infof(data, "GSSAPI handshake failure (invalid security layer)"); + + return CURLE_BAD_CONTENT_ENCODING; + } + sec_layer &= GSSAUTH_P_NONE; /* We do not support a security layer */ + + /* Process the maximum message size the server can receive */ + if(max_size > 0) { + /* The server has told us it supports a maximum receive buffer, however, as + we don't require one unless we are encrypting data, we tell the server + our receive buffer is zero. */ + max_size = 0; + } + + /* Allocate our message */ + messagelen = 4; + if(authzid) + messagelen += strlen(authzid); + message = malloc(messagelen); + if(!message) + return CURLE_OUT_OF_MEMORY; + + /* Populate the message with the security layer and client supported receive + message size. */ + message[0] = sec_layer & 0xFF; + message[1] = (max_size >> 16) & 0xFF; + message[2] = (max_size >> 8) & 0xFF; + message[3] = max_size & 0xFF; + + /* If given, append the authorization identity. */ + + if(authzid && *authzid) + memcpy(message + 4, authzid, messagelen - 4); + + /* Setup the "authentication data" security buffer */ + input_token.value = message; + input_token.length = messagelen; + + /* Encrypt the data */ + major_status = gss_wrap(&minor_status, krb5->context, 0, + GSS_C_QOP_DEFAULT, &input_token, NULL, + &output_token); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_wrap() failed: ", + major_status, minor_status); + free(message); + return CURLE_AUTH_ERROR; + } + + /* Return the response. */ + result = Curl_bufref_memdup(out, output_token.value, output_token.length); + /* Free the output buffer */ + gss_release_buffer(&unused_status, &output_token); + + /* Free the message buffer */ + free(message); + + return result; +} + +/* + * Curl_auth_cleanup_gssapi() + * + * This is used to clean up the GSSAPI (Kerberos V5) specific data. + * + * Parameters: + * + * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. + * + */ +void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5) +{ + OM_uint32 minor_status; + + /* Free our security context */ + if(krb5->context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER); + krb5->context = GSS_C_NO_CONTEXT; + } + + /* Free the SPN */ + if(krb5->spn != GSS_C_NO_NAME) { + gss_release_name(&minor_status, &krb5->spn); + krb5->spn = GSS_C_NO_NAME; + } +} + +#endif /* HAVE_GSSAPI && USE_KERBEROS5 */ diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c new file mode 100644 index 0000000..17a517a --- /dev/null +++ b/lib/vauth/krb5_sspi.c @@ -0,0 +1,475 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by Windows SSPI. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + + /* Release the package buffer as it is not required anymore */ + if(status == SEC_E_OK) { + s_pSecFn->FreeContextBuffer(SecurityPackage); + } + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* + * Curl_auth_create_gssapi_user_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) user token + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * mutual_auth [in] - Flag specifying whether or not mutual authentication + * is enabled. + * chlg [in] - Optional challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + const bool mutual_auth, + const struct bufref *chlg, + struct kerberos5data *krb5, + struct bufref *out) +{ + CURLcode result = CURLE_OK; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + if(!krb5->spn) { + /* Generate our SPN */ + krb5->spn = Curl_auth_build_spn(service, host, NULL); + if(!krb5->spn) + return CURLE_OUT_OF_MEMORY; + } + + if(!krb5->output_token) { + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + if(status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info"); + return CURLE_AUTH_ERROR; + } + + krb5->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + krb5->output_token = malloc(krb5->token_max); + if(!krb5->output_token) + return CURLE_OUT_OF_MEMORY; + } + + if(!krb5->credentials) { + /* Do we have credentials to use or are we using single sign-on? */ + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + krb5->p_identity = &krb5->identity; + } + else + /* Use the current Windows user */ + krb5->p_identity = NULL; + + /* Allocate our credentials handle */ + krb5->credentials = calloc(1, sizeof(CredHandle)); + if(!krb5->credentials) + return CURLE_OUT_OF_MEMORY; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) + TEXT(SP_NAME_KERBEROS), + SECPKG_CRED_OUTBOUND, NULL, + krb5->p_identity, NULL, NULL, + krb5->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + krb5->context = calloc(1, sizeof(CtxtHandle)); + if(!krb5->context) + return CURLE_OUT_OF_MEMORY; + } + + if(chlg) { + if(!Curl_bufref_len(chlg)) { + infof(data, "GSSAPI handshake failure (empty challenge message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg); + chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg)); + } + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = krb5->output_token; + resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); + + /* Generate our challenge-response message */ + status = s_pSecFn->InitializeSecurityContext(krb5->credentials, + chlg ? krb5->context : NULL, + krb5->spn, + (mutual_auth ? + ISC_REQ_MUTUAL_AUTH : 0), + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, 0, + &context, + &resp_desc, &attrs, + &expiry); + + if(status == SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + + if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + return CURLE_AUTH_ERROR; + + if(memcmp(&context, krb5->context, sizeof(context))) { + s_pSecFn->DeleteSecurityContext(krb5->context); + + memcpy(krb5->context, &context, sizeof(context)); + } + + if(resp_buf.cbBuffer) { + result = Curl_bufref_memdup(out, resp_buf.pvBuffer, resp_buf.cbBuffer); + } + else if(mutual_auth) + Curl_bufref_set(out, "", 0, NULL); + else + Curl_bufref_set(out, NULL, 0, NULL); + + return result; +} + +/* + * Curl_auth_create_gssapi_security_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) security + * token message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * authzid [in] - The authorization identity if some. + * chlg [in] - The optional challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *authzid, + const struct bufref *chlg, + struct kerberos5data *krb5, + struct bufref *out) +{ + size_t offset = 0; + size_t messagelen = 0; + size_t appdatalen = 0; + unsigned char *trailer = NULL; + unsigned char *message = NULL; + unsigned char *padding = NULL; + unsigned char *appdata = NULL; + SecBuffer input_buf[2]; + SecBuffer wrap_buf[3]; + SecBufferDesc input_desc; + SecBufferDesc wrap_desc; + unsigned char *indata; + unsigned long qop = 0; + unsigned long sec_layer = 0; + unsigned long max_size = 0; + SecPkgContext_Sizes sizes; + SECURITY_STATUS status; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + /* Ensure we have a valid challenge message */ + if(!Curl_bufref_len(chlg)) { + infof(data, "GSSAPI handshake failure (empty security message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Get our response size information */ + status = s_pSecFn->QueryContextAttributes(krb5->context, + SECPKG_ATTR_SIZES, + &sizes); + + if(status == SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + + if(status != SEC_E_OK) + return CURLE_AUTH_ERROR; + + /* Setup the "input" security buffer */ + input_desc.ulVersion = SECBUFFER_VERSION; + input_desc.cBuffers = 2; + input_desc.pBuffers = input_buf; + input_buf[0].BufferType = SECBUFFER_STREAM; + input_buf[0].pvBuffer = (void *) Curl_bufref_ptr(chlg); + input_buf[0].cbBuffer = curlx_uztoul(Curl_bufref_len(chlg)); + input_buf[1].BufferType = SECBUFFER_DATA; + input_buf[1].pvBuffer = NULL; + input_buf[1].cbBuffer = 0; + + /* Decrypt the inbound challenge and obtain the qop */ + status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); + if(status != SEC_E_OK) { + infof(data, "GSSAPI handshake failure (empty security message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(input_buf[1].cbBuffer != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Extract the security layer and the maximum message size */ + indata = input_buf[1].pvBuffer; + sec_layer = indata[0]; + max_size = ((unsigned long)indata[1] << 16) | + ((unsigned long)indata[2] << 8) | indata[3]; + + /* Free the challenge as it is not required anymore */ + s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); + + /* Process the security layer */ + if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { + infof(data, "GSSAPI handshake failure (invalid security layer)"); + return CURLE_BAD_CONTENT_ENCODING; + } + sec_layer &= KERB_WRAP_NO_ENCRYPT; /* We do not support a security layer */ + + /* Process the maximum message size the server can receive */ + if(max_size > 0) { + /* The server has told us it supports a maximum receive buffer, however, as + we don't require one unless we are encrypting data, we tell the server + our receive buffer is zero. */ + max_size = 0; + } + + /* Allocate the trailer */ + trailer = malloc(sizes.cbSecurityTrailer); + if(!trailer) + return CURLE_OUT_OF_MEMORY; + + /* Allocate our message */ + messagelen = 4; + if(authzid) + messagelen += strlen(authzid); + message = malloc(messagelen); + if(!message) { + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the message with the security layer and client supported receive + message size. */ + message[0] = sec_layer & 0xFF; + message[1] = (max_size >> 16) & 0xFF; + message[2] = (max_size >> 8) & 0xFF; + message[3] = max_size & 0xFF; + + /* If given, append the authorization identity. */ + + if(authzid && *authzid) + memcpy(message + 4, authzid, messagelen - 4); + + /* Allocate the padding */ + padding = malloc(sizes.cbBlockSize); + if(!padding) { + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the "authentication data" security buffer */ + wrap_desc.ulVersion = SECBUFFER_VERSION; + wrap_desc.cBuffers = 3; + wrap_desc.pBuffers = wrap_buf; + wrap_buf[0].BufferType = SECBUFFER_TOKEN; + wrap_buf[0].pvBuffer = trailer; + wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; + wrap_buf[1].BufferType = SECBUFFER_DATA; + wrap_buf[1].pvBuffer = message; + wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); + wrap_buf[2].BufferType = SECBUFFER_PADDING; + wrap_buf[2].pvBuffer = padding; + wrap_buf[2].cbBuffer = sizes.cbBlockSize; + + /* Encrypt the data */ + status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, + &wrap_desc, 0); + if(status != SEC_E_OK) { + free(padding); + free(message); + free(trailer); + + if(status == SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + + return CURLE_AUTH_ERROR; + } + + /* Allocate the encryption (wrap) buffer */ + appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + + wrap_buf[2].cbBuffer; + appdata = malloc(appdatalen); + if(!appdata) { + free(padding); + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the encryption buffer */ + memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); + offset += wrap_buf[0].cbBuffer; + memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); + offset += wrap_buf[1].cbBuffer; + memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); + + /* Free all of our local buffers */ + free(padding); + free(message); + free(trailer); + + /* Return the response. */ + Curl_bufref_set(out, appdata, appdatalen, curl_free); + return CURLE_OK; +} + +/* + * Curl_auth_cleanup_gssapi() + * + * This is used to clean up the GSSAPI (Kerberos V5) specific data. + * + * Parameters: + * + * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. + * + */ +void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5) +{ + /* Free our security context */ + if(krb5->context) { + s_pSecFn->DeleteSecurityContext(krb5->context); + free(krb5->context); + krb5->context = NULL; + } + + /* Free our credentials handle */ + if(krb5->credentials) { + s_pSecFn->FreeCredentialsHandle(krb5->credentials); + free(krb5->credentials); + krb5->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(krb5->p_identity); + krb5->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(krb5->spn); + Curl_safefree(krb5->output_token); + + /* Reset any variables */ + krb5->token_max = 0; +} + +#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5 */ diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c new file mode 100644 index 0000000..018e6a6 --- /dev/null +++ b/lib/vauth/ntlm.c @@ -0,0 +1,780 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) + +/* + * NTLM details: + * + * https://davenport.sourceforge.net/ntlm.html + * https://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#include "urldata.h" +#include "sendf.h" +#include "curl_ntlm_core.h" +#include "curl_gethostname.h" +#include "curl_multibyte.h" +#include "curl_md5.h" +#include "warnless.h" +#include "rand.h" +#include "vtls/vtls.h" +#include "strdup.h" + +#define BUILDING_CURL_NTLM_MSGS_C +#include "vauth/vauth.h" +#include "vauth/ntlm.h" +#include "curl_endian.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* "NTLMSSP" signature is always in ASCII regardless of the platform */ +#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" + +/* The fixed host name we provide, in order to not leak our real local host + name. Copy the name used by Firefox. */ +#define NTLM_HOSTNAME "WORKSTATION" + +#if DEBUG_ME +# define DEBUG_OUT(x) x +static void ntlm_print_flags(FILE *handle, unsigned long flags) +{ + if(flags & NTLMFLAG_NEGOTIATE_UNICODE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); + if(flags & NTLMFLAG_NEGOTIATE_OEM) + fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); + if(flags & NTLMFLAG_REQUEST_TARGET) + fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); + if(flags & (1<<3)) + fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); + if(flags & NTLMFLAG_NEGOTIATE_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); + if(flags & NTLMFLAG_NEGOTIATE_SEAL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); + if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); + if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); + if(flags & (1<<10)) + fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); + if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) + fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); + if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); + if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); + if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); + if(flags & NTLMFLAG_TARGET_TYPE_SERVER) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); + if(flags & NTLMFLAG_TARGET_TYPE_SHARE) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); + if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) + fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) + fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); + if(flags & (1<<24)) + fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); + if(flags & (1<<25)) + fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); + if(flags & (1<<26)) + fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); + if(flags & (1<<27)) + fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); + if(flags & (1<<28)) + fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); + if(flags & NTLMFLAG_NEGOTIATE_128) + fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); + if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); + if(flags & NTLMFLAG_NEGOTIATE_56) + fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); +} + +static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) +{ + const char *p = buf; + + (void) handle; + + fprintf(stderr, "0x"); + while(len-- > 0) + fprintf(stderr, "%02.2x", (unsigned int)*p++); +} +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +/* + * ntlm_decode_type2_target() + * + * This is used to decode the "target info" in the NTLM type-2 message + * received. + * + * Parameters: + * + * data [in] - The session handle. + * type2ref [in] - The type-2 message. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, + const struct bufref *type2ref, + struct ntlmdata *ntlm) +{ + unsigned short target_info_len = 0; + unsigned int target_info_offset = 0; + const unsigned char *type2 = Curl_bufref_ptr(type2ref); + size_t type2len = Curl_bufref_len(type2ref); + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + if(type2len >= 48) { + target_info_len = Curl_read16_le(&type2[40]); + target_info_offset = Curl_read32_le(&type2[44]); + if(target_info_len > 0) { + if((target_info_offset > type2len) || + (target_info_offset + target_info_len) > type2len || + target_info_offset < 48) { + infof(data, "NTLM handshake failure (bad type-2 message). " + "Target Info Offset Len is set incorrect by the peer"); + return CURLE_BAD_CONTENT_ENCODING; + } + + free(ntlm->target_info); /* replace any previous data */ + ntlm->target_info = Curl_memdup(&type2[target_info_offset], + target_info_len); + if(!ntlm->target_info) + return CURLE_OUT_OF_MEMORY; + } + } + + ntlm->target_info_len = target_info_len; + + return CURLE_OK; +} + +/* + NTLM message structure notes: + + A 'short' is a 'network short', a little-endian 16-bit unsigned value. + + A 'long' is a 'network long', a little-endian, 32-bit unsigned value. + + A 'security buffer' represents a triplet used to point to a buffer, + consisting of two shorts and one long: + + 1. A 'short' containing the length of the buffer content in bytes. + 2. A 'short' containing the allocated space for the buffer in bytes. + 3. A 'long' containing the offset to the start of the buffer in bytes, + from the beginning of the NTLM message. +*/ + +/* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE as NTLM as handled by libcurl. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + return TRUE; +} + +/* + * Curl_auth_decode_ntlm_type2_message() + * + * This is used to decode an NTLM type-2 message. The raw NTLM message is + * checked * for validity before the appropriate data for creating a type-3 + * message is * written to the given NTLM data structure. + * + * Parameters: + * + * data [in] - The session handle. + * type2ref [in] - The type-2 message. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, + const struct bufref *type2ref, + struct ntlmdata *ntlm) +{ + static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; + + /* NTLM type-2 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x02000000) + 12 Target Name security buffer + 20 Flags long + 24 Challenge 8 bytes + (32) Context 8 bytes (two consecutive longs) (*) + (40) Target Information security buffer (*) + (48) OS Version Structure 8 bytes (*) + 32 (48) (56) Start of data block (*) + (*) -> Optional + */ + + CURLcode result = CURLE_OK; + const unsigned char *type2 = Curl_bufref_ptr(type2ref); + size_t type2len = Curl_bufref_len(type2ref); + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void)data; +#endif + + ntlm->flags = 0; + + if((type2len < 32) || + (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) || + (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) { + /* This was not a good enough type-2 message */ + infof(data, "NTLM handshake failure (bad type-2 message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + ntlm->flags = Curl_read32_le(&type2[20]); + memcpy(ntlm->nonce, &type2[24], 8); + + if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { + result = ntlm_decode_type2_target(data, type2ref, ntlm); + if(result) { + infof(data, "NTLM handshake failure (bad type-2 message)"); + return result; + } + } + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); + ntlm_print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n nonce="); + ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); + fprintf(stderr, "\n****\n"); + fprintf(stderr, "**** Header %s\n ", header); + }); + + return result; +} + +/* copy the source to the destination and fill in zeroes in every + other destination byte! */ +static void unicodecpy(unsigned char *dest, const char *src, size_t length) +{ + size_t i; + for(i = 0; i < length; i++) { + dest[2 * i] = (unsigned char)src[i]; + dest[2 * i + 1] = '\0'; + } +} + +/* + * Curl_auth_create_ntlm_type1_message() + * + * This is used to generate an NTLM type-1 message ready for sending to the + * recipient using the appropriate compile time crypto API. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * ntlm [in/out] - The NTLM data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *hostname, + struct ntlmdata *ntlm, + struct bufref *out) +{ + /* NTLM type-1 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x01000000) + 12 Flags long + (16) Supplied Domain security buffer (*) + (24) Supplied Workstation security buffer (*) + (32) OS Version Structure 8 bytes (*) + (32) (40) Start of data block (*) + (*) -> Optional + */ + + size_t size; + + char *ntlmbuf; + const char *host = ""; /* empty */ + const char *domain = ""; /* empty */ + size_t hostlen = 0; + size_t domlen = 0; + size_t hostoff = 0; + size_t domoff = hostoff + hostlen; /* This is 0: remember that host and + domain are empty */ + (void)data; + (void)userp; + (void)passwdp; + (void)service; + (void)hostname; + + /* Clean up any former leftovers and initialise to defaults */ + Curl_auth_cleanup_ntlm(ntlm); + + ntlmbuf = aprintf(NTLMSSP_SIGNATURE "%c" + "\x01%c%c%c" /* 32-bit type = 1 */ + "%c%c%c%c" /* 32-bit NTLM flag field */ + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host name offset */ + "%c%c" /* 2 zeroes */ + "%s" /* host name */ + "%s", /* domain string */ + 0, /* trailing zero */ + 0, 0, 0, /* part of type-1 long */ + + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLMFLAG_NEGOTIATE_NTLM2_KEY | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0, 0, + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0, 0, + host, /* this is empty */ + domain /* this is empty */); + + if(!ntlmbuf) + return CURLE_OUT_OF_MEMORY; + + /* Initial packet length */ + size = 32 + hostlen + domlen; + + DEBUG_OUT({ + fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " + "0x%08.8x ", + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLMFLAG_NEGOTIATE_NTLM2_KEY | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLMFLAG_NEGOTIATE_NTLM2_KEY | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + ntlm_print_flags(stderr, + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLMFLAG_NEGOTIATE_NTLM2_KEY | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + fprintf(stderr, "\n****\n"); + }); + + Curl_bufref_set(out, ntlmbuf, size, curl_free); + return CURLE_OK; +} + +/* + * Curl_auth_create_ntlm_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready for + * sending to the recipient using the appropriate compile time crypto API. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + struct bufref *out) +{ + /* NTLM type-3 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x03000000) + 12 LM/LMv2 Response security buffer + 20 NTLM/NTLMv2 Response security buffer + 28 Target Name security buffer + 36 User Name security buffer + 44 Workstation Name security buffer + (52) Session Key security buffer (*) + (60) Flags long (*) + (64) OS Version Structure 8 bytes (*) + 52 (64) (72) Start of data block + (*) -> Optional + */ + + CURLcode result = CURLE_OK; + size_t size; + unsigned char ntlmbuf[NTLM_BUFSIZE]; + int lmrespoff; + unsigned char lmresp[24]; /* fixed-size */ + int ntrespoff; + unsigned int ntresplen = 24; + unsigned char ntresp[24]; /* fixed-size */ + unsigned char *ptr_ntresp = &ntresp[0]; + unsigned char *ntlmv2resp = NULL; + bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; + char host[HOSTNAME_MAX + 1] = ""; + const char *user; + const char *domain = ""; + size_t hostoff = 0; + size_t useroff = 0; + size_t domoff = 0; + size_t hostlen = 0; + size_t userlen = 0; + size_t domlen = 0; + + memset(lmresp, 0, sizeof(lmresp)); + memset(ntresp, 0, sizeof(ntresp)); + user = strchr(userp, '\\'); + if(!user) + user = strchr(userp, '/'); + + if(user) { + domain = userp; + domlen = (user - domain); + user++; + } + else + user = userp; + + userlen = strlen(user); + +#ifndef NTLM_HOSTNAME + /* Get the machine's un-qualified host name as NTLM doesn't like the fully + qualified domain name */ + if(Curl_gethostname(host, sizeof(host))) { + infof(data, "gethostname() failed, continuing without"); + hostlen = 0; + } + else { + hostlen = strlen(host); + } +#else + (void)msnprintf(host, sizeof(host), "%s", NTLM_HOSTNAME); + hostlen = sizeof(NTLM_HOSTNAME)-1; +#endif + + if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { + unsigned char ntbuffer[0x18]; + unsigned char entropy[8]; + unsigned char ntlmv2hash[0x18]; + + /* Full NTLM version 2 + Although this cannot be negotiated, it is used here if available, as + servers featuring extended security are likely supporting also + NTLMv2. */ + result = Curl_rand(data, entropy, 8); + if(result) + return result; + + result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer); + if(result) + return result; + + result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, + ntbuffer, ntlmv2hash); + if(result) + return result; + + /* LMv2 response */ + result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy, + &ntlm->nonce[0], lmresp); + if(result) + return result; + + /* NTLMv2 response */ + result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy, + ntlm, &ntlmv2resp, &ntresplen); + if(result) + return result; + + ptr_ntresp = ntlmv2resp; + } + else { + + unsigned char ntbuffer[0x18]; + unsigned char lmbuffer[0x18]; + + /* NTLM version 1 */ + + result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer); + if(result) + return result; + + Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); + + result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer); + if(result) + return result; + + Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); + ntlm->flags &= ~NTLMFLAG_NEGOTIATE_NTLM2_KEY; + + /* A safer but less compatible alternative is: + * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); + * See https://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ + } + + if(unicode) { + domlen = domlen * 2; + userlen = userlen * 2; + hostlen = hostlen * 2; + } + + lmrespoff = 64; /* size of the message header */ + ntrespoff = lmrespoff + 0x18; + domoff = ntrespoff + ntresplen; + useroff = domoff + domlen; + hostoff = useroff + userlen; + + /* Create the big type-3 message binary blob */ + size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x03%c%c%c" /* 32-bit type = 3 */ + + "%c%c" /* LanManager length */ + "%c%c" /* LanManager allocated space */ + "%c%c" /* LanManager offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* NT-response length */ + "%c%c" /* NT-response allocated space */ + "%c%c" /* NT-response offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* user length */ + "%c%c" /* user allocated space */ + "%c%c" /* user offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* session key length (unknown purpose) */ + "%c%c" /* session key allocated space (unknown purpose) */ + "%c%c" /* session key offset (unknown purpose) */ + "%c%c" /* 2 zeroes */ + + "%c%c%c%c", /* flags */ + + /* domain string */ + /* user string */ + /* host string */ + /* LanManager response */ + /* NT response */ + + 0, /* null-termination */ + 0, 0, 0, /* type-3 long, the 24 upper bits */ + + SHORTPAIR(0x18), /* LanManager response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(lmrespoff), + 0x0, 0x0, + + SHORTPAIR(ntresplen), /* NT-response length, twice */ + SHORTPAIR(ntresplen), + SHORTPAIR(ntrespoff), + 0x0, 0x0, + + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0x0, 0x0, + + SHORTPAIR(userlen), + SHORTPAIR(userlen), + SHORTPAIR(useroff), + 0x0, 0x0, + + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0x0, 0x0, + + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + + LONGQUARTET(ntlm->flags)); + + DEBUGASSERT(size == 64); + DEBUGASSERT(size == (size_t)lmrespoff); + + /* We append the binary hashes */ + if(size < (NTLM_BUFSIZE - 0x18)) { + memcpy(&ntlmbuf[size], lmresp, 0x18); + size += 0x18; + } + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE3 header lmresp="); + ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); + }); + + /* ntresplen + size should not be risking an integer overflow here */ + if(ntresplen + size > sizeof(ntlmbuf)) { + failf(data, "incoming NTLM message too big"); + return CURLE_OUT_OF_MEMORY; + } + DEBUGASSERT(size == (size_t)ntrespoff); + memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen); + size += ntresplen; + + DEBUG_OUT({ + fprintf(stderr, "\n ntresp="); + ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); + }); + + free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ + + DEBUG_OUT({ + fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", + LONGQUARTET(ntlm->flags), ntlm->flags); + ntlm_print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n****\n"); + }); + + /* Make sure that the domain, user and host strings fit in the + buffer before we copy them there. */ + if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { + failf(data, "user + domain + host name too big"); + return CURLE_OUT_OF_MEMORY; + } + + DEBUGASSERT(size == domoff); + if(unicode) + unicodecpy(&ntlmbuf[size], domain, domlen / 2); + else + memcpy(&ntlmbuf[size], domain, domlen); + + size += domlen; + + DEBUGASSERT(size == useroff); + if(unicode) + unicodecpy(&ntlmbuf[size], user, userlen / 2); + else + memcpy(&ntlmbuf[size], user, userlen); + + size += userlen; + + DEBUGASSERT(size == hostoff); + if(unicode) + unicodecpy(&ntlmbuf[size], host, hostlen / 2); + else + memcpy(&ntlmbuf[size], host, hostlen); + + size += hostlen; + + /* Return the binary blob. */ + result = Curl_bufref_memdup(out, ntlmbuf, size); + + Curl_auth_cleanup_ntlm(ntlm); + + return result; +} + +/* + * Curl_auth_cleanup_ntlm() + * + * This is used to clean up the NTLM specific data. + * + * Parameters: + * + * ntlm [in/out] - The NTLM data struct being cleaned up. + * + */ +void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm) +{ + /* Free the target info */ + Curl_safefree(ntlm->target_info); + + /* Reset any variables */ + ntlm->target_info_len = 0; +} + +#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/lib/vauth/ntlm.h b/lib/vauth/ntlm.h new file mode 100644 index 0000000..31ce921 --- /dev/null +++ b/lib/vauth/ntlm.h @@ -0,0 +1,143 @@ +#ifndef HEADER_VAUTH_NTLM_H +#define HEADER_VAUTH_NTLM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_NTLM + +/* NTLM buffer fixed size, large enough for long user + host + domain */ +#define NTLM_BUFSIZE 1024 + +/* Stuff only required for curl_ntlm_msgs.c */ +#ifdef BUILDING_CURL_NTLM_MSGS_C + +/* Flag bits definitions based on + https://davenport.sourceforge.net/ntlm.html */ + +#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) +/* Indicates that Unicode strings are supported for use in security buffer + data. */ + +#define NTLMFLAG_NEGOTIATE_OEM (1<<1) +/* Indicates that OEM strings are supported for use in security buffer data. */ + +#define NTLMFLAG_REQUEST_TARGET (1<<2) +/* Requests that the server's authentication realm be included in the Type 2 + message. */ + +/* unknown (1<<3) */ +#define NTLMFLAG_NEGOTIATE_SIGN (1<<4) +/* Specifies that authenticated communication between the client and server + should carry a digital signature (message integrity). */ + +#define NTLMFLAG_NEGOTIATE_SEAL (1<<5) +/* Specifies that authenticated communication between the client and server + should be encrypted (message confidentiality). */ + +#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6) +/* Indicates that datagram authentication is being used. */ + +#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7) +/* Indicates that the LAN Manager session key should be used for signing and + sealing authenticated communications. */ + +#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9) +/* Indicates that NTLM authentication is being used. */ + +/* unknown (1<<10) */ + +#define NTLMFLAG_NEGOTIATE_ANONYMOUS (1<<11) +/* Sent by the client in the Type 3 message to indicate that an anonymous + context has been established. This also affects the response fields. */ + +#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12) +/* Sent by the client in the Type 1 message to indicate that a desired + authentication realm is included in the message. */ + +#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13) +/* Sent by the client in the Type 1 message to indicate that the client + workstation's name is included in the message. */ + +#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14) +/* Sent by the server to indicate that the server and client are on the same + machine. Implies that the client may use a pre-established local security + context rather than responding to the challenge. */ + +#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15) +/* Indicates that authenticated communication between the client and server + should be signed with a "dummy" signature. */ + +#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16) +/* Sent by the server in the Type 2 message to indicate that the target + authentication realm is a domain. */ + +#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17) +/* Sent by the server in the Type 2 message to indicate that the target + authentication realm is a server. */ + +#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18) +/* Sent by the server in the Type 2 message to indicate that the target + authentication realm is a share. Presumably, this is for share-level + authentication. Usage is unclear. */ + +#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19) +/* Indicates that the NTLM2 signing and sealing scheme should be used for + protecting authenticated communications. */ + +#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20) +/* unknown purpose */ + +#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21) +/* unknown purpose */ + +#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22) +/* unknown purpose */ + +#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23) +/* Sent by the server in the Type 2 message to indicate that it is including a + Target Information block in the message. */ + +/* unknown (1<24) */ +/* unknown (1<25) */ +/* unknown (1<26) */ +/* unknown (1<27) */ +/* unknown (1<28) */ + +#define NTLMFLAG_NEGOTIATE_128 (1<<29) +/* Indicates that 128-bit encryption is supported. */ + +#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30) +/* Indicates that the client will provide an encrypted master key in + the "Session Key" field of the Type 3 message. */ + +#define NTLMFLAG_NEGOTIATE_56 (1<<31) +/* Indicates that 56-bit encryption is supported. */ + +#endif /* BUILDING_CURL_NTLM_MSGS_C */ + +#endif /* USE_NTLM */ + +#endif /* HEADER_VAUTH_NTLM_H */ diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c new file mode 100644 index 0000000..9205431 --- /dev/null +++ b/lib/vauth/ntlm_sspi.c @@ -0,0 +1,372 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_ntlm_core.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" +#include "strdup.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE if NTLM is supported by Windows SSPI. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + + /* Release the package buffer as it is not required anymore */ + if(status == SEC_E_OK) { + s_pSecFn->FreeContextBuffer(SecurityPackage); + } + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* + * Curl_auth_create_ntlm_type1_message() + * + * This is used to generate an already encoded NTLM type-1 message ready for + * sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * ntlm [in/out] - The NTLM data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + struct ntlmdata *ntlm, + struct bufref *out) +{ + PSecPkgInfo SecurityPackage; + SecBuffer type_1_buf; + SecBufferDesc type_1_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Clean up any former leftovers and initialise to defaults */ + Curl_auth_cleanup_ntlm(ntlm); + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + if(status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info"); + return CURLE_AUTH_ERROR; + } + + ntlm->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + ntlm->output_token = malloc(ntlm->token_max); + if(!ntlm->output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + CURLcode result; + + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + ntlm->p_identity = &ntlm->identity; + } + else + /* Use the current Windows user */ + ntlm->p_identity = NULL; + + /* Allocate our credentials handle */ + ntlm->credentials = calloc(1, sizeof(CredHandle)); + if(!ntlm->credentials) + return CURLE_OUT_OF_MEMORY; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_NTLM), + SECPKG_CRED_OUTBOUND, NULL, + ntlm->p_identity, NULL, NULL, + ntlm->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + ntlm->context = calloc(1, sizeof(CtxtHandle)); + if(!ntlm->context) + return CURLE_OUT_OF_MEMORY; + + ntlm->spn = Curl_auth_build_spn(service, host, NULL); + if(!ntlm->spn) + return CURLE_OUT_OF_MEMORY; + + /* Setup the type-1 "output" security buffer */ + type_1_desc.ulVersion = SECBUFFER_VERSION; + type_1_desc.cBuffers = 1; + type_1_desc.pBuffers = &type_1_buf; + type_1_buf.BufferType = SECBUFFER_TOKEN; + type_1_buf.pvBuffer = ntlm->output_token; + type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-1 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, + ntlm->spn, + 0, 0, SECURITY_NETWORK_DREP, + NULL, 0, + ntlm->context, &type_1_desc, + &attrs, &expiry); + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); + else if(status == SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + return CURLE_AUTH_ERROR; + + /* Return the response. */ + Curl_bufref_set(out, ntlm->output_token, type_1_buf.cbBuffer, NULL); + return CURLE_OK; +} + +/* + * Curl_auth_decode_ntlm_type2_message() + * + * This is used to decode an already encoded NTLM type-2 message. + * + * Parameters: + * + * data [in] - The session handle. + * type2 [in] - The type-2 message. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, + const struct bufref *type2, + struct ntlmdata *ntlm) +{ +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + /* Ensure we have a valid type-2 message */ + if(!Curl_bufref_len(type2)) { + infof(data, "NTLM handshake failure (empty type-2 message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Store the challenge for later use */ + ntlm->input_token = Curl_memdup0((const char *)Curl_bufref_ptr(type2), + Curl_bufref_len(type2)); + if(!ntlm->input_token) + return CURLE_OUT_OF_MEMORY; + ntlm->input_token_len = Curl_bufref_len(type2); + + return CURLE_OK; +} + +/* +* Curl_auth_create_ntlm_type3_message() + * Curl_auth_create_ntlm_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready for + * sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * out [out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + struct bufref *out) +{ + CURLcode result = CURLE_OK; + SecBuffer type_2_bufs[2]; + SecBuffer type_3_buf; + SecBufferDesc type_2_desc; + SecBufferDesc type_3_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + (void) passwdp; + (void) userp; + + /* Setup the type-2 "input" security buffer */ + type_2_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2_bufs[0]; + type_2_bufs[0].BufferType = SECBUFFER_TOKEN; + type_2_bufs[0].pvBuffer = ntlm->input_token; + type_2_bufs[0].cbBuffer = curlx_uztoul(ntlm->input_token_len); + +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + /* ssl context comes from schannel. + * When extended protection is used in IIS server, + * we have to pass a second SecBuffer to the SecBufferDesc + * otherwise IIS will not pass the authentication (401 response). + * Minimum supported version is Windows 7. + * https://docs.microsoft.com/en-us/security-updates + * /SecurityAdvisories/2009/973811 + */ + if(ntlm->sslContext) { + SEC_CHANNEL_BINDINGS channelBindings; + SecPkgContext_Bindings pkgBindings; + pkgBindings.Bindings = &channelBindings; + status = s_pSecFn->QueryContextAttributes( + ntlm->sslContext, + SECPKG_ATTR_ENDPOINT_BINDINGS, + &pkgBindings + ); + if(status == SEC_E_OK) { + type_2_desc.cBuffers++; + type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS; + type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength; + type_2_bufs[1].pvBuffer = pkgBindings.Bindings; + } + } +#endif + + /* Setup the type-3 "output" security buffer */ + type_3_desc.ulVersion = SECBUFFER_VERSION; + type_3_desc.cBuffers = 1; + type_3_desc.pBuffers = &type_3_buf; + type_3_buf.BufferType = SECBUFFER_TOKEN; + type_3_buf.pvBuffer = ntlm->output_token; + type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-3 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, + ntlm->context, + ntlm->spn, + 0, 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, ntlm->context, + &type_3_desc, + &attrs, &expiry); + if(status != SEC_E_OK) { + infof(data, "NTLM handshake failure (type-3 message): Status=%lx", + status); + + if(status == SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + + return CURLE_AUTH_ERROR; + } + + /* Return the response. */ + result = Curl_bufref_memdup(out, ntlm->output_token, type_3_buf.cbBuffer); + Curl_auth_cleanup_ntlm(ntlm); + return result; +} + +/* + * Curl_auth_cleanup_ntlm() + * + * This is used to clean up the NTLM specific data. + * + * Parameters: + * + * ntlm [in/out] - The NTLM data struct being cleaned up. + * + */ +void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm) +{ + /* Free our security context */ + if(ntlm->context) { + s_pSecFn->DeleteSecurityContext(ntlm->context); + free(ntlm->context); + ntlm->context = NULL; + } + + /* Free our credentials handle */ + if(ntlm->credentials) { + s_pSecFn->FreeCredentialsHandle(ntlm->credentials); + free(ntlm->credentials); + ntlm->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(ntlm->p_identity); + ntlm->p_identity = NULL; + + /* Free the input and output tokens */ + Curl_safefree(ntlm->input_token); + Curl_safefree(ntlm->output_token); + + /* Reset any variables */ + ntlm->token_max = 0; + + Curl_safefree(ntlm->spn); +} + +#endif /* USE_WINDOWS_SSPI && USE_NTLM */ diff --git a/lib/vauth/oauth2.c b/lib/vauth/oauth2.c new file mode 100644 index 0000000..a4adbdc --- /dev/null +++ b/lib/vauth/oauth2.c @@ -0,0 +1,108 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC6749 OAuth 2.0 Authorization Framework + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_POP3) || \ + (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)) + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "warnless.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_oauth_bearer_message() + * + * This is used to generate an OAuth 2.0 message ready for sending to the + * recipient. + * + * Parameters: + * + * user[in] - The user name. + * host[in] - The host name. + * port[in] - The port(when not Port 80). + * bearer[in] - The bearer token. + * out[out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_oauth_bearer_message(const char *user, + const char *host, + const long port, + const char *bearer, + struct bufref *out) +{ + char *oauth; + + /* Generate the message */ + if(port == 0 || port == 80) + oauth = aprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1", user, host, + bearer); + else + oauth = aprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, + host, port, bearer); + if(!oauth) + return CURLE_OUT_OF_MEMORY; + + Curl_bufref_set(out, oauth, strlen(oauth), curl_free); + return CURLE_OK; +} + +/* + * Curl_auth_create_xoauth_bearer_message() + * + * This is used to generate a XOAuth 2.0 message ready for * sending to the + * recipient. + * + * Parameters: + * + * user[in] - The user name. + * bearer[in] - The bearer token. + * out[out] - The result storage. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, + const char *bearer, + struct bufref *out) +{ + /* Generate the message */ + char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); + if(!xoauth) + return CURLE_OUT_OF_MEMORY; + + Curl_bufref_set(out, xoauth, strlen(xoauth), curl_free); + return CURLE_OK; +} +#endif /* disabled, no users */ diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c new file mode 100644 index 0000000..e1d52b7 --- /dev/null +++ b/lib/vauth/spnego_gssapi.c @@ -0,0 +1,281 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC4178 Simple and Protected GSS-API Negotiation Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && defined(USE_SPNEGO) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_gssapi.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate supported by the GSS-API library. + */ +bool Curl_auth_is_spnego_supported(void) +{ + return TRUE; +} + +/* + * Curl_auth_decode_spnego_message() + * + * This is used to decode an already encoded SPNEGO (Negotiate) challenge + * message. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passwdp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * chlg64 [in] - The optional base64 encoded challenge message. + * nego [in/out] - The Negotiate data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, + const char *user, + const char *password, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + (void) user; + (void) password; + + if(nego->context && nego->status == GSS_S_COMPLETE) { + /* We finished successfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_auth_cleanup_spnego(nego); + return CURLE_LOGIN_DENIED; + } + + if(!nego->spn) { + /* Generate our SPN */ + char *spn = Curl_auth_build_spn(service, NULL, host); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, + &nego->spn); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_import_name() failed: ", + major_status, minor_status); + + free(spn); + + return CURLE_AUTH_ERROR; + } + + free(spn); + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "SPNEGO handshake failure (empty challenge message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + } + + /* Generate our challenge-response message */ + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &nego->context, + nego->spn, + &Curl_spnego_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + TRUE, + NULL); + + /* Free the decoded challenge as it is not required anymore */ + Curl_safefree(input_token.value); + + nego->status = major_status; + if(GSS_ERROR(major_status)) { + if(output_token.value) + gss_release_buffer(&unused_status, &output_token); + + Curl_gss_log_error(data, "gss_init_sec_context() failed: ", + major_status, minor_status); + + return CURLE_AUTH_ERROR; + } + + if(!output_token.value || !output_token.length) { + if(output_token.value) + gss_release_buffer(&unused_status, &output_token); + + return CURLE_AUTH_ERROR; + } + + /* Free previous token */ + if(nego->output_token.length && nego->output_token.value) + gss_release_buffer(&unused_status, &nego->output_token); + + nego->output_token = output_token; + + return CURLE_OK; +} + +/* + * Curl_auth_create_spnego_message() + * + * This is used to generate an already encoded SPNEGO (Negotiate) response + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * nego [in/out] - The Negotiate data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego, + char **outptr, size_t *outlen) +{ + CURLcode result; + OM_uint32 minor_status; + + /* Base64 encode the already generated response */ + result = Curl_base64_encode(nego->output_token.value, + nego->output_token.length, + outptr, outlen); + + if(result) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + return result; + } + + if(!*outptr || !*outlen) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + return CURLE_REMOTE_ACCESS_DENIED; + } + + return CURLE_OK; +} + +/* + * Curl_auth_cleanup_spnego() + * + * This is used to clean up the SPNEGO (Negotiate) specific data. + * + * Parameters: + * + * nego [in/out] - The Negotiate data struct being cleaned up. + * + */ +void Curl_auth_cleanup_spnego(struct negotiatedata *nego) +{ + OM_uint32 minor_status; + + /* Free our security context */ + if(nego->context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER); + nego->context = GSS_C_NO_CONTEXT; + } + + /* Free the output token */ + if(nego->output_token.value) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + } + + /* Free the SPN */ + if(nego->spn != GSS_C_NO_NAME) { + gss_release_name(&minor_status, &nego->spn); + nego->spn = GSS_C_NO_NAME; + } + + /* Reset any variables */ + nego->status = 0; + nego->noauthpersist = FALSE; + nego->havenoauthpersist = FALSE; + nego->havenegdata = FALSE; + nego->havemultiplerequests = FALSE; +} + +#endif /* HAVE_GSSAPI && USE_SPNEGO */ diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c new file mode 100644 index 0000000..d3245d0 --- /dev/null +++ b/lib/vauth/spnego_sspi.c @@ -0,0 +1,364 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * RFC4178 Simple and Protected GSS-API Negotiation Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" +#include "strerror.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate is supported by Windows SSPI. + */ +bool Curl_auth_is_spnego_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Negotiate */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + + /* Release the package buffer as it is not required anymore */ + if(status == SEC_E_OK) { + s_pSecFn->FreeContextBuffer(SecurityPackage); + } + + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* + * Curl_auth_decode_spnego_message() + * + * This is used to decode an already encoded SPNEGO (Negotiate) challenge + * message. + * + * Parameters: + * + * data [in] - The session handle. + * user [in] - The user name in the format User or Domain\User. + * password [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * chlg64 [in] - The optional base64 encoded challenge message. + * nego [in/out] - The Negotiate data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, + const char *user, + const char *password, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf[2]; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + if(nego->context && nego->status == SEC_E_OK) { + /* We finished successfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_auth_cleanup_spnego(nego); + return CURLE_LOGIN_DENIED; + } + + if(!nego->spn) { + /* Generate our SPN */ + nego->spn = Curl_auth_build_spn(service, host, NULL); + if(!nego->spn) + return CURLE_OUT_OF_MEMORY; + } + + if(!nego->output_token) { + /* Query the security package for Negotiate */ + nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + if(nego->status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info"); + return CURLE_AUTH_ERROR; + } + + nego->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + nego->output_token = malloc(nego->token_max); + if(!nego->output_token) + return CURLE_OUT_OF_MEMORY; + } + + if(!nego->credentials) { + /* Do we have credentials to use or are we using single sign-on? */ + if(user && *user) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(user, password, &nego->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + nego->p_identity = &nego->identity; + } + else + /* Use the current Windows user */ + nego->p_identity = NULL; + + /* Allocate our credentials handle */ + nego->credentials = calloc(1, sizeof(CredHandle)); + if(!nego->credentials) + return CURLE_OUT_OF_MEMORY; + + /* Acquire our credentials handle */ + nego->status = + s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *)TEXT(SP_NAME_NEGOTIATE), + SECPKG_CRED_OUTBOUND, NULL, + nego->p_identity, NULL, NULL, + nego->credentials, &expiry); + if(nego->status != SEC_E_OK) + return CURLE_AUTH_ERROR; + + /* Allocate our new context handle */ + nego->context = calloc(1, sizeof(CtxtHandle)); + if(!nego->context) + return CURLE_OUT_OF_MEMORY; + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "SPNEGO handshake failure (empty challenge message)"); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf[0]; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = chlg; + chlg_buf[0].cbBuffer = curlx_uztoul(chlglen); + +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + /* ssl context comes from Schannel. + * When extended protection is used in IIS server, + * we have to pass a second SecBuffer to the SecBufferDesc + * otherwise IIS will not pass the authentication (401 response). + * Minimum supported version is Windows 7. + * https://docs.microsoft.com/en-us/security-updates + * /SecurityAdvisories/2009/973811 + */ + if(nego->sslContext) { + SEC_CHANNEL_BINDINGS channelBindings; + SecPkgContext_Bindings pkgBindings; + pkgBindings.Bindings = &channelBindings; + nego->status = s_pSecFn->QueryContextAttributes( + nego->sslContext, + SECPKG_ATTR_ENDPOINT_BINDINGS, + &pkgBindings + ); + if(nego->status == SEC_E_OK) { + chlg_desc.cBuffers++; + chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS; + chlg_buf[1].cbBuffer = pkgBindings.BindingsLength; + chlg_buf[1].pvBuffer = pkgBindings.Bindings; + } + } +#endif + } + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = nego->output_token; + resp_buf.cbBuffer = curlx_uztoul(nego->token_max); + + /* Generate our challenge-response message */ + nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials, + chlg ? nego->context : + NULL, + nego->spn, + ISC_REQ_CONFIDENTIALITY, + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, + 0, nego->context, + &resp_desc, &attrs, + &expiry); + + /* Free the decoded challenge as it is not required anymore */ + free(chlg); + + if(GSS_ERROR(nego->status)) { + char buffer[STRERROR_LEN]; + failf(data, "InitializeSecurityContext failed: %s", + Curl_sspi_strerror(nego->status, buffer, sizeof(buffer))); + + if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + + return CURLE_AUTH_ERROR; + } + + if(nego->status == SEC_I_COMPLETE_NEEDED || + nego->status == SEC_I_COMPLETE_AND_CONTINUE) { + nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc); + if(GSS_ERROR(nego->status)) { + char buffer[STRERROR_LEN]; + failf(data, "CompleteAuthToken failed: %s", + Curl_sspi_strerror(nego->status, buffer, sizeof(buffer))); + + if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY) + return CURLE_OUT_OF_MEMORY; + + return CURLE_AUTH_ERROR; + } + } + + nego->output_token_length = resp_buf.cbBuffer; + + return result; +} + +/* + * Curl_auth_create_spnego_message() + * + * This is used to generate an already encoded SPNEGO (Negotiate) response + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * nego [in/out] - The Negotiate data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego, + char **outptr, size_t *outlen) +{ + /* Base64 encode the already generated response */ + CURLcode result = Curl_base64_encode((const char *) nego->output_token, + nego->output_token_length, outptr, + outlen); + if(!result && (!*outptr || !*outlen)) { + free(*outptr); + result = CURLE_REMOTE_ACCESS_DENIED; + } + + return result; +} + +/* + * Curl_auth_cleanup_spnego() + * + * This is used to clean up the SPNEGO (Negotiate) specific data. + * + * Parameters: + * + * nego [in/out] - The Negotiate data struct being cleaned up. + * + */ +void Curl_auth_cleanup_spnego(struct negotiatedata *nego) +{ + /* Free our security context */ + if(nego->context) { + s_pSecFn->DeleteSecurityContext(nego->context); + free(nego->context); + nego->context = NULL; + } + + /* Free our credentials handle */ + if(nego->credentials) { + s_pSecFn->FreeCredentialsHandle(nego->credentials); + free(nego->credentials); + nego->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(nego->p_identity); + nego->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(nego->spn); + Curl_safefree(nego->output_token); + + /* Reset any variables */ + nego->status = 0; + nego->token_max = 0; + nego->noauthpersist = FALSE; + nego->havenoauthpersist = FALSE; + nego->havenegdata = FALSE; + nego->havemultiplerequests = FALSE; +} + +#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */ diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c new file mode 100644 index 0000000..62fc7c4 --- /dev/null +++ b/lib/vauth/vauth.c @@ -0,0 +1,163 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "vauth.h" +#include "urldata.h" +#include "strcase.h" +#include "curl_multibyte.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_build_spn() + * + * This is used to build a SPN string in the following formats: + * + * service/host@realm (Not currently used) + * service/host (Not used by GSS-API) + * service@realm (Not used by Windows SSPI) + * + * Parameters: + * + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * realm [in] - The realm. + * + * Returns a pointer to the newly allocated SPN. + */ +#if !defined(USE_WINDOWS_SSPI) +char *Curl_auth_build_spn(const char *service, const char *host, + const char *realm) +{ + char *spn = NULL; + + /* Generate our SPN */ + if(host && realm) + spn = aprintf("%s/%s@%s", service, host, realm); + else if(host) + spn = aprintf("%s/%s", service, host); + else if(realm) + spn = aprintf("%s@%s", service, realm); + + /* Return our newly allocated SPN */ + return spn; +} +#else +TCHAR *Curl_auth_build_spn(const char *service, const char *host, + const char *realm) +{ + char *utf8_spn = NULL; + TCHAR *tchar_spn = NULL; + TCHAR *dupe_tchar_spn = NULL; + + (void) realm; + + /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather + than doing this ourselves but the first is only available in Windows XP + and Windows Server 2003 and the latter is only available in Windows 2000 + but not Windows95/98/ME or Windows NT4.0 unless the Active Directory + Client Extensions are installed. As such it is far simpler for us to + formulate the SPN instead. */ + + /* Generate our UTF8 based SPN */ + utf8_spn = aprintf("%s/%s", service, host); + if(!utf8_spn) + return NULL; + + /* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar + must be freed by curlx_unicodefree we'll dupe the result so that the + pointer this function returns can be normally free'd. */ + tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn); + free(utf8_spn); + if(!tchar_spn) + return NULL; + dupe_tchar_spn = _tcsdup(tchar_spn); + curlx_unicodefree(tchar_spn); + return dupe_tchar_spn; +} +#endif /* USE_WINDOWS_SSPI */ + +/* + * Curl_auth_user_contains_domain() + * + * This is used to test if the specified user contains a Windows domain name as + * follows: + * + * Domain\User (Down-level Logon Name) + * Domain/User (curl Down-level format - for compatibility with existing code) + * User@Domain (User Principal Name) + * + * Note: The user name may be empty when using a GSS-API library or Windows + * SSPI as the user and domain are either obtained from the credentials cache + * when using GSS-API or via the currently logged in user's credentials when + * using Windows SSPI. + * + * Parameters: + * + * user [in] - The user name. + * + * Returns TRUE on success; otherwise FALSE. + */ +bool Curl_auth_user_contains_domain(const char *user) +{ + bool valid = FALSE; + + if(user && *user) { + /* Check we have a domain name or UPN present */ + char *p = strpbrk(user, "\\/@"); + + valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE : + FALSE); + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else + /* User and domain are obtained from the GSS-API credentials cache or the + currently logged in user from Windows */ + valid = TRUE; +#endif + + return valid; +} + +/* + * Curl_auth_ollowed_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. + */ +bool Curl_auth_allowed_to_host(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + return (!data->state.this_is_a_follow || + data->set.allow_auth_to_other_hosts || + (data->state.first_host && + strcasecompare(data->state.first_host, conn->host.name) && + (data->state.first_remote_port == conn->remote_port) && + (data->state.first_remote_protocol == conn->handler->protocol))); +} diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h new file mode 100644 index 0000000..9da0540 --- /dev/null +++ b/lib/vauth/vauth.h @@ -0,0 +1,238 @@ +#ifndef HEADER_CURL_VAUTH_H +#define HEADER_CURL_VAUTH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +#include "bufref.h" + +struct Curl_easy; + +#if !defined(CURL_DISABLE_DIGEST_AUTH) +struct digestdata; +#endif + +#if defined(USE_NTLM) +struct ntlmdata; +#endif + +#if defined(USE_KERBEROS5) +struct kerberos5data; +#endif + +#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) +struct negotiatedata; +#endif + +#if defined(USE_GSASL) +struct gsasldata; +#endif + +#if defined(USE_WINDOWS_SSPI) +#define GSS_ERROR(status) ((status) & 0x80000000) +#endif + +/* + * Curl_auth_allowed_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. + */ +bool Curl_auth_allowed_to_host(struct Curl_easy *data); + +/* This is used to build a SPN string */ +#if !defined(USE_WINDOWS_SSPI) +char *Curl_auth_build_spn(const char *service, const char *host, + const char *realm); +#else +TCHAR *Curl_auth_build_spn(const char *service, const char *host, + const char *realm); +#endif + +/* This is used to test if the user contains a Windows domain name */ +bool Curl_auth_user_contains_domain(const char *user); + +/* This is used to generate a PLAIN cleartext message */ +CURLcode Curl_auth_create_plain_message(const char *authzid, + const char *authcid, + const char *passwd, + struct bufref *out); + +/* This is used to generate a LOGIN cleartext message */ +CURLcode Curl_auth_create_login_message(const char *value, + struct bufref *out); + +/* This is used to generate an EXTERNAL cleartext message */ +CURLcode Curl_auth_create_external_message(const char *user, + struct bufref *out); + +#ifndef CURL_DISABLE_DIGEST_AUTH +/* This is used to generate a CRAM-MD5 response message */ +CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg, + const char *userp, + const char *passwdp, + struct bufref *out); + +/* This is used to evaluate if DIGEST is supported */ +bool Curl_auth_is_digest_supported(void); + +/* This is used to generate a base64 encoded DIGEST-MD5 response message */ +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, + const struct bufref *chlg, + const char *userp, + const char *passwdp, + const char *service, + struct bufref *out); + +/* This is used to decode an HTTP DIGEST challenge message */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest); + +/* This is used to generate an HTTP DIGEST response message */ +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uri, + struct digestdata *digest, + char **outptr, size_t *outlen); + +/* This is used to clean up the digest specific data */ +void Curl_auth_digest_cleanup(struct digestdata *digest); +#endif /* !CURL_DISABLE_DIGEST_AUTH */ + +#ifdef USE_GSASL +/* This is used to evaluate if MECH is supported by gsasl */ +bool Curl_auth_gsasl_is_supported(struct Curl_easy *data, + const char *mech, + struct gsasldata *gsasl); +/* This is used to start a gsasl method */ +CURLcode Curl_auth_gsasl_start(struct Curl_easy *data, + const char *userp, + const char *passwdp, + struct gsasldata *gsasl); + +/* This is used to process and generate a new SASL token */ +CURLcode Curl_auth_gsasl_token(struct Curl_easy *data, + const struct bufref *chlg, + struct gsasldata *gsasl, + struct bufref *out); + +/* This is used to clean up the gsasl specific data */ +void Curl_auth_gsasl_cleanup(struct gsasldata *digest); +#endif + +#if defined(USE_NTLM) +/* This is used to evaluate if NTLM is supported */ +bool Curl_auth_is_ntlm_supported(void); + +/* This is used to generate a base64 encoded NTLM type-1 message */ +CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + struct ntlmdata *ntlm, + struct bufref *out); + +/* This is used to decode a base64 encoded NTLM type-2 message */ +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, + const struct bufref *type2, + struct ntlmdata *ntlm); + +/* This is used to generate a base64 encoded NTLM type-3 message */ +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + struct bufref *out); + +/* This is used to clean up the NTLM specific data */ +void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm); +#endif /* USE_NTLM */ + +/* This is used to generate a base64 encoded OAuth 2.0 message */ +CURLcode Curl_auth_create_oauth_bearer_message(const char *user, + const char *host, + const long port, + const char *bearer, + struct bufref *out); + +/* This is used to generate a base64 encoded XOAuth 2.0 message */ +CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, + const char *bearer, + struct bufref *out); + +#if defined(USE_KERBEROS5) +/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */ +bool Curl_auth_is_gssapi_supported(void); + +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token + message */ +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + const bool mutual, + const struct bufref *chlg, + struct kerberos5data *krb5, + struct bufref *out); + +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security + token message */ +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *authzid, + const struct bufref *chlg, + struct kerberos5data *krb5, + struct bufref *out); + +/* This is used to clean up the GSSAPI specific data */ +void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5); +#endif /* USE_KERBEROS5 */ + +#if defined(USE_SPNEGO) +/* This is used to evaluate if SPNEGO (Negotiate) is supported */ +bool Curl_auth_is_spnego_supported(void); + +/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge + message */ +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, + const char *user, + const char *password, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego); + +/* This is used to generate a base64 encoded SPNEGO (Negotiate) response + message */ +CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego, + char **outptr, size_t *outlen); + +/* This is used to clean up the SPNEGO specific data */ +void Curl_auth_cleanup_spnego(struct negotiatedata *nego); + +#endif /* USE_SPNEGO */ + +#endif /* HEADER_CURL_VAUTH_H */ diff --git a/lib/version.c b/lib/version.c new file mode 100644 index 0000000..01c2a31 --- /dev/null +++ b/lib/version.c @@ -0,0 +1,678 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_NGHTTP2 +#include +#endif + +#include +#include "urldata.h" +#include "vtls/vtls.h" +#include "http2.h" +#include "vssh/ssh.h" +#include "vquic/vquic.h" +#include "curl_printf.h" +#include "easy_lock.h" + +#ifdef USE_ARES +# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ + defined(_WIN32) +# define CARES_STATICLIB +# endif +# include +#endif + +#ifdef USE_LIBIDN2 +#include +#endif + +#ifdef USE_LIBPSL +#include +#endif + +#ifdef USE_LIBRTMP +#include +#endif + +#ifdef HAVE_LIBZ +#include +#endif + +#ifdef HAVE_BROTLI +#if defined(__GNUC__) +/* Ignore -Wvla warnings in brotli headers */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvla" +#endif +#include +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#endif + +#ifdef HAVE_ZSTD +#include +#endif + +#ifdef USE_GSASL +#include +#endif + +#ifdef USE_OPENLDAP +#include +#endif + +#ifdef HAVE_BROTLI +static void brotli_version(char *buf, size_t bufsz) +{ + uint32_t brotli_version = BrotliDecoderVersion(); + unsigned int major = brotli_version >> 24; + unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12; + unsigned int patch = brotli_version & 0x00000FFF; + (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch); +} +#endif + +#ifdef HAVE_ZSTD +static void zstd_version(char *buf, size_t bufsz) +{ + unsigned long zstd_version = (unsigned long)ZSTD_versionNumber(); + unsigned int major = (unsigned int)(zstd_version / (100 * 100)); + unsigned int minor = (unsigned int)((zstd_version - + (major * 100 * 100)) / 100); + unsigned int patch = (unsigned int)(zstd_version - + (major * 100 * 100) - (minor * 100)); + (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch); +} +#endif + +/* + * curl_version() returns a pointer to a static buffer. + * + * It is implemented to work multi-threaded by making sure repeated invokes + * generate the exact same string and never write any temporary data like + * zeros in the data. + */ + +#define VERSION_PARTS 16 /* number of substrings we can concatenate */ + +char *curl_version(void) +{ + static char out[300]; + char *outp; + size_t outlen; + const char *src[VERSION_PARTS]; +#ifdef USE_SSL + char ssl_version[200]; +#endif +#ifdef HAVE_LIBZ + char z_version[40]; +#endif +#ifdef HAVE_BROTLI + char br_version[40] = "brotli/"; +#endif +#ifdef HAVE_ZSTD + char zst_version[40] = "zstd/"; +#endif +#ifdef USE_ARES + char cares_version[40]; +#endif +#if defined(USE_LIBIDN2) + char idn_version[40]; +#endif +#ifdef USE_LIBPSL + char psl_version[40]; +#endif +#ifdef USE_SSH + char ssh_version[40]; +#endif +#ifdef USE_NGHTTP2 + char h2_version[40]; +#endif +#ifdef ENABLE_QUIC + char h3_version[40]; +#endif +#ifdef USE_LIBRTMP + char rtmp_version[40]; +#endif +#ifdef USE_HYPER + char hyper_buf[30]; +#endif +#ifdef USE_GSASL + char gsasl_buf[30]; +#endif +#ifdef USE_OPENLDAP + char ldap_buf[30]; +#endif + int i = 0; + int j; + +#ifdef DEBUGBUILD + /* Override version string when environment variable CURL_VERSION is set */ + const char *debugversion = getenv("CURL_VERSION"); + if(debugversion) { + strncpy(out, debugversion, sizeof(out)-1); + out[sizeof(out)-1] = '\0'; + return out; + } +#endif + + src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION; +#ifdef USE_SSL + Curl_ssl_version(ssl_version, sizeof(ssl_version)); + src[i++] = ssl_version; +#endif +#ifdef HAVE_LIBZ + msnprintf(z_version, sizeof(z_version), "zlib/%s", zlibVersion()); + src[i++] = z_version; +#endif +#ifdef HAVE_BROTLI + brotli_version(&br_version[7], sizeof(br_version) - 7); + src[i++] = br_version; +#endif +#ifdef HAVE_ZSTD + zstd_version(&zst_version[5], sizeof(zst_version) - 5); + src[i++] = zst_version; +#endif +#ifdef USE_ARES + msnprintf(cares_version, sizeof(cares_version), + "c-ares/%s", ares_version(NULL)); + src[i++] = cares_version; +#endif +#ifdef USE_LIBIDN2 + msnprintf(idn_version, sizeof(idn_version), + "libidn2/%s", idn2_check_version(NULL)); + src[i++] = idn_version; +#elif defined(USE_WIN32_IDN) + src[i++] = (char *)"WinIDN"; +#endif + +#ifdef USE_LIBPSL + { + int num = psl_check_version_number(0); + msnprintf(psl_version, sizeof(psl_version), "libpsl/%d.%d.%d", + num >> 16, (num >> 8) & 0xff, num & 0xff); + src[i++] = psl_version; + } +#endif + +#ifdef USE_SSH + Curl_ssh_version(ssh_version, sizeof(ssh_version)); + src[i++] = ssh_version; +#endif +#ifdef USE_NGHTTP2 + Curl_http2_ver(h2_version, sizeof(h2_version)); + src[i++] = h2_version; +#endif +#ifdef ENABLE_QUIC + Curl_quic_ver(h3_version, sizeof(h3_version)); + src[i++] = h3_version; +#endif +#ifdef USE_LIBRTMP + { + char suff[2]; + if(RTMP_LIB_VERSION & 0xff) { + suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1; + suff[1] = '\0'; + } + else + suff[0] = '\0'; + + msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s", + RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, + suff); + src[i++] = rtmp_version; + } +#endif +#ifdef USE_HYPER + msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s", hyper_version()); + src[i++] = hyper_buf; +#endif +#ifdef USE_GSASL + msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s", + gsasl_check_version(NULL)); + src[i++] = gsasl_buf; +#endif +#ifdef USE_OPENLDAP + { + LDAPAPIInfo api; + api.ldapai_info_version = LDAP_API_INFO_VERSION; + + if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) { + unsigned int patch = api.ldapai_vendor_version % 100; + unsigned int major = api.ldapai_vendor_version / 10000; + unsigned int minor = + ((api.ldapai_vendor_version - major * 10000) - patch) / 100; + msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u", + api.ldapai_vendor_name, major, minor, patch); + src[i++] = ldap_buf; + ldap_memfree(api.ldapai_vendor_name); + ber_memvfree((void **)api.ldapai_extensions); + } + } +#endif + + DEBUGASSERT(i <= VERSION_PARTS); + + outp = &out[0]; + outlen = sizeof(out); + for(j = 0; j < i; j++) { + size_t n = strlen(src[j]); + /* we need room for a space, the string and the final zero */ + if(outlen <= (n + 2)) + break; + if(j) { + /* prepend a space if not the first */ + *outp++ = ' '; + outlen--; + } + memcpy(outp, src[j], n); + outp += n; + outlen -= n; + } + *outp = 0; + + return out; +} + +/* data for curl_version_info + + Keep the list sorted alphabetically. It is also written so that each + protocol line has its own #if line to make things easier on the eye. + */ + +static const char * const supported_protocols[] = { +#ifndef CURL_DISABLE_DICT + "dict", +#endif +#ifndef CURL_DISABLE_FILE + "file", +#endif +#ifndef CURL_DISABLE_FTP + "ftp", +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) + "ftps", +#endif +#ifndef CURL_DISABLE_GOPHER + "gopher", +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER) + "gophers", +#endif +#ifndef CURL_DISABLE_HTTP + "http", +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + "https", +#endif +#ifndef CURL_DISABLE_IMAP + "imap", +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP) + "imaps", +#endif +#ifndef CURL_DISABLE_LDAP + "ldap", +#if !defined(CURL_DISABLE_LDAPS) && \ + ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ + (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) + "ldaps", +#endif +#endif +#ifndef CURL_DISABLE_MQTT + "mqtt", +#endif +#ifndef CURL_DISABLE_POP3 + "pop3", +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3) + "pop3s", +#endif +#ifdef USE_LIBRTMP + "rtmp", + "rtmpe", + "rtmps", + "rtmpt", + "rtmpte", + "rtmpts", +#endif +#ifndef CURL_DISABLE_RTSP + "rtsp", +#endif +#if defined(USE_SSH) && !defined(USE_WOLFSSH) + "scp", +#endif +#ifdef USE_SSH + "sftp", +#endif +#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) + "smb", +# ifdef USE_SSL + "smbs", +# endif +#endif +#ifndef CURL_DISABLE_SMTP + "smtp", +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP) + "smtps", +#endif +#ifndef CURL_DISABLE_TELNET + "telnet", +#endif +#ifndef CURL_DISABLE_TFTP + "tftp", +#endif +#ifdef USE_WEBSOCKETS + "ws", +#endif +#if defined(USE_SSL) && defined(USE_WEBSOCKETS) + "wss", +#endif + + NULL +}; + +/* + * Feature presence run-time check functions. + * + * Warning: the value returned by these should not change between + * curl_global_init() and curl_global_cleanup() calls. + */ + +#if defined(USE_LIBIDN2) +static int idn_present(curl_version_info_data *info) +{ + return info->libidn != NULL; +} +#else +#define idn_present NULL +#endif + +#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \ + !defined(CURL_DISABLE_HTTP) +static int https_proxy_present(curl_version_info_data *info) +{ + (void) info; + return Curl_ssl_supports(NULL, SSLSUPP_HTTPS_PROXY); +} +#endif + +/* + * Features table. + * + * Keep the features alphabetically sorted. + * Use FEATURE() macro to define an entry: this allows documentation check. + */ + +#define FEATURE(name, present, bitmask) {(name), (present), (bitmask)} + +struct feat { + const char *name; + int (*present)(curl_version_info_data *info); + int bitmask; +}; + +static const struct feat features_table[] = { +#ifndef CURL_DISABLE_ALTSVC + FEATURE("alt-svc", NULL, CURL_VERSION_ALTSVC), +#endif +#ifdef CURLRES_ASYNCH + FEATURE("AsynchDNS", NULL, CURL_VERSION_ASYNCHDNS), +#endif +#ifdef HAVE_BROTLI + FEATURE("brotli", NULL, CURL_VERSION_BROTLI), +#endif +#ifdef DEBUGBUILD + FEATURE("Debug", NULL, CURL_VERSION_DEBUG), +#endif +#ifdef USE_GSASL + FEATURE("gsasl", NULL, CURL_VERSION_GSASL), +#endif +#ifdef HAVE_GSSAPI + FEATURE("GSS-API", NULL, CURL_VERSION_GSSAPI), +#endif +#ifndef CURL_DISABLE_HSTS + FEATURE("HSTS", NULL, CURL_VERSION_HSTS), +#endif +#if defined(USE_NGHTTP2) + FEATURE("HTTP2", NULL, CURL_VERSION_HTTP2), +#endif +#if defined(ENABLE_QUIC) + FEATURE("HTTP3", NULL, CURL_VERSION_HTTP3), +#endif +#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \ + !defined(CURL_DISABLE_HTTP) + FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY), +#endif +#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) + FEATURE("IDN", idn_present, CURL_VERSION_IDN), +#endif +#ifdef ENABLE_IPV6 + FEATURE("IPv6", NULL, CURL_VERSION_IPV6), +#endif +#ifdef USE_KERBEROS5 + FEATURE("Kerberos", NULL, CURL_VERSION_KERBEROS5), +#endif +#if (SIZEOF_CURL_OFF_T > 4) && \ + ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) ) + FEATURE("Largefile", NULL, CURL_VERSION_LARGEFILE), +#endif +#ifdef HAVE_LIBZ + FEATURE("libz", NULL, CURL_VERSION_LIBZ), +#endif +#ifdef CURL_WITH_MULTI_SSL + FEATURE("MultiSSL", NULL, CURL_VERSION_MULTI_SSL), +#endif +#ifdef USE_NTLM + FEATURE("NTLM", NULL, CURL_VERSION_NTLM), +#endif +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + FEATURE("NTLM_WB", NULL, CURL_VERSION_NTLM_WB), +#endif +#if defined(USE_LIBPSL) + FEATURE("PSL", NULL, CURL_VERSION_PSL), +#endif +#ifdef USE_SPNEGO + FEATURE("SPNEGO", NULL, CURL_VERSION_SPNEGO), +#endif +#ifdef USE_SSL + FEATURE("SSL", NULL, CURL_VERSION_SSL), +#endif +#ifdef USE_WINDOWS_SSPI + FEATURE("SSPI", NULL, CURL_VERSION_SSPI), +#endif +#ifdef GLOBAL_INIT_IS_THREADSAFE + FEATURE("threadsafe", NULL, CURL_VERSION_THREADSAFE), +#endif +#ifdef USE_TLS_SRP + FEATURE("TLS-SRP", NULL, CURL_VERSION_TLSAUTH_SRP), +#endif +#ifdef CURLDEBUG + FEATURE("TrackMemory", NULL, CURL_VERSION_CURLDEBUG), +#endif +#if defined(_WIN32) && defined(UNICODE) && defined(_UNICODE) + FEATURE("Unicode", NULL, CURL_VERSION_UNICODE), +#endif +#ifdef USE_UNIX_SOCKETS + FEATURE("UnixSockets", NULL, CURL_VERSION_UNIX_SOCKETS), +#endif +#ifdef HAVE_ZSTD + FEATURE("zstd", NULL, CURL_VERSION_ZSTD), +#endif + {NULL, NULL, 0} +}; + +static const char *feature_names[sizeof(features_table) / + sizeof(features_table[0])] = {NULL}; + + +static curl_version_info_data version_info = { + CURLVERSION_NOW, + LIBCURL_VERSION, + LIBCURL_VERSION_NUM, + OS, /* as found by configure or set by hand at build-time */ + 0, /* features bitmask is built at run-time */ + NULL, /* ssl_version */ + 0, /* ssl_version_num, this is kept at zero */ + NULL, /* zlib_version */ + supported_protocols, + NULL, /* c-ares version */ + 0, /* c-ares version numerical */ + NULL, /* libidn version */ + 0, /* iconv version */ + NULL, /* ssh lib version */ + 0, /* brotli_ver_num */ + NULL, /* brotli version */ + 0, /* nghttp2 version number */ + NULL, /* nghttp2 version string */ + NULL, /* quic library string */ +#ifdef CURL_CA_BUNDLE + CURL_CA_BUNDLE, /* cainfo */ +#else + NULL, +#endif +#ifdef CURL_CA_PATH + CURL_CA_PATH, /* capath */ +#else + NULL, +#endif + 0, /* zstd_ver_num */ + NULL, /* zstd version */ + NULL, /* Hyper version */ + NULL, /* gsasl version */ + feature_names +}; + +curl_version_info_data *curl_version_info(CURLversion stamp) +{ + size_t n; + const struct feat *p; + int features = 0; + +#if defined(USE_SSH) + static char ssh_buffer[80]; +#endif +#ifdef USE_SSL +#ifdef CURL_WITH_MULTI_SSL + static char ssl_buffer[200]; +#else + static char ssl_buffer[80]; +#endif +#endif +#ifdef HAVE_BROTLI + static char brotli_buffer[80]; +#endif +#ifdef HAVE_ZSTD + static char zstd_buffer[80]; +#endif + + (void)stamp; /* avoid compiler warnings, we don't use this */ + +#ifdef USE_SSL + Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); + version_info.ssl_version = ssl_buffer; +#endif + +#ifdef HAVE_LIBZ + version_info.libz_version = zlibVersion(); + /* libz left NULL if non-existing */ +#endif +#ifdef USE_ARES + { + int aresnum; + version_info.ares = ares_version(&aresnum); + version_info.ares_num = aresnum; + } +#endif +#ifdef USE_LIBIDN2 + /* This returns a version string if we use the given version or later, + otherwise it returns NULL */ + version_info.libidn = idn2_check_version(IDN2_VERSION); +#endif + +#if defined(USE_SSH) + Curl_ssh_version(ssh_buffer, sizeof(ssh_buffer)); + version_info.libssh_version = ssh_buffer; +#endif + +#ifdef HAVE_BROTLI + version_info.brotli_ver_num = BrotliDecoderVersion(); + brotli_version(brotli_buffer, sizeof(brotli_buffer)); + version_info.brotli_version = brotli_buffer; +#endif + +#ifdef HAVE_ZSTD + version_info.zstd_ver_num = (unsigned int)ZSTD_versionNumber(); + zstd_version(zstd_buffer, sizeof(zstd_buffer)); + version_info.zstd_version = zstd_buffer; +#endif + +#ifdef USE_NGHTTP2 + { + nghttp2_info *h2 = nghttp2_version(0); + version_info.nghttp2_ver_num = h2->version_num; + version_info.nghttp2_version = h2->version_str; + } +#endif + +#ifdef ENABLE_QUIC + { + static char quicbuffer[80]; + Curl_quic_ver(quicbuffer, sizeof(quicbuffer)); + version_info.quic_version = quicbuffer; + } +#endif + +#ifdef USE_HYPER + { + static char hyper_buffer[30]; + msnprintf(hyper_buffer, sizeof(hyper_buffer), "Hyper/%s", hyper_version()); + version_info.hyper_version = hyper_buffer; + } +#endif + +#ifdef USE_GSASL + { + version_info.gsasl_version = gsasl_check_version(NULL); + } +#endif + + /* Get available features, build bitmask and names array. */ + n = 0; + for(p = features_table; p->name; p++) + if(!p->present || p->present(&version_info)) { + features |= p->bitmask; + feature_names[n++] = p->name; + } + + feature_names[n] = NULL; /* Terminate array. */ + version_info.features = features; + + return &version_info; +} diff --git a/lib/version_win32.c b/lib/version_win32.c new file mode 100644 index 0000000..e0f239e --- /dev/null +++ b/lib/version_win32.c @@ -0,0 +1,319 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(_WIN32) + +#include +#include "version_win32.h" +#include "warnless.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW) + and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */ +struct OUR_OSVERSIONINFOEXW { + ULONG dwOSVersionInfoSize; + ULONG dwMajorVersion; + ULONG dwMinorVersion; + ULONG dwBuildNumber; + ULONG dwPlatformId; + WCHAR szCSDVersion[128]; + USHORT wServicePackMajor; + USHORT wServicePackMinor; + USHORT wSuiteMask; + UCHAR wProductType; + UCHAR wReserved; +}; + +/* + * curlx_verify_windows_version() + * + * This is used to verify if we are running on a specific windows version. + * + * Parameters: + * + * majorVersion [in] - The major version number. + * minorVersion [in] - The minor version number. + * buildVersion [in] - The build version number. If 0, this parameter is + * ignored. + * platform [in] - The optional platform identifier. + * condition [in] - The test condition used to specifier whether we are + * checking a version less then, equal to or greater than + * what is specified in the major and minor version + * numbers. + * + * Returns TRUE if matched; otherwise FALSE. + */ +bool curlx_verify_windows_version(const unsigned int majorVersion, + const unsigned int minorVersion, + const unsigned int buildVersion, + const PlatformIdentifier platform, + const VersionCondition condition) +{ + bool matched = FALSE; + +#if defined(CURL_WINDOWS_APP) + (void)buildVersion; + + /* We have no way to determine the Windows version from Windows apps, + so let's assume we're running on the target Windows version. */ + const WORD fullVersion = MAKEWORD(minorVersion, majorVersion); + const WORD targetVersion = (WORD)_WIN32_WINNT; + + switch(condition) { + case VERSION_LESS_THAN: + matched = targetVersion < fullVersion; + break; + + case VERSION_LESS_THAN_EQUAL: + matched = targetVersion <= fullVersion; + break; + + case VERSION_EQUAL: + matched = targetVersion == fullVersion; + break; + + case VERSION_GREATER_THAN_EQUAL: + matched = targetVersion >= fullVersion; + break; + + case VERSION_GREATER_THAN: + matched = targetVersion > fullVersion; + break; + } + + if(matched && (platform == PLATFORM_WINDOWS)) { + /* we're always running on PLATFORM_WINNT */ + matched = FALSE; + } +#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ + (_WIN32_WINNT < _WIN32_WINNT_WIN2K) + OSVERSIONINFO osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + + /* Find out Windows version */ + if(GetVersionEx(&osver)) { + /* Verify the Operating System version number */ + switch(condition) { + case VERSION_LESS_THAN: + if(osver.dwMajorVersion < majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion < minorVersion) || + (buildVersion != 0 && + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + osver.dwBuildNumber < buildVersion))) + matched = TRUE; + break; + + case VERSION_LESS_THAN_EQUAL: + if(osver.dwMajorVersion < majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion < minorVersion) || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + (buildVersion == 0 || + osver.dwBuildNumber <= buildVersion))) + matched = TRUE; + break; + + case VERSION_EQUAL: + if(osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + (buildVersion == 0 || + osver.dwBuildNumber == buildVersion)) + matched = TRUE; + break; + + case VERSION_GREATER_THAN_EQUAL: + if(osver.dwMajorVersion > majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion > minorVersion) || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + (buildVersion == 0 || + osver.dwBuildNumber >= buildVersion))) + matched = TRUE; + break; + + case VERSION_GREATER_THAN: + if(osver.dwMajorVersion > majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion > minorVersion) || + (buildVersion != 0 && + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + osver.dwBuildNumber > buildVersion))) + matched = TRUE; + break; + } + + /* Verify the platform identifier (if necessary) */ + if(matched) { + switch(platform) { + case PLATFORM_WINDOWS: + if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) + matched = FALSE; + break; + + case PLATFORM_WINNT: + if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) + matched = FALSE; + break; + + default: /* like platform == PLATFORM_DONT_CARE */ + break; + } + } + } +#else + ULONGLONG cm = 0; + struct OUR_OSVERSIONINFOEXW osver; + BYTE majorCondition; + BYTE minorCondition; + BYTE buildCondition; + BYTE spMajorCondition; + BYTE spMinorCondition; + DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; + + typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN) + (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG); + static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo; + static bool onetime = true; /* safe because first call is during init */ + + if(onetime) { + pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, + (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo"))); + onetime = false; + } + + switch(condition) { + case VERSION_LESS_THAN: + majorCondition = VER_LESS; + minorCondition = VER_LESS; + buildCondition = VER_LESS; + spMajorCondition = VER_LESS_EQUAL; + spMinorCondition = VER_LESS_EQUAL; + break; + + case VERSION_LESS_THAN_EQUAL: + majorCondition = VER_LESS_EQUAL; + minorCondition = VER_LESS_EQUAL; + buildCondition = VER_LESS_EQUAL; + spMajorCondition = VER_LESS_EQUAL; + spMinorCondition = VER_LESS_EQUAL; + break; + + case VERSION_EQUAL: + majorCondition = VER_EQUAL; + minorCondition = VER_EQUAL; + buildCondition = VER_EQUAL; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + case VERSION_GREATER_THAN_EQUAL: + majorCondition = VER_GREATER_EQUAL; + minorCondition = VER_GREATER_EQUAL; + buildCondition = VER_GREATER_EQUAL; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + case VERSION_GREATER_THAN: + majorCondition = VER_GREATER; + minorCondition = VER_GREATER; + buildCondition = VER_GREATER; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + default: + return FALSE; + } + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwMajorVersion = majorVersion; + osver.dwMinorVersion = minorVersion; + osver.dwBuildNumber = buildVersion; + if(platform == PLATFORM_WINDOWS) + osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + else if(platform == PLATFORM_WINNT) + osver.dwPlatformId = VER_PLATFORM_WIN32_NT; + + cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition); + cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition); + + if(platform != PLATFORM_DONT_CARE) { + cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); + dwTypeMask |= VER_PLATFORMID; + } + + /* Later versions of Windows have version functions that may not return the + real version of Windows unless the application is so manifested. We prefer + the real version always, so we use the Rtl variant of the function when + possible. Note though the function signatures have underlying fundamental + types that are the same, the return values are different. */ + if(pRtlVerifyVersionInfo) + matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); + else + matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm); + + /* Compare the build number separately. VerifyVersionInfo normally compares + major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not + do the same for build (eg 1.9 build 222 is not less than 2.0 build 111). + Build comparison is only needed when build numbers are equal (eg 1.9 is + always less than 2.0 so build comparison is not needed). */ + if(matched && buildVersion && + (condition == VERSION_EQUAL || + ((condition == VERSION_GREATER_THAN_EQUAL || + condition == VERSION_LESS_THAN_EQUAL) && + curlx_verify_windows_version(majorVersion, minorVersion, 0, + platform, VERSION_EQUAL)))) { + + cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition); + dwTypeMask = VER_BUILDNUMBER; + if(pRtlVerifyVersionInfo) + matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); + else + matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, + dwTypeMask, cm); + } + +#endif + + return matched; +} + +#endif /* _WIN32 */ diff --git a/lib/version_win32.h b/lib/version_win32.h new file mode 100644 index 0000000..95c0661 --- /dev/null +++ b/lib/version_win32.h @@ -0,0 +1,56 @@ +#ifndef HEADER_CURL_VERSION_WIN32_H +#define HEADER_CURL_VERSION_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(_WIN32) + +/* Version condition */ +typedef enum { + VERSION_LESS_THAN, + VERSION_LESS_THAN_EQUAL, + VERSION_EQUAL, + VERSION_GREATER_THAN_EQUAL, + VERSION_GREATER_THAN +} VersionCondition; + +/* Platform identifier */ +typedef enum { + PLATFORM_DONT_CARE, + PLATFORM_WINDOWS, + PLATFORM_WINNT +} PlatformIdentifier; + +/* This is used to verify if we are running on a specific windows version */ +bool curlx_verify_windows_version(const unsigned int majorVersion, + const unsigned int minorVersion, + const unsigned int buildVersion, + const PlatformIdentifier platform, + const VersionCondition condition); + +#endif /* _WIN32 */ + +#endif /* HEADER_CURL_VERSION_WIN32_H */ diff --git a/lib/vquic/curl_msh3.c b/lib/vquic/curl_msh3.c new file mode 100644 index 0000000..7674bc1 --- /dev/null +++ b/lib/vquic/curl_msh3.c @@ -0,0 +1,1092 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_MSH3 + +#include "urldata.h" +#include "timeval.h" +#include "multiif.h" +#include "sendf.h" +#include "curl_trc.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "connect.h" +#include "progress.h" +#include "http1.h" +#include "curl_msh3.h" +#include "socketpair.h" +#include "vtls/vtls.h" +#include "vquic/vquic.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef CURL_DISABLE_SOCKETPAIR +#error "MSH3 cannot be build with CURL_DISABLE_SOCKETPAIR set" +#endif + +#define H3_STREAM_WINDOW_SIZE (128 * 1024) +#define H3_STREAM_CHUNK_SIZE (16 * 1024) +#define H3_STREAM_RECV_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) + +#ifdef _WIN32 +#define msh3_lock CRITICAL_SECTION +#define msh3_lock_initialize(lock) InitializeCriticalSection(lock) +#define msh3_lock_uninitialize(lock) DeleteCriticalSection(lock) +#define msh3_lock_acquire(lock) EnterCriticalSection(lock) +#define msh3_lock_release(lock) LeaveCriticalSection(lock) +#else /* !_WIN32 */ +#include +#define msh3_lock pthread_mutex_t +#define msh3_lock_initialize(lock) do { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init(&attr); \ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init(lock, &attr); \ + pthread_mutexattr_destroy(&attr); \ +}while(0) +#define msh3_lock_uninitialize(lock) pthread_mutex_destroy(lock) +#define msh3_lock_acquire(lock) pthread_mutex_lock(lock) +#define msh3_lock_release(lock) pthread_mutex_unlock(lock) +#endif /* _WIN32 */ + + +static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection, + void *IfContext); +static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection, + void *IfContext); +static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection, + void *IfContext, + MSH3_REQUEST *Request); +static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request, + void *IfContext, + const MSH3_HEADER *Header); +static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request, + void *IfContext, uint32_t *Length, + const uint8_t *Data); +static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext, + bool Aborted, uint64_t AbortError); +static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request, + void *IfContext); +static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request, + void *IfContext, void *SendContext); + + +void Curl_msh3_ver(char *p, size_t len) +{ + uint32_t v[4]; + MsH3Version(v); + (void)msnprintf(p, len, "msh3/%d.%d.%d.%d", v[0], v[1], v[2], v[3]); +} + +#define SP_LOCAL 0 +#define SP_REMOTE 1 + +struct cf_msh3_ctx { + MSH3_API *api; + MSH3_CONNECTION *qconn; + struct Curl_sockaddr_ex addr; + curl_socket_t sock[2]; /* fake socket pair until we get support in msh3 */ + char l_ip[MAX_IPADR_LEN]; /* local IP as string */ + int l_port; /* local port number */ + struct cf_call_data call_data; + struct curltime connect_started; /* time the current attempt started */ + struct curltime handshake_at; /* time connect handshake finished */ + /* Flags written by msh3/msquic thread */ + bool handshake_complete; + bool handshake_succeeded; + bool connected; + /* Flags written by curl thread */ + BIT(verbose); + BIT(active); +}; + +/* How to access `call_data` from a cf_msh3 filter */ +#undef CF_CTX_CALL_DATA +#define CF_CTX_CALL_DATA(cf) \ + ((struct cf_msh3_ctx *)(cf)->ctx)->call_data + +/** + * All about the H3 internals of a stream + */ +struct stream_ctx { + struct MSH3_REQUEST *req; + struct bufq recvbuf; /* h3 response */ +#ifdef _WIN32 + CRITICAL_SECTION recv_lock; +#else /* !_WIN32 */ + pthread_mutex_t recv_lock; +#endif /* _WIN32 */ + uint64_t error3; /* HTTP/3 stream error code */ + int status_code; /* HTTP status code */ + CURLcode recv_error; + bool closed; + bool reset; + bool upload_done; + bool firstheader; /* FALSE until headers arrive */ + bool recv_header_complete; +}; + +#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \ + ((struct HTTP *)(d)->req.p.http)->h3_ctx \ + : NULL)) +#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx +#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \ + H3_STREAM_CTX(d)->id : -2) + + +static CURLcode h3_data_setup(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + + if(stream) + return CURLE_OK; + + stream = calloc(1, sizeof(*stream)); + if(!stream) + return CURLE_OUT_OF_MEMORY; + + H3_STREAM_LCTX(data) = stream; + stream->req = ZERO_NULL; + msh3_lock_initialize(&stream->recv_lock); + Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE, + H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); + CURL_TRC_CF(data, cf, "data setup"); + return CURLE_OK; +} + +static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + + (void)cf; + if(stream) { + CURL_TRC_CF(data, cf, "easy handle is done"); + Curl_bufq_free(&stream->recvbuf); + free(stream); + H3_STREAM_LCTX(data) = NULL; + } +} + +static void drain_stream_from_other_thread(struct Curl_easy *data, + struct stream_ctx *stream) +{ + unsigned char bits; + + /* risky */ + bits = CURL_CSELECT_IN; + if(stream && !stream->upload_done) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; + /* cannot expire from other thread */ + } +} + +static void drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(stream && !stream->upload_done) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +static const MSH3_CONNECTION_IF msh3_conn_if = { + msh3_conn_connected, + msh3_conn_shutdown_complete, + msh3_conn_new_request +}; + +static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection, + void *IfContext) +{ + struct Curl_cfilter *cf = IfContext; + struct cf_msh3_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + (void)Connection; + + CURL_TRC_CF(data, cf, "[MSH3] connected"); + ctx->handshake_succeeded = true; + ctx->connected = true; + ctx->handshake_complete = true; +} + +static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection, + void *IfContext) +{ + struct Curl_cfilter *cf = IfContext; + struct cf_msh3_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + + (void)Connection; + CURL_TRC_CF(data, cf, "[MSH3] shutdown complete"); + ctx->connected = false; + ctx->handshake_complete = true; +} + +static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection, + void *IfContext, + MSH3_REQUEST *Request) +{ + (void)Connection; + (void)IfContext; + (void)Request; +} + +static const MSH3_REQUEST_IF msh3_request_if = { + msh3_header_received, + msh3_data_received, + msh3_complete, + msh3_shutdown_complete, + msh3_data_sent +}; + +/* Decode HTTP status code. Returns -1 if no valid status code was + decoded. (duplicate from http2.c) */ +static int decode_status_code(const char *value, size_t len) +{ + int i; + int res; + + if(len != 3) { + return -1; + } + + res = 0; + + for(i = 0; i < 3; ++i) { + char c = value[i]; + + if(c < '0' || c > '9') { + return -1; + } + + res *= 10; + res += c - '0'; + } + + return res; +} + +/* + * write_resp_raw() copies response data in raw format to the `data`'s + * receive buffer. If not enough space is available, it appends to the + * `data`'s overflow buffer. + */ +static CURLcode write_resp_raw(struct Curl_easy *data, + const void *mem, size_t memlen) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + ssize_t nwritten; + + if(!stream) + return CURLE_RECV_ERROR; + + nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); + if(nwritten < 0) { + return result; + } + + if((size_t)nwritten < memlen) { + /* This MUST not happen. Our recbuf is dimensioned to hold the + * full max_stream_window and then some for this very reason. */ + DEBUGASSERT(0); + return CURLE_RECV_ERROR; + } + return result; +} + +static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request, + void *userp, + const MSH3_HEADER *hd) +{ + struct Curl_easy *data = userp; + struct stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result; + (void)Request; + + if(!stream || stream->recv_header_complete) { + return; + } + + msh3_lock_acquire(&stream->recv_lock); + + if((hd->NameLength == 7) && + !strncmp(HTTP_PSEUDO_STATUS, (char *)hd->Name, 7)) { + char line[14]; /* status line is always 13 characters long */ + size_t ncopy; + + DEBUGASSERT(!stream->firstheader); + stream->status_code = decode_status_code(hd->Value, hd->ValueLength); + DEBUGASSERT(stream->status_code != -1); + ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", + stream->status_code); + result = write_resp_raw(data, line, ncopy); + if(result) + stream->recv_error = result; + stream->firstheader = TRUE; + } + else { + /* store as an HTTP1-style header */ + DEBUGASSERT(stream->firstheader); + result = write_resp_raw(data, hd->Name, hd->NameLength); + if(!result) + result = write_resp_raw(data, ": ", 2); + if(!result) + result = write_resp_raw(data, hd->Value, hd->ValueLength); + if(!result) + result = write_resp_raw(data, "\r\n", 2); + if(result) { + stream->recv_error = result; + } + } + + drain_stream_from_other_thread(data, stream); + msh3_lock_release(&stream->recv_lock); +} + +static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request, + void *IfContext, uint32_t *buflen, + const uint8_t *buf) +{ + struct Curl_easy *data = IfContext; + struct stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result; + bool rv = FALSE; + + /* TODO: we would like to limit the amount of data we are buffer here. + * There seems to be no mechanism in msh3 to adjust flow control and + * it is undocumented what happens if we return FALSE here or less + * length (buflen is an inout parameter). + */ + (void)Request; + if(!stream) + return FALSE; + + msh3_lock_acquire(&stream->recv_lock); + + if(!stream->recv_header_complete) { + result = write_resp_raw(data, "\r\n", 2); + if(result) { + stream->recv_error = result; + goto out; + } + stream->recv_header_complete = true; + } + + result = write_resp_raw(data, buf, *buflen); + if(result) { + stream->recv_error = result; + } + rv = TRUE; + +out: + msh3_lock_release(&stream->recv_lock); + return rv; +} + +static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext, + bool aborted, uint64_t error) +{ + struct Curl_easy *data = IfContext; + struct stream_ctx *stream = H3_STREAM_CTX(data); + + (void)Request; + if(!stream) + return; + msh3_lock_acquire(&stream->recv_lock); + stream->closed = TRUE; + stream->recv_header_complete = true; + if(error) + stream->error3 = error; + if(aborted) + stream->reset = TRUE; + msh3_lock_release(&stream->recv_lock); +} + +static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request, + void *IfContext) +{ + struct Curl_easy *data = IfContext; + struct stream_ctx *stream = H3_STREAM_CTX(data); + + if(!stream) + return; + (void)Request; + (void)stream; +} + +static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request, + void *IfContext, void *SendContext) +{ + struct Curl_easy *data = IfContext; + struct stream_ctx *stream = H3_STREAM_CTX(data); + if(!stream) + return; + (void)Request; + (void)stream; + (void)SendContext; +} + +static ssize_t recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLcode *err) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nread = -1; + + if(!stream) { + *err = CURLE_RECV_ERROR; + return -1; + } + (void)cf; + if(stream->reset) { + failf(data, "HTTP/3 stream reset by server"); + *err = CURLE_PARTIAL_FILE; + CURL_TRC_CF(data, cf, "cf_recv, was reset -> %d", *err); + goto out; + } + else if(stream->error3) { + failf(data, "HTTP/3 stream was not closed cleanly: (error %zd)", + (ssize_t)stream->error3); + *err = CURLE_HTTP3; + CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly -> %d", *err); + goto out; + } + else { + CURL_TRC_CF(data, cf, "cf_recv, closed ok -> %d", *err); + } + *err = CURLE_OK; + nread = 0; + +out: + return nread; +} + +static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + + /* we have no indication from msh3 when it would be a good time + * to juggle the connection again. So, we compromise by calling + * us again every some milliseconds. */ + (void)cf; + if(stream && stream->req && !stream->closed) { + Curl_expire(data, 10, EXPIRE_QUIC); + } + else { + Curl_expire(data, 50, EXPIRE_QUIC); + } +} + +static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nread = -1; + struct cf_call_data save; + + (void)cf; + if(!stream) { + *err = CURLE_RECV_ERROR; + return -1; + } + CF_DATA_SAVE(save, cf, data); + CURL_TRC_CF(data, cf, "req: recv with %zu byte buffer", len); + + msh3_lock_acquire(&stream->recv_lock); + + if(stream->recv_error) { + failf(data, "request aborted"); + *err = stream->recv_error; + goto out; + } + + *err = CURLE_OK; + + if(!Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d", + len, nread, *err); + if(nread < 0) + goto out; + if(stream->closed) + drain_stream(cf, data); + } + else if(stream->closed) { + nread = recv_closed_stream(cf, data, err); + goto out; + } + else { + CURL_TRC_CF(data, cf, "req: nothing here, call again"); + *err = CURLE_AGAIN; + } + +out: + msh3_lock_release(&stream->recv_lock); + set_quic_expire(cf, data); + CF_DATA_RESTORE(cf, save); + return nread; +} + +static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h1_req_parser h1; + struct dynhds h2_headers; + MSH3_HEADER *nva = NULL; + size_t nheader, i; + ssize_t nwritten = -1; + struct cf_call_data save; + bool eos; + + CF_DATA_SAVE(save, cf, data); + + Curl_h1_req_parse_init(&h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); + Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); + + /* Sizes must match for cast below to work" */ + DEBUGASSERT(stream); + CURL_TRC_CF(data, cf, "req: send %zu bytes", len); + + if(!stream->req) { + /* The first send on the request contains the headers and possibly some + data. Parse out the headers and create the request, then if there is + any data left over go ahead and send it too. */ + nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, err); + if(nwritten < 0) + goto out; + DEBUGASSERT(h1.done); + DEBUGASSERT(h1.req); + + *err = Curl_http_req_to_h2(&h2_headers, h1.req, data); + if(*err) { + nwritten = -1; + goto out; + } + + nheader = Curl_dynhds_count(&h2_headers); + nva = malloc(sizeof(MSH3_HEADER) * nheader); + if(!nva) { + *err = CURLE_OUT_OF_MEMORY; + nwritten = -1; + goto out; + } + + for(i = 0; i < nheader; ++i) { + struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i); + nva[i].Name = e->name; + nva[i].NameLength = e->namelen; + nva[i].Value = e->value; + nva[i].ValueLength = e->valuelen; + } + + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + case HTTPREQ_PUT: + /* known request body size or -1 */ + eos = FALSE; + break; + default: + /* there is not request body */ + eos = TRUE; + stream->upload_done = TRUE; + break; + } + + CURL_TRC_CF(data, cf, "req: send %zu headers", nheader); + stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data, + nva, nheader, + eos ? MSH3_REQUEST_FLAG_FIN : + MSH3_REQUEST_FLAG_NONE); + if(!stream->req) { + failf(data, "request open failed"); + *err = CURLE_SEND_ERROR; + goto out; + } + *err = CURLE_OK; + nwritten = len; + goto out; + } + else { + /* request is open */ + CURL_TRC_CF(data, cf, "req: send %zu body bytes", len); + if(len > 0xFFFFFFFF) { + len = 0xFFFFFFFF; + } + + if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf, + (uint32_t)len, stream)) { + *err = CURLE_SEND_ERROR; + goto out; + } + + /* TODO - msh3/msquic will hold onto this memory until the send complete + event. How do we make sure curl doesn't free it until then? */ + *err = CURLE_OK; + nwritten = len; + } + +out: + set_quic_expire(cf, data); + free(nva); + Curl_h1_req_parse_free(&h1); + Curl_dynhds_free(&h2_headers); + CF_DATA_RESTORE(cf, save); + return nwritten; +} + +static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + if(stream && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) { + if(stream->recv_error) { + Curl_pollset_add_in(data, ps, ctx->sock[SP_LOCAL]); + drain_stream(cf, data); + } + else if(stream->req) { + Curl_pollset_add_out(data, ps, ctx->sock[SP_LOCAL]); + drain_stream(cf, data); + } + } +} + +static bool cf_msh3_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + struct cf_call_data save; + bool pending = FALSE; + + CF_DATA_SAVE(save, cf, data); + + (void)cf; + if(stream && stream->req) { + msh3_lock_acquire(&stream->recv_lock); + CURL_TRC_CF((struct Curl_easy *)data, cf, "data pending = %zu", + Curl_bufq_len(&stream->recvbuf)); + pending = !Curl_bufq_is_empty(&stream->recvbuf); + msh3_lock_release(&stream->recv_lock); + if(pending) + drain_stream(cf, (struct Curl_easy *)data); + } + + CF_DATA_RESTORE(cf, save); + return pending; +} + +static void cf_msh3_active(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + + /* use this socket from now on */ + cf->conn->sock[cf->sockindex] = ctx->sock[SP_LOCAL]; + /* the first socket info gets set at conn and data */ + if(cf->sockindex == FIRSTSOCKET) { + cf->conn->remote_addr = &ctx->addr; + #ifdef ENABLE_IPV6 + cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE; + #endif + Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port); + } + ctx->active = TRUE; +} + +static CURLcode h3_data_pause(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool pause) +{ + if(!pause) { + drain_stream(cf, data); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + return CURLE_OK; +} + +static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + struct cf_call_data save; + CURLcode result = CURLE_OK; + + CF_DATA_SAVE(save, cf, data); + + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_DATA_SETUP: + result = h3_data_setup(cf, data); + break; + case CF_CTRL_DATA_PAUSE: + result = h3_data_pause(cf, data, (arg1 != 0)); + break; + case CF_CTRL_DATA_DONE: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE_SEND: + CURL_TRC_CF(data, cf, "req: send done"); + if(stream) { + stream->upload_done = TRUE; + if(stream->req) { + char buf[1]; + if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_FIN, + buf, 0, data)) { + result = CURLE_SEND_ERROR; + } + } + } + break; + case CF_CTRL_CONN_INFO_UPDATE: + CURL_TRC_CF(data, cf, "req: update info"); + cf_msh3_active(cf, data); + break; + default: + break; + } + + CF_DATA_RESTORE(cf, save); + return result; +} + +static CURLcode cf_connect_start(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + struct ssl_primary_config *conn_config; + MSH3_ADDR addr = {0}; + CURLcode result; + bool verify; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; + verify = !!conn_config->verifypeer; + + memcpy(&addr, &ctx->addr.sa_addr, ctx->addr.addrlen); + MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port); + + if(verify && (conn_config->CAfile || conn_config->CApath)) { + /* TODO: need a way to provide trust anchors to MSH3 */ +#ifdef DEBUGBUILD + /* we need this for our test cases to run */ + CURL_TRC_CF(data, cf, "non-standard CA not supported, " + "switching off verifypeer in DEBUG mode"); + verify = 0; +#else + CURL_TRC_CF(data, cf, "non-standard CA not supported, " + "attempting with built-in verification"); +#endif + } + + CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)", + cf->conn->host.name, (int)cf->conn->remote_port, verify); + + ctx->api = MsH3ApiOpen(); + if(!ctx->api) { + failf(data, "can't create msh3 api"); + return CURLE_FAILED_INIT; + } + + ctx->qconn = MsH3ConnectionOpen(ctx->api, + &msh3_conn_if, + cf, + cf->conn->host.name, + &addr, + !verify); + if(!ctx->qconn) { + failf(data, "can't create msh3 connection"); + if(ctx->api) { + MsH3ApiClose(ctx->api); + ctx->api = NULL; + } + return CURLE_FAILED_INIT; + } + + result = h3_data_setup(cf, data); + if(result) + return result; + + return CURLE_OK; +} + +static CURLcode cf_msh3_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + struct cf_call_data save; + CURLcode result = CURLE_OK; + + (void)blocking; + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + CF_DATA_SAVE(save, cf, data); + + if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) { + if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0]) < 0) { + ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; + ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; + return CURLE_COULDNT_CONNECT; + } + } + + *done = FALSE; + if(!ctx->qconn) { + ctx->connect_started = Curl_now(); + result = cf_connect_start(cf, data); + if(result) + goto out; + } + + if(ctx->handshake_complete) { + ctx->handshake_at = Curl_now(); + if(ctx->handshake_succeeded) { + CURL_TRC_CF(data, cf, "handshake succeeded"); + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + cf->conn->httpversion = 30; + cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; + cf->connected = TRUE; + cf->conn->alpn = CURL_HTTP_VERSION_3; + *done = TRUE; + connkeep(cf->conn, "HTTP/3 default"); + Curl_pgrsTime(data, TIMER_APPCONNECT); + } + else { + failf(data, "failed to connect, handshake failed"); + result = CURLE_COULDNT_CONNECT; + } + } + +out: + CF_DATA_RESTORE(cf, save); + return result; +} + +static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + struct cf_call_data save; + + (void)data; + CF_DATA_SAVE(save, cf, data); + + if(ctx) { + CURL_TRC_CF(data, cf, "destroying"); + if(ctx->qconn) { + MsH3ConnectionClose(ctx->qconn); + ctx->qconn = NULL; + } + if(ctx->api) { + MsH3ApiClose(ctx->api); + ctx->api = NULL; + } + + if(ctx->active) { + /* We share our socket at cf->conn->sock[cf->sockindex] when active. + * If it is no longer there, someone has stolen (and hopefully + * closed it) and we just forget about it. + */ + ctx->active = FALSE; + if(ctx->sock[SP_LOCAL] == cf->conn->sock[cf->sockindex]) { + CURL_TRC_CF(data, cf, "cf_msh3_close(%d) active", + (int)ctx->sock[SP_LOCAL]); + cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD; + } + else { + CURL_TRC_CF(data, cf, "cf_socket_close(%d) no longer at " + "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]); + ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; + } + if(cf->sockindex == FIRSTSOCKET) + cf->conn->remote_addr = NULL; + } + if(ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) { + sclose(ctx->sock[SP_LOCAL]); + } + if(ctx->sock[SP_REMOTE] != CURL_SOCKET_BAD) { + sclose(ctx->sock[SP_REMOTE]); + } + ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; + ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; + } + CF_DATA_RESTORE(cf, save); +} + +static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + cf_msh3_close(cf, data); + free(cf->ctx); + cf->ctx = NULL; + /* no CF_DATA_RESTORE(cf, save); its gone */ + +} + +static CURLcode cf_msh3_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + + switch(query) { + case CF_QUERY_MAX_CONCURRENT: { + /* TODO: we do not have access to this so far, fake it */ + (void)ctx; + *pres1 = 100; + return CURLE_OK; + } + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + /* we do not know when the first byte arrived */ + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_msh3_ctx *ctx = cf->ctx; + + (void)data; + *input_pending = FALSE; + return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn && + ctx->connected; +} + +struct Curl_cftype Curl_cft_http3 = { + "HTTP/3", + CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX, + 0, + cf_msh3_destroy, + cf_msh3_connect, + cf_msh3_close, + Curl_cf_def_get_host, + cf_msh3_adjust_pollset, + cf_msh3_data_pending, + cf_msh3_send, + cf_msh3_recv, + cf_msh3_data_event, + cf_msh3_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_msh3_query, +}; + +CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai) +{ + struct cf_msh3_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL; + CURLcode result; + + (void)data; + (void)conn; + (void)ai; /* TODO: msh3 resolves itself? */ + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC); + ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; + ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; + + result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); + +out: + *pcf = (!result)? cf : NULL; + if(result) { + Curl_safefree(cf); + Curl_safefree(ctx); + } + + return result; +} + +bool Curl_conn_is_msh3(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL; + + (void)data; + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_http3) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; +} + +#endif /* USE_MSH3 */ diff --git a/lib/vquic/curl_msh3.h b/lib/vquic/curl_msh3.h new file mode 100644 index 0000000..33931f5 --- /dev/null +++ b/lib/vquic/curl_msh3.h @@ -0,0 +1,46 @@ +#ifndef HEADER_CURL_VQUIC_CURL_MSH3_H +#define HEADER_CURL_VQUIC_CURL_MSH3_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_MSH3 + +#include + +void Curl_msh3_ver(char *p, size_t len); + +CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai); + +bool Curl_conn_is_msh3(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex); + +#endif /* USE_MSQUIC */ + +#endif /* HEADER_CURL_VQUIC_CURL_MSH3_H */ diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c new file mode 100644 index 0000000..a26b3e4 --- /dev/null +++ b/lib/vquic/curl_ngtcp2.c @@ -0,0 +1,2386 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NGTCP2) && defined(USE_NGHTTP3) +#include +#include + +#ifdef USE_OPENSSL +#include +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#include +#else +#include +#endif +#include "vtls/openssl.h" +#elif defined(USE_GNUTLS) +#include +#include "vtls/gtls.h" +#elif defined(USE_WOLFSSL) +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "strdup.h" +#include "rand.h" +#include "multiif.h" +#include "strcase.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "connect.h" +#include "progress.h" +#include "strerror.h" +#include "dynbuf.h" +#include "http1.h" +#include "select.h" +#include "inet_pton.h" +#include "vquic.h" +#include "vquic_int.h" +#include "vquic-tls.h" +#include "vtls/keylog.h" +#include "vtls/vtls.h" +#include "curl_ngtcp2.h" + +#include "warnless.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +#define QUIC_MAX_STREAMS (256*1024) +#define QUIC_MAX_DATA (1*1024*1024) +#define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS) + +/* A stream window is the maximum amount we need to buffer for + * each active transfer. We use HTTP/3 flow control and only ACK + * when we take things out of the buffer. + * Chunk size is large enough to take a full DATA frame */ +#define H3_STREAM_WINDOW_SIZE (128 * 1024) +#define H3_STREAM_CHUNK_SIZE (16 * 1024) +/* The pool keeps spares around and half of a full stream windows + * seems good. More does not seem to improve performance. + * The benefit of the pool is that stream buffer to not keep + * spares. So memory consumption goes down when streams run empty, + * have a large upload done, etc. */ +#define H3_STREAM_POOL_SPARES \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 +/* Receive and Send max number of chunks just follows from the + * chunk size and window size */ +#define H3_STREAM_RECV_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) +#define H3_STREAM_SEND_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) + + +/* + * Store ngtcp2 version info in this buffer. + */ +void Curl_ngtcp2_ver(char *p, size_t len) +{ + const ngtcp2_info *ng2 = ngtcp2_version(0); + const nghttp3_info *ht3 = nghttp3_version(0); + (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s", + ng2->version_str, ht3->version_str); +} + +struct cf_ngtcp2_ctx { + struct cf_quic_ctx q; + struct ssl_peer peer; + struct quic_tls_ctx tls; + ngtcp2_path connected_path; + ngtcp2_conn *qconn; + ngtcp2_cid dcid; + ngtcp2_cid scid; + uint32_t version; + ngtcp2_settings settings; + ngtcp2_transport_params transport_params; + ngtcp2_ccerr last_error; + ngtcp2_crypto_conn_ref conn_ref; + struct cf_call_data call_data; + nghttp3_conn *h3conn; + nghttp3_settings h3settings; + struct curltime started_at; /* time the current attempt started */ + struct curltime handshake_at; /* time connect handshake finished */ + struct curltime reconnect_at; /* time the next attempt should start */ + struct bufc_pool stream_bufcp; /* chunk pool for streams */ + size_t max_stream_window; /* max flow window for one stream */ + uint64_t max_idle_ms; /* max idle time for QUIC connection */ + int qlogfd; +}; + +/* How to access `call_data` from a cf_ngtcp2 filter */ +#undef CF_CTX_CALL_DATA +#define CF_CTX_CALL_DATA(cf) \ + ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data + +/** + * All about the H3 internals of a stream + */ +struct h3_stream_ctx { + int64_t id; /* HTTP/3 protocol identifier */ + struct bufq sendbuf; /* h3 request body */ + struct bufq recvbuf; /* h3 response body */ + struct h1_req_parser h1; /* h1 request parsing */ + size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */ + size_t upload_blocked_len; /* the amount written last and EGAINed */ + size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */ + uint64_t error3; /* HTTP/3 stream error code */ + curl_off_t upload_left; /* number of request bytes left to upload */ + int status_code; /* HTTP status code */ + bool resp_hds_complete; /* we have a complete, final response */ + bool closed; /* TRUE on stream close */ + bool reset; /* TRUE on stream reset */ + bool send_closed; /* stream is local closed */ + BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */ +}; + +#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \ + ((struct HTTP *)(d)->req.p.http)->h3_ctx \ + : NULL)) +#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx +#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \ + H3_STREAM_CTX(d)->id : -2) + +static CURLcode h3_data_setup(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + + if(!data || !data->req.p.http) { + failf(data, "initialization failure, transfer not http initialized"); + return CURLE_FAILED_INIT; + } + + if(stream) + return CURLE_OK; + + stream = calloc(1, sizeof(*stream)); + if(!stream) + return CURLE_OUT_OF_MEMORY; + + stream->id = -1; + /* on send, we control how much we put into the buffer */ + Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, + H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); + stream->sendbuf_len_in_flight = 0; + /* on recv, we need a flexible buffer limit since we also write + * headers to it that are not counted against the nghttp3 flow limits. */ + Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, + H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); + stream->recv_buf_nonflow = 0; + Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); + + H3_STREAM_LCTX(data) = stream; + return CURLE_OK; +} + +static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + + (void)cf; + if(stream) { + CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id); + if(ctx->h3conn && !stream->closed) { + nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream->id); + nghttp3_conn_close_stream(ctx->h3conn, stream->id, + NGHTTP3_H3_REQUEST_CANCELLED); + nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL); + ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL); + stream->closed = TRUE; + } + + Curl_bufq_free(&stream->sendbuf); + Curl_bufq_free(&stream->recvbuf); + Curl_h1_req_parse_free(&stream->h1); + free(stream); + H3_STREAM_LCTX(data) = NULL; + } +} + +static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf, + struct Curl_easy *data, + int64_t stream_id) +{ + struct Curl_easy *sdata; + + (void)cf; + if(H3_STREAM_ID(data) == stream_id) { + return data; + } + else { + DEBUGASSERT(data->multi); + for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { + if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) { + return sdata; + } + } + } + return NULL; +} + +static void h3_drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(stream && stream->upload_left && !stream->send_closed) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +/* ngtcp2 default congestion controller does not perform pacing. Limit + the maximum packet burst to MAX_PKT_BURST packets. */ +#define MAX_PKT_BURST 10 + +struct pkt_io_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; + ngtcp2_tstamp ts; + size_t pkt_count; + ngtcp2_path_storage ps; +}; + +static void pktx_update_time(struct pkt_io_ctx *pktx, + struct Curl_cfilter *cf) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + + vquic_ctx_update_time(&ctx->q); + pktx->ts = ctx->q.last_op.tv_sec * NGTCP2_SECONDS + + ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS; +} + +static void pktx_init(struct pkt_io_ctx *pktx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + pktx->cf = cf; + pktx->data = data; + pktx->pkt_count = 0; + ngtcp2_path_storage_zero(&pktx->ps); + pktx_update_time(pktx, cf); +} + +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx); +static CURLcode cf_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx); +static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, + uint64_t datalen, void *user_data, + void *stream_user_data); + +static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) +{ + struct Curl_cfilter *cf = conn_ref->user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + return ctx->qconn; +} + +#ifdef DEBUG_NGTCP2 +static void quic_printf(void *user_data, const char *fmt, ...) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + + (void)ctx; /* TODO: need an easy handle to infof() message */ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} +#endif + +static void qlog_callback(void *user_data, uint32_t flags, + const void *data, size_t datalen) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + (void)flags; + if(ctx->qlogfd != -1) { + ssize_t rc = write(ctx->qlogfd, data, datalen); + if(rc == -1) { + /* on write error, stop further write attempts */ + close(ctx->qlogfd); + ctx->qlogfd = -1; + } + } + +} + +static void quic_settings(struct cf_ngtcp2_ctx *ctx, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) +{ + ngtcp2_settings *s = &ctx->settings; + ngtcp2_transport_params *t = &ctx->transport_params; + + ngtcp2_settings_default(s); + ngtcp2_transport_params_default(t); +#ifdef DEBUG_NGTCP2 + s->log_printf = quic_printf; +#else + s->log_printf = NULL; +#endif + + (void)data; + s->initial_ts = pktx->ts; + s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT; + s->max_window = 100 * ctx->max_stream_window; + s->max_stream_window = ctx->max_stream_window; + + t->initial_max_data = 10 * ctx->max_stream_window; + t->initial_max_stream_data_bidi_local = ctx->max_stream_window; + t->initial_max_stream_data_bidi_remote = ctx->max_stream_window; + t->initial_max_stream_data_uni = ctx->max_stream_window; + t->initial_max_streams_bidi = QUIC_MAX_STREAMS; + t->initial_max_streams_uni = QUIC_MAX_STREAMS; + t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS); + if(ctx->qlogfd != -1) { + s->qlog_write = qlog_callback; + } +} + +static int init_ngh3_conn(struct Curl_cfilter *cf); + +static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) +{ + (void)user_data; + (void)tconn; + return 0; +} + +static void report_consumed_data(struct Curl_cfilter *cf, + struct Curl_easy *data, + size_t consumed) +{ + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + struct cf_ngtcp2_ctx *ctx = cf->ctx; + + if(!stream) + return; + /* the HTTP/1.1 response headers are written to the buffer, but + * consuming those does not count against flow control. */ + if(stream->recv_buf_nonflow) { + if(consumed >= stream->recv_buf_nonflow) { + consumed -= stream->recv_buf_nonflow; + stream->recv_buf_nonflow = 0; + } + else { + stream->recv_buf_nonflow -= consumed; + consumed = 0; + } + } + if(consumed > 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] ACK %zu bytes of DATA", + stream->id, consumed); + ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, + consumed); + ngtcp2_conn_extend_max_offset(ctx->qconn, consumed); + } +} + +static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags, + int64_t stream_id, uint64_t offset, + const uint8_t *buf, size_t buflen, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + nghttp3_ssize nconsumed; + int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0; + struct Curl_easy *data = stream_user_data; + (void)offset; + (void)data; + + nconsumed = + nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin); + CURL_TRC_CF(data, cf, "[%" PRId64 "] read_stream(len=%zu) -> %zd", + stream_id, buflen, nconsumed); + if(nconsumed < 0) { + if(!data) { + struct Curl_easy *cdata = CF_DATA_CURRENT(cf); + CURL_TRC_CF(cdata, cf, "[%" PRId64 "] nghttp3 error on stream not " + "used by us, ignored", stream_id); + return 0; + } + ngtcp2_ccerr_set_application_error( + &ctx->last_error, + nghttp3_err_infer_quic_app_error_code((int)nconsumed), NULL, 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + /* number of bytes inside buflen which consists of framing overhead + * including QPACK HEADERS. In other words, it does not consume payload of + * DATA frame. */ + ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed); + ngtcp2_conn_extend_max_offset(tconn, nconsumed); + + return 0; +} + +static int +cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id, + uint64_t offset, uint64_t datalen, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + int rv; + (void)stream_id; + (void)tconn; + (void)offset; + (void)datalen; + (void)stream_user_data; + + rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags, + int64_t stream3_id, uint64_t app_error_code, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + int rv; + + (void)tconn; + (void)data; + /* stream is closed... */ + + if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) { + app_error_code = NGHTTP3_H3_NO_ERROR; + } + + rv = nghttp3_conn_close_stream(ctx->h3conn, stream3_id, + app_error_code); + CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(err=%" + PRIu64 ") -> %d", stream3_id, app_error_code, rv); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + ngtcp2_ccerr_set_application_error( + &ctx->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id, + uint64_t final_size, uint64_t app_error_code, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct Curl_easy *data = stream_user_data; + int rv; + (void)tconn; + (void)final_size; + (void)app_error_code; + (void)data; + + rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id); + CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + int rv; + (void)tconn; + (void)app_error_code; + (void)stream_user_data; + + rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn, + uint64_t max_streams, + void *user_data) +{ + (void)tconn; + (void)max_streams; + (void)user_data; + + return 0; +} + +static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id, + uint64_t max_data, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + struct Curl_easy *s_data; + struct h3_stream_ctx *stream; + int rv; + (void)tconn; + (void)max_data; + (void)stream_user_data; + + rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + s_data = get_stream_easy(cf, data, stream_id); + stream = H3_STREAM_CTX(s_data); + if(stream && stream->quic_flow_blocked) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] unblock quic flow", stream_id); + stream->quic_flow_blocked = FALSE; + h3_drain_stream(cf, data); + } + return 0; +} + +static void cb_rand(uint8_t *dest, size_t destlen, + const ngtcp2_rand_ctx *rand_ctx) +{ + CURLcode result; + (void)rand_ctx; + + result = Curl_rand(NULL, dest, destlen); + if(result) { + /* cb_rand is only used for non-cryptographic context. If Curl_rand + failed, just fill 0 and call it *random*. */ + memset(dest, 0, destlen); + } +} + +static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, + uint8_t *token, size_t cidlen, + void *user_data) +{ + CURLcode result; + (void)tconn; + (void)user_data; + + result = Curl_rand(NULL, cid->data, cidlen); + if(result) + return NGTCP2_ERR_CALLBACK_FAILURE; + cid->datalen = cidlen; + + result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN); + if(result) + return NGTCP2_ERR_CALLBACK_FAILURE; + + return 0; +} + +static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level, + void *user_data) +{ + struct Curl_cfilter *cf = user_data; + (void)tconn; + + if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT) { + return 0; + } + + if(init_ngh3_conn(cf) != CURLE_OK) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static ngtcp2_callbacks ng_callbacks = { + ngtcp2_crypto_client_initial_cb, + NULL, /* recv_client_initial */ + ngtcp2_crypto_recv_crypto_data_cb, + cb_handshake_completed, + NULL, /* recv_version_negotiation */ + ngtcp2_crypto_encrypt_cb, + ngtcp2_crypto_decrypt_cb, + ngtcp2_crypto_hp_mask_cb, + cb_recv_stream_data, + cb_acked_stream_data_offset, + NULL, /* stream_open */ + cb_stream_close, + NULL, /* recv_stateless_reset */ + ngtcp2_crypto_recv_retry_cb, + cb_extend_max_local_streams_bidi, + NULL, /* extend_max_local_streams_uni */ + cb_rand, + cb_get_new_connection_id, + NULL, /* remove_connection_id */ + ngtcp2_crypto_update_key_cb, /* update_key */ + NULL, /* path_validation */ + NULL, /* select_preferred_addr */ + cb_stream_reset, + NULL, /* extend_max_remote_streams_bidi */ + NULL, /* extend_max_remote_streams_uni */ + cb_extend_max_stream_data, + NULL, /* dcid_status */ + NULL, /* handshake_confirmed */ + NULL, /* recv_new_token */ + ngtcp2_crypto_delete_crypto_aead_ctx_cb, + ngtcp2_crypto_delete_crypto_cipher_ctx_cb, + NULL, /* recv_datagram */ + NULL, /* ack_datagram */ + NULL, /* lost_datagram */ + ngtcp2_crypto_get_path_challenge_data_cb, + cb_stream_stop_sending, + NULL, /* version_negotiation */ + cb_recv_rx_key, + NULL, /* recv_tx_key */ + NULL, /* early_data_rejected */ +}; + +/** + * Connection maintenance like timeouts on packet ACKs etc. are done by us, not + * the OS like for TCP. POLL events on the socket therefore are not + * sufficient. + * ngtcp2 tells us when it wants to be invoked again. We handle that via + * the `Curl_expire()` mechanisms. + */ +static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct pkt_io_ctx local_pktx; + ngtcp2_tstamp expiry; + + if(!pktx) { + pktx_init(&local_pktx, cf, data); + pktx = &local_pktx; + } + else { + pktx_update_time(pktx, cf); + } + + expiry = ngtcp2_conn_get_expiry(ctx->qconn); + if(expiry != UINT64_MAX) { + if(expiry <= pktx->ts) { + CURLcode result; + int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts); + if(rv) { + failf(data, "ngtcp2_conn_handle_expiry returned error: %s", + ngtcp2_strerror(rv)); + ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0); + return CURLE_SEND_ERROR; + } + result = cf_progress_ingress(cf, data, pktx); + if(result) + return result; + result = cf_progress_egress(cf, data, pktx); + if(result) + return result; + /* ask again, things might have changed */ + expiry = ngtcp2_conn_get_expiry(ctx->qconn); + } + + if(expiry > pktx->ts) { + ngtcp2_duration timeout = expiry - pktx->ts; + if(timeout % NGTCP2_MILLISECONDS) { + timeout += NGTCP2_MILLISECONDS; + } + Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC); + } + } + return CURLE_OK; +} + +static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + bool want_recv, want_send; + + if(!ctx->qconn) + return; + + Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); + if(want_recv || want_send) { + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + struct cf_call_data save; + bool c_exhaust, s_exhaust; + + CF_DATA_SAVE(save, cf, data); + c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) || + !ngtcp2_conn_get_max_data_left(ctx->qconn)); + s_exhaust = want_send && stream && stream->id >= 0 && + stream->quic_flow_blocked; + want_recv = (want_recv || c_exhaust || s_exhaust); + want_send = (!s_exhaust && want_send) || + !Curl_bufq_is_empty(&ctx->q.sendbuf); + + Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); + CF_DATA_RESTORE(cf, save); + } +} + +static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + (void)conn; + (void)stream_id; + + /* we might be called by nghttp3 after we already cleaned up */ + if(!stream) + return 0; + + stream->closed = TRUE; + stream->error3 = app_error_code; + if(stream->error3 != NGHTTP3_H3_NO_ERROR) { + stream->reset = TRUE; + stream->send_closed = TRUE; + CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64, + stream->id, stream->error3); + } + else { + CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->id); + } + h3_drain_stream(cf, data); + return 0; +} + +/* + * write_resp_raw() copies response data in raw format to the `data`'s + * receive buffer. If not enough space is available, it appends to the + * `data`'s overflow buffer. + */ +static CURLcode write_resp_raw(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, size_t memlen, + bool flow) +{ + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + ssize_t nwritten; + + (void)cf; + if(!stream) { + return CURLE_RECV_ERROR; + } + nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); + if(nwritten < 0) { + return result; + } + + if(!flow) + stream->recv_buf_nonflow += (size_t)nwritten; + + if((size_t)nwritten < memlen) { + /* This MUST not happen. Our recbuf is dimensioned to hold the + * full max_stream_window and then some for this very reason. */ + DEBUGASSERT(0); + return CURLE_RECV_ERROR; + } + return result; +} + +static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, + const uint8_t *buf, size_t buflen, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result; + + (void)conn; + (void)stream3_id; + + if(!stream) + return NGHTTP3_ERR_CALLBACK_FAILURE; + + result = write_resp_raw(cf, data, buf, buflen, TRUE); + if(result) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d", + stream->id, buflen, result); + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, buflen); + h3_drain_stream(cf, data); + return 0; +} + +static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream3_id, + size_t consumed, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + (void)conn; + (void)stream_user_data; + + /* nghttp3 has consumed bytes on the QUIC stream and we need to + * tell the QUIC connection to increase its flow control */ + ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream3_id, consumed); + ngtcp2_conn_extend_max_offset(ctx->qconn, consumed); + return 0; +} + +static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, + int fin, void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + (void)conn; + (void)stream_id; + (void)fin; + (void)cf; + + if(!stream) + return 0; + /* add a CRLF only if we've received some headers */ + result = write_resp_raw(cf, data, "\r\n", 2, FALSE); + if(result) { + return -1; + } + + CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d", + stream_id, stream->status_code); + if(stream->status_code / 100 != 1) { + stream->resp_hds_complete = TRUE; + } + h3_drain_stream(cf, data); + return 0; +} + +static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, + int32_t token, nghttp3_rcbuf *name, + nghttp3_rcbuf *value, uint8_t flags, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name); + nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value); + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + (void)conn; + (void)stream_id; + (void)token; + (void)flags; + (void)cf; + + /* we might have cleaned up this transfer already */ + if(!stream) + return 0; + + if(token == NGHTTP3_QPACK_TOKEN__STATUS) { + char line[14]; /* status line is always 13 characters long */ + size_t ncopy; + + result = Curl_http_decode_status(&stream->status_code, + (const char *)h3val.base, h3val.len); + if(result) + return -1; + ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", + stream->status_code); + CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line); + result = write_resp_raw(cf, data, line, ncopy, FALSE); + if(result) { + return -1; + } + } + else { + /* store as an HTTP1-style header */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s", + stream_id, (int)h3name.len, h3name.base, + (int)h3val.len, h3val.base); + result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, ": ", 2, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, "\r\n", 2, FALSE); + if(result) { + return -1; + } + } + return 0; +} + +static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + int rv; + (void)conn; + (void)stream_user_data; + + rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id, + app_error_code); + if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + struct Curl_cfilter *cf = user_data; + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct Curl_easy *data = stream_user_data; + int rv; + (void)conn; + (void)data; + + rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id, + app_error_code); + CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv); + if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static nghttp3_callbacks ngh3_callbacks = { + cb_h3_acked_req_body, /* acked_stream_data */ + cb_h3_stream_close, + cb_h3_recv_data, + cb_h3_deferred_consume, + NULL, /* begin_headers */ + cb_h3_recv_header, + cb_h3_end_headers, + NULL, /* begin_trailers */ + cb_h3_recv_header, + NULL, /* end_trailers */ + cb_h3_stop_sending, + NULL, /* end_stream */ + cb_h3_reset_stream, + NULL, /* shutdown */ + NULL /* recv_settings */ +}; + +static int init_ngh3_conn(struct Curl_cfilter *cf) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + CURLcode result; + int rc; + int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id; + + if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) { + return CURLE_QUIC_CONNECT_ERROR; + } + + nghttp3_settings_default(&ctx->h3settings); + + rc = nghttp3_conn_client_new(&ctx->h3conn, + &ngh3_callbacks, + &ctx->h3settings, + nghttp3_mem_default(), + cf); + if(rc) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &ctrl_stream_id, NULL); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto fail; + } + + rc = nghttp3_conn_bind_control_stream(ctx->h3conn, ctrl_stream_id); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto fail; + } + + rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_enc_stream_id, NULL); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto fail; + } + + rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_dec_stream_id, NULL); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto fail; + } + + rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id, + qpack_dec_stream_id); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto fail; + } + + return CURLE_OK; +fail: + + return result; +} + +static ssize_t recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h3_stream_ctx *stream, + CURLcode *err) +{ + ssize_t nread = -1; + + (void)cf; + if(stream->reset) { + failf(data, + "HTTP/3 stream %" PRId64 " reset by server", stream->id); + *err = stream->resp_hds_complete? CURLE_PARTIAL_FILE : CURLE_HTTP3; + goto out; + } + else if(!stream->resp_hds_complete) { + failf(data, + "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting" + " all response header fields, treated as error", + stream->id); + *err = CURLE_HTTP3; + goto out; + } + *err = CURLE_OK; + nread = 0; + +out: + return nread; +} + +/* incoming data frames on the h3 stream */ +static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nread = -1; + struct cf_call_data save; + struct pkt_io_ctx pktx; + + (void)ctx; + + CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(cf->connected); + DEBUGASSERT(ctx); + DEBUGASSERT(ctx->qconn); + DEBUGASSERT(ctx->h3conn); + *err = CURLE_OK; + + pktx_init(&pktx, cf, data); + + if(!stream) { + *err = CURLE_RECV_ERROR; + goto out; + } + + if(!Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->id, len, nread, *err); + goto out; + } + report_consumed_data(cf, data, nread); + } + + if(cf_progress_ingress(cf, data, &pktx)) { + *err = CURLE_RECV_ERROR; + nread = -1; + goto out; + } + + /* recvbuf had nothing before, maybe after progressing ingress? */ + if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->id, len, nread, *err); + goto out; + } + report_consumed_data(cf, data, nread); + } + + if(nread > 0) { + h3_drain_stream(cf, data); + } + else { + if(stream->closed) { + nread = recv_closed_stream(cf, data, stream, err); + goto out; + } + *err = CURLE_AGAIN; + nread = -1; + } + +out: + if(cf_progress_egress(cf, data, &pktx)) { + *err = CURLE_SEND_ERROR; + nread = -1; + } + else { + CURLcode result2 = check_and_set_expiry(cf, data, &pktx); + if(result2) { + *err = result2; + nread = -1; + } + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(len=%zu) -> %zd, %d", + stream? stream->id : -1, len, nread, *err); + CF_DATA_RESTORE(cf, save); + return nread; +} + +static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, + uint64_t datalen, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + size_t skiplen; + + (void)cf; + if(!stream) + return 0; + /* The server acknowledged `datalen` of bytes from our request body. + * This is a delta. We have kept this data in `sendbuf` for + * re-transmissions and can free it now. */ + if(datalen >= (uint64_t)stream->sendbuf_len_in_flight) + skiplen = stream->sendbuf_len_in_flight; + else + skiplen = (size_t)datalen; + Curl_bufq_skip(&stream->sendbuf, skiplen); + stream->sendbuf_len_in_flight -= skiplen; + + /* Everything ACKed, we resume upload processing */ + if(!stream->sendbuf_len_in_flight) { + int rv = nghttp3_conn_resume_stream(conn, stream_id); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static nghttp3_ssize +cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, + nghttp3_vec *vec, size_t veccnt, + uint32_t *pflags, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nwritten = 0; + size_t nvecs = 0; + (void)cf; + (void)conn; + (void)stream_id; + (void)user_data; + (void)veccnt; + + if(!stream) + return NGHTTP3_ERR_CALLBACK_FAILURE; + /* nghttp3 keeps references to the sendbuf data until it is ACKed + * by the server (see `cb_h3_acked_req_body()` for updates). + * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf` + * that we have already passed to nghttp3, but which have not been + * ACKed yet. + * Any amount beyond `sendbuf_len_in_flight` we need still to pass + * to nghttp3. Do that now, if we can. */ + if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) { + nvecs = 0; + while(nvecs < veccnt && + Curl_bufq_peek_at(&stream->sendbuf, + stream->sendbuf_len_in_flight, + (const unsigned char **)&vec[nvecs].base, + &vec[nvecs].len)) { + stream->sendbuf_len_in_flight += vec[nvecs].len; + nwritten += vec[nvecs].len; + ++nvecs; + } + DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */ + } + + if(nwritten > 0 && stream->upload_left != -1) + stream->upload_left -= nwritten; + + /* When we stopped sending and everything in `sendbuf` is "in flight", + * we are at the end of the request body. */ + if(stream->upload_left == 0) { + *pflags = NGHTTP3_DATA_FLAG_EOF; + stream->send_closed = TRUE; + } + else if(!nwritten) { + /* Not EOF, and nothing to give, we signal WOULDBLOCK. */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN", + stream->id); + return NGHTTP3_ERR_WOULDBLOCK; + } + + CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> " + "%d vecs%s with %zu (buffered=%zu, left=%" + CURL_FORMAT_CURL_OFF_T ")", + stream->id, (int)nvecs, + *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"", + nwritten, Curl_bufq_len(&stream->sendbuf), + stream->upload_left); + return (nghttp3_ssize)nvecs; +} + +/* Index where :authority header field will appear in request header + field list. */ +#define AUTHORITY_DST_IDX 3 + +static ssize_t h3_stream_open(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t len, + CURLcode *err) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = NULL; + struct dynhds h2_headers; + size_t nheader; + nghttp3_nv *nva = NULL; + int rc = 0; + unsigned int i; + ssize_t nwritten = -1; + nghttp3_data_reader reader; + nghttp3_data_reader *preader = NULL; + + Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); + + *err = h3_data_setup(cf, data); + if(*err) + goto out; + stream = H3_STREAM_CTX(data); + DEBUGASSERT(stream); + if(!stream) { + *err = CURLE_FAILED_INIT; + goto out; + } + + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + if(nwritten < 0) + goto out; + if(!stream->h1.done) { + /* need more data */ + goto out; + } + DEBUGASSERT(stream->h1.req); + + *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(*err) { + nwritten = -1; + goto out; + } + /* no longer needed */ + Curl_h1_req_parse_free(&stream->h1); + + nheader = Curl_dynhds_count(&h2_headers); + nva = malloc(sizeof(nghttp3_nv) * nheader); + if(!nva) { + *err = CURLE_OUT_OF_MEMORY; + nwritten = -1; + goto out; + } + + for(i = 0; i < nheader; ++i) { + struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i); + nva[i].name = (unsigned char *)e->name; + nva[i].namelen = e->namelen; + nva[i].value = (unsigned char *)e->value; + nva[i].valuelen = e->valuelen; + nva[i].flags = NGHTTP3_NV_FLAG_NONE; + } + + rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &stream->id, data); + if(rc) { + failf(data, "can get bidi streams"); + *err = CURLE_SEND_ERROR; + goto out; + } + + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + case HTTPREQ_PUT: + /* known request body size or -1 */ + if(data->state.infilesize != -1) + stream->upload_left = data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown */ + break; + default: + /* there is not request body */ + stream->upload_left = 0; /* no request body */ + break; + } + + stream->send_closed = (stream->upload_left == 0); + if(!stream->send_closed) { + reader.read_data = cb_h3_read_req_body; + preader = &reader; + } + + rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id, + nva, nheader, preader, data); + if(rc) { + switch(rc) { + case NGHTTP3_ERR_CONN_CLOSING: + CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, " + "connection is closing", stream->id); + break; + default: + CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)", + stream->id, rc, ngtcp2_strerror(rc)); + break; + } + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + + if(Curl_trc_is_verbose(data)) { + infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s", + stream->id, data->state.url); + for(i = 0; i < nheader; ++i) { + infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id, + (int)nva[i].namelen, nva[i].name, + (int)nva[i].valuelen, nva[i].value); + } + } + +out: + free(nva); + Curl_dynhds_free(&h2_headers); + return nwritten; +} + +static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t sent = 0; + struct cf_call_data save; + struct pkt_io_ctx pktx; + CURLcode result; + + CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(cf->connected); + DEBUGASSERT(ctx->qconn); + DEBUGASSERT(ctx->h3conn); + pktx_init(&pktx, cf, data); + *err = CURLE_OK; + + result = cf_progress_ingress(cf, data, &pktx); + if(result) { + *err = result; + sent = -1; + } + + if(!stream || stream->id < 0) { + sent = h3_stream_open(cf, data, buf, len, err); + if(sent < 0) { + CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err); + goto out; + } + stream = H3_STREAM_CTX(data); + } + else if(stream->upload_blocked_len) { + /* the data in `buf` has already been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + DEBUGASSERT(len >= stream->upload_blocked_len); + if(len < stream->upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happen. We are not prepared to handle that. */ + failf(data, "HTTP/3 send again with decreased length"); + *err = CURLE_HTTP3; + sent = -1; + goto out; + } + sent = (ssize_t)stream->upload_blocked_len; + stream->upload_blocked_len = 0; + } + else if(stream->closed) { + if(stream->resp_hds_complete) { + /* Server decided to close the stream after having sent us a final + * response. This is valid if it is not interested in the request + * body. This happens on 30x or 40x responses. + * We silently discard the data sent, since this is not a transport + * error situation. */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data" + "on closed stream with response", stream->id); + *err = CURLE_OK; + sent = (ssize_t)len; + goto out; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> stream closed", stream->id, len); + *err = CURLE_HTTP3; + sent = -1; + goto out; + } + else { + sent = Curl_bufq_write(&stream->sendbuf, buf, len, err); + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to " + "sendbuf(len=%zu) -> %zd, %d", + stream->id, len, sent, *err); + if(sent < 0) { + goto out; + } + + (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); + } + + result = cf_progress_egress(cf, data, &pktx); + if(result) { + *err = result; + sent = -1; + } + + if(stream && sent > 0 && stream->sendbuf_len_in_flight) { + /* We have unacknowledged DATA and cannot report success to our + * caller. Instead we EAGAIN and remember how much we have already + * "written" into our various internal connection buffers. */ + stream->upload_blocked_len = sent; + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), " + "%zu bytes in flight -> EGAIN", stream->id, len, + stream->sendbuf_len_in_flight); + *err = CURLE_AGAIN; + sent = -1; + } + +out: + result = check_and_set_expiry(cf, data, &pktx); + if(result) { + *err = result; + sent = -1; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d", + stream? stream->id : -1, len, sent, *err); + CF_DATA_RESTORE(cf, save); + return sent; +} + +static CURLcode qng_verify_peer(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + cf->conn->httpversion = 30; + cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; + + return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); +} + +static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, + struct sockaddr_storage *remote_addr, + socklen_t remote_addrlen, int ecn, + void *userp) +{ + struct pkt_io_ctx *pktx = userp; + struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx; + ngtcp2_pkt_info pi; + ngtcp2_path path; + int rv; + + ++pktx->pkt_count; + ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr, + ctx->q.local_addrlen); + ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr, + remote_addrlen); + pi.ecn = (uint8_t)ecn; + + rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts); + if(rv) { + CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)", + ngtcp2_strerror(rv), rv); + if(!ctx->last_error.error_code) { + if(rv == NGTCP2_ERR_CRYPTO) { + ngtcp2_ccerr_set_tls_alert(&ctx->last_error, + ngtcp2_conn_get_tls_alert(ctx->qconn), + NULL, 0); + } + else { + ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0); + } + } + + if(rv == NGTCP2_ERR_CRYPTO) + /* this is a "TLS problem", but a failed certificate verification + is a common reason for this */ + return CURLE_PEER_FAILED_VERIFICATION; + return CURLE_RECV_ERROR; + } + + return CURLE_OK; +} + +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct pkt_io_ctx local_pktx; + size_t pkts_chunk = 128, i; + size_t pkts_max = 10 * pkts_chunk; + CURLcode result = CURLE_OK; + + if(!pktx) { + pktx_init(&local_pktx, cf, data); + pktx = &local_pktx; + } + else { + pktx_update_time(pktx, cf); + } + + result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); + if(result) + return result; + + for(i = 0; i < pkts_max; i += pkts_chunk) { + pktx->pkt_count = 0; + result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk, + recv_pkt, pktx); + if(result) /* error */ + break; + if(pktx->pkt_count < pkts_chunk) /* got less than we could */ + break; + /* give egress a chance before we receive more */ + result = cf_progress_egress(cf, data, pktx); + if(result) /* error */ + break; + } + return result; +} + +/** + * Read a network packet to send from ngtcp2 into `buf`. + * Return number of bytes written or -1 with *err set. + */ +static ssize_t read_pkt_to_send(void *userp, + unsigned char *buf, size_t buflen, + CURLcode *err) +{ + struct pkt_io_ctx *x = userp; + struct cf_ngtcp2_ctx *ctx = x->cf->ctx; + nghttp3_vec vec[16]; + nghttp3_ssize veccnt; + ngtcp2_ssize ndatalen; + uint32_t flags; + int64_t stream_id; + int fin; + ssize_t nwritten, n; + veccnt = 0; + stream_id = -1; + fin = 0; + + /* ngtcp2 may want to put several frames from different streams into + * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so. + * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make + * another iteration. + * When ngtcp2 is happy (because it has no other frame that would fit + * or it has nothing more to send), it returns the total length + * of the assembled packet. This may be 0 if there was nothing to send. */ + nwritten = 0; + *err = CURLE_OK; + for(;;) { + + if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) { + veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec, + sizeof(vec) / sizeof(vec[0])); + if(veccnt < 0) { + failf(x->data, "nghttp3_conn_writev_stream returned error: %s", + nghttp3_strerror((int)veccnt)); + ngtcp2_ccerr_set_application_error( + &ctx->last_error, + nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0); + *err = CURLE_SEND_ERROR; + return -1; + } + } + + flags = NGTCP2_WRITE_STREAM_FLAG_MORE | + (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); + n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path, + NULL, buf, buflen, + &ndatalen, flags, stream_id, + (const ngtcp2_vec *)vec, veccnt, x->ts); + if(n == 0) { + /* nothing to send */ + *err = CURLE_AGAIN; + nwritten = -1; + goto out; + } + else if(n < 0) { + switch(n) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(x->data); + DEBUGASSERT(ndatalen == -1); + nghttp3_conn_block_stream(ctx->h3conn, stream_id); + CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] block quic flow", + stream_id); + DEBUGASSERT(stream); + if(stream) + stream->quic_flow_blocked = TRUE; + n = 0; + break; + } + case NGTCP2_ERR_STREAM_SHUT_WR: + DEBUGASSERT(ndatalen == -1); + nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id); + n = 0; + break; + case NGTCP2_ERR_WRITE_MORE: + /* ngtcp2 wants to send more. update the flow of the stream whose data + * is in the buffer and continue */ + DEBUGASSERT(ndatalen >= 0); + n = 0; + break; + default: + DEBUGASSERT(ndatalen == -1); + failf(x->data, "ngtcp2_conn_writev_stream returned error: %s", + ngtcp2_strerror((int)n)); + ngtcp2_ccerr_set_liberr(&ctx->last_error, (int)n, NULL, 0); + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + } + + if(ndatalen >= 0) { + /* we add the amount of data bytes to the flow windows */ + int rv = nghttp3_conn_add_write_offset(ctx->h3conn, stream_id, ndatalen); + if(rv) { + failf(x->data, "nghttp3_conn_add_write_offset returned error: %s\n", + nghttp3_strerror(rv)); + return CURLE_SEND_ERROR; + } + } + + if(n > 0) { + /* packet assembled, leave */ + nwritten = n; + goto out; + } + } +out: + return nwritten; +} + +static CURLcode cf_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + ssize_t nread; + size_t max_payload_size, path_max_payload_size, max_pktcnt; + size_t pktcnt = 0; + size_t gsolen = 0; /* this disables gso until we have a clue */ + CURLcode curlcode; + struct pkt_io_ctx local_pktx; + + if(!pktx) { + pktx_init(&local_pktx, cf, data); + pktx = &local_pktx; + } + else { + pktx_update_time(pktx, cf); + ngtcp2_path_storage_zero(&pktx->ps); + } + + curlcode = vquic_flush(cf, data, &ctx->q); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; + } + + /* In UDP, there is a maximum theoretical packet paload length and + * a minimum payload length that is "guarantueed" to work. + * To detect if this minimum payload can be increased, ngtcp2 sends + * now and then a packet payload larger than the minimum. It that + * is ACKed by the peer, both parties know that it works and + * the subsequent packets can use a larger one. + * This is called PMTUD (Path Maximum Transmission Unit Discovery). + * Since a PMTUD might be rejected right on send, we do not want it + * be followed by other packets of lesser size. Because those would + * also fail then. So, if we detect a PMTUD while buffering, we flush. + */ + max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn); + path_max_payload_size = + ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn); + /* maximum number of packets buffered before we flush to the socket */ + max_pktcnt = CURLMIN(MAX_PKT_BURST, + ctx->q.sendbuf.chunk_size / max_payload_size); + + for(;;) { + /* add the next packet to send, if any, to our buffer */ + nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, + read_pkt_to_send, pktx, &curlcode); + if(nread < 0) { + if(curlcode != CURLE_AGAIN) + return curlcode; + /* Nothing more to add, flush and leave */ + curlcode = vquic_send(cf, data, &ctx->q, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; + } + goto out; + } + + DEBUGASSERT(nread > 0); + if(pktcnt == 0) { + /* first packet in buffer. This is either of a known, "good" + * payload size or it is a PMTUD. We'll see. */ + gsolen = (size_t)nread; + } + else if((size_t)nread > gsolen || + (gsolen > path_max_payload_size && (size_t)nread != gsolen)) { + /* The just added packet is a PMTUD *or* the one(s) before the + * just added were PMTUD and the last one is smaller. + * Flush the buffer before the last add. */ + curlcode = vquic_send_tail_split(cf, data, &ctx->q, + gsolen, nread, nread); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; + } + pktcnt = 0; + continue; + } + + if(++pktcnt >= max_pktcnt || (size_t)nread < gsolen) { + /* Reached MAX_PKT_BURST *or* + * the capacity of our buffer *or* + * last add was shorter than the previous ones, flush */ + curlcode = vquic_send(cf, data, &ctx->q, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; + } + /* pktbuf has been completely sent */ + pktcnt = 0; + } + } + +out: + return CURLE_OK; +} + +/* + * Called from transfer.c:data_pending to know if we should keep looping + * to receive more data from the connection. + */ +static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + const struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + (void)cf; + return stream && !Curl_bufq_is_empty(&stream->recvbuf); +} + +static CURLcode h3_data_pause(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool pause) +{ + /* TODO: there seems right now no API in ngtcp2 to shrink/enlarge + * the streams windows. As we do in HTTP/2. */ + if(!pause) { + h3_drain_stream(cf, data); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + return CURLE_OK; +} + +static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_DATA_SETUP: + break; + case CF_CTRL_DATA_PAUSE: + result = h3_data_pause(cf, data, (arg1 != 0)); + break; + case CF_CTRL_DATA_DETACH: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE_SEND: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + if(stream && !stream->send_closed) { + stream->send_closed = TRUE; + stream->upload_left = Curl_bufq_len(&stream->sendbuf); + (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); + } + break; + } + case CF_CTRL_DATA_IDLE: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURL_TRC_CF(data, cf, "data idle"); + if(stream && !stream->closed) { + result = check_and_set_expiry(cf, data, NULL); + if(result) + CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result); + } + break; + } + default: + break; + } + CF_DATA_RESTORE(cf, save); + return result; +} + +static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx) +{ + struct cf_call_data save = ctx->call_data; + + if(ctx->qlogfd != -1) { + close(ctx->qlogfd); + } + Curl_vquic_tls_cleanup(&ctx->tls); + vquic_ctx_free(&ctx->q); + if(ctx->h3conn) + nghttp3_conn_del(ctx->h3conn); + if(ctx->qconn) + ngtcp2_conn_del(ctx->qconn); + Curl_bufcp_free(&ctx->stream_bufcp); + Curl_ssl_peer_cleanup(&ctx->peer); + + memset(ctx, 0, sizeof(*ctx)); + ctx->qlogfd = -1; + ctx->call_data = save; +} + +static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + if(ctx && ctx->qconn) { + char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE]; + struct pkt_io_ctx pktx; + ngtcp2_ssize rc; + + CURL_TRC_CF(data, cf, "close"); + pktx_init(&pktx, cf, data); + rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */ + NULL, /* pkt_info */ + (uint8_t *)buffer, sizeof(buffer), + &ctx->last_error, pktx.ts); + if(rc > 0) { + while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) && + SOCKERRNO == EINTR); + } + + cf_ngtcp2_ctx_clear(ctx); + } + + cf->connected = FALSE; + CF_DATA_RESTORE(cf, save); +} + +static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + CURL_TRC_CF(data, cf, "destroy"); + if(ctx) { + cf_ngtcp2_ctx_clear(ctx); + free(ctx); + } + cf->ctx = NULL; + /* No CF_DATA_RESTORE(cf, save) possible */ + (void)save; +} + +static CURLcode tls_ctx_setup(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + (void)cf; +#ifdef USE_OPENSSL +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed"); + return CURLE_FAILED_INIT; + } +#else + if(ngtcp2_crypto_quictls_configure_client_context(ctx->ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_quictls_configure_client_context failed"); + return CURLE_FAILED_INIT; + } +#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */ +#elif defined(USE_GNUTLS) + if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) { + failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed"); + return CURLE_FAILED_INIT; + } +#elif defined(USE_WOLFSSL) + if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed"); + return CURLE_FAILED_INIT; + } +#endif + return CURLE_OK; +} + +/* + * Might be called twice for happy eyeballs. + */ +static CURLcode cf_connect_start(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + int rc; + int rv; + CURLcode result; + const struct Curl_sockaddr_ex *sockaddr = NULL; + int qfd; + + ctx->version = NGTCP2_PROTO_VER_MAX; + ctx->max_stream_window = H3_STREAM_WINDOW_SIZE; + ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS; + Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, + H3_STREAM_POOL_SPARES); + + result = Curl_ssl_peer_init(&ctx->peer, cf); + if(result) + return result; + +#define H3_ALPN "\x2h3\x5h3-29" + result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, + H3_ALPN, sizeof(H3_ALPN) - 1, + tls_ctx_setup, &ctx->conn_ref); + if(result) + return result; + + ctx->dcid.datalen = NGTCP2_MAX_CIDLEN; + result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN); + if(result) + return result; + + ctx->scid.datalen = NGTCP2_MAX_CIDLEN; + result = Curl_rand(data, ctx->scid.data, NGTCP2_MAX_CIDLEN); + if(result) + return result; + + (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd); + ctx->qlogfd = qfd; /* -1 if failure above */ + quic_settings(ctx, data, pktx); + + result = vquic_ctx_init(&ctx->q); + if(result) + return result; + + Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, + &sockaddr, NULL, NULL, NULL, NULL); + if(!sockaddr) + return CURLE_QUIC_CONNECT_ERROR; + ctx->q.local_addrlen = sizeof(ctx->q.local_addr); + rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, + &ctx->q.local_addrlen); + if(rv == -1) + return CURLE_QUIC_CONNECT_ERROR; + + ngtcp2_addr_init(&ctx->connected_path.local, + (struct sockaddr *)&ctx->q.local_addr, + ctx->q.local_addrlen); + ngtcp2_addr_init(&ctx->connected_path.remote, + &sockaddr->sa_addr, sockaddr->addrlen); + + rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid, + &ctx->connected_path, + NGTCP2_PROTO_VER_V1, &ng_callbacks, + &ctx->settings, &ctx->transport_params, + NULL, cf); + if(rc) + return CURLE_QUIC_CONNECT_ERROR; + +#ifdef USE_GNUTLS + ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls->session); +#else + ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl); +#endif + + ngtcp2_ccerr_default(&ctx->last_error); + + ctx->conn_ref.get_conn = get_conn; + ctx->conn_ref.user_data = cf; + + return CURLE_OK; +} + +static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + struct curltime now; + struct pkt_io_ctx pktx; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* Connect the UDP filter first */ + if(!cf->next->connected) { + result = Curl_conn_cf_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + } + + *done = FALSE; + now = Curl_now(); + pktx_init(&pktx, cf, data); + + CF_DATA_SAVE(save, cf, data); + + if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) { + /* Not time yet to attempt the next connect */ + CURL_TRC_CF(data, cf, "waiting for reconnect time"); + goto out; + } + + if(!ctx->qconn) { + ctx->started_at = now; + result = cf_connect_start(cf, data, &pktx); + if(result) + goto out; + result = cf_progress_egress(cf, data, &pktx); + /* we do not expect to be able to recv anything yet */ + goto out; + } + + result = cf_progress_ingress(cf, data, &pktx); + if(result) + goto out; + + result = cf_progress_egress(cf, data, &pktx); + if(result) + goto out; + + if(ngtcp2_conn_get_handshake_completed(ctx->qconn)) { + ctx->handshake_at = now; + CURL_TRC_CF(data, cf, "handshake complete after %dms", + (int)Curl_timediff(now, ctx->started_at)); + result = qng_verify_peer(cf, data); + if(!result) { + CURL_TRC_CF(data, cf, "peer verified"); + cf->connected = TRUE; + cf->conn->alpn = CURL_HTTP_VERSION_3; + *done = TRUE; + connkeep(cf->conn, "HTTP/3 default"); + } + } + +out: + if(result == CURLE_RECV_ERROR && ctx->qconn && + ngtcp2_conn_in_draining_period(ctx->qconn)) { + /* When a QUIC server instance is shutting down, it may send us a + * CONNECTION_CLOSE right away. Our connection then enters the DRAINING + * state. The CONNECT may work in the near future again. Indicate + * that as a "weird" reply. */ + result = CURLE_WEIRD_SERVER_REPLY; + } + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(result) { + const char *r_ip = NULL; + int r_port = 0; + + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + infof(data, "QUIC connect to %s port %u failed: %s", + r_ip, r_port, curl_easy_strerror(result)); + } +#endif + if(!result && ctx->qconn) { + result = check_and_set_expiry(cf, data, &pktx); + } + if(result || *done) + CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done); + CF_DATA_RESTORE(cf, save); + return result; +} + +static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct cf_call_data save; + + switch(query) { + case CF_QUERY_MAX_CONCURRENT: { + const ngtcp2_transport_params *rp; + DEBUGASSERT(pres1); + + CF_DATA_SAVE(save, cf, data); + rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); + if(rp) + *pres1 = (rp->initial_max_streams_bidi > INT_MAX)? + INT_MAX : (int)rp->initial_max_streams_bidi; + else /* not arrived yet? */ + *pres1 = Curl_multi_max_concurrent_streams(data->multi); + CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1); + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + } + case CF_QUERY_CONNECT_REPLY_MS: + if(ctx->q.got_first_byte) { + timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at); + *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX; + } + else + *pres1 = -1; + return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + if(ctx->q.got_first_byte) + *when = ctx->q.first_byte_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + bool alive = FALSE; + const ngtcp2_transport_params *rp; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + *input_pending = FALSE; + if(!ctx->qconn) + goto out; + + /* Both sides of the QUIC connection announce they max idle times in + * the transport parameters. Look at the minimum of both and if + * we exceed this, regard the connection as dead. The other side + * may have completely purged it and will no longer respond + * to any packets from us. */ + rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); + if(rp) { + timediff_t idletime; + uint64_t idle_ms = ctx->max_idle_ms; + + if(rp->max_idle_timeout && + (rp->max_idle_timeout / NGTCP2_MILLISECONDS) < idle_ms) + idle_ms = (rp->max_idle_timeout / NGTCP2_MILLISECONDS); + idletime = Curl_timediff(Curl_now(), ctx->q.last_io); + if(idletime > 0 && (uint64_t)idletime > idle_ms) + goto out; + } + + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + goto out; + + alive = TRUE; + if(*input_pending) { + CURLcode result; + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + *input_pending = FALSE; + result = cf_progress_ingress(cf, data, NULL); + CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result); + alive = result? FALSE : TRUE; + } + +out: + CF_DATA_RESTORE(cf, save); + return alive; +} + +struct Curl_cftype Curl_cft_http3 = { + "HTTP/3", + CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX, + 0, + cf_ngtcp2_destroy, + cf_ngtcp2_connect, + cf_ngtcp2_close, + Curl_cf_def_get_host, + cf_ngtcp2_adjust_pollset, + cf_ngtcp2_data_pending, + cf_ngtcp2_send, + cf_ngtcp2_recv, + cf_ngtcp2_data_event, + cf_ngtcp2_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_ngtcp2_query, +}; + +CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai) +{ + struct cf_ngtcp2_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + CURLcode result; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + ctx->qlogfd = -1; + cf_ngtcp2_ctx_clear(ctx); + + result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); + if(result) + goto out; + + result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + if(result) + goto out; + + cf->conn = conn; + udp_cf->conn = cf->conn; + udp_cf->sockindex = cf->sockindex; + cf->next = udp_cf; + +out: + *pcf = (!result)? cf : NULL; + if(result) { + if(udp_cf) + Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); + Curl_safefree(cf); + Curl_safefree(ctx); + } + return result; +} + +bool Curl_conn_is_ngtcp2(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL; + + (void)data; + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_http3) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; +} + +#endif diff --git a/lib/vquic/curl_ngtcp2.h b/lib/vquic/curl_ngtcp2.h new file mode 100644 index 0000000..db3e611 --- /dev/null +++ b/lib/vquic/curl_ngtcp2.h @@ -0,0 +1,61 @@ +#ifndef HEADER_CURL_VQUIC_CURL_NGTCP2_H +#define HEADER_CURL_VQUIC_CURL_NGTCP2_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NGTCP2) && defined(USE_NGHTTP3) + +#ifdef HAVE_NETINET_UDP_H +#include +#endif + +#include +#include +#ifdef USE_OPENSSL +#include +#elif defined(USE_WOLFSSL) +#include +#include +#include +#endif + +struct Curl_cfilter; + +#include "urldata.h" + +void Curl_ngtcp2_ver(char *p, size_t len); + +CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai); + +bool Curl_conn_is_ngtcp2(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex); +#endif + +#endif /* HEADER_CURL_VQUIC_CURL_NGTCP2_H */ diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c new file mode 100644 index 0000000..c499a00 --- /dev/null +++ b/lib/vquic/curl_osslq.c @@ -0,0 +1,2237 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + +#include +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "strdup.h" +#include "rand.h" +#include "multiif.h" +#include "strcase.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "connect.h" +#include "progress.h" +#include "strerror.h" +#include "dynbuf.h" +#include "http1.h" +#include "select.h" +#include "inet_pton.h" +#include "vquic.h" +#include "vquic_int.h" +#include "vquic-tls.h" +#include "vtls/keylog.h" +#include "vtls/vtls.h" +#include "vtls/openssl.h" +#include "curl_osslq.h" + +#include "warnless.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* A stream window is the maximum amount we need to buffer for + * each active transfer. We use HTTP/3 flow control and only ACK + * when we take things out of the buffer. + * Chunk size is large enough to take a full DATA frame */ +#define H3_STREAM_WINDOW_SIZE (128 * 1024) +#define H3_STREAM_CHUNK_SIZE (16 * 1024) +/* The pool keeps spares around and half of a full stream windows + * seems good. More does not seem to improve performance. + * The benefit of the pool is that stream buffer to not keep + * spares. So memory consumption goes down when streams run empty, + * have a large upload done, etc. */ +#define H3_STREAM_POOL_SPARES \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 +/* Receive and Send max number of chunks just follows from the + * chunk size and window size */ +#define H3_STREAM_RECV_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) +#define H3_STREAM_SEND_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) + +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +typedef uint32_t sslerr_t; +#else +typedef unsigned long sslerr_t; +#endif + + +/* How to access `call_data` from a cf_osslq filter */ +#undef CF_CTX_CALL_DATA +#define CF_CTX_CALL_DATA(cf) \ + ((struct cf_osslq_ctx *)(cf)->ctx)->call_data + +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data); + +static const char *SSL_ERROR_to_str(int err) +{ + switch(err) { + case SSL_ERROR_NONE: + return "SSL_ERROR_NONE"; + case SSL_ERROR_SSL: + return "SSL_ERROR_SSL"; + case SSL_ERROR_WANT_READ: + return "SSL_ERROR_WANT_READ"; + case SSL_ERROR_WANT_WRITE: + return "SSL_ERROR_WANT_WRITE"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "SSL_ERROR_WANT_X509_LOOKUP"; + case SSL_ERROR_SYSCALL: + return "SSL_ERROR_SYSCALL"; + case SSL_ERROR_ZERO_RETURN: + return "SSL_ERROR_ZERO_RETURN"; + case SSL_ERROR_WANT_CONNECT: + return "SSL_ERROR_WANT_CONNECT"; + case SSL_ERROR_WANT_ACCEPT: + return "SSL_ERROR_WANT_ACCEPT"; +#if defined(SSL_ERROR_WANT_ASYNC) + case SSL_ERROR_WANT_ASYNC: + return "SSL_ERROR_WANT_ASYNC"; +#endif +#if defined(SSL_ERROR_WANT_ASYNC_JOB) + case SSL_ERROR_WANT_ASYNC_JOB: + return "SSL_ERROR_WANT_ASYNC_JOB"; +#endif +#if defined(SSL_ERROR_WANT_EARLY) + case SSL_ERROR_WANT_EARLY: + return "SSL_ERROR_WANT_EARLY"; +#endif + default: + return "SSL_ERROR unknown"; + } +} + +/* Return error string for last OpenSSL error */ +static char *ossl_strerror(unsigned long error, char *buf, size_t size) +{ + DEBUGASSERT(size); + *buf = '\0'; + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + ERR_error_string_n((uint32_t)error, buf, size); +#else + ERR_error_string_n(error, buf, size); +#endif + + if(!*buf) { + const char *msg = error ? "Unknown error" : "No error"; + if(strlen(msg) < size) + strcpy(buf, msg); + } + + return buf; +} + +static CURLcode make_bio_addr(BIO_ADDR **pbio_addr, + const struct Curl_sockaddr_ex *addr) +{ + BIO_ADDR *ba; + CURLcode result = CURLE_FAILED_INIT; + + ba = BIO_ADDR_new(); + if(!ba) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + switch(addr->family) { + case AF_INET: { + struct sockaddr_in * const sin = + (struct sockaddr_in * const)(void *)&addr->sa_addr; + if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr, + sizeof(sin->sin_addr), sin->sin_port)) { + goto out; + } + result = CURLE_OK; + break; + } +#ifdef ENABLE_IPV6 + case AF_INET6: { + struct sockaddr_in6 * const sin = + (struct sockaddr_in6 * const)(void *)&addr->sa_addr; + if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr, + sizeof(sin->sin6_addr), sin->sin6_port)) { + } + result = CURLE_OK; + break; + } +#endif /* ENABLE_IPV6 */ + default: + /* sunsupported */ + DEBUGASSERT(0); + break; + } + +out: + if(result && ba) { + BIO_ADDR_free(ba); + ba = NULL; + } + *pbio_addr = ba; + return result; +} + +/* QUIC stream (not necessarily H3) */ +struct cf_osslq_stream { + int64_t id; + SSL *ssl; + struct bufq recvbuf; /* QUIC war data recv buffer */ + BIT(recvd_eos); + BIT(closed); + BIT(reset); + BIT(send_blocked); +}; + +static CURLcode cf_osslq_stream_open(struct cf_osslq_stream *s, + SSL *conn, + uint64_t flags, + struct bufc_pool *bufcp, + void *user_data) +{ + DEBUGASSERT(!s->ssl); + Curl_bufq_initp(&s->recvbuf, bufcp, 1, BUFQ_OPT_NONE); + s->ssl = SSL_new_stream(conn, flags); + if(!s->ssl) { + return CURLE_FAILED_INIT; + } + s->id = SSL_get_stream_id(s->ssl); + SSL_set_app_data(s->ssl, user_data); + return CURLE_OK; +} + +static void cf_osslq_stream_cleanup(struct cf_osslq_stream *s) +{ + if(s->ssl) { + SSL_set_app_data(s->ssl, NULL); + SSL_free(s->ssl); + } + Curl_bufq_free(&s->recvbuf); + memset(s, 0, sizeof(*s)); +} + +static void cf_osslq_stream_close(struct cf_osslq_stream *s) +{ + if(s->ssl) { + SSL_free(s->ssl); + s->ssl = NULL; + } +} + +struct cf_osslq_h3conn { + nghttp3_conn *conn; + nghttp3_settings settings; + struct cf_osslq_stream s_ctrl; + struct cf_osslq_stream s_qpack_enc; + struct cf_osslq_stream s_qpack_dec; + struct cf_osslq_stream remote_ctrl[3]; /* uni streams opened by the peer */ + size_t remote_ctrl_n; /* number of peer streams opened */ +}; + +static void cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn *h3) +{ + size_t i; + + if(h3->conn) + nghttp3_conn_del(h3->conn); + cf_osslq_stream_cleanup(&h3->s_ctrl); + cf_osslq_stream_cleanup(&h3->s_qpack_enc); + cf_osslq_stream_cleanup(&h3->s_qpack_dec); + for(i = 0; i < h3->remote_ctrl_n; ++i) { + cf_osslq_stream_cleanup(&h3->remote_ctrl[i]); + } +} + +struct cf_osslq_ctx { + struct cf_quic_ctx q; + struct ssl_peer peer; + struct quic_tls_ctx tls; + struct cf_call_data call_data; + struct cf_osslq_h3conn h3; + struct curltime started_at; /* time the current attempt started */ + struct curltime handshake_at; /* time connect handshake finished */ + struct curltime first_byte_at; /* when first byte was recvd */ + struct curltime reconnect_at; /* time the next attempt should start */ + struct bufc_pool stream_bufcp; /* chunk pool for streams */ + size_t max_stream_window; /* max flow window for one stream */ + uint64_t max_idle_ms; /* max idle time for QUIC connection */ + BIT(got_first_byte); /* if first byte was received */ +#ifdef USE_OPENSSL + BIT(x509_store_setup); /* if x509 store has been set up */ + BIT(protocol_shutdown); /* QUIC connection is shut down */ +#endif +}; + +static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx) +{ + struct cf_call_data save = ctx->call_data; + + cf_osslq_h3conn_cleanup(&ctx->h3); + Curl_vquic_tls_cleanup(&ctx->tls); + vquic_ctx_free(&ctx->q); + Curl_bufcp_free(&ctx->stream_bufcp); + Curl_ssl_peer_cleanup(&ctx->peer); + + memset(ctx, 0, sizeof(*ctx)); + ctx->call_data = save; +} + +static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + if(ctx && ctx->tls.ssl) { + /* TODO: send connection close */ + CURL_TRC_CF(data, cf, "cf_osslq_close()"); + cf_osslq_ctx_clear(ctx); + } + + cf->connected = FALSE; + CF_DATA_RESTORE(cf, save); +} + +static void cf_osslq_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + CURL_TRC_CF(data, cf, "destroy"); + if(ctx) { + CURL_TRC_CF(data, cf, "cf_osslq_destroy()"); + cf_osslq_ctx_clear(ctx); + free(ctx); + } + cf->ctx = NULL; + /* No CF_DATA_RESTORE(cf, save) possible */ + (void)save; +} + +static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3, + SSL *stream_ssl, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + int64_t stream_id = SSL_get_stream_id(stream_ssl); + + if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) { + /* rejected, we are full */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] rejecting additional remote stream", + stream_id); + SSL_free(stream_ssl); + return CURLE_FAILED_INIT; + } + switch(SSL_get_stream_type(stream_ssl)) { + case SSL_STREAM_TYPE_READ: { + struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++]; + nstream->id = stream_id; + nstream->ssl = stream_ssl; + Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE); + CURL_TRC_CF(data, cf, "[%" PRId64 "] accepted new remote uni stream", + stream_id); + break; + } + default: + CURL_TRC_CF(data, cf, "[%" PRId64 "] rejecting remote non-uni-read" + " stream", stream_id); + SSL_free(stream_ssl); + return CURLE_FAILED_INIT; + } + return CURLE_OK; + +} + +static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, + struct Curl_easy *data, + int detail, CURLcode def_result) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = def_result; + sslerr_t errdetail; + char ebuf[256] = "unknown"; + const char *err_descr = ebuf; + long lerr; + int lib; + int reason; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + + errdetail = ERR_get_error(); + lib = ERR_GET_LIB(errdetail); + reason = ERR_GET_REASON(errdetail); + + if((lib == ERR_LIB_SSL) && + ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) || + (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) { + result = CURLE_PEER_FAILED_VERIFICATION; + + lerr = SSL_get_verify_result(ctx->tls.ssl); + if(lerr != X509_V_OK) { + ssl_config->certverifyresult = lerr; + msnprintf(ebuf, sizeof(ebuf), + "SSL certificate problem: %s", + X509_verify_cert_error_string(lerr)); + } + else + err_descr = "SSL certificate verification failed"; + } +#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED) + /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on + OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */ + else if((lib == ERR_LIB_SSL) && + (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) { + /* If client certificate is required, communicate the + error to client */ + result = CURLE_SSL_CLIENTCERT; + ossl_strerror(errdetail, ebuf, sizeof(ebuf)); + } +#endif + else if((lib == ERR_LIB_SSL) && (reason == SSL_R_PROTOCOL_IS_SHUTDOWN)) { + ctx->protocol_shutdown = TRUE; + err_descr = "QUIC connectin has been shut down"; + result = def_result; + } + else { + result = def_result; + ossl_strerror(errdetail, ebuf, sizeof(ebuf)); + } + + /* detail is already set to the SSL error above */ + + /* If we e.g. use SSLv2 request-method and the server doesn't like us + * (RST connection, etc.), OpenSSL gives no explanation whatsoever and + * the SO_ERROR is also lost. + */ + if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { + char extramsg[80]=""; + int sockerr = SOCKERRNO; + const char *r_ip = NULL; + int r_port = 0; + + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + if(sockerr && detail == SSL_ERROR_SYSCALL) + Curl_strerror(sockerr, extramsg, sizeof(extramsg)); + failf(data, "QUIC connect: %s in connection to %s:%d (%s)", + extramsg[0] ? extramsg : SSL_ERROR_to_str(detail), + ctx->peer.dispname, r_port, r_ip); + } + else { + /* Could be a CERT problem */ + failf(data, "%s", err_descr); + } + return result; +} + +static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + cf->conn->httpversion = 30; + cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; + + return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); +} + +/** + * All about the H3 internals of a stream + */ +struct h3_stream_ctx { + struct cf_osslq_stream s; + struct bufq sendbuf; /* h3 request body */ + struct bufq recvbuf; /* h3 response body */ + struct h1_req_parser h1; /* h1 request parsing */ + size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */ + size_t upload_blocked_len; /* the amount written last and EGAINed */ + size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */ + uint64_t error3; /* HTTP/3 stream error code */ + curl_off_t upload_left; /* number of request bytes left to upload */ + curl_off_t download_recvd; /* number of response DATA bytes received */ + int status_code; /* HTTP status code */ + bool resp_hds_complete; /* we have a complete, final response */ + bool closed; /* TRUE on stream close */ + bool reset; /* TRUE on stream reset */ + bool send_closed; /* stream is local closed */ + BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */ +}; + +#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \ + ((struct HTTP *)(d)->req.p.http)->h3_ctx \ + : NULL)) +#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx +#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \ + H3_STREAM_CTX(d)->s.id : -2) + +static CURLcode h3_data_setup(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + + if(!data || !data->req.p.http) { + failf(data, "initialization failure, transfer not http initialized"); + return CURLE_FAILED_INIT; + } + + if(stream) + return CURLE_OK; + + stream = calloc(1, sizeof(*stream)); + if(!stream) + return CURLE_OUT_OF_MEMORY; + + stream->s.id = -1; + /* on send, we control how much we put into the buffer */ + Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, + H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); + stream->sendbuf_len_in_flight = 0; + /* on recv, we need a flexible buffer limit since we also write + * headers to it that are not counted against the nghttp3 flow limits. */ + Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, + H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); + stream->recv_buf_nonflow = 0; + Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); + + H3_STREAM_LCTX(data) = stream; + return CURLE_OK; +} + +static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + + (void)cf; + if(stream) { + CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->s.id); + if(ctx->h3.conn && !stream->closed) { + nghttp3_conn_shutdown_stream_read(ctx->h3.conn, stream->s.id); + nghttp3_conn_close_stream(ctx->h3.conn, stream->s.id, + NGHTTP3_H3_REQUEST_CANCELLED); + nghttp3_conn_set_stream_user_data(ctx->h3.conn, stream->s.id, NULL); + stream->closed = TRUE; + } + + cf_osslq_stream_cleanup(&stream->s); + Curl_bufq_free(&stream->sendbuf); + Curl_bufq_free(&stream->recvbuf); + Curl_h1_req_parse_free(&stream->h1); + free(stream); + H3_STREAM_LCTX(data) = NULL; + } +} + +static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf, + struct Curl_easy *data, + int64_t stream_id) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + struct Curl_easy *sdata; + + if(stream && stream->s.id == stream_id) { + return &stream->s; + } + else if(ctx->h3.s_ctrl.id == stream_id) { + return &ctx->h3.s_ctrl; + } + else if(ctx->h3.s_qpack_enc.id == stream_id) { + return &ctx->h3.s_qpack_enc; + } + else if(ctx->h3.s_qpack_dec.id == stream_id) { + return &ctx->h3.s_qpack_dec; + } + else { + DEBUGASSERT(data->multi); + for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { + if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) { + stream = H3_STREAM_CTX(sdata); + return stream? &stream->s : NULL; + } + } + } + return NULL; +} + +static void h3_drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(stream && stream->upload_left && !stream->send_closed) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +static CURLcode h3_data_pause(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool pause) +{ + if(!pause) { + /* unpaused. make it run again right away */ + h3_drain_stream(cf, data); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + return CURLE_OK; +} + +static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + (void)conn; + (void)stream_id; + + /* we might be called by nghttp3 after we already cleaned up */ + if(!stream) + return 0; + + stream->closed = TRUE; + stream->error3 = app_error_code; + if(stream->error3 != NGHTTP3_H3_NO_ERROR) { + stream->reset = TRUE; + stream->send_closed = TRUE; + CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64, + stream->s.id, stream->error3); + } + else { + CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->s.id); + } + h3_drain_stream(cf, data); + return 0; +} + +/* + * write_resp_raw() copies response data in raw format to the `data`'s + * receive buffer. If not enough space is available, it appends to the + * `data`'s overflow buffer. + */ +static CURLcode write_resp_raw(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, size_t memlen, + bool flow) +{ + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + ssize_t nwritten; + + (void)cf; + if(!stream) { + return CURLE_RECV_ERROR; + } + nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); + if(nwritten < 0) { + return result; + } + + if(!flow) + stream->recv_buf_nonflow += (size_t)nwritten; + + if((size_t)nwritten < memlen) { + /* This MUST not happen. Our recbuf is dimensioned to hold the + * full max_stream_window and then some for this very reason. */ + DEBUGASSERT(0); + return CURLE_RECV_ERROR; + } + return result; +} + +static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, + const uint8_t *buf, size_t buflen, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result; + + (void)conn; + (void)stream3_id; + + if(!stream) + return NGHTTP3_ERR_CALLBACK_FAILURE; + + result = write_resp_raw(cf, data, buf, buflen, TRUE); + if(result) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d", + stream->s.id, buflen, result); + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + stream->download_recvd += (curl_off_t)buflen; + CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, total=%zd", + stream->s.id, buflen, stream->download_recvd); + h3_drain_stream(cf, data); + return 0; +} + +static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id, + size_t consumed, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + + (void)conn; + (void)stream_id; + if(stream) + CURL_TRC_CF(data, cf, "[%" PRId64 "] deferred consume %zu bytes", + stream->s.id, consumed); + return 0; +} + +static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, + int32_t token, nghttp3_rcbuf *name, + nghttp3_rcbuf *value, uint8_t flags, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name); + nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value); + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + (void)conn; + (void)stream_id; + (void)token; + (void)flags; + (void)cf; + + /* we might have cleaned up this transfer already */ + if(!stream) + return 0; + + if(token == NGHTTP3_QPACK_TOKEN__STATUS) { + char line[14]; /* status line is always 13 characters long */ + size_t ncopy; + + result = Curl_http_decode_status(&stream->status_code, + (const char *)h3val.base, h3val.len); + if(result) + return -1; + ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", + stream->status_code); + CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line); + result = write_resp_raw(cf, data, line, ncopy, FALSE); + if(result) { + return -1; + } + } + else { + /* store as an HTTP1-style header */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s", + stream_id, (int)h3name.len, h3name.base, + (int)h3val.len, h3val.base); + result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, ": ", 2, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, "\r\n", 2, FALSE); + if(result) { + return -1; + } + } + return 0; +} + +static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, + int fin, void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + (void)conn; + (void)stream_id; + (void)fin; + (void)cf; + + if(!stream) + return 0; + /* add a CRLF only if we've received some headers */ + result = write_resp_raw(cf, data, "\r\n", 2, FALSE); + if(result) { + return -1; + } + + CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d", + stream_id, stream->status_code); + if(stream->status_code / 100 != 1) { + stream->resp_hds_complete = TRUE; + } + h3_drain_stream(cf, data); + return 0; +} + +static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + (void)conn; + (void)app_error_code; + + if(!stream || !stream->s.ssl) + return 0; + + CURL_TRC_CF(data, cf, "[%" PRId64 "] stop_sending", stream_id); + cf_osslq_stream_close(&stream->s); + return 0; +} + +static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + int rv; + (void)conn; + + if(stream && stream->s.ssl) { + SSL_STREAM_RESET_ARGS args = {0}; + args.quic_error_code = app_error_code; + rv = !SSL_stream_reset(stream->s.ssl, &args, sizeof(args)); + CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv); + if(!rv) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static nghttp3_ssize +cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, + nghttp3_vec *vec, size_t veccnt, + uint32_t *pflags, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nwritten = 0; + size_t nvecs = 0; + (void)cf; + (void)conn; + (void)stream_id; + (void)user_data; + (void)veccnt; + + if(!stream) + return NGHTTP3_ERR_CALLBACK_FAILURE; + /* nghttp3 keeps references to the sendbuf data until it is ACKed + * by the server (see `cb_h3_acked_req_body()` for updates). + * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf` + * that we have already passed to nghttp3, but which have not been + * ACKed yet. + * Any amount beyond `sendbuf_len_in_flight` we need still to pass + * to nghttp3. Do that now, if we can. */ + if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) { + nvecs = 0; + while(nvecs < veccnt && + Curl_bufq_peek_at(&stream->sendbuf, + stream->sendbuf_len_in_flight, + (const unsigned char **)&vec[nvecs].base, + &vec[nvecs].len)) { + stream->sendbuf_len_in_flight += vec[nvecs].len; + nwritten += vec[nvecs].len; + ++nvecs; + } + DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */ + } + + if(nwritten > 0 && stream->upload_left != -1) + stream->upload_left -= nwritten; + + /* When we stopped sending and everything in `sendbuf` is "in flight", + * we are at the end of the request body. */ + if(stream->upload_left == 0) { + *pflags = NGHTTP3_DATA_FLAG_EOF; + stream->send_closed = TRUE; + } + else if(!nwritten) { + /* Not EOF, and nothing to give, we signal WOULDBLOCK. */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN", + stream->s.id); + return NGHTTP3_ERR_WOULDBLOCK; + } + + CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> " + "%d vecs%s with %zu (buffered=%zu, left=%" + CURL_FORMAT_CURL_OFF_T ")", + stream->s.id, (int)nvecs, + *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"", + nwritten, Curl_bufq_len(&stream->sendbuf), + stream->upload_left); + return (nghttp3_ssize)nvecs; +} + +static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, + uint64_t datalen, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + size_t skiplen; + + (void)cf; + if(!stream) + return 0; + /* The server acknowledged `datalen` of bytes from our request body. + * This is a delta. We have kept this data in `sendbuf` for + * re-transmissions and can free it now. */ + if(datalen >= (uint64_t)stream->sendbuf_len_in_flight) + skiplen = stream->sendbuf_len_in_flight; + else + skiplen = (size_t)datalen; + Curl_bufq_skip(&stream->sendbuf, skiplen); + stream->sendbuf_len_in_flight -= skiplen; + + /* Everything ACKed, we resume upload processing */ + if(!stream->sendbuf_len_in_flight) { + int rv = nghttp3_conn_resume_stream(conn, stream_id); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static nghttp3_callbacks ngh3_callbacks = { + cb_h3_acked_stream_data, + cb_h3_stream_close, + cb_h3_recv_data, + cb_h3_deferred_consume, + NULL, /* begin_headers */ + cb_h3_recv_header, + cb_h3_end_headers, + NULL, /* begin_trailers */ + cb_h3_recv_header, + NULL, /* end_trailers */ + cb_h3_stop_sending, + NULL, /* end_stream */ + cb_h3_reset_stream, + NULL, /* shutdown */ + NULL /* recv_settings */ +}; + +static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn, + void *user_data) +{ + struct cf_osslq_h3conn *h3 = &ctx->h3; + CURLcode result; + int rc; + + nghttp3_settings_default(&h3->settings); + rc = nghttp3_conn_client_new(&h3->conn, + &ngh3_callbacks, + &h3->settings, + nghttp3_mem_default(), + user_data); + if(rc) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + result = cf_osslq_stream_open(&h3->s_ctrl, conn, + SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI, + &ctx->stream_bufcp, NULL); + if(result) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + result = cf_osslq_stream_open(&h3->s_qpack_enc, conn, + SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI, + &ctx->stream_bufcp, NULL); + if(result) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + result = cf_osslq_stream_open(&h3->s_qpack_dec, conn, + SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI, + &ctx->stream_bufcp, NULL); + if(result) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + + rc = nghttp3_conn_bind_control_stream(h3->conn, h3->s_ctrl.id); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + rc = nghttp3_conn_bind_qpack_streams(h3->conn, h3->s_qpack_enc.id, + h3->s_qpack_dec.id); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + + result = CURLE_OK; +out: + return result; +} + +static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result; + int rv; + const struct Curl_sockaddr_ex *peer_addr = NULL; + int peer_port; + BIO *bio = NULL; + BIO_ADDR *baddr = NULL; + + Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, + H3_STREAM_POOL_SPARES); + result = Curl_ssl_peer_init(&ctx->peer, cf); + if(result) + goto out; + +#define H3_ALPN "\x2h3" + result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, + H3_ALPN, sizeof(H3_ALPN) - 1, + NULL, NULL); + if(result) + goto out; + + result = vquic_ctx_init(&ctx->q); + if(result) + goto out; + + result = CURLE_QUIC_CONNECT_ERROR; + Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, + &peer_addr, NULL, &peer_port, NULL, NULL); + if(!peer_addr) + goto out; + + ctx->q.local_addrlen = sizeof(ctx->q.local_addr); + rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, + &ctx->q.local_addrlen); + if(rv == -1) + goto out; + + result = make_bio_addr(&baddr, peer_addr); + if(result) { + failf(data, "error creating BIO_ADDR from sockaddr"); + goto out; + } + + bio = BIO_new_dgram(ctx->q.sockfd, BIO_NOCLOSE); + if(!bio) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(!SSL_set1_initial_peer_addr(ctx->tls.ssl, baddr)) { + failf(data, "failed to set the initial peer address"); + result = CURLE_FAILED_INIT; + goto out; + } + if(!SSL_set_blocking_mode(ctx->tls.ssl, 0)) { + failf(data, "failed to turn off blocking mode"); + result = CURLE_FAILED_INIT; + goto out; + } + + SSL_set_bio(ctx->tls.ssl, bio, bio); + bio = NULL; + SSL_set_connect_state(ctx->tls.ssl); + SSL_set_incoming_stream_policy(ctx->tls.ssl, + SSL_INCOMING_STREAM_POLICY_ACCEPT, 0); + /* setup the H3 things on top of the QUIC connection */ + result = cf_osslq_h3conn_init(ctx, ctx->tls.ssl, cf); + +out: + if(bio) + BIO_free(bio); + if(baddr) + BIO_ADDR_free(baddr); + CURL_TRC_CF(data, cf, "QUIC tls init -> %d", result); + return result; +} + +struct h3_quic_recv_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; + struct cf_osslq_stream *s; +}; + +static ssize_t h3_quic_recv(void *reader_ctx, + unsigned char *buf, size_t len, + CURLcode *err) +{ + struct h3_quic_recv_ctx *x = reader_ctx; + size_t nread; + int rv; + + *err = CURLE_OK; + rv = SSL_read_ex(x->s->ssl, buf, len, &nread); + if(rv <= 0) { + int detail = SSL_get_error(x->s->ssl, rv); + if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) { + *err = CURLE_AGAIN; + return -1; + } + else if(detail == SSL_ERROR_ZERO_RETURN) { + CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> EOS", + x->s->id); + x->s->recvd_eos = TRUE; + return 0; + } + else if(SSL_get_stream_read_state(x->s->ssl) == + SSL_STREAM_STATE_RESET_REMOTE) { + uint64_t app_error_code = NGHTTP3_H3_NO_ERROR; + SSL_get_stream_read_error_code(x->s->ssl, &app_error_code); + CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> RESET, " + "rv=%d, app_err=%" PRIu64, + x->s->id, rv, app_error_code); + if(app_error_code != NGHTTP3_H3_NO_ERROR) { + x->s->reset = TRUE; + } + x->s->recvd_eos = TRUE; + return 0; + } + else { + *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR); + return -1; + } + } + else { + /* CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> %zu bytes", + x->s->id, nread); */ + } + return (ssize_t)nread; +} + +static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + ssize_t nread; + struct h3_quic_recv_ctx x; + int rv, eagain = FALSE; + size_t total_recv_len = 0; + + DEBUGASSERT(s); + if(s->closed) + return CURLE_OK; + + x.cf = cf; + x.data = data; + x.s = s; + while(s->ssl && !s->closed && !eagain && + (total_recv_len < H3_STREAM_CHUNK_SIZE)) { + if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) { + while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) { + nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result); + if(nread < 0) { + if(result != CURLE_AGAIN) + goto out; + result = CURLE_OK; + eagain = TRUE; + } + } + } + + /* Forward what we have to nghttp3 */ + if(!Curl_bufq_is_empty(&s->recvbuf)) { + const unsigned char *buf; + size_t blen; + + while(Curl_bufq_peek(&s->recvbuf, &buf, &blen)) { + nread = nghttp3_conn_read_stream(ctx->h3.conn, s->id, + buf, blen, 0); + CURL_TRC_CF(data, cf, "[%" PRId64 "] forward %zu bytes " + "to nghttp3 -> %zd", s->id, blen, nread); + if(nread < 0) { + failf(data, "nghttp3_conn_read_stream(len=%zu) error: %s", + blen, nghttp3_strerror((int)nread)); + result = CURLE_RECV_ERROR; + goto out; + } + /* success, `nread` is the flow for QUIC to count as "consumed", + * not sure how that will work with OpenSSL. Anyways, without error, + * all data that we passed is not owned by nghttp3. */ + Curl_bufq_skip(&s->recvbuf, blen); + total_recv_len += blen; + } + } + + /* When we forwarded everything, handle RESET/EOS */ + if(Curl_bufq_is_empty(&s->recvbuf) && !s->closed) { + result = CURLE_OK; + if(s->reset) { + uint64_t app_error; + if(!SSL_get_stream_read_error_code(s->ssl, &app_error)) { + failf(data, "SSL_get_stream_read_error_code returned error"); + result = CURLE_RECV_ERROR; + goto out; + } + rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id, app_error); + s->closed = TRUE; + if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_close_stream returned error: %s", + nghttp3_strerror(rv)); + result = CURLE_RECV_ERROR; + goto out; + } + } + else if(s->recvd_eos) { + rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id, + NGHTTP3_H3_NO_ERROR); + s->closed = TRUE; + CURL_TRC_CF(data, cf, "[%" PRId64 "] close nghttp3 stream -> %d", + s->id, rv); + if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_close_stream returned error: %s", + nghttp3_strerror(rv)); + result = CURLE_RECV_ERROR; + goto out; + } + } + } + } +out: + if(result) + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_osslq_stream_recv -> %d", + s->id, result); + return result; +} + +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(!ctx->tls.ssl) + goto out; + + ERR_clear_error(); + + /* 1. Check for new incoming streams */ + while(1) { + SSL *snew = SSL_accept_stream(ctx->tls.ssl, SSL_ACCEPT_STREAM_NO_BLOCK); + if(!snew) + break; + + (void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data); + } + + if(!SSL_handle_events(ctx->tls.ssl)) { + int detail = SSL_get_error(ctx->tls.ssl, 0); + result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR); + } + + if(ctx->h3.conn) { + size_t i; + for(i = 0; i < ctx->h3.remote_ctrl_n; ++i) { + result = cf_osslq_stream_recv(&ctx->h3.remote_ctrl[i], cf, data); + if(result) + goto out; + } + } + + if(ctx->h3.conn) { + struct Curl_easy *sdata; + struct h3_stream_ctx *stream; + /* PULL all open streams */ + DEBUGASSERT(data->multi); + for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { + if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) { + stream = H3_STREAM_CTX(sdata); + if(stream && !stream->closed && + !Curl_bufq_is_full(&stream->recvbuf)) { + result = cf_osslq_stream_recv(&stream->s, cf, sdata); + if(result) + goto out; + } + } + } + } + +out: + CURL_TRC_CF(data, cf, "progress_ingress -> %d", result); + return result; +} + +/* Iterate over all streams and check if blocked can be unblocked */ +static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct Curl_easy *sdata; + struct h3_stream_ctx *stream; + + if(ctx->h3.conn) { + for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { + if(sdata->conn == data->conn) { + stream = H3_STREAM_CTX(sdata); + if(stream && stream->s.ssl && stream->s.send_blocked && + !SSL_want_write(stream->s.ssl)) { + nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id); + stream->s.send_blocked = FALSE; + h3_drain_stream(cf, sdata); + CURL_TRC_CF(sdata, cf, "unblocked"); + } + } + } + } + return CURLE_OK; +} + +static CURLcode h3_send_streams(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(!ctx->tls.ssl || !ctx->h3.conn) + goto out; + + for(;;) { + struct cf_osslq_stream *s = NULL; + nghttp3_vec vec[16]; + nghttp3_ssize n, i; + int64_t stream_id; + size_t written; + int eos, ok, rv; + size_t total_len, acked_len = 0; + bool blocked = FALSE; + + n = nghttp3_conn_writev_stream(ctx->h3.conn, &stream_id, &eos, + vec, ARRAYSIZE(vec)); + if(n < 0) { + failf(data, "nghttp3_conn_writev_stream returned error: %s", + nghttp3_strerror((int)n)); + result = CURLE_SEND_ERROR; + goto out; + } + if(stream_id < 0) { + result = CURLE_OK; + goto out; + } + + /* Get the stream for this data */ + s = cf_osslq_get_qstream(cf, data, stream_id); + if(!s) { + failf(data, "nghttp3_conn_writev_stream gave unknown stream %" PRId64, + stream_id); + result = CURLE_SEND_ERROR; + goto out; + } + /* Now write the data to the stream's SSL*, it may not all fit! */ + DEBUGASSERT(s->id == stream_id); + for(i = 0, total_len = 0; i < n; ++i) { + total_len += vec[i].len; + } + for(i = 0; (i < n) && !blocked; ++i) { + /* Without stream->s.ssl, we closed that already, so + * pretend the write did succeed. */ + written = vec[i].len; + ok = !s->ssl || SSL_write_ex(s->ssl, vec[i].base, vec[i].len, + &written); + if(ok) { + /* As OpenSSL buffers the data, we count this as acknowledged + * from nghttp3's point of view */ + CURL_TRC_CF(data, cf, "[%"PRId64"] send %zu bytes to QUIC ok", + s->id, vec[i].len); + acked_len += vec[i].len; + } + else { + int detail = SSL_get_error(s->ssl, 0); + switch(detail) { + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + /* QUIC blocked us from writing more */ + CURL_TRC_CF(data, cf, "[%"PRId64"] send %zu bytes to QUIC blocked", + s->id, vec[i].len); + written = 0; + nghttp3_conn_block_stream(ctx->h3.conn, s->id); + s->send_blocked = blocked = TRUE; + break; + default: + failf(data, "[%"PRId64"] send %zu bytes to QUIC, SSL error %d", + s->id, vec[i].len, detail); + result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR); + goto out; + } + } + } + + if(acked_len > 0 || (eos && !s->send_blocked)) { + /* Since QUIC buffers the data written internally, we can tell + * nghttp3 that it can move forward on it */ + rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_add_write_offset returned error: %s\n", + nghttp3_strerror(rv)); + result = CURLE_SEND_ERROR; + goto out; + } + rv = nghttp3_conn_add_ack_offset(ctx->h3.conn, s->id, acked_len); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_add_ack_offset returned error: %s\n", + nghttp3_strerror(rv)); + result = CURLE_SEND_ERROR; + goto out; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] forwarded %zu/%zu h3 bytes " + "to QUIC, eos=%d", s->id, acked_len, total_len, eos); + } + + if(eos && !s->send_blocked) { + /* wrote everything and H3 indicates end of stream */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] closing QUIC stream", s->id); + SSL_stream_conclude(s->ssl, 0); + } + } + +out: + CURL_TRC_CF(data, cf, "h3_send_streams -> %d", result); + return result; +} + +static CURLcode cf_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(!ctx->tls.ssl) + goto out; + + ERR_clear_error(); + result = h3_send_streams(cf, data); + if(result) + goto out; + + if(!SSL_handle_events(ctx->tls.ssl)) { + int detail = SSL_get_error(ctx->tls.ssl, 0); + result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR); + } + + result = cf_osslq_check_and_unblock(cf, data); + +out: + CURL_TRC_CF(data, cf, "progress_egress -> %d", result); + return result; +} + +static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct timeval tv; + timediff_t timeoutms; + int is_infinite = TRUE; + + if(ctx->tls.ssl && + SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite) && + !is_infinite) { + timeoutms = curlx_tvtoms(&tv); + /* QUIC want to be called again latest at the returned timeout */ + if(timeoutms <= 0) { + result = cf_progress_ingress(cf, data); + if(result) + goto out; + result = cf_progress_egress(cf, data); + if(result) + goto out; + if(SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite)) { + timeoutms = curlx_tvtoms(&tv); + } + } + if(!is_infinite) { + Curl_expire(data, timeoutms, EXPIRE_QUIC); + CURL_TRC_CF(data, cf, "QUIC expiry in %ldms", (long)timeoutms); + } + } +out: + return result; +} + +static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + struct curltime now; + int err; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* Connect the UDP filter first */ + if(!cf->next->connected) { + result = Curl_conn_cf_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + } + + *done = FALSE; + now = Curl_now(); + CF_DATA_SAVE(save, cf, data); + + if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) { + /* Not time yet to attempt the next connect */ + CURL_TRC_CF(data, cf, "waiting for reconnect time"); + goto out; + } + + if(!ctx->tls.ssl) { + ctx->started_at = now; + result = cf_osslq_ctx_start(cf, data); + if(result) + goto out; + } + + if(!ctx->got_first_byte) { + int readable = SOCKET_READABLE(ctx->q.sockfd, 0); + if(readable > 0 && (readable & CURL_CSELECT_IN)) { + ctx->got_first_byte = TRUE; + ctx->first_byte_at = Curl_now(); + } + } + + ERR_clear_error(); + err = SSL_do_handshake(ctx->tls.ssl); + + if(err == 1) { + /* connected */ + ctx->handshake_at = now; + CURL_TRC_CF(data, cf, "handshake complete after %dms", + (int)Curl_timediff(now, ctx->started_at)); + result = cf_osslq_verify_peer(cf, data); + if(!result) { + CURL_TRC_CF(data, cf, "peer verified"); + cf->connected = TRUE; + cf->conn->alpn = CURL_HTTP_VERSION_3; + *done = TRUE; + connkeep(cf->conn, "HTTP/3 default"); + } + } + else { + int detail = SSL_get_error(ctx->tls.ssl, err); + switch(detail) { + case SSL_ERROR_WANT_READ: + CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV"); + result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); + goto out; + case SSL_ERROR_WANT_WRITE: + CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND"); + result = CURLE_OK; + goto out; +#ifdef SSL_ERROR_WANT_ASYNC + case SSL_ERROR_WANT_ASYNC: + CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC"); + result = CURLE_OK; + goto out; +#endif +#ifdef SSL_ERROR_WANT_RETRY_VERIFY + case SSL_ERROR_WANT_RETRY_VERIFY: + result = CURLE_OK; + goto out; +#endif + default: + result = cf_osslq_ssl_err(cf, data, detail, CURLE_COULDNT_CONNECT); + goto out; + } + } + +out: + if(result == CURLE_RECV_ERROR && ctx->tls.ssl && ctx->protocol_shutdown) { + /* When a QUIC server instance is shutting down, it may send us a + * CONNECTION_CLOSE right away. Our connection then enters the DRAINING + * state. The CONNECT may work in the near future again. Indicate + * that as a "weird" reply. */ + result = CURLE_WEIRD_SERVER_REPLY; + } + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(result) { + const char *r_ip = NULL; + int r_port = 0; + + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + infof(data, "QUIC connect to %s port %u failed: %s", + r_ip, r_port, curl_easy_strerror(result)); + } +#endif + if(!result) + result = check_and_set_expiry(cf, data); + if(result || *done) + CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done); + CF_DATA_RESTORE(cf, save); + return result; +} + +static ssize_t h3_stream_open(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t len, + CURLcode *err) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = NULL; + struct dynhds h2_headers; + size_t nheader; + nghttp3_nv *nva = NULL; + int rc = 0; + unsigned int i; + ssize_t nwritten = -1; + nghttp3_data_reader reader; + nghttp3_data_reader *preader = NULL; + + Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); + + *err = h3_data_setup(cf, data); + if(*err) + goto out; + stream = H3_STREAM_CTX(data); + DEBUGASSERT(stream); + if(!stream) { + *err = CURLE_FAILED_INIT; + goto out; + } + + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + if(nwritten < 0) + goto out; + if(!stream->h1.done) { + /* need more data */ + goto out; + } + DEBUGASSERT(stream->h1.req); + + *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(*err) { + nwritten = -1; + goto out; + } + /* no longer needed */ + Curl_h1_req_parse_free(&stream->h1); + + nheader = Curl_dynhds_count(&h2_headers); + nva = malloc(sizeof(nghttp3_nv) * nheader); + if(!nva) { + *err = CURLE_OUT_OF_MEMORY; + nwritten = -1; + goto out; + } + + for(i = 0; i < nheader; ++i) { + struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i); + nva[i].name = (unsigned char *)e->name; + nva[i].namelen = e->namelen; + nva[i].value = (unsigned char *)e->value; + nva[i].valuelen = e->valuelen; + nva[i].flags = NGHTTP3_NV_FLAG_NONE; + } + + DEBUGASSERT(stream->s.id == -1); + *err = cf_osslq_stream_open(&stream->s, ctx->tls.ssl, 0, + &ctx->stream_bufcp, data); + if(*err) { + failf(data, "can't get bidi streams"); + *err = CURLE_SEND_ERROR; + goto out; + } + + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + case HTTPREQ_PUT: + /* known request body size or -1 */ + if(data->state.infilesize != -1) + stream->upload_left = data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown */ + break; + default: + /* there is not request body */ + stream->upload_left = 0; /* no request body */ + break; + } + + stream->send_closed = (stream->upload_left == 0); + if(!stream->send_closed) { + reader.read_data = cb_h3_read_req_body; + preader = &reader; + } + + rc = nghttp3_conn_submit_request(ctx->h3.conn, stream->s.id, + nva, nheader, preader, data); + if(rc) { + switch(rc) { + case NGHTTP3_ERR_CONN_CLOSING: + CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, " + "connection is closing", stream->s.id); + break; + default: + CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)", + stream->s.id, rc, nghttp3_strerror(rc)); + break; + } + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + + if(Curl_trc_is_verbose(data)) { + infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s", + stream->s.id, data->state.url); + for(i = 0; i < nheader; ++i) { + infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->s.id, + (int)nva[i].namelen, nva[i].name, + (int)nva[i].valuelen, nva[i].value); + } + } + +out: + free(nva); + Curl_dynhds_free(&h2_headers); + return nwritten; +} + +static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + struct cf_call_data save; + ssize_t nwritten; + CURLcode result; + + CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(cf->connected); + DEBUGASSERT(ctx->tls.ssl); + DEBUGASSERT(ctx->h3.conn); + *err = CURLE_OK; + + result = cf_progress_ingress(cf, data); + if(result) { + *err = result; + nwritten = -1; + goto out; + } + + result = cf_progress_egress(cf, data); + if(result) { + *err = result; + nwritten = -1; + goto out; + } + + if(!stream || stream->s.id < 0) { + nwritten = h3_stream_open(cf, data, buf, len, err); + if(nwritten < 0) { + CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err); + goto out; + } + stream = H3_STREAM_CTX(data); + } + else if(stream->upload_blocked_len) { + /* the data in `buf` has already been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + DEBUGASSERT(len >= stream->upload_blocked_len); + if(len < stream->upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happen. We are not prepared to handle that. */ + failf(data, "HTTP/3 send again with decreased length"); + *err = CURLE_HTTP3; + nwritten = -1; + goto out; + } + nwritten = (ssize_t)stream->upload_blocked_len; + stream->upload_blocked_len = 0; + } + else if(stream->closed) { + if(stream->resp_hds_complete) { + /* Server decided to close the stream after having sent us a final + * response. This is valid if it is not interested in the request + * body. This happens on 30x or 40x responses. + * We silently discard the data sent, since this is not a transport + * error situation. */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data" + "on closed stream with response", stream->s.id); + *err = CURLE_OK; + nwritten = (ssize_t)len; + goto out; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> stream closed", stream->s.id, len); + *err = CURLE_HTTP3; + nwritten = -1; + goto out; + } + else { + nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err); + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to " + "sendbuf(len=%zu) -> %zd, %d", + stream->s.id, len, nwritten, *err); + if(nwritten < 0) { + goto out; + } + + (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id); + } + + result = cf_progress_egress(cf, data); + if(result) { + *err = result; + nwritten = -1; + } + + if(stream && nwritten > 0 && stream->sendbuf_len_in_flight) { + /* We have unacknowledged DATA and cannot report success to our + * caller. Instead we EAGAIN and remember how much we have already + * "written" into our various internal connection buffers. */ + stream->upload_blocked_len = nwritten; + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), " + "%zu bytes in flight -> EGAIN", stream->s.id, len, + stream->sendbuf_len_in_flight); + *err = CURLE_AGAIN; + nwritten = -1; + } + +out: + result = check_and_set_expiry(cf, data); + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d", + stream? stream->s.id : -1, len, nwritten, *err); + CF_DATA_RESTORE(cf, save); + return nwritten; +} + +static ssize_t recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h3_stream_ctx *stream, + CURLcode *err) +{ + ssize_t nread = -1; + + (void)cf; + if(stream->reset) { + failf(data, + "HTTP/3 stream %" PRId64 " reset by server", stream->s.id); + *err = stream->resp_hds_complete? CURLE_PARTIAL_FILE : CURLE_HTTP3; + goto out; + } + else if(!stream->resp_hds_complete) { + failf(data, + "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting" + " all response header fields, treated as error", + stream->s.id); + *err = CURLE_HTTP3; + goto out; + } + *err = CURLE_OK; + nread = 0; + +out: + return nread; +} + +static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nread = -1; + struct cf_call_data save; + CURLcode result; + + (void)ctx; + CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(cf->connected); + DEBUGASSERT(ctx); + DEBUGASSERT(ctx->tls.ssl); + DEBUGASSERT(ctx->h3.conn); + *err = CURLE_OK; + + if(!stream) { + *err = CURLE_RECV_ERROR; + goto out; + } + + if(!Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->s.id, len, nread, *err); + goto out; + } + } + + result = cf_progress_ingress(cf, data); + if(result) { + *err = result; + nread = -1; + goto out; + } + + /* recvbuf had nothing before, maybe after progressing ingress? */ + if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->s.id, len, nread, *err); + goto out; + } + } + + if(nread > 0) { + h3_drain_stream(cf, data); + } + else { + if(stream->closed) { + nread = recv_closed_stream(cf, data, stream, err); + goto out; + } + *err = CURLE_AGAIN; + nread = -1; + } + +out: + if(cf_progress_egress(cf, data)) { + *err = CURLE_SEND_ERROR; + nread = -1; + } + else { + CURLcode result2 = check_and_set_expiry(cf, data); + if(result2) { + *err = result2; + nread = -1; + } + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(len=%zu) -> %zd, %d", + stream? stream->s.id : -1, len, nread, *err); + CF_DATA_RESTORE(cf, save); + return nread; +} + +/* + * Called from transfer.c:data_pending to know if we should keep looping + * to receive more data from the connection. + */ +static bool cf_osslq_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + const struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + (void)cf; + return stream && !Curl_bufq_is_empty(&stream->recvbuf); +} + +static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_DATA_SETUP: + break; + case CF_CTRL_DATA_PAUSE: + result = h3_data_pause(cf, data, (arg1 != 0)); + break; + case CF_CTRL_DATA_DETACH: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE_SEND: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + if(stream && !stream->send_closed) { + stream->send_closed = TRUE; + stream->upload_left = Curl_bufq_len(&stream->sendbuf); + (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id); + } + break; + } + case CF_CTRL_DATA_IDLE: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURL_TRC_CF(data, cf, "data idle"); + if(stream && !stream->closed) { + result = check_and_set_expiry(cf, data); + } + break; + } + default: + break; + } + CF_DATA_RESTORE(cf, save); + return result; +} + +static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + bool alive = FALSE; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + *input_pending = FALSE; + if(!ctx->tls.ssl) + goto out; + + /* TODO: how to check negotiated connection idle time? */ + + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + goto out; + + alive = TRUE; + if(*input_pending) { + CURLcode result; + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + *input_pending = FALSE; + result = cf_progress_ingress(cf, data); + CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result); + alive = result? FALSE : TRUE; + } + +out: + CF_DATA_RESTORE(cf, save); + return alive; +} + +static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + + if(!ctx->tls.ssl) { + /* NOP */ + } + else if(!cf->connected) { + /* during handshake, transfer has not started yet. we always + * add our socket for polling if SSL wants to send/recv */ + Curl_pollset_set(data, ps, ctx->q.sockfd, + SSL_net_read_desired(ctx->tls.ssl), + SSL_net_write_desired(ctx->tls.ssl)); + } + else { + /* once connected, we only modify the socket if it is present. + * this avoids adding it for paused transfers. */ + bool want_recv, want_send; + Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); + if(want_recv || want_send) { + Curl_pollset_set(data, ps, ctx->q.sockfd, + SSL_net_read_desired(ctx->tls.ssl), + SSL_net_write_desired(ctx->tls.ssl)); + } + } +} + +static CURLcode cf_osslq_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct cf_call_data save; + + switch(query) { + case CF_QUERY_MAX_CONCURRENT: { + /* TODO: how to get this? */ + CF_DATA_SAVE(save, cf, data); + *pres1 = 100; + CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1); + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + } + case CF_QUERY_CONNECT_REPLY_MS: + if(ctx->got_first_byte) { + timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at); + *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX; + } + else + *pres1 = -1; + return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + if(ctx->got_first_byte) + *when = ctx->first_byte_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +struct Curl_cftype Curl_cft_http3 = { + "HTTP/3", + CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX, + 0, + cf_osslq_destroy, + cf_osslq_connect, + cf_osslq_close, + Curl_cf_def_get_host, + cf_osslq_adjust_pollset, + cf_osslq_data_pending, + cf_osslq_send, + cf_osslq_recv, + cf_osslq_data_event, + cf_osslq_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_osslq_query, +}; + +CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai) +{ + struct cf_osslq_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + CURLcode result; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + cf_osslq_ctx_clear(ctx); + + result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); + if(result) + goto out; + + result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + if(result) + goto out; + + cf->conn = conn; + udp_cf->conn = cf->conn; + udp_cf->sockindex = cf->sockindex; + cf->next = udp_cf; + +out: + *pcf = (!result)? cf : NULL; + if(result) { + if(udp_cf) + Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); + Curl_safefree(cf); + Curl_safefree(ctx); + } + return result; +} + +bool Curl_conn_is_osslq(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL; + + (void)data; + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_http3) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; +} + +/* + * Store ngtcp2 version info in this buffer. + */ +void Curl_osslq_ver(char *p, size_t len) +{ + const nghttp3_info *ht3 = nghttp3_version(0); + (void)msnprintf(p, len, "nghttp3/%s", ht3->version_str); +} + +#endif /* USE_OPENSSL_QUIC && USE_NGHTTP3 */ diff --git a/lib/vquic/curl_osslq.h b/lib/vquic/curl_osslq.h new file mode 100644 index 0000000..0e12d70 --- /dev/null +++ b/lib/vquic/curl_osslq.h @@ -0,0 +1,51 @@ +#ifndef HEADER_CURL_VQUIC_CURL_OSSLQ_H +#define HEADER_CURL_VQUIC_CURL_OSSLQ_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + +#ifdef HAVE_NETINET_UDP_H +#include +#endif + +struct Curl_cfilter; + +#include "urldata.h" + +void Curl_osslq_ver(char *p, size_t len); + +CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai); + +bool Curl_conn_is_osslq(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex); +#endif + +#endif /* HEADER_CURL_VQUIC_CURL_OSSLQ_H */ diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c new file mode 100644 index 0000000..fcb0eb8 --- /dev/null +++ b/lib/vquic/curl_quiche.c @@ -0,0 +1,1598 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_QUICHE +#include +#include +#include +#include "bufq.h" +#include "urldata.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "sendf.h" +#include "strdup.h" +#include "rand.h" +#include "strcase.h" +#include "multiif.h" +#include "connect.h" +#include "progress.h" +#include "strerror.h" +#include "http1.h" +#include "vquic.h" +#include "vquic_int.h" +#include "vquic-tls.h" +#include "curl_quiche.h" +#include "transfer.h" +#include "inet_pton.h" +#include "vtls/openssl.h" +#include "vtls/keylog.h" +#include "vtls/vtls.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* HTTP/3 error values defined in RFC 9114, ch. 8.1 */ +#define CURL_H3_NO_ERROR (0x0100) + +#define QUIC_MAX_STREAMS (100) + +#define H3_STREAM_WINDOW_SIZE (128 * 1024) +#define H3_STREAM_CHUNK_SIZE (16 * 1024) +/* The pool keeps spares around and half of a full stream windows + * seems good. More does not seem to improve performance. + * The benefit of the pool is that stream buffer to not keep + * spares. So memory consumption goes down when streams run empty, + * have a large upload done, etc. */ +#define H3_STREAM_POOL_SPARES \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 +/* Receive and Send max number of chunks just follows from the + * chunk size and window size */ +#define H3_STREAM_RECV_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) +#define H3_STREAM_SEND_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) + +/* + * Store quiche version info in this buffer. + */ +void Curl_quiche_ver(char *p, size_t len) +{ + (void)msnprintf(p, len, "quiche/%s", quiche_version()); +} + +struct cf_quiche_ctx { + struct cf_quic_ctx q; + struct ssl_peer peer; + struct quic_tls_ctx tls; + quiche_conn *qconn; + quiche_config *cfg; + quiche_h3_conn *h3c; + quiche_h3_config *h3config; + uint8_t scid[QUICHE_MAX_CONN_ID_LEN]; + struct curltime started_at; /* time the current attempt started */ + struct curltime handshake_at; /* time connect handshake finished */ + struct curltime reconnect_at; /* time the next attempt should start */ + struct bufc_pool stream_bufcp; /* chunk pool for streams */ + curl_off_t data_recvd; + uint64_t max_idle_ms; /* max idle time for QUIC conn */ + BIT(goaway); /* got GOAWAY from server */ + BIT(x509_store_setup); /* if x509 store has been set up */ +}; + +#ifdef DEBUG_QUICHE +static void quiche_debug_log(const char *line, void *argp) +{ + (void)argp; + fprintf(stderr, "%s\n", line); +} +#endif + +static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx) +{ + if(ctx) { + if(ctx->h3c) + quiche_h3_conn_free(ctx->h3c); + if(ctx->h3config) + quiche_h3_config_free(ctx->h3config); + if(ctx->qconn) + quiche_conn_free(ctx->qconn); + if(ctx->cfg) + quiche_config_free(ctx->cfg); + /* quiche just freed ctx->tls.ssl */ + ctx->tls.ssl = NULL; + Curl_vquic_tls_cleanup(&ctx->tls); + Curl_ssl_peer_cleanup(&ctx->peer); + vquic_ctx_free(&ctx->q); + Curl_bufcp_free(&ctx->stream_bufcp); + + memset(ctx, 0, sizeof(*ctx)); + } +} + +/** + * All about the H3 internals of a stream + */ +struct stream_ctx { + int64_t id; /* HTTP/3 protocol stream identifier */ + struct bufq recvbuf; /* h3 response */ + struct h1_req_parser h1; /* h1 request parsing */ + uint64_t error3; /* HTTP/3 stream error code */ + curl_off_t upload_left; /* number of request bytes left to upload */ + bool closed; /* TRUE on stream close */ + bool reset; /* TRUE on stream reset */ + bool send_closed; /* stream is locally closed */ + bool resp_hds_complete; /* complete, final response has been received */ + bool resp_got_header; /* TRUE when h3 stream has recvd some HEADER */ + BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */ +}; + +#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \ + ((struct HTTP *)(d)->req.p.http)->h3_ctx \ + : NULL)) +#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx +#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \ + H3_STREAM_CTX(d)->id : -2) + +static void check_resumes(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct Curl_easy *sdata; + struct stream_ctx *stream; + + DEBUGASSERT(data->multi); + for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { + if(sdata->conn == data->conn) { + stream = H3_STREAM_CTX(sdata); + if(stream && stream->quic_flow_blocked) { + stream->quic_flow_blocked = FALSE; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + CURL_TRC_CF(data, cf, "[%"PRId64"] unblock", stream->id); + } + } + } +} + +static CURLcode h3_data_setup(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + + if(stream) + return CURLE_OK; + + stream = calloc(1, sizeof(*stream)); + if(!stream) + return CURLE_OUT_OF_MEMORY; + + H3_STREAM_LCTX(data) = stream; + stream->id = -1; + Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, + H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); + Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); + return CURLE_OK; +} + +static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + + (void)cf; + if(stream) { + CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id); + if(ctx->qconn && !stream->closed) { + quiche_conn_stream_shutdown(ctx->qconn, stream->id, + QUICHE_SHUTDOWN_READ, CURL_H3_NO_ERROR); + if(!stream->send_closed) { + quiche_conn_stream_shutdown(ctx->qconn, stream->id, + QUICHE_SHUTDOWN_WRITE, CURL_H3_NO_ERROR); + stream->send_closed = TRUE; + } + stream->closed = TRUE; + } + Curl_bufq_free(&stream->recvbuf); + Curl_h1_req_parse_free(&stream->h1); + free(stream); + H3_STREAM_LCTX(data) = NULL; + } +} + +static void drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(stream && !stream->send_closed && stream->upload_left) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf, + struct Curl_easy *data, + int64_t stream3_id) +{ + struct Curl_easy *sdata; + + (void)cf; + if(H3_STREAM_ID(data) == stream3_id) { + return data; + } + else { + DEBUGASSERT(data->multi); + for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { + if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream3_id) { + return sdata; + } + } + } + return NULL; +} + +/* + * write_resp_raw() copies response data in raw format to the `data`'s + * receive buffer. If not enough space is available, it appends to the + * `data`'s overflow buffer. + */ +static CURLcode write_resp_raw(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, size_t memlen) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + ssize_t nwritten; + + (void)cf; + if(!stream) + return CURLE_RECV_ERROR; + nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); + if(nwritten < 0) + return result; + + if((size_t)nwritten < memlen) { + /* This MUST not happen. Our recbuf is dimensioned to hold the + * full max_stream_window and then some for this very reason. */ + DEBUGASSERT(0); + return CURLE_RECV_ERROR; + } + return result; +} + +struct cb_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; +}; + +static int cb_each_header(uint8_t *name, size_t name_len, + uint8_t *value, size_t value_len, + void *argp) +{ + struct cb_ctx *x = argp; + struct stream_ctx *stream = H3_STREAM_CTX(x->data); + CURLcode result; + + if(!stream) + return CURLE_OK; + + if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7)) { + CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] status: %.*s", + stream->id, (int)value_len, value); + result = write_resp_raw(x->cf, x->data, "HTTP/3 ", sizeof("HTTP/3 ") - 1); + if(!result) + result = write_resp_raw(x->cf, x->data, value, value_len); + if(!result) + result = write_resp_raw(x->cf, x->data, " \r\n", 3); + } + else { + CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] header: %.*s: %.*s", + stream->id, (int)name_len, name, + (int)value_len, value); + result = write_resp_raw(x->cf, x->data, name, name_len); + if(!result) + result = write_resp_raw(x->cf, x->data, ": ", 2); + if(!result) + result = write_resp_raw(x->cf, x->data, value, value_len); + if(!result) + result = write_resp_raw(x->cf, x->data, "\r\n", 2); + } + if(result) { + CURL_TRC_CF(x->data, x->cf, "[%"PRId64"] on header error %d", + stream->id, result); + } + return result; +} + +static ssize_t stream_resp_read(void *reader_ctx, + unsigned char *buf, size_t len, + CURLcode *err) +{ + struct cb_ctx *x = reader_ctx; + struct cf_quiche_ctx *ctx = x->cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(x->data); + ssize_t nread; + + if(!stream) { + *err = CURLE_RECV_ERROR; + return -1; + } + + nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id, + buf, len); + if(nread >= 0) { + *err = CURLE_OK; + return nread; + } + else { + *err = CURLE_AGAIN; + return -1; + } +} + +static CURLcode cf_recv_body(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nwritten; + struct cb_ctx cb_ctx; + CURLcode result = CURLE_OK; + + if(!stream) + return CURLE_RECV_ERROR; + + if(!stream->resp_hds_complete) { + result = write_resp_raw(cf, data, "\r\n", 2); + if(result) + return result; + stream->resp_hds_complete = TRUE; + } + + cb_ctx.cf = cf; + cb_ctx.data = data; + nwritten = Curl_bufq_slurp(&stream->recvbuf, + stream_resp_read, &cb_ctx, &result); + + if(nwritten < 0 && result != CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "[%"PRId64"] recv_body error %zd", + stream->id, nwritten); + failf(data, "Error %d in HTTP/3 response body for stream[%"PRId64"]", + result, stream->id); + stream->closed = TRUE; + stream->reset = TRUE; + stream->send_closed = TRUE; + streamclose(cf->conn, "Reset of stream"); + return result; + } + return CURLE_OK; +} + +#ifdef DEBUGBUILD +static const char *cf_ev_name(quiche_h3_event *ev) +{ + switch(quiche_h3_event_type(ev)) { + case QUICHE_H3_EVENT_HEADERS: + return "HEADERS"; + case QUICHE_H3_EVENT_DATA: + return "DATA"; + case QUICHE_H3_EVENT_RESET: + return "RESET"; + case QUICHE_H3_EVENT_FINISHED: + return "FINISHED"; + case QUICHE_H3_EVENT_GOAWAY: + return "GOAWAY"; + default: + return "Unknown"; + } +} +#else +#define cf_ev_name(x) "" +#endif + +static CURLcode h3_process_event(struct Curl_cfilter *cf, + struct Curl_easy *data, + int64_t stream3_id, + quiche_h3_event *ev) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + struct cb_ctx cb_ctx; + CURLcode result = CURLE_OK; + int rc; + + if(!stream) + return CURLE_OK; + DEBUGASSERT(stream3_id == stream->id); + switch(quiche_h3_event_type(ev)) { + case QUICHE_H3_EVENT_HEADERS: + stream->resp_got_header = TRUE; + cb_ctx.cf = cf; + cb_ctx.data = data; + rc = quiche_h3_event_for_each_header(ev, cb_each_header, &cb_ctx); + if(rc) { + failf(data, "Error %d in HTTP/3 response header for stream[%"PRId64"]", + rc, stream3_id); + return CURLE_RECV_ERROR; + } + CURL_TRC_CF(data, cf, "[%"PRId64"] <- [HEADERS]", stream3_id); + break; + + case QUICHE_H3_EVENT_DATA: + if(!stream->closed) { + result = cf_recv_body(cf, data); + } + break; + + case QUICHE_H3_EVENT_RESET: + CURL_TRC_CF(data, cf, "[%"PRId64"] RESET", stream3_id); + stream->closed = TRUE; + stream->reset = TRUE; + stream->send_closed = TRUE; + streamclose(cf->conn, "Reset of stream"); + break; + + case QUICHE_H3_EVENT_FINISHED: + CURL_TRC_CF(data, cf, "[%"PRId64"] CLOSED", stream3_id); + if(!stream->resp_hds_complete) { + result = write_resp_raw(cf, data, "\r\n", 2); + if(result) + return result; + stream->resp_hds_complete = TRUE; + } + stream->closed = TRUE; + streamclose(cf->conn, "End of stream"); + break; + + case QUICHE_H3_EVENT_GOAWAY: + CURL_TRC_CF(data, cf, "[%"PRId64"] <- [GOAWAY]", stream3_id); + break; + + default: + CURL_TRC_CF(data, cf, "[%"PRId64"] recv, unhandled event %d", + stream3_id, quiche_h3_event_type(ev)); + break; + } + return result; +} + +static CURLcode cf_poll_events(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + struct Curl_easy *sdata; + quiche_h3_event *ev; + CURLcode result; + + /* Take in the events and distribute them to the transfers. */ + while(ctx->h3c) { + int64_t stream3_id = quiche_h3_conn_poll(ctx->h3c, ctx->qconn, &ev); + if(stream3_id == QUICHE_H3_ERR_DONE) { + break; + } + else if(stream3_id < 0) { + CURL_TRC_CF(data, cf, "[%"PRId64"] error poll: %"PRId64, + stream? stream->id : -1, stream3_id); + return CURLE_HTTP3; + } + + sdata = get_stream_easy(cf, data, stream3_id); + if(!sdata) { + CURL_TRC_CF(data, cf, "[%"PRId64"] discard event %s for " + "unknown [%"PRId64"]", + stream? stream->id : -1, cf_ev_name(ev), stream3_id); + } + else { + result = h3_process_event(cf, sdata, stream3_id, ev); + drain_stream(cf, sdata); + if(result) { + CURL_TRC_CF(data, cf, "[%"PRId64"] error processing event %s " + "for [%"PRId64"] -> %d", + stream? stream->id : -1, cf_ev_name(ev), + stream3_id, result); + if(data == sdata) { + /* Only report this error to the caller if it is about the + * transfer we were called with. Otherwise we fail a transfer + * due to a problem in another one. */ + quiche_h3_event_free(ev); + return result; + } + } + quiche_h3_event_free(ev); + } + } + return CURLE_OK; +} + +struct recv_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; + int pkts; +}; + +static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, + struct sockaddr_storage *remote_addr, + socklen_t remote_addrlen, int ecn, + void *userp) +{ + struct recv_ctx *r = userp; + struct cf_quiche_ctx *ctx = r->cf->ctx; + quiche_recv_info recv_info; + ssize_t nread; + + (void)ecn; + ++r->pkts; + + recv_info.to = (struct sockaddr *)&ctx->q.local_addr; + recv_info.to_len = ctx->q.local_addrlen; + recv_info.from = (struct sockaddr *)remote_addr; + recv_info.from_len = remote_addrlen; + + nread = quiche_conn_recv(ctx->qconn, (unsigned char *)pkt, pktlen, + &recv_info); + if(nread < 0) { + if(QUICHE_ERR_DONE == nread) { + CURL_TRC_CF(r->data, r->cf, "ingress, quiche is DONE"); + return CURLE_OK; + } + else if(QUICHE_ERR_TLS_FAIL == nread) { + long verify_ok = SSL_get_verify_result(ctx->tls.ssl); + if(verify_ok != X509_V_OK) { + failf(r->data, "SSL certificate problem: %s", + X509_verify_cert_error_string(verify_ok)); + return CURLE_PEER_FAILED_VERIFICATION; + } + } + else { + failf(r->data, "quiche_conn_recv() == %zd", nread); + return CURLE_RECV_ERROR; + } + } + else if((size_t)nread < pktlen) { + CURL_TRC_CF(r->data, r->cf, "ingress, quiche only read %zd/%zu bytes", + nread, pktlen); + } + + return CURLE_OK; +} + +static CURLcode cf_process_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct recv_ctx rctx; + CURLcode result; + + DEBUGASSERT(ctx->qconn); + result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); + if(result) + return result; + + rctx.cf = cf; + rctx.data = data; + rctx.pkts = 0; + + result = vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, &rctx); + if(result) + return result; + + if(rctx.pkts > 0) { + /* quiche digested ingress packets. It might have opened flow control + * windows again. */ + check_resumes(cf, data); + } + return cf_poll_events(cf, data); +} + +struct read_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; + quiche_send_info send_info; +}; + +static ssize_t read_pkt_to_send(void *userp, + unsigned char *buf, size_t buflen, + CURLcode *err) +{ + struct read_ctx *x = userp; + struct cf_quiche_ctx *ctx = x->cf->ctx; + ssize_t nwritten; + + nwritten = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info); + if(nwritten == QUICHE_ERR_DONE) { + *err = CURLE_AGAIN; + return -1; + } + + if(nwritten < 0) { + failf(x->data, "quiche_conn_send returned %zd", nwritten); + *err = CURLE_SEND_ERROR; + return -1; + } + *err = CURLE_OK; + return nwritten; +} + +/* + * flush_egress drains the buffers and sends off data. + * Calls failf() on errors. + */ +static CURLcode cf_flush_egress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + ssize_t nread; + CURLcode result; + int64_t expiry_ns; + int64_t timeout_ns; + struct read_ctx readx; + size_t pkt_count, gsolen; + + expiry_ns = quiche_conn_timeout_as_nanos(ctx->qconn); + if(!expiry_ns) { + quiche_conn_on_timeout(ctx->qconn); + if(quiche_conn_is_closed(ctx->qconn)) { + failf(data, "quiche_conn_on_timeout closed the connection"); + return CURLE_SEND_ERROR; + } + } + + result = vquic_flush(cf, data, &ctx->q); + if(result) { + if(result == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return result; + } + + readx.cf = cf; + readx.data = data; + memset(&readx.send_info, 0, sizeof(readx.send_info)); + pkt_count = 0; + gsolen = quiche_conn_max_send_udp_payload_size(ctx->qconn); + for(;;) { + /* add the next packet to send, if any, to our buffer */ + nread = Curl_bufq_sipn(&ctx->q.sendbuf, 0, + read_pkt_to_send, &readx, &result); + if(nread < 0) { + if(result != CURLE_AGAIN) + return result; + /* Nothing more to add, flush and leave */ + result = vquic_send(cf, data, &ctx->q, gsolen); + if(result) { + if(result == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return result; + } + goto out; + } + + ++pkt_count; + if((size_t)nread < gsolen || pkt_count >= MAX_PKT_BURST) { + result = vquic_send(cf, data, &ctx->q, gsolen); + if(result) { + if(result == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + goto out; + } + pkt_count = 0; + } + } + +out: + timeout_ns = quiche_conn_timeout_as_nanos(ctx->qconn); + if(timeout_ns % 1000000) + timeout_ns += 1000000; + /* expire resolution is milliseconds */ + Curl_expire(data, (timeout_ns / 1000000), EXPIRE_QUIC); + return result; +} + +static ssize_t recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLcode *err) +{ + struct stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nread = -1; + + DEBUGASSERT(stream); + if(stream->reset) { + failf(data, + "HTTP/3 stream %" PRId64 " reset by server", stream->id); + *err = stream->resp_got_header? CURLE_PARTIAL_FILE : CURLE_HTTP3; + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, was reset -> %d", + stream->id, *err); + } + else if(!stream->resp_got_header) { + failf(data, + "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting" + " all response header fields, treated as error", + stream->id); + /* *err = CURLE_PARTIAL_FILE; */ + *err = CURLE_HTTP3; + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, closed incomplete" + " -> %d", stream->id, *err); + } + else { + *err = CURLE_OK; + nread = 0; + } + return nread; +} + +static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nread = -1; + CURLcode result; + + vquic_ctx_update_time(&ctx->q); + + if(!stream) { + *err = CURLE_RECV_ERROR; + return -1; + } + + if(!Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->id, len, nread, *err); + if(nread < 0) + goto out; + } + + if(cf_process_ingress(cf, data)) { + CURL_TRC_CF(data, cf, "cf_recv, error on ingress"); + *err = CURLE_RECV_ERROR; + nread = -1; + goto out; + } + + /* recvbuf had nothing before, maybe after progressing ingress? */ + if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->id, len, nread, *err); + if(nread < 0) + goto out; + } + + if(nread > 0) { + if(stream->closed) + drain_stream(cf, data); + } + else { + if(stream->closed) { + nread = recv_closed_stream(cf, data, err); + goto out; + } + else if(quiche_conn_is_draining(ctx->qconn)) { + failf(data, "QUIC connection is draining"); + *err = CURLE_HTTP3; + nread = -1; + goto out; + } + *err = CURLE_AGAIN; + nread = -1; + } + +out: + result = cf_flush_egress(cf, data); + if(result) { + CURL_TRC_CF(data, cf, "cf_recv, flush egress failed"); + *err = result; + nread = -1; + } + if(nread > 0) + ctx->data_recvd += nread; + CURL_TRC_CF(data, cf, "[%"PRId64"] cf_recv(total=%" + CURL_FORMAT_CURL_OFF_T ") -> %zd, %d", + stream->id, ctx->data_recvd, nread, *err); + return nread; +} + +/* Index where :authority header field will appear in request header + field list. */ +#define AUTHORITY_DST_IDX 3 + +static ssize_t h3_open_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t len, + CURLcode *err) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + size_t nheader, i; + int64_t stream3_id; + struct dynhds h2_headers; + quiche_h3_header *nva = NULL; + ssize_t nwritten; + + if(!stream) { + *err = h3_data_setup(cf, data); + if(*err) { + return -1; + } + stream = H3_STREAM_CTX(data); + DEBUGASSERT(stream); + } + + Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); + + DEBUGASSERT(stream); + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + if(nwritten < 0) + goto out; + if(!stream->h1.done) { + /* need more data */ + goto out; + } + DEBUGASSERT(stream->h1.req); + + *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(*err) { + nwritten = -1; + goto out; + } + /* no longer needed */ + Curl_h1_req_parse_free(&stream->h1); + + nheader = Curl_dynhds_count(&h2_headers); + nva = malloc(sizeof(quiche_h3_header) * nheader); + if(!nva) { + *err = CURLE_OUT_OF_MEMORY; + nwritten = -1; + goto out; + } + + for(i = 0; i < nheader; ++i) { + struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i); + nva[i].name = (unsigned char *)e->name; + nva[i].name_len = e->namelen; + nva[i].value = (unsigned char *)e->value; + nva[i].value_len = e->valuelen; + } + + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + case HTTPREQ_PUT: + if(data->state.infilesize != -1) + stream->upload_left = data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown */ + break; + default: + stream->upload_left = 0; /* no request body */ + break; + } + + if(stream->upload_left == 0) + stream->send_closed = TRUE; + + stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader, + stream->send_closed); + if(stream3_id < 0) { + if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) { + /* quiche seems to report this error if the connection window is + * exhausted. Which happens frequently and intermittent. */ + CURL_TRC_CF(data, cf, "[%"PRId64"] blocked", stream->id); + stream->quic_flow_blocked = TRUE; + *err = CURLE_AGAIN; + nwritten = -1; + goto out; + } + else { + CURL_TRC_CF(data, cf, "send_request(%s) -> %" PRId64, + data->state.url, stream3_id); + } + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + + DEBUGASSERT(stream->id == -1); + *err = CURLE_OK; + stream->id = stream3_id; + stream->closed = FALSE; + stream->reset = FALSE; + + if(Curl_trc_is_verbose(data)) { + infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s", + stream->id, data->state.url); + for(i = 0; i < nheader; ++i) { + infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id, + (int)nva[i].name_len, nva[i].name, + (int)nva[i].value_len, nva[i].value); + } + } + +out: + free(nva); + Curl_dynhds_free(&h2_headers); + return nwritten; +} + +static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result; + ssize_t nwritten; + + vquic_ctx_update_time(&ctx->q); + + *err = cf_process_ingress(cf, data); + if(*err) { + nwritten = -1; + goto out; + } + + if(!stream || stream->id < 0) { + nwritten = h3_open_stream(cf, data, buf, len, err); + if(nwritten < 0) + goto out; + stream = H3_STREAM_CTX(data); + } + else if(stream->closed) { + if(stream->resp_hds_complete) { + /* sending request body on a stream that has been closed by the + * server. If the server has send us a final response, we should + * silently discard the send data. + * This happens for example on redirects where the server, instead + * of reading the full request body just closed the stream after + * sending the 30x response. + * This is sort of a race: had the transfer loop called recv first, + * it would see the response and stop/discard sending on its own- */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data" + "on closed stream with response", stream->id); + *err = CURLE_OK; + nwritten = (ssize_t)len; + goto out; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> stream closed", stream->id, len); + *err = CURLE_HTTP3; + nwritten = -1; + goto out; + } + else { + bool eof = (stream->upload_left >= 0 && + (curl_off_t)len >= stream->upload_left); + nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id, + (uint8_t *)buf, len, eof); + if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) { + /* TODO: we seem to be blocked on flow control and should HOLD + * sending. But when do we open again? */ + if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> window exhausted", stream->id, len); + stream->quic_flow_blocked = TRUE; + } + *err = CURLE_AGAIN; + nwritten = -1; + goto out; + } + else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> invalid stream state", stream->id, len); + *err = CURLE_HTTP3; + nwritten = -1; + goto out; + } + else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> exceeds size", stream->id, len); + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + else if(nwritten < 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> quiche err %zd", stream->id, len, nwritten); + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + else { + /* quiche accepted all or at least a part of the buf */ + if(stream->upload_left > 0) { + stream->upload_left = (nwritten < stream->upload_left)? + (stream->upload_left - nwritten) : 0; + } + if(stream->upload_left == 0) + stream->send_closed = TRUE; + + CURL_TRC_CF(data, cf, "[%" PRId64 "] send body(len=%zu, " + "left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd", + stream->id, len, stream->upload_left, nwritten); + *err = CURLE_OK; + } + } + +out: + result = cf_flush_egress(cf, data); + if(result) { + *err = result; + nwritten = -1; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d", + stream? stream->id : -1, len, nwritten, *err); + return nwritten; +} + +static bool stream_is_writeable(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + struct stream_ctx *stream = H3_STREAM_CTX(data); + + return stream && (quiche_conn_stream_writable(ctx->qconn, + (uint64_t)stream->id, 1) > 0); +} + +static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + bool want_recv, want_send; + + if(!ctx->qconn) + return; + + Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); + if(want_recv || want_send) { + struct stream_ctx *stream = H3_STREAM_CTX(data); + bool c_exhaust, s_exhaust; + + c_exhaust = FALSE; /* Have not found any call in quiche that tells + us if the connection itself is blocked */ + s_exhaust = want_send && stream && stream->id >= 0 && + (stream->quic_flow_blocked || !stream_is_writeable(cf, data)); + want_recv = (want_recv || c_exhaust || s_exhaust); + want_send = (!s_exhaust && want_send) || + !Curl_bufq_is_empty(&ctx->q.sendbuf); + + Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); + } +} + +/* + * Called from transfer.c:data_pending to know if we should keep looping + * to receive more data from the connection. + */ +static bool cf_quiche_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + const struct stream_ctx *stream = H3_STREAM_CTX(data); + (void)cf; + return stream && !Curl_bufq_is_empty(&stream->recvbuf); +} + +static CURLcode h3_data_pause(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool pause) +{ + /* TODO: there seems right now no API in quiche to shrink/enlarge + * the streams windows. As we do in HTTP/2. */ + if(!pause) { + drain_stream(cf, data); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + return CURLE_OK; +} + +static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + CURLcode result = CURLE_OK; + + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_DATA_SETUP: + break; + case CF_CTRL_DATA_PAUSE: + result = h3_data_pause(cf, data, (arg1 != 0)); + break; + case CF_CTRL_DATA_DETACH: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE_SEND: { + struct stream_ctx *stream = H3_STREAM_CTX(data); + if(stream && !stream->send_closed) { + unsigned char body[1]; + ssize_t sent; + + stream->send_closed = TRUE; + stream->upload_left = 0; + body[0] = 'X'; + sent = cf_quiche_send(cf, data, body, 0, &result); + CURL_TRC_CF(data, cf, "[%"PRId64"] DONE_SEND -> %zd, %d", + stream->id, sent, result); + } + break; + } + case CF_CTRL_DATA_IDLE: { + struct stream_ctx *stream = H3_STREAM_CTX(data); + if(stream && !stream->closed) { + result = cf_flush_egress(cf, data); + if(result) + CURL_TRC_CF(data, cf, "data idle, flush egress -> %d", result); + } + break; + } + default: + break; + } + return result; +} + +static CURLcode cf_connect_start(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + int rv; + CURLcode result; + const struct Curl_sockaddr_ex *sockaddr; + + DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD); + +#ifdef DEBUG_QUICHE + /* initialize debug log callback only once */ + static int debug_log_init = 0; + if(!debug_log_init) { + quiche_enable_debug_logging(quiche_debug_log, NULL); + debug_log_init = 1; + } +#endif + ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS; + Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, + H3_STREAM_POOL_SPARES); + ctx->data_recvd = 0; + + result = vquic_ctx_init(&ctx->q); + if(result) + return result; + + result = Curl_ssl_peer_init(&ctx->peer, cf); + if(result) + return result; + + ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION); + if(!ctx->cfg) { + failf(data, "can't create quiche config"); + return CURLE_FAILED_INIT; + } + quiche_config_enable_pacing(ctx->cfg, false); + quiche_config_set_max_idle_timeout(ctx->cfg, ctx->max_idle_ms * 1000); + quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024) + /* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */); + quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS); + quiche_config_set_initial_max_streams_uni(ctx->cfg, QUIC_MAX_STREAMS); + quiche_config_set_initial_max_stream_data_bidi_local(ctx->cfg, + H3_STREAM_WINDOW_SIZE); + quiche_config_set_initial_max_stream_data_bidi_remote(ctx->cfg, + H3_STREAM_WINDOW_SIZE); + quiche_config_set_initial_max_stream_data_uni(ctx->cfg, + H3_STREAM_WINDOW_SIZE); + quiche_config_set_disable_active_migration(ctx->cfg, TRUE); + + quiche_config_set_max_connection_window(ctx->cfg, + 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 *) + QUICHE_H3_APPLICATION_PROTOCOL, + sizeof(QUICHE_H3_APPLICATION_PROTOCOL) + - 1); + + result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, + QUICHE_H3_APPLICATION_PROTOCOL, + sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1, + NULL, cf); + if(result) + return result; + + result = Curl_rand(data, ctx->scid, sizeof(ctx->scid)); + if(result) + return result; + + Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, + &sockaddr, NULL, NULL, NULL, NULL); + ctx->q.local_addrlen = sizeof(ctx->q.local_addr); + rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, + &ctx->q.local_addrlen); + if(rv == -1) + return CURLE_QUIC_CONNECT_ERROR; + + ctx->qconn = quiche_conn_new_with_tls((const uint8_t *)ctx->scid, + sizeof(ctx->scid), NULL, 0, + (struct sockaddr *)&ctx->q.local_addr, + ctx->q.local_addrlen, + &sockaddr->sa_addr, sockaddr->addrlen, + ctx->cfg, ctx->tls.ssl, false); + if(!ctx->qconn) { + failf(data, "can't create quiche connection"); + return CURLE_OUT_OF_MEMORY; + } + + /* Known to not work on Windows */ +#if !defined(_WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD) + { + int qfd; + (void)Curl_qlogdir(data, ctx->scid, sizeof(ctx->scid), &qfd); + if(qfd != -1) + quiche_conn_set_qlog_fd(ctx->qconn, qfd, + "qlog title", "curl qlog"); + } +#endif + + result = cf_flush_egress(cf, data); + if(result) + return result; + + { + unsigned char alpn_protocols[] = QUICHE_H3_APPLICATION_PROTOCOL; + unsigned alpn_len, offset = 0; + + /* Replace each ALPN length prefix by a comma. */ + while(offset < sizeof(alpn_protocols) - 1) { + alpn_len = alpn_protocols[offset]; + alpn_protocols[offset] = ','; + offset += 1 + alpn_len; + } + + CURL_TRC_CF(data, cf, "Sent QUIC client Initial, ALPN: %s", + alpn_protocols + 1); + } + + return CURLE_OK; +} + +static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + cf->conn->httpversion = 30; + cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; + + return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); +} + +static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* Connect the UDP filter first */ + if(!cf->next->connected) { + result = Curl_conn_cf_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + } + + *done = FALSE; + vquic_ctx_update_time(&ctx->q); + + if(ctx->reconnect_at.tv_sec && + Curl_timediff(ctx->q.last_op, ctx->reconnect_at) < 0) { + /* Not time yet to attempt the next connect */ + CURL_TRC_CF(data, cf, "waiting for reconnect time"); + goto out; + } + + if(!ctx->qconn) { + result = cf_connect_start(cf, data); + if(result) + goto out; + ctx->started_at = ctx->q.last_op; + result = cf_flush_egress(cf, data); + /* we do not expect to be able to recv anything yet */ + goto out; + } + + result = cf_process_ingress(cf, data); + if(result) + goto out; + + result = cf_flush_egress(cf, data); + if(result) + goto out; + + if(quiche_conn_is_established(ctx->qconn)) { + ctx->handshake_at = ctx->q.last_op; + CURL_TRC_CF(data, cf, "handshake complete after %dms", + (int)Curl_timediff(ctx->handshake_at, ctx->started_at)); + result = cf_quiche_verify_peer(cf, data); + if(!result) { + CURL_TRC_CF(data, cf, "peer verified"); + ctx->h3config = quiche_h3_config_new(); + if(!ctx->h3config) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + /* Create a new HTTP/3 connection on the QUIC connection. */ + ctx->h3c = quiche_h3_conn_new_with_transport(ctx->qconn, ctx->h3config); + if(!ctx->h3c) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + cf->connected = TRUE; + cf->conn->alpn = CURL_HTTP_VERSION_3; + *done = TRUE; + connkeep(cf->conn, "HTTP/3 default"); + } + } + else if(quiche_conn_is_draining(ctx->qconn)) { + /* When a QUIC server instance is shutting down, it may send us a + * CONNECTION_CLOSE right away. Our connection then enters the DRAINING + * state. The CONNECT may work in the near future again. Indicate + * that as a "weird" reply. */ + result = CURLE_WEIRD_SERVER_REPLY; + } + +out: +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(result && result != CURLE_AGAIN) { + const char *r_ip; + int r_port; + + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + infof(data, "connect to %s port %u failed: %s", + r_ip, r_port, curl_easy_strerror(result)); + } +#endif + return result; +} + +static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + + if(ctx) { + if(ctx->qconn) { + vquic_ctx_update_time(&ctx->q); + (void)quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0); + /* flushing the egress is not a failsafe way to deliver all the + outstanding packets, but we also don't want to get stuck here... */ + (void)cf_flush_egress(cf, data); + } + cf_quiche_ctx_clear(ctx); + } +} + +static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + + (void)data; + cf_quiche_ctx_clear(ctx); + free(ctx); + cf->ctx = NULL; +} + +static CURLcode cf_quiche_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + + switch(query) { + case CF_QUERY_MAX_CONCURRENT: { + uint64_t max_streams = CONN_INUSE(cf->conn); + if(!ctx->goaway) { + max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn); + } + *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams; + CURL_TRC_CF(data, cf, "query: MAX_CONCURRENT -> %d", *pres1); + return CURLE_OK; + } + case CF_QUERY_CONNECT_REPLY_MS: + if(ctx->q.got_first_byte) { + timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at); + *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX; + } + else + *pres1 = -1; + return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + if(ctx->q.got_first_byte) + *when = ctx->q.first_byte_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + bool alive = TRUE; + + *input_pending = FALSE; + if(!ctx->qconn) + return FALSE; + + /* Both sides of the QUIC connection announce they max idle times in + * the transport parameters. Look at the minimum of both and if + * we exceed this, regard the connection as dead. The other side + * may have completely purged it and will no longer respond + * to any packets from us. */ + { + quiche_transport_params qpeerparams; + timediff_t idletime; + uint64_t idle_ms = ctx->max_idle_ms; + + if(quiche_conn_peer_transport_params(ctx->qconn, &qpeerparams) && + qpeerparams.peer_max_idle_timeout && + qpeerparams.peer_max_idle_timeout < idle_ms) + idle_ms = qpeerparams.peer_max_idle_timeout; + idletime = Curl_timediff(Curl_now(), cf->conn->lastused); + if(idletime > 0 && (uint64_t)idletime > idle_ms) + return FALSE; + } + + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + return FALSE; + + if(*input_pending) { + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + *input_pending = FALSE; + if(cf_process_ingress(cf, data)) + alive = FALSE; + else { + alive = TRUE; + } + } + + return alive; +} + +struct Curl_cftype Curl_cft_http3 = { + "HTTP/3", + CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX, + 0, + cf_quiche_destroy, + cf_quiche_connect, + cf_quiche_close, + Curl_cf_def_get_host, + cf_quiche_adjust_pollset, + cf_quiche_data_pending, + cf_quiche_send, + cf_quiche_recv, + cf_quiche_data_event, + cf_quiche_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_quiche_query, +}; + +CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai) +{ + struct cf_quiche_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + CURLcode result; + + (void)data; + (void)conn; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); + if(result) + goto out; + + result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + if(result) + goto out; + + udp_cf->conn = cf->conn; + udp_cf->sockindex = cf->sockindex; + cf->next = udp_cf; + +out: + *pcf = (!result)? cf : NULL; + if(result) { + if(udp_cf) + Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); + Curl_safefree(cf); + Curl_safefree(ctx); + } + + return result; +} + +bool Curl_conn_is_quiche(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL; + + (void)data; + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_http3) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; +} + +#endif diff --git a/lib/vquic/curl_quiche.h b/lib/vquic/curl_quiche.h new file mode 100644 index 0000000..bce781c --- /dev/null +++ b/lib/vquic/curl_quiche.h @@ -0,0 +1,50 @@ +#ifndef HEADER_CURL_VQUIC_CURL_QUICHE_H +#define HEADER_CURL_VQUIC_CURL_QUICHE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_QUICHE + +#include +#include + +struct Curl_cfilter; +struct Curl_easy; + +void Curl_quiche_ver(char *p, size_t len); + +CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai); + +bool Curl_conn_is_quiche(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex); + +#endif + +#endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */ diff --git a/lib/vquic/vquic-tls.c b/lib/vquic/vquic-tls.c new file mode 100644 index 0000000..cc7794e --- /dev/null +++ b/lib/vquic/vquic-tls.c @@ -0,0 +1,609 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(ENABLE_QUIC) && \ + (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL)) + +#ifdef USE_OPENSSL +#include +#include "vtls/openssl.h" +#elif defined(USE_GNUTLS) +#include +#include +#include +#include +#include +#include "vtls/gtls.h" +#elif defined(USE_WOLFSSL) +#include +#include +#include +#include "vtls/wolfssl.h" +#endif + +#include "urldata.h" +#include "curl_trc.h" +#include "cfilters.h" +#include "multiif.h" +#include "vtls/keylog.h" +#include "vtls/vtls.h" +#include "vquic-tls.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#ifdef USE_OPENSSL +#define QUIC_CIPHERS \ + "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ + "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" +#define QUIC_GROUPS "P-256:X25519:P-384:P-521" +#elif defined(USE_GNUTLS) +#define QUIC_PRIORITY \ + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \ + "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \ + "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \ + "%DISABLE_TLS13_COMPAT_MODE" +#elif defined(USE_WOLFSSL) +#define QUIC_CIPHERS \ + "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ + "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" +#define QUIC_GROUPS "P-256:P-384:P-521" +#endif + + +#ifdef USE_OPENSSL + +static void keylog_callback(const SSL *ssl, const char *line) +{ + (void)ssl; + Curl_tls_keylog_write_line(line); +} + +static CURLcode curl_ossl_init_ctx(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + Curl_vquic_tls_ctx_setup *ctx_setup) +{ + struct ssl_primary_config *conn_config; + CURLcode result = CURLE_FAILED_INIT; + + DEBUGASSERT(!ctx->ssl_ctx); +#ifdef USE_OPENSSL_QUIC + ctx->ssl_ctx = SSL_CTX_new(OSSL_QUIC_client_method()); +#else + ctx->ssl_ctx = SSL_CTX_new(TLS_method()); +#endif + if(!ctx->ssl_ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) { + result = CURLE_FAILED_INIT; + goto out; + } + + if(ctx_setup) { + result = ctx_setup(ctx, cf, data); + if(result) + goto out; + } + + SSL_CTX_set_default_verify_paths(ctx->ssl_ctx); + + { + const char *curves = conn_config->curves ? + conn_config->curves : QUIC_GROUPS; + if(!SSL_CTX_set1_curves_list(ctx->ssl_ctx, curves)) { + failf(data, "failed setting curves list for QUIC: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + +#ifndef OPENSSL_IS_BORINGSSL + { + const char *ciphers13 = conn_config->cipher_list13 ? + conn_config->cipher_list13 : QUIC_CIPHERS; + if(SSL_CTX_set_ciphersuites(ctx->ssl_ctx, ciphers13) != 1) { + failf(data, "failed setting QUIC cipher suite: %s", ciphers13); + return CURLE_SSL_CIPHER; + } + infof(data, "QUIC cipher selection: %s", ciphers13); + } +#endif + + /* Open the file if a TLS or QUIC backend has not done this before. */ + Curl_tls_keylog_open(); + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback); + } + + /* OpenSSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + SSL_CTX_set_verify(ctx->ssl_ctx, conn_config->verifypeer ? + SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + /* When a user callback is installed to modify the SSL_CTX, + * we need to do the full initialization before calling it. + * See: #11800 */ + if(!ctx->x509_store_setup) { + result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx); + if(result) + goto out; + ctx->x509_store_setup = TRUE; + } + Curl_set_in_callback(data, true); + result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + goto out; + } + } + result = CURLE_OK; + +out: + if(result && ctx->ssl_ctx) { + SSL_CTX_free(ctx->ssl_ctx); + ctx->ssl_ctx = NULL; + } + return result; +} + +static CURLcode curl_ossl_set_client_cert(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + SSL_CTX *ssl_ctx = ctx->ssl_ctx; + const struct ssl_config_data *ssl_config; + + ssl_config = Curl_ssl_cf_get_config(cf, data); + DEBUGASSERT(ssl_config); + + if(ssl_config->primary.clientcert || + ssl_config->primary.cert_blob || + ssl_config->cert_type) { + return Curl_ossl_set_client_cert( + data, ssl_ctx, ssl_config->primary.clientcert, + ssl_config->primary.cert_blob, ssl_config->cert_type, + ssl_config->key, ssl_config->key_blob, + ssl_config->key_type, ssl_config->key_passwd); + } + + return CURLE_OK; +} + +/** SSL callbacks ***/ + +static CURLcode curl_ossl_init_ssl(struct quic_tls_ctx *ctx, + struct Curl_easy *data, + struct ssl_peer *peer, + const char *alpn, size_t alpn_len, + void *user_data) +{ + DEBUGASSERT(!ctx->ssl); + ctx->ssl = SSL_new(ctx->ssl_ctx); + + SSL_set_app_data(ctx->ssl, user_data); + SSL_set_connect_state(ctx->ssl); +#ifndef USE_OPENSSL_QUIC + SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0); +#endif + + if(alpn) + SSL_set_alpn_protos(ctx->ssl, (const uint8_t *)alpn, (int)alpn_len); + + if(peer->sni) { + if(!SSL_set_tlsext_host_name(ctx->ssl, peer->sni)) { + failf(data, "Failed set SNI"); + SSL_free(ctx->ssl); + ctx->ssl = NULL; + return CURLE_QUIC_CONNECT_ERROR; + } + } + return CURLE_OK; +} + +#elif defined(USE_GNUTLS) +static int keylog_callback(gnutls_session_t session, const char *label, + const gnutls_datum_t *secret) +{ + gnutls_datum_t crandom; + gnutls_datum_t srandom; + + gnutls_session_get_random(session, &crandom, &srandom); + if(crandom.size != 32) { + return -1; + } + + Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size); + return 0; +} + +static CURLcode curl_gtls_init_ctx(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer, + const char *alpn, size_t alpn_len, + Curl_vquic_tls_ctx_setup *ctx_setup, + void *user_data) +{ + struct ssl_primary_config *conn_config; + CURLcode result; + gnutls_datum_t alpns[5]; + /* this will need some attention when HTTPS proxy over QUIC get fixed */ + long * const pverifyresult = &data->set.ssl.certverifyresult; + int rc; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; + + DEBUGASSERT(ctx->gtls == NULL); + ctx->gtls = calloc(1, sizeof(*(ctx->gtls))); + if(!ctx->gtls) + return CURLE_OUT_OF_MEMORY; + + result = gtls_client_init(data, conn_config, &data->set.ssl, + peer, ctx->gtls, pverifyresult); + if(result) + return result; + + gnutls_session_set_ptr(ctx->gtls->session, user_data); + + if(ctx_setup) { + result = ctx_setup(ctx, cf, data); + if(result) + return result; + } + + rc = gnutls_priority_set_direct(ctx->gtls->session, QUIC_PRIORITY, NULL); + if(rc < 0) { + CURL_TRC_CF(data, cf, "gnutls_priority_set_direct failed: %s\n", + gnutls_strerror(rc)); + return CURLE_QUIC_CONNECT_ERROR; + } + + /* Open the file if a TLS or QUIC backend has not done this before. */ + Curl_tls_keylog_open(); + if(Curl_tls_keylog_enabled()) { + gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback); + } + + /* convert the ALPN string from our arguments to a list of strings + * that gnutls wants and will convert internally back to this very + * string for sending to the server. nice. */ + if(alpn) { + size_t i, alen = alpn_len; + unsigned char *s = (unsigned char *)alpn; + unsigned char slen; + for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) { + slen = s[0]; + if(slen >= alen) + return CURLE_FAILED_INIT; + alpns[i].data = s + 1; + alpns[i].size = slen; + s += slen + 1; + alen -= (size_t)slen + 1; + } + if(alen) /* not all alpn chars used, wrong format or too many */ + return CURLE_FAILED_INIT; + if(i) { + gnutls_alpn_set_protocols(ctx->gtls->session, + alpns, (unsigned int)i, + GNUTLS_ALPN_MANDATORY); + } + } + + return CURLE_OK; +} +#elif defined(USE_WOLFSSL) + +#if defined(HAVE_SECRET_CALLBACK) +static void keylog_callback(const WOLFSSL *ssl, const char *line) +{ + (void)ssl; + Curl_tls_keylog_write_line(line); +} +#endif + +static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + Curl_vquic_tls_ctx_setup *ctx_setup) +{ + struct ssl_primary_config *conn_config; + CURLcode result = CURLE_FAILED_INIT; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) { + result = CURLE_FAILED_INIT; + goto out; + } + + ctx->ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + if(!ctx->ssl_ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(ctx_setup) { + result = ctx_setup(ctx, cf, data); + if(result) + goto out; + } + + wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx); + + if(wolfSSL_CTX_set_cipher_list(ctx->ssl_ctx, conn_config->cipher_list13 ? + conn_config->cipher_list13 : + QUIC_CIPHERS) != 1) { + char error_buffer[256]; + ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); + failf(data, "wolfSSL failed to set ciphers: %s", error_buffer); + goto out; + } + + if(wolfSSL_CTX_set1_groups_list(ctx->ssl_ctx, conn_config->curves ? + conn_config->curves : + (char *)QUIC_GROUPS) != 1) { + failf(data, "wolfSSL failed to set curves"); + goto out; + } + + /* Open the file if a TLS or QUIC backend has not done this before. */ + Curl_tls_keylog_open(); + if(Curl_tls_keylog_enabled()) { +#if defined(HAVE_SECRET_CALLBACK) + wolfSSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback); +#else + failf(data, "wolfSSL was built without keylog callback"); + goto out; +#endif + } + + if(conn_config->verifypeer) { + const char * const ssl_cafile = conn_config->CAfile; + const char * const ssl_capath = conn_config->CApath; + + wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); + if(ssl_cafile || ssl_capath) { + /* tell wolfSSL where to find CA certificates that are used to verify + the server's certificate. */ + int rc = + wolfSSL_CTX_load_verify_locations_ex(ctx->ssl_ctx, ssl_cafile, + ssl_capath, + WOLFSSL_LOAD_FLAG_IGNORE_ERR); + if(SSL_SUCCESS != rc) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + goto out; + } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } +#ifdef CURL_CA_FALLBACK + else { + /* verifying the peer without any CA certificates won't work so + use wolfssl's built-in default as fallback */ + wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx); + } +#endif + } + else { + wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL); + } + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + Curl_set_in_callback(data, true); + result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + goto out; + } + } + result = CURLE_OK; + +out: + if(result && ctx->ssl_ctx) { + SSL_CTX_free(ctx->ssl_ctx); + ctx->ssl_ctx = NULL; + } + return result; +} + +/** SSL callbacks ***/ + +static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx, + struct Curl_easy *data, + struct ssl_peer *peer, + const char *alpn, size_t alpn_len, + void *user_data) +{ + (void)data; + DEBUGASSERT(!ctx->ssl); + DEBUGASSERT(ctx->ssl_ctx); + ctx->ssl = wolfSSL_new(ctx->ssl_ctx); + + wolfSSL_set_app_data(ctx->ssl, user_data); + wolfSSL_set_connect_state(ctx->ssl); + wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0); + + if(alpn) + wolfSSL_set_alpn_protos(ctx->ssl, (const unsigned char *)alpn, + (int)alpn_len); + + if(peer->sni) { + wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME, + peer->sni, (unsigned short)strlen(peer->sni)); + } + + return CURLE_OK; +} +#endif /* defined(USE_WOLFSSL) */ + +CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer, + const char *alpn, size_t alpn_len, + Curl_vquic_tls_ctx_setup *ctx_setup, + void *user_data) +{ + CURLcode result; + +#ifdef USE_OPENSSL + result = curl_ossl_init_ctx(ctx, cf, data, ctx_setup); + if(result) + return result; + + result = curl_ossl_set_client_cert(ctx, cf, data); + if(result) + return result; + + return curl_ossl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data); +#elif defined(USE_GNUTLS) + (void)result; + return curl_gtls_init_ctx(ctx, cf, data, peer, alpn, alpn_len, + ctx_setup, user_data); +#elif defined(USE_WOLFSSL) + result = curl_wssl_init_ctx(ctx, cf, data, ctx_setup); + if(result) + return result; + + return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data); +#else +#error "no TLS lib in used, should not happen" + return CURLE_FAILED_INIT; +#endif +} + +void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx) +{ +#ifdef USE_OPENSSL + if(ctx->ssl) + SSL_free(ctx->ssl); + if(ctx->ssl_ctx) + SSL_CTX_free(ctx->ssl_ctx); +#elif defined(USE_GNUTLS) + if(ctx->gtls) { + if(ctx->gtls->cred) + gnutls_certificate_free_credentials(ctx->gtls->cred); + if(ctx->gtls->session) + gnutls_deinit(ctx->gtls->session); + free(ctx->gtls); + } +#elif defined(USE_WOLFSSL) + if(ctx->ssl) + wolfSSL_free(ctx->ssl); + if(ctx->ssl_ctx) + wolfSSL_CTX_free(ctx->ssl_ctx); +#endif + memset(ctx, 0, sizeof(*ctx)); +} + +CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ +#ifdef USE_OPENSSL + if(!ctx->x509_store_setup) { + CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx); + if(result) + return result; + ctx->x509_store_setup = TRUE; + } +#else + (void)ctx; (void)cf; (void)data; +#endif + return CURLE_OK; +} + +CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer) +{ + struct ssl_primary_config *conn_config; + CURLcode result = CURLE_OK; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) + return CURLE_FAILED_INIT; + + if(conn_config->verifyhost) { +#ifdef USE_OPENSSL + X509 *server_cert; + server_cert = SSL_get1_peer_certificate(ctx->ssl); + if(!server_cert) { + return CURLE_PEER_FAILED_VERIFICATION; + } + result = Curl_ossl_verifyhost(data, cf->conn, peer, server_cert); + X509_free(server_cert); + if(result) + return result; +#elif defined(USE_GNUTLS) + result = Curl_gtls_verifyserver(data, ctx->gtls->session, + conn_config, &data->set.ssl, peer, + data->set.str[STRING_SSL_PINNEDPUBLICKEY]); + if(result) + return result; +#elif defined(USE_WOLFSSL) + if(!peer->sni || + wolfSSL_check_domain_name(ctx->ssl, peer->sni) == SSL_FAILURE) + return CURLE_PEER_FAILED_VERIFICATION; +#endif + infof(data, "Verified certificate just fine"); + } + else + infof(data, "Skipped certificate verification"); +#ifdef USE_OPENSSL + if(data->set.ssl.certinfo) + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, ctx->ssl); +#endif + return result; +} + + +#endif /* !ENABLE_QUIC && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */ diff --git a/lib/vquic/vquic-tls.h b/lib/vquic/vquic-tls.h new file mode 100644 index 0000000..9c0dfd8 --- /dev/null +++ b/lib/vquic/vquic-tls.h @@ -0,0 +1,98 @@ +#ifndef HEADER_CURL_VQUIC_TLS_H +#define HEADER_CURL_VQUIC_TLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "bufq.h" + +#if defined(ENABLE_QUIC) && \ + (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL)) + +struct quic_tls_ctx { +#ifdef USE_OPENSSL + SSL_CTX *ssl_ctx; + SSL *ssl; +#elif defined(USE_GNUTLS) + struct gtls_instance *gtls; +#elif defined(USE_WOLFSSL) + WOLFSSL_CTX *ssl_ctx; + WOLFSSL *ssl; +#endif + BIT(x509_store_setup); /* if x509 store has been set up */ +}; + +/** + * Callback passed to `Curl_vquic_tls_init()` that can + * do early initializations on the not otherwise configured TLS + * instances created. This varies by TLS backend: + * - openssl/wolfssl: SSL_CTX* has just been created + * - gnutls: gtls_client_init() has run + */ +typedef CURLcode Curl_vquic_tls_ctx_setup(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data); + +/** + * Initialize the QUIC TLS instances based of the SSL configurations + * for the connection filter, transfer and peer. + * @param ctx the TLS context to initialize + * @param cf the connection filter involved + * @param data the transfer involved + * @param peer the peer that will be connected to + * @param alpn the ALPN string in protocol format ((len+bytes+)+), + * may be NULL + * @param alpn_len the overall number of bytes in `alpn` + * @param ctx_setup optional callback for very early TLS config + * @param user_data optional pointer to set in TLS application context + */ +CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer, + const char *alpn, size_t alpn_len, + Curl_vquic_tls_ctx_setup *ctx_setup, + void *user_data); + +/** + * Cleanup all data that has been initialized. + */ +void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx); + +CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data); + +/** + * After the QUIC basic handshake has been, verify that the peer + * (and its certificate) fulfill our requirements. + */ +CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer); + +#endif /* !ENABLE_QUIC && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */ + +#endif /* HEADER_CURL_VQUIC_TLS_H */ diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c new file mode 100644 index 0000000..612d25b --- /dev/null +++ b/lib/vquic/vquic.c @@ -0,0 +1,683 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* WIP, experimental: use recvmmsg() on linux + * we have no configure check, yet + * and also it is only available for _GNU_SOURCE, which + * we do not use otherwise. +#define HAVE_SENDMMSG + */ +#if defined(HAVE_SENDMMSG) +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#endif + +#include "curl_setup.h" + +#ifdef HAVE_FCNTL_H +#include +#endif +#include "urldata.h" +#include "bufq.h" +#include "dynbuf.h" +#include "cfilters.h" +#include "curl_trc.h" +#include "curl_msh3.h" +#include "curl_ngtcp2.h" +#include "curl_osslq.h" +#include "curl_quiche.h" +#include "rand.h" +#include "vquic.h" +#include "vquic_int.h" +#include "strerror.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +#ifdef ENABLE_QUIC + +#ifdef O_BINARY +#define QLOGMODE O_WRONLY|O_CREAT|O_BINARY +#else +#define QLOGMODE O_WRONLY|O_CREAT +#endif + +#define NW_CHUNK_SIZE (64 * 1024) +#define NW_SEND_CHUNKS 2 + + +void Curl_quic_ver(char *p, size_t len) +{ +#if defined(USE_NGTCP2) && defined(USE_NGHTTP3) + Curl_ngtcp2_ver(p, len); +#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + Curl_osslq_ver(p, len); +#elif defined(USE_QUICHE) + Curl_quiche_ver(p, len); +#elif defined(USE_MSH3) + Curl_msh3_ver(p, len); +#endif +} + +CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx) +{ + Curl_bufq_init2(&qctx->sendbuf, NW_CHUNK_SIZE, NW_SEND_CHUNKS, + BUFQ_OPT_SOFT_LIMIT); +#if defined(__linux__) && defined(UDP_SEGMENT) && defined(HAVE_SENDMSG) + qctx->no_gso = FALSE; +#else + qctx->no_gso = TRUE; +#endif +#ifdef DEBUGBUILD + { + char *p = getenv("CURL_DBG_QUIC_WBLOCK"); + if(p) { + long l = strtol(p, NULL, 10); + if(l >= 0 && l <= 100) + qctx->wblock_percent = (int)l; + } + } +#endif + vquic_ctx_update_time(qctx); + + return CURLE_OK; +} + +void vquic_ctx_free(struct cf_quic_ctx *qctx) +{ + Curl_bufq_free(&qctx->sendbuf); +} + +void vquic_ctx_update_time(struct cf_quic_ctx *qctx) +{ + qctx->last_op = Curl_now(); +} + +static CURLcode send_packet_no_gso(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + const uint8_t *pkt, size_t pktlen, + size_t gsolen, size_t *psent); + +static CURLcode do_sendmsg(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + const uint8_t *pkt, size_t pktlen, size_t gsolen, + size_t *psent) +{ +#ifdef HAVE_SENDMSG + struct iovec msg_iov; + struct msghdr msg = {0}; + ssize_t sent; +#if defined(__linux__) && defined(UDP_SEGMENT) + uint8_t msg_ctrl[32]; + struct cmsghdr *cm; +#endif + + *psent = 0; + msg_iov.iov_base = (uint8_t *)pkt; + msg_iov.iov_len = pktlen; + msg.msg_iov = &msg_iov; + msg.msg_iovlen = 1; + +#if defined(__linux__) && defined(UDP_SEGMENT) + if(pktlen > gsolen) { + /* Only set this, when we need it. macOS, for example, + * does not seem to like a msg_control of length 0. */ + msg.msg_control = msg_ctrl; + assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(uint16_t))); + msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); + cm = CMSG_FIRSTHDR(&msg); + cm->cmsg_level = SOL_UDP; + cm->cmsg_type = UDP_SEGMENT; + cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); + *(uint16_t *)(void *)CMSG_DATA(cm) = gsolen & 0xffff; + } +#endif + + + while((sent = sendmsg(qctx->sockfd, &msg, 0)) == -1 && SOCKERRNO == EINTR) + ; + + if(sent == -1) { + switch(SOCKERRNO) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + return CURLE_AGAIN; + case EMSGSIZE: + /* UDP datagram is too large; caused by PMTUD. Just let it be lost. */ + break; + case EIO: + if(pktlen > gsolen) { + /* GSO failure */ + failf(data, "sendmsg() returned %zd (errno %d); disable GSO", sent, + SOCKERRNO); + qctx->no_gso = TRUE; + return send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent); + } + FALLTHROUGH(); + default: + failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO); + return CURLE_SEND_ERROR; + } + } + else { + assert(pktlen == (size_t)sent); + } +#else + ssize_t sent; + (void)gsolen; + + *psent = 0; + + while((sent = send(qctx->sockfd, + (const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 && + SOCKERRNO == EINTR) + ; + + if(sent == -1) { + if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { + return CURLE_AGAIN; + } + else { + failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO); + if(SOCKERRNO != EMSGSIZE) { + return CURLE_SEND_ERROR; + } + /* UDP datagram is too large; caused by PMTUD. Just let it be + lost. */ + } + } +#endif + (void)cf; + *psent = pktlen; + + return CURLE_OK; +} + +static CURLcode send_packet_no_gso(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + const uint8_t *pkt, size_t pktlen, + size_t gsolen, size_t *psent) +{ + const uint8_t *p, *end = pkt + pktlen; + size_t sent; + + *psent = 0; + + for(p = pkt; p < end; p += gsolen) { + size_t len = CURLMIN(gsolen, (size_t)(end - p)); + CURLcode curlcode = do_sendmsg(cf, data, qctx, p, len, len, &sent); + if(curlcode != CURLE_OK) { + return curlcode; + } + *psent += sent; + } + + return CURLE_OK; +} + +static CURLcode vquic_send_packets(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + const uint8_t *pkt, size_t pktlen, + size_t gsolen, size_t *psent) +{ + CURLcode result; +#ifdef DEBUGBUILD + /* simulate network blocking/partial writes */ + if(qctx->wblock_percent > 0) { + unsigned char c; + Curl_rand(data, &c, 1); + if(c >= ((100-qctx->wblock_percent)*256/100)) { + CURL_TRC_CF(data, cf, "vquic_flush() simulate EWOULDBLOCK"); + return CURLE_AGAIN; + } + } +#endif + if(qctx->no_gso && pktlen > gsolen) { + result = send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent); + } + else { + result = do_sendmsg(cf, data, qctx, pkt, pktlen, gsolen, psent); + } + if(!result) + qctx->last_io = qctx->last_op; + return result; +} + +CURLcode vquic_flush(struct Curl_cfilter *cf, struct Curl_easy *data, + struct cf_quic_ctx *qctx) +{ + const unsigned char *buf; + size_t blen, sent; + CURLcode result; + size_t gsolen; + + while(Curl_bufq_peek(&qctx->sendbuf, &buf, &blen)) { + gsolen = qctx->gsolen; + if(qctx->split_len) { + gsolen = qctx->split_gsolen; + if(blen > qctx->split_len) + blen = qctx->split_len; + } + + result = vquic_send_packets(cf, data, qctx, buf, blen, gsolen, &sent); + CURL_TRC_CF(data, cf, "vquic_send(len=%zu, gso=%zu) -> %d, sent=%zu", + blen, gsolen, result, sent); + if(result) { + if(result == CURLE_AGAIN) { + Curl_bufq_skip(&qctx->sendbuf, sent); + if(qctx->split_len) + qctx->split_len -= sent; + } + return result; + } + Curl_bufq_skip(&qctx->sendbuf, sent); + if(qctx->split_len) + qctx->split_len -= sent; + } + return CURLE_OK; +} + +CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data, + struct cf_quic_ctx *qctx, size_t gsolen) +{ + qctx->gsolen = gsolen; + return vquic_flush(cf, data, qctx); +} + +CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data, + struct cf_quic_ctx *qctx, size_t gsolen, + size_t tail_len, size_t tail_gsolen) +{ + DEBUGASSERT(Curl_bufq_len(&qctx->sendbuf) > tail_len); + qctx->split_len = Curl_bufq_len(&qctx->sendbuf) - tail_len; + qctx->split_gsolen = gsolen; + qctx->gsolen = tail_gsolen; + CURL_TRC_CF(data, cf, "vquic_send_tail_split: [%zu gso=%zu][%zu gso=%zu]", + qctx->split_len, qctx->split_gsolen, + tail_len, qctx->gsolen); + return vquic_flush(cf, data, qctx); +} + +#ifdef HAVE_SENDMMSG +static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + size_t max_pkts, + vquic_recv_pkt_cb *recv_cb, void *userp) +{ +#define MMSG_NUM 64 + struct iovec msg_iov[MMSG_NUM]; + struct mmsghdr mmsg[MMSG_NUM]; + uint8_t bufs[MMSG_NUM][2*1024]; + struct sockaddr_storage remote_addr[MMSG_NUM]; + size_t total_nread, pkts; + int mcount, i, n; + char errstr[STRERROR_LEN]; + CURLcode result = CURLE_OK; + + DEBUGASSERT(max_pkts > 0); + pkts = 0; + total_nread = 0; + while(pkts < max_pkts) { + n = (int)CURLMIN(MMSG_NUM, max_pkts); + memset(&mmsg, 0, sizeof(mmsg)); + for(i = 0; i < n; ++i) { + msg_iov[i].iov_base = bufs[i]; + msg_iov[i].iov_len = (int)sizeof(bufs[i]); + mmsg[i].msg_hdr.msg_iov = &msg_iov[i]; + mmsg[i].msg_hdr.msg_iovlen = 1; + mmsg[i].msg_hdr.msg_name = &remote_addr[i]; + mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]); + } + + while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 && + SOCKERRNO == EINTR) + ; + if(mcount == -1) { + if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { + CURL_TRC_CF(data, cf, "ingress, recvmmsg -> EAGAIN"); + goto out; + } + if(!cf->connected && SOCKERRNO == ECONNREFUSED) { + const char *r_ip = NULL; + int r_port = 0; + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + failf(data, "QUIC: connection to %s port %u refused", + r_ip, r_port); + result = CURLE_COULDNT_CONNECT; + goto out; + } + Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); + failf(data, "QUIC: recvmsg() unexpectedly returned %d (errno=%d; %s)", + mcount, SOCKERRNO, errstr); + result = CURLE_RECV_ERROR; + goto out; + } + + CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount); + pkts += mcount; + for(i = 0; i < mcount; ++i) { + total_nread += mmsg[i].msg_len; + result = recv_cb(bufs[i], mmsg[i].msg_len, + mmsg[i].msg_hdr.msg_name, mmsg[i].msg_hdr.msg_namelen, + 0, userp); + if(result) + goto out; + } + } + +out: + if(total_nread || result) + CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", + pkts, total_nread, result); + return result; +} + +#elif defined(HAVE_SENDMSG) +static CURLcode recvmsg_packets(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + size_t max_pkts, + vquic_recv_pkt_cb *recv_cb, void *userp) +{ + struct iovec msg_iov; + struct msghdr msg; + uint8_t buf[64*1024]; + struct sockaddr_storage remote_addr; + size_t total_nread, pkts; + ssize_t nread; + char errstr[STRERROR_LEN]; + CURLcode result = CURLE_OK; + + msg_iov.iov_base = buf; + msg_iov.iov_len = (int)sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &msg_iov; + msg.msg_iovlen = 1; + + DEBUGASSERT(max_pkts > 0); + for(pkts = 0, total_nread = 0; pkts < max_pkts;) { + msg.msg_name = &remote_addr; + msg.msg_namelen = sizeof(remote_addr); + while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 && + SOCKERRNO == EINTR) + ; + if(nread == -1) { + if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { + goto out; + } + if(!cf->connected && SOCKERRNO == ECONNREFUSED) { + const char *r_ip = NULL; + int r_port = 0; + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + failf(data, "QUIC: connection to %s port %u refused", + r_ip, r_port); + result = CURLE_COULDNT_CONNECT; + goto out; + } + Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); + failf(data, "QUIC: recvmsg() unexpectedly returned %zd (errno=%d; %s)", + nread, SOCKERRNO, errstr); + result = CURLE_RECV_ERROR; + goto out; + } + + ++pkts; + total_nread += (size_t)nread; + result = recv_cb(buf, (size_t)nread, msg.msg_name, msg.msg_namelen, + 0, userp); + if(result) + goto out; + } + +out: + if(total_nread || result) + CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", + pkts, total_nread, result); + return result; +} + +#else /* HAVE_SENDMMSG || HAVE_SENDMSG */ +static CURLcode recvfrom_packets(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + size_t max_pkts, + vquic_recv_pkt_cb *recv_cb, void *userp) +{ + uint8_t buf[64*1024]; + int bufsize = (int)sizeof(buf); + struct sockaddr_storage remote_addr; + socklen_t remote_addrlen = sizeof(remote_addr); + size_t total_nread, pkts; + ssize_t nread; + char errstr[STRERROR_LEN]; + CURLcode result = CURLE_OK; + + DEBUGASSERT(max_pkts > 0); + for(pkts = 0, total_nread = 0; pkts < max_pkts;) { + while((nread = recvfrom(qctx->sockfd, (char *)buf, bufsize, 0, + (struct sockaddr *)&remote_addr, + &remote_addrlen)) == -1 && + SOCKERRNO == EINTR) + ; + if(nread == -1) { + if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { + CURL_TRC_CF(data, cf, "ingress, recvfrom -> EAGAIN"); + goto out; + } + if(!cf->connected && SOCKERRNO == ECONNREFUSED) { + const char *r_ip = NULL; + int r_port = 0; + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + failf(data, "QUIC: connection to %s port %u refused", + r_ip, r_port); + result = CURLE_COULDNT_CONNECT; + goto out; + } + Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); + failf(data, "QUIC: recvfrom() unexpectedly returned %zd (errno=%d; %s)", + nread, SOCKERRNO, errstr); + result = CURLE_RECV_ERROR; + goto out; + } + + ++pkts; + total_nread += (size_t)nread; + result = recv_cb(buf, (size_t)nread, &remote_addr, remote_addrlen, + 0, userp); + if(result) + goto out; + } + +out: + if(total_nread || result) + CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", + pkts, total_nread, result); + return result; +} +#endif /* !HAVE_SENDMMSG && !HAVE_SENDMSG */ + +CURLcode vquic_recv_packets(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + size_t max_pkts, + vquic_recv_pkt_cb *recv_cb, void *userp) +{ + CURLcode result; +#if defined(HAVE_SENDMMSG) + result = recvmmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp); +#elif defined(HAVE_SENDMSG) + result = recvmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp); +#else + result = recvfrom_packets(cf, data, qctx, max_pkts, recv_cb, userp); +#endif + if(!result) { + if(!qctx->got_first_byte) { + qctx->got_first_byte = TRUE; + qctx->first_byte_at = qctx->last_op; + } + qctx->last_io = qctx->last_op; + } + return result; +} + +/* + * If the QLOGDIR environment variable is set, open and return a file + * descriptor to write the log to. + * + * This function returns error if something failed outside of failing to + * create the file. Open file success is deemed by seeing if the returned fd + * is != -1. + */ +CURLcode Curl_qlogdir(struct Curl_easy *data, + unsigned char *scid, + size_t scidlen, + int *qlogfdp) +{ + const char *qlog_dir = getenv("QLOGDIR"); + *qlogfdp = -1; + if(qlog_dir) { + struct dynbuf fname; + CURLcode result; + unsigned int i; + Curl_dyn_init(&fname, DYN_QLOG_NAME); + result = Curl_dyn_add(&fname, qlog_dir); + if(!result) + result = Curl_dyn_add(&fname, "/"); + for(i = 0; (i < scidlen) && !result; i++) { + char hex[3]; + msnprintf(hex, 3, "%02x", scid[i]); + result = Curl_dyn_add(&fname, hex); + } + if(!result) + result = Curl_dyn_add(&fname, ".sqlog"); + + if(!result) { + int qlogfd = open(Curl_dyn_ptr(&fname), QLOGMODE, + data->set.new_file_perms); + if(qlogfd != -1) + *qlogfdp = qlogfd; + } + Curl_dyn_free(&fname); + if(result) + return result; + } + + return CURLE_OK; +} + +CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport) +{ + (void)transport; + DEBUGASSERT(transport == TRNSPRT_QUIC); +#if defined(USE_NGTCP2) && defined(USE_NGHTTP3) + return Curl_cf_ngtcp2_create(pcf, data, conn, ai); +#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + return Curl_cf_osslq_create(pcf, data, conn, ai); +#elif defined(USE_QUICHE) + return Curl_cf_quiche_create(pcf, data, conn, ai); +#elif defined(USE_MSH3) + return Curl_cf_msh3_create(pcf, data, conn, ai); +#else + *pcf = NULL; + (void)data; + (void)conn; + (void)ai; + return CURLE_NOT_BUILT_IN; +#endif +} + +bool Curl_conn_is_http3(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex) +{ +#if defined(USE_NGTCP2) && defined(USE_NGHTTP3) + return Curl_conn_is_ngtcp2(data, conn, sockindex); +#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + return Curl_conn_is_osslq(data, conn, sockindex); +#elif defined(USE_QUICHE) + return Curl_conn_is_quiche(data, conn, sockindex); +#elif defined(USE_MSH3) + return Curl_conn_is_msh3(data, conn, sockindex); +#else + return ((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (conn->httpversion == 30)); +#endif +} + +CURLcode Curl_conn_may_http3(struct Curl_easy *data, + const struct connectdata *conn) +{ + if(conn->transport == TRNSPRT_UNIX) { + /* cannot do QUIC over a unix domain socket */ + return CURLE_QUIC_CONNECT_ERROR; + } + if(!(conn->handler->flags & PROTOPT_SSL)) { + failf(data, "HTTP/3 requested for non-HTTPS URL"); + return CURLE_URL_MALFORMAT; + } +#ifndef CURL_DISABLE_PROXY + if(conn->bits.socksproxy) { + failf(data, "HTTP/3 is not supported over a SOCKS proxy"); + return CURLE_URL_MALFORMAT; + } + if(conn->bits.httpproxy && conn->bits.tunnel_proxy) { + failf(data, "HTTP/3 is not supported over a HTTP proxy"); + return CURLE_URL_MALFORMAT; + } +#endif + + return CURLE_OK; +} + +#else /* ENABLE_QUIC */ + +CURLcode Curl_conn_may_http3(struct Curl_easy *data, + const struct connectdata *conn) +{ + (void)conn; + (void)data; + DEBUGF(infof(data, "QUIC is not supported in this build")); + return CURLE_NOT_BUILT_IN; +} + +#endif /* !ENABLE_QUIC */ diff --git a/lib/vquic/vquic.h b/lib/vquic/vquic.h new file mode 100644 index 0000000..dc73957 --- /dev/null +++ b/lib/vquic/vquic.h @@ -0,0 +1,64 @@ +#ifndef HEADER_CURL_VQUIC_QUIC_H +#define HEADER_CURL_VQUIC_QUIC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef ENABLE_QUIC +struct Curl_cfilter; +struct Curl_easy; +struct connectdata; +struct Curl_addrinfo; + +void Curl_quic_ver(char *p, size_t len); + +CURLcode Curl_qlogdir(struct Curl_easy *data, + unsigned char *scid, + size_t scidlen, + int *qlogfdp); + + +CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport); + +bool Curl_conn_is_http3(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex); + +extern struct Curl_cftype Curl_cft_http3; + +#else /* ENABLE_QUIC */ + +#define Curl_conn_is_http3(a,b,c) FALSE + +#endif /* !ENABLE_QUIC */ + +CURLcode Curl_conn_may_http3(struct Curl_easy *data, + const struct connectdata *conn); + +#endif /* HEADER_CURL_VQUIC_QUIC_H */ diff --git a/lib/vquic/vquic_int.h b/lib/vquic/vquic_int.h new file mode 100644 index 0000000..c218a94 --- /dev/null +++ b/lib/vquic/vquic_int.h @@ -0,0 +1,93 @@ +#ifndef HEADER_CURL_VQUIC_QUIC_INT_H +#define HEADER_CURL_VQUIC_QUIC_INT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "bufq.h" + +#ifdef ENABLE_QUIC + +#define MAX_PKT_BURST 10 +#define MAX_UDP_PAYLOAD_SIZE 1452 +/* Default QUIC connection timeout we announce from our side */ +#define CURL_QUIC_MAX_IDLE_MS (120 * 1000) + +struct cf_quic_ctx { + curl_socket_t sockfd; /* connected UDP socket */ + struct sockaddr_storage local_addr; /* address socket is bound to */ + socklen_t local_addrlen; /* length of local address */ + + struct bufq sendbuf; /* buffer for sending one or more packets */ + struct curltime first_byte_at; /* when first byte was recvd */ + struct curltime last_op; /* last (attempted) send/recv operation */ + struct curltime last_io; /* last successful socket IO */ + size_t gsolen; /* length of individual packets in send buf */ + size_t split_len; /* if != 0, buffer length after which GSO differs */ + size_t split_gsolen; /* length of individual packets after split_len */ +#ifdef DEBUGBUILD + int wblock_percent; /* percent of writes doing EAGAIN */ +#endif + BIT(got_first_byte); /* if first byte was received */ + BIT(no_gso); /* do not use gso on sending */ +}; + +CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx); +void vquic_ctx_free(struct cf_quic_ctx *qctx); + +void vquic_ctx_update_time(struct cf_quic_ctx *qctx); + +void vquic_push_blocked_pkt(struct Curl_cfilter *cf, + struct cf_quic_ctx *qctx, + const uint8_t *pkt, size_t pktlen, size_t gsolen); + +CURLcode vquic_send_blocked_pkts(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx); + +CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data, + struct cf_quic_ctx *qctx, size_t gsolen); + +CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data, + struct cf_quic_ctx *qctx, size_t gsolen, + size_t tail_len, size_t tail_gsolen); + +CURLcode vquic_flush(struct Curl_cfilter *cf, struct Curl_easy *data, + struct cf_quic_ctx *qctx); + + +typedef CURLcode vquic_recv_pkt_cb(const unsigned char *pkt, size_t pktlen, + struct sockaddr_storage *remote_addr, + socklen_t remote_addrlen, int ecn, + void *userp); + +CURLcode vquic_recv_packets(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_quic_ctx *qctx, + size_t max_pkts, + vquic_recv_pkt_cb *recv_cb, void *userp); + +#endif /* !ENABLE_QUIC */ + +#endif /* HEADER_CURL_VQUIC_QUIC_INT_H */ diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c new file mode 100644 index 0000000..c6dc63a --- /dev/null +++ b/lib/vssh/libssh.c @@ -0,0 +1,2950 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Red Hat, Inc. + * + * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek, + * Robert Kolcun, Andreas Schneider + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_LIBSSH + +#include + +/* in 0.10.0 or later, ignore deprecated warnings */ +#define SSH_SUPPRESS_DEPRECATED +#include +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "ssh.h" +#include "url.h" +#include "speedcheck.h" +#include "getinfo.h" +#include "strdup.h" +#include "strcase.h" +#include "vtls/vtls.h" +#include "cfilters.h" +#include "connect.h" +#include "inet_ntop.h" +#include "parsedate.h" /* for the week day and month names */ +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "strtoofft.h" +#include "multiif.h" +#include "select.h" +#include "warnless.h" +#include "curl_path.h" + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* A recent macro provided by libssh. Or make our own. */ +#ifndef SSH_STRING_FREE_CHAR +#define SSH_STRING_FREE_CHAR(x) \ + do { \ + if(x) { \ + ssh_string_free_char(x); \ + x = NULL; \ + } \ + } while(0) +#endif + +/* These stat values may not be the same as the user's S_IFMT / S_IFLNK */ +#ifndef SSH_S_IFMT +#define SSH_S_IFMT 00170000 +#endif +#ifndef SSH_S_IFLNK +#define SSH_S_IFLNK 0120000 +#endif + +/* Local functions: */ +static CURLcode myssh_connect(struct Curl_easy *data, bool *done); +static CURLcode myssh_multi_statemach(struct Curl_easy *data, + bool *done); +static CURLcode myssh_do_it(struct Curl_easy *data, bool *done); + +static CURLcode scp_done(struct Curl_easy *data, + CURLcode, bool premature); +static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done); +static CURLcode scp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection); + +static CURLcode sftp_done(struct Curl_easy *data, + CURLcode, bool premature); +static CURLcode sftp_doing(struct Curl_easy *data, + bool *dophase_done); +static CURLcode sftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead); +static +CURLcode sftp_perform(struct Curl_easy *data, + bool *connected, + bool *dophase_done); + +static void sftp_quote(struct Curl_easy *data); +static void sftp_quote_stat(struct Curl_easy *data); +static int myssh_getsock(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t *sock); + +static CURLcode myssh_setup_connection(struct Curl_easy *data, + struct connectdata *conn); + +/* + * SCP protocol handler. + */ + +const struct Curl_handler Curl_handler_scp = { + "SCP", /* scheme */ + myssh_setup_connection, /* setup_connection */ + myssh_do_it, /* do_it */ + scp_done, /* done */ + ZERO_NULL, /* do_more */ + myssh_connect, /* connect_it */ + myssh_multi_statemach, /* connecting */ + scp_doing, /* doing */ + myssh_getsock, /* proto_getsock */ + myssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + myssh_getsock, /* perform_getsock */ + scp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SSH, /* defport */ + CURLPROTO_SCP, /* protocol */ + CURLPROTO_SCP, /* family */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ +}; + +/* + * SFTP protocol handler. + */ + +const struct Curl_handler Curl_handler_sftp = { + "SFTP", /* scheme */ + myssh_setup_connection, /* setup_connection */ + myssh_do_it, /* do_it */ + sftp_done, /* done */ + ZERO_NULL, /* do_more */ + myssh_connect, /* connect_it */ + myssh_multi_statemach, /* connecting */ + sftp_doing, /* doing */ + myssh_getsock, /* proto_getsock */ + myssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + myssh_getsock, /* perform_getsock */ + sftp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SSH, /* defport */ + CURLPROTO_SFTP, /* protocol */ + CURLPROTO_SFTP, /* family */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ +}; + +static CURLcode sftp_error_to_CURLE(int err) +{ + switch(err) { + case SSH_FX_OK: + return CURLE_OK; + + case SSH_FX_NO_SUCH_FILE: + case SSH_FX_NO_SUCH_PATH: + return CURLE_REMOTE_FILE_NOT_FOUND; + + case SSH_FX_PERMISSION_DENIED: + case SSH_FX_WRITE_PROTECT: + return CURLE_REMOTE_ACCESS_DENIED; + + case SSH_FX_FILE_ALREADY_EXISTS: + return CURLE_REMOTE_FILE_EXISTS; + + default: + break; + } + + return CURLE_SSH; +} + +#ifndef DEBUGBUILD +#define state(x,y) mystate(x,y) +#else +#define state(x,y) mystate(x,y, __LINE__) +#endif + +/* + * SSH State machine related code + */ +/* This is the ONLY way to change SSH state! */ +static void mystate(struct Curl_easy *data, sshstate nowstate +#ifdef DEBUGBUILD + , int lineno +#endif + ) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char *const names[] = { + "SSH_STOP", + "SSH_INIT", + "SSH_S_STARTUP", + "SSH_HOSTKEY", + "SSH_AUTHLIST", + "SSH_AUTH_PKEY_INIT", + "SSH_AUTH_PKEY", + "SSH_AUTH_PASS_INIT", + "SSH_AUTH_PASS", + "SSH_AUTH_AGENT_INIT", + "SSH_AUTH_AGENT_LIST", + "SSH_AUTH_AGENT", + "SSH_AUTH_HOST_INIT", + "SSH_AUTH_HOST", + "SSH_AUTH_KEY_INIT", + "SSH_AUTH_KEY", + "SSH_AUTH_GSSAPI", + "SSH_AUTH_DONE", + "SSH_SFTP_INIT", + "SSH_SFTP_REALPATH", + "SSH_SFTP_QUOTE_INIT", + "SSH_SFTP_POSTQUOTE_INIT", + "SSH_SFTP_QUOTE", + "SSH_SFTP_NEXT_QUOTE", + "SSH_SFTP_QUOTE_STAT", + "SSH_SFTP_QUOTE_SETSTAT", + "SSH_SFTP_QUOTE_SYMLINK", + "SSH_SFTP_QUOTE_MKDIR", + "SSH_SFTP_QUOTE_RENAME", + "SSH_SFTP_QUOTE_RMDIR", + "SSH_SFTP_QUOTE_UNLINK", + "SSH_SFTP_QUOTE_STATVFS", + "SSH_SFTP_GETINFO", + "SSH_SFTP_FILETIME", + "SSH_SFTP_TRANS_INIT", + "SSH_SFTP_UPLOAD_INIT", + "SSH_SFTP_CREATE_DIRS_INIT", + "SSH_SFTP_CREATE_DIRS", + "SSH_SFTP_CREATE_DIRS_MKDIR", + "SSH_SFTP_READDIR_INIT", + "SSH_SFTP_READDIR", + "SSH_SFTP_READDIR_LINK", + "SSH_SFTP_READDIR_BOTTOM", + "SSH_SFTP_READDIR_DONE", + "SSH_SFTP_DOWNLOAD_INIT", + "SSH_SFTP_DOWNLOAD_STAT", + "SSH_SFTP_CLOSE", + "SSH_SFTP_SHUTDOWN", + "SSH_SCP_TRANS_INIT", + "SSH_SCP_UPLOAD_INIT", + "SSH_SCP_DOWNLOAD_INIT", + "SSH_SCP_DOWNLOAD", + "SSH_SCP_DONE", + "SSH_SCP_SEND_EOF", + "SSH_SCP_WAIT_EOF", + "SSH_SCP_WAIT_CLOSE", + "SSH_SCP_CHANNEL_FREE", + "SSH_SESSION_DISCONNECT", + "SSH_SESSION_FREE", + "QUIT" + }; + + + if(sshc->state != nowstate) { + infof(data, "SSH %p state change from %s to %s (line %d)", + (void *) sshc, names[sshc->state], names[nowstate], + lineno); + } +#endif + + sshc->state = nowstate; +} + +/* Multiple options: + * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5 + * hash (90s style auth, not sure we should have it here) + * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first + * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE + * is returned by it. + * 3. none of the above. We only accept if it is present on known hosts. + * + * Returns SSH_OK or SSH_ERROR. + */ +static int myssh_is_known(struct Curl_easy *data) +{ + int rc; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + ssh_key pubkey; + size_t hlen; + unsigned char *hash = NULL; + char *found_base64 = NULL; + char *known_base64 = NULL; + int vstate; + enum curl_khmatch keymatch; + struct curl_khkey foundkey; + struct curl_khkey *knownkeyp = NULL; + curl_sshkeycallback func = + data->set.ssh_keyfunc; + +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + struct ssh_knownhosts_entry *knownhostsentry = NULL; + struct curl_khkey knownkey; +#endif + +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0) + rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey); +#else + rc = ssh_get_publickey(sshc->ssh_session, &pubkey); +#endif + if(rc != SSH_OK) + return rc; + + if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { + int i; + char md5buffer[33]; + const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; + + rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, + &hash, &hlen); + if(rc != SSH_OK || hlen != 16) { + failf(data, + "Denied establishing ssh session: md5 fingerprint not available"); + goto cleanup; + } + + for(i = 0; i < 16; i++) + msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]); + + infof(data, "SSH MD5 fingerprint: %s", md5buffer); + + if(!strcasecompare(md5buffer, pubkey_md5)) { + failf(data, + "Denied establishing ssh session: mismatch md5 fingerprint. " + "Remote %s is not equal to %s", md5buffer, pubkey_md5); + rc = SSH_ERROR; + goto cleanup; + } + + rc = SSH_OK; + goto cleanup; + } + + if(data->set.ssl.primary.verifyhost != TRUE) { + rc = SSH_OK; + goto cleanup; + } + +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + /* Get the known_key from the known hosts file */ + vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session, + &knownhostsentry); + + /* Case an entry was found in a known hosts file */ + if(knownhostsentry) { + if(knownhostsentry->publickey) { + rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey, + &known_base64); + if(rc != SSH_OK) { + goto cleanup; + } + knownkey.key = known_base64; + knownkey.len = strlen(known_base64); + + switch(ssh_key_type(knownhostsentry->publickey)) { + case SSH_KEYTYPE_RSA: + knownkey.keytype = CURLKHTYPE_RSA; + break; + case SSH_KEYTYPE_RSA1: + knownkey.keytype = CURLKHTYPE_RSA1; + break; + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P521: + knownkey.keytype = CURLKHTYPE_ECDSA; + break; + case SSH_KEYTYPE_ED25519: + knownkey.keytype = CURLKHTYPE_ED25519; + break; + case SSH_KEYTYPE_DSS: + knownkey.keytype = CURLKHTYPE_DSS; + break; + default: + rc = SSH_ERROR; + goto cleanup; + } + knownkeyp = &knownkey; + } + } + + switch(vstate) { + case SSH_KNOWN_HOSTS_OK: + keymatch = CURLKHMATCH_OK; + break; + case SSH_KNOWN_HOSTS_OTHER: + case SSH_KNOWN_HOSTS_NOT_FOUND: + case SSH_KNOWN_HOSTS_UNKNOWN: + case SSH_KNOWN_HOSTS_ERROR: + keymatch = CURLKHMATCH_MISSING; + break; + default: + keymatch = CURLKHMATCH_MISMATCH; + break; + } + +#else + vstate = ssh_is_server_known(sshc->ssh_session); + switch(vstate) { + case SSH_SERVER_KNOWN_OK: + keymatch = CURLKHMATCH_OK; + break; + case SSH_SERVER_FILE_NOT_FOUND: + case SSH_SERVER_NOT_KNOWN: + keymatch = CURLKHMATCH_MISSING; + break; + default: + keymatch = CURLKHMATCH_MISMATCH; + break; + } +#endif + + if(func) { /* use callback to determine action */ + rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64); + if(rc != SSH_OK) + goto cleanup; + + foundkey.key = found_base64; + foundkey.len = strlen(found_base64); + + switch(ssh_key_type(pubkey)) { + case SSH_KEYTYPE_RSA: + foundkey.keytype = CURLKHTYPE_RSA; + break; + case SSH_KEYTYPE_RSA1: + foundkey.keytype = CURLKHTYPE_RSA1; + break; + case SSH_KEYTYPE_ECDSA: +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P521: +#endif + foundkey.keytype = CURLKHTYPE_ECDSA; + break; +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0) + case SSH_KEYTYPE_ED25519: + foundkey.keytype = CURLKHTYPE_ED25519; + break; +#endif + case SSH_KEYTYPE_DSS: + foundkey.keytype = CURLKHTYPE_DSS; + break; + default: + rc = SSH_ERROR; + goto cleanup; + } + + Curl_set_in_callback(data, true); + rc = func(data, knownkeyp, /* from the knownhosts file */ + &foundkey, /* from the remote host */ + keymatch, data->set.ssh_keyfunc_userp); + Curl_set_in_callback(data, false); + + switch(rc) { + case CURLKHSTAT_FINE_ADD_TO_FILE: +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0) + rc = ssh_session_update_known_hosts(sshc->ssh_session); +#else + rc = ssh_write_knownhost(sshc->ssh_session); +#endif + if(rc != SSH_OK) { + goto cleanup; + } + break; + case CURLKHSTAT_FINE: + break; + default: /* REJECT/DEFER */ + rc = SSH_ERROR; + goto cleanup; + } + } + else { + if(keymatch != CURLKHMATCH_OK) { + rc = SSH_ERROR; + goto cleanup; + } + } + rc = SSH_OK; + +cleanup: + if(found_base64) { + (free)(found_base64); + } + if(known_base64) { + (free)(known_base64); + } + if(hash) + ssh_clean_pubkey_hash(&hash); + ssh_key_free(pubkey); +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + if(knownhostsentry) { + ssh_knownhosts_entry_free(knownhostsentry); + } +#endif + return rc; +} + +#define MOVE_TO_ERROR_STATE(_r) do { \ + state(data, SSH_SESSION_DISCONNECT); \ + sshc->actualcode = _r; \ + rc = SSH_ERROR; \ + } while(0) + +#define MOVE_TO_SFTP_CLOSE_STATE() do { \ + state(data, SSH_SFTP_CLOSE); \ + sshc->actualcode = \ + sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \ + rc = SSH_ERROR; \ + } while(0) + +#define MOVE_TO_PASSWD_AUTH do { \ + if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \ + rc = SSH_OK; \ + state(data, SSH_AUTH_PASS_INIT); \ + } \ + else { \ + MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \ + } \ + } while(0) + +#define MOVE_TO_KEY_AUTH do { \ + if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \ + rc = SSH_OK; \ + state(data, SSH_AUTH_KEY_INIT); \ + } \ + else { \ + MOVE_TO_PASSWD_AUTH; \ + } \ + } while(0) + +#define MOVE_TO_GSSAPI_AUTH do { \ + if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \ + rc = SSH_OK; \ + state(data, SSH_AUTH_GSSAPI); \ + } \ + else { \ + MOVE_TO_KEY_AUTH; \ + } \ + } while(0) + +static +int myssh_auth_interactive(struct connectdata *conn) +{ + int rc; + struct ssh_conn *sshc = &conn->proto.sshc; + int nprompts; + +restart: + switch(sshc->kbd_state) { + case 0: + rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL); + if(rc == SSH_AUTH_AGAIN) + return SSH_AGAIN; + + if(rc != SSH_AUTH_INFO) + return SSH_ERROR; + + nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session); + if(nprompts != 1) + return SSH_ERROR; + + rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd); + if(rc < 0) + return SSH_ERROR; + + FALLTHROUGH(); + case 1: + sshc->kbd_state = 1; + + rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL); + if(rc == SSH_AUTH_AGAIN) + return SSH_AGAIN; + else if(rc == SSH_AUTH_SUCCESS) + rc = SSH_OK; + else if(rc == SSH_AUTH_INFO) { + nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session); + if(nprompts) + return SSH_ERROR; + + sshc->kbd_state = 2; + goto restart; + } + else + rc = SSH_ERROR; + break; + case 2: + sshc->kbd_state = 2; + + rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL); + if(rc == SSH_AUTH_AGAIN) + return SSH_AGAIN; + else if(rc == SSH_AUTH_SUCCESS) + rc = SSH_OK; + else + rc = SSH_ERROR; + + break; + default: + return SSH_ERROR; + } + + sshc->kbd_state = 0; + return rc; +} + +/* + * ssh_statemach_act() runs the SSH state machine as far as it can without + * blocking and without reaching the end. The data the pointer 'block' points + * to will be set to TRUE if the libssh function returns SSH_AGAIN + * meaning it wants to be called again when the socket is ready + */ +static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct SSHPROTO *protop = data->req.p.ssh; + struct ssh_conn *sshc = &conn->proto.sshc; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc = SSH_NO_ERROR, err; + int seekerr = CURL_SEEKFUNC_OK; + const char *err_msg; + *block = 0; /* we're not blocking by default */ + + do { + + switch(sshc->state) { + case SSH_INIT: + sshc->secondCreateDirs = 0; + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_OK; + +#if 0 + ssh_set_log_level(SSH_LOG_PROTOCOL); +#endif + + /* Set libssh to non-blocking, since everything internally is + non-blocking */ + ssh_set_blocking(sshc->ssh_session, 0); + + state(data, SSH_S_STARTUP); + FALLTHROUGH(); + + case SSH_S_STARTUP: + rc = ssh_connect(sshc->ssh_session); + if(rc == SSH_AGAIN) + break; + + if(rc != SSH_OK) { + failf(data, "Failure establishing ssh session"); + MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT); + break; + } + + state(data, SSH_HOSTKEY); + + FALLTHROUGH(); + case SSH_HOSTKEY: + + rc = myssh_is_known(data); + if(rc != SSH_OK) { + MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION); + break; + } + + state(data, SSH_AUTHLIST); + FALLTHROUGH(); + case SSH_AUTHLIST:{ + sshc->authed = FALSE; + + rc = ssh_userauth_none(sshc->ssh_session, NULL); + if(rc == SSH_AUTH_AGAIN) { + rc = SSH_AGAIN; + break; + } + + if(rc == SSH_AUTH_SUCCESS) { + sshc->authed = TRUE; + infof(data, "Authenticated with none"); + state(data, SSH_AUTH_DONE); + break; + } + else if(rc == SSH_AUTH_ERROR) { + MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + break; + } + + sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL); + if(sshc->auth_methods) + infof(data, "SSH authentication methods available: %s%s%s%s", + sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ? + "public key, ": "", + sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ? + "GSSAPI, " : "", + sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ? + "keyboard-interactive, " : "", + sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ? + "password": ""); + if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { + state(data, SSH_AUTH_PKEY_INIT); + infof(data, "Authentication using SSH public key file"); + } + else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { + state(data, SSH_AUTH_GSSAPI); + } + else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { + state(data, SSH_AUTH_KEY_INIT); + } + else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { + state(data, SSH_AUTH_PASS_INIT); + } + else { /* unsupported authentication method */ + MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + break; + } + + break; + } + case SSH_AUTH_PKEY_INIT: + if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) { + MOVE_TO_GSSAPI_AUTH; + break; + } + + /* Two choices, (1) private key was given on CMD, + * (2) use the "default" keys. */ + if(data->set.str[STRING_SSH_PRIVATE_KEY]) { + if(sshc->pubkey && !data->set.ssl.key_passwd) { + rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL, + sshc->pubkey); + if(rc == SSH_AUTH_AGAIN) { + rc = SSH_AGAIN; + break; + } + + if(rc != SSH_OK) { + MOVE_TO_GSSAPI_AUTH; + break; + } + } + + rc = ssh_pki_import_privkey_file(data-> + set.str[STRING_SSH_PRIVATE_KEY], + data->set.ssl.key_passwd, NULL, + NULL, &sshc->privkey); + if(rc != SSH_OK) { + failf(data, "Could not load private key file %s", + data->set.str[STRING_SSH_PRIVATE_KEY]); + MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + break; + } + + state(data, SSH_AUTH_PKEY); + break; + + } + else { + rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL, + data->set.ssl.key_passwd); + if(rc == SSH_AUTH_AGAIN) { + rc = SSH_AGAIN; + break; + } + if(rc == SSH_AUTH_SUCCESS) { + rc = SSH_OK; + sshc->authed = TRUE; + infof(data, "Completed public key authentication"); + state(data, SSH_AUTH_DONE); + break; + } + + MOVE_TO_GSSAPI_AUTH; + } + break; + case SSH_AUTH_PKEY: + rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey); + if(rc == SSH_AUTH_AGAIN) { + rc = SSH_AGAIN; + break; + } + + if(rc == SSH_AUTH_SUCCESS) { + sshc->authed = TRUE; + infof(data, "Completed public key authentication"); + state(data, SSH_AUTH_DONE); + break; + } + else { + infof(data, "Failed public key authentication (rc: %d)", rc); + MOVE_TO_GSSAPI_AUTH; + } + break; + + case SSH_AUTH_GSSAPI: + if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) { + MOVE_TO_KEY_AUTH; + break; + } + + rc = ssh_userauth_gssapi(sshc->ssh_session); + if(rc == SSH_AUTH_AGAIN) { + rc = SSH_AGAIN; + break; + } + + if(rc == SSH_AUTH_SUCCESS) { + rc = SSH_OK; + sshc->authed = TRUE; + infof(data, "Completed gssapi authentication"); + state(data, SSH_AUTH_DONE); + break; + } + + MOVE_TO_KEY_AUTH; + break; + + case SSH_AUTH_KEY_INIT: + if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) { + state(data, SSH_AUTH_KEY); + } + else { + MOVE_TO_PASSWD_AUTH; + } + break; + + case SSH_AUTH_KEY: + /* keyboard-interactive authentication */ + rc = myssh_auth_interactive(conn); + if(rc == SSH_AGAIN) { + break; + } + if(rc == SSH_OK) { + sshc->authed = TRUE; + infof(data, "completed keyboard interactive authentication"); + state(data, SSH_AUTH_DONE); + } + else { + MOVE_TO_PASSWD_AUTH; + } + break; + + case SSH_AUTH_PASS_INIT: + if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) { + MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + break; + } + state(data, SSH_AUTH_PASS); + FALLTHROUGH(); + + case SSH_AUTH_PASS: + rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd); + if(rc == SSH_AUTH_AGAIN) { + rc = SSH_AGAIN; + break; + } + + if(rc == SSH_AUTH_SUCCESS) { + sshc->authed = TRUE; + infof(data, "Completed password authentication"); + state(data, SSH_AUTH_DONE); + } + else { + MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + } + break; + + case SSH_AUTH_DONE: + if(!sshc->authed) { + failf(data, "Authentication failure"); + MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + break; + } + + /* + * At this point we have an authenticated ssh session. + */ + infof(data, "Authentication complete"); + + Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ + + conn->sockfd = sock; + conn->writesockfd = CURL_SOCKET_BAD; + + if(conn->handler->protocol == CURLPROTO_SFTP) { + state(data, SSH_SFTP_INIT); + break; + } + infof(data, "SSH CONNECT phase done"); + state(data, SSH_STOP); + break; + + case SSH_SFTP_INIT: + ssh_set_blocking(sshc->ssh_session, 1); + + sshc->sftp_session = sftp_new(sshc->ssh_session); + if(!sshc->sftp_session) { + failf(data, "Failure initializing sftp session: %s", + ssh_get_error(sshc->ssh_session)); + MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); + break; + } + + rc = sftp_init(sshc->sftp_session); + if(rc != SSH_OK) { + failf(data, "Failure initializing sftp session: %s", + ssh_get_error(sshc->ssh_session)); + MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE)); + break; + } + state(data, SSH_SFTP_REALPATH); + FALLTHROUGH(); + case SSH_SFTP_REALPATH: + /* + * Get the "home" directory + */ + sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, "."); + if(!sshc->homedir) { + MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); + break; + } + data->state.most_recent_ftp_entrypath = sshc->homedir; + + /* This is the last step in the SFTP connect phase. Do note that while + we get the homedir here, we get the "workingpath" in the DO action + since the homedir will remain the same between request but the + working path will not. */ + DEBUGF(infof(data, "SSH CONNECT phase done")); + state(data, SSH_STOP); + break; + + case SSH_SFTP_QUOTE_INIT: + result = Curl_getworkingpath(data, sshc->homedir, &protop->path); + if(result) { + sshc->actualcode = result; + state(data, SSH_STOP); + break; + } + + if(data->set.quote) { + infof(data, "Sending quote commands"); + sshc->quote_item = data->set.quote; + state(data, SSH_SFTP_QUOTE); + } + else { + state(data, SSH_SFTP_GETINFO); + } + break; + + case SSH_SFTP_POSTQUOTE_INIT: + if(data->set.postquote) { + infof(data, "Sending quote commands"); + sshc->quote_item = data->set.postquote; + state(data, SSH_SFTP_QUOTE); + } + else { + state(data, SSH_STOP); + } + break; + + case SSH_SFTP_QUOTE: + /* Send any quote commands */ + sftp_quote(data); + break; + + case SSH_SFTP_NEXT_QUOTE: + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + + sshc->quote_item = sshc->quote_item->next; + + if(sshc->quote_item) { + state(data, SSH_SFTP_QUOTE); + } + else { + if(sshc->nextstate != SSH_NO_STATE) { + state(data, sshc->nextstate); + sshc->nextstate = SSH_NO_STATE; + } + else { + state(data, SSH_SFTP_GETINFO); + } + } + break; + + case SSH_SFTP_QUOTE_STAT: + sftp_quote_stat(data); + break; + + case SSH_SFTP_QUOTE_SETSTAT: + rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2, + sshc->quote_attrs); + if(rc && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Attempt to set SFTP stats failed: %s", + ssh_get_error(sshc->ssh_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + /* sshc->actualcode = sftp_error_to_CURLE(err); + * we do not send the actual error; we return + * the error the libssh2 backend is returning */ + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_SYMLINK: + rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2, + sshc->quote_path1); + if(rc && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "symlink command failed: %s", + ssh_get_error(sshc->ssh_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_MKDIR: + rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1, + (mode_t)data->set.new_directory_perms); + if(rc && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + failf(data, "mkdir command failed: %s", + ssh_get_error(sshc->ssh_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_RENAME: + rc = sftp_rename(sshc->sftp_session, sshc->quote_path1, + sshc->quote_path2); + if(rc && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "rename command failed: %s", + ssh_get_error(sshc->ssh_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_RMDIR: + rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1); + if(rc && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + failf(data, "rmdir command failed: %s", + ssh_get_error(sshc->ssh_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_UNLINK: + rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1); + if(rc && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + failf(data, "rm command failed: %s", + ssh_get_error(sshc->ssh_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_STATVFS: + { + sftp_statvfs_t statvfs; + + statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1); + if(!statvfs && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + failf(data, "statvfs command failed: %s", + ssh_get_error(sshc->ssh_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + else if(statvfs) { + #ifdef _MSC_VER + #define CURL_LIBSSH_VFS_SIZE_MASK "I64u" + #else + #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 + #endif + char *tmp = aprintf("statvfs:\n" + "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n", + statvfs->f_bsize, statvfs->f_frsize, + statvfs->f_blocks, statvfs->f_bfree, + statvfs->f_bavail, statvfs->f_files, + statvfs->f_ffree, statvfs->f_favail, + statvfs->f_fsid, statvfs->f_flag, + statvfs->f_namemax); + sftp_statvfs_free(statvfs); + + if(!tmp) { + result = CURLE_OUT_OF_MEMORY; + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + break; + } + + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + } + + case SSH_SFTP_GETINFO: + if(data->set.get_filetime) { + state(data, SSH_SFTP_FILETIME); + } + else { + state(data, SSH_SFTP_TRANS_INIT); + } + break; + + case SSH_SFTP_FILETIME: + { + sftp_attributes attrs; + + attrs = sftp_stat(sshc->sftp_session, protop->path); + if(attrs) { + data->info.filetime = attrs->mtime; + sftp_attributes_free(attrs); + } + + state(data, SSH_SFTP_TRANS_INIT); + break; + } + + case SSH_SFTP_TRANS_INIT: + if(data->state.upload) + state(data, SSH_SFTP_UPLOAD_INIT); + else { + if(protop->path[strlen(protop->path)-1] == '/') + state(data, SSH_SFTP_READDIR_INIT); + else + state(data, SSH_SFTP_DOWNLOAD_INIT); + } + break; + + case SSH_SFTP_UPLOAD_INIT: + { + int flags; + + if(data->state.resume_from) { + sftp_attributes attrs; + + if(data->state.resume_from < 0) { + attrs = sftp_stat(sshc->sftp_session, protop->path); + if(attrs) { + curl_off_t size = attrs->size; + if(size < 0) { + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); + MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME); + break; + } + data->state.resume_from = attrs->size; + + sftp_attributes_free(attrs); + } + else { + data->state.resume_from = 0; + } + } + } + + if(data->set.remote_append) + /* Try to open for append, but create if nonexisting */ + flags = O_WRONLY|O_CREAT|O_APPEND; + else if(data->state.resume_from > 0) + /* If we have restart position then open for append */ + flags = O_WRONLY|O_APPEND; + else + /* Clear file before writing (normal behavior) */ + flags = O_WRONLY|O_CREAT|O_TRUNC; + + if(sshc->sftp_file) + sftp_close(sshc->sftp_file); + sshc->sftp_file = + sftp_open(sshc->sftp_session, protop->path, + flags, (mode_t)data->set.new_file_perms); + if(!sshc->sftp_file) { + err = sftp_get_error(sshc->sftp_session); + + if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE || + err == SSH_FX_NO_SUCH_PATH)) && + (data->set.ftp_create_missing_dirs && + (strlen(protop->path) > 1))) { + /* try to create the path remotely */ + rc = 0; + sshc->secondCreateDirs = 1; + state(data, SSH_SFTP_CREATE_DIRS_INIT); + break; + } + else { + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + } + + /* If we have a restart point then we need to seek to the correct + position. */ + if(data->state.resume_from > 0) { + /* Let's read off the proper amount of bytes from the input. */ + if(conn->seek_func) { + Curl_set_in_callback(data, true); + seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, + SEEK_SET); + Curl_set_in_callback(data, false); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed = 0; + + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_FTP_COULDNT_USE_REST; + } + /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ + do { + char scratch[4*1024]; + size_t readthisamountnow = + (data->state.resume_from - passed > + (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread = + data->state.fread_func(scratch, 1, + readthisamountnow, data->state.in); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST); + break; + } + } while(passed < data->state.resume_from); + if(rc) + break; + } + + /* now, decrease the size of the read */ + if(data->state.infilesize > 0) { + data->state.infilesize -= data->state.resume_from; + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + + rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); + if(rc) { + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + } + if(data->state.infilesize > 0) { + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + /* upload data */ + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->sockfd = conn->writesockfd; + + /* store this original bitmask setup to use later on if we can't + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh sftp send function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_OUT; + + /* since we don't really wait for anything at this point, we want the + state machine to move on as soon as possible so we set a very short + timeout here */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + state(data, SSH_STOP); + break; + } + + case SSH_SFTP_CREATE_DIRS_INIT: + if(strlen(protop->path) > 1) { + sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */ + state(data, SSH_SFTP_CREATE_DIRS); + } + else { + state(data, SSH_SFTP_UPLOAD_INIT); + } + break; + + case SSH_SFTP_CREATE_DIRS: + sshc->slash_pos = strchr(sshc->slash_pos, '/'); + if(sshc->slash_pos) { + *sshc->slash_pos = 0; + + infof(data, "Creating directory '%s'", protop->path); + state(data, SSH_SFTP_CREATE_DIRS_MKDIR); + break; + } + state(data, SSH_SFTP_UPLOAD_INIT); + break; + + case SSH_SFTP_CREATE_DIRS_MKDIR: + /* 'mode' - parameter is preliminary - default to 0644 */ + rc = sftp_mkdir(sshc->sftp_session, protop->path, + (mode_t)data->set.new_directory_perms); + *sshc->slash_pos = '/'; + ++sshc->slash_pos; + if(rc < 0) { + /* + * Abort if failure wasn't that the dir already exists or the + * permission was denied (creation might succeed further down the + * path) - retry on unspecific FAILURE also + */ + err = sftp_get_error(sshc->sftp_session); + if((err != SSH_FX_FILE_ALREADY_EXISTS) && + (err != SSH_FX_FAILURE) && + (err != SSH_FX_PERMISSION_DENIED)) { + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + rc = 0; /* clear rc and continue */ + } + state(data, SSH_SFTP_CREATE_DIRS); + break; + + case SSH_SFTP_READDIR_INIT: + Curl_pgrsSetDownloadSize(data, -1); + if(data->req.no_body) { + state(data, SSH_STOP); + break; + } + + /* + * This is a directory that we are trying to get, so produce a directory + * listing + */ + sshc->sftp_dir = sftp_opendir(sshc->sftp_session, + protop->path); + if(!sshc->sftp_dir) { + failf(data, "Could not open directory for reading: %s", + ssh_get_error(sshc->ssh_session)); + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + state(data, SSH_SFTP_READDIR); + break; + + case SSH_SFTP_READDIR: + Curl_dyn_reset(&sshc->readdir_buf); + if(sshc->readdir_attrs) + sftp_attributes_free(sshc->readdir_attrs); + + sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir); + if(sshc->readdir_attrs) { + sshc->readdir_filename = sshc->readdir_attrs->name; + sshc->readdir_longentry = sshc->readdir_attrs->longname; + sshc->readdir_len = strlen(sshc->readdir_filename); + + if(data->set.list_only) { + char *tmpLine; + + tmpLine = aprintf("%s\n", sshc->readdir_filename); + if(!tmpLine) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + result = Curl_client_write(data, CLIENTWRITE_BODY, + tmpLine, sshc->readdir_len + 1); + free(tmpLine); + + if(result) { + state(data, SSH_STOP); + break; + } + + } + else { + if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) { + sshc->actualcode = CURLE_OUT_OF_MEMORY; + state(data, SSH_STOP); + break; + } + + if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) && + ((sshc->readdir_attrs->permissions & SSH_S_IFMT) == + SSH_S_IFLNK)) { + sshc->readdir_linkPath = aprintf("%s%s", protop->path, + sshc->readdir_filename); + + if(!sshc->readdir_linkPath) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + + state(data, SSH_SFTP_READDIR_LINK); + break; + } + state(data, SSH_SFTP_READDIR_BOTTOM); + break; + } + } + else if(sftp_dir_eof(sshc->sftp_dir)) { + state(data, SSH_SFTP_READDIR_DONE); + break; + } + else { + failf(data, "Could not open remote file for reading: %s", + ssh_get_error(sshc->ssh_session)); + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + break; + + case SSH_SFTP_READDIR_LINK: + if(sshc->readdir_link_attrs) + sftp_attributes_free(sshc->readdir_link_attrs); + + sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session, + sshc->readdir_linkPath); + if(sshc->readdir_link_attrs == 0) { + failf(data, "Could not read symlink for reading: %s", + ssh_get_error(sshc->ssh_session)); + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + + if(!sshc->readdir_link_attrs->name) { + sshc->readdir_tmp = sftp_readlink(sshc->sftp_session, + sshc->readdir_linkPath); + if(!sshc->readdir_filename) + sshc->readdir_len = 0; + else + sshc->readdir_len = strlen(sshc->readdir_tmp); + sshc->readdir_longentry = NULL; + sshc->readdir_filename = sshc->readdir_tmp; + } + else { + sshc->readdir_len = strlen(sshc->readdir_link_attrs->name); + sshc->readdir_filename = sshc->readdir_link_attrs->name; + sshc->readdir_longentry = sshc->readdir_link_attrs->longname; + } + + Curl_safefree(sshc->readdir_linkPath); + + if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s", + sshc->readdir_filename)) { + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + + sftp_attributes_free(sshc->readdir_link_attrs); + sshc->readdir_link_attrs = NULL; + sshc->readdir_filename = NULL; + sshc->readdir_longentry = NULL; + + state(data, SSH_SFTP_READDIR_BOTTOM); + FALLTHROUGH(); + case SSH_SFTP_READDIR_BOTTOM: + if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1)) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&sshc->readdir_buf), + Curl_dyn_len(&sshc->readdir_buf)); + + ssh_string_free_char(sshc->readdir_tmp); + sshc->readdir_tmp = NULL; + + if(result) { + state(data, SSH_STOP); + } + else + state(data, SSH_SFTP_READDIR); + break; + + case SSH_SFTP_READDIR_DONE: + sftp_closedir(sshc->sftp_dir); + sshc->sftp_dir = NULL; + + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + state(data, SSH_STOP); + break; + + case SSH_SFTP_DOWNLOAD_INIT: + /* + * Work on getting the specified file + */ + if(sshc->sftp_file) + sftp_close(sshc->sftp_file); + + sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path, + O_RDONLY, (mode_t)data->set.new_file_perms); + if(!sshc->sftp_file) { + failf(data, "Could not open remote file for reading: %s", + ssh_get_error(sshc->ssh_session)); + + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + sftp_file_set_nonblocking(sshc->sftp_file); + state(data, SSH_SFTP_DOWNLOAD_STAT); + break; + + case SSH_SFTP_DOWNLOAD_STAT: + { + sftp_attributes attrs; + curl_off_t size; + + attrs = sftp_fstat(sshc->sftp_file); + if(!attrs || + !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) || + (attrs->size == 0)) { + /* + * sftp_fstat didn't return an error, so maybe the server + * just doesn't support stat() + * OR the server doesn't return a file size with a stat() + * OR file size is 0 + */ + data->req.size = -1; + data->req.maxdownload = -1; + Curl_pgrsSetDownloadSize(data, -1); + size = 0; + } + else { + size = attrs->size; + + sftp_attributes_free(attrs); + + if(size < 0) { + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + if(data->state.use_range) { + curl_off_t from, to; + char *ptr; + char *ptr2; + CURLofft to_t; + CURLofft from_t; + + from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from); + if(from_t == CURL_OFFT_FLOW) { + return CURLE_RANGE_ERROR; + } + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) + ptr++; + to_t = curlx_strtoofft(ptr, &ptr2, 10, &to); + if(to_t == CURL_OFFT_FLOW) { + return CURLE_RANGE_ERROR; + } + if((to_t == CURL_OFFT_INVAL) /* no "to" value given */ + || (to >= size)) { + to = size - 1; + } + if(from_t) { + /* from is relative to end of file */ + from = size - to; + to = size - 1; + } + if(from > size) { + failf(data, "Offset (%" + CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" + CURL_FORMAT_CURL_OFF_T ")", from, size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + if(from > to) { + from = to; + size = 0; + } + else { + size = to - from + 1; + } + + rc = sftp_seek64(sshc->sftp_file, from); + if(rc) { + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + } + data->req.size = size; + data->req.maxdownload = size; + Curl_pgrsSetDownloadSize(data, size); + } + + /* We can resume if we can seek to the resume position */ + if(data->state.resume_from) { + if(data->state.resume_from < 0) { + /* We're supposed to download the last abs(from) bytes */ + if((curl_off_t)size < -data->state.resume_from) { + failf(data, "Offset (%" + CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" + CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* download from where? */ + data->state.resume_from += size; + } + else { + if((curl_off_t)size < data->state.resume_from) { + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + } + /* Now store the number of bytes we are expected to download */ + data->req.size = size - data->state.resume_from; + data->req.maxdownload = size - data->state.resume_from; + Curl_pgrsSetDownloadSize(data, + size - data->state.resume_from); + + rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); + if(rc) { + MOVE_TO_SFTP_CLOSE_STATE(); + break; + } + } + } + + /* Setup the actual download */ + if(data->req.size == 0) { + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + infof(data, "File already completely downloaded"); + state(data, SSH_STOP); + break; + } + Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->writesockfd = conn->sockfd; + + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh recv function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_IN; + + if(result) { + /* this should never occur; the close state should be entered + at the time the error occurs */ + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = result; + } + else { + sshc->sftp_recv_state = 0; + state(data, SSH_STOP); + } + break; + + case SSH_SFTP_CLOSE: + if(sshc->sftp_file) { + sftp_close(sshc->sftp_file); + sshc->sftp_file = NULL; + } + Curl_safefree(protop->path); + + DEBUGF(infof(data, "SFTP DONE done")); + + /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT + After nextstate is executed, the control should come back to + SSH_SFTP_CLOSE to pass the correct result back */ + if(sshc->nextstate != SSH_NO_STATE && + sshc->nextstate != SSH_SFTP_CLOSE) { + state(data, sshc->nextstate); + sshc->nextstate = SSH_SFTP_CLOSE; + } + else { + state(data, SSH_STOP); + result = sshc->actualcode; + } + break; + + case SSH_SFTP_SHUTDOWN: + /* during times we get here due to a broken transfer and then the + sftp_handle might not have been taken down so make sure that is done + before we proceed */ + + if(sshc->sftp_file) { + sftp_close(sshc->sftp_file); + sshc->sftp_file = NULL; + } + + if(sshc->sftp_session) { + sftp_free(sshc->sftp_session); + sshc->sftp_session = NULL; + } + + SSH_STRING_FREE_CHAR(sshc->homedir); + data->state.most_recent_ftp_entrypath = NULL; + + state(data, SSH_SESSION_DISCONNECT); + break; + + case SSH_SCP_TRANS_INIT: + result = Curl_getworkingpath(data, sshc->homedir, &protop->path); + if(result) { + sshc->actualcode = result; + state(data, SSH_STOP); + break; + } + + /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */ + ssh_set_blocking(sshc->ssh_session, 1); + + if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; + MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + break; + } + + sshc->scp_session = + ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path); + state(data, SSH_SCP_UPLOAD_INIT); + } + else { + sshc->scp_session = + ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path); + state(data, SSH_SCP_DOWNLOAD_INIT); + } + + if(!sshc->scp_session) { + err_msg = ssh_get_error(sshc->ssh_session); + failf(data, "%s", err_msg); + MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + } + + break; + + case SSH_SCP_UPLOAD_INIT: + + rc = ssh_scp_init(sshc->scp_session); + if(rc != SSH_OK) { + err_msg = ssh_get_error(sshc->ssh_session); + failf(data, "%s", err_msg); + MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + break; + } + + rc = ssh_scp_push_file(sshc->scp_session, protop->path, + data->state.infilesize, + (int)data->set.new_file_perms); + if(rc != SSH_OK) { + err_msg = ssh_get_error(sshc->ssh_session); + failf(data, "%s", err_msg); + MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + break; + } + + /* upload data */ + Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->sockfd = conn->writesockfd; + + /* store this original bitmask setup to use later on if we can't + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh scp send function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_OUT; + + state(data, SSH_STOP); + + break; + + case SSH_SCP_DOWNLOAD_INIT: + + rc = ssh_scp_init(sshc->scp_session); + if(rc != SSH_OK) { + err_msg = ssh_get_error(sshc->ssh_session); + failf(data, "%s", err_msg); + MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); + break; + } + state(data, SSH_SCP_DOWNLOAD); + FALLTHROUGH(); + + case SSH_SCP_DOWNLOAD:{ + curl_off_t bytecount; + + rc = ssh_scp_pull_request(sshc->scp_session); + if(rc != SSH_SCP_REQUEST_NEWFILE) { + err_msg = ssh_get_error(sshc->ssh_session); + failf(data, "%s", err_msg); + MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND); + break; + } + + /* download data */ + bytecount = ssh_scp_request_get_size(sshc->scp_session); + data->req.maxdownload = (curl_off_t) bytecount; + Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->writesockfd = conn->sockfd; + + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh recv function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_IN; + + state(data, SSH_STOP); + break; + } + case SSH_SCP_DONE: + if(data->state.upload) + state(data, SSH_SCP_SEND_EOF); + else + state(data, SSH_SCP_CHANNEL_FREE); + break; + + case SSH_SCP_SEND_EOF: + if(sshc->scp_session) { + rc = ssh_scp_close(sshc->scp_session); + if(rc == SSH_AGAIN) { + /* Currently the ssh_scp_close handles waiting for EOF in + * blocking way. + */ + break; + } + if(rc != SSH_OK) { + infof(data, "Failed to close libssh scp channel: %s", + ssh_get_error(sshc->ssh_session)); + } + } + + state(data, SSH_SCP_CHANNEL_FREE); + break; + + case SSH_SCP_CHANNEL_FREE: + if(sshc->scp_session) { + ssh_scp_free(sshc->scp_session); + sshc->scp_session = NULL; + } + DEBUGF(infof(data, "SCP DONE phase complete")); + + ssh_set_blocking(sshc->ssh_session, 0); + + state(data, SSH_SESSION_DISCONNECT); + FALLTHROUGH(); + + case SSH_SESSION_DISCONNECT: + /* during weird times when we've been prematurely aborted, the channel + is still alive when we reach this state and we MUST kill the channel + properly first */ + if(sshc->scp_session) { + ssh_scp_free(sshc->scp_session); + sshc->scp_session = NULL; + } + + ssh_disconnect(sshc->ssh_session); + if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) { + /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back, + tell the connection to forget about it. This libssh + bug is fixed in 0.10.0. */ + Curl_conn_forget_socket(data, FIRSTSOCKET); + } + + SSH_STRING_FREE_CHAR(sshc->homedir); + data->state.most_recent_ftp_entrypath = NULL; + + state(data, SSH_SESSION_FREE); + FALLTHROUGH(); + case SSH_SESSION_FREE: + if(sshc->ssh_session) { + ssh_free(sshc->ssh_session); + sshc->ssh_session = NULL; + } + + /* worst-case scenario cleanup */ + + DEBUGASSERT(sshc->ssh_session == NULL); + DEBUGASSERT(sshc->scp_session == NULL); + + if(sshc->readdir_tmp) { + ssh_string_free_char(sshc->readdir_tmp); + sshc->readdir_tmp = NULL; + } + + if(sshc->quote_attrs) + sftp_attributes_free(sshc->quote_attrs); + + if(sshc->readdir_attrs) + sftp_attributes_free(sshc->readdir_attrs); + + if(sshc->readdir_link_attrs) + sftp_attributes_free(sshc->readdir_link_attrs); + + if(sshc->privkey) + ssh_key_free(sshc->privkey); + if(sshc->pubkey) + ssh_key_free(sshc->pubkey); + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + Curl_dyn_free(&sshc->readdir_buf); + Curl_safefree(sshc->readdir_linkPath); + SSH_STRING_FREE_CHAR(sshc->homedir); + + /* the code we are about to return */ + result = sshc->actualcode; + + memset(sshc, 0, sizeof(struct ssh_conn)); + + connclose(conn, "SSH session free"); + sshc->state = SSH_SESSION_FREE; /* current */ + sshc->nextstate = SSH_NO_STATE; + state(data, SSH_STOP); + break; + + case SSH_QUIT: + default: + /* internal error */ + sshc->nextstate = SSH_NO_STATE; + state(data, SSH_STOP); + break; + + } + } while(!rc && (sshc->state != SSH_STOP)); + + + if(rc == SSH_AGAIN) { + /* we would block, we need to wait for the socket to be ready (in the + right direction too)! */ + *block = TRUE; + } + + return result; +} + + +/* called by the multi interface to figure out what socket(s) to wait for and + for what actions in the DO_DONE, PERFORM and WAITPERFORM states */ +static int myssh_getsock(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *sock) +{ + int bitmap = GETSOCK_BLANK; + (void)data; + sock[0] = conn->sock[FIRSTSOCKET]; + + if(conn->waitfor & KEEP_RECV) + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + + if(conn->waitfor & KEEP_SEND) + bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); + + if(!conn->waitfor) + bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); + + return bitmap; +} + +static void myssh_block2waitfor(struct connectdata *conn, bool block) +{ + struct ssh_conn *sshc = &conn->proto.sshc; + + /* If it didn't block, or nothing was returned by ssh_get_poll_flags + * have the original set */ + conn->waitfor = sshc->orig_waitfor; + + if(block) { + int dir = ssh_get_poll_flags(sshc->ssh_session); + if(dir & SSH_READ_PENDING) { + /* translate the libssh define bits into our own bit defines */ + conn->waitfor = KEEP_RECV; + } + else if(dir & SSH_WRITE_PENDING) { + conn->waitfor = KEEP_SEND; + } + } +} + +/* called repeatedly until done from multi.c */ +static CURLcode myssh_multi_statemach(struct Curl_easy *data, + bool *done) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + bool block; /* we store the status and use that to provide a ssh_getsock() + implementation */ + CURLcode result = myssh_statemach_act(data, &block); + + *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; + myssh_block2waitfor(conn, block); + + return result; +} + +static CURLcode myssh_block_statemach(struct Curl_easy *data, + bool disconnect) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result = CURLE_OK; + + while((sshc->state != SSH_STOP) && !result) { + bool block; + timediff_t left = 1000; + struct curltime now = Curl_now(); + + result = myssh_statemach_act(data, &block); + if(result) + break; + + if(!disconnect) { + if(Curl_pgrsUpdate(data)) + return CURLE_ABORTED_BY_CALLBACK; + + result = Curl_speedcheck(data, now); + if(result) + break; + + left = Curl_timeleft(data, NULL, FALSE); + if(left < 0) { + failf(data, "Operation timed out"); + return CURLE_OPERATION_TIMEDOUT; + } + } + + if(block) { + curl_socket_t fd_read = conn->sock[FIRSTSOCKET]; + /* wait for the socket to become ready */ + (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD, + CURL_SOCKET_BAD, left > 1000 ? 1000 : left); + } + + } + + return result; +} + +/* + * SSH setup connection + */ +static CURLcode myssh_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + struct SSHPROTO *ssh; + struct ssh_conn *sshc = &conn->proto.sshc; + + data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); + if(!ssh) + return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2); + + return CURLE_OK; +} + +static Curl_recv scp_recv, sftp_recv; +static Curl_send scp_send, sftp_send; + +/* + * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to + * do protocol-specific actions at connect-time. + */ +static CURLcode myssh_connect(struct Curl_easy *data, bool *done) +{ + struct ssh_conn *ssh; + CURLcode result; + struct connectdata *conn = data->conn; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc; + + /* initialize per-handle data if not already */ + if(!data->req.p.ssh) + myssh_setup_connection(data, conn); + + /* We default to persistent connections. We set this already in this connect + function to make the reuse checks properly be able to check this bit. */ + connkeep(conn, "SSH default"); + + if(conn->handler->protocol & CURLPROTO_SCP) { + conn->recv[FIRSTSOCKET] = scp_recv; + conn->send[FIRSTSOCKET] = scp_send; + } + else { + conn->recv[FIRSTSOCKET] = sftp_recv; + conn->send[FIRSTSOCKET] = sftp_send; + } + + ssh = &conn->proto.sshc; + + ssh->ssh_session = ssh_new(); + if(!ssh->ssh_session) { + failf(data, "Failure initialising ssh session"); + return CURLE_FAILED_INIT; + } + + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name); + if(rc != SSH_OK) { + failf(data, "Could not set remote host"); + return CURLE_FAILED_INIT; + } + + rc = ssh_options_parse_config(ssh->ssh_session, NULL); + if(rc != SSH_OK) { + infof(data, "Could not parse SSH configuration files"); + /* ignore */ + } + + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock); + if(rc != SSH_OK) { + failf(data, "Could not set socket"); + return CURLE_FAILED_INIT; + } + + if(conn->user && conn->user[0] != '\0') { + infof(data, "User: %s", conn->user); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user); + if(rc != SSH_OK) { + failf(data, "Could not set user"); + return CURLE_FAILED_INIT; + } + } + + if(data->set.str[STRING_SSH_KNOWNHOSTS]) { + infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, + data->set.str[STRING_SSH_KNOWNHOSTS]); + if(rc != SSH_OK) { + failf(data, "Could not set known hosts file path"); + return CURLE_FAILED_INIT; + } + } + + if(conn->remote_port) { + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT, + &conn->remote_port); + if(rc != SSH_OK) { + failf(data, "Could not set remote port"); + return CURLE_FAILED_INIT; + } + } + + if(data->set.ssh_compression) { + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION, + "zlib,zlib@openssh.com,none"); + if(rc != SSH_OK) { + failf(data, "Could not set compression"); + return CURLE_FAILED_INIT; + } + } + + ssh->privkey = NULL; + ssh->pubkey = NULL; + + if(data->set.str[STRING_SSH_PUBLIC_KEY]) { + rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY], + &ssh->pubkey); + if(rc != SSH_OK) { + failf(data, "Could not load public key file"); + return CURLE_FAILED_INIT; + } + } + + /* we do not verify here, we do it at the state machine, + * after connection */ + + state(data, SSH_INIT); + + result = myssh_multi_statemach(data, done); + + return result; +} + +/* called from multi.c while DOing */ +static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done) +{ + CURLcode result; + + result = myssh_multi_statemach(data, dophase_done); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + return result; +} + +/* + *********************************************************************** + * + * scp_perform() + * + * This is the actual DO function for SCP. Get a file according to + * the options previously setup. + */ + +static +CURLcode scp_perform(struct Curl_easy *data, + bool *connected, bool *dophase_done) +{ + CURLcode result = CURLE_OK; + + DEBUGF(infof(data, "DO phase starts")); + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + state(data, SSH_SCP_TRANS_INIT); + + result = myssh_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +static CURLcode myssh_do_it(struct Curl_easy *data, bool *done) +{ + CURLcode result; + bool connected = 0; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + + *done = FALSE; /* default to false */ + + data->req.size = -1; /* make sure this is unknown at this point */ + + sshc->actualcode = CURLE_OK; /* reset error code */ + sshc->secondCreateDirs = 0; /* reset the create dir attempt state + variable */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + if(conn->handler->protocol & CURLPROTO_SCP) + result = scp_perform(data, &connected, done); + else + result = sftp_perform(data, &connected, done); + + return result; +} + +/* BLOCKING, but the function is using the state machine so the only reason + this is still blocking is that the multi interface code has no support for + disconnecting operations that takes a while */ +static CURLcode scp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + CURLcode result = CURLE_OK; + struct ssh_conn *ssh = &conn->proto.sshc; + (void) dead_connection; + + if(ssh->ssh_session) { + /* only if there's a session still around to use! */ + + state(data, SSH_SESSION_DISCONNECT); + + result = myssh_block_statemach(data, TRUE); + } + + return result; +} + +/* generic done function for both SCP and SFTP called from their specific + done functions */ +static CURLcode myssh_done(struct Curl_easy *data, CURLcode status) +{ + CURLcode result = CURLE_OK; + struct SSHPROTO *protop = data->req.p.ssh; + + if(!status) { + /* run the state-machine */ + result = myssh_block_statemach(data, FALSE); + } + else + result = status; + + if(protop) + Curl_safefree(protop->path); + if(Curl_pgrsDone(data)) + return CURLE_ABORTED_BY_CALLBACK; + + data->req.keepon = 0; /* clear all bits */ + return result; +} + + +static CURLcode scp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + (void) premature; /* not used */ + + if(!status) + state(data, SSH_SCP_DONE); + + return myssh_done(data, status); + +} + +static ssize_t scp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + int rc; + struct connectdata *conn = data->conn; + (void) sockindex; /* we only support SCP on the fixed known primary socket */ + (void) err; + + rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len); + +#if 0 + /* The following code is misleading, mostly added as wishful thinking + * that libssh at some point will implement non-blocking ssh_scp_write/read. + * Currently rc can only be number of bytes read or SSH_ERROR. */ + myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE); + + if(rc == SSH_AGAIN) { + *err = CURLE_AGAIN; + return 0; + } + else +#endif + if(rc != SSH_OK) { + *err = CURLE_SSH; + return -1; + } + + return len; +} + +static ssize_t scp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + ssize_t nread; + struct connectdata *conn = data->conn; + (void) err; + (void) sockindex; /* we only support SCP on the fixed known primary socket */ + + /* libssh returns int */ + nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len); + +#if 0 + /* The following code is misleading, mostly added as wishful thinking + * that libssh at some point will implement non-blocking ssh_scp_write/read. + * Currently rc can only be SSH_OK or SSH_ERROR. */ + + myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE); + if(nread == SSH_AGAIN) { + *err = CURLE_AGAIN; + nread = -1; + } +#endif + + return nread; +} + +/* + * =============== SFTP =============== + */ + +/* + *********************************************************************** + * + * sftp_perform() + * + * This is the actual DO function for SFTP. Get a file/directory according to + * the options previously setup. + */ + +static +CURLcode sftp_perform(struct Curl_easy *data, + bool *connected, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + + DEBUGF(infof(data, "DO phase starts")); + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + state(data, SSH_SFTP_QUOTE_INIT); + + /* run the state-machine */ + result = myssh_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +/* called from multi.c while DOing */ +static CURLcode sftp_doing(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = myssh_multi_statemach(data, dophase_done); + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + return result; +} + +/* BLOCKING, but the function is using the state machine so the only reason + this is still blocking is that the multi interface code has no support for + disconnecting operations that takes a while */ +static CURLcode sftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + CURLcode result = CURLE_OK; + (void) dead_connection; + + DEBUGF(infof(data, "SSH DISCONNECT starts now")); + + if(conn->proto.sshc.ssh_session) { + /* only if there's a session still around to use! */ + state(data, SSH_SFTP_SHUTDOWN); + result = myssh_block_statemach(data, TRUE); + } + + DEBUGF(infof(data, "SSH DISCONNECT is done")); + + return result; + +} + +static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + + if(!status) { + /* Post quote commands are executed after the SFTP_CLOSE state to avoid + errors that could happen due to open file handles during POSTQUOTE + operation */ + if(!premature && data->set.postquote && !conn->bits.retry) + sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; + state(data, SSH_SFTP_CLOSE); + } + return myssh_done(data, status); +} + +/* return number of sent bytes */ +static ssize_t sftp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + ssize_t nwrite; + struct connectdata *conn = data->conn; + (void)sockindex; + + /* limit the writes to the maximum specified in Section 3 of + * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02 + */ + if(len > 32768) + len = 32768; + + nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len); + + myssh_block2waitfor(conn, FALSE); + +#if 0 /* not returned by libssh on write */ + if(nwrite == SSH_AGAIN) { + *err = CURLE_AGAIN; + nwrite = 0; + } + else +#endif + if(nwrite < 0) { + *err = CURLE_SSH; + nwrite = -1; + } + + return nwrite; +} + +/* + * Return number of received (decrypted) bytes + * or <0 on error + */ +static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + ssize_t nread; + struct connectdata *conn = data->conn; + (void)sockindex; + + DEBUGASSERT(len < CURL_MAX_READ_SIZE); + + switch(conn->proto.sshc.sftp_recv_state) { + case 0: + conn->proto.sshc.sftp_file_index = + sftp_async_read_begin(conn->proto.sshc.sftp_file, + (uint32_t)len); + if(conn->proto.sshc.sftp_file_index < 0) { + *err = CURLE_RECV_ERROR; + return -1; + } + + FALLTHROUGH(); + case 1: + conn->proto.sshc.sftp_recv_state = 1; + + nread = sftp_async_read(conn->proto.sshc.sftp_file, + mem, (uint32_t)len, + conn->proto.sshc.sftp_file_index); + + myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE); + + if(nread == SSH_AGAIN) { + *err = CURLE_AGAIN; + return -1; + } + else if(nread < 0) { + *err = CURLE_RECV_ERROR; + return -1; + } + + conn->proto.sshc.sftp_recv_state = 0; + return nread; + + default: + /* we never reach here */ + return -1; + } +} + +static void sftp_quote(struct Curl_easy *data) +{ + const char *cp; + struct connectdata *conn = data->conn; + struct SSHPROTO *protop = data->req.p.ssh; + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result; + + /* + * Support some of the "FTP" commands + */ + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server responds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + if(strcasecompare("pwd", cmd)) { + /* output debug output if that is requested */ + char *tmp = aprintf("257 \"%s\" is current directory.\n", + protop->path); + if(!tmp) { + sshc->actualcode = CURLE_OUT_OF_MEMORY; + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + return; + } + Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4); + Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp)); + + /* this sends an FTP-like "header" to the header callback so that the + current directory can be read very similar to how it is read when + using ordinary FTP. */ + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + else + state(data, SSH_SFTP_NEXT_QUOTE); + return; + } + + /* + * the arguments following the command must be separated from the + * command with a space so we can check for it unconditionally + */ + cp = strchr(cmd, ' '); + if(!cp) { + failf(data, "Syntax error in SFTP command. Supply parameter(s)"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return; + } + + /* + * also, every command takes at least one argument so we get that + * first argument right now + */ + result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error: Bad first parameter"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return; + } + + /* + * SFTP is a binary protocol, so we don't send text commands + * to the server. Instead, we scan for commands used by + * OpenSSH's sftp program and call the appropriate libssh + * functions. + */ + if(strncasecompare(cmd, "chgrp ", 6) || + strncasecompare(cmd, "chmod ", 6) || + strncasecompare(cmd, "chown ", 6) || + strncasecompare(cmd, "atime ", 6) || + strncasecompare(cmd, "mtime ", 6)) { + /* attribute change */ + + /* sshc->quote_path1 contains the mode to set */ + /* get the destination */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: " + "Bad second parameter"); + Curl_safefree(sshc->quote_path1); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return; + } + sshc->quote_attrs = NULL; + state(data, SSH_SFTP_QUOTE_STAT); + return; + } + if(strncasecompare(cmd, "ln ", 3) || + strncasecompare(cmd, "symlink ", 8)) { + /* symbolic linking */ + /* sshc->quote_path1 is the source */ + /* get the destination */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in ln/symlink: Bad second parameter"); + Curl_safefree(sshc->quote_path1); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return; + } + state(data, SSH_SFTP_QUOTE_SYMLINK); + return; + } + else if(strncasecompare(cmd, "mkdir ", 6)) { + /* create dir */ + state(data, SSH_SFTP_QUOTE_MKDIR); + return; + } + else if(strncasecompare(cmd, "rename ", 7)) { + /* rename file */ + /* first param is the source path */ + /* second param is the dest. path */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in rename: Bad second parameter"); + Curl_safefree(sshc->quote_path1); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return; + } + state(data, SSH_SFTP_QUOTE_RENAME); + return; + } + else if(strncasecompare(cmd, "rmdir ", 6)) { + /* delete dir */ + state(data, SSH_SFTP_QUOTE_RMDIR); + return; + } + else if(strncasecompare(cmd, "rm ", 3)) { + state(data, SSH_SFTP_QUOTE_UNLINK); + return; + } +#ifdef HAS_STATVFS_SUPPORT + else if(strncasecompare(cmd, "statvfs ", 8)) { + state(data, SSH_SFTP_QUOTE_STATVFS); + return; + } +#endif + + failf(data, "Unknown SFTP command"); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; +} + +static void sftp_quote_stat(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server responds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + /* We read the file attributes, store them in sshc->quote_attrs + * and modify them accordingly to command. Then we switch to + * QUOTE_SETSTAT state to write new ones. + */ + + if(sshc->quote_attrs) + sftp_attributes_free(sshc->quote_attrs); + sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2); + if(!sshc->quote_attrs) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Attempt to get SFTP stats failed: %d", + sftp_get_error(sshc->sftp_session)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return; + } + + /* Now set the new attributes... */ + if(strncasecompare(cmd, "chgrp", 5)) { + sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10); + if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chgrp gid not a number"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return; + } + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; + } + else if(strncasecompare(cmd, "chmod", 5)) { + mode_t perms; + perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8); + /* permissions are octal */ + if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chmod permissions not a number"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return; + } + sshc->quote_attrs->permissions = perms; + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS; + } + else if(strncasecompare(cmd, "chown", 5)) { + sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10); + if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chown uid not a number"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return; + } + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; + } + else if(strncasecompare(cmd, "atime", 5) || + strncasecompare(cmd, "mtime", 5)) { + time_t date = Curl_getdate_capped(sshc->quote_path1); + bool fail = FALSE; + if(date == -1) { + failf(data, "incorrect date format for %.*s", 5, cmd); + fail = TRUE; + } +#if SIZEOF_TIME_T > 4 + else if(date > 0xffffffff) { + failf(data, "date overflow"); + fail = TRUE; /* avoid setting a capped time */ + } +#endif + if(fail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return; + } + if(strncasecompare(cmd, "atime", 5)) + sshc->quote_attrs->atime = (uint32_t)date; + else /* mtime */ + sshc->quote_attrs->mtime = (uint32_t)date; + + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME; + } + + /* Now send the completed structure... */ + state(data, SSH_SFTP_QUOTE_SETSTAT); + return; +} + +CURLcode Curl_ssh_init(void) +{ + if(ssh_init()) { + DEBUGF(fprintf(stderr, "Error: libssh_init failed\n")); + return CURLE_FAILED_INIT; + } + return CURLE_OK; +} + +void Curl_ssh_cleanup(void) +{ + (void)ssh_finalize(); +} + +void Curl_ssh_version(char *buffer, size_t buflen) +{ + (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0)); +} + +#endif /* USE_LIBSSH */ diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c new file mode 100644 index 0000000..e9dfef9 --- /dev/null +++ b/lib/vssh/libssh2.c @@ -0,0 +1,3830 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* #define CURL_LIBSSH2_DEBUG */ + +#include "curl_setup.h" + +#ifdef USE_LIBSSH2 + +#include + +#include +#include + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "ssh.h" +#include "url.h" +#include "speedcheck.h" +#include "getinfo.h" +#include "strdup.h" +#include "strcase.h" +#include "vtls/vtls.h" +#include "cfilters.h" +#include "connect.h" +#include "inet_ntop.h" +#include "parsedate.h" /* for the week day and month names */ +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "strtoofft.h" +#include "multiif.h" +#include "select.h" +#include "warnless.h" +#include "curl_path.h" + +#include /* for base64 encoding/decoding */ +#include + + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#if LIBSSH2_VERSION_NUM >= 0x010206 +/* libssh2_sftp_statvfs and friends were added in 1.2.6 */ +#define HAS_STATVFS_SUPPORT 1 +#endif + +#define sftp_libssh2_realpath(s,p,t,m) \ + libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \ + (t), (m), LIBSSH2_SFTP_REALPATH) + +/* Local functions: */ +static const char *sftp_libssh2_strerror(unsigned long err); +static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); +static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); +static LIBSSH2_FREE_FUNC(my_libssh2_free); +static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data); +static CURLcode ssh_connect(struct Curl_easy *data, bool *done); +static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done); +static CURLcode ssh_do(struct Curl_easy *data, bool *done); +static CURLcode scp_done(struct Curl_easy *data, CURLcode c, bool premature); +static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done); +static CURLcode scp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection); +static CURLcode sftp_done(struct Curl_easy *data, CURLcode, bool premature); +static CURLcode sftp_doing(struct Curl_easy *data, bool *dophase_done); +static CURLcode sftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead); +static CURLcode sftp_perform(struct Curl_easy *data, bool *connected, + bool *dophase_done); +static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *sock); +static CURLcode ssh_setup_connection(struct Curl_easy *data, + struct connectdata *conn); +static void ssh_attach(struct Curl_easy *data, struct connectdata *conn); + +/* + * SCP protocol handler. + */ + +const struct Curl_handler Curl_handler_scp = { + "SCP", /* scheme */ + ssh_setup_connection, /* setup_connection */ + ssh_do, /* do_it */ + scp_done, /* done */ + ZERO_NULL, /* do_more */ + ssh_connect, /* connect_it */ + ssh_multi_statemach, /* connecting */ + scp_doing, /* doing */ + ssh_getsock, /* proto_getsock */ + ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ssh_getsock, /* perform_getsock */ + scp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ssh_attach, /* attach */ + PORT_SSH, /* defport */ + CURLPROTO_SCP, /* protocol */ + CURLPROTO_SCP, /* family */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ +}; + + +/* + * SFTP protocol handler. + */ + +const struct Curl_handler Curl_handler_sftp = { + "SFTP", /* scheme */ + ssh_setup_connection, /* setup_connection */ + ssh_do, /* do_it */ + sftp_done, /* done */ + ZERO_NULL, /* do_more */ + ssh_connect, /* connect_it */ + ssh_multi_statemach, /* connecting */ + sftp_doing, /* doing */ + ssh_getsock, /* proto_getsock */ + ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ssh_getsock, /* perform_getsock */ + sftp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ssh_attach, /* attach */ + PORT_SSH, /* defport */ + CURLPROTO_SFTP, /* protocol */ + CURLPROTO_SFTP, /* family */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ +}; + +static void +kbd_callback(const char *name, int name_len, const char *instruction, + int instruction_len, int num_prompts, + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, + void **abstract) +{ + struct Curl_easy *data = (struct Curl_easy *)*abstract; + +#ifdef CURL_LIBSSH2_DEBUG + fprintf(stderr, "name=%s\n", name); + fprintf(stderr, "name_len=%d\n", name_len); + fprintf(stderr, "instruction=%s\n", instruction); + fprintf(stderr, "instruction_len=%d\n", instruction_len); + fprintf(stderr, "num_prompts=%d\n", num_prompts); +#else + (void)name; + (void)name_len; + (void)instruction; + (void)instruction_len; +#endif /* CURL_LIBSSH2_DEBUG */ + if(num_prompts == 1) { + struct connectdata *conn = data->conn; + responses[0].text = strdup(conn->passwd); + responses[0].length = curlx_uztoui(strlen(conn->passwd)); + } + (void)prompts; +} /* kbd_callback */ + +static CURLcode sftp_libssh2_error_to_CURLE(unsigned long err) +{ + switch(err) { + case LIBSSH2_FX_OK: + return CURLE_OK; + + case LIBSSH2_FX_NO_SUCH_FILE: + case LIBSSH2_FX_NO_SUCH_PATH: + return CURLE_REMOTE_FILE_NOT_FOUND; + + case LIBSSH2_FX_PERMISSION_DENIED: + case LIBSSH2_FX_WRITE_PROTECT: + case LIBSSH2_FX_LOCK_CONFlICT: + return CURLE_REMOTE_ACCESS_DENIED; + + case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: + case LIBSSH2_FX_QUOTA_EXCEEDED: + return CURLE_REMOTE_DISK_FULL; + + case LIBSSH2_FX_FILE_ALREADY_EXISTS: + return CURLE_REMOTE_FILE_EXISTS; + + case LIBSSH2_FX_DIR_NOT_EMPTY: + return CURLE_QUOTE_ERROR; + + default: + break; + } + + return CURLE_SSH; +} + +static CURLcode libssh2_session_error_to_CURLE(int err) +{ + switch(err) { + /* Ordered by order of appearance in libssh2.h */ + case LIBSSH2_ERROR_NONE: + return CURLE_OK; + + /* This is the error returned by libssh2_scp_recv2 + * on unknown file */ + case LIBSSH2_ERROR_SCP_PROTOCOL: + return CURLE_REMOTE_FILE_NOT_FOUND; + + case LIBSSH2_ERROR_SOCKET_NONE: + return CURLE_COULDNT_CONNECT; + + case LIBSSH2_ERROR_ALLOC: + return CURLE_OUT_OF_MEMORY; + + case LIBSSH2_ERROR_SOCKET_SEND: + return CURLE_SEND_ERROR; + + case LIBSSH2_ERROR_HOSTKEY_INIT: + case LIBSSH2_ERROR_HOSTKEY_SIGN: + case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED: + case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED: + return CURLE_PEER_FAILED_VERIFICATION; + + case LIBSSH2_ERROR_PASSWORD_EXPIRED: + return CURLE_LOGIN_DENIED; + + case LIBSSH2_ERROR_SOCKET_TIMEOUT: + case LIBSSH2_ERROR_TIMEOUT: + return CURLE_OPERATION_TIMEDOUT; + + case LIBSSH2_ERROR_EAGAIN: + return CURLE_AGAIN; + } + + return CURLE_SSH; +} + +static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc) +{ + (void)abstract; /* arg not used */ + return malloc(count); +} + +static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc) +{ + (void)abstract; /* arg not used */ + return realloc(ptr, count); +} + +static LIBSSH2_FREE_FUNC(my_libssh2_free) +{ + (void)abstract; /* arg not used */ + if(ptr) /* ssh2 agent sometimes call free with null ptr */ + free(ptr); +} + +/* + * SSH State machine related code + */ +/* This is the ONLY way to change SSH state! */ +static void state(struct Curl_easy *data, sshstate nowstate) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[] = { + "SSH_STOP", + "SSH_INIT", + "SSH_S_STARTUP", + "SSH_HOSTKEY", + "SSH_AUTHLIST", + "SSH_AUTH_PKEY_INIT", + "SSH_AUTH_PKEY", + "SSH_AUTH_PASS_INIT", + "SSH_AUTH_PASS", + "SSH_AUTH_AGENT_INIT", + "SSH_AUTH_AGENT_LIST", + "SSH_AUTH_AGENT", + "SSH_AUTH_HOST_INIT", + "SSH_AUTH_HOST", + "SSH_AUTH_KEY_INIT", + "SSH_AUTH_KEY", + "SSH_AUTH_GSSAPI", + "SSH_AUTH_DONE", + "SSH_SFTP_INIT", + "SSH_SFTP_REALPATH", + "SSH_SFTP_QUOTE_INIT", + "SSH_SFTP_POSTQUOTE_INIT", + "SSH_SFTP_QUOTE", + "SSH_SFTP_NEXT_QUOTE", + "SSH_SFTP_QUOTE_STAT", + "SSH_SFTP_QUOTE_SETSTAT", + "SSH_SFTP_QUOTE_SYMLINK", + "SSH_SFTP_QUOTE_MKDIR", + "SSH_SFTP_QUOTE_RENAME", + "SSH_SFTP_QUOTE_RMDIR", + "SSH_SFTP_QUOTE_UNLINK", + "SSH_SFTP_QUOTE_STATVFS", + "SSH_SFTP_GETINFO", + "SSH_SFTP_FILETIME", + "SSH_SFTP_TRANS_INIT", + "SSH_SFTP_UPLOAD_INIT", + "SSH_SFTP_CREATE_DIRS_INIT", + "SSH_SFTP_CREATE_DIRS", + "SSH_SFTP_CREATE_DIRS_MKDIR", + "SSH_SFTP_READDIR_INIT", + "SSH_SFTP_READDIR", + "SSH_SFTP_READDIR_LINK", + "SSH_SFTP_READDIR_BOTTOM", + "SSH_SFTP_READDIR_DONE", + "SSH_SFTP_DOWNLOAD_INIT", + "SSH_SFTP_DOWNLOAD_STAT", + "SSH_SFTP_CLOSE", + "SSH_SFTP_SHUTDOWN", + "SSH_SCP_TRANS_INIT", + "SSH_SCP_UPLOAD_INIT", + "SSH_SCP_DOWNLOAD_INIT", + "SSH_SCP_DOWNLOAD", + "SSH_SCP_DONE", + "SSH_SCP_SEND_EOF", + "SSH_SCP_WAIT_EOF", + "SSH_SCP_WAIT_CLOSE", + "SSH_SCP_CHANNEL_FREE", + "SSH_SESSION_DISCONNECT", + "SSH_SESSION_FREE", + "QUIT" + }; + + /* a precaution to make sure the lists are in sync */ + DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST); + + if(sshc->state != nowstate) { + infof(data, "SFTP %p state change from %s to %s", + (void *)sshc, names[sshc->state], names[nowstate]); + } +#endif + + sshc->state = nowstate; +} + + +#ifdef HAVE_LIBSSH2_KNOWNHOST_API +static int sshkeycallback(struct Curl_easy *easy, + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch match, + void *clientp) +{ + (void)easy; + (void)knownkey; + (void)foundkey; + (void)clientp; + + /* we only allow perfect matches, and we reject everything else */ + return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE; +} +#endif + +/* + * Earlier libssh2 versions didn't have the ability to seek to 64bit positions + * with 32bit size_t. + */ +#ifdef HAVE_LIBSSH2_SFTP_SEEK64 +#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y) +#else +#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y) +#endif + +/* + * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit + * architectures so we check of the necessary function is present. + */ +#ifndef HAVE_LIBSSH2_SCP_SEND64 +#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0) +#else +#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \ + (libssh2_uint64_t)d, 0, 0) +#endif + +/* + * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64. + */ +#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE +#define session_startup(x,y) libssh2_session_handshake(x, y) +#else +#define session_startup(x,y) libssh2_session_startup(x, (int)y) +#endif +static int convert_ssh2_keytype(int sshkeytype) +{ + int keytype = CURLKHTYPE_UNKNOWN; + switch(sshkeytype) { + case LIBSSH2_HOSTKEY_TYPE_RSA: + keytype = CURLKHTYPE_RSA; + break; + case LIBSSH2_HOSTKEY_TYPE_DSS: + keytype = CURLKHTYPE_DSS; + break; +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: + keytype = CURLKHTYPE_ECDSA; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: + keytype = CURLKHTYPE_ECDSA; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: + keytype = CURLKHTYPE_ECDSA; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 + case LIBSSH2_HOSTKEY_TYPE_ED25519: + keytype = CURLKHTYPE_ED25519; + break; +#endif + } + return keytype; +} + +static CURLcode ssh_knownhost(struct Curl_easy *data) +{ + int sshkeytype = 0; + size_t keylen = 0; + int rc = 0; + CURLcode result = CURLE_OK; + +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + if(data->set.str[STRING_SSH_KNOWNHOSTS]) { + /* we're asked to verify the host against a file */ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + struct libssh2_knownhost *host = NULL; + const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, + &keylen, &sshkeytype); + int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE; + int keybit = 0; + + if(remotekey) { + /* + * A subject to figure out is what host name we need to pass in here. + * What host name does OpenSSH store in its file if an IDN name is + * used? + */ + enum curl_khmatch keymatch; + curl_sshkeycallback func = + data->set.ssh_keyfunc ? data->set.ssh_keyfunc : sshkeycallback; + struct curl_khkey knownkey; + struct curl_khkey *knownkeyp = NULL; + struct curl_khkey foundkey; + + switch(sshkeytype) { + case LIBSSH2_HOSTKEY_TYPE_RSA: + keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA; + break; + case LIBSSH2_HOSTKEY_TYPE_DSS: + keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS; + break; +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: + keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: + keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: + keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 + case LIBSSH2_HOSTKEY_TYPE_ED25519: + keybit = LIBSSH2_KNOWNHOST_KEY_ED25519; + break; +#endif + default: + infof(data, "unsupported key type, can't check knownhosts"); + keybit = 0; + break; + } + if(!keybit) + /* no check means failure! */ + rc = CURLKHSTAT_REJECT; + else { +#ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP + keycheck = libssh2_knownhost_checkp(sshc->kh, + conn->host.name, + (conn->remote_port != PORT_SSH)? + conn->remote_port:-1, + remotekey, keylen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN| + LIBSSH2_KNOWNHOST_KEYENC_RAW| + keybit, + &host); +#else + keycheck = libssh2_knownhost_check(sshc->kh, + conn->host.name, + remotekey, keylen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN| + LIBSSH2_KNOWNHOST_KEYENC_RAW| + keybit, + &host); +#endif + + infof(data, "SSH host check: %d, key: %s", keycheck, + (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)? + host->key:""); + + /* setup 'knownkey' */ + if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { + knownkey.key = host->key; + knownkey.len = 0; + knownkey.keytype = convert_ssh2_keytype(sshkeytype); + knownkeyp = &knownkey; + } + + /* setup 'foundkey' */ + foundkey.key = remotekey; + foundkey.len = keylen; + foundkey.keytype = convert_ssh2_keytype(sshkeytype); + + /* + * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the + * curl_khmatch enum are ever modified, we need to introduce a + * translation table here! + */ + keymatch = (enum curl_khmatch)keycheck; + + /* Ask the callback how to behave */ + Curl_set_in_callback(data, true); + rc = func(data, knownkeyp, /* from the knownhosts file */ + &foundkey, /* from the remote host */ + keymatch, data->set.ssh_keyfunc_userp); + Curl_set_in_callback(data, false); + } + } + else + /* no remotekey means failure! */ + rc = CURLKHSTAT_REJECT; + + switch(rc) { + default: /* unknown return codes will equal reject */ + case CURLKHSTAT_REJECT: + state(data, SSH_SESSION_FREE); + FALLTHROUGH(); + case CURLKHSTAT_DEFER: + /* DEFER means bail out but keep the SSH_HOSTKEY state */ + result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + break; + case CURLKHSTAT_FINE_REPLACE: + /* remove old host+key that doesn't match */ + if(host) + libssh2_knownhost_del(sshc->kh, host); + FALLTHROUGH(); + case CURLKHSTAT_FINE: + case CURLKHSTAT_FINE_ADD_TO_FILE: + /* proceed */ + if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) { + /* the found host+key didn't match but has been told to be fine + anyway so we add it in memory */ + int addrc = libssh2_knownhost_add(sshc->kh, + conn->host.name, NULL, + remotekey, keylen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN| + LIBSSH2_KNOWNHOST_KEYENC_RAW| + keybit, NULL); + if(addrc) + infof(data, "WARNING: adding the known host %s failed", + conn->host.name); + else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE || + rc == CURLKHSTAT_FINE_REPLACE) { + /* now we write the entire in-memory list of known hosts to the + known_hosts file */ + int wrc = + libssh2_knownhost_writefile(sshc->kh, + data->set.str[STRING_SSH_KNOWNHOSTS], + LIBSSH2_KNOWNHOST_FILE_OPENSSH); + if(wrc) { + infof(data, "WARNING: writing %s failed", + data->set.str[STRING_SSH_KNOWNHOSTS]); + } + } + } + break; + } + } +#else /* HAVE_LIBSSH2_KNOWNHOST_API */ + (void)data; +#endif + return result; +} + +static CURLcode ssh_check_fingerprint(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; + const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]; + + infof(data, "SSH MD5 public key: %s", + pubkey_md5 != NULL ? pubkey_md5 : "NULL"); + infof(data, "SSH SHA256 public key: %s", + pubkey_sha256 != NULL ? pubkey_sha256 : "NULL"); + + if(pubkey_sha256) { + const char *fingerprint = NULL; + char *fingerprint_b64 = NULL; + size_t fingerprint_b64_len; + size_t pub_pos = 0; + size_t b64_pos = 0; + +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + /* The fingerprint points to static storage (!), don't free() it. */ + fingerprint = libssh2_hostkey_hash(sshc->ssh_session, + LIBSSH2_HOSTKEY_HASH_SHA256); +#else + const char *hostkey; + size_t len = 0; + unsigned char hash[32]; + + hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL); + if(hostkey) { + if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len)) + fingerprint = (char *) hash; + } +#endif + + if(!fingerprint) { + failf(data, + "Denied establishing ssh session: sha256 fingerprint " + "not available"); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + + /* The length of fingerprint is 32 bytes for SHA256. + * See libssh2_hostkey_hash documentation. */ + if(Curl_base64_encode(fingerprint, 32, &fingerprint_b64, + &fingerprint_b64_len) != CURLE_OK) { + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + + if(!fingerprint_b64) { + failf(data, "sha256 fingerprint could not be encoded"); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + + infof(data, "SSH SHA256 fingerprint: %s", fingerprint_b64); + + /* Find the position of any = padding characters in the public key */ + while((pubkey_sha256[pub_pos] != '=') && pubkey_sha256[pub_pos]) { + pub_pos++; + } + + /* Find the position of any = padding characters in the base64 coded + * hostkey fingerprint */ + while((fingerprint_b64[b64_pos] != '=') && fingerprint_b64[b64_pos]) { + b64_pos++; + } + + /* Before we authenticate we check the hostkey's sha256 fingerprint + * against a known fingerprint, if available. + */ + if((pub_pos != b64_pos) || + strncmp(fingerprint_b64, pubkey_sha256, pub_pos)) { + failf(data, + "Denied establishing ssh session: mismatch sha256 fingerprint. " + "Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256); + free(fingerprint_b64); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + + free(fingerprint_b64); + + infof(data, "SHA256 checksum match"); + } + + if(pubkey_md5) { + char md5buffer[33]; + const char *fingerprint = NULL; + + fingerprint = libssh2_hostkey_hash(sshc->ssh_session, + LIBSSH2_HOSTKEY_HASH_MD5); + + if(fingerprint) { + /* The fingerprint points to static storage (!), don't free() it. */ + int i; + for(i = 0; i < 16; i++) { + msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); + } + + infof(data, "SSH MD5 fingerprint: %s", md5buffer); + } + + /* This does NOT verify the length of 'pubkey_md5' separately, which will + make the comparison below fail unless it is exactly 32 characters */ + if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) { + if(fingerprint) { + failf(data, + "Denied establishing ssh session: mismatch md5 fingerprint. " + "Remote %s is not equal to %s", md5buffer, pubkey_md5); + } + else { + failf(data, + "Denied establishing ssh session: md5 fingerprint " + "not available"); + } + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + infof(data, "MD5 checksum match"); + } + + if(!pubkey_md5 && !pubkey_sha256) { + if(data->set.ssh_hostkeyfunc) { + size_t keylen = 0; + int sshkeytype = 0; + int rc = 0; + /* we handle the process to the callback */ + const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, + &keylen, &sshkeytype); + if(remotekey) { + int keytype = convert_ssh2_keytype(sshkeytype); + Curl_set_in_callback(data, true); + rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp, + keytype, remotekey, keylen); + Curl_set_in_callback(data, false); + if(rc!= CURLKHMATCH_OK) { + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + } + else { + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + return CURLE_OK; + } + else { + return ssh_knownhost(data); + } + } + else { + /* as we already matched, we skip the check for known hosts */ + return CURLE_OK; + } +} + +/* + * ssh_force_knownhost_key_type() will check the known hosts file and try to + * force a specific public key type from the server if an entry is found. + */ +static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 + static const char * const hostkey_method_ssh_ed25519 + = "ssh-ed25519"; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 + static const char * const hostkey_method_ssh_ecdsa_521 + = "ecdsa-sha2-nistp521"; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 + static const char * const hostkey_method_ssh_ecdsa_384 + = "ecdsa-sha2-nistp384"; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 + static const char * const hostkey_method_ssh_ecdsa_256 + = "ecdsa-sha2-nistp256"; +#endif + static const char * const hostkey_method_ssh_rsa + = "ssh-rsa"; + static const char * const hostkey_method_ssh_rsa_all + = "rsa-sha2-256,rsa-sha2-512,ssh-rsa"; + static const char * const hostkey_method_ssh_dss + = "ssh-dss"; + + const char *hostkey_method = NULL; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + struct libssh2_knownhost* store = NULL; + const char *kh_name_end = NULL; + size_t kh_name_size = 0; + int port = 0; + bool found = false; + + if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { + /* lets try to find our host in the known hosts file */ + while(!libssh2_knownhost_get(sshc->kh, &store, store)) { + /* For non-standard ports, the name will be enclosed in */ + /* square brackets, followed by a colon and the port */ + if(store) { + if(store->name) { + if(store->name[0] == '[') { + kh_name_end = strstr(store->name, "]:"); + if(!kh_name_end) { + infof(data, "Invalid host pattern %s in %s", + store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); + continue; + } + port = atoi(kh_name_end + 2); + if(kh_name_end && (port == conn->remote_port)) { + kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end); + if(strncmp(store->name + 1, + conn->host.name, kh_name_size) == 0) { + found = true; + break; + } + } + } + else if(strcmp(store->name, conn->host.name) == 0) { + found = true; + break; + } + } + else { + found = true; + break; + } + } + } + + if(found) { + int rc; + infof(data, "Found host %s in %s", + conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); + + switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 + case LIBSSH2_KNOWNHOST_KEY_ED25519: + hostkey_method = hostkey_method_ssh_ed25519; + break; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 + case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: + hostkey_method = hostkey_method_ssh_ecdsa_521; + break; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 + case LIBSSH2_KNOWNHOST_KEY_ECDSA_384: + hostkey_method = hostkey_method_ssh_ecdsa_384; + break; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 + case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: + hostkey_method = hostkey_method_ssh_ecdsa_256; + break; +#endif + case LIBSSH2_KNOWNHOST_KEY_SSHRSA: +#ifdef HAVE_LIBSSH2_VERSION + if(libssh2_version(0x010900)) + /* since 1.9.0 libssh2_session_method_pref() works as expected */ + hostkey_method = hostkey_method_ssh_rsa_all; + else +#endif + /* old libssh2 which cannot correctly remove unsupported methods due + * to bug in src/kex.c or does not support the new methods anyways. + */ + hostkey_method = hostkey_method_ssh_rsa; + break; + case LIBSSH2_KNOWNHOST_KEY_SSHDSS: + hostkey_method = hostkey_method_ssh_dss; + break; + case LIBSSH2_KNOWNHOST_KEY_RSA1: + failf(data, "Found host key type RSA1 which is not supported"); + return CURLE_SSH; + default: + failf(data, "Unknown host key type: %i", + (store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK)); + return CURLE_SSH; + } + + infof(data, "Set \"%s\" as SSH hostkey type", hostkey_method); + rc = libssh2_session_method_pref(sshc->ssh_session, + LIBSSH2_METHOD_HOSTKEY, hostkey_method); + if(rc) { + char *errmsg = NULL; + int errlen; + libssh2_session_last_error(sshc->ssh_session, &errmsg, &errlen, 0); + failf(data, "libssh2: %s", errmsg); + result = libssh2_session_error_to_CURLE(rc); + } + } + else { + infof(data, "Did not find host %s in %s", + conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); + } + } + +#endif /* HAVE_LIBSSH2_KNOWNHOST_API */ + + return result; +} + +/* + * ssh_statemach_act() runs the SSH state machine as far as it can without + * blocking and without reaching the end. The data the pointer 'block' points + * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN + * meaning it wants to be called again when the socket is ready + */ + +static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct SSHPROTO *sshp = data->req.p.ssh; + struct ssh_conn *sshc = &conn->proto.sshc; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc = LIBSSH2_ERROR_NONE; + int ssherr; + unsigned long sftperr; + int seekerr = CURL_SEEKFUNC_OK; + size_t readdir_len; + *block = 0; /* we're not blocking by default */ + + do { + switch(sshc->state) { + case SSH_INIT: + sshc->secondCreateDirs = 0; + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_OK; + + /* Set libssh2 to non-blocking, since everything internally is + non-blocking */ + libssh2_session_set_blocking(sshc->ssh_session, 0); + + result = ssh_force_knownhost_key_type(data); + if(result) { + state(data, SSH_SESSION_FREE); + sshc->actualcode = result; + break; + } + + state(data, SSH_S_STARTUP); + FALLTHROUGH(); + + case SSH_S_STARTUP: + rc = session_startup(sshc->ssh_session, sock); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); + failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg); + + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_FAILED_INIT; + break; + } + + state(data, SSH_HOSTKEY); + + FALLTHROUGH(); + case SSH_HOSTKEY: + /* + * Before we authenticate we should check the hostkey's fingerprint + * against our known hosts. How that is handled (reading from file, + * whatever) is up to us. + */ + result = ssh_check_fingerprint(data); + if(!result) + state(data, SSH_AUTHLIST); + /* ssh_check_fingerprint sets state appropriately on error */ + break; + + case SSH_AUTHLIST: + /* + * Figure out authentication methods + * NB: As soon as we have provided a username to an openssh server we + * must never change it later. Thus, always specify the correct username + * here, even though the libssh2 docs kind of indicate that it should be + * possible to get a 'generic' list (not user-specific) of authentication + * methods, presumably with a blank username. That won't work in my + * experience. + * So always specify it here. + */ + sshc->authlist = libssh2_userauth_list(sshc->ssh_session, + conn->user, + curlx_uztoui(strlen(conn->user))); + + if(!sshc->authlist) { + if(libssh2_userauth_authenticated(sshc->ssh_session)) { + sshc->authed = TRUE; + infof(data, "SSH user accepted with no authentication"); + state(data, SSH_AUTH_DONE); + break; + } + ssherr = libssh2_session_last_errno(sshc->ssh_session); + if(ssherr == LIBSSH2_ERROR_EAGAIN) + rc = LIBSSH2_ERROR_EAGAIN; + else { + state(data, SSH_SESSION_FREE); + sshc->actualcode = libssh2_session_error_to_CURLE(ssherr); + } + break; + } + infof(data, "SSH authentication methods available: %s", + sshc->authlist); + + state(data, SSH_AUTH_PKEY_INIT); + break; + + case SSH_AUTH_PKEY_INIT: + /* + * Check the supported auth types in the order I feel is most secure + * with the requested type of authentication + */ + sshc->authed = FALSE; + + if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && + (strstr(sshc->authlist, "publickey") != NULL)) { + bool out_of_memory = FALSE; + + sshc->rsa_pub = sshc->rsa = NULL; + + if(data->set.str[STRING_SSH_PRIVATE_KEY]) + sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]); + else { + /* To ponder about: should really the lib be messing about with the + HOME environment variable etc? */ + char *home = curl_getenv("HOME"); + + /* If no private key file is specified, try some common paths. */ + if(home) { + /* Try ~/.ssh first. */ + sshc->rsa = aprintf("%s/.ssh/id_rsa", home); + if(!sshc->rsa) + out_of_memory = TRUE; + else if(access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + sshc->rsa = aprintf("%s/.ssh/id_dsa", home); + if(!sshc->rsa) + out_of_memory = TRUE; + else if(access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + } + } + free(home); + } + if(!out_of_memory && !sshc->rsa) { + /* Nothing found; try the current dir. */ + sshc->rsa = strdup("id_rsa"); + if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + sshc->rsa = strdup("id_dsa"); + if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + /* Out of guesses. Set to the empty string to avoid + * surprising info messages. */ + sshc->rsa = strdup(""); + } + } + } + } + + /* + * Unless the user explicitly specifies a public key file, let + * libssh2 extract the public key from the private key file. + * This is done by simply passing sshc->rsa_pub = NULL. + */ + if(data->set.str[STRING_SSH_PUBLIC_KEY] + /* treat empty string the same way as NULL */ + && data->set.str[STRING_SSH_PUBLIC_KEY][0]) { + sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); + if(!sshc->rsa_pub) + out_of_memory = TRUE; + } + + if(out_of_memory || !sshc->rsa) { + Curl_safefree(sshc->rsa); + Curl_safefree(sshc->rsa_pub); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + + sshc->passphrase = data->set.ssl.key_passwd; + if(!sshc->passphrase) + sshc->passphrase = ""; + + if(sshc->rsa_pub) + infof(data, "Using SSH public key file '%s'", sshc->rsa_pub); + infof(data, "Using SSH private key file '%s'", sshc->rsa); + + state(data, SSH_AUTH_PKEY); + } + else { + state(data, SSH_AUTH_PASS_INIT); + } + break; + + case SSH_AUTH_PKEY: + /* The function below checks if the files exists, no need to stat() here. + */ + rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session, + conn->user, + curlx_uztoui( + strlen(conn->user)), + sshc->rsa_pub, + sshc->rsa, sshc->passphrase); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + + if(rc == 0) { + sshc->authed = TRUE; + infof(data, "Initialized SSH public key authentication"); + state(data, SSH_AUTH_DONE); + } + else { + char *err_msg = NULL; + char unknown[] = "Reason unknown (-1)"; + if(rc == -1) { + /* No error message has been set and the last set error message, if + any, is from a previous error so ignore it. #11837 */ + err_msg = unknown; + } + else { + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + } + infof(data, "SSH public key authentication failed: %s", err_msg); + state(data, SSH_AUTH_PASS_INIT); + rc = 0; /* clear rc and continue */ + } + break; + + case SSH_AUTH_PASS_INIT: + if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) && + (strstr(sshc->authlist, "password") != NULL)) { + state(data, SSH_AUTH_PASS); + } + else { + state(data, SSH_AUTH_HOST_INIT); + rc = 0; /* clear rc and continue */ + } + break; + + case SSH_AUTH_PASS: + rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user, + curlx_uztoui(strlen(conn->user)), + conn->passwd, + curlx_uztoui(strlen(conn->passwd)), + NULL); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc == 0) { + sshc->authed = TRUE; + infof(data, "Initialized password authentication"); + state(data, SSH_AUTH_DONE); + } + else { + state(data, SSH_AUTH_HOST_INIT); + rc = 0; /* clear rc and continue */ + } + break; + + case SSH_AUTH_HOST_INIT: + if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) && + (strstr(sshc->authlist, "hostbased") != NULL)) { + state(data, SSH_AUTH_HOST); + } + else { + state(data, SSH_AUTH_AGENT_INIT); + } + break; + + case SSH_AUTH_HOST: + state(data, SSH_AUTH_AGENT_INIT); + break; + + case SSH_AUTH_AGENT_INIT: +#ifdef HAVE_LIBSSH2_AGENT_API + if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT) + && (strstr(sshc->authlist, "publickey") != NULL)) { + + /* Connect to the ssh-agent */ + /* The agent could be shared by a curl thread i believe + but nothing obvious as keys can be added/removed at any time */ + if(!sshc->ssh_agent) { + sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session); + if(!sshc->ssh_agent) { + infof(data, "Could not create agent object"); + + state(data, SSH_AUTH_KEY_INIT); + break; + } + } + + rc = libssh2_agent_connect(sshc->ssh_agent); + if(rc == LIBSSH2_ERROR_EAGAIN) + break; + if(rc < 0) { + infof(data, "Failure connecting to agent"); + state(data, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ + } + else { + state(data, SSH_AUTH_AGENT_LIST); + } + } + else +#endif /* HAVE_LIBSSH2_AGENT_API */ + state(data, SSH_AUTH_KEY_INIT); + break; + + case SSH_AUTH_AGENT_LIST: +#ifdef HAVE_LIBSSH2_AGENT_API + rc = libssh2_agent_list_identities(sshc->ssh_agent); + + if(rc == LIBSSH2_ERROR_EAGAIN) + break; + if(rc < 0) { + infof(data, "Failure requesting identities to agent"); + state(data, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ + } + else { + state(data, SSH_AUTH_AGENT); + sshc->sshagent_prev_identity = NULL; + } +#endif + break; + + case SSH_AUTH_AGENT: +#ifdef HAVE_LIBSSH2_AGENT_API + /* as prev_identity evolves only after an identity user auth finished we + can safely request it again as long as EAGAIN is returned here or by + libssh2_agent_userauth */ + rc = libssh2_agent_get_identity(sshc->ssh_agent, + &sshc->sshagent_identity, + sshc->sshagent_prev_identity); + if(rc == LIBSSH2_ERROR_EAGAIN) + break; + + if(rc == 0) { + rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user, + sshc->sshagent_identity); + + if(rc < 0) { + if(rc != LIBSSH2_ERROR_EAGAIN) { + /* tried and failed? go to next identity */ + sshc->sshagent_prev_identity = sshc->sshagent_identity; + } + break; + } + } + + if(rc < 0) + infof(data, "Failure requesting identities to agent"); + else if(rc == 1) + infof(data, "No identity would match"); + + if(rc == LIBSSH2_ERROR_NONE) { + sshc->authed = TRUE; + infof(data, "Agent based authentication successful"); + state(data, SSH_AUTH_DONE); + } + else { + state(data, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ + } +#endif + break; + + case SSH_AUTH_KEY_INIT: + if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) + && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) { + state(data, SSH_AUTH_KEY); + } + else { + state(data, SSH_AUTH_DONE); + } + break; + + case SSH_AUTH_KEY: + /* Authentication failed. Continue with keyboard-interactive now. */ + rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session, + conn->user, + curlx_uztoui( + strlen(conn->user)), + &kbd_callback); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc == 0) { + sshc->authed = TRUE; + infof(data, "Initialized keyboard interactive authentication"); + } + state(data, SSH_AUTH_DONE); + break; + + case SSH_AUTH_DONE: + if(!sshc->authed) { + failf(data, "Authentication failure"); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_LOGIN_DENIED; + break; + } + + /* + * At this point we have an authenticated ssh session. + */ + infof(data, "Authentication complete"); + + Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ + + conn->sockfd = sock; + conn->writesockfd = CURL_SOCKET_BAD; + + if(conn->handler->protocol == CURLPROTO_SFTP) { + state(data, SSH_SFTP_INIT); + break; + } + infof(data, "SSH CONNECT phase done"); + state(data, SSH_STOP); + break; + + case SSH_SFTP_INIT: + /* + * Start the libssh2 sftp session + */ + sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session); + if(!sshc->sftp_session) { + char *err_msg = NULL; + if(libssh2_session_last_errno(sshc->ssh_session) == + LIBSSH2_ERROR_EAGAIN) { + rc = LIBSSH2_ERROR_EAGAIN; + break; + } + + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + failf(data, "Failure initializing sftp session: %s", err_msg); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_FAILED_INIT; + break; + } + state(data, SSH_SFTP_REALPATH); + break; + + case SSH_SFTP_REALPATH: + { + char tempHome[PATH_MAX]; + + /* + * Get the "home" directory + */ + rc = sftp_libssh2_realpath(sshc->sftp_session, ".", + tempHome, PATH_MAX-1); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc > 0) { + /* It seems that this string is not always NULL terminated */ + tempHome[rc] = '\0'; + sshc->homedir = strdup(tempHome); + if(!sshc->homedir) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + data->state.most_recent_ftp_entrypath = sshc->homedir; + } + else { + /* Return the error type */ + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + if(sftperr) + result = sftp_libssh2_error_to_CURLE(sftperr); + else + /* in this case, the error wasn't in the SFTP level but for example + a time-out or similar */ + result = CURLE_SSH; + sshc->actualcode = result; + DEBUGF(infof(data, "error = %lu makes libcurl = %d", + sftperr, (int)result)); + state(data, SSH_STOP); + break; + } + } + /* This is the last step in the SFTP connect phase. Do note that while + we get the homedir here, we get the "workingpath" in the DO action + since the homedir will remain the same between request but the + working path will not. */ + DEBUGF(infof(data, "SSH CONNECT phase done")); + state(data, SSH_STOP); + break; + + case SSH_SFTP_QUOTE_INIT: + + result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); + if(result) { + sshc->actualcode = result; + state(data, SSH_STOP); + break; + } + + if(data->set.quote) { + infof(data, "Sending quote commands"); + sshc->quote_item = data->set.quote; + state(data, SSH_SFTP_QUOTE); + } + else { + state(data, SSH_SFTP_GETINFO); + } + break; + + case SSH_SFTP_POSTQUOTE_INIT: + if(data->set.postquote) { + infof(data, "Sending quote commands"); + sshc->quote_item = data->set.postquote; + state(data, SSH_SFTP_QUOTE); + } + else { + state(data, SSH_STOP); + } + break; + + case SSH_SFTP_QUOTE: + /* Send any quote commands */ + { + const char *cp; + + /* + * Support some of the "FTP" commands + * + * 'sshc->quote_item' is already verified to be non-NULL before it + * switched to this state. + */ + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server responds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + if(strcasecompare("pwd", cmd)) { + /* output debug output if that is requested */ + char *tmp = aprintf("257 \"%s\" is current directory.\n", + sshp->path); + if(!tmp) { + result = CURLE_OUT_OF_MEMORY; + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + break; + } + Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4); + Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp)); + + /* this sends an FTP-like "header" to the header callback so that the + current directory can be read very similar to how it is read when + using ordinary FTP. */ + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + else + state(data, SSH_SFTP_NEXT_QUOTE); + break; + } + + /* + * the arguments following the command must be separated from the + * command with a space so we can check for it unconditionally + */ + cp = strchr(cmd, ' '); + if(!cp) { + failf(data, "Syntax error command '%s', missing parameter", + cmd); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + + /* + * also, every command takes at least one argument so we get that + * first argument right now + */ + result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error: Bad first parameter to '%s'", cmd); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + break; + } + + /* + * SFTP is a binary protocol, so we don't send text commands + * to the server. Instead, we scan for commands used by + * OpenSSH's sftp program and call the appropriate libssh2 + * functions. + */ + if(strncasecompare(cmd, "chgrp ", 6) || + strncasecompare(cmd, "chmod ", 6) || + strncasecompare(cmd, "chown ", 6) || + strncasecompare(cmd, "atime ", 6) || + strncasecompare(cmd, "mtime ", 6)) { + /* attribute change */ + + /* sshc->quote_path1 contains the mode to set */ + /* get the destination */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in %s: Bad second parameter", cmd); + Curl_safefree(sshc->quote_path1); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + break; + } + memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); + state(data, SSH_SFTP_QUOTE_STAT); + break; + } + if(strncasecompare(cmd, "ln ", 3) || + strncasecompare(cmd, "symlink ", 8)) { + /* symbolic linking */ + /* sshc->quote_path1 is the source */ + /* get the destination */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, + "Syntax error in ln/symlink: Bad second parameter"); + Curl_safefree(sshc->quote_path1); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + break; + } + state(data, SSH_SFTP_QUOTE_SYMLINK); + break; + } + else if(strncasecompare(cmd, "mkdir ", 6)) { + /* create dir */ + state(data, SSH_SFTP_QUOTE_MKDIR); + break; + } + else if(strncasecompare(cmd, "rename ", 7)) { + /* rename file */ + /* first param is the source path */ + /* second param is the dest. path */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in rename: Bad second parameter"); + Curl_safefree(sshc->quote_path1); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + break; + } + state(data, SSH_SFTP_QUOTE_RENAME); + break; + } + else if(strncasecompare(cmd, "rmdir ", 6)) { + /* delete dir */ + state(data, SSH_SFTP_QUOTE_RMDIR); + break; + } + else if(strncasecompare(cmd, "rm ", 3)) { + state(data, SSH_SFTP_QUOTE_UNLINK); + break; + } +#ifdef HAS_STATVFS_SUPPORT + else if(strncasecompare(cmd, "statvfs ", 8)) { + state(data, SSH_SFTP_QUOTE_STATVFS); + break; + } +#endif + + failf(data, "Unknown SFTP command"); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + + case SSH_SFTP_NEXT_QUOTE: + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + + sshc->quote_item = sshc->quote_item->next; + + if(sshc->quote_item) { + state(data, SSH_SFTP_QUOTE); + } + else { + if(sshc->nextstate != SSH_NO_STATE) { + state(data, sshc->nextstate); + sshc->nextstate = SSH_NO_STATE; + } + else { + state(data, SSH_SFTP_GETINFO); + } + } + break; + + case SSH_SFTP_QUOTE_STAT: + { + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server responds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + if(!strncasecompare(cmd, "chmod", 5)) { + /* Since chown and chgrp only set owner OR group but libssh2 wants to + * set them both at once, we need to obtain the current ownership + * first. This takes an extra protocol round trip. + */ + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, + curlx_uztoui(strlen(sshc->quote_path2)), + LIBSSH2_SFTP_STAT, + &sshp->quote_attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { /* get those attributes */ + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Attempt to get SFTP stats failed: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + } + + /* Now set the new attributes... */ + if(strncasecompare(cmd, "chgrp", 5)) { + sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; + if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chgrp gid not a number"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + } + else if(strncasecompare(cmd, "chmod", 5)) { + sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; + /* permissions are octal */ + if(sshp->quote_attrs.permissions == 0 && + !ISDIGIT(sshc->quote_path1[0])) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chmod permissions not a number"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + } + else if(strncasecompare(cmd, "chown", 5)) { + sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; + if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chown uid not a number"); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + } + else if(strncasecompare(cmd, "atime", 5) || + strncasecompare(cmd, "mtime", 5)) { + time_t date = Curl_getdate_capped(sshc->quote_path1); + bool fail = FALSE; + + if(date == -1) { + failf(data, "incorrect date format for %.*s", 5, cmd); + fail = TRUE; + } +#if SIZEOF_TIME_T > SIZEOF_LONG + if(date > 0xffffffff) { + /* if 'long' can't old >32bit, this date cannot be sent */ + failf(data, "date overflow"); + fail = TRUE; + } +#endif + if(fail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + if(strncasecompare(cmd, "atime", 5)) + sshp->quote_attrs.atime = (unsigned long)date; + else /* mtime */ + sshp->quote_attrs.mtime = (unsigned long)date; + + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME; + } + + /* Now send the completed structure... */ + state(data, SSH_SFTP_QUOTE_SETSTAT); + break; + } + + case SSH_SFTP_QUOTE_SETSTAT: + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, + curlx_uztoui(strlen(sshc->quote_path2)), + LIBSSH2_SFTP_SETSTAT, + &sshp->quote_attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Attempt to set SFTP stats failed: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_SYMLINK: + rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1)), + sshc->quote_path2, + curlx_uztoui(strlen(sshc->quote_path2)), + LIBSSH2_SFTP_SYMLINK); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "symlink command failed: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_MKDIR: + rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1)), + data->set.new_directory_perms); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + failf(data, "mkdir command failed: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_RENAME: + rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1)), + sshc->quote_path2, + curlx_uztoui(strlen(sshc->quote_path2)), + LIBSSH2_SFTP_RENAME_OVERWRITE | + LIBSSH2_SFTP_RENAME_ATOMIC | + LIBSSH2_SFTP_RENAME_NATIVE); + + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "rename command failed: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_RMDIR: + rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1))); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + failf(data, "rmdir command failed: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + + case SSH_SFTP_QUOTE_UNLINK: + rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1))); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + +#ifdef HAS_STATVFS_SUPPORT + case SSH_SFTP_QUOTE_STATVFS: + { + LIBSSH2_SFTP_STATVFS statvfs; + rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1)), + &statvfs); + + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc && !sshc->acceptfail) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + failf(data, "statvfs command failed: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + else if(rc == 0) { + #ifdef _MSC_VER + #define CURL_LIBSSH2_VFS_SIZE_MASK "I64u" + #else + #define CURL_LIBSSH2_VFS_SIZE_MASK "llu" + #endif + char *tmp = aprintf("statvfs:\n" + "f_bsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_frsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_blocks: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_bfree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_bavail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_files: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_ffree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_favail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_fsid: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_flag: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_namemax: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n", + statvfs.f_bsize, statvfs.f_frsize, + statvfs.f_blocks, statvfs.f_bfree, + statvfs.f_bavail, statvfs.f_files, + statvfs.f_ffree, statvfs.f_favail, + statvfs.f_fsid, statvfs.f_flag, + statvfs.f_namemax); + if(!tmp) { + result = CURLE_OUT_OF_MEMORY; + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + break; + } + + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + state(data, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + } + state(data, SSH_SFTP_NEXT_QUOTE); + break; + } +#endif + case SSH_SFTP_GETINFO: + { + if(data->set.get_filetime) { + state(data, SSH_SFTP_FILETIME); + } + else { + state(data, SSH_SFTP_TRANS_INIT); + } + break; + } + + case SSH_SFTP_FILETIME: + { + LIBSSH2_SFTP_ATTRIBUTES attrs; + + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + LIBSSH2_SFTP_STAT, &attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc == 0) { + data->info.filetime = attrs.mtime; + } + + state(data, SSH_SFTP_TRANS_INIT); + break; + } + + case SSH_SFTP_TRANS_INIT: + if(data->state.upload) + state(data, SSH_SFTP_UPLOAD_INIT); + else { + if(sshp->path[strlen(sshp->path)-1] == '/') + state(data, SSH_SFTP_READDIR_INIT); + else + state(data, SSH_SFTP_DOWNLOAD_INIT); + } + break; + + case SSH_SFTP_UPLOAD_INIT: + { + unsigned long flags; + /* + * NOTE!!! libssh2 requires that the destination path is a full path + * that includes the destination file and name OR ends in a "/" + * If this is not done the destination file will be named the + * same name as the last directory in the path. + */ + + if(data->state.resume_from) { + LIBSSH2_SFTP_ATTRIBUTES attrs; + if(data->state.resume_from < 0) { + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + LIBSSH2_SFTP_STAT, &attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc) { + data->state.resume_from = 0; + } + else { + curl_off_t size = attrs.filesize; + if(size < 0) { + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + data->state.resume_from = attrs.filesize; + } + } + } + + if(data->set.remote_append) + /* Try to open for append, but create if nonexisting */ + flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND; + else if(data->state.resume_from > 0) + /* If we have restart position then open for append */ + flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND; + else + /* Clear file before writing (normal behavior) */ + flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC; + + sshc->sftp_handle = + libssh2_sftp_open_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + flags, data->set.new_file_perms, + LIBSSH2_SFTP_OPENFILE); + + if(!sshc->sftp_handle) { + rc = libssh2_session_last_errno(sshc->ssh_session); + + if(LIBSSH2_ERROR_EAGAIN == rc) + break; + + if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc) + /* only when there was an SFTP protocol error can we extract + the sftp error! */ + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + else + sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */ + + if(sshc->secondCreateDirs) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = sftperr != LIBSSH2_FX_OK ? + sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH; + failf(data, "Creating the dir/file failed: %s", + sftp_libssh2_strerror(sftperr)); + break; + } + if(((sftperr == LIBSSH2_FX_NO_SUCH_FILE) || + (sftperr == LIBSSH2_FX_FAILURE) || + (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) && + (data->set.ftp_create_missing_dirs && + (strlen(sshp->path) > 1))) { + /* try to create the path remotely */ + rc = 0; /* clear rc and continue */ + sshc->secondCreateDirs = 1; + state(data, SSH_SFTP_CREATE_DIRS_INIT); + break; + } + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = sftperr != LIBSSH2_FX_OK ? + sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH; + if(!sshc->actualcode) { + /* Sometimes, for some reason libssh2_sftp_last_error() returns zero + even though libssh2_sftp_open() failed previously! We need to + work around that! */ + sshc->actualcode = CURLE_SSH; + sftperr = LIBSSH2_FX_OK; + } + failf(data, "Upload failed: %s (%lu/%d)", + sftperr != LIBSSH2_FX_OK ? + sftp_libssh2_strerror(sftperr):"ssh error", + sftperr, rc); + break; + } + + /* If we have a restart point then we need to seek to the correct + position. */ + if(data->state.resume_from > 0) { + /* Let's read off the proper amount of bytes from the input. */ + if(conn->seek_func) { + Curl_set_in_callback(data, true); + seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, + SEEK_SET); + Curl_set_in_callback(data, false); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed = 0; + + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_FTP_COULDNT_USE_REST; + } + /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ + do { + char scratch[4*1024]; + size_t readthisamountnow = + (data->state.resume_from - passed > + (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread; + Curl_set_in_callback(data, true); + actuallyread = data->state.fread_func(scratch, 1, + readthisamountnow, + data->state.in); + Curl_set_in_callback(data, false); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); + } + + /* now, decrease the size of the read */ + if(data->state.infilesize > 0) { + data->state.infilesize -= data->state.resume_from; + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + + SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); + } + if(data->state.infilesize > 0) { + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + /* upload data */ + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->sockfd = conn->writesockfd; + + if(result) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = result; + } + else { + /* store this original bitmask setup to use later on if we can't + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh2 sftp send function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_OUT; + + /* since we don't really wait for anything at this point, we want the + state machine to move on as soon as possible so we set a very short + timeout here */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + state(data, SSH_STOP); + } + break; + } + + case SSH_SFTP_CREATE_DIRS_INIT: + if(strlen(sshp->path) > 1) { + sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */ + state(data, SSH_SFTP_CREATE_DIRS); + } + else { + state(data, SSH_SFTP_UPLOAD_INIT); + } + break; + + case SSH_SFTP_CREATE_DIRS: + sshc->slash_pos = strchr(sshc->slash_pos, '/'); + if(sshc->slash_pos) { + *sshc->slash_pos = 0; + + infof(data, "Creating directory '%s'", sshp->path); + state(data, SSH_SFTP_CREATE_DIRS_MKDIR); + break; + } + state(data, SSH_SFTP_UPLOAD_INIT); + break; + + case SSH_SFTP_CREATE_DIRS_MKDIR: + /* 'mode' - parameter is preliminary - default to 0644 */ + rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + data->set.new_directory_perms); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + *sshc->slash_pos = '/'; + ++sshc->slash_pos; + if(rc < 0) { + /* + * Abort if failure wasn't that the dir already exists or the + * permission was denied (creation might succeed further down the + * path) - retry on unspecific FAILURE also + */ + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) && + (sftperr != LIBSSH2_FX_FAILURE) && + (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) { + result = sftp_libssh2_error_to_CURLE(sftperr); + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = result?result:CURLE_SSH; + break; + } + rc = 0; /* clear rc and continue */ + } + state(data, SSH_SFTP_CREATE_DIRS); + break; + + case SSH_SFTP_READDIR_INIT: + Curl_pgrsSetDownloadSize(data, -1); + if(data->req.no_body) { + state(data, SSH_STOP); + break; + } + + /* + * This is a directory that we are trying to get, so produce a directory + * listing + */ + sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, + sshp->path, + curlx_uztoui( + strlen(sshp->path)), + 0, 0, LIBSSH2_SFTP_OPENDIR); + if(!sshc->sftp_handle) { + if(libssh2_session_last_errno(sshc->ssh_session) == + LIBSSH2_ERROR_EAGAIN) { + rc = LIBSSH2_ERROR_EAGAIN; + break; + } + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + failf(data, "Could not open directory for reading: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + result = sftp_libssh2_error_to_CURLE(sftperr); + sshc->actualcode = result?result:CURLE_SSH; + break; + } + sshp->readdir_filename = malloc(PATH_MAX + 1); + if(!sshp->readdir_filename) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + sshp->readdir_longentry = malloc(PATH_MAX + 1); + if(!sshp->readdir_longentry) { + Curl_safefree(sshp->readdir_filename); + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + Curl_dyn_init(&sshp->readdir, PATH_MAX * 2); + state(data, SSH_SFTP_READDIR); + break; + + case SSH_SFTP_READDIR: + rc = libssh2_sftp_readdir_ex(sshc->sftp_handle, + sshp->readdir_filename, + PATH_MAX, + sshp->readdir_longentry, + PATH_MAX, + &sshp->readdir_attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc > 0) { + readdir_len = (size_t) rc; + sshp->readdir_filename[readdir_len] = '\0'; + + if(data->set.list_only) { + result = Curl_client_write(data, CLIENTWRITE_BODY, + sshp->readdir_filename, + readdir_len); + if(!result) + result = Curl_client_write(data, CLIENTWRITE_BODY, + (char *)"\n", 1); + if(result) { + state(data, SSH_STOP); + break; + } + + } + else { + result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry); + + if(!result) { + if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && + ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFLNK)) { + Curl_dyn_init(&sshp->readdir_link, PATH_MAX); + result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path, + sshp->readdir_filename); + state(data, SSH_SFTP_READDIR_LINK); + if(!result) + break; + } + else { + state(data, SSH_SFTP_READDIR_BOTTOM); + break; + } + } + sshc->actualcode = result; + state(data, SSH_SFTP_CLOSE); + break; + } + } + else if(rc == 0) { + Curl_safefree(sshp->readdir_filename); + Curl_safefree(sshp->readdir_longentry); + state(data, SSH_SFTP_READDIR_DONE); + break; + } + else if(rc < 0) { + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + result = sftp_libssh2_error_to_CURLE(sftperr); + sshc->actualcode = result?result:CURLE_SSH; + failf(data, "Could not open remote file for reading: %s :: %d", + sftp_libssh2_strerror(sftperr), + libssh2_session_last_errno(sshc->ssh_session)); + Curl_safefree(sshp->readdir_filename); + Curl_safefree(sshp->readdir_longentry); + state(data, SSH_SFTP_CLOSE); + break; + } + break; + + case SSH_SFTP_READDIR_LINK: + rc = + libssh2_sftp_symlink_ex(sshc->sftp_session, + Curl_dyn_ptr(&sshp->readdir_link), + (int)Curl_dyn_len(&sshp->readdir_link), + sshp->readdir_filename, + PATH_MAX, LIBSSH2_SFTP_READLINK); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + Curl_dyn_free(&sshp->readdir_link); + + /* append filename and extra output */ + result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename); + + if(result) { + Curl_safefree(sshp->readdir_filename); + Curl_safefree(sshp->readdir_longentry); + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = result; + break; + } + + state(data, SSH_SFTP_READDIR_BOTTOM); + break; + + case SSH_SFTP_READDIR_BOTTOM: + result = Curl_dyn_addn(&sshp->readdir, "\n", 1); + if(!result) + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&sshp->readdir), + Curl_dyn_len(&sshp->readdir)); + + if(result) { + Curl_dyn_free(&sshp->readdir); + state(data, SSH_STOP); + } + else { + Curl_dyn_reset(&sshp->readdir); + state(data, SSH_SFTP_READDIR); + } + break; + + case SSH_SFTP_READDIR_DONE: + if(libssh2_sftp_closedir(sshc->sftp_handle) == + LIBSSH2_ERROR_EAGAIN) { + rc = LIBSSH2_ERROR_EAGAIN; + break; + } + sshc->sftp_handle = NULL; + Curl_safefree(sshp->readdir_filename); + Curl_safefree(sshp->readdir_longentry); + + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + state(data, SSH_STOP); + break; + + case SSH_SFTP_DOWNLOAD_INIT: + /* + * Work on getting the specified file + */ + sshc->sftp_handle = + libssh2_sftp_open_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + LIBSSH2_FXF_READ, data->set.new_file_perms, + LIBSSH2_SFTP_OPENFILE); + if(!sshc->sftp_handle) { + if(libssh2_session_last_errno(sshc->ssh_session) == + LIBSSH2_ERROR_EAGAIN) { + rc = LIBSSH2_ERROR_EAGAIN; + break; + } + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + failf(data, "Could not open remote file for reading: %s", + sftp_libssh2_strerror(sftperr)); + state(data, SSH_SFTP_CLOSE); + result = sftp_libssh2_error_to_CURLE(sftperr); + sshc->actualcode = result?result:CURLE_SSH; + break; + } + state(data, SSH_SFTP_DOWNLOAD_STAT); + break; + + case SSH_SFTP_DOWNLOAD_STAT: + { + LIBSSH2_SFTP_ATTRIBUTES attrs; + + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + LIBSSH2_SFTP_STAT, &attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc || + !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) || + (attrs.filesize == 0)) { + /* + * libssh2_sftp_open() didn't return an error, so maybe the server + * just doesn't support stat() + * OR the server doesn't return a file size with a stat() + * OR file size is 0 + */ + data->req.size = -1; + data->req.maxdownload = -1; + Curl_pgrsSetDownloadSize(data, -1); + } + else { + curl_off_t size = attrs.filesize; + + if(size < 0) { + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + if(data->state.use_range) { + curl_off_t from, to; + char *ptr; + char *ptr2; + CURLofft to_t; + CURLofft from_t; + + from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from); + if(from_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) + ptr++; + to_t = curlx_strtoofft(ptr, &ptr2, 10, &to); + if(to_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + if((to_t == CURL_OFFT_INVAL) /* no "to" value given */ + || (to >= size)) { + to = size - 1; + } + if(from_t) { + /* from is relative to end of file */ + from = size - to; + to = size - 1; + } + if(from > size) { + failf(data, "Offset (%" + CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" + CURL_FORMAT_CURL_OFF_T ")", from, + (curl_off_t)attrs.filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + if(from > to) { + from = to; + size = 0; + } + else { + size = to - from + 1; + } + + SFTP_SEEK(sshc->sftp_handle, from); + } + data->req.size = size; + data->req.maxdownload = size; + Curl_pgrsSetDownloadSize(data, size); + } + + /* We can resume if we can seek to the resume position */ + if(data->state.resume_from) { + if(data->state.resume_from < 0) { + /* We're supposed to download the last abs(from) bytes */ + if((curl_off_t)attrs.filesize < -data->state.resume_from) { + failf(data, "Offset (%" + CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" + CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, (curl_off_t)attrs.filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* download from where? */ + data->state.resume_from += attrs.filesize; + } + else { + if((curl_off_t)attrs.filesize < data->state.resume_from) { + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, (curl_off_t)attrs.filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + } + /* Now store the number of bytes we are expected to download */ + data->req.size = attrs.filesize - data->state.resume_from; + data->req.maxdownload = attrs.filesize - data->state.resume_from; + Curl_pgrsSetDownloadSize(data, + attrs.filesize - data->state.resume_from); + SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); + } + } + + /* Setup the actual download */ + if(data->req.size == 0) { + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + infof(data, "File already completely downloaded"); + state(data, SSH_STOP); + break; + } + Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->writesockfd = conn->sockfd; + + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_IN; + + if(result) { + /* this should never occur; the close state should be entered + at the time the error occurs */ + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = result; + } + else { + state(data, SSH_STOP); + } + break; + + case SSH_SFTP_CLOSE: + if(sshc->sftp_handle) { + rc = libssh2_sftp_close(sshc->sftp_handle); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg); + } + sshc->sftp_handle = NULL; + } + + Curl_safefree(sshp->path); + + DEBUGF(infof(data, "SFTP DONE done")); + + /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT + After nextstate is executed, the control should come back to + SSH_SFTP_CLOSE to pass the correct result back */ + if(sshc->nextstate != SSH_NO_STATE && + sshc->nextstate != SSH_SFTP_CLOSE) { + state(data, sshc->nextstate); + sshc->nextstate = SSH_SFTP_CLOSE; + } + else { + state(data, SSH_STOP); + result = sshc->actualcode; + } + break; + + case SSH_SFTP_SHUTDOWN: + /* during times we get here due to a broken transfer and then the + sftp_handle might not have been taken down so make sure that is done + before we proceed */ + + if(sshc->sftp_handle) { + rc = libssh2_sftp_close(sshc->sftp_handle); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, + NULL, 0); + infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg); + } + sshc->sftp_handle = NULL; + } + if(sshc->sftp_session) { + rc = libssh2_sftp_shutdown(sshc->sftp_session); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + infof(data, "Failed to stop libssh2 sftp subsystem"); + } + sshc->sftp_session = NULL; + } + + Curl_safefree(sshc->homedir); + data->state.most_recent_ftp_entrypath = NULL; + + state(data, SSH_SESSION_DISCONNECT); + break; + + case SSH_SCP_TRANS_INIT: + result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); + if(result) { + sshc->actualcode = result; + state(data, SSH_STOP); + break; + } + + if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; + state(data, SSH_SCP_CHANNEL_FREE); + break; + } + state(data, SSH_SCP_UPLOAD_INIT); + } + else { + state(data, SSH_SCP_DOWNLOAD_INIT); + } + break; + + case SSH_SCP_UPLOAD_INIT: + /* + * libssh2 requires that the destination path is a full path that + * includes the destination file and name OR ends in a "/" . If this is + * not done the destination file will be named the same name as the last + * directory in the path. + */ + sshc->ssh_channel = + SCP_SEND(sshc->ssh_session, sshp->path, data->set.new_file_perms, + data->state.infilesize); + if(!sshc->ssh_channel) { + int ssh_err; + char *err_msg = NULL; + + if(libssh2_session_last_errno(sshc->ssh_session) == + LIBSSH2_ERROR_EAGAIN) { + rc = LIBSSH2_ERROR_EAGAIN; + break; + } + + ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0)); + failf(data, "%s", err_msg); + state(data, SSH_SCP_CHANNEL_FREE); + sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); + /* Map generic errors to upload failed */ + if(sshc->actualcode == CURLE_SSH || + sshc->actualcode == CURLE_REMOTE_FILE_NOT_FOUND) + sshc->actualcode = CURLE_UPLOAD_FAILED; + break; + } + + /* upload data */ + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->sockfd = conn->writesockfd; + + if(result) { + state(data, SSH_SCP_CHANNEL_FREE); + sshc->actualcode = result; + } + else { + /* store this original bitmask setup to use later on if we can't + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh2 scp send function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_OUT; + + state(data, SSH_STOP); + } + break; + + case SSH_SCP_DOWNLOAD_INIT: + { + curl_off_t bytecount; + + /* + * We must check the remote file; if it is a directory no values will + * be set in sb + */ + + /* + * If support for >2GB files exists, use it. + */ + + /* get a fresh new channel from the ssh layer */ +#if LIBSSH2_VERSION_NUM < 0x010700 + struct stat sb; + memset(&sb, 0, sizeof(struct stat)); + sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, + sshp->path, &sb); +#else + libssh2_struct_stat sb; + memset(&sb, 0, sizeof(libssh2_struct_stat)); + sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, + sshp->path, &sb); +#endif + + if(!sshc->ssh_channel) { + int ssh_err; + char *err_msg = NULL; + + if(libssh2_session_last_errno(sshc->ssh_session) == + LIBSSH2_ERROR_EAGAIN) { + rc = LIBSSH2_ERROR_EAGAIN; + break; + } + + + ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0)); + failf(data, "%s", err_msg); + state(data, SSH_SCP_CHANNEL_FREE); + sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); + break; + } + + /* download data */ + bytecount = (curl_off_t)sb.st_size; + data->req.maxdownload = (curl_off_t)sb.st_size; + Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->writesockfd = conn->sockfd; + + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_IN; + + if(result) { + state(data, SSH_SCP_CHANNEL_FREE); + sshc->actualcode = result; + } + else + state(data, SSH_STOP); + } + break; + + case SSH_SCP_DONE: + if(data->state.upload) + state(data, SSH_SCP_SEND_EOF); + else + state(data, SSH_SCP_CHANNEL_FREE); + break; + + case SSH_SCP_SEND_EOF: + if(sshc->ssh_channel) { + rc = libssh2_channel_send_eof(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to send libssh2 channel EOF: %d %s", + rc, err_msg); + } + } + state(data, SSH_SCP_WAIT_EOF); + break; + + case SSH_SCP_WAIT_EOF: + if(sshc->ssh_channel) { + rc = libssh2_channel_wait_eof(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to get channel EOF: %d %s", rc, err_msg); + } + } + state(data, SSH_SCP_WAIT_CLOSE); + break; + + case SSH_SCP_WAIT_CLOSE: + if(sshc->ssh_channel) { + rc = libssh2_channel_wait_closed(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Channel failed to close: %d %s", rc, err_msg); + } + } + state(data, SSH_SCP_CHANNEL_FREE); + break; + + case SSH_SCP_CHANNEL_FREE: + if(sshc->ssh_channel) { + rc = libssh2_channel_free(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to free libssh2 scp subsystem: %d %s", + rc, err_msg); + } + sshc->ssh_channel = NULL; + } + DEBUGF(infof(data, "SCP DONE phase complete")); +#if 0 /* PREV */ + state(data, SSH_SESSION_DISCONNECT); +#endif + state(data, SSH_STOP); + result = sshc->actualcode; + break; + + case SSH_SESSION_DISCONNECT: + /* during weird times when we've been prematurely aborted, the channel + is still alive when we reach this state and we MUST kill the channel + properly first */ + if(sshc->ssh_channel) { + rc = libssh2_channel_free(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to free libssh2 scp subsystem: %d %s", + rc, err_msg); + } + sshc->ssh_channel = NULL; + } + + if(sshc->ssh_session) { + rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown"); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to disconnect libssh2 session: %d %s", + rc, err_msg); + } + } + + Curl_safefree(sshc->homedir); + data->state.most_recent_ftp_entrypath = NULL; + + state(data, SSH_SESSION_FREE); + break; + + case SSH_SESSION_FREE: +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + if(sshc->kh) { + libssh2_knownhost_free(sshc->kh); + sshc->kh = NULL; + } +#endif + +#ifdef HAVE_LIBSSH2_AGENT_API + if(sshc->ssh_agent) { + rc = libssh2_agent_disconnect(sshc->ssh_agent); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to disconnect from libssh2 agent: %d %s", + rc, err_msg); + } + libssh2_agent_free(sshc->ssh_agent); + sshc->ssh_agent = NULL; + + /* NB: there is no need to free identities, they are part of internal + agent stuff */ + sshc->sshagent_identity = NULL; + sshc->sshagent_prev_identity = NULL; + } +#endif + + if(sshc->ssh_session) { + rc = libssh2_session_free(sshc->ssh_session); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg); + } + sshc->ssh_session = NULL; + } + + /* worst-case scenario cleanup */ + + DEBUGASSERT(sshc->ssh_session == NULL); + DEBUGASSERT(sshc->ssh_channel == NULL); + DEBUGASSERT(sshc->sftp_session == NULL); + DEBUGASSERT(sshc->sftp_handle == NULL); +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + DEBUGASSERT(sshc->kh == NULL); +#endif +#ifdef HAVE_LIBSSH2_AGENT_API + DEBUGASSERT(sshc->ssh_agent == NULL); +#endif + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + Curl_safefree(sshc->homedir); + + /* the code we are about to return */ + result = sshc->actualcode; + + memset(sshc, 0, sizeof(struct ssh_conn)); + + connclose(conn, "SSH session free"); + sshc->state = SSH_SESSION_FREE; /* current */ + sshc->nextstate = SSH_NO_STATE; + state(data, SSH_STOP); + break; + + case SSH_QUIT: + default: + /* internal error */ + sshc->nextstate = SSH_NO_STATE; + state(data, SSH_STOP); + break; + } + + } while(!rc && (sshc->state != SSH_STOP)); + + if(rc == LIBSSH2_ERROR_EAGAIN) { + /* we would block, we need to wait for the socket to be ready (in the + right direction too)! */ + *block = TRUE; + } + + return result; +} + +/* called by the multi interface to figure out what socket(s) to wait for and + for what actions in the DO_DONE, PERFORM and WAITPERFORM states */ +static int ssh_getsock(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *sock) +{ + int bitmap = GETSOCK_BLANK; + (void)data; + + sock[0] = conn->sock[FIRSTSOCKET]; + + if(conn->waitfor & KEEP_RECV) + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + + if(conn->waitfor & KEEP_SEND) + bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); + + return bitmap; +} + +/* + * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this + * function is used to figure out in what direction and stores this info so + * that the multi interface can take advantage of it. Make sure to call this + * function in all cases so that when it _doesn't_ return EAGAIN we can + * restore the default wait bits. + */ +static void ssh_block2waitfor(struct Curl_easy *data, bool block) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + int dir = 0; + if(block) { + dir = libssh2_session_block_directions(sshc->ssh_session); + if(dir) { + /* translate the libssh2 define bits into our own bit defines */ + conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) | + ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0); + } + } + if(!dir) + /* It didn't block or libssh2 didn't reveal in which direction, put back + the original set */ + conn->waitfor = sshc->orig_waitfor; +} + +/* called repeatedly until done from multi.c */ +static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result = CURLE_OK; + bool block; /* we store the status and use that to provide a ssh_getsock() + implementation */ + do { + result = ssh_statemach_act(data, &block); + *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; + /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then + try again */ + } while(!result && !*done && !block); + ssh_block2waitfor(data, block); + + return result; +} + +static CURLcode ssh_block_statemach(struct Curl_easy *data, + struct connectdata *conn, + bool disconnect) +{ + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result = CURLE_OK; + struct curltime dis = Curl_now(); + + while((sshc->state != SSH_STOP) && !result) { + bool block; + timediff_t left = 1000; + struct curltime now = Curl_now(); + + result = ssh_statemach_act(data, &block); + if(result) + break; + + if(!disconnect) { + if(Curl_pgrsUpdate(data)) + return CURLE_ABORTED_BY_CALLBACK; + + result = Curl_speedcheck(data, now); + if(result) + break; + + left = Curl_timeleft(data, NULL, FALSE); + if(left < 0) { + failf(data, "Operation timed out"); + return CURLE_OPERATION_TIMEDOUT; + } + } + else if(Curl_timediff(now, dis) > 1000) { + /* disconnect timeout */ + failf(data, "Disconnect timed out"); + result = CURLE_OK; + break; + } + + if(block) { + int dir = libssh2_session_block_directions(sshc->ssh_session); + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + curl_socket_t fd_read = CURL_SOCKET_BAD; + curl_socket_t fd_write = CURL_SOCKET_BAD; + if(LIBSSH2_SESSION_BLOCK_INBOUND & dir) + fd_read = sock; + if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) + fd_write = sock; + /* wait for the socket to become ready */ + (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, + left>1000?1000:left); + } + } + + return result; +} + +/* + * SSH setup and connection + */ +static CURLcode ssh_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + struct SSHPROTO *ssh; + (void)conn; + + data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); + if(!ssh) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +static Curl_recv scp_recv, sftp_recv; +static Curl_send scp_send, sftp_send; + +#ifndef CURL_DISABLE_PROXY +static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer, + size_t length, int flags, void **abstract) +{ + struct Curl_easy *data = (struct Curl_easy *)*abstract; + ssize_t nread; + CURLcode result; + struct connectdata *conn = data->conn; + Curl_recv *backup = conn->recv[0]; + struct ssh_conn *ssh = &conn->proto.sshc; + (void)flags; + + /* swap in the TLS reader function for this call only, and then swap back + the SSH one again */ + conn->recv[0] = ssh->tls_recv; + result = Curl_read(data, sock, buffer, length, &nread); + conn->recv[0] = backup; + if(result == CURLE_AGAIN) + return -EAGAIN; /* magic return code for libssh2 */ + else if(result) + return -1; /* generic error */ + Curl_debug(data, CURLINFO_DATA_IN, (char *)buffer, (size_t)nread); + return nread; +} + +static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer, + size_t length, int flags, void **abstract) +{ + struct Curl_easy *data = (struct Curl_easy *)*abstract; + ssize_t nwrite; + CURLcode result; + struct connectdata *conn = data->conn; + Curl_send *backup = conn->send[0]; + struct ssh_conn *ssh = &conn->proto.sshc; + (void)flags; + + /* swap in the TLS writer function for this call only, and then swap back + the SSH one again */ + conn->send[0] = ssh->tls_send; + result = Curl_write(data, sock, buffer, length, &nwrite); + conn->send[0] = backup; + if(result == CURLE_AGAIN) + return -EAGAIN; /* magic return code for libssh2 */ + else if(result) + return -1; /* error */ + Curl_debug(data, CURLINFO_DATA_OUT, (char *)buffer, (size_t)nwrite); + return nwrite; +} +#endif + +/* + * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to + * do protocol-specific actions at connect-time. + */ +static CURLcode ssh_connect(struct Curl_easy *data, bool *done) +{ +#ifdef CURL_LIBSSH2_DEBUG + curl_socket_t sock; +#endif + struct ssh_conn *sshc; + CURLcode result; + struct connectdata *conn = data->conn; + + /* initialize per-handle data if not already */ + if(!data->req.p.ssh) { + result = ssh_setup_connection(data, conn); + if(result) + return result; + } + + /* We default to persistent connections. We set this already in this connect + function to make the reuse checks properly be able to check this bit. */ + connkeep(conn, "SSH default"); + + sshc = &conn->proto.sshc; + +#ifdef CURL_LIBSSH2_DEBUG + if(conn->user) { + infof(data, "User: %s", conn->user); + } + if(conn->passwd) { + infof(data, "Password: %s", conn->passwd); + } + sock = conn->sock[FIRSTSOCKET]; +#endif /* CURL_LIBSSH2_DEBUG */ + + /* libcurl MUST to set custom memory functions so that the kbd_callback + funciton's memory allocations can be properled freed */ + sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc, + my_libssh2_free, + my_libssh2_realloc, data); + + if(!sshc->ssh_session) { + failf(data, "Failure initialising ssh session"); + return CURLE_FAILED_INIT; + } + +#ifdef HAVE_LIBSSH2_VERSION + /* Set the packet read timeout if the libssh2 version supports it */ +#if LIBSSH2_VERSION_NUM >= 0x010B00 + if(data->set.server_response_timeout > 0) { + libssh2_session_set_read_timeout(sshc->ssh_session, + data->set.server_response_timeout / 1000); + } +#endif +#endif + +#ifndef CURL_DISABLE_PROXY + if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { + /* + Setup libssh2 callbacks to make it read/write TLS from the socket. + + ssize_t + recvcb(libssh2_socket_t sock, void *buffer, size_t length, + int flags, void **abstract); + + ssize_t + sendcb(libssh2_socket_t sock, const void *buffer, size_t length, + int flags, void **abstract); + + */ +#if LIBSSH2_VERSION_NUM >= 0x010b01 + infof(data, "Uses HTTPS proxy"); + libssh2_session_callback_set2(sshc->ssh_session, + LIBSSH2_CALLBACK_RECV, + (libssh2_cb_generic *)ssh_tls_recv); + libssh2_session_callback_set2(sshc->ssh_session, + LIBSSH2_CALLBACK_SEND, + (libssh2_cb_generic *)ssh_tls_send); +#else + /* + * This crazy union dance is here to avoid assigning a void pointer a + * function pointer as it is invalid C. The problem is of course that + * libssh2 has such an API... + */ + union receive { + void *recvp; + ssize_t (*recvptr)(libssh2_socket_t, void *, size_t, int, void **); + }; + union transfer { + void *sendp; + ssize_t (*sendptr)(libssh2_socket_t, const void *, size_t, int, void **); + }; + union receive sshrecv; + union transfer sshsend; + + sshrecv.recvptr = ssh_tls_recv; + sshsend.sendptr = ssh_tls_send; + + infof(data, "Uses HTTPS proxy"); + libssh2_session_callback_set(sshc->ssh_session, + LIBSSH2_CALLBACK_RECV, sshrecv.recvp); + libssh2_session_callback_set(sshc->ssh_session, + LIBSSH2_CALLBACK_SEND, sshsend.sendp); +#endif + + /* Store the underlying TLS recv/send function pointers to be used when + reading from the proxy */ + sshc->tls_recv = conn->recv[FIRSTSOCKET]; + sshc->tls_send = conn->send[FIRSTSOCKET]; + } + +#endif /* CURL_DISABLE_PROXY */ + if(conn->handler->protocol & CURLPROTO_SCP) { + conn->recv[FIRSTSOCKET] = scp_recv; + conn->send[FIRSTSOCKET] = scp_send; + } + else { + conn->recv[FIRSTSOCKET] = sftp_recv; + conn->send[FIRSTSOCKET] = sftp_send; + } + + if(data->set.ssh_compression) { +#if LIBSSH2_VERSION_NUM >= 0x010208 + if(libssh2_session_flag(sshc->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0) +#endif + infof(data, "Failed to enable compression for ssh session"); + } + +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + if(data->set.str[STRING_SSH_KNOWNHOSTS]) { + int rc; + sshc->kh = libssh2_knownhost_init(sshc->ssh_session); + if(!sshc->kh) { + libssh2_session_free(sshc->ssh_session); + sshc->ssh_session = NULL; + return CURLE_FAILED_INIT; + } + + /* read all known hosts from there */ + rc = libssh2_knownhost_readfile(sshc->kh, + data->set.str[STRING_SSH_KNOWNHOSTS], + LIBSSH2_KNOWNHOST_FILE_OPENSSH); + if(rc < 0) + infof(data, "Failed to read known hosts from %s", + data->set.str[STRING_SSH_KNOWNHOSTS]); + } +#endif /* HAVE_LIBSSH2_KNOWNHOST_API */ + +#ifdef CURL_LIBSSH2_DEBUG + libssh2_trace(sshc->ssh_session, ~0); + infof(data, "SSH socket: %d", (int)sock); +#endif /* CURL_LIBSSH2_DEBUG */ + + state(data, SSH_INIT); + + result = ssh_multi_statemach(data, done); + + return result; +} + +/* + *********************************************************************** + * + * scp_perform() + * + * This is the actual DO function for SCP. Get a file according to + * the options previously setup. + */ + +static +CURLcode scp_perform(struct Curl_easy *data, + bool *connected, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + + DEBUGF(infof(data, "DO phase starts")); + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + state(data, SSH_SCP_TRANS_INIT); + + /* run the state-machine */ + result = ssh_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +/* called from multi.c while DOing */ +static CURLcode scp_doing(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result; + result = ssh_multi_statemach(data, dophase_done); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + return result; +} + +/* + * The DO function is generic for both protocols. There was previously two + * separate ones but this way means less duplicated code. + */ + +static CURLcode ssh_do(struct Curl_easy *data, bool *done) +{ + CURLcode result; + bool connected = 0; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + + *done = FALSE; /* default to false */ + + data->req.size = -1; /* make sure this is unknown at this point */ + + sshc->actualcode = CURLE_OK; /* reset error code */ + sshc->secondCreateDirs = 0; /* reset the create dir attempt state + variable */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + if(conn->handler->protocol & CURLPROTO_SCP) + result = scp_perform(data, &connected, done); + else + result = sftp_perform(data, &connected, done); + + return result; +} + +/* BLOCKING, but the function is using the state machine so the only reason + this is still blocking is that the multi interface code has no support for + disconnecting operations that takes a while */ +static CURLcode scp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + CURLcode result = CURLE_OK; + struct ssh_conn *sshc = &conn->proto.sshc; + (void) dead_connection; + + if(sshc->ssh_session) { + /* only if there's a session still around to use! */ + state(data, SSH_SESSION_DISCONNECT); + result = ssh_block_statemach(data, conn, TRUE); + } + + return result; +} + +/* generic done function for both SCP and SFTP called from their specific + done functions */ +static CURLcode ssh_done(struct Curl_easy *data, CURLcode status) +{ + CURLcode result = CURLE_OK; + struct SSHPROTO *sshp = data->req.p.ssh; + struct connectdata *conn = data->conn; + + if(!status) + /* run the state-machine */ + result = ssh_block_statemach(data, conn, FALSE); + else + result = status; + + Curl_safefree(sshp->path); + Curl_safefree(sshp->readdir_filename); + Curl_safefree(sshp->readdir_longentry); + Curl_dyn_free(&sshp->readdir); + + if(Curl_pgrsDone(data)) + return CURLE_ABORTED_BY_CALLBACK; + + data->req.keepon = 0; /* clear all bits */ + return result; +} + + +static CURLcode scp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + (void)premature; /* not used */ + + if(!status) + state(data, SSH_SCP_DONE); + + return ssh_done(data, status); + +} + +static ssize_t scp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + ssize_t nwrite; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ + + /* libssh2_channel_write() returns int! */ + nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len); + + ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); + + if(nwrite == LIBSSH2_ERROR_EAGAIN) { + *err = CURLE_AGAIN; + nwrite = 0; + } + else if(nwrite < LIBSSH2_ERROR_NONE) { + *err = libssh2_session_error_to_CURLE((int)nwrite); + nwrite = -1; + } + + return nwrite; +} + +static ssize_t scp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + ssize_t nread; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ + + /* libssh2_channel_read() returns int */ + nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len); + + ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); + if(nread == LIBSSH2_ERROR_EAGAIN) { + *err = CURLE_AGAIN; + nread = -1; + } + + return nread; +} + +/* + * =============== SFTP =============== + */ + +/* + *********************************************************************** + * + * sftp_perform() + * + * This is the actual DO function for SFTP. Get a file/directory according to + * the options previously setup. + */ + +static +CURLcode sftp_perform(struct Curl_easy *data, + bool *connected, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + + DEBUGF(infof(data, "DO phase starts")); + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + state(data, SSH_SFTP_QUOTE_INIT); + + /* run the state-machine */ + result = ssh_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +/* called from multi.c while DOing */ +static CURLcode sftp_doing(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = ssh_multi_statemach(data, dophase_done); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + return result; +} + +/* BLOCKING, but the function is using the state machine so the only reason + this is still blocking is that the multi interface code has no support for + disconnecting operations that takes a while */ +static CURLcode sftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection) +{ + CURLcode result = CURLE_OK; + struct ssh_conn *sshc = &conn->proto.sshc; + (void) dead_connection; + + DEBUGF(infof(data, "SSH DISCONNECT starts now")); + + if(sshc->ssh_session) { + /* only if there's a session still around to use! */ + state(data, SSH_SFTP_SHUTDOWN); + result = ssh_block_statemach(data, conn, TRUE); + } + + DEBUGF(infof(data, "SSH DISCONNECT is done")); + + return result; + +} + +static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, + bool premature) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + + if(!status) { + /* Post quote commands are executed after the SFTP_CLOSE state to avoid + errors that could happen due to open file handles during POSTQUOTE + operation */ + if(!premature && data->set.postquote && !conn->bits.retry) + sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; + state(data, SSH_SFTP_CLOSE); + } + return ssh_done(data, status); +} + +/* return number of sent bytes */ +static ssize_t sftp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + ssize_t nwrite; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + (void)sockindex; + + nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len); + + ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); + + if(nwrite == LIBSSH2_ERROR_EAGAIN) { + *err = CURLE_AGAIN; + nwrite = 0; + } + else if(nwrite < LIBSSH2_ERROR_NONE) { + *err = libssh2_session_error_to_CURLE((int)nwrite); + nwrite = -1; + } + + return nwrite; +} + +/* + * Return number of received (decrypted) bytes + * or <0 on error + */ +static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + ssize_t nread; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + (void)sockindex; + + nread = libssh2_sftp_read(sshc->sftp_handle, mem, len); + + ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); + + if(nread == LIBSSH2_ERROR_EAGAIN) { + *err = CURLE_AGAIN; + nread = -1; + + } + else if(nread < 0) { + *err = libssh2_session_error_to_CURLE((int)nread); + } + return nread; +} + +static const char *sftp_libssh2_strerror(unsigned long err) +{ + switch(err) { + case LIBSSH2_FX_NO_SUCH_FILE: + return "No such file or directory"; + + case LIBSSH2_FX_PERMISSION_DENIED: + return "Permission denied"; + + case LIBSSH2_FX_FAILURE: + return "Operation failed"; + + case LIBSSH2_FX_BAD_MESSAGE: + return "Bad message from SFTP server"; + + case LIBSSH2_FX_NO_CONNECTION: + return "Not connected to SFTP server"; + + case LIBSSH2_FX_CONNECTION_LOST: + return "Connection to SFTP server lost"; + + case LIBSSH2_FX_OP_UNSUPPORTED: + return "Operation not supported by SFTP server"; + + case LIBSSH2_FX_INVALID_HANDLE: + return "Invalid handle"; + + case LIBSSH2_FX_NO_SUCH_PATH: + return "No such file or directory"; + + case LIBSSH2_FX_FILE_ALREADY_EXISTS: + return "File already exists"; + + case LIBSSH2_FX_WRITE_PROTECT: + return "File is write protected"; + + case LIBSSH2_FX_NO_MEDIA: + return "No media"; + + case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: + return "Disk full"; + + case LIBSSH2_FX_QUOTA_EXCEEDED: + return "User quota exceeded"; + + case LIBSSH2_FX_UNKNOWN_PRINCIPLE: + return "Unknown principle"; + + case LIBSSH2_FX_LOCK_CONFlICT: + return "File lock conflict"; + + case LIBSSH2_FX_DIR_NOT_EMPTY: + return "Directory not empty"; + + case LIBSSH2_FX_NOT_A_DIRECTORY: + return "Not a directory"; + + case LIBSSH2_FX_INVALID_FILENAME: + return "Invalid filename"; + + case LIBSSH2_FX_LINK_LOOP: + return "Link points to itself"; + } + return "Unknown error in libssh2"; +} + +CURLcode Curl_ssh_init(void) +{ +#ifdef HAVE_LIBSSH2_INIT + if(libssh2_init(0)) { + DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n")); + return CURLE_FAILED_INIT; + } +#endif + return CURLE_OK; +} + +void Curl_ssh_cleanup(void) +{ +#ifdef HAVE_LIBSSH2_EXIT + (void)libssh2_exit(); +#endif +} + +void Curl_ssh_version(char *buffer, size_t buflen) +{ + (void)msnprintf(buffer, buflen, "libssh2/%s", CURL_LIBSSH2_VERSION); +} + +/* The SSH session is associated with the *CONNECTION* but the callback user + * pointer is an easy handle pointer. This function allows us to reassign the + * user pointer to the *CURRENT* (new) easy handle. + */ +static void ssh_attach(struct Curl_easy *data, struct connectdata *conn) +{ + DEBUGASSERT(data); + DEBUGASSERT(conn); + if(conn->handler->protocol & PROTO_FAMILY_SSH) { + struct ssh_conn *sshc = &conn->proto.sshc; + if(sshc->ssh_session) { + /* only re-attach if the session already exists */ + void **abstract = libssh2_session_abstract(sshc->ssh_session); + *abstract = data; + } + } +} +#endif /* USE_LIBSSH2 */ diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h new file mode 100644 index 0000000..ca0533a --- /dev/null +++ b/lib/vssh/ssh.h @@ -0,0 +1,273 @@ +#ifndef HEADER_CURL_SSH_H +#define HEADER_CURL_SSH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_LIBSSH2) +#include +#include +#elif defined(USE_LIBSSH) +#include +#include +#elif defined(USE_WOLFSSH) +#include +#include +#endif + +/**************************************************************************** + * SSH unique setup + ***************************************************************************/ +typedef enum { + SSH_NO_STATE = -1, /* Used for "nextState" so say there is none */ + SSH_STOP = 0, /* do nothing state, stops the state machine */ + + SSH_INIT, /* First state in SSH-CONNECT */ + SSH_S_STARTUP, /* Session startup */ + SSH_HOSTKEY, /* verify hostkey */ + SSH_AUTHLIST, + SSH_AUTH_PKEY_INIT, + SSH_AUTH_PKEY, + SSH_AUTH_PASS_INIT, + SSH_AUTH_PASS, + SSH_AUTH_AGENT_INIT, /* initialize then wait for connection to agent */ + SSH_AUTH_AGENT_LIST, /* ask for list then wait for entire list to come */ + SSH_AUTH_AGENT, /* attempt one key at a time */ + SSH_AUTH_HOST_INIT, + SSH_AUTH_HOST, + SSH_AUTH_KEY_INIT, + SSH_AUTH_KEY, + SSH_AUTH_GSSAPI, + SSH_AUTH_DONE, + SSH_SFTP_INIT, + SSH_SFTP_REALPATH, /* Last state in SSH-CONNECT */ + + SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */ + SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */ + SSH_SFTP_QUOTE, + SSH_SFTP_NEXT_QUOTE, + SSH_SFTP_QUOTE_STAT, + SSH_SFTP_QUOTE_SETSTAT, + SSH_SFTP_QUOTE_SYMLINK, + SSH_SFTP_QUOTE_MKDIR, + SSH_SFTP_QUOTE_RENAME, + SSH_SFTP_QUOTE_RMDIR, + SSH_SFTP_QUOTE_UNLINK, + SSH_SFTP_QUOTE_STATVFS, + SSH_SFTP_GETINFO, + SSH_SFTP_FILETIME, + SSH_SFTP_TRANS_INIT, + SSH_SFTP_UPLOAD_INIT, + SSH_SFTP_CREATE_DIRS_INIT, + SSH_SFTP_CREATE_DIRS, + SSH_SFTP_CREATE_DIRS_MKDIR, + SSH_SFTP_READDIR_INIT, + SSH_SFTP_READDIR, + SSH_SFTP_READDIR_LINK, + SSH_SFTP_READDIR_BOTTOM, + SSH_SFTP_READDIR_DONE, + SSH_SFTP_DOWNLOAD_INIT, + SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */ + SSH_SFTP_CLOSE, /* Last state in SFTP-DONE */ + SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */ + SSH_SCP_TRANS_INIT, /* First state in SCP-DO */ + SSH_SCP_UPLOAD_INIT, + SSH_SCP_DOWNLOAD_INIT, + SSH_SCP_DOWNLOAD, + SSH_SCP_DONE, + SSH_SCP_SEND_EOF, + SSH_SCP_WAIT_EOF, + SSH_SCP_WAIT_CLOSE, + SSH_SCP_CHANNEL_FREE, /* Last state in SCP-DONE */ + SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */ + SSH_SESSION_FREE, /* Last state in SCP/SFTP-DISCONNECT */ + SSH_QUIT, + SSH_LAST /* never used */ +} sshstate; + +/* this struct is used in the HandleData struct which is part of the + Curl_easy, which means this is used on a per-easy handle basis. + Everything that is strictly related to a connection is banned from this + struct. */ +struct SSHPROTO { + char *path; /* the path we operate on */ +#ifdef USE_LIBSSH2 + struct dynbuf readdir_link; + struct dynbuf readdir; + char *readdir_filename; + char *readdir_longentry; + + LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */ + + /* Here's a set of struct members used by the SFTP_READDIR state */ + LIBSSH2_SFTP_ATTRIBUTES readdir_attrs; +#endif +}; + +/* ssh_conn is used for struct connection-oriented data in the connectdata + struct */ +struct ssh_conn { + const char *authlist; /* List of auth. methods, managed by libssh2 */ + + /* common */ + const char *passphrase; /* pass-phrase to use */ + char *rsa_pub; /* strdup'ed public key file */ + char *rsa; /* strdup'ed private key file */ + bool authed; /* the connection has been authenticated fine */ + bool acceptfail; /* used by the SFTP_QUOTE (continue if + quote command fails) */ + sshstate state; /* always use ssh.c:state() to change state! */ + sshstate nextstate; /* the state to goto after stopping */ + CURLcode actualcode; /* the actual error code */ + struct curl_slist *quote_item; /* for the quote option */ + char *quote_path1; /* two generic pointers for the QUOTE stuff */ + char *quote_path2; + + char *homedir; /* when doing SFTP we figure out home dir in the + connect phase */ + /* end of READDIR stuff */ + + int secondCreateDirs; /* counter use by the code to see if the + second attempt has been made to change + to/create a directory */ + int orig_waitfor; /* default READ/WRITE bits wait for */ + char *slash_pos; /* used by the SFTP_CREATE_DIRS state */ + +#if defined(USE_LIBSSH) + char *readdir_linkPath; + size_t readdir_len; + struct dynbuf readdir_buf; +/* our variables */ + unsigned kbd_state; /* 0 or 1 */ + ssh_key privkey; + ssh_key pubkey; + int auth_methods; + ssh_session ssh_session; + ssh_scp scp_session; + sftp_session sftp_session; + sftp_file sftp_file; + sftp_dir sftp_dir; + + unsigned sftp_recv_state; /* 0 or 1 */ + int sftp_file_index; /* for async read */ + sftp_attributes readdir_attrs; /* used by the SFTP readdir actions */ + sftp_attributes readdir_link_attrs; /* used by the SFTP readdir actions */ + sftp_attributes quote_attrs; /* used by the SFTP_QUOTE state */ + + const char *readdir_filename; /* points within readdir_attrs */ + const char *readdir_longentry; + char *readdir_tmp; +#elif defined(USE_LIBSSH2) + LIBSSH2_SESSION *ssh_session; /* Secure Shell session */ + LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */ + LIBSSH2_SFTP *sftp_session; /* SFTP handle */ + LIBSSH2_SFTP_HANDLE *sftp_handle; + +#ifndef CURL_DISABLE_PROXY + /* for HTTPS proxy storage */ + Curl_recv *tls_recv; + Curl_send *tls_send; +#endif + +#ifdef HAVE_LIBSSH2_AGENT_API + LIBSSH2_AGENT *ssh_agent; /* proxy to ssh-agent/pageant */ + struct libssh2_agent_publickey *sshagent_identity, + *sshagent_prev_identity; +#endif + + /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h + header */ +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + LIBSSH2_KNOWNHOSTS *kh; +#endif +#elif defined(USE_WOLFSSH) + WOLFSSH *ssh_session; + WOLFSSH_CTX *ctx; + word32 handleSz; + byte handle[WOLFSSH_MAX_HANDLE]; + curl_off_t offset; +#endif /* USE_LIBSSH */ +}; + +#if defined(USE_LIBSSH2) + +/* Feature detection based on version numbers to better work with + non-configure platforms */ + +#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000) +# error "SCP/SFTP protocols require libssh2 0.16 or later" +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010000 +#define HAVE_LIBSSH2_SFTP_SEEK64 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010100 +#define HAVE_LIBSSH2_VERSION 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010205 +#define HAVE_LIBSSH2_INIT 1 +#define HAVE_LIBSSH2_EXIT 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010206 +#define HAVE_LIBSSH2_KNOWNHOST_CHECKP 1 +#define HAVE_LIBSSH2_SCP_SEND64 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010208 +#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1 +#endif + +#ifdef HAVE_LIBSSH2_VERSION +/* get it run-time if possible */ +#define CURL_LIBSSH2_VERSION libssh2_version(0) +#else +/* use build-time if run-time not possible */ +#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION +#endif + +#endif /* USE_LIBSSH2 */ + +#ifdef USE_SSH + +extern const struct Curl_handler Curl_handler_scp; +extern const struct Curl_handler Curl_handler_sftp; + +/* generic SSH backend functions */ +CURLcode Curl_ssh_init(void); +void Curl_ssh_cleanup(void); +void Curl_ssh_version(char *buffer, size_t buflen); +void Curl_ssh_attach(struct Curl_easy *data, + struct connectdata *conn); +#else +/* for non-SSH builds */ +#define Curl_ssh_cleanup() +#define Curl_ssh_attach(x,y) +#define Curl_ssh_init() 0 +#endif + +#endif /* HEADER_CURL_SSH_H */ diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c new file mode 100644 index 0000000..7396791 --- /dev/null +++ b/lib/vssh/wolfssh.c @@ -0,0 +1,1167 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_WOLFSSH + +#include + +#include +#include +#include "urldata.h" +#include "cfilters.h" +#include "connect.h" +#include "sendf.h" +#include "progress.h" +#include "curl_path.h" +#include "strtoofft.h" +#include "transfer.h" +#include "speedcheck.h" +#include "select.h" +#include "multiif.h" +#include "warnless.h" +#include "strdup.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static CURLcode wssh_connect(struct Curl_easy *data, bool *done); +static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done); +static CURLcode wssh_do(struct Curl_easy *data, bool *done); +#if 0 +static CURLcode wscp_done(struct Curl_easy *data, + CURLcode, bool premature); +static CURLcode wscp_doing(struct Curl_easy *data, + bool *dophase_done); +static CURLcode wscp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection); +#endif +static CURLcode wsftp_done(struct Curl_easy *data, + CURLcode, bool premature); +static CURLcode wsftp_doing(struct Curl_easy *data, + bool *dophase_done); +static CURLcode wsftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead); +static int wssh_getsock(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *sock); +static CURLcode wssh_setup_connection(struct Curl_easy *data, + struct connectdata *conn); + +#if 0 +/* + * SCP protocol handler. + */ + +const struct Curl_handler Curl_handler_scp = { + "SCP", /* scheme */ + wssh_setup_connection, /* setup_connection */ + wssh_do, /* do_it */ + wscp_done, /* done */ + ZERO_NULL, /* do_more */ + wssh_connect, /* connect_it */ + wssh_multi_statemach, /* connecting */ + wscp_doing, /* doing */ + wssh_getsock, /* proto_getsock */ + wssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + wssh_getsock, /* perform_getsock */ + wscp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SSH, /* defport */ + CURLPROTO_SCP, /* protocol */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ +}; + +#endif + +/* + * SFTP protocol handler. + */ + +const struct Curl_handler Curl_handler_sftp = { + "SFTP", /* scheme */ + wssh_setup_connection, /* setup_connection */ + wssh_do, /* do_it */ + wsftp_done, /* done */ + ZERO_NULL, /* do_more */ + wssh_connect, /* connect_it */ + wssh_multi_statemach, /* connecting */ + wsftp_doing, /* doing */ + wssh_getsock, /* proto_getsock */ + wssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + wssh_getsock, /* perform_getsock */ + wsftp_disconnect, /* disconnect */ + ZERO_NULL, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_SSH, /* defport */ + CURLPROTO_SFTP, /* protocol */ + CURLPROTO_SFTP, /* family */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ +}; + +/* + * SSH State machine related code + */ +/* This is the ONLY way to change SSH state! */ +static void state(struct Curl_easy *data, sshstate nowstate) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[] = { + "SSH_STOP", + "SSH_INIT", + "SSH_S_STARTUP", + "SSH_HOSTKEY", + "SSH_AUTHLIST", + "SSH_AUTH_PKEY_INIT", + "SSH_AUTH_PKEY", + "SSH_AUTH_PASS_INIT", + "SSH_AUTH_PASS", + "SSH_AUTH_AGENT_INIT", + "SSH_AUTH_AGENT_LIST", + "SSH_AUTH_AGENT", + "SSH_AUTH_HOST_INIT", + "SSH_AUTH_HOST", + "SSH_AUTH_KEY_INIT", + "SSH_AUTH_KEY", + "SSH_AUTH_GSSAPI", + "SSH_AUTH_DONE", + "SSH_SFTP_INIT", + "SSH_SFTP_REALPATH", + "SSH_SFTP_QUOTE_INIT", + "SSH_SFTP_POSTQUOTE_INIT", + "SSH_SFTP_QUOTE", + "SSH_SFTP_NEXT_QUOTE", + "SSH_SFTP_QUOTE_STAT", + "SSH_SFTP_QUOTE_SETSTAT", + "SSH_SFTP_QUOTE_SYMLINK", + "SSH_SFTP_QUOTE_MKDIR", + "SSH_SFTP_QUOTE_RENAME", + "SSH_SFTP_QUOTE_RMDIR", + "SSH_SFTP_QUOTE_UNLINK", + "SSH_SFTP_QUOTE_STATVFS", + "SSH_SFTP_GETINFO", + "SSH_SFTP_FILETIME", + "SSH_SFTP_TRANS_INIT", + "SSH_SFTP_UPLOAD_INIT", + "SSH_SFTP_CREATE_DIRS_INIT", + "SSH_SFTP_CREATE_DIRS", + "SSH_SFTP_CREATE_DIRS_MKDIR", + "SSH_SFTP_READDIR_INIT", + "SSH_SFTP_READDIR", + "SSH_SFTP_READDIR_LINK", + "SSH_SFTP_READDIR_BOTTOM", + "SSH_SFTP_READDIR_DONE", + "SSH_SFTP_DOWNLOAD_INIT", + "SSH_SFTP_DOWNLOAD_STAT", + "SSH_SFTP_CLOSE", + "SSH_SFTP_SHUTDOWN", + "SSH_SCP_TRANS_INIT", + "SSH_SCP_UPLOAD_INIT", + "SSH_SCP_DOWNLOAD_INIT", + "SSH_SCP_DOWNLOAD", + "SSH_SCP_DONE", + "SSH_SCP_SEND_EOF", + "SSH_SCP_WAIT_EOF", + "SSH_SCP_WAIT_CLOSE", + "SSH_SCP_CHANNEL_FREE", + "SSH_SESSION_DISCONNECT", + "SSH_SESSION_FREE", + "QUIT" + }; + + /* a precaution to make sure the lists are in sync */ + DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST); + + if(sshc->state != nowstate) { + infof(data, "wolfssh %p state change from %s to %s", + (void *)sshc, names[sshc->state], names[nowstate]); + } +#endif + + sshc->state = nowstate; +} + +static ssize_t wscp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + ssize_t nwrite = 0; + (void)data; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ + (void)mem; + (void)len; + (void)err; + + return nwrite; +} + +static ssize_t wscp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + ssize_t nread = 0; + (void)data; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ + (void)mem; + (void)len; + (void)err; + + return nread; +} + +/* return number of sent bytes */ +static ssize_t wsftp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + word32 offset[2]; + int rc; + (void)sockindex; + + offset[0] = (word32)sshc->offset&0xFFFFFFFF; + offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; + + rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle, + sshc->handleSz, + &offset[0], + (byte *)mem, (word32)len); + + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + conn->waitfor = KEEP_RECV; + *err = CURLE_AGAIN; + return -1; + } + else if(rc == WS_WANT_WRITE) { + conn->waitfor = KEEP_SEND; + *err = CURLE_AGAIN; + return -1; + } + if(rc < 0) { + failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc); + return -1; + } + DEBUGASSERT(rc == (int)len); + infof(data, "sent %zu bytes SFTP from offset %" CURL_FORMAT_CURL_OFF_T, + len, sshc->offset); + sshc->offset += len; + return (ssize_t)rc; +} + +/* + * Return number of received (decrypted) bytes + * or <0 on error + */ +static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + int rc; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + word32 offset[2]; + (void)sockindex; + + offset[0] = (word32)sshc->offset&0xFFFFFFFF; + offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; + + rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle, + sshc->handleSz, + &offset[0], + (byte *)mem, (word32)len); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + conn->waitfor = KEEP_RECV; + *err = CURLE_AGAIN; + return -1; + } + else if(rc == WS_WANT_WRITE) { + conn->waitfor = KEEP_SEND; + *err = CURLE_AGAIN; + return -1; + } + + DEBUGASSERT(rc <= (int)len); + + if(rc < 0) { + failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc); + return -1; + } + sshc->offset += len; + + return (ssize_t)rc; +} + +/* + * SSH setup and connection + */ +static CURLcode wssh_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + struct SSHPROTO *ssh; + (void)conn; + + data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); + if(!ssh) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +static int userauth(byte authtype, + WS_UserAuthData* authdata, + void *ctx) +{ + struct Curl_easy *data = ctx; + DEBUGF(infof(data, "wolfssh callback: type %s", + authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" : + "PUBLICCKEY")); + if(authtype == WOLFSSH_USERAUTH_PASSWORD) { + authdata->sf.password.password = (byte *)data->conn->passwd; + authdata->sf.password.passwordSz = (word32) strlen(data->conn->passwd); + } + + return 0; +} + +static CURLcode wssh_connect(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc; + + /* initialize per-handle data if not already */ + if(!data->req.p.ssh) + wssh_setup_connection(data, conn); + + /* We default to persistent connections. We set this already in this connect + function to make the reuse checks properly be able to check this bit. */ + connkeep(conn, "SSH default"); + + if(conn->handler->protocol & CURLPROTO_SCP) { + conn->recv[FIRSTSOCKET] = wscp_recv; + conn->send[FIRSTSOCKET] = wscp_send; + } + else { + conn->recv[FIRSTSOCKET] = wsftp_recv; + conn->send[FIRSTSOCKET] = wsftp_send; + } + sshc = &conn->proto.sshc; + sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); + if(!sshc->ctx) { + failf(data, "No wolfSSH context"); + goto error; + } + + sshc->ssh_session = wolfSSH_new(sshc->ctx); + if(!sshc->ssh_session) { + failf(data, "No wolfSSH session"); + goto error; + } + + rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user); + if(rc != WS_SUCCESS) { + failf(data, "wolfSSH failed to set user name"); + goto error; + } + + /* set callback for authentication */ + wolfSSH_SetUserAuth(sshc->ctx, userauth); + wolfSSH_SetUserAuthCtx(sshc->ssh_session, data); + + rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock); + if(rc) { + failf(data, "wolfSSH failed to set socket"); + goto error; + } + +#if 0 + wolfSSH_Debugging_ON(); +#endif + + *done = TRUE; + if(conn->handler->protocol & CURLPROTO_SCP) + state(data, SSH_INIT); + else + state(data, SSH_SFTP_INIT); + + return wssh_multi_statemach(data, done); +error: + wolfSSH_free(sshc->ssh_session); + wolfSSH_CTX_free(sshc->ctx); + return CURLE_FAILED_INIT; +} + +/* + * wssh_statemach_act() runs the SSH state machine as far as it can without + * blocking and without reaching the end. The data the pointer 'block' points + * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it + * wants to be called again when the socket is ready + */ + +static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + struct SSHPROTO *sftp_scp = data->req.p.ssh; + WS_SFTPNAME *name; + int rc = 0; + *block = FALSE; /* we're not blocking by default */ + + do { + switch(sshc->state) { + case SSH_INIT: + state(data, SSH_S_STARTUP); + break; + + case SSH_S_STARTUP: + rc = wolfSSH_connect(sshc->ssh_session); + if(rc != WS_SUCCESS) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc != WS_SUCCESS) { + state(data, SSH_STOP); + return CURLE_SSH; + } + infof(data, "wolfssh connected"); + state(data, SSH_STOP); + break; + case SSH_STOP: + break; + + case SSH_SFTP_INIT: + rc = wolfSSH_SFTP_connect(sshc->ssh_session); + if(rc != WS_SUCCESS) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh SFTP connected"); + state(data, SSH_SFTP_REALPATH); + } + else { + failf(data, "wolfssh SFTP connect error %d", rc); + return CURLE_SSH; + } + break; + case SSH_SFTP_REALPATH: + name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)"."); + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(name && (rc == WS_SUCCESS)) { + sshc->homedir = Curl_memdup0(name->fName, name->fSz); + if(!sshc->homedir) + sshc->actualcode = CURLE_OUT_OF_MEMORY; + wolfSSH_SFTPNAME_list_free(name); + state(data, SSH_STOP); + return CURLE_OK; + } + failf(data, "wolfssh SFTP realpath %d", rc); + return CURLE_SSH; + + case SSH_SFTP_QUOTE_INIT: + result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path); + if(result) { + sshc->actualcode = result; + state(data, SSH_STOP); + break; + } + + if(data->set.quote) { + infof(data, "Sending quote commands"); + sshc->quote_item = data->set.quote; + state(data, SSH_SFTP_QUOTE); + } + else { + state(data, SSH_SFTP_GETINFO); + } + break; + case SSH_SFTP_GETINFO: + if(data->set.get_filetime) { + state(data, SSH_SFTP_FILETIME); + } + else { + state(data, SSH_SFTP_TRANS_INIT); + } + break; + case SSH_SFTP_TRANS_INIT: + if(data->state.upload) + state(data, SSH_SFTP_UPLOAD_INIT); + else { + if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') + state(data, SSH_SFTP_READDIR_INIT); + else + state(data, SSH_SFTP_DOWNLOAD_INIT); + } + break; + case SSH_SFTP_UPLOAD_INIT: { + word32 flags; + WS_SFTP_FILEATRB createattrs; + if(data->state.resume_from) { + WS_SFTP_FILEATRB attrs; + if(data->state.resume_from < 0) { + rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, + &attrs); + if(rc != WS_SUCCESS) + break; + + if(rc) { + data->state.resume_from = 0; + } + else { + curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; + if(size < 0) { + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + data->state.resume_from = size; + } + } + } + + if(data->set.remote_append) + /* Try to open for append, but create if nonexisting */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; + else if(data->state.resume_from > 0) + /* If we have restart position then open for append */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; + else + /* Clear file before writing (normal behavior) */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; + + memset(&createattrs, 0, sizeof(createattrs)); + createattrs.per = (word32)data->set.new_file_perms; + sshc->handleSz = sizeof(sshc->handle); + rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, + flags, &createattrs, + sshc->handle, &sshc->handleSz); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh SFTP open succeeded"); + } + else { + failf(data, "wolfssh SFTP upload open failed: %d", rc); + return CURLE_SSH; + } + state(data, SSH_SFTP_DOWNLOAD_STAT); + + /* If we have a restart point then we need to seek to the correct + position. */ + if(data->state.resume_from > 0) { + /* Let's read off the proper amount of bytes from the input. */ + int seekerr = CURL_SEEKFUNC_OK; + if(conn->seek_func) { + Curl_set_in_callback(data, true); + seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, + SEEK_SET); + Curl_set_in_callback(data, false); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed = 0; + + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_FTP_COULDNT_USE_REST; + } + /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ + do { + char scratch[4*1024]; + size_t readthisamountnow = + (data->state.resume_from - passed > + (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread; + Curl_set_in_callback(data, true); + actuallyread = data->state.fread_func(scratch, 1, + readthisamountnow, + data->state.in); + Curl_set_in_callback(data, false); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); + } + + /* now, decrease the size of the read */ + if(data->state.infilesize > 0) { + data->state.infilesize -= data->state.resume_from; + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + + sshc->offset += data->state.resume_from; + } + if(data->state.infilesize > 0) { + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + /* upload data */ + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->sockfd = conn->writesockfd; + + if(result) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = result; + } + else { + /* store this original bitmask setup to use later on if we can't + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh2 sftp send function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_OUT; + + /* since we don't really wait for anything at this point, we want the + state machine to move on as soon as possible so we set a very short + timeout here */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + state(data, SSH_STOP); + } + break; + } + case SSH_SFTP_DOWNLOAD_INIT: + sshc->handleSz = sizeof(sshc->handle); + rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, + WOLFSSH_FXF_READ, NULL, + sshc->handle, &sshc->handleSz); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh SFTP open succeeded"); + state(data, SSH_SFTP_DOWNLOAD_STAT); + return CURLE_OK; + } + + failf(data, "wolfssh SFTP open failed: %d", rc); + return CURLE_SSH; + + case SSH_SFTP_DOWNLOAD_STAT: { + WS_SFTP_FILEATRB attrs; + curl_off_t size; + + rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh STAT succeeded"); + } + else { + failf(data, "wolfssh SFTP open failed: %d", rc); + data->req.size = -1; + data->req.maxdownload = -1; + Curl_pgrsSetDownloadSize(data, -1); + return CURLE_SSH; + } + + size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0]; + + data->req.size = size; + data->req.maxdownload = size; + Curl_pgrsSetDownloadSize(data, size); + + infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes", size); + + /* We cannot seek with wolfSSH so resuming and range requests are not + possible */ + if(data->state.use_range || data->state.resume_from) { + infof(data, "wolfSSH cannot do range/seek on SFTP"); + return CURLE_BAD_DOWNLOAD_RESUME; + } + + /* Setup the actual download */ + if(data->req.size == 0) { + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + infof(data, "File already completely downloaded"); + state(data, SSH_STOP); + break; + } + Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->writesockfd = conn->sockfd; + + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ + data->state.select_bits = CURL_CSELECT_IN; + + if(result) { + /* this should never occur; the close state should be entered + at the time the error occurs */ + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = result; + } + else { + state(data, SSH_STOP); + } + break; + } + case SSH_SFTP_CLOSE: + if(sshc->handleSz) + rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle, + sshc->handleSz); + else + rc = WS_SUCCESS; /* directory listing */ + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + state(data, SSH_STOP); + return CURLE_OK; + } + + failf(data, "wolfssh SFTP CLOSE failed: %d", rc); + return CURLE_SSH; + + case SSH_SFTP_READDIR_INIT: + Curl_pgrsSetDownloadSize(data, -1); + if(data->req.no_body) { + state(data, SSH_STOP); + break; + } + state(data, SSH_SFTP_READDIR); + break; + + case SSH_SFTP_READDIR: + name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path); + if(!name) + rc = wolfSSH_get_error(sshc->ssh_session); + else + rc = WS_SUCCESS; + + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(name && (rc == WS_SUCCESS)) { + WS_SFTPNAME *origname = name; + result = CURLE_OK; + while(name) { + char *line = aprintf("%s\n", + data->set.list_only ? + name->fName : name->lName); + if(!line) { + state(data, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + result = Curl_client_write(data, CLIENTWRITE_BODY, + line, strlen(line)); + free(line); + if(result) { + sshc->actualcode = result; + break; + } + name = name->next; + } + wolfSSH_SFTPNAME_list_free(origname); + state(data, SSH_STOP); + return result; + } + failf(data, "wolfssh SFTP ls failed: %d", rc); + return CURLE_SSH; + + case SSH_SFTP_SHUTDOWN: + Curl_safefree(sshc->homedir); + wolfSSH_free(sshc->ssh_session); + wolfSSH_CTX_free(sshc->ctx); + state(data, SSH_STOP); + return CURLE_OK; + default: + break; + } + } while(!rc && (sshc->state != SSH_STOP)); + return result; +} + +/* called repeatedly until done from multi.c */ +static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result = CURLE_OK; + bool block; /* we store the status and use that to provide a ssh_getsock() + implementation */ + do { + result = wssh_statemach_act(data, &block); + *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; + /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then + try again */ + if(*done) { + DEBUGF(infof(data, "wssh_statemach_act says DONE")); + } + } while(!result && !*done && !block); + + return result; +} + +static +CURLcode wscp_perform(struct Curl_easy *data, + bool *connected, + bool *dophase_done) +{ + (void)data; + (void)connected; + (void)dophase_done; + return CURLE_OK; +} + +static +CURLcode wsftp_perform(struct Curl_easy *data, + bool *connected, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + + DEBUGF(infof(data, "DO phase starts")); + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + state(data, SSH_SFTP_QUOTE_INIT); + + /* run the state-machine */ + result = wssh_multi_statemach(data, dophase_done); + + *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + + return result; +} + +/* + * The DO function is generic for both protocols. + */ +static CURLcode wssh_do(struct Curl_easy *data, bool *done) +{ + CURLcode result; + bool connected = 0; + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + + *done = FALSE; /* default to false */ + data->req.size = -1; /* make sure this is unknown at this point */ + sshc->actualcode = CURLE_OK; /* reset error code */ + sshc->secondCreateDirs = 0; /* reset the create dir attempt state + variable */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + if(conn->handler->protocol & CURLPROTO_SCP) + result = wscp_perform(data, &connected, done); + else + result = wsftp_perform(data, &connected, done); + + return result; +} + +static CURLcode wssh_block_statemach(struct Curl_easy *data, + bool disconnect) +{ + struct connectdata *conn = data->conn; + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result = CURLE_OK; + + while((sshc->state != SSH_STOP) && !result) { + bool block; + timediff_t left = 1000; + struct curltime now = Curl_now(); + + result = wssh_statemach_act(data, &block); + if(result) + break; + + if(!disconnect) { + if(Curl_pgrsUpdate(data)) + return CURLE_ABORTED_BY_CALLBACK; + + result = Curl_speedcheck(data, now); + if(result) + break; + + left = Curl_timeleft(data, NULL, FALSE); + if(left < 0) { + failf(data, "Operation timed out"); + return CURLE_OPERATION_TIMEDOUT; + } + } + + if(!result) { + int dir = conn->waitfor; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + curl_socket_t fd_read = CURL_SOCKET_BAD; + curl_socket_t fd_write = CURL_SOCKET_BAD; + if(dir == KEEP_RECV) + fd_read = sock; + else if(dir == KEEP_SEND) + fd_write = sock; + + /* wait for the socket to become ready */ + (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, + left>1000?1000:left); /* ignore result */ + } + } + + return result; +} + +/* generic done function for both SCP and SFTP called from their specific + done functions */ +static CURLcode wssh_done(struct Curl_easy *data, CURLcode status) +{ + CURLcode result = CURLE_OK; + struct SSHPROTO *sftp_scp = data->req.p.ssh; + + if(!status) { + /* run the state-machine */ + result = wssh_block_statemach(data, FALSE); + } + else + result = status; + + if(sftp_scp) + Curl_safefree(sftp_scp->path); + if(Curl_pgrsDone(data)) + return CURLE_ABORTED_BY_CALLBACK; + + data->req.keepon = 0; /* clear all bits */ + return result; +} + +#if 0 +static CURLcode wscp_done(struct Curl_easy *data, + CURLcode code, bool premature) +{ + CURLcode result = CURLE_OK; + (void)conn; + (void)code; + (void)premature; + + return result; +} + +static CURLcode wscp_doing(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + (void)conn; + (void)dophase_done; + + return result; +} + +static CURLcode wscp_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection) +{ + CURLcode result = CURLE_OK; + (void)data; + (void)conn; + (void)dead_connection; + + return result; +} +#endif + +static CURLcode wsftp_done(struct Curl_easy *data, + CURLcode code, bool premature) +{ + (void)premature; + state(data, SSH_SFTP_CLOSE); + + return wssh_done(data, code); +} + +static CURLcode wsftp_doing(struct Curl_easy *data, + bool *dophase_done) +{ + CURLcode result = wssh_multi_statemach(data, dophase_done); + + if(*dophase_done) { + DEBUGF(infof(data, "DO phase is complete")); + } + return result; +} + +static CURLcode wsftp_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead) +{ + CURLcode result = CURLE_OK; + (void)dead; + + DEBUGF(infof(data, "SSH DISCONNECT starts now")); + + if(conn->proto.sshc.ssh_session) { + /* only if there's a session still around to use! */ + state(data, SSH_SFTP_SHUTDOWN); + result = wssh_block_statemach(data, TRUE); + } + + DEBUGF(infof(data, "SSH DISCONNECT is done")); + return result; +} + +static int wssh_getsock(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *sock) +{ + int bitmap = GETSOCK_BLANK; + int dir = conn->waitfor; + (void)data; + sock[0] = conn->sock[FIRSTSOCKET]; + + if(dir == KEEP_RECV) + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + else if(dir == KEEP_SEND) + bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); + + return bitmap; +} + +void Curl_ssh_version(char *buffer, size_t buflen) +{ + (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING); +} + +CURLcode Curl_ssh_init(void) +{ + if(WS_SUCCESS != wolfSSH_Init()) { + DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); + return CURLE_FAILED_INIT; + } + + return CURLE_OK; +} +void Curl_ssh_cleanup(void) +{ + (void)wolfSSH_Cleanup(); +} + +#endif /* USE_WOLFSSH */ diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c new file mode 100644 index 0000000..58394ba --- /dev/null +++ b/lib/vtls/bearssl.c @@ -0,0 +1,1226 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Michael Forney, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_BEARSSL + +#include + +#include "bearssl.h" +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "vtls.h" +#include "vtls_int.h" +#include "connect.h" +#include "select.h" +#include "multiif.h" +#include "curl_printf.h" +#include "strcase.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +struct x509_context { + const br_x509_class *vtable; + br_x509_minimal_context minimal; + br_x509_decoder_context decoder; + bool verifyhost; + bool verifypeer; + int cert_num; +}; + +struct bearssl_ssl_backend_data { + br_ssl_client_context ctx; + struct x509_context x509; + unsigned char buf[BR_SSL_BUFSIZE_BIDI]; + br_x509_trust_anchor *anchors; + size_t anchors_len; + const char *protocols[ALPN_ENTRIES_MAX]; + /* SSL client context is active */ + bool active; + /* size of pending write, yet to be flushed */ + size_t pending_write; +}; + +struct cafile_parser { + CURLcode err; + bool in_cert; + br_x509_decoder_context xc; + /* array of trust anchors loaded from CAfile */ + br_x509_trust_anchor *anchors; + size_t anchors_len; + /* buffer for DN data */ + unsigned char dn[1024]; + size_t dn_len; +}; + +#define CAFILE_SOURCE_PATH 1 +#define CAFILE_SOURCE_BLOB 2 +struct cafile_source { + int type; + const char *data; + size_t len; +}; + +static void append_dn(void *ctx, const void *buf, size_t len) +{ + struct cafile_parser *ca = ctx; + + if(ca->err != CURLE_OK || !ca->in_cert) + return; + if(sizeof(ca->dn) - ca->dn_len < len) { + ca->err = CURLE_FAILED_INIT; + return; + } + memcpy(ca->dn + ca->dn_len, buf, len); + ca->dn_len += len; +} + +static void x509_push(void *ctx, const void *buf, size_t len) +{ + struct cafile_parser *ca = ctx; + + if(ca->in_cert) + br_x509_decoder_push(&ca->xc, buf, len); +} + +static CURLcode load_cafile(struct cafile_source *source, + br_x509_trust_anchor **anchors, + size_t *anchors_len) +{ + struct cafile_parser ca; + br_pem_decoder_context pc; + br_x509_trust_anchor *ta; + size_t ta_size; + br_x509_trust_anchor *new_anchors; + size_t new_anchors_len; + br_x509_pkey *pkey; + FILE *fp = 0; + unsigned char buf[BUFSIZ]; + const unsigned char *p; + const char *name; + size_t n, i, pushed; + + DEBUGASSERT(source->type == CAFILE_SOURCE_PATH + || source->type == CAFILE_SOURCE_BLOB); + + if(source->type == CAFILE_SOURCE_PATH) { + fp = fopen(source->data, "rb"); + if(!fp) + return CURLE_SSL_CACERT_BADFILE; + } + + if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX) + return CURLE_SSL_CACERT_BADFILE; + + ca.err = CURLE_OK; + ca.in_cert = FALSE; + ca.anchors = NULL; + ca.anchors_len = 0; + br_pem_decoder_init(&pc); + br_pem_decoder_setdest(&pc, x509_push, &ca); + do { + if(source->type == CAFILE_SOURCE_PATH) { + n = fread(buf, 1, sizeof(buf), fp); + if(n == 0) + break; + p = buf; + } + else if(source->type == CAFILE_SOURCE_BLOB) { + n = source->len; + p = (unsigned char *) source->data; + } + while(n) { + pushed = br_pem_decoder_push(&pc, p, n); + if(ca.err) + goto fail; + p += pushed; + n -= pushed; + + switch(br_pem_decoder_event(&pc)) { + case 0: + break; + case BR_PEM_BEGIN_OBJ: + name = br_pem_decoder_name(&pc); + if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE")) + break; + br_x509_decoder_init(&ca.xc, append_dn, &ca); + ca.in_cert = TRUE; + ca.dn_len = 0; + break; + case BR_PEM_END_OBJ: + if(!ca.in_cert) + break; + ca.in_cert = FALSE; + if(br_x509_decoder_last_error(&ca.xc)) { + ca.err = CURLE_SSL_CACERT_BADFILE; + goto fail; + } + /* add trust anchor */ + if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) { + ca.err = CURLE_OUT_OF_MEMORY; + goto fail; + } + new_anchors_len = ca.anchors_len + 1; + new_anchors = realloc(ca.anchors, + new_anchors_len * sizeof(ca.anchors[0])); + if(!new_anchors) { + ca.err = CURLE_OUT_OF_MEMORY; + goto fail; + } + ca.anchors = new_anchors; + ca.anchors_len = new_anchors_len; + ta = &ca.anchors[ca.anchors_len - 1]; + ta->dn.data = NULL; + ta->flags = 0; + if(br_x509_decoder_isCA(&ca.xc)) + ta->flags |= BR_X509_TA_CA; + pkey = br_x509_decoder_get_pkey(&ca.xc); + if(!pkey) { + ca.err = CURLE_SSL_CACERT_BADFILE; + goto fail; + } + ta->pkey = *pkey; + + /* calculate space needed for trust anchor data */ + ta_size = ca.dn_len; + switch(pkey->key_type) { + case BR_KEYTYPE_RSA: + ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen; + break; + case BR_KEYTYPE_EC: + ta_size += pkey->key.ec.qlen; + break; + default: + ca.err = CURLE_FAILED_INIT; + goto fail; + } + + /* fill in trust anchor DN and public key data */ + ta->dn.data = malloc(ta_size); + if(!ta->dn.data) { + ca.err = CURLE_OUT_OF_MEMORY; + goto fail; + } + memcpy(ta->dn.data, ca.dn, ca.dn_len); + ta->dn.len = ca.dn_len; + switch(pkey->key_type) { + case BR_KEYTYPE_RSA: + ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len; + memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen); + ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen; + memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen); + break; + case BR_KEYTYPE_EC: + ta->pkey.key.ec.q = ta->dn.data + ta->dn.len; + memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen); + break; + } + break; + default: + ca.err = CURLE_SSL_CACERT_BADFILE; + goto fail; + } + } + } while(source->type != CAFILE_SOURCE_BLOB); + if(fp && ferror(fp)) + ca.err = CURLE_READ_ERROR; + else if(ca.in_cert) + ca.err = CURLE_SSL_CACERT_BADFILE; + +fail: + if(fp) + fclose(fp); + if(ca.err == CURLE_OK) { + *anchors = ca.anchors; + *anchors_len = ca.anchors_len; + } + else { + for(i = 0; i < ca.anchors_len; ++i) + free(ca.anchors[i].dn.data); + free(ca.anchors); + } + + return ca.err; +} + +static void x509_start_chain(const br_x509_class **ctx, + const char *server_name) +{ + struct x509_context *x509 = (struct x509_context *)ctx; + + if(!x509->verifypeer) { + x509->cert_num = 0; + return; + } + + if(!x509->verifyhost) + server_name = NULL; + x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name); +} + +static void x509_start_cert(const br_x509_class **ctx, uint32_t length) +{ + struct x509_context *x509 = (struct x509_context *)ctx; + + if(!x509->verifypeer) { + /* Only decode the first cert in the chain to obtain the public key */ + if(x509->cert_num == 0) + br_x509_decoder_init(&x509->decoder, NULL, NULL); + return; + } + + x509->minimal.vtable->start_cert(&x509->minimal.vtable, length); +} + +static void x509_append(const br_x509_class **ctx, const unsigned char *buf, + size_t len) +{ + struct x509_context *x509 = (struct x509_context *)ctx; + + if(!x509->verifypeer) { + if(x509->cert_num == 0) + br_x509_decoder_push(&x509->decoder, buf, len); + return; + } + + x509->minimal.vtable->append(&x509->minimal.vtable, buf, len); +} + +static void x509_end_cert(const br_x509_class **ctx) +{ + struct x509_context *x509 = (struct x509_context *)ctx; + + if(!x509->verifypeer) { + x509->cert_num++; + return; + } + + x509->minimal.vtable->end_cert(&x509->minimal.vtable); +} + +static unsigned x509_end_chain(const br_x509_class **ctx) +{ + struct x509_context *x509 = (struct x509_context *)ctx; + + if(!x509->verifypeer) { + return br_x509_decoder_last_error(&x509->decoder); + } + + return x509->minimal.vtable->end_chain(&x509->minimal.vtable); +} + +static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx, + unsigned *usages) +{ + struct x509_context *x509 = (struct x509_context *)ctx; + + if(!x509->verifypeer) { + /* Nothing in the chain is verified, just return the public key of the + first certificate and allow its usage for both TLS_RSA_* and + TLS_ECDHE_* */ + if(usages) + *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN; + return br_x509_decoder_get_pkey(&x509->decoder); + } + + return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages); +} + +static const br_x509_class x509_vtable = { + sizeof(struct x509_context), + x509_start_chain, + x509_start_cert, + x509_append, + x509_end_cert, + x509_end_chain, + x509_get_pkey +}; + +struct st_cipher { + const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */ + const char *alias_name; /* Alias name is the same as OpenSSL cipher name */ + uint16_t num; /* BearSSL cipher suite */ +}; + +/* Macro to initialize st_cipher data structure */ +#define CIPHER_DEF(num, alias) { #num, alias, BR_##num } + +static const struct st_cipher ciphertable[] = { + /* RFC 2246 TLS 1.0 */ + CIPHER_DEF(TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */ + "DES-CBC3-SHA"), + + /* RFC 3268 TLS 1.0 AES */ + CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */ + "AES128-SHA"), + CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */ + "AES256-SHA"), + + /* RFC 5246 TLS 1.2 */ + CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */ + "AES128-SHA256"), + CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */ + "AES256-SHA256"), + + /* RFC 5288 TLS 1.2 AES GCM */ + CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */ + "AES128-GCM-SHA256"), + CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */ + "AES256-GCM-SHA384"), + + /* RFC 4492 TLS 1.0 ECC */ + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */ + "ECDH-ECDSA-DES-CBC3-SHA"), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */ + "ECDH-ECDSA-AES128-SHA"), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */ + "ECDH-ECDSA-AES256-SHA"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */ + "ECDHE-ECDSA-DES-CBC3-SHA"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */ + "ECDHE-ECDSA-AES128-SHA"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */ + "ECDHE-ECDSA-AES256-SHA"), + CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */ + "ECDH-RSA-DES-CBC3-SHA"), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */ + "ECDH-RSA-AES128-SHA"), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */ + "ECDH-RSA-AES256-SHA"), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */ + "ECDHE-RSA-DES-CBC3-SHA"), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */ + "ECDHE-RSA-AES128-SHA"), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */ + "ECDHE-RSA-AES256-SHA"), + + /* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */ + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */ + "ECDHE-ECDSA-AES128-SHA256"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */ + "ECDHE-ECDSA-AES256-SHA384"), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */ + "ECDH-ECDSA-AES128-SHA256"), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */ + "ECDH-ECDSA-AES256-SHA384"), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */ + "ECDHE-RSA-AES128-SHA256"), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */ + "ECDHE-RSA-AES256-SHA384"), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */ + "ECDH-RSA-AES128-SHA256"), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */ + "ECDH-RSA-AES256-SHA384"), + + /* RFC 5289 TLS 1.2 GCM */ + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */ + "ECDHE-ECDSA-AES128-GCM-SHA256"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */ + "ECDHE-ECDSA-AES256-GCM-SHA384"), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */ + "ECDH-ECDSA-AES128-GCM-SHA256"), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */ + "ECDH-ECDSA-AES256-GCM-SHA384"), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */ + "ECDHE-RSA-AES128-GCM-SHA256"), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */ + "ECDHE-RSA-AES256-GCM-SHA384"), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */ + "ECDH-RSA-AES128-GCM-SHA256"), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */ + "ECDH-RSA-AES256-GCM-SHA384"), +#ifdef BR_TLS_RSA_WITH_AES_128_CCM + + /* RFC 6655 TLS 1.2 CCM + Supported since BearSSL 0.6 */ + CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */ + "AES128-CCM"), + CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */ + "AES256-CCM"), + CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */ + "AES128-CCM8"), + CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */ + "AES256-CCM8"), + + /* RFC 7251 TLS 1.2 ECC CCM + Supported since BearSSL 0.6 */ + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */ + "ECDHE-ECDSA-AES128-CCM"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */ + "ECDHE-ECDSA-AES256-CCM"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */ + "ECDHE-ECDSA-AES128-CCM8"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */ + "ECDHE-ECDSA-AES256-CCM8"), +#endif + + /* RFC 7905 TLS 1.2 ChaCha20-Poly1305 + Supported since BearSSL 0.2 */ + CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */ + "ECDHE-RSA-CHACHA20-POLY1305"), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */ + "ECDHE-ECDSA-CHACHA20-POLY1305"), +}; + +#define NUM_OF_CIPHERS (sizeof(ciphertable) / sizeof(ciphertable[0])) +#define CIPHER_NAME_BUF_LEN 64 + +static bool is_separator(char c) +{ + /* Return whether character is a cipher list separator. */ + switch(c) { + case ' ': + case '\t': + case ':': + case ',': + case ';': + return true; + } + return false; +} + +static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data, + br_ssl_engine_context *ssl_eng, + const char *ciphers) +{ + uint16_t selected_ciphers[NUM_OF_CIPHERS]; + size_t selected_count = 0; + const char *cipher_start = ciphers; + const char *cipher_end; + size_t i, j; + + if(!cipher_start) + return CURLE_SSL_CIPHER; + + while(true) { + const char *cipher; + size_t clen; + + /* Extract the next cipher name from the ciphers string */ + while(is_separator(*cipher_start)) + ++cipher_start; + if(!*cipher_start) + break; + cipher_end = cipher_start; + while(*cipher_end && !is_separator(*cipher_end)) + ++cipher_end; + + clen = cipher_end - cipher_start; + cipher = cipher_start; + + cipher_start = cipher_end; + + /* Lookup the cipher name in the table of available ciphers. If the cipher + name starts with "TLS_" we do the lookup by IANA name. Otherwise, we try + to match cipher name by an (OpenSSL) alias. */ + if(strncasecompare(cipher, "TLS_", 4)) { + for(i = 0; i < NUM_OF_CIPHERS && + (strlen(ciphertable[i].name) == clen) && + !strncasecompare(cipher, ciphertable[i].name, clen); ++i); + } + else { + for(i = 0; i < NUM_OF_CIPHERS && + (strlen(ciphertable[i].alias_name) == clen) && + !strncasecompare(cipher, ciphertable[i].alias_name, clen); ++i); + } + if(i == NUM_OF_CIPHERS) { + infof(data, "BearSSL: unknown cipher in list: %.*s", + (int)clen, cipher); + continue; + } + + /* No duplicates allowed */ + for(j = 0; j < selected_count && + selected_ciphers[j] != ciphertable[i].num; j++); + if(j < selected_count) { + infof(data, "BearSSL: duplicate cipher in list: %.*s", + (int)clen, cipher); + continue; + } + + DEBUGASSERT(selected_count < NUM_OF_CIPHERS); + selected_ciphers[selected_count] = ciphertable[i].num; + ++selected_count; + } + + if(selected_count == 0) { + failf(data, "BearSSL: no supported cipher in list"); + return CURLE_SSL_CIPHER; + } + + br_ssl_engine_set_suites(ssl_eng, selected_ciphers, selected_count); + return CURLE_OK; +} + +static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : conn_config->CAfile); + const char *hostname = connssl->peer.hostname; + const bool verifypeer = conn_config->verifypeer; + const bool verifyhost = conn_config->verifyhost; + CURLcode ret; + unsigned version_min, version_max; + int session_set = 0; + + DEBUGASSERT(backend); + CURL_TRC_CF(data, cf, "connect_step1"); + + switch(conn_config->version) { + case CURL_SSLVERSION_SSLv2: + failf(data, "BearSSL does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv3: + failf(data, "BearSSL does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_0: + version_min = BR_TLS10; + version_max = BR_TLS10; + break; + case CURL_SSLVERSION_TLSv1_1: + version_min = BR_TLS11; + version_max = BR_TLS11; + break; + case CURL_SSLVERSION_TLSv1_2: + version_min = BR_TLS12; + version_max = BR_TLS12; + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + version_min = BR_TLS10; + version_max = BR_TLS12; + break; + default: + failf(data, "BearSSL: unknown CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(verifypeer) { + if(ca_info_blob) { + struct cafile_source source; + source.type = CAFILE_SOURCE_BLOB; + source.data = ca_info_blob->data; + source.len = ca_info_blob->len; + + CURL_TRC_CF(data, cf, "connect_step1, load ca_info_blob"); + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); + if(ret != CURLE_OK) { + failf(data, "error importing CA certificate blob"); + return ret; + } + } + + if(ssl_cafile) { + struct cafile_source source; + source.type = CAFILE_SOURCE_PATH; + source.data = ssl_cafile; + source.len = 0; + + CURL_TRC_CF(data, cf, "connect_step1, load cafile"); + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); + if(ret != CURLE_OK) { + failf(data, "error setting certificate verify locations." + " CAfile: %s", ssl_cafile); + return ret; + } + } + } + + /* initialize SSL context */ + br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal, + backend->anchors, backend->anchors_len); + br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max); + br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf, + sizeof(backend->buf), 1); + + if(conn_config->cipher_list) { + /* Override the ciphers as specified. For the default cipher list see the + BearSSL source code of br_ssl_client_init_full() */ + CURL_TRC_CF(data, cf, "connect_step1, set ciphers"); + ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng, + conn_config->cipher_list); + if(ret) + return ret; + } + + /* initialize X.509 context */ + backend->x509.vtable = &x509_vtable; + backend->x509.verifypeer = verifypeer; + backend->x509.verifyhost = verifyhost; + br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); + + if(ssl_config->primary.sessionid) { + void *session; + + CURL_TRC_CF(data, cf, "connect_step1, check session cache"); + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) { + br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); + session_set = 1; + infof(data, "BearSSL: reusing session ID"); + } + Curl_ssl_sessionid_unlock(data); + } + + if(connssl->alpn) { + struct alpn_proto_buf proto; + size_t i; + + for(i = 0; i < connssl->alpn->count; ++i) { + backend->protocols[i] = connssl->alpn->entries[i]; + } + br_ssl_engine_set_protocol_names(&backend->ctx.eng, backend->protocols, + connssl->alpn->count); + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } + + if(connssl->peer.is_ip_address) { + if(verifyhost) { + failf(data, "BearSSL: " + "host verification of IP address is not supported"); + return CURLE_PEER_FAILED_VERIFICATION; + } + hostname = NULL; + } + else { + if(!connssl->peer.sni) { + failf(data, "Failed to set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + hostname = connssl->peer.sni; + CURL_TRC_CF(data, cf, "connect_step1, SNI set"); + } + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + Curl_set_in_callback(data, true); + ret = (*data->set.ssl.fsslctx)(data, &backend->ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(ret) { + failf(data, "BearSSL: error signaled by ssl ctx callback"); + return ret; + } + } + + if(!br_ssl_client_reset(&backend->ctx, hostname, session_set)) + return CURLE_FAILED_INIT; + backend->active = TRUE; + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static void bearssl_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + if(!cf->connected) { + curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data); + if(sock != CURL_SOCKET_BAD) { + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + unsigned state = br_ssl_engine_current_state(&backend->ctx.eng); + + if(state & BR_SSL_SENDREC) { + Curl_pollset_set_out_only(data, ps, sock); + } + else { + Curl_pollset_set_in_only(data, ps, sock); + } + } + } +} + +static CURLcode bearssl_run_until(struct Curl_cfilter *cf, + struct Curl_easy *data, + unsigned target) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + unsigned state; + unsigned char *buf; + size_t len; + ssize_t ret; + CURLcode result; + int err; + + DEBUGASSERT(backend); + + for(;;) { + state = br_ssl_engine_current_state(&backend->ctx.eng); + if(state & BR_SSL_CLOSED) { + err = br_ssl_engine_last_error(&backend->ctx.eng); + switch(err) { + case BR_ERR_OK: + /* TLS close notify */ + if(connssl->state != ssl_connection_complete) { + failf(data, "SSL: connection closed during handshake"); + return CURLE_SSL_CONNECT_ERROR; + } + return CURLE_OK; + case BR_ERR_X509_EXPIRED: + failf(data, "SSL: X.509 verification: " + "certificate is expired or not yet valid"); + return CURLE_PEER_FAILED_VERIFICATION; + case BR_ERR_X509_BAD_SERVER_NAME: + failf(data, "SSL: X.509 verification: " + "expected server name was not found in the chain"); + return CURLE_PEER_FAILED_VERIFICATION; + case BR_ERR_X509_NOT_TRUSTED: + failf(data, "SSL: X.509 verification: " + "chain could not be linked to a trust anchor"); + return CURLE_PEER_FAILED_VERIFICATION; + } + /* X.509 errors are documented to have the range 32..63 */ + if(err >= 32 && err < 64) + return CURLE_PEER_FAILED_VERIFICATION; + return CURLE_SSL_CONNECT_ERROR; + } + if(state & target) + return CURLE_OK; + if(state & BR_SSL_SENDREC) { + buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len); + ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result); + CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result); + if(ret <= 0) { + return result; + } + br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret); + } + else if(state & BR_SSL_RECVREC) { + buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len); + ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result); + CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result); + if(ret == 0) { + failf(data, "SSL: EOF without close notify"); + return CURLE_READ_ERROR; + } + if(ret <= 0) { + return result; + } + br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret); + } + } +} + +static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + CURLcode ret; + + DEBUGASSERT(backend); + CURL_TRC_CF(data, cf, "connect_step2"); + + ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP); + if(ret == CURLE_AGAIN) + return CURLE_OK; + if(ret == CURLE_OK) { + unsigned int tver; + if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) { + failf(data, "SSL: connection closed during handshake"); + return CURLE_SSL_CONNECT_ERROR; + } + connssl->connecting_state = ssl_connect_3; + /* Informational message */ + tver = br_ssl_engine_get_version(&backend->ctx.eng); + if(tver == 0x0303) + infof(data, "SSL connection using TLSv1.2"); + else if(tver == 0x0304) + infof(data, "SSL connection using TLSv1.3"); + else + infof(data, "SSL connection using TLS 0x%x", tver); + } + return ret; +} + +static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + CURLcode ret; + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + DEBUGASSERT(backend); + CURL_TRC_CF(data, cf, "connect_step3"); + + if(connssl->alpn) { + const char *proto; + + proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); + Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto, + proto? strlen(proto) : 0); + } + + if(ssl_config->primary.sessionid) { + bool incache; + bool added = FALSE; + void *oldsession; + br_ssl_session_parameters *session; + + session = malloc(sizeof(*session)); + if(!session) + return CURLE_OUT_OF_MEMORY; + br_ssl_engine_get_session_parameters(&backend->ctx.eng, session); + Curl_ssl_sessionid_lock(data); + incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL)); + if(incache) + Curl_ssl_delsessionid(data, oldsession); + ret = Curl_ssl_addsessionid(cf, data, session, 0, &added); + Curl_ssl_sessionid_unlock(data); + if(!added) + free(session); + if(ret) { + return CURLE_OUT_OF_MEMORY; + } + } + + connssl->connecting_state = ssl_connect_done; + + return CURLE_OK; +} + +static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + unsigned char *app; + size_t applen; + + DEBUGASSERT(backend); + + for(;;) { + *err = bearssl_run_until(cf, data, BR_SSL_SENDAPP); + if(*err) + return -1; + app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen); + if(!app) { + failf(data, "SSL: connection closed during write"); + *err = CURLE_SEND_ERROR; + return -1; + } + if(backend->pending_write) { + applen = backend->pending_write; + backend->pending_write = 0; + return applen; + } + if(applen > len) + applen = len; + memcpy(app, buf, applen); + br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen); + br_ssl_engine_flush(&backend->ctx.eng, 0); + backend->pending_write = applen; + } +} + +static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + unsigned char *app; + size_t applen; + + DEBUGASSERT(backend); + + *err = bearssl_run_until(cf, data, BR_SSL_RECVAPP); + if(*err != CURLE_OK) + return -1; + app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen); + if(!app) + return 0; + if(applen > len) + applen = len; + memcpy(buf, app, applen); + br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen); + + return applen; +} + +static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool nonblocking, + bool *done) +{ + CURLcode ret; + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + timediff_t timeout_ms; + int what; + + CURL_TRC_CF(data, cf, "connect_common(blocking=%d)", !nonblocking); + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + CURL_TRC_CF(data, cf, "connect_common, connected"); + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + ret = bearssl_connect_step1(cf, data); + if(ret) + return ret; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + CURL_TRC_CF(data, cf, "connect_common, check socket"); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); + CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if this + * connection is done nonblocking and this loop would execute again. This + * permits the owner of a multi handle to abort a connection attempt + * before step2 has completed while ensuring that a client using select() + * or epoll() will always have a valid fdset to wait on. + */ + ret = bearssl_connect_step2(cf, data); + if(ret || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return ret; + } + + if(ssl_connect_3 == connssl->connecting_state) { + ret = bearssl_connect_step3(cf, data); + if(ret) + return ret; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +static size_t bearssl_version(char *buffer, size_t size) +{ + return msnprintf(buffer, size, "BearSSL"); +} + +static bool bearssl_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct ssl_connect_data *ctx = cf->ctx; + struct bearssl_ssl_backend_data *backend; + + (void)data; + DEBUGASSERT(ctx && ctx->backend); + backend = (struct bearssl_ssl_backend_data *)ctx->backend; + return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP; +} + +static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM, + unsigned char *entropy, size_t length) +{ + static br_hmac_drbg_context ctx; + static bool seeded = FALSE; + + if(!seeded) { + br_prng_seeder seeder; + + br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0); + seeder = br_prng_seeder_system(NULL); + if(!seeder || !seeder(&ctx.vtable)) + return CURLE_FAILED_INIT; + seeded = TRUE; + } + br_hmac_drbg_generate(&ctx, entropy, length); + + return CURLE_OK; +} + +static CURLcode bearssl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode ret; + bool done = FALSE; + + ret = bearssl_connect_common(cf, data, FALSE, &done); + if(ret) + return ret; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + return bearssl_connect_common(cf, data, TRUE, done); +} + +static void *bearssl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + DEBUGASSERT(backend); + return &backend->ctx; +} + +static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; + size_t i; + + DEBUGASSERT(backend); + + if(backend->active) { + backend->active = FALSE; + br_ssl_engine_close(&backend->ctx.eng); + (void)bearssl_run_until(cf, data, BR_SSL_CLOSED); + } + if(backend->anchors) { + for(i = 0; i < backend->anchors_len; ++i) + free(backend->anchors[i].dn.data); + Curl_safefree(backend->anchors); + } +} + +static void bearssl_session_free(void *ptr) +{ + free(ptr); +} + +static CURLcode bearssl_sha256sum(const unsigned char *input, + size_t inputlen, + unsigned char *sha256sum, + size_t sha256len UNUSED_PARAM) +{ + br_sha256_context ctx; + + br_sha256_init(&ctx); + br_sha256_update(&ctx, input, inputlen); + br_sha256_out(&ctx, sha256sum); + return CURLE_OK; +} + +const struct Curl_ssl Curl_ssl_bearssl = { + { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */ + SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY, + sizeof(struct bearssl_ssl_backend_data), + + Curl_none_init, /* init */ + Curl_none_cleanup, /* cleanup */ + bearssl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + bearssl_data_pending, /* data_pending */ + bearssl_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + bearssl_connect, /* connect */ + bearssl_connect_nonblocking, /* connect_nonblocking */ + bearssl_adjust_pollset, /* adjust_pollset */ + bearssl_get_internals, /* get_internals */ + bearssl_close, /* close_one */ + Curl_none_close_all, /* close_all */ + bearssl_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + bearssl_sha256sum, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + bearssl_recv, /* recv decrypted data */ + bearssl_send, /* send data to encrypt */ +}; + +#endif /* USE_BEARSSL */ diff --git a/lib/vtls/bearssl.h b/lib/vtls/bearssl.h new file mode 100644 index 0000000..b3651b0 --- /dev/null +++ b/lib/vtls/bearssl.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_BEARSSL_H +#define HEADER_CURL_BEARSSL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Michael Forney, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_BEARSSL + +extern const struct Curl_ssl Curl_ssl_bearssl; + +#endif /* USE_BEARSSL */ +#endif /* HEADER_CURL_BEARSSL_H */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c new file mode 100644 index 0000000..b95c5be --- /dev/null +++ b/lib/vtls/gtls.c @@ -0,0 +1,1677 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + * Note: don't use the GnuTLS' *_t variable type names in this source code, + * since they were not present in 1.0.X. + */ + +#include "curl_setup.h" + +#ifdef USE_GNUTLS + +#include +#include +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "gtls.h" +#include "vtls.h" +#include "vtls_int.h" +#include "vauth/vauth.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "strcase.h" +#include "warnless.h" +#include "x509asn1.h" +#include "multiif.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* Enable GnuTLS debugging by defining GTLSDEBUG */ +/*#define GTLSDEBUG */ + +#ifdef GTLSDEBUG +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} +#endif +static bool gtls_inited = FALSE; + +#if !defined(GNUTLS_VERSION_NUMBER) || (GNUTLS_VERSION_NUMBER < 0x03010a) +#error "too old GnuTLS version" +#endif + +# include + +struct gtls_ssl_backend_data { + struct gtls_instance gtls; +}; + +static ssize_t gtls_push(void *s, const void *buf, size_t blen) +{ + struct Curl_cfilter *cf = s; + struct ssl_connect_data *connssl = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result; + + DEBUGASSERT(data); + nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); + if(nwritten < 0) { + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + gnutls_transport_set_errno(backend->gtls.session, + (CURLE_AGAIN == result)? EAGAIN : EINVAL); + nwritten = -1; + } + return nwritten; +} + +static ssize_t gtls_pull(void *s, void *buf, size_t blen) +{ + struct Curl_cfilter *cf = s; + struct ssl_connect_data *connssl = cf->ctx; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nread; + CURLcode result; + + DEBUGASSERT(data); + nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); + if(nread < 0) { + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + gnutls_transport_set_errno(backend->gtls.session, + (CURLE_AGAIN == result)? EAGAIN : EINVAL); + nread = -1; + } + return nread; +} + +/* gtls_init() + * + * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that + * are not thread-safe and thus this function itself is not thread-safe and + * must only be called from within curl_global_init() to keep the thread + * situation under control! + */ +static int gtls_init(void) +{ + int ret = 1; + if(!gtls_inited) { + ret = gnutls_global_init()?0:1; +#ifdef GTLSDEBUG + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(2); +#endif + gtls_inited = TRUE; + } + return ret; +} + +static void gtls_cleanup(void) +{ + if(gtls_inited) { + gnutls_global_deinit(); + gtls_inited = FALSE; + } +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void showtime(struct Curl_easy *data, + const char *text, + time_t stamp) +{ + struct tm buffer; + const struct tm *tm = &buffer; + char str[96]; + CURLcode result = Curl_gmtime(stamp, &buffer); + if(result) + return; + + msnprintf(str, + sizeof(str), + " %s: %s, %02d %s %4d %02d:%02d:%02d GMT", + text, + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + infof(data, "%s", str); +} +#endif + +static gnutls_datum_t load_file(const char *file) +{ + FILE *f; + gnutls_datum_t loaded_file = { NULL, 0 }; + long filelen; + void *ptr; + + f = fopen(file, "rb"); + if(!f) + return loaded_file; + if(fseek(f, 0, SEEK_END) != 0 + || (filelen = ftell(f)) < 0 + || fseek(f, 0, SEEK_SET) != 0 + || !(ptr = malloc((size_t)filelen))) + goto out; + if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { + free(ptr); + goto out; + } + + loaded_file.data = ptr; + loaded_file.size = (unsigned int)filelen; +out: + fclose(f); + return loaded_file; +} + +static void unload_file(gnutls_datum_t data) +{ + free(data.data); +} + + +/* this function does a SSL/TLS (re-)handshake */ +static CURLcode handshake(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool duringconnect, + bool nonblocking) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + gnutls_session_t session; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + + DEBUGASSERT(backend); + session = backend->gtls.session; + + for(;;) { + timediff_t timeout_ms; + int rc; + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, duringconnect); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + int what; + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0: + timeout_ms?timeout_ms:1000); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) + return CURLE_OK; + else if(timeout_ms) { + /* timeout */ + failf(data, "SSL connection timeout at %ld", (long)timeout_ms); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + rc = gnutls_handshake(session); + + if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { + connssl->connecting_state = + gnutls_record_get_direction(session)? + ssl_connect_2_writing:ssl_connect_2_reading; + continue; + } + else if((rc < 0) && !gnutls_error_is_fatal(rc)) { + const char *strerr = NULL; + + if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { + int alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(!strerr) + strerr = gnutls_strerror(rc); + + infof(data, "gnutls_handshake() warning: %s", strerr); + continue; + } + else if(rc < 0) { + const char *strerr = NULL; + + if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { + int alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(!strerr) + strerr = gnutls_strerror(rc); + + failf(data, "gnutls_handshake() failed: %s", strerr); + return CURLE_SSL_CONNECT_ERROR; + } + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + return CURLE_OK; + } +} + +static gnutls_x509_crt_fmt_t do_file_type(const char *type) +{ + if(!type || !type[0]) + return GNUTLS_X509_FMT_PEM; + if(strcasecompare(type, "PEM")) + return GNUTLS_X509_FMT_PEM; + if(strcasecompare(type, "DER")) + return GNUTLS_X509_FMT_DER; + return GNUTLS_X509_FMT_PEM; /* default to PEM */ +} + +#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" +/* If GnuTLS was compiled without support for SRP it will error out if SRP is + requested in the priority string, so treat it specially + */ +#define GNUTLS_SRP "+SRP" + +static CURLcode +set_ssl_version_min_max(struct Curl_easy *data, + struct ssl_primary_config *conn_config, + const char **prioritylist, + const char *tls13support) +{ + long ssl_version = conn_config->version; + long ssl_version_max = conn_config->version_max; + + if((ssl_version == CURL_SSLVERSION_DEFAULT) || + (ssl_version == CURL_SSLVERSION_TLSv1)) + ssl_version = CURL_SSLVERSION_TLSv1_0; + if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) + ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT; + if(!tls13support) { + /* If the running GnuTLS doesn't support TLS 1.3, we must not specify a + prioritylist involving that since it will make GnuTLS return an en + error back at us */ + if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) || + (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) { + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + } + } + else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) { + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; + } + + switch(ssl_version | ssl_version_max) { + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:+VERS-TLS1.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2:+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_3: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_3: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_3: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.3:+VERS-TLS1.2"; + return CURLE_OK; + } + + failf(data, "GnuTLS: cannot set ssl protocol"); + return CURLE_SSL_CONNECT_ERROR; +} + +CURLcode gtls_client_init(struct Curl_easy *data, + struct ssl_primary_config *config, + struct ssl_config_data *ssl_config, + struct ssl_peer *peer, + struct gtls_instance *gtls, + long *pverifyresult) +{ + unsigned int init_flags; + int rc; + bool sni = TRUE; /* default is SNI enabled */ + const char *prioritylist; + const char *err = NULL; + const char *tls13support; + CURLcode result; + + if(!gtls_inited) + gtls_init(); + + *pverifyresult = 0; + + if(config->version == CURL_SSLVERSION_SSLv2) { + failf(data, "GnuTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + else if(config->version == CURL_SSLVERSION_SSLv3) + sni = FALSE; /* SSLv3 has no SNI */ + + /* allocate a cred struct */ + rc = gnutls_certificate_allocate_credentials(>ls->cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + +#ifdef USE_GNUTLS_SRP + if(config->username && Curl_auth_allowed_to_host(data)) { + infof(data, "Using TLS-SRP username: %s", config->username); + + rc = gnutls_srp_allocate_client_credentials(>ls->srp_client_cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_allocate_client_cred() failed: %s", + gnutls_strerror(rc)); + return CURLE_OUT_OF_MEMORY; + } + + rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred, + config->username, + config->password); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_set_client_cred() failed: %s", + gnutls_strerror(rc)); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } +#endif + + if(config->verifypeer) { + bool imported_native_ca = false; + + if(ssl_config->native_ca_store) { + rc = gnutls_certificate_set_x509_system_trust(gtls->cred); + if(rc < 0) + infof(data, "error reading native ca store (%s), continuing anyway", + gnutls_strerror(rc)); + else { + infof(data, "found %d certificates in native ca store", rc); + if(rc > 0) + imported_native_ca = true; + } + } + + if(config->CAfile) { + /* set the trusted CA cert bundle file */ + gnutls_certificate_set_verify_flags(gtls->cred, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); + + rc = gnutls_certificate_set_x509_trust_file(gtls->cred, + config->CAfile, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)%s", + config->CAfile, gnutls_strerror(rc), + (imported_native_ca ? ", continuing anyway" : "")); + if(!imported_native_ca) { + *pverifyresult = rc; + return CURLE_SSL_CACERT_BADFILE; + } + } + else + infof(data, "found %d certificates in %s", rc, config->CAfile); + } + + if(config->CApath) { + /* set the trusted CA cert directory */ + rc = gnutls_certificate_set_x509_trust_dir(gtls->cred, + config->CApath, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)%s", + config->CApath, gnutls_strerror(rc), + (imported_native_ca ? ", continuing anyway" : "")); + if(!imported_native_ca) { + *pverifyresult = rc; + return CURLE_SSL_CACERT_BADFILE; + } + } + else + infof(data, "found %d certificates in %s", rc, config->CApath); + } + } + + if(config->CRLfile) { + /* set the CRL list file */ + rc = gnutls_certificate_set_x509_crl_file(gtls->cred, + config->CRLfile, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + failf(data, "error reading crl file %s (%s)", + config->CRLfile, gnutls_strerror(rc)); + return CURLE_SSL_CRL_BADFILE; + } + else + infof(data, "found %d CRL in %s", rc, config->CRLfile); + } + + /* Initialize TLS session as a client */ + init_flags = GNUTLS_CLIENT; + +#if defined(GNUTLS_FORCE_CLIENT_CERT) + init_flags |= GNUTLS_FORCE_CLIENT_CERT; +#endif + +#if defined(GNUTLS_NO_TICKETS) + /* Disable TLS session tickets */ + init_flags |= GNUTLS_NO_TICKETS; +#endif + + rc = gnutls_init(>ls->session, init_flags); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_init() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + if(sni && peer->sni) { + if(gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS, + peer->sni, strlen(peer->sni)) < 0) { + failf(data, "Failed to set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* Use default priorities */ + rc = gnutls_set_default_priority(gtls->session); + if(rc != GNUTLS_E_SUCCESS) + return CURLE_SSL_CONNECT_ERROR; + + /* "In GnuTLS 3.6.5, TLS 1.3 is enabled by default" */ + tls13support = gnutls_check_version("3.6.5"); + + /* Ensure +SRP comes at the *end* of all relevant strings so that it can be + * removed if a run-time error indicates that SRP is not supported by this + * GnuTLS version */ + + if(config->version == CURL_SSLVERSION_SSLv2 || + config->version == CURL_SSLVERSION_SSLv3) { + failf(data, "GnuTLS does not support SSLv2 or SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(config->version == CURL_SSLVERSION_TLSv1_3) { + if(!tls13support) { + failf(data, "This GnuTLS installation does not support TLS 1.3"); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* At this point we know we have a supported TLS version, so set it */ + result = set_ssl_version_min_max(data, config, &prioritylist, tls13support); + if(result) + return result; + +#ifdef USE_GNUTLS_SRP + /* Only add SRP to the cipher list if SRP is requested. Otherwise + * GnuTLS will disable TLS 1.3 support. */ + if(config->username) { + char *prioritysrp = aprintf("%s:" GNUTLS_SRP, prioritylist); + if(!prioritysrp) + return CURLE_OUT_OF_MEMORY; + rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err); + free(prioritysrp); + + if((rc == GNUTLS_E_INVALID_REQUEST) && err) { + infof(data, "This GnuTLS does not support SRP"); + } + } + else { +#endif + infof(data, "GnuTLS ciphers: %s", prioritylist); + rc = gnutls_priority_set_direct(gtls->session, prioritylist, &err); +#ifdef USE_GNUTLS_SRP + } +#endif + + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "Error %d setting GnuTLS cipher list starting with %s", + rc, err); + return CURLE_SSL_CONNECT_ERROR; + } + + if(config->clientcert) { + if(ssl_config->key_passwd) { + const unsigned int supported_key_encryption_algorithms = + GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | + GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | + GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | + GNUTLS_PKCS_USE_PBES2_AES_256; + rc = gnutls_certificate_set_x509_key_file2( + gtls->cred, + config->clientcert, + ssl_config->key ? ssl_config->key : config->clientcert, + do_file_type(ssl_config->cert_type), + ssl_config->key_passwd, + supported_key_encryption_algorithms); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, + "error reading X.509 potentially-encrypted key file: %s", + gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { + if(gnutls_certificate_set_x509_key_file( + gtls->cred, + config->clientcert, + ssl_config->key ? ssl_config->key : config->clientcert, + do_file_type(ssl_config->cert_type) ) != + GNUTLS_E_SUCCESS) { + failf(data, "error reading X.509 key or certificate file"); + return CURLE_SSL_CONNECT_ERROR; + } + } + } + +#ifdef USE_GNUTLS_SRP + /* put the credentials to the current session */ + if(config->username) { + rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_SRP, + gtls->srp_client_cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + } + else +#endif + { + rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE, + gtls->cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + } + + if(config->verifystatus) { + rc = gnutls_ocsp_status_request_enable_client(gtls->session, + NULL, 0, NULL); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + } + + return CURLE_OK; +} + +static CURLcode +gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + long * const pverifyresult = &ssl_config->certverifyresult; + CURLcode result; + + DEBUGASSERT(backend); + + if(connssl->state == ssl_connection_complete) + /* to make us tolerant against being called more than once for the + same connection */ + return CURLE_OK; + + result = gtls_client_init(data, conn_config, ssl_config, + &connssl->peer, + &backend->gtls, pverifyresult); + if(result) + return result; + + if(connssl->alpn) { + struct alpn_proto_buf proto; + gnutls_datum_t alpn[ALPN_ENTRIES_MAX]; + size_t i; + + for(i = 0; i < connssl->alpn->count; ++i) { + alpn[i].data = (unsigned char *)connssl->alpn->entries[i]; + alpn[i].size = (unsigned)strlen(connssl->alpn->entries[i]); + } + if(gnutls_alpn_set_protocols(backend->gtls.session, alpn, + (unsigned)connssl->alpn->count, 0)) { + failf(data, "failed setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } + + /* This might be a reconnect, so we check for a session ID in the cache + to speed up things */ + if(conn_config->sessionid) { + void *ssl_sessionid; + size_t ssl_idsize; + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) { + /* we got a session id, use it! */ + gnutls_session_set_data(backend->gtls.session, + ssl_sessionid, ssl_idsize); + + /* Informational message */ + infof(data, "SSL reusing session ID"); + } + Curl_ssl_sessionid_unlock(data); + } + + /* register callback functions and handle to send and receive data. */ + gnutls_transport_set_ptr(backend->gtls.session, cf); + gnutls_transport_set_push_function(backend->gtls.session, gtls_push); + gnutls_transport_set_pull_function(backend->gtls.session, gtls_pull); + + return CURLE_OK; +} + +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, + gnutls_x509_crt_t cert, + const char *pinnedpubkey) +{ + /* Scratch */ + size_t len1 = 0, len2 = 0; + unsigned char *buff1 = NULL; + + gnutls_pubkey_t key = NULL; + + /* Result is returned to caller */ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + + if(!cert) + return result; + + do { + int ret; + + /* Begin Gyrations to get the public key */ + gnutls_pubkey_init(&key); + + ret = gnutls_pubkey_import_x509(key, cert, 0); + if(ret < 0) + break; /* failed */ + + ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1); + if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0) + break; /* failed */ + + buff1 = malloc(len1); + if(!buff1) + break; /* failed */ + + len2 = len1; + + ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2); + if(ret < 0 || len1 != len2) + break; /* failed */ + + /* End Gyrations */ + + /* The one good exit point */ + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); + } while(0); + + if(key) + gnutls_pubkey_deinit(key); + + Curl_safefree(buff1); + + return result; +} + +CURLcode +Curl_gtls_verifyserver(struct Curl_easy *data, + gnutls_session_t session, + struct ssl_primary_config *config, + struct ssl_config_data *ssl_config, + struct ssl_peer *peer, + const char *pinned_key) +{ + unsigned int cert_list_size; + const gnutls_datum_t *chainp; + unsigned int verify_status = 0; + gnutls_x509_crt_t x509_cert, x509_issuer; + gnutls_datum_t issuerp; + gnutls_datum_t certfields; + char certname[65] = ""; /* limited to 64 chars by ASN.1 */ + size_t size; + time_t certclock; + int rc; + CURLcode result = CURLE_OK; +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const char *ptr; + unsigned int algo; + unsigned int bits; + gnutls_protocol_t version = gnutls_protocol_get_version(session); +#endif + long * const certverifyresult = &ssl_config->certverifyresult; + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ + ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), + gnutls_cipher_get(session), + gnutls_mac_get(session)); + + infof(data, "SSL connection using %s / %s", + gnutls_protocol_get_name(version), ptr); +#endif + + /* This function will return the peer's raw certificate (chain) as sent by + the peer. These certificates are in raw format (DER encoded for + X.509). In case of a X.509 then a certificate list may be present. The + first certificate in the list is the peer's certificate, following the + issuer's certificate, then the issuer's issuer etc. */ + + chainp = gnutls_certificate_get_peers(session, &cert_list_size); + if(!chainp) { + if(config->verifypeer || + config->verifyhost || + config->issuercert) { +#ifdef USE_GNUTLS_SRP + if(ssl_config->primary.username && !config->verifypeer && + gnutls_cipher_get(session)) { + /* no peer cert, but auth is ok if we have SRP user and cipher and no + peer verify */ + } + else { +#endif + failf(data, "failed to get server cert"); + *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND; + return CURLE_PEER_FAILED_VERIFICATION; +#ifdef USE_GNUTLS_SRP + } +#endif + } + infof(data, " common name: WARNING couldn't obtain"); + } + + if(data->set.ssl.certinfo && chainp) { + unsigned int i; + + result = Curl_ssl_init_certinfo(data, cert_list_size); + if(result) + return result; + + for(i = 0; i < cert_list_size; i++) { + const char *beg = (const char *) chainp[i].data; + const char *end = beg + chainp[i].size; + + result = Curl_extract_certinfo(data, i, beg, end); + if(result) + return result; + } + } + + if(config->verifypeer) { + /* This function will try to verify the peer's certificate and return its + status (trusted, invalid etc.). The value of status should be one or + more of the gnutls_certificate_status_t enumerated elements bitwise + or'd. To avoid denial of service attacks some default upper limits + regarding the certificate key size and chain size are set. To override + them use gnutls_certificate_set_verify_limits(). */ + + rc = gnutls_certificate_verify_peers2(session, &verify_status); + if(rc < 0) { + failf(data, "server cert verify failed: %d", rc); + *certverifyresult = rc; + return CURLE_SSL_CONNECT_ERROR; + } + + *certverifyresult = verify_status; + + /* verify_status is a bitmask of gnutls_certificate_status bits */ + if(verify_status & GNUTLS_CERT_INVALID) { + if(config->verifypeer) { + failf(data, "server certificate verification failed. CAfile: %s " + "CRLfile: %s", config->CAfile ? config->CAfile: + "none", + ssl_config->primary.CRLfile ? + ssl_config->primary.CRLfile : "none"); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, " server certificate verification FAILED"); + } + else + infof(data, " server certificate verification OK"); + } + else + infof(data, " server certificate verification SKIPPED"); + + if(config->verifystatus) { + if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { + gnutls_datum_t status_request; + gnutls_ocsp_resp_t ocsp_resp; + + gnutls_ocsp_cert_status_t status; + gnutls_x509_crl_reason_t reason; + + rc = gnutls_ocsp_status_request_get(session, &status_request); + + infof(data, " server certificate status verification FAILED"); + + if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + failf(data, "No OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + gnutls_ocsp_resp_init(&ocsp_resp); + + rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, + &status, NULL, NULL, NULL, &reason); + + switch(status) { + case GNUTLS_OCSP_CERT_GOOD: + break; + + case GNUTLS_OCSP_CERT_REVOKED: { + const char *crl_reason; + + switch(reason) { + default: + case GNUTLS_X509_CRLREASON_UNSPECIFIED: + crl_reason = "unspecified reason"; + break; + + case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: + crl_reason = "private key compromised"; + break; + + case GNUTLS_X509_CRLREASON_CACOMPROMISE: + crl_reason = "CA compromised"; + break; + + case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: + crl_reason = "affiliation has changed"; + break; + + case GNUTLS_X509_CRLREASON_SUPERSEDED: + crl_reason = "certificate superseded"; + break; + + case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: + crl_reason = "operation has ceased"; + break; + + case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: + crl_reason = "certificate is on hold"; + break; + + case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: + crl_reason = "will be removed from delta CRL"; + break; + + case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: + crl_reason = "privilege withdrawn"; + break; + + case GNUTLS_X509_CRLREASON_AACOMPROMISE: + crl_reason = "AA compromised"; + break; + } + + failf(data, "Server certificate was revoked: %s", crl_reason); + break; + } + + default: + case GNUTLS_OCSP_CERT_UNKNOWN: + failf(data, "Server certificate status is unknown"); + break; + } + + gnutls_ocsp_resp_deinit(ocsp_resp); + + return CURLE_SSL_INVALIDCERTSTATUS; + } + else + infof(data, " server certificate status verification OK"); + } + else + infof(data, " server certificate status verification SKIPPED"); + + /* initialize an X.509 certificate structure. */ + gnutls_x509_crt_init(&x509_cert); + + if(chainp) + /* convert the given DER or PEM encoded Certificate to the native + gnutls_x509_crt_t format */ + gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + + if(config->issuercert) { + gnutls_x509_crt_init(&x509_issuer); + issuerp = load_file(config->issuercert); + gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); + rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); + gnutls_x509_crt_deinit(x509_issuer); + unload_file(issuerp); + if(rc <= 0) { + failf(data, "server certificate issuer check failed (IssuerCert: %s)", + config->issuercert?config->issuercert:"none"); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_ISSUER_ERROR; + } + infof(data, " server certificate issuer check OK (Issuer Cert: %s)", + config->issuercert?config->issuercert:"none"); + } + + size = sizeof(certname); + rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, + 0, /* the first and only one */ + FALSE, + certname, + &size); + if(rc) { + infof(data, "error fetching CN from cert:%s", + gnutls_strerror(rc)); + } + + /* This function will check if the given certificate's subject matches the + given hostname. This is a basic implementation of the matching described + in RFC2818 (HTTPS), which takes into account wildcards, and the subject + alternative name PKIX extension. Returns non zero on success, and zero on + failure. */ + rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname); +#if GNUTLS_VERSION_NUMBER < 0x030306 + /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP + addresses. */ + if(!rc) { +#ifdef ENABLE_IPV6 + #define use_addr in6_addr +#else + #define use_addr in_addr +#endif + unsigned char addrbuf[sizeof(struct use_addr)]; + size_t addrlen = 0; + + if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0) + addrlen = 4; +#ifdef ENABLE_IPV6 + else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0) + addrlen = 16; +#endif + + if(addrlen) { + unsigned char certaddr[sizeof(struct use_addr)]; + int i; + + for(i = 0; ; i++) { + size_t certaddrlen = sizeof(certaddr); + int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr, + &certaddrlen, NULL); + /* If this happens, it wasn't an IP address. */ + if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) + continue; + if(ret < 0) + break; + if(ret != GNUTLS_SAN_IPADDRESS) + continue; + if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) { + rc = 1; + break; + } + } + } + } +#endif + if(!rc) { + if(config->verifyhost) { + failf(data, "SSL: certificate subject name (%s) does not match " + "target host name '%s'", certname, peer->dispname); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, " common name: %s (does not match '%s')", + certname, peer->dispname); + } + else + infof(data, " common name: %s (matched)", certname); + + /* Check for time-based validity */ + certclock = gnutls_x509_crt_get_expiration_time(x509_cert); + + if(certclock == (time_t)-1) { + if(config->verifypeer) { + failf(data, "server cert expiration date verify failed"); + *certverifyresult = GNUTLS_CERT_EXPIRED; + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_CONNECT_ERROR; + } + else + infof(data, " server certificate expiration date verify FAILED"); + } + else { + if(certclock < time(NULL)) { + if(config->verifypeer) { + failf(data, "server certificate expiration date has passed."); + *certverifyresult = GNUTLS_CERT_EXPIRED; + gnutls_x509_crt_deinit(x509_cert); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, " server certificate expiration date FAILED"); + } + else + infof(data, " server certificate expiration date OK"); + } + + certclock = gnutls_x509_crt_get_activation_time(x509_cert); + + if(certclock == (time_t)-1) { + if(config->verifypeer) { + failf(data, "server cert activation date verify failed"); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_CONNECT_ERROR; + } + else + infof(data, " server certificate activation date verify FAILED"); + } + else { + if(certclock > time(NULL)) { + if(config->verifypeer) { + failf(data, "server certificate not activated yet."); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; + gnutls_x509_crt_deinit(x509_cert); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, " server certificate activation date FAILED"); + } + else + infof(data, " server certificate activation date OK"); + } + + if(pinned_key) { + result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key); + if(result != CURLE_OK) { + failf(data, "SSL: public key does not match pinned public key"); + gnutls_x509_crt_deinit(x509_cert); + return result; + } + } + + /* Show: + + - subject + - start date + - expire date + - common name + - issuer + + */ + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + /* public key algorithm's parameters */ + algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); + infof(data, " certificate public key: %s", + gnutls_pk_algorithm_get_name(algo)); + + /* version of the X.509 certificate. */ + infof(data, " certificate version: #%d", + gnutls_x509_crt_get_version(x509_cert)); + + + rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); + if(rc) + infof(data, "Failed to get certificate name"); + else { + infof(data, " subject: %s", certfields.data); + + certclock = gnutls_x509_crt_get_activation_time(x509_cert); + showtime(data, "start date", certclock); + + certclock = gnutls_x509_crt_get_expiration_time(x509_cert); + showtime(data, "expire date", certclock); + + gnutls_free(certfields.data); + } + + rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); + if(rc) + infof(data, "Failed to get certificate issuer"); + else { + infof(data, " issuer: %s", certfields.data); + + gnutls_free(certfields.data); + } +#endif + + gnutls_x509_crt_deinit(x509_cert); + + return result; +} + +static CURLcode gtls_verifyserver(struct Curl_cfilter *cf, + struct Curl_easy *data, + gnutls_session_t session) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + const char *pinned_key = Curl_ssl_cf_is_proxy(cf)? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + CURLcode result; + + result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config, + &connssl->peer, pinned_key); + if(result) + goto out; + + if(connssl->alpn) { + gnutls_datum_t proto; + int rc; + + rc = gnutls_alpn_get_selected_protocol(session, &proto); + if(rc == 0) + Curl_alpn_set_negotiated(cf, data, proto.data, proto.size); + else + Curl_alpn_set_negotiated(cf, data, NULL, 0); + } + + if(ssl_config->primary.sessionid) { + /* we always unconditionally get the session id here, as even if we + already got it from the cache and asked to use it in the connection, it + might've been rejected and then a new one is in use now and we need to + detect that. */ + void *connect_sessionid; + size_t connect_idsize = 0; + + /* get the session ID data size */ + gnutls_session_get_data(session, NULL, &connect_idsize); + connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ + + if(connect_sessionid) { + bool incache; + bool added = FALSE; + void *ssl_sessionid; + + /* extract session ID to the allocated buffer */ + gnutls_session_get_data(session, connect_sessionid, &connect_idsize); + + Curl_ssl_sessionid_lock(data); + incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)); + if(incache) { + /* there was one before in the cache, so instead of risking that the + previous one was rejected, we just kill that and store the new */ + Curl_ssl_delsessionid(data, ssl_sessionid); + } + + /* store this session id */ + result = Curl_ssl_addsessionid(cf, data, connect_sessionid, + connect_idsize, &added); + Curl_ssl_sessionid_unlock(data); + if(!added) + free(connect_sessionid); + if(result) { + result = CURLE_OUT_OF_MEMORY; + } + } + else + result = CURLE_OUT_OF_MEMORY; + } + +out: + return result; +} + +/* + * This function is called after the TCP connect has completed. Setup the TLS + * layer and do all necessary magic. + */ +/* We use connssl->connecting_state to keep track of the connection status; + there are three states: 'ssl_connect_1' (not started yet or complete), + 'ssl_connect_2_reading' (waiting for data from server), and + 'ssl_connect_2_writing' (waiting to be able to write). + */ +static CURLcode +gtls_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool nonblocking, + bool *done) +{ + struct ssl_connect_data *connssl = cf->ctx; + int rc; + CURLcode result = CURLE_OK; + + /* Initiate the connection, if not already done */ + if(ssl_connect_1 == connssl->connecting_state) { + rc = gtls_connect_step1(cf, data); + if(rc) { + result = rc; + goto out; + } + } + + rc = handshake(cf, data, TRUE, nonblocking); + if(rc) { + /* handshake() sets its own error message with failf() */ + result = rc; + goto out; + } + + /* Finish connecting once the handshake is done */ + if(ssl_connect_1 == connssl->connecting_state) { + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + gnutls_session_t session; + DEBUGASSERT(backend); + session = backend->gtls.session; + rc = gtls_verifyserver(cf, data, session); + if(rc) { + result = rc; + goto out; + } + connssl->state = ssl_connection_complete; + } + +out: + *done = ssl_connect_1 == connssl->connecting_state; + + return result; +} + +static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + return gtls_connect_common(cf, data, TRUE, done); +} + +static CURLcode gtls_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result; + bool done = FALSE; + + result = gtls_connect_common(cf, data, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +static bool gtls_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct ssl_connect_data *ctx = cf->ctx; + struct gtls_ssl_backend_data *backend; + + (void)data; + DEBUGASSERT(ctx && ctx->backend); + backend = (struct gtls_ssl_backend_data *)ctx->backend; + if(backend->gtls.session && + 0 != gnutls_record_check_pending(backend->gtls.session)) + return TRUE; + return FALSE; +} + +static ssize_t gtls_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + ssize_t rc; + + (void)data; + DEBUGASSERT(backend); + rc = gnutls_record_send(backend->gtls.session, mem, len); + + if(rc < 0) { + *curlcode = (rc == GNUTLS_E_AGAIN) + ? CURLE_AGAIN + : CURLE_SEND_ERROR; + + rc = -1; + } + + return rc; +} + +static void gtls_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + + (void) data; + DEBUGASSERT(backend); + + if(backend->gtls.session) { + char buf[32]; + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf)); + gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR); + gnutls_deinit(backend->gtls.session); + backend->gtls.session = NULL; + } + if(backend->gtls.cred) { + gnutls_certificate_free_credentials(backend->gtls.cred); + backend->gtls.cred = NULL; + } +#ifdef USE_GNUTLS_SRP + if(backend->gtls.srp_client_cred) { + gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred); + backend->gtls.srp_client_cred = NULL; + } +#endif +} + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +static int gtls_shutdown(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + int retval = 0; + + DEBUGASSERT(backend); + +#ifndef CURL_DISABLE_FTP + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + response. Thus we wait for a close notify alert from the server, but + we do not send one. Let's hope other servers do the same... */ + + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR); +#endif + + if(backend->gtls.session) { + ssize_t result; + bool done = FALSE; + char buf[120]; + + while(!done) { + int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), + SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + result = gnutls_record_recv(backend->gtls.session, + buf, sizeof(buf)); + switch(result) { + case 0: + /* This is the expected response. There was no data but only + the close notify alert */ + done = TRUE; + break; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED"); + break; + default: + retval = -1; + done = TRUE; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = TRUE; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + retval = -1; + done = TRUE; + } + } + gnutls_deinit(backend->gtls.session); + } + gnutls_certificate_free_credentials(backend->gtls.cred); + +#ifdef USE_GNUTLS_SRP + { + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + if(ssl_config->primary.username) + gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred); + } +#endif + + backend->gtls.cred = NULL; + backend->gtls.session = NULL; + + return retval; +} + +static ssize_t gtls_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, + size_t buffersize, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + ssize_t ret; + + (void)data; + DEBUGASSERT(backend); + + ret = gnutls_record_recv(backend->gtls.session, buf, buffersize); + if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { + *curlcode = CURLE_AGAIN; + ret = -1; + goto out; + } + + if(ret == GNUTLS_E_REHANDSHAKE) { + /* BLOCKING call, this is bad but a work-around for now. Fixing this "the + proper way" takes a whole lot of work. */ + CURLcode result = handshake(cf, data, FALSE, FALSE); + if(result) + /* handshake() writes error message on its own */ + *curlcode = result; + else + *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ + ret = -1; + goto out; + } + + if(ret < 0) { + failf(data, "GnuTLS recv error (%d): %s", + + (int)ret, gnutls_strerror((int)ret)); + *curlcode = CURLE_RECV_ERROR; + ret = -1; + goto out; + } + +out: + return ret; +} + +static void gtls_session_free(void *ptr) +{ + free(ptr); +} + +static size_t gtls_version(char *buffer, size_t size) +{ + return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); +} + +/* data might be NULL! */ +static CURLcode gtls_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) +{ + int rc; + (void)data; + rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); + return rc?CURLE_FAILED_INIT:CURLE_OK; +} + +static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len) +{ + struct sha256_ctx SHA256pw; + sha256_init(&SHA256pw); + sha256_update(&SHA256pw, (unsigned int)tmplen, tmp); + sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum); + return CURLE_OK; +} + +static bool gtls_cert_status_request(void) +{ + return TRUE; +} + +static void *gtls_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + (void)info; + DEBUGASSERT(backend); + return backend->gtls.session; +} + +const struct Curl_ssl Curl_ssl_gnutls = { + { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */ + + SSLSUPP_CA_PATH | + SSLSUPP_CERTINFO | + SSLSUPP_PINNEDPUBKEY | + SSLSUPP_HTTPS_PROXY, + + sizeof(struct gtls_ssl_backend_data), + + gtls_init, /* init */ + gtls_cleanup, /* cleanup */ + gtls_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + gtls_shutdown, /* shutdown */ + gtls_data_pending, /* data_pending */ + gtls_random, /* random */ + gtls_cert_status_request, /* cert_status_request */ + gtls_connect, /* connect */ + gtls_connect_nonblocking, /* connect_nonblocking */ + Curl_ssl_adjust_pollset, /* adjust_pollset */ + gtls_get_internals, /* get_internals */ + gtls_close, /* close_one */ + Curl_none_close_all, /* close_all */ + gtls_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + gtls_sha256sum, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + gtls_recv, /* recv decrypted data */ + gtls_send, /* send data to encrypt */ +}; + +#endif /* USE_GNUTLS */ diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h new file mode 100644 index 0000000..1a81c01 --- /dev/null +++ b/lib/vtls/gtls.h @@ -0,0 +1,75 @@ +#ifndef HEADER_CURL_GTLS_H +#define HEADER_CURL_GTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include + +#ifdef USE_GNUTLS + +#include + +#ifdef HAVE_GNUTLS_SRP +/* the function exists */ +#ifdef USE_TLS_SRP +/* the functionality is not disabled */ +#define USE_GNUTLS_SRP +#endif +#endif + +struct Curl_easy; +struct Curl_cfilter; +struct ssl_primary_config; +struct ssl_config_data; +struct ssl_peer; + +struct gtls_instance { + gnutls_session_t session; + gnutls_certificate_credentials_t cred; +#ifdef USE_GNUTLS_SRP + gnutls_srp_client_credentials_t srp_client_cred; +#endif +}; + +CURLcode +gtls_client_init(struct Curl_easy *data, + struct ssl_primary_config *config, + struct ssl_config_data *ssl_config, + struct ssl_peer *peer, + struct gtls_instance *gtls, + long *pverifyresult); + +CURLcode +Curl_gtls_verifyserver(struct Curl_easy *data, + gnutls_session_t session, + struct ssl_primary_config *config, + struct ssl_config_data *ssl_config, + struct ssl_peer *peer, + const char *pinned_key); + +extern const struct Curl_ssl Curl_ssl_gnutls; + +#endif /* USE_GNUTLS */ +#endif /* HEADER_CURL_GTLS_H */ diff --git a/lib/vtls/hostcheck.c b/lib/vtls/hostcheck.c new file mode 100644 index 0000000..2726dca --- /dev/null +++ b/lib/vtls/hostcheck.c @@ -0,0 +1,135 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_OPENSSL) \ + || defined(USE_SCHANNEL) +/* these backends use functions from this file */ + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#include "curl_memrchr.h" + +#include "hostcheck.h" +#include "strcase.h" +#include "hostip.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* check the two input strings with given length, but do not + assume they end in nul-bytes */ +static bool pmatch(const char *hostname, size_t hostlen, + const char *pattern, size_t patternlen) +{ + if(hostlen != patternlen) + return FALSE; + return strncasecompare(hostname, pattern, hostlen); +} + +/* + * Match a hostname against a wildcard pattern. + * E.g. + * "foo.host.com" matches "*.host.com". + * + * We use the matching rule described in RFC6125, section 6.4.3. + * https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.3 + * + * In addition: ignore trailing dots in the host names and wildcards, so that + * the names are used normalized. This is what the browsers do. + * + * Do not allow wildcard matching on IP numbers. There are apparently + * certificates being used with an IP address in the CN field, thus making no + * apparent distinction between a name and an IP. We need to detect the use of + * an IP address and not wildcard match on such names. + * + * Only match on "*" being used for the leftmost label, not "a*", "a*b" nor + * "*b". + * + * Return TRUE on a match. FALSE if not. + * + * @unittest: 1397 + */ + +static bool hostmatch(const char *hostname, + size_t hostlen, + const char *pattern, + size_t patternlen) +{ + const char *pattern_label_end; + + DEBUGASSERT(pattern); + DEBUGASSERT(patternlen); + DEBUGASSERT(hostname); + DEBUGASSERT(hostlen); + + /* normalize pattern and hostname by stripping off trailing dots */ + if(hostname[hostlen-1]=='.') + hostlen--; + if(pattern[patternlen-1]=='.') + patternlen--; + + if(strncmp(pattern, "*.", 2)) + return pmatch(hostname, hostlen, pattern, patternlen); + + /* detect IP address as hostname and fail the match if so */ + else if(Curl_host_is_ipnum(hostname)) + return FALSE; + + /* We require at least 2 dots in the pattern to avoid too wide wildcard + match. */ + pattern_label_end = memchr(pattern, '.', patternlen); + if(!pattern_label_end || + (memrchr(pattern, '.', patternlen) == pattern_label_end)) + return pmatch(hostname, hostlen, pattern, patternlen); + else { + const char *hostname_label_end = memchr(hostname, '.', hostlen); + if(hostname_label_end) { + size_t skiphost = hostname_label_end - hostname; + size_t skiplen = pattern_label_end - pattern; + return pmatch(hostname_label_end, hostlen - skiphost, + pattern_label_end, patternlen - skiplen); + } + } + return FALSE; +} + +/* + * Curl_cert_hostcheck() returns TRUE if a match and FALSE if not. + */ +bool Curl_cert_hostcheck(const char *match, size_t matchlen, + const char *hostname, size_t hostlen) +{ + if(match && *match && hostname && *hostname) + return hostmatch(hostname, hostlen, match, matchlen); + return FALSE; +} + +#endif /* OPENSSL or SCHANNEL */ diff --git a/lib/vtls/hostcheck.h b/lib/vtls/hostcheck.h new file mode 100644 index 0000000..22a1ac2 --- /dev/null +++ b/lib/vtls/hostcheck.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_HOSTCHECK_H +#define HEADER_CURL_HOSTCHECK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include + +/* returns TRUE if there's a match */ +bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen, + const char *hostname, size_t hostlen); + +#endif /* HEADER_CURL_HOSTCHECK_H */ diff --git a/lib/vtls/keylog.c b/lib/vtls/keylog.c new file mode 100644 index 0000000..fbcb25c --- /dev/null +++ b/lib/vtls/keylog.c @@ -0,0 +1,166 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(USE_OPENSSL) || \ + defined(USE_WOLFSSL) || \ + (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \ + defined(USE_QUICHE) + +#include "keylog.h" +#include + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1) + +#define CLIENT_RANDOM_SIZE 32 + +/* + * The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the + * secret size depends on the cipher suite's hash function which is 32 bytes + * for SHA-256 and 48 bytes for SHA-384. + */ +#define SECRET_MAXLEN 48 + + +/* The fp for the open SSLKEYLOGFILE, or NULL if not open */ +static FILE *keylog_file_fp; + +void +Curl_tls_keylog_open(void) +{ + char *keylog_file_name; + + if(!keylog_file_fp) { + keylog_file_name = curl_getenv("SSLKEYLOGFILE"); + if(keylog_file_name) { + keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); + if(keylog_file_fp) { +#ifdef _WIN32 + if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) +#else + if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) +#endif + { + fclose(keylog_file_fp); + keylog_file_fp = NULL; + } + } + Curl_safefree(keylog_file_name); + } + } +} + +void +Curl_tls_keylog_close(void) +{ + if(keylog_file_fp) { + fclose(keylog_file_fp); + keylog_file_fp = NULL; + } +} + +bool +Curl_tls_keylog_enabled(void) +{ + return keylog_file_fp != NULL; +} + +bool +Curl_tls_keylog_write_line(const char *line) +{ + /* The current maximum valid keylog line length LF and NUL is 195. */ + size_t linelen; + char buf[256]; + + if(!keylog_file_fp || !line) { + return false; + } + + linelen = strlen(line); + if(linelen == 0 || linelen > sizeof(buf) - 2) { + /* Empty line or too big to fit in a LF and NUL. */ + return false; + } + + memcpy(buf, line, linelen); + if(line[linelen - 1] != '\n') { + buf[linelen++] = '\n'; + } + buf[linelen] = '\0'; + + /* Using fputs here instead of fprintf since libcurl's fprintf replacement + may not be thread-safe. */ + fputs(buf, keylog_file_fp); + return true; +} + +bool +Curl_tls_keylog_write(const char *label, + const unsigned char client_random[CLIENT_RANDOM_SIZE], + const unsigned char *secret, size_t secretlen) +{ + const char *hex = "0123456789ABCDEF"; + size_t pos, i; + char line[KEYLOG_LABEL_MAXLEN + 1 + 2 * CLIENT_RANDOM_SIZE + 1 + + 2 * SECRET_MAXLEN + 1 + 1]; + + if(!keylog_file_fp) { + return false; + } + + pos = strlen(label); + if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) { + /* Should never happen - sanity check anyway. */ + return false; + } + + memcpy(line, label, pos); + line[pos++] = ' '; + + /* Client Random */ + for(i = 0; i < CLIENT_RANDOM_SIZE; i++) { + line[pos++] = hex[client_random[i] >> 4]; + line[pos++] = hex[client_random[i] & 0xF]; + } + line[pos++] = ' '; + + /* Secret */ + for(i = 0; i < secretlen; i++) { + line[pos++] = hex[secret[i] >> 4]; + line[pos++] = hex[secret[i] & 0xF]; + } + line[pos++] = '\n'; + line[pos] = '\0'; + + /* Using fputs here instead of fprintf since libcurl's fprintf replacement + may not be thread-safe. */ + fputs(line, keylog_file_fp); + return true; +} + +#endif /* TLS or QUIC backend */ diff --git a/lib/vtls/keylog.h b/lib/vtls/keylog.h new file mode 100644 index 0000000..eff5bf3 --- /dev/null +++ b/lib/vtls/keylog.h @@ -0,0 +1,58 @@ +#ifndef HEADER_CURL_KEYLOG_H +#define HEADER_CURL_KEYLOG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +/* + * Opens the TLS key log file if requested by the user. The SSLKEYLOGFILE + * environment variable specifies the output file. + */ +void Curl_tls_keylog_open(void); + +/* + * Closes the TLS key log file if not already. + */ +void Curl_tls_keylog_close(void); + +/* + * Returns true if the user successfully enabled the TLS key log file. + */ +bool Curl_tls_keylog_enabled(void); + +/* + * Appends a key log file entry. + * Returns true iff the key log file is open and a valid entry was provided. + */ +bool Curl_tls_keylog_write(const char *label, + const unsigned char client_random[32], + const unsigned char *secret, size_t secretlen); + +/* + * Appends a line to the key log file, ensure it is terminated by a LF. + * Returns true iff the key log file is open and a valid line was provided. + */ +bool Curl_tls_keylog_write_line(const char *line); + +#endif /* HEADER_CURL_KEYLOG_H */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c new file mode 100644 index 0000000..7d70de5 --- /dev/null +++ b/lib/vtls/mbedtls.c @@ -0,0 +1,1311 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + */ + +#include "curl_setup.h" + +#ifdef USE_MBEDTLS + +/* Define this to enable lots of debugging for mbedTLS */ +/* #define MBEDTLS_DEBUG */ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +/* mbedTLS (as of v3.5.1) has a duplicate function declaration + in its public headers. Disable the warning that detects it. */ +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +#include +#if MBEDTLS_VERSION_NUMBER >= 0x02040000 +#include +#else +#include +#endif +#include +#include + +#include +#include +#include +#include + +#if MBEDTLS_VERSION_MAJOR >= 2 +# ifdef MBEDTLS_DEBUG +# include +# endif +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "mbedtls.h" +#include "vtls.h" +#include "vtls_int.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "multiif.h" +#include "mbedtls_threadlock.h" +#include "strdup.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* ALPN for http2 */ +#ifdef USE_HTTP2 +# undef HAS_ALPN +# ifdef MBEDTLS_SSL_ALPN +# define HAS_ALPN +# endif +#endif + +struct mbed_ssl_backend_data { + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + mbedtls_ssl_context ssl; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; +#ifdef MBEDTLS_X509_CRL_PARSE_C + mbedtls_x509_crl crl; +#endif + mbedtls_pk_context pk; + mbedtls_ssl_config config; +#ifdef HAS_ALPN + const char *protocols[3]; +#endif +}; + +/* apply threading? */ +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) +#define THREADING_SUPPORT +#endif + +#ifndef MBEDTLS_ERROR_C +#define mbedtls_strerror(a,b,c) b[0] = 0 +#endif + +#if defined(THREADING_SUPPORT) +static mbedtls_entropy_context ts_entropy; + +static int entropy_init_initialized = 0; + +/* start of entropy_init_mutex() */ +static void entropy_init_mutex(mbedtls_entropy_context *ctx) +{ + /* lock 0 = entropy_init_mutex() */ + Curl_mbedtlsthreadlock_lock_function(0); + if(entropy_init_initialized == 0) { + mbedtls_entropy_init(ctx); + entropy_init_initialized = 1; + } + Curl_mbedtlsthreadlock_unlock_function(0); +} +/* end of entropy_init_mutex() */ + +/* start of entropy_func_mutex() */ +static int entropy_func_mutex(void *data, unsigned char *output, size_t len) +{ + int ret; + /* lock 1 = entropy_func_mutex() */ + Curl_mbedtlsthreadlock_lock_function(1); + ret = mbedtls_entropy_func(data, output, len); + Curl_mbedtlsthreadlock_unlock_function(1); + + return ret; +} +/* end of entropy_func_mutex() */ + +#endif /* THREADING_SUPPORT */ + +#ifdef MBEDTLS_DEBUG +static void mbed_debug(void *context, int level, const char *f_name, + int line_nb, const char *line) +{ + struct Curl_easy *data = NULL; + + if(!context) + return; + + data = (struct Curl_easy *)context; + + infof(data, "%s", line); + (void) level; +} +#endif + +static int mbedtls_bio_cf_write(void *bio, + const unsigned char *buf, size_t blen) +{ + struct Curl_cfilter *cf = bio; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result; + + DEBUGASSERT(data); + if(!data) + return 0; + + nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result); + CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d", + blen, nwritten, result); + if(nwritten < 0 && CURLE_AGAIN == result) { + nwritten = MBEDTLS_ERR_SSL_WANT_WRITE; + } + return (int)nwritten; +} + +static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) +{ + struct Curl_cfilter *cf = bio; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nread; + CURLcode result; + + DEBUGASSERT(data); + if(!data) + return 0; + /* OpenSSL catches this case, so should we. */ + if(!buf) + return 0; + + nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result); + CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %zd, err=%d", + blen, nread, result); + if(nread < 0 && CURLE_AGAIN == result) { + nread = MBEDTLS_ERR_SSL_WANT_READ; + } + return (int)nread; +} + +/* + * profile + */ +static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = +{ + /* Hashes from SHA-1 and above */ + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 1024, /* RSA min key len */ +}; + +/* See https://tls.mbed.org/discussions/generic/ + howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der +*/ +#define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE) +#define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES) + +#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) + +static CURLcode mbedtls_version_from_curl(int *mbedver, long version) +{ +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + switch(version) { + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + break; + } +#else + switch(version) { + case CURL_SSLVERSION_TLSv1_0: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_1; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_2; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + break; + } +#endif + + return CURLE_SSL_CONNECT_ERROR; +} + +static CURLcode +set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3; + int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3; +#else + int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; + int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; +#endif + long ssl_version = conn_config->version; + long ssl_version_max = conn_config->version_max; + CURLcode result = CURLE_OK; + + DEBUGASSERT(backend); + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ssl_version = CURL_SSLVERSION_TLSv1_0; + break; + } + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + + result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version); + if(result) { + failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); + return result; + } + result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16); + if(result) { + failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); + return result; + } + + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ver_min); + mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ver_max); + + return result; +} + +static CURLcode +mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : conn_config->CAfile); + const bool verifypeer = conn_config->verifypeer; + const char * const ssl_capath = conn_config->CApath; + char * const ssl_cert = ssl_config->primary.clientcert; + const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; + const char * const ssl_crlfile = ssl_config->primary.CRLfile; + const char *hostname = connssl->peer.hostname; + int ret = -1; + char errorbuf[128]; + + DEBUGASSERT(backend); + + if((conn_config->version == CURL_SSLVERSION_SSLv2) || + (conn_config->version == CURL_SSLVERSION_SSLv3)) { + failf(data, "Not supported SSL version"); + return CURLE_NOT_BUILT_IN; + } + +#ifdef THREADING_SUPPORT + entropy_init_mutex(&ts_entropy); + mbedtls_ctr_drbg_init(&backend->ctr_drbg); + + ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex, + &ts_entropy, NULL, 0); + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s", + -ret, errorbuf); + return CURLE_FAILED_INIT; + } +#else + mbedtls_entropy_init(&backend->entropy); + mbedtls_ctr_drbg_init(&backend->ctr_drbg); + + ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func, + &backend->entropy, NULL, 0); + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s", + -ret, errorbuf); + return CURLE_FAILED_INIT; + } +#endif /* THREADING_SUPPORT */ + + /* Load the trusted CA */ + mbedtls_x509_crt_init(&backend->cacert); + + if(ca_info_blob && verifypeer) { + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null + terminated even when provided the exact length, forcing us to waste + extra memory here. */ + unsigned char *newblob = Curl_memdup0(ca_info_blob->data, + ca_info_blob->len); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + ret = mbedtls_x509_crt_parse(&backend->cacert, newblob, + ca_info_blob->len + 1); + free(newblob); + if(ret<0) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CERTPROBLEM; + } + } + + if(ssl_cafile && verifypeer) { +#ifdef MBEDTLS_FS_IO + ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile); + + if(ret<0) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", + ssl_cafile, -ret, errorbuf); + return CURLE_SSL_CACERT_BADFILE; + } +#else + failf(data, "mbedtls: functions that use the filesystem not built in"); + return CURLE_NOT_BUILT_IN; +#endif + } + + if(ssl_capath) { +#ifdef MBEDTLS_FS_IO + ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath); + + if(ret<0) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s", + ssl_capath, -ret, errorbuf); + + if(verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } +#else + failf(data, "mbedtls: functions that use the filesystem not built in"); + return CURLE_NOT_BUILT_IN; +#endif + } + + /* Load the client certificate */ + mbedtls_x509_crt_init(&backend->clicert); + + if(ssl_cert) { +#ifdef MBEDTLS_FS_IO + ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert); + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s", + ssl_cert, -ret, errorbuf); + + return CURLE_SSL_CERTPROBLEM; + } +#else + failf(data, "mbedtls: functions that use the filesystem not built in"); + return CURLE_NOT_BUILT_IN; +#endif + } + + if(ssl_cert_blob) { + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null + terminated even when provided the exact length, forcing us to waste + extra memory here. */ + unsigned char *newblob = Curl_memdup0(ssl_cert_blob->data, + ssl_cert_blob->len); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + ret = mbedtls_x509_crt_parse(&backend->clicert, newblob, + ssl_cert_blob->len + 1); + free(newblob); + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", + ssl_config->key, -ret, errorbuf); + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load the client private key */ + mbedtls_pk_init(&backend->pk); + + if(ssl_config->key || ssl_config->key_blob) { + if(ssl_config->key) { +#ifdef MBEDTLS_FS_IO +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, + ssl_config->key_passwd, + mbedtls_ctr_drbg_random, + &backend->ctr_drbg); +#else + ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, + ssl_config->key_passwd); +#endif + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", + ssl_config->key, -ret, errorbuf); + return CURLE_SSL_CERTPROBLEM; + } +#else + failf(data, "mbedtls: functions that use the filesystem not built in"); + return CURLE_NOT_BUILT_IN; +#endif + } + else { + const struct curl_blob *ssl_key_blob = ssl_config->key_blob; + const unsigned char *key_data = + (const unsigned char *)ssl_key_blob->data; + const char *passwd = ssl_config->key_passwd; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, + (const unsigned char *)passwd, + passwd ? strlen(passwd) : 0, + mbedtls_ctr_drbg_random, + &backend->ctr_drbg); +#else + ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, + (const unsigned char *)passwd, + passwd ? strlen(passwd) : 0); +#endif + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CERTPROBLEM; + } + } + + if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || + mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) + ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; + } + + /* Load the CRL */ +#ifdef MBEDTLS_X509_CRL_PARSE_C + mbedtls_x509_crl_init(&backend->crl); + + if(ssl_crlfile) { +#ifdef MBEDTLS_FS_IO + ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile); + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s", + ssl_crlfile, -ret, errorbuf); + + return CURLE_SSL_CRL_BADFILE; + } +#else + failf(data, "mbedtls: functions that use the filesystem not built in"); + return CURLE_NOT_BUILT_IN; +#endif + } +#else + if(ssl_crlfile) { + failf(data, "mbedtls: crl support not built in"); + return CURLE_NOT_BUILT_IN; + } +#endif + + infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port); + + mbedtls_ssl_config_init(&backend->config); + ret = mbedtls_ssl_config_defaults(&backend->config, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if(ret) { + failf(data, "mbedTLS: ssl_config failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + mbedtls_ssl_init(&backend->ssl); + if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) { + failf(data, "mbedTLS: ssl_init failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* new profile with RSA min key len = 1024 ... */ + mbedtls_ssl_conf_cert_profile(&backend->config, + &mbedtls_x509_crt_profile_fr); + + switch(conn_config->version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +#if MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_1); + infof(data, "mbedTLS: Set min SSL version to TLS 1.0"); + break; +#endif + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + { + CURLcode result = set_ssl_version_min_max(cf, data); + if(result != CURLE_OK) + return result; + break; + } + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL); + + mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random, + &backend->ctr_drbg); + mbedtls_ssl_set_bio(&backend->ssl, cf, + mbedtls_bio_cf_write, + mbedtls_bio_cf_read, + NULL /* rev_timeout() */); + + mbedtls_ssl_conf_ciphersuites(&backend->config, + mbedtls_ssl_list_ciphersuites()); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + mbedtls_ssl_conf_renegotiation(&backend->config, + MBEDTLS_SSL_RENEGOTIATION_ENABLED); +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + mbedtls_ssl_conf_session_tickets(&backend->config, + MBEDTLS_SSL_SESSION_TICKETS_DISABLED); +#endif + + /* Check if there's a cached ID we can/should use here! */ + if(ssl_config->primary.sessionid) { + void *old_session = NULL; + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) { + ret = mbedtls_ssl_set_session(&backend->ssl, old_session); + if(ret) { + Curl_ssl_sessionid_unlock(data); + failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "mbedTLS reusing session"); + } + Curl_ssl_sessionid_unlock(data); + } + + mbedtls_ssl_conf_ca_chain(&backend->config, + &backend->cacert, +#ifdef MBEDTLS_X509_CRL_PARSE_C + &backend->crl); +#else + NULL); +#endif + + if(ssl_config->key || ssl_config->key_blob) { + mbedtls_ssl_conf_own_cert(&backend->config, + &backend->clicert, &backend->pk); + } + + if(connssl->peer.sni) { + if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni)) { + /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and + the name to set in the SNI extension. So even if curl connects to a + host specified as an IP address, this function must be used. */ + failf(data, "Failed to set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + } + +#ifdef HAS_ALPN + if(connssl->alpn) { + struct alpn_proto_buf proto; + size_t i; + + for(i = 0; i < connssl->alpn->count; ++i) { + backend->protocols[i] = connssl->alpn->entries[i]; + } + /* this function doesn't clone the protocols array, which is why we need + to keep it around */ + if(mbedtls_ssl_conf_alpn_protocols(&backend->config, + &backend->protocols[0])) { + failf(data, "Failed setting ALPN protocols"); + return CURLE_SSL_CONNECT_ERROR; + } + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } +#endif + +#ifdef MBEDTLS_DEBUG + /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ + mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data); + /* - 0 No debug + * - 1 Error + * - 2 State change + * - 3 Informational + * - 4 Verbose + */ + mbedtls_debug_set_threshold(4); +#endif + + /* give application a chance to interfere with mbedTLS set up. */ + if(data->set.ssl.fsslctx) { + ret = (*data->set.ssl.fsslctx)(data, &backend->config, + data->set.ssl.fsslctxp); + if(ret) { + failf(data, "error signaled by ssl ctx callback"); + return ret; + } + } + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static CURLcode +mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + int ret; + struct ssl_connect_data *connssl = cf->ctx; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + const mbedtls_x509_crt *peercert; + const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + + DEBUGASSERT(backend); + + ret = mbedtls_ssl_handshake(&backend->ssl); + + if(ret == MBEDTLS_ERR_SSL_WANT_READ) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + } + else if(ret) { + char errorbuf[128]; + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CONNECT_ERROR; + } + + infof(data, "mbedTLS: Handshake complete, cipher is %s", + mbedtls_ssl_get_ciphersuite(&backend->ssl)); + + ret = mbedtls_ssl_get_verify_result(&backend->ssl); + + if(!conn_config->verifyhost) + /* Ignore hostname errors if verifyhost is disabled */ + ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; + + if(ret && conn_config->verifypeer) { + if(ret & MBEDTLS_X509_BADCERT_EXPIRED) + failf(data, "Cert verify failed: BADCERT_EXPIRED"); + + else if(ret & MBEDTLS_X509_BADCERT_REVOKED) + failf(data, "Cert verify failed: BADCERT_REVOKED"); + + else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) + failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); + + else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) + failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); + + else if(ret & MBEDTLS_X509_BADCERT_FUTURE) + failf(data, "Cert verify failed: BADCERT_FUTURE"); + + return CURLE_PEER_FAILED_VERIFICATION; + } + + peercert = mbedtls_ssl_get_peer_cert(&backend->ssl); + + if(peercert && data->set.verbose) { + const size_t bufsize = 16384; + char *buffer = malloc(bufsize); + + if(!buffer) + return CURLE_OUT_OF_MEMORY; + + if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) + infof(data, "Dumping cert info: %s", buffer); + else + infof(data, "Unable to dump certificate information"); + + free(buffer); + } + + if(pinnedpubkey) { + int size; + CURLcode result; + mbedtls_x509_crt *p = NULL; + unsigned char *pubkey = NULL; + +#if MBEDTLS_VERSION_NUMBER == 0x03000000 + if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || + !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { +#else + if(!peercert || !peercert->raw.p || !peercert->raw.len) { +#endif + failf(data, "Failed due to missing peer certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + p = calloc(1, sizeof(*p)); + + if(!p) + return CURLE_OUT_OF_MEMORY; + + pubkey = malloc(PUB_DER_MAX_BYTES); + + if(!pubkey) { + result = CURLE_OUT_OF_MEMORY; + goto pinnedpubkey_error; + } + + mbedtls_x509_crt_init(p); + + /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der + needs a non-const key, for now. + https://github.com/ARMmbed/mbedtls/issues/396 */ +#if MBEDTLS_VERSION_NUMBER == 0x03000000 + if(mbedtls_x509_crt_parse_der(p, + peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), + peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { +#else + if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { +#endif + failf(data, "Failed copying peer certificate"); + result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + goto pinnedpubkey_error; + } + +#if MBEDTLS_VERSION_NUMBER == 0x03000000 + size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, + PUB_DER_MAX_BYTES); +#else + size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); +#endif + + if(size <= 0) { + failf(data, "Failed copying public key from peer certificate"); + result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + goto pinnedpubkey_error; + } + + /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ + result = Curl_pin_peer_pubkey(data, + pinnedpubkey, + &pubkey[PUB_DER_MAX_BYTES - size], size); +pinnedpubkey_error: + mbedtls_x509_crt_free(p); + free(p); + free(pubkey); + if(result) { + return result; + } + } + +#ifdef HAS_ALPN + if(connssl->alpn) { + const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl); + + Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto, + proto? strlen(proto) : 0); + } +#endif + + connssl->connecting_state = ssl_connect_3; + infof(data, "SSL connected"); + + return CURLE_OK; +} + +static CURLcode +mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + CURLcode retcode = CURLE_OK; + struct ssl_connect_data *connssl = cf->ctx; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + DEBUGASSERT(backend); + + if(ssl_config->primary.sessionid) { + int ret; + mbedtls_ssl_session *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; + bool added = FALSE; + + our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); + if(!our_ssl_sessionid) + return CURLE_OUT_OF_MEMORY; + + mbedtls_ssl_session_init(our_ssl_sessionid); + + ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid); + if(ret) { + if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED) + mbedtls_ssl_session_free(our_ssl_sessionid); + free(our_ssl_sessionid); + failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } + + /* If there's already a matching session in the cache, delete it */ + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)) + Curl_ssl_delsessionid(data, old_ssl_sessionid); + + retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, + 0, &added); + Curl_ssl_sessionid_unlock(data); + if(!added) { + mbedtls_ssl_session_free(our_ssl_sessionid); + free(our_ssl_sessionid); + } + if(retcode) { + failf(data, "failed to store ssl session"); + return retcode; + } + } + + connssl->connecting_state = ssl_connect_done; + + return CURLE_OK; +} + +static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *mem, size_t len, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + int ret = -1; + + (void)data; + DEBUGASSERT(backend); + ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len); + + if(ret < 0) { + *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ? + CURLE_AGAIN : CURLE_SEND_ERROR; + ret = -1; + } + + return ret; +} + +static void mbedtls_close_all(struct Curl_easy *data) +{ + (void)data; +} + +static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + char buf[32]; + + (void)data; + DEBUGASSERT(backend); + + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf)); + + mbedtls_pk_free(&backend->pk); + mbedtls_x509_crt_free(&backend->clicert); + mbedtls_x509_crt_free(&backend->cacert); +#ifdef MBEDTLS_X509_CRL_PARSE_C + mbedtls_x509_crl_free(&backend->crl); +#endif + mbedtls_ssl_config_free(&backend->config); + mbedtls_ssl_free(&backend->ssl); + mbedtls_ctr_drbg_free(&backend->ctr_drbg); +#ifndef THREADING_SUPPORT + mbedtls_entropy_free(&backend->entropy); +#endif /* THREADING_SUPPORT */ +} + +static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t buffersize, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + int ret = -1; + ssize_t len = -1; + + (void)data; + DEBUGASSERT(backend); + + ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, + buffersize); + + if(ret <= 0) { + if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) + return 0; + + *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ? + CURLE_AGAIN : CURLE_RECV_ERROR; + return -1; + } + + len = ret; + + return len; +} + +static void mbedtls_session_free(void *ptr) +{ + mbedtls_ssl_session_free(ptr); + free(ptr); +} + +static size_t mbedtls_version(char *buffer, size_t size) +{ +#ifdef MBEDTLS_VERSION_C + /* if mbedtls_version_get_number() is available it is better */ + unsigned int version = mbedtls_version_get_number(); + return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24, + (version>>16)&0xff, (version>>8)&0xff); +#else + return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING); +#endif +} + +static CURLcode mbedtls_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + int ret = -1; + char errorbuf[128]; + mbedtls_entropy_context ctr_entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_init(&ctr_entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, + &ctr_entropy, NULL, 0); + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s", + -ret, errorbuf); + } + else { + ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s", + -ret, errorbuf); + } + } + + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&ctr_entropy); + + return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT; +#elif defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_state hs; + mbedtls_havege_init(&hs); + mbedtls_havege_random(&hs, entropy, length); + mbedtls_havege_free(&hs); + return CURLE_OK; +#else + return CURLE_NOT_BUILT_IN; +#endif +} + +static CURLcode +mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, + bool nonblocking, + bool *done) +{ + CURLcode retcode; + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + timediff_t timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + /* Find out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + retcode = mbed_connect_step1(cf, data); + if(retcode) + return retcode; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + retcode = mbed_connect_step2(cf, data); + if(retcode || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return retcode; + + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3 == connssl->connecting_state) { + retcode = mbed_connect_step3(cf, data); + if(retcode) + return retcode; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + return mbed_connect_common(cf, data, TRUE, done); +} + + +static CURLcode mbedtls_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode retcode; + bool done = FALSE; + + retcode = mbed_connect_common(cf, data, FALSE, &done); + if(retcode) + return retcode; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +/* + * return 0 error initializing SSL + * return 1 SSL initialized successfully + */ +static int mbedtls_init(void) +{ + return Curl_mbedtlsthreadlock_thread_setup(); +} + +static void mbedtls_cleanup(void) +{ +#ifdef THREADING_SUPPORT + mbedtls_entropy_free(&ts_entropy); +#endif /* THREADING_SUPPORT */ + (void)Curl_mbedtlsthreadlock_thread_cleanup(); +} + +static bool mbedtls_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct ssl_connect_data *ctx = cf->ctx; + struct mbed_ssl_backend_data *backend; + + (void)data; + DEBUGASSERT(ctx && ctx->backend); + backend = (struct mbed_ssl_backend_data *)ctx->backend; + return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0; +} + +static CURLcode mbedtls_sha256sum(const unsigned char *input, + size_t inputlen, + unsigned char *sha256sum, + size_t sha256len UNUSED_PARAM) +{ + /* TODO: explain this for different mbedtls 2.x vs 3 version */ + (void)sha256len; +#if MBEDTLS_VERSION_NUMBER < 0x02070000 + mbedtls_sha256(input, inputlen, sha256sum, 0); +#else + /* returns 0 on success, otherwise failure */ +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0) +#else + if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0) +#endif + return CURLE_BAD_FUNCTION_ARGUMENT; +#endif + return CURLE_OK; +} + +static void *mbedtls_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; + (void)info; + DEBUGASSERT(backend); + return &backend->ssl; +} + +const struct Curl_ssl Curl_ssl_mbedtls = { + { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */ + + SSLSUPP_CA_PATH | + SSLSUPP_CAINFO_BLOB | + SSLSUPP_PINNEDPUBKEY | + SSLSUPP_SSL_CTX | + SSLSUPP_HTTPS_PROXY, + + sizeof(struct mbed_ssl_backend_data), + + mbedtls_init, /* init */ + mbedtls_cleanup, /* cleanup */ + mbedtls_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + mbedtls_data_pending, /* data_pending */ + mbedtls_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + mbedtls_connect, /* connect */ + mbedtls_connect_nonblocking, /* connect_nonblocking */ + Curl_ssl_adjust_pollset, /* adjust_pollset */ + mbedtls_get_internals, /* get_internals */ + mbedtls_close, /* close_one */ + mbedtls_close_all, /* close_all */ + mbedtls_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + mbedtls_sha256sum, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + mbed_recv, /* recv decrypted data */ + mbed_send, /* send data to encrypt */ +}; + +#endif /* USE_MBEDTLS */ diff --git a/lib/vtls/mbedtls.h b/lib/vtls/mbedtls.h new file mode 100644 index 0000000..d8a0a06 --- /dev/null +++ b/lib/vtls/mbedtls.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_MBEDTLS_H +#define HEADER_CURL_MBEDTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_MBEDTLS + +extern const struct Curl_ssl Curl_ssl_mbedtls; + +#endif /* USE_MBEDTLS */ +#endif /* HEADER_CURL_MBEDTLS_H */ diff --git a/lib/vtls/mbedtls_threadlock.c b/lib/vtls/mbedtls_threadlock.c new file mode 100644 index 0000000..22b1b22 --- /dev/null +++ b/lib/vtls/mbedtls_threadlock.c @@ -0,0 +1,134 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(USE_MBEDTLS) && \ + ((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ + defined(USE_THREADS_WIN32)) + +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) +# include +# define MBEDTLS_MUTEX_T pthread_mutex_t +#elif defined(USE_THREADS_WIN32) +# define MBEDTLS_MUTEX_T HANDLE +#endif + +#include "mbedtls_threadlock.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* number of thread locks */ +#define NUMT 2 + +/* This array will store all of the mutexes available to Mbedtls. */ +static MBEDTLS_MUTEX_T *mutex_buf = NULL; + +int Curl_mbedtlsthreadlock_thread_setup(void) +{ + int i; + + mutex_buf = calloc(1, NUMT * sizeof(MBEDTLS_MUTEX_T)); + if(!mutex_buf) + return 0; /* error, no number of threads defined */ + + for(i = 0; i < NUMT; i++) { +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) + if(pthread_mutex_init(&mutex_buf[i], NULL)) + return 0; /* pthread_mutex_init failed */ +#elif defined(USE_THREADS_WIN32) + mutex_buf[i] = CreateMutex(0, FALSE, 0); + if(mutex_buf[i] == 0) + return 0; /* CreateMutex failed */ +#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ + } + + return 1; /* OK */ +} + +int Curl_mbedtlsthreadlock_thread_cleanup(void) +{ + int i; + + if(!mutex_buf) + return 0; /* error, no threads locks defined */ + + for(i = 0; i < NUMT; i++) { +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) + if(pthread_mutex_destroy(&mutex_buf[i])) + return 0; /* pthread_mutex_destroy failed */ +#elif defined(USE_THREADS_WIN32) + if(!CloseHandle(mutex_buf[i])) + return 0; /* CloseHandle failed */ +#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ + } + free(mutex_buf); + mutex_buf = NULL; + + return 1; /* OK */ +} + +int Curl_mbedtlsthreadlock_lock_function(int n) +{ + if(n < NUMT) { +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) + if(pthread_mutex_lock(&mutex_buf[n])) { + DEBUGF(fprintf(stderr, + "Error: mbedtlsthreadlock_lock_function failed\n")); + return 0; /* pthread_mutex_lock failed */ + } +#elif defined(USE_THREADS_WIN32) + if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) { + DEBUGF(fprintf(stderr, + "Error: mbedtlsthreadlock_lock_function failed\n")); + return 0; /* pthread_mutex_lock failed */ + } +#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ + } + return 1; /* OK */ +} + +int Curl_mbedtlsthreadlock_unlock_function(int n) +{ + if(n < NUMT) { +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) + if(pthread_mutex_unlock(&mutex_buf[n])) { + DEBUGF(fprintf(stderr, + "Error: mbedtlsthreadlock_unlock_function failed\n")); + return 0; /* pthread_mutex_unlock failed */ + } +#elif defined(USE_THREADS_WIN32) + if(!ReleaseMutex(mutex_buf[n])) { + DEBUGF(fprintf(stderr, + "Error: mbedtlsthreadlock_unlock_function failed\n")); + return 0; /* pthread_mutex_lock failed */ + } +#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ + } + return 1; /* OK */ +} + +#endif /* USE_MBEDTLS */ diff --git a/lib/vtls/mbedtls_threadlock.h b/lib/vtls/mbedtls_threadlock.h new file mode 100644 index 0000000..2b0bd41 --- /dev/null +++ b/lib/vtls/mbedtls_threadlock.h @@ -0,0 +1,50 @@ +#ifndef HEADER_CURL_MBEDTLS_THREADLOCK_H +#define HEADER_CURL_MBEDTLS_THREADLOCK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_MBEDTLS + +#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ + defined(USE_THREADS_WIN32) + +int Curl_mbedtlsthreadlock_thread_setup(void); +int Curl_mbedtlsthreadlock_thread_cleanup(void); +int Curl_mbedtlsthreadlock_lock_function(int n); +int Curl_mbedtlsthreadlock_unlock_function(int n); + +#else + +#define Curl_mbedtlsthreadlock_thread_setup() 1 +#define Curl_mbedtlsthreadlock_thread_cleanup() 1 +#define Curl_mbedtlsthreadlock_lock_function(x) 1 +#define Curl_mbedtlsthreadlock_unlock_function(x) 1 + +#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ + +#endif /* USE_MBEDTLS */ + +#endif /* HEADER_CURL_MBEDTLS_THREADLOCK_H */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c new file mode 100644 index 0000000..8d60870 --- /dev/null +++ b/lib/vtls/openssl.c @@ -0,0 +1,4954 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + */ + +#include "curl_setup.h" + +#if defined(USE_QUICHE) || defined(USE_OPENSSL) + +#include + +/* Wincrypt must be included before anything that could include OpenSSL. */ +#if defined(USE_WIN32_CRYPTO) +#include +/* Undefine wincrypt conflicting symbols for BoringSSL. */ +#undef X509_NAME +#undef X509_EXTENSIONS +#undef PKCS7_ISSUER_AND_SERIAL +#undef PKCS7_SIGNER_INFO +#undef OCSP_REQUEST +#undef OCSP_RESPONSE +#endif + +#include "urldata.h" +#include "sendf.h" +#include "formdata.h" /* for the boundary function */ +#include "url.h" /* for the ssl config check function */ +#include "inet_pton.h" +#include "openssl.h" +#include "connect.h" +#include "slist.h" +#include "select.h" +#include "vtls.h" +#include "vtls_int.h" +#include "vauth/vauth.h" +#include "keylog.h" +#include "strcase.h" +#include "hostcheck.h" +#include "multiif.h" +#include "strerror.h" +#include "curl_printf.h" + +#include +#include +#include +#ifndef OPENSSL_NO_DSA +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) +#include +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) && /* 0.9.7 or later */ \ + !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_UI_CONSOLE) +#define USE_OPENSSL_ENGINE +#include +#endif + +#include "warnless.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +/* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS + renegotiations when built with BoringSSL. Renegotiating is non-compliant + with HTTP/2 and "an extremely dangerous protocol feature". Beware. + +#define ALLOW_RENEG 1 + */ + +#ifndef OPENSSL_VERSION_NUMBER +#error "OPENSSL_VERSION_NUMBER not defined" +#endif + +#ifdef USE_OPENSSL_ENGINE +#include +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x00909000L +#define SSL_METHOD_QUAL const +#else +#define SSL_METHOD_QUAL +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) +#define HAVE_ERR_REMOVE_THREAD_STATE 1 +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x20700000L) +#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER +#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ +#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ +#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ +#define CONST_EXTS const +#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 + +/* funny typecast define due to difference in API */ +#ifdef LIBRESSL_VERSION_NUMBER +#define ARG2_X509_signature_print (X509_ALGOR *) +#else +#define ARG2_X509_signature_print +#endif + +#else +/* For OpenSSL before 1.1.0 */ +#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) +#define X509_get0_notBefore(x) X509_get_notBefore(x) +#define X509_get0_notAfter(x) X509_get_notAfter(x) +#define CONST_EXTS /* nope */ +#ifndef LIBRESSL_VERSION_NUMBER +#define OpenSSL_version_num() SSLeay() +#endif +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x20700000L) +#define HAVE_X509_GET0_SIGNATURE 1 +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */ +#define HAVE_SSL_GET_SHUTDOWN 1 +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \ + OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \ + !defined(OPENSSL_NO_COMP) +#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1 +#endif + +#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) +/* not present in older OpenSSL */ +#define OPENSSL_load_builtin_modules(x) +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#define HAVE_EVP_PKEY_GET_PARAMS 1 +#endif + +#ifdef HAVE_EVP_PKEY_GET_PARAMS +#include +#define DECLARE_PKEY_PARAM_BIGNUM(name) BIGNUM *name = NULL +#define FREE_PKEY_PARAM_BIGNUM(name) BN_clear_free(name) +#else +#define DECLARE_PKEY_PARAM_BIGNUM(name) const BIGNUM *name +#define FREE_PKEY_PARAM_BIGNUM(name) +#endif + +/* + * Whether SSL_CTX_set_keylog_callback is available. + * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 + * BoringSSL: supported since d28f59c27bac (committed 2015-11-19) + * LibreSSL: supported since 3.5.0 (released 2022-02-24) + */ +#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER)) || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER >= 0x3050000fL) || \ + defined(OPENSSL_IS_BORINGSSL) +#define HAVE_KEYLOG_CALLBACK +#endif + +/* Whether SSL_CTX_set_ciphersuites is available. + * OpenSSL: supported since 1.1.1 (commit a53b5be6a05) + * BoringSSL: no + * LibreSSL: supported since 3.4.1 (released 2021-10-14) + */ +#if ((OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER)) || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER >= 0x3040100fL)) && \ + !defined(OPENSSL_IS_BORINGSSL) + #define HAVE_SSL_CTX_SET_CIPHERSUITES + #if !defined(OPENSSL_IS_AWSLC) + #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH + #endif +#endif + +/* + * Whether SSL_CTX_set1_curves_list is available. + * OpenSSL: supported since 1.0.2, see + * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html + * BoringSSL: supported since 5fd1807d95f7 (committed 2016-09-30) + * LibreSSL: since 2.5.3 (April 12, 2017) + */ +#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) || \ + defined(OPENSSL_IS_BORINGSSL) +#define HAVE_SSL_CTX_SET_EC_CURVES +#endif + +#if defined(LIBRESSL_VERSION_NUMBER) +#define OSSL_PACKAGE "LibreSSL" +#elif defined(OPENSSL_IS_BORINGSSL) +#define OSSL_PACKAGE "BoringSSL" +#elif defined(OPENSSL_IS_AWSLC) +#define OSSL_PACKAGE "AWS-LC" +#else +# if defined(USE_NGTCP2) && defined(USE_NGHTTP3) +# define OSSL_PACKAGE "quictls" +# else +# define OSSL_PACKAGE "OpenSSL" +#endif +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +/* up2date versions of OpenSSL maintain reasonably secure defaults without + * breaking compatibility, so it is better not to override the defaults in curl + */ +#define DEFAULT_CIPHER_SELECTION NULL +#else +/* ... but it is not the case with old versions of OpenSSL */ +#define DEFAULT_CIPHER_SELECTION \ + "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" +#endif + +#ifdef HAVE_OPENSSL_SRP +/* the function exists */ +#ifdef USE_TLS_SRP +/* the functionality is not disabled */ +#define USE_OPENSSL_SRP +#endif +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#define HAVE_RANDOM_INIT_BY_DEFAULT 1 +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x2070100fL) && \ + !defined(OPENSSL_IS_BORINGSSL) && \ + !defined(OPENSSL_IS_AWSLC) +#define HAVE_OPENSSL_VERSION +#endif + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +typedef uint32_t sslerr_t; +#else +typedef unsigned long sslerr_t; +#endif + +/* + * Whether the OpenSSL version has the API needed to support sharing an + * X509_STORE between connections. The API is: + * * `X509_STORE_up_ref` -- Introduced: OpenSSL 1.1.0. + */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* OpenSSL >= 1.1.0 */ +#define HAVE_SSL_X509_STORE_SHARE +#endif + +/* What API version do we use? */ +#if defined(LIBRESSL_VERSION_NUMBER) +#define USE_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f) +#else /* !LIBRESSL_VERSION_NUMBER */ +#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L) +#endif /* !LIBRESSL_VERSION_NUMBER */ + +struct ossl_ssl_backend_data { + /* these ones requires specific SSL-types */ + SSL_CTX* ctx; + SSL* handle; + X509* server_cert; + BIO_METHOD *bio_method; + CURLcode io_result; /* result of last BIO cfilter operation */ +#ifndef HAVE_KEYLOG_CALLBACK + /* Set to true once a valid keylog entry has been created to avoid dupes. */ + bool keylog_done; +#endif + bool x509_store_setup; /* x509 store has been set up */ +}; + +#if defined(HAVE_SSL_X509_STORE_SHARE) +struct multi_ssl_backend_data { + char *CAfile; /* CAfile path used to generate X509 store */ + X509_STORE *store; /* cached X509 store or NULL if none */ + struct curltime time; /* when the cached store was created */ +}; +#endif /* HAVE_SSL_X509_STORE_SHARE */ + +#define push_certinfo(_label, _num) \ +do { \ + long info_len = BIO_get_mem_data(mem, &ptr); \ + Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ + if(1 != BIO_reset(mem)) \ + break; \ +} while(0) + +static void pubkey_show(struct Curl_easy *data, + BIO *mem, + int num, + const char *type, + const char *name, + const BIGNUM *bn) +{ + char *ptr; + char namebuf[32]; + + msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); + + if(bn) + BN_print(mem, bn); + push_certinfo(namebuf, num); +} + +#ifdef HAVE_OPAQUE_RSA_DSA_DH +#define print_pubkey_BN(_type, _name, _num) \ + pubkey_show(data, mem, _num, #_type, #_name, _name) + +#else +#define print_pubkey_BN(_type, _name, _num) \ +do { \ + if(_type->_name) { \ + pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ + } \ +} while(0) +#endif + +static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) +{ + int i, ilen; + + ilen = (int)len; + if(ilen < 0) + return 1; /* buffer too big */ + + i = i2t_ASN1_OBJECT(buf, ilen, a); + + if(i >= ilen) + return 1; /* buffer too small */ + + return 0; +} + +static void X509V3_ext(struct Curl_easy *data, + int certnum, + CONST_EXTS STACK_OF(X509_EXTENSION) *exts) +{ + int i; + + if((int)sk_X509_EXTENSION_num(exts) <= 0) + /* no extensions, bail out */ + return; + + for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { + ASN1_OBJECT *obj; + X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); + BUF_MEM *biomem; + char namebuf[128]; + BIO *bio_out = BIO_new(BIO_s_mem()); + + if(!bio_out) + return; + + obj = X509_EXTENSION_get_object(ext); + + asn1_object_dump(obj, namebuf, sizeof(namebuf)); + + if(!X509V3_EXT_print(bio_out, ext, 0, 0)) + ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); + + BIO_get_mem_ptr(bio_out, &biomem); + Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data, + biomem->length); + BIO_free(bio_out); + } +} + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +typedef size_t numcert_t; +#else +typedef int numcert_t; +#endif + +CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl) +{ + CURLcode result; + STACK_OF(X509) *sk; + int i; + numcert_t numcerts; + BIO *mem; + + DEBUGASSERT(ssl); + + sk = SSL_get_peer_cert_chain(ssl); + if(!sk) { + return CURLE_OUT_OF_MEMORY; + } + + numcerts = sk_X509_num(sk); + + result = Curl_ssl_init_certinfo(data, (int)numcerts); + if(result) { + return result; + } + + mem = BIO_new(BIO_s_mem()); + if(!mem) { + return CURLE_OUT_OF_MEMORY; + } + + for(i = 0; i < (int)numcerts; i++) { + ASN1_INTEGER *num; + X509 *x = sk_X509_value(sk, i); + EVP_PKEY *pubkey = NULL; + int j; + char *ptr; + const ASN1_BIT_STRING *psig = NULL; + + X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Subject", i); + + X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Issuer", i); + + BIO_printf(mem, "%lx", X509_get_version(x)); + push_certinfo("Version", i); + + num = X509_get_serialNumber(x); + if(num->type == V_ASN1_NEG_INTEGER) + BIO_puts(mem, "-"); + for(j = 0; j < num->length; j++) + BIO_printf(mem, "%02x", num->data[j]); + push_certinfo("Serial Number", i); + +#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) + { + const X509_ALGOR *sigalg = NULL; + X509_PUBKEY *xpubkey = NULL; + ASN1_OBJECT *pubkeyoid = NULL; + + X509_get0_signature(&psig, &sigalg, x); + if(sigalg) { + const ASN1_OBJECT *sigalgoid = NULL; + X509_ALGOR_get0(&sigalgoid, NULL, NULL, sigalg); + i2a_ASN1_OBJECT(mem, sigalgoid); + push_certinfo("Signature Algorithm", i); + } + + xpubkey = X509_get_X509_PUBKEY(x); + if(xpubkey) { + X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey); + if(pubkeyoid) { + i2a_ASN1_OBJECT(mem, pubkeyoid); + push_certinfo("Public Key Algorithm", i); + } + } + + X509V3_ext(data, i, X509_get0_extensions(x)); + } +#else + { + /* before OpenSSL 1.0.2 */ + X509_CINF *cinf = x->cert_info; + + i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); + push_certinfo("Signature Algorithm", i); + + i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); + push_certinfo("Public Key Algorithm", i); + + X509V3_ext(data, i, cinf->extensions); + + psig = x->signature; + } +#endif + + ASN1_TIME_print(mem, X509_get0_notBefore(x)); + push_certinfo("Start date", i); + + ASN1_TIME_print(mem, X509_get0_notAfter(x)); + push_certinfo("Expire date", i); + + pubkey = X509_get_pubkey(x); + if(!pubkey) + infof(data, " Unable to load public key"); + else { + int pktype; +#ifdef HAVE_OPAQUE_EVP_PKEY + pktype = EVP_PKEY_id(pubkey); +#else + pktype = pubkey->type; +#endif + switch(pktype) { + case EVP_PKEY_RSA: + { +#ifndef HAVE_EVP_PKEY_GET_PARAMS + RSA *rsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + rsa = EVP_PKEY_get0_RSA(pubkey); +#else + rsa = pubkey->pkey.rsa; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(n); + DECLARE_PKEY_PARAM_BIGNUM(e); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e); +#else + RSA_get0_key(rsa, &n, &e, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ + BIO_printf(mem, "%d", n ? BN_num_bits(n) : 0); +#else + BIO_printf(mem, "%d", rsa->n ? BN_num_bits(rsa->n) : 0); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + push_certinfo("RSA Public Key", i); + print_pubkey_BN(rsa, n, i); + print_pubkey_BN(rsa, e, i); + FREE_PKEY_PARAM_BIGNUM(n); + FREE_PKEY_PARAM_BIGNUM(e); + } + + break; + } + case EVP_PKEY_DSA: + { +#ifndef OPENSSL_NO_DSA +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DSA *dsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + dsa = EVP_PKEY_get0_DSA(pubkey); +#else + dsa = pubkey->pkey.dsa; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else + DSA_get0_pqg(dsa, &p, &q, &g); + DSA_get0_key(dsa, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + print_pubkey_BN(dsa, p, i); + print_pubkey_BN(dsa, q, i); + print_pubkey_BN(dsa, g, i); + print_pubkey_BN(dsa, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); + } +#endif /* !OPENSSL_NO_DSA */ + break; + } + case EVP_PKEY_DH: + { +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DH *dh; +#ifdef HAVE_OPAQUE_EVP_PKEY + dh = EVP_PKEY_get0_DH(pubkey); +#else + dh = pubkey->pkey.dh; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else + DH_get0_pqg(dh, &p, &q, &g); + DH_get0_key(dh, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, q, i); + print_pubkey_BN(dh, g, i); +#else + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, g, i); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + print_pubkey_BN(dh, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); + } + break; + } + } + EVP_PKEY_free(pubkey); + } + + if(psig) { + for(j = 0; j < psig->length; j++) + BIO_printf(mem, "%02x:", psig->data[j]); + push_certinfo("Signature", i); + } + + PEM_write_bio_X509(mem, x); + push_certinfo("Cert", i); + } + + BIO_free(mem); + + return CURLE_OK; +} + +#endif /* quiche or OpenSSL */ + +#ifdef USE_OPENSSL + +#if USE_PRE_1_1_API +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL +#define BIO_set_init(x,v) ((x)->init=(v)) +#define BIO_get_data(x) ((x)->ptr) +#define BIO_set_data(x,v) ((x)->ptr=(v)) +#endif +#define BIO_get_shutdown(x) ((x)->shutdown) +#define BIO_set_shutdown(x,v) ((x)->shutdown=(v)) +#endif /* USE_PRE_1_1_API */ + +static int ossl_bio_cf_create(BIO *bio) +{ + BIO_set_shutdown(bio, 1); + BIO_set_init(bio, 1); +#if USE_PRE_1_1_API + bio->num = -1; +#endif + BIO_set_data(bio, NULL); + return 1; +} + +static int ossl_bio_cf_destroy(BIO *bio) +{ + if(!bio) + return 0; + return 1; +} + +static long ossl_bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + struct Curl_cfilter *cf = BIO_get_data(bio); + long ret = 1; + + (void)cf; + (void)ptr; + switch(cmd) { + case BIO_CTRL_GET_CLOSE: + ret = (long)BIO_get_shutdown(bio); + break; + case BIO_CTRL_SET_CLOSE: + BIO_set_shutdown(bio, (int)num); + break; + case BIO_CTRL_FLUSH: + /* we do no delayed writes, but if we ever would, this + * needs to trigger it. */ + ret = 1; + break; + case BIO_CTRL_DUP: + ret = 1; + break; +#ifdef BIO_CTRL_EOF + case BIO_CTRL_EOF: + /* EOF has been reached on input? */ + return (!cf->next || !cf->next->connected); +#endif + default: + ret = 0; + break; + } + return ret; +} + +static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen) +{ + struct Curl_cfilter *cf = BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result = CURLE_SEND_ERROR; + + DEBUGASSERT(data); + nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); + CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d", + blen, (int)nwritten, result); + BIO_clear_retry_flags(bio); + backend->io_result = result; + if(nwritten < 0) { + if(CURLE_AGAIN == result) + BIO_set_retry_write(bio); + } + return (int)nwritten; +} + +static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) +{ + struct Curl_cfilter *cf = BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nread; + CURLcode result = CURLE_RECV_ERROR; + + DEBUGASSERT(data); + /* OpenSSL catches this case, so should we. */ + if(!buf) + return 0; + + nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); + CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d", + blen, (int)nread, result); + BIO_clear_retry_flags(bio); + backend->io_result = result; + if(nread < 0) { + if(CURLE_AGAIN == result) + BIO_set_retry_read(bio); + } + + /* Before returning server replies to the SSL instance, we need + * to have setup the x509 store or verification will fail. */ + if(!backend->x509_store_setup) { + result = Curl_ssl_setup_x509_store(cf, data, backend->ctx); + if(result) { + backend->io_result = result; + return -1; + } + backend->x509_store_setup = TRUE; + } + + return (int)nread; +} + +#if USE_PRE_1_1_API + +static BIO_METHOD ossl_bio_cf_meth_1_0 = { + BIO_TYPE_MEM, + "OpenSSL CF BIO", + ossl_bio_cf_out_write, + ossl_bio_cf_in_read, + NULL, /* puts is never called */ + NULL, /* gets is never called */ + ossl_bio_cf_ctrl, + ossl_bio_cf_create, + ossl_bio_cf_destroy, + NULL +}; + +static BIO_METHOD *ossl_bio_cf_method_create(void) +{ + return &ossl_bio_cf_meth_1_0; +} + +#define ossl_bio_cf_method_free(m) Curl_nop_stmt + +#else + +static BIO_METHOD *ossl_bio_cf_method_create(void) +{ + BIO_METHOD *m = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO"); + if(m) { + BIO_meth_set_write(m, &ossl_bio_cf_out_write); + BIO_meth_set_read(m, &ossl_bio_cf_in_read); + BIO_meth_set_ctrl(m, &ossl_bio_cf_ctrl); + BIO_meth_set_create(m, &ossl_bio_cf_create); + BIO_meth_set_destroy(m, &ossl_bio_cf_destroy); + } + return m; +} + +static void ossl_bio_cf_method_free(BIO_METHOD *m) +{ + if(m) + BIO_meth_free(m); +} + +#endif + + +/* + * Number of bytes to read from the random number seed file. This must be + * a finite value (because some entropy "files" like /dev/urandom have + * an infinite length), but must be large enough to provide enough + * entropy to properly seed OpenSSL's PRNG. + */ +#define RAND_LOAD_LENGTH 1024 + +#ifdef HAVE_KEYLOG_CALLBACK +static void ossl_keylog_callback(const SSL *ssl, const char *line) +{ + (void)ssl; + + Curl_tls_keylog_write_line(line); +} +#else +/* + * ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the + * OpenSSL being used doesn't have native support for doing that. + */ +static void +ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done) +{ + const SSL_SESSION *session = SSL_get_session(ssl); + unsigned char client_random[SSL3_RANDOM_SIZE]; + unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; + int master_key_length = 0; + + if(!session || *keylog_done) + return; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x20700000L) + /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that + * we have a valid SSL context if we have a non-NULL session. */ + SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE); + master_key_length = (int) + SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH); +#else + if(ssl->s3 && session->master_key_length > 0) { + master_key_length = session->master_key_length; + memcpy(master_key, session->master_key, session->master_key_length); + memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE); + } +#endif + + /* The handshake has not progressed sufficiently yet, or this is a TLS 1.3 + * session (when curl was built with older OpenSSL headers and running with + * newer OpenSSL runtime libraries). */ + if(master_key_length <= 0) + return; + + *keylog_done = true; + Curl_tls_keylog_write("CLIENT_RANDOM", client_random, + master_key, master_key_length); +} +#endif /* !HAVE_KEYLOG_CALLBACK */ + +static const char *SSL_ERROR_to_str(int err) +{ + switch(err) { + case SSL_ERROR_NONE: + return "SSL_ERROR_NONE"; + case SSL_ERROR_SSL: + return "SSL_ERROR_SSL"; + case SSL_ERROR_WANT_READ: + return "SSL_ERROR_WANT_READ"; + case SSL_ERROR_WANT_WRITE: + return "SSL_ERROR_WANT_WRITE"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "SSL_ERROR_WANT_X509_LOOKUP"; + case SSL_ERROR_SYSCALL: + return "SSL_ERROR_SYSCALL"; + case SSL_ERROR_ZERO_RETURN: + return "SSL_ERROR_ZERO_RETURN"; + case SSL_ERROR_WANT_CONNECT: + return "SSL_ERROR_WANT_CONNECT"; + case SSL_ERROR_WANT_ACCEPT: + return "SSL_ERROR_WANT_ACCEPT"; +#if defined(SSL_ERROR_WANT_ASYNC) + case SSL_ERROR_WANT_ASYNC: + return "SSL_ERROR_WANT_ASYNC"; +#endif +#if defined(SSL_ERROR_WANT_ASYNC_JOB) + case SSL_ERROR_WANT_ASYNC_JOB: + return "SSL_ERROR_WANT_ASYNC_JOB"; +#endif +#if defined(SSL_ERROR_WANT_EARLY) + case SSL_ERROR_WANT_EARLY: + return "SSL_ERROR_WANT_EARLY"; +#endif + default: + return "SSL_ERROR unknown"; + } +} + +static size_t ossl_version(char *buffer, size_t size); + +/* Return error string for last OpenSSL error + */ +static char *ossl_strerror(unsigned long error, char *buf, size_t size) +{ + size_t len; + DEBUGASSERT(size); + *buf = '\0'; + + len = ossl_version(buf, size); + DEBUGASSERT(len < (size - 2)); + if(len < (size - 2)) { + buf += len; + size -= (len + 2); + *buf++ = ':'; + *buf++ = ' '; + *buf = '\0'; + } + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + ERR_error_string_n((uint32_t)error, buf, size); +#else + ERR_error_string_n(error, buf, size); +#endif + + if(!*buf) { + const char *msg = error ? "Unknown error" : "No error"; + if(strlen(msg) < size) + strcpy(buf, msg); + } + + return buf; +} + +static int passwd_callback(char *buf, int num, int encrypting, + void *global_passwd) +{ + DEBUGASSERT(0 == encrypting); + + if(!encrypting) { + int klen = curlx_uztosi(strlen((char *)global_passwd)); + if(num > klen) { + memcpy(buf, global_passwd, klen + 1); + return klen; + } + } + return 0; +} + +/* + * rand_enough() returns TRUE if we have seeded the random engine properly. + */ +static bool rand_enough(void) +{ + return (0 != RAND_status()) ? TRUE : FALSE; +} + +static CURLcode ossl_seed(struct Curl_easy *data) +{ + /* This might get called before it has been added to a multi handle */ + if(data->multi && data->multi->ssl_seeded) + return CURLE_OK; + + if(rand_enough()) { + /* OpenSSL 1.1.0+ should return here */ + if(data->multi) + data->multi->ssl_seeded = TRUE; + return CURLE_OK; + } +#ifdef HAVE_RANDOM_INIT_BY_DEFAULT + /* with OpenSSL 1.1.0+, a failed RAND_status is a showstopper */ + failf(data, "Insufficient randomness"); + return CURLE_SSL_CONNECT_ERROR; +#else + +#ifdef RANDOM_FILE + RAND_load_file(RANDOM_FILE, RAND_LOAD_LENGTH); + if(rand_enough()) + return CURLE_OK; +#endif + + /* fallback to a custom seeding of the PRNG using a hash based on a current + time */ + do { + unsigned char randb[64]; + size_t len = sizeof(randb); + size_t i, i_max; + for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) { + struct curltime tv = Curl_now(); + Curl_wait_ms(1); + tv.tv_sec *= i + 1; + tv.tv_usec *= (unsigned int)i + 2; + tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) * + (i + 3)) << 8; + tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec + + Curl_now().tv_usec) * + (i + 4)) << 16; + memcpy(&randb[i * sizeof(struct curltime)], &tv, + sizeof(struct curltime)); + } + RAND_add(randb, (int)len, (double)len/2); + } while(!rand_enough()); + + { + /* generates a default path for the random seed file */ + char fname[256]; + fname[0] = 0; /* blank it first */ + RAND_file_name(fname, sizeof(fname)); + if(fname[0]) { + /* we got a file name to try */ + RAND_load_file(fname, RAND_LOAD_LENGTH); + if(rand_enough()) + return CURLE_OK; + } + } + + infof(data, "libcurl is now using a weak random seed"); + return (rand_enough() ? CURLE_OK : + CURLE_SSL_CONNECT_ERROR /* confusing error code */); +#endif +} + +#ifndef SSL_FILETYPE_ENGINE +#define SSL_FILETYPE_ENGINE 42 +#endif +#ifndef SSL_FILETYPE_PKCS12 +#define SSL_FILETYPE_PKCS12 43 +#endif +static int do_file_type(const char *type) +{ + if(!type || !type[0]) + return SSL_FILETYPE_PEM; + if(strcasecompare(type, "PEM")) + return SSL_FILETYPE_PEM; + if(strcasecompare(type, "DER")) + return SSL_FILETYPE_ASN1; + if(strcasecompare(type, "ENG")) + return SSL_FILETYPE_ENGINE; + if(strcasecompare(type, "P12")) + return SSL_FILETYPE_PKCS12; + return -1; +} + +#ifdef USE_OPENSSL_ENGINE +/* + * Supply default password to the engine user interface conversation. + * The password is passed by OpenSSL engine from ENGINE_load_private_key() + * last argument to the ui and can be obtained by UI_get0_user_data(ui) here. + */ +static int ssl_ui_reader(UI *ui, UI_STRING *uis) +{ + const char *password; + switch(UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + password = (const char *)UI_get0_user_data(ui); + if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { + UI_set_result(ui, uis, password); + return 1; + } + FALLTHROUGH(); + default: + break; + } + return (UI_method_get_reader(UI_OpenSSL()))(ui, uis); +} + +/* + * Suppress interactive request for a default password if available. + */ +static int ssl_ui_writer(UI *ui, UI_STRING *uis) +{ + switch(UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + if(UI_get0_user_data(ui) && + (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { + return 1; + } + FALLTHROUGH(); + default: + break; + } + return (UI_method_get_writer(UI_OpenSSL()))(ui, uis); +} + +/* + * Check if a given string is a PKCS#11 URI + */ +static bool is_pkcs11_uri(const char *string) +{ + return (string && strncasecompare(string, "pkcs11:", 7)); +} + +#endif + +static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine); + +static int +SSL_CTX_use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob, + int type, const char *key_passwd) +{ + int ret = 0; + X509 *x = NULL; + /* the typecast of blob->len is fine since it is guaranteed to never be + larger than CURL_MAX_INPUT_LENGTH */ + BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len)); + if(!in) + return CURLE_OUT_OF_MEMORY; + + if(type == SSL_FILETYPE_ASN1) { + /* j = ERR_R_ASN1_LIB; */ + x = d2i_X509_bio(in, NULL); + } + else if(type == SSL_FILETYPE_PEM) { + /* ERR_R_PEM_LIB; */ + x = PEM_read_bio_X509(in, NULL, + passwd_callback, (void *)key_passwd); + } + else { + ret = 0; + goto end; + } + + if(!x) { + ret = 0; + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); +end: + X509_free(x); + BIO_free(in); + return ret; +} + +static int +SSL_CTX_use_PrivateKey_blob(SSL_CTX *ctx, const struct curl_blob *blob, + int type, const char *key_passwd) +{ + int ret = 0; + EVP_PKEY *pkey = NULL; + BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len)); + if(!in) + return CURLE_OUT_OF_MEMORY; + + if(type == SSL_FILETYPE_PEM) + pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback, + (void *)key_passwd); + else if(type == SSL_FILETYPE_ASN1) + pkey = d2i_PrivateKey_bio(in, NULL); + else { + ret = 0; + goto end; + } + if(!pkey) { + ret = 0; + goto end; + } + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + EVP_PKEY_free(pkey); +end: + BIO_free(in); + return ret; +} + +static int +SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob, + const char *key_passwd) +{ +/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */ +#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* OpenSSL 1.0.2 or later */ \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + (LIBRESSL_VERSION_NUMBER < 0x2090100fL)) /* LibreSSL 2.9.1 or later */ + int ret = 0; + X509 *x = NULL; + void *passwd_callback_userdata = (void *)key_passwd; + BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len)); + if(!in) + return CURLE_OUT_OF_MEMORY; + + ERR_clear_error(); + + x = PEM_read_bio_X509_AUX(in, NULL, + passwd_callback, (void *)key_passwd); + + if(!x) { + ret = 0; + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + + if(ERR_peek_error() != 0) + ret = 0; + + if(ret) { + X509 *ca; + sslerr_t err; + + if(!SSL_CTX_clear_chain_certs(ctx)) { + ret = 0; + goto end; + } + + while((ca = PEM_read_bio_X509(in, NULL, passwd_callback, + passwd_callback_userdata)) + != NULL) { + + if(!SSL_CTX_add0_chain_cert(ctx, ca)) { + X509_free(ca); + ret = 0; + goto end; + } + } + + err = ERR_peek_last_error(); + if((ERR_GET_LIB(err) == ERR_LIB_PEM) && + (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) + ERR_clear_error(); + else + ret = 0; + } + +end: + X509_free(x); + BIO_free(in); + return ret; +#else + (void)ctx; /* unused */ + (void)blob; /* unused */ + (void)key_passwd; /* unused */ + return 0; +#endif +} + +static +int cert_stuff(struct Curl_easy *data, + SSL_CTX* ctx, + char *cert_file, + const struct curl_blob *cert_blob, + const char *cert_type, + char *key_file, + const struct curl_blob *key_blob, + const char *key_type, + char *key_passwd) +{ + char error_buffer[256]; + bool check_privkey = TRUE; + + int file_type = do_file_type(cert_type); + + if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE)) { + SSL *ssl; + X509 *x509; + int cert_done = 0; + int cert_use_result; + + if(key_passwd) { + /* set the password in the callback userdata */ + SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd); + /* Set passwd callback: */ + SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); + } + + + switch(file_type) { + case SSL_FILETYPE_PEM: + /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ + cert_use_result = cert_blob ? + SSL_CTX_use_certificate_chain_blob(ctx, cert_blob, key_passwd) : + SSL_CTX_use_certificate_chain_file(ctx, cert_file); + if(cert_use_result != 1) { + failf(data, + "could not load PEM client certificate from %s, " OSSL_PACKAGE + " error %s, " + "(no key found, wrong pass phrase, or wrong file format?)", + (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file), + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } + break; + + case SSL_FILETYPE_ASN1: + /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but + we use the case above for PEM so this can only be performed with + ASN1 files. */ + + cert_use_result = cert_blob ? + SSL_CTX_use_certificate_blob(ctx, cert_blob, + file_type, key_passwd) : + SSL_CTX_use_certificate_file(ctx, cert_file, file_type); + if(cert_use_result != 1) { + failf(data, + "could not load ASN1 client certificate from %s, " OSSL_PACKAGE + " error %s, " + "(no key found, wrong pass phrase, or wrong file format?)", + (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file), + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } + break; + case SSL_FILETYPE_ENGINE: +#if defined(USE_OPENSSL_ENGINE) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME) + { + /* Implicitly use pkcs11 engine if none was provided and the + * cert_file is a PKCS#11 URI */ + if(!data->state.engine) { + if(is_pkcs11_uri(cert_file)) { + if(ossl_set_engine(data, "pkcs11") != CURLE_OK) { + return 0; + } + } + } + + if(data->state.engine) { + const char *cmd_name = "LOAD_CERT_CTRL"; + struct { + const char *cert_id; + X509 *cert; + } params; + + params.cert_id = cert_file; + params.cert = NULL; + + /* Does the engine supports LOAD_CERT_CTRL ? */ + if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, + 0, (void *)cmd_name, NULL)) { + failf(data, "ssl engine does not support loading certificates"); + return 0; + } + + /* Load the certificate from the engine */ + if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name, + 0, ¶ms, NULL, 1)) { + failf(data, "ssl engine cannot load client cert with id" + " '%s' [%s]", cert_file, + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + + if(!params.cert) { + failf(data, "ssl engine didn't initialized the certificate " + "properly."); + return 0; + } + + if(SSL_CTX_use_certificate(ctx, params.cert) != 1) { + failf(data, "unable to set client certificate [%s]", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + X509_free(params.cert); /* we don't need the handle any more... */ + } + else { + failf(data, "crypto engine not set, can't load certificate"); + return 0; + } + } + break; +#else + failf(data, "file type ENG for certificate not implemented"); + return 0; +#endif + + case SSL_FILETYPE_PKCS12: + { + BIO *cert_bio = NULL; + PKCS12 *p12 = NULL; + EVP_PKEY *pri; + STACK_OF(X509) *ca = NULL; + if(cert_blob) { + cert_bio = BIO_new_mem_buf(cert_blob->data, (int)(cert_blob->len)); + if(!cert_bio) { + failf(data, + "BIO_new_mem_buf NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } + } + else { + cert_bio = BIO_new(BIO_s_file()); + if(!cert_bio) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } + + if(BIO_read_filename(cert_bio, cert_file) <= 0) { + failf(data, "could not open PKCS12 file '%s'", cert_file); + BIO_free(cert_bio); + return 0; + } + } + + p12 = d2i_PKCS12_bio(cert_bio, NULL); + BIO_free(cert_bio); + + if(!p12) { + failf(data, "error reading PKCS12 file '%s'", + cert_blob ? "(memory blob)" : cert_file); + return 0; + } + + PKCS12_PBE_add(); + + if(!PKCS12_parse(p12, key_passwd, &pri, &x509, + &ca)) { + failf(data, + "could not parse PKCS12 file, check password, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + PKCS12_free(p12); + return 0; + } + + PKCS12_free(p12); + + if(SSL_CTX_use_certificate(ctx, x509) != 1) { + failf(data, + "could not load PKCS12 client certificate, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + goto fail; + } + + if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { + failf(data, "unable to use private key from PKCS12 file '%s'", + cert_file); + goto fail; + } + + if(!SSL_CTX_check_private_key (ctx)) { + failf(data, "private key from PKCS12 file '%s' " + "does not match certificate in same file", cert_file); + goto fail; + } + /* Set Certificate Verification chain */ + if(ca) { + while(sk_X509_num(ca)) { + /* + * Note that sk_X509_pop() is used below to make sure the cert is + * removed from the stack properly before getting passed to + * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously + * we used sk_X509_value() instead, but then we'd clean it in the + * subsequent sk_X509_pop_free() call. + */ + X509 *x = sk_X509_pop(ca); + if(!SSL_CTX_add_client_CA(ctx, x)) { + X509_free(x); + failf(data, "cannot add certificate to client CA list"); + goto fail; + } + if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { + X509_free(x); + failf(data, "cannot add certificate to certificate chain"); + goto fail; + } + } + } + + cert_done = 1; +fail: + EVP_PKEY_free(pri); + X509_free(x509); + sk_X509_pop_free(ca, X509_free); + if(!cert_done) + return 0; /* failure! */ + break; + } + default: + failf(data, "not supported file type '%s' for certificate", cert_type); + return 0; + } + + if((!key_file) && (!key_blob)) { + key_file = cert_file; + key_blob = cert_blob; + } + else + file_type = do_file_type(key_type); + + switch(file_type) { + case SSL_FILETYPE_PEM: + if(cert_done) + break; + FALLTHROUGH(); + case SSL_FILETYPE_ASN1: + cert_use_result = key_blob ? + SSL_CTX_use_PrivateKey_blob(ctx, key_blob, file_type, key_passwd) : + SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type); + if(cert_use_result != 1) { + failf(data, "unable to set private key file: '%s' type %s", + key_file?key_file:"(memory blob)", key_type?key_type:"PEM"); + return 0; + } + break; + case SSL_FILETYPE_ENGINE: +#ifdef USE_OPENSSL_ENGINE + { + EVP_PKEY *priv_key = NULL; + + /* Implicitly use pkcs11 engine if none was provided and the + * key_file is a PKCS#11 URI */ + if(!data->state.engine) { + if(is_pkcs11_uri(key_file)) { + if(ossl_set_engine(data, "pkcs11") != CURLE_OK) { + return 0; + } + } + } + + if(data->state.engine) { + UI_METHOD *ui_method = + UI_create_method((char *)"curl user interface"); + if(!ui_method) { + failf(data, "unable do create " OSSL_PACKAGE + " user-interface method"); + return 0; + } + UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); + UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); + UI_method_set_reader(ui_method, ssl_ui_reader); + UI_method_set_writer(ui_method, ssl_ui_writer); + priv_key = ENGINE_load_private_key(data->state.engine, key_file, + ui_method, + key_passwd); + UI_destroy_method(ui_method); + if(!priv_key) { + failf(data, "failed to load private key from crypto engine"); + return 0; + } + if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { + failf(data, "unable to set private key"); + EVP_PKEY_free(priv_key); + return 0; + } + EVP_PKEY_free(priv_key); /* we don't need the handle any more... */ + } + else { + failf(data, "crypto engine not set, can't load private key"); + return 0; + } + } + break; +#else + failf(data, "file type ENG for private key not supported"); + return 0; +#endif + case SSL_FILETYPE_PKCS12: + if(!cert_done) { + failf(data, "file type P12 for private key not supported"); + return 0; + } + break; + default: + failf(data, "not supported file type for private key"); + return 0; + } + + ssl = SSL_new(ctx); + if(!ssl) { + failf(data, "unable to create an SSL structure"); + return 0; + } + + x509 = SSL_get_certificate(ssl); + + /* This version was provided by Evan Jordan and is supposed to not + leak memory as the previous version: */ + if(x509) { + EVP_PKEY *pktmp = X509_get_pubkey(x509); + EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl)); + EVP_PKEY_free(pktmp); + } + +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) && \ + !defined(OPENSSL_NO_DEPRECATED_3_0) + { + /* If RSA is used, don't check the private key if its flags indicate + * it doesn't support it. */ + EVP_PKEY *priv_key = SSL_get_privatekey(ssl); + int pktype; +#ifdef HAVE_OPAQUE_EVP_PKEY + pktype = EVP_PKEY_id(priv_key); +#else + pktype = priv_key->type; +#endif + if(pktype == EVP_PKEY_RSA) { + RSA *rsa = EVP_PKEY_get1_RSA(priv_key); + if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK) + check_privkey = FALSE; + RSA_free(rsa); /* Decrement reference count */ + } + } +#endif + + SSL_free(ssl); + + /* If we are using DSA, we can copy the parameters from + * the private key */ + + if(check_privkey == TRUE) { + /* Now we know that a key and cert have been set against + * the SSL context */ + if(!SSL_CTX_check_private_key(ctx)) { + failf(data, "Private key does not match the certificate public key"); + return 0; + } + } + } + return 1; +} + +CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data, SSL_CTX *ctx, + char *cert_file, + const struct curl_blob *cert_blob, + const char *cert_type, char *key_file, + const struct curl_blob *key_blob, + const char *key_type, char *key_passwd) +{ + int rv = cert_stuff(data, ctx, cert_file, cert_blob, cert_type, key_file, + key_blob, key_type, key_passwd); + if(rv != 1) { + return CURLE_SSL_CERTPROBLEM; + } + + return CURLE_OK; +} + +/* returns non-zero on failure */ +static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) +{ + BIO *bio_out = BIO_new(BIO_s_mem()); + BUF_MEM *biomem; + int rc; + + if(!bio_out) + return 1; /* alloc failed! */ + + rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC); + BIO_get_mem_ptr(bio_out, &biomem); + + if((size_t)biomem->length < size) + size = biomem->length; + else + size--; /* don't overwrite the buffer end */ + + memcpy(buf, biomem->data, size); + buf[size] = 0; + + BIO_free(bio_out); + + return !rc; +} + +/** + * Global SSL init + * + * @retval 0 error initializing SSL + * @retval 1 SSL initialized successfully + */ +static int ossl_init(void) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL) + const uint64_t flags = +#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN + /* not present in BoringSSL */ + OPENSSL_INIT_ENGINE_ALL_BUILTIN | +#endif +#ifdef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG + OPENSSL_INIT_NO_LOAD_CONFIG | +#else + OPENSSL_INIT_LOAD_CONFIG | +#endif + 0; + OPENSSL_init_ssl(flags, NULL); +#else + OPENSSL_load_builtin_modules(); + +#ifdef USE_OPENSSL_ENGINE + ENGINE_load_builtin_engines(); +#endif + +/* CONF_MFLAGS_DEFAULT_SECTION was introduced some time between 0.9.8b and + 0.9.8e */ +#ifndef CONF_MFLAGS_DEFAULT_SECTION +#define CONF_MFLAGS_DEFAULT_SECTION 0x0 +#endif + +#ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG + CONF_modules_load_file(NULL, NULL, + CONF_MFLAGS_DEFAULT_SECTION| + CONF_MFLAGS_IGNORE_MISSING_FILE); +#endif + + /* Let's get nice error messages */ + SSL_load_error_strings(); + + /* Init the global ciphers and digests */ + if(!SSLeay_add_ssl_algorithms()) + return 0; + + OpenSSL_add_all_algorithms(); +#endif + + Curl_tls_keylog_open(); + + return 1; +} + +/* Global cleanup */ +static void ossl_cleanup(void) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL) + /* OpenSSL 1.1 deprecates all these cleanup functions and + turns them into no-ops in OpenSSL 1.0 compatibility mode */ +#else + /* Free ciphers and digests lists */ + EVP_cleanup(); + +#ifdef USE_OPENSSL_ENGINE + /* Free engine list */ + ENGINE_cleanup(); +#endif + + /* Free OpenSSL error strings */ + ERR_free_strings(); + + /* Free thread local error state, destroying hash upon zero refcount */ +#ifdef HAVE_ERR_REMOVE_THREAD_STATE + ERR_remove_thread_state(NULL); +#else + ERR_remove_state(0); +#endif + + /* Free all memory allocated by all configuration modules */ + CONF_modules_free(); + +#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS + SSL_COMP_free_compression_methods(); +#endif +#endif + + Curl_tls_keylog_close(); +} + +/* Selects an OpenSSL crypto engine + */ +static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine) +{ +#ifdef USE_OPENSSL_ENGINE + ENGINE *e; + +#if OPENSSL_VERSION_NUMBER >= 0x00909000L + e = ENGINE_by_id(engine); +#else + /* avoid memory leak */ + for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { + const char *e_id = ENGINE_get_id(e); + if(!strcmp(engine, e_id)) + break; + } +#endif + + if(!e) { + failf(data, "SSL Engine '%s' not found", engine); + return CURLE_SSL_ENGINE_NOTFOUND; + } + + if(data->state.engine) { + ENGINE_finish(data->state.engine); + ENGINE_free(data->state.engine); + data->state.engine = NULL; + } + if(!ENGINE_init(e)) { + char buf[256]; + + ENGINE_free(e); + failf(data, "Failed to initialise SSL Engine '%s': %s", + engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); + return CURLE_SSL_ENGINE_INITFAILED; + } + data->state.engine = e; + return CURLE_OK; +#else + (void)engine; + failf(data, "SSL Engine not supported"); + return CURLE_SSL_ENGINE_NOTFOUND; +#endif +} + +/* Sets engine as default for all SSL operations + */ +static CURLcode ossl_set_engine_default(struct Curl_easy *data) +{ +#ifdef USE_OPENSSL_ENGINE + if(data->state.engine) { + if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { + infof(data, "set default crypto engine '%s'", + ENGINE_get_id(data->state.engine)); + } + else { + failf(data, "set default crypto engine '%s' failed", + ENGINE_get_id(data->state.engine)); + return CURLE_SSL_ENGINE_SETFAILED; + } + } +#else + (void) data; +#endif + return CURLE_OK; +} + +/* Return list of OpenSSL crypto engine names. + */ +static struct curl_slist *ossl_engines_list(struct Curl_easy *data) +{ + struct curl_slist *list = NULL; +#ifdef USE_OPENSSL_ENGINE + struct curl_slist *beg; + ENGINE *e; + + for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { + beg = curl_slist_append(list, ENGINE_get_id(e)); + if(!beg) { + curl_slist_free_all(list); + return NULL; + } + list = beg; + } +#endif + (void) data; + return list; +} + +static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + + (void)data; + DEBUGASSERT(backend); + + if(backend->handle) { + if(cf->next && cf->next->connected) { + char buf[1024]; + int nread, err; + long sslerr; + + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)SSL_read(backend->handle, buf, (int)sizeof(buf)); + ERR_clear_error(); + if(SSL_shutdown(backend->handle) == 1) { + CURL_TRC_CF(data, cf, "SSL shutdown finished"); + } + else { + nread = SSL_read(backend->handle, buf, (int)sizeof(buf)); + err = SSL_get_error(backend->handle, nread); + switch(err) { + case SSL_ERROR_NONE: /* this is not an error */ + case SSL_ERROR_ZERO_RETURN: /* no more data */ + CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server"); + break; + case SSL_ERROR_WANT_READ: + /* SSL has send its notify and now wants to read the reply + * from the server. We are not really interested in that. */ + CURL_TRC_CF(data, cf, "SSL shutdown sent"); + break; + case SSL_ERROR_WANT_WRITE: + CURL_TRC_CF(data, cf, "SSL shutdown send blocked"); + break; + default: + sslerr = ERR_get_error(); + CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d", + (sslerr ? + ossl_strerror(sslerr, buf, sizeof(buf)) : + SSL_ERROR_to_str(err)), + SOCKERRNO); + break; + } + } + + ERR_clear_error(); + SSL_set_connect_state(backend->handle); + } + + SSL_free(backend->handle); + backend->handle = NULL; + } + if(backend->ctx) { + SSL_CTX_free(backend->ctx); + backend->ctx = NULL; + backend->x509_store_setup = FALSE; + } + if(backend->bio_method) { + ossl_bio_cf_method_free(backend->bio_method); + backend->bio_method = NULL; + } +} + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +static int ossl_shutdown(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + int retval = 0; + struct ssl_connect_data *connssl = cf->ctx; + char buf[256]; /* We will use this for the OpenSSL error buffer, so it has + to be at least 256 bytes long. */ + unsigned long sslerror; + int nread; + int buffsize; + int err; + bool done = FALSE; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + int loop = 10; + + DEBUGASSERT(backend); + +#ifndef CURL_DISABLE_FTP + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + response. Thus we wait for a close notify alert from the server, but + we do not send one. Let's hope other servers do the same... */ + + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + (void)SSL_shutdown(backend->handle); +#endif + + if(backend->handle) { + buffsize = (int)sizeof(buf); + while(!done && loop--) { + int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), + SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + ERR_clear_error(); + + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + nread = SSL_read(backend->handle, buf, buffsize); + err = SSL_get_error(backend->handle, nread); + + switch(err) { + case SSL_ERROR_NONE: /* this is not an error */ + case SSL_ERROR_ZERO_RETURN: /* no more data */ + /* This is the expected response. There was no data but only + the close notify alert */ + done = TRUE; + break; + case SSL_ERROR_WANT_READ: + /* there's data pending, re-invoke SSL_read() */ + infof(data, "SSL_ERROR_WANT_READ"); + break; + case SSL_ERROR_WANT_WRITE: + /* SSL wants a write. Really odd. Let's bail out. */ + infof(data, "SSL_ERROR_WANT_WRITE"); + done = TRUE; + break; + default: + /* openssl/ssl.h says "look at error stack/return value/errno" */ + sslerror = ERR_get_error(); + failf(data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d", + (sslerror ? + ossl_strerror(sslerror, buf, sizeof(buf)) : + SSL_ERROR_to_str(err)), + SOCKERRNO); + done = TRUE; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = TRUE; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + retval = -1; + done = TRUE; + } + } /* while()-loop for the select() */ + + if(data->set.verbose) { +#ifdef HAVE_SSL_GET_SHUTDOWN + switch(SSL_get_shutdown(backend->handle)) { + case SSL_SENT_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN"); + break; + case SSL_RECEIVED_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN"); + break; + case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" + "SSL_RECEIVED__SHUTDOWN"); + break; + } +#endif + } + + SSL_free(backend->handle); + backend->handle = NULL; + } + return retval; +} + +static void ossl_session_free(void *ptr) +{ + /* free the ID */ + SSL_SESSION_free(ptr); +} + +/* + * This function is called when the 'data' struct is going away. Close + * down everything and free all resources! + */ +static void ossl_close_all(struct Curl_easy *data) +{ +#ifdef USE_OPENSSL_ENGINE + if(data->state.engine) { + ENGINE_finish(data->state.engine); + ENGINE_free(data->state.engine); + data->state.engine = NULL; + } +#else + (void)data; +#endif +#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \ + defined(HAVE_ERR_REMOVE_THREAD_STATE) + /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread + so we need to clean it here in case the thread will be killed. All OpenSSL + code should extract the error in association with the error so clearing + this queue here should be harmless at worst. */ + ERR_remove_thread_state(NULL); +#endif +} + +/* ====================================================== */ + +/* + * Match subjectAltName against the host name. + */ +static bool subj_alt_hostcheck(struct Curl_easy *data, + const char *match_pattern, + size_t matchlen, + const char *hostname, + size_t hostlen, + const char *dispname) +{ +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)dispname; + (void)data; +#endif + if(Curl_cert_hostcheck(match_pattern, matchlen, hostname, hostlen)) { + infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"", + dispname, match_pattern); + return TRUE; + } + return FALSE; +} + +/* Quote from RFC2818 section 3.1 "Server Identity" + + If a subjectAltName extension of type dNSName is present, that MUST + be used as the identity. Otherwise, the (most specific) Common Name + field in the Subject field of the certificate MUST be used. Although + the use of the Common Name is existing practice, it is deprecated and + Certification Authorities are encouraged to use the dNSName instead. + + Matching is performed using the matching rules specified by + [RFC2459]. If more than one identity of a given type is present in + the certificate (e.g., more than one dNSName name, a match in any one + of the set is considered acceptable.) Names may contain the wildcard + character * which is considered to match any single domain name + component or component fragment. E.g., *.a.com matches foo.a.com but + not bar.foo.a.com. f*.com matches foo.com but not bar.com. + + In some cases, the URI is specified as an IP address rather than a + hostname. In this case, the iPAddress subjectAltName must be present + in the certificate and must exactly match the IP in the URI. + + This function is now used from ngtcp2 (QUIC) as well. +*/ +CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + struct ssl_peer *peer, X509 *server_cert) +{ + bool matched = FALSE; + int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ + size_t addrlen = 0; + STACK_OF(GENERAL_NAME) *altnames; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + CURLcode result = CURLE_OK; + bool dNSName = FALSE; /* if a dNSName field exists in the cert */ + bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ + size_t hostlen; + + (void)conn; + hostlen = strlen(peer->hostname); + if(peer->is_ip_address) { +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip && + Curl_inet_pton(AF_INET6, peer->hostname, &addr)) { + target = GEN_IPADD; + addrlen = sizeof(struct in6_addr); + } + else +#endif + if(Curl_inet_pton(AF_INET, peer->hostname, &addr)) { + target = GEN_IPADD; + addrlen = sizeof(struct in_addr); + } + } + + /* get a "list" of alternative names */ + altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); + + if(altnames) { +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + size_t numalts; + size_t i; +#else + int numalts; + int i; +#endif + bool dnsmatched = FALSE; + bool ipmatched = FALSE; + + /* get amount of alternatives, RFC2459 claims there MUST be at least + one, but we don't depend on it... */ + numalts = sk_GENERAL_NAME_num(altnames); + + /* loop through all alternatives - until a dnsmatch */ + for(i = 0; (i < numalts) && !dnsmatched; i++) { + /* get a handle to alternative name number i */ + const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); + + if(check->type == GEN_DNS) + dNSName = TRUE; + else if(check->type == GEN_IPADD) + iPAddress = TRUE; + + /* only check alternatives of the same type the target is */ + if(check->type == target) { + /* get data and length */ + const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5); + size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5); + + switch(target) { + case GEN_DNS: /* name/pattern comparison */ + /* The OpenSSL man page explicitly says: "In general it cannot be + assumed that the data returned by ASN1_STRING_data() is null + terminated or does not contain embedded nulls." But also that + "The actual format of the data will depend on the actual string + type itself: for example for an IA5String the data will be ASCII" + + It has been however verified that in 0.9.6 and 0.9.7, IA5String + is always null-terminated. + */ + if((altlen == strlen(altptr)) && + /* if this isn't true, there was an embedded zero in the name + string and we cannot match it. */ + subj_alt_hostcheck(data, altptr, altlen, + peer->hostname, hostlen, + peer->dispname)) { + dnsmatched = TRUE; + } + break; + + case GEN_IPADD: /* IP address comparison */ + /* compare alternative IP address if the data chunk is the same size + our server IP address is */ + if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { + ipmatched = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's IP address!", + peer->dispname); + } + break; + } + } + } + GENERAL_NAMES_free(altnames); + + if(dnsmatched || ipmatched) + matched = TRUE; + } + + if(matched) + /* an alternative name matched */ + ; + else if(dNSName || iPAddress) { + infof(data, " subjectAltName does not match %s", peer->dispname); + failf(data, "SSL: no alternative certificate subject name matches " + "target host name '%s'", peer->dispname); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else { + /* we have to look to the last occurrence of a commonName in the + distinguished one to get the most significant one. */ + int i = -1; + unsigned char *peer_CN = NULL; + int peerlen = 0; + + /* The following is done because of a bug in 0.9.6b */ + X509_NAME *name = X509_get_subject_name(server_cert); + if(name) { + int j; + while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) + i = j; + } + + /* we have the name entry and we will now convert this to a string + that we can use for comparison. Doing this we support BMPstring, + UTF8, etc. */ + + if(i >= 0) { + ASN1_STRING *tmp = + X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); + + /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input + is already UTF-8 encoded. We check for this case and copy the raw + string manually to avoid the problem. This code can be made + conditional in the future when OpenSSL has been fixed. */ + if(tmp) { + if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { + peerlen = ASN1_STRING_length(tmp); + if(peerlen >= 0) { + peer_CN = OPENSSL_malloc(peerlen + 1); + if(peer_CN) { + memcpy(peer_CN, ASN1_STRING_get0_data(tmp), peerlen); + peer_CN[peerlen] = '\0'; + } + else + result = CURLE_OUT_OF_MEMORY; + } + } + else /* not a UTF8 name */ + peerlen = ASN1_STRING_to_UTF8(&peer_CN, tmp); + + if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != peerlen)) { + /* there was a terminating zero before the end of string, this + cannot match and we return failure! */ + failf(data, "SSL: illegal cert name field"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + } + } + + if(result) + /* error already detected, pass through */ + ; + else if(!peer_CN) { + failf(data, + "SSL: unable to obtain common name from peer certificate"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else if(!Curl_cert_hostcheck((const char *)peer_CN, + peerlen, peer->hostname, hostlen)) { + failf(data, "SSL: certificate subject name '%s' does not match " + "target host name '%s'", peer_CN, peer->dispname); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else { + infof(data, " common name: %s (matched)", peer_CN); + } + if(peer_CN) + OPENSSL_free(peer_CN); + } + + return result; +} + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) +static CURLcode verifystatus(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + int i, ocsp_status; +#if defined(OPENSSL_IS_AWSLC) + const uint8_t *status; +#else + unsigned char *status; +#endif + const unsigned char *p; + CURLcode result = CURLE_OK; + OCSP_RESPONSE *rsp = NULL; + OCSP_BASICRESP *br = NULL; + X509_STORE *st = NULL; + STACK_OF(X509) *ch = NULL; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + X509 *cert; + OCSP_CERTID *id = NULL; + int cert_status, crl_reason; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + int ret; + long len; + + DEBUGASSERT(backend); + + len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status); + + if(!status) { + failf(data, "No OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + p = status; + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if(!rsp) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ocsp_status = OCSP_response_status(rsp); + if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + failf(data, "Invalid OCSP response status: %s (%d)", + OCSP_response_status_str(ocsp_status), ocsp_status); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + br = OCSP_response_get1_basic(rsp); + if(!br) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ch = SSL_get_peer_cert_chain(backend->handle); + if(!ch) { + failf(data, "Could not get peer certificate chain"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + st = SSL_CTX_get_cert_store(backend->ctx); + +#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER <= 0x2040200fL)) + /* The authorized responder cert in the OCSP response MUST be signed by the + peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, + no problem, but if it's an intermediate cert OpenSSL has a bug where it + expects this issuer to be present in the chain embedded in the OCSP + response. So we add it if necessary. */ + + /* First make sure the peer cert chain includes both a peer and an issuer, + and the OCSP response contains a responder cert. */ + if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { + X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); + + /* Find issuer of responder cert and add it to the OCSP response chain */ + for(i = 0; i < sk_X509_num(ch); i++) { + X509 *issuer = sk_X509_value(ch, i); + if(X509_check_issued(issuer, responder) == X509_V_OK) { + if(!OCSP_basic_add1_cert(br, issuer)) { + failf(data, "Could not add issuer cert to OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + } + } +#endif + + if(OCSP_basic_verify(br, ch, st, 0) <= 0) { + failf(data, "OCSP response verification failed"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + /* Compute the certificate's ID */ + cert = SSL_get1_peer_certificate(backend->handle); + if(!cert) { + failf(data, "Error getting peer certificate"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + for(i = 0; i < (int)sk_X509_num(ch); i++) { + X509 *issuer = sk_X509_value(ch, i); + if(X509_check_issued(issuer, cert) == X509_V_OK) { + id = OCSP_cert_to_id(EVP_sha1(), cert, issuer); + break; + } + } + X509_free(cert); + + if(!id) { + failf(data, "Error computing OCSP ID"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + /* Find the single OCSP response corresponding to the certificate ID */ + ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev, + &thisupd, &nextupd); + OCSP_CERTID_free(id); + if(ret != 1) { + failf(data, "Could not find certificate ID in OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + /* Validate the corresponding single OCSP response */ + if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { + failf(data, "OCSP response has expired"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + infof(data, "SSL certificate status: %s (%d)", + OCSP_cert_status_str(cert_status), cert_status); + + switch(cert_status) { + case V_OCSP_CERTSTATUS_GOOD: + break; + + case V_OCSP_CERTSTATUS_REVOKED: + result = CURLE_SSL_INVALIDCERTSTATUS; + failf(data, "SSL certificate revocation reason: %s (%d)", + OCSP_crl_reason_str(crl_reason), crl_reason); + goto end; + + case V_OCSP_CERTSTATUS_UNKNOWN: + default: + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + +end: + if(br) + OCSP_BASICRESP_free(br); + OCSP_RESPONSE_free(rsp); + + return result; +} +#endif + +#endif /* USE_OPENSSL */ + +/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions + and thus this cannot be done there. */ +#ifdef SSL_CTRL_SET_MSG_CALLBACK + +static const char *ssl_msg_type(int ssl_ver, int msg) +{ +#ifdef SSL2_VERSION_MAJOR + if(ssl_ver == SSL2_VERSION_MAJOR) { + switch(msg) { + case SSL2_MT_ERROR: + return "Error"; + case SSL2_MT_CLIENT_HELLO: + return "Client hello"; + case SSL2_MT_CLIENT_MASTER_KEY: + return "Client key"; + case SSL2_MT_CLIENT_FINISHED: + return "Client finished"; + case SSL2_MT_SERVER_HELLO: + return "Server hello"; + case SSL2_MT_SERVER_VERIFY: + return "Server verify"; + case SSL2_MT_SERVER_FINISHED: + return "Server finished"; + case SSL2_MT_REQUEST_CERTIFICATE: + return "Request CERT"; + case SSL2_MT_CLIENT_CERTIFICATE: + return "Client CERT"; + } + } + else +#endif + if(ssl_ver == SSL3_VERSION_MAJOR) { + switch(msg) { + case SSL3_MT_HELLO_REQUEST: + return "Hello request"; + case SSL3_MT_CLIENT_HELLO: + return "Client hello"; + case SSL3_MT_SERVER_HELLO: + return "Server hello"; +#ifdef SSL3_MT_NEWSESSION_TICKET + case SSL3_MT_NEWSESSION_TICKET: + return "Newsession Ticket"; +#endif + case SSL3_MT_CERTIFICATE: + return "Certificate"; + case SSL3_MT_SERVER_KEY_EXCHANGE: + return "Server key exchange"; + case SSL3_MT_CLIENT_KEY_EXCHANGE: + return "Client key exchange"; + case SSL3_MT_CERTIFICATE_REQUEST: + return "Request CERT"; + case SSL3_MT_SERVER_DONE: + return "Server finished"; + case SSL3_MT_CERTIFICATE_VERIFY: + return "CERT verify"; + case SSL3_MT_FINISHED: + return "Finished"; +#ifdef SSL3_MT_CERTIFICATE_STATUS + case SSL3_MT_CERTIFICATE_STATUS: + return "Certificate Status"; +#endif +#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS + case SSL3_MT_ENCRYPTED_EXTENSIONS: + return "Encrypted Extensions"; +#endif +#ifdef SSL3_MT_SUPPLEMENTAL_DATA + case SSL3_MT_SUPPLEMENTAL_DATA: + return "Supplemental data"; +#endif +#ifdef SSL3_MT_END_OF_EARLY_DATA + case SSL3_MT_END_OF_EARLY_DATA: + return "End of early data"; +#endif +#ifdef SSL3_MT_KEY_UPDATE + case SSL3_MT_KEY_UPDATE: + return "Key update"; +#endif +#ifdef SSL3_MT_NEXT_PROTO + case SSL3_MT_NEXT_PROTO: + return "Next protocol"; +#endif +#ifdef SSL3_MT_MESSAGE_HASH + case SSL3_MT_MESSAGE_HASH: + return "Message hash"; +#endif + } + } + return "Unknown"; +} + +static const char *tls_rt_type(int type) +{ + switch(type) { +#ifdef SSL3_RT_HEADER + case SSL3_RT_HEADER: + return "TLS header"; +#endif + case SSL3_RT_CHANGE_CIPHER_SPEC: + return "TLS change cipher"; + case SSL3_RT_ALERT: + return "TLS alert"; + case SSL3_RT_HANDSHAKE: + return "TLS handshake"; + case SSL3_RT_APPLICATION_DATA: + return "TLS app data"; + default: + return "TLS Unknown"; + } +} + +/* + * Our callback from the SSL/TLS layers. + */ +static void ossl_trace(int direction, int ssl_ver, int content_type, + const void *buf, size_t len, SSL *ssl, + void *userp) +{ + const char *verstr = "???"; + struct Curl_cfilter *cf = userp; + struct Curl_easy *data = NULL; + char unknown[32]; + + if(!cf) + return; + data = CF_DATA_CURRENT(cf); + if(!data || !data->set.fdebug || (direction && direction != 1)) + return; + + switch(ssl_ver) { +#ifdef SSL2_VERSION /* removed in recent versions */ + case SSL2_VERSION: + verstr = "SSLv2"; + break; +#endif +#ifdef SSL3_VERSION + case SSL3_VERSION: + verstr = "SSLv3"; + break; +#endif + case TLS1_VERSION: + verstr = "TLSv1.0"; + break; +#ifdef TLS1_1_VERSION + case TLS1_1_VERSION: + verstr = "TLSv1.1"; + break; +#endif +#ifdef TLS1_2_VERSION + case TLS1_2_VERSION: + verstr = "TLSv1.2"; + break; +#endif +#ifdef TLS1_3_VERSION + case TLS1_3_VERSION: + verstr = "TLSv1.3"; + break; +#endif + case 0: + break; + default: + msnprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); + verstr = unknown; + break; + } + + /* Log progress for interesting records only (like Handshake or Alert), skip + * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0). + * For TLS 1.3, skip notification of the decrypted inner Content-Type. + */ + if(ssl_ver +#ifdef SSL3_RT_HEADER + && content_type != SSL3_RT_HEADER +#endif +#ifdef SSL3_RT_INNER_CONTENT_TYPE + && content_type != SSL3_RT_INNER_CONTENT_TYPE +#endif + ) { + const char *msg_name, *tls_rt_name; + char ssl_buf[1024]; + int msg_type, txt_len; + + /* the info given when the version is zero is not that useful for us */ + + ssl_ver >>= 8; /* check the upper 8 bits only below */ + + /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL + * always pass-up content-type as 0. But the interesting message-type + * is at 'buf[0]'. + */ + if(ssl_ver == SSL3_VERSION_MAJOR && content_type) + tls_rt_name = tls_rt_type(content_type); + else + tls_rt_name = ""; + + if(content_type == SSL3_RT_CHANGE_CIPHER_SPEC) { + msg_type = *(char *)buf; + msg_name = "Change cipher spec"; + } + else if(content_type == SSL3_RT_ALERT) { + msg_type = (((char *)buf)[0] << 8) + ((char *)buf)[1]; + msg_name = SSL_alert_desc_string_long(msg_type); + } + else { + msg_type = *(char *)buf; + msg_name = ssl_msg_type(ssl_ver, msg_type); + } + + txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), + "%s (%s), %s, %s (%d):\n", + verstr, direction?"OUT":"IN", + tls_rt_name, msg_name, msg_type); + if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) { + Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len); + } + } + + Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : + CURLINFO_SSL_DATA_IN, (char *)buf, len); + (void) ssl; +} +#endif + +#ifdef USE_OPENSSL +/* ====================================================== */ + +/* Check for OpenSSL 1.0.2 which has ALPN support. */ +#undef HAS_ALPN +#if OPENSSL_VERSION_NUMBER >= 0x10002000L \ + && !defined(OPENSSL_NO_TLSEXT) +# define HAS_ALPN 1 +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ +static CURLcode +ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + /* first, TLS min version... */ + long curl_ssl_version_min = conn_config->version; + long curl_ssl_version_max; + + /* convert curl min SSL version option to OpenSSL constant */ +#if (defined(OPENSSL_IS_BORINGSSL) || \ + defined(OPENSSL_IS_AWSLC) || \ + defined(LIBRESSL_VERSION_NUMBER)) + uint16_t ossl_ssl_version_min = 0; + uint16_t ossl_ssl_version_max = 0; +#else + long ossl_ssl_version_min = 0; + long ossl_ssl_version_max = 0; +#endif + switch(curl_ssl_version_min) { + case CURL_SSLVERSION_TLSv1: /* TLS 1.x */ + case CURL_SSLVERSION_TLSv1_0: + ossl_ssl_version_min = TLS1_VERSION; + break; + case CURL_SSLVERSION_TLSv1_1: + ossl_ssl_version_min = TLS1_1_VERSION; + break; + case CURL_SSLVERSION_TLSv1_2: + ossl_ssl_version_min = TLS1_2_VERSION; + break; + case CURL_SSLVERSION_TLSv1_3: +#ifdef TLS1_3_VERSION + ossl_ssl_version_min = TLS1_3_VERSION; + break; +#else + return CURLE_NOT_BUILT_IN; +#endif + } + + /* CURL_SSLVERSION_DEFAULT means that no option was selected. + We don't want to pass 0 to SSL_CTX_set_min_proto_version as + it would enable all versions down to the lowest supported by + the library. + So we skip this, and stay with the library default + */ + if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) { + if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) { + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* ... then, TLS max version */ + curl_ssl_version_max = conn_config->version_max; + + /* convert curl max SSL version option to OpenSSL constant */ + switch(curl_ssl_version_max) { + case CURL_SSLVERSION_MAX_TLSv1_0: + ossl_ssl_version_max = TLS1_VERSION; + break; + case CURL_SSLVERSION_MAX_TLSv1_1: + ossl_ssl_version_max = TLS1_1_VERSION; + break; + case CURL_SSLVERSION_MAX_TLSv1_2: + ossl_ssl_version_max = TLS1_2_VERSION; + break; +#ifdef TLS1_3_VERSION + case CURL_SSLVERSION_MAX_TLSv1_3: + ossl_ssl_version_max = TLS1_3_VERSION; + break; +#endif + case CURL_SSLVERSION_MAX_NONE: /* none selected */ + case CURL_SSLVERSION_MAX_DEFAULT: /* max selected */ + default: + /* SSL_CTX_set_max_proto_version states that: + setting the maximum to 0 will enable + protocol versions up to the highest version + supported by the library */ + ossl_ssl_version_max = 0; + break; + } + + if(!SSL_CTX_set_max_proto_version(ctx, ossl_ssl_version_max)) { + return CURLE_SSL_CONNECT_ERROR; + } + + return CURLE_OK; +} +#endif + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +typedef uint32_t ctx_option_t; +#elif OPENSSL_VERSION_NUMBER >= 0x30000000L +typedef uint64_t ctx_option_t; +#else +typedef long ctx_option_t; +#endif + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */ +static CURLcode +ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + long ssl_version = conn_config->version; + long ssl_version_max = conn_config->version_max; + + (void) data; /* In case it's unused. */ + + switch(ssl_version) { + case CURL_SSLVERSION_TLSv1_3: +#ifdef TLS1_3_VERSION + { + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + DEBUGASSERT(backend); + SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION); + *ctx_options |= SSL_OP_NO_TLSv1_2; + } +#else + (void)ctx_options; + failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); + return CURLE_NOT_BUILT_IN; +#endif + FALLTHROUGH(); + case CURL_SSLVERSION_TLSv1_2: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1_1; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); + return CURLE_NOT_BUILT_IN; +#endif + FALLTHROUGH(); + case CURL_SSLVERSION_TLSv1_1: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); + return CURLE_NOT_BUILT_IN; +#endif + FALLTHROUGH(); + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1: + break; + } + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_TLSv1_0: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1_1; +#endif + FALLTHROUGH(); + case CURL_SSLVERSION_MAX_TLSv1_1: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1_2; +#endif + FALLTHROUGH(); + case CURL_SSLVERSION_MAX_TLSv1_2: +#ifdef TLS1_3_VERSION + *ctx_options |= SSL_OP_NO_TLSv1_3; +#endif + break; + case CURL_SSLVERSION_MAX_TLSv1_3: +#ifdef TLS1_3_VERSION + break; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); + return CURLE_NOT_BUILT_IN; +#endif + } + return CURLE_OK; +} +#endif + +/* The "new session" callback must return zero if the session can be removed + * or non-zero if the session has been put into the session cache. + */ +static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) +{ + int res = 0; + struct Curl_easy *data; + struct Curl_cfilter *cf; + const struct ssl_config_data *config; + struct ssl_connect_data *connssl; + bool isproxy; + + cf = (struct Curl_cfilter*) SSL_get_app_data(ssl); + connssl = cf? cf->ctx : NULL; + data = connssl? CF_DATA_CURRENT(cf) : NULL; + /* The sockindex has been stored as a pointer to an array element */ + if(!cf || !data) + return 0; + + isproxy = Curl_ssl_cf_is_proxy(cf); + + config = Curl_ssl_cf_get_config(cf, data); + if(config->primary.sessionid) { + bool incache; + bool added = FALSE; + void *old_ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(data); + if(isproxy) + incache = FALSE; + else + incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing"); + Curl_ssl_delsessionid(data, old_ssl_sessionid); + incache = FALSE; + } + } + + if(!incache) { + if(!Curl_ssl_addsessionid(cf, data, ssl_sessionid, + 0 /* unknown size */, &added)) { + if(added) { + /* the session has been put into the session cache */ + res = 1; + } + } + else + failf(data, "failed to store ssl session"); + } + Curl_ssl_sessionid_unlock(data); + } + + return res; +} + +static CURLcode load_cacert_from_memory(X509_STORE *store, + const struct curl_blob *ca_info_blob) +{ + /* these need to be freed at the end */ + BIO *cbio = NULL; + STACK_OF(X509_INFO) *inf = NULL; + + /* everything else is just a reference */ + int i, count = 0; + X509_INFO *itmp = NULL; + + if(ca_info_blob->len > (size_t)INT_MAX) + return CURLE_SSL_CACERT_BADFILE; + + cbio = BIO_new_mem_buf(ca_info_blob->data, (int)ca_info_blob->len); + if(!cbio) + return CURLE_OUT_OF_MEMORY; + + inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL); + if(!inf) { + BIO_free(cbio); + return CURLE_SSL_CACERT_BADFILE; + } + + /* add each entry from PEM file to x509_store */ + for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) { + itmp = sk_X509_INFO_value(inf, i); + if(itmp->x509) { + if(X509_STORE_add_cert(store, itmp->x509)) { + ++count; + } + else { + /* set count to 0 to return an error */ + count = 0; + break; + } + } + if(itmp->crl) { + if(X509_STORE_add_crl(store, itmp->crl)) { + ++count; + } + else { + /* set count to 0 to return an error */ + count = 0; + break; + } + } + } + + sk_X509_INFO_pop_free(inf, X509_INFO_free); + BIO_free(cbio); + + /* if we didn't end up importing anything, treat that as an error */ + return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE; +} + +#if defined(USE_WIN32_CRYPTO) +static CURLcode import_windows_cert_store(struct Curl_easy *data, + const char *name, + X509_STORE *store, + bool *imported) +{ + CURLcode result = CURLE_OK; + HCERTSTORE hStore; + + *imported = false; + + hStore = CertOpenSystemStoreA(0, name); + if(hStore) { + PCCERT_CONTEXT pContext = NULL; + /* The array of enhanced key usage OIDs will vary per certificate and + is declared outside of the loop so that rather than malloc/free each + iteration we can grow it with realloc, when necessary. */ + CERT_ENHKEY_USAGE *enhkey_usage = NULL; + DWORD enhkey_usage_size = 0; + + /* This loop makes a best effort to import all valid certificates from + the MS root store. If a certificate cannot be imported it is + skipped. 'result' is used to store only hard-fail conditions (such + as out of memory) that cause an early break. */ + result = CURLE_OK; + for(;;) { + X509 *x509; + FILETIME now; + BYTE key_usage[2]; + DWORD req_size; + const unsigned char *encoded_cert; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + char cert_name[256]; +#endif + + pContext = CertEnumCertificatesInStore(hStore, pContext); + if(!pContext) + break; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, + NULL, cert_name, sizeof(cert_name))) { + strcpy(cert_name, "Unknown"); + } + infof(data, "SSL: Checking cert \"%s\"", cert_name); +#endif + encoded_cert = (const unsigned char *)pContext->pbCertEncoded; + if(!encoded_cert) + continue; + + GetSystemTimeAsFileTime(&now); + if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || + CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) + continue; + + /* If key usage exists check for signing attribute */ + if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, + pContext->pCertInfo, + key_usage, sizeof(key_usage))) { + if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + continue; + } + else if(GetLastError()) + continue; + + /* If enhanced key usage exists check for server auth attribute. + * + * Note "In a Microsoft environment, a certificate might also have + * EKU extended properties that specify valid uses for the + * certificate." The call below checks both, and behavior varies + * depending on what is found. For more details see + * CertGetEnhancedKeyUsage doc. + */ + if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { + if(req_size && req_size > enhkey_usage_size) { + void *tmp = realloc(enhkey_usage, req_size); + + if(!tmp) { + failf(data, "SSL: Out of memory allocating for OID list"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; + enhkey_usage_size = req_size; + } + + if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { + if(!enhkey_usage->cUsageIdentifier) { + /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate + is good for all uses. If it returns zero, the certificate + has no valid uses." */ + if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND) + continue; + } + else { + DWORD i; + bool found = false; + + for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { + if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, + enhkey_usage->rgpszUsageIdentifier[i])) { + found = true; + break; + } + } + + if(!found) + continue; + } + } + else + continue; + } + else + continue; + + x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if(!x509) + continue; + + /* Try to import the certificate. This may fail for legitimate + reasons such as duplicate certificate, which is allowed by MS but + not OpenSSL. */ + if(X509_STORE_add_cert(store, x509) == 1) { +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "SSL: Imported cert \"%s\"", cert_name); +#endif + *imported = true; + } + X509_free(x509); + } + + free(enhkey_usage); + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + if(result) + return result; + } + + return result; +} +#endif + +static CURLcode populate_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + X509_STORE *store) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + CURLcode result = CURLE_OK; + X509_LOOKUP *lookup = NULL; + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : conn_config->CAfile); + const char * const ssl_capath = conn_config->CApath; + const char * const ssl_crlfile = ssl_config->primary.CRLfile; + const bool verifypeer = conn_config->verifypeer; + bool imported_native_ca = false; + bool imported_ca_info_blob = false; + + CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d", + ssl_cafile? ssl_cafile : "none", !!ca_info_blob); + if(!store) + return CURLE_OUT_OF_MEMORY; + + if(verifypeer) { +#if defined(USE_WIN32_CRYPTO) + /* Import certificates from the Windows root certificate store if + requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://datatracker.ietf.org/doc/html/rfc5280 */ + if(ssl_config->native_ca_store) { + const char *storeNames[] = { + "ROOT", /* Trusted Root Certification Authorities */ + "CA" /* Intermediate Certification Authorities */ + }; + size_t i; + for(i = 0; i < ARRAYSIZE(storeNames); ++i) { + bool imported = false; + result = import_windows_cert_store(data, storeNames[i], store, + &imported); + if(result) + return result; + if(imported) { + infof(data, "successfully imported Windows %s store", storeNames[i]); + imported_native_ca = true; + } + else + infof(data, "error importing Windows %s store, continuing anyway", + storeNames[i]); + } + } +#endif + if(ca_info_blob) { + result = load_cacert_from_memory(store, ca_info_blob); + if(result) { + failf(data, "error importing CA certificate blob"); + return result; + } + else { + imported_ca_info_blob = true; + infof(data, "successfully imported CA certificate blob"); + } + } + + if(ssl_cafile || ssl_capath) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + if(ssl_cafile && !X509_STORE_load_file(store, ssl_cafile)) { + if(!imported_native_ca && !imported_ca_info_blob) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "error setting certificate file, continuing anyway"); + } + if(ssl_capath && !X509_STORE_load_path(store, ssl_capath)) { + if(!imported_native_ca && !imported_ca_info_blob) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "error setting certificate path, continuing anyway"); + } +#else + /* tell OpenSSL where to find CA certificates that are used to verify the + server's certificate. */ + if(!X509_STORE_load_locations(store, ssl_cafile, ssl_capath)) { + if(!imported_native_ca && !imported_ca_info_blob) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + infof(data, "error setting certificate verify locations," + " continuing anyway"); + } + } +#endif + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } + +#ifdef CURL_CA_FALLBACK + if(!ssl_cafile && !ssl_capath && + !imported_native_ca && !imported_ca_info_blob) { + /* verifying the peer without any CA certificates won't + work so use openssl's built-in default as fallback */ + X509_STORE_set_default_paths(store); + } +#endif + } + + if(ssl_crlfile) { + /* tell OpenSSL where to find CRL file that is used to check certificate + * revocation */ + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + if(!lookup || + (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", ssl_crlfile); + return CURLE_SSL_CRL_BADFILE; + } + /* Everything is fine. */ + infof(data, "successfully loaded CRL file:"); + X509_STORE_set_flags(store, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + infof(data, " CRLfile: %s", ssl_crlfile); + } + + if(verifypeer) { + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. Newer versions of + OpenSSL do alternate chain checking by default but we do not know how to + determine that in a reliable manner. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) + X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST); +#endif +#ifdef X509_V_FLAG_PARTIAL_CHAIN + if(!ssl_config->no_partialchain && !ssl_crlfile) { + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with a CRL check. + */ + X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN); + } +#endif + } + + return result; +} + +#if defined(HAVE_SSL_X509_STORE_SHARE) +static bool cached_x509_store_expired(const struct Curl_easy *data, + const struct multi_ssl_backend_data *mb) +{ + const struct ssl_general_config *cfg = &data->set.general_ssl; + struct curltime now = Curl_now(); + timediff_t elapsed_ms = Curl_timediff(now, mb->time); + timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000; + + if(timeout_ms < 0) + return false; + + return elapsed_ms >= timeout_ms; +} + +static bool cached_x509_store_different( + struct Curl_cfilter *cf, + const struct multi_ssl_backend_data *mb) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!mb->CAfile || !conn_config->CAfile) + return mb->CAfile != conn_config->CAfile; + + return strcmp(mb->CAfile, conn_config->CAfile); +} + +static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi; + X509_STORE *store = NULL; + + DEBUGASSERT(multi); + if(multi && + multi->ssl_backend_data && + multi->ssl_backend_data->store && + !cached_x509_store_expired(data, multi->ssl_backend_data) && + !cached_x509_store_different(cf, multi->ssl_backend_data)) { + store = multi->ssl_backend_data->store; + } + + return store; +} + +static void set_cached_x509_store(struct Curl_cfilter *cf, + const struct Curl_easy *data, + X509_STORE *store) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi; + struct multi_ssl_backend_data *mbackend; + + DEBUGASSERT(multi); + if(!multi) + return; + + if(!multi->ssl_backend_data) { + multi->ssl_backend_data = calloc(1, sizeof(struct multi_ssl_backend_data)); + if(!multi->ssl_backend_data) + return; + } + + mbackend = multi->ssl_backend_data; + + if(X509_STORE_up_ref(store)) { + char *CAfile = NULL; + + if(conn_config->CAfile) { + CAfile = strdup(conn_config->CAfile); + if(!CAfile) { + X509_STORE_free(store); + return; + } + } + + if(mbackend->store) { + X509_STORE_free(mbackend->store); + free(mbackend->CAfile); + } + + mbackend->time = Curl_now(); + mbackend->store = store; + mbackend->CAfile = CAfile; + } +} + +CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + SSL_CTX *ssl_ctx) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + CURLcode result = CURLE_OK; + X509_STORE *cached_store; + bool cache_criteria_met; + + /* Consider the X509 store cacheable if it comes exclusively from a CAfile, + or no source is provided and we are falling back to openssl's built-in + default. */ + cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) && + conn_config->verifypeer && + !conn_config->CApath && + !conn_config->ca_info_blob && + !ssl_config->primary.CRLfile && + !ssl_config->native_ca_store; + + cached_store = get_cached_x509_store(cf, data); + if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) { + SSL_CTX_set_cert_store(ssl_ctx, cached_store); + } + else { + X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); + + result = populate_x509_store(cf, data, store); + if(result == CURLE_OK && cache_criteria_met) { + set_cached_x509_store(cf, data, store); + } + } + + return result; +} +#else /* HAVE_SSL_X509_STORE_SHARE */ +CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + SSL_CTX *ssl_ctx) +{ + X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); + + return populate_x509_store(cf, data, store); +} +#endif /* HAVE_SSL_X509_STORE_SHARE */ + +static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + char *ciphers; + SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; + struct ssl_connect_data *connssl = cf->ctx; + ctx_option_t ctx_options = 0; + void *ssl_sessionid = NULL; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + BIO *bio; + const long int ssl_version = conn_config->version; + char * const ssl_cert = ssl_config->primary.clientcert; + const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; + const char * const ssl_cert_type = ssl_config->cert_type; + const bool verifypeer = conn_config->verifypeer; + char error_buffer[256]; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); + DEBUGASSERT(backend); + + /* Make funny stuff to get random input */ + result = ossl_seed(data); + if(result) + return result; + + ssl_config->certverifyresult = !X509_V_OK; + + /* check to see if we've been told to use an explicit SSL/TLS version */ + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + /* it will be handled later with the context options */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + req_method = TLS_client_method(); +#else + req_method = SSLv23_client_method(); +#endif + break; + case CURL_SSLVERSION_SSLv2: + failf(data, "No SSLv2 support"); + return CURLE_NOT_BUILT_IN; + case CURL_SSLVERSION_SSLv3: + failf(data, "No SSLv3 support"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(backend->ctx) { + /* This happens when an error was encountered before in this + * step and we are called to do it again. Get rid of any leftover + * from the previous call. */ + ossl_close(cf, data); + } + backend->ctx = SSL_CTX_new(req_method); + + if(!backend->ctx) { + failf(data, "SSL: couldn't create a context: %s", + ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); + return CURLE_OUT_OF_MEMORY; + } + +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + +#ifdef SSL_CTRL_SET_MSG_CALLBACK + if(data->set.fdebug && data->set.verbose) { + /* the SSL trace callback is only used for verbose logging */ + SSL_CTX_set_msg_callback(backend->ctx, ossl_trace); + SSL_CTX_set_msg_callback_arg(backend->ctx, cf); + } +#endif + + /* OpenSSL contains code to work around lots of bugs and flaws in various + SSL-implementations. SSL_CTX_set_options() is used to enabled those + work-arounds. The man page for this option states that SSL_OP_ALL enables + all the work-arounds and that "It is usually safe to use SSL_OP_ALL to + enable the bug workaround options if compatibility with somewhat broken + implementations is desired." + + The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to + disable "rfc4507bis session ticket support". rfc4507bis was later turned + into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077 + + The enabled extension concerns the session management. I wonder how often + libcurl stops a connection and then resumes a TLS session. Also, sending + the session data is some overhead. I suggest that you just use your + proposed patch (which explicitly disables TICKET). + + If someone writes an application with libcurl and OpenSSL who wants to + enable the feature, one can do this in the SSL callback. + + SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper + interoperability with web server Netscape Enterprise Server 2.0.1 which + was released back in 1996. + + Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has + become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate + CVE-2010-4180 when using previous OpenSSL versions we no longer enable + this option regardless of OpenSSL version and SSL_OP_ALL definition. + + OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability + (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to + SSL_OP_ALL that _disables_ that work-around despite the fact that + SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to + keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit + must not be set. + */ + + ctx_options = SSL_OP_ALL; + +#ifdef SSL_OP_NO_TICKET + ctx_options |= SSL_OP_NO_TICKET; +#endif + +#ifdef SSL_OP_NO_COMPRESSION + ctx_options |= SSL_OP_NO_COMPRESSION; +#endif + +#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + /* mitigate CVE-2010-4180 */ + ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; +#endif + +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + /* unless the user explicitly asks to allow the protocol vulnerability we + use the work-around */ + if(!ssl_config->enable_beast) + ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +#endif + + switch(ssl_version) { + case CURL_SSLVERSION_SSLv2: + case CURL_SSLVERSION_SSLv3: + return CURLE_NOT_BUILT_IN; + + /* "--tlsv" options mean TLS >= version */ + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_0: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_1: /* TLS >= version 1.1 */ + case CURL_SSLVERSION_TLSv1_2: /* TLS >= version 1.2 */ + case CURL_SSLVERSION_TLSv1_3: /* TLS >= version 1.3 */ + /* asking for any TLS version as the minimum, means no SSL versions + allowed */ + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ + result = ossl_set_ssl_version_min_max(cf, backend->ctx); +#else + result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data); +#endif + if(result != CURLE_OK) + return result; + break; + + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + SSL_CTX_set_options(backend->ctx, ctx_options); + +#ifdef HAS_ALPN + if(connssl->alpn) { + struct alpn_proto_buf proto; + + result = Curl_alpn_to_proto_buf(&proto, connssl->alpn); + if(result || + SSL_CTX_set_alpn_protos(backend->ctx, proto.data, proto.len)) { + failf(data, "Error setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } +#endif + + if(ssl_cert || ssl_cert_blob || ssl_cert_type) { + if(!result && + !cert_stuff(data, backend->ctx, + ssl_cert, ssl_cert_blob, ssl_cert_type, + ssl_config->key, ssl_config->key_blob, + ssl_config->key_type, ssl_config->key_passwd)) + result = CURLE_SSL_CERTPROBLEM; + if(result) + /* failf() is already done in cert_stuff() */ + return result; + } + + ciphers = conn_config->cipher_list; + if(!ciphers) + ciphers = (char *)DEFAULT_CIPHER_SELECTION; + if(ciphers) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s", ciphers); + } + +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + { + char *ciphers13 = conn_config->cipher_list13; + if(ciphers13) { + if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) { + failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); + return CURLE_SSL_CIPHER; + } + infof(data, "TLS 1.3 cipher selection: %s", ciphers13); + } + } +#endif + +#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH + /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ + SSL_CTX_set_post_handshake_auth(backend->ctx, 1); +#endif + +#ifdef HAVE_SSL_CTX_SET_EC_CURVES + { + char *curves = conn_config->curves; + if(curves) { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } +#endif + +#ifdef USE_OPENSSL_SRP + if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) { + char * const ssl_username = ssl_config->primary.username; + char * const ssl_password = ssl_config->primary.password; + infof(data, "Using TLS-SRP username: %s", ssl_username); + + if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CTX_set_srp_password(backend->ctx, ssl_password)) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!conn_config->cipher_list) { + infof(data, "Setting cipher list SRP"); + + if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { + failf(data, "failed setting SRP cipher list"); + return CURLE_SSL_CIPHER; + } + } + } +#endif + + /* OpenSSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + SSL_CTX_set_verify(backend->ctx, + verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); + + /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ +#ifdef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback); + } +#endif + + /* Enable the session cache because it's a prerequisite for the "new session" + * callback. Use the "external storage" mode to prevent OpenSSL from creating + * an internal session cache. + */ + SSL_CTX_set_session_cache_mode(backend->ctx, + SSL_SESS_CACHE_CLIENT | + SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb); + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + /* When a user callback is installed to modify the SSL_CTX, + * we need to do the full initialization before calling it. + * See: #11800 */ + if(!backend->x509_store_setup) { + result = Curl_ssl_setup_x509_store(cf, data, backend->ctx); + if(result) + return result; + backend->x509_store_setup = TRUE; + } + Curl_set_in_callback(data, true); + result = (*data->set.ssl.fsslctx)(data, backend->ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } + + /* Let's make an SSL structure */ + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { + failf(data, "SSL: couldn't create a context (handle)"); + return CURLE_OUT_OF_MEMORY; + } + + SSL_set_app_data(backend->handle, cf); + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(conn_config->verifystatus) + SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp); +#endif + +#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \ + defined(ALLOW_RENEG) + SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely); +#endif + + SSL_set_connect_state(backend->handle); + + backend->server_cert = 0x0; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if(connssl->peer.sni) { + if(!SSL_set_tlsext_host_name(backend->handle, connssl->peer.sni)) { + failf(data, "Failed set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + SSL_set_app_data(backend->handle, cf); + + connssl->reused_session = FALSE; + if(ssl_config->primary.sessionid) { + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if(!SSL_set_session(backend->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(data); + failf(data, "SSL: SSL_set_session failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL reusing session ID"); + connssl->reused_session = TRUE; + } + Curl_ssl_sessionid_unlock(data); + } + + backend->bio_method = ossl_bio_cf_method_create(); + if(!backend->bio_method) + return CURLE_OUT_OF_MEMORY; + bio = BIO_new(backend->bio_method); + if(!bio) + return CURLE_OUT_OF_MEMORY; + + BIO_set_data(bio, cf); +#ifdef HAVE_SSL_SET0_WBIO + /* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works + * without backward compat quirks. Every call takes one reference, so we + * up it and pass. SSL* then owns it and will free. + * We check on the function in configure, since libressl and friends + * each have their own versions to add support for this. */ + BIO_up_ref(bio); + SSL_set0_rbio(backend->handle, bio); + SSL_set0_wbio(backend->handle, bio); +#else + SSL_set_bio(backend->handle, bio, bio); +#endif + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + int err; + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + DEBUGASSERT(ssl_connect_2 == connssl->connecting_state + || ssl_connect_2_reading == connssl->connecting_state + || ssl_connect_2_writing == connssl->connecting_state); + DEBUGASSERT(backend); + + ERR_clear_error(); + + err = SSL_connect(backend->handle); + + if(!backend->x509_store_setup) { + /* After having send off the ClientHello, we prepare the x509 + * store to verify the coming certificate from the server */ + CURLcode result = Curl_ssl_setup_x509_store(cf, data, backend->ctx); + if(result) + return result; + backend->x509_store_setup = TRUE; + } + +#ifndef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + /* If key logging is enabled, wait for the handshake to complete and then + * proceed with logging secrets (for TLS 1.2 or older). + */ + ossl_log_tls12_secret(backend->handle, &backend->keylog_done); + } +#endif + + /* 1 is fine + 0 is "not successful but was shut down controlled" + <0 is "handshake was not successful, because a fatal error occurred" */ + if(1 != err) { + int detail = SSL_get_error(backend->handle, err); + + if(SSL_ERROR_WANT_READ == detail) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + if(SSL_ERROR_WANT_WRITE == detail) { + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + } +#ifdef SSL_ERROR_WANT_ASYNC + if(SSL_ERROR_WANT_ASYNC == detail) { + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; + } +#endif +#ifdef SSL_ERROR_WANT_RETRY_VERIFY + if(SSL_ERROR_WANT_RETRY_VERIFY == detail) { + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; + } +#endif + if(backend->io_result == CURLE_AGAIN) { + return CURLE_OK; + } + else { + /* untreated error */ + sslerr_t errdetail; + char error_buffer[256]=""; + CURLcode result; + long lerr; + int lib; + int reason; + + /* the connection failed, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_2; + + /* Get the earliest error code from the thread's error queue and remove + the entry. */ + errdetail = ERR_get_error(); + + /* Extract which lib and reason */ + lib = ERR_GET_LIB(errdetail); + reason = ERR_GET_REASON(errdetail); + + if((lib == ERR_LIB_SSL) && + ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) || + (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) { + result = CURLE_PEER_FAILED_VERIFICATION; + + lerr = SSL_get_verify_result(backend->handle); + if(lerr != X509_V_OK) { + ssl_config->certverifyresult = lerr; + msnprintf(error_buffer, sizeof(error_buffer), + "SSL certificate problem: %s", + X509_verify_cert_error_string(lerr)); + } + else + /* strcpy() is fine here as long as the string fits within + error_buffer */ + strcpy(error_buffer, "SSL certificate verification failed"); + } +#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED) + /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on + OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */ + else if((lib == ERR_LIB_SSL) && + (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) { + /* If client certificate is required, communicate the + error to client */ + result = CURLE_SSL_CLIENTCERT; + ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); + } +#endif + else { + result = CURLE_SSL_CONNECT_ERROR; + ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); + } + + /* detail is already set to the SSL error above */ + + /* If we e.g. use SSLv2 request-method and the server doesn't like us + * (RST connection, etc.), OpenSSL gives no explanation whatsoever and + * the SO_ERROR is also lost. + */ + if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { + char extramsg[80]=""; + int sockerr = SOCKERRNO; + + if(sockerr && detail == SSL_ERROR_SYSCALL) + Curl_strerror(sockerr, extramsg, sizeof(extramsg)); + failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ", + extramsg[0] ? extramsg : SSL_ERROR_to_str(detail), + connssl->peer.hostname, connssl->port); + return result; + } + + /* Could be a CERT problem */ + failf(data, "%s", error_buffer); + + return result; + } + } + else { + int psigtype_nid = NID_undef; + const char *negotiated_group_name = NULL; + + /* we connected fine, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_3; + +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + SSL_get_peer_signature_type_nid(backend->handle, &psigtype_nid); +#if (OPENSSL_VERSION_NUMBER >= 0x30200000L) + negotiated_group_name = SSL_get0_group_name(backend->handle); +#else + negotiated_group_name = + OBJ_nid2sn(SSL_get_negotiated_group(backend->handle) & 0x0000FFFF); +#endif +#endif + + /* Informational message */ + infof(data, "SSL connection using %s / %s / %s / %s", + SSL_get_version(backend->handle), + SSL_get_cipher(backend->handle), + negotiated_group_name? negotiated_group_name : "[blank]", + OBJ_nid2sn(psigtype_nid)); + +#ifdef HAS_ALPN + /* Sets data and len to negotiated protocol, len is 0 if no protocol was + * negotiated + */ + if(connssl->alpn) { + const unsigned char *neg_protocol; + unsigned int len; + SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len); + + return Curl_alpn_set_negotiated(cf, data, neg_protocol, len); + } +#endif + + return CURLE_OK; + } +} + +/* + * Heavily modified from: + * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL + */ +static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, + const char *pinnedpubkey) +{ + /* Scratch */ + int len1 = 0, len2 = 0; + unsigned char *buff1 = NULL, *temp = NULL; + + /* Result is returned to caller */ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + + if(!cert) + return result; + + do { + /* Begin Gyrations to get the subjectPublicKeyInfo */ + /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ + + /* https://groups.google.com/group/mailing.openssl.users/browse_thread + /thread/d61858dae102c6c7 */ + len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); + if(len1 < 1) + break; /* failed */ + + buff1 = temp = malloc(len1); + if(!buff1) + break; /* failed */ + + /* https://www.openssl.org/docs/crypto/d2i_X509.html */ + len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp); + + /* + * These checks are verifying we got back the same values as when we + * sized the buffer. It's pretty weak since they should always be the + * same. But it gives us something to test. + */ + if((len1 != len2) || !temp || ((temp - buff1) != len1)) + break; /* failed */ + + /* End Gyrations */ + + /* The one good exit point */ + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); + } while(0); + + if(buff1) + free(buff1); + + return result; +} + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x3060000fL) && \ + !defined(OPENSSL_IS_BORINGSSL) && \ + !defined(OPENSSL_IS_AWSLC) && \ + !defined(CURL_DISABLE_VERBOSE_STRINGS) +static void infof_certstack(struct Curl_easy *data, const SSL *ssl) +{ + STACK_OF(X509) *certstack; + long verify_result; + int num_cert_levels; + int cert_level; + + verify_result = SSL_get_verify_result(ssl); + if(verify_result != X509_V_OK) + certstack = SSL_get_peer_cert_chain(ssl); + else + certstack = SSL_get0_verified_chain(ssl); + num_cert_levels = sk_X509_num(certstack); + + for(cert_level = 0; cert_level < num_cert_levels; cert_level++) { + char cert_algorithm[80] = ""; + char group_name_final[80] = ""; + const X509_ALGOR *palg_cert = NULL; + const ASN1_OBJECT *paobj_cert = NULL; + X509 *current_cert; + EVP_PKEY *current_pkey; + int key_bits; + int key_sec_bits; + int get_group_name; + const char *type_name; + + current_cert = sk_X509_value(certstack, cert_level); + + X509_get0_signature(NULL, &palg_cert, current_cert); + X509_ALGOR_get0(&paobj_cert, NULL, NULL, palg_cert); + OBJ_obj2txt(cert_algorithm, sizeof(cert_algorithm), paobj_cert, 0); + + current_pkey = X509_get0_pubkey(current_cert); + key_bits = EVP_PKEY_bits(current_pkey); +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) +#define EVP_PKEY_get_security_bits EVP_PKEY_security_bits +#endif + key_sec_bits = EVP_PKEY_get_security_bits(current_pkey); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + { + char group_name[80] = ""; + get_group_name = EVP_PKEY_get_group_name(current_pkey, group_name, + sizeof(group_name), NULL); + msnprintf(group_name_final, sizeof(group_name_final), "/%s", group_name); + } + type_name = EVP_PKEY_get0_type_name(current_pkey); +#else + get_group_name = 0; + type_name = NULL; +#endif + + infof(data, + " Certificate level %d: " + "Public key type %s%s (%d/%d Bits/secBits), signed using %s", + cert_level, type_name ? type_name : "?", + get_group_name == 0 ? "" : group_name_final, + key_bits, key_sec_bits, cert_algorithm); + } +} +#else +#define infof_certstack(data, ssl) +#endif + +/* + * Get the server cert, verify it and show it, etc., only call failf() if the + * 'strict' argument is TRUE as otherwise all this is for informational + * purposes only! + * + * We check certificates to authenticate the server; otherwise we risk + * man-in-the-middle attack. + */ +static CURLcode servercert(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool strict) +{ + struct connectdata *conn = cf->conn; + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + CURLcode result = CURLE_OK; + int rc; + long lerr; + X509 *issuer; + BIO *fp = NULL; + char error_buffer[256]=""; + char buffer[2048]; + const char *ptr; + BIO *mem = BIO_new(BIO_s_mem()); + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + + DEBUGASSERT(backend); + + if(!mem) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return CURLE_OUT_OF_MEMORY; + } + + if(data->set.ssl.certinfo) + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, backend->handle); + + backend->server_cert = SSL_get1_peer_certificate(backend->handle); + if(!backend->server_cert) { + BIO_free(mem); + if(!strict) + return CURLE_OK; + + failf(data, "SSL: couldn't get peer certificate"); + return CURLE_PEER_FAILED_VERIFICATION; + } + + infof(data, "%s certificate:", + Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server"); + + rc = x509_name_oneline(X509_get_subject_name(backend->server_cert), + buffer, sizeof(buffer)); + infof(data, " subject: %s", rc?"[NONE]":buffer); + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + { + long len; + ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " start date: %.*s", (int)len, ptr); + (void)BIO_reset(mem); + + ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " expire date: %.*s", (int)len, ptr); + (void)BIO_reset(mem); + } +#endif + + BIO_free(mem); + + if(conn_config->verifyhost) { + result = Curl_ossl_verifyhost(data, conn, &connssl->peer, + backend->server_cert); + if(result) { + X509_free(backend->server_cert); + backend->server_cert = NULL; + return result; + } + } + + rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert), + buffer, sizeof(buffer)); + if(rc) { + if(strict) + failf(data, "SSL: couldn't get X509-issuer name"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else { + infof(data, " issuer: %s", buffer); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + /* e.g. match issuer name with provided issuer certificate */ + if(conn_config->issuercert || conn_config->issuercert_blob) { + if(conn_config->issuercert_blob) { + fp = BIO_new_mem_buf(conn_config->issuercert_blob->data, + (int)conn_config->issuercert_blob->len); + if(!fp) { + failf(data, + "BIO_new_mem_buf NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_OUT_OF_MEMORY; + } + } + else { + fp = BIO_new(BIO_s_file()); + if(!fp) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_OUT_OF_MEMORY; + } + + if(BIO_read_filename(fp, conn_config->issuercert) <= 0) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", + conn_config->issuercert); + BIO_free(fp); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + } + + issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); + if(!issuer) { + if(strict) + failf(data, "SSL: Unable to read issuer cert (%s)", + conn_config->issuercert); + BIO_free(fp); + X509_free(issuer); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + + if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) { + if(strict) + failf(data, "SSL: Certificate issuer check failed (%s)", + conn_config->issuercert); + BIO_free(fp); + X509_free(issuer); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + + infof(data, " SSL certificate issuer check ok (%s)", + conn_config->issuercert); + BIO_free(fp); + X509_free(issuer); + } + + lerr = SSL_get_verify_result(backend->handle); + ssl_config->certverifyresult = lerr; + if(lerr != X509_V_OK) { + if(conn_config->verifypeer) { + /* We probably never reach this, because SSL_connect() will fail + and we return earlier if verifypeer is set? */ + if(strict) + failf(data, "SSL certificate verify result: %s (%ld)", + X509_verify_cert_error_string(lerr), lerr); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, " SSL certificate verify result: %s (%ld)," + " continuing anyway.", + X509_verify_cert_error_string(lerr), lerr); + } + else + infof(data, " SSL certificate verify ok."); + } + + infof_certstack(data, backend->handle); + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(conn_config->verifystatus && !connssl->reused_session) { + /* don't do this after Session ID reuse */ + result = verifystatus(cf, data); + if(result) { + /* when verifystatus failed, remove the session id from the cache again + if present */ + if(!Curl_ssl_cf_is_proxy(cf)) { + void *old_ssl_sessionid = NULL; + bool incache; + Curl_ssl_sessionid_lock(data); + incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)); + if(incache) { + infof(data, "Remove session ID again from cache"); + Curl_ssl_delsessionid(data, old_ssl_sessionid); + } + Curl_ssl_sessionid_unlock(data); + } + + X509_free(backend->server_cert); + backend->server_cert = NULL; + return result; + } + } +#endif + + if(!strict) + /* when not strict, we don't bother about the verify cert problems */ + result = CURLE_OK; + + ptr = Curl_ssl_cf_is_proxy(cf)? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(!result && ptr) { + result = ossl_pkp_pin_peer_pubkey(data, backend->server_cert, ptr); + if(result) + failf(data, "SSL: public key does not match pinned public key"); + } + + X509_free(backend->server_cert); + backend->server_cert = NULL; + connssl->connecting_state = ssl_connect_done; + + return result; +} + +static CURLcode ossl_connect_step3(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + + /* + * We check certificates to authenticate the server; otherwise we risk + * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to + * verify the peer, ignore faults and failures from the server cert + * operations. + */ + + result = servercert(cf, data, conn_config->verifypeer || + conn_config->verifyhost); + + if(!result) + connssl->connecting_state = ssl_connect_done; + + return result; +} + +static CURLcode ossl_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool nonblocking, + bool *done) +{ + CURLcode result = CURLE_OK; + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + /* Find out how much more time we're allowed */ + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time is already up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = ossl_connect_step1(cf, data); + if(result) + goto out; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + result = CURLE_OPERATION_TIMEDOUT; + goto out; + } + + /* if ssl is expecting something, check if it's available. */ + if(!nonblocking && + (connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing)) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + result = CURLE_SSL_CONNECT_ERROR; + goto out; + } + if(0 == what) { + /* timeout */ + failf(data, "SSL connection timeout"); + result = CURLE_OPERATION_TIMEDOUT; + goto out; + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if this + * connection is done nonblocking and this loop would execute again. This + * permits the owner of a multi handle to abort a connection attempt + * before step2 has completed while ensuring that a client using select() + * or epoll() will always have a valid fdset to wait on. + */ + result = ossl_connect_step2(cf, data); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + goto out; + + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3 == connssl->connecting_state) { + result = ossl_connect_step3(cf, data); + if(result) + goto out; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + +out: + return result; +} + +static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + return ossl_connect_common(cf, data, TRUE, done); +} + +static CURLcode ossl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result; + bool done = FALSE; + + result = ossl_connect_common(cf, data, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +static bool ossl_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + + (void)data; + DEBUGASSERT(connssl && backend); + if(backend->handle && SSL_pending(backend->handle)) + return TRUE; + return FALSE; +} + +static ssize_t ossl_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + /* SSL_write() is said to return 'int' while write() and send() returns + 'size_t' */ + int err; + char error_buffer[256]; + sslerr_t sslerror; + int memlen; + int rc; + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + + (void)data; + DEBUGASSERT(backend); + + ERR_clear_error(); + + memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; + rc = SSL_write(backend->handle, mem, memlen); + + if(rc <= 0) { + err = SSL_get_error(backend->handle, rc); + + switch(err) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* The operation did not complete; the same TLS/SSL I/O function + should be called again later. This is basically an EWOULDBLOCK + equivalent. */ + *curlcode = CURLE_AGAIN; + rc = -1; + goto out; + case SSL_ERROR_SYSCALL: + { + int sockerr = SOCKERRNO; + + if(backend->io_result == CURLE_AGAIN) { + *curlcode = CURLE_AGAIN; + rc = -1; + goto out; + } + sslerror = ERR_get_error(); + if(sslerror) + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); + else if(sockerr) + Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + else + msnprintf(error_buffer, sizeof(error_buffer), "%s", + SSL_ERROR_to_str(err)); + + failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d", + error_buffer, sockerr); + *curlcode = CURLE_SEND_ERROR; + rc = -1; + goto out; + } + case SSL_ERROR_SSL: { + /* A failure in the SSL library occurred, usually a protocol error. + The OpenSSL error queue contains more information on the error. */ + sslerror = ERR_get_error(); + failf(data, "SSL_write() error: %s", + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); + *curlcode = CURLE_SEND_ERROR; + rc = -1; + goto out; + } + default: + /* a true error */ + failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d", + SSL_ERROR_to_str(err), SOCKERRNO); + *curlcode = CURLE_SEND_ERROR; + rc = -1; + goto out; + } + } + *curlcode = CURLE_OK; + +out: + return (ssize_t)rc; /* number of bytes */ +} + +static ssize_t ossl_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, /* transfer */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + CURLcode *curlcode) +{ + char error_buffer[256]; + unsigned long sslerror; + ssize_t nread; + int buffsize; + struct connectdata *conn = cf->conn; + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + + (void)data; + DEBUGASSERT(backend); + + ERR_clear_error(); + + buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; + nread = (ssize_t)SSL_read(backend->handle, buf, buffsize); + + if(nread <= 0) { + /* failed SSL_read */ + int err = SSL_get_error(backend->handle, (int)nread); + + switch(err) { + case SSL_ERROR_NONE: /* this is not an error */ + break; + case SSL_ERROR_ZERO_RETURN: /* no more data */ + /* close_notify alert */ + if(cf->sockindex == FIRSTSOCKET) + /* mark the connection for close if it is indeed the control + connection */ + connclose(conn, "TLS close_notify"); + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* there's data pending, re-invoke SSL_read() */ + *curlcode = CURLE_AGAIN; + nread = -1; + goto out; + default: + /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return + value/errno" */ + /* https://www.openssl.org/docs/crypto/ERR_get_error.html */ + if(backend->io_result == CURLE_AGAIN) { + *curlcode = CURLE_AGAIN; + nread = -1; + goto out; + } + sslerror = ERR_get_error(); + if((nread < 0) || sslerror) { + /* If the return code was negative or there actually is an error in the + queue */ + int sockerr = SOCKERRNO; + if(sslerror) + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); + else if(sockerr && err == SSL_ERROR_SYSCALL) + Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + else + msnprintf(error_buffer, sizeof(error_buffer), "%s", + SSL_ERROR_to_str(err)); + failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d", + error_buffer, sockerr); + *curlcode = CURLE_RECV_ERROR; + nread = -1; + goto out; + } + /* For debug builds be a little stricter and error on any + SSL_ERROR_SYSCALL. For example a server may have closed the connection + abruptly without a close_notify alert. For compatibility with older + peers we don't do this by default. #4624 + + We can use this to gauge how many users may be affected, and + if it goes ok eventually transition to allow in dev and release with + the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */ +#ifdef DEBUGBUILD + if(err == SSL_ERROR_SYSCALL) { + int sockerr = SOCKERRNO; + if(sockerr) + Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + else { + msnprintf(error_buffer, sizeof(error_buffer), + "Connection closed abruptly"); + } + failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d" + " (Fatal because this is a curl debug build)", + error_buffer, sockerr); + *curlcode = CURLE_RECV_ERROR; + nread = -1; + goto out; + } +#endif + } + } + +out: + return nread; +} + +static size_t ossl_version(char *buffer, size_t size) +{ +#ifdef LIBRESSL_VERSION_NUMBER +#ifdef HAVE_OPENSSL_VERSION + char *p; + int count; + const char *ver = OpenSSL_version(OPENSSL_VERSION); + const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */ + if(strncasecompare(ver, expected, sizeof(expected) - 1)) { + ver += sizeof(expected) - 1; + } + count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); + for(p = buffer; *p; ++p) { + if(ISBLANK(*p)) + *p = '_'; + } + return count; +#else + return msnprintf(buffer, size, "%s/%lx.%lx.%lx", + OSSL_PACKAGE, + (LIBRESSL_VERSION_NUMBER>>28)&0xf, + (LIBRESSL_VERSION_NUMBER>>20)&0xff, + (LIBRESSL_VERSION_NUMBER>>12)&0xff); +#endif +#elif defined(OPENSSL_IS_BORINGSSL) +#ifdef CURL_BORINGSSL_VERSION + return msnprintf(buffer, size, "%s/%s", + OSSL_PACKAGE, + CURL_BORINGSSL_VERSION); +#else + return msnprintf(buffer, size, OSSL_PACKAGE); +#endif +#elif defined(OPENSSL_IS_AWSLC) + return msnprintf(buffer, size, "%s/%s", + OSSL_PACKAGE, + AWSLC_VERSION_NUMBER_STRING); +#elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING) + return msnprintf(buffer, size, "%s/%s", + OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING)); +#else + /* not LibreSSL, BoringSSL and not using OpenSSL_version */ + + char sub[3]; + unsigned long ssleay_value; + sub[2]='\0'; + sub[1]='\0'; + ssleay_value = OpenSSL_version_num(); + if(ssleay_value < 0x906000) { + ssleay_value = SSLEAY_VERSION_NUMBER; + sub[0]='\0'; + } + else { + if(ssleay_value&0xff0) { + int minor_ver = (ssleay_value >> 4) & 0xff; + if(minor_ver > 26) { + /* handle extended version introduced for 0.9.8za */ + sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); + sub[0] = 'z'; + } + else { + sub[0] = (char) (minor_ver + 'a' - 1); + } + } + else + sub[0]='\0'; + } + + return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s" +#ifdef OPENSSL_FIPS + "-fips" +#endif + , + OSSL_PACKAGE, + (ssleay_value>>28)&0xf, + (ssleay_value>>20)&0xff, + (ssleay_value>>12)&0xff, + sub); +#endif /* OPENSSL_IS_BORINGSSL */ +} + +/* can be called with data == NULL */ +static CURLcode ossl_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) +{ + int rc; + if(data) { + if(ossl_seed(data)) /* Initiate the seed if not already done */ + return CURLE_FAILED_INIT; /* couldn't seed for some reason */ + } + else { + if(!rand_enough()) + return CURLE_FAILED_INIT; + } + /* RAND_bytes() returns 1 on success, 0 otherwise. */ + rc = RAND_bytes(entropy, curlx_uztosi(length)); + return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT); +} + +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) +static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) +{ + EVP_MD_CTX *mdctx; + unsigned int len = 0; + (void) unused; + + mdctx = EVP_MD_CTX_create(); + if(!mdctx) + return CURLE_OUT_OF_MEMORY; + if(!EVP_DigestInit(mdctx, EVP_sha256())) { + EVP_MD_CTX_destroy(mdctx); + return CURLE_FAILED_INIT; + } + EVP_DigestUpdate(mdctx, tmp, tmplen); + EVP_DigestFinal_ex(mdctx, sha256sum, &len); + EVP_MD_CTX_destroy(mdctx); + return CURLE_OK; +} +#endif + +static bool ossl_cert_status_request(void) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + return TRUE; +#else + return FALSE; +#endif +} + +static void *ossl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info) +{ + /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + DEBUGASSERT(backend); + return info == CURLINFO_TLS_SESSION ? + (void *)backend->ctx : (void *)backend->handle; +} + +static void ossl_free_multi_ssl_backend_data( + struct multi_ssl_backend_data *mbackend) +{ +#if defined(HAVE_SSL_X509_STORE_SHARE) + if(mbackend->store) { + X509_STORE_free(mbackend->store); + } + free(mbackend->CAfile); + free(mbackend); +#else /* HAVE_SSL_X509_STORE_SHARE */ + (void)mbackend; +#endif /* HAVE_SSL_X509_STORE_SHARE */ +} + +const struct Curl_ssl Curl_ssl_openssl = { + { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */ + + SSLSUPP_CA_PATH | + SSLSUPP_CAINFO_BLOB | + SSLSUPP_CERTINFO | + SSLSUPP_PINNEDPUBKEY | + SSLSUPP_SSL_CTX | +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + SSLSUPP_TLS13_CIPHERSUITES | +#endif + SSLSUPP_HTTPS_PROXY, + + sizeof(struct ossl_ssl_backend_data), + + ossl_init, /* init */ + ossl_cleanup, /* cleanup */ + ossl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + ossl_shutdown, /* shutdown */ + ossl_data_pending, /* data_pending */ + ossl_random, /* random */ + ossl_cert_status_request, /* cert_status_request */ + ossl_connect, /* connect */ + ossl_connect_nonblocking, /* connect_nonblocking */ + Curl_ssl_adjust_pollset, /* adjust_pollset */ + ossl_get_internals, /* get_internals */ + ossl_close, /* close_one */ + ossl_close_all, /* close_all */ + ossl_session_free, /* session_free */ + ossl_set_engine, /* set_engine */ + ossl_set_engine_default, /* set_engine_default */ + ossl_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) + ossl_sha256sum, /* sha256sum */ +#else + NULL, /* sha256sum */ +#endif + NULL, /* use of data in this connection */ + NULL, /* remote of data from this connection */ + ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */ + ossl_recv, /* recv decrypted data */ + ossl_send, /* send data to encrypt */ +}; + +#endif /* USE_OPENSSL */ diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h new file mode 100644 index 0000000..e802363 --- /dev/null +++ b/lib/vtls/openssl.h @@ -0,0 +1,70 @@ +#ifndef HEADER_CURL_SSLUSE_H +#define HEADER_CURL_SSLUSE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_OPENSSL +/* + * This header should only be needed to get included by vtls.c, openssl.c + * and ngtcp2.c + */ +#include +#include + +#include "urldata.h" + +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) +#define SSL_get1_peer_certificate SSL_get_peer_certificate +#endif + +CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + struct ssl_peer *peer, X509 *server_cert); +extern const struct Curl_ssl Curl_ssl_openssl; + +CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data, + SSL_CTX *ctx, char *cert_file, + const struct curl_blob *cert_blob, + const char *cert_type, char *key_file, + const struct curl_blob *key_blob, + const char *key_type, char *key_passwd); + +CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl); + +/** + * Setup the OpenSSL X509_STORE in `ssl_ctx` for the cfilter `cf` and + * easy handle `data`. Will allow reuse of a shared cache if suitable + * and configured. + */ +CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + SSL_CTX *ssl_ctx); + +CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf, + struct Curl_easy *data, + SSL_CTX *ssl_ctx); + +#endif /* USE_OPENSSL */ +#endif /* HEADER_CURL_SSLUSE_H */ diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c new file mode 100644 index 0000000..d589709 --- /dev/null +++ b/lib/vtls/rustls.c @@ -0,0 +1,730 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Jacob Hoffman-Andrews, + * + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_RUSTLS + +#include "curl_printf.h" + +#include +#include + +#include "inet_pton.h" +#include "urldata.h" +#include "sendf.h" +#include "vtls.h" +#include "vtls_int.h" +#include "select.h" +#include "strerror.h" +#include "multiif.h" +#include "connect.h" /* for the connect timeout */ + +struct rustls_ssl_backend_data +{ + const struct rustls_client_config *config; + struct rustls_connection *conn; + bool data_pending; +}; + +/* For a given rustls_result error code, return the best-matching CURLcode. */ +static CURLcode map_error(rustls_result r) +{ + if(rustls_result_is_cert_error(r)) { + return CURLE_PEER_FAILED_VERIFICATION; + } + switch(r) { + case RUSTLS_RESULT_OK: + return CURLE_OK; + case RUSTLS_RESULT_NULL_PARAMETER: + return CURLE_BAD_FUNCTION_ARGUMENT; + default: + return CURLE_READ_ERROR; + } +} + +static bool +cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) +{ + struct ssl_connect_data *ctx = cf->ctx; + struct rustls_ssl_backend_data *backend; + + (void)data; + DEBUGASSERT(ctx && ctx->backend); + backend = (struct rustls_ssl_backend_data *)ctx->backend; + return backend->data_pending; +} + +struct io_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; +}; + +static int +read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n) +{ + struct io_ctx *io_ctx = userdata; + CURLcode result; + int ret = 0; + ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data, + (char *)buf, len, &result); + if(nread < 0) { + nread = 0; + if(CURLE_AGAIN == result) + ret = EAGAIN; + else + ret = EINVAL; + } + *out_n = (int)nread; + return ret; +} + +static int +write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n) +{ + struct io_ctx *io_ctx = userdata; + CURLcode result; + int ret = 0; + ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data, + (const char *)buf, len, &result); + if(nwritten < 0) { + nwritten = 0; + if(CURLE_AGAIN == result) + ret = EAGAIN; + else + ret = EINVAL; + } + *out_n = (int)nwritten; + /* + CURL_TRC_CFX(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d", + len, nwritten, result)); + */ + return ret; +} + +static ssize_t tls_recv_more(struct Curl_cfilter *cf, + struct Curl_easy *data, CURLcode *err) +{ + struct ssl_connect_data *const connssl = cf->ctx; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; + struct io_ctx io_ctx; + size_t tls_bytes_read = 0; + rustls_io_result io_error; + rustls_result rresult = 0; + + io_ctx.cf = cf; + io_ctx.data = data; + io_error = rustls_connection_read_tls(backend->conn, read_cb, &io_ctx, + &tls_bytes_read); + if(io_error == EAGAIN || io_error == EWOULDBLOCK) { + *err = CURLE_AGAIN; + return -1; + } + else if(io_error) { + char buffer[STRERROR_LEN]; + failf(data, "reading from socket: %s", + Curl_strerror(io_error, buffer, sizeof(buffer))); + *err = CURLE_READ_ERROR; + return -1; + } + + rresult = rustls_connection_process_new_packets(backend->conn); + if(rresult != RUSTLS_RESULT_OK) { + char errorbuf[255]; + size_t errorlen; + rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); + failf(data, "rustls_connection_process_new_packets: %.*s", + (int)errorlen, errorbuf); + *err = map_error(rresult); + return -1; + } + + backend->data_pending = TRUE; + *err = CURLE_OK; + return (ssize_t)tls_bytes_read; +} + +/* + * On each run: + * - Read a chunk of bytes from the socket into rustls' TLS input buffer. + * - Tell rustls to process any new packets. + * - Read out as many plaintext bytes from rustls as possible, until hitting + * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up. + * + * It's okay to call this function with plainbuf == NULL and plainlen == 0. + * In that case, it will copy bytes from the socket into rustls' TLS input + * buffer, and process packets, but won't consume bytes from rustls' plaintext + * output buffer. + */ +static ssize_t +cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *plainbuf, size_t plainlen, CURLcode *err) +{ + struct ssl_connect_data *const connssl = cf->ctx; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; + struct rustls_connection *rconn = NULL; + size_t n = 0; + size_t plain_bytes_copied = 0; + rustls_result rresult = 0; + ssize_t nread; + bool eof = FALSE; + + DEBUGASSERT(backend); + rconn = backend->conn; + + while(plain_bytes_copied < plainlen) { + if(!backend->data_pending) { + if(tls_recv_more(cf, data, err) < 0) { + if(*err != CURLE_AGAIN) { + nread = -1; + goto out; + } + break; + } + } + + rresult = rustls_connection_read(rconn, + (uint8_t *)plainbuf + plain_bytes_copied, + plainlen - plain_bytes_copied, + &n); + if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) { + backend->data_pending = FALSE; + } + else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) { + failf(data, "rustls: peer closed TCP connection " + "without first closing TLS connection"); + *err = CURLE_READ_ERROR; + nread = -1; + goto out; + } + else if(rresult != RUSTLS_RESULT_OK) { + /* n always equals 0 in this case, don't need to check it */ + char errorbuf[255]; + size_t errorlen; + rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); + failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf); + *err = CURLE_READ_ERROR; + nread = -1; + goto out; + } + else if(n == 0) { + /* n == 0 indicates clean EOF, but we may have read some other + plaintext bytes before we reached this. Break out of the loop + so we can figure out whether to return success or EOF. */ + eof = TRUE; + break; + } + else { + plain_bytes_copied += n; + } + } + + if(plain_bytes_copied) { + *err = CURLE_OK; + nread = (ssize_t)plain_bytes_copied; + } + else if(eof) { + *err = CURLE_OK; + nread = 0; + } + else { + *err = CURLE_AGAIN; + nread = -1; + } + +out: + CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", + plainlen, nread, *err); + return nread; +} + +/* + * On each call: + * - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0). + * - Fully drain rustls' plaintext output buffer into the socket until + * we get either an error or EAGAIN/EWOULDBLOCK. + * + * It's okay to call this function with plainbuf == NULL and plainlen == 0. + * In that case, it won't read anything into rustls' plaintext input buffer. + * It will only drain rustls' plaintext output buffer into the socket. + */ +static ssize_t +cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *plainbuf, size_t plainlen, CURLcode *err) +{ + struct ssl_connect_data *const connssl = cf->ctx; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; + struct rustls_connection *rconn = NULL; + struct io_ctx io_ctx; + size_t plainwritten = 0; + size_t tlswritten = 0; + size_t tlswritten_total = 0; + rustls_result rresult; + rustls_io_result io_error; + char errorbuf[256]; + size_t errorlen; + + DEBUGASSERT(backend); + rconn = backend->conn; + + CURL_TRC_CF(data, cf, "cf_send: %ld plain bytes", plainlen); + + io_ctx.cf = cf; + io_ctx.data = data; + + if(plainlen > 0) { + rresult = rustls_connection_write(rconn, plainbuf, plainlen, + &plainwritten); + if(rresult != RUSTLS_RESULT_OK) { + rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); + failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf); + *err = CURLE_WRITE_ERROR; + return -1; + } + else if(plainwritten == 0) { + failf(data, "rustls_connection_write: EOF"); + *err = CURLE_WRITE_ERROR; + return -1; + } + } + + while(rustls_connection_wants_write(rconn)) { + io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx, + &tlswritten); + if(io_error == EAGAIN || io_error == EWOULDBLOCK) { + CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes", + tlswritten_total); + *err = CURLE_AGAIN; + return -1; + } + else if(io_error) { + char buffer[STRERROR_LEN]; + failf(data, "writing to socket: %s", + Curl_strerror(io_error, buffer, sizeof(buffer))); + *err = CURLE_WRITE_ERROR; + return -1; + } + if(tlswritten == 0) { + failf(data, "EOF in swrite"); + *err = CURLE_WRITE_ERROR; + return -1; + } + CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten); + tlswritten_total += tlswritten; + } + + return plainwritten; +} + +/* A server certificate verify callback for rustls that always returns + RUSTLS_RESULT_OK, or in other words disable certificate verification. */ +static enum rustls_result +cr_verify_none(void *userdata UNUSED_PARAM, + const rustls_verify_server_cert_params *params UNUSED_PARAM) +{ + return RUSTLS_RESULT_OK; +} + +static bool +cr_hostname_is_ip(const char *hostname) +{ + struct in_addr in; +#ifdef ENABLE_IPV6 + struct in6_addr in6; + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) { + return true; + } +#endif /* ENABLE_IPV6 */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { + return true; + } + return false; +} + +static CURLcode +cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, + struct rustls_ssl_backend_data *const backend) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct rustls_connection *rconn = NULL; + struct rustls_client_config_builder *config_builder = NULL; + struct rustls_root_cert_store *roots = NULL; + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : conn_config->CAfile); + const bool verifypeer = conn_config->verifypeer; + const char *hostname = connssl->peer.hostname; + char errorbuf[256]; + size_t errorlen; + int result; + + DEBUGASSERT(backend); + rconn = backend->conn; + + config_builder = rustls_client_config_builder_new(); + if(connssl->alpn) { + struct alpn_proto_buf proto; + rustls_slice_bytes alpn[ALPN_ENTRIES_MAX]; + size_t i; + + for(i = 0; i < connssl->alpn->count; ++i) { + alpn[i].data = (const uint8_t *)connssl->alpn->entries[i]; + alpn[i].len = strlen(connssl->alpn->entries[i]); + } + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, + connssl->alpn->count); + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } + if(!verifypeer) { + rustls_client_config_builder_dangerous_set_certificate_verifier( + config_builder, cr_verify_none); + /* rustls doesn't support IP addresses (as of 0.19.0), and will reject + * connections created with an IP address, even when certificate + * verification is turned off. Set a placeholder hostname and disable + * SNI. */ + if(cr_hostname_is_ip(hostname)) { + rustls_client_config_builder_set_enable_sni(config_builder, false); + hostname = "example.invalid"; + } + } + else if(ca_info_blob) { + roots = rustls_root_cert_store_new(); + + /* Enable strict parsing only if verification isn't disabled. */ + result = rustls_root_cert_store_add_pem(roots, ca_info_blob->data, + ca_info_blob->len, verifypeer); + if(result != RUSTLS_RESULT_OK) { + failf(data, "rustls: failed to parse trusted certificates from blob"); + rustls_root_cert_store_free(roots); + rustls_client_config_free( + rustls_client_config_builder_build(config_builder)); + return CURLE_SSL_CACERT_BADFILE; + } + + result = rustls_client_config_builder_use_roots(config_builder, roots); + rustls_root_cert_store_free(roots); + if(result != RUSTLS_RESULT_OK) { + failf(data, "rustls: failed to load trusted certificates"); + rustls_client_config_free( + rustls_client_config_builder_build(config_builder)); + return CURLE_SSL_CACERT_BADFILE; + } + } + else if(ssl_cafile) { + result = rustls_client_config_builder_load_roots_from_file( + config_builder, ssl_cafile); + if(result != RUSTLS_RESULT_OK) { + failf(data, "rustls: failed to load trusted certificates"); + rustls_client_config_free( + rustls_client_config_builder_build(config_builder)); + return CURLE_SSL_CACERT_BADFILE; + } + } + + backend->config = rustls_client_config_builder_build(config_builder); + DEBUGASSERT(rconn == NULL); + { + /* rustls claims to manage ip address hostnames as well here. So, + * if we have an SNI, we use it, otherwise we pass the hostname */ + char *server = connssl->peer.sni? + connssl->peer.sni : connssl->peer.hostname; + result = rustls_client_connection_new(backend->config, server, &rconn); + } + if(result != RUSTLS_RESULT_OK) { + rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen); + failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf); + return CURLE_COULDNT_CONNECT; + } + rustls_connection_set_userdata(rconn, backend); + backend->conn = rconn; + return CURLE_OK; +} + +static void +cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data, + const struct rustls_connection *rconn) +{ + const uint8_t *protocol = NULL; + size_t len = 0; + + rustls_connection_get_alpn_protocol(rconn, &protocol, &len); + Curl_alpn_set_negotiated(cf, data, protocol, len); +} + +/* Given an established network connection, do a TLS handshake. + * + * If `blocking` is true, this function will block until the handshake is + * complete. Otherwise it will return as soon as I/O would block. + * + * For the non-blocking I/O case, this function will set `*done` to true + * once the handshake is complete. This function never reads the value of + * `*done*`. + */ +static CURLcode +cr_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, + bool *done) +{ + struct ssl_connect_data *const connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; + struct rustls_connection *rconn = NULL; + CURLcode tmperr = CURLE_OK; + int result; + int what; + bool wants_read; + bool wants_write; + curl_socket_t writefd; + curl_socket_t readfd; + timediff_t timeout_ms; + timediff_t socket_check_timeout; + + DEBUGASSERT(backend); + + if(ssl_connection_none == connssl->state) { + result = cr_init_backend(cf, data, + (struct rustls_ssl_backend_data *)connssl->backend); + if(result != CURLE_OK) { + return result; + } + connssl->state = ssl_connection_negotiating; + } + + rconn = backend->conn; + + /* Read/write data until the handshake is done or the socket would block. */ + for(;;) { + /* + * Connection has been established according to rustls. Set send/recv + * handlers, and update the state machine. + */ + if(!rustls_connection_is_handshaking(rconn)) { + infof(data, "Done handshaking"); + /* Done with the handshake. Set up callbacks to send/receive data. */ + connssl->state = ssl_connection_complete; + + cr_set_negotiated_alpn(cf, data, rconn); + + *done = TRUE; + return CURLE_OK; + } + + wants_read = rustls_connection_wants_read(rconn); + wants_write = rustls_connection_wants_write(rconn); + DEBUGASSERT(wants_read || wants_write); + writefd = wants_write?sockfd:CURL_SOCKET_BAD; + readfd = wants_read?sockfd:CURL_SOCKET_BAD; + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "rustls: operation timed out before socket check"); + return CURLE_OPERATION_TIMEDOUT; + } + + socket_check_timeout = blocking?timeout_ms:0; + + what = Curl_socket_check( + readfd, CURL_SOCKET_BAD, writefd, socket_check_timeout); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + if(blocking && 0 == what) { + failf(data, "rustls connection timeout after %" + CURL_FORMAT_TIMEDIFF_T " ms", socket_check_timeout); + return CURLE_OPERATION_TIMEDOUT; + } + if(0 == what) { + infof(data, "Curl_socket_check: %s would block", + wants_read&&wants_write ? "writing and reading" : + wants_write ? "writing" : "reading"); + *done = FALSE; + return CURLE_OK; + } + /* socket is readable or writable */ + + if(wants_write) { + infof(data, "rustls_connection wants us to write_tls."); + cr_send(cf, data, NULL, 0, &tmperr); + if(tmperr == CURLE_AGAIN) { + infof(data, "writing would block"); + /* fall through */ + } + else if(tmperr != CURLE_OK) { + return tmperr; + } + } + + if(wants_read) { + infof(data, "rustls_connection wants us to read_tls."); + + if(tls_recv_more(cf, data, &tmperr) < 0) { + if(tmperr == CURLE_AGAIN) { + infof(data, "reading would block"); + /* fall through */ + } + else if(tmperr == CURLE_READ_ERROR) { + return CURLE_SSL_CONNECT_ERROR; + } + else { + return tmperr; + } + } + } + } + + /* We should never fall through the loop. We should return either because + the handshake is done or because we can't read/write without blocking. */ + DEBUGASSERT(false); +} + +static CURLcode +cr_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, bool *done) +{ + return cr_connect_common(cf, data, false, done); +} + +static CURLcode +cr_connect_blocking(struct Curl_cfilter *cf UNUSED_PARAM, + struct Curl_easy *data UNUSED_PARAM) +{ + bool done; /* unused */ + return cr_connect_common(cf, data, true, &done); +} + +static void cr_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + if(!cf->connected) { + curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data); + struct ssl_connect_data *const connssl = cf->ctx; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; + struct rustls_connection *rconn = NULL; + + (void)data; + DEBUGASSERT(backend); + rconn = backend->conn; + + if(rustls_connection_wants_write(rconn)) { + Curl_pollset_add_out(data, ps, sock); + } + if(rustls_connection_wants_read(rconn)) { + Curl_pollset_add_in(data, ps, sock); + } + } +} + +static void * +cr_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + struct rustls_ssl_backend_data *backend = + (struct rustls_ssl_backend_data *)connssl->backend; + DEBUGASSERT(backend); + return &backend->conn; +} + +static void +cr_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct rustls_ssl_backend_data *backend = + (struct rustls_ssl_backend_data *)connssl->backend; + CURLcode tmperr = CURLE_OK; + ssize_t n = 0; + + DEBUGASSERT(backend); + + if(backend->conn) { + rustls_connection_send_close_notify(backend->conn); + n = cr_send(cf, data, NULL, 0, &tmperr); + if(n < 0) { + failf(data, "rustls: error sending close_notify: %d", tmperr); + } + + rustls_connection_free(backend->conn); + backend->conn = NULL; + } + if(backend->config) { + rustls_client_config_free(backend->config); + backend->config = NULL; + } +} + +static size_t cr_version(char *buffer, size_t size) +{ + struct rustls_str ver = rustls_version(); + return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data); +} + +const struct Curl_ssl Curl_ssl_rustls = { + { CURLSSLBACKEND_RUSTLS, "rustls" }, + SSLSUPP_CAINFO_BLOB | /* supports */ + SSLSUPP_TLS13_CIPHERSUITES | + SSLSUPP_HTTPS_PROXY, + sizeof(struct rustls_ssl_backend_data), + + Curl_none_init, /* init */ + Curl_none_cleanup, /* cleanup */ + cr_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + cr_data_pending, /* data_pending */ + Curl_none_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + cr_connect_blocking, /* connect */ + cr_connect_nonblocking, /* connect_nonblocking */ + cr_adjust_pollset, /* adjust_pollset */ + cr_get_internals, /* get_internals */ + cr_close, /* close_one */ + Curl_none_close_all, /* close_all */ + Curl_none_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + NULL, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + cr_recv, /* recv decrypted data */ + cr_send, /* send data to encrypt */ +}; + +#endif /* USE_RUSTLS */ diff --git a/lib/vtls/rustls.h b/lib/vtls/rustls.h new file mode 100644 index 0000000..bfbe23d --- /dev/null +++ b/lib/vtls/rustls.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Jacob Hoffman-Andrews, + * + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#ifndef HEADER_CURL_RUSTLS_H +#define HEADER_CURL_RUSTLS_H + +#include "curl_setup.h" + +#ifdef USE_RUSTLS + +extern const struct Curl_ssl Curl_ssl_rustls; + +#endif /* USE_RUSTLS */ +#endif /* HEADER_CURL_RUSTLS_H */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c new file mode 100644 index 0000000..45c3373 --- /dev/null +++ b/lib/vtls/schannel.c @@ -0,0 +1,2931 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Marc Hoersken, + * Copyright (C) Mark Salisbury, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Source file for all Schannel-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + */ + +#include "curl_setup.h" + +#ifdef USE_SCHANNEL + +#ifndef USE_WINDOWS_SSPI +# error "Can't compile SCHANNEL support without SSPI." +#endif + +#include "schannel.h" +#include "schannel_int.h" +#include "vtls.h" +#include "vtls_int.h" +#include "strcase.h" +#include "sendf.h" +#include "connect.h" /* for the connect timeout */ +#include "strerror.h" +#include "select.h" /* for the socket readiness */ +#include "inet_pton.h" /* for IP addr SNI check */ +#include "curl_multibyte.h" +#include "warnless.h" +#include "x509asn1.h" +#include "curl_printf.h" +#include "multiif.h" +#include "version_win32.h" +#include "rand.h" + +/* The last #include file should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* ALPN requires version 8.1 of the Windows SDK, which was + shipped with Visual Studio 2013, aka _MSC_VER 1800: + + https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_) +# define HAS_ALPN 1 +#endif + +#ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM +#define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305" +#endif + +#ifndef BCRYPT_CHAIN_MODE_CCM +#define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM" +#endif + +#ifndef BCRYPT_CHAIN_MODE_GCM +#define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM" +#endif + +#ifndef BCRYPT_AES_ALGORITHM +#define BCRYPT_AES_ALGORITHM L"AES" +#endif + +#ifndef BCRYPT_SHA256_ALGORITHM +#define BCRYPT_SHA256_ALGORITHM L"SHA256" +#endif + +#ifndef BCRYPT_SHA384_ALGORITHM +#define BCRYPT_SHA384_ALGORITHM L"SHA384" +#endif + +#ifdef HAS_CLIENT_CERT_PATH +#ifdef UNICODE +#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W +#else +#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A +#endif +#endif + +#ifndef SP_PROT_TLS1_0_CLIENT +#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT +#endif + +#ifndef SP_PROT_TLS1_1_CLIENT +#define SP_PROT_TLS1_1_CLIENT 0x00000200 +#endif + +#ifndef SP_PROT_TLS1_2_CLIENT +#define SP_PROT_TLS1_2_CLIENT 0x00000800 +#endif + +#ifndef SP_PROT_TLS1_3_CLIENT +#define SP_PROT_TLS1_3_CLIENT 0x00002000 +#endif + +#ifndef SCH_USE_STRONG_CRYPTO +#define SCH_USE_STRONG_CRYPTO 0x00400000 +#endif + +#ifndef SECBUFFER_ALERT +#define SECBUFFER_ALERT 17 +#endif + +/* Both schannel buffer sizes must be > 0 */ +#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 +#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 + +#define CERT_THUMBPRINT_STR_LEN 40 +#define CERT_THUMBPRINT_DATA_LEN 20 + +/* Uncomment to force verbose output + * #define infof(x, y, ...) printf(y, __VA_ARGS__) + * #define failf(x, y, ...) printf(y, __VA_ARGS__) + */ + +#ifndef CALG_SHA_256 +# define CALG_SHA_256 0x0000800c +#endif + +#ifndef PKCS12_NO_PERSIST_KEY +#define PKCS12_NO_PERSIST_KEY 0x00008000 +#endif + +static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char *pinnedpubkey); + +static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType, + void *BufDataPtr, unsigned long BufByteSize) +{ + buffer->cbBuffer = BufByteSize; + buffer->BufferType = BufType; + buffer->pvBuffer = BufDataPtr; +} + +static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, + unsigned long NumArrElem) +{ + desc->ulVersion = SECBUFFER_VERSION; + desc->pBuffers = BufArr; + desc->cBuffers = NumArrElem; +} + +static CURLcode +schannel_set_ssl_version_min_max(DWORD *enabled_protocols, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + long ssl_version = conn_config->version; + long ssl_version_max = conn_config->version_max; + long i = ssl_version; + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + case CURL_SSLVERSION_MAX_DEFAULT: + + /* Windows Server 2022 and newer (including Windows 11) support TLS 1.3 + built-in. Previous builds of Windows 10 had broken TLS 1.3 + implementations that could be enabled via registry. + */ + if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; + } + else /* Windows 10 and older */ + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + + break; + } + + for(; i <= (ssl_version_max >> 16); ++i) { + switch(i) { + case CURL_SSLVERSION_TLSv1_0: + (*enabled_protocols) |= SP_PROT_TLS1_0_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_1: + (*enabled_protocols) |= SP_PROT_TLS1_1_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_2: + (*enabled_protocols) |= SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_3: + + /* Windows Server 2022 and newer */ + if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + (*enabled_protocols) |= SP_PROT_TLS1_3_CLIENT; + break; + } + else { /* Windows 10 and older */ + failf(data, "schannel: TLS 1.3 not supported on Windows prior to 11"); + return CURLE_SSL_CONNECT_ERROR; + } + } + } + return CURLE_OK; +} + +/* longest is 26, buffer is slightly bigger */ +#define LONGEST_ALG_ID 32 +#define CIPHEROPTION(x) {#x, x} + +struct algo { + const char *name; + int id; +}; + +static const struct algo algs[]= { + CIPHEROPTION(CALG_MD2), + CIPHEROPTION(CALG_MD4), + CIPHEROPTION(CALG_MD5), + CIPHEROPTION(CALG_SHA), + CIPHEROPTION(CALG_SHA1), + CIPHEROPTION(CALG_MAC), + CIPHEROPTION(CALG_RSA_SIGN), + CIPHEROPTION(CALG_DSS_SIGN), +/* ifdefs for the options that are defined conditionally in wincrypt.h */ +#ifdef CALG_NO_SIGN + CIPHEROPTION(CALG_NO_SIGN), +#endif + CIPHEROPTION(CALG_RSA_KEYX), + CIPHEROPTION(CALG_DES), +#ifdef CALG_3DES_112 + CIPHEROPTION(CALG_3DES_112), +#endif + CIPHEROPTION(CALG_3DES), + CIPHEROPTION(CALG_DESX), + CIPHEROPTION(CALG_RC2), + CIPHEROPTION(CALG_RC4), + CIPHEROPTION(CALG_SEAL), +#ifdef CALG_DH_SF + CIPHEROPTION(CALG_DH_SF), +#endif + CIPHEROPTION(CALG_DH_EPHEM), +#ifdef CALG_AGREEDKEY_ANY + CIPHEROPTION(CALG_AGREEDKEY_ANY), +#endif +#ifdef CALG_HUGHES_MD5 + CIPHEROPTION(CALG_HUGHES_MD5), +#endif + CIPHEROPTION(CALG_SKIPJACK), +#ifdef CALG_TEK + CIPHEROPTION(CALG_TEK), +#endif + CIPHEROPTION(CALG_CYLINK_MEK), + CIPHEROPTION(CALG_SSL3_SHAMD5), +#ifdef CALG_SSL3_MASTER + CIPHEROPTION(CALG_SSL3_MASTER), +#endif +#ifdef CALG_SCHANNEL_MASTER_HASH + CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH), +#endif +#ifdef CALG_SCHANNEL_MAC_KEY + CIPHEROPTION(CALG_SCHANNEL_MAC_KEY), +#endif +#ifdef CALG_SCHANNEL_ENC_KEY + CIPHEROPTION(CALG_SCHANNEL_ENC_KEY), +#endif +#ifdef CALG_PCT1_MASTER + CIPHEROPTION(CALG_PCT1_MASTER), +#endif +#ifdef CALG_SSL2_MASTER + CIPHEROPTION(CALG_SSL2_MASTER), +#endif +#ifdef CALG_TLS1_MASTER + CIPHEROPTION(CALG_TLS1_MASTER), +#endif +#ifdef CALG_RC5 + CIPHEROPTION(CALG_RC5), +#endif +#ifdef CALG_HMAC + CIPHEROPTION(CALG_HMAC), +#endif +#ifdef CALG_TLS1PRF + CIPHEROPTION(CALG_TLS1PRF), +#endif +#ifdef CALG_HASH_REPLACE_OWF + CIPHEROPTION(CALG_HASH_REPLACE_OWF), +#endif +#ifdef CALG_AES_128 + CIPHEROPTION(CALG_AES_128), +#endif +#ifdef CALG_AES_192 + CIPHEROPTION(CALG_AES_192), +#endif +#ifdef CALG_AES_256 + CIPHEROPTION(CALG_AES_256), +#endif +#ifdef CALG_AES + CIPHEROPTION(CALG_AES), +#endif +#ifdef CALG_SHA_256 + CIPHEROPTION(CALG_SHA_256), +#endif +#ifdef CALG_SHA_384 + CIPHEROPTION(CALG_SHA_384), +#endif +#ifdef CALG_SHA_512 + CIPHEROPTION(CALG_SHA_512), +#endif +#ifdef CALG_ECDH + CIPHEROPTION(CALG_ECDH), +#endif +#ifdef CALG_ECMQV + CIPHEROPTION(CALG_ECMQV), +#endif +#ifdef CALG_ECDSA + CIPHEROPTION(CALG_ECDSA), +#endif +#ifdef CALG_ECDH_EPHEM + CIPHEROPTION(CALG_ECDH_EPHEM), +#endif + {NULL, 0}, +}; + +static int +get_alg_id_by_name(char *name) +{ + char *nameEnd = strchr(name, ':'); + size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name); + int i; + + for(i = 0; algs[i].name; i++) { + if((n == strlen(algs[i].name) && !strncmp(algs[i].name, name, n))) + return algs[i].id; + } + return 0; /* not found */ +} + +#define NUM_CIPHERS 47 /* There are 47 options listed above */ + +static CURLcode +set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers, + ALG_ID *algIds) +{ + char *startCur = ciphers; + int algCount = 0; + while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) { + long alg = strtol(startCur, 0, 0); + if(!alg) + alg = get_alg_id_by_name(startCur); + if(alg) + algIds[algCount++] = alg; + else if(!strncmp(startCur, "USE_STRONG_CRYPTO", + sizeof("USE_STRONG_CRYPTO") - 1) || + !strncmp(startCur, "SCH_USE_STRONG_CRYPTO", + sizeof("SCH_USE_STRONG_CRYPTO") - 1)) + schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO; + else + return CURLE_SSL_CIPHER; + startCur = strchr(startCur, ':'); + if(startCur) + startCur++; + } + schannel_cred->palgSupportedAlgs = algIds; + schannel_cred->cSupportedAlgs = algCount; + return CURLE_OK; +} + +#ifdef HAS_CLIENT_CERT_PATH + +/* Function allocates memory for store_path only if CURLE_OK is returned */ +static CURLcode +get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, + TCHAR **thumbprint) +{ + TCHAR *sep; + TCHAR *store_path_start; + size_t store_name_len; + + sep = _tcschr(path, TEXT('\\')); + if(!sep) + return CURLE_SSL_CERTPROBLEM; + + store_name_len = sep - path; + + if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_CURRENT_USER; + else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE; + else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE; + else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_SERVICES; + else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_USERS; + else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"), + store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY; + else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"), + store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY; + else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"), + store_name_len) == 0) + *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE; + else + return CURLE_SSL_CERTPROBLEM; + + store_path_start = sep + 1; + + sep = _tcschr(store_path_start, TEXT('\\')); + if(!sep) + return CURLE_SSL_CERTPROBLEM; + + *thumbprint = sep + 1; + if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN) + return CURLE_SSL_CERTPROBLEM; + + *sep = TEXT('\0'); + *store_path = _tcsdup(store_path_start); + *sep = TEXT('\\'); + if(!*store_path) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} +#endif + +static bool algo(const char *check, char *namep, size_t nlen) +{ + return (strlen(check) == nlen) && !strncmp(check, namep, nlen); +} + +static CURLcode +schannel_acquire_credential_handle(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + +#ifdef HAS_CLIENT_CERT_PATH + PCCERT_CONTEXT client_certs[1] = { NULL }; + HCERTSTORE client_cert_store = NULL; +#endif + SECURITY_STATUS sspi_status = SEC_E_OK; + CURLcode result; + + /* setup Schannel API options */ + DWORD flags = 0; + DWORD enabled_protocols = 0; + + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)(connssl->backend); + + DEBUGASSERT(backend); + + if(conn_config->verifypeer) { +#ifdef HAS_MANUAL_VERIFY_API + if(backend->use_manual_cred_validation) + flags = SCH_CRED_MANUAL_CRED_VALIDATION; + else +#endif + flags = SCH_CRED_AUTO_CRED_VALIDATION; + + if(ssl_config->no_revoke) { + flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + + DEBUGF(infof(data, "schannel: disabled server certificate revocation " + "checks")); + } + else if(ssl_config->revoke_best_effort) { + flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN; + + DEBUGF(infof(data, "schannel: ignore revocation offline errors")); + } + else { + flags |= SCH_CRED_REVOCATION_CHECK_CHAIN; + + DEBUGF(infof(data, + "schannel: checking server certificate revocation")); + } + } + else { + flags = SCH_CRED_MANUAL_CRED_VALIDATION | + SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + DEBUGF(infof(data, + "schannel: disabled server cert revocation checks")); + } + + if(!conn_config->verifyhost) { + flags |= SCH_CRED_NO_SERVERNAME_CHECK; + DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from " + "comparing the supplied target name with the subject " + "names in server certificates.")); + } + + if(!ssl_config->auto_client_cert) { + flags &= ~SCH_CRED_USE_DEFAULT_CREDS; + flags |= SCH_CRED_NO_DEFAULT_CREDS; + infof(data, "schannel: disabled automatic use of client certificate"); + } + else + infof(data, "schannel: enabled automatic use of client certificate"); + + switch(conn_config->version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + { + result = schannel_set_ssl_version_min_max(&enabled_protocols, cf, data); + if(result != CURLE_OK) + return result; + break; + } + case CURL_SSLVERSION_SSLv3: + case CURL_SSLVERSION_SSLv2: + failf(data, "SSL versions not supported"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + +#ifdef HAS_CLIENT_CERT_PATH + /* client certificate */ + if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { + DWORD cert_store_name = 0; + TCHAR *cert_store_path = NULL; + TCHAR *cert_thumbprint_str = NULL; + CRYPT_HASH_BLOB cert_thumbprint; + BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN]; + HCERTSTORE cert_store = NULL; + FILE *fInCert = NULL; + void *certdata = NULL; + size_t certsize = 0; + bool blob = data->set.ssl.primary.cert_blob != NULL; + TCHAR *cert_path = NULL; + if(blob) { + certdata = data->set.ssl.primary.cert_blob->data; + certsize = data->set.ssl.primary.cert_blob->len; + } + else { + cert_path = curlx_convert_UTF8_to_tchar( + data->set.ssl.primary.clientcert); + if(!cert_path) + return CURLE_OUT_OF_MEMORY; + + result = get_cert_location(cert_path, &cert_store_name, + &cert_store_path, &cert_thumbprint_str); + + if(result && (data->set.ssl.primary.clientcert[0]!='\0')) + fInCert = fopen(data->set.ssl.primary.clientcert, "rb"); + + if(result && !fInCert) { + failf(data, "schannel: Failed to get certificate location" + " or file for %s", + data->set.ssl.primary.clientcert); + curlx_unicodefree(cert_path); + return result; + } + } + + if((fInCert || blob) && (data->set.ssl.cert_type) && + (!strcasecompare(data->set.ssl.cert_type, "P12"))) { + failf(data, "schannel: certificate format compatibility error " + " for %s", + blob ? "(memory blob)" : data->set.ssl.primary.clientcert); + curlx_unicodefree(cert_path); + return CURLE_SSL_CERTPROBLEM; + } + + if(fInCert || blob) { + /* Reading a .P12 or .pfx file, like the example at bottom of + https://social.msdn.microsoft.com/Forums/windowsdesktop/ + en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 + */ + CRYPT_DATA_BLOB datablob; + WCHAR* pszPassword; + size_t pwd_len = 0; + int str_w_len = 0; + const char *cert_showfilename_error = blob ? + "(memory blob)" : data->set.ssl.primary.clientcert; + curlx_unicodefree(cert_path); + if(fInCert) { + long cert_tell = 0; + bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0; + if(continue_reading) + cert_tell = ftell(fInCert); + 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) + certdata = malloc(certsize + 1); + if((!certdata) || + ((int) fread(certdata, certsize, 1, fInCert) != 1)) + continue_reading = FALSE; + fclose(fInCert); + if(!continue_reading) { + failf(data, "schannel: Failed to read cert file %s", + data->set.ssl.primary.clientcert); + free(certdata); + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Convert key-pair data to the in-memory certificate store */ + datablob.pbData = (BYTE*)certdata; + datablob.cbData = (DWORD)certsize; + + if(data->set.ssl.key_passwd) + pwd_len = strlen(data->set.ssl.key_passwd); + pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1)); + if(pszPassword) { + if(pwd_len > 0) + str_w_len = MultiByteToWideChar(CP_UTF8, + MB_ERR_INVALID_CHARS, + data->set.ssl.key_passwd, + (int)pwd_len, + pszPassword, (int)(pwd_len + 1)); + + if((str_w_len >= 0) && (str_w_len <= (int)pwd_len)) + pszPassword[str_w_len] = 0; + else + pszPassword[0] = 0; + + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) + cert_store = PFXImportCertStore(&datablob, pszPassword, + PKCS12_NO_PERSIST_KEY); + else + cert_store = PFXImportCertStore(&datablob, pszPassword, 0); + + free(pszPassword); + } + if(!blob) + free(certdata); + if(!cert_store) { + DWORD errorcode = GetLastError(); + if(errorcode == ERROR_INVALID_PASSWORD) + failf(data, "schannel: Failed to import cert file %s, " + "password is bad", + cert_showfilename_error); + else + failf(data, "schannel: Failed to import cert file %s, " + "last error is 0x%lx", + cert_showfilename_error, errorcode); + return CURLE_SSL_CERTPROBLEM; + } + + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_ANY, NULL, NULL); + + if(!client_certs[0]) { + failf(data, "schannel: Failed to get certificate from file %s" + ", last error is 0x%lx", + cert_showfilename_error, GetLastError()); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + } + else { + cert_store = + CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, + (HCRYPTPROV)NULL, + CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, + cert_store_path); + if(!cert_store) { + char *path_utf8 = + curlx_convert_tchar_to_UTF8(cert_store_path); + failf(data, "schannel: Failed to open cert store %lx %s, " + "last error is 0x%lx", + cert_store_name, + (path_utf8 ? path_utf8 : "(unknown)"), + GetLastError()); + free(cert_store_path); + curlx_unicodefree(path_utf8); + curlx_unicodefree(cert_path); + return CURLE_SSL_CERTPROBLEM; + } + free(cert_store_path); + + cert_thumbprint.pbData = cert_thumbprint_data; + cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; + + if(!CryptStringToBinary(cert_thumbprint_str, + CERT_THUMBPRINT_STR_LEN, + CRYPT_STRING_HEX, + cert_thumbprint_data, + &cert_thumbprint.cbData, + NULL, NULL)) { + curlx_unicodefree(cert_path); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_HASH, &cert_thumbprint, NULL); + + curlx_unicodefree(cert_path); + + if(!client_certs[0]) { + /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + } + client_cert_store = cert_store; + } +#else + if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { + failf(data, "schannel: client cert support not built in"); + return CURLE_NOT_BUILT_IN; + } +#endif + + /* allocate memory for the reusable credential handle */ + backend->cred = (struct Curl_schannel_cred *) + calloc(1, sizeof(struct Curl_schannel_cred)); + if(!backend->cred) { + failf(data, "schannel: unable to allocate memory"); + +#ifdef HAS_CLIENT_CERT_PATH + if(client_certs[0]) + CertFreeCertificateContext(client_certs[0]); + if(client_cert_store) + CertCloseStore(client_cert_store, 0); +#endif + + return CURLE_OUT_OF_MEMORY; + } + backend->cred->refcount = 1; + +#ifdef HAS_CLIENT_CERT_PATH + /* Since we did not persist the key, we need to extend the store's + * lifetime until the end of the connection + */ + backend->cred->client_cert_store = client_cert_store; +#endif + + /* We support TLS 1.3 starting in Windows 10 version 1809 (OS build 17763) as + long as the user did not set a legacy algorithm list + (CURLOPT_SSL_CIPHER_LIST). */ + if(!conn_config->cipher_list && + curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + + char *ciphers13 = 0; + + bool disable_aes_gcm_sha384 = FALSE; + bool disable_aes_gcm_sha256 = FALSE; + bool disable_chacha_poly = FALSE; + bool disable_aes_ccm_8_sha256 = FALSE; + bool disable_aes_ccm_sha256 = FALSE; + + SCH_CREDENTIALS credentials = { 0 }; + TLS_PARAMETERS tls_parameters = { 0 }; + CRYPTO_SETTINGS crypto_settings[4] = { { 0 } }; + UNICODE_STRING blocked_ccm_modes[1] = { { 0 } }; + UNICODE_STRING blocked_gcm_modes[1] = { { 0 } }; + + int crypto_settings_idx = 0; + + + /* If TLS 1.3 ciphers are explicitly listed, then + * disable all the ciphers and re-enable which + * ciphers the user has provided. + */ + ciphers13 = conn_config->cipher_list13; + if(ciphers13) { + const int remaining_ciphers = 5; + + /* detect which remaining ciphers to enable + and then disable everything else. + */ + + char *startCur = ciphers13; + int algCount = 0; + char *nameEnd; + + disable_aes_gcm_sha384 = TRUE; + disable_aes_gcm_sha256 = TRUE; + disable_chacha_poly = TRUE; + disable_aes_ccm_8_sha256 = TRUE; + disable_aes_ccm_sha256 = TRUE; + + while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) { + size_t n; + char *namep; + nameEnd = strchr(startCur, ':'); + n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur); + namep = startCur; + + if(disable_aes_gcm_sha384 && + algo("TLS_AES_256_GCM_SHA384", namep, n)) { + disable_aes_gcm_sha384 = FALSE; + } + else if(disable_aes_gcm_sha256 + && algo("TLS_AES_128_GCM_SHA256", namep, n)) { + disable_aes_gcm_sha256 = FALSE; + } + else if(disable_chacha_poly + && algo("TLS_CHACHA20_POLY1305_SHA256", namep, n)) { + disable_chacha_poly = FALSE; + } + else if(disable_aes_ccm_8_sha256 + && algo("TLS_AES_128_CCM_8_SHA256", namep, n)) { + disable_aes_ccm_8_sha256 = FALSE; + } + else if(disable_aes_ccm_sha256 + && algo("TLS_AES_128_CCM_SHA256", namep, n)) { + disable_aes_ccm_sha256 = FALSE; + } + else { + failf(data, "schannel: Unknown TLS 1.3 cipher: %.*s", (int)n, namep); + return CURLE_SSL_CIPHER; + } + + startCur = nameEnd; + if(startCur) + startCur++; + + algCount++; + } + } + + if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256 + && disable_chacha_poly && disable_aes_ccm_8_sha256 + && disable_aes_ccm_sha256) { + failf(data, "schannel: All available TLS 1.3 ciphers were disabled"); + return CURLE_SSL_CIPHER; + } + + /* Disable TLS_AES_128_CCM_8_SHA256 and/or TLS_AES_128_CCM_SHA256 */ + if(disable_aes_ccm_8_sha256 || disable_aes_ccm_sha256) { + /* + Disallow AES_CCM algorithm. + */ + blocked_ccm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_CCM); + blocked_ccm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_CCM); + blocked_ccm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_CCM; + + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageCipher; + crypto_settings[crypto_settings_idx].rgstrChainingModes = + blocked_ccm_modes; + crypto_settings[crypto_settings_idx].cChainingModes = + ARRAYSIZE(blocked_ccm_modes); + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)BCRYPT_AES_ALGORITHM; + + /* only disabling one of the CCM modes */ + if(disable_aes_ccm_8_sha256 != disable_aes_ccm_sha256) { + if(disable_aes_ccm_8_sha256) + crypto_settings[crypto_settings_idx].dwMinBitLength = 128; + else /* disable_aes_ccm_sha256 */ + crypto_settings[crypto_settings_idx].dwMaxBitLength = 64; + } + + crypto_settings_idx++; + } + + /* Disable TLS_AES_256_GCM_SHA384 and/or TLS_AES_128_GCM_SHA256 */ + if(disable_aes_gcm_sha384 || disable_aes_gcm_sha256) { + + /* + Disallow AES_GCM algorithm + */ + blocked_gcm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_GCM); + blocked_gcm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_GCM); + blocked_gcm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_GCM; + + /* if only one is disabled, then explicitly disable the + digest cipher suite (sha384 or sha256) */ + if(disable_aes_gcm_sha384 != disable_aes_gcm_sha256) { + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageDigest; + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(disable_aes_gcm_sha384 ? + BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(disable_aes_gcm_sha384 ? + BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)(disable_aes_gcm_sha384 ? + BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM); + } + else { /* Disable both AES_GCM ciphers */ + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageCipher; + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)BCRYPT_AES_ALGORITHM; + } + + crypto_settings[crypto_settings_idx].rgstrChainingModes = + blocked_gcm_modes; + crypto_settings[crypto_settings_idx].cChainingModes = 1; + + crypto_settings_idx++; + } + + /* + Disable ChaCha20-Poly1305. + */ + if(disable_chacha_poly) { + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageCipher; + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM; + crypto_settings_idx++; + } + + tls_parameters.pDisabledCrypto = crypto_settings; + + /* The number of blocked suites */ + tls_parameters.cDisabledCrypto = crypto_settings_idx; + credentials.pTlsParameters = &tls_parameters; + credentials.cTlsParameters = 1; + + credentials.dwVersion = SCH_CREDENTIALS_VERSION; + credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO; + + credentials.pTlsParameters->grbitDisabledProtocols = + (DWORD)~enabled_protocols; + +#ifdef HAS_CLIENT_CERT_PATH + if(client_certs[0]) { + credentials.cCreds = 1; + credentials.paCred = client_certs; + } +#endif + + sspi_status = + s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME, + SECPKG_CRED_OUTBOUND, NULL, + &credentials, NULL, NULL, + &backend->cred->cred_handle, + &backend->cred->time_stamp); + } + else { + /* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS + doesn't document it, currently Schannel will not negotiate TLS 1.3 when + SCHANNEL_CRED is used. */ + ALG_ID algIds[NUM_CIPHERS]; + char *ciphers = conn_config->cipher_list; + SCHANNEL_CRED schannel_cred = { 0 }; + schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; + schannel_cred.dwFlags = flags; + schannel_cred.grbitEnabledProtocols = enabled_protocols; + + if(ciphers) { + if((enabled_protocols & SP_PROT_TLS1_3_CLIENT)) { + infof(data, "schannel: WARNING: This version of Schannel may " + "negotiate a less-secure TLS version than TLS 1.3 because the " + "user set an algorithm cipher list."); + } + if(conn_config->cipher_list13) { + failf(data, "schannel: This version of Schannel does not support " + "setting an algorithm cipher list and TLS 1.3 cipher list at " + "the same time"); + return CURLE_SSL_CIPHER; + } + result = set_ssl_ciphers(&schannel_cred, ciphers, algIds); + if(CURLE_OK != result) { + failf(data, "schannel: Failed setting algorithm cipher list"); + return result; + } + } + else { + schannel_cred.dwFlags = flags | SCH_USE_STRONG_CRYPTO; + } + +#ifdef HAS_CLIENT_CERT_PATH + if(client_certs[0]) { + schannel_cred.cCreds = 1; + schannel_cred.paCred = client_certs; + } +#endif + + sspi_status = + s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME, + SECPKG_CRED_OUTBOUND, NULL, + &schannel_cred, NULL, NULL, + &backend->cred->cred_handle, + &backend->cred->time_stamp); + } + +#ifdef HAS_CLIENT_CERT_PATH + if(client_certs[0]) + CertFreeCertificateContext(client_certs[0]); +#endif + + if(sspi_status != SEC_E_OK) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: AcquireCredentialsHandle failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + Curl_safefree(backend->cred); + switch(sspi_status) { + case SEC_E_INSUFFICIENT_MEMORY: + return CURLE_OUT_OF_MEMORY; + case SEC_E_NO_CREDENTIALS: + case SEC_E_SECPKG_NOT_FOUND: + case SEC_E_NOT_OWNER: + case SEC_E_UNKNOWN_CREDENTIALS: + case SEC_E_INTERNAL_ERROR: + default: + return CURLE_SSL_CONNECT_ERROR; + } + } + + return CURLE_OK; +} + +static CURLcode +schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + ssize_t written = -1; + struct ssl_connect_data *connssl = cf->ctx; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + SecBuffer outbuf; + SecBufferDesc outbuf_desc; + SecBuffer inbuf; + SecBufferDesc inbuf_desc; +#ifdef HAS_ALPN + unsigned char alpn_buffer[128]; +#endif + SECURITY_STATUS sspi_status = SEC_E_OK; + struct Curl_schannel_cred *old_cred = NULL; + CURLcode result; + + DEBUGASSERT(backend); + DEBUGF(infof(data, + "schannel: SSL/TLS connection with %s port %d (step 1/3)", + connssl->peer.hostname, connssl->port)); + + if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT, + VERSION_LESS_THAN_EQUAL)) { + /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and + algorithms that may not be supported by all servers. */ + infof(data, "schannel: Windows version is old and may not be able to " + "connect to some servers due to lack of SNI, algorithms, etc."); + } + +#ifdef HAS_ALPN + /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. + Also it doesn't seem to be supported for Wine, see curl bug #983. */ + backend->use_alpn = connssl->alpn && + !GetProcAddress(GetModuleHandle(TEXT("ntdll")), + "wine_get_version") && + curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL); +#else + backend->use_alpn = false; +#endif + +#ifdef _WIN32_WCE +#ifdef HAS_MANUAL_VERIFY_API + /* certificate validation on CE doesn't seem to work right; we'll + * do it following a more manual process. */ + backend->use_manual_cred_validation = true; +#else +#error "compiler too old to support requisite manual cert verify for Win CE" +#endif +#else +#ifdef HAS_MANUAL_VERIFY_API + if(conn_config->CAfile || conn_config->ca_info_blob) { + if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + backend->use_manual_cred_validation = true; + } + else { + failf(data, "schannel: this version of Windows is too old to support " + "certificate verification via CA bundle file."); + return CURLE_SSL_CACERT_BADFILE; + } + } + else + backend->use_manual_cred_validation = false; +#else + if(conn_config->CAfile || conn_config->ca_info_blob) { + failf(data, "schannel: CA cert support not built in"); + return CURLE_NOT_BUILT_IN; + } +#endif +#endif + + backend->cred = NULL; + + /* check for an existing reusable credential handle */ + if(ssl_config->primary.sessionid) { + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) { + backend->cred = old_cred; + DEBUGF(infof(data, "schannel: reusing existing credential handle")); + + /* increment the reference counter of the credential/session handle */ + backend->cred->refcount++; + DEBUGF(infof(data, + "schannel: incremented credential handle refcount = %d", + backend->cred->refcount)); + } + Curl_ssl_sessionid_unlock(data); + } + + if(!backend->cred) { + char *snihost; + result = schannel_acquire_credential_handle(cf, data); + if(result) + return result; + /* schannel_acquire_credential_handle() sets backend->cred accordingly or + it returns error otherwise. */ + + /* A hostname associated with the credential is needed by + InitializeSecurityContext for SNI and other reasons. */ + snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname; + backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost); + if(!backend->cred->sni_hostname) + return CURLE_OUT_OF_MEMORY; + } + + /* Warn if SNI is disabled due to use of an IP address */ + if(connssl->peer.is_ip_address) { + infof(data, "schannel: using IP address, SNI is not supported by OS."); + } + +#ifdef HAS_ALPN + if(backend->use_alpn) { + int cur = 0; + int list_start_index = 0; + unsigned int *extension_len = NULL; + unsigned short* list_len = NULL; + struct alpn_proto_buf proto; + + /* The first four bytes will be an unsigned int indicating number + of bytes of data in the rest of the buffer. */ + extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]); + cur += (int)sizeof(unsigned int); + + /* The next four bytes are an indicator that this buffer will contain + ALPN data, as opposed to NPN, for example. */ + *(unsigned int *)(void *)&alpn_buffer[cur] = + SecApplicationProtocolNegotiationExt_ALPN; + cur += (int)sizeof(unsigned int); + + /* The next two bytes will be an unsigned short indicating the number + of bytes used to list the preferred protocols. */ + list_len = (unsigned short*)(void *)(&alpn_buffer[cur]); + cur += (int)sizeof(unsigned short); + + list_start_index = cur; + + result = Curl_alpn_to_proto_buf(&proto, connssl->alpn); + if(result) { + failf(data, "Error setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } + memcpy(&alpn_buffer[cur], proto.data, proto.len); + cur += proto.len; + + *list_len = curlx_uitous(cur - list_start_index); + *extension_len = (unsigned int)(*list_len + + sizeof(unsigned int) + sizeof(unsigned short)); + + InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); + + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } + else { + InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); + } +#else /* HAS_ALPN */ + InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); +#endif + + /* setup output buffer */ + InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, &outbuf, 1); + + /* security request flags */ + backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_STREAM; + + if(!ssl_config->auto_client_cert) { + backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + } + + /* allocate memory for the security context handle */ + backend->ctxt = (struct Curl_schannel_ctxt *) + calloc(1, sizeof(struct Curl_schannel_ctxt)); + if(!backend->ctxt) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + + /* Schannel InitializeSecurityContext: + https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + + At the moment we don't pass inbuf unless we're using ALPN since we only + use it for that, and Wine (for which we currently disable ALPN) is giving + us problems with inbuf regardless. https://github.com/curl/curl/issues/983 + */ + sspi_status = s_pSecFn->InitializeSecurityContext( + &backend->cred->cred_handle, NULL, backend->cred->sni_hostname, + backend->req_flags, 0, 0, + (backend->use_alpn ? &inbuf_desc : NULL), + 0, &backend->ctxt->ctxt_handle, + &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); + + if(sspi_status != SEC_I_CONTINUE_NEEDED) { + char buffer[STRERROR_LEN]; + Curl_safefree(backend->ctxt); + switch(sspi_status) { + case SEC_E_INSUFFICIENT_MEMORY: + failf(data, "schannel: initial InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_OUT_OF_MEMORY; + case SEC_E_WRONG_PRINCIPAL: + failf(data, "schannel: SNI or certificate check failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_PEER_FAILED_VERIFICATION; + /* + case SEC_E_INVALID_HANDLE: + case SEC_E_INVALID_TOKEN: + case SEC_E_LOGON_DENIED: + case SEC_E_TARGET_UNKNOWN: + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + case SEC_E_INTERNAL_ERROR: + case SEC_E_NO_CREDENTIALS: + case SEC_E_UNSUPPORTED_FUNCTION: + case SEC_E_APPLICATION_PROTOCOL_MISMATCH: + */ + default: + failf(data, "schannel: initial InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + } + + DEBUGF(infof(data, "schannel: sending initial handshake data: " + "sending %lu bytes.", outbuf.cbBuffer)); + + /* send initial handshake data which is now stored in output buffer */ + written = Curl_conn_cf_send(cf->next, data, + outbuf.pvBuffer, outbuf.cbBuffer, + &result); + s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); + if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { + failf(data, "schannel: failed to send initial handshake data: " + "sent %zd of %lu bytes", written, outbuf.cbBuffer); + return CURLE_SSL_CONNECT_ERROR; + } + + DEBUGF(infof(data, "schannel: sent initial handshake data: " + "sent %zd bytes", written)); + + backend->recv_unrecoverable_err = CURLE_OK; + backend->recv_sspi_close_notify = false; + backend->recv_connection_closed = false; + backend->recv_renegotiating = false; + backend->encdata_is_incomplete = false; + + /* continue to second handshake step */ + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static CURLcode +schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + int i; + ssize_t nread = -1, written = -1; + unsigned char *reallocated_buffer; + SecBuffer outbuf[3]; + SecBufferDesc outbuf_desc; + SecBuffer inbuf[2]; + SecBufferDesc inbuf_desc; + SECURITY_STATUS sspi_status = SEC_E_OK; + CURLcode result; + bool doread; + const char *pubkey_ptr; + + DEBUGASSERT(backend); + + doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; + + DEBUGF(infof(data, + "schannel: SSL/TLS connection with %s port %d (step 2/3)", + connssl->peer.hostname, connssl->port)); + + if(!backend->cred || !backend->ctxt) + return CURLE_SSL_CONNECT_ERROR; + + /* buffer to store previously received and decrypted data */ + if(!backend->decdata_buffer) { + backend->decdata_offset = 0; + backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + backend->decdata_buffer = malloc(backend->decdata_length); + if(!backend->decdata_buffer) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + } + + /* buffer to store previously received and encrypted data */ + if(!backend->encdata_buffer) { + backend->encdata_is_incomplete = false; + backend->encdata_offset = 0; + backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + backend->encdata_buffer = malloc(backend->encdata_length); + if(!backend->encdata_buffer) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + } + + /* if we need a bigger buffer to read a full message, increase buffer now */ + if(backend->encdata_length - backend->encdata_offset < + CURL_SCHANNEL_BUFFER_FREE_SIZE) { + /* increase internal encrypted data buffer */ + size_t reallocated_length = backend->encdata_offset + + CURL_SCHANNEL_BUFFER_FREE_SIZE; + reallocated_buffer = realloc(backend->encdata_buffer, + reallocated_length); + + if(!reallocated_buffer) { + failf(data, "schannel: unable to re-allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + else { + backend->encdata_buffer = reallocated_buffer; + backend->encdata_length = reallocated_length; + } + } + + for(;;) { + if(doread) { + /* read encrypted handshake data from socket */ + nread = Curl_conn_cf_recv(cf->next, data, + (char *) (backend->encdata_buffer + + backend->encdata_offset), + backend->encdata_length - + backend->encdata_offset, + &result); + if(result == CURLE_AGAIN) { + if(connssl->connecting_state != ssl_connect_2_writing) + connssl->connecting_state = ssl_connect_2_reading; + DEBUGF(infof(data, "schannel: failed to receive handshake, " + "need more data")); + return CURLE_OK; + } + else if((result != CURLE_OK) || (nread == 0)) { + failf(data, "schannel: failed to receive handshake, " + "SSL/TLS connection failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* increase encrypted data buffer offset */ + backend->encdata_offset += nread; + backend->encdata_is_incomplete = false; + DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); + } + + DEBUGF(infof(data, + "schannel: encrypted data buffer: offset %zu length %zu", + backend->encdata_offset, backend->encdata_length)); + + /* setup input buffers */ + InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset), + curlx_uztoul(backend->encdata_offset)); + InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, inbuf, 2); + + /* setup output buffers */ + InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); + InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); + InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, outbuf, 3); + + if(!inbuf[0].pvBuffer) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + + /* copy received handshake data into input buffer */ + memcpy(inbuf[0].pvBuffer, backend->encdata_buffer, + backend->encdata_offset); + + sspi_status = s_pSecFn->InitializeSecurityContext( + &backend->cred->cred_handle, &backend->ctxt->ctxt_handle, + backend->cred->sni_hostname, backend->req_flags, + 0, 0, &inbuf_desc, 0, NULL, + &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); + + /* free buffer for received handshake data */ + Curl_safefree(inbuf[0].pvBuffer); + + /* check if the handshake was incomplete */ + if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { + backend->encdata_is_incomplete = true; + connssl->connecting_state = ssl_connect_2_reading; + DEBUGF(infof(data, + "schannel: received incomplete message, need more data")); + return CURLE_OK; + } + + /* If the server has requested a client certificate, attempt to continue + the handshake without one. This will allow connections to servers which + request a client certificate but do not require it. */ + if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && + !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { + backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + connssl->connecting_state = ssl_connect_2_writing; + DEBUGF(infof(data, + "schannel: a client certificate has been requested")); + return CURLE_OK; + } + + /* check if the handshake needs to be continued */ + if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { + for(i = 0; i < 3; i++) { + /* search for handshake tokens that need to be send */ + if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { + DEBUGF(infof(data, "schannel: sending next handshake data: " + "sending %lu bytes.", outbuf[i].cbBuffer)); + + /* send handshake token to server */ + written = Curl_conn_cf_send(cf->next, data, + outbuf[i].pvBuffer, outbuf[i].cbBuffer, + &result); + if((result != CURLE_OK) || + (outbuf[i].cbBuffer != (size_t) written)) { + failf(data, "schannel: failed to send next handshake data: " + "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* free obsolete buffer */ + if(outbuf[i].pvBuffer) { + s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer); + } + } + } + else { + char buffer[STRERROR_LEN]; + switch(sspi_status) { + case SEC_E_INSUFFICIENT_MEMORY: + failf(data, "schannel: next InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_OUT_OF_MEMORY; + case SEC_E_WRONG_PRINCIPAL: + failf(data, "schannel: SNI or certificate check failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_PEER_FAILED_VERIFICATION; + case SEC_E_UNTRUSTED_ROOT: + failf(data, "schannel: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_PEER_FAILED_VERIFICATION; + /* + case SEC_E_INVALID_HANDLE: + case SEC_E_INVALID_TOKEN: + case SEC_E_LOGON_DENIED: + case SEC_E_TARGET_UNKNOWN: + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + case SEC_E_INTERNAL_ERROR: + case SEC_E_NO_CREDENTIALS: + case SEC_E_UNSUPPORTED_FUNCTION: + case SEC_E_APPLICATION_PROTOCOL_MISMATCH: + */ + default: + failf(data, "schannel: next InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* check if there was additional remaining encrypted data */ + if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { + DEBUGF(infof(data, "schannel: encrypted data length: %lu", + inbuf[1].cbBuffer)); + /* + There are two cases where we could be getting extra data here: + 1) If we're renegotiating a connection and the handshake is already + complete (from the server perspective), it can encrypted app data + (not handshake data) in an extra buffer at this point. + 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a + connection and this extra data is part of the handshake. + We should process the data immediately; waiting for the socket to + be ready may fail since the server is done sending handshake data. + */ + /* check if the remaining data is less than the total amount + and therefore begins after the already processed data */ + if(backend->encdata_offset > inbuf[1].cbBuffer) { + memmove(backend->encdata_buffer, + (backend->encdata_buffer + backend->encdata_offset) - + inbuf[1].cbBuffer, inbuf[1].cbBuffer); + backend->encdata_offset = inbuf[1].cbBuffer; + if(sspi_status == SEC_I_CONTINUE_NEEDED) { + doread = FALSE; + continue; + } + } + } + else { + backend->encdata_offset = 0; + } + break; + } + + /* check if the handshake needs to be continued */ + if(sspi_status == SEC_I_CONTINUE_NEEDED) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + + /* check if the handshake is complete */ + if(sspi_status == SEC_E_OK) { + connssl->connecting_state = ssl_connect_3; + DEBUGF(infof(data, "schannel: SSL/TLS handshake complete")); + } + + pubkey_ptr = Curl_ssl_cf_is_proxy(cf)? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(pubkey_ptr) { + result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr); + if(result) { + failf(data, "SSL: public key does not match pinned public key"); + return result; + } + } + +#ifdef HAS_MANUAL_VERIFY_API + if(conn_config->verifypeer && backend->use_manual_cred_validation) { + /* Certificate verification also verifies the hostname if verifyhost */ + return Curl_verify_certificate(cf, data); + } +#endif + + /* Verify the hostname manually when certificate verification is disabled, + because in that case Schannel won't verify it. */ + if(!conn_config->verifypeer && conn_config->verifyhost) + return Curl_verify_host(cf, data); + + return CURLE_OK; +} + +static bool +valid_cert_encoding(const CERT_CONTEXT *cert_context) +{ + return (cert_context != NULL) && + ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && + (cert_context->pbCertEncoded != NULL) && + (cert_context->cbCertEncoded > 0); +} + +typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, + bool reverse_order, void *arg); + +static void +traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func, + void *arg) +{ + const CERT_CONTEXT *current_context = NULL; + bool should_continue = true; + bool first = true; + bool reverse_order = false; + while(should_continue && + (current_context = CertEnumCertificatesInStore( + context->hCertStore, + current_context)) != NULL) { + /* Windows 11 22H2 OS Build 22621.674 or higher enumerates certificates in + leaf-to-root order while all previous versions of Windows enumerate + certificates in root-to-leaf order. Determine the order of enumeration + by comparing SECPKG_ATTR_REMOTE_CERT_CONTEXT's pbCertContext with the + first certificate's pbCertContext. */ + if(first && context->pbCertEncoded != current_context->pbCertEncoded) + reverse_order = true; + should_continue = func(current_context, reverse_order, arg); + first = false; + } + + if(current_context) + CertFreeCertificateContext(current_context); +} + +static bool +cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order, + void *certs_count) +{ + (void)reverse_order; /* unused */ + if(valid_cert_encoding(ccert_context)) + (*(int *)certs_count)++; + return true; +} + +struct Adder_args +{ + struct Curl_easy *data; + CURLcode result; + int idx; + int certs_count; +}; + +static bool +add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order, + void *raw_arg) +{ + struct Adder_args *args = (struct Adder_args*)raw_arg; + args->result = CURLE_OK; + if(valid_cert_encoding(ccert_context)) { + const char *beg = (const char *) ccert_context->pbCertEncoded; + const char *end = beg + ccert_context->cbCertEncoded; + int insert_index = reverse_order ? (args->certs_count - 1) - args->idx : + args->idx; + args->result = Curl_extract_certinfo(args->data, insert_index, + beg, end); + args->idx++; + } + return args->result == CURLE_OK; +} + +static CURLcode +schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + CURLcode result = CURLE_OK; + SECURITY_STATUS sspi_status = SEC_E_OK; + CERT_CONTEXT *ccert_context = NULL; +#ifdef HAS_ALPN + SecPkgContext_ApplicationProtocol alpn_result; +#endif + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + DEBUGASSERT(backend); + + DEBUGF(infof(data, + "schannel: SSL/TLS connection with %s port %d (step 3/3)", + connssl->peer.hostname, connssl->port)); + + if(!backend->cred) + return CURLE_SSL_CONNECT_ERROR; + + /* check if the required context attributes are met */ + if(backend->ret_flags != backend->req_flags) { + if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT)) + failf(data, "schannel: failed to setup sequence detection"); + if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT)) + failf(data, "schannel: failed to setup replay detection"); + if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY)) + failf(data, "schannel: failed to setup confidentiality"); + if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY)) + failf(data, "schannel: failed to setup memory allocation"); + if(!(backend->ret_flags & ISC_RET_STREAM)) + failf(data, "schannel: failed to setup stream orientation"); + return CURLE_SSL_CONNECT_ERROR; + } + +#ifdef HAS_ALPN + if(backend->use_alpn) { + sspi_status = + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, + SECPKG_ATTR_APPLICATION_PROTOCOL, + &alpn_result); + + if(sspi_status != SEC_E_OK) { + failf(data, "schannel: failed to retrieve ALPN result"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(alpn_result.ProtoNegoStatus == + SecApplicationProtocolNegotiationStatus_Success) { + unsigned char prev_alpn = cf->conn->alpn; + + Curl_alpn_set_negotiated(cf, data, alpn_result.ProtocolId, + alpn_result.ProtocolIdSize); + if(backend->recv_renegotiating) { + if(prev_alpn != cf->conn->alpn && + prev_alpn != CURL_HTTP_VERSION_NONE) { + /* Renegotiation selected a different protocol now, we cannot + * deal with this */ + failf(data, "schannel: server selected an ALPN protocol too late"); + return CURLE_SSL_CONNECT_ERROR; + } + } + } + else { + if(!backend->recv_renegotiating) + Curl_alpn_set_negotiated(cf, data, NULL, 0); + } + } +#endif + + /* save the current session data for possible reuse */ + if(ssl_config->primary.sessionid) { + bool incache; + bool added = FALSE; + struct Curl_schannel_cred *old_cred = NULL; + + Curl_ssl_sessionid_lock(data); + incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)); + if(incache) { + if(old_cred != backend->cred) { + DEBUGF(infof(data, + "schannel: old credential handle is stale, removing")); + /* we're not taking old_cred ownership here, no refcount++ is needed */ + Curl_ssl_delsessionid(data, (void *)old_cred); + incache = FALSE; + } + } + if(!incache) { + result = Curl_ssl_addsessionid(cf, data, backend->cred, + sizeof(struct Curl_schannel_cred), + &added); + if(result) { + Curl_ssl_sessionid_unlock(data); + failf(data, "schannel: failed to store credential handle"); + return result; + } + else if(added) { + /* this cred session is now also referenced by sessionid cache */ + backend->cred->refcount++; + DEBUGF(infof(data, + "schannel: stored credential handle in session cache")); + } + } + Curl_ssl_sessionid_unlock(data); + } + + if(data->set.ssl.certinfo) { + int certs_count = 0; + sspi_status = + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &ccert_context); + + if((sspi_status != SEC_E_OK) || !ccert_context) { + failf(data, "schannel: failed to retrieve remote cert context"); + return CURLE_PEER_FAILED_VERIFICATION; + } + + traverse_cert_store(ccert_context, cert_counter_callback, &certs_count); + + result = Curl_ssl_init_certinfo(data, certs_count); + if(!result) { + struct Adder_args args; + args.data = data; + args.idx = 0; + args.certs_count = certs_count; + traverse_cert_store(ccert_context, add_cert_to_certinfo, &args); + result = args.result; + } + CertFreeCertificateContext(ccert_context); + if(result) + return result; + } + + connssl->connecting_state = ssl_connect_done; + + return CURLE_OK; +} + +static CURLcode +schannel_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool nonblocking, bool *done) +{ + CURLcode result; + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + timediff_t timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + /* check out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL/TLS connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = schannel_connect_step1(cf, data); + if(result) + return result; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL/TLS connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; + + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL/TLS connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + result = schannel_connect_step2(cf, data); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; + + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3 == connssl->connecting_state) { + result = schannel_connect_step3(cf, data); + if(result) + return result; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + /* When SSPI is used in combination with Schannel + * we need the Schannel context to create the Schannel + * binding to pass the IIS extended protection checks. + * Available on Windows 7 or later. + */ + { + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + DEBUGASSERT(backend); + cf->conn->sslContext = &backend->ctxt->ctxt_handle; + } +#endif + + *done = TRUE; + } + else + *done = FALSE; + + /* reset our connection state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +static ssize_t +schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, CURLcode *err) +{ + ssize_t written = -1; + size_t data_len = 0; + unsigned char *ptr = NULL; + struct ssl_connect_data *connssl = cf->ctx; + SecBuffer outbuf[4]; + SecBufferDesc outbuf_desc; + SECURITY_STATUS sspi_status = SEC_E_OK; + CURLcode result; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + + DEBUGASSERT(backend); + + /* check if the maximum stream sizes were queried */ + if(backend->stream_sizes.cbMaximumMessage == 0) { + sspi_status = s_pSecFn->QueryContextAttributes( + &backend->ctxt->ctxt_handle, + SECPKG_ATTR_STREAM_SIZES, + &backend->stream_sizes); + if(sspi_status != SEC_E_OK) { + *err = CURLE_SEND_ERROR; + return -1; + } + } + + /* check if the buffer is longer than the maximum message length */ + if(len > backend->stream_sizes.cbMaximumMessage) { + len = backend->stream_sizes.cbMaximumMessage; + } + + /* calculate the complete message length and allocate a buffer for it */ + data_len = backend->stream_sizes.cbHeader + len + + backend->stream_sizes.cbTrailer; + ptr = (unsigned char *) malloc(data_len); + if(!ptr) { + *err = CURLE_OUT_OF_MEMORY; + return -1; + } + + /* setup output buffers (header, data, trailer, empty) */ + InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, + ptr, backend->stream_sizes.cbHeader); + InitSecBuffer(&outbuf[1], SECBUFFER_DATA, + ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len)); + InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, + ptr + backend->stream_sizes.cbHeader + len, + backend->stream_sizes.cbTrailer); + InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, outbuf, 4); + + /* copy data into output buffer */ + memcpy(outbuf[1].pvBuffer, buf, len); + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ + sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0, + &outbuf_desc, 0); + + /* check if the message was encrypted */ + if(sspi_status == SEC_E_OK) { + written = 0; + + /* send the encrypted message including header, data and trailer */ + len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; + + /* + It's important to send the full message which includes the header, + encrypted payload, and trailer. Until the client receives all the + data a coherent message has not been delivered and the client + can't read any of it. + + If we wanted to buffer the unwritten encrypted bytes, we would + tell the client that all data it has requested to be sent has been + sent. The unwritten encrypted bytes would be the first bytes to + send on the next invocation. + Here's the catch with this - if we tell the client that all the + bytes have been sent, will the client call this method again to + send the buffered data? Looking at who calls this function, it + seems the answer is NO. + */ + + /* send entire message or fail */ + while(len > (size_t)written) { + ssize_t this_write = 0; + int what; + timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE); + if(timeout_ms < 0) { + /* we already got the timeout */ + failf(data, "schannel: timed out sending data " + "(bytes sent: %zd)", written); + *err = CURLE_OPERATION_TIMEDOUT; + written = -1; + break; + } + else if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + what = SOCKET_WRITABLE(Curl_conn_cf_get_socket(cf, data), timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + *err = CURLE_SEND_ERROR; + written = -1; + break; + } + else if(0 == what) { + failf(data, "schannel: timed out sending data " + "(bytes sent: %zd)", written); + *err = CURLE_OPERATION_TIMEDOUT; + written = -1; + break; + } + /* socket is writable */ + + this_write = Curl_conn_cf_send(cf->next, data, + ptr + written, len - written, + &result); + if(result == CURLE_AGAIN) + continue; + else if(result != CURLE_OK) { + *err = result; + written = -1; + break; + } + + written += this_write; + } + } + else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) { + *err = CURLE_OUT_OF_MEMORY; + } + else{ + *err = CURLE_SEND_ERROR; + } + + Curl_safefree(ptr); + + if(len == (size_t)written) + /* Encrypted message including header, data and trailer entirely sent. + The return value is the number of unencrypted bytes that were sent. */ + written = outbuf[1].cbBuffer; + + return written; +} + +static ssize_t +schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *err) +{ + size_t size = 0; + ssize_t nread = -1; + struct ssl_connect_data *connssl = cf->ctx; + unsigned char *reallocated_buffer; + size_t reallocated_length; + bool done = FALSE; + SecBuffer inbuf[4]; + SecBufferDesc inbuf_desc; + SECURITY_STATUS sspi_status = SEC_E_OK; + /* we want the length of the encrypted buffer to be at least large enough + that it can hold all the bytes requested and some TLS record overhead. */ + size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + + DEBUGASSERT(backend); + + /**************************************************************************** + * Don't return or set backend->recv_unrecoverable_err unless in the cleanup. + * The pattern for return error is set *err, optional infof, goto cleanup. + * + * Our priority is to always return as much decrypted data to the caller as + * possible, even if an error occurs. The state of the decrypted buffer must + * always be valid. Transfer of decrypted data to the caller's buffer is + * handled in the cleanup. + */ + + DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len)); + *err = CURLE_OK; + + if(len && len <= backend->decdata_offset) { + infof(data, "schannel: enough decrypted data is already available"); + goto cleanup; + } + else if(backend->recv_unrecoverable_err) { + *err = backend->recv_unrecoverable_err; + infof(data, "schannel: an unrecoverable error occurred in a prior call"); + goto cleanup; + } + else if(backend->recv_sspi_close_notify) { + /* once a server has indicated shutdown there is no more encrypted data */ + infof(data, "schannel: server indicated shutdown in a prior call"); + goto cleanup; + } + + /* It's debatable what to return when !len. Regardless we can't return + immediately because there may be data to decrypt (in the case we want to + decrypt all encrypted cached data) so handle !len later in cleanup. + */ + else if(len && !backend->recv_connection_closed) { + /* increase enc buffer in order to fit the requested amount of data */ + size = backend->encdata_length - backend->encdata_offset; + if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || + backend->encdata_length < min_encdata_length) { + reallocated_length = backend->encdata_offset + + CURL_SCHANNEL_BUFFER_FREE_SIZE; + if(reallocated_length < min_encdata_length) { + reallocated_length = min_encdata_length; + } + reallocated_buffer = realloc(backend->encdata_buffer, + reallocated_length); + if(!reallocated_buffer) { + *err = CURLE_OUT_OF_MEMORY; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; + } + + backend->encdata_buffer = reallocated_buffer; + backend->encdata_length = reallocated_length; + size = backend->encdata_length - backend->encdata_offset; + DEBUGF(infof(data, "schannel: encdata_buffer resized %zu", + backend->encdata_length)); + } + + DEBUGF(infof(data, + "schannel: encrypted data buffer: offset %zu length %zu", + backend->encdata_offset, backend->encdata_length)); + + /* read encrypted data from socket */ + nread = Curl_conn_cf_recv(cf->next, data, + (char *)(backend->encdata_buffer + + backend->encdata_offset), + size, err); + if(*err) { + nread = -1; + if(*err == CURLE_AGAIN) + DEBUGF(infof(data, + "schannel: recv returned CURLE_AGAIN")); + else if(*err == CURLE_RECV_ERROR) + infof(data, "schannel: recv returned CURLE_RECV_ERROR"); + else + infof(data, "schannel: recv returned error %d", *err); + } + else if(nread == 0) { + backend->recv_connection_closed = true; + DEBUGF(infof(data, "schannel: server closed the connection")); + } + else if(nread > 0) { + backend->encdata_offset += (size_t)nread; + backend->encdata_is_incomplete = false; + DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); + } + } + + DEBUGF(infof(data, + "schannel: encrypted data buffer: offset %zu length %zu", + backend->encdata_offset, backend->encdata_length)); + + /* decrypt loop */ + while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK && + (!len || backend->decdata_offset < len || + backend->recv_connection_closed)) { + /* prepare data buffer for DecryptMessage call */ + InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer, + curlx_uztoul(backend->encdata_offset)); + + /* we need 3 more empty input buffers for possible output */ + InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); + InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0); + InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, inbuf, 4); + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx + */ + sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle, + &inbuf_desc, 0, NULL); + + /* check if everything went fine (server may want to renegotiate + or shutdown the connection context) */ + if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || + sspi_status == SEC_I_CONTEXT_EXPIRED) { + /* check for successfully decrypted data, even before actual + renegotiation or shutdown of the connection context */ + if(inbuf[1].BufferType == SECBUFFER_DATA) { + DEBUGF(infof(data, "schannel: decrypted data length: %lu", + inbuf[1].cbBuffer)); + + /* increase buffer in order to fit the received amount of data */ + size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? + inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; + if(backend->decdata_length - backend->decdata_offset < size || + backend->decdata_length < len) { + /* increase internal decrypted data buffer */ + reallocated_length = backend->decdata_offset + size; + /* make sure that the requested amount of data fits */ + if(reallocated_length < len) { + reallocated_length = len; + } + reallocated_buffer = realloc(backend->decdata_buffer, + reallocated_length); + if(!reallocated_buffer) { + *err = CURLE_OUT_OF_MEMORY; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; + } + backend->decdata_buffer = reallocated_buffer; + backend->decdata_length = reallocated_length; + } + + /* copy decrypted data to internal buffer */ + size = inbuf[1].cbBuffer; + if(size) { + memcpy(backend->decdata_buffer + backend->decdata_offset, + inbuf[1].pvBuffer, size); + backend->decdata_offset += size; + } + + DEBUGF(infof(data, "schannel: decrypted data added: %zu", size)); + DEBUGF(infof(data, + "schannel: decrypted cached: offset %zu length %zu", + backend->decdata_offset, backend->decdata_length)); + } + + /* check for remaining encrypted data */ + if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { + DEBUGF(infof(data, "schannel: encrypted data length: %lu", + inbuf[3].cbBuffer)); + + /* check if the remaining data is less than the total amount + * and therefore begins after the already processed data + */ + if(backend->encdata_offset > inbuf[3].cbBuffer) { + /* move remaining encrypted data forward to the beginning of + buffer */ + memmove(backend->encdata_buffer, + (backend->encdata_buffer + backend->encdata_offset) - + inbuf[3].cbBuffer, inbuf[3].cbBuffer); + backend->encdata_offset = inbuf[3].cbBuffer; + } + + DEBUGF(infof(data, + "schannel: encrypted cached: offset %zu length %zu", + backend->encdata_offset, backend->encdata_length)); + } + else { + /* reset encrypted buffer offset, because there is no data remaining */ + backend->encdata_offset = 0; + } + + /* check if server wants to renegotiate the connection context */ + if(sspi_status == SEC_I_RENEGOTIATE) { + infof(data, "schannel: remote party requests renegotiation"); + if(*err && *err != CURLE_AGAIN) { + infof(data, "schannel: can't renegotiate, an error is pending"); + goto cleanup; + } + + /* begin renegotiation */ + infof(data, "schannel: renegotiating SSL/TLS connection"); + connssl->state = ssl_connection_negotiating; + connssl->connecting_state = ssl_connect_2_writing; + backend->recv_renegotiating = true; + *err = schannel_connect_common(cf, data, FALSE, &done); + backend->recv_renegotiating = false; + if(*err) { + infof(data, "schannel: renegotiation failed"); + goto cleanup; + } + /* now retry receiving data */ + sspi_status = SEC_E_OK; + infof(data, "schannel: SSL/TLS connection renegotiated"); + continue; + } + /* check if the server closed the connection */ + else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { + /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not + returned so we have to work around that in cleanup. */ + backend->recv_sspi_close_notify = true; + if(!backend->recv_connection_closed) { + backend->recv_connection_closed = true; + infof(data, "schannel: server closed the connection"); + } + goto cleanup; + } + } + else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { + backend->encdata_is_incomplete = true; + if(!*err) + *err = CURLE_AGAIN; + infof(data, "schannel: failed to decrypt data, need more data"); + goto cleanup; + } + else { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + char buffer[STRERROR_LEN]; + infof(data, "schannel: failed to read data from server: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); +#endif + *err = CURLE_RECV_ERROR; + goto cleanup; + } + } + + DEBUGF(infof(data, + "schannel: encrypted data buffer: offset %zu length %zu", + backend->encdata_offset, backend->encdata_length)); + + DEBUGF(infof(data, + "schannel: decrypted data buffer: offset %zu length %zu", + backend->decdata_offset, backend->decdata_length)); + +cleanup: + /* Warning- there is no guarantee the encdata state is valid at this point */ + DEBUGF(infof(data, "schannel: schannel_recv cleanup")); + + /* Error if the connection has closed without a close_notify. + + The behavior here is a matter of debate. We don't want to be vulnerable + to a truncation attack however there's some browser precedent for + ignoring the close_notify for compatibility reasons. + + Additionally, Windows 2000 (v5.0) is a special case since it seems it + doesn't return close_notify. In that case if the connection was closed we + assume it was graceful (close_notify) since there doesn't seem to be a + way to tell. + */ + if(len && !backend->decdata_offset && backend->recv_connection_closed && + !backend->recv_sspi_close_notify) { + bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT, + VERSION_EQUAL); + + if(isWin2k && sspi_status == SEC_E_OK) + backend->recv_sspi_close_notify = true; + else { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: server closed abruptly (missing close_notify)"); + } + } + + /* Any error other than CURLE_AGAIN is an unrecoverable error. */ + if(*err && *err != CURLE_AGAIN) + backend->recv_unrecoverable_err = *err; + + size = len < backend->decdata_offset ? len : backend->decdata_offset; + if(size) { + memcpy(buf, backend->decdata_buffer, size); + memmove(backend->decdata_buffer, backend->decdata_buffer + size, + backend->decdata_offset - size); + backend->decdata_offset -= size; + DEBUGF(infof(data, "schannel: decrypted data returned %zu", size)); + DEBUGF(infof(data, + "schannel: decrypted data buffer: offset %zu length %zu", + backend->decdata_offset, backend->decdata_length)); + *err = CURLE_OK; + return (ssize_t)size; + } + + if(!*err && !backend->recv_connection_closed) + *err = CURLE_AGAIN; + + /* It's debatable what to return when !len. We could return whatever error + we got from decryption but instead we override here so the return is + consistent. + */ + if(!len) + *err = CURLE_OK; + + return *err ? -1 : 0; +} + +static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + return schannel_connect_common(cf, data, TRUE, done); +} + +static CURLcode schannel_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result; + bool done = FALSE; + + result = schannel_connect_common(cf, data, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +static bool schannel_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + const struct ssl_connect_data *connssl = cf->ctx; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + + (void)data; + DEBUGASSERT(backend); + + if(backend->ctxt) /* SSL/TLS is in use */ + return (backend->decdata_offset > 0 || + (backend->encdata_offset > 0 && !backend->encdata_is_incomplete)); + else + return FALSE; +} + +static void schannel_session_free(void *ptr) +{ + /* this is expected to be called under sessionid lock */ + struct Curl_schannel_cred *cred = ptr; + + if(cred) { + cred->refcount--; + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + curlx_unicodefree(cred->sni_hostname); +#ifdef HAS_CLIENT_CERT_PATH + if(cred->client_cert_store) { + CertCloseStore(cred->client_cert_store, 0); + cred->client_cert_store = NULL; + } +#endif + Curl_safefree(cred); + } + } +} + +/* shut down the SSL connection and clean up related memory. + this function can be called multiple times on the same connection including + if the SSL connection failed (eg connection made but failed handshake). */ +static int schannel_shutdown(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx + * Shutting Down an Schannel Connection + */ + struct ssl_connect_data *connssl = cf->ctx; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + + DEBUGASSERT(data); + DEBUGASSERT(backend); + + if(backend->ctxt) { + infof(data, "schannel: shutting down SSL/TLS connection with %s port %d", + connssl->peer.hostname, connssl->port); + } + + if(backend->cred && backend->ctxt) { + SecBufferDesc BuffDesc; + SecBuffer Buffer; + SECURITY_STATUS sspi_status; + SecBuffer outbuf; + SecBufferDesc outbuf_desc; + CURLcode result; + DWORD dwshut = SCHANNEL_SHUTDOWN; + + InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); + InitSecBufferDesc(&BuffDesc, &Buffer, 1); + + sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle, + &BuffDesc); + + if(sspi_status != SEC_E_OK) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: ApplyControlToken failure: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + } + + /* setup output buffer */ + InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, &outbuf, 1); + + sspi_status = s_pSecFn->InitializeSecurityContext( + &backend->cred->cred_handle, + &backend->ctxt->ctxt_handle, + backend->cred->sni_hostname, + backend->req_flags, + 0, + 0, + NULL, + 0, + &backend->ctxt->ctxt_handle, + &outbuf_desc, + &backend->ret_flags, + &backend->ctxt->time_stamp); + + if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { + /* send close message which is in output buffer */ + ssize_t written = Curl_conn_cf_send(cf->next, data, + outbuf.pvBuffer, outbuf.cbBuffer, + &result); + s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); + if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { + infof(data, "schannel: failed to send close msg: %s" + " (bytes written: %zd)", curl_easy_strerror(result), written); + } + } + } + + /* free SSPI Schannel API security context handle */ + if(backend->ctxt) { + DEBUGF(infof(data, "schannel: clear security context handle")); + s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle); + Curl_safefree(backend->ctxt); + } + + /* free SSPI Schannel API credential handle */ + if(backend->cred) { + Curl_ssl_sessionid_lock(data); + schannel_session_free(backend->cred); + Curl_ssl_sessionid_unlock(data); + backend->cred = NULL; + } + + /* free internal buffer for received encrypted data */ + if(backend->encdata_buffer) { + Curl_safefree(backend->encdata_buffer); + backend->encdata_length = 0; + backend->encdata_offset = 0; + backend->encdata_is_incomplete = false; + } + + /* free internal buffer for received decrypted data */ + if(backend->decdata_buffer) { + Curl_safefree(backend->decdata_buffer); + backend->decdata_length = 0; + backend->decdata_offset = 0; + } + + return CURLE_OK; +} + +static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + schannel_shutdown(cf, data); +} + +static int schannel_init(void) +{ + return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); +} + +static void schannel_cleanup(void) +{ + Curl_sspi_global_cleanup(); +} + +static size_t schannel_version(char *buffer, size_t size) +{ + size = msnprintf(buffer, size, "Schannel"); + + return size; +} + +static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM, + unsigned char *entropy, size_t length) +{ + (void)data; + + return Curl_win32_random(entropy, length); +} + +static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char *pinnedpubkey) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + CERT_CONTEXT *pCertContextServer = NULL; + + /* Result is returned to caller */ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + DEBUGASSERT(backend); + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + + do { + SECURITY_STATUS sspi_status; + const char *x509_der; + DWORD x509_der_len; + struct Curl_X509certificate x509_parsed; + struct Curl_asn1Element *pubkey; + + sspi_status = + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &pCertContextServer); + + if((sspi_status != SEC_E_OK) || !pCertContextServer) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: Failed to read remote certificate context: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + break; /* failed */ + } + + + if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) && + (pCertContextServer->cbCertEncoded > 0))) + break; + + x509_der = (const char *)pCertContextServer->pbCertEncoded; + x509_der_len = pCertContextServer->cbCertEncoded; + memset(&x509_parsed, 0, sizeof(x509_parsed)); + if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) + break; + + pubkey = &x509_parsed.subjectPublicKeyInfo; + if(!pubkey->header || pubkey->end <= pubkey->header) { + failf(data, "SSL: failed retrieving public key from server certificate"); + break; + } + + result = Curl_pin_peer_pubkey(data, + pinnedpubkey, + (const unsigned char *)pubkey->header, + (size_t)(pubkey->end - pubkey->header)); + if(result) { + failf(data, "SSL: public key does not match pinned public key"); + } + } while(0); + + if(pCertContextServer) + CertFreeCertificateContext(pCertContextServer); + + return result; +} + +static void schannel_checksum(const unsigned char *input, + size_t inputlen, + unsigned char *checksum, + size_t checksumlen, + DWORD provType, + const unsigned int algId) +{ + HCRYPTPROV hProv = 0; + HCRYPTHASH hHash = 0; + DWORD cbHashSize = 0; + DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize); + DWORD dwChecksumLen = (DWORD)checksumlen; + + /* since this can fail in multiple ways, zero memory first so we never + * return old data + */ + memset(checksum, 0, checksumlen); + + if(!CryptAcquireContext(&hProv, NULL, NULL, provType, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return; /* failed */ + + do { + if(!CryptCreateHash(hProv, algId, 0, 0, &hHash)) + break; /* failed */ + + if(!CryptHashData(hHash, input, (DWORD)inputlen, 0)) + break; /* failed */ + + /* get hash size */ + if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize, + &dwHashSizeLen, 0)) + break; /* failed */ + + /* check hash size */ + if(checksumlen < cbHashSize) + break; /* failed */ + + if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0)) + break; /* failed */ + } while(0); + + if(hHash) + CryptDestroyHash(hHash); + + if(hProv) + CryptReleaseContext(hProv, 0); +} + +static CURLcode schannel_sha256sum(const unsigned char *input, + size_t inputlen, + unsigned char *sha256sum, + size_t sha256len) +{ + schannel_checksum(input, inputlen, sha256sum, sha256len, + PROV_RSA_AES, CALG_SHA_256); + return CURLE_OK; +} + +static void *schannel_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + (void)info; + DEBUGASSERT(backend); + return &backend->ctxt->ctxt_handle; +} + +HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi; + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + struct schannel_multi_ssl_backend_data *mbackend; + const struct ssl_general_config *cfg = &data->set.general_ssl; + timediff_t timeout_ms; + timediff_t elapsed_ms; + struct curltime now; + unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH]; + + DEBUGASSERT(multi); + + if(!multi || !multi->ssl_backend_data) { + return NULL; + } + + mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data; + if(!mbackend->cert_store) { + return NULL; + } + + /* zero ca_cache_timeout completely disables caching */ + if(!cfg->ca_cache_timeout) { + return NULL; + } + + /* check for cache timeout by using the cached_x509_store_expired timediff + calculation pattern from openssl.c. + negative timeout means retain forever. */ + timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000; + if(timeout_ms >= 0) { + now = Curl_now(); + elapsed_ms = Curl_timediff(now, mbackend->time); + if(elapsed_ms >= timeout_ms) { + return NULL; + } + } + + if(ca_info_blob) { + if(!mbackend->CAinfo_blob_digest) { + return NULL; + } + if(mbackend->CAinfo_blob_size != ca_info_blob->len) { + return NULL; + } + schannel_sha256sum((const unsigned char *)ca_info_blob->data, + ca_info_blob->len, + info_blob_digest, + CURL_SHA256_DIGEST_LENGTH); + if(memcmp(mbackend->CAinfo_blob_digest, + info_blob_digest, + CURL_SHA256_DIGEST_LENGTH)) { + return NULL; + } + } + else { + if(!conn_config->CAfile || !mbackend->CAfile || + strcmp(mbackend->CAfile, conn_config->CAfile)) { + return NULL; + } + } + + return mbackend->cert_store; +} + +bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, + const struct Curl_easy *data, + HCERTSTORE cert_store) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi; + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + struct schannel_multi_ssl_backend_data *mbackend; + unsigned char *CAinfo_blob_digest = NULL; + size_t CAinfo_blob_size = 0; + char *CAfile = NULL; + + DEBUGASSERT(multi); + + if(!multi) { + return false; + } + + if(!multi->ssl_backend_data) { + multi->ssl_backend_data = + calloc(1, sizeof(struct schannel_multi_ssl_backend_data)); + if(!multi->ssl_backend_data) { + return false; + } + } + + mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data; + + + if(ca_info_blob) { + CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH); + if(!CAinfo_blob_digest) { + return false; + } + schannel_sha256sum((const unsigned char *)ca_info_blob->data, + ca_info_blob->len, + CAinfo_blob_digest, + CURL_SHA256_DIGEST_LENGTH); + CAinfo_blob_size = ca_info_blob->len; + } + else { + if(conn_config->CAfile) { + CAfile = strdup(conn_config->CAfile); + if(!CAfile) { + return false; + } + } + } + + /* free old cache data */ + if(mbackend->cert_store) { + CertCloseStore(mbackend->cert_store, 0); + } + free(mbackend->CAinfo_blob_digest); + free(mbackend->CAfile); + + mbackend->time = Curl_now(); + mbackend->cert_store = cert_store; + mbackend->CAinfo_blob_digest = CAinfo_blob_digest; + mbackend->CAinfo_blob_size = CAinfo_blob_size; + mbackend->CAfile = CAfile; + return true; +} + +static void schannel_free_multi_ssl_backend_data( + struct multi_ssl_backend_data *msbd) +{ + struct schannel_multi_ssl_backend_data *mbackend = + (struct schannel_multi_ssl_backend_data*)msbd; + if(mbackend->cert_store) { + CertCloseStore(mbackend->cert_store, 0); + } + free(mbackend->CAinfo_blob_digest); + free(mbackend->CAfile); + free(mbackend); +} + +const struct Curl_ssl Curl_ssl_schannel = { + { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */ + + SSLSUPP_CERTINFO | +#ifdef HAS_MANUAL_VERIFY_API + SSLSUPP_CAINFO_BLOB | +#endif + SSLSUPP_PINNEDPUBKEY | + SSLSUPP_TLS13_CIPHERSUITES | + SSLSUPP_HTTPS_PROXY, + + sizeof(struct schannel_ssl_backend_data), + + schannel_init, /* init */ + schannel_cleanup, /* cleanup */ + schannel_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + schannel_shutdown, /* shutdown */ + schannel_data_pending, /* data_pending */ + schannel_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + schannel_connect, /* connect */ + schannel_connect_nonblocking, /* connect_nonblocking */ + Curl_ssl_adjust_pollset, /* adjust_pollset */ + schannel_get_internals, /* get_internals */ + schannel_close, /* close_one */ + Curl_none_close_all, /* close_all */ + schannel_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + schannel_sha256sum, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */ + schannel_recv, /* recv decrypted data */ + schannel_send, /* send data to encrypt */ +}; + +#endif /* USE_SCHANNEL */ diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h new file mode 100644 index 0000000..b26334b --- /dev/null +++ b/lib/vtls/schannel.h @@ -0,0 +1,86 @@ +#ifndef HEADER_CURL_SCHANNEL_H +#define HEADER_CURL_SCHANNEL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Marc Hoersken, , et al. + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_SCHANNEL + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4201) +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif +/* Wincrypt must be included before anything that could include OpenSSL. */ +#if defined(USE_WIN32_CRYPTO) +#include +/* Undefine wincrypt conflicting symbols for BoringSSL. */ +#undef X509_NAME +#undef X509_EXTENSIONS +#undef PKCS7_ISSUER_AND_SERIAL +#undef PKCS7_SIGNER_INFO +#undef OCSP_REQUEST +#undef OCSP_RESPONSE +#endif + +#include +#include +#include "curl_sspi.h" + +#include "cfilters.h" +#include "urldata.h" + +/* has been included via the above . + * Or in case of ldap.c, it was included via . + * And since has this: + * #define X509_NAME ((LPCSTR) 7) + * + * And in BoringSSL's there is: + * typedef struct X509_name_st X509_NAME; + * etc. + * + * this will cause all kinds of C-preprocessing paste errors in + * BoringSSL's : So just undefine those defines here + * (and only here). + */ +#if defined(OPENSSL_IS_BORINGSSL) +# undef X509_NAME +# undef X509_CERT_PAIR +# undef X509_EXTENSIONS +#endif + +extern const struct Curl_ssl Curl_ssl_schannel; + +CURLcode Curl_verify_host(struct Curl_cfilter *cf, + struct Curl_easy *data); + +CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, + struct Curl_easy *data); + +#endif /* USE_SCHANNEL */ +#endif /* HEADER_CURL_SCHANNEL_H */ diff --git a/lib/vtls/schannel_int.h b/lib/vtls/schannel_int.h new file mode 100644 index 0000000..fe7450d --- /dev/null +++ b/lib/vtls/schannel_int.h @@ -0,0 +1,170 @@ +#ifndef HEADER_CURL_SCHANNEL_INT_H +#define HEADER_CURL_SCHANNEL_INT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Marc Hoersken, , et al. + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_SCHANNEL + +#if defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN) +#define HAS_MANUAL_VERIFY_API +#endif + +#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ + && !defined(DISABLE_SCHANNEL_CLIENT_CERT) +#define HAS_CLIENT_CERT_PATH +#endif + +#ifndef CRYPT_DECODE_NOCOPY_FLAG +#define CRYPT_DECODE_NOCOPY_FLAG 0x1 +#endif + +#ifndef CRYPT_DECODE_ALLOC_FLAG +#define CRYPT_DECODE_ALLOC_FLAG 0x8000 +#endif + +#ifndef CERT_ALT_NAME_DNS_NAME +#define CERT_ALT_NAME_DNS_NAME 3 +#endif + +#ifndef CERT_ALT_NAME_IP_ADDRESS +#define CERT_ALT_NAME_IP_ADDRESS 8 +#endif + + +#ifndef SCH_CREDENTIALS_VERSION + +#define SCH_CREDENTIALS_VERSION 0x00000005 + +typedef enum _eTlsAlgorithmUsage +{ + TlsParametersCngAlgUsageKeyExchange, + TlsParametersCngAlgUsageSignature, + TlsParametersCngAlgUsageCipher, + TlsParametersCngAlgUsageDigest, + TlsParametersCngAlgUsageCertSig +} eTlsAlgorithmUsage; + +typedef struct _CRYPTO_SETTINGS +{ + eTlsAlgorithmUsage eAlgorithmUsage; + UNICODE_STRING strCngAlgId; + DWORD cChainingModes; + PUNICODE_STRING rgstrChainingModes; + DWORD dwMinBitLength; + DWORD dwMaxBitLength; +} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS; + +typedef struct _TLS_PARAMETERS +{ + DWORD cAlpnIds; + PUNICODE_STRING rgstrAlpnIds; + DWORD grbitDisabledProtocols; + DWORD cDisabledCrypto; + PCRYPTO_SETTINGS pDisabledCrypto; + DWORD dwFlags; +} TLS_PARAMETERS, * PTLS_PARAMETERS; + +typedef struct _SCH_CREDENTIALS +{ + DWORD dwVersion; + DWORD dwCredFormat; + DWORD cCreds; + PCCERT_CONTEXT* paCred; + HCERTSTORE hRootStore; + + DWORD cMappers; + struct _HMAPPER **aphMappers; + + DWORD dwSessionLifespan; + DWORD dwFlags; + DWORD cTlsParameters; + PTLS_PARAMETERS pTlsParameters; +} SCH_CREDENTIALS, * PSCH_CREDENTIALS; + +#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16 +#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16 +#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16 +#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16 + +#endif /* SCH_CREDENTIALS_VERSION */ + +struct Curl_schannel_cred { + CredHandle cred_handle; + TimeStamp time_stamp; + TCHAR *sni_hostname; +#ifdef HAS_CLIENT_CERT_PATH + HCERTSTORE client_cert_store; +#endif + int refcount; +}; + +struct Curl_schannel_ctxt { + CtxtHandle ctxt_handle; + TimeStamp time_stamp; +}; + +struct schannel_ssl_backend_data { + struct Curl_schannel_cred *cred; + struct Curl_schannel_ctxt *ctxt; + SecPkgContext_StreamSizes stream_sizes; + size_t encdata_length, decdata_length; + size_t encdata_offset, decdata_offset; + unsigned char *encdata_buffer, *decdata_buffer; + /* encdata_is_incomplete: if encdata contains only a partial record that + can't be decrypted without another recv() (that is, status is + SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds + more bytes into encdata then set this back to false. */ + bool encdata_is_incomplete; + unsigned long req_flags, ret_flags; + CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ + bool recv_sspi_close_notify; /* true if connection closed by close_notify */ + bool recv_connection_closed; /* true if connection closed, regardless how */ + bool recv_renegotiating; /* true if recv is doing renegotiation */ + bool use_alpn; /* true if ALPN is used for this connection */ +#ifdef HAS_MANUAL_VERIFY_API + bool use_manual_cred_validation; /* true if manual cred validation is used */ +#endif +}; + +struct schannel_multi_ssl_backend_data { + unsigned char *CAinfo_blob_digest; /* CA info blob digest */ + size_t CAinfo_blob_size; /* CA info blob size */ + char *CAfile; /* CAfile path used to generate + certificate store */ + HCERTSTORE cert_store; /* cached certificate store or + NULL if none */ + struct curltime time; /* when the cached store was created */ +}; + +HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, + const struct Curl_easy *data); + +bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, + const struct Curl_easy *data, + HCERTSTORE cert_store); + +#endif /* USE_SCHANNEL */ +#endif /* HEADER_CURL_SCHANNEL_INT_H */ diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c new file mode 100644 index 0000000..24146d0 --- /dev/null +++ b/lib/vtls/schannel_verify.c @@ -0,0 +1,787 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Marc Hoersken, + * Copyright (C) Mark Salisbury, + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Source file for Schannel-specific certificate verification. This code should + * only be invoked by code in schannel.c. + */ + +#include "curl_setup.h" + +#ifdef USE_SCHANNEL +#ifndef USE_WINDOWS_SSPI +# error "Can't compile SCHANNEL support without SSPI." +#endif + +#include "schannel.h" +#include "schannel_int.h" + +#include "vtls.h" +#include "vtls_int.h" +#include "sendf.h" +#include "strerror.h" +#include "curl_multibyte.h" +#include "curl_printf.h" +#include "hostcheck.h" +#include "version_win32.h" + +/* The last #include file should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend) + + +#ifdef HAS_MANUAL_VERIFY_API + +#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */ +#define BEGIN_CERT "-----BEGIN CERTIFICATE-----" +#define END_CERT "\n-----END CERTIFICATE-----" + +struct cert_chain_engine_config_win7 { + DWORD cbSize; + HCERTSTORE hRestrictedRoot; + HCERTSTORE hRestrictedTrust; + HCERTSTORE hRestrictedOther; + DWORD cAdditionalStore; + HCERTSTORE *rghAdditionalStore; + DWORD dwFlags; + DWORD dwUrlRetrievalTimeout; + DWORD MaximumCachedCertificates; + DWORD CycleDetectionModulus; + HCERTSTORE hExclusiveRoot; + HCERTSTORE hExclusiveTrustedPeople; +}; + +static int is_cr_or_lf(char c) +{ + return c == '\r' || c == '\n'; +} + +/* Search the substring needle,needlelen into string haystack,haystacklen + * Strings don't need to be terminated by a '\0'. + * Similar of OSX/Linux memmem (not available on Visual Studio). + * Return position of beginning of first occurrence or NULL if not found + */ +static const char *c_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + const char *p; + char first; + const char *str_limit = (const char *)haystack + haystacklen; + if(!needlelen || needlelen > haystacklen) + return NULL; + first = *(const char *)needle; + for(p = (const char *)haystack; p <= (str_limit - needlelen); p++) + if(((*p) == first) && (memcmp(p, needle, needlelen) == 0)) + return p; + + return NULL; +} + +static CURLcode add_certs_data_to_store(HCERTSTORE trust_store, + const char *ca_buffer, + size_t ca_buffer_size, + 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); + CURLcode result = CURLE_OK; + int num_certs = 0; + bool more_certs = 1; + const char *current_ca_file_ptr = ca_buffer; + const char *ca_buffer_limit = ca_buffer + ca_buffer_size; + + while(more_certs && (current_ca_file_ptr MAX_CAFILE_SIZE) { + failf(data, + "schannel: CA file exceeds max size of %u bytes", + MAX_CAFILE_SIZE); + result = CURLE_SSL_CACERT_BADFILE; + goto cleanup; + } + + ca_file_bufsize = (size_t)file_size.QuadPart; + ca_file_buffer = (char *)malloc(ca_file_bufsize + 1); + if(!ca_file_buffer) { + result = CURLE_OUT_OF_MEMORY; + goto cleanup; + } + + while(total_bytes_read < ca_file_bufsize) { + DWORD bytes_to_read = (DWORD)(ca_file_bufsize - total_bytes_read); + DWORD bytes_read = 0; + + if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read, + bytes_to_read, &bytes_read, NULL)) { + char buffer[STRERROR_LEN]; + failf(data, + "schannel: failed to read from CA file '%s': %s", + ca_file, + Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); + result = CURLE_SSL_CACERT_BADFILE; + goto cleanup; + } + if(bytes_read == 0) { + /* Premature EOF -- adjust the bufsize to the new value */ + ca_file_bufsize = total_bytes_read; + } + else { + total_bytes_read += bytes_read; + } + } + + /* Null terminate the buffer */ + ca_file_buffer[ca_file_bufsize] = '\0'; + + result = add_certs_data_to_store(trust_store, + ca_file_buffer, ca_file_bufsize, + ca_file, + data); + +cleanup: + if(ca_file_handle != INVALID_HANDLE_VALUE) { + CloseHandle(ca_file_handle); + } + Curl_safefree(ca_file_buffer); + curlx_unicodefree(ca_file_tstr); + + return result; +} + +#endif /* HAS_MANUAL_VERIFY_API */ + +/* + * Returns the number of characters necessary to populate all the host_names. + * If host_names is not NULL, populate it with all the host names. Each string + * in the host_names is null-terminated and the last string is double + * null-terminated. If no DNS names are found, a single null-terminated empty + * string is returned. + */ +static DWORD cert_get_name_string(struct Curl_easy *data, + CERT_CONTEXT *cert_context, + LPTSTR host_names, + DWORD length) +{ + DWORD actual_length = 0; + BOOL compute_content = FALSE; + CERT_INFO *cert_info = NULL; + CERT_EXTENSION *extension = NULL; + CRYPT_DECODE_PARA decode_para = {0, 0, 0}; + CERT_ALT_NAME_INFO *alt_name_info = NULL; + DWORD alt_name_info_size = 0; + BOOL ret_val = FALSE; + LPTSTR current_pos = NULL; + DWORD i; + +#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG + /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */ + if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + /* CertGetNameString will provide the 8-bit character string without + * any decoding */ + DWORD name_flags = + CERT_NAME_DISABLE_IE4_UTF8_FLAG | CERT_NAME_SEARCH_ALL_NAMES_FLAG; + actual_length = CertGetNameString(cert_context, + CERT_NAME_DNS_TYPE, + name_flags, + NULL, + host_names, + length); + return actual_length; + } +#endif + + compute_content = host_names != NULL && length != 0; + + /* Initialize default return values. */ + actual_length = 1; + if(compute_content) { + *host_names = '\0'; + } + + if(!cert_context) { + failf(data, "schannel: Null certificate context."); + return actual_length; + } + + cert_info = cert_context->pCertInfo; + if(!cert_info) { + failf(data, "schannel: Null certificate info."); + return actual_length; + } + + extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2, + cert_info->cExtension, + cert_info->rgExtension); + if(!extension) { + failf(data, "schannel: CertFindExtension() returned no extension."); + return actual_length; + } + + decode_para.cbSize = sizeof(CRYPT_DECODE_PARA); + + ret_val = + CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + szOID_SUBJECT_ALT_NAME2, + extension->Value.pbData, + extension->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, + &decode_para, + &alt_name_info, + &alt_name_info_size); + if(!ret_val) { + failf(data, + "schannel: CryptDecodeObjectEx() returned no alternate name " + "information."); + return actual_length; + } + + current_pos = host_names; + + /* Iterate over the alternate names and populate host_names. */ + for(i = 0; i < alt_name_info->cAltEntry; i++) { + const CERT_ALT_NAME_ENTRY *entry = &alt_name_info->rgAltEntry[i]; + wchar_t *dns_w = NULL; + size_t current_length = 0; + + if(entry->dwAltNameChoice != CERT_ALT_NAME_DNS_NAME) { + continue; + } + if(!entry->pwszDNSName) { + infof(data, "schannel: Empty DNS name."); + continue; + } + current_length = wcslen(entry->pwszDNSName) + 1; + if(!compute_content) { + actual_length += (DWORD)current_length; + continue; + } + /* Sanity check to prevent buffer overrun. */ + if((actual_length + current_length) > length) { + failf(data, "schannel: Not enough memory to list all host names."); + break; + } + dns_w = entry->pwszDNSName; + /* pwszDNSName is in ia5 string format and hence doesn't contain any + * non-ascii characters. */ + while(*dns_w != '\0') { + *current_pos++ = (char)(*dns_w++); + } + *current_pos++ = '\0'; + actual_length += (DWORD)current_length; + } + if(compute_content) { + /* Last string has double null-terminator. */ + *current_pos = '\0'; + } + return actual_length; +} + +/* Verify the server's hostname */ +CURLcode Curl_verify_host(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + SECURITY_STATUS sspi_status; + CURLcode result = CURLE_PEER_FAILED_VERIFICATION; + CERT_CONTEXT *pCertContextServer = NULL; + TCHAR *cert_hostname_buff = NULL; + size_t cert_hostname_buff_index = 0; + const char *conn_hostname = connssl->peer.hostname; + size_t hostlen = strlen(conn_hostname); + DWORD len = 0; + DWORD actual_len = 0; + + sspi_status = + s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &pCertContextServer); + + if((sspi_status != SEC_E_OK) || !pCertContextServer) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: Failed to read remote certificate context: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + result = CURLE_PEER_FAILED_VERIFICATION; + goto cleanup; + } + + /* Determine the size of the string needed for the cert hostname */ + len = cert_get_name_string(data, pCertContextServer, NULL, 0); + if(len == 0) { + failf(data, + "schannel: CertGetNameString() returned no " + "certificate name information"); + result = CURLE_PEER_FAILED_VERIFICATION; + goto cleanup; + } + + /* CertGetNameString guarantees that the returned name will not contain + * embedded null bytes. This appears to be undocumented behavior. + */ + cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR)); + if(!cert_hostname_buff) { + result = CURLE_OUT_OF_MEMORY; + goto cleanup; + } + actual_len = cert_get_name_string( + data, pCertContextServer, (LPTSTR)cert_hostname_buff, len); + + /* Sanity check */ + if(actual_len != len) { + failf(data, + "schannel: CertGetNameString() returned certificate " + "name information of unexpected size"); + result = CURLE_PEER_FAILED_VERIFICATION; + goto cleanup; + } + + /* cert_hostname_buff contains all DNS names, where each name is + * null-terminated and the last DNS name is double null-terminated. Due to + * this encoding, use the length of the buffer to iterate over all names. + */ + result = CURLE_PEER_FAILED_VERIFICATION; + while(cert_hostname_buff_index < len && + cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') && + result == CURLE_PEER_FAILED_VERIFICATION) { + + char *cert_hostname; + + /* Comparing the cert name and the connection hostname encoded as UTF-8 + * is acceptable since both values are assumed to use ASCII + * (or some equivalent) encoding + */ + cert_hostname = curlx_convert_tchar_to_UTF8( + &cert_hostname_buff[cert_hostname_buff_index]); + if(!cert_hostname) { + result = CURLE_OUT_OF_MEMORY; + } + else { + if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname), + conn_hostname, hostlen)) { + infof(data, + "schannel: connection hostname (%s) validated " + "against certificate name (%s)", + conn_hostname, cert_hostname); + result = CURLE_OK; + } + else { + size_t cert_hostname_len; + + infof(data, + "schannel: connection hostname (%s) did not match " + "against certificate name (%s)", + conn_hostname, cert_hostname); + + cert_hostname_len = + _tcslen(&cert_hostname_buff[cert_hostname_buff_index]); + + /* Move on to next cert name */ + cert_hostname_buff_index += cert_hostname_len + 1; + + result = CURLE_PEER_FAILED_VERIFICATION; + } + curlx_unicodefree(cert_hostname); + } + } + + if(result == CURLE_PEER_FAILED_VERIFICATION) { + failf(data, + "schannel: CertGetNameString() failed to match " + "connection hostname (%s) against server certificate names", + conn_hostname); + } + else if(result != CURLE_OK) + failf(data, "schannel: server certificate name verification failed"); + +cleanup: + Curl_safefree(cert_hostname_buff); + + if(pCertContextServer) + CertFreeCertificateContext(pCertContextServer); + + return result; +} + + +#ifdef HAS_MANUAL_VERIFY_API +/* Verify the server's certificate and hostname */ +CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + SECURITY_STATUS sspi_status; + CURLcode result = CURLE_OK; + CERT_CONTEXT *pCertContextServer = NULL; + const CERT_CHAIN_CONTEXT *pChainContext = NULL; + HCERTCHAINENGINE cert_chain_engine = NULL; + HCERTSTORE trust_store = NULL; + HCERTSTORE own_trust_store = NULL; + + DEBUGASSERT(BACKEND); + + sspi_status = + s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &pCertContextServer); + + if((sspi_status != SEC_E_OK) || !pCertContextServer) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: Failed to read remote certificate context: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + result = CURLE_PEER_FAILED_VERIFICATION; + } + + if(result == CURLE_OK && + (conn_config->CAfile || conn_config->ca_info_blob) && + BACKEND->use_manual_cred_validation) { + /* + * Create a chain engine that uses the certificates in the CA file as + * trusted certificates. This is only supported on Windows 7+. + */ + + if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, + VERSION_LESS_THAN)) { + failf(data, "schannel: this version of Windows is too old to support " + "certificate verification via CA bundle file."); + result = CURLE_SSL_CACERT_BADFILE; + } + else { + /* try cache */ + trust_store = Curl_schannel_get_cached_cert_store(cf, data); + + if(trust_store) { + infof(data, "schannel: reusing certificate store from cache"); + } + else { + /* Open the certificate store */ + trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY, + 0, + (HCRYPTPROV)NULL, + CERT_STORE_CREATE_NEW_FLAG, + NULL); + if(!trust_store) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: failed to create certificate store: %s", + Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); + result = CURLE_SSL_CACERT_BADFILE; + } + else { + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + own_trust_store = trust_store; + + if(ca_info_blob) { + result = add_certs_data_to_store(trust_store, + (const char *)ca_info_blob->data, + ca_info_blob->len, + "(memory blob)", + data); + } + else { + result = add_certs_file_to_store(trust_store, + conn_config->CAfile, + data); + } + if(result == CURLE_OK) { + if(Curl_schannel_set_cached_cert_store(cf, data, trust_store)) { + own_trust_store = NULL; + } + } + } + } + } + + if(result == CURLE_OK) { + struct cert_chain_engine_config_win7 engine_config; + BOOL create_engine_result; + + memset(&engine_config, 0, sizeof(engine_config)); + engine_config.cbSize = sizeof(engine_config); + engine_config.hExclusiveRoot = trust_store; + + /* CertCreateCertificateChainEngine will check the expected size of the + * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size + * does not match the expected size. When this occurs, it indicates that + * CAINFO is not supported on the version of Windows in use. + */ + create_engine_result = + CertCreateCertificateChainEngine( + (CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine); + if(!create_engine_result) { + char buffer[STRERROR_LEN]; + failf(data, + "schannel: failed to create certificate chain engine: %s", + Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); + result = CURLE_SSL_CACERT_BADFILE; + } + } + } + + if(result == CURLE_OK) { + CERT_CHAIN_PARA ChainPara; + + memset(&ChainPara, 0, sizeof(ChainPara)); + ChainPara.cbSize = sizeof(ChainPara); + + if(!CertGetCertificateChain(cert_chain_engine, + pCertContextServer, + NULL, + pCertContextServer->hCertStore, + &ChainPara, + (ssl_config->no_revoke ? 0 : + CERT_CHAIN_REVOCATION_CHECK_CHAIN), + NULL, + &pChainContext)) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: CertGetCertificateChain failed: %s", + Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); + pChainContext = NULL; + result = CURLE_PEER_FAILED_VERIFICATION; + } + + if(result == CURLE_OK) { + CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; + DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); + dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; + + if(data->set.ssl.revoke_best_effort) { + /* Ignore errors when root certificates are missing the revocation + * list URL, or when the list could not be downloaded because the + * server is currently unreachable. */ + dwTrustErrorMask &= ~(DWORD)(CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION); + } + + if(dwTrustErrorMask) { + if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_REVOKED"); + else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_PARTIAL_CHAIN"); + else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_UNTRUSTED_ROOT"); + else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_NOT_TIME_VALID"); + else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_REVOCATION_STATUS_UNKNOWN"); + else + failf(data, "schannel: CertGetCertificateChain error mask: 0x%08lx", + dwTrustErrorMask); + result = CURLE_PEER_FAILED_VERIFICATION; + } + } + } + + if(result == CURLE_OK) { + if(conn_config->verifyhost) { + result = Curl_verify_host(cf, data); + } + } + + if(cert_chain_engine) { + CertFreeCertificateChainEngine(cert_chain_engine); + } + + if(own_trust_store) { + CertCloseStore(own_trust_store, 0); + } + + if(pChainContext) + CertFreeCertificateChain(pChainContext); + + if(pCertContextServer) + CertFreeCertificateContext(pCertContextServer); + + return result; +} + +#endif /* HAS_MANUAL_VERIFY_API */ +#endif /* USE_SCHANNEL */ diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c new file mode 100644 index 0000000..1f37305 --- /dev/null +++ b/lib/vtls/sectransp.c @@ -0,0 +1,3493 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * Copyright (C) Nick Zitzmann, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Source file for all iOS and macOS SecureTransport-specific code for the + * TLS/SSL layer. No code but vtls.c should ever call or use these functions. + */ + +#include "curl_setup.h" + +#include "urldata.h" /* for the Curl_easy definition */ +#include "curl_base64.h" +#include "strtok.h" +#include "multiif.h" +#include "strcase.h" +#include "x509asn1.h" +#include "strerror.h" + +#ifdef USE_SECTRANSP + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wtautological-pointer-compare" +#endif /* __clang__ */ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Waddress" +#pragma GCC diagnostic ignored "-Wundef" +#pragma GCC diagnostic ignored "-Wunreachable-code" +#endif + +#include + +#include +/* For some reason, when building for iOS, the omnibus header above does + * not include SecureTransport.h as of iOS SDK 5.1. */ +#include +#include +#include + +/* The Security framework has changed greatly between iOS and different macOS + versions, and we will try to support as many of them as we can (back to + Leopard and iOS 5) by using macros and weak-linking. + + In general, you want to build this using the most recent OS SDK, since some + features require curl to be built against the latest SDK. TLS 1.1 and 1.2 + support, for instance, require the macOS 10.8 SDK or later. TLS 1.3 + requires the macOS 10.13 or iOS 11 SDK or later. */ +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 +#error "The Secure Transport back-end requires Leopard or later." +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */ + +#define CURL_BUILD_IOS 0 +#define CURL_BUILD_IOS_7 0 +#define CURL_BUILD_IOS_9 0 +#define CURL_BUILD_IOS_11 0 +#define CURL_BUILD_IOS_13 0 +#define CURL_BUILD_MAC 1 +/* This is the maximum API level we are allowed to use when building: */ +#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 +#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 +#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 +#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 +#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 +#define CURL_BUILD_MAC_10_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 +#define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 +#define CURL_BUILD_MAC_10_15 MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 +/* These macros mean "the following code is present to allow runtime backward + compatibility with at least this cat or earlier": + (You set this at build-time using the compiler command line option + "-mmacosx-version-min.") */ +#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 +#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060 +#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 +#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080 +#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 + +#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE +#define CURL_BUILD_IOS 1 +#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 +#define CURL_BUILD_IOS_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 +#define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 +#define CURL_BUILD_IOS_13 __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 +#define CURL_BUILD_MAC 0 +#define CURL_BUILD_MAC_10_5 0 +#define CURL_BUILD_MAC_10_6 0 +#define CURL_BUILD_MAC_10_7 0 +#define CURL_BUILD_MAC_10_8 0 +#define CURL_BUILD_MAC_10_9 0 +#define CURL_BUILD_MAC_10_11 0 +#define CURL_BUILD_MAC_10_13 0 +#define CURL_BUILD_MAC_10_15 0 +#define CURL_SUPPORT_MAC_10_5 0 +#define CURL_SUPPORT_MAC_10_6 0 +#define CURL_SUPPORT_MAC_10_7 0 +#define CURL_SUPPORT_MAC_10_8 0 +#define CURL_SUPPORT_MAC_10_9 0 + +#else +#error "The Secure Transport back-end requires iOS or macOS." +#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ + +#if CURL_BUILD_MAC +#include +#endif /* CURL_BUILD_MAC */ + +#include "sendf.h" +#include "inet_pton.h" +#include "connect.h" +#include "select.h" +#include "vtls.h" +#include "vtls_int.h" +#include "sectransp.h" +#include "curl_printf.h" +#include "strdup.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + + +/* From MacTypes.h (which we can't include because it isn't present in iOS: */ +#define ioErr -36 +#define paramErr -50 + +struct st_ssl_backend_data { + SSLContextRef ssl_ctx; + bool ssl_direction; /* true if writing, false if reading */ + size_t ssl_write_buffered_length; +}; + +struct st_cipher { + const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */ + const char *alias_name; /* Alias name is the same as OpenSSL cipher name */ + SSLCipherSuite num; /* Cipher suite code/number defined in IANA registry */ + bool weak; /* Flag to mark cipher as weak based on previous implementation + of Secure Transport back-end by CURL */ +}; + +/* Macro to initialize st_cipher data structure: stringify id to name, cipher + number/id, 'weak' suite flag + */ +#define CIPHER_DEF(num, alias, weak) \ + { #num, alias, num, weak } + +/* + Macro to initialize st_cipher data structure with name, code (IANA cipher + number/id value), and 'weak' suite flag. The first 28 cipher suite numbers + have the same IANA code for both SSL and TLS standards: numbers 0x0000 to + 0x001B. They have different names though. The first 4 letters of the cipher + suite name are the protocol name: "SSL_" or "TLS_", rest of the IANA name is + the same for both SSL and TLS cipher suite name. + The second part of the problem is that macOS/iOS SDKs don't define all TLS + codes but only 12 of them. The SDK defines all SSL codes though, i.e. SSL_NUM + constant is always defined for those 28 ciphers while TLS_NUM is defined only + for 12 of the first 28 ciphers. Those 12 TLS cipher codes match to + corresponding SSL enum value and represent the same cipher suite. Therefore + we'll use the SSL enum value for those cipher suites because it is defined + for all 28 of them. + We make internal data consistent and based on TLS names, i.e. all st_cipher + item names start with the "TLS_" prefix. + Summarizing all the above, those 28 first ciphers are presented in our table + with both TLS and SSL names. Their cipher numbers are assigned based on the + SDK enum value for the SSL cipher, which matches to IANA TLS number. + */ +#define CIPHER_DEF_SSLTLS(num_wo_prefix, alias, weak) \ + { "TLS_" #num_wo_prefix, alias, SSL_##num_wo_prefix, weak } + +/* + Cipher suites were marked as weak based on the following: + RC4 encryption - rfc7465, the document contains a list of deprecated ciphers. + Marked in the code below as weak. + RC2 encryption - many mentions, was found vulnerable to a relatively easy + attack https://link.springer.com/chapter/10.1007%2F3-540-69710-1_14 + Marked in the code below as weak. + DES and IDEA encryption - rfc5469, has a list of deprecated ciphers. + Marked in the code below as weak. + Anonymous Diffie-Hellman authentication and anonymous elliptic curve + Diffie-Hellman - vulnerable to a man-in-the-middle attack. Deprecated by + RFC 4346 aka TLS 1.1 (section A.5, page 60) + Null bulk encryption suites - not encrypted communication + Export ciphers, i.e. ciphers with restrictions to be used outside the US for + software exported to some countries, they were excluded from TLS 1.1 + version. More precisely, they were noted as ciphers which MUST NOT be + negotiated in RFC 4346 aka TLS 1.1 (section A.5, pages 60 and 61). + All of those filters were considered weak because they contain a weak + algorithm like DES, RC2 or RC4, and already considered weak by other + criteria. + 3DES - NIST deprecated it and is going to retire it by 2023 + https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA + OpenSSL https://www.openssl.org/blog/blog/2016/08/24/sweet32/ also + deprecated those ciphers. Some other libraries also consider it + vulnerable or at least not strong enough. + + CBC ciphers are vulnerable with SSL3.0 and TLS1.0: + https://www.cisco.com/c/en/us/support/docs/security/email-security-appliance + /118518-technote-esa-00.html + We don't take care of this issue because it is resolved by later TLS + versions and for us, it requires more complicated checks, we need to + check a protocol version also. Vulnerability doesn't look very critical + and we do not filter out those cipher suites. + */ + +#define CIPHER_WEAK_NOT_ENCRYPTED TRUE +#define CIPHER_WEAK_RC_ENCRYPTION TRUE +#define CIPHER_WEAK_DES_ENCRYPTION TRUE +#define CIPHER_WEAK_IDEA_ENCRYPTION TRUE +#define CIPHER_WEAK_ANON_AUTH TRUE +#define CIPHER_WEAK_3DES_ENCRYPTION TRUE +#define CIPHER_STRONG_ENOUGH FALSE + +/* Please do not change the order of the first ciphers available for SSL. + Do not insert and do not delete any of them. Code below + depends on their order and continuity. + If you add a new cipher, please maintain order by number, i.e. + insert in between existing items to appropriate place based on + cipher suite IANA number +*/ +static const struct st_cipher ciphertable[] = { + /* SSL version 3.0 and initial TLS 1.0 cipher suites. + Defined since SDK 10.2.8 */ + CIPHER_DEF_SSLTLS(NULL_WITH_NULL_NULL, /* 0x0000 */ + NULL, + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF_SSLTLS(RSA_WITH_NULL_MD5, /* 0x0001 */ + "NULL-MD5", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF_SSLTLS(RSA_WITH_NULL_SHA, /* 0x0002 */ + "NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC4_40_MD5, /* 0x0003 */ + "EXP-RC4-MD5", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_MD5, /* 0x0004 */ + "RC4-MD5", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_SHA, /* 0x0005 */ + "RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* 0x0006 */ + "EXP-RC2-CBC-MD5", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF_SSLTLS(RSA_WITH_IDEA_CBC_SHA, /* 0x0007 */ + "IDEA-CBC-SHA", + CIPHER_WEAK_IDEA_ENCRYPTION), + CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0008 */ + "EXP-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(RSA_WITH_DES_CBC_SHA, /* 0x0009 */ + "DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */ + "DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DH_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x000B */ + "EXP-DH-DSS-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DH_DSS_WITH_DES_CBC_SHA, /* 0x000C */ + "DH-DSS-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DH_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x000D */ + "DH-DSS-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DH_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x000E */ + "EXP-DH-RSA-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DH_RSA_WITH_DES_CBC_SHA, /* 0x000F */ + "DH-RSA-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0010 */ + "DH-RSA-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x0011 */ + "EXP-EDH-DSS-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DHE_DSS_WITH_DES_CBC_SHA, /* 0x0012 */ + "EDH-DSS-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x0013 */ + "DHE-DSS-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0014 */ + "EXP-EDH-RSA-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DHE_RSA_WITH_DES_CBC_SHA, /* 0x0015 */ + "EDH-RSA-DES-CBC-SHA", + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0016 */ + "DHE-RSA-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_RC4_40_MD5, /* 0x0017 */ + "EXP-ADH-RC4-MD5", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF_SSLTLS(DH_anon_WITH_RC4_128_MD5, /* 0x0018 */ + "ADH-RC4-MD5", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_DES40_CBC_SHA, /* 0x0019 */ + "EXP-ADH-DES-CBC-SHA", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF_SSLTLS(DH_anon_WITH_DES_CBC_SHA, /* 0x001A */ + "ADH-DES-CBC-SHA", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF_SSLTLS(DH_anon_WITH_3DES_EDE_CBC_SHA, /* 0x001B */ + "ADH-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* 0x001C */ + NULL, + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* 0x001D */ + NULL, + CIPHER_STRONG_ENOUGH), + +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */ + CIPHER_DEF(TLS_PSK_WITH_NULL_SHA, /* 0x002C */ + "PSK-NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA, /* 0x002D */ + "DHE-PSK-NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA, /* 0x002E */ + "RSA-PSK-NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), +#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ + + /* TLS addenda using AES, per RFC 3268. Defined since SDK 10.4u */ + CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */ + "AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA, /* 0x0030 */ + "DH-DSS-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA, /* 0x0031 */ + "DH-RSA-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* 0x0032 */ + "DHE-DSS-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* 0x0033 */ + "DHE-RSA-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA, /* 0x0034 */ + "ADH-AES128-SHA", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */ + "AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA, /* 0x0036 */ + "DH-DSS-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA, /* 0x0037 */ + "DH-RSA-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* 0x0038 */ + "DHE-DSS-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* 0x0039 */ + "DHE-RSA-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA, /* 0x003A */ + "ADH-AES256-SHA", + CIPHER_WEAK_ANON_AUTH), + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + /* TLS 1.2 addenda, RFC 5246 */ + /* Server provided RSA certificate for key exchange. */ + CIPHER_DEF(TLS_RSA_WITH_NULL_SHA256, /* 0x003B */ + "NULL-SHA256", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */ + "AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */ + "AES256-SHA256", + CIPHER_STRONG_ENOUGH), + /* Server-authenticated (and optionally client-authenticated) + Diffie-Hellman. */ + CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA256, /* 0x003E */ + "DH-DSS-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA256, /* 0x003F */ + "DH-RSA-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, /* 0x0040 */ + "DHE-DSS-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + + /* TLS 1.2 addenda, RFC 5246 */ + CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */ + "DHE-RSA-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA256, /* 0x0068 */ + "DH-DSS-AES256-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA256, /* 0x0069 */ + "DH-RSA-AES256-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, /* 0x006A */ + "DHE-DSS-AES256-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */ + "DHE-RSA-AES256-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA256, /* 0x006C */ + "ADH-AES128-SHA256", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA256, /* 0x006D */ + "ADH-AES256-SHA256", + CIPHER_WEAK_ANON_AUTH), +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + /* Addendum from RFC 4279, TLS PSK */ + CIPHER_DEF(TLS_PSK_WITH_RC4_128_SHA, /* 0x008A */ + "PSK-RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(TLS_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008B */ + "PSK-3DES-EDE-CBC-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA, /* 0x008C */ + "PSK-AES128-CBC-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA, /* 0x008D */ + "PSK-AES256-CBC-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_PSK_WITH_RC4_128_SHA, /* 0x008E */ + "DHE-PSK-RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008F */ + "DHE-PSK-3DES-EDE-CBC-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, /* 0x0090 */ + "DHE-PSK-AES128-CBC-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, /* 0x0091 */ + "DHE-PSK-AES256-CBC-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_PSK_WITH_RC4_128_SHA, /* 0x0092 */ + "RSA-PSK-RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x0093 */ + "RSA-PSK-3DES-EDE-CBC-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, /* 0x0094 */ + "RSA-PSK-AES128-CBC-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, /* 0x0095 */ + "RSA-PSK-AES256-CBC-SHA", + CIPHER_STRONG_ENOUGH), +#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites + for TLS. */ + CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */ + "AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */ + "AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */ + "DHE-RSA-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */ + "DHE-RSA-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_GCM_SHA256, /* 0x00A0 */ + "DH-RSA-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_GCM_SHA384, /* 0x00A1 */ + "DH-RSA-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A2 */ + "DHE-DSS-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A3 */ + "DHE-DSS-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A4 */ + "DH-DSS-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A5 */ + "DH-DSS-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DH_anon_WITH_AES_128_GCM_SHA256, /* 0x00A6 */ + "ADH-AES128-GCM-SHA256", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF(TLS_DH_anon_WITH_AES_256_GCM_SHA384, /* 0x00A7 */ + "ADH-AES256-GCM-SHA384", + CIPHER_WEAK_ANON_AUTH), +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + /* RFC 5487 - PSK with SHA-256/384 and AES GCM */ + CIPHER_DEF(TLS_PSK_WITH_AES_128_GCM_SHA256, /* 0x00A8 */ + "PSK-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_PSK_WITH_AES_256_GCM_SHA384, /* 0x00A9 */ + "PSK-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AA */ + "DHE-PSK-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AB */ + "DHE-PSK-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AC */ + "RSA-PSK-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AD */ + "RSA-PSK-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA256, /* 0x00AE */ + "PSK-AES128-CBC-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA384, /* 0x00AF */ + "PSK-AES256-CBC-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_PSK_WITH_NULL_SHA256, /* 0x00B0 */ + "PSK-NULL-SHA256", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_PSK_WITH_NULL_SHA384, /* 0x00B1 */ + "PSK-NULL-SHA384", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B2 */ + "DHE-PSK-AES128-CBC-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B3 */ + "DHE-PSK-AES256-CBC-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA256, /* 0x00B4 */ + "DHE-PSK-NULL-SHA256", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA384, /* 0x00B5 */ + "DHE-PSK-NULL-SHA384", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B6 */ + "RSA-PSK-AES128-CBC-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B7 */ + "RSA-PSK-AES256-CBC-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA256, /* 0x00B8 */ + "RSA-PSK-NULL-SHA256", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA384, /* 0x00B9 */ + "RSA-PSK-NULL-SHA384", + CIPHER_WEAK_NOT_ENCRYPTED), +#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ + + /* RFC 5746 - Secure Renegotiation. This is not a real suite, + it is a response to initiate negotiation again */ + CIPHER_DEF(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, /* 0x00FF */ + NULL, + CIPHER_STRONG_ENOUGH), + +#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 + /* TLS 1.3 standard cipher suites for ChaCha20+Poly1305. + Note: TLS 1.3 ciphersuites do not specify the key exchange + algorithm -- they only specify the symmetric ciphers. + Cipher alias name matches to OpenSSL cipher name, and for + TLS 1.3 ciphers */ + CIPHER_DEF(TLS_AES_128_GCM_SHA256, /* 0x1301 */ + NULL, /* The OpenSSL cipher name matches to the IANA name */ + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_AES_256_GCM_SHA384, /* 0x1302 */ + NULL, /* The OpenSSL cipher name matches to the IANA name */ + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */ + NULL, /* The OpenSSL cipher name matches to the IANA name */ + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_AES_128_CCM_SHA256, /* 0x1304 */ + NULL, /* The OpenSSL cipher name matches to the IANA name */ + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_AES_128_CCM_8_SHA256, /* 0x1305 */ + NULL, /* The OpenSSL cipher name matches to the IANA name */ + CIPHER_STRONG_ENOUGH), +#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ + +#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS + /* ECDSA addenda, RFC 4492 */ + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_NULL_SHA, /* 0xC001 */ + "ECDH-ECDSA-NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, /* 0xC002 */ + "ECDH-ECDSA-RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */ + "ECDH-ECDSA-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */ + "ECDH-ECDSA-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */ + "ECDH-ECDSA-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_NULL_SHA, /* 0xC006 */ + "ECDHE-ECDSA-NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, /* 0xC007 */ + "ECDHE-ECDSA-RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */ + "ECDHE-ECDSA-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */ + "ECDHE-ECDSA-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */ + "ECDHE-ECDSA-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_RSA_WITH_NULL_SHA, /* 0xC00B */ + "ECDH-RSA-NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_ECDH_RSA_WITH_RC4_128_SHA, /* 0xC00C */ + "ECDH-RSA-RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */ + "ECDH-RSA-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */ + "ECDH-RSA-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */ + "ECDH-RSA-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_NULL_SHA, /* 0xC010 */ + "ECDHE-RSA-NULL-SHA", + CIPHER_WEAK_NOT_ENCRYPTED), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_RC4_128_SHA, /* 0xC011 */ + "ECDHE-RSA-RC4-SHA", + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */ + "ECDHE-RSA-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */ + "ECDHE-RSA-AES128-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */ + "ECDHE-RSA-AES256-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_anon_WITH_NULL_SHA, /* 0xC015 */ + "AECDH-NULL-SHA", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF(TLS_ECDH_anon_WITH_RC4_128_SHA, /* 0xC016 */ + "AECDH-RC4-SHA", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, /* 0xC017 */ + "AECDH-DES-CBC3-SHA", + CIPHER_WEAK_3DES_ENCRYPTION), + CIPHER_DEF(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, /* 0xC018 */ + "AECDH-AES128-SHA", + CIPHER_WEAK_ANON_AUTH), + CIPHER_DEF(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, /* 0xC019 */ + "AECDH-AES256-SHA", + CIPHER_WEAK_ANON_AUTH), +#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with + HMAC SHA-256/384. */ + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */ + "ECDHE-ECDSA-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */ + "ECDHE-ECDSA-AES256-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */ + "ECDH-ECDSA-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */ + "ECDH-ECDSA-AES256-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */ + "ECDHE-RSA-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */ + "ECDHE-RSA-AES256-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */ + "ECDH-RSA-AES128-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */ + "ECDH-RSA-AES256-SHA384", + CIPHER_STRONG_ENOUGH), + /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with + SHA-256/384 and AES Galois Counter Mode (GCM) */ + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */ + "ECDHE-ECDSA-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */ + "ECDHE-ECDSA-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */ + "ECDH-ECDSA-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */ + "ECDH-ECDSA-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */ + "ECDHE-RSA-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */ + "ECDHE-RSA-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */ + "ECDH-RSA-AES128-GCM-SHA256", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */ + "ECDH-RSA-AES256-GCM-SHA384", + CIPHER_STRONG_ENOUGH), +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + +#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 + /* ECDHE_PSK Cipher Suites for Transport Layer Security (TLS), RFC 5489 */ + CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, /* 0xC035 */ + "ECDHE-PSK-AES128-CBC-SHA", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, /* 0xC036 */ + "ECDHE-PSK-AES256-CBC-SHA", + CIPHER_STRONG_ENOUGH), +#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */ + +#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 + /* Addenda from rfc 7905 ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS). */ + CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */ + "ECDHE-RSA-CHACHA20-POLY1305", + CIPHER_STRONG_ENOUGH), + CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */ + "ECDHE-ECDSA-CHACHA20-POLY1305", + CIPHER_STRONG_ENOUGH), +#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ + +#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 + /* ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS), + RFC 7905 */ + CIPHER_DEF(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCAB */ + "PSK-CHACHA20-POLY1305", + CIPHER_STRONG_ENOUGH), +#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */ + + /* Tags for SSL 2 cipher kinds which are not specified for SSL 3. + Defined since SDK 10.2.8 */ + CIPHER_DEF(SSL_RSA_WITH_RC2_CBC_MD5, /* 0xFF80 */ + NULL, + CIPHER_WEAK_RC_ENCRYPTION), + CIPHER_DEF(SSL_RSA_WITH_IDEA_CBC_MD5, /* 0xFF81 */ + NULL, + CIPHER_WEAK_IDEA_ENCRYPTION), + CIPHER_DEF(SSL_RSA_WITH_DES_CBC_MD5, /* 0xFF82 */ + NULL, + CIPHER_WEAK_DES_ENCRYPTION), + CIPHER_DEF(SSL_RSA_WITH_3DES_EDE_CBC_MD5, /* 0xFF83 */ + NULL, + CIPHER_WEAK_3DES_ENCRYPTION), +}; + +#define NUM_OF_CIPHERS sizeof(ciphertable)/sizeof(ciphertable[0]) + + +/* pinned public key support tests */ + +/* version 1 supports macOS 10.12+ and iOS 10+ */ +#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ + (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) +#define SECTRANSP_PINNEDPUBKEY_V1 1 +#endif + +/* version 2 supports MacOSX 10.7+ */ +#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) +#define SECTRANSP_PINNEDPUBKEY_V2 1 +#endif + +#if defined(SECTRANSP_PINNEDPUBKEY_V1) || defined(SECTRANSP_PINNEDPUBKEY_V2) +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define SECTRANSP_PINNEDPUBKEY 1 +#endif /* SECTRANSP_PINNEDPUBKEY */ + +#ifdef SECTRANSP_PINNEDPUBKEY +/* both new and old APIs return rsa keys missing the spki header (not DER) */ +static const unsigned char rsa4096SpkiHeader[] = { + 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00}; + +static const unsigned char rsa2048SpkiHeader[] = { + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00}; +#ifdef SECTRANSP_PINNEDPUBKEY_V1 +/* the *new* version doesn't return DER encoded ecdsa certs like the old... */ +static const unsigned char ecDsaSecp256r1SpkiHeader[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00}; + +static const unsigned char ecDsaSecp384r1SpkiHeader[] = { + 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, + 0x00, 0x22, 0x03, 0x62, 0x00}; +#endif /* SECTRANSP_PINNEDPUBKEY_V1 */ +#endif /* SECTRANSP_PINNEDPUBKEY */ + +static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection, + void *buf, + size_t *dataLength) /* IN/OUT */ +{ + struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nread; + CURLcode result; + OSStatus rtn = noErr; + + DEBUGASSERT(data); + nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result); + CURL_TRC_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d", + *dataLength, nread, result); + if(nread < 0) { + switch(result) { + case CURLE_OK: + case CURLE_AGAIN: + rtn = errSSLWouldBlock; + backend->ssl_direction = false; + break; + default: + rtn = ioErr; + break; + } + nread = 0; + } + else if(nread == 0) { + rtn = errSSLClosedGraceful; + } + else if((size_t)nread < *dataLength) { + rtn = errSSLWouldBlock; + } + *dataLength = nread; + return rtn; +} + +static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection, + const void *buf, + size_t *dataLength) /* IN/OUT */ +{ + struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result; + OSStatus rtn = noErr; + + DEBUGASSERT(data); + nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result); + CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d", + *dataLength, nwritten, result); + if(nwritten <= 0) { + if(result == CURLE_AGAIN) { + rtn = errSSLWouldBlock; + backend->ssl_direction = true; + } + else { + rtn = ioErr; + } + nwritten = 0; + } + else if((size_t)nwritten < *dataLength) { + rtn = errSSLWouldBlock; + } + *dataLength = nwritten; + return rtn; +} + +CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) +{ + /* The first ciphers in the ciphertable are continuous. Here we do small + optimization and instead of loop directly get SSL name by cipher number. + */ + size_t i; + if(cipher <= SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA) { + return ciphertable[cipher].name; + } + /* Iterate through the rest of the ciphers */ + for(i = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA + 1; i < NUM_OF_CIPHERS; + ++i) { + if(ciphertable[i].num == cipher) { + return ciphertable[i].name; + } + } + return ciphertable[SSL_NULL_WITH_NULL_NULL].name; +} + +#if CURL_BUILD_MAC +CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) +{ + int mib[2]; + char *os_version; + size_t os_version_len; + char *os_version_major, *os_version_minor; + char *tok_buf; + + /* Get the Darwin kernel version from the kernel using sysctl(): */ + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1) + return; + os_version = malloc(os_version_len*sizeof(char)); + if(!os_version) + return; + if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) { + free(os_version); + return; + } + + /* Parse the version: */ + os_version_major = strtok_r(os_version, ".", &tok_buf); + os_version_minor = strtok_r(NULL, ".", &tok_buf); + *major = atoi(os_version_major); + *minor = atoi(os_version_minor); + free(os_version); +} +#endif /* CURL_BUILD_MAC */ + +/* Apple provides a myriad of ways of getting information about a certificate + into a string. Some aren't available under iOS or newer cats. So here's + a unified function for getting a string describing the certificate that + ought to work in all cats starting with Leopard. */ +CF_INLINE CFStringRef getsubject(SecCertificateRef cert) +{ + CFStringRef server_cert_summary = CFSTR("(null)"); + +#if CURL_BUILD_IOS + /* iOS: There's only one way to do this. */ + server_cert_summary = SecCertificateCopySubjectSummary(cert); +#else +#if CURL_BUILD_MAC_10_7 + /* Lion & later: Get the long description if we can. */ + if(SecCertificateCopyLongDescription) + server_cert_summary = + SecCertificateCopyLongDescription(NULL, cert, NULL); + else +#endif /* CURL_BUILD_MAC_10_7 */ +#if CURL_BUILD_MAC_10_6 + /* Snow Leopard: Get the certificate summary. */ + if(SecCertificateCopySubjectSummary) + server_cert_summary = SecCertificateCopySubjectSummary(cert); + else +#endif /* CURL_BUILD_MAC_10_6 */ + /* Leopard is as far back as we go... */ + (void)SecCertificateCopyCommonName(cert, &server_cert_summary); +#endif /* CURL_BUILD_IOS */ + return server_cert_summary; +} + +static CURLcode CopyCertSubject(struct Curl_easy *data, + SecCertificateRef cert, char **certp) +{ + CFStringRef c = getsubject(cert); + CURLcode result = CURLE_OK; + const char *direct; + char *cbuf = NULL; + *certp = NULL; + + if(!c) { + failf(data, "SSL: invalid CA certificate subject"); + return CURLE_PEER_FAILED_VERIFICATION; + } + + /* If the subject is already available as UTF-8 encoded (ie 'direct') then + use that, else convert it. */ + direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8); + if(direct) { + *certp = strdup(direct); + if(!*certp) { + failf(data, "SSL: out of memory"); + result = CURLE_OUT_OF_MEMORY; + } + } + else { + size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1; + cbuf = calloc(1, cbuf_size); + if(cbuf) { + if(!CFStringGetCString(c, cbuf, cbuf_size, + kCFStringEncodingUTF8)) { + failf(data, "SSL: invalid CA certificate subject"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else + /* pass back the buffer */ + *certp = cbuf; + } + else { + failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size); + result = CURLE_OUT_OF_MEMORY; + } + } + if(result) + free(cbuf); + CFRelease(c); + return result; +} + +#if CURL_SUPPORT_MAC_10_6 +/* The SecKeychainSearch API was deprecated in Lion, and using it will raise + deprecation warnings, so let's not compile this unless it's necessary: */ +static OSStatus CopyIdentityWithLabelOldSchool(char *label, + SecIdentityRef *out_c_a_k) +{ + OSStatus status = errSecItemNotFound; + SecKeychainAttributeList attr_list; + SecKeychainAttribute attr; + SecKeychainSearchRef search = NULL; + SecCertificateRef cert = NULL; + + /* Set up the attribute list: */ + attr_list.count = 1L; + attr_list.attr = &attr; + + /* Set up our lone search criterion: */ + attr.tag = kSecLabelItemAttr; + attr.data = label; + attr.length = (UInt32)strlen(label); + + /* Start searching: */ + status = SecKeychainSearchCreateFromAttributes(NULL, + kSecCertificateItemClass, + &attr_list, + &search); + if(status == noErr) { + status = SecKeychainSearchCopyNext(search, + (SecKeychainItemRef *)&cert); + if(status == noErr && cert) { + /* If we found a certificate, does it have a private key? */ + status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k); + CFRelease(cert); + } + } + + if(search) + CFRelease(search); + return status; +} +#endif /* CURL_SUPPORT_MAC_10_6 */ + +static OSStatus CopyIdentityWithLabel(char *label, + SecIdentityRef *out_cert_and_key) +{ + OSStatus status = errSecItemNotFound; + +#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS + CFArrayRef keys_list; + CFIndex keys_list_count; + CFIndex i; + + /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. + kSecClassIdentity was introduced in Lion. If both exist, let's use them + to find the certificate. */ + if(SecItemCopyMatching && kSecClassIdentity) { + CFTypeRef keys[5]; + CFTypeRef values[5]; + CFDictionaryRef query_dict; + CFStringRef label_cf = CFStringCreateWithCString(NULL, label, + kCFStringEncodingUTF8); + + /* Set up our search criteria and expected results: */ + values[0] = kSecClassIdentity; /* we want a certificate and a key */ + keys[0] = kSecClass; + values[1] = kCFBooleanTrue; /* we want a reference */ + keys[1] = kSecReturnRef; + values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the + * label matching below worked correctly */ + keys[2] = kSecMatchLimit; + /* identity searches need a SecPolicyRef in order to work */ + values[3] = SecPolicyCreateSSL(false, NULL); + keys[3] = kSecMatchPolicy; + /* match the name of the certificate (doesn't work in macOS 10.12.1) */ + values[4] = label_cf; + keys[4] = kSecAttrLabel; + query_dict = CFDictionaryCreate(NULL, (const void **)keys, + (const void **)values, 5L, + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRelease(values[3]); + + /* Do we have a match? */ + status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list); + + /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity, + * we need to find the correct identity ourselves */ + if(status == noErr) { + keys_list_count = CFArrayGetCount(keys_list); + *out_cert_and_key = NULL; + status = 1; + for(i = 0; idata, blob->len); + status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate; + resource_imported = (pkcs_data != NULL); + } + else { + pkcs_url = + CFURLCreateFromFileSystemRepresentation(NULL, + (const UInt8 *)cPath, + strlen(cPath), false); + resource_imported = + CFURLCreateDataAndPropertiesFromResource(NULL, + pkcs_url, &pkcs_data, + NULL, NULL, &status); + } + + if(resource_imported) { + CFArrayRef items = NULL; + + /* On iOS SecPKCS12Import will never add the client certificate to the + * Keychain. + * + * It gives us back a SecIdentityRef that we can use directly. */ +#if CURL_BUILD_IOS + const void *cKeys[] = {kSecImportExportPassphrase}; + const void *cValues[] = {password}; + CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, + password ? 1L : 0L, NULL, NULL); + + if(options) { + status = SecPKCS12Import(pkcs_data, options, &items); + CFRelease(options); + } + + + /* On macOS SecPKCS12Import will always add the client certificate to + * the Keychain. + * + * As this doesn't match iOS, and apps may not want to see their client + * certificate saved in the user's keychain, we use SecItemImport + * with a NULL keychain to avoid importing it. + * + * This returns a SecCertificateRef from which we can construct a + * SecIdentityRef. + */ +#elif CURL_BUILD_MAC_10_7 + SecItemImportExportKeyParameters keyParams; + SecExternalFormat inputFormat = kSecFormatPKCS12; + SecExternalItemType inputType = kSecItemTypeCertificate; + + memset(&keyParams, 0x00, sizeof(keyParams)); + keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; + keyParams.passphrase = password; + + status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType, + 0, &keyParams, NULL, &items); +#endif + + + /* Extract the SecIdentityRef */ + if(status == errSecSuccess && items && CFArrayGetCount(items)) { + CFIndex i, count; + count = CFArrayGetCount(items); + + for(i = 0; i < count; i++) { + CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i); + CFTypeID itemID = CFGetTypeID(item); + + if(itemID == CFDictionaryGetTypeID()) { + CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue( + (CFDictionaryRef) item, + kSecImportItemIdentity); + CFRetain(identity); + *out_cert_and_key = (SecIdentityRef) identity; + break; + } +#if CURL_BUILD_MAC_10_7 + else if(itemID == SecCertificateGetTypeID()) { + status = SecIdentityCreateWithCertificate(NULL, + (SecCertificateRef) item, + out_cert_and_key); + break; + } +#endif + } + } + + if(items) + CFRelease(items); + CFRelease(pkcs_data); + } +#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ + if(password) + CFRelease(password); + if(pkcs_url) + CFRelease(pkcs_url); + return status; +} + +/* This code was borrowed from nss.c, with some modifications: + * Determine whether the nickname passed in is a filename that needs to + * be loaded as a PEM or a nickname. + * + * returns 1 for a file + * returns 0 for not a file + */ +CF_INLINE bool is_file(const char *filename) +{ + struct_stat st; + + if(!filename) + return false; + + if(stat(filename, &st) == 0) + return S_ISREG(st.st_mode); + return false; +} + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS +static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver, + long ssl_version) +{ + switch(ssl_version) { + case CURL_SSLVERSION_TLSv1_0: + *darwinver = kTLSProtocol1; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1: + *darwinver = kTLSProtocol11; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2: + *darwinver = kTLSProtocol12; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + /* TLS 1.3 support first appeared in iOS 11 and macOS 10.13 */ +#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 + if(__builtin_available(macOS 10.13, iOS 11.0, *)) { + *darwinver = kTLSProtocol13; + return CURLE_OK; + } +#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && + HAVE_BUILTIN_AVAILABLE == 1 */ + break; + } + return CURLE_SSL_CONNECT_ERROR; +} +#endif + +static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + long ssl_version = conn_config->version; + long ssl_version_max = conn_config->version_max; + long max_supported_version_by_os; + + DEBUGASSERT(backend); + + /* macOS 10.5-10.7 supported TLS 1.0 only. + macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2. + macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */ +#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 + if(__builtin_available(macOS 10.13, iOS 11.0, *)) { + max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3; + } + else { + max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2; + } +#else + max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2; +#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && + HAVE_BUILTIN_AVAILABLE == 1 */ + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ssl_version = CURL_SSLVERSION_TLSv1_0; + break; + } + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = max_supported_version_by_os; + break; + } + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLSetProtocolVersionMax) { + SSLProtocol darwin_ver_min = kTLSProtocol1; + SSLProtocol darwin_ver_max = kTLSProtocol1; + CURLcode result = sectransp_version_from_curl(&darwin_ver_min, + ssl_version); + if(result) { + failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); + return result; + } + result = sectransp_version_from_curl(&darwin_ver_max, + ssl_version_max >> 16); + if(result) { + failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); + return result; + } + + (void)SSLSetProtocolVersionMin(backend->ssl_ctx, darwin_ver_min); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, darwin_ver_max); + return result; + } + else { +#if CURL_SUPPORT_MAC_10_8 + long i = ssl_version; + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kSSLProtocolAll, + false); + for(; i <= (ssl_version_max >> 16); i++) { + switch(i) { + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_TLSv1_1: + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kTLSProtocol11, + true); + break; + case CURL_SSLVERSION_TLSv1_2: + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "Your version of the OS does not support TLSv1.3"); + return CURLE_SSL_CONNECT_ERROR; + } + } + return CURLE_OK; +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + failf(data, "Secure Transport: cannot set SSL protocol"); + return CURLE_SSL_CONNECT_ERROR; +} + +static bool is_cipher_suite_strong(SSLCipherSuite suite_num) +{ + size_t i; + for(i = 0; i < NUM_OF_CIPHERS; ++i) { + if(ciphertable[i].num == suite_num) { + return !ciphertable[i].weak; + } + } + /* If the cipher is not in our list, assume it is a new one + and therefore strong. Previous implementation was the same, + if cipher suite is not in the list, it was considered strong enough */ + return true; +} + +static bool is_separator(char c) +{ + /* Return whether character is a cipher list separator. */ + switch(c) { + case ' ': + case '\t': + case ':': + case ',': + case ';': + return true; + } + return false; +} + +static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data, + SSLContextRef ssl_ctx) +{ + size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i; + SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL; + OSStatus err = noErr; + +#if CURL_BUILD_MAC + int darwinver_maj = 0, darwinver_min = 0; + + GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); +#endif /* CURL_BUILD_MAC */ + + /* Disable cipher suites that ST supports but are not safe. These ciphers + are unlikely to be used in any case since ST gives other ciphers a much + higher priority, but it's probably better that we not connect at all than + to give the user a false sense of security if the server only supports + insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */ + err = SSLGetNumberSupportedCiphers(ssl_ctx, &all_ciphers_count); + if(err != noErr) { + failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d", + err); + return CURLE_SSL_CIPHER; + } + all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); + if(!all_ciphers) { + failf(data, "SSL: Failed to allocate memory for all ciphers"); + return CURLE_OUT_OF_MEMORY; + } + allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); + if(!allowed_ciphers) { + Curl_safefree(all_ciphers); + failf(data, "SSL: Failed to allocate memory for allowed ciphers"); + return CURLE_OUT_OF_MEMORY; + } + err = SSLGetSupportedCiphers(ssl_ctx, all_ciphers, + &all_ciphers_count); + if(err != noErr) { + Curl_safefree(all_ciphers); + Curl_safefree(allowed_ciphers); + return CURLE_SSL_CIPHER; + } + for(i = 0UL ; i < all_ciphers_count ; i++) { +#if CURL_BUILD_MAC + /* There's a known bug in early versions of Mountain Lion where ST's ECC + ciphers (cipher suite 0xC001 through 0xC032) simply do not work. + Work around the problem here by disabling those ciphers if we are + running in an affected version of OS X. */ + if(darwinver_maj == 12 && darwinver_min <= 3 && + all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) { + continue; + } +#endif /* CURL_BUILD_MAC */ + if(is_cipher_suite_strong(all_ciphers[i])) { + allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i]; + } + } + err = SSLSetEnabledCiphers(ssl_ctx, allowed_ciphers, + allowed_ciphers_count); + Curl_safefree(all_ciphers); + Curl_safefree(allowed_ciphers); + if(err != noErr) { + failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); + return CURLE_SSL_CIPHER; + } + return CURLE_OK; +} + +static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data, + SSLContextRef ssl_ctx, + const char *ciphers) +{ + size_t ciphers_count = 0; + const char *cipher_start = ciphers; + OSStatus err = noErr; + SSLCipherSuite selected_ciphers[NUM_OF_CIPHERS]; + + if(!ciphers) + return CURLE_OK; + + while(is_separator(*ciphers)) /* Skip initial separators. */ + ciphers++; + if(!*ciphers) + return CURLE_OK; + + cipher_start = ciphers; + while(*cipher_start && ciphers_count < NUM_OF_CIPHERS) { + bool cipher_found = FALSE; + size_t cipher_len = 0; + const char *cipher_end = NULL; + bool tls_name = FALSE; + size_t i; + + /* Skip separators */ + while(is_separator(*cipher_start)) + cipher_start++; + if(*cipher_start == '\0') { + break; + } + /* Find last position of a cipher in the ciphers string */ + cipher_end = cipher_start; + while(*cipher_end != '\0' && !is_separator(*cipher_end)) { + ++cipher_end; + } + + /* IANA cipher names start with the TLS_ or SSL_ prefix. + If the 4th symbol of the cipher is '_' we look for a cipher in the + table by its (TLS) name. + Otherwise, we try to match cipher by an alias. */ + if(cipher_start[3] == '_') { + tls_name = TRUE; + } + /* Iterate through the cipher table and look for the cipher, starting + the cipher number 0x01 because the 0x00 is not the real cipher */ + cipher_len = cipher_end - cipher_start; + for(i = 1; i < NUM_OF_CIPHERS; ++i) { + const char *table_cipher_name = NULL; + if(tls_name) { + table_cipher_name = ciphertable[i].name; + } + else if(ciphertable[i].alias_name) { + table_cipher_name = ciphertable[i].alias_name; + } + else { + continue; + } + /* Compare a part of the string between separators with a cipher name + in the table and make sure we matched the whole cipher name */ + if(strncmp(cipher_start, table_cipher_name, cipher_len) == 0 + && table_cipher_name[cipher_len] == '\0') { + selected_ciphers[ciphers_count] = ciphertable[i].num; + ++ciphers_count; + cipher_found = TRUE; + break; + } + } + if(!cipher_found) { + /* It would be more human-readable if we print the wrong cipher name + but we don't want to allocate any additional memory and copy the name + into it, then add it into logs. + Also, we do not modify an original cipher list string. We just point + to positions where cipher starts and ends in the cipher list string. + The message is a bit cryptic and longer than necessary but can be + understood by humans. */ + failf(data, "SSL: cipher string \"%s\" contains unsupported cipher name" + " starting position %zd and ending position %zd", + ciphers, + cipher_start - ciphers, + cipher_end - ciphers); + return CURLE_SSL_CIPHER; + } + if(*cipher_end) { + cipher_start = cipher_end + 1; + } + else { + break; + } + } + /* All cipher suites in the list are found. Report to logs as-is */ + infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers); + + err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count); + if(err != noErr) { + failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); + return CURLE_SSL_CIPHER; + } + return CURLE_OK; +} + +static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + const struct curl_blob *ssl_cablob = conn_config->ca_info_blob; + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ssl_cablob ? NULL : conn_config->CAfile); + const bool verifypeer = conn_config->verifypeer; + char * const ssl_cert = ssl_config->primary.clientcert; + const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; + char *ciphers; + OSStatus err = noErr; +#if CURL_BUILD_MAC + int darwinver_maj = 0, darwinver_min = 0; + + DEBUGASSERT(backend); + + CURL_TRC_CF(data, cf, "connect_step1"); + GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); +#endif /* CURL_BUILD_MAC */ + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLCreateContext) { /* use the newer API if available */ + if(backend->ssl_ctx) + CFRelease(backend->ssl_ctx); + backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); + if(!backend->ssl_ctx) { + failf(data, "SSL: couldn't create a context"); + return CURLE_OUT_OF_MEMORY; + } + } + else { + /* The old ST API does not exist under iOS, so don't compile it: */ +#if CURL_SUPPORT_MAC_10_8 + if(backend->ssl_ctx) + (void)SSLDisposeContext(backend->ssl_ctx); + err = SSLNewContext(false, &(backend->ssl_ctx)); + if(err != noErr) { + failf(data, "SSL: couldn't create a context: OSStatus %d", err); + return CURLE_OUT_OF_MEMORY; + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#else + if(backend->ssl_ctx) + (void)SSLDisposeContext(backend->ssl_ctx); + err = SSLNewContext(false, &(backend->ssl_ctx)); + if(err != noErr) { + failf(data, "SSL: couldn't create a context: OSStatus %d", err); + return CURLE_OUT_OF_MEMORY; + } +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */ + + /* check to see if we've been told to use an explicit SSL/TLS version */ +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLSetProtocolVersionMax) { + switch(conn_config->version) { + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1); +#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 + if(__builtin_available(macOS 10.13, iOS 11.0, *)) { + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13); + } + else { + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12); + } +#else + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12); +#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && + HAVE_BUILTIN_AVAILABLE == 1 */ + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + { + CURLcode result = set_ssl_version_min_max(cf, data); + if(result != CURLE_OK) + return result; + break; + } + case CURL_SSLVERSION_SSLv3: + case CURL_SSLVERSION_SSLv2: + failf(data, "SSL versions not supported"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { +#if CURL_SUPPORT_MAC_10_8 + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kSSLProtocolAll, + false); + switch(conn_config->version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kTLSProtocol1, + true); + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kTLSProtocol11, + true); + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + { + CURLcode result = set_ssl_version_min_max(cf, data); + if(result != CURLE_OK) + return result; + break; + } + case CURL_SSLVERSION_SSLv3: + case CURL_SSLVERSION_SSLv2: + failf(data, "SSL versions not supported"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#else + if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) { + failf(data, "Your version of the OS does not support to set maximum" + " SSL/TLS version"); + return CURLE_SSL_CONNECT_ERROR; + } + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false); + switch(conn_config->version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_TLSv1_1: + failf(data, "Your version of the OS does not support TLSv1.1"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_2: + failf(data, "Your version of the OS does not support TLSv1.2"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "Your version of the OS does not support TLSv1.3"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv2: + case CURL_SSLVERSION_SSLv3: + failf(data, "SSL versions not supported"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + +#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 + if(connssl->alpn) { + if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { + struct alpn_proto_buf proto; + size_t i; + CFStringRef cstr; + CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0, + &kCFTypeArrayCallBacks); + for(i = 0; i < connssl->alpn->count; ++i) { + cstr = CFStringCreateWithCString(NULL, connssl->alpn->entries[i], + kCFStringEncodingUTF8); + if(!cstr) + return CURLE_OUT_OF_MEMORY; + CFArrayAppendValue(alpnArr, cstr); + CFRelease(cstr); + } + err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr); + if(err != noErr) + infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d", + err); + CFRelease(alpnArr); + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } + } +#endif + + if(ssl_config->key) { + infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " + "Transport. The private key must be in the Keychain."); + } + + if(ssl_cert || ssl_cert_blob) { + bool is_cert_data = ssl_cert_blob != NULL; + bool is_cert_file = (!is_cert_data) && is_file(ssl_cert); + SecIdentityRef cert_and_key = NULL; + + /* User wants to authenticate with a client cert. Look for it. Assume that + the user wants to use an identity loaded from the Keychain. If not, try + it as a file on disk */ + + if(!is_cert_data) + err = CopyIdentityWithLabel(ssl_cert, &cert_and_key); + else + err = !noErr; + if((err != noErr) && (is_cert_file || is_cert_data)) { + if(!ssl_config->cert_type) + infof(data, "SSL: Certificate type not set, assuming " + "PKCS#12 format."); + else if(!strcasecompare(ssl_config->cert_type, "P12")) { + failf(data, "SSL: The Security framework only supports " + "loading identities that are in PKCS#12 format."); + return CURLE_SSL_CERTPROBLEM; + } + + err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob, + ssl_config->key_passwd, + &cert_and_key); + } + + if(err == noErr && cert_and_key) { + SecCertificateRef cert = NULL; + CFTypeRef certs_c[1]; + CFArrayRef certs; + + /* If we found one, print it out: */ + err = SecIdentityCopyCertificate(cert_and_key, &cert); + if(err == noErr) { + char *certp; + CURLcode result = CopyCertSubject(data, cert, &certp); + if(!result) { + infof(data, "Client certificate: %s", certp); + free(certp); + } + + CFRelease(cert); + if(result == CURLE_PEER_FAILED_VERIFICATION) + return CURLE_SSL_CERTPROBLEM; + if(result) + return result; + } + certs_c[0] = cert_and_key; + certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, + &kCFTypeArrayCallBacks); + err = SSLSetCertificate(backend->ssl_ctx, certs); + if(certs) + CFRelease(certs); + if(err != noErr) { + failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err); + return CURLE_SSL_CERTPROBLEM; + } + CFRelease(cert_and_key); + } + else { + const char *cert_showfilename_error = + is_cert_data ? "(memory blob)" : ssl_cert; + + switch(err) { + case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ + failf(data, "SSL: Incorrect password for the certificate \"%s\" " + "and its private key.", cert_showfilename_error); + break; + case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ + failf(data, "SSL: Couldn't make sense of the data in the " + "certificate \"%s\" and its private key.", + cert_showfilename_error); + break; + case -25260: /* errSecPassphraseRequired */ + failf(data, "SSL The certificate \"%s\" requires a password.", + cert_showfilename_error); + break; + case errSecItemNotFound: + failf(data, "SSL: Can't find the certificate \"%s\" and its private " + "key in the Keychain.", cert_showfilename_error); + break; + default: + failf(data, "SSL: Can't load the certificate \"%s\" and its private " + "key: OSStatus %d", cert_showfilename_error, err); + break; + } + return CURLE_SSL_CERTPROBLEM; + } + } + + /* SSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ +#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS + /* Snow Leopard introduced the SSLSetSessionOption() function, but due to + a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag + works, it doesn't work as expected under Snow Leopard, Lion or + Mountain Lion. + So we need to call SSLSetEnableCertVerify() on those older cats in order + to disable certificate validation if the user turned that off. + (SecureTransport will always validate the certificate chain by + default.) + Note: + Darwin 11.x.x is Lion (10.7) + Darwin 12.x.x is Mountain Lion (10.8) + Darwin 13.x.x is Mavericks (10.9) + Darwin 14.x.x is Yosemite (10.10) + Darwin 15.x.x is El Capitan (10.11) + */ +#if CURL_BUILD_MAC + if(SSLSetSessionOption && darwinver_maj >= 13) { +#else + if(SSLSetSessionOption) { +#endif /* CURL_BUILD_MAC */ + bool break_on_auth = !conn_config->verifypeer || + ssl_cafile || ssl_cablob; + err = SSLSetSessionOption(backend->ssl_ctx, + kSSLSessionOptionBreakOnServerAuth, + break_on_auth); + if(err != noErr) { + failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { +#if CURL_SUPPORT_MAC_10_8 + err = SSLSetEnableCertVerify(backend->ssl_ctx, + conn_config->verifypeer?true:false); + if(err != noErr) { + failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#else + err = SSLSetEnableCertVerify(backend->ssl_ctx, + conn_config->verifypeer?true:false); + if(err != noErr) { + failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ + + if((ssl_cafile || ssl_cablob) && verifypeer) { + bool is_cert_data = ssl_cablob != NULL; + bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile); + + if(!(is_cert_file || is_cert_data)) { + failf(data, "SSL: can't load CA certificate file %s", + ssl_cafile ? ssl_cafile : "(blob memory)"); + return CURLE_SSL_CACERT_BADFILE; + } + } + + /* Configure hostname check. SNI is used if available. + * Both hostname check and SNI require SSLSetPeerDomainName(). + * Also: the verifyhost setting influences SNI usage */ + if(conn_config->verifyhost) { + char *server = connssl->peer.sni? + connssl->peer.sni : connssl->peer.hostname; + err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server)); + + if(err != noErr) { + failf(data, "SSL: SSLSetPeerDomainName() failed: OSStatus %d", + err); + return CURLE_SSL_CONNECT_ERROR; + } + + if(connssl->peer.is_ip_address) { + infof(data, "WARNING: using IP address, SNI is being disabled by " + "the OS."); + } + } + else { + infof(data, "WARNING: disabling hostname validation also disables SNI."); + } + + ciphers = conn_config->cipher_list; + if(ciphers) { + err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers); + } + else { + err = sectransp_set_default_ciphers(data, backend->ssl_ctx); + } + if(err != noErr) { + failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. " + "Error code: %d", err); + return CURLE_SSL_CIPHER; + } + +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + /* We want to enable 1/n-1 when using a CBC cipher unless the user + specifically doesn't want us doing that: */ + if(SSLSetSessionOption) { + SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord, + !ssl_config->enable_beast); + SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart, + ssl_config->falsestart); /* false start support */ + } +#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ + + /* Check if there's a cached ID we can/should use here! */ + if(ssl_config->primary.sessionid) { + char *ssl_sessionid; + size_t ssl_sessionid_len; + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid, + &ssl_sessionid_len)) { + /* we got a session id, use it! */ + err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + Curl_ssl_sessionid_unlock(data); + if(err != noErr) { + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL reusing session ID"); + } + /* If there isn't one, then let's make one up! This has to be done prior + to starting the handshake. */ + else { + CURLcode result; + ssl_sessionid = + aprintf("%s:%d:%d:%s:%d", + ssl_cafile ? ssl_cafile : "(blob memory)", + verifypeer, conn_config->verifyhost, connssl->peer.hostname, + connssl->port); + ssl_sessionid_len = strlen(ssl_sessionid); + + err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + if(err != noErr) { + Curl_ssl_sessionid_unlock(data); + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + result = Curl_ssl_addsessionid(cf, data, ssl_sessionid, + ssl_sessionid_len, NULL); + Curl_ssl_sessionid_unlock(data); + if(result) { + failf(data, "failed to store ssl session"); + return result; + } + } + } + + err = SSLSetIOFuncs(backend->ssl_ctx, + sectransp_bio_cf_in_read, + sectransp_bio_cf_out_write); + if(err != noErr) { + failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + err = SSLSetConnection(backend->ssl_ctx, cf); + if(err != noErr) { + failf(data, "SSL: SSLSetConnection() failed: %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; +} + +static long pem_to_der(const char *in, unsigned char **out, size_t *outlen) +{ + char *sep_start, *sep_end, *cert_start, *cert_end; + size_t i, j, err; + size_t len; + unsigned char *b64; + + /* Jump through the separators at the beginning of the certificate. */ + sep_start = strstr(in, "-----"); + if(!sep_start) + return 0; + cert_start = strstr(sep_start + 1, "-----"); + if(!cert_start) + return -1; + + cert_start += 5; + + /* Find separator after the end of the certificate. */ + cert_end = strstr(cert_start, "-----"); + if(!cert_end) + return -1; + + sep_end = strstr(cert_end + 1, "-----"); + if(!sep_end) + return -1; + sep_end += 5; + + len = cert_end - cert_start; + b64 = malloc(len + 1); + if(!b64) + return -1; + + /* Create base64 string without linefeeds. */ + for(i = 0, j = 0; i < len; i++) { + if(cert_start[i] != '\r' && cert_start[i] != '\n') + b64[j++] = cert_start[i]; + } + b64[j] = '\0'; + + err = Curl_base64_decode((const char *)b64, out, outlen); + free(b64); + if(err) { + free(*out); + return -1; + } + + return sep_end - in; +} + +#define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */ + +static int read_cert(const char *file, unsigned char **out, size_t *outlen) +{ + int fd; + ssize_t n; + unsigned char buf[512]; + struct dynbuf certs; + + Curl_dyn_init(&certs, MAX_CERTS_SIZE); + + fd = open(file, 0); + if(fd < 0) + return -1; + + for(;;) { + n = read(fd, buf, sizeof(buf)); + if(!n) + break; + if(n < 0) { + close(fd); + Curl_dyn_free(&certs); + return -1; + } + if(Curl_dyn_addn(&certs, buf, n)) { + close(fd); + return -1; + } + } + close(fd); + + *out = Curl_dyn_uptr(&certs); + *outlen = Curl_dyn_len(&certs); + + return 0; +} + +static int append_cert_to_array(struct Curl_easy *data, + const unsigned char *buf, size_t buflen, + CFMutableArrayRef array) +{ + char *certp; + CURLcode result; + SecCertificateRef cacert; + CFDataRef certdata; + + certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen); + if(!certdata) { + failf(data, "SSL: failed to allocate array for CA certificate"); + return CURLE_OUT_OF_MEMORY; + } + + cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata); + CFRelease(certdata); + if(!cacert) { + failf(data, "SSL: failed to create SecCertificate from CA certificate"); + return CURLE_SSL_CACERT_BADFILE; + } + + /* Check if cacert is valid. */ + result = CopyCertSubject(data, cacert, &certp); + switch(result) { + case CURLE_OK: + break; + case CURLE_PEER_FAILED_VERIFICATION: + return CURLE_SSL_CACERT_BADFILE; + case CURLE_OUT_OF_MEMORY: + default: + return result; + } + free(certp); + + CFArrayAppendValue(array, cacert); + CFRelease(cacert); + + return CURLE_OK; +} + +static CURLcode verify_cert_buf(struct Curl_cfilter *cf, + struct Curl_easy *data, + const unsigned char *certbuf, size_t buflen, + SSLContextRef ctx) +{ + int n = 0, rc; + long res; + unsigned char *der; + size_t derlen, offset = 0; + OSStatus ret; + SecTrustResultType trust_eval; + CFMutableArrayRef array = NULL; + SecTrustRef trust = NULL; + CURLcode result = CURLE_PEER_FAILED_VERIFICATION; + (void)cf; + /* + * Certbuf now contains the contents of the certificate file, which can be + * - a single DER certificate, + * - a single PEM certificate or + * - a bunch of PEM certificates (certificate bundle). + * + * Go through certbuf, and convert any PEM certificate in it into DER + * format. + */ + array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + if(!array) { + failf(data, "SSL: out of memory creating CA certificate array"); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + while(offset < buflen) { + n++; + + /* + * Check if the certificate is in PEM format, and convert it to DER. If + * this fails, we assume the certificate is in DER format. + */ + res = pem_to_der((const char *)certbuf + offset, &der, &derlen); + if(res < 0) { + failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle", + n, offset); + result = CURLE_SSL_CACERT_BADFILE; + goto out; + } + offset += res; + + if(res == 0 && offset == 0) { + /* This is not a PEM file, probably a certificate in DER format. */ + rc = append_cert_to_array(data, certbuf, buflen, array); + if(rc != CURLE_OK) { + CURL_TRC_CF(data, cf, "append_cert for CA failed"); + result = rc; + goto out; + } + break; + } + else if(res == 0) { + /* No more certificates in the bundle. */ + break; + } + + rc = append_cert_to_array(data, der, derlen, array); + free(der); + if(rc != CURLE_OK) { + CURL_TRC_CF(data, cf, "append_cert for CA failed"); + result = rc; + goto out; + } + } + + ret = SSLCopyPeerTrust(ctx, &trust); + if(!trust) { + failf(data, "SSL: error getting certificate chain"); + goto out; + } + else if(ret != noErr) { + failf(data, "SSLCopyPeerTrust() returned error %d", ret); + goto out; + } + + CURL_TRC_CF(data, cf, "setting %d trust anchors", n); + ret = SecTrustSetAnchorCertificates(trust, array); + if(ret != noErr) { + failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret); + goto out; + } + ret = SecTrustSetAnchorCertificatesOnly(trust, true); + if(ret != noErr) { + failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret); + goto out; + } + + trust_eval = 0; + ret = SecTrustEvaluate(trust, &trust_eval); + if(ret != noErr) { + failf(data, "SecTrustEvaluate() returned error %d", ret); + goto out; + } + + switch(trust_eval) { + case kSecTrustResultUnspecified: + /* what does this really mean? */ + CURL_TRC_CF(data, cf, "trust result: Unspecified"); + result = CURLE_OK; + goto out; + case kSecTrustResultProceed: + CURL_TRC_CF(data, cf, "trust result: Proceed"); + result = CURLE_OK; + goto out; + + case kSecTrustResultRecoverableTrustFailure: + failf(data, "SSL: peer not verified: RecoverableTrustFailure"); + goto out; + case kSecTrustResultDeny: + failf(data, "SSL: peer not verified: Deny"); + goto out; + default: + failf(data, "SSL: perr not verified: result=%d", trust_eval); + goto out; + } + +out: + if(trust) + CFRelease(trust); + if(array) + CFRelease(array); + return result; +} + +static CURLcode verify_cert(struct Curl_cfilter *cf, + struct Curl_easy *data, const char *cafile, + const struct curl_blob *ca_info_blob, + SSLContextRef ctx) +{ + CURLcode result; + unsigned char *certbuf; + size_t buflen; + bool free_certbuf = FALSE; + + if(ca_info_blob) { + CURL_TRC_CF(data, cf, "verify_peer, CA from config blob"); + certbuf = ca_info_blob->data; + buflen = ca_info_blob->len; + } + else if(cafile) { + CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile); + if(read_cert(cafile, &certbuf, &buflen) < 0) { + failf(data, "SSL: failed to read or invalid CA certificate"); + return CURLE_SSL_CACERT_BADFILE; + } + free_certbuf = TRUE; + } + else + return CURLE_SSL_CACERT_BADFILE; + + result = verify_cert_buf(cf, data, certbuf, buflen, ctx); + if(free_certbuf) + free(certbuf); + return result; +} + + +#ifdef SECTRANSP_PINNEDPUBKEY +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, + SSLContextRef ctx, + const char *pinnedpubkey) +{ /* Scratch */ + size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24; + unsigned char *pubkey = NULL, *realpubkey = NULL; + const unsigned char *spkiHeader = NULL; + CFDataRef publicKeyBits = NULL; + + /* Result is returned to caller */ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + + + if(!ctx) + return result; + + do { + SecTrustRef trust; + OSStatus ret; + SecKeyRef keyRef; + + ret = SSLCopyPeerTrust(ctx, &trust); + if(ret != noErr || !trust) + break; + + keyRef = SecTrustCopyPublicKey(trust); + CFRelease(trust); + if(!keyRef) + break; + +#ifdef SECTRANSP_PINNEDPUBKEY_V1 + + publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL); + CFRelease(keyRef); + if(!publicKeyBits) + break; + +#elif SECTRANSP_PINNEDPUBKEY_V2 + + { + OSStatus success; + success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, + &publicKeyBits); + CFRelease(keyRef); + if(success != errSecSuccess || !publicKeyBits) + break; + } + +#endif /* SECTRANSP_PINNEDPUBKEY_V2 */ + + pubkeylen = CFDataGetLength(publicKeyBits); + pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits); + + switch(pubkeylen) { + case 526: + /* 4096 bit RSA pubkeylen == 526 */ + spkiHeader = rsa4096SpkiHeader; + break; + case 270: + /* 2048 bit RSA pubkeylen == 270 */ + spkiHeader = rsa2048SpkiHeader; + break; +#ifdef SECTRANSP_PINNEDPUBKEY_V1 + case 65: + /* ecDSA secp256r1 pubkeylen == 65 */ + spkiHeader = ecDsaSecp256r1SpkiHeader; + spkiHeaderLength = 26; + break; + case 97: + /* ecDSA secp384r1 pubkeylen == 97 */ + spkiHeader = ecDsaSecp384r1SpkiHeader; + spkiHeaderLength = 23; + break; + default: + infof(data, "SSL: unhandled public key length: %zu", pubkeylen); +#elif SECTRANSP_PINNEDPUBKEY_V2 + default: + /* ecDSA secp256r1 pubkeylen == 91 header already included? + * ecDSA secp384r1 header already included too + * we assume rest of algorithms do same, so do nothing + */ + result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey, + pubkeylen); +#endif /* SECTRANSP_PINNEDPUBKEY_V2 */ + continue; /* break from loop */ + } + + realpubkeylen = pubkeylen + spkiHeaderLength; + realpubkey = malloc(realpubkeylen); + if(!realpubkey) + break; + + memcpy(realpubkey, spkiHeader, spkiHeaderLength); + memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen); + + result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey, + realpubkeylen); + + } while(0); + + Curl_safefree(realpubkey); + if(publicKeyBits) + CFRelease(publicKeyBits); + + return result; +} +#endif /* SECTRANSP_PINNEDPUBKEY */ + +static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + OSStatus err; + SSLCipherSuite cipher; + SSLProtocol protocol = 0; + + DEBUGASSERT(ssl_connect_2 == connssl->connecting_state + || ssl_connect_2_reading == connssl->connecting_state + || ssl_connect_2_writing == connssl->connecting_state); + DEBUGASSERT(backend); + CURL_TRC_CF(data, cf, "connect_step2"); + + /* Here goes nothing: */ +check_handshake: + err = SSLHandshake(backend->ssl_ctx); + + if(err != noErr) { + switch(err) { + case errSSLWouldBlock: /* they're not done with us yet */ + connssl->connecting_state = backend->ssl_direction ? + ssl_connect_2_writing : ssl_connect_2_reading; + return CURLE_OK; + + /* The below is errSSLServerAuthCompleted; it's not defined in + Leopard's headers */ + case -9841: + if((conn_config->CAfile || conn_config->ca_info_blob) && + conn_config->verifypeer) { + CURLcode result = verify_cert(cf, data, conn_config->CAfile, + conn_config->ca_info_blob, + backend->ssl_ctx); + if(result) + return result; + } + /* the documentation says we need to call SSLHandshake() again */ + goto check_handshake; + + /* Problem with encrypt / decrypt */ + case errSSLPeerDecodeError: + failf(data, "Decode failed"); + break; + case errSSLDecryptionFail: + case errSSLPeerDecryptionFail: + failf(data, "Decryption failed"); + break; + case errSSLPeerDecryptError: + failf(data, "A decryption error occurred"); + break; + case errSSLBadCipherSuite: + failf(data, "A bad SSL cipher suite was encountered"); + break; + case errSSLCrypto: + failf(data, "An underlying cryptographic error was encountered"); + break; +#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9 + case errSSLWeakPeerEphemeralDHKey: + failf(data, "Indicates a weak ephemeral Diffie-Hellman key"); + break; +#endif + + /* Problem with the message record validation */ + case errSSLBadRecordMac: + case errSSLPeerBadRecordMac: + failf(data, "A record with a bad message authentication code (MAC) " + "was encountered"); + break; + case errSSLRecordOverflow: + case errSSLPeerRecordOverflow: + failf(data, "A record overflow occurred"); + break; + + /* Problem with zlib decompression */ + case errSSLPeerDecompressFail: + failf(data, "Decompression failed"); + break; + + /* Problem with access */ + case errSSLPeerAccessDenied: + failf(data, "Access was denied"); + break; + case errSSLPeerInsufficientSecurity: + failf(data, "There is insufficient security for this operation"); + break; + + /* These are all certificate problems with the server: */ + case errSSLXCertChainInvalid: + failf(data, "SSL certificate problem: Invalid certificate chain"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLUnknownRootCert: + failf(data, "SSL certificate problem: Untrusted root certificate"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLNoRootCert: + failf(data, "SSL certificate problem: No root certificate"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLCertNotYetValid: + failf(data, "SSL certificate problem: The certificate chain had a " + "certificate that is not yet valid"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLCertExpired: + case errSSLPeerCertExpired: + failf(data, "SSL certificate problem: Certificate chain had an " + "expired certificate"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLBadCert: + case errSSLPeerBadCert: + failf(data, "SSL certificate problem: Couldn't understand the server " + "certificate format"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLPeerUnsupportedCert: + failf(data, "SSL certificate problem: An unsupported certificate " + "format was encountered"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLPeerCertRevoked: + failf(data, "SSL certificate problem: The certificate was revoked"); + return CURLE_PEER_FAILED_VERIFICATION; + case errSSLPeerCertUnknown: + failf(data, "SSL certificate problem: The certificate is unknown"); + return CURLE_PEER_FAILED_VERIFICATION; + + /* These are all certificate problems with the client: */ + case errSecAuthFailed: + failf(data, "SSL authentication failed"); + break; + case errSSLPeerHandshakeFail: + failf(data, "SSL peer handshake failed, the server most likely " + "requires a client certificate to connect"); + break; + case errSSLPeerUnknownCA: + failf(data, "SSL server rejected the client certificate due to " + "the certificate being signed by an unknown certificate " + "authority"); + break; + + /* This error is raised if the server's cert didn't match the server's + host name: */ + case errSSLHostNameMismatch: + failf(data, "SSL certificate peer verification failed, the " + "certificate did not match \"%s\"\n", connssl->peer.dispname); + return CURLE_PEER_FAILED_VERIFICATION; + + /* Problem with SSL / TLS negotiation */ + case errSSLNegotiation: + failf(data, "Could not negotiate an SSL cipher suite with the server"); + break; + case errSSLBadConfiguration: + failf(data, "A configuration error occurred"); + break; + case errSSLProtocol: + failf(data, "SSL protocol error"); + break; + case errSSLPeerProtocolVersion: + failf(data, "A bad protocol version was encountered"); + break; + case errSSLPeerNoRenegotiation: + failf(data, "No renegotiation is allowed"); + break; + + /* Generic handshake errors: */ + case errSSLConnectionRefused: + failf(data, "Server dropped the connection during the SSL handshake"); + break; + case errSSLClosedAbort: + failf(data, "Server aborted the SSL handshake"); + break; + case errSSLClosedGraceful: + failf(data, "The connection closed gracefully"); + break; + case errSSLClosedNoNotify: + failf(data, "The server closed the session with no notification"); + break; + /* Sometimes paramErr happens with buggy ciphers: */ + case paramErr: + case errSSLInternal: + case errSSLPeerInternalError: + failf(data, "Internal SSL engine error encountered during the " + "SSL handshake"); + break; + case errSSLFatalAlert: + failf(data, "Fatal SSL engine error encountered during the SSL " + "handshake"); + break; + /* Unclassified error */ + case errSSLBufferOverflow: + failf(data, "An insufficient buffer was provided"); + break; + case errSSLIllegalParam: + failf(data, "An illegal parameter was encountered"); + break; + case errSSLModuleAttach: + failf(data, "Module attach failure"); + break; + case errSSLSessionNotFound: + failf(data, "An attempt to restore an unknown session failed"); + break; + case errSSLPeerExportRestriction: + failf(data, "An export restriction occurred"); + break; + case errSSLPeerUserCancelled: + failf(data, "The user canceled the operation"); + break; + case errSSLPeerUnexpectedMsg: + failf(data, "Peer rejected unexpected message"); + break; +#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9 + /* Treating non-fatal error as fatal like before */ + case errSSLClientHelloReceived: + failf(data, "A non-fatal result for providing a server name " + "indication"); + break; +#endif + + /* Error codes defined in the enum but should never be returned. + We list them here just in case. */ +#if CURL_BUILD_MAC_10_6 + /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */ + case errSSLClientCertRequested: + failf(data, "Server requested a client certificate during the " + "handshake"); + return CURLE_SSL_CLIENTCERT; +#endif +#if CURL_BUILD_MAC_10_9 + /* Alias for errSSLLast, end of error range */ + case errSSLUnexpectedRecord: + failf(data, "Unexpected (skipped) record in DTLS"); + break; +#endif + default: + /* May also return codes listed in Security Framework Result Codes */ + failf(data, "Unknown SSL protocol error in connection to %s:%d", + connssl->peer.hostname, err); + break; + } + return CURLE_SSL_CONNECT_ERROR; + } + else { + /* we have been connected fine, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_3; + +#ifdef SECTRANSP_PINNEDPUBKEY + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + CURLcode result = + pkp_pin_peer_pubkey(data, backend->ssl_ctx, + data->set.str[STRING_SSL_PINNEDPUBLICKEY]); + if(result) { + failf(data, "SSL: public key does not match pinned public key"); + return result; + } + } +#endif /* SECTRANSP_PINNEDPUBKEY */ + + /* Informational message */ + (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher); + (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol); + switch(protocol) { + case kSSLProtocol2: + infof(data, "SSL 2.0 connection using %s", + TLSCipherNameForNumber(cipher)); + break; + case kSSLProtocol3: + infof(data, "SSL 3.0 connection using %s", + TLSCipherNameForNumber(cipher)); + break; + case kTLSProtocol1: + infof(data, "TLS 1.0 connection using %s", + TLSCipherNameForNumber(cipher)); + break; +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + case kTLSProtocol11: + infof(data, "TLS 1.1 connection using %s", + TLSCipherNameForNumber(cipher)); + break; + case kTLSProtocol12: + infof(data, "TLS 1.2 connection using %s", + TLSCipherNameForNumber(cipher)); + break; +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ +#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 + case kTLSProtocol13: + infof(data, "TLS 1.3 connection using %s", + TLSCipherNameForNumber(cipher)); + break; +#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ + default: + infof(data, "Unknown protocol connection"); + break; + } + +#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 + if(connssl->alpn) { + if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { + CFArrayRef alpnArr = NULL; + CFStringRef chosenProtocol = NULL; + err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr); + + if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1) + chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0); + +#ifdef USE_HTTP2 + if(chosenProtocol && + !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) { + cf->conn->alpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(chosenProtocol && + !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) { + cf->conn->alpn = CURL_HTTP_VERSION_1_1; + } + else + infof(data, VTLS_INFOF_NO_ALPN); + + Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? + BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + + /* chosenProtocol is a reference to the string within alpnArr + and doesn't need to be freed separately */ + if(alpnArr) + CFRelease(alpnArr); + } + } +#endif + + return CURLE_OK; + } +} + +static CURLcode +add_cert_to_certinfo(struct Curl_easy *data, + SecCertificateRef server_cert, + int idx) +{ + CURLcode result = CURLE_OK; + const char *beg; + const char *end; + CFDataRef cert_data = SecCertificateCopyData(server_cert); + + if(!cert_data) + return CURLE_PEER_FAILED_VERIFICATION; + + beg = (const char *)CFDataGetBytePtr(cert_data); + end = beg + CFDataGetLength(cert_data); + result = Curl_extract_certinfo(data, idx, beg, end); + CFRelease(cert_data); + return result; +} + +static CURLcode +collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data, + SecCertificateRef server_cert, + CFIndex idx) +{ + CURLcode result = CURLE_OK; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(data->set.verbose) { + char *certp; + result = CopyCertSubject(data, server_cert, &certp); + if(!result) { + infof(data, "Server certificate: %s", certp); + free(certp); + } + } +#endif + if(ssl_config->certinfo) + result = add_cert_to_certinfo(data, server_cert, (int)idx); + return result; +} + +/* This should be called during step3 of the connection at the earliest */ +static CURLcode collect_server_cert(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const bool show_verbose_server_cert = data->set.verbose; +#else + const bool show_verbose_server_cert = false; +#endif + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + CURLcode result = ssl_config->certinfo ? + CURLE_PEER_FAILED_VERIFICATION : CURLE_OK; + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + CFArrayRef server_certs = NULL; + SecCertificateRef server_cert; + OSStatus err; + CFIndex i, count; + SecTrustRef trust = NULL; + + DEBUGASSERT(backend); + + if(!show_verbose_server_cert && !ssl_config->certinfo) + return CURLE_OK; + + if(!backend->ssl_ctx) + return result; + +#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS +#if CURL_BUILD_IOS +#pragma unused(server_certs) + err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); + /* For some reason, SSLCopyPeerTrust() can return noErr and yet return + a null trust, so be on guard for that: */ + if(err == noErr && trust) { + count = SecTrustGetCertificateCount(trust); + if(ssl_config->certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { + server_cert = SecTrustGetCertificateAtIndex(trust, i); + result = collect_server_cert_single(cf, data, server_cert, i); + } + CFRelease(trust); + } +#else + /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion. + The function SecTrustGetCertificateAtIndex() is officially present + in Lion, but it is unfortunately also present in Snow Leopard as + private API and doesn't work as expected. So we have to look for + a different symbol to make sure this code is only executed under + Lion or later. */ + if(SecTrustCopyPublicKey) { +#pragma unused(server_certs) + err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); + /* For some reason, SSLCopyPeerTrust() can return noErr and yet return + a null trust, so be on guard for that: */ + if(err == noErr && trust) { + count = SecTrustGetCertificateCount(trust); + if(ssl_config->certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { + server_cert = SecTrustGetCertificateAtIndex(trust, i); + result = collect_server_cert_single(cf, data, server_cert, i); + } + CFRelease(trust); + } + } + else { +#if CURL_SUPPORT_MAC_10_8 + err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); + /* Just in case SSLCopyPeerCertificates() returns null too... */ + if(err == noErr && server_certs) { + count = CFArrayGetCount(server_certs); + if(ssl_config->certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { + server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, + i); + result = collect_server_cert_single(cf, data, server_cert, i); + } + CFRelease(server_certs); + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#endif /* CURL_BUILD_IOS */ +#else +#pragma unused(trust) + err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); + if(err == noErr) { + count = CFArrayGetCount(server_certs); + if(ssl_config->certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { + server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); + result = collect_server_cert_single(cf, data, server_cert, i); + } + CFRelease(server_certs); + } +#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ + return result; +} + +static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + CURLcode result; + + CURL_TRC_CF(data, cf, "connect_step3"); + /* There is no step 3! + * Well, okay, let's collect server certificates, and if verbose mode is on, + * let's print the details of the server certificates. */ + result = collect_server_cert(cf, data); + if(result) + return result; + + connssl->connecting_state = ssl_connect_done; + return CURLE_OK; +} + +static CURLcode +sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, + bool nonblocking, + bool *done) +{ + CURLcode result; + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + /* Find out how much more time we're allowed */ + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = sectransp_connect_step1(cf, data); + if(result) + return result; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if this + * connection is done nonblocking and this loop would execute again. This + * permits the owner of a multi handle to abort a connection attempt + * before step2 has completed while ensuring that a client using select() + * or epoll() will always have a valid fdset to wait on. + */ + result = sectransp_connect_step2(cf, data); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; + + } /* repeat step2 until all transactions are done. */ + + + if(ssl_connect_3 == connssl->connecting_state) { + result = sectransp_connect_step3(cf, data); + if(result) + return result; + } + + if(ssl_connect_done == connssl->connecting_state) { + CURL_TRC_CF(data, cf, "connected"); + connssl->state = ssl_connection_complete; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +static CURLcode sectransp_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + return sectransp_connect_common(cf, data, TRUE, done); +} + +static CURLcode sectransp_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result; + bool done = FALSE; + + result = sectransp_connect_common(cf, data, FALSE, &done); + + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + + (void) data; + + DEBUGASSERT(backend); + + if(backend->ssl_ctx) { + CURL_TRC_CF(data, cf, "close"); + (void)SSLClose(backend->ssl_ctx); +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLCreateContext) + CFRelease(backend->ssl_ctx); +#if CURL_SUPPORT_MAC_10_8 + else + (void)SSLDisposeContext(backend->ssl_ctx); +#endif /* CURL_SUPPORT_MAC_10_8 */ +#else + (void)SSLDisposeContext(backend->ssl_ctx); +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + backend->ssl_ctx = NULL; + } +} + +static int sectransp_shutdown(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + ssize_t nread; + int what; + int rc; + char buf[120]; + int loop = 10; /* avoid getting stuck */ + CURLcode result; + + DEBUGASSERT(backend); + + if(!backend->ssl_ctx) + return 0; + +#ifndef CURL_DISABLE_FTP + if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) + return 0; +#endif + + sectransp_close(cf, data); + + rc = 0; + + what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), + SSL_SHUTDOWN_TIMEOUT); + + CURL_TRC_CF(data, cf, "shutdown"); + while(loop--) { + if(what < 0) { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + rc = -1; + break; + } + + if(!what) { /* timeout */ + failf(data, "SSL shutdown timeout"); + break; + } + + /* Something to read, let's do it and hope that it is the close + notify alert from the server. No way to SSL_Read now, so use read(). */ + + nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result); + + if(nread < 0) { + failf(data, "read: %s", curl_easy_strerror(result)); + rc = -1; + } + + if(nread <= 0) + break; + + what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0); + } + + return rc; +} + +static void sectransp_session_free(void *ptr) +{ + /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a + cached session ID inside the Security framework. There is a private + function that does this, but I don't want to have to explain to you why I + got your application rejected from the App Store due to the use of a + private API, so the best we can do is free up our own char array that we + created way back in sectransp_connect_step1... */ + Curl_safefree(ptr); +} + +static size_t sectransp_version(char *buffer, size_t size) +{ + return msnprintf(buffer, size, "SecureTransport"); +} + +static bool sectransp_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + const struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + OSStatus err; + size_t buffer; + + (void)data; + DEBUGASSERT(backend); + + if(backend->ssl_ctx) { /* SSL is in use */ + CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending"); + err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer); + if(err == noErr) + return buffer > 0UL; + return false; + } + else + return false; +} + +static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM, + unsigned char *entropy, size_t length) +{ + /* arc4random_buf() isn't available on cats older than Lion, so let's + do this manually for the benefit of the older cats. */ + size_t i; + u_int32_t random_number = 0; + + (void)data; + + for(i = 0 ; i < length ; i++) { + if(i % sizeof(u_int32_t) == 0) + random_number = arc4random(); + entropy[i] = random_number & 0xFF; + random_number >>= 8; + } + i = random_number = 0; + return CURLE_OK; +} + +static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len) +{ + (void)sha256len; + assert(sha256len >= CURL_SHA256_DIGEST_LENGTH); + (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum); + return CURLE_OK; +} + +static bool sectransp_false_start(void) +{ +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + if(SSLSetSessionOption) + return TRUE; +#endif + return FALSE; +} + +static ssize_t sectransp_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + size_t processed = 0UL; + OSStatus err; + + DEBUGASSERT(backend); + + /* The SSLWrite() function works a little differently than expected. The + fourth argument (processed) is currently documented in Apple's + documentation as: "On return, the length, in bytes, of the data actually + written." + + Now, one could interpret that as "written to the socket," but actually, + it returns the amount of data that was written to a buffer internal to + the SSLContextRef instead. So it's possible for SSLWrite() to return + errSSLWouldBlock and a number of bytes "written" because those bytes were + encrypted and written to a buffer, not to the socket. + + So if this happens, then we need to keep calling SSLWrite() over and + over again with no new data until it quits returning errSSLWouldBlock. */ + + /* Do we have buffered data to write from the last time we were called? */ + if(backend->ssl_write_buffered_length) { + /* Write the buffered data: */ + err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed); + switch(err) { + case noErr: + /* processed is always going to be 0 because we didn't write to + the buffer, so return how much was written to the socket */ + processed = backend->ssl_write_buffered_length; + backend->ssl_write_buffered_length = 0UL; + break; + case errSSLWouldBlock: /* argh, try again */ + *curlcode = CURLE_AGAIN; + return -1L; + default: + failf(data, "SSLWrite() returned error %d", err); + *curlcode = CURLE_SEND_ERROR; + return -1L; + } + } + else { + /* We've got new data to write: */ + err = SSLWrite(backend->ssl_ctx, mem, len, &processed); + if(err != noErr) { + switch(err) { + case errSSLWouldBlock: + /* Data was buffered but not sent, we have to tell the caller + to try sending again, and remember how much was buffered */ + backend->ssl_write_buffered_length = len; + *curlcode = CURLE_AGAIN; + return -1L; + default: + failf(data, "SSLWrite() returned error %d", err); + *curlcode = CURLE_SEND_ERROR; + return -1L; + } + } + } + return (ssize_t)processed; +} + +static ssize_t sectransp_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, + size_t buffersize, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + size_t processed = 0UL; + OSStatus err; + + DEBUGASSERT(backend); + +again: + *curlcode = CURLE_OK; + err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed); + + if(err != noErr) { + switch(err) { + case errSSLWouldBlock: /* return how much we read (if anything) */ + if(processed) { + return (ssize_t)processed; + } + *curlcode = CURLE_AGAIN; + return -1L; + + /* errSSLClosedGraceful - server gracefully shut down the SSL session + errSSLClosedNoNotify - server hung up on us instead of sending a + closure alert notice, read() is returning 0 + Either way, inform the caller that the server disconnected. */ + case errSSLClosedGraceful: + case errSSLClosedNoNotify: + *curlcode = CURLE_OK; + return 0; + + /* The below is errSSLPeerAuthCompleted; it's not defined in + Leopard's headers */ + case -9841: + if((conn_config->CAfile || conn_config->ca_info_blob) && + conn_config->verifypeer) { + CURLcode result = verify_cert(cf, data, conn_config->CAfile, + conn_config->ca_info_blob, + backend->ssl_ctx); + if(result) { + *curlcode = result; + return -1; + } + } + goto again; + default: + failf(data, "SSLRead() return error %d", err); + *curlcode = CURLE_RECV_ERROR; + return -1L; + } + } + return (ssize_t)processed; +} + +static void *sectransp_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; + (void)info; + DEBUGASSERT(backend); + return backend->ssl_ctx; +} + +const struct Curl_ssl Curl_ssl_sectransp = { + { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */ + + SSLSUPP_CAINFO_BLOB | + SSLSUPP_CERTINFO | +#ifdef SECTRANSP_PINNEDPUBKEY + SSLSUPP_PINNEDPUBKEY | +#endif /* SECTRANSP_PINNEDPUBKEY */ + SSLSUPP_HTTPS_PROXY, + + sizeof(struct st_ssl_backend_data), + + Curl_none_init, /* init */ + Curl_none_cleanup, /* cleanup */ + sectransp_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + sectransp_shutdown, /* shutdown */ + sectransp_data_pending, /* data_pending */ + sectransp_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + sectransp_connect, /* connect */ + sectransp_connect_nonblocking, /* connect_nonblocking */ + Curl_ssl_adjust_pollset, /* adjust_pollset */ + sectransp_get_internals, /* get_internals */ + sectransp_close, /* close_one */ + Curl_none_close_all, /* close_all */ + sectransp_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + sectransp_false_start, /* false_start */ + sectransp_sha256sum, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + sectransp_recv, /* recv decrypted data */ + sectransp_send, /* send data to encrypt */ +}; + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif /* USE_SECTRANSP */ diff --git a/lib/vtls/sectransp.h b/lib/vtls/sectransp.h new file mode 100644 index 0000000..0f1085a --- /dev/null +++ b/lib/vtls/sectransp.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_SECTRANSP_H +#define HEADER_CURL_SECTRANSP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Nick Zitzmann, . + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_SECTRANSP + +extern const struct Curl_ssl Curl_ssl_sectransp; + +#endif /* USE_SECTRANSP */ +#endif /* HEADER_CURL_SECTRANSP_H */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c new file mode 100644 index 0000000..e928ba5 --- /dev/null +++ b/lib/vtls/vtls.c @@ -0,0 +1,2173 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* This file is for implementing all "generic" SSL functions that all libcurl + internals should use. It is then responsible for calling the proper + "backend" function. + + SSL-functions in libcurl should call functions in this source file, and not + to any specific SSL-layer. + + Curl_ssl_ - prefix for generic ones + + Note that this source code uses the functions of the configured SSL + backend via the global Curl_ssl instance. + + "SSL/TLS Strong Encryption: An Introduction" + https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html +*/ + +#include "curl_setup.h" + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "urldata.h" +#include "cfilters.h" + +#include "vtls.h" /* generic SSL protos etc */ +#include "vtls_int.h" +#include "slist.h" +#include "sendf.h" +#include "strcase.h" +#include "url.h" +#include "progress.h" +#include "share.h" +#include "multiif.h" +#include "timeval.h" +#include "curl_md5.h" +#include "warnless.h" +#include "curl_base64.h" +#include "curl_printf.h" +#include "inet_pton.h" +#include "strdup.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + + +/* convenience macro to check if this handle is using a shared SSL session */ +#define SSLSESSION_SHARED(data) (data->share && \ + (data->share->specifier & \ + (1<var) { \ + dest->var = strdup(source->var); \ + if(!dest->var) \ + return FALSE; \ + } \ + else \ + dest->var = NULL; \ + } while(0) + +#define CLONE_BLOB(var) \ + do { \ + if(blobdup(&dest->var, source->var)) \ + return FALSE; \ + } while(0) + +static CURLcode blobdup(struct curl_blob **dest, + struct curl_blob *src) +{ + DEBUGASSERT(dest); + DEBUGASSERT(!*dest); + if(src) { + /* only if there's data to dupe! */ + struct curl_blob *d; + d = malloc(sizeof(struct curl_blob) + src->len); + if(!d) + return CURLE_OUT_OF_MEMORY; + d->len = src->len; + /* Always duplicate because the connection may survive longer than the + handle that passed in the blob. */ + d->flags = CURL_BLOB_COPY; + d->data = (void *)((char *)d + sizeof(struct curl_blob)); + memcpy(d->data, src->data, src->len); + *dest = d; + } + return CURLE_OK; +} + +/* returns TRUE if the blobs are identical */ +static bool blobcmp(struct curl_blob *first, struct curl_blob *second) +{ + if(!first && !second) /* both are NULL */ + return TRUE; + if(!first || !second) /* one is NULL */ + return FALSE; + if(first->len != second->len) /* different sizes */ + return FALSE; + return !memcmp(first->data, second->data, first->len); /* same data */ +} + +#ifdef USE_SSL +static const struct alpn_spec ALPN_SPEC_H11 = { + { ALPN_HTTP_1_1 }, 1 +}; +#ifdef USE_HTTP2 +static const struct alpn_spec ALPN_SPEC_H2_H11 = { + { ALPN_H2, ALPN_HTTP_1_1 }, 2 +}; +#endif + +static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn) +{ + if(!use_alpn) + return NULL; +#ifdef USE_HTTP2 + if(httpwant >= CURL_HTTP_VERSION_2) + return &ALPN_SPEC_H2_H11; +#else + (void)httpwant; +#endif + /* Use the ALPN protocol "http/1.1" for HTTP/1.x. + Avoid "http/1.0" because some servers don't support it. */ + return &ALPN_SPEC_H11; +} +#endif /* USE_SSL */ + + +void Curl_ssl_easy_config_init(struct Curl_easy *data) +{ + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ + data->set.ssl.primary.verifypeer = TRUE; + data->set.ssl.primary.verifyhost = TRUE; + data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */ +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl = data->set.ssl; +#endif +} + +static bool +match_ssl_primary_config(struct Curl_easy *data, + struct ssl_primary_config *c1, + struct ssl_primary_config *c2) +{ + (void)data; + if((c1->version == c2->version) && + (c1->version_max == c2->version_max) && + (c1->ssl_options == c2->ssl_options) && + (c1->verifypeer == c2->verifypeer) && + (c1->verifyhost == c2->verifyhost) && + (c1->verifystatus == c2->verifystatus) && + blobcmp(c1->cert_blob, c2->cert_blob) && + blobcmp(c1->ca_info_blob, c2->ca_info_blob) && + blobcmp(c1->issuercert_blob, c2->issuercert_blob) && + Curl_safecmp(c1->CApath, c2->CApath) && + Curl_safecmp(c1->CAfile, c2->CAfile) && + Curl_safecmp(c1->issuercert, c2->issuercert) && + Curl_safecmp(c1->clientcert, c2->clientcert) && +#ifdef USE_TLS_SRP + !Curl_timestrcmp(c1->username, c2->username) && + !Curl_timestrcmp(c1->password, c2->password) && +#endif + strcasecompare(c1->cipher_list, c2->cipher_list) && + strcasecompare(c1->cipher_list13, c2->cipher_list13) && + strcasecompare(c1->curves, c2->curves) && + strcasecompare(c1->CRLfile, c2->CRLfile) && + strcasecompare(c1->pinned_key, c2->pinned_key)) + return TRUE; + + return FALSE; +} + +bool Curl_ssl_conn_config_match(struct Curl_easy *data, + struct connectdata *candidate, + bool proxy) +{ +#ifndef CURL_DISABLE_PROXY + if(proxy) + return match_ssl_primary_config(data, &data->set.proxy_ssl.primary, + &candidate->proxy_ssl_config); +#else + (void)proxy; +#endif + return match_ssl_primary_config(data, &data->set.ssl.primary, + &candidate->ssl_config); +} + +static bool clone_ssl_primary_config(struct ssl_primary_config *source, + struct ssl_primary_config *dest) +{ + dest->version = source->version; + dest->version_max = source->version_max; + dest->verifypeer = source->verifypeer; + dest->verifyhost = source->verifyhost; + dest->verifystatus = source->verifystatus; + dest->sessionid = source->sessionid; + dest->ssl_options = source->ssl_options; + + CLONE_BLOB(cert_blob); + CLONE_BLOB(ca_info_blob); + CLONE_BLOB(issuercert_blob); + CLONE_STRING(CApath); + CLONE_STRING(CAfile); + CLONE_STRING(issuercert); + CLONE_STRING(clientcert); + CLONE_STRING(cipher_list); + CLONE_STRING(cipher_list13); + CLONE_STRING(pinned_key); + CLONE_STRING(curves); + CLONE_STRING(CRLfile); +#ifdef USE_TLS_SRP + CLONE_STRING(username); + CLONE_STRING(password); +#endif + + return TRUE; +} + +static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) +{ + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->CAfile); + Curl_safefree(sslc->issuercert); + Curl_safefree(sslc->clientcert); + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->cipher_list13); + Curl_safefree(sslc->pinned_key); + Curl_safefree(sslc->cert_blob); + Curl_safefree(sslc->ca_info_blob); + Curl_safefree(sslc->issuercert_blob); + Curl_safefree(sslc->curves); + Curl_safefree(sslc->CRLfile); +#ifdef USE_TLS_SRP + Curl_safefree(sslc->username); + Curl_safefree(sslc->password); +#endif +} + +CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data) +{ + data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE]; + data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE]; + data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; + data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; + data->set.ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST]; + data->set.ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST]; + data->set.ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; + data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; + data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; +#ifdef USE_TLS_SRP + data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME]; + data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +#endif + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE]; + data->set.ssl.key = data->set.str[STRING_KEY]; + data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE]; + data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD]; + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT]; + data->set.ssl.key_blob = data->set.blobs[BLOB_KEY]; + +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + data->set.proxy_ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + data->set.proxy_ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; + data->set.proxy_ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; + data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; + data->set.proxy_ssl.primary.ca_info_blob = + data->set.blobs[BLOB_CAINFO_PROXY]; + data->set.proxy_ssl.primary.issuercert = + data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.proxy_ssl.primary.issuercert_blob = + data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY]; + data->set.proxy_ssl.primary.CRLfile = + data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; + data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; + data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; + data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY]; +#ifdef USE_TLS_SRP + data->set.proxy_ssl.primary.username = + data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; + data->set.proxy_ssl.primary.password = + data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; +#endif +#endif /* CURL_DISABLE_PROXY */ + + return CURLE_OK; +} + +CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data, + struct connectdata *conn) +{ + /* Clone "primary" SSL configurations from the esay handle to + * the connection. They are used for connection cache matching and + * probably outlive the easy handle */ + if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config)) + return CURLE_OUT_OF_MEMORY; +#ifndef CURL_DISABLE_PROXY + if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary, + &conn->proxy_ssl_config)) + return CURLE_OUT_OF_MEMORY; +#endif + return CURLE_OK; +} + +void Curl_ssl_conn_config_cleanup(struct connectdata *conn) +{ + Curl_free_primary_ssl_config(&conn->ssl_config); +#ifndef CURL_DISABLE_PROXY + Curl_free_primary_ssl_config(&conn->proxy_ssl_config); +#endif +} + +void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy) +{ + /* May be called on an easy that has no connection yet */ + if(data->conn) { + struct ssl_primary_config *src, *dest; +#ifndef CURL_DISABLE_PROXY + src = for_proxy? &data->set.proxy_ssl.primary : &data->set.ssl.primary; + dest = for_proxy? &data->conn->proxy_ssl_config : &data->conn->ssl_config; +#else + (void)for_proxy; + src = &data->set.ssl.primary; + dest = &data->conn->ssl_config; +#endif + dest->verifyhost = src->verifyhost; + dest->verifypeer = src->verifypeer; + dest->verifystatus = src->verifystatus; + } +} + +#ifdef USE_SSL +static int multissl_setup(const struct Curl_ssl *backend); +#endif + +curl_sslbackend Curl_ssl_backend(void) +{ +#ifdef USE_SSL + multissl_setup(NULL); + return Curl_ssl->info.id; +#else + return CURLSSLBACKEND_NONE; +#endif +} + +#ifdef USE_SSL + +/* "global" init done? */ +static bool init_ssl = FALSE; + +/** + * Global SSL init + * + * @retval 0 error initializing SSL + * @retval 1 SSL initialized successfully + */ +int Curl_ssl_init(void) +{ + /* make sure this is only done once */ + if(init_ssl) + return 1; + init_ssl = TRUE; /* never again */ + + return Curl_ssl->init(); +} + +#if defined(CURL_WITH_MULTI_SSL) +static const struct Curl_ssl Curl_ssl_multi; +#endif + +/* Global cleanup */ +void Curl_ssl_cleanup(void) +{ + if(init_ssl) { + /* only cleanup if we did a previous init */ + Curl_ssl->cleanup(); +#if defined(CURL_WITH_MULTI_SSL) + Curl_ssl = &Curl_ssl_multi; +#endif + init_ssl = FALSE; + } +} + +static bool ssl_prefs_check(struct Curl_easy *data) +{ + /* check for CURLOPT_SSLVERSION invalid parameter value */ + const unsigned char sslver = data->set.ssl.primary.version; + if(sslver >= CURL_SSLVERSION_LAST) { + failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); + return FALSE; + } + + switch(data->set.ssl.primary.version_max) { + case CURL_SSLVERSION_MAX_NONE: + case CURL_SSLVERSION_MAX_DEFAULT: + break; + + default: + if((data->set.ssl.primary.version_max >> 16) < sslver) { + failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION"); + return FALSE; + } + } + + return TRUE; +} + +static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, + const struct alpn_spec *alpn) +{ + struct ssl_connect_data *ctx; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) + return NULL; + + ctx->alpn = alpn; + ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data); + if(!ctx->backend) { + free(ctx); + return NULL; + } + return ctx; +} + +static void cf_ctx_free(struct ssl_connect_data *ctx) +{ + if(ctx) { + free(ctx->backend); + free(ctx); + } +} + +static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + CURLcode result; + + if(!ssl_prefs_check(data)) + return CURLE_SSL_CONNECT_ERROR; + + /* mark this is being ssl-enabled from here on. */ + connssl->state = ssl_connection_negotiating; + + result = Curl_ssl->connect_blocking(cf, data); + + if(!result) { + DEBUGASSERT(connssl->state == ssl_connection_complete); + } + + return result; +} + +static CURLcode +ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data, + bool *done) +{ + if(!ssl_prefs_check(data)) + return CURLE_SSL_CONNECT_ERROR; + + /* mark this is being ssl requested from here on. */ + return Curl_ssl->connect_nonblocking(cf, data, done); +} + +/* + * Lock shared SSL session data + */ +void Curl_ssl_sessionid_lock(struct Curl_easy *data) +{ + if(SSLSESSION_SHARED(data)) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); +} + +/* + * Unlock shared SSL session data + */ +void Curl_ssl_sessionid_unlock(struct Curl_easy *data) +{ + if(SSLSESSION_SHARED(data)) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); +} + +/* + * Check if there's a session ID for the given connection in the cache, and if + * there's one suitable, it is provided. Returns TRUE when no entry matched. + */ +bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, + struct Curl_easy *data, + void **ssl_sessionid, + size_t *idsize) /* set 0 if unknown */ +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + struct Curl_ssl_session *check; + size_t i; + long *general_age; + bool no_match = TRUE; + + *ssl_sessionid = NULL; + if(!ssl_config) + return TRUE; + + DEBUGASSERT(ssl_config->primary.sessionid); + + if(!ssl_config->primary.sessionid || !data->state.session) + /* session ID reuse is disabled or the session cache has not been + setup */ + return TRUE; + + /* Lock if shared */ + if(SSLSESSION_SHARED(data)) + general_age = &data->share->sessionage; + else + general_age = &data->state.sessionage; + + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { + check = &data->state.session[i]; + if(!check->sessionid) + /* not session ID means blank entry */ + continue; + if(strcasecompare(connssl->peer.hostname, check->name) && + ((!cf->conn->bits.conn_to_host && !check->conn_to_host) || + (cf->conn->bits.conn_to_host && check->conn_to_host && + strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) && + ((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) || + (cf->conn->bits.conn_to_port && check->conn_to_port != -1 && + cf->conn->conn_to_port == check->conn_to_port)) && + (connssl->port == check->remote_port) && + strcasecompare(cf->conn->handler->scheme, check->scheme) && + match_ssl_primary_config(data, conn_config, &check->ssl_config)) { + /* yes, we have a session ID! */ + (*general_age)++; /* increase general age */ + check->age = *general_age; /* set this as used in this age */ + *ssl_sessionid = check->sessionid; + if(idsize) + *idsize = check->idsize; + no_match = FALSE; + break; + } + } + + DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d", + no_match? "Didn't find": "Found", + Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host", + cf->conn->handler->scheme, connssl->peer.hostname, + connssl->port)); + return no_match; +} + +/* + * Kill a single session ID entry in the cache. + */ +void Curl_ssl_kill_session(struct Curl_ssl_session *session) +{ + if(session->sessionid) { + /* defensive check */ + + /* free the ID the SSL-layer specific way */ + Curl_ssl->session_free(session->sessionid); + + session->sessionid = NULL; + session->age = 0; /* fresh */ + + Curl_free_primary_ssl_config(&session->ssl_config); + + Curl_safefree(session->name); + Curl_safefree(session->conn_to_host); + } +} + +/* + * Delete the given session ID from the cache. + */ +void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid) +{ + size_t i; + + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { + struct Curl_ssl_session *check = &data->state.session[i]; + + if(check->sessionid == ssl_sessionid) { + Curl_ssl_kill_session(check); + break; + } + } +} + +/* + * Store session id in the session cache. The ID passed on to this function + * must already have been extracted and allocated the proper way for the SSL + * layer. Curl_XXXX_session_free() will be called to free/kill the session ID + * later on. + */ +CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf, + struct Curl_easy *data, + void *ssl_sessionid, + size_t idsize, + bool *added) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + size_t i; + struct Curl_ssl_session *store; + long oldest_age; + char *clone_host; + char *clone_conn_to_host; + int conn_to_port; + long *general_age; + + if(added) + *added = FALSE; + + if(!data->state.session) + return CURLE_OK; + + store = &data->state.session[0]; + oldest_age = data->state.session[0].age; /* zero if unused */ + (void)ssl_config; + DEBUGASSERT(ssl_config->primary.sessionid); + + clone_host = strdup(connssl->peer.hostname); + if(!clone_host) + return CURLE_OUT_OF_MEMORY; /* bail out */ + + if(cf->conn->bits.conn_to_host) { + clone_conn_to_host = strdup(cf->conn->conn_to_host.name); + if(!clone_conn_to_host) { + free(clone_host); + return CURLE_OUT_OF_MEMORY; /* bail out */ + } + } + else + clone_conn_to_host = NULL; + + if(cf->conn->bits.conn_to_port) + conn_to_port = cf->conn->conn_to_port; + else + conn_to_port = -1; + + /* Now we should add the session ID and the host name to the cache, (remove + the oldest if necessary) */ + + /* If using shared SSL session, lock! */ + if(SSLSESSION_SHARED(data)) { + general_age = &data->share->sessionage; + } + else { + general_age = &data->state.sessionage; + } + + /* find an empty slot for us, or find the oldest */ + for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && + data->state.session[i].sessionid; i++) { + if(data->state.session[i].age < oldest_age) { + oldest_age = data->state.session[i].age; + store = &data->state.session[i]; + } + } + if(i == data->set.general_ssl.max_ssl_sessions) + /* cache is full, we must "kill" the oldest entry! */ + Curl_ssl_kill_session(store); + else + store = &data->state.session[i]; /* use this slot */ + + /* now init the session struct wisely */ + store->sessionid = ssl_sessionid; + store->idsize = idsize; + store->age = *general_age; /* set current age */ + /* free it if there's one already present */ + free(store->name); + free(store->conn_to_host); + store->name = clone_host; /* clone host name */ + store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ + store->conn_to_port = conn_to_port; /* connect to port number */ + /* port number */ + store->remote_port = connssl->port; + store->scheme = cf->conn->handler->scheme; + + if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) { + Curl_free_primary_ssl_config(&store->ssl_config); + store->sessionid = NULL; /* let caller free sessionid */ + free(clone_host); + free(clone_conn_to_host); + return CURLE_OUT_OF_MEMORY; + } + + if(added) + *added = TRUE; + + DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]", + store->scheme, store->name, store->remote_port, + Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server")); + return CURLE_OK; +} + +void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend) +{ + if(Curl_ssl->free_multi_ssl_backend_data && mbackend) + Curl_ssl->free_multi_ssl_backend_data(mbackend); +} + +void Curl_ssl_close_all(struct Curl_easy *data) +{ + /* kill the session ID cache if not shared */ + if(data->state.session && !SSLSESSION_SHARED(data)) { + size_t i; + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) + /* the single-killer function handles empty table slots */ + Curl_ssl_kill_session(&data->state.session[i]); + + /* free the cache data */ + Curl_safefree(data->state.session); + } + + Curl_ssl->close_all(data); +} + +void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, + struct easy_pollset *ps) +{ + if(!cf->connected) { + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data); + if(sock != CURL_SOCKET_BAD) { + if(connssl->connecting_state == ssl_connect_2_writing) { + Curl_pollset_set_out_only(data, ps, sock); + } + else { + Curl_pollset_set_in_only(data, ps, sock); + } + } + } +} + +/* Selects an SSL crypto engine + */ +CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) +{ + return Curl_ssl->set_engine(data, engine); +} + +/* Selects the default SSL crypto engine + */ +CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data) +{ + return Curl_ssl->set_engine_default(data); +} + +/* Return list of OpenSSL crypto engine names. */ +struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) +{ + return Curl_ssl->engines_list(data); +} + +/* + * This sets up a session ID cache to the specified size. Make sure this code + * is agnostic to what underlying SSL technology we use. + */ +CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) +{ + struct Curl_ssl_session *session; + + if(data->state.session) + /* this is just a precaution to prevent multiple inits */ + return CURLE_OK; + + session = calloc(amount, sizeof(struct Curl_ssl_session)); + if(!session) + return CURLE_OUT_OF_MEMORY; + + /* store the info in the SSL section */ + data->set.general_ssl.max_ssl_sessions = amount; + data->state.session = session; + data->state.sessionage = 1; /* this is brand new */ + return CURLE_OK; +} + +static size_t multissl_version(char *buffer, size_t size); + +void Curl_ssl_version(char *buffer, size_t size) +{ +#ifdef CURL_WITH_MULTI_SSL + (void)multissl_version(buffer, size); +#else + (void)Curl_ssl->version(buffer, size); +#endif +} + +void Curl_ssl_free_certinfo(struct Curl_easy *data) +{ + struct curl_certinfo *ci = &data->info.certs; + + if(ci->num_of_certs) { + /* free all individual lists used */ + int i; + for(i = 0; inum_of_certs; i++) { + curl_slist_free_all(ci->certinfo[i]); + ci->certinfo[i] = NULL; + } + + free(ci->certinfo); /* free the actual array too */ + ci->certinfo = NULL; + ci->num_of_certs = 0; + } +} + +CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num) +{ + struct curl_certinfo *ci = &data->info.certs; + struct curl_slist **table; + + /* Free any previous certificate information structures */ + Curl_ssl_free_certinfo(data); + + /* Allocate the required certificate information structures */ + table = calloc((size_t) num, sizeof(struct curl_slist *)); + if(!table) + return CURLE_OUT_OF_MEMORY; + + ci->num_of_certs = num; + ci->certinfo = table; + + return CURLE_OK; +} + +/* + * 'value' is NOT a null-terminated string + */ +CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, + int certnum, + const char *label, + const char *value, + size_t valuelen) +{ + struct curl_certinfo *ci = &data->info.certs; + struct curl_slist *nl; + CURLcode result = CURLE_OK; + struct dynbuf build; + + Curl_dyn_init(&build, 10000); + + if(Curl_dyn_add(&build, label) || + Curl_dyn_addn(&build, ":", 1) || + Curl_dyn_addn(&build, value, valuelen)) + return CURLE_OUT_OF_MEMORY; + + nl = Curl_slist_append_nodup(ci->certinfo[certnum], + Curl_dyn_ptr(&build)); + if(!nl) { + Curl_dyn_free(&build); + curl_slist_free_all(ci->certinfo[certnum]); + result = CURLE_OUT_OF_MEMORY; + } + + ci->certinfo[certnum] = nl; + return result; +} + +CURLcode Curl_ssl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) +{ + return Curl_ssl->random(data, entropy, length); +} + +/* + * Public key pem to der conversion + */ + +static CURLcode pubkey_pem_to_der(const char *pem, + unsigned char **der, size_t *der_len) +{ + char *stripped_pem, *begin_pos, *end_pos; + size_t pem_count, stripped_pem_count = 0, pem_len; + CURLcode result; + + /* if no pem, exit. */ + if(!pem) + return CURLE_BAD_CONTENT_ENCODING; + + begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----"); + if(!begin_pos) + return CURLE_BAD_CONTENT_ENCODING; + + pem_count = begin_pos - pem; + /* Invalid if not at beginning AND not directly following \n */ + if(0 != pem_count && '\n' != pem[pem_count - 1]) + return CURLE_BAD_CONTENT_ENCODING; + + /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ + pem_count += 26; + + /* Invalid if not directly following \n */ + end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----"); + if(!end_pos) + return CURLE_BAD_CONTENT_ENCODING; + + pem_len = end_pos - pem; + + stripped_pem = malloc(pem_len - pem_count + 1); + if(!stripped_pem) + return CURLE_OUT_OF_MEMORY; + + /* + * Here we loop through the pem array one character at a time between the + * correct indices, and place each character that is not '\n' or '\r' + * into the stripped_pem array, which should represent the raw base64 string + */ + while(pem_count < pem_len) { + if('\n' != pem[pem_count] && '\r' != pem[pem_count]) + stripped_pem[stripped_pem_count++] = pem[pem_count]; + ++pem_count; + } + /* Place the null terminator in the correct place */ + stripped_pem[stripped_pem_count] = '\0'; + + result = Curl_base64_decode(stripped_pem, der, der_len); + + Curl_safefree(stripped_pem); + + return result; +} + +/* + * Generic pinned public key check. + */ + +CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, + const char *pinnedpubkey, + const unsigned char *pubkey, size_t pubkeylen) +{ + FILE *fp; + unsigned char *buf = NULL, *pem_ptr = NULL; + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; +#endif + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + if(!pubkey || !pubkeylen) + return result; + + /* only do this if pinnedpubkey starts with "sha256//", length 8 */ + if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { + CURLcode encode; + size_t encodedlen = 0; + char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos; + unsigned char *sha256sumdigest; + + if(!Curl_ssl->sha256sum) { + /* without sha256 support, this cannot match */ + return result; + } + + /* compute sha256sum of public key */ + sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH); + if(!sha256sumdigest) + return CURLE_OUT_OF_MEMORY; + encode = Curl_ssl->sha256sum(pubkey, pubkeylen, + sha256sumdigest, CURL_SHA256_DIGEST_LENGTH); + + if(!encode) + encode = Curl_base64_encode((char *)sha256sumdigest, + CURL_SHA256_DIGEST_LENGTH, &encoded, + &encodedlen); + Curl_safefree(sha256sumdigest); + + if(encode) + return encode; + + infof(data, " public key hash: sha256//%s", encoded); + + /* it starts with sha256//, copy so we can modify it */ + pinkeycopy = strdup(pinnedpubkey); + if(!pinkeycopy) { + Curl_safefree(encoded); + return CURLE_OUT_OF_MEMORY; + } + /* point begin_pos to the copy, and start extracting keys */ + begin_pos = pinkeycopy; + do { + end_pos = strstr(begin_pos, ";sha256//"); + /* + * if there is an end_pos, null terminate, + * otherwise it'll go to the end of the original string + */ + if(end_pos) + end_pos[0] = '\0'; + + /* compare base64 sha256 digests, 8 is the length of "sha256//" */ + if(encodedlen == strlen(begin_pos + 8) && + !memcmp(encoded, begin_pos + 8, encodedlen)) { + result = CURLE_OK; + break; + } + + /* + * change back the null-terminator we changed earlier, + * and look for next begin + */ + if(end_pos) { + end_pos[0] = ';'; + begin_pos = strstr(end_pos, "sha256//"); + } + } while(end_pos && begin_pos); + Curl_safefree(encoded); + Curl_safefree(pinkeycopy); + return result; + } + + fp = fopen(pinnedpubkey, "rb"); + if(!fp) + return result; + + do { + long filesize; + size_t size, pem_len; + CURLcode pem_read; + + /* Determine the file's size */ + if(fseek(fp, 0, SEEK_END)) + break; + filesize = ftell(fp); + if(fseek(fp, 0, SEEK_SET)) + break; + if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE) + break; + + /* + * if the size of our certificate is bigger than the file + * size then it can't match + */ + size = curlx_sotouz((curl_off_t) filesize); + if(pubkeylen > size) + break; + + /* + * Allocate buffer for the pinned key + * With 1 additional byte for null terminator in case of PEM key + */ + buf = malloc(size + 1); + if(!buf) + break; + + /* Returns number of elements read, which should be 1 */ + if((int) fread(buf, size, 1, fp) != 1) + break; + + /* If the sizes are the same, it can't be base64 encoded, must be der */ + if(pubkeylen == size) { + if(!memcmp(pubkey, buf, pubkeylen)) + result = CURLE_OK; + break; + } + + /* + * Otherwise we will assume it's PEM and try to decode it + * after placing null terminator + */ + buf[size] = '\0'; + pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len); + /* if it wasn't read successfully, exit */ + if(pem_read) + break; + + /* + * if the size of our certificate doesn't match the size of + * the decoded file, they can't be the same, otherwise compare + */ + if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen)) + result = CURLE_OK; + } while(0); + + Curl_safefree(buf); + Curl_safefree(pem_ptr); + fclose(fp); + + return result; +} + +/* + * Check whether the SSL backend supports the status_request extension. + */ +bool Curl_ssl_cert_status_request(void) +{ + return Curl_ssl->cert_status_request(); +} + +/* + * Check whether the SSL backend supports false start. + */ +bool Curl_ssl_false_start(struct Curl_easy *data) +{ + (void)data; + return Curl_ssl->false_start(); +} + +/* + * Default implementations for unsupported functions. + */ + +int Curl_none_init(void) +{ + return 1; +} + +void Curl_none_cleanup(void) +{ } + +int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM, + struct Curl_easy *data UNUSED_PARAM) +{ + (void)data; + (void)cf; + return 0; +} + +int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + (void)cf; + (void)data; + return -1; +} + +CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM, + unsigned char *entropy UNUSED_PARAM, + size_t length UNUSED_PARAM) +{ + (void)data; + (void)entropy; + (void)length; + return CURLE_NOT_BUILT_IN; +} + +void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM) +{ + (void)data; +} + +void Curl_none_session_free(void *ptr UNUSED_PARAM) +{ + (void)ptr; +} + +bool Curl_none_data_pending(struct Curl_cfilter *cf UNUSED_PARAM, + const struct Curl_easy *data UNUSED_PARAM) +{ + (void)cf; + (void)data; + return 0; +} + +bool Curl_none_cert_status_request(void) +{ + return FALSE; +} + +CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM, + const char *engine UNUSED_PARAM) +{ + (void)data; + (void)engine; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM) +{ + (void)data; + return CURLE_NOT_BUILT_IN; +} + +struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM) +{ + (void)data; + return (struct curl_slist *)NULL; +} + +bool Curl_none_false_start(void) +{ + return FALSE; +} + +static int multissl_init(void) +{ + if(multissl_setup(NULL)) + return 1; + return Curl_ssl->init(); +} + +static CURLcode multissl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + if(multissl_setup(NULL)) + return CURLE_FAILED_INIT; + return Curl_ssl->connect_blocking(cf, data); +} + +static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + if(multissl_setup(NULL)) + return CURLE_FAILED_INIT; + return Curl_ssl->connect_nonblocking(cf, data, done); +} + +static void multissl_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + if(multissl_setup(NULL)) + return; + Curl_ssl->adjust_pollset(cf, data, ps); +} + +static void *multissl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info) +{ + if(multissl_setup(NULL)) + return NULL; + return Curl_ssl->get_internals(connssl, info); +} + +static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + if(multissl_setup(NULL)) + return; + Curl_ssl->close(cf, data); +} + +static ssize_t multissl_recv_plain(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t len, CURLcode *code) +{ + if(multissl_setup(NULL)) + return CURLE_FAILED_INIT; + return Curl_ssl->recv_plain(cf, data, buf, len, code); +} + +static ssize_t multissl_send_plain(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, size_t len, + CURLcode *code) +{ + if(multissl_setup(NULL)) + return CURLE_FAILED_INIT; + return Curl_ssl->send_plain(cf, data, mem, len, code); +} + +static const struct Curl_ssl Curl_ssl_multi = { + { CURLSSLBACKEND_NONE, "multi" }, /* info */ + 0, /* supports nothing */ + (size_t)-1, /* something insanely large to be on the safe side */ + + multissl_init, /* init */ + Curl_none_cleanup, /* cleanup */ + multissl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + Curl_none_data_pending, /* data_pending */ + Curl_none_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + multissl_connect, /* connect */ + multissl_connect_nonblocking, /* connect_nonblocking */ + multissl_adjust_pollset, /* adjust_pollset */ + multissl_get_internals, /* get_internals */ + multissl_close, /* close_one */ + Curl_none_close_all, /* close_all */ + Curl_none_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + NULL, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + multissl_recv_plain, /* recv decrypted data */ + multissl_send_plain, /* send data to encrypt */ +}; + +const struct Curl_ssl *Curl_ssl = +#if defined(CURL_WITH_MULTI_SSL) + &Curl_ssl_multi; +#elif defined(USE_WOLFSSL) + &Curl_ssl_wolfssl; +#elif defined(USE_SECTRANSP) + &Curl_ssl_sectransp; +#elif defined(USE_GNUTLS) + &Curl_ssl_gnutls; +#elif defined(USE_MBEDTLS) + &Curl_ssl_mbedtls; +#elif defined(USE_RUSTLS) + &Curl_ssl_rustls; +#elif defined(USE_OPENSSL) + &Curl_ssl_openssl; +#elif defined(USE_SCHANNEL) + &Curl_ssl_schannel; +#elif defined(USE_BEARSSL) + &Curl_ssl_bearssl; +#else +#error "Missing struct Curl_ssl for selected SSL backend" +#endif + +static const struct Curl_ssl *available_backends[] = { +#if defined(USE_WOLFSSL) + &Curl_ssl_wolfssl, +#endif +#if defined(USE_SECTRANSP) + &Curl_ssl_sectransp, +#endif +#if defined(USE_GNUTLS) + &Curl_ssl_gnutls, +#endif +#if defined(USE_MBEDTLS) + &Curl_ssl_mbedtls, +#endif +#if defined(USE_OPENSSL) + &Curl_ssl_openssl, +#endif +#if defined(USE_SCHANNEL) + &Curl_ssl_schannel, +#endif +#if defined(USE_BEARSSL) + &Curl_ssl_bearssl, +#endif +#if defined(USE_RUSTLS) + &Curl_ssl_rustls, +#endif + NULL +}; + +static size_t multissl_version(char *buffer, size_t size) +{ + static const struct Curl_ssl *selected; + static char backends[200]; + static size_t backends_len; + const struct Curl_ssl *current; + + current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl; + + if(current != selected) { + char *p = backends; + char *end = backends + sizeof(backends); + int i; + + selected = current; + + backends[0] = '\0'; + + for(i = 0; available_backends[i]; ++i) { + char vb[200]; + bool paren = (selected != available_backends[i]); + + if(available_backends[i]->version(vb, sizeof(vb))) { + p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""), + (paren ? "(" : ""), vb, (paren ? ")" : "")); + } + } + + backends_len = p - backends; + } + + if(size) { + if(backends_len < size) + strcpy(buffer, backends); + else + *buffer = 0; /* did not fit */ + } + return 0; +} + +static int multissl_setup(const struct Curl_ssl *backend) +{ + const char *env; + char *env_tmp; + + if(Curl_ssl != &Curl_ssl_multi) + return 1; + + if(backend) { + Curl_ssl = backend; + return 0; + } + + if(!available_backends[0]) + return 1; + + env = env_tmp = curl_getenv("CURL_SSL_BACKEND"); +#ifdef CURL_DEFAULT_SSL_BACKEND + if(!env) + env = CURL_DEFAULT_SSL_BACKEND; +#endif + if(env) { + int i; + for(i = 0; available_backends[i]; i++) { + if(strcasecompare(env, available_backends[i]->info.name)) { + Curl_ssl = available_backends[i]; + free(env_tmp); + return 0; + } + } + } + + /* Fall back to first available backend */ + Curl_ssl = available_backends[0]; + free(env_tmp); + return 0; +} + +/* This function is used to select the SSL backend to use. It is called by + curl_global_sslset (easy.c) which uses the global init lock. */ +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) +{ + int i; + + if(avail) + *avail = (const curl_ssl_backend **)&available_backends; + + if(Curl_ssl != &Curl_ssl_multi) + return id == Curl_ssl->info.id || + (name && strcasecompare(name, Curl_ssl->info.name)) ? + CURLSSLSET_OK : +#if defined(CURL_WITH_MULTI_SSL) + CURLSSLSET_TOO_LATE; +#else + CURLSSLSET_UNKNOWN_BACKEND; +#endif + + for(i = 0; available_backends[i]; i++) { + if(available_backends[i]->info.id == id || + (name && strcasecompare(available_backends[i]->info.name, name))) { + multissl_setup(available_backends[i]); + return CURLSSLSET_OK; + } + } + + return CURLSSLSET_UNKNOWN_BACKEND; +} + +#else /* USE_SSL */ +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) +{ + (void)id; + (void)name; + (void)avail; + return CURLSSLSET_NO_BACKENDS; +} + +#endif /* !USE_SSL */ + +#ifdef USE_SSL + +void Curl_ssl_peer_cleanup(struct ssl_peer *peer) +{ + if(peer->dispname != peer->hostname) + free(peer->dispname); + free(peer->sni); + free(peer->hostname); + peer->hostname = peer->sni = peer->dispname = NULL; + peer->is_ip_address = FALSE; +} + +static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + if(connssl) { + Curl_ssl->close(cf, data); + connssl->state = ssl_connection_none; + Curl_ssl_peer_cleanup(&connssl->peer); + } + cf->connected = FALSE; +} + +static int is_ip_address(const char *hostname) +{ +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + return (hostname && hostname[0] && (Curl_inet_pton(AF_INET, hostname, &addr) +#ifdef ENABLE_IPV6 + || Curl_inet_pton(AF_INET6, hostname, &addr) +#endif + )); +} + +CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf) +{ + struct ssl_connect_data *connssl = cf->ctx; + const char *ehostname, *edispname; + int eport; + + /* We need the hostname for SNI negotiation. Once handshaked, this + * remains the SNI hostname for the TLS connection. But when the + * connection is reused, the settings in cf->conn might change. + * So we keep a copy of the hostname we use for SNI. + */ +#ifndef CURL_DISABLE_PROXY + if(Curl_ssl_cf_is_proxy(cf)) { + ehostname = cf->conn->http_proxy.host.name; + edispname = cf->conn->http_proxy.host.dispname; + eport = cf->conn->http_proxy.port; + } + else +#endif + { + ehostname = cf->conn->host.name; + edispname = cf->conn->host.dispname; + eport = cf->conn->remote_port; + } + + /* change if ehostname changed */ + if(ehostname && (!peer->hostname + || strcmp(ehostname, peer->hostname))) { + Curl_ssl_peer_cleanup(peer); + peer->hostname = strdup(ehostname); + if(!peer->hostname) { + Curl_ssl_peer_cleanup(peer); + return CURLE_OUT_OF_MEMORY; + } + if(!edispname || !strcmp(ehostname, edispname)) + peer->dispname = peer->hostname; + else { + peer->dispname = strdup(edispname); + if(!peer->dispname) { + Curl_ssl_peer_cleanup(peer); + return CURLE_OUT_OF_MEMORY; + } + } + + peer->sni = NULL; + peer->is_ip_address = is_ip_address(peer->hostname)? TRUE : FALSE; + if(peer->hostname[0] && !peer->is_ip_address) { + /* not an IP address, normalize according to RCC 6066 ch. 3, + * max len of SNI is 2^16-1, no trailing dot */ + size_t len = strlen(peer->hostname); + if(len && (peer->hostname[len-1] == '.')) + len--; + if(len < USHRT_MAX) { + peer->sni = calloc(1, len + 1); + if(!peer->sni) { + Curl_ssl_peer_cleanup(peer); + return CURLE_OUT_OF_MEMORY; + } + Curl_strntolower(peer->sni, peer->hostname, len); + peer->sni[len] = 0; + } + } + + } + connssl->port = eport; + return CURLE_OK; +} + +static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + cf_close(cf, data); + CF_DATA_RESTORE(cf, save); + cf_ctx_free(cf->ctx); + cf->ctx = NULL; +} + +static void ssl_cf_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + cf_close(cf, data); + if(cf->next) + cf->next->cft->do_close(cf->next, data); + CF_DATA_RESTORE(cf, save); +} + +static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct cf_call_data save; + CURLcode result; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + CF_DATA_SAVE(save, cf, data); + CURL_TRC_CF(data, cf, "cf_connect()"); + (void)connssl; + DEBUGASSERT(data->conn); + DEBUGASSERT(data->conn == cf->conn); + DEBUGASSERT(connssl); + DEBUGASSERT(cf->conn->host.name); + + result = cf->next->cft->do_connect(cf->next, data, blocking, done); + if(result || !*done) + goto out; + + *done = FALSE; + result = Curl_ssl_peer_init(&connssl->peer, cf); + if(result) + goto out; + + if(blocking) { + result = ssl_connect(cf, data); + *done = (result == CURLE_OK); + } + else { + result = ssl_connect_nonblocking(cf, data, done); + } + + if(!result && *done) { + cf->connected = TRUE; + connssl->handshake_done = Curl_now(); + DEBUGASSERT(connssl->state == ssl_connection_complete); + } +out: + CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done); + CF_DATA_RESTORE(cf, save); + return result; +} + +static bool ssl_cf_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct cf_call_data save; + bool result; + + CF_DATA_SAVE(save, cf, data); + if(Curl_ssl->data_pending(cf, data)) + result = TRUE; + else + result = cf->next->cft->has_data_pending(cf->next, data); + CF_DATA_RESTORE(cf, save); + return result; +} + +static ssize_t ssl_cf_send(struct Curl_cfilter *cf, + struct Curl_easy *data, const void *buf, size_t len, + CURLcode *err) +{ + struct cf_call_data save; + ssize_t nwritten; + + CF_DATA_SAVE(save, cf, data); + *err = CURLE_OK; + nwritten = Curl_ssl->send_plain(cf, data, buf, len, err); + CF_DATA_RESTORE(cf, save); + return nwritten; +} + +static ssize_t ssl_cf_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, char *buf, size_t len, + CURLcode *err) +{ + struct cf_call_data save; + ssize_t nread; + size_t ntotal = 0; + + CF_DATA_SAVE(save, cf, data); + *err = CURLE_OK; + /* Do receive until we fill the buffer somehwhat or EGAIN, error or EOF */ + while(!ntotal || (len - ntotal) > (4*1024)) { + *err = CURLE_OK; + nread = Curl_ssl->recv_plain(cf, data, buf + ntotal, len - ntotal, err); + if(nread < 0) { + if(*err == CURLE_AGAIN && ntotal > 0) { + /* we EAGAINed after having reed data, return the success amount */ + *err = CURLE_OK; + break; + } + /* we have a an error to report */ + goto out; + } + else if(nread == 0) { + /* eof */ + break; + } + ntotal += (size_t)nread; + DEBUGASSERT((size_t)ntotal <= len); + } + nread = (ssize_t)ntotal; +out: + CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, + nread, *err); + CF_DATA_RESTORE(cf, save); + return nread; +} + +static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_call_data save; + + if(!cf->connected) { + CF_DATA_SAVE(save, cf, data); + Curl_ssl->adjust_pollset(cf, data, ps); + CF_DATA_RESTORE(cf, save); + } +} + +static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct cf_call_data save; + + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_DATA_ATTACH: + if(Curl_ssl->attach_data) { + CF_DATA_SAVE(save, cf, data); + Curl_ssl->attach_data(cf, data); + CF_DATA_RESTORE(cf, save); + } + break; + case CF_CTRL_DATA_DETACH: + if(Curl_ssl->detach_data) { + CF_DATA_SAVE(save, cf, data); + Curl_ssl->detach_data(cf, data); + CF_DATA_RESTORE(cf, save); + } + break; + default: + break; + } + return CURLE_OK; +} + +static CURLcode ssl_cf_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct ssl_connect_data *connssl = cf->ctx; + + switch(query) { + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected && !Curl_ssl_cf_is_proxy(cf)) + *when = connssl->handshake_done; + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, + bool *input_pending) +{ + struct cf_call_data save; + int result; + /* + * This function tries to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ + CF_DATA_SAVE(save, cf, data); + result = Curl_ssl->check_cxn(cf, data); + CF_DATA_RESTORE(cf, save); + if(result > 0) { + *input_pending = TRUE; + return TRUE; + } + if(result == 0) { + *input_pending = FALSE; + return FALSE; + } + /* ssl backend does not know */ + return cf->next? + cf->next->cft->is_alive(cf->next, data, input_pending) : + FALSE; /* pessimistic in absence of data */ +} + +struct Curl_cftype Curl_cft_ssl = { + "SSL", + CF_TYPE_SSL, + CURL_LOG_LVL_NONE, + ssl_cf_destroy, + ssl_cf_connect, + ssl_cf_close, + Curl_cf_def_get_host, + ssl_cf_adjust_pollset, + ssl_cf_data_pending, + ssl_cf_send, + ssl_cf_recv, + ssl_cf_cntrl, + cf_ssl_is_alive, + Curl_cf_def_conn_keep_alive, + ssl_cf_query, +}; + +#ifndef CURL_DISABLE_PROXY + +struct Curl_cftype Curl_cft_ssl_proxy = { + "SSL-PROXY", + CF_TYPE_SSL, + CURL_LOG_LVL_NONE, + ssl_cf_destroy, + ssl_cf_connect, + ssl_cf_close, + Curl_cf_def_get_host, + ssl_cf_adjust_pollset, + ssl_cf_data_pending, + ssl_cf_send, + ssl_cf_recv, + ssl_cf_cntrl, + cf_ssl_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, +}; + +#endif /* !CURL_DISABLE_PROXY */ + +static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn) +{ + struct Curl_cfilter *cf = NULL; + struct ssl_connect_data *ctx; + CURLcode result; + + DEBUGASSERT(data->conn); + + ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant, + conn->bits.tls_enable_alpn)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + result = Curl_cf_create(&cf, &Curl_cft_ssl, ctx); + +out: + if(result) + cf_ctx_free(ctx); + *pcf = result? NULL : cf; + return result; +} + +CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf; + CURLcode result; + + result = cf_ssl_create(&cf, data, conn); + if(!result) + Curl_conn_cf_add(data, conn, sockindex, cf); + return result; +} + +CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + CURLcode result; + + result = cf_ssl_create(&cf, data, cf_at->conn); + if(!result) + Curl_conn_cf_insert_after(cf_at, cf); + return result; +} + +#ifndef CURL_DISABLE_PROXY + +static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn) +{ + struct Curl_cfilter *cf = NULL; + struct ssl_connect_data *ctx; + CURLcode result; + bool use_alpn = conn->bits.tls_enable_alpn; + int httpwant = CURL_HTTP_VERSION_1_1; + +#ifdef USE_HTTP2 + if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) { + use_alpn = TRUE; + httpwant = CURL_HTTP_VERSION_2; + } +#endif + + ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + result = Curl_cf_create(&cf, &Curl_cft_ssl_proxy, ctx); + +out: + if(result) + cf_ctx_free(ctx); + *pcf = result? NULL : cf; + return result; +} + +CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + CURLcode result; + + result = cf_ssl_proxy_create(&cf, data, cf_at->conn); + if(!result) + Curl_conn_cf_insert_after(cf_at, cf); + return result; +} + +#endif /* !CURL_DISABLE_PROXY */ + +bool Curl_ssl_supports(struct Curl_easy *data, int option) +{ + (void)data; + return (Curl_ssl->supports & option)? TRUE : FALSE; +} + +static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf) +{ + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_ssl) + return cf; +#ifndef CURL_DISABLE_PROXY + if(cf->cft == &Curl_cft_ssl_proxy) + return cf; +#endif + } + return NULL; +} + + +void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, + CURLINFO info, int n) +{ + void *result = NULL; + (void)n; + if(data->conn) { + struct Curl_cfilter *cf; + /* get first SSL filter in chain, if any is present */ + cf = get_ssl_filter(data->conn->cfilter[sockindex]); + if(cf) { + struct cf_call_data save; + CF_DATA_SAVE(save, cf, data); + result = Curl_ssl->get_internals(cf->ctx, info); + CF_DATA_RESTORE(cf, save); + } + } + return result; +} + +CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, + int sockindex) +{ + struct Curl_cfilter *cf, *head; + CURLcode result = CURLE_OK; + + (void)data; + head = data->conn? data->conn->cfilter[sockindex] : NULL; + for(cf = head; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_ssl) { + if(Curl_ssl->shut_down(cf, data)) + result = CURLE_SSL_SHUTDOWN_FAILED; + Curl_conn_cf_discard_sub(head, cf, data, FALSE); + break; + } + } + return result; +} + +bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf) +{ +#ifndef CURL_DISABLE_PROXY + return (cf->cft == &Curl_cft_ssl_proxy); +#else + (void)cf; + return FALSE; +#endif +} + +struct ssl_config_data * +Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data) +{ +#ifdef CURL_DISABLE_PROXY + (void)cf; + return &data->set.ssl; +#else + return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl; +#endif +} + +struct ssl_primary_config * +Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf) +{ +#ifdef CURL_DISABLE_PROXY + return &cf->conn->ssl_config; +#else + return Curl_ssl_cf_is_proxy(cf)? + &cf->conn->proxy_ssl_config : &cf->conn->ssl_config; +#endif +} + +CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf, + const struct alpn_spec *spec) +{ + size_t i, len; + int off = 0; + unsigned char blen; + + memset(buf, 0, sizeof(*buf)); + for(i = 0; spec && i < spec->count; ++i) { + len = strlen(spec->entries[i]); + if(len >= ALPN_NAME_MAX) + return CURLE_FAILED_INIT; + blen = (unsigned char)len; + if(off + blen + 1 >= (int)sizeof(buf->data)) + return CURLE_FAILED_INIT; + buf->data[off++] = blen; + memcpy(buf->data + off, spec->entries[i], blen); + off += blen; + } + buf->len = off; + return CURLE_OK; +} + +CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf, + const struct alpn_spec *spec) +{ + size_t i, len; + size_t off = 0; + + memset(buf, 0, sizeof(*buf)); + for(i = 0; spec && i < spec->count; ++i) { + len = strlen(spec->entries[i]); + if(len >= ALPN_NAME_MAX) + return CURLE_FAILED_INIT; + if(off + len + 2 >= sizeof(buf->data)) + return CURLE_FAILED_INIT; + if(off) + buf->data[off++] = ','; + memcpy(buf->data + off, spec->entries[i], len); + off += len; + } + buf->data[off] = '\0'; + buf->len = (int)off; + return CURLE_OK; +} + +CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data, + const unsigned char *proto, + size_t proto_len) +{ + int can_multi = 0; + unsigned char *palpn = +#ifndef CURL_DISABLE_PROXY + (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))? + &cf->conn->proxy_alpn : &cf->conn->alpn +#else + &cf->conn->alpn +#endif + ; + + if(proto && proto_len) { + if(proto_len == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) { + *palpn = CURL_HTTP_VERSION_1_1; + } +#ifdef USE_HTTP2 + else if(proto_len == ALPN_H2_LENGTH && + !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) { + *palpn = CURL_HTTP_VERSION_2; + can_multi = 1; + } +#endif +#ifdef USE_HTTP3 + else if(proto_len == ALPN_H3_LENGTH && + !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) { + *palpn = CURL_HTTP_VERSION_3; + can_multi = 1; + } +#endif + else { + *palpn = CURL_HTTP_VERSION_NONE; + failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto); + /* TODO: do we want to fail this? Previous code just ignored it and + * some vtls backends even ignore the return code of this function. */ + /* return CURLE_NOT_BUILT_IN; */ + goto out; + } + infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto); + } + else { + *palpn = CURL_HTTP_VERSION_NONE; + infof(data, VTLS_INFOF_NO_ALPN); + } + +out: + if(!Curl_ssl_cf_is_proxy(cf)) + Curl_multiuse_state(data, can_multi? + BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + return CURLE_OK; +} + +#endif /* USE_SSL */ diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h new file mode 100644 index 0000000..744bbf8 --- /dev/null +++ b/lib/vtls/vtls.h @@ -0,0 +1,258 @@ +#ifndef HEADER_CURL_VTLS_H +#define HEADER_CURL_VTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +struct connectdata; +struct ssl_config_data; +struct ssl_primary_config; +struct Curl_ssl_session; + +#define SSLSUPP_CA_PATH (1<<0) /* supports CAPATH */ +#define SSLSUPP_CERTINFO (1<<1) /* supports CURLOPT_CERTINFO */ +#define SSLSUPP_PINNEDPUBKEY (1<<2) /* supports CURLOPT_PINNEDPUBLICKEY */ +#define SSLSUPP_SSL_CTX (1<<3) /* supports CURLOPT_SSL_CTX */ +#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */ +#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */ +#define SSLSUPP_CAINFO_BLOB (1<<6) + +#define ALPN_ACCEPTED "ALPN: server accepted " + +#define VTLS_INFOF_NO_ALPN \ + "ALPN: server did not agree on a protocol. Uses default." +#define VTLS_INFOF_ALPN_OFFER_1STR \ + "ALPN: curl offers %s" +#define VTLS_INFOF_ALPN_ACCEPTED_1STR \ + ALPN_ACCEPTED "%s" +#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR \ + ALPN_ACCEPTED "%.*s" + +/* Curl_multi SSL backend-specific data; declared differently by each SSL + backend */ +struct multi_ssl_backend_data; +struct Curl_cfilter; + +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + +#ifndef MAX_PINNED_PUBKEY_SIZE +#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ +#endif + +#ifndef CURL_SHA256_DIGEST_LENGTH +#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */ +#endif + +curl_sslbackend Curl_ssl_backend(void); + +/** + * Init ssl config for a new easy handle. + */ +void Curl_ssl_easy_config_init(struct Curl_easy *data); + +/** + * Init the `data->set.ssl` and `data->set.proxy_ssl` for + * connection matching use. + */ +CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data); + +/** + * Init SSL configs (main + proxy) for a new connection from the easy handle. + */ +CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data, + struct connectdata *conn); + +/** + * Free allocated resources in SSL configs (main + proxy) for + * the given connection. + */ +void Curl_ssl_conn_config_cleanup(struct connectdata *conn); + +/** + * Return TRUE iff SSL configuration from `conn` is functionally the + * same as the one on `candidate`. + * @param proxy match the proxy SSL config or the main one + */ +bool Curl_ssl_conn_config_match(struct Curl_easy *data, + struct connectdata *candidate, + bool proxy); + +/* Update certain connection SSL config flags after they have + * been changed on the easy handle. Will work for `verifypeer`, + * `verifyhost` and `verifystatus`. */ +void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy); + +/** + * Init SSL peer information for filter. Can be called repeatedly. + */ +CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf); +/** + * Free all allocated data and reset peer information. + */ +void Curl_ssl_peer_cleanup(struct ssl_peer *peer); + +#ifdef USE_SSL +int Curl_ssl_init(void); +void Curl_ssl_cleanup(void); +/* tell the SSL stuff to close down all open information regarding + connections (and thus session ID caching etc) */ +void Curl_ssl_close_all(struct Curl_easy *data); +CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine); +/* Sets engine as default for all SSL operations */ +CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data); +struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); + +/* init the SSL session ID cache */ +CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); +void Curl_ssl_version(char *buffer, size_t size); + +/* Certificate information list handling. */ + +void Curl_ssl_free_certinfo(struct Curl_easy *data); +CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num); +CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum, + const char *label, const char *value, + size_t valuelen); +CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, + const char *label, const char *value); + +/* Functions to be used by SSL library adaptation functions */ + +/* Lock session cache mutex. + * Call this before calling other Curl_ssl_*session* functions + * Caller should unlock this mutex as soon as possible, as it may block + * other SSL connection from making progress. + * The purpose of explicitly locking SSL session cache data is to allow + * individual SSL engines to manage session lifetime in their specific way. + */ +void Curl_ssl_sessionid_lock(struct Curl_easy *data); + +/* Unlock session cache mutex */ +void Curl_ssl_sessionid_unlock(struct Curl_easy *data); + +/* Kill a single session ID entry in the cache + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * This will call engine-specific curlssl_session_free function, which must + * take sessionid object ownership from sessionid cache + * (e.g. decrement refcount). + */ +void Curl_ssl_kill_session(struct Curl_ssl_session *session); +/* delete a session from the cache + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * This will call engine-specific curlssl_session_free function, which must + * take sessionid object ownership from sessionid cache + * (e.g. decrement refcount). + */ +void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid); + +/* get N random bytes into the buffer */ +CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, + size_t length); +/* Check pinned public key. */ +CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, + const char *pinnedpubkey, + const unsigned char *pubkey, size_t pubkeylen); + +bool Curl_ssl_cert_status_request(void); + +bool Curl_ssl_false_start(struct Curl_easy *data); + +void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend); + +#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ + +CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex); + +CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data); + +CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, + int sockindex); + +#ifndef CURL_DISABLE_PROXY +CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data); +#endif /* !CURL_DISABLE_PROXY */ + +/** + * True iff the underlying SSL implementation supports the option. + * Option is one of the defined SSLSUPP_* values. + * `data` maybe NULL for the features of the default implementation. + */ +bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option); + +/** + * Get the internal ssl instance (like OpenSSL's SSL*) from the filter + * chain at `sockindex` of type specified by `info`. + * For `n` == 0, the first active (top down) instance is returned. + * 1 gives the second active, etc. + * NULL is returned when no active SSL filter is present. + */ +void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, + CURLINFO info, int n); + +/** + * Get the ssl_config_data in `data` that is relevant for cfilter `cf`. + */ +struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf, + struct Curl_easy *data); + +/** + * Get the primary config relevant for the filter from its connection. + */ +struct ssl_primary_config * + Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf); + +extern struct Curl_cftype Curl_cft_ssl; +#ifndef CURL_DISABLE_PROXY +extern struct Curl_cftype Curl_cft_ssl_proxy; +#endif + +#else /* if not USE_SSL */ + +/* When SSL support is not present, just define away these function calls */ +#define Curl_ssl_init() 1 +#define Curl_ssl_cleanup() Curl_nop_stmt +#define Curl_ssl_close_all(x) Curl_nop_stmt +#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN +#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN +#define Curl_ssl_engines_list(x) NULL +#define Curl_ssl_initsessions(x,y) CURLE_OK +#define Curl_ssl_free_certinfo(x) Curl_nop_stmt +#define Curl_ssl_kill_session(x) Curl_nop_stmt +#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) +#define Curl_ssl_cert_status_request() FALSE +#define Curl_ssl_false_start(a) FALSE +#define Curl_ssl_get_internals(a,b,c,d) NULL +#define Curl_ssl_supports(a,b) FALSE +#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN +#define Curl_ssl_cfilter_remove(a,b) CURLE_OK +#define Curl_ssl_cf_get_config(a,b) NULL +#define Curl_ssl_cf_get_primary_config(a) NULL +#endif + +#endif /* HEADER_CURL_VTLS_H */ diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h new file mode 100644 index 0000000..af7ae55 --- /dev/null +++ b/lib/vtls/vtls_int.h @@ -0,0 +1,207 @@ +#ifndef HEADER_CURL_VTLS_INT_H +#define HEADER_CURL_VTLS_INT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" +#include "cfilters.h" +#include "urldata.h" + +#ifdef USE_SSL + +/* see https://www.iana.org/assignments/tls-extensiontype-values/ */ +#define ALPN_HTTP_1_1_LENGTH 8 +#define ALPN_HTTP_1_1 "http/1.1" +#define ALPN_H2_LENGTH 2 +#define ALPN_H2 "h2" +#define ALPN_H3_LENGTH 2 +#define ALPN_H3 "h3" + +/* conservative sizes on the ALPN entries and count we are handling, + * we can increase these if we ever feel the need or have to accommodate + * ALPN strings from the "outside". */ +#define ALPN_NAME_MAX 10 +#define ALPN_ENTRIES_MAX 3 +#define ALPN_PROTO_BUF_MAX (ALPN_ENTRIES_MAX * (ALPN_NAME_MAX + 1)) + +struct alpn_spec { + const char entries[ALPN_ENTRIES_MAX][ALPN_NAME_MAX]; + size_t count; /* number of entries */ +}; + +struct alpn_proto_buf { + unsigned char data[ALPN_PROTO_BUF_MAX]; + int len; +}; + +CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf, + const struct alpn_spec *spec); +CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf, + const struct alpn_spec *spec); + +CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data, + const unsigned char *proto, + size_t proto_len); + +/* Information in each SSL cfilter context: cf->ctx */ +struct ssl_connect_data { + ssl_connection_state state; + ssl_connect_state connecting_state; + struct ssl_peer peer; + const struct alpn_spec *alpn; /* ALPN to use or NULL for none */ + void *backend; /* vtls backend specific props */ + struct cf_call_data call_data; /* data handle used in current call */ + struct curltime handshake_done; /* time when handshake finished */ + int port; /* remote port at origin */ + BIT(use_alpn); /* if ALPN shall be used in handshake */ + BIT(reused_session); /* session-ID was reused for this */ +}; + + +#undef CF_CTX_CALL_DATA +#define CF_CTX_CALL_DATA(cf) \ + ((struct ssl_connect_data *)(cf)->ctx)->call_data + + +/* Definitions for SSL Implementations */ + +struct Curl_ssl { + /* + * This *must* be the first entry to allow returning the list of available + * backends in curl_global_sslset(). + */ + curl_ssl_backend info; + unsigned int supports; /* bitfield, see above */ + size_t sizeof_ssl_backend_data; + + int (*init)(void); + void (*cleanup)(void); + + size_t (*version)(char *buffer, size_t size); + int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data); + int (*shut_down)(struct Curl_cfilter *cf, + struct Curl_easy *data); + bool (*data_pending)(struct Curl_cfilter *cf, + const struct Curl_easy *data); + + /* return 0 if a find random is filled in */ + CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy, + size_t length); + bool (*cert_status_request)(void); + + CURLcode (*connect_blocking)(struct Curl_cfilter *cf, + struct Curl_easy *data); + CURLcode (*connect_nonblocking)(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done); + + /* During handshake, adjust the pollset to include the socket + * for POLLOUT or POLLIN as needed. + * Mandatory. */ + void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data, + struct easy_pollset *ps); + void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info); + void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data); + void (*close_all)(struct Curl_easy *data); + void (*session_free)(void *ptr); + + CURLcode (*set_engine)(struct Curl_easy *data, const char *engine); + CURLcode (*set_engine_default)(struct Curl_easy *data); + struct curl_slist *(*engines_list)(struct Curl_easy *data); + + bool (*false_start)(void); + CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen, + unsigned char *sha256sum, size_t sha256sumlen); + + bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data); + void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data); + + void (*free_multi_ssl_backend_data)(struct multi_ssl_backend_data *mbackend); + + ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, CURLcode *code); + ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *mem, size_t len, CURLcode *code); + +}; + +extern const struct Curl_ssl *Curl_ssl; + + +int Curl_none_init(void); +void Curl_none_cleanup(void); +int Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data); +int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data); +CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy, + size_t length); +void Curl_none_close_all(struct Curl_easy *data); +void Curl_none_session_free(void *ptr); +bool Curl_none_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data); +bool Curl_none_cert_status_request(void); +CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine); +CURLcode Curl_none_set_engine_default(struct Curl_easy *data); +struct curl_slist *Curl_none_engines_list(struct Curl_easy *data); +bool Curl_none_false_start(void); +void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, + struct easy_pollset *ps); + +/** + * Get the SSL filter below the given one or NULL if there is none. + */ +bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf); + +/* extract a session ID + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * Caller must make sure that the ownership of returned sessionid object + * is properly taken (e.g. its refcount is incremented + * under sessionid mutex). + */ +bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, + struct Curl_easy *data, + void **ssl_sessionid, + size_t *idsize); /* set 0 if unknown */ +/* add a new session ID + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * Caller must ensure that it has properly shared ownership of this sessionid + * object with cache (e.g. incrementing refcount on success) + */ +CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf, + struct Curl_easy *data, + void *ssl_sessionid, + size_t idsize, + bool *added); + +#include "openssl.h" /* OpenSSL versions */ +#include "gtls.h" /* GnuTLS versions */ +#include "wolfssl.h" /* wolfSSL versions */ +#include "schannel.h" /* Schannel SSPI version */ +#include "sectransp.h" /* SecureTransport (Darwin) version */ +#include "mbedtls.h" /* mbedTLS versions */ +#include "bearssl.h" /* BearSSL versions */ +#include "rustls.h" /* rustls versions */ + +#endif /* USE_SSL */ + +#endif /* HEADER_CURL_VTLS_INT_H */ diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c new file mode 100644 index 0000000..a3c017c --- /dev/null +++ b/lib/vtls/wolfssl.c @@ -0,0 +1,1418 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* + * Source file for all wolfSSL specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + */ + +#include "curl_setup.h" + +#ifdef USE_WOLFSSL + +#define WOLFSSL_OPTIONS_IGNORE_SYS +#include +#include + +/* To determine what functions are available we rely on one or both of: + - the user's options.h generated by wolfSSL + - the symbols detected by curl's configure + Since they are markedly different from one another, and one or the other may + not be available, we do some checking below to bring things in sync. */ + +/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */ +#ifndef HAVE_ALPN +#ifdef HAVE_WOLFSSL_USEALPN +#define HAVE_ALPN +#endif +#endif + +#include + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "vtls.h" +#include "vtls_int.h" +#include "keylog.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "strcase.h" +#include "x509asn1.h" +#include "curl_printf.h" +#include "multiif.h" + +#include +#include +#include +#include "wolfssl.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* KEEP_PEER_CERT is a product of the presence of build time symbol + OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is + in wolfSSL's settings.h, and the latter two are build time symbols in + options.h. */ +#ifndef KEEP_PEER_CERT +#if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ + (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) +#define KEEP_PEER_CERT +#endif +#endif + +#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO +#define USE_BIO_CHAIN +#else +#undef USE_BIO_CHAIN +#endif + +struct wolfssl_ssl_backend_data { + WOLFSSL_CTX *ctx; + WOLFSSL *handle; + CURLcode io_result; /* result of last BIO cfilter operation */ +}; + +#ifdef OPENSSL_EXTRA +/* + * Availability note: + * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in + * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that + * option is not set, then TLS 1.3 will not be logged. + * For TLS 1.2 and before, we use wolfSSL_get_keys(). + * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA + * (--enable-opensslextra or --enable-all). + */ +#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) +static int +wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret, + int secretSz, void *ctx) +{ + const char *label; + unsigned char client_random[SSL3_RANDOM_SIZE]; + (void)ctx; + + if(!ssl || !Curl_tls_keylog_enabled()) { + return 0; + } + + switch(id) { + case CLIENT_EARLY_TRAFFIC_SECRET: + label = "CLIENT_EARLY_TRAFFIC_SECRET"; + break; + case CLIENT_HANDSHAKE_TRAFFIC_SECRET: + label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; + break; + case SERVER_HANDSHAKE_TRAFFIC_SECRET: + label = "SERVER_HANDSHAKE_TRAFFIC_SECRET"; + break; + case CLIENT_TRAFFIC_SECRET: + label = "CLIENT_TRAFFIC_SECRET_0"; + break; + case SERVER_TRAFFIC_SECRET: + label = "SERVER_TRAFFIC_SECRET_0"; + break; + case EARLY_EXPORTER_SECRET: + label = "EARLY_EXPORTER_SECRET"; + break; + case EXPORTER_SECRET: + label = "EXPORTER_SECRET"; + break; + default: + return 0; + } + + if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) { + /* Should never happen as wolfSSL_KeepArrays() was called before. */ + return 0; + } + + Curl_tls_keylog_write(label, client_random, secret, secretSz); + return 0; +} +#endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */ + +static void +wolfssl_log_tls12_secret(SSL *ssl) +{ + unsigned char *ms, *sr, *cr; + unsigned int msLen, srLen, crLen, i, x = 0; + +#if LIBWOLFSSL_VERSION_HEX >= 0x0300d000 /* >= 3.13.0 */ + /* wolfSSL_GetVersion is available since 3.13, we use it instead of + * SSL_version since the latter relies on OPENSSL_ALL (--enable-opensslall or + * --enable-all). Failing to perform this check could result in an unusable + * key log line when TLS 1.3 is actually negotiated. */ + switch(wolfSSL_GetVersion(ssl)) { + case WOLFSSL_SSLV3: + case WOLFSSL_TLSV1: + case WOLFSSL_TLSV1_1: + case WOLFSSL_TLSV1_2: + break; + default: + /* TLS 1.3 does not use this mechanism, the "master secret" returned below + * is not directly usable. */ + return; + } +#endif + + if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != + SSL_SUCCESS) { + return; + } + + /* Check for a missing master secret and skip logging. That can happen if + * curl rejects the server certificate and aborts the handshake. + */ + for(i = 0; i < msLen; i++) { + x |= ms[i]; + } + if(x == 0) { + return; + } + + Curl_tls_keylog_write("CLIENT_RANDOM", cr, ms, msLen); +} +#endif /* OPENSSL_EXTRA */ + +static int do_file_type(const char *type) +{ + if(!type || !type[0]) + return SSL_FILETYPE_PEM; + if(strcasecompare(type, "PEM")) + return SSL_FILETYPE_PEM; + if(strcasecompare(type, "DER")) + return SSL_FILETYPE_ASN1; + return -1; +} + +#ifdef HAVE_LIBOQS +struct group_name_map { + const word16 group; + const char *name; +}; + +static const struct group_name_map gnm[] = { + { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" }, + { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" }, + { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" }, + { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" }, + { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" }, + { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" }, + { 0, NULL } +}; +#endif + +#ifdef USE_BIO_CHAIN + +static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio) +{ + wolfSSL_BIO_set_shutdown(bio, 1); + wolfSSL_BIO_set_init(bio, 1); + wolfSSL_BIO_set_data(bio, NULL); + return 1; +} + +static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio) +{ + if(!bio) + return 0; + return 1; +} + +static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) +{ + struct Curl_cfilter *cf = BIO_get_data(bio); + long ret = 1; + + (void)cf; + (void)ptr; + switch(cmd) { + case BIO_CTRL_GET_CLOSE: + ret = (long)wolfSSL_BIO_get_shutdown(bio); + break; + case BIO_CTRL_SET_CLOSE: + wolfSSL_BIO_set_shutdown(bio, (int)num); + break; + case BIO_CTRL_FLUSH: + /* we do no delayed writes, but if we ever would, this + * needs to trigger it. */ + ret = 1; + break; + case BIO_CTRL_DUP: + ret = 1; + break; +#ifdef BIO_CTRL_EOF + case BIO_CTRL_EOF: + /* EOF has been reached on input? */ + return (!cf->next || !cf->next->connected); +#endif + default: + ret = 0; + break; + } + return ret; +} + +static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio, + const char *buf, int blen) +{ + struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); + backend->io_result = result; + CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d", + blen, nwritten, result); + wolfSSL_BIO_clear_retry_flags(bio); + if(nwritten < 0 && CURLE_AGAIN == result) + BIO_set_retry_write(bio); + return (int)nwritten; +} + +static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) +{ + struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nread; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + /* OpenSSL catches this case, so should we. */ + if(!buf) + return 0; + + nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); + backend->io_result = result; + CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result); + wolfSSL_BIO_clear_retry_flags(bio); + if(nread < 0 && CURLE_AGAIN == result) + BIO_set_retry_read(bio); + return (int)nread; +} + +static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL; + +static void wolfssl_bio_cf_init_methods(void) +{ + wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO"); + wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write); + wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read); + wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl); + wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create); + wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy); +} + +static void wolfssl_bio_cf_free_methods(void) +{ + wolfSSL_BIO_meth_free(wolfssl_bio_cf_method); +} + +#else /* USE_BIO_CHAIN */ + +#define wolfssl_bio_cf_init_methods() Curl_nop_stmt +#define wolfssl_bio_cf_free_methods() Curl_nop_stmt + +#endif /* !USE_BIO_CHAIN */ + +/* + * This function loads all the client/CA certificates and CRLs. Setup the TLS + * layer and do all necessary magic. + */ +static CURLcode +wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + char *ciphers, *curves; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : conn_config->CAfile); + const char * const ssl_capath = conn_config->CApath; + WOLFSSL_METHOD* req_method = NULL; +#ifdef HAVE_LIBOQS + word16 oqsAlg = 0; + size_t idx = 0; +#endif +#ifdef HAVE_SNI + bool sni = FALSE; +#define use_sni(x) sni = (x) +#else +#define use_sni(x) Curl_nop_stmt +#endif + bool imported_native_ca = false; + bool imported_ca_info_blob = false; + + DEBUGASSERT(backend); + + if(connssl->state == ssl_connection_complete) + return CURLE_OK; + + if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) { + failf(data, "wolfSSL does not support to set maximum SSL/TLS version"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* check to see if we've been told to use an explicit SSL/TLS version */ + switch(conn_config->version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ + /* minimum protocol version is set later after the CTX object is created */ + req_method = SSLv23_client_method(); +#else + infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " + "TLS 1.0 is used exclusively"); + req_method = TLSv1_client_method(); +#endif + use_sni(TRUE); + break; + case CURL_SSLVERSION_TLSv1_0: +#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS) + req_method = TLSv1_client_method(); + use_sni(TRUE); +#else + failf(data, "wolfSSL does not support TLS 1.0"); + return CURLE_NOT_BUILT_IN; +#endif + break; + case CURL_SSLVERSION_TLSv1_1: +#ifndef NO_OLD_TLS + req_method = TLSv1_1_client_method(); + use_sni(TRUE); +#else + failf(data, "wolfSSL does not support TLS 1.1"); + return CURLE_NOT_BUILT_IN; +#endif + break; + case CURL_SSLVERSION_TLSv1_2: +#ifndef WOLFSSL_NO_TLS12 + req_method = TLSv1_2_client_method(); + use_sni(TRUE); +#else + failf(data, "wolfSSL does not support TLS 1.2"); + return CURLE_NOT_BUILT_IN; +#endif + break; + case CURL_SSLVERSION_TLSv1_3: +#ifdef WOLFSSL_TLS13 + req_method = wolfTLSv1_3_client_method(); + use_sni(TRUE); + break; +#else + failf(data, "wolfSSL: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; +#endif + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(!req_method) { + failf(data, "SSL: couldn't create a method"); + return CURLE_OUT_OF_MEMORY; + } + + if(backend->ctx) + wolfSSL_CTX_free(backend->ctx); + backend->ctx = wolfSSL_CTX_new(req_method); + + if(!backend->ctx) { + failf(data, "SSL: couldn't create a context"); + return CURLE_OUT_OF_MEMORY; + } + + switch(conn_config->version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ + /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is + * whatever minimum version of TLS was built in and at least TLS 1.0. For + * later library versions that could change (eg TLS 1.0 built in but + * defaults to TLS 1.1) so we have this short circuit evaluation to find + * the minimum supported TLS version. + */ + if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) && + (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) && + (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1) +#ifdef WOLFSSL_TLS13 + && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1) +#endif + ) { + failf(data, "SSL: couldn't set the minimum protocol version"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif + default: + break; + } + + ciphers = conn_config->cipher_list; + if(ciphers) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s", ciphers); + } + + curves = conn_config->curves; + if(curves) { + +#ifdef HAVE_LIBOQS + for(idx = 0; gnm[idx].name != NULL; idx++) { + if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) { + oqsAlg = gnm[idx].group; + break; + } + } + + if(oqsAlg == 0) +#endif + { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } + +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS) + /* load native CA certificates */ + if(ssl_config->native_ca_store) { + if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) { + infof(data, "error importing native CA store, continuing anyway"); + } + else { + imported_native_ca = true; + infof(data, "successfully imported native CA store"); + } + } +#endif /* !NO_FILESYSTEM */ + + /* load certificate blob */ + if(ca_info_blob) { + if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data, + ca_info_blob->len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + if(imported_native_ca) { + infof(data, "error importing CA certificate blob, continuing anyway"); + } + else { + failf(data, "error importing CA certificate blob"); + return CURLE_SSL_CACERT_BADFILE; + } + } + else { + imported_ca_info_blob = true; + infof(data, "successfully imported CA certificate blob"); + } + } + +#ifndef NO_FILESYSTEM + /* load trusted cacert from file if not blob */ + if(ssl_cafile || ssl_capath) { + int rc = + wolfSSL_CTX_load_verify_locations_ex(backend->ctx, + ssl_cafile, + ssl_capath, + WOLFSSL_LOAD_FLAG_IGNORE_ERR); + if(SSL_SUCCESS != rc) { + if(conn_config->verifypeer && !imported_ca_info_blob && + !imported_native_ca) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + /* Just continue with a warning if no strict certificate + verification is required. */ + infof(data, "error setting certificate verify locations," + " continuing anyway:"); + } + } + else { + /* Everything is fine. */ + infof(data, "successfully set certificate verify locations:"); + } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } + + /* Load the client certificate, and private key */ + if(ssl_config->primary.clientcert && ssl_config->key) { + int file_type = do_file_type(ssl_config->cert_type); + + if(file_type == WOLFSSL_FILETYPE_PEM) { + if(wolfSSL_CTX_use_certificate_chain_file(backend->ctx, + ssl_config->primary.clientcert) + != 1) { + failf(data, "unable to use client certificate"); + return CURLE_SSL_CONNECT_ERROR; + } + } + else if(file_type == WOLFSSL_FILETYPE_ASN1) { + if(wolfSSL_CTX_use_certificate_file(backend->ctx, + ssl_config->primary.clientcert, + file_type) != 1) { + failf(data, "unable to use client certificate"); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { + failf(data, "unknown cert type"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + file_type = do_file_type(ssl_config->key_type); + if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key, + file_type) != 1) { + failf(data, "unable to set private key"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* !NO_FILESYSTEM */ + + /* SSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + wolfSSL_CTX_set_verify(backend->ctx, + conn_config->verifypeer?SSL_VERIFY_PEER: + SSL_VERIFY_NONE, NULL); + +#ifdef HAVE_SNI + if(sni && connssl->peer.sni) { + size_t sni_len = strlen(connssl->peer.sni); + if((sni_len < USHRT_MAX)) { + if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, + connssl->peer.sni, + (unsigned short)sni_len) != 1) { + failf(data, "Failed to set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + } + } +#endif + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx, + data->set.ssl.fsslctxp); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } +#ifdef NO_FILESYSTEM + else if(conn_config->verifypeer) { + failf(data, "SSL: Certificates can't be loaded because wolfSSL was built" + " with \"no filesystem\". Either disable peer verification" + " (insecure) or if you are building an application with libcurl you" + " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); + return CURLE_SSL_CONNECT_ERROR; + } +#endif + + /* Let's make an SSL structure */ + if(backend->handle) + wolfSSL_free(backend->handle); + backend->handle = wolfSSL_new(backend->ctx); + if(!backend->handle) { + failf(data, "SSL: couldn't create a handle"); + return CURLE_OUT_OF_MEMORY; + } + +#ifdef HAVE_LIBOQS + if(oqsAlg) { + if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) { + failf(data, "unable to use oqs KEM"); + } + } +#endif + +#ifdef HAVE_ALPN + if(connssl->alpn) { + struct alpn_proto_buf proto; + CURLcode result; + + result = Curl_alpn_to_proto_str(&proto, connssl->alpn); + if(result || + wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len, + WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { + failf(data, "SSL: failed setting ALPN protocols"); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } +#endif /* HAVE_ALPN */ + +#ifdef OPENSSL_EXTRA + if(Curl_tls_keylog_enabled()) { + /* Ensure the Client Random is preserved. */ + wolfSSL_KeepArrays(backend->handle); +#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) + wolfSSL_set_tls13_secret_cb(backend->handle, + wolfssl_tls13_secret_callback, NULL); +#endif + } +#endif /* OPENSSL_EXTRA */ + +#ifdef HAVE_SECURE_RENEGOTIATION + if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) { + failf(data, "SSL: failed setting secure renegotiation"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* HAVE_SECURE_RENEGOTIATION */ + + /* Check if there's a cached ID we can/should use here! */ + if(ssl_config->primary.sessionid) { + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if(!SSL_set_session(backend->handle, ssl_sessionid)) { + Curl_ssl_delsessionid(data, ssl_sessionid); + infof(data, "Can't use session ID, going on without"); + } + else + infof(data, "SSL reusing session ID"); + } + Curl_ssl_sessionid_unlock(data); + } + +#ifdef USE_BIO_CHAIN + { + WOLFSSL_BIO *bio; + + bio = BIO_new(wolfssl_bio_cf_method); + if(!bio) + return CURLE_OUT_OF_MEMORY; + + wolfSSL_BIO_set_data(bio, cf); + wolfSSL_set_bio(backend->handle, bio, bio); + } +#else /* USE_BIO_CHAIN */ + /* pass the raw socket into the SSL layer */ + if(!wolfSSL_set_fd(backend->handle, + (int)Curl_conn_cf_get_socket(cf, data))) { + failf(data, "SSL: SSL_set_fd failed"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* !USE_BIO_CHAIN */ + + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; +} + + +static CURLcode +wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + int ret = -1; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + + DEBUGASSERT(backend); + + wolfSSL_ERR_clear_error(); + + /* Enable RFC2818 checks */ + if(conn_config->verifyhost) { + char *snihost = connssl->peer.sni? + connssl->peer.sni : connssl->peer.hostname; + if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE) + return CURLE_SSL_CONNECT_ERROR; + } + + ret = wolfSSL_connect(backend->handle); + +#ifdef OPENSSL_EXTRA + if(Curl_tls_keylog_enabled()) { + /* If key logging is enabled, wait for the handshake to complete and then + * proceed with logging secrets (for TLS 1.2 or older). + * + * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits + * for the server response. At that point the master secret is not yet + * available, so we must not try to read it. + * To log the secret on completion with a handshake failure, detect + * completion via the observation that there is nothing to read or write. + * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever + * changes, the worst case is that no key is logged on error. + */ + if(ret == SSL_SUCCESS || + (!wolfSSL_want_read(backend->handle) && + !wolfSSL_want_write(backend->handle))) { + wolfssl_log_tls12_secret(backend->handle); + /* Client Random and master secrets are no longer needed, erase these. + * Ignored while the handshake is still in progress. */ + wolfSSL_FreeArrays(backend->handle); + } + } +#endif /* OPENSSL_EXTRA */ + + if(ret != 1) { + char error_buffer[WOLFSSL_MAX_ERROR_SZ]; + int detail = wolfSSL_get_error(backend->handle, ret); + + if(SSL_ERROR_WANT_READ == detail) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + else if(SSL_ERROR_WANT_WRITE == detail) { + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + } + /* There is no easy way to override only the CN matching. + * This will enable the override of both mismatching SubjectAltNames + * as also mismatching CN fields */ + else if(DOMAIN_NAME_MISMATCH == detail) { +#if 1 + failf(data, " subject alt name(s) or common name do not match \"%s\"", + connssl->peer.dispname); + return CURLE_PEER_FAILED_VERIFICATION; +#else + /* When the wolfssl_check_domain_name() is used and you desire to + * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost + * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA + * error. The only way to do this is currently to switch the + * Wolfssl_check_domain_name() in and out based on the + * 'ssl_config.verifyhost' value. */ + if(conn_config->verifyhost) { + failf(data, + " subject alt name(s) or common name do not match \"%s\"\n", + connssl->dispname); + return CURLE_PEER_FAILED_VERIFICATION; + } + else { + infof(data, + " subject alt name(s) and/or common name do not match \"%s\"", + connssl->dispname); + return CURLE_OK; + } +#endif + } +#if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ + else if(ASN_NO_SIGNER_E == detail) { + if(conn_config->verifypeer) { + failf(data, " CA signer not available for verification"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + /* Just continue with a warning if no strict certificate + verification is required. */ + infof(data, "CA signer not available for verification, " + "continuing anyway"); + } + } +#endif + else if(backend->io_result == CURLE_AGAIN) { + return CURLE_OK; + } + else { + failf(data, "SSL_connect failed with error %d: %s", detail, + wolfSSL_ERR_error_string(detail, error_buffer)); + return CURLE_SSL_CONNECT_ERROR; + } + } + + if(pinnedpubkey) { +#ifdef KEEP_PEER_CERT + X509 *x509; + const char *x509_der; + int x509_der_len; + struct Curl_X509certificate x509_parsed; + struct Curl_asn1Element *pubkey; + CURLcode result; + + x509 = wolfSSL_get_peer_certificate(backend->handle); + if(!x509) { + failf(data, "SSL: failed retrieving server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len); + if(!x509_der) { + failf(data, "SSL: failed retrieving ASN.1 server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + memset(&x509_parsed, 0, sizeof(x509_parsed)); + if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + pubkey = &x509_parsed.subjectPublicKeyInfo; + if(!pubkey->header || pubkey->end <= pubkey->header) { + failf(data, "SSL: failed retrieving public key from server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + result = Curl_pin_peer_pubkey(data, + pinnedpubkey, + (const unsigned char *)pubkey->header, + (size_t)(pubkey->end - pubkey->header)); + if(result) { + failf(data, "SSL: public key does not match pinned public key"); + return result; + } +#else + failf(data, "Library lacks pinning support built-in"); + return CURLE_NOT_BUILT_IN; +#endif + } + +#ifdef HAVE_ALPN + if(connssl->alpn) { + int rc; + char *protocol = NULL; + unsigned short protocol_len = 0; + + rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len); + + if(rc == SSL_SUCCESS) { + Curl_alpn_set_negotiated(cf, data, (const unsigned char *)protocol, + protocol_len); + } + else if(rc == SSL_ALPN_NOT_FOUND) + Curl_alpn_set_negotiated(cf, data, NULL, 0); + else { + failf(data, "ALPN, failure getting protocol, error %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* HAVE_ALPN */ + + connssl->connecting_state = ssl_connect_3; +#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) + infof(data, "SSL connection using %s / %s", + wolfSSL_get_version(backend->handle), + wolfSSL_get_cipher_name(backend->handle)); +#else + infof(data, "SSL connected"); +#endif + + return CURLE_OK; +} + + +static CURLcode +wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + DEBUGASSERT(backend); + + if(ssl_config->primary.sessionid) { + bool incache; + bool added = FALSE; + void *old_ssl_sessionid = NULL; + /* wolfSSL_get1_session allocates memory that has to be freed. */ + WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle); + + if(our_ssl_sessionid) { + Curl_ssl_sessionid_lock(data); + incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing"); + Curl_ssl_delsessionid(data, old_ssl_sessionid); + incache = FALSE; + } + } + + if(!incache) { + result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL); + if(result) { + Curl_ssl_sessionid_unlock(data); + wolfSSL_SESSION_free(our_ssl_sessionid); + failf(data, "failed to store ssl session"); + return result; + } + else { + added = TRUE; + } + } + Curl_ssl_sessionid_unlock(data); + + if(!added) { + /* If the session info wasn't added to the cache, free our copy. */ + wolfSSL_SESSION_free(our_ssl_sessionid); + } + } + } + + connssl->connecting_state = ssl_connect_done; + + return result; +} + + +static ssize_t wolfssl_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + char error_buffer[WOLFSSL_MAX_ERROR_SZ]; + int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; + int rc; + + DEBUGASSERT(backend); + + wolfSSL_ERR_clear_error(); + + rc = wolfSSL_write(backend->handle, mem, memlen); + if(rc <= 0) { + int err = wolfSSL_get_error(backend->handle, rc); + + switch(err) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* there's data pending, re-invoke SSL_write() */ + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len); + *curlcode = CURLE_AGAIN; + return -1; + default: + if(backend->io_result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len); + *curlcode = CURLE_AGAIN; + return -1; + } + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err); + failf(data, "SSL write: %s, errno %d", + wolfSSL_ERR_error_string(err, error_buffer), + SOCKERRNO); + *curlcode = CURLE_SEND_ERROR; + return -1; + } + } + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc); + return rc; +} + +static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + + (void) data; + + DEBUGASSERT(backend); + + if(backend->handle) { + char buf[32]; + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf)); + (void)wolfSSL_shutdown(backend->handle); + wolfSSL_free(backend->handle); + backend->handle = NULL; + } + if(backend->ctx) { + wolfSSL_CTX_free(backend->ctx); + backend->ctx = NULL; + } +} + +static ssize_t wolfssl_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t blen, + CURLcode *curlcode) +{ + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + char error_buffer[WOLFSSL_MAX_ERROR_SZ]; + int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen; + int nread; + + DEBUGASSERT(backend); + + wolfSSL_ERR_clear_error(); + *curlcode = CURLE_OK; + + nread = wolfSSL_read(backend->handle, buf, buffsize); + + if(nread <= 0) { + int err = wolfSSL_get_error(backend->handle, nread); + + switch(err) { + case SSL_ERROR_ZERO_RETURN: /* no more data */ + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen); + *curlcode = CURLE_OK; + return 0; + case SSL_ERROR_NONE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* there's data pending, re-invoke wolfSSL_read() */ + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen); + *curlcode = CURLE_AGAIN; + return -1; + default: + if(backend->io_result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen); + *curlcode = CURLE_AGAIN; + return -1; + } + failf(data, "SSL read: %s, errno %d", + wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO); + *curlcode = CURLE_RECV_ERROR; + return -1; + } + } + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread); + return nread; +} + + +static void wolfssl_session_free(void *ptr) +{ + wolfSSL_SESSION_free(ptr); +} + + +static size_t wolfssl_version(char *buffer, size_t size) +{ +#if LIBWOLFSSL_VERSION_HEX >= 0x03006000 + return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); +#elif defined(WOLFSSL_VERSION) + return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); +#endif +} + + +static int wolfssl_init(void) +{ + int ret; + +#ifdef OPENSSL_EXTRA + Curl_tls_keylog_open(); +#endif + ret = (wolfSSL_Init() == SSL_SUCCESS); + wolfssl_bio_cf_init_methods(); + return ret; +} + + +static void wolfssl_cleanup(void) +{ + wolfssl_bio_cf_free_methods(); + wolfSSL_Cleanup(); +#ifdef OPENSSL_EXTRA + Curl_tls_keylog_close(); +#endif +} + + +static bool wolfssl_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct ssl_connect_data *ctx = cf->ctx; + struct wolfssl_ssl_backend_data *backend; + + (void)data; + DEBUGASSERT(ctx && ctx->backend); + + backend = (struct wolfssl_ssl_backend_data *)ctx->backend; + if(backend->handle) /* SSL is in use */ + return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE; + else + return FALSE; +} + + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +static int wolfssl_shutdown(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct ssl_connect_data *ctx = cf->ctx; + struct wolfssl_ssl_backend_data *backend; + int retval = 0; + + (void)data; + DEBUGASSERT(ctx && ctx->backend); + + backend = (struct wolfssl_ssl_backend_data *)ctx->backend; + if(backend->handle) { + wolfSSL_ERR_clear_error(); + wolfSSL_free(backend->handle); + backend->handle = NULL; + } + return retval; +} + + +static CURLcode +wolfssl_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool nonblocking, + bool *done) +{ + CURLcode result; + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + /* Find out how much more time we're allowed */ + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = wolfssl_connect_step1(cf, data); + if(result) + return result; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + result = wolfssl_connect_step2(cf, data); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3 == connssl->connecting_state) { + result = wolfssl_connect_step3(cf, data); + if(result) + return result; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + + +static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + return wolfssl_connect_common(cf, data, TRUE, done); +} + + +static CURLcode wolfssl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + CURLcode result; + bool done = FALSE; + + result = wolfssl_connect_common(cf, data, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +static CURLcode wolfssl_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) +{ + WC_RNG rng; + (void)data; + if(wc_InitRng(&rng)) + return CURLE_FAILED_INIT; + if(length > UINT_MAX) + return CURLE_FAILED_INIT; + if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length)) + return CURLE_FAILED_INIT; + if(wc_FreeRng(&rng)) + return CURLE_FAILED_INIT; + return CURLE_OK; +} + +static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) +{ + wc_Sha256 SHA256pw; + (void)unused; + if(wc_InitSha256(&SHA256pw)) + return CURLE_FAILED_INIT; + wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen); + wc_Sha256Final(&SHA256pw, sha256sum); + return CURLE_OK; +} + +static void *wolfssl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + (void)info; + DEBUGASSERT(backend); + return backend->handle; +} + +const struct Curl_ssl Curl_ssl_wolfssl = { + { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */ + +#ifdef KEEP_PEER_CERT + SSLSUPP_PINNEDPUBKEY | +#endif +#ifdef USE_BIO_CHAIN + SSLSUPP_HTTPS_PROXY | +#endif + SSLSUPP_CA_PATH | + SSLSUPP_CAINFO_BLOB | + SSLSUPP_SSL_CTX, + + sizeof(struct wolfssl_ssl_backend_data), + + wolfssl_init, /* init */ + wolfssl_cleanup, /* cleanup */ + wolfssl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + wolfssl_shutdown, /* shutdown */ + wolfssl_data_pending, /* data_pending */ + wolfssl_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + wolfssl_connect, /* connect */ + wolfssl_connect_nonblocking, /* connect_nonblocking */ + Curl_ssl_adjust_pollset, /* adjust_pollset */ + wolfssl_get_internals, /* get_internals */ + wolfssl_close, /* close_one */ + Curl_none_close_all, /* close_all */ + wolfssl_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + wolfssl_sha256sum, /* sha256sum */ + NULL, /* associate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + wolfssl_recv, /* recv decrypted data */ + wolfssl_send, /* send data to encrypt */ +}; + +#endif diff --git a/lib/vtls/wolfssl.h b/lib/vtls/wolfssl.h new file mode 100644 index 0000000..a5ed848 --- /dev/null +++ b/lib/vtls/wolfssl.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_WOLFSSL_H +#define HEADER_CURL_WOLFSSL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_WOLFSSL + +extern const struct Curl_ssl Curl_ssl_wolfssl; + +#endif /* USE_WOLFSSL */ +#endif /* HEADER_CURL_WOLFSSL_H */ diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c new file mode 100644 index 0000000..da07936 --- /dev/null +++ b/lib/vtls/x509asn1.c @@ -0,0 +1,1229 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \ + defined(USE_SCHANNEL) || defined(USE_SECTRANSP) + +#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL) +#define WANT_PARSEX509 /* uses Curl_parseX509() */ +#endif + +#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) +#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */ +#define WANT_PARSEX509 /* ... uses Curl_parseX509() */ +#endif + +#include +#include "urldata.h" +#include "strcase.h" +#include "curl_ctype.h" +#include "hostcheck.h" +#include "vtls/vtls.h" +#include "vtls/vtls_int.h" +#include "sendf.h" +#include "inet_pton.h" +#include "curl_base64.h" +#include "x509asn1.h" +#include "dynbuf.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Constants. + */ + +/* Largest supported ASN.1 structure. */ +#define CURL_ASN1_MAX ((size_t) 0x40000) /* 256K */ + +/* ASN.1 classes. */ +#define CURL_ASN1_UNIVERSAL 0 +#define CURL_ASN1_APPLICATION 1 +#define CURL_ASN1_CONTEXT_SPECIFIC 2 +#define CURL_ASN1_PRIVATE 3 + +/* ASN.1 types. */ +#define CURL_ASN1_BOOLEAN 1 +#define CURL_ASN1_INTEGER 2 +#define CURL_ASN1_BIT_STRING 3 +#define CURL_ASN1_OCTET_STRING 4 +#define CURL_ASN1_NULL 5 +#define CURL_ASN1_OBJECT_IDENTIFIER 6 +#define CURL_ASN1_OBJECT_DESCRIPTOR 7 +#define CURL_ASN1_INSTANCE_OF 8 +#define CURL_ASN1_REAL 9 +#define CURL_ASN1_ENUMERATED 10 +#define CURL_ASN1_EMBEDDED 11 +#define CURL_ASN1_UTF8_STRING 12 +#define CURL_ASN1_RELATIVE_OID 13 +#define CURL_ASN1_SEQUENCE 16 +#define CURL_ASN1_SET 17 +#define CURL_ASN1_NUMERIC_STRING 18 +#define CURL_ASN1_PRINTABLE_STRING 19 +#define CURL_ASN1_TELETEX_STRING 20 +#define CURL_ASN1_VIDEOTEX_STRING 21 +#define CURL_ASN1_IA5_STRING 22 +#define CURL_ASN1_UTC_TIME 23 +#define CURL_ASN1_GENERALIZED_TIME 24 +#define CURL_ASN1_GRAPHIC_STRING 25 +#define CURL_ASN1_VISIBLE_STRING 26 +#define CURL_ASN1_GENERAL_STRING 27 +#define CURL_ASN1_UNIVERSAL_STRING 28 +#define CURL_ASN1_CHARACTER_STRING 29 +#define CURL_ASN1_BMP_STRING 30 + +/* Max sixes */ + +#define MAX_X509_STR 10000 +#define MAX_X509_CERT 100000 + +#ifdef WANT_EXTRACT_CERTINFO +/* ASN.1 OID table entry. */ +struct Curl_OID { + const char *numoid; /* Dotted-numeric OID. */ + const char *textoid; /* OID name. */ +}; + +/* ASN.1 OIDs. */ +static const char cnOID[] = "2.5.4.3"; /* Common name. */ +static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */ + +static const struct Curl_OID OIDtable[] = { + { "1.2.840.10040.4.1", "dsa" }, + { "1.2.840.10040.4.3", "dsa-with-sha1" }, + { "1.2.840.10045.2.1", "ecPublicKey" }, + { "1.2.840.10045.3.0.1", "c2pnb163v1" }, + { "1.2.840.10045.4.1", "ecdsa-with-SHA1" }, + { "1.2.840.10046.2.1", "dhpublicnumber" }, + { "1.2.840.113549.1.1.1", "rsaEncryption" }, + { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" }, + { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" }, + { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" }, + { "1.2.840.113549.1.1.10", "RSASSA-PSS" }, + { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" }, + { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" }, + { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" }, + { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" }, + { "1.2.840.113549.2.2", "md2" }, + { "1.2.840.113549.2.5", "md5" }, + { "1.3.14.3.2.26", "sha1" }, + { cnOID, "CN" }, + { "2.5.4.4", "SN" }, + { "2.5.4.5", "serialNumber" }, + { "2.5.4.6", "C" }, + { "2.5.4.7", "L" }, + { "2.5.4.8", "ST" }, + { "2.5.4.9", "streetAddress" }, + { "2.5.4.10", "O" }, + { "2.5.4.11", "OU" }, + { "2.5.4.12", "title" }, + { "2.5.4.13", "description" }, + { "2.5.4.17", "postalCode" }, + { "2.5.4.41", "name" }, + { "2.5.4.42", "givenName" }, + { "2.5.4.43", "initials" }, + { "2.5.4.44", "generationQualifier" }, + { "2.5.4.45", "X500UniqueIdentifier" }, + { "2.5.4.46", "dnQualifier" }, + { "2.5.4.65", "pseudonym" }, + { "1.2.840.113549.1.9.1", "emailAddress" }, + { "2.5.4.72", "role" }, + { sanOID, "subjectAltName" }, + { "2.5.29.18", "issuerAltName" }, + { "2.5.29.19", "basicConstraints" }, + { "2.16.840.1.101.3.4.2.4", "sha224" }, + { "2.16.840.1.101.3.4.2.1", "sha256" }, + { "2.16.840.1.101.3.4.2.2", "sha384" }, + { "2.16.840.1.101.3.4.2.3", "sha512" }, + { (const char *) NULL, (const char *) NULL } +}; + +#endif /* WANT_EXTRACT_CERTINFO */ + +/* + * Lightweight ASN.1 parser. + * In particular, it does not check for syntactic/lexical errors. + * It is intended to support certificate information gathering for SSL backends + * that offer a mean to get certificates as a whole, but do not supply + * entry points to get particular certificate sub-fields. + * Please note there is no pretension here to rewrite a full SSL library. + */ + +static const char *getASN1Element(struct Curl_asn1Element *elem, + const char *beg, const char *end) + WARN_UNUSED_RESULT; + +static const char *getASN1Element(struct Curl_asn1Element *elem, + const char *beg, const char *end) +{ + unsigned char b; + size_t len; + struct Curl_asn1Element lelem; + + /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' + ending at `end'. + Returns a pointer in source string after the parsed element, or NULL + if an error occurs. */ + if(!beg || !end || beg >= end || !*beg || + (size_t)(end - beg) > CURL_ASN1_MAX) + return NULL; + + /* Process header byte. */ + elem->header = beg; + b = (unsigned char) *beg++; + elem->constructed = (b & 0x20) != 0; + elem->class = (b >> 6) & 3; + b &= 0x1F; + if(b == 0x1F) + return NULL; /* Long tag values not supported here. */ + elem->tag = b; + + /* Process length. */ + if(beg >= end) + return NULL; + b = (unsigned char) *beg++; + if(!(b & 0x80)) + len = b; + else if(!(b &= 0x7F)) { + /* Unspecified length. Since we have all the data, we can determine the + effective length by skipping element until an end element is found. */ + if(!elem->constructed) + return NULL; + elem->beg = beg; + while(beg < end && *beg) { + beg = getASN1Element(&lelem, beg, end); + if(!beg) + return NULL; + } + if(beg >= end) + return NULL; + elem->end = beg; + return beg + 1; + } + else if((unsigned)b > (size_t)(end - beg)) + return NULL; /* Does not fit in source. */ + else { + /* Get long length. */ + len = 0; + do { + if(len & 0xFF000000L) + return NULL; /* Lengths > 32 bits are not supported. */ + len = (len << 8) | (unsigned char) *beg++; + } while(--b); + } + if(len > (size_t)(end - beg)) + return NULL; /* Element data does not fit in source. */ + elem->beg = beg; + elem->end = beg + len; + return elem->end; +} + +#ifdef WANT_EXTRACT_CERTINFO + +/* + * Search the null terminated OID or OID identifier in local table. + * Return the table entry pointer or NULL if not found. + */ +static const struct Curl_OID *searchOID(const char *oid) +{ + const struct Curl_OID *op; + for(op = OIDtable; op->numoid; op++) + if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) + return op; + + return NULL; +} + +/* + * Convert an ASN.1 Boolean value into its string representation. + * + * Return error code. + */ + +static CURLcode bool2str(struct dynbuf *store, + const char *beg, const char *end) +{ + if(end - beg != 1) + return CURLE_BAD_FUNCTION_ARGUMENT; + return Curl_dyn_add(store, *beg? "TRUE": "FALSE"); +} + +/* + * Convert an ASN.1 octet string to a printable string. + * + * Return error code. + */ +static CURLcode octet2str(struct dynbuf *store, + const char *beg, const char *end) +{ + CURLcode result = CURLE_OK; + + while(!result && beg < end) + result = Curl_dyn_addf(store, "%02x:", (unsigned char) *beg++); + + return result; +} + +static CURLcode bit2str(struct dynbuf *store, + const char *beg, const char *end) +{ + /* Convert an ASN.1 bit string to a printable string. */ + + if(++beg > end) + return CURLE_BAD_FUNCTION_ARGUMENT; + return octet2str(store, beg, end); +} + +/* + * Convert an ASN.1 integer value into its string representation. + * + * Returns error. + */ +static CURLcode int2str(struct dynbuf *store, + const char *beg, const char *end) +{ + unsigned int val = 0; + size_t n = end - beg; + + if(!n) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(n > 4) + return octet2str(store, beg, end); + + /* Represent integers <= 32-bit as a single value. */ + if(*beg & 0x80) + val = ~val; + + do + val = (val << 8) | *(const unsigned char *) beg++; + while(beg < end); + return Curl_dyn_addf(store, "%s%x", val >= 10? "0x": "", val); +} + +/* + * Convert from an ASN.1 typed string to UTF8. + * + * The result is stored in a dynbuf that is inited by the user of this + * function. + * + * Returns error. + */ +static CURLcode +utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end) +{ + size_t inlength = end - from; + int size = 1; + CURLcode result = CURLE_OK; + + switch(type) { + case CURL_ASN1_BMP_STRING: + size = 2; + break; + case CURL_ASN1_UNIVERSAL_STRING: + size = 4; + break; + case CURL_ASN1_NUMERIC_STRING: + case CURL_ASN1_PRINTABLE_STRING: + case CURL_ASN1_TELETEX_STRING: + case CURL_ASN1_IA5_STRING: + case CURL_ASN1_VISIBLE_STRING: + case CURL_ASN1_UTF8_STRING: + break; + default: + return CURLE_BAD_FUNCTION_ARGUMENT; /* Conversion not supported. */ + } + + if(inlength % size) + /* Length inconsistent with character size. */ + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(type == CURL_ASN1_UTF8_STRING) { + /* Just copy. */ + if(inlength) + result = Curl_dyn_addn(to, from, inlength); + } + else { + while(!result && (from < end)) { + char buf[4]; /* decode buffer */ + int charsize = 1; + unsigned int wc = 0; + + switch(size) { + case 4: + wc = (wc << 8) | *(const unsigned char *) from++; + wc = (wc << 8) | *(const unsigned char *) from++; + FALLTHROUGH(); + case 2: + wc = (wc << 8) | *(const unsigned char *) from++; + FALLTHROUGH(); + default: /* case 1: */ + wc = (wc << 8) | *(const unsigned char *) from++; + } + if(wc >= 0x00000080) { + if(wc >= 0x00000800) { + if(wc >= 0x00010000) { + if(wc >= 0x00200000) { + free(buf); + /* Invalid char. size for target encoding. */ + return CURLE_WEIRD_SERVER_REPLY; + } + buf[3] = (char) (0x80 | (wc & 0x3F)); + wc = (wc >> 6) | 0x00010000; + charsize++; + } + buf[2] = (char) (0x80 | (wc & 0x3F)); + wc = (wc >> 6) | 0x00000800; + charsize++; + } + buf[1] = (char) (0x80 | (wc & 0x3F)); + wc = (wc >> 6) | 0x000000C0; + charsize++; + } + buf[0] = (char) wc; + result = Curl_dyn_addn(to, buf, charsize); + } + } + return result; +} + +/* + * Convert an ASN.1 OID into its dotted string representation. + * + * Return error code. + */ +static CURLcode encodeOID(struct dynbuf *store, + const char *beg, const char *end) +{ + unsigned int x; + unsigned int y; + CURLcode result = CURLE_OK; + + /* Process the first two numbers. */ + y = *(const unsigned char *) beg++; + x = y / 40; + y -= x * 40; + + result = Curl_dyn_addf(store, "%u.%u", x, y); + if(result) + return result; + + /* Process the trailing numbers. */ + while(beg < end) { + x = 0; + do { + if(x & 0xFF000000) + return 0; + y = *(const unsigned char *) beg++; + x = (x << 7) | (y & 0x7F); + } while(y & 0x80); + result = Curl_dyn_addf(store, ".%u", x); + } + return result; +} + +/* + * Convert an ASN.1 OID into its dotted or symbolic string representation. + * + * Return error code. + */ + +static CURLcode OID2str(struct dynbuf *store, + const char *beg, const char *end, bool symbolic) +{ + CURLcode result = CURLE_OK; + if(beg < end) { + if(symbolic) { + struct dynbuf buf; + Curl_dyn_init(&buf, MAX_X509_STR); + result = encodeOID(&buf, beg, end); + + if(!result) { + const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf)); + if(op) + result = Curl_dyn_add(store, op->textoid); + Curl_dyn_free(&buf); + } + } + else + result = encodeOID(store, beg, end); + } + return result; +} + +static CURLcode GTime2str(struct dynbuf *store, + const char *beg, const char *end) +{ + const char *tzp; + const char *fracp; + char sec1, sec2; + size_t fracl; + size_t tzl; + const char *sep = ""; + + /* Convert an ASN.1 Generalized time to a printable string. + Return the dynamically allocated string, or NULL if an error occurs. */ + + for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++) + ; + + /* Get seconds digits. */ + sec1 = '0'; + switch(fracp - beg - 12) { + case 0: + sec2 = '0'; + break; + case 2: + sec1 = fracp[-2]; + FALLTHROUGH(); + case 1: + sec2 = fracp[-1]; + break; + default: + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + /* Scan for timezone, measure fractional seconds. */ + tzp = fracp; + fracl = 0; + if(fracp < end && (*fracp == '.' || *fracp == ',')) { + fracp++; + do + tzp++; + while(tzp < end && *tzp >= '0' && *tzp <= '9'); + /* Strip leading zeroes in fractional seconds. */ + for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--) + ; + } + + /* Process timezone. */ + if(tzp >= end) + ; /* Nothing to do. */ + else if(*tzp == 'Z') { + tzp = " GMT"; + end = tzp + 4; + } + else { + sep = " "; + tzp++; + } + + tzl = end - tzp; + return Curl_dyn_addf(store, + "%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s", + beg, beg + 4, beg + 6, + beg + 8, beg + 10, sec1, sec2, + fracl? ".": "", (int)fracl, fracp, + sep, (int)tzl, tzp); +} + +/* + * Convert an ASN.1 UTC time to a printable string. + * + * Return error code. + */ +static CURLcode UTime2str(struct dynbuf *store, + const char *beg, const char *end) +{ + const char *tzp; + size_t tzl; + const char *sec; + + for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++) + ; + /* Get the seconds. */ + sec = beg + 10; + switch(tzp - sec) { + case 0: + sec = "00"; + FALLTHROUGH(); + case 2: + break; + default: + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + /* Process timezone. */ + if(tzp >= end) + return CURLE_BAD_FUNCTION_ARGUMENT; + if(*tzp == 'Z') { + tzp = "GMT"; + end = tzp + 3; + } + else + tzp++; + + tzl = end - tzp; + return Curl_dyn_addf(store, "%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s", + 20 - (*beg >= '5'), beg, beg + 2, beg + 4, + beg + 6, beg + 8, sec, + (int)tzl, tzp); +} + +/* + * Convert an ASN.1 element to a printable string. + * + * Return error + */ +static CURLcode ASN1tostr(struct dynbuf *store, + struct Curl_asn1Element *elem, int type) +{ + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + if(elem->constructed) + return CURLE_OK; /* No conversion of structured elements. */ + + if(!type) + type = elem->tag; /* Type not forced: use element tag as type. */ + + switch(type) { + case CURL_ASN1_BOOLEAN: + result = bool2str(store, elem->beg, elem->end); + break; + case CURL_ASN1_INTEGER: + case CURL_ASN1_ENUMERATED: + result = int2str(store, elem->beg, elem->end); + break; + case CURL_ASN1_BIT_STRING: + result = bit2str(store, elem->beg, elem->end); + break; + case CURL_ASN1_OCTET_STRING: + result = octet2str(store, elem->beg, elem->end); + break; + case CURL_ASN1_NULL: + result = Curl_dyn_addn(store, "", 1); + break; + case CURL_ASN1_OBJECT_IDENTIFIER: + result = OID2str(store, elem->beg, elem->end, TRUE); + break; + case CURL_ASN1_UTC_TIME: + result = UTime2str(store, elem->beg, elem->end); + break; + case CURL_ASN1_GENERALIZED_TIME: + result = GTime2str(store, elem->beg, elem->end); + break; + case CURL_ASN1_UTF8_STRING: + case CURL_ASN1_NUMERIC_STRING: + case CURL_ASN1_PRINTABLE_STRING: + case CURL_ASN1_TELETEX_STRING: + case CURL_ASN1_IA5_STRING: + case CURL_ASN1_VISIBLE_STRING: + case CURL_ASN1_UNIVERSAL_STRING: + case CURL_ASN1_BMP_STRING: + result = utf8asn1str(store, type, elem->beg, elem->end); + break; + } + + return result; +} + +/* + * ASCII encode distinguished name at `dn' into the store dynbuf. + * + * Returns error. + */ +static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn) +{ + struct Curl_asn1Element rdn; + struct Curl_asn1Element atv; + struct Curl_asn1Element oid; + struct Curl_asn1Element value; + const char *p1; + const char *p2; + const char *p3; + const char *str; + CURLcode result = CURLE_OK; + bool added = FALSE; + struct dynbuf temp; + Curl_dyn_init(&temp, MAX_X509_STR); + + for(p1 = dn->beg; p1 < dn->end;) { + p1 = getASN1Element(&rdn, p1, dn->end); + if(!p1) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } + for(p2 = rdn.beg; p2 < rdn.end;) { + p2 = getASN1Element(&atv, p2, rdn.end); + if(!p2) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } + p3 = getASN1Element(&oid, atv.beg, atv.end); + if(!p3) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } + if(!getASN1Element(&value, p3, atv.end)) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } + Curl_dyn_reset(&temp); + result = ASN1tostr(&temp, &oid, 0); + if(result) + goto error; + + str = Curl_dyn_ptr(&temp); + + /* Encode delimiter. + If attribute has a short uppercase name, delimiter is ", ". */ + for(p3 = str; ISUPPER(*p3); p3++) + ; + if(added) { + if(p3 - str > 2) + result = Curl_dyn_addn(store, "/", 1); + else + result = Curl_dyn_addn(store, ", ", 2); + if(result) + goto error; + } + + /* Encode attribute name. */ + result = Curl_dyn_add(store, str); + if(result) + goto error; + + /* Generate equal sign. */ + result = Curl_dyn_addn(store, "=", 1); + if(result) + goto error; + + /* Generate value. */ + result = ASN1tostr(store, &value, 0); + if(result) + goto error; + Curl_dyn_reset(&temp); + added = TRUE; /* use separator for next */ + } + } +error: + Curl_dyn_free(&temp); + + return result; +} + +#endif /* WANT_EXTRACT_CERTINFO */ + +#ifdef WANT_PARSEX509 +/* + * ASN.1 parse an X509 certificate into structure subfields. + * Syntax is assumed to have already been checked by the SSL backend. + * See RFC 5280. + */ +int Curl_parseX509(struct Curl_X509certificate *cert, + const char *beg, const char *end) +{ + struct Curl_asn1Element elem; + struct Curl_asn1Element tbsCertificate; + const char *ccp; + static const char defaultVersion = 0; /* v1. */ + + cert->certificate.header = NULL; + cert->certificate.beg = beg; + cert->certificate.end = end; + + /* Get the sequence content. */ + if(!getASN1Element(&elem, beg, end)) + return -1; /* Invalid bounds/size. */ + beg = elem.beg; + end = elem.end; + + /* Get tbsCertificate. */ + beg = getASN1Element(&tbsCertificate, beg, end); + if(!beg) + return -1; + /* Skip the signatureAlgorithm. */ + beg = getASN1Element(&cert->signatureAlgorithm, beg, end); + if(!beg) + return -1; + /* Get the signatureValue. */ + if(!getASN1Element(&cert->signature, beg, end)) + return -1; + + /* Parse TBSCertificate. */ + beg = tbsCertificate.beg; + end = tbsCertificate.end; + /* Get optional version, get serialNumber. */ + cert->version.header = NULL; + cert->version.beg = &defaultVersion; + cert->version.end = &defaultVersion + sizeof(defaultVersion); + beg = getASN1Element(&elem, beg, end); + if(!beg) + return -1; + if(elem.tag == 0) { + if(!getASN1Element(&cert->version, elem.beg, elem.end)) + return -1; + beg = getASN1Element(&elem, beg, end); + if(!beg) + return -1; + } + cert->serialNumber = elem; + /* Get signature algorithm. */ + beg = getASN1Element(&cert->signatureAlgorithm, beg, end); + /* Get issuer. */ + beg = getASN1Element(&cert->issuer, beg, end); + if(!beg) + return -1; + /* Get notBefore and notAfter. */ + beg = getASN1Element(&elem, beg, end); + if(!beg) + return -1; + ccp = getASN1Element(&cert->notBefore, elem.beg, elem.end); + if(!ccp) + return -1; + if(!getASN1Element(&cert->notAfter, ccp, elem.end)) + return -1; + /* Get subject. */ + beg = getASN1Element(&cert->subject, beg, end); + if(!beg) + return -1; + /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */ + beg = getASN1Element(&cert->subjectPublicKeyInfo, beg, end); + if(!beg) + return -1; + ccp = getASN1Element(&cert->subjectPublicKeyAlgorithm, + cert->subjectPublicKeyInfo.beg, + cert->subjectPublicKeyInfo.end); + if(!ccp) + return -1; + if(!getASN1Element(&cert->subjectPublicKey, ccp, + cert->subjectPublicKeyInfo.end)) + return -1; + /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ + cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; + cert->extensions.tag = elem.tag = 0; + cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; + cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; + cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; + cert->extensions.header = NULL; + cert->extensions.beg = cert->extensions.end = ""; + if(beg < end) { + beg = getASN1Element(&elem, beg, end); + if(!beg) + return -1; + } + if(elem.tag == 1) { + cert->issuerUniqueID = elem; + if(beg < end) { + beg = getASN1Element(&elem, beg, end); + if(!beg) + return -1; + } + } + if(elem.tag == 2) { + cert->subjectUniqueID = elem; + if(beg < end) { + beg = getASN1Element(&elem, beg, end); + if(!beg) + return -1; + } + } + if(elem.tag == 3) + if(!getASN1Element(&cert->extensions, elem.beg, elem.end)) + return -1; + return 0; +} + +#endif /* WANT_PARSEX509 */ + +#ifdef WANT_EXTRACT_CERTINFO + +static CURLcode dumpAlgo(struct dynbuf *store, + struct Curl_asn1Element *param, + const char *beg, const char *end) +{ + struct Curl_asn1Element oid; + + /* Get algorithm parameters and return algorithm name. */ + + beg = getASN1Element(&oid, beg, end); + if(!beg) + return CURLE_BAD_FUNCTION_ARGUMENT; + param->header = NULL; + param->tag = 0; + param->beg = param->end = end; + if(beg < end) { + const char *p = getASN1Element(param, beg, end); + if(!p) + return CURLE_BAD_FUNCTION_ARGUMENT; + } + return OID2str(store, oid.beg, oid.end, TRUE); +} + +/* + * This is a convenience function for push_certinfo_len that takes a zero + * terminated value. + */ +static CURLcode ssl_push_certinfo(struct Curl_easy *data, + int certnum, + const char *label, + const char *value) +{ + size_t valuelen = strlen(value); + + return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); +} + +/* + * This is a convenience function for push_certinfo_len that takes a + * dynbuf value. + * + * It also does the verbose output if !certnum. + */ +static CURLcode ssl_push_certinfo_dyn(struct Curl_easy *data, + int certnum, + const char *label, + struct dynbuf *ptr) +{ + size_t valuelen = Curl_dyn_len(ptr); + char *value = Curl_dyn_ptr(ptr); + + CURLcode result = Curl_ssl_push_certinfo_len(data, certnum, label, + value, valuelen); + + if(!certnum && !result) + infof(data, " %s: %s", label, value); + + return result; +} + +static CURLcode do_pubkey_field(struct Curl_easy *data, int certnum, + const char *label, + struct Curl_asn1Element *elem) +{ + CURLcode result; + struct dynbuf out; + + Curl_dyn_init(&out, MAX_X509_STR); + + /* Generate a certificate information record for the public key. */ + + result = ASN1tostr(&out, elem, 0); + if(!result) { + if(data->set.ssl.certinfo) + result = ssl_push_certinfo_dyn(data, certnum, label, &out); + Curl_dyn_free(&out); + } + return result; +} + +/* return 0 on success, 1 on error */ +static int do_pubkey(struct Curl_easy *data, int certnum, + const char *algo, struct Curl_asn1Element *param, + struct Curl_asn1Element *pubkey) +{ + struct Curl_asn1Element elem; + struct Curl_asn1Element pk; + const char *p; + + /* Generate all information records for the public key. */ + + if(strcasecompare(algo, "ecPublicKey")) { + /* + * ECC public key is all the data, a value of type BIT STRING mapped to + * OCTET STRING and should not be parsed as an ASN.1 value. + */ + const size_t len = ((pubkey->end - pubkey->beg - 2) * 4); + if(!certnum) + infof(data, " ECC Public Key (%zu bits)", len); + if(data->set.ssl.certinfo) { + char q[sizeof(len) * 8 / 3 + 1]; + (void)msnprintf(q, sizeof(q), "%zu", len); + if(ssl_push_certinfo(data, certnum, "ECC Public Key", q)) + return 1; + } + return do_pubkey_field(data, certnum, "ecPublicKey", pubkey); + } + + /* Get the public key (single element). */ + if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end)) + return 1; + + if(strcasecompare(algo, "rsaEncryption")) { + const char *q; + size_t len; + + p = getASN1Element(&elem, pk.beg, pk.end); + if(!p) + return 1; + + /* Compute key length. */ + for(q = elem.beg; !*q && q < elem.end; q++) + ; + len = ((elem.end - q) * 8); + if(len) { + unsigned int i; + for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1) + len--; + } + if(len > 32) + elem.beg = q; /* Strip leading zero bytes. */ + if(!certnum) + infof(data, " RSA Public Key (%zu bits)", len); + if(data->set.ssl.certinfo) { + char r[sizeof(len) * 8 / 3 + 1]; + msnprintf(r, sizeof(r), "%zu", len); + if(ssl_push_certinfo(data, certnum, "RSA Public Key", r)) + return 1; + } + /* Generate coefficients. */ + if(do_pubkey_field(data, certnum, "rsa(n)", &elem)) + return 1; + if(!getASN1Element(&elem, p, pk.end)) + return 1; + if(do_pubkey_field(data, certnum, "rsa(e)", &elem)) + return 1; + } + else if(strcasecompare(algo, "dsa")) { + p = getASN1Element(&elem, param->beg, param->end); + if(p) { + if(do_pubkey_field(data, certnum, "dsa(p)", &elem)) + return 1; + p = getASN1Element(&elem, p, param->end); + if(p) { + if(do_pubkey_field(data, certnum, "dsa(q)", &elem)) + return 1; + if(getASN1Element(&elem, p, param->end)) { + if(do_pubkey_field(data, certnum, "dsa(g)", &elem)) + return 1; + if(do_pubkey_field(data, certnum, "dsa(pub_key)", &pk)) + return 1; + } + } + } + } + else if(strcasecompare(algo, "dhpublicnumber")) { + p = getASN1Element(&elem, param->beg, param->end); + if(p) { + if(do_pubkey_field(data, certnum, "dh(p)", &elem)) + return 1; + if(getASN1Element(&elem, param->beg, param->end)) { + if(do_pubkey_field(data, certnum, "dh(g)", &elem)) + return 1; + if(do_pubkey_field(data, certnum, "dh(pub_key)", &pk)) + return 1; + } + } + } + return 0; +} + +/* + * Convert an ASN.1 distinguished name into a printable string. + * Return error. + */ +static CURLcode DNtostr(struct dynbuf *store, + struct Curl_asn1Element *dn) +{ + return encodeDN(store, dn); +} + +CURLcode Curl_extract_certinfo(struct Curl_easy *data, + int certnum, + const char *beg, + const char *end) +{ + struct Curl_X509certificate cert; + struct Curl_asn1Element param; + char *certptr; + size_t clen; + struct dynbuf out; + CURLcode result = CURLE_OK; + unsigned int version; + const char *ptr; + int rc; + + if(!data->set.ssl.certinfo) + if(certnum) + return CURLE_OK; + + Curl_dyn_init(&out, MAX_X509_STR); + /* Prepare the certificate information for curl_easy_getinfo(). */ + + /* Extract the certificate ASN.1 elements. */ + if(Curl_parseX509(&cert, beg, end)) + return CURLE_PEER_FAILED_VERIFICATION; + + /* Subject. */ + result = DNtostr(&out, &cert.subject); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Subject", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); + + /* Issuer. */ + result = DNtostr(&out, &cert.issuer); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Issuer", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); + + /* Version (always fits in less than 32 bits). */ + version = 0; + for(ptr = cert.version.beg; ptr < cert.version.end; ptr++) + version = (version << 8) | *(const unsigned char *) ptr; + if(data->set.ssl.certinfo) { + result = Curl_dyn_addf(&out, "%x", version); + if(result) + goto done; + result = ssl_push_certinfo_dyn(data, certnum, "Version", &out); + if(result) + goto done; + Curl_dyn_reset(&out); + } + + /* Serial number. */ + result = ASN1tostr(&out, &cert.serialNumber, 0); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Serial Number", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); + + /* Signature algorithm .*/ + result = dumpAlgo(&out, ¶m, cert.signatureAlgorithm.beg, + cert.signatureAlgorithm.end); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Signature Algorithm", + &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); + + /* Start Date. */ + result = ASN1tostr(&out, &cert.notBefore, 0); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Start Date", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); + + /* Expire Date. */ + result = ASN1tostr(&out, &cert.notAfter, 0); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Expire Date", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); + + /* Public Key Algorithm. */ + result = dumpAlgo(&out, ¶m, cert.subjectPublicKeyAlgorithm.beg, + cert.subjectPublicKeyAlgorithm.end); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Public Key Algorithm", + &out); + if(result) + goto done; + } + + rc = do_pubkey(data, certnum, Curl_dyn_ptr(&out), + ¶m, &cert.subjectPublicKey); + if(rc) { + result = CURLE_OUT_OF_MEMORY; /* the most likely error */ + goto done; + } + Curl_dyn_reset(&out); + + /* Signature. */ + result = ASN1tostr(&out, &cert.signature, 0); + if(result) + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Signature", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); + + /* Generate PEM certificate. */ + result = Curl_base64_encode(cert.certificate.beg, + cert.certificate.end - cert.certificate.beg, + &certptr, &clen); + if(result) + goto done; + + /* Generate the final output certificate string. Format is: + -----BEGIN CERTIFICATE-----\n + \n + . + . + . + -----END CERTIFICATE-----\n + */ + + Curl_dyn_reset(&out); + + /* Build the certificate string. */ + result = Curl_dyn_add(&out, "-----BEGIN CERTIFICATE-----\n"); + if(!result) { + size_t j = 0; + + while(!result && (j < clen)) { + size_t chunksize = (clen - j) > 64 ? 64 : (clen - j); + result = Curl_dyn_addn(&out, &certptr[j], chunksize); + if(!result) + result = Curl_dyn_addn(&out, "\n", 1); + j += chunksize; + } + if(!result) + result = Curl_dyn_add(&out, "-----END CERTIFICATE-----\n"); + } + free(certptr); + if(!result) + if(data->set.ssl.certinfo) + result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out); + +done: + Curl_dyn_free(&out); + return result; +} + +#endif /* WANT_EXTRACT_CERTINFO */ + +#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */ diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h new file mode 100644 index 0000000..23a67b8 --- /dev/null +++ b/lib/vtls/x509asn1.h @@ -0,0 +1,80 @@ +#ifndef HEADER_CURL_X509ASN1_H +#define HEADER_CURL_X509ASN1_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \ + defined(USE_SCHANNEL) || defined(USE_SECTRANSP) + +#include "cfilters.h" +#include "urldata.h" + +/* + * Types. + */ + +/* ASN.1 parsed element. */ +struct Curl_asn1Element { + const char *header; /* Pointer to header byte. */ + const char *beg; /* Pointer to element data. */ + const char *end; /* Pointer to 1st byte after element. */ + unsigned char class; /* ASN.1 element class. */ + unsigned char tag; /* ASN.1 element tag. */ + bool constructed; /* Element is constructed. */ +}; + +/* X509 certificate: RFC 5280. */ +struct Curl_X509certificate { + struct Curl_asn1Element certificate; + struct Curl_asn1Element version; + struct Curl_asn1Element serialNumber; + struct Curl_asn1Element signatureAlgorithm; + struct Curl_asn1Element signature; + struct Curl_asn1Element issuer; + struct Curl_asn1Element notBefore; + struct Curl_asn1Element notAfter; + struct Curl_asn1Element subject; + struct Curl_asn1Element subjectPublicKeyInfo; + struct Curl_asn1Element subjectPublicKeyAlgorithm; + struct Curl_asn1Element subjectPublicKey; + struct Curl_asn1Element issuerUniqueID; + struct Curl_asn1Element subjectUniqueID; + struct Curl_asn1Element extensions; +}; + +/* + * Prototypes. + */ + +int Curl_parseX509(struct Curl_X509certificate *cert, + const char *beg, const char *end); +CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum, + const char *beg, const char *end); +CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data, + const char *beg, const char *end); +#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */ +#endif /* HEADER_CURL_X509ASN1_H */ diff --git a/lib/warnless.c b/lib/warnless.c new file mode 100644 index 0000000..c80937b --- /dev/null +++ b/lib/warnless.c @@ -0,0 +1,386 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(__INTEL_COMPILER) && defined(__unix__) + +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#endif /* __INTEL_COMPILER && __unix__ */ + +#include "warnless.h" + +#ifdef _WIN32 +#undef read +#undef write +#endif + +#include + +#define CURL_MASK_UCHAR ((unsigned char)~0) +#define CURL_MASK_SCHAR (CURL_MASK_UCHAR >> 1) + +#define CURL_MASK_USHORT ((unsigned short)~0) +#define CURL_MASK_SSHORT (CURL_MASK_USHORT >> 1) + +#define CURL_MASK_UINT ((unsigned int)~0) +#define CURL_MASK_SINT (CURL_MASK_UINT >> 1) + +#define CURL_MASK_ULONG ((unsigned long)~0) +#define CURL_MASK_SLONG (CURL_MASK_ULONG >> 1) + +#define CURL_MASK_UCOFFT ((unsigned CURL_TYPEOF_CURL_OFF_T)~0) +#define CURL_MASK_SCOFFT (CURL_MASK_UCOFFT >> 1) + +#define CURL_MASK_USIZE_T ((size_t)~0) +#define CURL_MASK_SSIZE_T (CURL_MASK_USIZE_T >> 1) + +/* +** unsigned long to unsigned short +*/ + +unsigned short curlx_ultous(unsigned long ulnum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT); + return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned long to unsigned char +*/ + +unsigned char curlx_ultouc(unsigned long ulnum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR); + return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned size_t to signed curl_off_t +*/ + +curl_off_t curlx_uztoso(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable:4310) /* cast truncates constant value */ +#endif + + DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT); + return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT); + +#if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# pragma warning(pop) +#endif +} + +/* +** unsigned size_t to signed int +*/ + +int curlx_uztosi(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT); + return (int)(uznum & (size_t) CURL_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned size_t to unsigned long +*/ + +unsigned long curlx_uztoul(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + +#if ULONG_MAX < SIZE_T_MAX + DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG); +#endif + return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned size_t to unsigned int +*/ + +unsigned int curlx_uztoui(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + +#if UINT_MAX < SIZE_T_MAX + DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT); +#endif + return (unsigned int)(uznum & (size_t) CURL_MASK_UINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** signed long to signed int +*/ + +int curlx_sltosi(long slnum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(slnum >= 0); +#if INT_MAX < LONG_MAX + DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT); +#endif + return (int)(slnum & (long) CURL_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** signed long to unsigned int +*/ + +unsigned int curlx_sltoui(long slnum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(slnum >= 0); +#if UINT_MAX < LONG_MAX + DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT); +#endif + return (unsigned int)(slnum & (long) CURL_MASK_UINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** signed long to unsigned short +*/ + +unsigned short curlx_sltous(long slnum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(slnum >= 0); + DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT); + return (unsigned short)(slnum & (long) CURL_MASK_USHORT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned size_t to signed ssize_t +*/ + +ssize_t curlx_uztosz(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T); + return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** signed curl_off_t to unsigned size_t +*/ + +size_t curlx_sotouz(curl_off_t sonum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(sonum >= 0); + return (size_t)(sonum & (curl_off_t) CURL_MASK_USIZE_T); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** signed ssize_t to signed int +*/ + +int curlx_sztosi(ssize_t sznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(sznum >= 0); +#if INT_MAX < SSIZE_T_MAX + DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT); +#endif + return (int)(sznum & (ssize_t) CURL_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned int to unsigned short +*/ + +unsigned short curlx_uitous(unsigned int uinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT); + return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** signed int to unsigned size_t +*/ + +size_t curlx_sitouz(int sinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(sinum >= 0); + return (size_t) sinum; + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +#ifdef USE_WINSOCK + +/* +** curl_socket_t to signed int +*/ + +int curlx_sktosi(curl_socket_t s) +{ + return (int)((ssize_t) s); +} + +/* +** signed int to curl_socket_t +*/ + +curl_socket_t curlx_sitosk(int i) +{ + return (curl_socket_t)((ssize_t) i); +} + +#endif /* USE_WINSOCK */ + +#if defined(_WIN32) + +ssize_t curlx_read(int fd, void *buf, size_t count) +{ + return (ssize_t)read(fd, buf, curlx_uztoui(count)); +} + +ssize_t curlx_write(int fd, const void *buf, size_t count) +{ + return (ssize_t)write(fd, buf, curlx_uztoui(count)); +} + +#endif /* _WIN32 */ + +/* Ensure that warnless.h redefinitions continue to have an effect + in "unity" builds. */ +#undef HEADER_CURL_WARNLESS_H_REDEFS diff --git a/lib/warnless.h b/lib/warnless.h new file mode 100644 index 0000000..e5a02c8 --- /dev/null +++ b/lib/warnless.h @@ -0,0 +1,106 @@ +#ifndef HEADER_CURL_WARNLESS_H +#define HEADER_CURL_WARNLESS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_WINSOCK +#include /* for curl_socket_t */ +#endif + +#define CURLX_FUNCTION_CAST(target_type, func) \ + (target_type)(void (*) (void))(func) + +unsigned short curlx_ultous(unsigned long ulnum); + +unsigned char curlx_ultouc(unsigned long ulnum); + +int curlx_uztosi(size_t uznum); + +curl_off_t curlx_uztoso(size_t uznum); + +unsigned long curlx_uztoul(size_t uznum); + +unsigned int curlx_uztoui(size_t uznum); + +int curlx_sltosi(long slnum); + +unsigned int curlx_sltoui(long slnum); + +unsigned short curlx_sltous(long slnum); + +ssize_t curlx_uztosz(size_t uznum); + +size_t curlx_sotouz(curl_off_t sonum); + +int curlx_sztosi(ssize_t sznum); + +unsigned short curlx_uitous(unsigned int uinum); + +size_t curlx_sitouz(int sinum); + +#ifdef USE_WINSOCK + +int curlx_sktosi(curl_socket_t s); + +curl_socket_t curlx_sitosk(int i); + +#endif /* USE_WINSOCK */ + +#if defined(_WIN32) + +ssize_t curlx_read(int fd, void *buf, size_t count); + +ssize_t curlx_write(int fd, const void *buf, size_t count); + +#endif /* _WIN32 */ + +#if defined(__INTEL_COMPILER) && defined(__unix__) + +int curlx_FD_ISSET(int fd, fd_set *fdset); + +void curlx_FD_SET(int fd, fd_set *fdset); + +void curlx_FD_ZERO(fd_set *fdset); + +unsigned short curlx_htons(unsigned short usnum); + +unsigned short curlx_ntohs(unsigned short usnum); + +#endif /* __INTEL_COMPILER && __unix__ */ + +#endif /* HEADER_CURL_WARNLESS_H */ + +#ifndef HEADER_CURL_WARNLESS_H_REDEFS +#define HEADER_CURL_WARNLESS_H_REDEFS + +#if defined(_WIN32) +#undef read +#define read(fd, buf, count) curlx_read(fd, buf, count) +#undef write +#define write(fd, buf, count) curlx_write(fd, buf, count) +#endif + +#endif /* HEADER_CURL_WARNLESS_H_REDEFS */ diff --git a/lib/ws.c b/lib/ws.c new file mode 100644 index 0000000..d976518 --- /dev/null +++ b/lib/ws.c @@ -0,0 +1,1260 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" +#include + +#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) + +#include "urldata.h" +#include "bufq.h" +#include "dynbuf.h" +#include "rand.h" +#include "curl_base64.h" +#include "connect.h" +#include "sendf.h" +#include "multiif.h" +#include "ws.h" +#include "easyif.h" +#include "transfer.h" +#include "nonblock.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +#define WSBIT_FIN 0x80 +#define WSBIT_OPCODE_CONT 0 +#define WSBIT_OPCODE_TEXT (1) +#define WSBIT_OPCODE_BIN (2) +#define WSBIT_OPCODE_CLOSE (8) +#define WSBIT_OPCODE_PING (9) +#define WSBIT_OPCODE_PONG (0xa) +#define WSBIT_OPCODE_MASK (0xf) + +#define WSBIT_MASK 0x80 + +/* buffer dimensioning */ +#define WS_CHUNK_SIZE 65535 +#define WS_CHUNK_COUNT 2 + +struct ws_frame_meta { + char proto_opcode; + int flags; + const char *name; +}; + +static struct ws_frame_meta WS_FRAMES[] = { + { WSBIT_OPCODE_CONT, CURLWS_CONT, "CONT" }, + { WSBIT_OPCODE_TEXT, CURLWS_TEXT, "TEXT" }, + { WSBIT_OPCODE_BIN, CURLWS_BINARY, "BIN" }, + { WSBIT_OPCODE_CLOSE, CURLWS_CLOSE, "CLOSE" }, + { WSBIT_OPCODE_PING, CURLWS_PING, "PING" }, + { WSBIT_OPCODE_PONG, CURLWS_PONG, "PONG" }, +}; + +static const char *ws_frame_name_of_op(unsigned char proto_opcode) +{ + unsigned char opcode = proto_opcode & WSBIT_OPCODE_MASK; + size_t i; + for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) { + if(WS_FRAMES[i].proto_opcode == opcode) + return WS_FRAMES[i].name; + } + return "???"; +} + +static int ws_frame_op2flags(unsigned char proto_opcode) +{ + unsigned char opcode = proto_opcode & WSBIT_OPCODE_MASK; + size_t i; + for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) { + if(WS_FRAMES[i].proto_opcode == opcode) + return WS_FRAMES[i].flags; + } + return 0; +} + +static unsigned char ws_frame_flags2op(int flags) +{ + size_t i; + for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) { + if(WS_FRAMES[i].flags & flags) + return WS_FRAMES[i].proto_opcode; + } + return 0; +} + +static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data, + const char *msg) +{ + switch(dec->head_len) { + case 0: + break; + case 1: + infof(data, "WS-DEC: %s [%s%s]", msg, + ws_frame_name_of_op(dec->head[0]), + (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL"); + break; + default: + if(dec->head_len < dec->head_total) { + infof(data, "WS-DEC: %s [%s%s](%d/%d)", msg, + ws_frame_name_of_op(dec->head[0]), + (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL", + dec->head_len, dec->head_total); + } + else { + infof(data, "WS-DEC: %s [%s%s payload=%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "]", + msg, ws_frame_name_of_op(dec->head[0]), + (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL", + dec->payload_offset, dec->payload_len); + } + break; + } +} + +typedef ssize_t ws_write_payload(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *userp, + CURLcode *err); + + +static void ws_dec_reset(struct ws_decoder *dec) +{ + dec->frame_age = 0; + dec->frame_flags = 0; + dec->payload_offset = 0; + dec->payload_len = 0; + dec->head_len = dec->head_total = 0; + dec->state = WS_DEC_INIT; +} + +static void ws_dec_init(struct ws_decoder *dec) +{ + ws_dec_reset(dec); +} + +static CURLcode ws_dec_read_head(struct ws_decoder *dec, + struct Curl_easy *data, + struct bufq *inraw) +{ + const unsigned char *inbuf; + size_t inlen; + + while(Curl_bufq_peek(inraw, &inbuf, &inlen)) { + if(dec->head_len == 0) { + dec->head[0] = *inbuf; + Curl_bufq_skip(inraw, 1); + + dec->frame_flags = ws_frame_op2flags(dec->head[0]); + if(!dec->frame_flags) { + failf(data, "WS: unknown opcode: %x", dec->head[0]); + ws_dec_reset(dec); + return CURLE_RECV_ERROR; + } + dec->head_len = 1; + /* ws_dec_info(dec, data, "seeing opcode"); */ + continue; + } + else if(dec->head_len == 1) { + dec->head[1] = *inbuf; + Curl_bufq_skip(inraw, 1); + dec->head_len = 2; + + if(dec->head[1] & WSBIT_MASK) { + /* A client MUST close a connection if it detects a masked frame. */ + failf(data, "WS: masked input frame"); + ws_dec_reset(dec); + return CURLE_RECV_ERROR; + } + /* How long is the frame head? */ + if(dec->head[1] == 126) { + dec->head_total = 4; + continue; + } + else if(dec->head[1] == 127) { + dec->head_total = 10; + continue; + } + else { + dec->head_total = 2; + } + } + + if(dec->head_len < dec->head_total) { + dec->head[dec->head_len] = *inbuf; + Curl_bufq_skip(inraw, 1); + ++dec->head_len; + if(dec->head_len < dec->head_total) { + /* ws_dec_info(dec, data, "decoding head"); */ + continue; + } + } + /* got the complete frame head */ + DEBUGASSERT(dec->head_len == dec->head_total); + switch(dec->head_total) { + case 2: + dec->payload_len = dec->head[1]; + break; + case 4: + dec->payload_len = (dec->head[2] << 8) | dec->head[3]; + break; + case 10: + if(dec->head[2] > 127) { + failf(data, "WS: frame length longer than 64 signed not supported"); + return CURLE_RECV_ERROR; + } + dec->payload_len = ((curl_off_t)dec->head[2] << 56) | + (curl_off_t)dec->head[3] << 48 | + (curl_off_t)dec->head[4] << 40 | + (curl_off_t)dec->head[5] << 32 | + (curl_off_t)dec->head[6] << 24 | + (curl_off_t)dec->head[7] << 16 | + (curl_off_t)dec->head[8] << 8 | + dec->head[9]; + break; + default: + /* this should never happen */ + DEBUGASSERT(0); + failf(data, "WS: unexpected frame header length"); + return CURLE_RECV_ERROR; + } + + dec->frame_age = 0; + dec->payload_offset = 0; + ws_dec_info(dec, data, "decoded"); + return CURLE_OK; + } + return CURLE_AGAIN; +} + +static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, + struct Curl_easy *data, + struct bufq *inraw, + ws_write_payload *write_payload, + void *write_ctx) +{ + const unsigned char *inbuf; + size_t inlen; + ssize_t nwritten; + CURLcode result; + curl_off_t remain = dec->payload_len - dec->payload_offset; + + (void)data; + while(remain && Curl_bufq_peek(inraw, &inbuf, &inlen)) { + if((curl_off_t)inlen > remain) + inlen = (size_t)remain; + nwritten = write_payload(inbuf, inlen, dec->frame_age, dec->frame_flags, + dec->payload_offset, dec->payload_len, + write_ctx, &result); + if(nwritten < 0) + return result; + Curl_bufq_skip(inraw, (size_t)nwritten); + dec->payload_offset += (curl_off_t)nwritten; + remain = dec->payload_len - dec->payload_offset; + /* infof(data, "WS-DEC: passed %zd bytes payload, %" + CURL_FORMAT_CURL_OFF_T " remain", + nwritten, remain); */ + } + + return remain? CURLE_AGAIN : CURLE_OK; +} + +static CURLcode ws_dec_pass(struct ws_decoder *dec, + struct Curl_easy *data, + struct bufq *inraw, + ws_write_payload *write_payload, + void *write_ctx) +{ + CURLcode result; + + if(Curl_bufq_is_empty(inraw)) + return CURLE_AGAIN; + + switch(dec->state) { + case WS_DEC_INIT: + ws_dec_reset(dec); + dec->state = WS_DEC_HEAD; + FALLTHROUGH(); + case WS_DEC_HEAD: + result = ws_dec_read_head(dec, data, inraw); + if(result) { + if(result != CURLE_AGAIN) { + infof(data, "WS: decode error %d", (int)result); + break; /* real error */ + } + /* incomplete ws frame head */ + DEBUGASSERT(Curl_bufq_is_empty(inraw)); + break; + } + /* head parsing done */ + dec->state = WS_DEC_PAYLOAD; + if(dec->payload_len == 0) { + ssize_t nwritten; + const unsigned char tmp = '\0'; + /* special case of a 0 length frame, need to write once */ + nwritten = write_payload(&tmp, 0, dec->frame_age, dec->frame_flags, + 0, 0, write_ctx, &result); + if(nwritten < 0) + return result; + dec->state = WS_DEC_INIT; + break; + } + FALLTHROUGH(); + case WS_DEC_PAYLOAD: + result = ws_dec_pass_payload(dec, data, inraw, write_payload, write_ctx); + ws_dec_info(dec, data, "passing"); + if(result) + return result; + /* paylod parsing done */ + dec->state = WS_DEC_INIT; + break; + default: + /* we covered all enums above, but some code analyzers are whimps */ + result = CURLE_FAILED_INIT; + } + return result; +} + +static void update_meta(struct websocket *ws, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + size_t cur_len) +{ + ws->frame.age = frame_age; + ws->frame.flags = frame_flags; + ws->frame.offset = payload_offset; + ws->frame.len = cur_len; + ws->frame.bytesleft = (payload_len - payload_offset - cur_len); +} + +/* WebSockets decoding client writer */ +struct ws_cw_ctx { + struct Curl_cwriter super; + struct bufq buf; +}; + +static CURLcode ws_cw_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct ws_cw_ctx *ctx = (struct ws_cw_ctx *)writer; + (void)data; + Curl_bufq_init2(&ctx->buf, WS_CHUNK_SIZE, 1, BUFQ_OPT_SOFT_LIMIT); + return CURLE_OK; +} + +static void ws_cw_close(struct Curl_easy *data, struct Curl_cwriter *writer) +{ + struct ws_cw_ctx *ctx = (struct ws_cw_ctx *)writer; + (void) data; + Curl_bufq_free(&ctx->buf); +} + +struct ws_cw_dec_ctx { + struct Curl_easy *data; + struct websocket *ws; + struct Curl_cwriter *next_writer; + int cw_type; +}; + +static ssize_t ws_cw_dec_next(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *user_data, + CURLcode *err) +{ + struct ws_cw_dec_ctx *ctx = user_data; + struct Curl_easy *data = ctx->data; + struct websocket *ws = ctx->ws; + curl_off_t remain = (payload_len - (payload_offset + buflen)); + + (void)frame_age; + if((frame_flags & CURLWS_PING) && !remain) { + /* auto-respond to PINGs, only works for single-frame payloads atm */ + size_t bytes; + infof(data, "WS: auto-respond to PING with a PONG"); + /* send back the exact same content as a PONG */ + *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG); + if(*err) + return -1; + } + else if(buflen || !remain) { + /* forward the decoded frame to the next client writer. */ + update_meta(ws, frame_age, frame_flags, payload_offset, + payload_len, buflen); + + *err = Curl_cwriter_write(data, ctx->next_writer, ctx->cw_type, + (const char *)buf, buflen); + if(*err) + return -1; + } + *err = CURLE_OK; + return (ssize_t)buflen; +} + +static CURLcode ws_cw_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + struct ws_cw_ctx *ctx = (struct ws_cw_ctx *)writer; + struct websocket *ws; + CURLcode result; + + if(!(type & CLIENTWRITE_BODY) || data->set.ws_raw_mode) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + ws = data->conn->proto.ws; + if(!ws) { + failf(data, "WS: not a websocket transfer"); + return CURLE_FAILED_INIT; + } + + if(nbytes) { + ssize_t nwritten; + nwritten = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf, + nbytes, &result); + if(nwritten < 0) { + infof(data, "WS: error adding data to buffer %d", result); + return result; + } + } + + while(!Curl_bufq_is_empty(&ctx->buf)) { + struct ws_cw_dec_ctx pass_ctx; + pass_ctx.data = data; + pass_ctx.ws = ws; + pass_ctx.next_writer = writer->next; + pass_ctx.cw_type = type; + result = ws_dec_pass(&ws->dec, data, &ctx->buf, + ws_cw_dec_next, &pass_ctx); + if(result == CURLE_AGAIN) + /* insufficient amount of data, keep it for later. + * we pretend to have written all since we have a copy */ + return CURLE_OK; + else if(result) { + infof(data, "WS: decode error %d", (int)result); + return result; + } + } + + if((type & CLIENTWRITE_EOS) && !Curl_bufq_is_empty(&ctx->buf)) { + infof(data, "WS: decode ending with %zd frame bytes remaining", + Curl_bufq_len(&ctx->buf)); + return CURLE_RECV_ERROR; + } + + return CURLE_OK; +} + +/* WebSocket payload decoding client writer. */ +static const struct Curl_cwtype ws_cw_decode = { + "ws-decode", + NULL, + ws_cw_init, + ws_cw_write, + ws_cw_close, + sizeof(struct ws_cw_ctx) +}; + + +static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data, + const char *msg) +{ + infof(data, "WS-ENC: %s [%s%s%s payload=%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "]", + msg, ws_frame_name_of_op(enc->firstbyte), + (enc->firstbyte & WSBIT_OPCODE_MASK) == WSBIT_OPCODE_CONT ? + " CONT" : "", + (enc->firstbyte & WSBIT_FIN)? "" : " NON-FIN", + enc->payload_len - enc->payload_remain, enc->payload_len); +} + +static void ws_enc_reset(struct ws_encoder *enc) +{ + enc->payload_remain = 0; + enc->xori = 0; + enc->contfragment = FALSE; +} + +static void ws_enc_init(struct ws_encoder *enc) +{ + ws_enc_reset(enc); +} + +/*** + RFC 6455 Section 5.2 + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/64) | + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ +*/ + +static ssize_t ws_enc_write_head(struct Curl_easy *data, + struct ws_encoder *enc, + unsigned int flags, + curl_off_t payload_len, + struct bufq *out, + CURLcode *err) +{ + unsigned char firstbyte = 0; + unsigned char opcode; + unsigned char head[14]; + size_t hlen; + ssize_t n; + + if(payload_len < 0) { + failf(data, "WS: starting new frame with negative payload length %" + CURL_FORMAT_CURL_OFF_T, payload_len); + *err = CURLE_SEND_ERROR; + return -1; + } + + if(enc->payload_remain > 0) { + /* trying to write a new frame before the previous one is finished */ + failf(data, "WS: starting new frame with %zd bytes from last one" + "remaining to be sent", (ssize_t)enc->payload_remain); + *err = CURLE_SEND_ERROR; + return -1; + } + + opcode = ws_frame_flags2op(flags); + if(!opcode) { + failf(data, "WS: provided flags not recognized '%x'", flags); + *err = CURLE_SEND_ERROR; + return -1; + } + + if(!(flags & CURLWS_CONT)) { + if(!enc->contfragment) + /* not marked as continuing, this is the final fragment */ + firstbyte |= WSBIT_FIN | opcode; + else + /* marked as continuing, this is the final fragment; set CONT + opcode and FIN bit */ + firstbyte |= WSBIT_FIN | WSBIT_OPCODE_CONT; + + enc->contfragment = FALSE; + } + else if(enc->contfragment) { + /* the previous fragment was not a final one and this isn't either, keep a + CONT opcode and no FIN bit */ + firstbyte |= WSBIT_OPCODE_CONT; + } + else { + firstbyte = opcode; + enc->contfragment = TRUE; + } + + head[0] = enc->firstbyte = firstbyte; + if(payload_len > 65535) { + head[1] = 127 | WSBIT_MASK; + head[2] = (unsigned char)((payload_len >> 56) & 0xff); + head[3] = (unsigned char)((payload_len >> 48) & 0xff); + head[4] = (unsigned char)((payload_len >> 40) & 0xff); + head[5] = (unsigned char)((payload_len >> 32) & 0xff); + head[6] = (unsigned char)((payload_len >> 24) & 0xff); + head[7] = (unsigned char)((payload_len >> 16) & 0xff); + head[8] = (unsigned char)((payload_len >> 8) & 0xff); + head[9] = (unsigned char)(payload_len & 0xff); + hlen = 10; + } + else if(payload_len >= 126) { + head[1] = 126 | WSBIT_MASK; + head[2] = (unsigned char)((payload_len >> 8) & 0xff); + head[3] = (unsigned char)(payload_len & 0xff); + hlen = 4; + } + else { + head[1] = (unsigned char)payload_len | WSBIT_MASK; + hlen = 2; + } + + enc->payload_remain = enc->payload_len = payload_len; + ws_enc_info(enc, data, "sending"); + + /* add 4 bytes mask */ + memcpy(&head[hlen], &enc->mask, 4); + hlen += 4; + /* reset for payload to come */ + enc->xori = 0; + + n = Curl_bufq_write(out, head, hlen, err); + if(n < 0) + return -1; + if((size_t)n != hlen) { + /* We use a bufq with SOFT_LIMIT, writing should always succeed */ + DEBUGASSERT(0); + *err = CURLE_SEND_ERROR; + return -1; + } + return n; +} + +static ssize_t ws_enc_write_payload(struct ws_encoder *enc, + struct Curl_easy *data, + const unsigned char *buf, size_t buflen, + struct bufq *out, CURLcode *err) +{ + ssize_t n; + size_t i, len; + + if(Curl_bufq_is_full(out)) { + *err = CURLE_AGAIN; + return -1; + } + + /* not the most performant way to do this */ + len = buflen; + if((curl_off_t)len > enc->payload_remain) + len = (size_t)enc->payload_remain; + + for(i = 0; i < len; ++i) { + unsigned char c = buf[i] ^ enc->mask[enc->xori]; + n = Curl_bufq_write(out, &c, 1, err); + if(n < 0) { + if((*err != CURLE_AGAIN) || !i) + return -1; + break; + } + enc->xori++; + enc->xori &= 3; + } + enc->payload_remain -= (curl_off_t)i; + ws_enc_info(enc, data, "buffered"); + return (ssize_t)i; +} + + +struct wsfield { + const char *name; + const char *val; +}; + +CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req) +{ + unsigned int i; + CURLcode result = CURLE_OK; + unsigned char rand[16]; + char *randstr; + size_t randlen; + char keyval[40]; + struct SingleRequest *k = &data->req; + struct wsfield heads[]= { + { + /* The request MUST contain an |Upgrade| header field whose value + MUST include the "websocket" keyword. */ + "Upgrade:", "websocket" + }, + { + /* The request MUST contain a |Connection| header field whose value + MUST include the "Upgrade" token. */ + "Connection:", "Upgrade", + }, + { + /* The request MUST include a header field with the name + |Sec-WebSocket-Version|. The value of this header field MUST be + 13. */ + "Sec-WebSocket-Version:", "13", + }, + { + /* The request MUST include a header field with the name + |Sec-WebSocket-Key|. The value of this header field MUST be a nonce + consisting of a randomly selected 16-byte value that has been + base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be + selected randomly for each connection. */ + "Sec-WebSocket-Key:", NULL, + } + }; + heads[3].val = &keyval[0]; + + /* 16 bytes random */ + result = Curl_rand(data, (unsigned char *)rand, sizeof(rand)); + if(result) + return result; + result = Curl_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen); + if(result) + return result; + DEBUGASSERT(randlen < sizeof(keyval)); + if(randlen >= sizeof(keyval)) + return CURLE_FAILED_INIT; + strcpy(keyval, randstr); + free(randstr); + for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) { + if(!Curl_checkheaders(data, STRCONST(heads[i].name))) { +#ifdef USE_HYPER + char field[128]; + msnprintf(field, sizeof(field), "%s %s", heads[i].name, + heads[i].val); + result = Curl_hyper_header(data, req, field); +#else + (void)data; + result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name, + heads[i].val); +#endif + } + } + k->upgr101 = UPGR101_WS; + return result; +} + +/* + * 'nread' is number of bytes of websocket data already in the buffer at + * 'mem'. + */ +CURLcode Curl_ws_accept(struct Curl_easy *data, + const char *mem, size_t nread) +{ + struct SingleRequest *k = &data->req; + struct websocket *ws; + struct Curl_cwriter *ws_dec_writer; + CURLcode result; + + DEBUGASSERT(data->conn); + ws = data->conn->proto.ws; + if(!ws) { + ws = calloc(1, sizeof(*ws)); + if(!ws) + return CURLE_OUT_OF_MEMORY; + data->conn->proto.ws = ws; + Curl_bufq_init2(&ws->recvbuf, WS_CHUNK_SIZE, WS_CHUNK_COUNT, + BUFQ_OPT_SOFT_LIMIT); + Curl_bufq_init2(&ws->sendbuf, WS_CHUNK_SIZE, WS_CHUNK_COUNT, + BUFQ_OPT_SOFT_LIMIT); + ws_dec_init(&ws->dec); + ws_enc_init(&ws->enc); + } + else { + Curl_bufq_reset(&ws->recvbuf); + ws_dec_reset(&ws->dec); + ws_enc_reset(&ws->enc); + } + /* Verify the Sec-WebSocket-Accept response. + + The sent value is the base64 encoded version of a SHA-1 hash done on the + |Sec-WebSocket-Key| header field concatenated with + the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11". + */ + + /* If the response includes a |Sec-WebSocket-Extensions| header field and + this header field indicates the use of an extension that was not present + in the client's handshake (the server has indicated an extension not + requested by the client), the client MUST Fail the WebSocket Connection. + */ + + /* If the response includes a |Sec-WebSocket-Protocol| header field + and this header field indicates the use of a subprotocol that was + not present in the client's handshake (the server has indicated a + subprotocol not requested by the client), the client MUST Fail + the WebSocket Connection. */ + + /* 4 bytes random */ + + result = Curl_rand(data, (unsigned char *)&ws->enc.mask, + sizeof(ws->enc.mask)); + if(result) + return result; + infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x", + ws->enc.mask[0], ws->enc.mask[1], ws->enc.mask[2], ws->enc.mask[3]); + + /* Install our client writer that decodes WS frames payload */ + result = Curl_cwriter_create(&ws_dec_writer, data, &ws_cw_decode, + CURL_CW_CONTENT_DECODE); + if(result) + return result; + + result = Curl_cwriter_add(data, ws_dec_writer); + if(result) { + Curl_cwriter_free(data, ws_dec_writer); + return result; + } + + if(data->set.connect_only) { + ssize_t nwritten; + /* In CONNECT_ONLY setup, the payloads from `mem` need to be received + * when using `curl_ws_recv` later on after this transfer is already + * marked as DONE. */ + nwritten = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem, + nread, &result); + if(nwritten < 0) + return result; + infof(data, "%zu bytes websocket payload", nread); + } + else { /* !connect_only */ + /* And pass any additional data to the writers */ + if(nread) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)mem, nread); + } + } + k->upgr101 = UPGR101_RECEIVED; + + return result; +} + +struct ws_collect { + struct Curl_easy *data; + void *buffer; + size_t buflen; + size_t bufidx; + int frame_age; + int frame_flags; + curl_off_t payload_offset; + curl_off_t payload_len; + bool written; +}; + +static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *userp, + CURLcode *err) +{ + struct ws_collect *ctx = userp; + size_t nwritten; + curl_off_t remain = (payload_len - (payload_offset + buflen)); + + if(!ctx->bufidx) { + /* first write */ + ctx->frame_age = frame_age; + ctx->frame_flags = frame_flags; + ctx->payload_offset = payload_offset; + ctx->payload_len = payload_len; + } + + if((frame_flags & CURLWS_PING) && !remain) { + /* auto-respond to PINGs, only works for single-frame payloads atm */ + size_t bytes; + infof(ctx->data, "WS: auto-respond to PING with a PONG"); + /* send back the exact same content as a PONG */ + *err = curl_ws_send(ctx->data, buf, buflen, &bytes, 0, CURLWS_PONG); + if(*err) + return -1; + nwritten = bytes; + } + else { + ctx->written = TRUE; + DEBUGASSERT(ctx->buflen >= ctx->bufidx); + nwritten = CURLMIN(buflen, ctx->buflen - ctx->bufidx); + if(!nwritten) { + if(!buflen) { /* 0 length write, we accept that */ + *err = CURLE_OK; + return 0; + } + *err = CURLE_AGAIN; /* no more space */ + return -1; + } + *err = CURLE_OK; + memcpy(ctx->buffer, buf, nwritten); + ctx->bufidx += nwritten; + } + return nwritten; +} + +static ssize_t nw_in_recv(void *reader_ctx, + unsigned char *buf, size_t buflen, + CURLcode *err) +{ + struct Curl_easy *data = reader_ctx; + size_t nread; + + *err = curl_easy_recv(data, buf, buflen, &nread); + if(*err) + return -1; + return (ssize_t)nread; +} + +CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, + size_t buflen, size_t *nread, + const struct curl_ws_frame **metap) +{ + struct connectdata *conn = data->conn; + struct websocket *ws; + bool done = FALSE; /* not filled passed buffer yet */ + struct ws_collect ctx; + CURLcode result; + + if(!conn) { + /* Unhappy hack with lifetimes of transfers and connection */ + if(!data->set.connect_only) { + failf(data, "CONNECT_ONLY is required"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + + Curl_getconnectinfo(data, &conn); + if(!conn) { + failf(data, "connection not found"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + ws = conn->proto.ws; + if(!ws) { + failf(data, "connection is not setup for websocket"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + *nread = 0; + *metap = NULL; + /* get a download buffer */ + result = Curl_preconnect(data); + if(result) + return result; + + memset(&ctx, 0, sizeof(ctx)); + ctx.data = data; + ctx.buffer = buffer; + ctx.buflen = buflen; + + while(!done) { + /* receive more when our buffer is empty */ + if(Curl_bufq_is_empty(&ws->recvbuf)) { + ssize_t n = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &result); + if(n < 0) { + return result; + } + else if(n == 0) { + /* connection closed */ + infof(data, "connection expectedly closed?"); + return CURLE_GOT_NOTHING; + } + DEBUGF(infof(data, "curl_ws_recv, added %zu bytes from network", + Curl_bufq_len(&ws->recvbuf))); + } + + result = ws_dec_pass(&ws->dec, data, &ws->recvbuf, + ws_client_collect, &ctx); + if(result == CURLE_AGAIN) { + if(!ctx.written) { + ws_dec_info(&ws->dec, data, "need more input"); + continue; /* nothing written, try more input */ + } + done = TRUE; + break; + } + else if(result) { + return result; + } + else if(ctx.written) { + /* The decoded frame is passed back to our caller. + * There are frames like PING were we auto-respond to and + * that we do not return. For these `ctx.written` is not set. */ + done = TRUE; + break; + } + } + + /* update frame information to be passed back */ + update_meta(ws, ctx.frame_age, ctx.frame_flags, ctx.payload_offset, + ctx.payload_len, ctx.bufidx); + *metap = &ws->frame; + *nread = ws->frame.len; + /* infof(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %" + CURL_FORMAT_CURL_OFF_T ", %" CURL_FORMAT_CURL_OFF_T " left)", + buflen, *nread, ws->frame.offset, ws->frame.bytesleft); */ + return CURLE_OK; +} + +static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws, + bool complete) +{ + if(!Curl_bufq_is_empty(&ws->sendbuf)) { + CURLcode result; + const unsigned char *out; + size_t outlen; + ssize_t n; + + while(Curl_bufq_peek(&ws->sendbuf, &out, &outlen)) { + if(data->set.connect_only) + result = Curl_senddata(data, out, outlen, &n); + else + result = Curl_write(data, data->conn->writesockfd, out, outlen, &n); + if(result) { + if(result == CURLE_AGAIN) { + if(!complete) { + infof(data, "WS: flush EAGAIN, %zu bytes remain in buffer", + Curl_bufq_len(&ws->sendbuf)); + return result; + } + /* TODO: the current design does not allow for buffered writes. + * We need to flush the buffer now. There is no ws_flush() later */ + n = 0; + continue; + } + else if(result) { + failf(data, "WS: flush, write error %d", result); + return result; + } + } + else { + infof(data, "WS: flushed %zu bytes", (size_t)n); + Curl_bufq_skip(&ws->sendbuf, (size_t)n); + } + } + } + return CURLE_OK; +} + +CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t fragsize, + unsigned int flags) +{ + struct websocket *ws; + ssize_t nwritten, n; + size_t space; + CURLcode result; + + *sent = 0; + if(!data->conn && data->set.connect_only) { + result = Curl_connect_only_attach(data); + if(result) + return result; + } + if(!data->conn) { + failf(data, "No associated connection"); + return CURLE_SEND_ERROR; + } + if(!data->conn->proto.ws) { + failf(data, "Not a websocket transfer"); + return CURLE_SEND_ERROR; + } + ws = data->conn->proto.ws; + + if(data->set.ws_raw_mode) { + if(fragsize || flags) { + DEBUGF(infof(data, "ws_send: " + "fragsize and flags cannot be non-zero in raw mode")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!buflen) + /* nothing to do */ + return CURLE_OK; + /* raw mode sends exactly what was requested, and this is from within + the write callback */ + if(Curl_is_in_callback(data)) { + result = Curl_write(data, data->conn->writesockfd, buffer, buflen, + &nwritten); + } + else + result = Curl_senddata(data, buffer, buflen, &nwritten); + + infof(data, "WS: wanted to send %zu bytes, sent %zu bytes", + buflen, nwritten); + *sent = (nwritten >= 0)? (size_t)nwritten : 0; + return result; + } + + /* Not RAW mode, buf we do the frame encoding */ + result = ws_flush(data, ws, FALSE); + if(result) + return result; + + /* TODO: the current design does not allow partial writes, afaict. + * It is not clear who the application is supposed to react. */ + space = Curl_bufq_space(&ws->sendbuf); + DEBUGF(infof(data, "curl_ws_send(len=%zu), sendbuf len=%zu space %zu", + buflen, Curl_bufq_len(&ws->sendbuf), space)); + if(space < 14) + return CURLE_AGAIN; + + if(flags & CURLWS_OFFSET) { + if(fragsize) { + /* a frame series 'fragsize' bytes big, this is the first */ + n = ws_enc_write_head(data, &ws->enc, flags, fragsize, + &ws->sendbuf, &result); + if(n < 0) + return result; + } + else { + if((curl_off_t)buflen > ws->enc.payload_remain) { + infof(data, "WS: unaligned frame size (sending %zu instead of %" + CURL_FORMAT_CURL_OFF_T ")", + buflen, ws->enc.payload_remain); + } + } + } + else if(!ws->enc.payload_remain) { + n = ws_enc_write_head(data, &ws->enc, flags, (curl_off_t)buflen, + &ws->sendbuf, &result); + if(n < 0) + return result; + } + + n = ws_enc_write_payload(&ws->enc, data, + buffer, buflen, &ws->sendbuf, &result); + if(n < 0) + return result; + + *sent = (size_t)n; + return ws_flush(data, ws, TRUE); +} + +static void ws_free(struct connectdata *conn) +{ + if(conn && conn->proto.ws) { + Curl_bufq_free(&conn->proto.ws->recvbuf); + Curl_bufq_free(&conn->proto.ws->sendbuf); + Curl_safefree(conn->proto.ws); + } +} + +static CURLcode ws_setup_conn(struct Curl_easy *data, + struct connectdata *conn) +{ + /* websockets is 1.1 only (for now) */ + data->state.httpwant = CURL_HTTP_VERSION_1_1; + return Curl_http_setup_conn(data, conn); +} + + +void Curl_ws_done(struct Curl_easy *data) +{ + (void)data; +} + +static CURLcode ws_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) +{ + (void)data; + (void)dead_connection; + ws_free(conn); + return CURLE_OK; +} + +CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +{ + /* we only return something for websocket, called from within the callback + when not using raw mode */ + if(GOOD_EASY_HANDLE(data) && Curl_is_in_callback(data) && data->conn && + data->conn->proto.ws && !data->set.ws_raw_mode) + return &data->conn->proto.ws->frame; + return NULL; +} + +const struct Curl_handler Curl_handler_ws = { + "WS", /* scheme */ + ws_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + Curl_http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ws_disconnect, /* disconnect */ + Curl_http_write_resp, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTP, /* defport */ + CURLPROTO_WS, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_CREDSPERREQUEST | /* flags */ + PROTOPT_USERPWDCTRL +}; + +#ifdef USE_SSL +const struct Curl_handler Curl_handler_wss = { + "WSS", /* scheme */ + ws_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + NULL, /* connecting */ + ZERO_NULL, /* doing */ + NULL, /* proto_getsock */ + Curl_http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ws_disconnect, /* disconnect */ + Curl_http_write_resp, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTPS, /* defport */ + CURLPROTO_WSS, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */ + PROTOPT_USERPWDCTRL +}; +#endif + + +#else + +CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, + size_t *nread, + const struct curl_ws_frame **metap) +{ + (void)curl; + (void)buffer; + (void)buflen; + (void)nread; + (void)metap; + return CURLE_NOT_BUILT_IN; +} + +CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t fragsize, + unsigned int flags) +{ + (void)curl; + (void)buffer; + (void)buflen; + (void)sent; + (void)fragsize; + (void)flags; + return CURLE_NOT_BUILT_IN; +} + +CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +{ + (void)data; + return NULL; +} +#endif /* USE_WEBSOCKETS */ diff --git a/lib/ws.h b/lib/ws.h new file mode 100644 index 0000000..5f40d45 --- /dev/null +++ b/lib/ws.h @@ -0,0 +1,92 @@ +#ifndef HEADER_CURL_WS_H +#define HEADER_CURL_WS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) + +#ifdef USE_HYPER +#define REQTYPE void +#else +#define REQTYPE struct dynbuf +#endif + +/* a client-side WS frame decoder, parsing frame headers and + * payload, keeping track of current position and stats */ +enum ws_dec_state { + WS_DEC_INIT, + WS_DEC_HEAD, + WS_DEC_PAYLOAD +}; + +struct ws_decoder { + int frame_age; /* zero */ + int frame_flags; /* See the CURLWS_* defines */ + curl_off_t payload_offset; /* the offset parsing is at */ + curl_off_t payload_len; + unsigned char head[10]; + int head_len, head_total; + enum ws_dec_state state; +}; + +/* a client-side WS frame encoder, generating frame headers and + * converting payloads, tracking remaining data in current frame */ +struct ws_encoder { + curl_off_t payload_len; /* payload length of current frame */ + curl_off_t payload_remain; /* remaining payload of current */ + unsigned int xori; /* xor index */ + unsigned char mask[4]; /* 32 bit mask for this connection */ + unsigned char firstbyte; /* first byte of frame we encode */ + bool contfragment; /* set TRUE if the previous fragment sent was not final */ +}; + +/* A websocket connection with en- and decoder that treat frames + * and keep track of boundaries. */ +struct websocket { + struct Curl_easy *data; /* used for write callback handling */ + struct ws_decoder dec; /* decode of we frames */ + struct ws_encoder enc; /* decode of we frames */ + struct bufq recvbuf; /* raw data from the server */ + struct bufq sendbuf; /* raw data to be sent to the server */ + struct curl_ws_frame frame; /* the current WS FRAME received */ +}; + +CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req); +CURLcode Curl_ws_accept(struct Curl_easy *data, const char *mem, size_t len); +void Curl_ws_done(struct Curl_easy *data); + +extern const struct Curl_handler Curl_handler_ws; +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_wss; +#endif + + +#else +#define Curl_ws_request(x,y) CURLE_OK +#define Curl_ws_done(x) Curl_nop_stmt +#define Curl_ws_free(x) Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_WS_H */ diff --git a/libcurl.def b/libcurl.def new file mode 100644 index 0000000..c6c9606 --- /dev/null +++ b/libcurl.def @@ -0,0 +1,94 @@ +EXPORTS +curl_easy_cleanup +curl_easy_duphandle +curl_easy_escape +curl_easy_getinfo +curl_easy_header +curl_easy_init +curl_easy_nextheader +curl_easy_option_by_id +curl_easy_option_by_name +curl_easy_option_next +curl_easy_pause +curl_easy_perform +curl_easy_recv +curl_easy_reset +curl_easy_send +curl_easy_setopt +curl_easy_strerror +curl_easy_unescape +curl_easy_upkeep +curl_escape +curl_formadd +curl_formfree +curl_formget +curl_free +curl_getdate +curl_getenv +curl_global_cleanup +curl_global_init +curl_global_init_mem +curl_global_sslset +curl_global_trace +curl_maprintf +curl_mfprintf +curl_mime_addpart +curl_mime_data +curl_mime_data_cb +curl_mime_encoder +curl_mime_filedata +curl_mime_filename +curl_mime_free +curl_mime_headers +curl_mime_init +curl_mime_name +curl_mime_subparts +curl_mime_type +curl_mprintf +curl_msnprintf +curl_msprintf +curl_multi_add_handle +curl_multi_assign +curl_multi_cleanup +curl_multi_fdset +curl_multi_get_handles +curl_multi_info_read +curl_multi_init +curl_multi_perform +curl_multi_poll +curl_multi_remove_handle +curl_multi_setopt +curl_multi_socket +curl_multi_socket_action +curl_multi_socket_all +curl_multi_strerror +curl_multi_timeout +curl_multi_wait +curl_multi_wakeup +curl_mvaprintf +curl_mvfprintf +curl_mvprintf +curl_mvsnprintf +curl_mvsprintf +curl_pushheader_byname +curl_pushheader_bynum +curl_share_cleanup +curl_share_init +curl_share_setopt +curl_share_strerror +curl_slist_append +curl_slist_free_all +curl_strequal +curl_strnequal +curl_unescape +curl_url +curl_url_cleanup +curl_url_dup +curl_url_get +curl_url_set +curl_url_strerror +curl_version +curl_version_info +curl_ws_meta +curl_ws_recv +curl_ws_send diff --git a/libcurl.pc.in b/libcurl.pc.in new file mode 100644 index 0000000..9db6b0f --- /dev/null +++ b/libcurl.pc.in @@ -0,0 +1,41 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# This should most probably benefit from getting a "Requires:" field added +# dynamically by configure. +# +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +supported_protocols="@SUPPORT_PROTOCOLS@" +supported_features="@SUPPORT_FEATURES@" + +Name: libcurl +URL: https://curl.se/ +Description: Library to transfer files with ftp, http, etc. +Version: @CURLVERSION@ +Libs: -L${libdir} -lcurl @LIBCURL_NO_SHARED@ +Libs.private: @LIBCURL_LIBS@ +Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@ diff --git a/ltmain.sh b/ltmain.sh new file mode 100755 index 0000000..1dea62a --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,11436 @@ +#! /usr/bin/env sh +## DO NOT EDIT - This file generated from ./build-aux/ltmain.in +## by inline-source v2019-02-19.15 + +# libtool (GNU libtool) 2.4.7 +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996-2019, 2021-2022 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.7 Debian-2.4.7-7" +package_revision=2.4.7 + + +## ------ ## +## Usage. ## +## ------ ## + +# Run './libtool --help' for help with using this script from the +# command line. + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# After configure completes, it has a better idea of some of the +# shell tools we need than the defaults used by the functions shared +# with bootstrap, so set those here where they can still be over- +# ridden by the user, but otherwise take precedence. + +: ${AUTOCONF="autoconf"} +: ${AUTOMAKE="automake"} + + +## -------------------------- ## +## Source external libraries. ## +## -------------------------- ## + +# Much of our low-level functionality needs to be sourced from external +# libraries, which are installed to $pkgauxdir. + +# Set a version string for this script. +scriptversion=2019-02-19.15; # UTC + +# General shell script boiler plate, and helper functions. +# Written by Gary V. Vaughan, 2004 + +# This is free software. There is NO warranty; not even for +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Copyright (C) 2004-2019, 2021 Bootstrap Authors +# +# This file is dual licensed under the terms of the MIT license +# , and GPL version 2 or later +# . You must apply one of +# these licenses when using or redistributing this software or any of +# the files within it. See the URLs above, or the file `LICENSE` +# included in the Bootstrap distribution for the full license texts. + +# Please report bugs or propose patches to: +# + + +## ------ ## +## Usage. ## +## ------ ## + +# Evaluate this file near the top of your script to gain access to +# the functions and variables defined here: +# +# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh +# +# If you need to override any of the default environment variable +# settings, do that before evaluating this file. + + +## -------------------- ## +## Shell normalisation. ## +## -------------------- ## + +# Some shells need a little help to be as Bourne compatible as possible. +# Before doing anything else, make sure all that help has been provided! + +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac +fi + +# NLS nuisances: We save the old values in case they are required later. +_G_user_locale= +_G_safe_locale= +for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test set = \"\${$_G_var+set}\"; then + save_$_G_var=\$$_G_var + $_G_var=C + export $_G_var + _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" + _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" + fi" +done +# These NLS vars are set unconditionally (bootstrap issue #24). Unset those +# in case the environment reset is needed later and the $save_* variant is not +# defined (see the code above). +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +# Make sure IFS has a sensible default +sp=' ' +nl=' +' +IFS="$sp $nl" + +# There are apparently some retarded systems that use ';' as a PATH separator! +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# func_unset VAR +# -------------- +# Portably unset VAR. +# In some shells, an 'unset VAR' statement leaves a non-zero return +# status if VAR is already unset, which might be problematic if the +# statement is used at the end of a function (thus poisoning its return +# value) or when 'set -e' is active (causing even a spurious abort of +# the script in this case). +func_unset () +{ + { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; } +} + + +# Make sure CDPATH doesn't cause `cd` commands to output the target dir. +func_unset CDPATH + +# Make sure ${,E,F}GREP behave sanely. +func_unset GREP_OPTIONS + + +## ------------------------- ## +## Locate command utilities. ## +## ------------------------- ## + + +# func_executable_p FILE +# ---------------------- +# Check that FILE is an executable regular file. +func_executable_p () +{ + test -f "$1" && test -x "$1" +} + + +# func_path_progs PROGS_LIST CHECK_FUNC [PATH] +# -------------------------------------------- +# Search for either a program that responds to --version with output +# containing "GNU", or else returned by CHECK_FUNC otherwise, by +# trying all the directories in PATH with each of the elements of +# PROGS_LIST. +# +# CHECK_FUNC should accept the path to a candidate program, and +# set $func_check_prog_result if it truncates its output less than +# $_G_path_prog_max characters. +func_path_progs () +{ + _G_progs_list=$1 + _G_check_func=$2 + _G_PATH=${3-"$PATH"} + + _G_path_prog_max=0 + _G_path_prog_found=false + _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} + for _G_dir in $_G_PATH; do + IFS=$_G_save_IFS + test -z "$_G_dir" && _G_dir=. + for _G_prog_name in $_G_progs_list; do + for _exeext in '' .EXE; do + _G_path_prog=$_G_dir/$_G_prog_name$_exeext + func_executable_p "$_G_path_prog" || continue + case `"$_G_path_prog" --version 2>&1` in + *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; + *) $_G_check_func $_G_path_prog + func_path_progs_result=$func_check_prog_result + ;; + esac + $_G_path_prog_found && break 3 + done + done + done + IFS=$_G_save_IFS + test -z "$func_path_progs_result" && { + echo "no acceptable sed could be found in \$PATH" >&2 + exit 1 + } +} + + +# We want to be able to use the functions in this file before configure +# has figured out where the best binaries are kept, which means we have +# to search for them ourselves - except when the results are already set +# where we skip the searches. + +# Unless the user overrides by setting SED, search the path for either GNU +# sed, or the sed that truncates its output the least. +test -z "$SED" && { + _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for _G_i in 1 2 3 4 5 6 7; do + _G_sed_script=$_G_sed_script$nl$_G_sed_script + done + echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed + _G_sed_script= + + func_check_prog_sed () + { + _G_path_prog=$1 + + _G_count=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo '' >> conftest.nl + "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin" + rm -f conftest.sed + SED=$func_path_progs_result +} + + +# Unless the user overrides by setting GREP, search the path for either GNU +# grep, or the grep that truncates its output the least. +test -z "$GREP" && { + func_check_prog_grep () + { + _G_path_prog=$1 + + _G_count=0 + _G_path_prog_max=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo 'GREP' >> conftest.nl + "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin" + GREP=$func_path_progs_result +} + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# All uppercase variable names are used for environment variables. These +# variables can be overridden by the user before calling a script that +# uses them if a suitable command of that name is not already available +# in the command search PATH. + +: ${CP="cp -f"} +: ${ECHO="printf %s\n"} +: ${EGREP="$GREP -E"} +: ${FGREP="$GREP -F"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} + + +## -------------------- ## +## Useful sed snippets. ## +## -------------------- ## + +sed_dirname='s|/[^/]*$||' +sed_basename='s|^.*/||' + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s|\([`"$\\]\)|\\\1|g' + +# Same as above, but do not quote variable references. +sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' + +# Sed substitution that converts a w32 file name or path +# that contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-'\' parameter expansions in output of sed_double_quote_subst that +# were '\'-ed in input to the same. If an odd number of '\' preceded a +# '$' in input to sed_double_quote_subst, that '$' was protected from +# expansion. Since each input '\' is now two '\'s, look for any number +# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. +_G_bs='\\' +_G_bs2='\\\\' +_G_bs4='\\\\\\\\' +_G_dollar='\$' +sed_double_backslash="\ + s/$_G_bs4/&\\ +/g + s/^$_G_bs2$_G_dollar/$_G_bs&/ + s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g + s/\n//g" + +# require_check_ifs_backslash +# --------------------------- +# Check if we can use backslash as IFS='\' separator, and set +# $check_ifs_backshlash_broken to ':' or 'false'. +require_check_ifs_backslash=func_require_check_ifs_backslash +func_require_check_ifs_backslash () +{ + _G_save_IFS=$IFS + IFS='\' + _G_check_ifs_backshlash='a\\b' + for _G_i in $_G_check_ifs_backshlash + do + case $_G_i in + a) + check_ifs_backshlash_broken=false + ;; + '') + break + ;; + *) + check_ifs_backshlash_broken=: + break + ;; + esac + done + IFS=$_G_save_IFS + require_check_ifs_backslash=: +} + + +## ----------------- ## +## Global variables. ## +## ----------------- ## + +# Except for the global variables explicitly listed below, the following +# functions in the '^func_' namespace, and the '^require_' namespace +# variables initialised in the 'Resource management' section, sourcing +# this file will not pollute your global namespace with anything +# else. There's no portable way to scope variables in Bourne shell +# though, so actually running these functions will sometimes place +# results into a variable named after the function, and often use +# temporary variables in the '^_G_' namespace. If you are careful to +# avoid using those namespaces casually in your sourcing script, things +# should continue to work as you expect. And, of course, you can freely +# overwrite any of the functions or variables defined here before +# calling anything to customize them. + +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +# Allow overriding, eg assuming that you follow the convention of +# putting '$debug_cmd' at the start of all your functions, you can get +# bash to show function call trace with: +# +# debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name +debug_cmd=${debug_cmd-":"} +exit_cmd=: + +# By convention, finish your script with: +# +# exit $exit_status +# +# so that you can set exit_status to non-zero if you want to indicate +# something went wrong during execution without actually bailing out at +# the point of failure. +exit_status=$EXIT_SUCCESS + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath=$0 + +# The name of this program. +progname=`$ECHO "$progpath" |$SED "$sed_basename"` + +# Make sure we have an absolute progpath for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` + progdir=`cd "$progdir" && pwd` + progpath=$progdir/$progname + ;; + *) + _G_IFS=$IFS + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS=$_G_IFS + test -x "$progdir/$progname" && break + done + IFS=$_G_IFS + test -n "$progdir" || progdir=`pwd` + progpath=$progdir/$progname + ;; +esac + + +## ----------------- ## +## Standard options. ## +## ----------------- ## + +# The following options affect the operation of the functions defined +# below, and should be set appropriately depending on run-time para- +# meters passed on the command line. + +opt_dry_run=false +opt_quiet=false +opt_verbose=false + +# Categories 'all' and 'none' are always available. Append any others +# you will pass as the first argument to func_warning from your own +# code. +warning_categories= + +# By default, display warnings according to 'opt_warning_types'. Set +# 'warning_func' to ':' to elide all warnings, or func_fatal_error to +# treat the next displayed warning as a fatal error. +warning_func=func_warn_and_continue + +# Set to 'all' to display all warnings, 'none' to suppress all +# warnings, or a space delimited list of some subset of +# 'warning_categories' to display only the listed warnings. +opt_warning_types=all + + +## -------------------- ## +## Resource management. ## +## -------------------- ## + +# This section contains definitions for functions that each ensure a +# particular resource (a file, or a non-empty configuration variable for +# example) is available, and if appropriate to extract default values +# from pertinent package files. Call them using their associated +# 'require_*' variable to ensure that they are executed, at most, once. +# +# It's entirely deliberate that calling these functions can set +# variables that don't obey the namespace limitations obeyed by the rest +# of this file, in order that that they be as useful as possible to +# callers. + + +# require_term_colors +# ------------------- +# Allow display of bold text on terminals that support it. +require_term_colors=func_require_term_colors +func_require_term_colors () +{ + $debug_cmd + + test -t 1 && { + # COLORTERM and USE_ANSI_COLORS environment variables take + # precedence, because most terminfo databases neglect to describe + # whether color sequences are supported. + test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} + + if test 1 = "$USE_ANSI_COLORS"; then + # Standard ANSI escape sequences + tc_reset='' + tc_bold=''; tc_standout='' + tc_red=''; tc_green='' + tc_blue=''; tc_cyan='' + else + # Otherwise trust the terminfo database after all. + test -n "`tput sgr0 2>/dev/null`" && { + tc_reset=`tput sgr0` + test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` + tc_standout=$tc_bold + test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` + test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` + test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` + test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` + test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` + } + fi + } + + require_term_colors=: +} + + +## ----------------- ## +## Function library. ## +## ----------------- ## + +# This section contains a variety of useful functions to call in your +# scripts. Take note of the portable wrappers for features provided by +# some modern shells, which will fall back to slower equivalents on +# less featureful shells. + + +# func_append VAR VALUE +# --------------------- +# Append VALUE onto the existing contents of VAR. + + # _G_HAVE_PLUSEQ_OP + # Can be empty, in which case the shell is probed, "yes" if += is + # useable or anything else if it does not work. + if test -z "$_G_HAVE_PLUSEQ_OP" && \ + __PLUSEQ_TEST="a" && \ + __PLUSEQ_TEST+=" b" 2>/dev/null && \ + test "a b" = "$__PLUSEQ_TEST"; then + _G_HAVE_PLUSEQ_OP=yes + fi + +if test yes = "$_G_HAVE_PLUSEQ_OP" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_append () + { + $debug_cmd + + eval "$1+=\$2" + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_append () + { + $debug_cmd + + eval "$1=\$$1\$2" + } +fi + + +# func_append_quoted VAR VALUE +# ---------------------------- +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +if test yes = "$_G_HAVE_PLUSEQ_OP"; then + eval 'func_append_quoted () + { + $debug_cmd + + func_quote_arg pretty "$2" + eval "$1+=\\ \$func_quote_arg_result" + }' +else + func_append_quoted () + { + $debug_cmd + + func_quote_arg pretty "$2" + eval "$1=\$$1\\ \$func_quote_arg_result" + } +fi + + +# func_append_uniq VAR VALUE +# -------------------------- +# Append unique VALUE onto the existing contents of VAR, assuming +# entries are delimited by the first character of VALUE. For example: +# +# func_append_uniq options " --another-option option-argument" +# +# will only append to $options if " --another-option option-argument " +# is not already present somewhere in $options already (note spaces at +# each end implied by leading space in second argument). +func_append_uniq () +{ + $debug_cmd + + eval _G_current_value='`$ECHO $'$1'`' + _G_delim=`expr "$2" : '\(.\)'` + + case $_G_delim$_G_current_value$_G_delim in + *"$2$_G_delim"*) ;; + *) func_append "$@" ;; + esac +} + + +# func_arith TERM... +# ------------------ +# Set func_arith_result to the result of evaluating TERMs. + test -z "$_G_HAVE_ARITH_OP" \ + && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ + && _G_HAVE_ARITH_OP=yes + +if test yes = "$_G_HAVE_ARITH_OP"; then + eval 'func_arith () + { + $debug_cmd + + func_arith_result=$(( $* )) + }' +else + func_arith () + { + $debug_cmd + + func_arith_result=`expr "$@"` + } +fi + + +# func_basename FILE +# ------------------ +# Set func_basename_result to FILE with everything up to and including +# the last / stripped. +if test yes = "$_G_HAVE_XSI_OPS"; then + # If this shell supports suffix pattern removal, then use it to avoid + # forking. Hide the definitions single quotes in case the shell chokes + # on unsupported syntax... + _b='func_basename_result=${1##*/}' + _d='case $1 in + */*) func_dirname_result=${1%/*}$2 ;; + * ) func_dirname_result=$3 ;; + esac' + +else + # ...otherwise fall back to using sed. + _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' + _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` + if test "X$func_dirname_result" = "X$1"; then + func_dirname_result=$3 + else + func_append func_dirname_result "$2" + fi' +fi + +eval 'func_basename () +{ + $debug_cmd + + '"$_b"' +}' + + +# func_dirname FILE APPEND NONDIR_REPLACEMENT +# ------------------------------------------- +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +eval 'func_dirname () +{ + $debug_cmd + + '"$_d"' +}' + + +# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT +# -------------------------------------------------------- +# Perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# For efficiency, we do not delegate to the functions above but instead +# duplicate the functionality here. +eval 'func_dirname_and_basename () +{ + $debug_cmd + + '"$_b"' + '"$_d"' +}' + + +# func_echo ARG... +# ---------------- +# Echo program name prefixed message. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_echo_all ARG... +# -------------------- +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + + +# func_echo_infix_1 INFIX ARG... +# ------------------------------ +# Echo program name, followed by INFIX on the first line, with any +# additional lines not showing INFIX. +func_echo_infix_1 () +{ + $debug_cmd + + $require_term_colors + + _G_infix=$1; shift + _G_indent=$_G_infix + _G_prefix="$progname: $_G_infix: " + _G_message=$* + + # Strip color escape sequences before counting printable length + for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" + do + test -n "$_G_tc" && { + _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` + _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` + } + done + _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes + + func_echo_infix_1_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_infix_1_IFS + $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 + _G_prefix=$_G_indent + done + IFS=$func_echo_infix_1_IFS +} + + +# func_error ARG... +# ----------------- +# Echo program name prefixed message to standard error. +func_error () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 +} + + +# func_fatal_error ARG... +# ----------------------- +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + $debug_cmd + + func_error "$*" + exit $EXIT_FAILURE +} + + +# func_grep EXPRESSION FILENAME +# ----------------------------- +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $debug_cmd + + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_len STRING +# --------------- +# Set func_len_result to the length of STRING. STRING may not +# start with a hyphen. + test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_len () + { + $debug_cmd + + func_len_result=${#1} + }' +else + func_len () + { + $debug_cmd + + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` + } +fi + + +# func_mkdir_p DIRECTORY-PATH +# --------------------------- +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + $debug_cmd + + _G_directory_path=$1 + _G_dir_list= + + if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then + + # Protect directory names starting with '-' + case $_G_directory_path in + -*) _G_directory_path=./$_G_directory_path ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$_G_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + _G_dir_list=$_G_directory_path:$_G_dir_list + + # If the last portion added has no slash in it, the list is done + case $_G_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` + done + _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` + + func_mkdir_p_IFS=$IFS; IFS=: + for _G_dir in $_G_dir_list; do + IFS=$func_mkdir_p_IFS + # mkdir can fail with a 'File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$_G_dir" 2>/dev/null || : + done + IFS=$func_mkdir_p_IFS + + # Bail out if we (or some other process) failed to create a directory. + test -d "$_G_directory_path" || \ + func_fatal_error "Failed to create '$1'" + fi +} + + +# func_mktempdir [BASENAME] +# ------------------------- +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, BASENAME is the basename for that directory. +func_mktempdir () +{ + $debug_cmd + + _G_template=${TMPDIR-/tmp}/${1-$progname} + + if test : = "$opt_dry_run"; then + # Return a directory name, but don't create it in dry-run mode + _G_tmpdir=$_G_template-$$ + else + + # If mktemp works, use that first and foremost + _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` + + if test ! -d "$_G_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + _G_tmpdir=$_G_template-${RANDOM-0}$$ + + func_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$_G_tmpdir" + umask $func_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$_G_tmpdir" || \ + func_fatal_error "cannot create temporary directory '$_G_tmpdir'" + fi + + $ECHO "$_G_tmpdir" +} + + +# func_normal_abspath PATH +# ------------------------ +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +func_normal_abspath () +{ + $debug_cmd + + # These SED scripts presuppose an absolute path with a trailing slash. + _G_pathcar='s|^/\([^/]*\).*$|\1|' + _G_pathcdr='s|^/[^/]*||' + _G_removedotparts=':dotsl + s|/\./|/|g + t dotsl + s|/\.$|/|' + _G_collapseslashes='s|/\{1,\}|/|g' + _G_finalslash='s|/*$|/|' + + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` + while :; do + # Processed it all yet? + if test / = "$func_normal_abspath_tpath"; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result"; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + + +# func_notquiet ARG... +# -------------------- +# Echo program name prefixed message only when not in quiet mode. +func_notquiet () +{ + $debug_cmd + + $opt_quiet || func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + + +# func_relative_path SRCDIR DSTDIR +# -------------------------------- +# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. +func_relative_path () +{ + $debug_cmd + + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=$func_dirname_result + if test -z "$func_relative_path_tlibdir"; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test -n "$func_stripname_result"; then + func_append func_relative_path_result "/$func_stripname_result" + fi + + # Normalisation. If bindir is libdir, return '.' else relative path. + if test -n "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + fi + + test -n "$func_relative_path_result" || func_relative_path_result=. + + : +} + + +# func_quote_portable EVAL ARG +# ---------------------------- +# Internal function to portably implement func_quote_arg. Note that we still +# keep attention to performance here so we as much as possible try to avoid +# calling sed binary (so far O(N) complexity as long as func_append is O(1)). +func_quote_portable () +{ + $debug_cmd + + $require_check_ifs_backslash + + func_quote_portable_result=$2 + + # one-time-loop (easy break) + while true + do + if $1; then + func_quote_portable_result=`$ECHO "$2" | $SED \ + -e "$sed_double_quote_subst" -e "$sed_double_backslash"` + break + fi + + # Quote for eval. + case $func_quote_portable_result in + *[\\\`\"\$]*) + # Fallback to sed for $func_check_bs_ifs_broken=:, or when the string + # contains the shell wildcard characters. + case $check_ifs_backshlash_broken$func_quote_portable_result in + :*|*[\[\*\?]*) + func_quote_portable_result=`$ECHO "$func_quote_portable_result" \ + | $SED "$sed_quote_subst"` + break + ;; + esac + + func_quote_portable_old_IFS=$IFS + for _G_char in '\' '`' '"' '$' + do + # STATE($1) PREV($2) SEPARATOR($3) + set start "" "" + func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy + IFS=$_G_char + for _G_part in $func_quote_portable_result + do + case $1 in + quote) + func_append func_quote_portable_result "$3$2" + set quote "$_G_part" "\\$_G_char" + ;; + start) + set first "" "" + func_quote_portable_result= + ;; + first) + set quote "$_G_part" "" + ;; + esac + done + done + IFS=$func_quote_portable_old_IFS + ;; + *) ;; + esac + break + done + + func_quote_portable_unquoted_result=$func_quote_portable_result + case $func_quote_portable_result in + # double-quote args containing shell metacharacters to delay + # word splitting, command substitution and variable expansion + # for a subsequent eval. + # many bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_portable_result=\"$func_quote_portable_result\" + ;; + esac +} + + +# func_quotefast_eval ARG +# ----------------------- +# Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG', +# but optimized for speed. Result is stored in $func_quotefast_eval. +if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then + printf -v _GL_test_printf_tilde %q '~' + if test '\~' = "$_GL_test_printf_tilde"; then + func_quotefast_eval () + { + printf -v func_quotefast_eval_result %q "$1" + } + else + # Broken older Bash implementations. Make those faster too if possible. + func_quotefast_eval () + { + case $1 in + '~'*) + func_quote_portable false "$1" + func_quotefast_eval_result=$func_quote_portable_result + ;; + *) + printf -v func_quotefast_eval_result %q "$1" + ;; + esac + } + fi +else + func_quotefast_eval () + { + func_quote_portable false "$1" + func_quotefast_eval_result=$func_quote_portable_result + } +fi + + +# func_quote_arg MODEs ARG +# ------------------------ +# Quote one ARG to be evaled later. MODEs argument may contain zero or more +# specifiers listed below separated by ',' character. This function returns two +# values: +# i) func_quote_arg_result +# double-quoted (when needed), suitable for a subsequent eval +# ii) func_quote_arg_unquoted_result +# has all characters that are still active within double +# quotes backslashified. Available only if 'unquoted' is specified. +# +# Available modes: +# ---------------- +# 'eval' (default) +# - escape shell special characters +# 'expand' +# - the same as 'eval'; but do not quote variable references +# 'pretty' +# - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might +# be used later in func_quote to get output like: 'echo "a b"' instead +# of 'echo a\ b'. This is slower than default on some shells. +# 'unquoted' +# - produce also $func_quote_arg_unquoted_result which does not contain +# wrapping double-quotes. +# +# Examples for 'func_quote_arg pretty,unquoted string': +# +# string | *_result | *_unquoted_result +# ------------+-----------------------+------------------- +# " | \" | \" +# a b | "a b" | a b +# "a b" | "\"a b\"" | \"a b\" +# * | "*" | * +# z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\" +# +# Examples for 'func_quote_arg pretty,unquoted,expand string': +# +# string | *_result | *_unquoted_result +# --------------+---------------------+-------------------- +# z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\" +func_quote_arg () +{ + _G_quote_expand=false + case ,$1, in + *,expand,*) + _G_quote_expand=: + ;; + esac + + case ,$1, in + *,pretty,*|*,expand,*|*,unquoted,*) + func_quote_portable $_G_quote_expand "$2" + func_quote_arg_result=$func_quote_portable_result + func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result + ;; + *) + # Faster quote-for-eval for some shells. + func_quotefast_eval "$2" + func_quote_arg_result=$func_quotefast_eval_result + ;; + esac +} + + +# func_quote MODEs ARGs... +# ------------------------ +# Quote all ARGs to be evaled later and join them into single command. See +# func_quote_arg's description for more info. +func_quote () +{ + $debug_cmd + _G_func_quote_mode=$1 ; shift + func_quote_result= + while test 0 -lt $#; do + func_quote_arg "$_G_func_quote_mode" "$1" + if test -n "$func_quote_result"; then + func_append func_quote_result " $func_quote_arg_result" + else + func_append func_quote_result "$func_quote_arg_result" + fi + shift + done +} + + +# func_stripname PREFIX SUFFIX NAME +# --------------------------------- +# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_stripname () + { + $debug_cmd + + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary variable first. + func_stripname_result=$3 + func_stripname_result=${func_stripname_result#"$1"} + func_stripname_result=${func_stripname_result%"$2"} + }' +else + func_stripname () + { + $debug_cmd + + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; + esac + } +fi + + +# func_show_eval CMD [FAIL_EXP] +# ----------------------------- +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + func_quote_arg pretty,expand "$_G_cmd" + eval "func_notquiet $func_quote_arg_result" + + $opt_dry_run || { + eval "$_G_cmd" + _G_status=$? + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_show_eval_locale CMD [FAIL_EXP] +# ------------------------------------ +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + $opt_quiet || { + func_quote_arg expand,pretty "$_G_cmd" + eval "func_echo $func_quote_arg_result" + } + + $opt_dry_run || { + eval "$_G_user_locale + $_G_cmd" + _G_status=$? + eval "$_G_safe_locale" + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_tr_sh +# ---------- +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + $debug_cmd + + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_verbose ARG... +# ------------------- +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $debug_cmd + + $opt_verbose && func_echo "$*" + + : +} + + +# func_warn_and_continue ARG... +# ----------------------------- +# Echo program name prefixed warning message to standard error. +func_warn_and_continue () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 +} + + +# func_warning CATEGORY ARG... +# ---------------------------- +# Echo program name prefixed warning message to standard error. Warning +# messages can be filtered according to CATEGORY, where this function +# elides messages where CATEGORY is not listed in the global variable +# 'opt_warning_types'. +func_warning () +{ + $debug_cmd + + # CATEGORY must be in the warning_categories list! + case " $warning_categories " in + *" $1 "*) ;; + *) func_internal_error "invalid warning category '$1'" ;; + esac + + _G_category=$1 + shift + + case " $opt_warning_types " in + *" $_G_category "*) $warning_func ${1+"$@"} ;; + esac +} + + +# func_sort_ver VER1 VER2 +# ----------------------- +# 'sort -V' is not generally available. +# Note this deviates from the version comparison in automake +# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a +# but this should suffice as we won't be specifying old +# version formats or redundant trailing .0 in bootstrap.conf. +# If we did want full compatibility then we should probably +# use m4_version_compare from autoconf. +func_sort_ver () +{ + $debug_cmd + + printf '%s\n%s\n' "$1" "$2" \ + | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n +} + +# func_lt_ver PREV CURR +# --------------------- +# Return true if PREV and CURR are in the correct order according to +# func_sort_ver, otherwise false. Use it like this: +# +# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." +func_lt_ver () +{ + $debug_cmd + + test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: +#! /bin/sh + +# A portable, pluggable option parser for Bourne shell. +# Written by Gary V. Vaughan, 2010 + +# This is free software. There is NO warranty; not even for +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Copyright (C) 2010-2019, 2021 Bootstrap Authors +# +# This file is dual licensed under the terms of the MIT license +# , and GPL version 2 or later +# . You must apply one of +# these licenses when using or redistributing this software or any of +# the files within it. See the URLs above, or the file `LICENSE` +# included in the Bootstrap distribution for the full license texts. + +# Please report bugs or propose patches to: +# + +# Set a version string for this script. +scriptversion=2019-02-19.15; # UTC + + +## ------ ## +## Usage. ## +## ------ ## + +# This file is a library for parsing options in your shell scripts along +# with assorted other useful supporting features that you can make use +# of too. +# +# For the simplest scripts you might need only: +# +# #!/bin/sh +# . relative/path/to/funclib.sh +# . relative/path/to/options-parser +# scriptversion=1.0 +# func_options ${1+"$@"} +# eval set dummy "$func_options_result"; shift +# ...rest of your script... +# +# In order for the '--version' option to work, you will need to have a +# suitably formatted comment like the one at the top of this file +# starting with '# Written by ' and ending with '# Copyright'. +# +# For '-h' and '--help' to work, you will also need a one line +# description of your script's purpose in a comment directly above the +# '# Written by ' line, like the one at the top of this file. +# +# The default options also support '--debug', which will turn on shell +# execution tracing (see the comment above debug_cmd below for another +# use), and '--verbose' and the func_verbose function to allow your script +# to display verbose messages only when your user has specified +# '--verbose'. +# +# After sourcing this file, you can plug in processing for additional +# options by amending the variables from the 'Configuration' section +# below, and following the instructions in the 'Option parsing' +# section further down. + +## -------------- ## +## Configuration. ## +## -------------- ## + +# You should override these variables in your script after sourcing this +# file so that they reflect the customisations you have added to the +# option parser. + +# The usage line for option parsing errors and the start of '-h' and +# '--help' output messages. You can embed shell variables for delayed +# expansion at the time the message is displayed, but you will need to +# quote other shell meta-characters carefully to prevent them being +# expanded when the contents are evaled. +usage='$progpath [OPTION]...' + +# Short help message in response to '-h' and '--help'. Add to this or +# override it after sourcing this library to reflect the full set of +# options your script accepts. +usage_message="\ + --debug enable verbose shell tracing + -W, --warnings=CATEGORY + report the warnings falling in CATEGORY [all] + -v, --verbose verbosely report processing + --version print version information and exit + -h, --help print short or long help message and exit +" + +# Additional text appended to 'usage_message' in response to '--help'. +long_help_message=" +Warning categories include: + 'all' show all warnings + 'none' turn off all the warnings + 'error' warnings are treated as fatal errors" + +# Help message printed before fatal option parsing errors. +fatal_help="Try '\$progname --help' for more information." + + + +## ------------------------- ## +## Hook function management. ## +## ------------------------- ## + +# This section contains functions for adding, removing, and running hooks +# in the main code. A hook is just a list of function names that can be +# run in order later on. + +# func_hookable FUNC_NAME +# ----------------------- +# Declare that FUNC_NAME will run hooks added with +# 'func_add_hook FUNC_NAME ...'. +func_hookable () +{ + $debug_cmd + + func_append hookable_fns " $1" +} + + +# func_add_hook FUNC_NAME HOOK_FUNC +# --------------------------------- +# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must +# first have been declared "hookable" by a call to 'func_hookable'. +func_add_hook () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not accept hook functions." ;; + esac + + eval func_append ${1}_hooks '" $2"' +} + + +# func_remove_hook FUNC_NAME HOOK_FUNC +# ------------------------------------ +# Remove HOOK_FUNC from the list of hook functions to be called by +# FUNC_NAME. +func_remove_hook () +{ + $debug_cmd + + eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' +} + + +# func_propagate_result FUNC_NAME_A FUNC_NAME_B +# --------------------------------------------- +# If the *_result variable of FUNC_NAME_A _is set_, assign its value to +# *_result variable of FUNC_NAME_B. +func_propagate_result () +{ + $debug_cmd + + func_propagate_result_result=: + if eval "test \"\${${1}_result+set}\" = set" + then + eval "${2}_result=\$${1}_result" + else + func_propagate_result_result=false + fi +} + + +# func_run_hooks FUNC_NAME [ARG]... +# --------------------------------- +# Run all hook functions registered to FUNC_NAME. +# It's assumed that the list of hook functions contains nothing more +# than a whitespace-delimited list of legal shell function names, and +# no effort is wasted trying to catch shell meta-characters or preserve +# whitespace. +func_run_hooks () +{ + $debug_cmd + + _G_rc_run_hooks=false + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not support hook functions." ;; + esac + + eval _G_hook_fns=\$$1_hooks; shift + + for _G_hook in $_G_hook_fns; do + func_unset "${_G_hook}_result" + eval $_G_hook '${1+"$@"}' + func_propagate_result $_G_hook func_run_hooks + if $func_propagate_result_result; then + eval set dummy "$func_run_hooks_result"; shift + fi + done +} + + + +## --------------- ## +## Option parsing. ## +## --------------- ## + +# In order to add your own option parsing hooks, you must accept the +# full positional parameter list from your hook function. You may remove +# or edit any options that you action, and then pass back the remaining +# unprocessed options in '_result', escaped +# suitably for 'eval'. +# +# The '_result' variable is automatically unset +# before your hook gets called; for best performance, only set the +# *_result variable when necessary (i.e. don't call the 'func_quote' +# function unnecessarily because it can be an expensive operation on some +# machines). +# +# Like this: +# +# my_options_prep () +# { +# $debug_cmd +# +# # Extend the existing usage message. +# usage_message=$usage_message' +# -s, --silent don'\''t print informational messages +# ' +# # No change in '$@' (ignored completely by this hook). Leave +# # my_options_prep_result variable intact. +# } +# func_add_hook func_options_prep my_options_prep +# +# +# my_silent_option () +# { +# $debug_cmd +# +# args_changed=false +# +# # Note that, for efficiency, we parse as many options as we can +# # recognise in a loop before passing the remainder back to the +# # caller on the first unrecognised argument we encounter. +# while test $# -gt 0; do +# opt=$1; shift +# case $opt in +# --silent|-s) opt_silent=: +# args_changed=: +# ;; +# # Separate non-argument short options: +# -s*) func_split_short_opt "$_G_opt" +# set dummy "$func_split_short_opt_name" \ +# "-$func_split_short_opt_arg" ${1+"$@"} +# shift +# args_changed=: +# ;; +# *) # Make sure the first unrecognised option "$_G_opt" +# # is added back to "$@" in case we need it later, +# # if $args_changed was set to 'true'. +# set dummy "$_G_opt" ${1+"$@"}; shift; break ;; +# esac +# done +# +# # Only call 'func_quote' here if we processed at least one argument. +# if $args_changed; then +# func_quote eval ${1+"$@"} +# my_silent_option_result=$func_quote_result +# fi +# } +# func_add_hook func_parse_options my_silent_option +# +# +# my_option_validation () +# { +# $debug_cmd +# +# $opt_silent && $opt_verbose && func_fatal_help "\ +# '--silent' and '--verbose' options are mutually exclusive." +# } +# func_add_hook func_validate_options my_option_validation +# +# You'll also need to manually amend $usage_message to reflect the extra +# options you parse. It's preferable to append if you can, so that +# multiple option parsing hooks can be added safely. + + +# func_options_finish [ARG]... +# ---------------------------- +# Finishing the option parse loop (call 'func_options' hooks ATM). +func_options_finish () +{ + $debug_cmd + + func_run_hooks func_options ${1+"$@"} + func_propagate_result func_run_hooks func_options_finish +} + + +# func_options [ARG]... +# --------------------- +# All the functions called inside func_options are hookable. See the +# individual implementations for details. +func_hookable func_options +func_options () +{ + $debug_cmd + + _G_options_quoted=false + + for my_func in options_prep parse_options validate_options options_finish + do + func_unset func_${my_func}_result + func_unset func_run_hooks_result + eval func_$my_func '${1+"$@"}' + func_propagate_result func_$my_func func_options + if $func_propagate_result_result; then + eval set dummy "$func_options_result"; shift + _G_options_quoted=: + fi + done + + $_G_options_quoted || { + # As we (func_options) are top-level options-parser function and + # nobody quoted "$@" for us yet, we need to do it explicitly for + # caller. + func_quote eval ${1+"$@"} + func_options_result=$func_quote_result + } +} + + +# func_options_prep [ARG]... +# -------------------------- +# All initialisations required before starting the option parse loop. +# Note that when calling hook functions, we pass through the list of +# positional parameters. If a hook function modifies that list, and +# needs to propagate that back to rest of this script, then the complete +# modified list must be put in 'func_run_hooks_result' before returning. +func_hookable func_options_prep +func_options_prep () +{ + $debug_cmd + + # Option defaults: + opt_verbose=false + opt_warning_types= + + func_run_hooks func_options_prep ${1+"$@"} + func_propagate_result func_run_hooks func_options_prep +} + + +# func_parse_options [ARG]... +# --------------------------- +# The main option parsing loop. +func_hookable func_parse_options +func_parse_options () +{ + $debug_cmd + + _G_parse_options_requote=false + # this just eases exit handling + while test $# -gt 0; do + # Defer to hook functions for initial option parsing, so they + # get priority in the event of reusing an option name. + func_run_hooks func_parse_options ${1+"$@"} + func_propagate_result func_run_hooks func_parse_options + if $func_propagate_result_result; then + eval set dummy "$func_parse_options_result"; shift + # Even though we may have changed "$@", we passed the "$@" array + # down into the hook and it quoted it for us (because we are in + # this if-branch). No need to quote it again. + _G_parse_options_requote=false + fi + + # Break out of the loop if we already parsed every option. + test $# -gt 0 || break + + # We expect that one of the options parsed in this function matches + # and thus we remove _G_opt from "$@" and need to re-quote. + _G_match_parse_options=: + _G_opt=$1 + shift + case $_G_opt in + --debug|-x) debug_cmd='set -x' + func_echo "enabling shell trace mode" >&2 + $debug_cmd + ;; + + --no-warnings|--no-warning|--no-warn) + set dummy --warnings none ${1+"$@"} + shift + ;; + + --warnings|--warning|-W) + if test $# = 0 && func_missing_arg $_G_opt; then + _G_parse_options_requote=: + break + fi + case " $warning_categories $1" in + *" $1 "*) + # trailing space prevents matching last $1 above + func_append_uniq opt_warning_types " $1" + ;; + *all) + opt_warning_types=$warning_categories + ;; + *none) + opt_warning_types=none + warning_func=: + ;; + *error) + opt_warning_types=$warning_categories + warning_func=func_fatal_error + ;; + *) + func_fatal_error \ + "unsupported warning category: '$1'" + ;; + esac + shift + ;; + + --verbose|-v) opt_verbose=: ;; + --version) func_version ;; + -\?|-h) func_usage ;; + --help) func_help ;; + + # Separate optargs to long options (plugins may need this): + --*=*) func_split_equals "$_G_opt" + set dummy "$func_split_equals_lhs" \ + "$func_split_equals_rhs" ${1+"$@"} + shift + ;; + + # Separate optargs to short options: + -W*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-v*|-x*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) _G_parse_options_requote=: ; break ;; + -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; + *) set dummy "$_G_opt" ${1+"$@"}; shift + _G_match_parse_options=false + break + ;; + esac + + if $_G_match_parse_options; then + _G_parse_options_requote=: + fi + done + + if $_G_parse_options_requote; then + # save modified positional parameters for caller + func_quote eval ${1+"$@"} + func_parse_options_result=$func_quote_result + fi +} + + +# func_validate_options [ARG]... +# ------------------------------ +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +func_hookable func_validate_options +func_validate_options () +{ + $debug_cmd + + # Display all warnings if -W was not given. + test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" + + func_run_hooks func_validate_options ${1+"$@"} + func_propagate_result func_run_hooks func_validate_options + + # Bail if the options were screwed! + $exit_cmd $EXIT_FAILURE +} + + + +## ----------------- ## +## Helper functions. ## +## ----------------- ## + +# This section contains the helper functions used by the rest of the +# hookable option parser framework in ascii-betical order. + + +# func_fatal_help ARG... +# ---------------------- +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + eval \$ECHO \""$fatal_help"\" + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + + +# func_help +# --------- +# Echo long help message to standard output and exit. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message" + exit 0 +} + + +# func_missing_arg ARGNAME +# ------------------------ +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $debug_cmd + + func_error "Missing argument for '$1'." + exit_cmd=exit +} + + +# func_split_equals STRING +# ------------------------ +# Set func_split_equals_lhs and func_split_equals_rhs shell variables +# after splitting STRING at the '=' sign. +test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=${1%%=*} + func_split_equals_rhs=${1#*=} + if test "x$func_split_equals_lhs" = "x$1"; then + func_split_equals_rhs= + fi + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` + func_split_equals_rhs= + test "x$func_split_equals_lhs=" = "x$1" \ + || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` + } +fi #func_split_equals + + +# func_split_short_opt SHORTOPT +# ----------------------------- +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"} + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_name=`expr "x$1" : 'x\(-.\)'` + func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` + } +fi #func_split_short_opt + + +# func_usage +# ---------- +# Echo short help message to standard output and exit. +func_usage () +{ + $debug_cmd + + func_usage_message + $ECHO "Run '$progname --help |${PAGER-more}' for full usage" + exit 0 +} + + +# func_usage_message +# ------------------ +# Echo short help message to standard output. +func_usage_message () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + echo + $SED -n 's|^# || + /^Written by/{ + x;p;x + } + h + /^Written by/q' < "$progpath" + echo + eval \$ECHO \""$usage_message"\" +} + + +# func_version +# ------------ +# Echo version message to standard output and exit. +# The version message is extracted from the calling file's header +# comments, with leading '# ' stripped: +# 1. First display the progname and version +# 2. Followed by the header comment line matching /^# Written by / +# 3. Then a blank line followed by the first following line matching +# /^# Copyright / +# 4. Immediately followed by any lines between the previous matches, +# except lines preceding the intervening completely blank line. +# For example, see the header comments of this file. +func_version () +{ + $debug_cmd + + printf '%s\n' "$progname $scriptversion" + $SED -n ' + /^# Written by /!b + s|^# ||; p; n + + :fwd2blnk + /./ { + n + b fwd2blnk + } + p; n + + :holdwrnt + s|^# || + s|^# *$|| + /^Copyright /!{ + /./H + n + b holdwrnt + } + + s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| + G + s|\(\n\)\n*|\1|g + p; q' < "$progpath" + + exit $? +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: + +# Set a version string. +scriptversion='(GNU libtool) 2.4.7' + + +# func_echo ARG... +# ---------------- +# Libtool also displays the current mode in messages, so override +# funclib.sh func_echo with this custom definition. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_warning ARG... +# ------------------- +# Libtool warnings are not categorized, so override funclib.sh +# func_warning with this simpler definition. +func_warning () +{ + $debug_cmd + + $warning_func ${1+"$@"} +} + + +## ---------------- ## +## Options parsing. ## +## ---------------- ## + +# Hook in the functions to make sure our own options are parsed during +# the option parsing loop. + +usage='$progpath [OPTION]... [MODE-ARG]...' + +# Short help message in response to '-h'. +usage_message="Options: + --config show all configuration variables + --debug enable verbose shell tracing + -n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --mode=MODE use operation mode MODE + --no-warnings equivalent to '-Wnone' + --preserve-dup-deps don't remove duplicate dependency libraries + --quiet, --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + -v, --verbose print more informational messages than default + --version print version information + -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] + -h, --help, --help-all print short, long, or detailed help message +" + +# Additional text appended to 'usage_message' in response to '--help'. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. When passed as first option, +'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. +Try '$progname --help --mode=MODE' for a more detailed description of MODE. + +When reporting a bug, please describe a test case to reproduce it and +include the following information: + + host-triplet: $host + shell: $SHELL + compiler: $LTCC + compiler flags: $LTCFLAGS + linker: $LD (gnu? $with_gnu_ld) + version: $progname $scriptversion Debian-2.4.7-7 + automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` + autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` + +Report bugs to . +GNU libtool home page: . +General help using GNU software: ." + exit 0 +} + + +# func_lo2o OBJECT-NAME +# --------------------- +# Transform OBJECT-NAME from a '.lo' suffix to the platform specific +# object suffix. + +lo2o=s/\\.lo\$/.$objext/ +o2lo=s/\\.$objext\$/.lo/ + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_lo2o () + { + case $1 in + *.lo) func_lo2o_result=${1%.lo}.$objext ;; + * ) func_lo2o_result=$1 ;; + esac + }' + + # func_xform LIBOBJ-OR-SOURCE + # --------------------------- + # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) + # suffix to a '.lo' libtool-object suffix. + eval 'func_xform () + { + func_xform_result=${1%.*}.lo + }' +else + # ...otherwise fall back to using sed. + func_lo2o () + { + func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` + } + + func_xform () + { + func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` + } +fi + + +# func_fatal_configuration ARG... +# ------------------------------- +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_fatal_error ${1+"$@"} \ + "See the $PACKAGE documentation for more information." \ + "Fatal configuration error." +} + + +# func_config +# ----------- +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + + +# func_features +# ------------- +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test yes = "$build_libtool_libs"; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test yes = "$build_old_libs"; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + + +# func_enable_tag TAGNAME +# ----------------------- +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname=$1 + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf=/$re_begincf/,/$re_endcf/p + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + + +# func_check_version_match +# ------------------------ +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# libtool_options_prep [ARG]... +# ----------------------------- +# Preparation for options parsed by libtool. +libtool_options_prep () +{ + $debug_mode + + # Option defaults: + opt_config=false + opt_dlopen= + opt_dry_run=false + opt_help=false + opt_mode= + opt_preserve_dup_deps=false + opt_quiet=false + + nonopt= + preserve_args= + + _G_rc_lt_options_prep=: + + _G_rc_lt_options_prep=: + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + *) + _G_rc_lt_options_prep=false + ;; + esac + + if $_G_rc_lt_options_prep; then + # Pass back the list of options. + func_quote eval ${1+"$@"} + libtool_options_prep_result=$func_quote_result + fi +} +func_add_hook func_options_prep libtool_options_prep + + +# libtool_parse_options [ARG]... +# --------------------------------- +# Provide handling for libtool specific options. +libtool_parse_options () +{ + $debug_cmd + + _G_rc_lt_parse_options=false + + # Perform our own loop to consume as many options as possible in + # each iteration. + while test $# -gt 0; do + _G_match_lt_parse_options=: + _G_opt=$1 + shift + case $_G_opt in + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + + --config) func_config ;; + + --dlopen|-dlopen) + opt_dlopen="${opt_dlopen+$opt_dlopen +}$1" + shift + ;; + + --preserve-dup-deps) + opt_preserve_dup_deps=: ;; + + --features) func_features ;; + + --finish) set dummy --mode finish ${1+"$@"}; shift ;; + + --help) opt_help=: ;; + + --help-all) opt_help=': help-all' ;; + + --mode) test $# = 0 && func_missing_arg $_G_opt && break + opt_mode=$1 + case $1 in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $_G_opt" + exit_cmd=exit + break + ;; + esac + shift + ;; + + --no-silent|--no-quiet) + opt_quiet=false + func_append preserve_args " $_G_opt" + ;; + + --no-warnings|--no-warning|--no-warn) + opt_warning=false + func_append preserve_args " $_G_opt" + ;; + + --no-verbose) + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --silent|--quiet) + opt_quiet=: + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --tag) test $# = 0 && func_missing_arg $_G_opt && break + opt_tag=$1 + func_append preserve_args " $_G_opt $1" + func_enable_tag "$1" + shift + ;; + + --verbose|-v) opt_quiet=false + opt_verbose=: + func_append preserve_args " $_G_opt" + ;; + + # An option not handled by this hook function: + *) set dummy "$_G_opt" ${1+"$@"} ; shift + _G_match_lt_parse_options=false + break + ;; + esac + $_G_match_lt_parse_options && _G_rc_lt_parse_options=: + done + + if $_G_rc_lt_parse_options; then + # save modified positional parameters for caller + func_quote eval ${1+"$@"} + libtool_parse_options_result=$func_quote_result + fi +} +func_add_hook func_parse_options libtool_parse_options + + + +# libtool_validate_options [ARG]... +# --------------------------------- +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +libtool_validate_options () +{ + # save first non-option argument + if test 0 -lt $#; then + nonopt=$1 + shift + fi + + # preserve --debug + test : = "$debug_cmd" || func_append preserve_args " --debug" + + case $host in + # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 + # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + test yes != "$build_libtool_libs" \ + && test yes != "$build_old_libs" \ + && func_fatal_configuration "not configured to build any kind of library" + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test execute != "$opt_mode"; then + func_error "unrecognized option '-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help=$help + help="Try '$progname --help --mode=$opt_mode' for more information." + } + + # Pass back the unparsed argument list + func_quote eval ${1+"$@"} + libtool_validate_options_result=$func_quote_result +} +func_add_hook func_validate_options libtool_validate_options + + +# Process options as early as possible so that --help and --version +# can return quickly. +func_options ${1+"$@"} +eval set dummy "$func_options_result"; shift + + + +## ----------- ## +## Main. ## +## ----------- ## + +magic='%%%MAGIC variable%%%' +magic_exe='%%%MAGIC EXE variable%%%' + +# Global variables. +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# func_generated_by_libtool +# True iff stdin has been generated by Libtool. This function is only +# a basic sanity check; it will hardly flush out determined imposters. +func_generated_by_libtool_p () +{ + $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if 'file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case $lalib_p_line in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test yes = "$lalib_p" +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + test -f "$1" && + $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $debug_cmd + + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# 'FILE.' does not work on cygwin managed mounts. +func_source () +{ + $debug_cmd + + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case $lt_sysroot:$1 in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result='='$func_stripname_result + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $debug_cmd + + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with '--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=$1 + if test yes = "$build_libtool_libs"; then + write_lobj=\'$2\' + else + write_lobj=none + fi + + if test yes = "$build_old_libs"; then + write_oldobj=\'$3\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $debug_cmd + + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result= + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result"; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $debug_cmd + + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $debug_cmd + + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $debug_cmd + + if test -z "$2" && test -n "$1"; then + func_error "Could not determine host file name corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result=$1 + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $debug_cmd + + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " '$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result=$3 + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $debug_cmd + + case $4 in + $1 ) func_to_host_path_result=$3$func_to_host_path_result + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via '$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $debug_cmd + + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $debug_cmd + + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result=$1 +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result=$func_convert_core_msys_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result=$func_convert_core_file_wine_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via '$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $debug_cmd + + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd=func_convert_path_$func_stripname_result + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $debug_cmd + + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result=$1 +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_msys_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_path_wine_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_dll_def_p FILE +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with _LT_DLL_DEF_P in libtool.m4 +func_dll_def_p () +{ + $debug_cmd + + func_dll_def_p_tmp=`$SED -n \ + -e 's/^[ ]*//' \ + -e '/^\(;.*\)*$/d' \ + -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ + -e q \ + "$1"` + test DEF = "$func_dll_def_p_tmp" +} + + +# func_mode_compile arg... +func_mode_compile () +{ + $debug_cmd + + # Get the compilation command and the source file. + base_compile= + srcfile=$nonopt # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg=$arg + arg_mode=normal + ;; + + target ) + libobj=$arg + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify '-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs=$IFS; IFS=, + for arg in $args; do + IFS=$save_ifs + func_append_quoted lastarg "$arg" + done + IFS=$save_ifs + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg=$srcfile + srcfile=$arg + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with '-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj=$func_basename_result + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from '$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test yes = "$build_libtool_libs" \ + || func_fatal_configuration "cannot build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_arg pretty "$libobj" + test "X$libobj" != "X$func_quote_arg_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name '$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname=$func_basename_result + xdir=$func_dirname_result + lobj=$xdir$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test yes = "$build_old_libs"; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test no = "$compiler_c_o"; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext + lockfile=$output_obj.lock + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test yes = "$need_locks"; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test warn = "$need_locks"; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_arg pretty "$srcfile" + qsrcfile=$func_quote_arg_result + + # Only build a PIC object if we are building libtool libraries. + if test yes = "$build_libtool_libs"; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test no != "$pic_mode"; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test yes = "$suppress_opt"; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test yes = "$build_old_libs"; then + if test yes != "$pic_mode"; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test yes = "$compiler_c_o"; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test no != "$need_locks"; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test compile = "$opt_mode" && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a '.o' file suitable for static linking + -static only build a '.o' file suitable for static linking + -Wc,FLAG + -Xcompiler FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a 'standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix '.c' with the +library object suffix, '.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to '-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the '--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the 'install' or 'cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE use a list of object files found in FILE to specify objects + -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wa,FLAG + -Xassembler FLAG pass linker-specific FLAG directly to the assembler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with '-') are ignored. + +Every other argument is treated as a filename. Files ending in '.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in '.la', then a libtool library is created, +only library objects ('.lo' files) may be specified, and '-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created +using 'ar' and 'ranlib', or on Windows using 'lib'. + +If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode '$opt_mode'" + ;; + esac + + echo + $ECHO "Try '$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test : = "$opt_help"; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | $SED -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + $SED '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $debug_cmd + + # The first argument is the command name. + cmd=$nonopt + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "'$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "'$file' was not linked with '-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir=$func_dirname_result + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir=$func_dirname_result + ;; + + *) + func_warning "'-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir=$absdir + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic=$magic + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file=$progdir/$program + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file=$progdir/$program + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if $opt_dry_run; then + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + else + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd=\$cmd$args + fi +} + +test execute = "$opt_mode" && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $debug_cmd + + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "'$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument '$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and '=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_quiet && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the '-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the '$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the '$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the '$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test finish = "$opt_mode" && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $debug_cmd + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac + then + # Aesthetically quote it. + func_quote_arg pretty "$nonopt" + install_prog="$func_quote_arg_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_arg pretty "$arg" + func_append install_prog "$func_quote_arg_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=false + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=: ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test X-m = "X$prev" && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_arg pretty "$arg" + func_append install_prog " $func_quote_arg_result" + if test -n "$arg2"; then + func_quote_arg pretty "$arg2" + fi + func_append install_shared_prog " $func_quote_arg_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the '$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_arg pretty "$install_override_mode" + func_append install_shared_prog " -m $func_quote_arg_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=: + if $isdir; then + destdir=$dest + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir=$func_dirname_result + destname=$func_basename_result + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "'$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "'$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic=$magic + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir=$func_dirname_result + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking '$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname=$1 + shift + + srcname=$realname + test -n "$relink_command" && srcname=${realname}T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme=$stripme + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme= + ;; + esac + ;; + os2*) + case $realname in + *_dll.a) + tstripme= + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try 'ln -sf' first, because the 'ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib=$destdir/$realname + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name=$func_basename_result + instname=$dir/${name}i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile=$destdir/$destname + else + func_basename "$file" + destfile=$func_basename_result + destfile=$destdir/$destfile + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest=$destfile + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to '$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test yes = "$build_old_libs"; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile=$destdir/$destname + else + func_basename "$file" + destfile=$func_basename_result + destfile=$destdir/$destfile + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext= + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=.exe + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script '$wrapper'" + + finalize=: + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "'$lib' has not been installed in '$libdir'" + finalize=false + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test no = "$fast_install" && test -n "$relink_command"; then + $opt_dry_run || { + if $finalize; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file=$func_basename_result + outputname=$tmpdir/$file + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_quiet || { + func_quote_arg expand,pretty "$relink_command" + eval "func_echo $func_quote_arg_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink '$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file=$outputname + else + func_warning "cannot relink '$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name=$func_basename_result + + # Set up the ranlib parameters. + oldlib=$destdir/$name + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run '$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test install = "$opt_mode" && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $debug_cmd + + my_outputname=$1 + my_originator=$2 + my_pic_p=${3-false} + my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms=${my_outputname}S.c + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist=$output_objdir/$my_outputname.nm + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* External symbol declarations for the compiler. */\ +" + + if test yes = "$dlself"; then + func_verbose "generating symbol list for '$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from '$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols=$output_objdir/$outputname.exp + $opt_dry_run || { + $RM $export_symbols + eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from '$dlprefile'" + func_basename "$dlprefile" + name=$func_basename_result + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename= + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname"; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename=$func_basename_result + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename"; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + func_show_eval '$RM "${nlist}I"' + if test -n "$global_symbol_to_import"; then + eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[];\ +" + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ +static void lt_syminit(void) +{ + LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; + for (; symbol->name; ++symbol) + {" + $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" + echo >> "$output_objdir/$my_dlsyms" "\ + } +}" + fi + echo >> "$output_objdir/$my_dlsyms" "\ +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{ {\"$my_originator\", (void *) 0}," + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ + {\"@INIT@\", (void *) <_syminit}," + fi + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + $my_pic_p && pic_flag_for_symtable=" $pic_flag" + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' + + # Transform the symbol file into the correct name. + symfileobj=$output_objdir/${my_outputname}S.$objext + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for '$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $debug_cmd + + win32_libid_type=unknown + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + case $nm_interface in + "MS dumpbin") + if func_cygming_ms_implib_p "$1" || + func_cygming_gnu_implib_p "$1" + then + win32_nmres=import + else + win32_nmres= + fi + ;; + *) + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s|.*|import| + p + q + } + }'` + ;; + esac + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $debug_cmd + + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $debug_cmd + + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive that possess that section. Heuristic: eliminate + # all those that have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $debug_cmd + + if func_cygming_gnu_implib_p "$1"; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1"; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result= + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $debug_cmd + + f_ex_an_ar_dir=$1; shift + f_ex_an_ar_oldlib=$1 + if test yes = "$lock_old_archive_extraction"; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test yes = "$lock_old_archive_extraction"; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $debug_cmd + + my_gentop=$1; shift + my_oldlibs=${1+"$@"} + my_oldobjs= + my_xlib= + my_xabs= + my_xdir= + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib=$func_basename_result + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir=$my_gentop/$my_xlib_u + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + func_basename "$darwin_archive" + darwin_base_archive=$func_basename_result + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches; do + func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" + $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" + cd "unfat-$$/$darwin_base_archive-$darwin_arch" + func_extract_an_archive "`pwd`" "$darwin_base_archive" + cd "$darwin_curdir" + $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result=$my_oldobjs +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory where it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + func_quote_arg pretty "$ECHO" + qECHO=$func_quote_arg_result + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=$qECHO + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ that is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options that match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test yes = "$fast_install"; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + \$ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* declarations of non-ANSI functions */ +#if defined __MINGW32__ +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined __CYGWIN__ +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined other_platform || defined ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined _MSC_VER +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +#elif defined __MINGW32__ +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined __CYGWIN__ +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined other platforms ... */ +#endif + +#if defined PATH_MAX +# define LT_PATHMAX PATH_MAX +#elif defined MAXPATHLEN +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ + defined __OS2__ +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free (stale); stale = 0; } \ +} while (0) + +#if defined LT_DEBUGWRAPPER +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + size_t tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined HAVE_DOS_BASED_FILE_SYSTEM + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined HAVE_DOS_BASED_FILE_SYSTEM + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = (size_t) (q - p); + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (STREQ (str, pat)) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + size_t len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + size_t orig_value_len = strlen (orig_value); + size_t add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + size_t len = strlen (new_value); + while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[--len] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $debug_cmd + + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_suncc_cstd_abi +# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! +# Several compiler flags select an ABI that is incompatible with the +# Cstd library. Avoid specifying it if any are in CXXFLAGS. +func_suncc_cstd_abi () +{ + $debug_cmd + + case " $compile_command " in + *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) + suncc_use_cstd_abi=no + ;; + *) + suncc_use_cstd_abi=yes + ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $debug_cmd + + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # what system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll that has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + os2dllname= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=false + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module=$wl-single_module + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test yes != "$build_libtool_libs" \ + && func_fatal_configuration "cannot build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg=$1 + shift + func_quote_arg pretty,unquoted "$arg" + qarg=$func_quote_arg_unquoted_result + func_append libtool_args " $func_quote_arg_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir=$arg + prev= + continue + ;; + dlfiles|dlprefiles) + $preload || { + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=: + } + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test no = "$dlself"; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test dlprefiles = "$prev"; then + dlself=yes + elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test dlfiles = "$prev"; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols=$arg + test -f "$arg" \ + || func_fatal_error "symbol file '$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex=$arg + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir=$arg + prev= + continue + ;; + mllvm) + # Clang does not use LLVM to link, so we can simply discard any + # '-mllvm $arg' options when doing the link step. + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + if test none != "$pic_object"; then + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + fi + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; then + arg=$non_pic_object + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object=$pic_object + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file '$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + os2dllname) + os2dllname=$arg + prev= + continue + ;; + precious_regex) + precious_files_regex=$arg + prev= + continue + ;; + release) + release=-$arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test rpath = "$prev"; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds=$arg + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xassembler) + func_append compiler_flags " -Xassembler $qarg" + prev= + func_append compile_command " -Xassembler $qarg" + func_append finalize_command " -Xassembler $qarg" + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg=$arg + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "'-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test X-export-symbols = "X$arg"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between '-L' and '$1'" + else + func_fatal_error "need path for '-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of '$dir'" + dir=$absdir + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test X-lc = "X$arg" || test X-lm = "X$arg"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test X-lc = "X$arg" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) + # Do not include libc due to us having libc/libc_r. + test X-lc = "X$arg" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test X-lc = "X$arg" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test X-lc = "X$arg" && continue + ;; + esac + elif test X-lc_r = "X$arg"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -mllvm) + prev=mllvm + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + # Solaris ld rejects as of 11.4. Refer to Oracle bug 22985199. + -pthread) + case $host in + *solaris2*) ;; + *) + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + ;; + esac + continue + ;; + -mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module=$wl-multi_module + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "'-no-install' is ignored for $host" + func_warning "assuming '-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -os2dllname) + prev=os2dllname + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_arg pretty "$flag" + func_append arg " $func_quote_arg_result" + func_append compiler_flags " $func_quote_arg_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_arg pretty "$flag" + func_append arg " $wl$func_quote_arg_result" + func_append compiler_flags " $wl$func_quote_arg_result" + func_append linker_flags " $func_quote_arg_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xassembler) + prev=xassembler + continue + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # -fstack-protector* stack protector flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + # -specs=* GCC specs files + # -stdlib=* select c++ std lib with clang + # -fsanitize=* Clang/GCC memory and address sanitizer + # -fuse-ld=* Linker select flags for GCC + # -static-* direct GCC to link specific libraries statically + # -fcilkplus Cilk Plus language extension features for C/C++ + # -Wa,* Pass flags directly to the assembler + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ + -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus|-Wa,*) + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + -Z*) + if test os2 = "`expr $host : '.*\(os2\)'`"; then + # OS/2 uses -Zxxx to specify OS/2-specific options + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case $arg in + -Zlinker | -Zstack) + prev=xcompiler + ;; + esac + continue + else + # Otherwise treat like 'Some other compiler flag' below + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + fi + ;; + + # Some other compiler flag. + -* | +*) + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + test none = "$pic_object" || { + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + } + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; then + arg=$non_pic_object + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object=$pic_object + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test dlfiles = "$prev"; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test dlprefiles = "$prev"; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the '$prevarg' option requires an argument" + + if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname=$func_basename_result + libobjs_save=$libobjs + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + # Definition is injected by LT_CONFIG during libtool generation. + func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" + + func_dirname "$output" "/" "" + output_objdir=$func_dirname_result$objdir + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test lib = "$linkmode"; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=false + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test lib,link = "$linkmode,$pass"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs=$tmp_deplibs + fi + + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass"; then + libs=$deplibs + deplibs= + fi + if test prog = "$linkmode"; then + case $pass in + dlopen) libs=$dlfiles ;; + dlpreopen) libs=$dlprefiles ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test lib,dlpreopen = "$linkmode,$pass"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs=$dlprefiles + fi + if test dlopen = "$pass"; then + # Collect dlpreopened libraries + save_deplibs=$deplibs + deplibs= + fi + + for deplib in $libs; do + lib= + found=false + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test lib != "$linkmode" && test prog != "$linkmode"; then + func_warning "'-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test lib = "$linkmode"; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib=$searchdir/lib$name$search_ext + if test -f "$lib"; then + if test .la = "$search_ext"; then + found=: + else + found=false + fi + break 2 + fi + done + done + if $found; then + # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll=$l + done + if test "X$ll" = "X$old_library"; then # only static version available + found=false + func_dirname "$lib" "" "." + ladir=$func_dirname_result + lib=$ladir/$old_library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + else + # deplib doesn't seem to be a libtool library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + *.ltframework) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test conv = "$pass" && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + if test scan = "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "'-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test link = "$pass"; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=false + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=: + fi + ;; + pass_all) + valid_a_lib=: + ;; + esac + if $valid_a_lib; then + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + else + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + fi + ;; + esac + continue + ;; + prog) + if test link != "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + elif test prog = "$linkmode"; then + if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=: + continue + ;; + esac # case $deplib + + $found || test -f "$lib" \ + || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "'$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir=$func_dirname_result + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass" || + { test prog != "$linkmode" && test lib != "$linkmode"; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test conv = "$pass"; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test prog != "$linkmode" && test lib != "$linkmode"; then + func_fatal_error "'$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test yes = "$prefer_static_libs" || + test built,no = "$prefer_static_libs,$installed"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib=$l + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + + # This library was specified with -dlopen. + if test dlopen = "$pass"; then + test -z "$libdir" \ + && func_fatal_error "cannot -dlopen a convenience library: '$lib'" + if test -z "$dlname" || + test yes != "$dlopen_support" || + test no = "$build_libtool_libs" + then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of '$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir=$ladir + fi + ;; + esac + func_basename "$lib" + laname=$func_basename_result + + # Find the relevant object directory and library name. + if test yes = "$installed"; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library '$lib' was moved." + dir=$ladir + absdir=$abs_ladir + libdir=$abs_ladir + else + dir=$lt_sysroot$libdir + absdir=$lt_sysroot$libdir + fi + test yes = "$hardcode_automatic" && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir=$ladir + absdir=$abs_ladir + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir=$ladir/$objdir + absdir=$abs_ladir/$objdir + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test dlpreopen = "$pass"; then + if test -z "$libdir" && test prog = "$linkmode"; then + func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" + fi + case $host in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test lib = "$linkmode"; then + deplibs="$dir/$old_library $deplibs" + elif test prog,link = "$linkmode,$pass"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test prog = "$linkmode" && test link != "$pass"; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=false + if test no != "$link_all_deplibs" || test -z "$library_names" || + test no = "$build_libtool_libs"; then + linkalldeplibs=: + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if $linkalldeplibs; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test prog,link = "$linkmode,$pass"; then + if test -n "$library_names" && + { { test no = "$prefer_static_libs" || + test built,yes = "$prefer_static_libs,$installed"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then + # Make sure the rpath contains only unique directories. + case $temp_rpath: in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if $alldeplibs && + { test pass_all = "$deplibs_check_method" || + { test yes = "$build_libtool_libs" && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test built = "$use_static_libs" && test yes = "$installed"; then + use_static_libs=no + fi + if test -n "$library_names" && + { test no = "$use_static_libs" || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc* | *os2*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test no = "$installed"; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule= + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule=$dlpremoduletest + break + fi + done + if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then + echo + if test prog = "$linkmode"; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test lib = "$linkmode" && + test yes = "$hardcode_into_libs"; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname=$1 + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname=$dlname + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc* | *os2*) + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + esac + eval soname=\"$soname_spec\" + else + soname=$realname + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot=$soname + func_basename "$soroot" + soname=$func_basename_result + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from '$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for '$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test prog = "$linkmode" || test relink != "$opt_mode"; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test no = "$hardcode_direct"; then + add=$dir/$linklib + case $host in + *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; + *-*-sysv4*uw2*) add_dir=-L$dir ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir=-L$dir ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we cannot + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library"; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add=$dir/$old_library + fi + elif test -n "$old_library"; then + add=$dir/$old_library + fi + fi + esac + elif test no = "$hardcode_minus_L"; then + case $host in + *-*-sunos*) add_shlibpath=$dir ;; + esac + add_dir=-L$dir + add=-l$name + elif test no = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + relink) + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$dir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$absdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test yes != "$lib_linked"; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test prog = "$linkmode"; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test yes != "$hardcode_direct" && + test yes != "$hardcode_minus_L" && + test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test prog = "$linkmode" || test relink = "$opt_mode"; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$libdir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$libdir + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add=-l$name + elif test yes = "$hardcode_automatic"; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib"; then + add=$inst_prefix_dir$libdir/$linklib + else + add=$libdir/$linklib + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir=-L$libdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + fi + + if test prog = "$linkmode"; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test prog = "$linkmode"; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test unsupported != "$hardcode_direct"; then + test -n "$old_library" && linklib=$old_library + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test yes = "$build_libtool_libs"; then + # Not a shared library + if test pass_all != "$deplibs_check_method"; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system cannot link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test yes = "$module"; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using 'nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** 'nm' from GNU binutils and a full rebuild may help." + fi + if test no = "$build_old_libs"; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test lib = "$linkmode"; then + if test -n "$dependency_libs" && + { test yes != "$hardcode_into_libs" || + test yes = "$build_old_libs" || + test yes = "$link_static"; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs=$temp_deplibs + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test no != "$link_all_deplibs"; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path=$deplib ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of '$dir'" + absdir=$dir + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names"; then + for tmp in $deplibrary_names; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl"; then + depdepl=$absdir/$objdir/$depdepl + darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" + func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" + path= + fi + fi + ;; + *) + path=-L$absdir/$objdir + ;; + esac + else + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "'$deplib' seems to be moved" + + path=-L$absdir + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test link = "$pass"; then + if test prog = "$linkmode"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs=$newdependency_libs + if test dlpreopen = "$pass"; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test dlopen != "$pass"; then + test conv = "$pass" || { + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + } + + if test prog,link = "$linkmode,$pass"; then + vars="compile_deplibs finalize_deplibs" + else + vars=deplibs + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + + # Add Sun CC postdeps if required: + test CXX = "$tagname" && { + case $host_os in + linux*) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) # Sun C++ 5.9 + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + + solaris*) + func_cc_basename "$CC" + case $func_cc_basename_result in + CC* | sunCC*) + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + esac + } + + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i= + ;; + esac + if test -n "$i"; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test prog = "$linkmode"; then + dlfiles=$newdlfiles + fi + if test prog = "$linkmode" || test lib = "$linkmode"; then + dlprefiles=$newdlprefiles + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "'-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "'-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs=$output + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form 'libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test no = "$module" \ + && func_fatal_help "libtool library '$output' must begin with 'lib'" + + if test no != "$need_lib_prefix"; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test pass_all != "$deplibs_check_method"; then + func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test no = "$dlself" \ + || func_warning "'-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test 1 -lt "$#" \ + && func_warning "ignoring multiple '-rpath's for a libtool library" + + install_libdir=$1 + + oldlibs= + if test -z "$rpath"; then + if test yes = "$build_libtool_libs"; then + # Building a libtool convenience library. + # Some compilers have problems with a '.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "'-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs=$IFS; IFS=: + set dummy $vinfo 0 0 0 + shift + IFS=$save_ifs + + test -n "$7" && \ + func_fatal_help "too many parameters to '-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major=$1 + number_minor=$2 + number_revision=$3 + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # that has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_revision + ;; + freebsd-aout|qnx|sunos) + current=$number_major + revision=$number_minor + age=0 + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_minor + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type '$version_type'" + ;; + esac + ;; + no) + current=$1 + revision=$2 + age=$3 + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT '$current' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION '$revision' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE '$age' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE '$age' is greater than the current interface number '$current'" + func_fatal_error "'$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + # On Darwin other compilers + case $CC in + nagfor*) + verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + ;; + *) + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + esac + ;; + + freebsd-aout) + major=.$current + versuffix=.$current.$revision + ;; + + freebsd-elf | midnightbsd-elf) + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + irix | nonstopux) + if test no = "$lt_irix_increment"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring=$verstring_prefix$major.$revision + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test 0 -ne "$loop"; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring_prefix$major.$iface:$verstring + done + + # Before this point, $major must not contain '.'. + major=.$major + versuffix=$major.$revision + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=.$current.$age.$revision + verstring=$current.$age.$revision + + # Add in all the interfaces that we are compatible with. + loop=$age + while test 0 -ne "$loop"; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring:$iface.0 + done + + # Make executables depend on our current version. + func_append verstring ":$current.0" + ;; + + qnx) + major=.$current + versuffix=.$current + ;; + + sco) + major=.$current + versuffix=.$current + ;; + + sunos) + major=.$current + versuffix=.$current.$revision + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 file systems. + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + + *) + func_fatal_configuration "unknown library version type '$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring=0.0 + ;; + esac + if test no = "$need_version"; then + versuffix= + else + versuffix=.0.0 + fi + fi + + # Remove version info from name if versioning should be avoided + if test yes,no = "$avoid_version,$need_version"; then + major= + versuffix= + verstring= + fi + + # Check to see if the archive will have undefined symbols. + if test yes = "$allow_undefined"; then + if test unsupported = "$allow_undefined_flag"; then + if test yes = "$build_old_libs"; then + func_warning "undefined symbols not allowed in $host shared libraries; building static only" + build_libtool_libs=no + else + func_fatal_error "can't build $host shared library unless -no-undefined is specified" + fi + fi + else + # Don't allow undefined symbols. + allow_undefined_flag=$no_undefined_flag + fi + + fi + + func_generate_dlsyms "$libname" "$libname" : + func_append libobjs " $symfileobj" + test " " = "$libobjs" && libobjs= + + if test relink != "$opt_mode"; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) + if test -n "$precious_files_regex"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles=$dlfiles + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles=$dlprefiles + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test yes = "$build_libtool_libs"; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test yes = "$build_libtool_need_lc"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release= + versuffix= + major= + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib=$potent_lib + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | $SED 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; + *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib= + break 2 + fi + done + done + fi + if test -n "$a_deplib"; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib"; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib= + ;; + esac + fi + if test -n "$a_deplib"; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib=$potent_lib # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib= + break 2 + fi + done + done + fi + if test -n "$a_deplib"; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib"; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs= + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + for i in $predeps $postdeps; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test none = "$deplibs_check_method"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test yes = "$droppeddeps"; then + if test yes = "$module"; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using 'nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** 'nm' from GNU binutils and a full rebuild may help." + fi + if test no = "$build_old_libs"; then + oldlibs=$output_objdir/$libname.$libext + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test no = "$allow_undefined"; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test no = "$build_old_libs"; then + oldlibs=$output_objdir/$libname.$libext + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs=$new_libs + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test yes = "$build_libtool_libs"; then + # Remove $wl instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test yes = "$hardcode_into_libs"; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath=$finalize_rpath + test relink = "$opt_mode" || rpath=$compile_rpath$rpath + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath=$finalize_shlibpath + test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname=$1 + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname=$realname + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib=$output_objdir/$realname + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols=$output_objdir/$libname.uexp + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + func_dll_def_p "$export_symbols" || { + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols=$export_symbols + export_symbols= + always_export_symbols=yes + } + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs=$IFS; IFS='~' + for cmd1 in $cmds; do + IFS=$save_ifs + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test yes = "$try_normal_branch" \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=$output_objdir/$output_la.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS=$save_ifs + if test -n "$export_symbols_regex" && test : != "$skipped_export"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test : != "$skipped_export" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs=$tmp_deplibs + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test yes = "$compiler_needs_object" && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test relink = "$opt_mode"; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test yes = "$module" && test -n "$module_cmds"; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test : != "$skipped_export" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then + output=$output_objdir/$output_la.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then + output=$output_objdir/$output_la.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test yes = "$compiler_needs_object"; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-$k.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test -z "$objlist" || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test 1 -eq "$k"; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-$k.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-$k.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + ${skipped_export-false} && { + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + } + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs=$IFS; IFS='~' + for cmd in $concat_cmds; do + IFS=$save_ifs + $opt_quiet || { + func_quote_arg expand,pretty "$cmd" + eval "func_echo $func_quote_arg_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS=$save_ifs + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + ${skipped_export-false} && { + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + } + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test yes = "$module" && test -n "$module_cmds"; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs=$IFS; IFS='~' + for cmd in $cmds; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + $opt_quiet || { + func_quote_arg expand,pretty "$cmd" + eval "func_echo $func_quote_arg_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS=$save_ifs + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test yes = "$module" || test yes = "$export_dynamic"; then + # On all known operating systems, these are identical. + dlname=$soname + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "'-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object '$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj=$output + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # if reload_cmds runs $LD directly, get rid of -Wl from + # whole_archive_flag_spec and hope we can get by with turning comma + # into space. + case $reload_cmds in + *\$LD[\ \$]*) wl= ;; + esac + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags + else + gentop=$output_objdir/${obj}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test yes = "$build_libtool_libs" || libobjs=$non_pic_objects + + # Create the old-style object. + reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs + + output=$obj + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + test yes = "$build_libtool_libs" || { + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + } + + if test -n "$pic_flag" || test default != "$pic_mode"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output=$libobj + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "'-release' is ignored for programs" + + $preload \ + && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ + && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test CXX = "$tagname"; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " $wl-bind_at_load" + func_append finalize_command " $wl-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs=$new_libs + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath=$rpath + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath=$rpath + + if test -n "$libobjs" && test yes = "$build_old_libs"; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" false + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=: + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=false + ;; + *cygwin* | *mingw* ) + test yes = "$build_libtool_libs" || wrappers_required=false + ;; + *) + if test no = "$need_relink" || test yes != "$build_libtool_libs"; then + wrappers_required=false + fi + ;; + esac + $wrappers_required || { + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command=$compile_command$compile_rpath + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.$objext"; then + func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' + fi + + exit $exit_status + } + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test yes = "$no_install"; then + # We don't need to create a wrapper script. + link_command=$compile_var$compile_command$compile_rpath + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + case $hardcode_action,$fast_install in + relink,*) + # Fast installation is not supported + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "'$output' will be relinked during installation" + ;; + *,yes) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + ;; + *,no) + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + ;; + *,needless) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command= + ;; + esac + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_arg pretty "$var_value" + relink_command="$var=$func_quote_arg_result; export $var; $relink_command" + fi + done + func_quote eval cd "`pwd`" + func_quote_arg pretty,unquoted "($func_quote_result; $relink_command)" + relink_command=$func_quote_arg_unquoted_result + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource=$output_path/$objdir/lt-$output_name.c + cwrapper=$output_path/$output_name.exe + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host"; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + case $build_libtool_libs in + convenience) + oldobjs="$libobjs_save $symfileobj" + addlibs=$convenience + build_libtool_libs=no + ;; + module) + oldobjs=$libobjs_save + addlibs=$old_convenience + build_libtool_libs=no + ;; + *) + oldobjs="$old_deplibs $non_pic_objects" + $preload && test -f "$symfileobj" \ + && func_append oldobjs " $symfileobj" + addlibs=$old_convenience + ;; + esac + + if test -n "$addlibs"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase=$func_basename_result + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj"; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test -z "$oldobjs"; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test yes = "$build_old_libs" && old_library=$libname.$libext + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_arg pretty,unquoted "$var_value" + relink_command="$var=$func_quote_arg_unquoted_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + func_quote eval cd "`pwd`" + relink_command="($func_quote_result; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + func_quote_arg pretty,unquoted "$relink_command" + relink_command=$func_quote_arg_unquoted_result + if test yes = "$hardcode_automatic"; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test yes = "$installed"; then + if test -z "$install_libdir"; then + break + fi + output=$output_objdir/${outputname}i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name=$func_basename_result + func_resolve_sysroot "$deplib" + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs=$newdependency_libs + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles=$newdlprefiles + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles=$newdlprefiles + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test -n "$bindir"; then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result/$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test no,yes = "$installed,$need_relink"; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +if test link = "$opt_mode" || test relink = "$opt_mode"; then + func_mode_link ${1+"$@"} +fi + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $debug_cmd + + RM=$nonopt + files= + rmforce=false + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic=$magic + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=: ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir=$func_dirname_result + if test . = "$dir"; then + odir=$objdir + else + odir=$dir/$objdir + fi + func_basename "$file" + name=$func_basename_result + test uninstall = "$opt_mode" && odir=$dir + + # Remember odir for removal later, being careful to avoid duplicates + if test clean = "$opt_mode"; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif $rmforce; then + continue + fi + + rmfiles=$file + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case $opt_mode in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && test none != "$pic_object"; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && test none != "$non_pic_object"; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test clean = "$opt_mode"; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.$objext" + if test yes = "$fast_install" && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name"; then + func_append rmfiles " $odir/lt-$noexename.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the $objdir's in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then + func_mode_uninstall ${1+"$@"} +fi + +test -z "$opt_mode" && { + help=$generic_help + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode '$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# where we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/m4/curl-amissl.m4 b/m4/curl-amissl.m4 new file mode 100644 index 0000000..48067e7 --- /dev/null +++ b/m4/curl-amissl.m4 @@ -0,0 +1,69 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +AC_DEFUN([CURL_WITH_AMISSL], [ +AC_MSG_CHECKING([whether to enable Amiga native SSL/TLS (AmiSSL v5)]) +if test "$HAVE_PROTO_BSDSOCKET_H" = "1"; then + if test "x$OPT_AMISSL" != xno; then + ssl_msg= + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include + #include + ]],[[ + #if defined(AMISSL_CURRENT_VERSION) && defined(AMISSL_V3xx) && \ + (OPENSSL_VERSION_NUMBER >= 0x30000000L) && \ + defined(PROTO_AMISSL_H) + return 0; + #else + #error not AmiSSL v5 / OpenSSL 3 + #endif + ]]) + ],[ + AC_MSG_RESULT([yes]) + ssl_msg="AmiSSL" + test amissl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + AMISSL_ENABLED=1 + OPENSSL_ENABLED=1 + # Use AmiSSL's built-in ca bundle + check_for_ca_bundle=1 + with_ca_fallback=yes + LIBS="-lamisslstubs -lamisslauto $LIBS" + AC_DEFINE(USE_AMISSL, 1, [if AmiSSL is in use]) + AC_DEFINE(USE_OPENSSL, 1, [if OpenSSL is in use]) + AC_DEFINE_UNQUOTED(HAVE_OPENSSL3, 1, [Define to 1 if using OpenSSL 3 or later.]) + AC_CHECK_HEADERS(openssl/x509.h openssl/rsa.h openssl/crypto.h \ + openssl/pem.h openssl/ssl.h openssl/err.h) + ],[ + AC_MSG_RESULT([no]) + ]) + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" + else + AC_MSG_RESULT(no) + fi +else + AC_MSG_RESULT(no) +fi + +]) diff --git a/m4/curl-bearssl.m4 b/m4/curl-bearssl.m4 new file mode 100644 index 0000000..f2d661d --- /dev/null +++ b/m4/curl-bearssl.m4 @@ -0,0 +1,110 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +AC_DEFUN([CURL_WITH_BEARSSL], [ +dnl ---------------------------------------------------- +dnl check for BearSSL +dnl ---------------------------------------------------- + +if test "x$OPT_BEARSSL" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + ssl_msg= + + if test X"$OPT_BEARSSL" != Xno; then + + if test "$OPT_BEARSSL" = "yes"; then + OPT_BEARSSL="" + fi + + if test -z "$OPT_BEARSSL" ; then + dnl check for lib first without setting any new path + + AC_CHECK_LIB(bearssl, br_ssl_client_init_full, + dnl libbearssl found, set the variable + [ + AC_DEFINE(USE_BEARSSL, 1, [if BearSSL is enabled]) + AC_SUBST(USE_BEARSSL, [1]) + BEARSSL_ENABLED=1 + USE_BEARSSL="yes" + ssl_msg="BearSSL" + test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], [], -lbearssl) + fi + + addld="" + addlib="" + addcflags="" + bearssllib="" + + if test "x$USE_BEARSSL" != "xyes"; then + dnl add the path and test again + addld=-L$OPT_BEARSSL/lib$libsuff + addcflags=-I$OPT_BEARSSL/include + bearssllib=$OPT_BEARSSL/lib$libsuff + + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + AC_CHECK_LIB(bearssl, br_ssl_client_init_full, + [ + AC_DEFINE(USE_BEARSSL, 1, [if BearSSL is enabled]) + AC_SUBST(USE_BEARSSL, [1]) + BEARSSL_ENABLED=1 + USE_BEARSSL="yes" + ssl_msg="BearSSL" + test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], + [ + CPPFLAGS=$_cppflags + LDFLAGS=$_ldflags + ], -lbearssl) + fi + + if test "x$USE_BEARSSL" = "xyes"; then + AC_MSG_NOTICE([detected BearSSL]) + check_for_ca_bundle=1 + + LIBS="-lbearssl $LIBS" + + if test -n "$bearssllib"; then + dnl when shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to + dnl CURL_LIBRARY_PATH to prevent further configure tests to fail + dnl due to this + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$bearssllib" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $bearssllib to CURL_LIBRARY_PATH]) + fi + fi + fi + + fi dnl BearSSL not disabled + + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi +]) diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 new file mode 100644 index 0000000..9a45477 --- /dev/null +++ b/m4/curl-compilers.m4 @@ -0,0 +1,1627 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +# File version for 'aclocal' use. Keep it a single number. +# serial 67 + + +dnl CURL_CHECK_COMPILER +dnl ------------------------------------------------- +dnl Verify if the C compiler being used is known. + +AC_DEFUN([CURL_CHECK_COMPILER], [ + # + compiler_id="unknown" + compiler_num="0" + # + flags_dbg_yes="unknown" + flags_opt_all="unknown" + flags_opt_yes="unknown" + flags_opt_off="unknown" + # + flags_prefer_cppflags="no" + # + CURL_CHECK_COMPILER_DEC_C + CURL_CHECK_COMPILER_HPUX_C + CURL_CHECK_COMPILER_IBM_C + CURL_CHECK_COMPILER_INTEL_C + CURL_CHECK_COMPILER_CLANG + CURL_CHECK_COMPILER_GNU_C + CURL_CHECK_COMPILER_SGI_MIPSPRO_C + CURL_CHECK_COMPILER_SGI_MIPS_C + CURL_CHECK_COMPILER_SUNPRO_C + CURL_CHECK_COMPILER_TINY_C + # + if test "$compiler_id" = "unknown"; then + cat <<_EOF 1>&2 +*** +*** Warning: This configure script does not have information about the +*** compiler you are using, relative to the flags required to enable or +*** disable generation of debug info, optimization options or warnings. +*** +*** Whatever settings are present in CFLAGS will be used for this run. +*** +*** If you wish to help the curl project to better support your compiler +*** you can report this and the required info on the libcurl development +*** mailing list: https://lists.haxx.selistinfo/curl-library/ +*** +_EOF + fi +]) + + +dnl CURL_CHECK_COMPILER_CLANG +dnl ------------------------------------------------- +dnl Verify if compiler being used is clang. + +AC_DEFUN([CURL_CHECK_COMPILER_CLANG], [ + AC_BEFORE([$0],[CURL_CHECK_COMPILER_GNU_C])dnl + AC_MSG_CHECKING([if compiler is clang]) + CURL_CHECK_DEF([__clang__], [], [silent]) + if test "$curl_cv_have_def___clang__" = "yes"; then + AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([if compiler is xlclang]) + CURL_CHECK_DEF([__ibmxl__], [], [silent]) + if test "$curl_cv_have_def___ibmxl__" = "yes" ; then + dnl IBM's almost-compatible clang version + AC_MSG_RESULT([yes]) + compiler_id="XLCLANG" + else + AC_MSG_RESULT([no]) + compiler_id="CLANG" + fi + AC_MSG_CHECKING([compiler version]) + fullclangver=`$CC -v 2>&1 | grep version` + if echo $fullclangver | grep 'Apple' >/dev/null; then + appleclang=1 + else + appleclang=0 + fi + clangver=`echo $fullclangver | grep "based on LLVM " | "$SED" 's/.*(based on LLVM \(@<:@0-9@:>@*\.@<:@0-9@:>@*\).*)/\1/'` + if test -z "$clangver"; then + clangver=`echo $fullclangver | "$SED" 's/.*version \(@<:@0-9@:>@*\.@<:@0-9@:>@*\).*/\1/'` + oldapple=0 + else + oldapple=1 + fi + clangvhi=`echo $clangver | cut -d . -f1` + clangvlo=`echo $clangver | cut -d . -f2` + compiler_num=`(expr $clangvhi "*" 100 + $clangvlo) 2>/dev/null` + if test "$appleclang" = '1' && test "$oldapple" = '0'; then + dnl Starting with Xcode 7 / clang 3.7, Apple clang won't tell its upstream version + if test "$compiler_num" -ge '1300'; then compiler_num='1200' + elif test "$compiler_num" -ge '1205'; then compiler_num='1101' + elif test "$compiler_num" -ge '1204'; then compiler_num='1000' + elif test "$compiler_num" -ge '1107'; then compiler_num='900' + elif test "$compiler_num" -ge '1103'; then compiler_num='800' + elif test "$compiler_num" -ge '1003'; then compiler_num='700' + elif test "$compiler_num" -ge '1001'; then compiler_num='600' + elif test "$compiler_num" -ge '904'; then compiler_num='500' + elif test "$compiler_num" -ge '902'; then compiler_num='400' + elif test "$compiler_num" -ge '803'; then compiler_num='309' + elif test "$compiler_num" -ge '703'; then compiler_num='308' + else compiler_num='307' + fi + fi + AC_MSG_RESULT([clang '$compiler_num' (raw: '$fullclangver' / '$clangver')]) + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -Os -O3 -O4" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_DEC_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is DEC C. + +AC_DEFUN([CURL_CHECK_COMPILER_DEC_C], [ + AC_MSG_CHECKING([if compiler is DEC/Compaq/HP C]) + CURL_CHECK_DEF([__DECC], [], [silent]) + CURL_CHECK_DEF([__DECC_VER], [], [silent]) + if test "$curl_cv_have_def___DECC" = "yes" && + test "$curl_cv_have_def___DECC_VER" = "yes"; then + AC_MSG_RESULT([yes]) + compiler_id="DEC_C" + flags_dbg_yes="-g2" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4" + flags_opt_yes="-O1" + flags_opt_off="-O0" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_GNU_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is GNU C +dnl +dnl $compiler_num will be set to MAJOR * 100 + MINOR for gcc less than version +dnl 7 and just $MAJOR * 100 for gcc version 7 and later. +dnl +dnl Examples: +dnl Version 1.2.3 => 102 +dnl Version 2.95 => 295 +dnl Version 4.7 => 407 +dnl Version 9.2.1 => 900 +dnl +AC_DEFUN([CURL_CHECK_COMPILER_GNU_C], [ + AC_REQUIRE([CURL_CHECK_COMPILER_INTEL_C])dnl + AC_REQUIRE([CURL_CHECK_COMPILER_CLANG])dnl + AC_MSG_CHECKING([if compiler is GNU C]) + CURL_CHECK_DEF([__GNUC__], [], [silent]) + if test "$curl_cv_have_def___GNUC__" = "yes" && + test "$compiler_id" = "unknown"; then + AC_MSG_RESULT([yes]) + compiler_id="GNU_C" + AC_MSG_CHECKING([compiler version]) + # strip '-suffix' parts, e.g. Ubuntu Windows cross-gcc returns '10-win32' + gccver=`$CC -dumpversion | sed -E 's/-.+$//'` + gccvhi=`echo $gccver | cut -d . -f1` + if echo $gccver | grep -F '.' >/dev/null; then + gccvlo=`echo $gccver | cut -d . -f2` + else + gccvlo="0" + fi + compiler_num=`(expr $gccvhi "*" 100 + $gccvlo) 2>/dev/null` + AC_MSG_RESULT([gcc '$compiler_num' (raw: '$gccver')]) + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os -Og -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_HPUX_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is HP-UX C. + +AC_DEFUN([CURL_CHECK_COMPILER_HPUX_C], [ + AC_MSG_CHECKING([if compiler is HP-UX C]) + CURL_CHECK_DEF([__HP_cc], [], [silent]) + if test "$curl_cv_have_def___HP_cc" = "yes"; then + AC_MSG_RESULT([yes]) + compiler_id="HP_UX_C" + flags_dbg_yes="-g" + flags_opt_all="-O +O0 +O1 +O2 +O3 +O4" + flags_opt_yes="+O2" + flags_opt_off="+O0" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_IBM_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is IBM C. + +AC_DEFUN([CURL_CHECK_COMPILER_IBM_C], [ + AC_MSG_CHECKING([if compiler is IBM C]) + CURL_CHECK_DEF([__IBMC__], [], [silent]) + if test "$curl_cv_have_def___IBMC__" = "yes"; then + AC_MSG_RESULT([yes]) + compiler_id="IBM_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4 -O5" + flags_opt_all="$flags_opt_all -qnooptimize" + flags_opt_all="$flags_opt_all -qoptimize=0" + flags_opt_all="$flags_opt_all -qoptimize=1" + flags_opt_all="$flags_opt_all -qoptimize=2" + flags_opt_all="$flags_opt_all -qoptimize=3" + flags_opt_all="$flags_opt_all -qoptimize=4" + flags_opt_all="$flags_opt_all -qoptimize=5" + flags_opt_yes="-O2" + flags_opt_off="-qnooptimize" + flags_prefer_cppflags="yes" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_INTEL_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is Intel C. + +AC_DEFUN([CURL_CHECK_COMPILER_INTEL_C], [ + AC_BEFORE([$0],[CURL_CHECK_COMPILER_GNU_C])dnl + AC_MSG_CHECKING([if compiler is Intel C]) + CURL_CHECK_DEF([__INTEL_COMPILER], [], [silent]) + if test "$curl_cv_have_def___INTEL_COMPILER" = "yes"; then + AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([compiler version]) + compiler_num="$curl_cv_def___INTEL_COMPILER" + AC_MSG_RESULT([Intel C '$compiler_num']) + CURL_CHECK_DEF([__unix__], [], [silent]) + if test "$curl_cv_have_def___unix__" = "yes"; then + compiler_id="INTEL_UNIX_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + compiler_id="INTEL_WINDOWS_C" + flags_dbg_yes="/Zi /Oy-" + flags_opt_all="/O /O0 /O1 /O2 /O3 /Od /Og /Og- /Oi /Oi-" + flags_opt_yes="/O2" + flags_opt_off="/Od" + fi + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_SGI_MIPS_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is SGI MIPS C. + +AC_DEFUN([CURL_CHECK_COMPILER_SGI_MIPS_C], [ + AC_REQUIRE([CURL_CHECK_COMPILER_SGI_MIPSPRO_C])dnl + AC_MSG_CHECKING([if compiler is SGI MIPS C]) + CURL_CHECK_DEF([__GNUC__], [], [silent]) + CURL_CHECK_DEF([__sgi], [], [silent]) + if test "$curl_cv_have_def___GNUC__" = "no" && + test "$curl_cv_have_def___sgi" = "yes" && + test "$compiler_id" = "unknown"; then + AC_MSG_RESULT([yes]) + compiler_id="SGI_MIPS_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_SGI_MIPSPRO_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is SGI MIPSpro C. + +AC_DEFUN([CURL_CHECK_COMPILER_SGI_MIPSPRO_C], [ + AC_BEFORE([$0],[CURL_CHECK_COMPILER_SGI_MIPS_C])dnl + AC_MSG_CHECKING([if compiler is SGI MIPSpro C]) + CURL_CHECK_DEF([__GNUC__], [], [silent]) + CURL_CHECK_DEF([_COMPILER_VERSION], [], [silent]) + CURL_CHECK_DEF([_SGI_COMPILER_VERSION], [], [silent]) + if test "$curl_cv_have_def___GNUC__" = "no" && + (test "$curl_cv_have_def__SGI_COMPILER_VERSION" = "yes" || + test "$curl_cv_have_def__COMPILER_VERSION" = "yes"); then + AC_MSG_RESULT([yes]) + compiler_id="SGI_MIPSPRO_C" + flags_dbg_yes="-g" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_SUNPRO_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is SunPro C. + +AC_DEFUN([CURL_CHECK_COMPILER_SUNPRO_C], [ + AC_MSG_CHECKING([if compiler is SunPro C]) + CURL_CHECK_DEF([__SUNPRO_C], [], [silent]) + if test "$curl_cv_have_def___SUNPRO_C" = "yes"; then + AC_MSG_RESULT([yes]) + compiler_id="SUNPRO_C" + flags_dbg_yes="-g" + flags_opt_all="-O -xO -xO1 -xO2 -xO3 -xO4 -xO5" + flags_opt_yes="-xO2" + flags_opt_off="" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_TINY_C +dnl ------------------------------------------------- +dnl Verify if compiler being used is Tiny C. + +AC_DEFUN([CURL_CHECK_COMPILER_TINY_C], [ + AC_MSG_CHECKING([if compiler is Tiny C]) + CURL_CHECK_DEF([__TINYC__], [], [silent]) + if test "$curl_cv_have_def___TINYC__" = "yes"; then + AC_MSG_RESULT([yes]) + compiler_id="TINY_C" + flags_dbg_yes="-g" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" + else + AC_MSG_RESULT([no]) + fi +]) + +dnl CURL_CONVERT_INCLUDE_TO_ISYSTEM +dnl ------------------------------------------------- +dnl Changes standard include paths present in CFLAGS +dnl and CPPFLAGS into isystem include paths. This is +dnl done to prevent GNUC from generating warnings on +dnl headers from these locations, although on ancient +dnl GNUC versions these warnings are not silenced. + +AC_DEFUN([CURL_CONVERT_INCLUDE_TO_ISYSTEM], [ + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + AC_REQUIRE([CURL_CHECK_COMPILER])dnl + AC_MSG_CHECKING([convert -I options to -isystem]) + if test "$compiler_id" = "GNU_C" || + test "$compiler_id" = "CLANG"; then + AC_MSG_RESULT([yes]) + tmp_has_include="no" + tmp_chg_FLAGS="$CFLAGS" + for word1 in $tmp_chg_FLAGS; do + case "$word1" in + -I*) + tmp_has_include="yes" + ;; + esac + done + if test "$tmp_has_include" = "yes"; then + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` + CFLAGS="$tmp_chg_FLAGS" + squeeze CFLAGS + fi + tmp_has_include="no" + tmp_chg_FLAGS="$CPPFLAGS" + for word1 in $tmp_chg_FLAGS; do + case "$word1" in + -I*) + tmp_has_include="yes" + ;; + esac + done + if test "$tmp_has_include" = "yes"; then + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` + tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` + CPPFLAGS="$tmp_chg_FLAGS" + squeeze CPPFLAGS + fi + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_COMPILER_WORKS_IFELSE ([ACTION-IF-WORKS], [ACTION-IF-NOT-WORKS]) +dnl ------------------------------------------------- +dnl Verify if the C compiler seems to work with the +dnl settings that are 'active' at the time the test +dnl is performed. + +AC_DEFUN([CURL_COMPILER_WORKS_IFELSE], [ + dnl compilation capability verification + tmp_compiler_works="unknown" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ + int i = 1; + return i; + ]]) + ],[ + tmp_compiler_works="yes" + ],[ + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/cc-fail: /' conftest.err >&6 + echo " " >&6 + ]) + dnl linking capability verification + if test "$tmp_compiler_works" = "yes"; then + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ + int i = 1; + return i; + ]]) + ],[ + tmp_compiler_works="yes" + ],[ + tmp_compiler_works="no" + echo " " >&6 + sed 's/^/link-fail: /' conftest.err >&6 + echo " " >&6 + ]) + fi + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tmp_compiler_works" = "yes"; then + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ +# ifdef __STDC__ +# include +# endif + ]],[[ + int i = 0; + exit(i); + ]]) + ],[ + tmp_compiler_works="yes" + ],[ + tmp_compiler_works="no" + echo " " >&6 + echo "run-fail: test program exited with status $ac_status" >&6 + echo " " >&6 + ]) + fi + dnl branch upon test result + if test "$tmp_compiler_works" = "yes"; then + ifelse($1,,:,[$1]) + ifelse($2,,,[else + $2]) + fi +]) + + +dnl CURL_SET_COMPILER_BASIC_OPTS +dnl ------------------------------------------------- +dnl Sets compiler specific options/flags which do not +dnl depend on configure's debug, optimize or warnings +dnl options. + +AC_DEFUN([CURL_SET_COMPILER_BASIC_OPTS], [ + AC_REQUIRE([CURL_CHECK_COMPILER])dnl + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CPPFLAGS="$CPPFLAGS" + tmp_save_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="" + tmp_CFLAGS="" + # + case "$compiler_id" in + # + CLANG) + # + dnl Disable warnings for unused arguments, otherwise clang will + dnl warn about compile-time arguments used during link-time, like + dnl -O and -g and -pedantic. + tmp_CFLAGS="$tmp_CFLAGS -Qunused-arguments" + ;; + # + DEC_C) + # + dnl Select strict ANSI C compiler mode + tmp_CFLAGS="$tmp_CFLAGS -std1" + dnl Turn off optimizer ANSI C aliasing rules + tmp_CFLAGS="$tmp_CFLAGS -noansi_alias" + dnl Generate warnings for missing function prototypes + tmp_CFLAGS="$tmp_CFLAGS -warnprotos" + dnl Change some warnings into fatal errors + tmp_CFLAGS="$tmp_CFLAGS -msg_fatal toofewargs,toomanyargs" + ;; + # + GNU_C) + # + dnl turn implicit-function-declaration warning into error, + dnl at least gcc 2.95 and later support this + if test "$compiler_num" -ge "295"; then + tmp_CFLAGS="$tmp_CFLAGS -Werror-implicit-function-declaration" + fi + ;; + # + HP_UX_C) + # + dnl Disallow run-time dereferencing of null pointers + tmp_CFLAGS="$tmp_CFLAGS -z" + dnl Disable some remarks + dnl #4227: padding struct with n bytes to align member + dnl #4255: padding size of struct with n bytes to alignment boundary + tmp_CFLAGS="$tmp_CFLAGS +W 4227,4255" + ;; + # + IBM_C) + # + dnl Ensure that compiler optimizations are always thread-safe. + tmp_CPPFLAGS="$tmp_CPPFLAGS -qthreaded" + dnl Disable type based strict aliasing optimizations, using worst + dnl case aliasing assumptions when compiling. Type based aliasing + dnl would restrict the lvalues that could be safely used to access + dnl a data object. + tmp_CPPFLAGS="$tmp_CPPFLAGS -qnoansialias" + dnl Force compiler to stop after the compilation phase, without + dnl generating an object code file when compilation has errors. + tmp_CPPFLAGS="$tmp_CPPFLAGS -qhalt=e" + ;; + # + INTEL_UNIX_C) + # + dnl On unix this compiler uses gcc's header files, so + dnl we select ANSI C89 dialect plus GNU extensions. + tmp_CFLAGS="$tmp_CFLAGS -std=gnu89" + dnl Change some warnings into errors + dnl #140: too many arguments in function call + dnl #147: declaration is incompatible with 'previous one' + dnl #165: too few arguments in function call + dnl #266: function declared implicitly + tmp_CPPFLAGS="$tmp_CPPFLAGS -diag-error 140,147,165,266" + dnl Disable some remarks + dnl #279: controlling expression is constant + dnl #981: operands are evaluated in unspecified order + dnl #1025: zero extending result of unary operation + dnl #1469: "cc" clobber ignored + dnl #2259: non-pointer conversion from X to Y may lose significant bits + tmp_CPPFLAGS="$tmp_CPPFLAGS -diag-disable 279,981,1025,1469,2259" + ;; + # + INTEL_WINDOWS_C) + # + dnl Placeholder + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SGI_MIPS_C) + # + dnl Placeholder + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SGI_MIPSPRO_C) + # + dnl Placeholder + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SUNPRO_C) + # + dnl Placeholder + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + TINY_C) + # + dnl Placeholder + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + esac + # + squeeze tmp_CPPFLAGS + squeeze tmp_CFLAGS + # + if test ! -z "$tmp_CFLAGS" || test ! -z "$tmp_CPPFLAGS"; then + AC_MSG_CHECKING([if compiler accepts some basic options]) + CPPFLAGS="$tmp_save_CPPFLAGS $tmp_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" + squeeze CPPFLAGS + squeeze CFLAGS + CURL_COMPILER_WORKS_IFELSE([ + AC_MSG_RESULT([yes]) + AC_MSG_NOTICE([compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_WARN([compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS]) + dnl restore initial settings + CPPFLAGS="$tmp_save_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS" + ]) + fi + # + fi +]) + + +dnl CURL_SET_COMPILER_DEBUG_OPTS +dnl ------------------------------------------------- +dnl Sets compiler specific options/flags which depend +dnl on configure's debug option. + +AC_DEFUN([CURL_SET_COMPILER_DEBUG_OPTS], [ + AC_REQUIRE([CURL_CHECK_OPTION_DEBUG])dnl + AC_REQUIRE([CURL_CHECK_COMPILER])dnl + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CFLAGS="$CFLAGS" + tmp_save_CPPFLAGS="$CPPFLAGS" + # + tmp_options="" + tmp_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="$CPPFLAGS" + # + if test "$want_debug" = "yes"; then + AC_MSG_CHECKING([if compiler accepts debug enabling options]) + tmp_options="$flags_dbg_yes" + fi + # + if test "$flags_prefer_cppflags" = "yes"; then + CPPFLAGS="$tmp_CPPFLAGS $tmp_options" + CFLAGS="$tmp_CFLAGS" + else + CPPFLAGS="$tmp_CPPFLAGS" + CFLAGS="$tmp_CFLAGS $tmp_options" + fi + squeeze CPPFLAGS + squeeze CFLAGS + fi +]) + + +dnl CURL_SET_COMPILER_OPTIMIZE_OPTS +dnl ------------------------------------------------- +dnl Sets compiler specific options/flags which depend +dnl on configure's optimize option. + +AC_DEFUN([CURL_SET_COMPILER_OPTIMIZE_OPTS], [ + AC_REQUIRE([CURL_CHECK_OPTION_OPTIMIZE])dnl + AC_REQUIRE([CURL_CHECK_COMPILER])dnl + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CFLAGS="$CFLAGS" + tmp_save_CPPFLAGS="$CPPFLAGS" + # + tmp_options="" + tmp_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="$CPPFLAGS" + honor_optimize_option="yes" + # + dnl If optimization request setting has not been explicitly specified, + dnl it has been derived from the debug setting and initially assumed. + dnl This initially assumed optimizer setting will finally be ignored + dnl if CFLAGS or CPPFLAGS already hold optimizer flags. This implies + dnl that an initially assumed optimizer setting might not be honored. + # + if test "$want_optimize" = "assume_no" || + test "$want_optimize" = "assume_yes"; then + AC_MSG_CHECKING([if compiler optimizer assumed setting might be used]) + CURL_VAR_MATCH_IFELSE([tmp_CFLAGS],[$flags_opt_all],[ + honor_optimize_option="no" + ]) + CURL_VAR_MATCH_IFELSE([tmp_CPPFLAGS],[$flags_opt_all],[ + honor_optimize_option="no" + ]) + AC_MSG_RESULT([$honor_optimize_option]) + if test "$honor_optimize_option" = "yes"; then + if test "$want_optimize" = "assume_yes"; then + want_optimize="yes" + fi + if test "$want_optimize" = "assume_no"; then + want_optimize="no" + fi + fi + fi + # + if test "$honor_optimize_option" = "yes"; then + CURL_VAR_STRIP([tmp_CFLAGS],[$flags_opt_all]) + CURL_VAR_STRIP([tmp_CPPFLAGS],[$flags_opt_all]) + if test "$want_optimize" = "yes"; then + AC_MSG_CHECKING([if compiler accepts optimizer enabling options]) + tmp_options="$flags_opt_yes" + fi + if test "$want_optimize" = "no"; then + AC_MSG_CHECKING([if compiler accepts optimizer disabling options]) + tmp_options="$flags_opt_off" + fi + if test "$flags_prefer_cppflags" = "yes"; then + CPPFLAGS="$tmp_CPPFLAGS $tmp_options" + CFLAGS="$tmp_CFLAGS" + else + CPPFLAGS="$tmp_CPPFLAGS" + CFLAGS="$tmp_CFLAGS $tmp_options" + fi + squeeze CPPFLAGS + squeeze CFLAGS + CURL_COMPILER_WORKS_IFELSE([ + AC_MSG_RESULT([yes]) + AC_MSG_NOTICE([compiler options added: $tmp_options]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_WARN([compiler options rejected: $tmp_options]) + dnl restore initial settings + CPPFLAGS="$tmp_save_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS" + ]) + fi + # + fi +]) + + +dnl CURL_SET_COMPILER_WARNING_OPTS +dnl ------------------------------------------------- +dnl Sets compiler options/flags which depend on +dnl configure's warnings given option. + +AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ + AC_REQUIRE([CURL_CHECK_OPTION_WARNINGS])dnl + AC_REQUIRE([CURL_CHECK_COMPILER])dnl + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + # + if test "$compiler_id" != "unknown"; then + # + tmp_save_CPPFLAGS="$CPPFLAGS" + tmp_save_CFLAGS="$CFLAGS" + tmp_CPPFLAGS="" + tmp_CFLAGS="" + # + case "$compiler_id" in + # + CLANG) + # + if test "$want_warnings" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -pedantic" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [all extra]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [pointer-arith write-strings]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [shadow]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [inline nested-externs]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-declarations]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-prototypes]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-long-long" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [float-equal]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [sign-compare]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-multichar" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [undef]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-format-nonliteral" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [endif-labels strict-prototypes]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [declaration-after-statement]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-align]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-system-headers" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [shorten-64-to-32]) + # + dnl Only clang 1.1 or later + if test "$compiler_num" -ge "101"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused]) + fi + # + dnl Only clang 2.7 or later + if test "$compiler_num" -ge "207"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [address]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [attributes]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [bad-function-cast]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [conversion]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [div-by-zero format-security]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [empty-body]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-field-initializers]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-noreturn]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [old-style-definition]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [redundant-decls]) + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [type-limits]) + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unreachable-code unused-parameter]) + fi + # + dnl Only clang 2.8 or later + if test "$compiler_num" -ge "208"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [ignored-qualifiers]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [vla]) + fi + # + dnl Only clang 2.9 or later + if test "$compiler_num" -ge "209"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [sign-conversion]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-error=sign-conversion" # FIXME + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [shift-sign-overflow]) + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs + fi + # + dnl Only clang 3.0 or later + if test "$compiler_num" -ge "300"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [language-extension-token]) + tmp_CFLAGS="$tmp_CFLAGS -Wformat=2" + fi + # + dnl Only clang 3.2 or later + if test "$compiler_num" -ge "302"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [enum-conversion]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [sometimes-uninitialized]) + case $host_os in + cygwin* | mingw*) + dnl skip missing-variable-declarations warnings for cygwin and + dnl mingw because the libtool wrapper executable causes them + ;; + *) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-variable-declarations]) + ;; + esac + fi + # + dnl Only clang 3.4 or later + if test "$compiler_num" -ge "304"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [header-guard]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-const-variable]) + fi + # + dnl Only clang 3.5 or later + if test "$compiler_num" -ge "305"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [pragmas]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unreachable-code-break]) + fi + # + dnl Only clang 3.6 or later + if test "$compiler_num" -ge "306"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [double-promotion]) + fi + # + dnl Only clang 3.9 or later + if test "$compiler_num" -ge "309"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [comma]) + # avoid the varargs warning, fixed in 4.0 + # https://bugs.llvm.org/show_bug.cgi?id=29140 + if test "$compiler_num" -lt "400"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-varargs" + fi + fi + dnl clang 7 or later + if test "$compiler_num" -ge "700"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [assign-enum]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [extra-semi-stmt]) + fi + dnl clang 10 or later + if test "$compiler_num" -ge "1000"; then + tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough" # we have silencing markup for clang 10.0 and above only + fi + fi + dnl Disable pointer to bool conversion warnings since they cause + dnl lib/securetransp.c cause several warnings for checks we want. + dnl This option should be placed after -Wconversion. + tmp_CFLAGS="$tmp_CFLAGS -Wno-pointer-bool-conversion" + ;; + # + DEC_C) + # + if test "$want_warnings" = "yes"; then + dnl Select a higher warning level than default level2 + tmp_CFLAGS="$tmp_CFLAGS -msg_enable level3" + fi + ;; + # + GNU_C) + # + if test "$want_warnings" = "yes"; then + # + dnl Do not enable -pedantic when cross-compiling with a gcc older + dnl than 3.0, to avoid warnings from third party system headers. + if test "x$cross_compiling" != "xyes" || + test "$compiler_num" -ge "300"; then + tmp_CFLAGS="$tmp_CFLAGS -pedantic" + fi + # + dnl Set of options we believe *ALL* gcc versions support: + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [all]) + tmp_CFLAGS="$tmp_CFLAGS -W" + # + dnl Only gcc 1.4 or later + if test "$compiler_num" -ge "104"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [pointer-arith write-strings]) + dnl If not cross-compiling with a gcc older than 3.0 + if test "x$cross_compiling" != "xyes" || + test "$compiler_num" -ge "300"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused shadow]) + fi + fi + # + dnl Only gcc 2.7 or later + if test "$compiler_num" -ge "207"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [inline nested-externs]) + dnl If not cross-compiling with a gcc older than 3.0 + if test "x$cross_compiling" != "xyes" || + test "$compiler_num" -ge "300"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-declarations]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-prototypes]) + fi + fi + # + dnl Only gcc 2.95 or later + if test "$compiler_num" -ge "295"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-long-long" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [bad-function-cast]) + fi + # + dnl Only gcc 2.96 or later + if test "$compiler_num" -ge "296"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [float-equal]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-multichar" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [sign-compare]) + dnl -Wundef used only if gcc is 2.96 or later since we get + dnl lots of "`_POSIX_C_SOURCE' is not defined" in system + dnl headers with gcc 2.95.4 on FreeBSD 4.9 + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [undef]) + fi + # + dnl Only gcc 2.97 or later + if test "$compiler_num" -ge "297"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-format-nonliteral" + fi + # + dnl Only gcc 3.0 or later + if test "$compiler_num" -ge "300"; then + dnl -Wunreachable-code seems totally unreliable on my gcc 3.3.2 on + dnl on i686-Linux as it gives us heaps with false positives. + dnl Also, on gcc 4.0.X it is totally unbearable and complains all + dnl over making it unusable for generic purposes. Let's not use it. + tmp_CFLAGS="$tmp_CFLAGS" + fi + # + dnl Only gcc 3.3 or later + if test "$compiler_num" -ge "303"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [endif-labels strict-prototypes]) + fi + # + dnl Only gcc 3.4 or later + if test "$compiler_num" -ge "304"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [declaration-after-statement]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [old-style-definition]) + fi + # + dnl Only gcc 4.0 or later + if test "$compiler_num" -ge "400"; then + tmp_CFLAGS="$tmp_CFLAGS -Wstrict-aliasing=3" + fi + # + dnl Only gcc 4.1 or later + if test "$compiler_num" -ge "401"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [attributes]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [div-by-zero format-security]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-field-initializers]) + case $host in + *-*-msys*) + ;; + *) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-noreturn]) # Seen to clash with libtool-generated stub code + ;; + esac + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unreachable-code unused-parameter]) + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [pragmas]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [redundant-decls]) + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case + # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical + fi + # + dnl Only gcc 4.2 or later + if test "$compiler_num" -ge "402"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-align]) + fi + # + dnl Only gcc 4.3 or later + if test "$compiler_num" -ge "403"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [address]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [type-limits old-style-declaration]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-parameter-type empty-body]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [clobbered ignored-qualifiers]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [conversion trampolines]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [sign-conversion]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-error=sign-conversion" # FIXME + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [vla]) + dnl required for -Warray-bounds, included in -Wall + tmp_CFLAGS="$tmp_CFLAGS -ftree-vrp" + fi + # + dnl Only gcc 4.5 or later + if test "$compiler_num" -ge "405"; then + dnl Only windows targets + if test "$curl_cv_native_windows" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-pedantic-ms-format" + fi + fi + # + dnl Only gcc 4.6 or later + if test "$compiler_num" -ge "406"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [double-promotion]) + fi + # + dnl only gcc 4.8 or later + if test "$compiler_num" -ge "408"; then + tmp_CFLAGS="$tmp_CFLAGS -Wformat=2" + fi + # + dnl Only gcc 5 or later + if test "$compiler_num" -ge "500"; then + tmp_CFLAGS="$tmp_CFLAGS -Warray-bounds=2" + fi + # + dnl Only gcc 6 or later + if test "$compiler_num" -ge "600"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [shift-negative-value]) + tmp_CFLAGS="$tmp_CFLAGS -Wshift-overflow=2" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [null-dereference]) + tmp_CFLAGS="$tmp_CFLAGS -fdelete-null-pointer-checks" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [duplicated-cond]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-const-variable]) + fi + # + dnl Only gcc 7 or later + if test "$compiler_num" -ge "700"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [duplicated-branches]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [restrict]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [alloc-zero]) + tmp_CFLAGS="$tmp_CFLAGS -Wformat-overflow=2" + tmp_CFLAGS="$tmp_CFLAGS -Wformat-truncation=2" + tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough" + fi + # + dnl Only gcc 10 or later + if test "$compiler_num" -ge "1000"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [arith-conversion]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [enum-conversion]) + fi + # + fi + # + dnl Do not issue warnings for code in system include paths. + if test "$compiler_num" -ge "300"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-system-headers" + else + dnl When cross-compiling with a gcc older than 3.0, disable + dnl some warnings triggered on third party system headers. + if test "x$cross_compiling" = "xyes"; then + if test "$compiler_num" -ge "104"; then + dnl gcc 1.4 or later + tmp_CFLAGS="$tmp_CFLAGS -Wno-unused -Wno-shadow" + fi + if test "$compiler_num" -ge "207"; then + dnl gcc 2.7 or later + tmp_CFLAGS="$tmp_CFLAGS -Wno-missing-declarations" + tmp_CFLAGS="$tmp_CFLAGS -Wno-missing-prototypes" + fi + fi + fi + ;; + # + HP_UX_C) + # + if test "$want_warnings" = "yes"; then + dnl Issue all warnings + tmp_CFLAGS="$tmp_CFLAGS +w1" + fi + ;; + # + IBM_C) + # + dnl Placeholder + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + INTEL_UNIX_C) + # + if test "$want_warnings" = "yes"; then + if test "$compiler_num" -gt "600"; then + dnl Show errors, warnings, and remarks + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wall -w2" + dnl Perform extra compile-time code checking + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wcheck" + dnl Warn on nested comments + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wcomment" + dnl Show warnings relative to deprecated features + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wdeprecated" + dnl Enable warnings for missing prototypes + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wmissing-prototypes" + dnl Enable warnings for 64-bit portability issues + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wp64" + dnl Enable warnings for questionable pointer arithmetic + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wpointer-arith" + dnl Check for function return typw issues + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wreturn-type" + dnl Warn on variable declarations hiding a previous one + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wshadow" + dnl Warn when a variable is used before initialized + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wuninitialized" + dnl Warn if a declared function is not used + tmp_CPPFLAGS="$tmp_CPPFLAGS -Wunused-function" + fi + fi + dnl Disable using EBP register in optimizations + tmp_CFLAGS="$tmp_CFLAGS -fno-omit-frame-pointer" + dnl Disable use of ANSI C aliasing rules in optimizations + tmp_CFLAGS="$tmp_CFLAGS -fno-strict-aliasing" + dnl Value-safe optimizations on floating-point data + tmp_CFLAGS="$tmp_CFLAGS -fp-model precise" + ;; + # + INTEL_WINDOWS_C) + # + dnl Placeholder + tmp_CFLAGS="$tmp_CFLAGS" + ;; + # + SGI_MIPS_C) + # + if test "$want_warnings" = "yes"; then + dnl Perform stricter semantic and lint-like checks + tmp_CFLAGS="$tmp_CFLAGS -fullwarn" + fi + ;; + # + SGI_MIPSPRO_C) + # + if test "$want_warnings" = "yes"; then + dnl Perform stricter semantic and lint-like checks + tmp_CFLAGS="$tmp_CFLAGS -fullwarn" + dnl Disable some remarks + dnl #1209: controlling expression is constant + tmp_CFLAGS="$tmp_CFLAGS -woff 1209" + fi + ;; + # + SUNPRO_C) + # + if test "$want_warnings" = "yes"; then + dnl Perform stricter semantic and lint-like checks + tmp_CFLAGS="$tmp_CFLAGS -v" + fi + ;; + # + TINY_C) + # + if test "$want_warnings" = "yes"; then + dnl Activate all warnings + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [all]) + dnl Make string constants be of type const char * + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [write-strings]) + dnl Warn use of unsupported GCC features ignored by TCC + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unsupported]) + fi + ;; + # + esac + # + squeeze tmp_CPPFLAGS + squeeze tmp_CFLAGS + # + if test ! -z "$tmp_CFLAGS" || test ! -z "$tmp_CPPFLAGS"; then + AC_MSG_CHECKING([if compiler accepts strict warning options]) + CPPFLAGS="$tmp_save_CPPFLAGS $tmp_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" + squeeze CPPFLAGS + squeeze CFLAGS + CURL_COMPILER_WORKS_IFELSE([ + AC_MSG_RESULT([yes]) + AC_MSG_NOTICE([compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_WARN([compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS]) + dnl restore initial settings + CPPFLAGS="$tmp_save_CPPFLAGS" + CFLAGS="$tmp_save_CFLAGS" + ]) + fi + # + fi +]) + + +dnl CURL_SHFUNC_SQUEEZE +dnl ------------------------------------------------- +dnl Declares a shell function squeeze() which removes +dnl redundant whitespace out of a shell variable. + +AC_DEFUN([CURL_SHFUNC_SQUEEZE], [ +squeeze() { + _sqz_result="" + eval _sqz_input=\[$][$]1 + for _sqz_token in $_sqz_input; do + if test -z "$_sqz_result"; then + _sqz_result="$_sqz_token" + else + _sqz_result="$_sqz_result $_sqz_token" + fi + done + eval [$]1=\$_sqz_result + return 0 +} +]) + + +dnl CURL_CHECK_CURLDEBUG +dnl ------------------------------------------------- +dnl Settings which depend on configure's curldebug given +dnl option, and other additional configure pre-requisites. +dnl Actually the curl debug memory tracking feature can +dnl only be used/enabled when libcurl is built as a static +dnl library or as a shared one on those systems on which +dnl shared libraries support undefined symbols. + +AC_DEFUN([CURL_CHECK_CURLDEBUG], [ + AC_REQUIRE([XC_LIBTOOL])dnl + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + supports_curldebug="unknown" + if test "$want_curldebug" = "yes"; then + if test "x$enable_shared" != "xno" && + test "x$enable_shared" != "xyes"; then + AC_MSG_WARN([unknown enable_shared setting.]) + supports_curldebug="no" + fi + if test "x$enable_static" != "xno" && + test "x$enable_static" != "xyes"; then + AC_MSG_WARN([unknown enable_static setting.]) + supports_curldebug="no" + fi + if test "$supports_curldebug" != "no"; then + if test "$enable_shared" = "yes" && + test "x$xc_lt_shlib_use_no_undefined" = 'xyes'; then + supports_curldebug="no" + AC_MSG_WARN([shared library does not support undefined symbols.]) + fi + fi + fi + # + if test "$want_curldebug" = "yes"; then + AC_MSG_CHECKING([if curl debug memory tracking can be enabled]) + test "$supports_curldebug" = "no" || supports_curldebug="yes" + AC_MSG_RESULT([$supports_curldebug]) + if test "$supports_curldebug" = "no"; then + AC_MSG_WARN([cannot enable curl debug memory tracking.]) + want_curldebug="no" + fi + fi +]) + + + +dnl CURL_CHECK_COMPILER_HALT_ON_ERROR +dnl ------------------------------------------------- +dnl Verifies if the compiler actually halts after the +dnl compilation phase without generating any object +dnl code file, when the source compiles with errors. + +AC_DEFUN([CURL_CHECK_COMPILER_HALT_ON_ERROR], [ + AC_MSG_CHECKING([if compiler halts on compilation errors]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ + force compilation error + ]]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([compiler does not halt on compilation errors.]) + ],[ + AC_MSG_RESULT([yes]) + ]) +]) + + +dnl CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE +dnl ------------------------------------------------- +dnl Verifies if the compiler actually halts after the +dnl compilation phase without generating any object +dnl code file, when the source code tries to define a +dnl type for a constant array with negative dimension. + +AC_DEFUN([CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE], [ + AC_REQUIRE([CURL_CHECK_COMPILER_HALT_ON_ERROR])dnl + AC_MSG_CHECKING([if compiler halts on negative sized arrays]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + typedef char bad_t[sizeof(char) == sizeof(int) ? -1 : -1 ]; + ]],[[ + bad_t dummy; + ]]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([compiler does not halt on negative sized arrays.]) + ],[ + AC_MSG_RESULT([yes]) + ]) +]) + + +dnl CURL_CHECK_COMPILER_STRUCT_MEMBER_SIZE +dnl ------------------------------------------------- +dnl Verifies if the compiler is capable of handling the +dnl size of a struct member, struct which is a function +dnl result, as a compilation-time condition inside the +dnl type definition of a constant array. + +AC_DEFUN([CURL_CHECK_COMPILER_STRUCT_MEMBER_SIZE], [ + AC_REQUIRE([CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE])dnl + AC_MSG_CHECKING([if compiler struct member size checking works]) + tst_compiler_check_one_works="unknown" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + struct mystruct { + int mi; + char mc; + struct mystruct *next; + }; + struct mystruct myfunc(); + typedef char good_t1[sizeof(myfunc().mi) == sizeof(int) ? 1 : -1 ]; + typedef char good_t2[sizeof(myfunc().mc) == sizeof(char) ? 1 : -1 ]; + ]],[[ + good_t1 dummy1; + good_t2 dummy2; + ]]) + ],[ + tst_compiler_check_one_works="yes" + ],[ + tst_compiler_check_one_works="no" + sed 's/^/cc-src: /' conftest.$ac_ext >&6 + sed 's/^/cc-err: /' conftest.err >&6 + ]) + tst_compiler_check_two_works="unknown" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + struct mystruct { + int mi; + char mc; + struct mystruct *next; + }; + struct mystruct myfunc(); + typedef char bad_t1[sizeof(myfunc().mi) != sizeof(int) ? 1 : -1 ]; + typedef char bad_t2[sizeof(myfunc().mc) != sizeof(char) ? 1 : -1 ]; + ]],[[ + bad_t1 dummy1; + bad_t2 dummy2; + ]]) + ],[ + tst_compiler_check_two_works="no" + ],[ + tst_compiler_check_two_works="yes" + ]) + if test "$tst_compiler_check_one_works" = "yes" && + test "$tst_compiler_check_two_works" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([compiler fails struct member size checking.]) + fi +]) + + +dnl CURL_CHECK_COMPILER_SYMBOL_HIDING +dnl ------------------------------------------------- +dnl Verify if compiler supports hiding library internal symbols, setting +dnl shell variable supports_symbol_hiding value as appropriate, as well as +dnl variables symbol_hiding_CFLAGS and symbol_hiding_EXTERN when supported. + +AC_DEFUN([CURL_CHECK_COMPILER_SYMBOL_HIDING], [ + AC_REQUIRE([CURL_CHECK_COMPILER])dnl + AC_BEFORE([$0],[CURL_CONFIGURE_SYMBOL_HIDING])dnl + AC_MSG_CHECKING([if compiler supports hiding library internal symbols]) + supports_symbol_hiding="no" + symbol_hiding_CFLAGS="" + symbol_hiding_EXTERN="" + tmp_CFLAGS="" + tmp_EXTERN="" + case "$compiler_id" in + CLANG) + dnl All versions of clang support -fvisibility= + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" + ;; + GNU_C) + dnl Only gcc 3.4 or later + if test "$compiler_num" -ge "304"; then + if $CC --help --verbose 2>/dev/null | grep fvisibility= >/dev/null ; then + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" + fi + fi + ;; + INTEL_UNIX_C) + dnl Only icc 9.0 or later + if test "$compiler_num" -ge "900"; then + if $CC --help --verbose 2>&1 | grep fvisibility= > /dev/null ; then + tmp_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +# include + ]],[[ + printf("icc fvisibility bug test"); + ]]) + ],[ + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" + ]) + CFLAGS="$tmp_save_CFLAGS" + fi + fi + ;; + SUNPRO_C) + if $CC 2>&1 | grep flags >/dev/null && $CC -flags | grep xldscope= >/dev/null ; then + tmp_EXTERN="__global" + tmp_CFLAGS="-xldscope=hidden" + supports_symbol_hiding="yes" + fi + ;; + esac + if test "$supports_symbol_hiding" = "yes"; then + tmp_save_CFLAGS="$CFLAGS" + CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" + squeeze CFLAGS + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $tmp_EXTERN char *dummy(char *buff); + char *dummy(char *buff) + { + if(buff) + return ++buff; + else + return buff; + } + ]],[[ + char b[16]; + char *r = dummy(&b[0]); + if(r) + return (int)*r; + ]]) + ],[ + supports_symbol_hiding="yes" + if test -f conftest.err; then + grep 'visibility' conftest.err >/dev/null + if test "$?" -eq "0"; then + supports_symbol_hiding="no" + fi + fi + ],[ + supports_symbol_hiding="no" + echo " " >&6 + sed 's/^/cc-src: /' conftest.$ac_ext >&6 + sed 's/^/cc-err: /' conftest.err >&6 + echo " " >&6 + ]) + CFLAGS="$tmp_save_CFLAGS" + fi + if test "$supports_symbol_hiding" = "yes"; then + AC_MSG_RESULT([yes]) + symbol_hiding_CFLAGS="$tmp_CFLAGS" + symbol_hiding_EXTERN="$tmp_EXTERN" + else + AC_MSG_RESULT([no]) + fi +]) + + +dnl CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH +dnl ------------------------------------------------- +dnl Verifies if the compiler actually halts after the +dnl compilation phase without generating any object +dnl code file, when the source code tries to redefine +dnl a prototype which does not match previous one. + +AC_DEFUN([CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH], [ + AC_REQUIRE([CURL_CHECK_COMPILER_HALT_ON_ERROR])dnl + AC_MSG_CHECKING([if compiler halts on function prototype mismatch]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +# include + int rand(int n); + int rand(int n) + { + if(n) + return ++n; + else + return n; + } + ]],[[ + int i[2]={0,0}; + int j = rand(i[0]); + if(j) + return j; + ]]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([compiler does not halt on function prototype mismatch.]) + ],[ + AC_MSG_RESULT([yes]) + ]) +]) + + +dnl CURL_VAR_MATCH (VARNAME, VALUE) +dnl ------------------------------------------------- +dnl Verifies if shell variable VARNAME contains VALUE. +dnl Contents of variable VARNAME and VALUE are handled +dnl as whitespace separated lists of words. If at least +dnl one word of VALUE is present in VARNAME the match +dnl is considered positive, otherwise false. + +AC_DEFUN([CURL_VAR_MATCH], [ + ac_var_match_word="no" + for word1 in $[$1]; do + for word2 in [$2]; do + if test "$word1" = "$word2"; then + ac_var_match_word="yes" + fi + done + done +]) + + +dnl CURL_VAR_MATCH_IFELSE (VARNAME, VALUE, +dnl [ACTION-IF-MATCH], [ACTION-IF-NOT-MATCH]) +dnl ------------------------------------------------- +dnl This performs a CURL_VAR_MATCH check and executes +dnl first branch if the match is positive, otherwise +dnl the second branch is executed. + +AC_DEFUN([CURL_VAR_MATCH_IFELSE], [ + CURL_VAR_MATCH([$1],[$2]) + if test "$ac_var_match_word" = "yes"; then + ifelse($3,,:,[$3]) + ifelse($4,,,[else + $4]) + fi +]) + + +dnl CURL_VAR_STRIP (VARNAME, VALUE) +dnl ------------------------------------------------- +dnl Contents of variable VARNAME and VALUE are handled +dnl as whitespace separated lists of words. Each word +dnl from VALUE is removed from VARNAME when present. + +AC_DEFUN([CURL_VAR_STRIP], [ + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + ac_var_stripped="" + for word1 in $[$1]; do + ac_var_strip_word="no" + for word2 in [$2]; do + if test "$word1" = "$word2"; then + ac_var_strip_word="yes" + fi + done + if test "$ac_var_strip_word" = "no"; then + ac_var_stripped="$ac_var_stripped $word1" + fi + done + dnl squeeze whitespace out of result + [$1]="$ac_var_stripped" + squeeze [$1] +]) + +dnl CURL_ADD_COMPILER_WARNINGS (WARNING-LIST, NEW-WARNINGS) +dnl ------------------------------------------------------- +dnl Contents of variable WARNING-LIST and NEW-WARNINGS are +dnl handled as whitespace separated lists of words. +dnl Add each compiler warning from NEW-WARNINGS that has not +dnl been disabled via CFLAGS to WARNING-LIST. + +AC_DEFUN([CURL_ADD_COMPILER_WARNINGS], [ + AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl + ac_var_added_warnings="" + for warning in [$2]; do + CURL_VAR_MATCH(CFLAGS, [-Wno-$warning -W$warning]) + if test "$ac_var_match_word" = "no"; then + ac_var_added_warnings="$ac_var_added_warnings -W$warning" + fi + done + dnl squeeze whitespace out of result + [$1]="$[$1] $ac_var_added_warnings" + squeeze [$1] +]) diff --git a/m4/curl-confopts.m4 b/m4/curl-confopts.m4 new file mode 100644 index 0000000..37f7d4c --- /dev/null +++ b/m4/curl-confopts.m4 @@ -0,0 +1,668 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +# File version for 'aclocal' use. Keep it a single number. +# serial 19 + +dnl CURL_CHECK_OPTION_THREADED_RESOLVER +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-threaded-resolver or --disable-threaded-resolver, and +dnl set shell variable want_thres as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_THREADED_RESOLVER], [ + AC_MSG_CHECKING([whether to enable the threaded resolver]) + OPT_THRES="default" + AC_ARG_ENABLE(threaded_resolver, +AS_HELP_STRING([--enable-threaded-resolver],[Enable threaded resolver]) +AS_HELP_STRING([--disable-threaded-resolver],[Disable threaded resolver]), + OPT_THRES=$enableval) + case "$OPT_THRES" in + no) + dnl --disable-threaded-resolver option used + want_thres="no" + ;; + *) + dnl configure option not specified + want_thres="yes" + ;; + esac + AC_MSG_RESULT([$want_thres]) +]) + +dnl CURL_CHECK_OPTION_ARES +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-ares or --disable-ares, and +dnl set shell variable want_ares as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_ARES], [ +dnl AC_BEFORE([$0],[CURL_CHECK_OPTION_THREADS])dnl + AC_BEFORE([$0],[CURL_CHECK_LIB_ARES])dnl + AC_MSG_CHECKING([whether to enable c-ares for DNS lookups]) + OPT_ARES="default" + AC_ARG_ENABLE(ares, +AS_HELP_STRING([--enable-ares@<:@=PATH@:>@],[Enable c-ares for DNS lookups]) +AS_HELP_STRING([--disable-ares],[Disable c-ares for DNS lookups]), + OPT_ARES=$enableval) + case "$OPT_ARES" in + no) + dnl --disable-ares option used + want_ares="no" + ;; + default) + dnl configure option not specified + want_ares="no" + ;; + *) + dnl --enable-ares option used + want_ares="yes" + if test -n "$enableval" && test "$enableval" != "yes"; then + want_ares_path="$enableval" + fi + ;; + esac + AC_MSG_RESULT([$want_ares]) +]) + + +dnl CURL_CHECK_OPTION_CURLDEBUG +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-curldebug or --disable-curldebug, and set +dnl shell variable want_curldebug value as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_CURLDEBUG], [ + AC_BEFORE([$0],[CURL_CHECK_CURLDEBUG])dnl + AC_MSG_CHECKING([whether to enable curl debug memory tracking]) + OPT_CURLDEBUG_BUILD="default" + AC_ARG_ENABLE(curldebug, +AS_HELP_STRING([--enable-curldebug],[Enable curl debug memory tracking]) +AS_HELP_STRING([--disable-curldebug],[Disable curl debug memory tracking]), + OPT_CURLDEBUG_BUILD=$enableval) + case "$OPT_CURLDEBUG_BUILD" in + no) + dnl --disable-curldebug option used + want_curldebug="no" + AC_MSG_RESULT([no]) + ;; + default) + dnl configure's curldebug option not specified. Initially we will + dnl handle this as a request to use the same setting as option + dnl --enable-debug. IOW, initially, for debug-enabled builds + dnl this will be handled as a request to enable curldebug if + dnl possible, and for debug-disabled builds this will be handled + dnl as a request to disable curldebug. + if test "$want_debug" = "yes"; then + AC_MSG_RESULT([(assumed) yes]) + AC_DEFINE(CURLDEBUG, 1, [to enable curl debug memory tracking]) + else + AC_MSG_RESULT([no]) + fi + want_curldebug_assumed="yes" + want_curldebug="$want_debug" + ;; + *) + dnl --enable-curldebug option used. + dnl The use of this option value is a request to enable curl's + dnl debug memory tracking for the libcurl library. This can only + dnl be done when some requisites are simultaneously satisfied. + dnl Later on, these requisites are verified and if they are not + dnl fully satisfied the option will be ignored and act as if + dnl --disable-curldebug had been given setting shell variable + dnl want_curldebug to 'no'. + want_curldebug="yes" + AC_DEFINE(CURLDEBUG, 1, [to enable curl debug memory tracking]) + AC_MSG_RESULT([yes]) + ;; + esac +]) + + +dnl CURL_CHECK_OPTION_DEBUG +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-debug or --disable-debug, and set shell +dnl variable want_debug value as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_DEBUG], [ + AC_BEFORE([$0],[CURL_CHECK_OPTION_WARNINGS])dnl + AC_BEFORE([$0],[CURL_CHECK_OPTION_CURLDEBUG])dnl + AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl + AC_MSG_CHECKING([whether to enable debug build options]) + OPT_DEBUG_BUILD="default" + AC_ARG_ENABLE(debug, +AS_HELP_STRING([--enable-debug],[Enable debug build options]) +AS_HELP_STRING([--disable-debug],[Disable debug build options]), + OPT_DEBUG_BUILD=$enableval) + case "$OPT_DEBUG_BUILD" in + no) + dnl --disable-debug option used + want_debug="no" + ;; + default) + dnl configure option not specified + want_debug="no" + ;; + *) + dnl --enable-debug option used + want_debug="yes" + AC_DEFINE(DEBUGBUILD, 1, [enable debug build options]) + ;; + esac + AC_MSG_RESULT([$want_debug]) +]) + +dnl CURL_CHECK_OPTION_OPTIMIZE +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-optimize or --disable-optimize, and set +dnl shell variable want_optimize value as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_OPTIMIZE], [ + AC_REQUIRE([CURL_CHECK_OPTION_DEBUG])dnl + AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl + AC_MSG_CHECKING([whether to enable compiler optimizer]) + OPT_COMPILER_OPTIMIZE="default" + AC_ARG_ENABLE(optimize, +AS_HELP_STRING([--enable-optimize],[Enable compiler optimizations]) +AS_HELP_STRING([--disable-optimize],[Disable compiler optimizations]), + OPT_COMPILER_OPTIMIZE=$enableval) + case "$OPT_COMPILER_OPTIMIZE" in + no) + dnl --disable-optimize option used. We will handle this as + dnl a request to disable compiler optimizations if possible. + dnl If the compiler is known CFLAGS and CPPFLAGS will be + dnl overridden, otherwise this can not be honored. + want_optimize="no" + AC_MSG_RESULT([no]) + ;; + default) + dnl configure's optimize option not specified. Initially we will + dnl handle this as a request contrary to configure's setting + dnl for --enable-debug. IOW, initially, for debug-enabled builds + dnl this will be handled as a request to disable optimizations if + dnl possible, and for debug-disabled builds this will be handled + dnl initially as a request to enable optimizations if possible. + dnl Finally, if the compiler is known and CFLAGS and CPPFLAGS do + dnl not have any optimizer flag the request will be honored, in + dnl any other case the request can not be honored. + dnl IOW, existing optimizer flags defined in CFLAGS or CPPFLAGS + dnl will always take precedence over any initial assumption. + if test "$want_debug" = "yes"; then + want_optimize="assume_no" + AC_MSG_RESULT([(assumed) no]) + else + want_optimize="assume_yes" + AC_MSG_RESULT([(assumed) yes]) + fi + ;; + *) + dnl --enable-optimize option used. We will handle this as + dnl a request to enable compiler optimizations if possible. + dnl If the compiler is known CFLAGS and CPPFLAGS will be + dnl overridden, otherwise this can not be honored. + want_optimize="yes" + AC_MSG_RESULT([yes]) + ;; + esac +]) + + +dnl CURL_CHECK_OPTION_SYMBOL_HIDING +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-symbol-hiding or --disable-symbol-hiding, +dnl setting shell variable want_symbol_hiding value. + +AC_DEFUN([CURL_CHECK_OPTION_SYMBOL_HIDING], [ + AC_BEFORE([$0],[CURL_CHECK_COMPILER_SYMBOL_HIDING])dnl + AC_MSG_CHECKING([whether to enable hiding of library internal symbols]) + OPT_SYMBOL_HIDING="default" + AC_ARG_ENABLE(symbol-hiding, +AS_HELP_STRING([--enable-symbol-hiding],[Enable hiding of library internal symbols]) +AS_HELP_STRING([--disable-symbol-hiding],[Disable hiding of library internal symbols]), + OPT_SYMBOL_HIDING=$enableval) + case "$OPT_SYMBOL_HIDING" in + no) + dnl --disable-symbol-hiding option used. + dnl This is an indication to not attempt hiding of library internal + dnl symbols. Default symbol visibility will be used, which normally + dnl exposes all library internal symbols. + want_symbol_hiding="no" + AC_MSG_RESULT([no]) + ;; + default) + dnl configure's symbol-hiding option not specified. + dnl Handle this as if --enable-symbol-hiding option was given. + want_symbol_hiding="yes" + AC_MSG_RESULT([yes]) + ;; + *) + dnl --enable-symbol-hiding option used. + dnl This is an indication to attempt hiding of library internal + dnl symbols. This is only supported on some compilers/linkers. + want_symbol_hiding="yes" + AC_MSG_RESULT([yes]) + ;; + esac +]) + + +dnl CURL_CHECK_OPTION_THREADS +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-threads or --disable-threads, and +dnl set shell variable want_threads as appropriate. + +dnl AC_DEFUN([CURL_CHECK_OPTION_THREADS], [ +dnl AC_BEFORE([$0],[CURL_CHECK_LIB_THREADS])dnl +dnl AC_MSG_CHECKING([whether to enable threads for DNS lookups]) +dnl OPT_THREADS="default" +dnl AC_ARG_ENABLE(threads, +dnl AS_HELP_STRING([--enable-threads@<:@=PATH@:>@],[Enable threads for DNS lookups]) +dnl AS_HELP_STRING([--disable-threads],[Disable threads for DNS lookups]), +dnl OPT_THREADS=$enableval) +dnl case "$OPT_THREADS" in +dnl no) +dnl dnl --disable-threads option used +dnl want_threads="no" +dnl AC_MSG_RESULT([no]) +dnl ;; +dnl default) +dnl dnl configure option not specified +dnl want_threads="no" +dnl AC_MSG_RESULT([(assumed) no]) +dnl ;; +dnl *) +dnl dnl --enable-threads option used +dnl want_threads="yes" +dnl want_threads_path="$enableval" +dnl AC_MSG_RESULT([yes]) +dnl ;; +dnl esac +dnl # +dnl if test "$want_ares" = "assume_yes"; then +dnl if test "$want_threads" = "yes"; then +dnl AC_MSG_CHECKING([whether to ignore c-ares enabling assumed setting]) +dnl AC_MSG_RESULT([yes]) +dnl want_ares="no" +dnl else +dnl want_ares="yes" +dnl fi +dnl fi +dnl if test "$want_threads" = "yes" && test "$want_ares" = "yes"; then +dnl AC_MSG_ERROR([options --enable-ares and --enable-threads are mutually exclusive, at most one may be enabled.]) +dnl fi +dnl ]) + +dnl CURL_CHECK_OPTION_RT +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --disable-rt and set shell variable dontwant_rt +dnl as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_RT], [ + AC_BEFORE([$0], [CURL_CHECK_LIB_THREADS])dnl + AC_MSG_CHECKING([whether to disable dependency on -lrt]) + OPT_RT="default" + AC_ARG_ENABLE(rt, + AS_HELP_STRING([--disable-rt],[disable dependency on -lrt]), + OPT_RT=$enableval) + case "$OPT_RT" in + no) + dnl --disable-rt used (reverse logic) + dontwant_rt="yes" + AC_MSG_RESULT([yes]) + ;; + default) + dnl configure option not specified (so not disabled) + dontwant_rt="no" + AC_MSG_RESULT([(assumed no)]) + ;; + *) + dnl --enable-rt option used (reverse logic) + dontwant_rt="no" + AC_MSG_RESULT([no]) + ;; + esac +]) + +dnl CURL_CHECK_OPTION_WARNINGS +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-warnings or --disable-warnings, and set +dnl shell variable want_warnings as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_WARNINGS], [ + AC_REQUIRE([CURL_CHECK_OPTION_DEBUG])dnl + AC_BEFORE([$0],[CURL_CHECK_OPTION_WERROR])dnl + AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl + AC_MSG_CHECKING([whether to enable strict compiler warnings]) + OPT_COMPILER_WARNINGS="default" + AC_ARG_ENABLE(warnings, +AS_HELP_STRING([--enable-warnings],[Enable strict compiler warnings]) +AS_HELP_STRING([--disable-warnings],[Disable strict compiler warnings]), + OPT_COMPILER_WARNINGS=$enableval) + case "$OPT_COMPILER_WARNINGS" in + no) + dnl --disable-warnings option used + want_warnings="no" + ;; + default) + dnl configure option not specified, so + dnl use same setting as --enable-debug + want_warnings="$want_debug" + ;; + *) + dnl --enable-warnings option used + want_warnings="yes" + ;; + esac + AC_MSG_RESULT([$want_warnings]) +]) + +dnl CURL_CHECK_OPTION_WERROR +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-werror or --disable-werror, and set +dnl shell variable want_werror as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_WERROR], [ + AC_BEFORE([$0],[CURL_CHECK_COMPILER])dnl + AC_MSG_CHECKING([whether to enable compiler warnings as errors]) + OPT_COMPILER_WERROR="default" + AC_ARG_ENABLE(werror, +AS_HELP_STRING([--enable-werror],[Enable compiler warnings as errors]) +AS_HELP_STRING([--disable-werror],[Disable compiler warnings as errors]), + OPT_COMPILER_WERROR=$enableval) + case "$OPT_COMPILER_WERROR" in + no) + dnl --disable-werror option used + want_werror="no" + ;; + default) + dnl configure option not specified + want_werror="no" + ;; + *) + dnl --enable-werror option used + want_werror="yes" + ;; + esac + AC_MSG_RESULT([$want_werror]) +]) + + +dnl CURL_CHECK_NONBLOCKING_SOCKET +dnl ------------------------------------------------- +dnl Check for how to set a socket into non-blocking state. + +AC_DEFUN([CURL_CHECK_NONBLOCKING_SOCKET], [ + AC_REQUIRE([CURL_CHECK_FUNC_FCNTL])dnl + AC_REQUIRE([CURL_CHECK_FUNC_IOCTLSOCKET])dnl + AC_REQUIRE([CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL])dnl + # + tst_method="unknown" + + AC_MSG_CHECKING([how to set a socket into non-blocking mode]) + if test "x$curl_cv_func_fcntl_o_nonblock" = "xyes"; then + tst_method="fcntl O_NONBLOCK" + elif test "x$curl_cv_func_ioctl_fionbio" = "xyes"; then + tst_method="ioctl FIONBIO" + elif test "x$curl_cv_func_ioctlsocket_fionbio" = "xyes"; then + tst_method="ioctlsocket FIONBIO" + elif test "x$curl_cv_func_ioctlsocket_camel_fionbio" = "xyes"; then + tst_method="IoctlSocket FIONBIO" + elif test "x$curl_cv_func_setsockopt_so_nonblock" = "xyes"; then + tst_method="setsockopt SO_NONBLOCK" + fi + AC_MSG_RESULT([$tst_method]) + if test "$tst_method" = "unknown"; then + AC_MSG_WARN([cannot determine non-blocking socket method.]) + fi +]) + + +dnl CURL_CONFIGURE_SYMBOL_HIDING +dnl ------------------------------------------------- +dnl Depending on --enable-symbol-hiding or --disable-symbol-hiding +dnl configure option, and compiler capability to actually honor such +dnl option, this will modify compiler flags as appropriate and also +dnl provide needed definitions for configuration and Makefile.am files. +dnl This macro should not be used until all compilation tests have +dnl been done to prevent interferences on other tests. + +AC_DEFUN([CURL_CONFIGURE_SYMBOL_HIDING], [ + AC_MSG_CHECKING([whether hiding of library internal symbols will actually happen]) + CFLAG_CURL_SYMBOL_HIDING="" + doing_symbol_hiding="no" + if test "$want_symbol_hiding" = "yes" && + test "$supports_symbol_hiding" = "yes"; then + doing_symbol_hiding="yes" + CFLAG_CURL_SYMBOL_HIDING="$symbol_hiding_CFLAGS" + AC_DEFINE_UNQUOTED(CURL_EXTERN_SYMBOL, $symbol_hiding_EXTERN, + [Definition to make a library symbol externally visible.]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + AM_CONDITIONAL(DOING_CURL_SYMBOL_HIDING, test x$doing_symbol_hiding = xyes) + AC_SUBST(CFLAG_CURL_SYMBOL_HIDING) +]) + + +dnl CURL_CHECK_LIB_ARES +dnl ------------------------------------------------- +dnl When c-ares library support has been requested, performs necessary checks +dnl and adjustments needed to enable support of this library. + +AC_DEFUN([CURL_CHECK_LIB_ARES], [ + # + if test "$want_ares" = "yes"; then + dnl c-ares library support has been requested + clean_CPPFLAGS="$CPPFLAGS" + clean_LDFLAGS="$LDFLAGS" + clean_LIBS="$LIBS" + configure_runpath=`pwd` + if test -n "$want_ares_path"; then + dnl c-ares library path has been specified + ARES_PCDIR="$want_ares_path/lib/pkgconfig" + CURL_CHECK_PKGCONFIG(libcares, [$ARES_PCDIR]) + if test "$PKGCONFIG" != "no" ; then + ares_LIBS=`CURL_EXPORT_PCDIR([$ARES_PCDIR]) + $PKGCONFIG --libs-only-l libcares` + ares_LDFLAGS=`CURL_EXPORT_PCDIR([$ARES_PCDIR]) + $PKGCONFIG --libs-only-L libcares` + ares_CPPFLAGS=`CURL_EXPORT_PCDIR([$ARES_PCDIR]) + $PKGCONFIG --cflags-only-I libcares` + AC_MSG_NOTICE([pkg-config: ares LIBS: "$ares_LIBS"]) + AC_MSG_NOTICE([pkg-config: ares LDFLAGS: "$ares_LDFLAGS"]) + AC_MSG_NOTICE([pkg-config: ares CPPFLAGS: "$ares_CPPFLAGS"]) + else + dnl ... path without pkg-config + ares_CPPFLAGS="-I$want_ares_path/include" + ares_LDFLAGS="-L$want_ares_path/lib" + ares_LIBS="-lcares" + fi + else + dnl c-ares path not specified, use defaults + CURL_CHECK_PKGCONFIG(libcares) + if test "$PKGCONFIG" != "no" ; then + ares_LIBS=`$PKGCONFIG --libs-only-l libcares` + ares_LDFLAGS=`$PKGCONFIG --libs-only-L libcares` + ares_CPPFLAGS=`$PKGCONFIG --cflags-only-I libcares` + AC_MSG_NOTICE([pkg-config: ares_LIBS: "$ares_LIBS"]) + AC_MSG_NOTICE([pkg-config: ares_LDFLAGS: "$ares_LDFLAGS"]) + AC_MSG_NOTICE([pkg-config: ares_CPPFLAGS: "$ares_CPPFLAGS"]) + else + ares_CPPFLAGS="" + ares_LDFLAGS="" + ares_LIBS="-lcares" + fi + fi + # + CPPFLAGS="$clean_CPPFLAGS $ares_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS $ares_LDFLAGS" + LIBS="$ares_LIBS $clean_LIBS" + # + + dnl check if c-ares new enough + AC_MSG_CHECKING([that c-ares is good and recent enough]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#include + /* set of dummy functions in case c-ares was built with debug */ + void curl_dofree() { } + void curl_sclose() { } + void curl_domalloc() { } + void curl_docalloc() { } + void curl_socket() { } + ]],[[ + ares_channel channel; + ares_cancel(channel); /* added in 1.2.0 */ + ares_process_fd(channel, 0, 0); /* added in 1.4.0 */ + ares_dup(&channel, channel); /* added in 1.6.0 */ + ]]) + ],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([c-ares library defective or too old]) + dnl restore initial settings + CPPFLAGS="$clean_CPPFLAGS" + LDFLAGS="$clean_LDFLAGS" + LIBS="$clean_LIBS" + # prevent usage + want_ares="no" + ]) + + if test "$want_ares" = "yes"; then + dnl finally c-ares will be used + AC_DEFINE(USE_ARES, 1, [Define to enable c-ares support]) + AC_SUBST([USE_ARES], [1]) + curl_res_msg="c-ares" + fi + fi +]) + + +dnl CURL_CHECK_OPTION_NTLM_WB +dnl ------------------------------------------------- +dnl Verify if configure has been invoked with option +dnl --enable-ntlm-wb or --disable-ntlm-wb, and set +dnl shell variable want_ntlm_wb and want_ntlm_wb_file +dnl as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_NTLM_WB], [ + AC_BEFORE([$0],[CURL_CHECK_NTLM_WB])dnl + OPT_NTLM_WB="default" + AC_ARG_ENABLE(ntlm-wb, +AS_HELP_STRING([--enable-ntlm-wb@<:@=FILE@:>@],[Enable NTLM delegation to winbind's ntlm_auth helper, where FILE is ntlm_auth's absolute filename (default: /usr/bin/ntlm_auth)]) +AS_HELP_STRING([--disable-ntlm-wb],[Disable NTLM delegation to winbind's ntlm_auth helper]), + OPT_NTLM_WB=$enableval) + want_ntlm_wb_file="/usr/bin/ntlm_auth" + case "$OPT_NTLM_WB" in + no) + dnl --disable-ntlm-wb option used + want_ntlm_wb="no" + ;; + default) + dnl configure option not specified + want_ntlm_wb="yes" + ;; + *) + dnl --enable-ntlm-wb option used + want_ntlm_wb="yes" + if test -n "$enableval" && test "$enableval" != "yes"; then + want_ntlm_wb_file="$enableval" + fi + ;; + esac +]) + + +dnl CURL_CHECK_NTLM_WB +dnl ------------------------------------------------- +dnl Check if support for NTLM delegation to winbind's +dnl ntlm_auth helper will finally be enabled depending +dnl on given configure options and target platform. + +AC_DEFUN([CURL_CHECK_NTLM_WB], [ + AC_REQUIRE([CURL_CHECK_OPTION_NTLM_WB])dnl + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + AC_MSG_CHECKING([whether to enable NTLM delegation to winbind's helper]) + if test "$curl_cv_native_windows" = "yes" || + test "x$SSL_ENABLED" = "x"; then + want_ntlm_wb_file="" + want_ntlm_wb="no" + elif test "x$ac_cv_func_fork" != "xyes"; then + dnl ntlm_wb requires fork + want_ntlm_wb="no" + fi + AC_MSG_RESULT([$want_ntlm_wb]) + if test "$want_ntlm_wb" = "yes"; then + AC_DEFINE(NTLM_WB_ENABLED, 1, + [Define to enable NTLM delegation to winbind's ntlm_auth helper.]) + AC_DEFINE_UNQUOTED(NTLM_WB_FILE, "$want_ntlm_wb_file", + [Define absolute filename for winbind's ntlm_auth helper.]) + NTLM_WB_ENABLED=1 + fi +]) + +dnl CURL_CHECK_OPTION_ECH +dnl ----------------------------------------------------- +dnl Verify whether configure has been invoked with option +dnl --enable-ech or --disable-ech, and set +dnl shell variable want_ech as appropriate. + +AC_DEFUN([CURL_CHECK_OPTION_ECH], [ + AC_MSG_CHECKING([whether to enable ECH support]) + OPT_ECH="default" + AC_ARG_ENABLE(ech, +AS_HELP_STRING([--enable-ech],[Enable ECH support]) +AS_HELP_STRING([--disable-ech],[Disable ECH support]), + OPT_ECH=$enableval) + case "$OPT_ECH" in + no) + dnl --disable-ech option used + want_ech="no" + curl_ech_msg="no (--enable-ech)" + AC_MSG_RESULT([no]) + ;; + default) + dnl configure option not specified + want_ech="no" + curl_ech_msg="no (--enable-ech)" + AC_MSG_RESULT([no]) + ;; + *) + dnl --enable-ech option used + want_ech="yes" + curl_ech_msg="enabled (--disable-ech)" + experimental="ech" + AC_MSG_RESULT([yes]) + ;; + esac +]) diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4 new file mode 100644 index 0000000..425d9f9 --- /dev/null +++ b/m4/curl-functions.m4 @@ -0,0 +1,5918 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +# File version for 'aclocal' use. Keep it a single number. +# serial 73 + + +dnl CURL_INCLUDES_ARPA_INET +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when arpa/inet.h is to be included. + +AC_DEFUN([CURL_INCLUDES_ARPA_INET], [ +curl_includes_arpa_inet="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef _WIN32 +#include +#include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h sys/socket.h netinet/in.h arpa/inet.h, + [], [], [$curl_includes_arpa_inet]) +]) + + +dnl CURL_INCLUDES_FCNTL +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when fcntl.h is to be included. + +AC_DEFUN([CURL_INCLUDES_FCNTL], [ +curl_includes_fcntl="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h unistd.h fcntl.h, + [], [], [$curl_includes_fcntl]) +]) + + +dnl CURL_INCLUDES_IFADDRS +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when ifaddrs.h is to be included. + +AC_DEFUN([CURL_INCLUDES_IFADDRS], [ +curl_includes_ifaddrs="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_IFADDRS_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h sys/socket.h netinet/in.h ifaddrs.h, + [], [], [$curl_includes_ifaddrs]) +]) + + +dnl CURL_INCLUDES_LIBGEN +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when libgen.h is to be included. + +AC_DEFUN([CURL_INCLUDES_LIBGEN], [ +curl_includes_libgen="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_LIBGEN_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h libgen.h, + [], [], [$curl_includes_libgen]) +]) + + +dnl CURL_INCLUDES_NETDB +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when netdb.h is to be included. + +AC_DEFUN([CURL_INCLUDES_NETDB], [ +curl_includes_netdb="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h netdb.h, + [], [], [$curl_includes_netdb]) +]) + + +dnl CURL_INCLUDES_POLL +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when poll.h is to be included. + +AC_DEFUN([CURL_INCLUDES_POLL], [ +curl_includes_poll="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_POLL_H +# include +#endif +#ifdef HAVE_SYS_POLL_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h poll.h sys/poll.h, + [], [], [$curl_includes_poll]) +]) + + +dnl CURL_INCLUDES_SETJMP +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when setjmp.h is to be included. + +AC_DEFUN([CURL_INCLUDES_SETJMP], [ +curl_includes_setjmp="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h, + [], [], [$curl_includes_setjmp]) +]) + + +dnl CURL_INCLUDES_SIGNAL +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when signal.h is to be included. + +AC_DEFUN([CURL_INCLUDES_SIGNAL], [ +curl_includes_signal="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h, + [], [], [$curl_includes_signal]) +]) + + +dnl CURL_INCLUDES_SOCKET +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when socket.h is to be included. + +AC_DEFUN([CURL_INCLUDES_SOCKET], [ +curl_includes_socket="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SOCKET_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h socket.h, + [], [], [$curl_includes_socket]) +]) + + +dnl CURL_INCLUDES_STDLIB +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when stdlib.h is to be included. + +AC_DEFUN([CURL_INCLUDES_STDLIB], [ +curl_includes_stdlib="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h, + [], [], [$curl_includes_stdlib]) +]) + + +dnl CURL_INCLUDES_STRING +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when string(s).h is to be included. + +AC_DEFUN([CURL_INCLUDES_STRING], [ +curl_includes_string="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +#ifdef HAVE_STRINGS_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h strings.h, + [], [], [$curl_includes_string]) +]) + + +dnl CURL_INCLUDES_STROPTS +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when stropts.h is to be included. + +AC_DEFUN([CURL_INCLUDES_STROPTS], [ +curl_includes_stropts="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_STROPTS_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h unistd.h sys/socket.h sys/ioctl.h stropts.h, + [], [], [$curl_includes_stropts]) +]) + + +dnl CURL_INCLUDES_SYS_SOCKET +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when sys/socket.h is to be included. + +AC_DEFUN([CURL_INCLUDES_SYS_SOCKET], [ +curl_includes_sys_socket="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h sys/socket.h, + [], [], [$curl_includes_sys_socket]) +]) + + +dnl CURL_INCLUDES_SYS_TYPES +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when sys/types.h is to be included. + +AC_DEFUN([CURL_INCLUDES_SYS_TYPES], [ +curl_includes_sys_types="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h, + [], [], [$curl_includes_sys_types]) +]) + + +dnl CURL_INCLUDES_SYS_XATTR +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when sys/xattr.h is to be included. + +AC_DEFUN([CURL_INCLUDES_SYS_XATTR], [ +curl_includes_sys_xattr="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_XATTR_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h sys/xattr.h, + [], [], [$curl_includes_sys_xattr]) +]) + +dnl CURL_INCLUDES_TIME +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when time.h is to be included. + +AC_DEFUN([CURL_INCLUDES_TIME], [ +curl_includes_time="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h sys/time.h, + [], [], [$curl_includes_time]) +]) + + +dnl CURL_INCLUDES_UNISTD +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when unistd.h is to be included. + +AC_DEFUN([CURL_INCLUDES_UNISTD], [ +curl_includes_unistd="\ +/* includes start */ +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + sys/types.h unistd.h, + [], [], [$curl_includes_unistd]) +]) + + +dnl CURL_INCLUDES_WINSOCK2 +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when winsock2.h is to be included. + +AC_DEFUN([CURL_INCLUDES_WINSOCK2], [ +curl_includes_winsock2="\ +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif +/* includes end */" + CURL_CHECK_NATIVE_WINDOWS +]) + + +dnl CURL_INCLUDES_WS2TCPIP +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when ws2tcpip.h is to be included. + +AC_DEFUN([CURL_INCLUDES_WS2TCPIP], [ +curl_includes_ws2tcpip="\ +/* includes start */ +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +#endif +/* includes end */" + CURL_CHECK_NATIVE_WINDOWS +]) + + +dnl CURL_INCLUDES_BSDSOCKET +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when bsdsocket.h is to be included. + +AC_DEFUN([CURL_INCLUDES_BSDSOCKET], [ +curl_includes_bsdsocket="\ +/* includes start */ +#if defined(HAVE_PROTO_BSDSOCKET_H) +# define __NO_NET_API +# define __USE_INLINE__ +# include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif +# ifdef __amigaos4__ +struct SocketIFace *ISocket = NULL; +# else +struct Library *SocketBase = NULL; +# endif +# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) +#endif +/* includes end */" + AC_CHECK_HEADERS( + proto/bsdsocket.h, + [], [], [$curl_includes_bsdsocket]) +]) + +dnl CURL_INCLUDES_NETIF +dnl ------------------------------------------------- +dnl Set up variable with list of headers that must be +dnl included when net/if.h is to be included. + +AC_DEFUN([CURL_INCLUDES_NETIF], [ +curl_includes_netif="\ +/* includes start */ +#ifdef HAVE_NET_IF_H +# include +#endif +/* includes end */" + AC_CHECK_HEADERS( + net/if.h, + [], [], [$curl_includes_netif]) +]) + + +dnl CURL_PREPROCESS_CALLCONV +dnl ------------------------------------------------- +dnl Set up variable with a preprocessor block which +dnl defines function calling convention. + +AC_DEFUN([CURL_PREPROCESS_CALLCONV], [ +curl_preprocess_callconv="\ +/* preprocess start */ +#ifdef _WIN32 +# define FUNCALLCONV __stdcall +#else +# define FUNCALLCONV +#endif +/* preprocess end */" +]) + + +dnl CURL_CHECK_FUNC_ALARM +dnl ------------------------------------------------- +dnl Verify if alarm is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_alarm, then +dnl HAVE_ALARM will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_ALARM], [ + AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl + # + tst_links_alarm="unknown" + tst_proto_alarm="unknown" + tst_compi_alarm="unknown" + tst_allow_alarm="unknown" + # + AC_MSG_CHECKING([if alarm can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([alarm]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_alarm="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_alarm="no" + ]) + # + if test "$tst_links_alarm" = "yes"; then + AC_MSG_CHECKING([if alarm is prototyped]) + AC_EGREP_CPP([alarm],[ + $curl_includes_unistd + ],[ + AC_MSG_RESULT([yes]) + tst_proto_alarm="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_alarm="no" + ]) + fi + # + if test "$tst_proto_alarm" = "yes"; then + AC_MSG_CHECKING([if alarm is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_unistd + ]],[[ + if(0 != alarm(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_alarm="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_alarm="no" + ]) + fi + # + if test "$tst_compi_alarm" = "yes"; then + AC_MSG_CHECKING([if alarm usage allowed]) + if test "x$curl_disallow_alarm" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_alarm="yes" + else + AC_MSG_RESULT([no]) + tst_allow_alarm="no" + fi + fi + # + AC_MSG_CHECKING([if alarm might be used]) + if test "$tst_links_alarm" = "yes" && + test "$tst_proto_alarm" = "yes" && + test "$tst_compi_alarm" = "yes" && + test "$tst_allow_alarm" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_ALARM, 1, + [Define to 1 if you have the alarm function.]) + curl_cv_func_alarm="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_alarm="no" + fi +]) + + +dnl CURL_CHECK_FUNC_BASENAME +dnl ------------------------------------------------- +dnl Verify if basename is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_basename, then +dnl HAVE_BASENAME will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_BASENAME], [ + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + AC_REQUIRE([CURL_INCLUDES_LIBGEN])dnl + AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl + # + tst_links_basename="unknown" + tst_proto_basename="unknown" + tst_compi_basename="unknown" + tst_allow_basename="unknown" + # + AC_MSG_CHECKING([if basename can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([basename]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_basename="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_basename="no" + ]) + # + if test "$tst_links_basename" = "yes"; then + AC_MSG_CHECKING([if basename is prototyped]) + AC_EGREP_CPP([basename],[ + $curl_includes_string + $curl_includes_libgen + $curl_includes_unistd + ],[ + AC_MSG_RESULT([yes]) + tst_proto_basename="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_basename="no" + ]) + fi + # + if test "$tst_proto_basename" = "yes"; then + AC_MSG_CHECKING([if basename is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + $curl_includes_libgen + $curl_includes_unistd + ]],[[ + if(0 != basename(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_basename="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_basename="no" + ]) + fi + # + if test "$tst_compi_basename" = "yes"; then + AC_MSG_CHECKING([if basename usage allowed]) + if test "x$curl_disallow_basename" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_basename="yes" + else + AC_MSG_RESULT([no]) + tst_allow_basename="no" + fi + fi + # + AC_MSG_CHECKING([if basename might be used]) + if test "$tst_links_basename" = "yes" && + test "$tst_proto_basename" = "yes" && + test "$tst_compi_basename" = "yes" && + test "$tst_allow_basename" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_BASENAME, 1, + [Define to 1 if you have the basename function.]) + curl_cv_func_basename="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_basename="no" + fi +]) + + +dnl CURL_CHECK_FUNC_CLOSESOCKET +dnl ------------------------------------------------- +dnl Verify if closesocket is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_closesocket, then +dnl HAVE_CLOSESOCKET will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_CLOSESOCKET], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl + # + tst_links_closesocket="unknown" + tst_proto_closesocket="unknown" + tst_compi_closesocket="unknown" + tst_allow_closesocket="unknown" + # + AC_MSG_CHECKING([if closesocket can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_socket + ]],[[ + if(0 != closesocket(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_closesocket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_closesocket="no" + ]) + # + if test "$tst_links_closesocket" = "yes"; then + AC_MSG_CHECKING([if closesocket is prototyped]) + AC_EGREP_CPP([closesocket],[ + $curl_includes_winsock2 + $curl_includes_socket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_closesocket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_closesocket="no" + ]) + fi + # + if test "$tst_proto_closesocket" = "yes"; then + AC_MSG_CHECKING([if closesocket is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_socket + ]],[[ + if(0 != closesocket(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_closesocket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_closesocket="no" + ]) + fi + # + if test "$tst_compi_closesocket" = "yes"; then + AC_MSG_CHECKING([if closesocket usage allowed]) + if test "x$curl_disallow_closesocket" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_closesocket="yes" + else + AC_MSG_RESULT([no]) + tst_allow_closesocket="no" + fi + fi + # + AC_MSG_CHECKING([if closesocket might be used]) + if test "$tst_links_closesocket" = "yes" && + test "$tst_proto_closesocket" = "yes" && + test "$tst_compi_closesocket" = "yes" && + test "$tst_allow_closesocket" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_CLOSESOCKET, 1, + [Define to 1 if you have the closesocket function.]) + curl_cv_func_closesocket="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_closesocket="no" + fi +]) + + +dnl CURL_CHECK_FUNC_CLOSESOCKET_CAMEL +dnl ------------------------------------------------- +dnl Verify if CloseSocket is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_closesocket_camel, +dnl then HAVE_CLOSESOCKET_CAMEL will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_CLOSESOCKET_CAMEL], [ + AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + # + tst_links_closesocket_camel="unknown" + tst_proto_closesocket_camel="unknown" + tst_compi_closesocket_camel="unknown" + tst_allow_closesocket_camel="unknown" + # + AC_MSG_CHECKING([if CloseSocket can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_bsdsocket + $curl_includes_sys_socket + ]],[[ + if(0 != CloseSocket(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_closesocket_camel="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_closesocket_camel="no" + ]) + # + if test "$tst_links_closesocket_camel" = "yes"; then + AC_MSG_CHECKING([if CloseSocket is prototyped]) + AC_EGREP_CPP([CloseSocket],[ + $curl_includes_bsdsocket + $curl_includes_sys_socket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_closesocket_camel="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_closesocket_camel="no" + ]) + fi + # + if test "$tst_proto_closesocket_camel" = "yes"; then + AC_MSG_CHECKING([if CloseSocket is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_bsdsocket + $curl_includes_sys_socket + ]],[[ + if(0 != CloseSocket(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_closesocket_camel="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_closesocket_camel="no" + ]) + fi + # + if test "$tst_compi_closesocket_camel" = "yes"; then + AC_MSG_CHECKING([if CloseSocket usage allowed]) + if test "x$curl_disallow_closesocket_camel" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_closesocket_camel="yes" + else + AC_MSG_RESULT([no]) + tst_allow_closesocket_camel="no" + fi + fi + # + AC_MSG_CHECKING([if CloseSocket might be used]) + if test "$tst_links_closesocket_camel" = "yes" && + test "$tst_proto_closesocket_camel" = "yes" && + test "$tst_compi_closesocket_camel" = "yes" && + test "$tst_allow_closesocket_camel" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_CLOSESOCKET_CAMEL, 1, + [Define to 1 if you have the CloseSocket camel case function.]) + curl_cv_func_closesocket_camel="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_closesocket_camel="no" + fi +]) + +dnl CURL_CHECK_FUNC_FCNTL +dnl ------------------------------------------------- +dnl Verify if fcntl is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_fcntl, then +dnl HAVE_FCNTL will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FCNTL], [ + AC_REQUIRE([CURL_INCLUDES_FCNTL])dnl + # + tst_links_fcntl="unknown" + tst_proto_fcntl="unknown" + tst_compi_fcntl="unknown" + tst_allow_fcntl="unknown" + # + AC_MSG_CHECKING([if fcntl can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([fcntl]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_fcntl="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_fcntl="no" + ]) + # + if test "$tst_links_fcntl" = "yes"; then + AC_MSG_CHECKING([if fcntl is prototyped]) + AC_EGREP_CPP([fcntl],[ + $curl_includes_fcntl + ],[ + AC_MSG_RESULT([yes]) + tst_proto_fcntl="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_fcntl="no" + ]) + fi + # + if test "$tst_proto_fcntl" = "yes"; then + AC_MSG_CHECKING([if fcntl is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_fcntl + ]],[[ + if(0 != fcntl(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fcntl="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fcntl="no" + ]) + fi + # + if test "$tst_compi_fcntl" = "yes"; then + AC_MSG_CHECKING([if fcntl usage allowed]) + if test "x$curl_disallow_fcntl" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_fcntl="yes" + else + AC_MSG_RESULT([no]) + tst_allow_fcntl="no" + fi + fi + # + AC_MSG_CHECKING([if fcntl might be used]) + if test "$tst_links_fcntl" = "yes" && + test "$tst_proto_fcntl" = "yes" && + test "$tst_compi_fcntl" = "yes" && + test "$tst_allow_fcntl" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FCNTL, 1, + [Define to 1 if you have the fcntl function.]) + curl_cv_func_fcntl="yes" + CURL_CHECK_FUNC_FCNTL_O_NONBLOCK + else + AC_MSG_RESULT([no]) + curl_cv_func_fcntl="no" + fi +]) + + +dnl CURL_CHECK_FUNC_FCNTL_O_NONBLOCK +dnl ------------------------------------------------- +dnl Verify if fcntl with status flag O_NONBLOCK is +dnl available, can be compiled, and seems to work. If +dnl all of these are true, then HAVE_FCNTL_O_NONBLOCK +dnl will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FCNTL_O_NONBLOCK], [ + # + tst_compi_fcntl_o_nonblock="unknown" + tst_allow_fcntl_o_nonblock="unknown" + # + case $host_os in + sunos4* | aix3*) + dnl O_NONBLOCK does not work on these platforms + curl_disallow_fcntl_o_nonblock="yes" + ;; + esac + # + if test "$curl_cv_func_fcntl" = "yes"; then + AC_MSG_CHECKING([if fcntl O_NONBLOCK is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_fcntl + ]],[[ + int flags = 0; + if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fcntl_o_nonblock="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fcntl_o_nonblock="no" + ]) + fi + # + if test "$tst_compi_fcntl_o_nonblock" = "yes"; then + AC_MSG_CHECKING([if fcntl O_NONBLOCK usage allowed]) + if test "x$curl_disallow_fcntl_o_nonblock" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_fcntl_o_nonblock="yes" + else + AC_MSG_RESULT([no]) + tst_allow_fcntl_o_nonblock="no" + fi + fi + # + AC_MSG_CHECKING([if fcntl O_NONBLOCK might be used]) + if test "$tst_compi_fcntl_o_nonblock" = "yes" && + test "$tst_allow_fcntl_o_nonblock" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FCNTL_O_NONBLOCK, 1, + [Define to 1 if you have a working fcntl O_NONBLOCK function.]) + curl_cv_func_fcntl_o_nonblock="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_fcntl_o_nonblock="no" + fi +]) + +dnl CURL_CHECK_FUNC_FGETXATTR +dnl ------------------------------------------------- +dnl Verify if fgetxattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_fgetxattr, then +dnl HAVE_FGETXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FGETXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_fgetxattr="unknown" + tst_proto_fgetxattr="unknown" + tst_compi_fgetxattr="unknown" + tst_allow_fgetxattr="unknown" + tst_nargs_fgetxattr="unknown" + # + AC_MSG_CHECKING([if fgetxattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([fgetxattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_fgetxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_fgetxattr="no" + ]) + # + if test "$tst_links_fgetxattr" = "yes"; then + AC_MSG_CHECKING([if fgetxattr is prototyped]) + AC_EGREP_CPP([fgetxattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_fgetxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_fgetxattr="no" + ]) + fi + # + if test "$tst_proto_fgetxattr" = "yes"; then + if test "$tst_nargs_fgetxattr" = "unknown"; then + AC_MSG_CHECKING([if fgetxattr takes 4 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != fgetxattr(0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fgetxattr="yes" + tst_nargs_fgetxattr="4" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fgetxattr="no" + ]) + fi + if test "$tst_nargs_fgetxattr" = "unknown"; then + AC_MSG_CHECKING([if fgetxattr takes 6 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != fgetxattr(0, 0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fgetxattr="yes" + tst_nargs_fgetxattr="6" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fgetxattr="no" + ]) + fi + AC_MSG_CHECKING([if fgetxattr is compilable]) + if test "$tst_compi_fgetxattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_fgetxattr" = "yes"; then + AC_MSG_CHECKING([if fgetxattr usage allowed]) + if test "x$curl_disallow_fgetxattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_fgetxattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_fgetxattr="no" + fi + fi + # + AC_MSG_CHECKING([if fgetxattr might be used]) + if test "$tst_links_fgetxattr" = "yes" && + test "$tst_proto_fgetxattr" = "yes" && + test "$tst_compi_fgetxattr" = "yes" && + test "$tst_allow_fgetxattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FGETXATTR, 1, + [Define to 1 if you have the fgetxattr function.]) + dnl AC_DEFINE_UNQUOTED(FGETXATTR_ARGS, $tst_nargs_fgetxattr, + dnl [Specifies the number of arguments to fgetxattr]) + # + if test "$tst_nargs_fgetxattr" -eq "4"; then + AC_DEFINE(HAVE_FGETXATTR_4, 1, [fgetxattr() takes 4 args]) + elif test "$tst_nargs_fgetxattr" -eq "6"; then + AC_DEFINE(HAVE_FGETXATTR_6, 1, [fgetxattr() takes 6 args]) + fi + # + curl_cv_func_fgetxattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_fgetxattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_FLISTXATTR +dnl ------------------------------------------------- +dnl Verify if flistxattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_flistxattr, then +dnl HAVE_FLISTXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FLISTXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_flistxattr="unknown" + tst_proto_flistxattr="unknown" + tst_compi_flistxattr="unknown" + tst_allow_flistxattr="unknown" + tst_nargs_flistxattr="unknown" + # + AC_MSG_CHECKING([if flistxattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([flistxattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_flistxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_flistxattr="no" + ]) + # + if test "$tst_links_flistxattr" = "yes"; then + AC_MSG_CHECKING([if flistxattr is prototyped]) + AC_EGREP_CPP([flistxattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_flistxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_flistxattr="no" + ]) + fi + # + if test "$tst_proto_flistxattr" = "yes"; then + if test "$tst_nargs_flistxattr" = "unknown"; then + AC_MSG_CHECKING([if flistxattr takes 3 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != flistxattr(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_flistxattr="yes" + tst_nargs_flistxattr="3" + ],[ + AC_MSG_RESULT([no]) + tst_compi_flistxattr="no" + ]) + fi + if test "$tst_nargs_flistxattr" = "unknown"; then + AC_MSG_CHECKING([if flistxattr takes 4 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != flistxattr(0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_flistxattr="yes" + tst_nargs_flistxattr="4" + ],[ + AC_MSG_RESULT([no]) + tst_compi_flistxattr="no" + ]) + fi + AC_MSG_CHECKING([if flistxattr is compilable]) + if test "$tst_compi_flistxattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_flistxattr" = "yes"; then + AC_MSG_CHECKING([if flistxattr usage allowed]) + if test "x$curl_disallow_flistxattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_flistxattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_flistxattr="no" + fi + fi + # + AC_MSG_CHECKING([if flistxattr might be used]) + if test "$tst_links_flistxattr" = "yes" && + test "$tst_proto_flistxattr" = "yes" && + test "$tst_compi_flistxattr" = "yes" && + test "$tst_allow_flistxattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FLISTXATTR, 1, + [Define to 1 if you have the flistxattr function.]) + dnl AC_DEFINE_UNQUOTED(FLISTXATTR_ARGS, $tst_nargs_flistxattr, + dnl [Specifies the number of arguments to flistxattr]) + # + if test "$tst_nargs_flistxattr" -eq "3"; then + AC_DEFINE(HAVE_FLISTXATTR_3, 1, [flistxattr() takes 3 args]) + elif test "$tst_nargs_flistxattr" -eq "4"; then + AC_DEFINE(HAVE_FLISTXATTR_4, 1, [flistxattr() takes 4 args]) + fi + # + curl_cv_func_flistxattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_flistxattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_FREEADDRINFO +dnl ------------------------------------------------- +dnl Verify if freeaddrinfo is available, prototyped, +dnl and can be compiled. If all of these are true, +dnl and usage has not been previously disallowed with +dnl shell variable curl_disallow_freeaddrinfo, then +dnl HAVE_FREEADDRINFO will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FREEADDRINFO], [ + AC_REQUIRE([CURL_INCLUDES_WS2TCPIP])dnl + AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl + AC_REQUIRE([CURL_INCLUDES_NETDB])dnl + # + tst_links_freeaddrinfo="unknown" + tst_proto_freeaddrinfo="unknown" + tst_compi_freeaddrinfo="unknown" + tst_allow_freeaddrinfo="unknown" + # + AC_MSG_CHECKING([if freeaddrinfo can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + ]],[[ + freeaddrinfo(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_freeaddrinfo="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_freeaddrinfo="no" + ]) + # + if test "$tst_links_freeaddrinfo" = "yes"; then + AC_MSG_CHECKING([if freeaddrinfo is prototyped]) + AC_EGREP_CPP([freeaddrinfo],[ + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + ],[ + AC_MSG_RESULT([yes]) + tst_proto_freeaddrinfo="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_freeaddrinfo="no" + ]) + fi + # + if test "$tst_proto_freeaddrinfo" = "yes"; then + AC_MSG_CHECKING([if freeaddrinfo is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + ]],[[ + freeaddrinfo(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_freeaddrinfo="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_freeaddrinfo="no" + ]) + fi + # + if test "$tst_compi_freeaddrinfo" = "yes"; then + AC_MSG_CHECKING([if freeaddrinfo usage allowed]) + if test "x$curl_disallow_freeaddrinfo" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_freeaddrinfo="yes" + else + AC_MSG_RESULT([no]) + tst_allow_freeaddrinfo="no" + fi + fi + # + AC_MSG_CHECKING([if freeaddrinfo might be used]) + if test "$tst_links_freeaddrinfo" = "yes" && + test "$tst_proto_freeaddrinfo" = "yes" && + test "$tst_compi_freeaddrinfo" = "yes" && + test "$tst_allow_freeaddrinfo" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FREEADDRINFO, 1, + [Define to 1 if you have the freeaddrinfo function.]) + curl_cv_func_freeaddrinfo="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_freeaddrinfo="no" + fi +]) + + +dnl CURL_CHECK_FUNC_FREMOVEXATTR +dnl ------------------------------------------------- +dnl Verify if fremovexattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_fremovexattr, then +dnl HAVE_FREMOVEXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FREMOVEXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_fremovexattr="unknown" + tst_proto_fremovexattr="unknown" + tst_compi_fremovexattr="unknown" + tst_allow_fremovexattr="unknown" + tst_nargs_fremovexattr="unknown" + # + AC_MSG_CHECKING([if fremovexattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([fremovexattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_fremovexattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_fremovexattr="no" + ]) + # + if test "$tst_links_fremovexattr" = "yes"; then + AC_MSG_CHECKING([if fremovexattr is prototyped]) + AC_EGREP_CPP([fremovexattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_fremovexattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_fremovexattr="no" + ]) + fi + # + if test "$tst_proto_fremovexattr" = "yes"; then + if test "$tst_nargs_fremovexattr" = "unknown"; then + AC_MSG_CHECKING([if fremovexattr takes 2 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != fremovexattr(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fremovexattr="yes" + tst_nargs_fremovexattr="2" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fremovexattr="no" + ]) + fi + if test "$tst_nargs_fremovexattr" = "unknown"; then + AC_MSG_CHECKING([if fremovexattr takes 3 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != fremovexattr(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fremovexattr="yes" + tst_nargs_fremovexattr="3" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fremovexattr="no" + ]) + fi + AC_MSG_CHECKING([if fremovexattr is compilable]) + if test "$tst_compi_fremovexattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_fremovexattr" = "yes"; then + AC_MSG_CHECKING([if fremovexattr usage allowed]) + if test "x$curl_disallow_fremovexattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_fremovexattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_fremovexattr="no" + fi + fi + # + AC_MSG_CHECKING([if fremovexattr might be used]) + if test "$tst_links_fremovexattr" = "yes" && + test "$tst_proto_fremovexattr" = "yes" && + test "$tst_compi_fremovexattr" = "yes" && + test "$tst_allow_fremovexattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FREMOVEXATTR, 1, + [Define to 1 if you have the fremovexattr function.]) + dnl AC_DEFINE_UNQUOTED(FREMOVEXATTR_ARGS, $tst_nargs_fremovexattr, + dnl [Specifies the number of arguments to fremovexattr]) + # + if test "$tst_nargs_fremovexattr" -eq "2"; then + AC_DEFINE(HAVE_FREMOVEXATTR_2, 1, [fremovexattr() takes 2 args]) + elif test "$tst_nargs_fremovexattr" -eq "3"; then + AC_DEFINE(HAVE_FREMOVEXATTR_3, 1, [fremovexattr() takes 3 args]) + fi + # + curl_cv_func_fremovexattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_fremovexattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_FSETXATTR +dnl ------------------------------------------------- +dnl Verify if fsetxattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_fsetxattr, then +dnl HAVE_FSETXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FSETXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_fsetxattr="unknown" + tst_proto_fsetxattr="unknown" + tst_compi_fsetxattr="unknown" + tst_allow_fsetxattr="unknown" + tst_nargs_fsetxattr="unknown" + # + AC_MSG_CHECKING([if fsetxattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([fsetxattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_fsetxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_fsetxattr="no" + ]) + # + if test "$tst_links_fsetxattr" = "yes"; then + AC_MSG_CHECKING([if fsetxattr is prototyped]) + AC_EGREP_CPP([fsetxattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_fsetxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_fsetxattr="no" + ]) + fi + # + if test "$tst_proto_fsetxattr" = "yes"; then + if test "$tst_nargs_fsetxattr" = "unknown"; then + AC_MSG_CHECKING([if fsetxattr takes 5 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != fsetxattr(0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fsetxattr="yes" + tst_nargs_fsetxattr="5" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fsetxattr="no" + ]) + fi + if test "$tst_nargs_fsetxattr" = "unknown"; then + AC_MSG_CHECKING([if fsetxattr takes 6 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != fsetxattr(0, 0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_fsetxattr="yes" + tst_nargs_fsetxattr="6" + ],[ + AC_MSG_RESULT([no]) + tst_compi_fsetxattr="no" + ]) + fi + AC_MSG_CHECKING([if fsetxattr is compilable]) + if test "$tst_compi_fsetxattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_fsetxattr" = "yes"; then + AC_MSG_CHECKING([if fsetxattr usage allowed]) + if test "x$curl_disallow_fsetxattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_fsetxattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_fsetxattr="no" + fi + fi + # + AC_MSG_CHECKING([if fsetxattr might be used]) + if test "$tst_links_fsetxattr" = "yes" && + test "$tst_proto_fsetxattr" = "yes" && + test "$tst_compi_fsetxattr" = "yes" && + test "$tst_allow_fsetxattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FSETXATTR, 1, + [Define to 1 if you have the fsetxattr function.]) + dnl AC_DEFINE_UNQUOTED(FSETXATTR_ARGS, $tst_nargs_fsetxattr, + dnl [Specifies the number of arguments to fsetxattr]) + # + if test "$tst_nargs_fsetxattr" -eq "5"; then + AC_DEFINE(HAVE_FSETXATTR_5, 1, [fsetxattr() takes 5 args]) + elif test "$tst_nargs_fsetxattr" -eq "6"; then + AC_DEFINE(HAVE_FSETXATTR_6, 1, [fsetxattr() takes 6 args]) + fi + # + curl_cv_func_fsetxattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_fsetxattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_FTRUNCATE +dnl ------------------------------------------------- +dnl Verify if ftruncate is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_ftruncate, then +dnl HAVE_FTRUNCATE will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_FTRUNCATE], [ + AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl + # + tst_links_ftruncate="unknown" + tst_proto_ftruncate="unknown" + tst_compi_ftruncate="unknown" + tst_allow_ftruncate="unknown" + # + AC_MSG_CHECKING([if ftruncate can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([ftruncate]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_ftruncate="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_ftruncate="no" + ]) + # + if test "$tst_links_ftruncate" = "yes"; then + AC_MSG_CHECKING([if ftruncate is prototyped]) + AC_EGREP_CPP([ftruncate],[ + $curl_includes_unistd + ],[ + AC_MSG_RESULT([yes]) + tst_proto_ftruncate="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_ftruncate="no" + ]) + fi + # + if test "$tst_proto_ftruncate" = "yes"; then + AC_MSG_CHECKING([if ftruncate is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_unistd + ]],[[ + if(0 != ftruncate(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ftruncate="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ftruncate="no" + ]) + fi + # + if test "$tst_compi_ftruncate" = "yes"; then + AC_MSG_CHECKING([if ftruncate usage allowed]) + if test "x$curl_disallow_ftruncate" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ftruncate="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ftruncate="no" + fi + fi + # + AC_MSG_CHECKING([if ftruncate might be used]) + if test "$tst_links_ftruncate" = "yes" && + test "$tst_proto_ftruncate" = "yes" && + test "$tst_compi_ftruncate" = "yes" && + test "$tst_allow_ftruncate" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_FTRUNCATE, 1, + [Define to 1 if you have the ftruncate function.]) + curl_cv_func_ftruncate="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_ftruncate="no" + fi +]) + + +dnl CURL_CHECK_FUNC_GETADDRINFO +dnl ------------------------------------------------- +dnl Verify if getaddrinfo is available, prototyped, can +dnl be compiled and seems to work. If all of these are +dnl true, and usage has not been previously disallowed +dnl with shell variable curl_disallow_getaddrinfo, then +dnl HAVE_GETADDRINFO will be defined. Additionally when +dnl HAVE_GETADDRINFO gets defined this will also attempt +dnl to find out if getaddrinfo happens to be threadsafe, +dnl defining HAVE_GETADDRINFO_THREADSAFE when true. + +AC_DEFUN([CURL_CHECK_FUNC_GETADDRINFO], [ + AC_REQUIRE([CURL_INCLUDES_WS2TCPIP])dnl + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl + AC_REQUIRE([CURL_INCLUDES_NETDB])dnl + AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl + # + tst_links_getaddrinfo="unknown" + tst_proto_getaddrinfo="unknown" + tst_compi_getaddrinfo="unknown" + tst_works_getaddrinfo="unknown" + tst_allow_getaddrinfo="unknown" + tst_tsafe_getaddrinfo="unknown" + # + AC_MSG_CHECKING([if getaddrinfo can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + ]],[[ + if(0 != getaddrinfo(0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_getaddrinfo="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_getaddrinfo="no" + ]) + # + if test "$tst_links_getaddrinfo" = "yes"; then + AC_MSG_CHECKING([if getaddrinfo is prototyped]) + AC_EGREP_CPP([getaddrinfo],[ + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + ],[ + AC_MSG_RESULT([yes]) + tst_proto_getaddrinfo="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_getaddrinfo="no" + ]) + fi + # + if test "$tst_proto_getaddrinfo" = "yes"; then + AC_MSG_CHECKING([if getaddrinfo is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_ws2tcpip + $curl_includes_sys_socket + $curl_includes_netdb + ]],[[ + if(0 != getaddrinfo(0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_getaddrinfo="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_getaddrinfo="no" + ]) + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_getaddrinfo" = "yes"; then + AC_MSG_CHECKING([if getaddrinfo seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_ws2tcpip + $curl_includes_stdlib + $curl_includes_string + $curl_includes_sys_socket + $curl_includes_netdb + ]],[[ + struct addrinfo hints; + struct addrinfo *ai = 0; + int error; + + #ifdef _WIN32 + WSADATA wsa; + if(WSAStartup(MAKEWORD(2, 2), &wsa)) + exit(2); + #endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo("127.0.0.1", 0, &hints, &ai); + if(error || !ai) + exit(1); /* fail */ + else + exit(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_getaddrinfo="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_getaddrinfo="no" + ]) + fi + # + if test "$tst_compi_getaddrinfo" = "yes" && + test "$tst_works_getaddrinfo" != "no"; then + AC_MSG_CHECKING([if getaddrinfo usage allowed]) + if test "x$curl_disallow_getaddrinfo" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_getaddrinfo="yes" + else + AC_MSG_RESULT([no]) + tst_allow_getaddrinfo="no" + fi + fi + # + AC_MSG_CHECKING([if getaddrinfo might be used]) + if test "$tst_links_getaddrinfo" = "yes" && + test "$tst_proto_getaddrinfo" = "yes" && + test "$tst_compi_getaddrinfo" = "yes" && + test "$tst_allow_getaddrinfo" = "yes" && + test "$tst_works_getaddrinfo" != "no"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETADDRINFO, 1, + [Define to 1 if you have a working getaddrinfo function.]) + curl_cv_func_getaddrinfo="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_getaddrinfo="no" + curl_cv_func_getaddrinfo_threadsafe="no" + fi + # + if test "$curl_cv_func_getaddrinfo" = "yes"; then + AC_MSG_CHECKING([if getaddrinfo is threadsafe]) + case $host_os in + aix[[1234]].* | aix5.[[01]].*) + dnl aix 5.1 and older + tst_tsafe_getaddrinfo="no" + ;; + aix*) + dnl aix 5.2 and newer + tst_tsafe_getaddrinfo="yes" + ;; + darwin[[12345]].*) + dnl darwin 5.0 and mac os x 10.1.X and older + tst_tsafe_getaddrinfo="no" + ;; + darwin*) + dnl darwin 6.0 and mac os x 10.2.X and newer + tst_tsafe_getaddrinfo="yes" + ;; + freebsd[[1234]].* | freebsd5.[[1234]]*) + dnl freebsd 5.4 and older + tst_tsafe_getaddrinfo="no" + ;; + freebsd*) + dnl freebsd 5.5 and newer + tst_tsafe_getaddrinfo="yes" + ;; + hpux[[123456789]].* | hpux10.* | hpux11.0* | hpux11.10*) + dnl hpux 11.10 and older + tst_tsafe_getaddrinfo="no" + ;; + hpux*) + dnl hpux 11.11 and newer + tst_tsafe_getaddrinfo="yes" + ;; + midnightbsd*) + dnl all MidnightBSD versions + tst_tsafe_getaddrinfo="yes" + ;; + netbsd[[123]].*) + dnl netbsd 3.X and older + tst_tsafe_getaddrinfo="no" + ;; + netbsd*) + dnl netbsd 4.X and newer + tst_tsafe_getaddrinfo="yes" + ;; + *bsd*) + dnl All other bsd's + tst_tsafe_getaddrinfo="no" + ;; + solaris2*) + dnl solaris which have it + tst_tsafe_getaddrinfo="yes" + ;; + esac + if test "$tst_tsafe_getaddrinfo" = "unknown" && + test "$curl_cv_native_windows" = "yes"; then + tst_tsafe_getaddrinfo="yes" + fi + if test "$tst_tsafe_getaddrinfo" = "unknown"; then + CURL_CHECK_DEF_CC([h_errno], [ + $curl_includes_sys_socket + $curl_includes_netdb + ], [silent]) + if test "$curl_cv_have_def_h_errno" = "yes"; then + tst_h_errno_macro="yes" + else + tst_h_errno_macro="no" + fi + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_socket + $curl_includes_netdb + ]],[[ + h_errno = 2; + if(0 != h_errno) + return 1; + ]]) + ],[ + tst_h_errno_modifiable_lvalue="yes" + ],[ + tst_h_errno_modifiable_lvalue="no" + ]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) + return 0; +#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700) + return 0; +#else + force compilation error +#endif + ]]) + ],[ + tst_h_errno_sbs_issue_7="yes" + ],[ + tst_h_errno_sbs_issue_7="no" + ]) + if test "$tst_h_errno_macro" = "no" && + test "$tst_h_errno_modifiable_lvalue" = "no" && + test "$tst_h_errno_sbs_issue_7" = "no"; then + tst_tsafe_getaddrinfo="no" + else + tst_tsafe_getaddrinfo="yes" + fi + fi + AC_MSG_RESULT([$tst_tsafe_getaddrinfo]) + if test "$tst_tsafe_getaddrinfo" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_GETADDRINFO_THREADSAFE, 1, + [Define to 1 if the getaddrinfo function is threadsafe.]) + curl_cv_func_getaddrinfo_threadsafe="yes" + else + curl_cv_func_getaddrinfo_threadsafe="no" + fi + fi +]) + + +dnl CURL_CHECK_FUNC_GETHOSTBYNAME +dnl ------------------------------------------------- +dnl Verify if gethostbyname is available, prototyped, +dnl and can be compiled. If all of these are true, +dnl and usage has not been previously disallowed with +dnl shell variable curl_disallow_gethostbyname, then +dnl HAVE_GETHOSTBYNAME will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GETHOSTBYNAME], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_NETDB])dnl + # + tst_links_gethostbyname="unknown" + tst_proto_gethostbyname="unknown" + tst_compi_gethostbyname="unknown" + tst_allow_gethostbyname="unknown" + # + AC_MSG_CHECKING([if gethostbyname can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_netdb + ]],[[ + if(0 != gethostbyname(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_gethostbyname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_gethostbyname="no" + ]) + # + if test "$tst_links_gethostbyname" = "yes"; then + AC_MSG_CHECKING([if gethostbyname is prototyped]) + AC_EGREP_CPP([gethostbyname],[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_netdb + ],[ + AC_MSG_RESULT([yes]) + tst_proto_gethostbyname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_gethostbyname="no" + ]) + fi + # + if test "$tst_proto_gethostbyname" = "yes"; then + AC_MSG_CHECKING([if gethostbyname is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_netdb + ]],[[ + if(0 != gethostbyname(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_gethostbyname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_gethostbyname="no" + ]) + fi + # + if test "$tst_compi_gethostbyname" = "yes"; then + AC_MSG_CHECKING([if gethostbyname usage allowed]) + if test "x$curl_disallow_gethostbyname" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_gethostbyname="yes" + else + AC_MSG_RESULT([no]) + tst_allow_gethostbyname="no" + fi + fi + # + AC_MSG_CHECKING([if gethostbyname might be used]) + if test "$tst_links_gethostbyname" = "yes" && + test "$tst_proto_gethostbyname" = "yes" && + test "$tst_compi_gethostbyname" = "yes" && + test "$tst_allow_gethostbyname" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETHOSTBYNAME, 1, + [Define to 1 if you have the gethostbyname function.]) + curl_cv_func_gethostbyname="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_gethostbyname="no" + fi +]) + + +dnl CURL_CHECK_FUNC_GETHOSTBYNAME_R +dnl ------------------------------------------------- +dnl Verify if gethostbyname_r is available, prototyped, +dnl and can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_gethostbyname_r, then +dnl HAVE_GETHOSTBYNAME_R will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GETHOSTBYNAME_R], [ + AC_REQUIRE([CURL_INCLUDES_NETDB])dnl + # + tst_links_gethostbyname_r="unknown" + tst_proto_gethostbyname_r="unknown" + tst_compi_gethostbyname_r="unknown" + tst_allow_gethostbyname_r="unknown" + tst_nargs_gethostbyname_r="unknown" + # + AC_MSG_CHECKING([if gethostbyname_r can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([gethostbyname_r]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_gethostbyname_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_gethostbyname_r="no" + ]) + # + if test "$tst_links_gethostbyname_r" = "yes"; then + AC_MSG_CHECKING([if gethostbyname_r is prototyped]) + AC_EGREP_CPP([gethostbyname_r],[ + $curl_includes_netdb + ],[ + AC_MSG_RESULT([yes]) + tst_proto_gethostbyname_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_gethostbyname_r="no" + ]) + fi + # + if test "$tst_proto_gethostbyname_r" = "yes"; then + if test "$tst_nargs_gethostbyname_r" = "unknown"; then + AC_MSG_CHECKING([if gethostbyname_r takes 3 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_netdb + $curl_includes_bsdsocket + ]],[[ + if(0 != gethostbyname_r(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_gethostbyname_r="yes" + tst_nargs_gethostbyname_r="3" + ],[ + AC_MSG_RESULT([no]) + tst_compi_gethostbyname_r="no" + ]) + fi + if test "$tst_nargs_gethostbyname_r" = "unknown"; then + AC_MSG_CHECKING([if gethostbyname_r takes 5 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_netdb + $curl_includes_bsdsocket + ]],[[ + if(0 != gethostbyname_r(0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_gethostbyname_r="yes" + tst_nargs_gethostbyname_r="5" + ],[ + AC_MSG_RESULT([no]) + tst_compi_gethostbyname_r="no" + ]) + fi + if test "$tst_nargs_gethostbyname_r" = "unknown"; then + AC_MSG_CHECKING([if gethostbyname_r takes 6 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_netdb + $curl_includes_bsdsocket + ]],[[ + if(0 != gethostbyname_r(0, 0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_gethostbyname_r="yes" + tst_nargs_gethostbyname_r="6" + ],[ + AC_MSG_RESULT([no]) + tst_compi_gethostbyname_r="no" + ]) + fi + AC_MSG_CHECKING([if gethostbyname_r is compilable]) + if test "$tst_compi_gethostbyname_r" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_gethostbyname_r" = "yes"; then + AC_MSG_CHECKING([if gethostbyname_r usage allowed]) + if test "x$curl_disallow_gethostbyname_r" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_gethostbyname_r="yes" + else + AC_MSG_RESULT([no]) + tst_allow_gethostbyname_r="no" + fi + fi + # + AC_MSG_CHECKING([if gethostbyname_r might be used]) + if test "$tst_links_gethostbyname_r" = "yes" && + test "$tst_proto_gethostbyname_r" = "yes" && + test "$tst_compi_gethostbyname_r" = "yes" && + test "$tst_allow_gethostbyname_r" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETHOSTBYNAME_R, 1, + [Define to 1 if you have the gethostbyname_r function.]) + dnl AC_DEFINE_UNQUOTED(GETHOSTBYNAME_R_ARGS, $tst_nargs_gethostbyname_r, + dnl [Specifies the number of arguments to gethostbyname_r]) + # + if test "$tst_nargs_gethostbyname_r" -eq "3"; then + AC_DEFINE(HAVE_GETHOSTBYNAME_R_3, 1, [gethostbyname_r() takes 3 args]) + elif test "$tst_nargs_gethostbyname_r" -eq "5"; then + AC_DEFINE(HAVE_GETHOSTBYNAME_R_5, 1, [gethostbyname_r() takes 5 args]) + elif test "$tst_nargs_gethostbyname_r" -eq "6"; then + AC_DEFINE(HAVE_GETHOSTBYNAME_R_6, 1, [gethostbyname_r() takes 6 args]) + fi + # + curl_cv_func_gethostbyname_r="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_gethostbyname_r="no" + fi +]) + + +dnl CURL_CHECK_FUNC_GETHOSTNAME +dnl ------------------------------------------------- +dnl Verify if gethostname is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_gethostname, then +dnl HAVE_GETHOSTNAME will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GETHOSTNAME], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl + AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl + # + tst_links_gethostname="unknown" + tst_proto_gethostname="unknown" + tst_compi_gethostname="unknown" + tst_allow_gethostname="unknown" + # + AC_MSG_CHECKING([if gethostname can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + ]],[[ + if(0 != gethostname(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_gethostname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_gethostname="no" + ]) + # + if test "$tst_links_gethostname" = "yes"; then + AC_MSG_CHECKING([if gethostname is prototyped]) + AC_EGREP_CPP([gethostname],[ + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_gethostname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_gethostname="no" + ]) + fi + # + if test "$tst_proto_gethostname" = "yes"; then + AC_MSG_CHECKING([if gethostname is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + ]],[[ + if(0 != gethostname(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_gethostname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_gethostname="no" + ]) + fi + # + if test "$tst_compi_gethostname" = "yes"; then + AC_MSG_CHECKING([for gethostname arg 2 data type]) + tst_gethostname_type_arg2="unknown" + for tst_arg1 in 'char *' 'unsigned char *' 'void *'; do + for tst_arg2 in 'int' 'unsigned int' 'size_t'; do + if test "$tst_gethostname_type_arg2" = "unknown"; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_unistd + $curl_includes_bsdsocket + $curl_preprocess_callconv + extern int FUNCALLCONV gethostname($tst_arg1, $tst_arg2); + ]],[[ + if(0 != gethostname(0, 0)) + return 1; + ]]) + ],[ + tst_gethostname_type_arg2="$tst_arg2" + ]) + fi + done + done + AC_MSG_RESULT([$tst_gethostname_type_arg2]) + if test "$tst_gethostname_type_arg2" != "unknown"; then + AC_DEFINE_UNQUOTED(GETHOSTNAME_TYPE_ARG2, $tst_gethostname_type_arg2, + [Define to the type of arg 2 for gethostname.]) + fi + fi + # + if test "$tst_compi_gethostname" = "yes"; then + AC_MSG_CHECKING([if gethostname usage allowed]) + if test "x$curl_disallow_gethostname" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_gethostname="yes" + else + AC_MSG_RESULT([no]) + tst_allow_gethostname="no" + fi + fi + # + AC_MSG_CHECKING([if gethostname might be used]) + if test "$tst_links_gethostname" = "yes" && + test "$tst_proto_gethostname" = "yes" && + test "$tst_compi_gethostname" = "yes" && + test "$tst_allow_gethostname" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETHOSTNAME, 1, + [Define to 1 if you have the gethostname function.]) + curl_cv_func_gethostname="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_gethostname="no" + fi +]) + +dnl CURL_CHECK_FUNC_GETPEERNAME +dnl ------------------------------------------------- +dnl Verify if getpeername is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_getpeername, then +dnl HAVE_GETPEERNAME will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GETPEERNAME], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl + AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + # + tst_links_getpeername="unknown" + tst_proto_getpeername="unknown" + tst_compi_getpeername="unknown" + tst_allow_getpeername="unknown" + # + AC_MSG_CHECKING([if getpeername can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + ]],[[ + if(0 != getpeername(0, (void *)0, (void *)0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_getpeername="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_getpeername="no" + ]) + # + if test "$tst_links_getpeername" = "yes"; then + AC_MSG_CHECKING([if getpeername is prototyped]) + AC_EGREP_CPP([getpeername],[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_getpeername="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_getpeername="no" + ]) + fi + # + if test "$tst_proto_getpeername" = "yes"; then + AC_MSG_CHECKING([if getpeername is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + ]],[[ + if(0 != getpeername(0, (void *)0, (void *)0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_getpeername="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_getpeername="no" + ]) + fi + # + if test "$tst_compi_getpeername" = "yes"; then + AC_MSG_CHECKING([if getpeername usage allowed]) + if test "x$curl_disallow_getpeername" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_getpeername="yes" + else + AC_MSG_RESULT([no]) + tst_allow_getpeername="no" + fi + fi + # + AC_MSG_CHECKING([if getpeername might be used]) + if test "$tst_links_getpeername" = "yes" && + test "$tst_proto_getpeername" = "yes" && + test "$tst_compi_getpeername" = "yes" && + test "$tst_allow_getpeername" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETPEERNAME, 1, + [Define to 1 if you have the getpeername function.]) + curl_cv_func_getpeername="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_getpeername="no" + fi +]) + +dnl CURL_CHECK_FUNC_GETSOCKNAME +dnl ------------------------------------------------- +dnl Verify if getsockname is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_getsockname, then +dnl HAVE_GETSOCKNAME will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GETSOCKNAME], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl + AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + # + tst_links_getsockname="unknown" + tst_proto_getsockname="unknown" + tst_compi_getsockname="unknown" + tst_allow_getsockname="unknown" + # + AC_MSG_CHECKING([if getsockname can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + ]],[[ + if(0 != getsockname(0, (void *)0, (void *)0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_getsockname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_getsockname="no" + ]) + # + if test "$tst_links_getsockname" = "yes"; then + AC_MSG_CHECKING([if getsockname is prototyped]) + AC_EGREP_CPP([getsockname],[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_getsockname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_getsockname="no" + ]) + fi + # + if test "$tst_proto_getsockname" = "yes"; then + AC_MSG_CHECKING([if getsockname is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + ]],[[ + if(0 != getsockname(0, (void *)0, (void *)0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_getsockname="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_getsockname="no" + ]) + fi + # + if test "$tst_compi_getsockname" = "yes"; then + AC_MSG_CHECKING([if getsockname usage allowed]) + if test "x$curl_disallow_getsockname" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_getsockname="yes" + else + AC_MSG_RESULT([no]) + tst_allow_getsockname="no" + fi + fi + # + AC_MSG_CHECKING([if getsockname might be used]) + if test "$tst_links_getsockname" = "yes" && + test "$tst_proto_getsockname" = "yes" && + test "$tst_compi_getsockname" = "yes" && + test "$tst_allow_getsockname" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETSOCKNAME, 1, + [Define to 1 if you have the getsockname function.]) + curl_cv_func_getsockname="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_getsockname="no" + fi +]) + +dnl CURL_CHECK_FUNC_IF_NAMETOINDEX +dnl ------------------------------------------------- +dnl Verify if if_nametoindex is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_if_nametoindex, then +dnl HAVE_IF_NAMETOINDEX will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IF_NAMETOINDEX], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_NETIF])dnl + AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl + # + tst_links_if_nametoindex="unknown" + tst_proto_if_nametoindex="unknown" + tst_compi_if_nametoindex="unknown" + tst_allow_if_nametoindex="unknown" + # + AC_MSG_CHECKING([if if_nametoindex can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + #include + ]],[[ + if(0 != if_nametoindex("")) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_if_nametoindex="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_if_nametoindex="no" + ]) + # + if test "$tst_links_if_nametoindex" = "yes"; then + AC_MSG_CHECKING([if if_nametoindex is prototyped]) + AC_EGREP_CPP([if_nametoindex],[ + $curl_includes_winsock2 + $curl_includes_netif + ],[ + AC_MSG_RESULT([yes]) + tst_proto_if_nametoindex="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_if_nametoindex="no" + ]) + fi + # + if test "$tst_proto_if_nametoindex" = "yes"; then + AC_MSG_CHECKING([if if_nametoindex is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_netif + ]],[[ + if(0 != if_nametoindex("")) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_if_nametoindex="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_if_nametoindex="no" + ]) + fi + # + if test "$tst_compi_if_nametoindex" = "yes"; then + AC_MSG_CHECKING([if if_nametoindex usage allowed]) + if test "x$curl_disallow_if_nametoindex" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_if_nametoindex="yes" + else + AC_MSG_RESULT([no]) + tst_allow_if_nametoindex="no" + fi + fi + # + AC_MSG_CHECKING([if if_nametoindex might be used]) + if test "$tst_links_if_nametoindex" = "yes" && + test "$tst_proto_if_nametoindex" = "yes" && + test "$tst_compi_if_nametoindex" = "yes" && + test "$tst_allow_if_nametoindex" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IF_NAMETOINDEX, 1, + [Define to 1 if you have the if_nametoindex function.]) + curl_cv_func_if_nametoindex="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_if_nametoindex="no" + fi +]) + + +dnl CURL_CHECK_FUNC_GETIFADDRS +dnl ------------------------------------------------- +dnl Verify if getifaddrs is available, prototyped, can +dnl be compiled and seems to work. If all of these are +dnl true, and usage has not been previously disallowed +dnl with shell variable curl_disallow_getifaddrs, then +dnl HAVE_GETIFADDRS will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GETIFADDRS], [ + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + AC_REQUIRE([CURL_INCLUDES_IFADDRS])dnl + # + tst_links_getifaddrs="unknown" + tst_proto_getifaddrs="unknown" + tst_compi_getifaddrs="unknown" + tst_works_getifaddrs="unknown" + tst_allow_getifaddrs="unknown" + # + AC_MSG_CHECKING([if getifaddrs can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([getifaddrs]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_getifaddrs="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_getifaddrs="no" + ]) + # + if test "$tst_links_getifaddrs" = "yes"; then + AC_MSG_CHECKING([if getifaddrs is prototyped]) + AC_EGREP_CPP([getifaddrs],[ + $curl_includes_ifaddrs + ],[ + AC_MSG_RESULT([yes]) + tst_proto_getifaddrs="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_getifaddrs="no" + ]) + fi + # + if test "$tst_proto_getifaddrs" = "yes"; then + AC_MSG_CHECKING([if getifaddrs is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_ifaddrs + ]],[[ + if(0 != getifaddrs(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_getifaddrs="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_getifaddrs="no" + ]) + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_getifaddrs" = "yes"; then + AC_MSG_CHECKING([if getifaddrs seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + $curl_includes_ifaddrs + ]],[[ + struct ifaddrs *ifa = 0; + int error; + + error = getifaddrs(&ifa); + if(error || !ifa) + exit(1); /* fail */ + else + exit(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_getifaddrs="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_getifaddrs="no" + ]) + fi + # + if test "$tst_compi_getifaddrs" = "yes" && + test "$tst_works_getifaddrs" != "no"; then + AC_MSG_CHECKING([if getifaddrs usage allowed]) + if test "x$curl_disallow_getifaddrs" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_getifaddrs="yes" + else + AC_MSG_RESULT([no]) + tst_allow_getifaddrs="no" + fi + fi + # + AC_MSG_CHECKING([if getifaddrs might be used]) + if test "$tst_links_getifaddrs" = "yes" && + test "$tst_proto_getifaddrs" = "yes" && + test "$tst_compi_getifaddrs" = "yes" && + test "$tst_allow_getifaddrs" = "yes" && + test "$tst_works_getifaddrs" != "no"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETIFADDRS, 1, + [Define to 1 if you have a working getifaddrs function.]) + curl_cv_func_getifaddrs="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_getifaddrs="no" + fi +]) + + +dnl CURL_CHECK_FUNC_GETXATTR +dnl ------------------------------------------------- +dnl Verify if getxattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_getxattr, then +dnl HAVE_GETXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GETXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_getxattr="unknown" + tst_proto_getxattr="unknown" + tst_compi_getxattr="unknown" + tst_allow_getxattr="unknown" + tst_nargs_getxattr="unknown" + # + AC_MSG_CHECKING([if getxattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([getxattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_getxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_getxattr="no" + ]) + # + if test "$tst_links_getxattr" = "yes"; then + AC_MSG_CHECKING([if getxattr is prototyped]) + AC_EGREP_CPP([getxattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_getxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_getxattr="no" + ]) + fi + # + if test "$tst_proto_getxattr" = "yes"; then + if test "$tst_nargs_getxattr" = "unknown"; then + AC_MSG_CHECKING([if getxattr takes 4 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != getxattr(0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_getxattr="yes" + tst_nargs_getxattr="4" + ],[ + AC_MSG_RESULT([no]) + tst_compi_getxattr="no" + ]) + fi + if test "$tst_nargs_getxattr" = "unknown"; then + AC_MSG_CHECKING([if getxattr takes 6 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != getxattr(0, 0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_getxattr="yes" + tst_nargs_getxattr="6" + ],[ + AC_MSG_RESULT([no]) + tst_compi_getxattr="no" + ]) + fi + AC_MSG_CHECKING([if getxattr is compilable]) + if test "$tst_compi_getxattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_getxattr" = "yes"; then + AC_MSG_CHECKING([if getxattr usage allowed]) + if test "x$curl_disallow_getxattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_getxattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_getxattr="no" + fi + fi + # + AC_MSG_CHECKING([if getxattr might be used]) + if test "$tst_links_getxattr" = "yes" && + test "$tst_proto_getxattr" = "yes" && + test "$tst_compi_getxattr" = "yes" && + test "$tst_allow_getxattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GETXATTR, 1, + [Define to 1 if you have the getxattr function.]) + dnl AC_DEFINE_UNQUOTED(GETXATTR_ARGS, $tst_nargs_getxattr, + dnl [Specifies the number of arguments to getxattr]) + # + if test "$tst_nargs_getxattr" -eq "4"; then + AC_DEFINE(HAVE_GETXATTR_4, 1, [getxattr() takes 4 args]) + elif test "$tst_nargs_getxattr" -eq "6"; then + AC_DEFINE(HAVE_GETXATTR_6, 1, [getxattr() takes 6 args]) + fi + # + curl_cv_func_getxattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_getxattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_GMTIME_R +dnl ------------------------------------------------- +dnl Verify if gmtime_r is available, prototyped, can +dnl be compiled and seems to work. If all of these are +dnl true, and usage has not been previously disallowed +dnl with shell variable curl_disallow_gmtime_r, then +dnl HAVE_GMTIME_R will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_GMTIME_R], [ + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + AC_REQUIRE([CURL_INCLUDES_TIME])dnl + # + tst_links_gmtime_r="unknown" + tst_proto_gmtime_r="unknown" + tst_compi_gmtime_r="unknown" + tst_works_gmtime_r="unknown" + tst_allow_gmtime_r="unknown" + # + AC_MSG_CHECKING([if gmtime_r can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([gmtime_r]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_gmtime_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_gmtime_r="no" + ]) + # + if test "$tst_links_gmtime_r" = "yes"; then + AC_MSG_CHECKING([if gmtime_r is prototyped]) + AC_EGREP_CPP([gmtime_r],[ + $curl_includes_time + ],[ + AC_MSG_RESULT([yes]) + tst_proto_gmtime_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_gmtime_r="no" + ]) + fi + # + if test "$tst_proto_gmtime_r" = "yes"; then + AC_MSG_CHECKING([if gmtime_r is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_time + ]],[[ + if(0 != gmtime_r(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_gmtime_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_gmtime_r="no" + ]) + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_gmtime_r" = "yes"; then + AC_MSG_CHECKING([if gmtime_r seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + $curl_includes_time + ]],[[ + time_t local = 1170352587; + struct tm *gmt = 0; + struct tm result; + gmt = gmtime_r(&local, &result); + if(gmt) + exit(0); + else + exit(1); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_gmtime_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_gmtime_r="no" + ]) + fi + # + if test "$tst_compi_gmtime_r" = "yes" && + test "$tst_works_gmtime_r" != "no"; then + AC_MSG_CHECKING([if gmtime_r usage allowed]) + if test "x$curl_disallow_gmtime_r" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_gmtime_r="yes" + else + AC_MSG_RESULT([no]) + tst_allow_gmtime_r="no" + fi + fi + # + AC_MSG_CHECKING([if gmtime_r might be used]) + if test "$tst_links_gmtime_r" = "yes" && + test "$tst_proto_gmtime_r" = "yes" && + test "$tst_compi_gmtime_r" = "yes" && + test "$tst_allow_gmtime_r" = "yes" && + test "$tst_works_gmtime_r" != "no"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_GMTIME_R, 1, + [Define to 1 if you have a working gmtime_r function.]) + curl_cv_func_gmtime_r="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_gmtime_r="no" + fi +]) + + +dnl CURL_CHECK_FUNC_INET_NTOP +dnl ------------------------------------------------- +dnl Verify if inet_ntop is available, prototyped, can +dnl be compiled and seems to work. If all of these are +dnl true, and usage has not been previously disallowed +dnl with shell variable curl_disallow_inet_ntop, then +dnl HAVE_INET_NTOP will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_INET_NTOP], [ + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + AC_REQUIRE([CURL_INCLUDES_ARPA_INET])dnl + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_inet_ntop="unknown" + tst_proto_inet_ntop="unknown" + tst_compi_inet_ntop="unknown" + tst_works_inet_ntop="unknown" + tst_allow_inet_ntop="unknown" + # + AC_MSG_CHECKING([if inet_ntop can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([inet_ntop]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_inet_ntop="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_inet_ntop="no" + ]) + # + if test "$tst_links_inet_ntop" = "yes"; then + AC_MSG_CHECKING([if inet_ntop is prototyped]) + AC_EGREP_CPP([inet_ntop],[ + $curl_includes_arpa_inet + ],[ + AC_MSG_RESULT([yes]) + tst_proto_inet_ntop="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_inet_ntop="no" + ]) + fi + # + if test "$tst_proto_inet_ntop" = "yes"; then + AC_MSG_CHECKING([if inet_ntop is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_arpa_inet + ]],[[ + if(0 != inet_ntop(0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_inet_ntop="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_inet_ntop="no" + ]) + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_inet_ntop" = "yes"; then + AC_MSG_CHECKING([if inet_ntop seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + $curl_includes_arpa_inet + $curl_includes_string + ]],[[ + char ipv6res[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + char ipv4res[sizeof "255.255.255.255"]; + unsigned char ipv6a[26]; + unsigned char ipv4a[5]; + char *ipv6ptr = 0; + char *ipv4ptr = 0; + /* - */ + ipv4res[0] = '\0'; + ipv4a[0] = 0xc0; + ipv4a[1] = 0xa8; + ipv4a[2] = 0x64; + ipv4a[3] = 0x01; + ipv4a[4] = 0x01; + /* - */ + ipv4ptr = inet_ntop(AF_INET, ipv4a, ipv4res, sizeof(ipv4res)); + if(!ipv4ptr) + exit(1); /* fail */ + if(ipv4ptr != ipv4res) + exit(1); /* fail */ + if(!ipv4ptr[0]) + exit(1); /* fail */ + if(memcmp(ipv4res, "192.168.100.1", 13) != 0) + exit(1); /* fail */ + /* - */ + ipv6res[0] = '\0'; + memset(ipv6a, 0, sizeof(ipv6a)); + ipv6a[0] = 0xfe; + ipv6a[1] = 0x80; + ipv6a[8] = 0x02; + ipv6a[9] = 0x14; + ipv6a[10] = 0x4f; + ipv6a[11] = 0xff; + ipv6a[12] = 0xfe; + ipv6a[13] = 0x0b; + ipv6a[14] = 0x76; + ipv6a[15] = 0xc8; + ipv6a[25] = 0x01; + /* - */ + ipv6ptr = inet_ntop(AF_INET6, ipv6a, ipv6res, sizeof(ipv6res)); + if(!ipv6ptr) + exit(1); /* fail */ + if(ipv6ptr != ipv6res) + exit(1); /* fail */ + if(!ipv6ptr[0]) + exit(1); /* fail */ + if(memcmp(ipv6res, "fe80::214:4fff:fe0b:76c8", 24) != 0) + exit(1); /* fail */ + /* - */ + exit(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_inet_ntop="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_inet_ntop="no" + ]) + fi + # + if test "$tst_compi_inet_ntop" = "yes" && + test "$tst_works_inet_ntop" != "no"; then + AC_MSG_CHECKING([if inet_ntop usage allowed]) + if test "x$curl_disallow_inet_ntop" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_inet_ntop="yes" + else + AC_MSG_RESULT([no]) + tst_allow_inet_ntop="no" + fi + fi + # + AC_MSG_CHECKING([if inet_ntop might be used]) + if test "$tst_links_inet_ntop" = "yes" && + test "$tst_proto_inet_ntop" = "yes" && + test "$tst_compi_inet_ntop" = "yes" && + test "$tst_allow_inet_ntop" = "yes" && + test "$tst_works_inet_ntop" != "no"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_INET_NTOP, 1, + [Define to 1 if you have a IPv6 capable working inet_ntop function.]) + curl_cv_func_inet_ntop="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_inet_ntop="no" + fi +]) + + +dnl CURL_CHECK_FUNC_INET_PTON +dnl ------------------------------------------------- +dnl Verify if inet_pton is available, prototyped, can +dnl be compiled and seems to work. If all of these are +dnl true, and usage has not been previously disallowed +dnl with shell variable curl_disallow_inet_pton, then +dnl HAVE_INET_PTON will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_INET_PTON], [ + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + AC_REQUIRE([CURL_INCLUDES_ARPA_INET])dnl + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_inet_pton="unknown" + tst_proto_inet_pton="unknown" + tst_compi_inet_pton="unknown" + tst_works_inet_pton="unknown" + tst_allow_inet_pton="unknown" + # + AC_MSG_CHECKING([if inet_pton can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([inet_pton]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_inet_pton="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_inet_pton="no" + ]) + # + if test "$tst_links_inet_pton" = "yes"; then + AC_MSG_CHECKING([if inet_pton is prototyped]) + AC_EGREP_CPP([inet_pton],[ + $curl_includes_arpa_inet + ],[ + AC_MSG_RESULT([yes]) + tst_proto_inet_pton="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_inet_pton="no" + ]) + fi + # + if test "$tst_proto_inet_pton" = "yes"; then + AC_MSG_CHECKING([if inet_pton is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_arpa_inet + ]],[[ + if(0 != inet_pton(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_inet_pton="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_inet_pton="no" + ]) + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_inet_pton" = "yes"; then + AC_MSG_CHECKING([if inet_pton seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + $curl_includes_arpa_inet + $curl_includes_string + ]],[[ + unsigned char ipv6a[16+1]; + unsigned char ipv4a[4+1]; + const char *ipv6src = "fe80::214:4fff:fe0b:76c8"; + const char *ipv4src = "192.168.100.1"; + /* - */ + memset(ipv4a, 1, sizeof(ipv4a)); + if(1 != inet_pton(AF_INET, ipv4src, ipv4a)) + exit(1); /* fail */ + /* - */ + if( (ipv4a[0] != 0xc0) || + (ipv4a[1] != 0xa8) || + (ipv4a[2] != 0x64) || + (ipv4a[3] != 0x01) || + (ipv4a[4] != 0x01) ) + exit(1); /* fail */ + /* - */ + memset(ipv6a, 1, sizeof(ipv6a)); + if(1 != inet_pton(AF_INET6, ipv6src, ipv6a)) + exit(1); /* fail */ + /* - */ + if( (ipv6a[0] != 0xfe) || + (ipv6a[1] != 0x80) || + (ipv6a[8] != 0x02) || + (ipv6a[9] != 0x14) || + (ipv6a[10] != 0x4f) || + (ipv6a[11] != 0xff) || + (ipv6a[12] != 0xfe) || + (ipv6a[13] != 0x0b) || + (ipv6a[14] != 0x76) || + (ipv6a[15] != 0xc8) || + (ipv6a[16] != 0x01) ) + exit(1); /* fail */ + /* - */ + if( (ipv6a[2] != 0x0) || + (ipv6a[3] != 0x0) || + (ipv6a[4] != 0x0) || + (ipv6a[5] != 0x0) || + (ipv6a[6] != 0x0) || + (ipv6a[7] != 0x0) ) + exit(1); /* fail */ + /* - */ + exit(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_inet_pton="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_inet_pton="no" + ]) + fi + # + if test "$tst_compi_inet_pton" = "yes" && + test "$tst_works_inet_pton" != "no"; then + AC_MSG_CHECKING([if inet_pton usage allowed]) + if test "x$curl_disallow_inet_pton" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_inet_pton="yes" + else + AC_MSG_RESULT([no]) + tst_allow_inet_pton="no" + fi + fi + # + AC_MSG_CHECKING([if inet_pton might be used]) + if test "$tst_links_inet_pton" = "yes" && + test "$tst_proto_inet_pton" = "yes" && + test "$tst_compi_inet_pton" = "yes" && + test "$tst_allow_inet_pton" = "yes" && + test "$tst_works_inet_pton" != "no"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_INET_PTON, 1, + [Define to 1 if you have a IPv6 capable working inet_pton function.]) + curl_cv_func_inet_pton="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_inet_pton="no" + fi +]) + + +dnl CURL_CHECK_FUNC_IOCTL +dnl ------------------------------------------------- +dnl Verify if ioctl is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_ioctl, then +dnl HAVE_IOCTL will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IOCTL], [ + AC_REQUIRE([CURL_INCLUDES_STROPTS])dnl + # + tst_links_ioctl="unknown" + tst_proto_ioctl="unknown" + tst_compi_ioctl="unknown" + tst_allow_ioctl="unknown" + # + AC_MSG_CHECKING([if ioctl can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([ioctl]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_ioctl="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_ioctl="no" + ]) + # + if test "$tst_links_ioctl" = "yes"; then + AC_MSG_CHECKING([if ioctl is prototyped]) + AC_EGREP_CPP([ioctl],[ + $curl_includes_stropts + ],[ + AC_MSG_RESULT([yes]) + tst_proto_ioctl="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_ioctl="no" + ]) + fi + # + if test "$tst_proto_ioctl" = "yes"; then + AC_MSG_CHECKING([if ioctl is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stropts + ]],[[ + if(0 != ioctl(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ioctl="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ioctl="no" + ]) + fi + # + if test "$tst_compi_ioctl" = "yes"; then + AC_MSG_CHECKING([if ioctl usage allowed]) + if test "x$curl_disallow_ioctl" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ioctl="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ioctl="no" + fi + fi + # + AC_MSG_CHECKING([if ioctl might be used]) + if test "$tst_links_ioctl" = "yes" && + test "$tst_proto_ioctl" = "yes" && + test "$tst_compi_ioctl" = "yes" && + test "$tst_allow_ioctl" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IOCTL, 1, + [Define to 1 if you have the ioctl function.]) + curl_cv_func_ioctl="yes" + CURL_CHECK_FUNC_IOCTL_FIONBIO + CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR + else + AC_MSG_RESULT([no]) + curl_cv_func_ioctl="no" + fi +]) + + +dnl CURL_CHECK_FUNC_IOCTL_FIONBIO +dnl ------------------------------------------------- +dnl Verify if ioctl with the FIONBIO command is +dnl available, can be compiled, and seems to work. If +dnl all of these are true, then HAVE_IOCTL_FIONBIO +dnl will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IOCTL_FIONBIO], [ + # + tst_compi_ioctl_fionbio="unknown" + tst_allow_ioctl_fionbio="unknown" + # + if test "$curl_cv_func_ioctl" = "yes"; then + AC_MSG_CHECKING([if ioctl FIONBIO is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stropts + ]],[[ + int flags = 0; + if(0 != ioctl(0, FIONBIO, &flags)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ioctl_fionbio="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ioctl_fionbio="no" + ]) + fi + # + if test "$tst_compi_ioctl_fionbio" = "yes"; then + AC_MSG_CHECKING([if ioctl FIONBIO usage allowed]) + if test "x$curl_disallow_ioctl_fionbio" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ioctl_fionbio="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ioctl_fionbio="no" + fi + fi + # + AC_MSG_CHECKING([if ioctl FIONBIO might be used]) + if test "$tst_compi_ioctl_fionbio" = "yes" && + test "$tst_allow_ioctl_fionbio" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IOCTL_FIONBIO, 1, + [Define to 1 if you have a working ioctl FIONBIO function.]) + curl_cv_func_ioctl_fionbio="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_ioctl_fionbio="no" + fi +]) + + +dnl CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR +dnl ------------------------------------------------- +dnl Verify if ioctl with the SIOCGIFADDR command is available, +dnl struct ifreq is defined, they can be compiled, and seem to +dnl work. If all of these are true, then HAVE_IOCTL_SIOCGIFADDR +dnl will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR], [ + # + tst_compi_ioctl_siocgifaddr="unknown" + tst_allow_ioctl_siocgifaddr="unknown" + # + if test "$curl_cv_func_ioctl" = "yes"; then + AC_MSG_CHECKING([if ioctl SIOCGIFADDR is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stropts + #include + ]],[[ + struct ifreq ifr; + if(0 != ioctl(0, SIOCGIFADDR, &ifr)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ioctl_siocgifaddr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ioctl_siocgifaddr="no" + ]) + fi + # + if test "$tst_compi_ioctl_siocgifaddr" = "yes"; then + AC_MSG_CHECKING([if ioctl SIOCGIFADDR usage allowed]) + if test "x$curl_disallow_ioctl_siocgifaddr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ioctl_siocgifaddr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ioctl_siocgifaddr="no" + fi + fi + # + AC_MSG_CHECKING([if ioctl SIOCGIFADDR might be used]) + if test "$tst_compi_ioctl_siocgifaddr" = "yes" && + test "$tst_allow_ioctl_siocgifaddr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IOCTL_SIOCGIFADDR, 1, + [Define to 1 if you have a working ioctl SIOCGIFADDR function.]) + curl_cv_func_ioctl_siocgifaddr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_ioctl_siocgifaddr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_IOCTLSOCKET +dnl ------------------------------------------------- +dnl Verify if ioctlsocket is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_ioctlsocket, then +dnl HAVE_IOCTLSOCKET will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + # + tst_links_ioctlsocket="unknown" + tst_proto_ioctlsocket="unknown" + tst_compi_ioctlsocket="unknown" + tst_allow_ioctlsocket="unknown" + # + AC_MSG_CHECKING([if ioctlsocket can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + ]],[[ + if(0 != ioctlsocket(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_ioctlsocket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_ioctlsocket="no" + ]) + # + if test "$tst_links_ioctlsocket" = "yes"; then + AC_MSG_CHECKING([if ioctlsocket is prototyped]) + AC_EGREP_CPP([ioctlsocket],[ + $curl_includes_winsock2 + ],[ + AC_MSG_RESULT([yes]) + tst_proto_ioctlsocket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_ioctlsocket="no" + ]) + fi + # + if test "$tst_proto_ioctlsocket" = "yes"; then + AC_MSG_CHECKING([if ioctlsocket is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + ]],[[ + if(0 != ioctlsocket(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ioctlsocket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ioctlsocket="no" + ]) + fi + # + if test "$tst_compi_ioctlsocket" = "yes"; then + AC_MSG_CHECKING([if ioctlsocket usage allowed]) + if test "x$curl_disallow_ioctlsocket" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ioctlsocket="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ioctlsocket="no" + fi + fi + # + AC_MSG_CHECKING([if ioctlsocket might be used]) + if test "$tst_links_ioctlsocket" = "yes" && + test "$tst_proto_ioctlsocket" = "yes" && + test "$tst_compi_ioctlsocket" = "yes" && + test "$tst_allow_ioctlsocket" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET, 1, + [Define to 1 if you have the ioctlsocket function.]) + curl_cv_func_ioctlsocket="yes" + CURL_CHECK_FUNC_IOCTLSOCKET_FIONBIO + else + AC_MSG_RESULT([no]) + curl_cv_func_ioctlsocket="no" + fi +]) + + +dnl CURL_CHECK_FUNC_IOCTLSOCKET_FIONBIO +dnl ------------------------------------------------- +dnl Verify if ioctlsocket with the FIONBIO command is +dnl available, can be compiled, and seems to work. If +dnl all of these are true, then HAVE_IOCTLSOCKET_FIONBIO +dnl will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET_FIONBIO], [ + # + tst_compi_ioctlsocket_fionbio="unknown" + tst_allow_ioctlsocket_fionbio="unknown" + # + if test "$curl_cv_func_ioctlsocket" = "yes"; then + AC_MSG_CHECKING([if ioctlsocket FIONBIO is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + ]],[[ + int flags = 0; + if(0 != ioctlsocket(0, FIONBIO, &flags)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ioctlsocket_fionbio="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ioctlsocket_fionbio="no" + ]) + fi + # + if test "$tst_compi_ioctlsocket_fionbio" = "yes"; then + AC_MSG_CHECKING([if ioctlsocket FIONBIO usage allowed]) + if test "x$curl_disallow_ioctlsocket_fionbio" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ioctlsocket_fionbio="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ioctlsocket_fionbio="no" + fi + fi + # + AC_MSG_CHECKING([if ioctlsocket FIONBIO might be used]) + if test "$tst_compi_ioctlsocket_fionbio" = "yes" && + test "$tst_allow_ioctlsocket_fionbio" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET_FIONBIO, 1, + [Define to 1 if you have a working ioctlsocket FIONBIO function.]) + curl_cv_func_ioctlsocket_fionbio="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_ioctlsocket_fionbio="no" + fi +]) + + +dnl CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL +dnl ------------------------------------------------- +dnl Verify if IoctlSocket is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_ioctlsocket_camel, +dnl then HAVE_IOCTLSOCKET_CAMEL will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL], [ + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + # + tst_links_ioctlsocket_camel="unknown" + tst_proto_ioctlsocket_camel="unknown" + tst_compi_ioctlsocket_camel="unknown" + tst_allow_ioctlsocket_camel="unknown" + # + AC_MSG_CHECKING([if IoctlSocket can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_bsdsocket + ]],[[ + IoctlSocket(0, 0, 0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_ioctlsocket_camel="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_ioctlsocket_camel="no" + ]) + # + if test "$tst_links_ioctlsocket_camel" = "yes"; then + AC_MSG_CHECKING([if IoctlSocket is prototyped]) + AC_EGREP_CPP([IoctlSocket],[ + $curl_includes_bsdsocket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_ioctlsocket_camel="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_ioctlsocket_camel="no" + ]) + fi + # + if test "$tst_proto_ioctlsocket_camel" = "yes"; then + AC_MSG_CHECKING([if IoctlSocket is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_bsdsocket + ]],[[ + if(0 != IoctlSocket(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ioctlsocket_camel="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ioctlsocket_camel="no" + ]) + fi + # + if test "$tst_compi_ioctlsocket_camel" = "yes"; then + AC_MSG_CHECKING([if IoctlSocket usage allowed]) + if test "x$curl_disallow_ioctlsocket_camel" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ioctlsocket_camel="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ioctlsocket_camel="no" + fi + fi + # + AC_MSG_CHECKING([if IoctlSocket might be used]) + if test "$tst_links_ioctlsocket_camel" = "yes" && + test "$tst_proto_ioctlsocket_camel" = "yes" && + test "$tst_compi_ioctlsocket_camel" = "yes" && + test "$tst_allow_ioctlsocket_camel" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET_CAMEL, 1, + [Define to 1 if you have the IoctlSocket camel case function.]) + curl_cv_func_ioctlsocket_camel="yes" + CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL_FIONBIO + else + AC_MSG_RESULT([no]) + curl_cv_func_ioctlsocket_camel="no" + fi +]) + + +dnl CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL_FIONBIO +dnl ------------------------------------------------- +dnl Verify if IoctlSocket with FIONBIO command is available, +dnl can be compiled, and seems to work. If all of these are +dnl true, then HAVE_IOCTLSOCKET_CAMEL_FIONBIO will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL_FIONBIO], [ + AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl + # + tst_compi_ioctlsocket_camel_fionbio="unknown" + tst_allow_ioctlsocket_camel_fionbio="unknown" + # + if test "$curl_cv_func_ioctlsocket_camel" = "yes"; then + AC_MSG_CHECKING([if IoctlSocket FIONBIO is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_bsdsocket + ]],[[ + long flags = 0; + if(0 != IoctlSocket(0, FIONBIO, &flags)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_ioctlsocket_camel_fionbio="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_ioctlsocket_camel_fionbio="no" + ]) + fi + # + if test "$tst_compi_ioctlsocket_camel_fionbio" = "yes"; then + AC_MSG_CHECKING([if IoctlSocket FIONBIO usage allowed]) + if test "x$curl_disallow_ioctlsocket_camel_fionbio" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_ioctlsocket_camel_fionbio="yes" + else + AC_MSG_RESULT([no]) + tst_allow_ioctlsocket_camel_fionbio="no" + fi + fi + # + AC_MSG_CHECKING([if IoctlSocket FIONBIO might be used]) + if test "$tst_compi_ioctlsocket_camel_fionbio" = "yes" && + test "$tst_allow_ioctlsocket_camel_fionbio" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET_CAMEL_FIONBIO, 1, + [Define to 1 if you have a working IoctlSocket camel case FIONBIO function.]) + curl_cv_func_ioctlsocket_camel_fionbio="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_ioctlsocket_camel_fionbio="no" + fi +]) + + +dnl CURL_CHECK_FUNC_LISTXATTR +dnl ------------------------------------------------- +dnl Verify if listxattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_listxattr, then +dnl HAVE_LISTXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_LISTXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_listxattr="unknown" + tst_proto_listxattr="unknown" + tst_compi_listxattr="unknown" + tst_allow_listxattr="unknown" + tst_nargs_listxattr="unknown" + # + AC_MSG_CHECKING([if listxattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([listxattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_listxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_listxattr="no" + ]) + # + if test "$tst_links_listxattr" = "yes"; then + AC_MSG_CHECKING([if listxattr is prototyped]) + AC_EGREP_CPP([listxattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_listxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_listxattr="no" + ]) + fi + # + if test "$tst_proto_listxattr" = "yes"; then + if test "$tst_nargs_listxattr" = "unknown"; then + AC_MSG_CHECKING([if listxattr takes 3 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != listxattr(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_listxattr="yes" + tst_nargs_listxattr="3" + ],[ + AC_MSG_RESULT([no]) + tst_compi_listxattr="no" + ]) + fi + if test "$tst_nargs_listxattr" = "unknown"; then + AC_MSG_CHECKING([if listxattr takes 4 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != listxattr(0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_listxattr="yes" + tst_nargs_listxattr="4" + ],[ + AC_MSG_RESULT([no]) + tst_compi_listxattr="no" + ]) + fi + AC_MSG_CHECKING([if listxattr is compilable]) + if test "$tst_compi_listxattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_listxattr" = "yes"; then + AC_MSG_CHECKING([if listxattr usage allowed]) + if test "x$curl_disallow_listxattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_listxattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_listxattr="no" + fi + fi + # + AC_MSG_CHECKING([if listxattr might be used]) + if test "$tst_links_listxattr" = "yes" && + test "$tst_proto_listxattr" = "yes" && + test "$tst_compi_listxattr" = "yes" && + test "$tst_allow_listxattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_LISTXATTR, 1, + [Define to 1 if you have the listxattr function.]) + dnl AC_DEFINE_UNQUOTED(LISTXATTR_ARGS, $tst_nargs_listxattr, + dnl [Specifies the number of arguments to listxattr]) + # + if test "$tst_nargs_listxattr" -eq "3"; then + AC_DEFINE(HAVE_LISTXATTR_3, 1, [listxattr() takes 3 args]) + elif test "$tst_nargs_listxattr" -eq "4"; then + AC_DEFINE(HAVE_LISTXATTR_4, 1, [listxattr() takes 4 args]) + fi + # + curl_cv_func_listxattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_listxattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_MEMRCHR +dnl ------------------------------------------------- +dnl Verify if memrchr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_memrchr, then +dnl HAVE_MEMRCHR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_MEMRCHR], [ + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_memrchr="unknown" + tst_macro_memrchr="unknown" + tst_proto_memrchr="unknown" + tst_compi_memrchr="unknown" + tst_allow_memrchr="unknown" + # + AC_MSG_CHECKING([if memrchr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([memrchr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_memrchr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_memrchr="no" + ]) + # + if test "$tst_links_memrchr" = "no"; then + AC_MSG_CHECKING([if memrchr seems a macro]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != memrchr(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_macro_memrchr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_macro_memrchr="no" + ]) + fi + # + if test "$tst_links_memrchr" = "yes"; then + AC_MSG_CHECKING([if memrchr is prototyped]) + AC_EGREP_CPP([memrchr],[ + $curl_includes_string + ],[ + AC_MSG_RESULT([yes]) + tst_proto_memrchr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_memrchr="no" + ]) + fi + # + if test "$tst_proto_memrchr" = "yes" || + test "$tst_macro_memrchr" = "yes"; then + AC_MSG_CHECKING([if memrchr is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != memrchr(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_memrchr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_memrchr="no" + ]) + fi + # + if test "$tst_compi_memrchr" = "yes"; then + AC_MSG_CHECKING([if memrchr usage allowed]) + if test "x$curl_disallow_memrchr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_memrchr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_memrchr="no" + fi + fi + # + AC_MSG_CHECKING([if memrchr might be used]) + if (test "$tst_proto_memrchr" = "yes" || + test "$tst_macro_memrchr" = "yes") && + test "$tst_compi_memrchr" = "yes" && + test "$tst_allow_memrchr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_MEMRCHR, 1, + [Define to 1 if you have the memrchr function or macro.]) + curl_cv_func_memrchr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_memrchr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_POLL +dnl ------------------------------------------------- +dnl Verify if poll is available, prototyped, can +dnl be compiled and seems to work. + +AC_DEFUN([CURL_CHECK_FUNC_POLL], [ + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + AC_REQUIRE([CURL_INCLUDES_POLL])dnl + # + tst_links_poll="unknown" + tst_proto_poll="unknown" + tst_compi_poll="unknown" + tst_works_poll="unknown" + tst_allow_poll="unknown" + # + case $host_os in + darwin*|interix*) + dnl poll() does not work on these platforms + dnl Interix: "does provide poll(), but the implementing developer must + dnl have been in a bad mood, because poll() only works on the /proc + dnl filesystem here" + dnl macOS: poll() first didn't exist, then was broken until fixed in 10.9 + dnl only to break again in 10.12. + curl_disallow_poll="yes" + tst_compi_poll="no" + ;; + esac + # + AC_MSG_CHECKING([if poll can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_poll + ]],[[ + if(0 != poll(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_poll="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_poll="no" + ]) + # + if test "$tst_links_poll" = "yes"; then + AC_MSG_CHECKING([if poll is prototyped]) + AC_EGREP_CPP([poll],[ + $curl_includes_poll + ],[ + AC_MSG_RESULT([yes]) + tst_proto_poll="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_poll="no" + ]) + fi + # + if test "$tst_proto_poll" = "yes"; then + AC_MSG_CHECKING([if poll is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_poll + ]],[[ + if(0 != poll(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_poll="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_poll="no" + ]) + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_compi_poll" = "yes"; then + AC_MSG_CHECKING([if poll seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + $curl_includes_poll + $curl_includes_time + ]],[[ + /* detect the original poll() breakage */ + if(0 != poll(0, 0, 10)) + exit(1); /* fail */ + else { + /* detect the 10.12 poll() breakage */ + struct timeval before, after; + int rc; + size_t us; + + gettimeofday(&before, NULL); + rc = poll(NULL, 0, 500); + gettimeofday(&after, NULL); + + us = (after.tv_sec - before.tv_sec) * 1000000 + + (after.tv_usec - before.tv_usec); + + if(us < 400000) + exit(1); + } + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_poll="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_poll="no" + ]) + fi + # + if test "$tst_compi_poll" = "yes" && + test "$tst_works_poll" != "no"; then + AC_MSG_CHECKING([if poll usage allowed]) + if test "x$curl_disallow_poll" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_poll="yes" + else + AC_MSG_RESULT([no]) + tst_allow_poll="no" + fi + fi + # + AC_MSG_CHECKING([if poll might be used]) + if test "$tst_links_poll" = "yes" && + test "$tst_proto_poll" = "yes" && + test "$tst_compi_poll" = "yes" && + test "$tst_allow_poll" = "yes" && + test "$tst_works_poll" != "no"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_POLL_FINE, 1, + [If you have a fine poll]) + curl_cv_func_poll="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_poll="no" + fi +]) + + +dnl CURL_CHECK_FUNC_REMOVEXATTR +dnl ------------------------------------------------- +dnl Verify if removexattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_removexattr, then +dnl HAVE_REMOVEXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_REMOVEXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_removexattr="unknown" + tst_proto_removexattr="unknown" + tst_compi_removexattr="unknown" + tst_allow_removexattr="unknown" + tst_nargs_removexattr="unknown" + # + AC_MSG_CHECKING([if removexattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([removexattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_removexattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_removexattr="no" + ]) + # + if test "$tst_links_removexattr" = "yes"; then + AC_MSG_CHECKING([if removexattr is prototyped]) + AC_EGREP_CPP([removexattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_removexattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_removexattr="no" + ]) + fi + # + if test "$tst_proto_removexattr" = "yes"; then + if test "$tst_nargs_removexattr" = "unknown"; then + AC_MSG_CHECKING([if removexattr takes 2 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != removexattr(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_removexattr="yes" + tst_nargs_removexattr="2" + ],[ + AC_MSG_RESULT([no]) + tst_compi_removexattr="no" + ]) + fi + if test "$tst_nargs_removexattr" = "unknown"; then + AC_MSG_CHECKING([if removexattr takes 3 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != removexattr(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_removexattr="yes" + tst_nargs_removexattr="3" + ],[ + AC_MSG_RESULT([no]) + tst_compi_removexattr="no" + ]) + fi + AC_MSG_CHECKING([if removexattr is compilable]) + if test "$tst_compi_removexattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_removexattr" = "yes"; then + AC_MSG_CHECKING([if removexattr usage allowed]) + if test "x$curl_disallow_removexattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_removexattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_removexattr="no" + fi + fi + # + AC_MSG_CHECKING([if removexattr might be used]) + if test "$tst_links_removexattr" = "yes" && + test "$tst_proto_removexattr" = "yes" && + test "$tst_compi_removexattr" = "yes" && + test "$tst_allow_removexattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_REMOVEXATTR, 1, + [Define to 1 if you have the removexattr function.]) + dnl AC_DEFINE_UNQUOTED(REMOVEXATTR_ARGS, $tst_nargs_removexattr, + dnl [Specifies the number of arguments to removexattr]) + # + if test "$tst_nargs_removexattr" -eq "2"; then + AC_DEFINE(HAVE_REMOVEXATTR_2, 1, [removexattr() takes 2 args]) + elif test "$tst_nargs_removexattr" -eq "3"; then + AC_DEFINE(HAVE_REMOVEXATTR_3, 1, [removexattr() takes 3 args]) + fi + # + curl_cv_func_removexattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_removexattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SETSOCKOPT_SO_NONBLOCK +dnl ------------------------------------------------- +dnl Verify if setsockopt with the SO_NONBLOCK command is +dnl available, can be compiled, and seems to work. If +dnl all of these are true, then HAVE_SETSOCKOPT_SO_NONBLOCK +dnl will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SETSOCKOPT_SO_NONBLOCK], [ + # + tst_compi_setsockopt_so_nonblock="unknown" + tst_allow_setsockopt_so_nonblock="unknown" + # + if test "$curl_cv_func_setsockopt" = "yes"; then + AC_MSG_CHECKING([if setsockopt SO_NONBLOCK is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + ]],[[ + if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_setsockopt_so_nonblock="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_setsockopt_so_nonblock="no" + ]) + fi + # + if test "$tst_compi_setsockopt_so_nonblock" = "yes"; then + AC_MSG_CHECKING([if setsockopt SO_NONBLOCK usage allowed]) + if test "x$curl_disallow_setsockopt_so_nonblock" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_setsockopt_so_nonblock="yes" + else + AC_MSG_RESULT([no]) + tst_allow_setsockopt_so_nonblock="no" + fi + fi + # + AC_MSG_CHECKING([if setsockopt SO_NONBLOCK might be used]) + if test "$tst_compi_setsockopt_so_nonblock" = "yes" && + test "$tst_allow_setsockopt_so_nonblock" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SETSOCKOPT_SO_NONBLOCK, 1, + [Define to 1 if you have a working setsockopt SO_NONBLOCK function.]) + curl_cv_func_setsockopt_so_nonblock="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_setsockopt_so_nonblock="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SETXATTR +dnl ------------------------------------------------- +dnl Verify if setxattr is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_setxattr, then +dnl HAVE_SETXATTR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SETXATTR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl + # + tst_links_setxattr="unknown" + tst_proto_setxattr="unknown" + tst_compi_setxattr="unknown" + tst_allow_setxattr="unknown" + tst_nargs_setxattr="unknown" + # + AC_MSG_CHECKING([if setxattr can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([setxattr]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_setxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_setxattr="no" + ]) + # + if test "$tst_links_setxattr" = "yes"; then + AC_MSG_CHECKING([if setxattr is prototyped]) + AC_EGREP_CPP([setxattr],[ + $curl_includes_sys_xattr + ],[ + AC_MSG_RESULT([yes]) + tst_proto_setxattr="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_setxattr="no" + ]) + fi + # + if test "$tst_proto_setxattr" = "yes"; then + if test "$tst_nargs_setxattr" = "unknown"; then + AC_MSG_CHECKING([if setxattr takes 5 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != setxattr(0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_setxattr="yes" + tst_nargs_setxattr="5" + ],[ + AC_MSG_RESULT([no]) + tst_compi_setxattr="no" + ]) + fi + if test "$tst_nargs_setxattr" = "unknown"; then + AC_MSG_CHECKING([if setxattr takes 6 args.]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_xattr + ]],[[ + if(0 != setxattr(0, 0, 0, 0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_setxattr="yes" + tst_nargs_setxattr="6" + ],[ + AC_MSG_RESULT([no]) + tst_compi_setxattr="no" + ]) + fi + AC_MSG_CHECKING([if setxattr is compilable]) + if test "$tst_compi_setxattr" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + if test "$tst_compi_setxattr" = "yes"; then + AC_MSG_CHECKING([if setxattr usage allowed]) + if test "x$curl_disallow_setxattr" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_setxattr="yes" + else + AC_MSG_RESULT([no]) + tst_allow_setxattr="no" + fi + fi + # + AC_MSG_CHECKING([if setxattr might be used]) + if test "$tst_links_setxattr" = "yes" && + test "$tst_proto_setxattr" = "yes" && + test "$tst_compi_setxattr" = "yes" && + test "$tst_allow_setxattr" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SETXATTR, 1, + [Define to 1 if you have the setxattr function.]) + dnl AC_DEFINE_UNQUOTED(SETXATTR_ARGS, $tst_nargs_setxattr, + dnl [Specifies the number of arguments to setxattr]) + # + if test "$tst_nargs_setxattr" -eq "5"; then + AC_DEFINE(HAVE_SETXATTR_5, 1, [setxattr() takes 5 args]) + elif test "$tst_nargs_setxattr" -eq "6"; then + AC_DEFINE(HAVE_SETXATTR_6, 1, [setxattr() takes 6 args]) + fi + # + curl_cv_func_setxattr="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_setxattr="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SIGACTION +dnl ------------------------------------------------- +dnl Verify if sigaction is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_sigaction, then +dnl HAVE_SIGACTION will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SIGACTION], [ + AC_REQUIRE([CURL_INCLUDES_SIGNAL])dnl + # + tst_links_sigaction="unknown" + tst_proto_sigaction="unknown" + tst_compi_sigaction="unknown" + tst_allow_sigaction="unknown" + # + AC_MSG_CHECKING([if sigaction can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([sigaction]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_sigaction="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_sigaction="no" + ]) + # + if test "$tst_links_sigaction" = "yes"; then + AC_MSG_CHECKING([if sigaction is prototyped]) + AC_EGREP_CPP([sigaction],[ + $curl_includes_signal + ],[ + AC_MSG_RESULT([yes]) + tst_proto_sigaction="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_sigaction="no" + ]) + fi + # + if test "$tst_proto_sigaction" = "yes"; then + AC_MSG_CHECKING([if sigaction is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_signal + ]],[[ + if(0 != sigaction(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_sigaction="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_sigaction="no" + ]) + fi + # + if test "$tst_compi_sigaction" = "yes"; then + AC_MSG_CHECKING([if sigaction usage allowed]) + if test "x$curl_disallow_sigaction" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_sigaction="yes" + else + AC_MSG_RESULT([no]) + tst_allow_sigaction="no" + fi + fi + # + AC_MSG_CHECKING([if sigaction might be used]) + if test "$tst_links_sigaction" = "yes" && + test "$tst_proto_sigaction" = "yes" && + test "$tst_compi_sigaction" = "yes" && + test "$tst_allow_sigaction" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SIGACTION, 1, + [Define to 1 if you have the sigaction function.]) + curl_cv_func_sigaction="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_sigaction="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SIGINTERRUPT +dnl ------------------------------------------------- +dnl Verify if siginterrupt is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_siginterrupt, then +dnl HAVE_SIGINTERRUPT will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SIGINTERRUPT], [ + AC_REQUIRE([CURL_INCLUDES_SIGNAL])dnl + # + tst_links_siginterrupt="unknown" + tst_proto_siginterrupt="unknown" + tst_compi_siginterrupt="unknown" + tst_allow_siginterrupt="unknown" + # + AC_MSG_CHECKING([if siginterrupt can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([siginterrupt]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_siginterrupt="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_siginterrupt="no" + ]) + # + if test "$tst_links_siginterrupt" = "yes"; then + AC_MSG_CHECKING([if siginterrupt is prototyped]) + AC_EGREP_CPP([siginterrupt],[ + $curl_includes_signal + ],[ + AC_MSG_RESULT([yes]) + tst_proto_siginterrupt="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_siginterrupt="no" + ]) + fi + # + if test "$tst_proto_siginterrupt" = "yes"; then + AC_MSG_CHECKING([if siginterrupt is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_signal + ]],[[ + if(0 != siginterrupt(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_siginterrupt="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_siginterrupt="no" + ]) + fi + # + if test "$tst_compi_siginterrupt" = "yes"; then + AC_MSG_CHECKING([if siginterrupt usage allowed]) + if test "x$curl_disallow_siginterrupt" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_siginterrupt="yes" + else + AC_MSG_RESULT([no]) + tst_allow_siginterrupt="no" + fi + fi + # + AC_MSG_CHECKING([if siginterrupt might be used]) + if test "$tst_links_siginterrupt" = "yes" && + test "$tst_proto_siginterrupt" = "yes" && + test "$tst_compi_siginterrupt" = "yes" && + test "$tst_allow_siginterrupt" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SIGINTERRUPT, 1, + [Define to 1 if you have the siginterrupt function.]) + curl_cv_func_siginterrupt="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_siginterrupt="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SIGNAL +dnl ------------------------------------------------- +dnl Verify if signal is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_signal, then +dnl HAVE_SIGNAL will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SIGNAL], [ + AC_REQUIRE([CURL_INCLUDES_SIGNAL])dnl + # + tst_links_signal="unknown" + tst_proto_signal="unknown" + tst_compi_signal="unknown" + tst_allow_signal="unknown" + # + AC_MSG_CHECKING([if signal can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([signal]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_signal="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_signal="no" + ]) + # + if test "$tst_links_signal" = "yes"; then + AC_MSG_CHECKING([if signal is prototyped]) + AC_EGREP_CPP([signal],[ + $curl_includes_signal + ],[ + AC_MSG_RESULT([yes]) + tst_proto_signal="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_signal="no" + ]) + fi + # + if test "$tst_proto_signal" = "yes"; then + AC_MSG_CHECKING([if signal is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_signal + ]],[[ + if(0 != signal(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_signal="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_signal="no" + ]) + fi + # + if test "$tst_compi_signal" = "yes"; then + AC_MSG_CHECKING([if signal usage allowed]) + if test "x$curl_disallow_signal" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_signal="yes" + else + AC_MSG_RESULT([no]) + tst_allow_signal="no" + fi + fi + # + AC_MSG_CHECKING([if signal might be used]) + if test "$tst_links_signal" = "yes" && + test "$tst_proto_signal" = "yes" && + test "$tst_compi_signal" = "yes" && + test "$tst_allow_signal" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SIGNAL, 1, + [Define to 1 if you have the signal function.]) + curl_cv_func_signal="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_signal="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SIGSETJMP +dnl ------------------------------------------------- +dnl Verify if sigsetjmp is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_sigsetjmp, then +dnl HAVE_SIGSETJMP will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SIGSETJMP], [ + AC_REQUIRE([CURL_INCLUDES_SETJMP])dnl + # + tst_links_sigsetjmp="unknown" + tst_macro_sigsetjmp="unknown" + tst_proto_sigsetjmp="unknown" + tst_compi_sigsetjmp="unknown" + tst_allow_sigsetjmp="unknown" + # + AC_MSG_CHECKING([if sigsetjmp can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([sigsetjmp]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_sigsetjmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_sigsetjmp="no" + ]) + # + if test "$tst_links_sigsetjmp" = "no"; then + AC_MSG_CHECKING([if sigsetjmp seems a macro]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_setjmp + ]],[[ + sigjmp_buf env; + if(0 != sigsetjmp(env, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_macro_sigsetjmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_macro_sigsetjmp="no" + ]) + fi + # + if test "$tst_links_sigsetjmp" = "yes"; then + AC_MSG_CHECKING([if sigsetjmp is prototyped]) + AC_EGREP_CPP([sigsetjmp],[ + $curl_includes_setjmp + ],[ + AC_MSG_RESULT([yes]) + tst_proto_sigsetjmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_sigsetjmp="no" + ]) + fi + # + if test "$tst_proto_sigsetjmp" = "yes" || + test "$tst_macro_sigsetjmp" = "yes"; then + AC_MSG_CHECKING([if sigsetjmp is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_setjmp + ]],[[ + sigjmp_buf env; + if(0 != sigsetjmp(env, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_sigsetjmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_sigsetjmp="no" + ]) + fi + # + if test "$tst_compi_sigsetjmp" = "yes"; then + AC_MSG_CHECKING([if sigsetjmp usage allowed]) + if test "x$curl_disallow_sigsetjmp" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_sigsetjmp="yes" + else + AC_MSG_RESULT([no]) + tst_allow_sigsetjmp="no" + fi + fi + # + AC_MSG_CHECKING([if sigsetjmp might be used]) + if (test "$tst_proto_sigsetjmp" = "yes" || + test "$tst_macro_sigsetjmp" = "yes") && + test "$tst_compi_sigsetjmp" = "yes" && + test "$tst_allow_sigsetjmp" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SIGSETJMP, 1, + [Define to 1 if you have the sigsetjmp function or macro.]) + curl_cv_func_sigsetjmp="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_sigsetjmp="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SOCKET +dnl ------------------------------------------------- +dnl Verify if socket is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_socket, then +dnl HAVE_SOCKET will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SOCKET], [ + AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl + AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl + AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl + # + tst_links_socket="unknown" + tst_proto_socket="unknown" + tst_compi_socket="unknown" + tst_allow_socket="unknown" + # + AC_MSG_CHECKING([if socket can be linked]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + $curl_includes_socket + ]],[[ + if(0 != socket(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_socket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_socket="no" + ]) + # + if test "$tst_links_socket" = "yes"; then + AC_MSG_CHECKING([if socket is prototyped]) + AC_EGREP_CPP([socket],[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + $curl_includes_socket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_socket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_socket="no" + ]) + fi + # + if test "$tst_proto_socket" = "yes"; then + AC_MSG_CHECKING([if socket is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_winsock2 + $curl_includes_bsdsocket + $curl_includes_sys_socket + $curl_includes_socket + ]],[[ + if(0 != socket(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_socket="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_socket="no" + ]) + fi + # + if test "$tst_compi_socket" = "yes"; then + AC_MSG_CHECKING([if socket usage allowed]) + if test "x$curl_disallow_socket" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_socket="yes" + else + AC_MSG_RESULT([no]) + tst_allow_socket="no" + fi + fi + # + AC_MSG_CHECKING([if socket might be used]) + if test "$tst_links_socket" = "yes" && + test "$tst_proto_socket" = "yes" && + test "$tst_compi_socket" = "yes" && + test "$tst_allow_socket" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SOCKET, 1, + [Define to 1 if you have the socket function.]) + curl_cv_func_socket="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_socket="no" + fi +]) + + +dnl CURL_CHECK_FUNC_SOCKETPAIR +dnl ------------------------------------------------- +dnl Verify if socketpair is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_socketpair, then +dnl HAVE_SOCKETPAIR will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_SOCKETPAIR], [ + AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl + AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl + # + tst_links_socketpair="unknown" + tst_proto_socketpair="unknown" + tst_compi_socketpair="unknown" + tst_allow_socketpair="unknown" + # + AC_MSG_CHECKING([if socketpair can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([socketpair]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_socketpair="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_socketpair="no" + ]) + # + if test "$tst_links_socketpair" = "yes"; then + AC_MSG_CHECKING([if socketpair is prototyped]) + AC_EGREP_CPP([socketpair],[ + $curl_includes_sys_socket + $curl_includes_socket + ],[ + AC_MSG_RESULT([yes]) + tst_proto_socketpair="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_socketpair="no" + ]) + fi + # + if test "$tst_proto_socketpair" = "yes"; then + AC_MSG_CHECKING([if socketpair is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_sys_socket + $curl_includes_socket + ]],[[ + int sv[2]; + if(0 != socketpair(0, 0, 0, sv)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_socketpair="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_socketpair="no" + ]) + fi + # + if test "$tst_compi_socketpair" = "yes"; then + AC_MSG_CHECKING([if socketpair usage allowed]) + if test "x$curl_disallow_socketpair" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_socketpair="yes" + else + AC_MSG_RESULT([no]) + tst_allow_socketpair="no" + fi + fi + # + AC_MSG_CHECKING([if socketpair might be used]) + if test "$tst_links_socketpair" = "yes" && + test "$tst_proto_socketpair" = "yes" && + test "$tst_compi_socketpair" = "yes" && + test "$tst_allow_socketpair" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_SOCKETPAIR, 1, + [Define to 1 if you have the socketpair function.]) + curl_cv_func_socketpair="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_socketpair="no" + fi +]) + + +dnl CURL_CHECK_FUNC_STRCASECMP +dnl ------------------------------------------------- +dnl Verify if strcasecmp is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_strcasecmp, then +dnl HAVE_STRCASECMP will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_STRCASECMP], [ + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_strcasecmp="unknown" + tst_proto_strcasecmp="unknown" + tst_compi_strcasecmp="unknown" + tst_allow_strcasecmp="unknown" + # + AC_MSG_CHECKING([if strcasecmp can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strcasecmp]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_strcasecmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_strcasecmp="no" + ]) + # + if test "$tst_links_strcasecmp" = "yes"; then + AC_MSG_CHECKING([if strcasecmp is prototyped]) + AC_EGREP_CPP([strcasecmp],[ + $curl_includes_string + ],[ + AC_MSG_RESULT([yes]) + tst_proto_strcasecmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_strcasecmp="no" + ]) + fi + # + if test "$tst_proto_strcasecmp" = "yes"; then + AC_MSG_CHECKING([if strcasecmp is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != strcasecmp(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_strcasecmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_strcasecmp="no" + ]) + fi + # + if test "$tst_compi_strcasecmp" = "yes"; then + AC_MSG_CHECKING([if strcasecmp usage allowed]) + if test "x$curl_disallow_strcasecmp" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_strcasecmp="yes" + else + AC_MSG_RESULT([no]) + tst_allow_strcasecmp="no" + fi + fi + # + AC_MSG_CHECKING([if strcasecmp might be used]) + if test "$tst_links_strcasecmp" = "yes" && + test "$tst_proto_strcasecmp" = "yes" && + test "$tst_compi_strcasecmp" = "yes" && + test "$tst_allow_strcasecmp" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_STRCASECMP, 1, + [Define to 1 if you have the strcasecmp function.]) + curl_cv_func_strcasecmp="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_strcasecmp="no" + fi +]) + +dnl CURL_CHECK_FUNC_STRCMPI +dnl ------------------------------------------------- +dnl Verify if strcmpi is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_strcmpi, then +dnl HAVE_STRCMPI will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_STRCMPI], [ + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_strcmpi="unknown" + tst_proto_strcmpi="unknown" + tst_compi_strcmpi="unknown" + tst_allow_strcmpi="unknown" + # + AC_MSG_CHECKING([if strcmpi can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strcmpi]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_strcmpi="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_strcmpi="no" + ]) + # + if test "$tst_links_strcmpi" = "yes"; then + AC_MSG_CHECKING([if strcmpi is prototyped]) + AC_EGREP_CPP([strcmpi],[ + $curl_includes_string + ],[ + AC_MSG_RESULT([yes]) + tst_proto_strcmpi="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_strcmpi="no" + ]) + fi + # + if test "$tst_proto_strcmpi" = "yes"; then + AC_MSG_CHECKING([if strcmpi is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != strcmpi(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_strcmpi="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_strcmpi="no" + ]) + fi + # + if test "$tst_compi_strcmpi" = "yes"; then + AC_MSG_CHECKING([if strcmpi usage allowed]) + if test "x$curl_disallow_strcmpi" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_strcmpi="yes" + else + AC_MSG_RESULT([no]) + tst_allow_strcmpi="no" + fi + fi + # + AC_MSG_CHECKING([if strcmpi might be used]) + if test "$tst_links_strcmpi" = "yes" && + test "$tst_proto_strcmpi" = "yes" && + test "$tst_compi_strcmpi" = "yes" && + test "$tst_allow_strcmpi" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_STRCMPI, 1, + [Define to 1 if you have the strcmpi function.]) + curl_cv_func_strcmpi="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_strcmpi="no" + fi +]) + + +dnl CURL_CHECK_FUNC_STRDUP +dnl ------------------------------------------------- +dnl Verify if strdup is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_strdup, then +dnl HAVE_STRDUP will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_STRDUP], [ + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_strdup="unknown" + tst_proto_strdup="unknown" + tst_compi_strdup="unknown" + tst_allow_strdup="unknown" + # + AC_MSG_CHECKING([if strdup can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strdup]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_strdup="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_strdup="no" + ]) + # + if test "$tst_links_strdup" = "yes"; then + AC_MSG_CHECKING([if strdup is prototyped]) + AC_EGREP_CPP([strdup],[ + $curl_includes_string + ],[ + AC_MSG_RESULT([yes]) + tst_proto_strdup="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_strdup="no" + ]) + fi + # + if test "$tst_proto_strdup" = "yes"; then + AC_MSG_CHECKING([if strdup is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != strdup(0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_strdup="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_strdup="no" + ]) + fi + # + if test "$tst_compi_strdup" = "yes"; then + AC_MSG_CHECKING([if strdup usage allowed]) + if test "x$curl_disallow_strdup" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_strdup="yes" + else + AC_MSG_RESULT([no]) + tst_allow_strdup="no" + fi + fi + # + AC_MSG_CHECKING([if strdup might be used]) + if test "$tst_links_strdup" = "yes" && + test "$tst_proto_strdup" = "yes" && + test "$tst_compi_strdup" = "yes" && + test "$tst_allow_strdup" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_STRDUP, 1, + [Define to 1 if you have the strdup function.]) + curl_cv_func_strdup="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_strdup="no" + fi +]) + + +dnl CURL_CHECK_FUNC_STRERROR_R +dnl ------------------------------------------------- +dnl Verify if strerror_r is available, prototyped, can be compiled and +dnl seems to work. If all of these are true, and usage has not been +dnl previously disallowed with shell variable curl_disallow_strerror_r, +dnl then HAVE_STRERROR_R will be defined, as well as one of +dnl HAVE_GLIBC_STRERROR_R or HAVE_POSIX_STRERROR_R. +dnl +dnl glibc-style strerror_r: +dnl +dnl char *strerror_r(int errnum, char *workbuf, size_t bufsize); +dnl +dnl glibc-style strerror_r returns a pointer to the error string, +dnl and might use the provided workbuf as a scratch area if needed. A +dnl quick test on a few systems shows that it's usually not used at all. +dnl +dnl POSIX-style strerror_r: +dnl +dnl int strerror_r(int errnum, char *resultbuf, size_t bufsize); +dnl +dnl POSIX-style strerror_r returns 0 upon successful completion and the +dnl error string in the provided resultbuf. +dnl + +AC_DEFUN([CURL_CHECK_FUNC_STRERROR_R], [ + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_strerror_r="unknown" + tst_proto_strerror_r="unknown" + tst_compi_strerror_r="unknown" + tst_glibc_strerror_r="unknown" + tst_posix_strerror_r="unknown" + tst_allow_strerror_r="unknown" + tst_works_glibc_strerror_r="unknown" + tst_works_posix_strerror_r="unknown" + tst_glibc_strerror_r_type_arg3="unknown" + tst_posix_strerror_r_type_arg3="unknown" + # + AC_MSG_CHECKING([if strerror_r can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strerror_r]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_strerror_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_strerror_r="no" + ]) + # + if test "$tst_links_strerror_r" = "yes"; then + AC_MSG_CHECKING([if strerror_r is prototyped]) + AC_EGREP_CPP([strerror_r],[ + $curl_includes_string + ],[ + AC_MSG_RESULT([yes]) + tst_proto_strerror_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_strerror_r="no" + ]) + fi + # + if test "$tst_proto_strerror_r" = "yes"; then + AC_MSG_CHECKING([if strerror_r is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != strerror_r(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_strerror_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_strerror_r="no" + ]) + fi + # + if test "$tst_compi_strerror_r" = "yes"; then + AC_MSG_CHECKING([if strerror_r is glibc like]) + tst_glibc_strerror_r_type_arg3="unknown" + for arg3 in 'size_t' 'int' 'unsigned int'; do + if test "$tst_glibc_strerror_r_type_arg3" = "unknown"; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + char *strerror_r(int errnum, char *workbuf, $arg3 bufsize); + ]],[[ + if(0 != strerror_r(0, 0, 0)) + return 1; + ]]) + ],[ + tst_glibc_strerror_r_type_arg3="$arg3" + ]) + fi + done + case "$tst_glibc_strerror_r_type_arg3" in + unknown) + AC_MSG_RESULT([no]) + tst_glibc_strerror_r="no" + ;; + *) + AC_MSG_RESULT([yes]) + tst_glibc_strerror_r="yes" + ;; + esac + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_glibc_strerror_r" = "yes"; then + AC_MSG_CHECKING([if strerror_r seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + $curl_includes_string +# include + ]],[[ + char buffer[1024]; + char *string = 0; + buffer[0] = '\0'; + string = strerror_r(EACCES, buffer, sizeof(buffer)); + if(!string) + exit(1); /* fail */ + if(!string[0]) + exit(1); /* fail */ + else + exit(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_glibc_strerror_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_glibc_strerror_r="no" + ]) + fi + # + if test "$tst_compi_strerror_r" = "yes" && + test "$tst_works_glibc_strerror_r" != "yes"; then + AC_MSG_CHECKING([if strerror_r is POSIX like]) + tst_posix_strerror_r_type_arg3="unknown" + for arg3 in 'size_t' 'int' 'unsigned int'; do + if test "$tst_posix_strerror_r_type_arg3" = "unknown"; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + int strerror_r(int errnum, char *resultbuf, $arg3 bufsize); + ]],[[ + if(0 != strerror_r(0, 0, 0)) + return 1; + ]]) + ],[ + tst_posix_strerror_r_type_arg3="$arg3" + ]) + fi + done + case "$tst_posix_strerror_r_type_arg3" in + unknown) + AC_MSG_RESULT([no]) + tst_posix_strerror_r="no" + ;; + *) + AC_MSG_RESULT([yes]) + tst_posix_strerror_r="yes" + ;; + esac + fi + # + dnl only do runtime verification when not cross-compiling + if test "x$cross_compiling" != "xyes" && + test "$tst_posix_strerror_r" = "yes"; then + AC_MSG_CHECKING([if strerror_r seems to work]) + CURL_RUN_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + $curl_includes_string +# include + ]],[[ + char buffer[1024]; + int error = 1; + buffer[0] = '\0'; + error = strerror_r(EACCES, buffer, sizeof(buffer)); + if(error) + exit(1); /* fail */ + if(buffer[0] == '\0') + exit(1); /* fail */ + else + exit(0); + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_works_posix_strerror_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_works_posix_strerror_r="no" + ]) + fi + # + if test "$tst_works_glibc_strerror_r" = "yes"; then + tst_posix_strerror_r="no" + fi + if test "$tst_works_posix_strerror_r" = "yes"; then + tst_glibc_strerror_r="no" + fi + if test "$tst_glibc_strerror_r" = "yes" && + test "$tst_works_glibc_strerror_r" != "no" && + test "$tst_posix_strerror_r" != "yes"; then + tst_allow_strerror_r="check" + fi + if test "$tst_posix_strerror_r" = "yes" && + test "$tst_works_posix_strerror_r" != "no" && + test "$tst_glibc_strerror_r" != "yes"; then + tst_allow_strerror_r="check" + fi + if test "$tst_allow_strerror_r" = "check"; then + AC_MSG_CHECKING([if strerror_r usage allowed]) + if test "x$curl_disallow_strerror_r" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_strerror_r="yes" + else + AC_MSG_RESULT([no]) + tst_allow_strerror_r="no" + fi + fi + # + AC_MSG_CHECKING([if strerror_r might be used]) + if test "$tst_links_strerror_r" = "yes" && + test "$tst_proto_strerror_r" = "yes" && + test "$tst_compi_strerror_r" = "yes" && + test "$tst_allow_strerror_r" = "yes"; then + AC_MSG_RESULT([yes]) + if test "$tst_glibc_strerror_r" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_STRERROR_R, 1, + [Define to 1 if you have the strerror_r function.]) + AC_DEFINE_UNQUOTED(HAVE_GLIBC_STRERROR_R, 1, + [Define to 1 if you have a working glibc-style strerror_r function.]) + fi + if test "$tst_posix_strerror_r" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_STRERROR_R, 1, + [Define to 1 if you have the strerror_r function.]) + AC_DEFINE_UNQUOTED(HAVE_POSIX_STRERROR_R, 1, + [Define to 1 if you have a working POSIX-style strerror_r function.]) + fi + curl_cv_func_strerror_r="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_strerror_r="no" + fi + # + if test "$tst_compi_strerror_r" = "yes" && + test "$tst_allow_strerror_r" = "unknown"; then + AC_MSG_WARN([cannot determine strerror_r() style: edit lib/curl_config.h manually.]) + fi + # +]) + + +dnl CURL_CHECK_FUNC_STRICMP +dnl ------------------------------------------------- +dnl Verify if stricmp is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_stricmp, then +dnl HAVE_STRICMP will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_STRICMP], [ + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_stricmp="unknown" + tst_proto_stricmp="unknown" + tst_compi_stricmp="unknown" + tst_allow_stricmp="unknown" + # + AC_MSG_CHECKING([if stricmp can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([stricmp]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_stricmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_stricmp="no" + ]) + # + if test "$tst_links_stricmp" = "yes"; then + AC_MSG_CHECKING([if stricmp is prototyped]) + AC_EGREP_CPP([stricmp],[ + $curl_includes_string + ],[ + AC_MSG_RESULT([yes]) + tst_proto_stricmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_stricmp="no" + ]) + fi + # + if test "$tst_proto_stricmp" = "yes"; then + AC_MSG_CHECKING([if stricmp is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != stricmp(0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_stricmp="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_stricmp="no" + ]) + fi + # + if test "$tst_compi_stricmp" = "yes"; then + AC_MSG_CHECKING([if stricmp usage allowed]) + if test "x$curl_disallow_stricmp" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_stricmp="yes" + else + AC_MSG_RESULT([no]) + tst_allow_stricmp="no" + fi + fi + # + AC_MSG_CHECKING([if stricmp might be used]) + if test "$tst_links_stricmp" = "yes" && + test "$tst_proto_stricmp" = "yes" && + test "$tst_compi_stricmp" = "yes" && + test "$tst_allow_stricmp" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_STRICMP, 1, + [Define to 1 if you have the stricmp function.]) + curl_cv_func_stricmp="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_stricmp="no" + fi +]) + + +dnl CURL_CHECK_FUNC_STRTOK_R +dnl ------------------------------------------------- +dnl Verify if strtok_r is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_strtok_r, then +dnl HAVE_STRTOK_R will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_STRTOK_R], [ + AC_REQUIRE([CURL_INCLUDES_STRING])dnl + # + tst_links_strtok_r="unknown" + tst_proto_strtok_r="unknown" + tst_compi_strtok_r="unknown" + tst_allow_strtok_r="unknown" + # + AC_MSG_CHECKING([if strtok_r can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strtok_r]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_strtok_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_strtok_r="no" + ]) + # + if test "$tst_links_strtok_r" = "yes"; then + AC_MSG_CHECKING([if strtok_r is prototyped]) + AC_EGREP_CPP([strtok_r],[ + $curl_includes_string + ],[ + AC_MSG_RESULT([yes]) + tst_proto_strtok_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_strtok_r="no" + ]) + fi + # + if test "$tst_proto_strtok_r" = "yes"; then + AC_MSG_CHECKING([if strtok_r is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_string + ]],[[ + if(0 != strtok_r(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_strtok_r="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_strtok_r="no" + ]) + fi + # + if test "$tst_compi_strtok_r" = "yes"; then + AC_MSG_CHECKING([if strtok_r usage allowed]) + if test "x$curl_disallow_strtok_r" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_strtok_r="yes" + else + AC_MSG_RESULT([no]) + tst_allow_strtok_r="no" + fi + fi + # + AC_MSG_CHECKING([if strtok_r might be used]) + if test "$tst_links_strtok_r" = "yes" && + test "$tst_proto_strtok_r" = "yes" && + test "$tst_compi_strtok_r" = "yes" && + test "$tst_allow_strtok_r" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_STRTOK_R, 1, + [Define to 1 if you have the strtok_r function.]) + curl_cv_func_strtok_r="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_strtok_r="no" + fi +]) + + +dnl CURL_CHECK_FUNC_STRTOLL +dnl ------------------------------------------------- +dnl Verify if strtoll is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable curl_disallow_strtoll, then +dnl HAVE_STRTOLL will be defined. + +AC_DEFUN([CURL_CHECK_FUNC_STRTOLL], [ + AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl + # + tst_links_strtoll="unknown" + tst_proto_strtoll="unknown" + tst_compi_strtoll="unknown" + tst_allow_strtoll="unknown" + # + AC_MSG_CHECKING([if strtoll can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strtoll]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_strtoll="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_strtoll="no" + ]) + # + if test "$tst_links_strtoll" = "yes"; then + AC_MSG_CHECKING([if strtoll is prototyped]) + AC_EGREP_CPP([strtoll],[ + $curl_includes_stdlib + ],[ + AC_MSG_RESULT([yes]) + tst_proto_strtoll="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_strtoll="no" + ]) + fi + # + if test "$tst_proto_strtoll" = "yes"; then + AC_MSG_CHECKING([if strtoll is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_stdlib + ]],[[ + if(0 != strtoll(0, 0, 0)) + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_strtoll="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_strtoll="no" + ]) + fi + # + if test "$tst_compi_strtoll" = "yes"; then + AC_MSG_CHECKING([if strtoll usage allowed]) + if test "x$curl_disallow_strtoll" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_strtoll="yes" + else + AC_MSG_RESULT([no]) + tst_allow_strtoll="no" + fi + fi + # + AC_MSG_CHECKING([if strtoll might be used]) + if test "$tst_links_strtoll" = "yes" && + test "$tst_proto_strtoll" = "yes" && + test "$tst_compi_strtoll" = "yes" && + test "$tst_allow_strtoll" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_STRTOLL, 1, + [Define to 1 if you have the strtoll function.]) + curl_cv_func_strtoll="yes" + else + AC_MSG_RESULT([no]) + curl_cv_func_strtoll="no" + fi +]) + +dnl CURL_RUN_IFELSE +dnl ------------------------------------------------- +dnl Wrapper macro to use instead of AC_RUN_IFELSE. It +dnl sets LD_LIBRARY_PATH locally for this run only, from the +dnl CURL_LIBRARY_PATH variable. It keeps the LD_LIBRARY_PATH +dnl changes contained within this macro. + +AC_DEFUN([CURL_RUN_IFELSE], [ + case $host_os in + darwin*) + AC_RUN_IFELSE([AC_LANG_SOURCE([$1])], $2, $3, $4) + ;; + *) + oldcc=$CC + old=$LD_LIBRARY_PATH + CC="sh ./run-compiler" + LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old + export LD_LIBRARY_PATH + AC_RUN_IFELSE([AC_LANG_SOURCE([$1])], $2, $3, $4) + LD_LIBRARY_PATH=$old # restore + CC=$oldcc + ;; + esac +]) + +dnl CURL_COVERAGE +dnl -------------------------------------------------- +dnl Switch on options and libs to build with gcc's code coverage. +dnl + +AC_DEFUN([CURL_COVERAGE],[ + AC_REQUIRE([AC_PROG_SED]) + AC_REQUIRE([AC_ARG_ENABLE]) + AC_MSG_CHECKING([for code coverage support]) + coverage="no" + curl_coverage_msg="disabled" + + dnl check if enabled by argument + AC_ARG_ENABLE(code-coverage, + AS_HELP_STRING([--enable-code-coverage], [Provide code coverage]), + coverage="$enableval") + + dnl if not gcc switch off again + AS_IF([ test "$GCC" != "yes" ], coverage="no" ) + AC_MSG_RESULT($coverage) + + if test "x$coverage" = "xyes"; then + curl_coverage_msg="enabled" + + AC_CHECK_TOOL([GCOV], [gcov], [gcov]) + if test -z "$GCOV"; then + AC_MSG_ERROR([needs gcov for code coverage]) + fi + AC_CHECK_PROG([LCOV], [lcov], [lcov]) + if test -z "$LCOV"; then + AC_MSG_ERROR([needs lcov for code coverage]) + fi + + CPPFLAGS="$CPPFLAGS -DNDEBUG" + CFLAGS="$CFLAGS -O0 -g -fprofile-arcs -ftest-coverage" + LIBS="$LIBS -lgcov" + fi +]) + +dnl CURL_ATOMIC +dnl ------------------------------------------------------------- +dnl Check if _Atomic works. But only check if stdatomic.h exists. +dnl +AC_DEFUN([CURL_ATOMIC],[ + AC_CHECK_HEADERS(stdatomic.h, [ + AC_MSG_CHECKING([if _Atomic is available]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + $curl_includes_unistd + ]],[[ + _Atomic int i = 0; + i = 4; // Force an atomic-write operation. + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_ATOMIC, 1, + [Define to 1 if you have _Atomic support.]) + tst_atomic="yes" + ],[ + AC_MSG_RESULT([no]) + tst_atomic="no" + ]) + ]) +]) + +# Rewrite inspired by the functionality once provided by +# AX_COMPILE_CHECK_SIZEOF. Uses the switch() "trick" to find the size of the +# given type. +# +# This code fails to compile: +# +# switch() { case 0: case 0: } +# +# By making the second case number a boolean check, it fails to compile the +# test code when the boolean is false and thus creating a zero, making it a +# duplicated case label. If the boolean equals true, it becomes a one, the +# code compiles and we know it was a match. +# +# The check iterates over all possible sizes and stops as soon it compiles +# error-free. +# +# Usage: +# +# CURL_SIZEOF(TYPE, [HEADERS]) +# + +AC_DEFUN([CURL_SIZEOF], [ + dnl The #define name to make autoheader put the name in curl_config.h.in + define(TYPE, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl + + AC_MSG_CHECKING(size of $1) + r=0 + dnl Check the sizes in a reasonable order + for typesize in 8 4 2 16 1; do + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +$2 +]], + [switch(0) { + case 0: + case (sizeof($1) == $typesize):; + } + ]) ], + [ + r=$typesize], + [ + r=0]) + dnl get out of the loop once matched + if test $r -gt 0; then + break; + fi + done + if test $r -eq 0; then + AC_MSG_ERROR([Failed to find size of $1]) + fi + AC_MSG_RESULT($r) + dnl lowercase and underscore instead of space + tname=$(echo "ac_cv_sizeof_$1" | tr A-Z a-z | tr " " "_") + eval "$tname=$r" + + AC_DEFINE_UNQUOTED(TYPE, [$r], [Size of $1 in number of bytes]) + +]) diff --git a/m4/curl-gnutls.m4 b/m4/curl-gnutls.m4 new file mode 100644 index 0000000..d4f553d --- /dev/null +++ b/m4/curl-gnutls.m4 @@ -0,0 +1,168 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +dnl ---------------------------------------------------- +dnl check for GnuTLS +dnl ---------------------------------------------------- + +AC_DEFUN([CURL_WITH_GNUTLS], [ +if test "x$OPT_GNUTLS" != xno; then + ssl_msg= + + if test X"$OPT_GNUTLS" != Xno; then + + addld="" + addlib="" + gtlslib="" + version="" + addcflags="" + + if test "x$OPT_GNUTLS" = "xyes"; then + dnl this is with no particular path given + CURL_CHECK_PKGCONFIG(gnutls) + + if test "$PKGCONFIG" != "no" ; then + addlib=`$PKGCONFIG --libs-only-l gnutls` + addld=`$PKGCONFIG --libs-only-L gnutls` + addcflags=`$PKGCONFIG --cflags-only-I gnutls` + version=`$PKGCONFIG --modversion gnutls` + gtlslib=`echo $addld | $SED -e 's/^-L//'` + else + dnl without pkg-config, we try libgnutls-config as that was how it + dnl used to be done + check=`libgnutls-config --version 2>/dev/null` + if test -n "$check"; then + addlib=`libgnutls-config --libs` + addcflags=`libgnutls-config --cflags` + version=`libgnutls-config --version` + gtlslib=`libgnutls-config --prefix`/lib$libsuff + fi + fi + else + dnl this is with a given path, first check if there's a libgnutls-config + dnl there and if not, make an educated guess + cfg=$OPT_GNUTLS/bin/libgnutls-config + check=`$cfg --version 2>/dev/null` + if test -n "$check"; then + addlib=`$cfg --libs` + addcflags=`$cfg --cflags` + version=`$cfg --version` + gtlslib=`$cfg --prefix`/lib$libsuff + else + dnl without pkg-config and libgnutls-config, we guess a lot! + addlib=-lgnutls + addld=-L$OPT_GNUTLS/lib$libsuff + addcflags=-I$OPT_GNUTLS/include + version="" # we just don't know + gtlslib=$OPT_GNUTLS/lib$libsuff + fi + fi + + if test -z "$version"; then + dnl lots of efforts, still no go + version="unknown" + fi + + if test -n "$addlib"; then + + CLEANLIBS="$LIBS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLDFLAGS="$LDFLAGS" + + LIBS="$addlib $LIBS" + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + dnl this function is selected since it was introduced in 3.1.10 + AC_CHECK_LIB(gnutls, gnutls_x509_crt_get_dn2, + [ + AC_DEFINE(USE_GNUTLS, 1, [if GnuTLS is enabled]) + AC_SUBST(USE_GNUTLS, [1]) + GNUTLS_ENABLED=1 + USE_GNUTLS="yes" + ssl_msg="GnuTLS" + QUIC_ENABLED=yes + test gnutls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], + [ + LIBS="$CLEANLIBS" + CPPFLAGS="$CLEANCPPFLAGS" + ]) + + if test "x$USE_GNUTLS" = "xyes"; then + AC_MSG_NOTICE([detected GnuTLS version $version]) + check_for_ca_bundle=1 + if test -n "$gtlslib"; then + dnl when shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to + dnl CURL_LIBRARY_PATH to prevent further configure tests to fail + dnl due to this + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$gtlslib" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $gtlslib to CURL_LIBRARY_PATH]) + fi + fi + fi + + fi + + fi dnl GNUTLS not disabled + + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + +dnl --- +dnl Check which crypto backend GnuTLS uses +dnl --- + +if test "$GNUTLS_ENABLED" = "1"; then + USE_GNUTLS_NETTLE= + # First check if we can detect either crypto library via transitive linking + AC_CHECK_LIB(gnutls, nettle_MD5Init, [ USE_GNUTLS_NETTLE=1 ]) + + # If not, try linking directly to both of them to see if they are available + if test "$USE_GNUTLS_NETTLE" = ""; then + AC_CHECK_LIB(nettle, nettle_MD5Init, [ USE_GNUTLS_NETTLE=1 ]) + fi + if test "$USE_GNUTLS_NETTLE" = ""; then + AC_MSG_ERROR([GnuTLS found, but nettle was not found]) + fi + LIBS="-lnettle $LIBS" +fi + +dnl --- +dnl We require GnuTLS with SRP support. +dnl --- +if test "$GNUTLS_ENABLED" = "1"; then + AC_CHECK_LIB(gnutls, gnutls_srp_verifier, + [ + AC_DEFINE(HAVE_GNUTLS_SRP, 1, [if you have the function gnutls_srp_verifier]) + AC_SUBST(HAVE_GNUTLS_SRP, [1]) + ]) +fi + +]) diff --git a/m4/curl-mbedtls.m4 b/m4/curl-mbedtls.m4 new file mode 100644 index 0000000..64116e7 --- /dev/null +++ b/m4/curl-mbedtls.m4 @@ -0,0 +1,111 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +dnl ---------------------------------------------------- +dnl check for mbedTLS +dnl ---------------------------------------------------- +AC_DEFUN([CURL_WITH_MBEDTLS], [ + +if test "x$OPT_MBEDTLS" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + ssl_msg= + + if test X"$OPT_MBEDTLS" != Xno; then + + if test "$OPT_MBEDTLS" = "yes"; then + OPT_MBEDTLS="" + fi + + if test -z "$OPT_MBEDTLS" ; then + dnl check for lib first without setting any new path + + AC_CHECK_LIB(mbedtls, mbedtls_havege_init, + dnl libmbedtls found, set the variable + [ + AC_DEFINE(USE_MBEDTLS, 1, [if mbedTLS is enabled]) + AC_SUBST(USE_MBEDTLS, [1]) + MBEDTLS_ENABLED=1 + USE_MBEDTLS="yes" + ssl_msg="mbedTLS" + test mbedtls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], [], -lmbedx509 -lmbedcrypto) + fi + + addld="" + addlib="" + addcflags="" + mbedtlslib="" + + if test "x$USE_MBEDTLS" != "xyes"; then + dnl add the path and test again + addld=-L$OPT_MBEDTLS/lib$libsuff + addcflags=-I$OPT_MBEDTLS/include + mbedtlslib=$OPT_MBEDTLS/lib$libsuff + + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + AC_CHECK_LIB(mbedtls, mbedtls_ssl_init, + [ + AC_DEFINE(USE_MBEDTLS, 1, [if mbedTLS is enabled]) + AC_SUBST(USE_MBEDTLS, [1]) + MBEDTLS_ENABLED=1 + USE_MBEDTLS="yes" + ssl_msg="mbedTLS" + test mbedtls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], + [ + CPPFLAGS=$_cppflags + LDFLAGS=$_ldflags + ], -lmbedx509 -lmbedcrypto) + fi + + if test "x$USE_MBEDTLS" = "xyes"; then + AC_MSG_NOTICE([detected mbedTLS]) + check_for_ca_bundle=1 + + LIBS="-lmbedtls -lmbedx509 -lmbedcrypto $LIBS" + + if test -n "$mbedtlslib"; then + dnl when shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to + dnl CURL_LIBRARY_PATH to prevent further configure tests to fail + dnl due to this + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$mbedtlslib" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $mbedtlslib to CURL_LIBRARY_PATH]) + fi + fi + fi + + fi dnl mbedTLS not disabled + + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + +]) diff --git a/m4/curl-openssl.m4 b/m4/curl-openssl.m4 new file mode 100644 index 0000000..2fb2abe --- /dev/null +++ b/m4/curl-openssl.m4 @@ -0,0 +1,446 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +# File version for 'aclocal' use. Keep it a single number. +# serial 5 + +dnl ********************************************************************** +dnl Check for OpenSSL libraries and headers +dnl ********************************************************************** + +AC_DEFUN([CURL_WITH_OPENSSL], [ +if test "x$OPT_OPENSSL" != xno; then + ssl_msg= + + dnl backup the pre-ssl variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + dnl This is for Msys/Mingw + case $host in + *-*-msys* | *-*-mingw*) + AC_MSG_CHECKING([for gdi32]) + my_ac_save_LIBS=$LIBS + LIBS="-lgdi32 $LIBS" + AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ + #include + #include + ]], + [[ + GdiFlush(); + ]])], + [ dnl worked! + AC_MSG_RESULT([yes])], + [ dnl failed, restore LIBS + LIBS=$my_ac_save_LIBS + AC_MSG_RESULT(no)] + ) + ;; + esac + + case "$OPT_OPENSSL" in + yes) + dnl --with-openssl (without path) used + PKGTEST="yes" + PREFIX_OPENSSL= + ;; + *) + dnl check the given --with-openssl spot + PKGTEST="no" + PREFIX_OPENSSL=$OPT_OPENSSL + + dnl Try pkg-config even when cross-compiling. Since we + dnl specify PKG_CONFIG_LIBDIR we're only looking where + dnl the user told us to look + OPENSSL_PCDIR="$OPT_OPENSSL/lib/pkgconfig" + if test -f "$OPENSSL_PCDIR/openssl.pc"; then + AC_MSG_NOTICE([PKG_CONFIG_LIBDIR will be set to "$OPENSSL_PCDIR"]) + PKGTEST="yes" + fi + + if test "$PKGTEST" != "yes"; then + # try lib64 instead + OPENSSL_PCDIR="$OPT_OPENSSL/lib64/pkgconfig" + if test -f "$OPENSSL_PCDIR/openssl.pc"; then + AC_MSG_NOTICE([PKG_CONFIG_LIBDIR will be set to "$OPENSSL_PCDIR"]) + PKGTEST="yes" + fi + fi + + if test "$PKGTEST" != "yes"; then + if test ! -f "$PREFIX_OPENSSL/include/openssl/ssl.h"; then + AC_MSG_ERROR([$PREFIX_OPENSSL is a bad --with-openssl prefix!]) + fi + fi + + dnl in case pkg-config comes up empty, use what we got + dnl via --with-openssl + LIB_OPENSSL="$PREFIX_OPENSSL/lib$libsuff" + if test "$PREFIX_OPENSSL" != "/usr" ; then + SSL_LDFLAGS="-L$LIB_OPENSSL" + SSL_CPPFLAGS="-I$PREFIX_OPENSSL/include" + fi + ;; + esac + + if test "$PKGTEST" = "yes"; then + + CURL_CHECK_PKGCONFIG(openssl, [$OPENSSL_PCDIR]) + + if test "$PKGCONFIG" != "no" ; then + SSL_LIBS=`CURL_EXPORT_PCDIR([$OPENSSL_PCDIR]) dnl + $PKGCONFIG --libs-only-l --libs-only-other openssl 2>/dev/null` + + SSL_LDFLAGS=`CURL_EXPORT_PCDIR([$OPENSSL_PCDIR]) dnl + $PKGCONFIG --libs-only-L openssl 2>/dev/null` + + SSL_CPPFLAGS=`CURL_EXPORT_PCDIR([$OPENSSL_PCDIR]) dnl + $PKGCONFIG --cflags-only-I openssl 2>/dev/null` + + AC_SUBST(SSL_LIBS) + AC_MSG_NOTICE([pkg-config: SSL_LIBS: "$SSL_LIBS"]) + AC_MSG_NOTICE([pkg-config: SSL_LDFLAGS: "$SSL_LDFLAGS"]) + AC_MSG_NOTICE([pkg-config: SSL_CPPFLAGS: "$SSL_CPPFLAGS"]) + + LIB_OPENSSL=`echo $SSL_LDFLAGS | sed -e 's/^-L//'` + + dnl use the values pkg-config reported. This is here + dnl instead of below with CPPFLAGS and LDFLAGS because we only + dnl learn about this via pkg-config. If we only have + dnl the argument to --with-openssl we don't know what + dnl additional libs may be necessary. Hope that we + dnl don't need any. + LIBS="$SSL_LIBS $LIBS" + fi + fi + + dnl finally, set flags to use SSL + CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS" + LDFLAGS="$LDFLAGS $SSL_LDFLAGS" + + AC_CHECK_LIB(crypto, HMAC_Update,[ + HAVECRYPTO="yes" + LIBS="-lcrypto $LIBS" + ],[ + if test -n "$LIB_OPENSSL" ; then + LDFLAGS="$CLEANLDFLAGS -L$LIB_OPENSSL" + fi + if test "$PKGCONFIG" = "no" -a -n "$PREFIX_OPENSSL" ; then + # only set this if pkg-config wasn't used + CPPFLAGS="$CLEANCPPFLAGS -I$PREFIX_OPENSSL/include" + fi + # Linking previously failed, try extra paths from --with-openssl or + # pkg-config. Use a different function name to avoid reusing the earlier + # cached result. + AC_CHECK_LIB(crypto, HMAC_Init_ex,[ + HAVECRYPTO="yes" + LIBS="-lcrypto $LIBS"], [ + + dnl still no, but what about with -ldl? + AC_MSG_CHECKING([OpenSSL linking with -ldl]) + LIBS="-lcrypto $CLEANLIBS -ldl" + AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ + #include + ]], [[ + ERR_clear_error(); + ]]) ], + [ + AC_MSG_RESULT(yes) + HAVECRYPTO="yes" + ], + [ + AC_MSG_RESULT(no) + dnl ok, so what about both -ldl and -lpthread? + dnl This may be necessary for static libraries. + + AC_MSG_CHECKING([OpenSSL linking with -ldl and -lpthread]) + LIBS="-lcrypto $CLEANLIBS -ldl -lpthread" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + #include + ]], [[ + ERR_clear_error(); + ]])], + [ + AC_MSG_RESULT(yes) + HAVECRYPTO="yes" + ], + [ + AC_MSG_RESULT(no) + LDFLAGS="$CLEANLDFLAGS" + CPPFLAGS="$CLEANCPPFLAGS" + LIBS="$CLEANLIBS" + + ]) + + ]) + + ]) + ]) + + if test X"$HAVECRYPTO" = X"yes"; then + dnl This is only reasonable to do if crypto actually is there: check for + dnl SSL libs NOTE: it is important to do this AFTER the crypto lib + + AC_CHECK_LIB(ssl, SSL_connect) + + if test "$ac_cv_lib_ssl_SSL_connect" != yes; then + dnl we didn't find the SSL lib, try the RSAglue/rsaref stuff + AC_MSG_CHECKING(for ssl with RSAglue/rsaref libs in use); + OLIBS=$LIBS + LIBS="-lRSAglue -lrsaref $LIBS" + AC_CHECK_LIB(ssl, SSL_connect) + if test "$ac_cv_lib_ssl_SSL_connect" != yes; then + dnl still no SSL_connect + AC_MSG_RESULT(no) + LIBS=$OLIBS + else + AC_MSG_RESULT(yes) + fi + + else + + dnl Have the libraries--check for OpenSSL headers + AC_CHECK_HEADERS(openssl/x509.h openssl/rsa.h openssl/crypto.h \ + openssl/pem.h openssl/ssl.h openssl/err.h, + ssl_msg="OpenSSL" + test openssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + OPENSSL_ENABLED=1 + AC_DEFINE(USE_OPENSSL, 1, [if OpenSSL is in use])) + + if test $ac_cv_header_openssl_x509_h = no; then + dnl we don't use the "action" part of the AC_CHECK_HEADERS macro + dnl since 'err.h' might in fact find a krb4 header with the same + dnl name + AC_CHECK_HEADERS(x509.h rsa.h crypto.h pem.h ssl.h err.h) + + if test $ac_cv_header_x509_h = yes && + test $ac_cv_header_crypto_h = yes && + test $ac_cv_header_ssl_h = yes; then + dnl three matches + ssl_msg="OpenSSL" + OPENSSL_ENABLED=1 + fi + fi + fi + + if test X"$OPENSSL_ENABLED" != X"1"; then + LIBS="$CLEANLIBS" + fi + + if test X"$OPT_OPENSSL" != Xoff && + test "$OPENSSL_ENABLED" != "1"; then + AC_MSG_ERROR([OpenSSL libs and/or directories were not found where specified!]) + fi + fi + + if test X"$OPENSSL_ENABLED" = X"1"; then + dnl These can only exist if OpenSSL exists + + AC_MSG_CHECKING([for BoringSSL]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include + ]],[[ + #ifndef OPENSSL_IS_BORINGSSL + #error not boringssl + #endif + ]]) + ],[ + AC_MSG_RESULT([yes]) + ssl_msg="BoringSSL" + OPENSSL_IS_BORINGSSL=1 + ],[ + AC_MSG_RESULT([no]) + ]) + + AC_MSG_CHECKING([for AWS-LC]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include + ]],[[ + #ifndef OPENSSL_IS_AWSLC + #error not AWS-LC + #endif + ]]) + ],[ + AC_MSG_RESULT([yes]) + ssl_msg="AWS-LC" + OPENSSL_IS_BORINGSSL=1 + ],[ + AC_MSG_RESULT([no]) + ]) + + AC_MSG_CHECKING([for libressl]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ + int dummy = LIBRESSL_VERSION_NUMBER; + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_LIBRESSL, 1, + [Define to 1 if using libressl.]) + ssl_msg="libressl" + ],[ + AC_MSG_RESULT([no]) + ]) + + AC_MSG_CHECKING([for OpenSSL >= v3]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ + #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + return 0; + #else + #error older than 3 + #endif + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_OPENSSL3, 1, + [Define to 1 if using OpenSSL 3 or later.]) + ssl_msg="OpenSSL v3+" + ],[ + AC_MSG_RESULT([no]) + ]) + fi + + dnl is this OpenSSL (fork) providing the original QUIC API? + AC_CHECK_FUNCS([SSL_set_quic_use_legacy_codepoint], + [QUIC_ENABLED=yes]) + if test "$QUIC_ENABLED" = "yes"; then + AC_MSG_NOTICE([OpenSSL fork speaks QUIC API]) + else + AC_MSG_NOTICE([OpenSSL version does not speak QUIC API]) + fi + + if test "$OPENSSL_ENABLED" = "1"; then + if test -n "$LIB_OPENSSL"; then + dnl when the ssl shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH + dnl to prevent further configure tests to fail due to this + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_OPENSSL" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $LIB_OPENSSL to CURL_LIBRARY_PATH]) + fi + fi + check_for_ca_bundle=1 + fi + + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + +if test X"$OPT_OPENSSL" != Xno && + test "$OPENSSL_ENABLED" != "1"; then + AC_MSG_NOTICE([OPT_OPENSSL: $OPT_OPENSSL]) + AC_MSG_NOTICE([OPENSSL_ENABLED: $OPENSSL_ENABLED]) + AC_MSG_ERROR([--with-openssl was given but OpenSSL could not be detected]) +fi + +dnl ********************************************************************** +dnl Check for the random seed preferences +dnl ********************************************************************** + +if test X"$OPENSSL_ENABLED" = X"1"; then + dnl Check for user-specified random device + AC_ARG_WITH(random, + AS_HELP_STRING([--with-random=FILE], + [read randomness from FILE (default=/dev/urandom)]), + [ RANDOM_FILE="$withval" ], + [ + if test x$cross_compiling != xyes; then + dnl Check for random device + AC_CHECK_FILE("/dev/urandom", [ RANDOM_FILE="/dev/urandom"] ) + else + AC_MSG_WARN([skipped the /dev/urandom detection when cross-compiling]) + fi + ] + ) + if test -n "$RANDOM_FILE" && test X"$RANDOM_FILE" != Xno ; then + AC_SUBST(RANDOM_FILE) + AC_DEFINE_UNQUOTED(RANDOM_FILE, "$RANDOM_FILE", + [a suitable file to read random data from]) + fi +fi + +dnl --- +dnl We require OpenSSL with SRP support. +dnl --- +if test "$OPENSSL_ENABLED" = "1"; then + AC_MSG_CHECKING([for SRP support in OpenSSL]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ + SSL_CTX_set_srp_username(NULL, ""); + SSL_CTX_set_srp_password(NULL, ""); + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_OPENSSL_SRP, 1, [if you have the functions SSL_CTX_set_srp_username and SSL_CTX_set_srp_password]) + AC_SUBST(HAVE_OPENSSL_SRP, [1]) + ],[ + AC_MSG_RESULT([no]) + ]) +fi + +dnl --- +dnl Whether the OpenSSL configuration will be loaded automatically +dnl --- +if test X"$OPENSSL_ENABLED" = X"1"; then +AC_ARG_ENABLE(openssl-auto-load-config, +AS_HELP_STRING([--enable-openssl-auto-load-config],[Enable automatic loading of OpenSSL configuration]) +AS_HELP_STRING([--disable-openssl-auto-load-config],[Disable automatic loading of OpenSSL configuration]), +[ if test X"$enableval" = X"no"; then + AC_MSG_NOTICE([automatic loading of OpenSSL configuration disabled]) + AC_DEFINE(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG, 1, [if the OpenSSL configuration won't be loaded automatically]) + fi +]) +fi + +dnl --- +dnl We may use OpenSSL QUIC. +dnl --- +if test "$OPENSSL_ENABLED" = "1"; then + AC_MSG_CHECKING([for QUIC support in OpenSSL]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ + OSSL_QUIC_client_method(); + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_OPENSSL_QUIC, 1, [if you have the functions OSSL_QUIC_client_method]) + AC_SUBST(HAVE_OPENSSL_QUIC, [1]) + ],[ + AC_MSG_RESULT([no]) + ]) +fi +]) diff --git a/m4/curl-override.m4 b/m4/curl-override.m4 new file mode 100644 index 0000000..b4a8df9 --- /dev/null +++ b/m4/curl-override.m4 @@ -0,0 +1,98 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +#*************************************************************************** +#*************************************************************************** + +# File version for 'aclocal' use. Keep it a single number. +# serial 7 + +dnl CURL_OVERRIDE_AUTOCONF +dnl ------------------------------------------------- +dnl Placing a call to this macro in configure.ac after +dnl the one to AC_INIT will make macros in this file +dnl visible to the rest of the compilation overriding +dnl those from Autoconf. + +AC_DEFUN([CURL_OVERRIDE_AUTOCONF], [ +AC_BEFORE([$0],[AC_PROG_LIBTOOL]) +# using curl-override.m4 +]) + +dnl Override Autoconf's AC_LANG_PROGRAM (C) +dnl ------------------------------------------------- +dnl This is done to prevent compiler warning +dnl 'function declaration isn't a prototype' +dnl in function main. This requires at least +dnl a c89 compiler and does not support K&R. + +m4_define([AC_LANG_PROGRAM(C)], +[$1 +int main (void) +{ +$2 + ; + return 0; +}]) + +dnl Override Autoconf's AC_LANG_CALL (C) +dnl ------------------------------------------------- +dnl This is a backport of Autoconf's 2.60 with the +dnl embedded comments that hit the resulting script +dnl removed. This is done to reduce configure size +dnl and use fixed macro across Autoconf versions. + +m4_define([AC_LANG_CALL(C)], +[AC_LANG_PROGRAM([$1 +m4_if([$2], [main], , +[ +#ifdef __cplusplus +extern "C" +#endif +char $2 ();])], [return $2 ();])]) + +dnl Override Autoconf's AC_LANG_FUNC_LINK_TRY (C) +dnl ------------------------------------------------- +dnl This is a backport of Autoconf's 2.60 with the +dnl embedded comments that hit the resulting script +dnl removed. This is done to reduce configure size +dnl and use fixed macro across Autoconf versions. + +m4_define([AC_LANG_FUNC_LINK_TRY(C)], +[AC_LANG_PROGRAM( +[ +#define $1 innocuous_$1 +#ifdef __STDC__ +# include +#else +# include +#endif +#undef $1 +#ifdef __cplusplus +extern "C" +#endif +char $1 (); +#if defined __stub_$1 || defined __stub___$1 +choke me +#endif +], [return $1 ();])]) diff --git a/m4/curl-reentrant.m4 b/m4/curl-reentrant.m4 new file mode 100644 index 0000000..c1f3339 --- /dev/null +++ b/m4/curl-reentrant.m4 @@ -0,0 +1,506 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +# File version for 'aclocal' use. Keep it a single number. +# serial 10 + +dnl Note 1 +dnl ------ +dnl None of the CURL_CHECK_NEED_REENTRANT_* macros shall use HAVE_FOO_H to +dnl conditionally include header files. These macros are used early in the +dnl configure process much before header file availability is known. + + +dnl CURL_CHECK_NEED_REENTRANT_ERRNO +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes errno available as a preprocessor macro. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_ERRNO], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ + if(0 != errno) + return 1; + ]]) + ],[ + tmp_errno="yes" + ],[ + tmp_errno="no" + ]) + if test "$tmp_errno" = "yes"; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ +#ifdef errno + int dummy=1; +#else + force compilation error +#endif + ]]) + ],[ + tmp_errno="errno_macro_defined" + ],[ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#define _REENTRANT +#include + ]],[[ +#ifdef errno + int dummy=1; +#else + force compilation error +#endif + ]]) + ],[ + tmp_errno="errno_macro_needs_reentrant" + tmp_need_reentrant="yes" + ]) + ]) + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_GMTIME_R +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes function gmtime_r compiler visible. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GMTIME_R], [ + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([gmtime_r]) + ],[ + tmp_gmtime_r="yes" + ],[ + tmp_gmtime_r="no" + ]) + if test "$tmp_gmtime_r" = "yes"; then + AC_EGREP_CPP([gmtime_r],[ +#include +#include + ],[ + tmp_gmtime_r="proto_declared" + ],[ + AC_EGREP_CPP([gmtime_r],[ +#define _REENTRANT +#include +#include + ],[ + tmp_gmtime_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + ]) + ]) + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_LOCALTIME_R +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes function localtime_r compiler visible. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_LOCALTIME_R], [ + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([localtime_r]) + ],[ + tmp_localtime_r="yes" + ],[ + tmp_localtime_r="no" + ]) + if test "$tmp_localtime_r" = "yes"; then + AC_EGREP_CPP([localtime_r],[ +#include +#include + ],[ + tmp_localtime_r="proto_declared" + ],[ + AC_EGREP_CPP([localtime_r],[ +#define _REENTRANT +#include +#include + ],[ + tmp_localtime_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + ]) + ]) + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_STRERROR_R +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes function strerror_r compiler visible. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_STRERROR_R], [ + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strerror_r]) + ],[ + tmp_strerror_r="yes" + ],[ + tmp_strerror_r="no" + ]) + if test "$tmp_strerror_r" = "yes"; then + AC_EGREP_CPP([strerror_r],[ +#include +#include + ],[ + tmp_strerror_r="proto_declared" + ],[ + AC_EGREP_CPP([strerror_r],[ +#define _REENTRANT +#include +#include + ],[ + tmp_strerror_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + ]) + ]) + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_STRTOK_R +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes function strtok_r compiler visible. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_STRTOK_R], [ + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([strtok_r]) + ],[ + tmp_strtok_r="yes" + ],[ + tmp_strtok_r="no" + ]) + if test "$tmp_strtok_r" = "yes"; then + AC_EGREP_CPP([strtok_r],[ +#include +#include + ],[ + tmp_strtok_r="proto_declared" + ],[ + AC_EGREP_CPP([strtok_r],[ +#define _REENTRANT +#include +#include + ],[ + tmp_strtok_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + ]) + ]) + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_GETHOSTBYNAME_R +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes function gethostbyname_r compiler visible. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GETHOSTBYNAME_R], [ + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([gethostbyname_r]) + ],[ + tmp_gethostbyname_r="yes" + ],[ + tmp_gethostbyname_r="no" + ]) + if test "$tmp_gethostbyname_r" = "yes"; then + AC_EGREP_CPP([gethostbyname_r],[ +#include +#include + ],[ + tmp_gethostbyname_r="proto_declared" + ],[ + AC_EGREP_CPP([gethostbyname_r],[ +#define _REENTRANT +#include +#include + ],[ + tmp_gethostbyname_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + ]) + ]) + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_GETPROTOBYNAME_R +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes function getprotobyname_r compiler visible. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GETPROTOBYNAME_R], [ + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([getprotobyname_r]) + ],[ + tmp_getprotobyname_r="yes" + ],[ + tmp_getprotobyname_r="no" + ]) + if test "$tmp_getprotobyname_r" = "yes"; then + AC_EGREP_CPP([getprotobyname_r],[ +#include +#include + ],[ + tmp_getprotobyname_r="proto_declared" + ],[ + AC_EGREP_CPP([getprotobyname_r],[ +#define _REENTRANT +#include +#include + ],[ + tmp_getprotobyname_r="proto_needs_reentrant" + tmp_need_reentrant="yes" + ]) + ]) + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_FUNCTIONS_R +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl makes several _r functions compiler visible. +dnl Internal macro for CURL_CONFIGURE_REENTRANT. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_FUNCTIONS_R], [ + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_GMTIME_R + fi + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_LOCALTIME_R + fi + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_STRERROR_R + fi + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_STRTOK_R + fi + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_GETHOSTBYNAME_R + fi + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_GETPROTOBYNAME_R + fi +]) + + +dnl CURL_CHECK_NEED_REENTRANT_SYSTEM +dnl ------------------------------------------------- +dnl Checks if the preprocessor _REENTRANT definition +dnl must be unconditionally done for this platform. +dnl Internal macro for CURL_CONFIGURE_REENTRANT. + +AC_DEFUN([CURL_CHECK_NEED_REENTRANT_SYSTEM], [ + case $host_os in + solaris*) + tmp_need_reentrant="yes" + ;; + *) + tmp_need_reentrant="no" + ;; + esac +]) + + +dnl CURL_CHECK_NEED_THREAD_SAFE_SYSTEM +dnl ------------------------------------------------- +dnl Checks if the preprocessor _THREAD_SAFE definition +dnl must be unconditionally done for this platform. +dnl Internal macro for CURL_CONFIGURE_THREAD_SAFE. + +AC_DEFUN([CURL_CHECK_NEED_THREAD_SAFE_SYSTEM], [ + case $host_os in + aix[[123]].* | aix4.[[012]].*) + dnl aix 4.2 and older + tmp_need_thread_safe="no" + ;; + aix*) + dnl AIX 4.3 and newer + tmp_need_thread_safe="yes" + ;; + *) + tmp_need_thread_safe="no" + ;; + esac +]) + + +dnl CURL_CONFIGURE_FROM_NOW_ON_WITH_REENTRANT +dnl ------------------------------------------------- +dnl This macro ensures that configuration tests done +dnl after this will execute with preprocessor symbol +dnl _REENTRANT defined. This macro also ensures that +dnl the generated config file defines NEED_REENTRANT +dnl and that in turn curl_setup.h will define _REENTRANT. +dnl Internal macro for CURL_CONFIGURE_REENTRANT. + +AC_DEFUN([CURL_CONFIGURE_FROM_NOW_ON_WITH_REENTRANT], [ +AC_DEFINE(NEED_REENTRANT, 1, + [Define to 1 if _REENTRANT preprocessor symbol must be defined.]) +cat >>confdefs.h <<_EOF +#ifndef _REENTRANT +# define _REENTRANT +#endif +_EOF +]) + + +dnl CURL_CONFIGURE_FROM_NOW_ON_WITH_THREAD_SAFE +dnl ------------------------------------------------- +dnl This macro ensures that configuration tests done +dnl after this will execute with preprocessor symbol +dnl _THREAD_SAFE defined. This macro also ensures that +dnl the generated config file defines NEED_THREAD_SAFE +dnl and that in turn curl_setup.h will define _THREAD_SAFE. +dnl Internal macro for CURL_CONFIGURE_THREAD_SAFE. + +AC_DEFUN([CURL_CONFIGURE_FROM_NOW_ON_WITH_THREAD_SAFE], [ +AC_DEFINE(NEED_THREAD_SAFE, 1, + [Define to 1 if _THREAD_SAFE preprocessor symbol must be defined.]) +cat >>confdefs.h <<_EOF +#ifndef _THREAD_SAFE +# define _THREAD_SAFE +#endif +_EOF +]) + + +dnl CURL_CONFIGURE_REENTRANT +dnl ------------------------------------------------- +dnl This first checks if the preprocessor _REENTRANT +dnl symbol is already defined. If it isn't currently +dnl defined a set of checks are performed to verify +dnl if its definition is required to make visible to +dnl the compiler a set of *_r functions. Finally, if +dnl _REENTRANT is already defined or needed it takes +dnl care of making adjustments necessary to ensure +dnl that it is defined equally for further configure +dnl tests and generated config file. + +AC_DEFUN([CURL_CONFIGURE_REENTRANT], [ + AC_PREREQ([2.50])dnl + # + AC_MSG_CHECKING([if _REENTRANT is already defined]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ +#ifdef _REENTRANT + int dummy=1; +#else + force compilation error +#endif + ]]) + ],[ + AC_MSG_RESULT([yes]) + tmp_reentrant_initially_defined="yes" + ],[ + AC_MSG_RESULT([no]) + tmp_reentrant_initially_defined="no" + ]) + # + if test "$tmp_reentrant_initially_defined" = "no"; then + AC_MSG_CHECKING([if _REENTRANT is actually needed]) + CURL_CHECK_NEED_REENTRANT_SYSTEM + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_ERRNO + fi + if test "$tmp_need_reentrant" = "no"; then + CURL_CHECK_NEED_REENTRANT_FUNCTIONS_R + fi + if test "$tmp_need_reentrant" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + AC_MSG_CHECKING([if _REENTRANT is onwards defined]) + if test "$tmp_reentrant_initially_defined" = "yes" || + test "$tmp_need_reentrant" = "yes"; then + CURL_CONFIGURE_FROM_NOW_ON_WITH_REENTRANT + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + # +]) + + +dnl CURL_CONFIGURE_THREAD_SAFE +dnl ------------------------------------------------- +dnl This first checks if the preprocessor _THREAD_SAFE +dnl symbol is already defined. If it isn't currently +dnl defined a set of checks are performed to verify +dnl if its definition is required. Finally, if +dnl _THREAD_SAFE is already defined or needed it takes +dnl care of making adjustments necessary to ensure +dnl that it is defined equally for further configure +dnl tests and generated config file. + +AC_DEFUN([CURL_CONFIGURE_THREAD_SAFE], [ + AC_PREREQ([2.50])dnl + # + AC_MSG_CHECKING([if _THREAD_SAFE is already defined]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + ]],[[ +#ifdef _THREAD_SAFE + int dummy=1; +#else + force compilation error +#endif + ]]) + ],[ + AC_MSG_RESULT([yes]) + tmp_thread_safe_initially_defined="yes" + ],[ + AC_MSG_RESULT([no]) + tmp_thread_safe_initially_defined="no" + ]) + # + if test "$tmp_thread_safe_initially_defined" = "no"; then + AC_MSG_CHECKING([if _THREAD_SAFE is actually needed]) + CURL_CHECK_NEED_THREAD_SAFE_SYSTEM + if test "$tmp_need_thread_safe" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + # + AC_MSG_CHECKING([if _THREAD_SAFE is onwards defined]) + if test "$tmp_thread_safe_initially_defined" = "yes" || + test "$tmp_need_thread_safe" = "yes"; then + CURL_CONFIGURE_FROM_NOW_ON_WITH_THREAD_SAFE + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + # +]) diff --git a/m4/curl-rustls.m4 b/m4/curl-rustls.m4 new file mode 100644 index 0000000..75542e4 --- /dev/null +++ b/m4/curl-rustls.m4 @@ -0,0 +1,111 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +AC_DEFUN([CURL_WITH_RUSTLS], [ +dnl ---------------------------------------------------- +dnl check for rustls +dnl ---------------------------------------------------- + +if test "x$OPT_RUSTLS" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + ssl_msg= + + if test X"$OPT_RUSTLS" != Xno; then + + if test "$OPT_RUSTLS" = "yes"; then + OPT_RUSTLS="" + fi + + case $host_os in + darwin*) + LDFLAGS="$LDFLAGS -framework Security" + ;; + *) + ;; + esac + + if test -z "$OPT_RUSTLS" ; then + dnl check for lib first without setting any new path + + AC_CHECK_LIB(rustls, rustls_client_session_read, + dnl librustls found, set the variable + [ + AC_DEFINE(USE_RUSTLS, 1, [if rustls is enabled]) + AC_SUBST(USE_RUSTLS, [1]) + RUSTLS_ENABLED=1 + USE_RUSTLS="yes" + ssl_msg="rustls" + test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], [], -lpthread -ldl -lm) + fi + + if test "x$USE_RUSTLS" != "xyes"; then + dnl add the path and test again + addld=-L$OPT_RUSTLS/lib$libsuff + addcflags=-I$OPT_RUSTLS/include + rustlslib=$OPT_RUSTLS/lib$libsuff + + LDFLAGS="$LDFLAGS $addld" + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + fi + + AC_CHECK_LIB(rustls, rustls_connection_read, + [ + AC_DEFINE(USE_RUSTLS, 1, [if rustls is enabled]) + AC_SUBST(USE_RUSTLS, [1]) + RUSTLS_ENABLED=1 + USE_RUSTLS="yes" + ssl_msg="rustls" + test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], + AC_MSG_ERROR([--with-rustls was specified but could not find rustls.]), + -lpthread -ldl -lm) + fi + + if test "x$USE_RUSTLS" = "xyes"; then + AC_MSG_NOTICE([detected rustls]) + check_for_ca_bundle=1 + + LIBS="-lrustls -lpthread -ldl -lm $LIBS" + + if test -n "$rustlslib"; then + dnl when shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to + dnl CURL_LIBRARY_PATH to prevent further configure tests to fail + dnl due to this + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$rustlslib" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $rustlslib to CURL_LIBRARY_PATH]) + fi + fi + fi + + fi dnl rustls not disabled + + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi +]) diff --git a/m4/curl-schannel.m4 b/m4/curl-schannel.m4 new file mode 100644 index 0000000..016bfd4 --- /dev/null +++ b/m4/curl-schannel.m4 @@ -0,0 +1,48 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +AC_DEFUN([CURL_WITH_SCHANNEL], [ +AC_MSG_CHECKING([whether to enable Windows native SSL/TLS]) +if test "x$OPT_SCHANNEL" != xno; then + ssl_msg= + if test "x$OPT_SCHANNEL" != "xno" && + test "x$curl_cv_native_windows" = "xyes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_SCHANNEL, 1, [to enable Windows native SSL/TLS support]) + AC_SUBST(USE_SCHANNEL, [1]) + ssl_msg="Schannel" + test schannel != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + SCHANNEL_ENABLED=1 + # --with-schannel implies --enable-sspi + AC_DEFINE(USE_WINDOWS_SSPI, 1, [to enable SSPI support]) + AC_SUBST(USE_WINDOWS_SSPI, [1]) + curl_sspi_msg="enabled" + else + AC_MSG_RESULT(no) + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +else + AC_MSG_RESULT(no) +fi +]) diff --git a/m4/curl-sectransp.m4 b/m4/curl-sectransp.m4 new file mode 100644 index 0000000..77b37be --- /dev/null +++ b/m4/curl-sectransp.m4 @@ -0,0 +1,45 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +AC_DEFUN([CURL_WITH_SECURETRANSPORT], [ +AC_MSG_CHECKING([whether to enable Secure Transport]) +if test "x$OPT_SECURETRANSPORT" != xno; then + if test "x$OPT_SECURETRANSPORT" != "xno" && + (test "x$cross_compiling" != "xno" || test -d "/System/Library/Frameworks/Security.framework"); then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_SECTRANSP, 1, [enable Secure Transport]) + AC_SUBST(USE_SECTRANSP, [1]) + ssl_msg="Secure Transport" + test secure-transport != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + SECURETRANSPORT_ENABLED=1 + LDFLAGS="$LDFLAGS -framework CoreFoundation -framework CoreServices -framework Security" + else + AC_MSG_RESULT(no) + fi + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +else + AC_MSG_RESULT(no) +fi + +]) diff --git a/m4/curl-sysconfig.m4 b/m4/curl-sysconfig.m4 new file mode 100644 index 0000000..9b287bc --- /dev/null +++ b/m4/curl-sysconfig.m4 @@ -0,0 +1,54 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +AC_DEFUN([CURL_DARWIN_SYSTEMCONFIGURATION], [ +AC_MSG_CHECKING([whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks]) +case $host_os in + darwin*) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]],[[ +#if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) + return 0; +#else +#error Not macOS +#endif + ]]) + ],[ + build_for_macos="yes" + ],[ + build_for_macos="no" + ]) + if test "x$build_for_macos" != xno; then + AC_MSG_RESULT(yes) + LDFLAGS="$LDFLAGS -framework CoreFoundation -framework CoreServices -framework SystemConfiguration" + else + AC_MSG_RESULT(no) + fi + ;; + *) + AC_MSG_RESULT(no) +esac +]) diff --git a/m4/curl-wolfssl.m4 b/m4/curl-wolfssl.m4 new file mode 100644 index 0000000..1da47a9 --- /dev/null +++ b/m4/curl-wolfssl.m4 @@ -0,0 +1,176 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +AC_DEFUN([CURL_WITH_WOLFSSL], [ +dnl ---------------------------------------------------- +dnl check for wolfSSL +dnl ---------------------------------------------------- + +case "$OPT_WOLFSSL" in + yes|no) + wolfpkg="" + ;; + *) + wolfpkg="$withval/lib/pkgconfig" + ;; +esac + +if test "x$OPT_WOLFSSL" != xno; then + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + + ssl_msg= + + if test X"$OPT_WOLFSSL" != Xno; then + + if test "$OPT_WOLFSSL" = "yes"; then + OPT_WOLFSSL="" + fi + + dnl try pkg-config magic + CURL_CHECK_PKGCONFIG(wolfssl, [$wolfpkg]) + AC_MSG_NOTICE([Check dir $wolfpkg]) + + addld="" + addlib="" + addcflags="" + if test "$PKGCONFIG" != "no" ; then + addlib=`CURL_EXPORT_PCDIR([$wolfpkg]) + $PKGCONFIG --libs-only-l wolfssl` + addld=`CURL_EXPORT_PCDIR([$wolfpkg]) + $PKGCONFIG --libs-only-L wolfssl` + addcflags=`CURL_EXPORT_PCDIR([$wolfpkg]) + $PKGCONFIG --cflags-only-I wolfssl` + version=`CURL_EXPORT_PCDIR([$wolfpkg]) + $PKGCONFIG --modversion wolfssl` + wolfssllibpath=`echo $addld | $SED -e 's/^-L//'` + else + addlib=-lwolfssl + dnl use system defaults if user does not supply a path + if test -n "$OPT_WOLFSSL"; then + addld=-L$OPT_WOLFSSL/lib$libsuff + addcflags=-I$OPT_WOLFSSL/include + wolfssllibpath=$OPT_WOLFSSL/lib$libsuff + fi + fi + + if test "x$USE_WOLFSSL" != "xyes"; then + + LDFLAGS="$LDFLAGS $addld" + AC_MSG_NOTICE([Add $addld to LDFLAGS]) + if test "$addcflags" != "-I/usr/include"; then + CPPFLAGS="$CPPFLAGS $addcflags" + AC_MSG_NOTICE([Add $addcflags to CPPFLAGS]) + fi + + my_ac_save_LIBS="$LIBS" + LIBS="$addlib $LIBS" + AC_MSG_NOTICE([Add $addlib to LIBS]) + + AC_MSG_CHECKING([for wolfSSL_Init in -lwolfssl]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +/* These aren't needed for detection and confuse WolfSSL. + They are set up properly later if it is detected. */ +#undef SIZEOF_LONG +#undef SIZEOF_LONG_LONG +#include +#include + ]],[[ + return wolfSSL_Init(); + ]]) + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(USE_WOLFSSL, 1, [if wolfSSL is enabled]) + AC_SUBST(USE_WOLFSSL, [1]) + WOLFSSL_ENABLED=1 + USE_WOLFSSL="yes" + ssl_msg="WolfSSL" + QUIC_ENABLED=yes + test wolfssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes + ], + [ + AC_MSG_RESULT(no) + CPPFLAGS=$_cppflags + LDFLAGS=$_ldflags + wolfssllibpath="" + ]) + LIBS="$my_ac_save_LIBS" + fi + + if test "x$USE_WOLFSSL" = "xyes"; then + AC_MSG_NOTICE([detected wolfSSL]) + check_for_ca_bundle=1 + + dnl wolfssl/ctaocrypt/types.h needs SIZEOF_LONG_LONG defined! + CURL_SIZEOF(long long) + + LIBS="$addlib -lm $LIBS" + + dnl WolfSSL needs configure --enable-opensslextra to have *get_peer* + dnl DES* is needed for NTLM support and lives in the OpenSSL compatibility + dnl layer + AC_CHECK_FUNCS(wolfSSL_get_peer_certificate \ + wolfSSL_UseALPN ) + + dnl if this symbol is present, we want the include path to include the + dnl OpenSSL API root as well + AC_CHECK_FUNC(wolfSSL_DES_ecb_encrypt, + [ + AC_DEFINE(HAVE_WOLFSSL_DES_ECB_ENCRYPT, 1, + [if you have wolfSSL_DES_ecb_encrypt]) + WOLFSSL_NTLM=1 + ] + ) + + dnl if this symbol is present, we can make use of BIO filter chains + AC_CHECK_FUNC(wolfSSL_BIO_set_shutdown, + [ + AC_DEFINE(HAVE_WOLFSSL_FULL_BIO, 1, + [if you have wolfSSL_BIO_set_shutdown]) + WOLFSSL_FULL_BIO=1 + ] + ) + + if test -n "$wolfssllibpath"; then + dnl when shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to + dnl CURL_LIBRARY_PATH to prevent further configure tests to fail + dnl due to this + if test "x$cross_compiling" != "xyes"; then + CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$wolfssllibpath" + export CURL_LIBRARY_PATH + AC_MSG_NOTICE([Added $wolfssllibpath to CURL_LIBRARY_PATH]) + fi + fi + else + AC_MSG_ERROR([--with-wolfssl but wolfSSL was not found or doesn't work]) + fi + + fi dnl wolfSSL not disabled + + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" +fi + +]) diff --git a/m4/libtool.m4 b/m4/libtool.m4 new file mode 100644 index 0000000..e7b6833 --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,8427 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996-2001, 2003-2019, 2021-2022 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +]) + +# serial 59 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_PREPARE_CC_BASENAME +# ----------------------- +m4_defun([_LT_PREPARE_CC_BASENAME], [ +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in @S|@*""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} +])# _LT_PREPARE_CC_BASENAME + + +# _LT_CC_BASENAME(CC) +# ------------------- +# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, +# but that macro is also expanded into generated libtool script, which +# arranges for $SED and $ECHO to be set by different means. +m4_defun([_LT_CC_BASENAME], +[m4_require([_LT_PREPARE_CC_BASENAME])dnl +AC_REQUIRE([_LT_DECL_SED])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl +func_cc_basename $1 +cc_basename=$func_cc_basename_result +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_DECL_FILECMD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl +m4_require([_LT_CMD_TRUNCATE])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC and +# ICC, which need '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from 'configure', and 'config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# 'config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain=$ac_aux_dir/ltmain.sh +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the 'libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to 'config.status' so that its +# declaration there will have the same value as in 'configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags='_LT_TAGS'dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into 'config.status', and then the shell code to quote escape them in +# for loops in 'config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# '#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test 0 = "$lt_write_fail" && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +'$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test 0 != $[#] +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try '$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try '$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test yes = "$silent" && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +_LT_COPYING +_LT_LIBTOOL_TAGS + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +_LT_PREPARE_MUNGE_PATH_LIST +_LT_PREPARE_CC_BASENAME + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + $SED '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS=$save_LDFLAGS + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR $AR_FLAGS libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR $AR_FLAGS libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) + case $MACOSX_DEPLOYMENT_TARGET,$host in + 10.[[012]],*|,*powerpc*-darwin[[5-8]]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + *) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test yes = "$lt_cv_ld_force_load"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + _LT_TAGVAR(module_expsym_cmds, $1)="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + m4_if([$1], [CXX], +[ if test yes != "$lt_cv_apple_cc_single_mod"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script that will find a shell with a builtin +# printf (that we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case $ECHO in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], + [Search for dependent libraries within DIR (or the compiler's sysroot + if not specified).])], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([$with_sysroot]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and where our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `$FILECMD conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + emul=elf + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `$FILECMD conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `$FILECMD conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `$FILECMD conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +_LT_DECL([], [AR], [1], [The archiver]) + +# Use ARFLAGS variable as AR's operation code to sync the variable naming with +# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have +# higher priority because thats what people were doing historically (setting +# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS +# variable obsoleted/removed. + +test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} +lt_ar_flags=$AR_FLAGS +_LT_DECL([], [lt_ar_flags], [0], [Flags to create an archive (by configure)]) + +# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override +# by AR_FLAGS because that was never working and AR_FLAGS is about to die. +_LT_DECL([], [AR_FLAGS], [\@S|@{ARFLAGS-"\@S|@lt_ar_flags"}], + [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test yes = "[$]$2"; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS +]) + +if test yes = "[$]$2"; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n "$lt_cv_sys_max_cmd_len"; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes = "$cross_compiling"; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen=shl_load], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen=dlopen], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links=nottested +if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test no = "$hard_links"; then + AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", + [Define to the sub-directory where libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then + + # We can hardcode non-existent directories. + if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && + test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || + test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -z "$STRIP"; then + AC_MSG_RESULT([no]) +else + if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) + else + case $host_os in + darwin*) + # FIXME - insert some real tests, host_os isn't really good enough + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + ;; + freebsd*) + if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac + fi +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_PREPARE_MUNGE_PATH_LIST +# --------------------------- +# Make sure func_munge_path_list() is defined correctly. +m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], +[[# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x@S|@2 in + x) + ;; + *:) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" + ;; + x:*) + eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" + ;; + *) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + esac +} +]])# _LT_PREPARE_PATH_LIST + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +AC_ARG_VAR([LT_SYS_LIBRARY_PATH], +[User-defined run-time library search path.]) + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a[(]lib.so.V[)]' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl* | *,icl*) + # Native MSVC or ICC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC and ICC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly* | midnightbsd*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], + [Detected run-time system search path for libraries]) +_LT_DECL([], [configure_time_lt_sys_library_path], [2], + [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program that can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$1"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac]) +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program that can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test no = "$withval" || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], +[if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi]) +rm -f conftest.i conftest2.i conftest.out]) +])# _LT_PATH_DD + + +# _LT_CMD_TRUNCATE +# ---------------- +# find command to truncate a binary pipe +m4_defun([_LT_CMD_TRUNCATE], +[m4_require([_LT_PATH_DD]) +AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], +[printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) +_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], + [Command to truncate a binary pipe]) +])# _LT_CMD_TRUNCATE + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +AC_CACHE_CHECK([how to recognize dependent libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[[4-9]]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[[45]]*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='$FILECMD -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly* | midnightbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=$FILECMD + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=$FILECMD + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=$FILECMD + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi]) +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# _LT_DLL_DEF_P([FILE]) +# --------------------- +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with func_dll_def_p in the libtool script +AC_DEFUN([_LT_DLL_DEF_P], +[dnl + test DEF = "`$SED -n dnl + -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace + -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments + -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl + -e q dnl Only consider the first "real" line + $1`" dnl +])# _LT_DLL_DEF_P + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM=-lm) + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++ or ICC, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD + if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], + [Transform the output of nm into a list of symbols to manually relocate]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([nm_interface], [lt_cv_nm_interface], [1], + [The name lister interface]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly* | midnightbsd*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64, which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test yes = "$GCC"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # flang / f18. f95 an alias for gfortran or flang on Debian + flang* | f18* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl* | icl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/([[^)]]\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl* | icl*) + # Native MSVC or ICC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC and ICC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly* | midnightbsd*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS=$save_LDFLAGS]) + if test yes = "$lt_cv_irix_exported_symbol"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(ld_shlibs, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + ;; + + osf3*) + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting $shlibpath_var if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC=$CC +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report what library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC=$lt_save_CC +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_caught_CXX_error"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test yes = "$GXX"; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test yes = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='$wl' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GXX"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl* | ,icl* | no,icl*) + # Native MSVC or ICC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly* | midnightbsd*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + + _LT_TAGVAR(GCC, $1)=$GXX + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test yes != "$_lt_caught_CXX_error" + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case @S|@2 in + .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; + *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)=$prev$p + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test no = "$pre_test_object_deps_done"; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)=$p + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)=$p + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test no = "$F77"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_F77"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$G77 + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_F77" + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test no = "$FC"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_FC"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_FC" + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code=$lt_simple_compile_test_code + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_FILECMD +# ---------------- +# Check for a file(cmd) program that can be used to detect file type and magic +m4_defun([_LT_DECL_FILECMD], +[AC_CHECK_TOOL([FILECMD], [file], [:]) +_LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types]) +])# _LD_DECL_FILECMD + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f "$lt_ac_sed" && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test 10 -lt "$lt_ac_count" && break + lt_ac_count=`expr $lt_ac_count + 1` + if test "$lt_ac_count" -gt "$lt_ac_max"; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine what file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 0000000..b0b5e9c --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,437 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free +# Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 8 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option '$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl 'shared' nor 'disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], + [_LT_WITH_AIX_SONAME([aix])]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the 'shared' and +# 'disable-shared' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the 'static' and +# 'disable-static' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the 'fast-install' +# and 'disable-fast-install' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_AIX_SONAME([DEFAULT]) +# ---------------------------------- +# implement the --with-aix-soname flag, and support the `aix-soname=aix' +# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT +# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. +m4_define([_LT_WITH_AIX_SONAME], +[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl +shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[[5-9]]*,yes) + AC_MSG_CHECKING([which variant of shared library versioning to provide]) + AC_ARG_WITH([aix-soname], + [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], + [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], + [case $withval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --with-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname], + [AC_CACHE_VAL([lt_cv_with_aix_soname], + [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) + with_aix_soname=$lt_cv_with_aix_soname]) + AC_MSG_RESULT([$with_aix_soname]) + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + +_LT_DECL([], [shared_archive_member_spec], [0], + [Shared archive member basename, for filename based shared library versioning on AIX])dnl +])# _LT_WITH_AIX_SONAME + +LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the 'pic-only' and 'no-pic' +# LT_INIT options. +# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [pic_mode=m4_default([$1], [default])]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 new file mode 100644 index 0000000..902508b --- /dev/null +++ b/m4/ltsugar.m4 @@ -0,0 +1,124 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59, which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 new file mode 100644 index 0000000..b155d0a --- /dev/null +++ b/m4/ltversion.m4 @@ -0,0 +1,24 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation, +# Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 4245 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.7]) +m4_define([LT_PACKAGE_REVISION], [2.4.7]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.7' +macro_revision='2.4.7' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 new file mode 100644 index 0000000..0f7a875 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,99 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free +# Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/m4/xc-am-iface.m4 b/m4/xc-am-iface.m4 new file mode 100644 index 0000000..c035f58 --- /dev/null +++ b/m4/xc-am-iface.m4 @@ -0,0 +1,85 @@ +#--------------------------------------------------------------------------- +# +# xc-am-iface.m4 +# +# Copyright (C) Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +# serial 1 + + +dnl _XC_AUTOMAKE_BODY +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl This macro performs embedding of automake initialization +dnl code into configure script. When automake version 1.14 or +dnl newer is used at configure script generation time, this +dnl results in 'subdir-objects' automake option being used. +dnl When using automake versions older than 1.14 this option +dnl is not used when generating configure script. +dnl +dnl Existence of automake _AM_PROG_CC_C_O m4 private macro +dnl is used to differentiate automake version 1.14 from older +dnl ones which lack this macro. + +m4_define([_XC_AUTOMAKE_BODY], +[dnl +## --------------------------------------- ## +## Start of automake initialization code ## +## --------------------------------------- ## +m4_ifdef([_AM_PROG_CC_C_O], +[ +AM_INIT_AUTOMAKE([subdir-objects]) +],[ +AM_INIT_AUTOMAKE +])dnl +## ------------------------------------- ## +## End of automake initialization code ## +## ------------------------------------- ## +dnl +m4_define([$0], [])[]dnl +]) + + +dnl XC_AUTOMAKE +dnl ------------------------------------------------- +dnl Public macro. +dnl +dnl This macro embeds automake machinery into configure +dnl script regardless of automake version used in order +dnl to generate configure script. +dnl +dnl When using automake version 1.14 or newer, automake +dnl initialization option 'subdir-objects' is used to +dnl generate the configure script, otherwise this option +dnl is not used. + +AC_DEFUN([XC_AUTOMAKE], +[dnl +AC_PREREQ([2.50])dnl +dnl +AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl +dnl +_XC_AUTOMAKE_BODY +dnl +m4_ifdef([AM_INIT_AUTOMAKE], + [m4_undefine([AM_INIT_AUTOMAKE])])dnl +dnl +m4_define([$0], [])[]dnl +]) diff --git a/m4/xc-cc-check.m4 b/m4/xc-cc-check.m4 new file mode 100644 index 0000000..a6cfb07 --- /dev/null +++ b/m4/xc-cc-check.m4 @@ -0,0 +1,97 @@ +#--------------------------------------------------------------------------- +# +# xc-cc-check.m4 +# +# Copyright (C), Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +# serial 1 + + +dnl _XC_PROG_CC_PREAMBLE +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_PROG_CC_PREAMBLE], [ + xc_prog_cc_prev_IFS=$IFS + xc_prog_cc_prev_LIBS=$LIBS + xc_prog_cc_prev_CFLAGS=$CFLAGS + xc_prog_cc_prev_LDFLAGS=$LDFLAGS + xc_prog_cc_prev_CPPFLAGS=$CPPFLAGS +]) + + +dnl _XC_PROG_CC_POSTLUDE +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_PROG_CC_POSTLUDE], [ + IFS=$xc_prog_cc_prev_IFS + LIBS=$xc_prog_cc_prev_LIBS + CFLAGS=$xc_prog_cc_prev_CFLAGS + LDFLAGS=$xc_prog_cc_prev_LDFLAGS + CPPFLAGS=$xc_prog_cc_prev_CPPFLAGS + AC_SUBST([CC])dnl + AC_SUBST([CPP])dnl + AC_SUBST([LIBS])dnl + AC_SUBST([CFLAGS])dnl + AC_SUBST([LDFLAGS])dnl + AC_SUBST([CPPFLAGS])dnl +]) + + +dnl _XC_PROG_CC +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_PROG_CC], [ + AC_REQUIRE([_XC_PROG_CC_PREAMBLE])dnl + AC_REQUIRE([XC_CHECK_BUILD_FLAGS])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AM_PROG_CC_C_O])dnl + AC_REQUIRE([AC_PROG_CPP])dnl + AC_REQUIRE([_XC_PROG_CC_POSTLUDE])dnl +]) + + +dnl XC_CHECK_PROG_CC +dnl ------------------------------------------------- +dnl Public macro. +dnl +dnl Checks for C compiler and C preprocessor programs, +dnl while doing some previous sanity validation on user +dnl provided LIBS, LDFLAGS, CPPFLAGS and CFLAGS values +dnl that must succeed in order to continue execution. +dnl +dnl This sets variables CC and CPP, while preventing +dnl LIBS, LDFLAGS, CFLAGS, CPPFLAGS and IFS from being +dnl unexpectedly changed by underlying macros. + +AC_DEFUN([XC_CHECK_PROG_CC], [ + AC_PREREQ([2.50])dnl + AC_BEFORE([$0],[_XC_PROG_CC_PREAMBLE])dnl + AC_BEFORE([$0],[AC_PROG_INSTALL])dnl + AC_BEFORE([$0],[AC_PROG_CC])dnl + AC_BEFORE([$0],[AM_PROG_CC_C_O])dnl + AC_BEFORE([$0],[AC_PROG_CPP])dnl + AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl + AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl + AC_BEFORE([$0],[_XC_PROG_CC_POSTLUDE])dnl + AC_REQUIRE([_XC_PROG_CC])dnl +]) diff --git a/m4/xc-lt-iface.m4 b/m4/xc-lt-iface.m4 new file mode 100644 index 0000000..d5e437f --- /dev/null +++ b/m4/xc-lt-iface.m4 @@ -0,0 +1,466 @@ +#--------------------------------------------------------------------------- +# +# xc-lt-iface.m4 +# +# Copyright (C), Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +# serial 1 + + +dnl _XC_LIBTOOL_PREAMBLE +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Checks some configure script options related with +dnl libtool and customizes its default behavior before +dnl libtool code is actually used in script. + +m4_define([_XC_LIBTOOL_PREAMBLE], +[dnl +# ------------------------------------ # +# Determine libtool default behavior # +# ------------------------------------ # + +# +# Default behavior is to enable shared and static libraries on systems +# where libtool knows how to build both library versions, and does not +# require separate configuration and build runs for each flavor. +# + +xc_lt_want_enable_shared='yes' +xc_lt_want_enable_static='yes' + +# +# User may have disabled shared or static libraries. +# +case "x$enable_shared" in @%:@ ( + xno) + xc_lt_want_enable_shared='no' + ;; +esac +case "x$enable_static" in @%:@ ( + xno) + xc_lt_want_enable_static='no' + ;; +esac +if test "x$xc_lt_want_enable_shared" = 'xno' && + test "x$xc_lt_want_enable_static" = 'xno'; then + AC_MSG_ERROR([can not disable shared and static libraries simultaneously]) +fi + +# +# Default behavior on systems that require independent configuration +# and build runs for shared and static is to enable shared libraries +# and disable static ones. On these systems option '--disable-shared' +# must be used in order to build a proper static library. +# + +if test "x$xc_lt_want_enable_shared" = 'xyes' && + test "x$xc_lt_want_enable_static" = 'xyes'; then + case $host_os in @%:@ ( + pw32* | cegcc* | os2* | aix*) + xc_lt_want_enable_static='no' + ;; + esac +fi + +# +# Make libtool aware of current shared and static library preferences +# taking in account that, depending on host characteristics, libtool +# may modify these option preferences later in this configure script. +# + +enable_shared=$xc_lt_want_enable_shared +enable_static=$xc_lt_want_enable_static + +# +# Default behavior is to build PIC objects for shared libraries and +# non-PIC objects for static libraries. +# + +xc_lt_want_with_pic='default' + +# +# User may have specified PIC preference. +# + +case "x$with_pic" in @%:@ (( + xno) + xc_lt_want_with_pic='no' + ;; + xyes) + xc_lt_want_with_pic='yes' + ;; +esac + +# +# Default behavior on some systems where building a shared library out +# of non-PIC compiled objects will fail with following linker error +# "relocation R_X86_64_32 can not be used when making a shared object" +# is to build PIC objects even for static libraries. This behavior may +# be overridden using 'configure --disable-shared --without-pic'. +# + +if test "x$xc_lt_want_with_pic" = 'xdefault'; then + case $host_cpu in @%:@ ( + x86_64 | amd64 | ia64) + case $host_os in @%:@ ( + linux* | freebsd* | midnightbsd*) + xc_lt_want_with_pic='yes' + ;; + esac + ;; + esac +fi + +# +# Make libtool aware of current PIC preference taking in account that, +# depending on host characteristics, libtool may modify PIC default +# behavior to fit host system idiosyncrasies later in this script. +# + +with_pic=$xc_lt_want_with_pic +dnl +m4_define([$0],[])dnl +]) + + +dnl _XC_LIBTOOL_BODY +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl This macro performs embedding of libtool code into +dnl configure script, regardless of libtool version in +dnl use when generating configure script. + +m4_define([_XC_LIBTOOL_BODY], +[dnl +## ----------------------- ## +## Start of libtool code ## +## ----------------------- ## +m4_ifdef([LT_INIT], +[dnl +LT_INIT([win32-dll]) +],[dnl +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL +])dnl +## --------------------- ## +## End of libtool code ## +## --------------------- ## +dnl +m4_define([$0], [])[]dnl +]) + + +dnl _XC_CHECK_LT_BUILD_LIBRARIES +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Checks whether libtool shared and static libraries +dnl are finally built depending on user input, default +dnl behavior and knowledge that libtool has about host +dnl characteristics. +dnl Results stored in following shell variables: +dnl xc_lt_build_shared +dnl xc_lt_build_static + +m4_define([_XC_CHECK_LT_BUILD_LIBRARIES], +[dnl +# +# Verify if finally libtool shared libraries will be built +# + +case "x$enable_shared" in @%:@ (( + xyes | xno) + xc_lt_build_shared=$enable_shared + ;; + *) + AC_MSG_ERROR([unexpected libtool enable_shared value: $enable_shared]) + ;; +esac + +# +# Verify if finally libtool static libraries will be built +# + +case "x$enable_static" in @%:@ (( + xyes | xno) + xc_lt_build_static=$enable_static + ;; + *) + AC_MSG_ERROR([unexpected libtool enable_static value: $enable_static]) + ;; +esac +dnl +m4_define([$0],[])dnl +]) + + +dnl _XC_CHECK_LT_SHLIB_USE_VERSION_INFO +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Checks if the -version-info linker flag must be +dnl provided when building libtool shared libraries. +dnl Result stored in xc_lt_shlib_use_version_info. + +m4_define([_XC_CHECK_LT_SHLIB_USE_VERSION_INFO], +[dnl +# +# Verify if libtool shared libraries should be linked using flag -version-info +# + +AC_MSG_CHECKING([whether to build shared libraries with -version-info]) +xc_lt_shlib_use_version_info='yes' +if test "x$version_type" = 'xnone'; then + xc_lt_shlib_use_version_info='no' +fi +case $host_os in @%:@ ( + amigaos*) + xc_lt_shlib_use_version_info='yes' + ;; +esac +AC_MSG_RESULT([$xc_lt_shlib_use_version_info]) +dnl +m4_define([$0], [])[]dnl +]) + + +dnl _XC_CHECK_LT_SHLIB_USE_NO_UNDEFINED +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Checks if the -no-undefined linker flag must be +dnl provided when building libtool shared libraries. +dnl Result stored in xc_lt_shlib_use_no_undefined. + +m4_define([_XC_CHECK_LT_SHLIB_USE_NO_UNDEFINED], +[dnl +# +# Verify if libtool shared libraries should be linked using flag -no-undefined +# + +AC_MSG_CHECKING([whether to build shared libraries with -no-undefined]) +xc_lt_shlib_use_no_undefined='no' +if test "x$allow_undefined" = 'xno'; then + xc_lt_shlib_use_no_undefined='yes' +elif test "x$allow_undefined_flag" = 'xunsupported'; then + xc_lt_shlib_use_no_undefined='yes' +fi +case $host_os in @%:@ ( + cygwin* | mingw* | pw32* | cegcc* | os2* | aix*) + xc_lt_shlib_use_no_undefined='yes' + ;; +esac +AC_MSG_RESULT([$xc_lt_shlib_use_no_undefined]) +dnl +m4_define([$0], [])[]dnl +]) + + +dnl _XC_CHECK_LT_SHLIB_USE_MIMPURE_TEXT +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Checks if the -mimpure-text linker flag must be +dnl provided when building libtool shared libraries. +dnl Result stored in xc_lt_shlib_use_mimpure_text. + +m4_define([_XC_CHECK_LT_SHLIB_USE_MIMPURE_TEXT], +[dnl +# +# Verify if libtool shared libraries should be linked using flag -mimpure-text +# + +AC_MSG_CHECKING([whether to build shared libraries with -mimpure-text]) +xc_lt_shlib_use_mimpure_text='no' +case $host_os in @%:@ ( + solaris2*) + if test "x$GCC" = 'xyes'; then + xc_lt_shlib_use_mimpure_text='yes' + fi + ;; +esac +AC_MSG_RESULT([$xc_lt_shlib_use_mimpure_text]) +dnl +m4_define([$0], [])[]dnl +]) + + +dnl _XC_CHECK_LT_BUILD_WITH_PIC +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Checks whether libtool shared and static libraries +dnl would be built with PIC depending on user input, +dnl default behavior and knowledge that libtool has +dnl about host characteristics. +dnl Results stored in following shell variables: +dnl xc_lt_build_shared_with_pic +dnl xc_lt_build_static_with_pic + +m4_define([_XC_CHECK_LT_BUILD_WITH_PIC], +[dnl +# +# Find out whether libtool libraries would be built with PIC +# + +case "x$pic_mode" in @%:@ (((( + xdefault) + xc_lt_build_shared_with_pic='yes' + xc_lt_build_static_with_pic='no' + ;; + xyes) + xc_lt_build_shared_with_pic='yes' + xc_lt_build_static_with_pic='yes' + ;; + xno) + xc_lt_build_shared_with_pic='no' + xc_lt_build_static_with_pic='no' + ;; + *) + xc_lt_build_shared_with_pic='unknown' + xc_lt_build_static_with_pic='unknown' + AC_MSG_WARN([unexpected libtool pic_mode value: $pic_mode]) + ;; +esac +AC_MSG_CHECKING([whether to build shared libraries with PIC]) +AC_MSG_RESULT([$xc_lt_build_shared_with_pic]) +AC_MSG_CHECKING([whether to build static libraries with PIC]) +AC_MSG_RESULT([$xc_lt_build_static_with_pic]) +dnl +m4_define([$0],[])dnl +]) + + +dnl _XC_CHECK_LT_BUILD_SINGLE_VERSION +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Checks whether a libtool shared or static library +dnl is finally built exclusively without the other. +dnl Results stored in following shell variables: +dnl xc_lt_build_shared_only +dnl xc_lt_build_static_only + +m4_define([_XC_CHECK_LT_BUILD_SINGLE_VERSION], +[dnl +# +# Verify if libtool shared libraries will be built while static not built +# + +AC_MSG_CHECKING([whether to build shared libraries only]) +if test "$xc_lt_build_shared" = 'yes' && + test "$xc_lt_build_static" = 'no'; then + xc_lt_build_shared_only='yes' +else + xc_lt_build_shared_only='no' +fi +AC_MSG_RESULT([$xc_lt_build_shared_only]) + +# +# Verify if libtool static libraries will be built while shared not built +# + +AC_MSG_CHECKING([whether to build static libraries only]) +if test "$xc_lt_build_static" = 'yes' && + test "$xc_lt_build_shared" = 'no'; then + xc_lt_build_static_only='yes' +else + xc_lt_build_static_only='no' +fi +AC_MSG_RESULT([$xc_lt_build_static_only]) +dnl +m4_define([$0],[])dnl +]) + + +dnl _XC_LIBTOOL_POSTLUDE +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Performs several checks related with libtool that +dnl can not be done unless libtool code has already +dnl been executed. See individual check descriptions +dnl for further info. + +m4_define([_XC_LIBTOOL_POSTLUDE], +[dnl +_XC_CHECK_LT_BUILD_LIBRARIES +_XC_CHECK_LT_SHLIB_USE_VERSION_INFO +_XC_CHECK_LT_SHLIB_USE_NO_UNDEFINED +_XC_CHECK_LT_SHLIB_USE_MIMPURE_TEXT +_XC_CHECK_LT_BUILD_WITH_PIC +_XC_CHECK_LT_BUILD_SINGLE_VERSION +dnl +m4_define([$0],[])dnl +]) + + +dnl XC_LIBTOOL +dnl ------------------------------------------------- +dnl Public macro. +dnl +dnl This macro embeds libtool machinery into configure +dnl script, regardless of libtool version, and performs +dnl several additional checks whose results can be used +dnl later on. +dnl +dnl Usage of this macro ensures that generated configure +dnl script uses equivalent logic irrespective of autoconf +dnl or libtool version being used to generate configure +dnl script. +dnl +dnl Results stored in following shell variables: +dnl xc_lt_build_shared +dnl xc_lt_build_static +dnl xc_lt_shlib_use_version_info +dnl xc_lt_shlib_use_no_undefined +dnl xc_lt_shlib_use_mimpure_text +dnl xc_lt_build_shared_with_pic +dnl xc_lt_build_static_with_pic +dnl xc_lt_build_shared_only +dnl xc_lt_build_static_only + +AC_DEFUN([XC_LIBTOOL], +[dnl +AC_PREREQ([2.50])dnl +dnl +AC_BEFORE([$0],[LT_INIT])dnl +AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl +AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl +dnl +AC_REQUIRE([XC_CHECK_PATH_SEPARATOR])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +dnl +_XC_LIBTOOL_PREAMBLE +_XC_LIBTOOL_BODY +_XC_LIBTOOL_POSTLUDE +dnl +m4_ifdef([AC_LIBTOOL_WIN32_DLL], + [m4_undefine([AC_LIBTOOL_WIN32_DLL])])dnl +m4_ifdef([AC_PROG_LIBTOOL], + [m4_undefine([AC_PROG_LIBTOOL])])dnl +m4_ifdef([LT_INIT], + [m4_undefine([LT_INIT])])dnl +dnl +m4_define([$0],[])dnl +]) diff --git a/m4/xc-translit.m4 b/m4/xc-translit.m4 new file mode 100644 index 0000000..6d66771 --- /dev/null +++ b/m4/xc-translit.m4 @@ -0,0 +1,165 @@ +#--------------------------------------------------------------------------- +# +# xc-translit.m4 +# +# Copyright (C), Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +# File version for 'aclocal' use. Keep it a single number. +# serial 2 + + +dnl XC_SH_TR_SH (expression) +dnl ------------------------------------------------- +dnl Shell execution time transliteration of 'expression' +dnl argument, where all non-alfanumeric characters are +dnl converted to the underscore '_' character. +dnl Normal shell expansion and substitution takes place +dnl for given 'expression' at shell execution time before +dnl transliteration is applied to it. + +AC_DEFUN([XC_SH_TR_SH], +[`echo "$1" | sed 's/[[^a-zA-Z0-9_]]/_/g'`]) + + +dnl XC_SH_TR_SH_EX (expression, [extra]) +dnl ------------------------------------------------- +dnl Like XC_SH_TR_SH but transliterating characters +dnl given in 'extra' argument to lowercase 'p'. For +dnl example [*+], [*], and [+] are valid 'extra' args. + +AC_DEFUN([XC_SH_TR_SH_EX], +[ifelse([$2], [], + [XC_SH_TR_SH([$1])], + [`echo "$1" | sed 's/[[$2]]/p/g' | sed 's/[[^a-zA-Z0-9_]]/_/g'`])]) + + +dnl XC_M4_TR_SH (expression) +dnl ------------------------------------------------- +dnl m4 execution time transliteration of 'expression' +dnl argument, where all non-alfanumeric characters are +dnl converted to the underscore '_' character. + +AC_DEFUN([XC_M4_TR_SH], +[patsubst(XC_QPATSUBST(XC_QUOTE($1), + [[^a-zA-Z0-9_]], [_]), + [\(_\(.*\)_\)], [\2])]) + + +dnl XC_M4_TR_SH_EX (expression, [extra]) +dnl ------------------------------------------------- +dnl Like XC_M4_TR_SH but transliterating characters +dnl given in 'extra' argument to lowercase 'p'. For +dnl example [*+], [*], and [+] are valid 'extra' args. + +AC_DEFUN([XC_M4_TR_SH_EX], +[ifelse([$2], [], + [XC_M4_TR_SH([$1])], + [patsubst(XC_QPATSUBST(XC_QPATSUBST(XC_QUOTE($1), + [[$2]], + [p]), + [[^a-zA-Z0-9_]], [_]), + [\(_\(.*\)_\)], [\2])])]) + + +dnl XC_SH_TR_CPP (expression) +dnl ------------------------------------------------- +dnl Shell execution time transliteration of 'expression' +dnl argument, where all non-alfanumeric characters are +dnl converted to the underscore '_' character and alnum +dnl characters are converted to uppercase. +dnl Normal shell expansion and substitution takes place +dnl for given 'expression' at shell execution time before +dnl transliteration is applied to it. + +AC_DEFUN([XC_SH_TR_CPP], +[`echo "$1" | dnl +sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' | dnl +sed 's/[[^A-Z0-9_]]/_/g'`]) + + +dnl XC_SH_TR_CPP_EX (expression, [extra]) +dnl ------------------------------------------------- +dnl Like XC_SH_TR_CPP but transliterating characters +dnl given in 'extra' argument to uppercase 'P'. For +dnl example [*+], [*], and [+] are valid 'extra' args. + +AC_DEFUN([XC_SH_TR_CPP_EX], +[ifelse([$2], [], + [XC_SH_TR_CPP([$1])], + [`echo "$1" | dnl +sed 's/[[$2]]/P/g' | dnl +sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' | dnl +sed 's/[[^A-Z0-9_]]/_/g'`])]) + + +dnl XC_M4_TR_CPP (expression) +dnl ------------------------------------------------- +dnl m4 execution time transliteration of 'expression' +dnl argument, where all non-alfanumeric characters are +dnl converted to the underscore '_' character and alnum +dnl characters are converted to uppercase. + +AC_DEFUN([XC_M4_TR_CPP], +[patsubst(XC_QPATSUBST(XC_QTRANSLIT(XC_QUOTE($1), + [abcdefghijklmnopqrstuvwxyz], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ]), + [[^A-Z0-9_]], [_]), + [\(_\(.*\)_\)], [\2])]) + + +dnl XC_M4_TR_CPP_EX (expression, [extra]) +dnl ------------------------------------------------- +dnl Like XC_M4_TR_CPP but transliterating characters +dnl given in 'extra' argument to uppercase 'P'. For +dnl example [*+], [*], and [+] are valid 'extra' args. + +AC_DEFUN([XC_M4_TR_CPP_EX], +[ifelse([$2], [], + [XC_M4_TR_CPP([$1])], + [patsubst(XC_QPATSUBST(XC_QTRANSLIT(XC_QPATSUBST(XC_QUOTE($1), + [[$2]], + [P]), + [abcdefghijklmnopqrstuvwxyz], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ]), + [[^A-Z0-9_]], [_]), + [\(_\(.*\)_\)], [\2])])]) + + +dnl XC_QUOTE (expression) +dnl ------------------------------------------------- +dnl Expands to quoted result of 'expression' expansion. + +AC_DEFUN([XC_QUOTE], +[[$@]]) + + +dnl XC_QPATSUBST (string, regexp[, repl]) +dnl ------------------------------------------------- +dnl Expands to quoted result of 'patsubst' expansion. + +AC_DEFUN([XC_QPATSUBST], +[XC_QUOTE(patsubst([$1], [$2], [$3]))]) + + +dnl XC_QTRANSLIT (string, chars, repl) +dnl ------------------------------------------------- +dnl Expands to quoted result of 'translit' expansion. + +AC_DEFUN([XC_QTRANSLIT], +[XC_QUOTE(translit([$1], [$2], [$3]))]) diff --git a/m4/xc-val-flgs.m4 b/m4/xc-val-flgs.m4 new file mode 100644 index 0000000..c8f7796 --- /dev/null +++ b/m4/xc-val-flgs.m4 @@ -0,0 +1,244 @@ +#--------------------------------------------------------------------------- +# +# xc-val-flgs.m4 +# +# Copyright (C), Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +# serial 1 + + +dnl _XC_CHECK_VAR_LIBS +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_CHECK_VAR_LIBS], [ + xc_bad_var_libs=no + for xc_word in $LIBS; do + case "$xc_word" in + -l* | --library=*) + : + ;; + *) + xc_bad_var_libs=yes + ;; + esac + done + if test $xc_bad_var_libs = yes; then + AC_MSG_NOTICE([using LIBS: $LIBS]) + AC_MSG_NOTICE([LIBS note: LIBS should only be used to specify libraries (-lname).]) + fi +]) + + +dnl _XC_CHECK_VAR_LDFLAGS +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_CHECK_VAR_LDFLAGS], [ + xc_bad_var_ldflags=no + for xc_word in $LDFLAGS; do + case "$xc_word" in + -D*) + xc_bad_var_ldflags=yes + ;; + -U*) + xc_bad_var_ldflags=yes + ;; + -I*) + xc_bad_var_ldflags=yes + ;; + -l* | --library=*) + xc_bad_var_ldflags=yes + ;; + esac + done + if test $xc_bad_var_ldflags = yes; then + AC_MSG_NOTICE([using LDFLAGS: $LDFLAGS]) + xc_bad_var_msg="LDFLAGS note: LDFLAGS should only be used to specify linker flags, not" + for xc_word in $LDFLAGS; do + case "$xc_word" in + -D*) + AC_MSG_NOTICE([$xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word]) + ;; + -U*) + AC_MSG_NOTICE([$xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word]) + ;; + -I*) + AC_MSG_NOTICE([$xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word]) + ;; + -l* | --library=*) + AC_MSG_NOTICE([$xc_bad_var_msg libraries. Use LIBS for: $xc_word]) + ;; + esac + done + fi +]) + + +dnl _XC_CHECK_VAR_CPPFLAGS +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_CHECK_VAR_CPPFLAGS], [ + xc_bad_var_cppflags=no + for xc_word in $CPPFLAGS; do + case "$xc_word" in + -rpath*) + xc_bad_var_cppflags=yes + ;; + -L* | --library-path=*) + xc_bad_var_cppflags=yes + ;; + -l* | --library=*) + xc_bad_var_cppflags=yes + ;; + esac + done + if test $xc_bad_var_cppflags = yes; then + AC_MSG_NOTICE([using CPPFLAGS: $CPPFLAGS]) + xc_bad_var_msg="CPPFLAGS note: CPPFLAGS should only be used to specify C preprocessor flags, not" + for xc_word in $CPPFLAGS; do + case "$xc_word" in + -rpath*) + AC_MSG_NOTICE([$xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word]) + ;; + -L* | --library-path=*) + AC_MSG_NOTICE([$xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word]) + ;; + -l* | --library=*) + AC_MSG_NOTICE([$xc_bad_var_msg libraries. Use LIBS for: $xc_word]) + ;; + esac + done + fi +]) + + +dnl _XC_CHECK_VAR_CFLAGS +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_CHECK_VAR_CFLAGS], [ + xc_bad_var_cflags=no + for xc_word in $CFLAGS; do + case "$xc_word" in + -D*) + xc_bad_var_cflags=yes + ;; + -U*) + xc_bad_var_cflags=yes + ;; + -I*) + xc_bad_var_cflags=yes + ;; + -rpath*) + xc_bad_var_cflags=yes + ;; + -L* | --library-path=*) + xc_bad_var_cflags=yes + ;; + -l* | --library=*) + xc_bad_var_cflags=yes + ;; + esac + done + if test $xc_bad_var_cflags = yes; then + AC_MSG_NOTICE([using CFLAGS: $CFLAGS]) + xc_bad_var_msg="CFLAGS note: CFLAGS should only be used to specify C compiler flags, not" + for xc_word in $CFLAGS; do + case "$xc_word" in + -D*) + AC_MSG_NOTICE([$xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word]) + ;; + -U*) + AC_MSG_NOTICE([$xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word]) + ;; + -I*) + AC_MSG_NOTICE([$xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word]) + ;; + -rpath*) + AC_MSG_NOTICE([$xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word]) + ;; + -L* | --library-path=*) + AC_MSG_NOTICE([$xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word]) + ;; + -l* | --library=*) + AC_MSG_NOTICE([$xc_bad_var_msg libraries. Use LIBS for: $xc_word]) + ;; + esac + done + fi +]) + + +dnl XC_CHECK_USER_FLAGS +dnl ------------------------------------------------- +dnl Public macro. +dnl +dnl Performs some sanity checks for LIBS, LDFLAGS, +dnl CPPFLAGS and CFLAGS values that the user might +dnl have set. When checks fails, user is noticed +dnl about errors detected in all of them and script +dnl execution is halted. +dnl +dnl Intended to be used early in configure script. + +AC_DEFUN([XC_CHECK_USER_FLAGS], [ + AC_PREREQ([2.50])dnl + AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl + dnl check order below matters + _XC_CHECK_VAR_LIBS + _XC_CHECK_VAR_LDFLAGS + _XC_CHECK_VAR_CPPFLAGS + _XC_CHECK_VAR_CFLAGS + if test $xc_bad_var_libs = yes || + test $xc_bad_var_cflags = yes || + test $xc_bad_var_ldflags = yes || + test $xc_bad_var_cppflags = yes; then + AC_MSG_ERROR([Can not continue. Fix errors mentioned immediately above this line.]) + fi +]) + + +dnl XC_CHECK_BUILD_FLAGS +dnl ------------------------------------------------- +dnl Public macro. +dnl +dnl Performs some sanity checks for LIBS, LDFLAGS, +dnl CPPFLAGS and CFLAGS values that the configure +dnl script might have set. When checks fails, user +dnl is noticed about errors detected in all of them +dnl but script continues execution. +dnl +dnl Intended to be used very late in configure script. + +AC_DEFUN([XC_CHECK_BUILD_FLAGS], [ + AC_PREREQ([2.50])dnl + dnl check order below matters + _XC_CHECK_VAR_LIBS + _XC_CHECK_VAR_LDFLAGS + _XC_CHECK_VAR_CPPFLAGS + _XC_CHECK_VAR_CFLAGS + if test $xc_bad_var_libs = yes || + test $xc_bad_var_cflags = yes || + test $xc_bad_var_ldflags = yes || + test $xc_bad_var_cppflags = yes; then + AC_MSG_WARN([Continuing even with errors mentioned immediately above this line.]) + fi +]) diff --git a/m4/zz40-xc-ovr.m4 b/m4/zz40-xc-ovr.m4 new file mode 100644 index 0000000..fa45787 --- /dev/null +++ b/m4/zz40-xc-ovr.m4 @@ -0,0 +1,667 @@ +#--------------------------------------------------------------------------- +# +# zz40-xc-ovr.m4 +# +# Copyright (C) Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +dnl The funny name of this file is intentional in order to make it +dnl sort alphabetically after any libtool, autoconf or automake +dnl provided .m4 macro file that might get copied into this same +dnl subdirectory. This allows that macro (re)definitions from this +dnl file may override those provided in other files. + + +dnl Version macros +dnl ------------------------------------------------- +dnl Public macros. + +m4_define([XC_CONFIGURE_PREAMBLE_VER_MAJOR],[1])dnl +m4_define([XC_CONFIGURE_PREAMBLE_VER_MINOR],[0])dnl + + +dnl _XC_CFG_PRE_PREAMBLE +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_CFG_PRE_PREAMBLE], +[ +## -------------------------------- ## +@%:@@%:@ [XC_CONFIGURE_PREAMBLE] ver: []dnl +XC_CONFIGURE_PREAMBLE_VER_MAJOR.[]dnl +XC_CONFIGURE_PREAMBLE_VER_MINOR ## +## -------------------------------- ## + +xc_configure_preamble_ver_major='XC_CONFIGURE_PREAMBLE_VER_MAJOR' +xc_configure_preamble_ver_minor='XC_CONFIGURE_PREAMBLE_VER_MINOR' + +# +# Set IFS to space, tab and newline. +# + +xc_space=' ' +xc_tab=' ' +xc_newline=' +' +IFS="$xc_space$xc_tab$xc_newline" + +# +# Set internationalization behavior variables. +# + +LANG='C' +LC_ALL='C' +LANGUAGE='C' +export LANG +export LC_ALL +export LANGUAGE + +# +# Some useful variables. +# + +xc_msg_warn='configure: WARNING:' +xc_msg_abrt='Can not continue.' +xc_msg_err='configure: error:' +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_CMD_ECHO +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'echo' command +dnl is available, otherwise aborts execution. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO], +[dnl +AC_REQUIRE([_XC_CFG_PRE_PREAMBLE])dnl +# +# Verify that 'echo' command is available, otherwise abort. +# + +xc_tst_str='unknown' +(`echo "$xc_tst_str" >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in @%:@ (( + xsuccess) + : + ;; + *) + # Try built-in echo, and fail. + echo "$xc_msg_err 'echo' command not found. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_CMD_TEST +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'test' command +dnl is available, otherwise aborts execution. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_CMD_TEST], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl +# +# Verify that 'test' command is available, otherwise abort. +# + +xc_tst_str='unknown' +(`test -n "$xc_tst_str" >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in @%:@ (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'test' command not found. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_VAR_PATH +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'PATH' variable +dnl is set, otherwise aborts execution. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_VAR_PATH], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl +# +# Verify that 'PATH' variable is set, otherwise abort. +# + +xc_tst_str='unknown' +(`test -n "$PATH" >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in @%:@ (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'PATH' variable not set. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_CMD_EXPR +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'expr' command +dnl is available, otherwise aborts execution. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl +# +# Verify that 'expr' command is available, otherwise abort. +# + +xc_tst_str='unknown' +xc_tst_str=`expr "$xc_tst_str" : '.*' 2>/dev/null` +case "x$xc_tst_str" in @%:@ (( + x7) + : + ;; + *) + echo "$xc_msg_err 'expr' command not found. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_UTIL_SED +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'sed' utility +dnl is found within 'PATH', otherwise aborts execution. +dnl +dnl This 'sed' is required in order to allow configure +dnl script bootstrapping itself. No fancy testing for a +dnl proper 'sed' this early, that should be done later. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_SED], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl +# +# Verify that 'sed' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown' +xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ + | sed -e 's:unknown:success:' 2>/dev/null` +case "x$xc_tst_str" in @%:@ (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'sed' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_UTIL_GREP +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'grep' utility +dnl is found within 'PATH', otherwise aborts execution. +dnl +dnl This 'grep' is required in order to allow configure +dnl script bootstrapping itself. No fancy testing for a +dnl proper 'grep' this early, that should be done later. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_GREP], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl +# +# Verify that 'grep' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown' +(`echo "$xc_tst_str" 2>/dev/null \ + | grep 'unknown' >/dev/null 2>&1`) && xc_tst_str='success' +case "x$xc_tst_str" in @%:@ (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'grep' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_UTIL_TR +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'tr' utility +dnl is found within 'PATH', otherwise aborts execution. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_TR], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl +# +# Verify that 'tr' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str="${xc_tab}98s7u6c5c4e3s2s10" +xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ + | tr -d "0123456789$xc_tab" 2>/dev/null` +case "x$xc_tst_str" in @%:@ (( + xsuccess) + : + ;; + *) + echo "$xc_msg_err 'tr' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_UTIL_WC +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'wc' utility +dnl is found within 'PATH', otherwise aborts execution. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_WC], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl +# +# Verify that 'wc' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown unknown unknown unknown' +xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ + | wc -w 2>/dev/null | tr -d "$xc_space$xc_tab" 2>/dev/null` +case "x$xc_tst_str" in @%:@ (( + x4) + : + ;; + *) + echo "$xc_msg_err 'wc' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_BASIC_CHK_UTIL_CAT +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that verifies that 'cat' utility +dnl is found within 'PATH', otherwise aborts execution. + +AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_CAT], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl +# +# Verify that 'cat' utility is found within 'PATH', otherwise abort. +# + +xc_tst_str='unknown' +xc_tst_str=`cat <<_EOT 2>/dev/null \ + | wc -l 2>/dev/null | tr -d "$xc_space$xc_tab" 2>/dev/null +unknown +unknown +unknown +_EOT` +case "x$xc_tst_str" in @%:@ (( + x3) + : + ;; + *) + echo "$xc_msg_err 'cat' utility not found in 'PATH'. $xc_msg_abrt" >&2 + exit 1 + ;; +esac +]) + + +dnl _XC_CFG_PRE_CHECK_PATH_SEPARATOR +dnl ------------------------------------------------- +dnl Private macro. +dnl +dnl Emits shell code that computes the path separator +dnl and stores the result in 'PATH_SEPARATOR', unless +dnl the user has already set it with a non-empty value. +dnl +dnl This path separator is the symbol used to separate +dnl or differentiate paths inside the 'PATH' environment +dnl variable. +dnl +dnl Non-empty user provided 'PATH_SEPARATOR' always +dnl overrides the auto-detected one. + +AC_DEFUN([_XC_CFG_PRE_CHECK_PATH_SEPARATOR], +[dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl +# +# Auto-detect and set 'PATH_SEPARATOR', unless it is already non-empty set. +# + +# Directory count in 'PATH' when using a colon separator. +xc_tst_dirs_col='x' +xc_tst_prev_IFS=$IFS; IFS=':' +for xc_tst_dir in $PATH; do + IFS=$xc_tst_prev_IFS + xc_tst_dirs_col="x$xc_tst_dirs_col" +done +IFS=$xc_tst_prev_IFS +xc_tst_dirs_col=`expr "$xc_tst_dirs_col" : '.*'` + +# Directory count in 'PATH' when using a semicolon separator. +xc_tst_dirs_sem='x' +xc_tst_prev_IFS=$IFS; IFS=';' +for xc_tst_dir in $PATH; do + IFS=$xc_tst_prev_IFS + xc_tst_dirs_sem="x$xc_tst_dirs_sem" +done +IFS=$xc_tst_prev_IFS +xc_tst_dirs_sem=`expr "$xc_tst_dirs_sem" : '.*'` + +if test $xc_tst_dirs_sem -eq $xc_tst_dirs_col; then + # When both counting methods give the same result we do not want to + # chose one over the other, and consider auto-detection not possible. + if test -z "$PATH_SEPARATOR"; then + # User should provide the correct 'PATH_SEPARATOR' definition. + # Until then, guess that it is colon! + echo "$xc_msg_warn path separator not determined, guessing colon" >&2 + PATH_SEPARATOR=':' + fi +else + # Separator with the greater directory count is the auto-detected one. + if test $xc_tst_dirs_sem -gt $xc_tst_dirs_col; then + xc_tst_auto_separator=';' + else + xc_tst_auto_separator=':' + fi + if test -z "$PATH_SEPARATOR"; then + # Simply use the auto-detected one when not already set. + PATH_SEPARATOR=$xc_tst_auto_separator + elif test "x$PATH_SEPARATOR" != "x$xc_tst_auto_separator"; then + echo "$xc_msg_warn 'PATH_SEPARATOR' does not match auto-detected one." >&2 + fi +fi +xc_PATH_SEPARATOR=$PATH_SEPARATOR +AC_SUBST([PATH_SEPARATOR])dnl +]) + + +dnl _XC_CFG_PRE_POSTLUDE +dnl ------------------------------------------------- +dnl Private macro. + +AC_DEFUN([_XC_CFG_PRE_POSTLUDE], +[dnl +AC_REQUIRE([_XC_CFG_PRE_PREAMBLE])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_SED])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_GREP])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_CAT])dnl +AC_REQUIRE([_XC_CFG_PRE_CHECK_PATH_SEPARATOR])dnl +dnl +xc_configure_preamble_result='yes' +]) + + +dnl XC_CONFIGURE_PREAMBLE +dnl ------------------------------------------------- +dnl Public macro. +dnl +dnl This macro emits shell code which does some +dnl very basic checks related with the availability +dnl of some commands and utilities needed to allow +dnl configure script bootstrapping itself when using +dnl these to figure out other settings. Also emits +dnl code that performs PATH_SEPARATOR auto-detection +dnl and sets its value unless it is already set with +dnl a non-empty value. +dnl +dnl These basic checks are intended to be placed and +dnl executed as early as possible in the resulting +dnl configure script, and as such these must be pure +dnl and portable shell code. +dnl +dnl This macro may be used directly, or indirectly +dnl when using other macros that AC_REQUIRE it such +dnl as XC_CHECK_PATH_SEPARATOR. +dnl +dnl Currently the mechanism used to ensure that this +dnl macro expands early enough in generated configure +dnl script is making it override autoconf and libtool +dnl PATH_SEPARATOR check. + +AC_DEFUN([XC_CONFIGURE_PREAMBLE], +[dnl +AC_PREREQ([2.50])dnl +dnl +AC_BEFORE([$0],[_XC_CFG_PRE_PREAMBLE])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_SED])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_GREP])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_CAT])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_CHECK_PATH_SEPARATOR])dnl +AC_BEFORE([$0],[_XC_CFG_PRE_POSTLUDE])dnl +dnl +AC_BEFORE([$0],[AC_CHECK_TOOL])dnl +AC_BEFORE([$0],[AC_CHECK_PROG])dnl +AC_BEFORE([$0],[AC_CHECK_TOOLS])dnl +AC_BEFORE([$0],[AC_CHECK_PROGS])dnl +dnl +AC_BEFORE([$0],[AC_PATH_TOOL])dnl +AC_BEFORE([$0],[AC_PATH_PROG])dnl +AC_BEFORE([$0],[AC_PATH_PROGS])dnl +dnl +AC_BEFORE([$0],[AC_PROG_SED])dnl +AC_BEFORE([$0],[AC_PROG_GREP])dnl +AC_BEFORE([$0],[AC_PROG_LN_S])dnl +AC_BEFORE([$0],[AC_PROG_MKDIR_P])dnl +AC_BEFORE([$0],[AC_PROG_INSTALL])dnl +AC_BEFORE([$0],[AC_PROG_MAKE_SET])dnl +AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl +dnl +AC_BEFORE([$0],[LT_INIT])dnl +AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl +AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl +dnl +AC_REQUIRE([_XC_CFG_PRE_PREAMBLE])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_SED])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_GREP])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl +AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_CAT])dnl +AC_REQUIRE([_XC_CFG_PRE_CHECK_PATH_SEPARATOR])dnl +AC_REQUIRE([_XC_CFG_PRE_POSTLUDE])dnl +dnl +m4_pattern_forbid([^_*XC])dnl +m4_define([$0],[])dnl +]) + + +dnl Override autoconf and libtool PATH_SEPARATOR check +dnl ------------------------------------------------- +dnl Macros overriding. +dnl +dnl This is done to ensure that the same check is +dnl used across different autoconf versions and to +dnl allow expansion of XC_CONFIGURE_PREAMBLE macro +dnl early enough in the generated configure script. + +dnl +dnl Override when using autoconf 2.53 and newer. +dnl + +m4_ifdef([_AS_PATH_SEPARATOR_PREPARE], +[dnl +m4_undefine([_AS_PATH_SEPARATOR_PREPARE])dnl +m4_defun([_AS_PATH_SEPARATOR_PREPARE], +[dnl +AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl +m4_define([$0],[])dnl +])dnl +]) + +dnl +dnl Override when using autoconf 2.50 to 2.52 +dnl + +m4_ifdef([_AC_INIT_PREPARE_FS_SEPARATORS], +[dnl +m4_undefine([_AC_INIT_PREPARE_FS_SEPARATORS])dnl +m4_defun([_AC_INIT_PREPARE_FS_SEPARATORS], +[dnl +AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl +ac_path_separator=$PATH_SEPARATOR +m4_define([$0],[])dnl +])dnl +]) + +dnl +dnl Override when using libtool 1.4.2 +dnl + +m4_ifdef([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR], +[dnl +m4_undefine([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl +m4_defun([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR], +[dnl +AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl +lt_cv_sys_path_separator=$PATH_SEPARATOR +m4_define([$0],[])dnl +])dnl +]) + + +dnl XC_CHECK_PATH_SEPARATOR +dnl ------------------------------------------------- +dnl Public macro. +dnl +dnl Usage of this macro ensures that generated configure +dnl script uses the same PATH_SEPARATOR check irrespective +dnl of autoconf or libtool version being used to generate +dnl configure script. +dnl +dnl Emits shell code that computes the path separator +dnl and stores the result in 'PATH_SEPARATOR', unless +dnl the user has already set it with a non-empty value. +dnl +dnl This path separator is the symbol used to separate +dnl or differentiate paths inside the 'PATH' environment +dnl variable. +dnl +dnl Non-empty user provided 'PATH_SEPARATOR' always +dnl overrides the auto-detected one. +dnl +dnl Strictly speaking the check is done in two steps. The +dnl first, which does the actual check, takes place in +dnl XC_CONFIGURE_PREAMBLE macro and happens very early in +dnl generated configure script. The second one shows and +dnl logs the result of the check into config.log at a later +dnl configure stage. Placement of this second stage in +dnl generated configure script will be done where first +dnl direct or indirect usage of this macro happens. + +AC_DEFUN([XC_CHECK_PATH_SEPARATOR], +[dnl +AC_PREREQ([2.50])dnl +dnl +AC_BEFORE([$0],[AC_CHECK_TOOL])dnl +AC_BEFORE([$0],[AC_CHECK_PROG])dnl +AC_BEFORE([$0],[AC_CHECK_TOOLS])dnl +AC_BEFORE([$0],[AC_CHECK_PROGS])dnl +dnl +AC_BEFORE([$0],[AC_PATH_TOOL])dnl +AC_BEFORE([$0],[AC_PATH_PROG])dnl +AC_BEFORE([$0],[AC_PATH_PROGS])dnl +dnl +AC_BEFORE([$0],[AC_PROG_SED])dnl +AC_BEFORE([$0],[AC_PROG_GREP])dnl +AC_BEFORE([$0],[AC_PROG_LN_S])dnl +AC_BEFORE([$0],[AC_PROG_MKDIR_P])dnl +AC_BEFORE([$0],[AC_PROG_INSTALL])dnl +AC_BEFORE([$0],[AC_PROG_MAKE_SET])dnl +AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl +dnl +AC_BEFORE([$0],[LT_INIT])dnl +AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl +AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl +dnl +AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl +dnl +# +# Check that 'XC_CONFIGURE_PREAMBLE' has already run. +# + +if test -z "$xc_configure_preamble_result"; then + AC_MSG_ERROR([xc_configure_preamble_result not set (internal problem)]) +fi + +# +# Check that 'PATH_SEPARATOR' has already been set. +# + +if test -z "$xc_PATH_SEPARATOR"; then + AC_MSG_ERROR([xc_PATH_SEPARATOR not set (internal problem)]) +fi +if test -z "$PATH_SEPARATOR"; then + AC_MSG_ERROR([PATH_SEPARATOR not set (internal or config.site problem)]) +fi +AC_MSG_CHECKING([for path separator]) +AC_MSG_RESULT([$PATH_SEPARATOR]) +if test "x$PATH_SEPARATOR" != "x$xc_PATH_SEPARATOR"; then + AC_MSG_CHECKING([for initial path separator]) + AC_MSG_RESULT([$xc_PATH_SEPARATOR]) + AC_MSG_ERROR([path separator mismatch (internal or config.site problem)]) +fi +dnl +m4_pattern_forbid([^_*XC])dnl +m4_define([$0],[])dnl +]) diff --git a/m4/zz50-xc-ovr.m4 b/m4/zz50-xc-ovr.m4 new file mode 100644 index 0000000..18c1f0a --- /dev/null +++ b/m4/zz50-xc-ovr.m4 @@ -0,0 +1,61 @@ +#--------------------------------------------------------------------------- +# +# zz50-xc-ovr.m4 +# +# Copyright (C), Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +# serial 1 + + +dnl The funny name of this file is intentional in order to make it +dnl sort alphabetically after any libtool, autoconf or automake +dnl provided .m4 macro file that might get copied into this same +dnl subdirectory. This allows that macro (re)definitions from this +dnl file may override those provided in other files. + + +dnl Override some language related macros +dnl ------------------------------------------------- +dnl This is done to prevent Libtool 1.5.X from doing +dnl unnecessary C++, Fortran and Java tests when only +dnl using C language and reduce resulting configure +dnl script by nearly 300 Kb. + +m4_ifdef([AC_LIBTOOL_LANG_CXX_CONFIG], + [m4_undefine([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_define([AC_LIBTOOL_LANG_CXX_CONFIG],[:]) + +m4_ifdef([AC_LIBTOOL_LANG_F77_CONFIG], + [m4_undefine([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_define([AC_LIBTOOL_LANG_F77_CONFIG],[:]) + +m4_ifdef([AC_LIBTOOL_LANG_GCJ_CONFIG], + [m4_undefine([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_define([AC_LIBTOOL_LANG_GCJ_CONFIG],[:]) + + +dnl XC_OVR_ZZ50 +dnl ------------------------------------------------- +dnl Placing a call to this macro in configure.ac will +dnl make macros in this file visible to other macros +dnl used for same configure script, overriding those +dnl provided elsewhere. + +AC_DEFUN([XC_OVR_ZZ50], + [AC_BEFORE([$0],[AC_PROG_LIBTOOL])]) diff --git a/m4/zz60-xc-ovr.m4 b/m4/zz60-xc-ovr.m4 new file mode 100644 index 0000000..5316686 --- /dev/null +++ b/m4/zz60-xc-ovr.m4 @@ -0,0 +1,65 @@ +#--------------------------------------------------------------------------- +# +# zz60-xc-ovr.m4 +# +# Copyright (C), Daniel Stenberg +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#--------------------------------------------------------------------------- + +# serial 1 + + +dnl The funny name of this file is intentional in order to make it +dnl sort alphabetically after any libtool, autoconf or automake +dnl provided .m4 macro file that might get copied into this same +dnl subdirectory. This allows that macro (re)definitions from this +dnl file may override those provided in other files. + + +dnl Override an autoconf provided macro +dnl ------------------------------------------------- +dnl This macro overrides the one provided by autoconf +dnl 2.58 or newer, and provides macro definition for +dnl autoconf 2.57 or older which lack it. This allows +dnl using libtool 2.2 or newer, which requires that +dnl this macro is used in configure.ac, with autoconf +dnl 2.57 or older. + +m4_ifdef([AC_CONFIG_MACRO_DIR], +[dnl +m4_undefine([AC_CONFIG_MACRO_DIR])dnl +]) +m4_define([AC_CONFIG_MACRO_DIR],[]) + + +dnl XC_OVR_ZZ60 +dnl ------------------------------------------------- +dnl Placing a call to this macro in configure.ac will +dnl make macros in this file visible to other macros +dnl used for same configure script, overriding those +dnl provided elsewhere. + +AC_DEFUN([XC_OVR_ZZ60], +[dnl +AC_BEFORE([$0],[LT_INIT])dnl +AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl +AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl +AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl +dnl +AC_BEFORE([$0],[AC_CONFIG_MACRO_DIR])dnl +AC_BEFORE([$0],[AC_CONFIG_MACRO_DIRS])dnl +]) diff --git a/maketgz b/maketgz new file mode 100755 index 0000000..4ebda82 --- /dev/null +++ b/maketgz @@ -0,0 +1,220 @@ +#!/bin/sh +# Script to build release-archives with. Note that this requires a checkout +# from git and you should first run ./buildconf and build curl once. +# +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +version=$1 + +if [ -z "$version" ]; then + echo "Specify a version number!" + exit +fi + +if [ "xonly" = "x$2" ]; then + echo "Setup version number only!" + only=1 +fi + +libversion="$version" + +# we make curl the same version as libcurl +curlversion=$libversion + +major=`echo $libversion | cut -d. -f1 | sed -e "s/[^0-9]//g"` +minor=`echo $libversion | cut -d. -f2 | sed -e "s/[^0-9]//g"` +patch=`echo $libversion | cut -d. -f3 | cut -d- -f1 | sed -e "s/[^0-9]//g"` + +if test -z "$patch"; then + echo "invalid version number? needs to be z.y.z" + exit +fi + +# +# As a precaution, remove all *.dist files that may be lying around, to reduce +# the risk of old leftovers getting shipped. The root 'Makefile.dist' is the +# exception. +echo "removing all old *.dist files" +find . -name "*.dist" -a ! -name Makefile.dist -exec rm {} \; + +numeric=`perl -e 'printf("%02x%02x%02x\n", '"$major, $minor, $patch);"` + +HEADER=include/curl/curlver.h +CHEADER=src/tool_version.h +PLIST=lib/libcurl.plist +PLISTO=$PLIST + +if test -z "$only"; then + ext=".dist" + # when not setting up version numbers locally + for a in $HEADER $CHEADER $PLIST; do + cp $a "$a$ext" + done + HEADER="$HEADER$ext" + CHEADER="$CHEADER$ext" + PLIST="$PLIST$ext" +fi + +# requires a date command that knows + for format +datestamp=`date +"%F"` + +# Replace version number in header file: +sed -i.bak \ + -e 's/^#define LIBCURL_VERSION .*/#define LIBCURL_VERSION "'$libversion'"/g' \ + -e 's/^#define LIBCURL_VERSION_NUM .*/#define LIBCURL_VERSION_NUM 0x'$numeric'/g' \ + -e 's/^#define LIBCURL_VERSION_MAJOR .*/#define LIBCURL_VERSION_MAJOR '$major'/g' \ + -e 's/^#define LIBCURL_VERSION_MINOR .*/#define LIBCURL_VERSION_MINOR '$minor'/g' \ + -e 's/^#define LIBCURL_VERSION_PATCH .*/#define LIBCURL_VERSION_PATCH '$patch'/g' \ + -e "s/^#define LIBCURL_TIMESTAMP .*/#define LIBCURL_TIMESTAMP \"$datestamp\"/g" \ + $HEADER +rm -f "$HEADER.bak" + +# Replace version number in header file: +sed -i.bak 's/#define CURL_VERSION .*/#define CURL_VERSION "'$curlversion'"/g' $CHEADER +rm -f "$CHEADER.bak" + +# Replace version number in plist file: +sed "s/@CURL_PLIST_VERSION@/$curlversion/g" < $PLISTO.in >$PLIST + +if test -n "$only"; then + # done! + exit; +fi + +echo "curl version $curlversion" +echo "libcurl version $libversion" +echo "libcurl numerical $numeric" +echo "datestamp $datestamp" + +findprog() { + file="$1" + for part in `echo $PATH| tr ':' ' '`; do + path="$part/$file" + if [ -x "$path" ]; then + # there it is! + return 1 + fi + done + + # no such executable + return 0 +} + +############################################################################ +# +# Enforce a rerun of configure (updates the VERSION) +# + +echo "Re-running config.status" +./config.status --recheck >/dev/null + +############################################################################ +# +# automake is needed to run to make a non-GNU Makefile.in if Makefile.am has +# been modified. +# + +if { findprog automake >/dev/null 2>/dev/null; } then + echo "- Could not find or run automake, I hope you know what you're doing!" +else + echo "Runs automake --include-deps" + automake --include-deps Makefile >/dev/null +fi + +############################################################################ +# +# make the generated file newer than the man page + +touch src/tool_hugehelp.c + +############################################################################ +# +# Update the IDE files +echo "make vc-ide" +make -s vc-ide + +echo "produce CHANGES" +git log --pretty=fuller --no-color --date=short --decorate=full -1000 | ./scripts/log2changes.pl > CHANGES.dist + +############################################################################ +# +# Now run make dist to generate a tar.gz archive +# + +echo "make dist" +targz="curl-$version.tar.gz" +make -sj dist VERSION=$version +res=$? + +if test "$res" != 0; then + echo "make dist failed" + exit 2 +fi + +############################################################################ +# +# Now make a bz2 archive from the tar.gz original +# + +bzip2="curl-$version.tar.bz2" +echo "Generating $bzip2" +gzip -dc $targz | bzip2 --best > $bzip2 + +############################################################################ +# +# Now make an xz archive from the tar.gz original +# + +xz="curl-$version.tar.xz" +echo "Generating $xz" +gzip -dc $targz | xz -6e - > $xz + +############################################################################ +# +# Now make a zip archive from the tar.gz original +# +makezip() { + rm -rf $tempdir + mkdir $tempdir + cd $tempdir + gzip -dc ../$targz | tar -xf - + find . | zip $zip -@ >/dev/null + mv $zip ../ + cd .. + rm -rf $tempdir +} + +zip="curl-$version.zip" +echo "Generating $zip" +tempdir=".builddir" +makezip + +echo "------------------" +echo "maketgz report:" +echo "" +ls -l $targz $bzip2 $zip $xz + +echo "Run this:" +echo "gpg -b -a $targz && gpg -b -a $bzip2 && gpg -b -a $zip && gpg -b -a $xz" diff --git a/missing b/missing new file mode 100755 index 0000000..1fe1611 --- /dev/null +++ b/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# Originally written by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try '$0 --help' for more information" + exit 1 +fi + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and +'g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: unknown '$1' option" + echo 1>&2 "Try '$0 --help' for more information" + exit 1 + ;; + +esac + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=https://www.perl.org/ +flex_URL=https://github.com/westes/flex +gnu_software_URL=https://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/packages/Makefile.am b/packages/Makefile.am new file mode 100644 index 0000000..b7bf1e5 --- /dev/null +++ b/packages/Makefile.am @@ -0,0 +1,51 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +SUBDIRS = vms + +EXTRA_DIST = README.md \ + OS400/README.OS400 \ + OS400/rpg-examples \ + OS400/ccsidcurl.c \ + OS400/ccsidcurl.h \ + OS400/curlcl.c \ + OS400/curlmain.c \ + OS400/curl.inc.in \ + OS400/initscript.sh \ + OS400/config400.default \ + OS400/make-include.sh \ + OS400/make-lib.sh \ + OS400/make-src.sh \ + OS400/make-tests.sh \ + OS400/makefile.sh \ + OS400/os400sys.c \ + OS400/os400sys.h \ + OS400/curl.cmd + +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) + +checksrc: + $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(srcdir)/OS400/*.[ch]) diff --git a/packages/Makefile.in b/packages/Makefile.in new file mode 100644 index 0000000..c15b621 --- /dev/null +++ b/packages/Makefile.in @@ -0,0 +1,797 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = packages +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in README.md +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +SUBDIRS = vms +EXTRA_DIST = README.md \ + OS400/README.OS400 \ + OS400/rpg-examples \ + OS400/ccsidcurl.c \ + OS400/ccsidcurl.h \ + OS400/curlcl.c \ + OS400/curlmain.c \ + OS400/curl.inc.in \ + OS400/initscript.sh \ + OS400/config400.default \ + OS400/make-include.sh \ + OS400/make-lib.sh \ + OS400/make-src.sh \ + OS400/make-tests.sh \ + OS400/makefile.sh \ + OS400/os400sys.c \ + OS400/os400sys.h \ + OS400/curl.cmd + +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign packages/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign packages/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +checksrc: + $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(srcdir)/OS400/*.[ch]) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/packages/OS400/README.OS400 b/packages/OS400/README.OS400 new file mode 100644 index 0000000..38b2c7f --- /dev/null +++ b/packages/OS400/README.OS400 @@ -0,0 +1,391 @@ + +Implementation notes: + + This is a true OS/400 ILE implementation, not a PASE implementation (for +PASE, use AIX implementation). + + The biggest problem with OS/400 is EBCDIC. Libcurl implements an internal +conversion mechanism, but it has been designed for computers that have a +single native character set. OS/400 default native character set varies +depending on the country for which it has been localized. And more, a job +may dynamically alter its "native" character set. + Several characters that do not have fixed code in EBCDIC variants are +used in libcurl strings. As a consequence, using the existing conversion +mechanism would have lead in a localized binary library - not portable across +countries. + For this reason, and because libcurl was originally designed for ASCII based +operating systems, the current OS/400 implementation uses ASCII as internal +character set. This has been accomplished using the QADRT library and +include files, a C and system procedures ASCII wrapper library. See IBM QADRT +description for more information. + This then results in libcurl being an ASCII library: any function string +argument is taken/returned in ASCII and a C/C++ calling program built around +QADRT may use libcurl functions as on any other platform. + QADRT does not define ASCII wrappers for all C/system procedures: the +OS/400 configuration header file and an additional module (os400sys.c) define +some more of them, that are used by libcurl and that QADRT left out. + To support all the different variants of EBCDIC, non-standard wrapper +procedures have been added to libcurl on OS/400: they provide an additional +CCSID (numeric Coded Character Set ID specific to OS/400) parameter for each +string argument. Callback procedures arguments giving access to strings are +NOT converted, so text gathered this way is (probably !) ASCII. + + Another OS/400 problem comes from the fact that the last fixed argument of a +vararg procedure may not be of type char, unsigned char, short or unsigned +short. Enums that are internally implemented by the C compiler as one of these +types are also forbidden. Libcurl uses enums as vararg procedure tagfields... +Happily, there is a pragma forcing enums to type "int". The original libcurl +header files are thus altered during build process to use this pragma, in +order to force libcurl enums of being type int (the pragma disposition in use +before inclusion is restored before resuming the including unit compilation). + + Non-standard EBCDIC wrapper prototypes are defined in an additional header +file: ccsidcurl.h. These should be self-explanatory to an OS/400-aware +designer. CCSID 0 can be used to select the current job's CCSID. + Wrapper procedures with variable arguments are described below: + +_ curl_easy_setopt_ccsid() + Variable arguments are a string pointer and a CCSID (unsigned int) for +options: + CURLOPT_ABSTRACT_UNIX_SOCKET + CURLOPT_ACCEPT_ENCODING + CURLOPT_ALTSVC + CURLOPT_AWS_SIGV4 + CURLOPT_CAINFO + CURLOPT_CAPATH + CURLOPT_COOKIE + CURLOPT_COOKIEFILE + CURLOPT_COOKIEJAR + CURLOPT_COOKIELIST + CURLOPT_CRLFILE + CURLOPT_CUSTOMREQUEST + CURLOPT_DEFAULT_PROTOCOL + CURLOPT_DNS_INTERFACE + CURLOPT_DNS_LOCAL_IP4 + CURLOPT_DNS_LOCAL_IP6 + CURLOPT_DNS_SERVERS + CURLOPT_DOH_URL + CURLOPT_EGDSOCKET + CURLOPT_FTPPORT + CURLOPT_FTP_ACCOUNT + CURLOPT_FTP_ALTERNATIVE_TO_USER + CURLOPT_HAPROXY_CLIENT_IP + CURLOPT_HSTS + CURLOPT_INTERFACE + CURLOPT_ISSUERCERT + CURLOPT_KEYPASSWD + CURLOPT_KRBLEVEL + CURLOPT_LOGIN_OPTIONS + CURLOPT_MAIL_AUTH + CURLOPT_MAIL_FROM + CURLOPT_NETRC_FILE + CURLOPT_NOPROXY + CURLOPT_PASSWORD + CURLOPT_PINNEDPUBLICKEY + CURLOPT_PRE_PROXY + CURLOPT_PROTOCOLS_STR + CURLOPT_PROXY + CURLOPT_PROXYPASSWORD + CURLOPT_PROXYUSERNAME + CURLOPT_PROXYUSERPWD + CURLOPT_PROXY_CAINFO + CURLOPT_PROXY_CAPATH + CURLOPT_PROXY_CRLFILE + CURLOPT_PROXY_ISSUERCERT + CURLOPT_PROXY_KEYPASSWD + CURLOPT_PROXY_PINNEDPUBLICKEY + CURLOPT_PROXY_SERVICE_NAME + CURLOPT_PROXY_SSLCERT + CURLOPT_PROXY_SSLCERTTYPE + CURLOPT_PROXY_SSLKEY + CURLOPT_PROXY_SSLKEYTYPE + CURLOPT_PROXY_SSL_CIPHER_LIST + CURLOPT_PROXY_TLS13_CIPHERS + CURLOPT_PROXY_TLSAUTH_PASSWORD + CURLOPT_PROXY_TLSAUTH_TYPE + CURLOPT_PROXY_TLSAUTH_USERNAME + CURLOPT_RANDOM_FILE + CURLOPT_RANGE + CURLOPT_REDIR_PROTOCOLS_STR + CURLOPT_REFERER + CURLOPT_REQUEST_TARGET + CURLOPT_RTSP_SESSION_ID + CURLOPT_RTSP_STREAM_URI + CURLOPT_RTSP_TRANSPORT + CURLOPT_SASL_AUTHZID + CURLOPT_SERVICE_NAME + CURLOPT_SOCKS5_GSSAPI_SERVICE + CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 + CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 + CURLOPT_SSH_KNOWNHOSTS + CURLOPT_SSH_PRIVATE_KEYFILE + CURLOPT_SSH_PUBLIC_KEYFILE + CURLOPT_SSLCERT + CURLOPT_SSLCERTTYPE + CURLOPT_SSLENGINE + CURLOPT_SSLKEY + CURLOPT_SSLKEYTYPE + CURLOPT_SSL_CIPHER_LIST + CURLOPT_SSL_EC_CURVES + CURLOPT_TLS13_CIPHERS + CURLOPT_TLSAUTH_PASSWORD + CURLOPT_TLSAUTH_TYPE + CURLOPT_TLSAUTH_USERNAME + CURLOPT_UNIX_SOCKET_PATH + CURLOPT_URL + CURLOPT_USERAGENT + CURLOPT_USERNAME + CURLOPT_USERPWD + CURLOPT_XOAUTH2_BEARER + All blob options are also supported. + In all other cases, it ignores the ccsid parameter and behaves as +curl_easy_setopt(). + Note that CURLOPT_ERRORBUFFER is not in the list above, since it gives the +address of an (empty) character buffer, not the address of a string. +CURLOPT_POSTFIELDS stores the address of static binary data (of type void *) +and thus is not converted. If CURLOPT_COPYPOSTFIELDS is issued after +CURLOPT_POSTFIELDSIZE != -1, the data size is adjusted according to the +CCSID conversion result length. + +_ curl_formadd_ccsid() + In the variable argument list, string pointers should be followed by a (long) +CCSID for the following options: + CURLFORM_BUFFER + CURLFORM_CONTENTTYPE + CURLFORM_COPYCONTENTS + CURLFORM_COPYNAME + CURLFORM_FILE + CURLFORM_FILECONTENT + CURLFORM_FILENAME + CURLFORM_PTRNAME + If taken from an argument array, an additional array entry must follow each +entry containing one of the above option. This additional entry holds the CCSID +in its value field, and the option field is meaningless. + It is not possible to have a string pointer and its CCSID across a function +parameter/array boundary. + Please note that CURLFORM_PTRCONTENTS and CURLFORM_BUFFERPTR are considered +unconvertible strings and thus are NOT followed by a CCSID. + +_ curl_easy_getinfo_ccsid() + The following options are followed by a 'char * *' and a CCSID. Unlike +curl_easy_getinfo(), the value returned in the pointer should be released with +curl_free() after use: + CURLINFO_CONTENT_TYPE + CURLINFO_EFFECTIVE_URL + CURLINFO_FTP_ENTRY_PATH + CURLINFO_LOCAL_IP + CURLINFO_PRIMARY_IP + CURLINFO_REDIRECT_URL + CURLINFO_REFERER + CURLINFO_RTSP_SESSION_ID + CURLINFO_SCHEME + Likewise, the following options are followed by a struct curl_slist * * and a +CCSID. + CURLINFO_COOKIELIST + CURLINFO_SSL_ENGINES +Lists returned should be released with curl_slist_free_all() after use. + Option CURLINFO_CERTINFO is followed by a struct curl_certinfo * * and a +CCSID. Returned structures should be freed with curl_certinfo_free_all() +after use. + Other options are processed like in curl_easy_getinfo(). + +_ curl_easy_strerror_ccsid(), curl_multi_strerror_ccsid(), +curl_share_strerror_ccsid() and curl_url_strerror_ccsid() work as their +non-ccsid version and return a string encoded in the additional ccsid +parameter. These strings belong to libcurl and may not be freed by the caller. +A subsequent call to the same procedure in the same thread invalidates the +previous result. + +_ curl_pushheader_bynum_cssid() and curl_pushheader_byname_ccsid() + Although the prototypes are self-explanatory, the returned string pointer +should be released with curl_free() after use, as opposite to the non-ccsid +versions of these procedures. + Please note that HTTP2 is not (yet) implemented on OS/400, thus these +functions will always return NULL. + +_ curl_easy_option_by_name_ccsid() returns a pointer to an untranslated option +metadata structure. As each curl_easyoption structure holds the option name in +ASCII, the curl_easy_option_get_name_ccsid() function allows getting it in any +supported ccsid. However the caller should release the returned pointer with +curl_free() after use. + +_ curl_easy_header_ccsid() works as its non-CCSID counterpart but requires an +additional ccsid parameter specifying the name parameter encoding. The output +hout parameter is kept in libcurl's encoding and should not be altered. + +_ curl_from_ccsid() and curl_to_ccsid() are string encoding conversion +functions between ASCII (latin1) and the given CCSID. The first parameter is +the source string, the second is the CCSID and the returned value is a pointer +to the dynamically allocated string. These functions do not impact on Curl's +behavior and are only provided for user convenience. After use, returned values +must be released with curl_free(). + + + Standard compilation environment does support neither autotools nor make; +in fact, very few common utilities are available. As a consequence, the +config-os400.h has been coded manually and the compilation scripts are +a set of shell scripts stored in subdirectory packages/OS400. + + The "curl" command and the test environment are currently not supported on +OS/400. + + +Protocols currently implemented on OS/400: +_ DICT +_ FILE +_ FTP +_ FTPS +_ FTP with secure transmission +_ GOPHER +_ HTTP +_ HTTPS +_ IMAP +_ IMAPS +_ IMAP with secure transmission +_ LDAP +_ POP3 +_ POP3S +_ POP3 with secure transmission +_ RTSP +_ SCP if libssh2 is enabled +_ SFTP if libssh2 is enabled +_ SMTP +_ SMTPS +_ SMTP with secure transmission +_ TELNET +_ TFTP + + + +Compiling on OS/400: + + These instructions targets people who knows about OS/400, compiling, IFS and +archive extraction. Do not ask questions about these subjects if you're not +familiar with. + +_ As a prerequisite, QADRT development environment must be installed. + For more information on downloading and installing the QADRT development kit, + please see https://www.ibm.com/support/pages/node/6258183 +_ If data compression has to be supported, ZLIB development environment must + be installed. +_ Likewise, if SCP and SFTP protocols have to be compiled in, LIBSSH2 + developent environment must be installed. +_ Install the curl source directory in IFS. Do NOT install it in the + installation target directory (which defaults to /curl). +_ Enter Qshell (QSH, not PASE) +_ Change current directory to the curl installation directory +_ Change current directory to ./packages/OS400 +- If you want to change the default configuration parameters like debug info + generation, optimization level, listing option, target library, ZLIB/LIBSSH2 + availability and location, etc., copy file config400.default to + config400.override and edit the latter. Do not edit the original default file + as it might be overwritten by a subsequent source installation. +_ Copy any file in the current directory to makelog (i.e.: + cp initscript.sh makelog): this is intended to create the makelog file with + an ASCII CCSID! +_ Enter the command "sh makefile.sh > makelog 2>&1" +_ Examine the makelog file to check for compilation errors. CZM0383 warnings on + C or system standard API come from QADRT inlining and can safely be ignored. + + Without configuration parameters override, this will produce the following +OS/400 objects: +_ Library CURL. All other objects will be stored in this library. +_ Modules for all libcurl units. +_ Binding directory CURL_A, to be used at calling program link time for + statically binding the modules (specify BNDSRVPGM(QADRTTS QGLDCLNT QGLDBRDR) + when creating a program using CURL_A). +_ Service program CURL., where is extracted from the + lib/Makefile.am VERSION variable. To be used at calling program run-time + when this program has dynamically bound curl at link time. +_ Binding directory CURL. To be used to dynamically bind libcurl when linking a + calling program. +- CLI tool bound program CURL. +- CLI command CURL. +_ Source file H. It contains all the include members needed to compile a C/C++ + module using libcurl, and an ILE/RPG /copy member for support in this + language. +_ Standard C/C++ libcurl include members in file H. +_ CCSIDCURL member in file H. This defines the non-standard EBCDIC wrappers for + C and C++. +_ CURL.INC member in file H. This defines everything needed by an ILE/RPG + program using libcurl. +_ IFS directory /curl/include/curl containing the C header files for IFS source + C/C++ compilation and curl.inc.rpgle for IFS source ILE/RPG compilation. +- IFS link /curl/bin/curl to CLI tool program. + + +Special programming consideration: + +QADRT being used, the following points must be considered: +_ If static binding is used, service program QADRTTS must be linked too. +_ The EBCDIC CCSID used by QADRT is 37 by default, NOT THE JOB'S CCSID. If + another EBCDIC CCSID is required, it must be set via a locale through a call + to setlocale_a (QADRT's setlocale() ASCII wrapper) with category LC_ALL or + LC_CTYPE, or by setting environment variable QADRT_ENV_LOCALE to the locale + object path before executing the program. +_ Do not use original source include files unless you know what you are doing. + Use the installed members instead (in /QSYS.LIB/CURL.LIB/H.FILE and + /curl/include/curl). + + + +ILE/RPG support: + + Since most of the ILE OS/400 programmers use ILE/RPG exclusively, a +definition /INCLUDE member is provided for this language. To include all +libcurl definitions in an ILE/RPG module, line + + h bnddir('CURL/CURL') + +must figure in the program header, and line + + d/include curl/h,curl.inc + +in the global data section of the module's source code. + + No vararg procedure support exists in ILE/RPG: for this reason, the following +considerations apply: +_ Procedures curl_easy_setopt_long(), curl_easy_setopt_object(), + curl_easy_setopt_function(), curl_easy_setopt_offset() and + curl_easy_setopt_blob() are all alias prototypes to curl_easy_setopt(), but + with different parameter lists. +_ Procedures curl_easy_getinfo_string(), curl_easy_getinfo_long(), + curl_easy_getinfo_double(), curl_easy_getinfo_slist(), + curl_easy_getinfo_ptr(), curl_easy_getinfo_socket() and + curl_easy_getinfo_off_t() are all alias prototypes to curl_easy_getinfo(), + but with different parameter lists. +_ Procedures curl_multi_setopt_long(), curl_multi_setopt_object(), + curl_multi_setopt_function() and curl_multi_setopt_offset() are all alias + prototypes to curl_multi_setopt(), but with different parameter lists. +_ Procedures curl_share_setopt_int(), curl_share_setopt_ptr() and + curl_share_setopt_proc() are all alias prototypes to curl_share_setopt, + but with different parameter lists. +_ Procedure curl_easy_setopt_blob_ccsid() is an alias of + curl_easy_setopt_ccsid() supporting blob encoding conversion. +_ The prototype of procedure curl_formadd() allows specifying a pointer option + and the CURLFORM_END option. This makes possible to use an option array + without any additional definition. If some specific incompatible argument + list is used in the ILE/RPG program, the latter must define a specialised + alias. The same applies to curl_formadd_ccsid() too. +_ Since V7R4M0, procedure overloading is used to emulate limited "vararg-like" + definitions of curl_easy_setopt(), curl_multi_setopt(), curl_share_setopt() + and curl_easy_getinfo(). Blob and CCSID alternatives are NOT included in + overloading. + + Since RPG cannot cast a long to a pointer, procedure curl_form_long_value() +is provided for that purpose: this allows storing a long value in the +curl_forms array. Please note the form API is deprecated and the MIME API +should be used instead. + + +CLI tool: + + The build system provides it as a bound program, an IFS link to it and a +simple CL command. The latter however is not able to provide a different +parameter for each option since there are too many of those; instead, +parameters are entered in a single field subject to quoting and escaping, in +the same form as expected by the standard CLI program. + Care must be taken about the program output encoding: by default, it is sent +to the standard output and is thus subject to transcoding. It is therefore +recommended to use option "--output" to redirect output to a specific IFS file. +Similar problems may occur about the standard input encoding. diff --git a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c new file mode 100644 index 0000000..596c1f1 --- /dev/null +++ b/packages/OS400/ccsidcurl.c @@ -0,0 +1,1527 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ + +/* CCSID API wrappers for OS/400. */ + +#include +#include +#include +#include +#include +#include + +#pragma enum(int) + +#include "curl.h" +#include "mprintf.h" +#include "slist.h" +#include "urldata.h" +#include "url.h" +#include "setopt.h" +#include "getinfo.h" +#include "ccsidcurl.h" + +#include "os400sys.h" + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t) ~0) /* Is unsigned on OS/400. */ +#endif + + +#define ASCII_CCSID 819 /* Use ISO-8859-1 as ASCII. */ +#define NOCONV_CCSID 65535 /* No conversion. */ +#define ICONV_ID_SIZE 32 /* Size of iconv_open() code identifier. */ +#define ICONV_OPEN_ERROR(t) ((t).return_value == -1) + +#define ALLOC_GRANULE 8 /* Alloc. granule for curl_formadd_ccsid(). */ + + +static void +makeOS400IconvCode(char buf[ICONV_ID_SIZE], unsigned int ccsid) +{ + /** + *** Convert a CCSID to the corresponding IBM iconv_open() character + *** code identifier. + *** This code is specific to the OS400 implementation of the iconv library. + *** CCSID 65535 (no conversion) is replaced by the ASCII CCSID. + *** CCSID 0 is interpreted by the OS400 as the job's CCSID. + **/ + + ccsid &= 0xFFFF; + + if(ccsid == NOCONV_CCSID) + ccsid = ASCII_CCSID; + + memset(buf, 0, ICONV_ID_SIZE); + curl_msprintf(buf, "IBMCCSID%05u0000000", ccsid); +} + + +static iconv_t +iconv_open_CCSID(unsigned int ccsidout, unsigned int ccsidin, + unsigned int cstr) +{ + char fromcode[ICONV_ID_SIZE]; + char tocode[ICONV_ID_SIZE]; + + /** + *** Like iconv_open(), but character codes are given as CCSIDs. + *** If `cstr' is non-zero, conversion is set up to stop whenever a + *** null character is encountered. + *** See iconv_open() IBM description in "National Language Support API". + **/ + + makeOS400IconvCode(fromcode, ccsidin); + makeOS400IconvCode(tocode, ccsidout); + memset(tocode + 13, 0, sizeof(tocode) - 13); /* Dest. code id format. */ + + if(cstr) + fromcode[18] = '1'; /* Set null-terminator flag. */ + + return iconv_open(tocode, fromcode); +} + + +static int +convert(char *d, size_t dlen, int dccsid, + const char *s, int slen, int sccsid) +{ + int i; + iconv_t cd; + size_t lslen; + + /** + *** Convert `sccsid'-coded `slen'-data bytes at `s' into `dccsid'-coded + *** data stored in the `dlen'-byte buffer at `d'. + *** If `slen' < 0, source string is null-terminated. + *** CCSID 65535 (no conversion) is replaced by the ASCII CCSID. + *** Return the converted destination byte count, or -1 if error. + **/ + + if(sccsid == 65535) + sccsid = ASCII_CCSID; + + if(dccsid == 65535) + dccsid = ASCII_CCSID; + + if(sccsid == dccsid) { + lslen = slen >= 0? slen: strlen(s) + 1; + i = lslen < dlen? lslen: dlen; + + if(s != d && i > 0) + memcpy(d, s, i); + + return i; + } + + if(slen < 0) { + lslen = 0; + cd = iconv_open_CCSID(dccsid, sccsid, 1); + } + else { + lslen = (size_t) slen; + cd = iconv_open_CCSID(dccsid, sccsid, 0); + } + + if(ICONV_OPEN_ERROR(cd)) + return -1; + + i = dlen; + + if((int) iconv(cd, (char * *) &s, &lslen, &d, &dlen) < 0) + i = -1; + else + i -= dlen; + + iconv_close(cd); + return i; +} + + +static char *dynconvert(int dccsid, const char *s, int slen, int sccsid) +{ + char *d; + char *cp; + size_t dlen; + int l; + static const char nullbyte = 0; + + /* Like convert, but the destination is allocated and returned. */ + + dlen = (size_t) (slen < 0? strlen(s): slen) + 1; + dlen *= MAX_CONV_EXPANSION; /* Allow some expansion. */ + d = malloc(dlen); + + if(!d) + return (char *) NULL; + + l = convert(d, dlen, dccsid, s, slen, sccsid); + + if(l < 0) { + free(d); + return (char *) NULL; + } + + if(slen < 0) { + /* Need to null-terminate even when source length is given. + Since destination code size is unknown, use a conversion to generate + terminator. */ + + int l2 = convert(d + l, dlen - l, dccsid, &nullbyte, -1, ASCII_CCSID); + + if(l2 < 0) { + free(d); + return (char *) NULL; + } + + l += l2; + } + + if((size_t) l < dlen) { + cp = realloc(d, l); /* Shorten to minimum needed. */ + + if(cp) + d = cp; + } + + return d; +} + + +static struct curl_slist * +slist_convert(int dccsid, struct curl_slist *from, int sccsid) +{ + struct curl_slist *to = (struct curl_slist *) NULL; + + for(; from; from = from->next) { + struct curl_slist *nl; + char *cp = dynconvert(dccsid, from->data, -1, sccsid); + + if(!cp) { + curl_slist_free_all(to); + return (struct curl_slist *) NULL; + } + nl = Curl_slist_append_nodup(to, cp); + if(!nl) { + curl_slist_free_all(to); + free(cp); + return NULL; + } + to = nl; + } + return to; +} + + +static char * +keyed_string(localkey_t key, const char *ascii, unsigned int ccsid) +{ + int i; + char *ebcdic; + + if(!ascii) + return (char *) NULL; + + i = MAX_CONV_EXPANSION * (strlen(ascii) + 1); + + ebcdic = Curl_thread_buffer(key, i); + if(!ebcdic) + return ebcdic; + + if(convert(ebcdic, i, ccsid, ascii, -1, ASCII_CCSID) < 0) + return (char *) NULL; + + return ebcdic; +} + + +const char * +curl_to_ccsid(const char *s, unsigned int ccsid) +{ + if(s) + s = dynconvert(ccsid, s, -1, ASCII_CCSID); + return s; +} + + +const char * +curl_from_ccsid(const char *s, unsigned int ccsid) +{ + if(s) + s = dynconvert(ASCII_CCSID, s, -1, ccsid); + return s; +} + + +char * +curl_version_ccsid(unsigned int ccsid) +{ + return keyed_string(LK_CURL_VERSION, curl_version(), ccsid); +} + + +char * +curl_easy_escape_ccsid(CURL *handle, const char *string, int length, + unsigned int sccsid, unsigned int dccsid) +{ + char *s; + char *d; + + if(!string) { + errno = EINVAL; + return (char *) NULL; + } + + s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid); + + if(!s) + return (char *) NULL; + + d = curl_easy_escape(handle, s, 0); + free(s); + + if(!d) + return (char *) NULL; + + s = dynconvert(dccsid, d, -1, ASCII_CCSID); + free(d); + return s; +} + + +char * +curl_easy_unescape_ccsid(CURL *handle, const char *string, int length, + int *outlength, + unsigned int sccsid, unsigned int dccsid) +{ + char *s; + char *d; + + if(!string) { + errno = EINVAL; + return (char *) NULL; + } + + s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid); + + if(!s) + return (char *) NULL; + + d = curl_easy_unescape(handle, s, 0, outlength); + free(s); + + if(!d) + return (char *) NULL; + + s = dynconvert(dccsid, d, -1, ASCII_CCSID); + free(d); + + if(s && outlength) + *outlength = strlen(s); + + return s; +} + + +struct curl_slist * +curl_slist_append_ccsid(struct curl_slist *list, + const char *data, unsigned int ccsid) +{ + char *s; + + s = (char *) NULL; + + if(!data) + return curl_slist_append(list, data); + + s = dynconvert(ASCII_CCSID, data, -1, ccsid); + + if(!s) + return (struct curl_slist *) NULL; + + list = curl_slist_append(list, s); + free(s); + return list; +} + + +time_t +curl_getdate_ccsid(const char *p, const time_t *unused, unsigned int ccsid) +{ + char *s; + time_t t; + + if(!p) + return curl_getdate(p, unused); + + s = dynconvert(ASCII_CCSID, p, -1, ccsid); + + if(!s) + return (time_t) -1; + + t = curl_getdate(s, unused); + free(s); + return t; +} + + +static int +convert_version_info_string(const char **stringp, + char **bufp, int *left, unsigned int ccsid) +{ + /* Helper for curl_version_info_ccsid(): convert a string if defined. + Result is stored in the `*left'-byte buffer at `*bufp'. + `*bufp' and `*left' are updated accordingly. + Return 0 if ok, else -1. */ + + if(*stringp) { + int l = convert(*bufp, *left, ccsid, *stringp, -1, ASCII_CCSID); + + if(l <= 0) + return -1; + + *stringp = *bufp; + *bufp += l; + *left -= l; + } + + return 0; +} + + +curl_version_info_data * +curl_version_info_ccsid(CURLversion stamp, unsigned int ccsid) +{ + curl_version_info_data *p; + char *cp; + int n; + int nproto; + curl_version_info_data *id; + int i; + const char **cpp; + static const size_t charfields[] = { + offsetof(curl_version_info_data, version), + offsetof(curl_version_info_data, host), + offsetof(curl_version_info_data, ssl_version), + offsetof(curl_version_info_data, libz_version), + offsetof(curl_version_info_data, ares), + offsetof(curl_version_info_data, libidn), + offsetof(curl_version_info_data, libssh_version), + offsetof(curl_version_info_data, brotli_version), + offsetof(curl_version_info_data, nghttp2_version), + offsetof(curl_version_info_data, quic_version), + offsetof(curl_version_info_data, cainfo), + offsetof(curl_version_info_data, capath), + offsetof(curl_version_info_data, zstd_version), + offsetof(curl_version_info_data, hyper_version), + offsetof(curl_version_info_data, gsasl_version), + offsetof(curl_version_info_data, feature_names) + }; + + /* The assertion below is possible, because although the second operand + is an enum member, the first is a #define. In that case, the OS/400 C + compiler seems to compare string values after substitution. */ + +#if CURLVERSION_NOW != CURLVERSION_ELEVENTH +#error curl_version_info_data structure has changed: upgrade this procedure. +#endif + + /* If caller has been compiled with a newer version, error. */ + + if(stamp > CURLVERSION_NOW) + return (curl_version_info_data *) NULL; + + p = curl_version_info(stamp); + + if(!p) + return p; + + /* Measure thread space needed. */ + + n = 0; + nproto = 0; + + if(p->protocols) { + while(p->protocols[nproto]) + n += strlen(p->protocols[nproto++]); + + n += nproto++; + } + + for(i = 0; i < sizeof(charfields) / sizeof(charfields[0]); i++) { + cpp = (const char **) ((char *) p + charfields[i]); + if(*cpp) + n += strlen(*cpp) + 1; + } + + /* Allocate thread space. */ + + n *= MAX_CONV_EXPANSION; + + if(nproto) + n += nproto * sizeof(const char *); + + cp = Curl_thread_buffer(LK_VERSION_INFO_DATA, n); + id = (curl_version_info_data *) Curl_thread_buffer(LK_VERSION_INFO, + sizeof(*id)); + + if(!id || !cp) + return (curl_version_info_data *) NULL; + + /* Copy data and convert strings. */ + + memcpy((char *) id, (char *) p, sizeof(*p)); + + if(id->protocols) { + i = nproto * sizeof(id->protocols[0]); + + id->protocols = (const char * const *) cp; + memcpy(cp, (char *) p->protocols, i); + cp += i; + n -= i; + + for(i = 0; id->protocols[i]; i++) + if(convert_version_info_string(((const char * *) id->protocols) + i, + &cp, &n, ccsid)) + return (curl_version_info_data *) NULL; + } + + for(i = 0; i < sizeof(charfields) / sizeof(charfields[0]); i++) { + cpp = (const char **) ((char *) p + charfields[i]); + if(*cpp && convert_version_info_string(cpp, &cp, &n, ccsid)) + return (curl_version_info_data *) NULL; + } + + return id; +} + + +const char * +curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid) +{ + return keyed_string(LK_EASY_STRERROR, curl_easy_strerror(error), ccsid); +} + + +const char * +curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid) +{ + return keyed_string(LK_SHARE_STRERROR, curl_share_strerror(error), ccsid); +} + + +const char * +curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid) +{ + return keyed_string(LK_MULTI_STRERROR, curl_multi_strerror(error), ccsid); +} + + +const char * +curl_url_strerror_ccsid(CURLUcode error, unsigned int ccsid) +{ + return keyed_string(LK_URL_STRERROR, curl_url_strerror(error), ccsid); +} + + +void +curl_certinfo_free_all(struct curl_certinfo *info) +{ + /* Free all memory used by certificate info. */ + if(info) { + if(info->certinfo) { + int i; + + for(i = 0; i < info->num_of_certs; i++) + curl_slist_free_all(info->certinfo[i]); + free((char *) info->certinfo); + } + free((char *) info); + } +} + + +CURLcode +curl_easy_getinfo_ccsid(CURL *curl, CURLINFO info, ...) +{ + va_list arg; + void *paramp; + CURLcode ret; + struct Curl_easy *data; + + /* WARNING: unlike curl_easy_getinfo(), the strings returned by this + procedure have to be free'ed. */ + + data = (struct Curl_easy *) curl; + va_start(arg, info); + paramp = va_arg(arg, void *); + ret = Curl_getinfo(data, info, paramp); + + if(ret == CURLE_OK) { + unsigned int ccsid; + char **cpp; + struct curl_slist **slp; + struct curl_certinfo *cipf; + struct curl_certinfo *cipt; + + switch((int) info & CURLINFO_TYPEMASK) { + + case CURLINFO_STRING: + ccsid = va_arg(arg, unsigned int); + cpp = (char * *) paramp; + + if(*cpp) { + *cpp = dynconvert(ccsid, *cpp, -1, ASCII_CCSID); + + if(!*cpp) + ret = CURLE_OUT_OF_MEMORY; + } + + break; + + case CURLINFO_SLIST: + ccsid = va_arg(arg, unsigned int); + switch(info) { + case CURLINFO_CERTINFO: + cipf = *(struct curl_certinfo * *) paramp; + if(cipf) { + cipt = (struct curl_certinfo *) malloc(sizeof(*cipt)); + if(!cipt) + ret = CURLE_OUT_OF_MEMORY; + else { + cipt->certinfo = (struct curl_slist **) + calloc(cipf->num_of_certs + + 1, sizeof(struct curl_slist *)); + if(!cipt->certinfo) + ret = CURLE_OUT_OF_MEMORY; + else { + int i; + + cipt->num_of_certs = cipf->num_of_certs; + for(i = 0; i < cipf->num_of_certs; i++) + if(cipf->certinfo[i]) + if(!(cipt->certinfo[i] = slist_convert(ccsid, + cipf->certinfo[i], + ASCII_CCSID))) { + ret = CURLE_OUT_OF_MEMORY; + break; + } + } + } + + if(ret != CURLE_OK) { + curl_certinfo_free_all(cipt); + cipt = (struct curl_certinfo *) NULL; + } + + *(struct curl_certinfo * *) paramp = cipt; + } + + break; + + case CURLINFO_TLS_SESSION: + case CURLINFO_TLS_SSL_PTR: + case CURLINFO_SOCKET: + break; + + default: + slp = (struct curl_slist **) paramp; + if(*slp) { + *slp = slist_convert(ccsid, *slp, ASCII_CCSID); + if(!*slp) + ret = CURLE_OUT_OF_MEMORY; + } + break; + } + } + } + + va_end(arg); + return ret; +} + + +static int +Curl_is_formadd_string(CURLformoption option) +{ + switch(option) { + + case CURLFORM_FILENAME: + case CURLFORM_CONTENTTYPE: + case CURLFORM_BUFFER: + case CURLFORM_FILE: + case CURLFORM_FILECONTENT: + case CURLFORM_COPYCONTENTS: + case CURLFORM_COPYNAME: + return 1; + } + + return 0; +} + + +static void +Curl_formadd_release_local(struct curl_forms *forms, int nargs, int skip) +{ + while(nargs--) + if(nargs != skip) + if(Curl_is_formadd_string(forms[nargs].option)) + if(forms[nargs].value) + free((char *) forms[nargs].value); + + free((char *) forms); +} + + +static int +Curl_formadd_convert(struct curl_forms *forms, + int formx, int lengthx, unsigned int ccsid) +{ + int l; + char *cp; + char *cp2; + + if(formx < 0 || !forms[formx].value) + return 0; + + if(lengthx >= 0) + l = (int) forms[lengthx].value; + else + l = strlen(forms[formx].value) + 1; + + cp = malloc(MAX_CONV_EXPANSION * l); + + if(!cp) + return -1; + + l = convert(cp, MAX_CONV_EXPANSION * l, ASCII_CCSID, + forms[formx].value, l, ccsid); + + if(l < 0) { + free(cp); + return -1; + } + + cp2 = realloc(cp, l); /* Shorten buffer to the string size. */ + + if(cp2) + cp = cp2; + + forms[formx].value = cp; + + if(lengthx >= 0) + forms[lengthx].value = (char *) l; /* Update length after conversion. */ + + return l; +} + + +CURLFORMcode +curl_formadd_ccsid(struct curl_httppost **httppost, + struct curl_httppost **last_post, ...) +{ + va_list arg; + CURLformoption option; + CURLFORMcode result; + struct curl_forms *forms; + struct curl_forms *lforms; + struct curl_forms *tforms; + unsigned int lformlen; + const char *value; + unsigned int ccsid; + int nargs; + int namex; + int namelengthx; + int contentx; + int lengthx; + unsigned int contentccsid; + unsigned int nameccsid; + + /* A single curl_formadd() call cannot be split in several calls to deal + with all parameters: the original parameters are thus copied to a local + curl_forms array and converted to ASCII when needed. + CURLFORM_PTRNAME is processed as if it were CURLFORM_COPYNAME. + CURLFORM_COPYNAME and CURLFORM_NAMELENGTH occurrence order in + parameters is not defined; for this reason, the actual conversion is + delayed to the end of parameter processing. The same applies to + CURLFORM_COPYCONTENTS/CURLFORM_CONTENTSLENGTH, but these may appear + several times in the parameter list; the problem resides here in knowing + which CURLFORM_CONTENTSLENGTH applies to which CURLFORM_COPYCONTENTS and + when we can be sure to have both info for conversion: end of parameter + list is such a point, but CURLFORM_CONTENTTYPE is also used here as a + natural separator between content data definitions; this seems to be + in accordance with FormAdd() behavior. */ + + /* Allocate the local curl_forms array. */ + + lformlen = ALLOC_GRANULE; + lforms = malloc(lformlen * sizeof(*lforms)); + + if(!lforms) + return CURL_FORMADD_MEMORY; + + /* Process the arguments, copying them into local array, latching conversion + indexes and converting when needed. */ + + result = CURL_FORMADD_OK; + nargs = 0; + contentx = -1; + lengthx = -1; + namex = -1; + namelengthx = -1; + forms = (struct curl_forms *) NULL; + va_start(arg, last_post); + + for(;;) { + /* Make sure there is still room for an item in local array. */ + + if(nargs >= lformlen) { + lformlen += ALLOC_GRANULE; + tforms = realloc(lforms, lformlen * sizeof(*lforms)); + + if(!tforms) { + result = CURL_FORMADD_MEMORY; + break; + } + + lforms = tforms; + } + + /* Get next option. */ + + if(forms) { + /* Get option from array. */ + + option = forms->option; + value = forms->value; + forms++; + } + else { + /* Get option from arguments. */ + + option = va_arg(arg, CURLformoption); + + if(option == CURLFORM_END) + break; + } + + /* Dispatch by option. */ + + switch(option) { + + case CURLFORM_END: + forms = (struct curl_forms *) NULL; /* Leave array mode. */ + continue; + + case CURLFORM_ARRAY: + if(!forms) { + forms = va_arg(arg, struct curl_forms *); + continue; + } + + result = CURL_FORMADD_ILLEGAL_ARRAY; + break; + + case CURLFORM_COPYNAME: + option = CURLFORM_PTRNAME; /* Static for now. */ + + case CURLFORM_PTRNAME: + if(namex >= 0) + result = CURL_FORMADD_OPTION_TWICE; + + namex = nargs; + + if(!forms) { + value = va_arg(arg, char *); + nameccsid = (unsigned int) va_arg(arg, long); + } + else { + nameccsid = (unsigned int) forms->value; + forms++; + } + + break; + + case CURLFORM_COPYCONTENTS: + if(contentx >= 0) + result = CURL_FORMADD_OPTION_TWICE; + + contentx = nargs; + + if(!forms) { + value = va_arg(arg, char *); + contentccsid = (unsigned int) va_arg(arg, long); + } + else { + contentccsid = (unsigned int) forms->value; + forms++; + } + + break; + + case CURLFORM_PTRCONTENTS: + case CURLFORM_BUFFERPTR: + if(!forms) + value = va_arg(arg, char *); /* No conversion. */ + + break; + + case CURLFORM_CONTENTSLENGTH: + lengthx = nargs; + + if(!forms) + value = (char *) va_arg(arg, long); + + break; + + case CURLFORM_CONTENTLEN: + lengthx = nargs; + + if(!forms) + value = (char *) va_arg(arg, curl_off_t); + + break; + + case CURLFORM_NAMELENGTH: + namelengthx = nargs; + + if(!forms) + value = (char *) va_arg(arg, long); + + break; + + case CURLFORM_BUFFERLENGTH: + if(!forms) + value = (char *) va_arg(arg, long); + + break; + + case CURLFORM_CONTENTHEADER: + if(!forms) + value = (char *) va_arg(arg, struct curl_slist *); + + break; + + case CURLFORM_STREAM: + if(!forms) + value = (char *) va_arg(arg, void *); + + break; + + case CURLFORM_CONTENTTYPE: + /* If a previous content has been encountered, convert it now. */ + + if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) { + result = CURL_FORMADD_MEMORY; + break; + } + + contentx = -1; + lengthx = -1; + /* Fall into default. */ + + default: + /* Must be a convertible string. */ + + if(!Curl_is_formadd_string(option)) { + result = CURL_FORMADD_UNKNOWN_OPTION; + break; + } + + if(!forms) { + value = va_arg(arg, char *); + ccsid = (unsigned int) va_arg(arg, long); + } + else { + ccsid = (unsigned int) forms->value; + forms++; + } + + /* Do the conversion. */ + + lforms[nargs].value = value; + + if(Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) { + result = CURL_FORMADD_MEMORY; + break; + } + + value = lforms[nargs].value; + } + + if(result != CURL_FORMADD_OK) + break; + + lforms[nargs].value = value; + lforms[nargs++].option = option; + } + + va_end(arg); + + /* Convert the name and the last content, now that we know their lengths. */ + + if(result == CURL_FORMADD_OK && namex >= 0) { + if(Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0) + result = CURL_FORMADD_MEMORY; + else + lforms[namex].option = CURLFORM_COPYNAME; /* Force copy. */ + } + + if(result == CURL_FORMADD_OK) { + if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) + result = CURL_FORMADD_MEMORY; + else + contentx = -1; + } + + /* Do the formadd with our converted parameters. */ + + if(result == CURL_FORMADD_OK) { + lforms[nargs].option = CURLFORM_END; + result = curl_formadd(httppost, last_post, + CURLFORM_ARRAY, lforms, CURLFORM_END); + } + + /* Terminate. */ + + Curl_formadd_release_local(lforms, nargs, contentx); + return result; +} + + +struct cfcdata { + curl_formget_callback append; + void * arg; + unsigned int ccsid; +}; + + +static size_t +Curl_formget_callback_ccsid(void *arg, const char *buf, size_t len) +{ + struct cfcdata *p; + char *b; + int l; + size_t ret; + + p = (struct cfcdata *) arg; + + if((long) len <= 0) + return (*p->append)(p->arg, buf, len); + + b = malloc(MAX_CONV_EXPANSION * len); + + if(!b) + return (size_t) -1; + + l = convert(b, MAX_CONV_EXPANSION * len, p->ccsid, buf, len, ASCII_CCSID); + + if(l < 0) { + free(b); + return (size_t) -1; + } + + ret = (*p->append)(p->arg, b, l); + free(b); + return ret == l? len: -1; +} + + +int +curl_formget_ccsid(struct curl_httppost *form, void *arg, + curl_formget_callback append, unsigned int ccsid) +{ + struct cfcdata lcfc; + + lcfc.append = append; + lcfc.arg = arg; + lcfc.ccsid = ccsid; + return curl_formget(form, (void *) &lcfc, Curl_formget_callback_ccsid); +} + + +CURLcode +curl_easy_setopt_ccsid(CURL *easy, CURLoption tag, ...) +{ + CURLcode result; + va_list arg; + char *s; + char *cp = NULL; + unsigned int ccsid; + curl_off_t pfsize; + + va_start(arg, tag); + + switch(tag) { + + /* BEGIN TRANSLATABLE STRING OPTIONS */ + /* Keep option symbols in alphanumeric order and retain the BEGIN/END + armor comments. */ + case CURLOPT_ABSTRACT_UNIX_SOCKET: + case CURLOPT_ACCEPT_ENCODING: + case CURLOPT_ALTSVC: + case CURLOPT_AWS_SIGV4: + case CURLOPT_CAINFO: + case CURLOPT_CAPATH: + case CURLOPT_COOKIE: + case CURLOPT_COOKIEFILE: + case CURLOPT_COOKIEJAR: + case CURLOPT_COOKIELIST: + case CURLOPT_CRLFILE: + case CURLOPT_CUSTOMREQUEST: + case CURLOPT_DEFAULT_PROTOCOL: + case CURLOPT_DNS_INTERFACE: + case CURLOPT_DNS_LOCAL_IP4: + case CURLOPT_DNS_LOCAL_IP6: + case CURLOPT_DNS_SERVERS: + case CURLOPT_DOH_URL: + case CURLOPT_EGDSOCKET: + case CURLOPT_FTPPORT: + case CURLOPT_FTP_ACCOUNT: + case CURLOPT_FTP_ALTERNATIVE_TO_USER: + case CURLOPT_HAPROXY_CLIENT_IP: + case CURLOPT_HSTS: + case CURLOPT_INTERFACE: + case CURLOPT_ISSUERCERT: + case CURLOPT_KEYPASSWD: + case CURLOPT_KRBLEVEL: + case CURLOPT_LOGIN_OPTIONS: + case CURLOPT_MAIL_AUTH: + case CURLOPT_MAIL_FROM: + case CURLOPT_NETRC_FILE: + case CURLOPT_NOPROXY: + case CURLOPT_PASSWORD: + case CURLOPT_PINNEDPUBLICKEY: + case CURLOPT_PRE_PROXY: + case CURLOPT_PROTOCOLS_STR: + case CURLOPT_PROXY: + case CURLOPT_PROXYPASSWORD: + case CURLOPT_PROXYUSERNAME: + case CURLOPT_PROXYUSERPWD: + case CURLOPT_PROXY_CAINFO: + case CURLOPT_PROXY_CAPATH: + case CURLOPT_PROXY_CRLFILE: + case CURLOPT_PROXY_ISSUERCERT: + case CURLOPT_PROXY_KEYPASSWD: + case CURLOPT_PROXY_PINNEDPUBLICKEY: + case CURLOPT_PROXY_SERVICE_NAME: + case CURLOPT_PROXY_SSLCERT: + case CURLOPT_PROXY_SSLCERTTYPE: + case CURLOPT_PROXY_SSLKEY: + case CURLOPT_PROXY_SSLKEYTYPE: + case CURLOPT_PROXY_SSL_CIPHER_LIST: + case CURLOPT_PROXY_TLS13_CIPHERS: + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + case CURLOPT_PROXY_TLSAUTH_TYPE: + case CURLOPT_PROXY_TLSAUTH_USERNAME: + case CURLOPT_RANDOM_FILE: + case CURLOPT_RANGE: + case CURLOPT_REDIR_PROTOCOLS_STR: + case CURLOPT_REFERER: + case CURLOPT_REQUEST_TARGET: + case CURLOPT_RTSP_SESSION_ID: + case CURLOPT_RTSP_STREAM_URI: + case CURLOPT_RTSP_TRANSPORT: + case CURLOPT_SASL_AUTHZID: + case CURLOPT_SERVICE_NAME: + case CURLOPT_SOCKS5_GSSAPI_SERVICE: + case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: + case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256: + case CURLOPT_SSH_KNOWNHOSTS: + case CURLOPT_SSH_PRIVATE_KEYFILE: + case CURLOPT_SSH_PUBLIC_KEYFILE: + case CURLOPT_SSLCERT: + case CURLOPT_SSLCERTTYPE: + case CURLOPT_SSLENGINE: + case CURLOPT_SSLKEY: + case CURLOPT_SSLKEYTYPE: + case CURLOPT_SSL_CIPHER_LIST: + case CURLOPT_SSL_EC_CURVES: + case CURLOPT_TLS13_CIPHERS: + case CURLOPT_TLSAUTH_PASSWORD: + case CURLOPT_TLSAUTH_TYPE: + case CURLOPT_TLSAUTH_USERNAME: + case CURLOPT_UNIX_SOCKET_PATH: + case CURLOPT_URL: + case CURLOPT_USERAGENT: + case CURLOPT_USERNAME: + case CURLOPT_USERPWD: + case CURLOPT_XOAUTH2_BEARER: + /* END TRANSLATABLE STRING OPTIONS */ + s = va_arg(arg, char *); + ccsid = va_arg(arg, unsigned int); + + if(s) { + s = dynconvert(ASCII_CCSID, s, -1, ccsid); + + if(!s) { + result = CURLE_OUT_OF_MEMORY; + break; + } + } + + result = curl_easy_setopt(easy, tag, s); + free(s); + break; + + case CURLOPT_COPYPOSTFIELDS: + /* Special case: byte count may have been given by CURLOPT_POSTFIELDSIZE + prior to this call. In this case, convert the given byte count and + replace the length according to the conversion result. */ + s = va_arg(arg, char *); + ccsid = va_arg(arg, unsigned int); + + pfsize = easy->set.postfieldsize; + + if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) { + result = curl_easy_setopt(easy, CURLOPT_COPYPOSTFIELDS, s); + break; + } + + if(pfsize == -1) { + /* Data is null-terminated. */ + s = dynconvert(ASCII_CCSID, s, -1, ccsid); + + if(!s) { + result = CURLE_OUT_OF_MEMORY; + break; + } + } + else { + /* Data length specified. */ + size_t len; + + if(pfsize < 0 || pfsize > SIZE_MAX) { + result = CURLE_OUT_OF_MEMORY; + break; + } + + len = pfsize; + pfsize = len * MAX_CONV_EXPANSION; + + if(pfsize > SIZE_MAX) + pfsize = SIZE_MAX; + + cp = malloc(pfsize); + + if(!cp) { + result = CURLE_OUT_OF_MEMORY; + break; + } + + pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid); + + if(pfsize < 0) { + result = CURLE_OUT_OF_MEMORY; + break; + } + + easy->set.postfieldsize = pfsize; /* Replace data size. */ + s = cp; + } + + result = curl_easy_setopt(easy, CURLOPT_POSTFIELDS, s); + easy->set.str[STRING_COPYPOSTFIELDS] = s; /* Give to library. */ + break; + + default: + if(tag / 10000 == CURLOPTTYPE_BLOB) { + struct curl_blob *bp = va_arg(arg, struct curl_blob *); + struct curl_blob blob; + + ccsid = va_arg(arg, unsigned int); + + if(bp && bp->data && bp->len && + ccsid != NOCONV_CCSID && ccsid != ASCII_CCSID) { + pfsize = (curl_off_t) bp->len * MAX_CONV_EXPANSION; + + if(pfsize > SIZE_MAX) + pfsize = SIZE_MAX; + + cp = malloc(pfsize); + + if(!cp) { + result = CURLE_OUT_OF_MEMORY; + break; + } + + pfsize = convert(cp, pfsize, ASCII_CCSID, bp->data, bp->len, ccsid); + + if(pfsize < 0) { + result = CURLE_OUT_OF_MEMORY; + break; + } + + blob.data = cp; + blob.len = pfsize; + blob.flags = bp->flags | CURL_BLOB_COPY; + bp = &blob; + } + result = curl_easy_setopt(easy, tag, &blob); + break; + } + FALLTHROUGH(); + case CURLOPT_ERRORBUFFER: /* This is an output buffer. */ + result = Curl_vsetopt(easy, tag, arg); + break; + } + + va_end(arg); + free(cp); + return result; +} + + +/* ILE/RPG helper functions. */ + +char * +curl_form_long_value(long value) +{ + /* ILE/RPG cannot cast an integer to a pointer. This procedure does it. */ + + return (char *) value; +} + + +CURLcode +curl_easy_setopt_RPGnum_(CURL *easy, CURLoption tag, curl_off_t arg) +{ + /* ILE/RPG procedure overloading cannot discriminate between different + size and/or signedness of format arguments. This provides a generic + wrapper that adapts size to the given tag expectation. + This procedure is not intended to be explicitly called from user code. */ + if(tag / 10000 != CURLOPTTYPE_OFF_T) + return curl_easy_setopt(easy, tag, (long) arg); + return curl_easy_setopt(easy, tag, arg); +} + + +CURLcode +curl_multi_setopt_RPGnum_(CURLM *multi, CURLMoption tag, curl_off_t arg) +{ + /* Likewise, for multi handle. */ + if(tag / 10000 != CURLOPTTYPE_OFF_T) + return curl_multi_setopt(multi, tag, (long) arg); + return curl_multi_setopt(multi, tag, arg); +} + + +char * +curl_pushheader_bynum_cssid(struct curl_pushheaders *h, + size_t num, unsigned int ccsid) +{ + char *d = (char *) NULL; + char *s = curl_pushheader_bynum(h, num); + + if(s) + d = dynconvert(ccsid, s, -1, ASCII_CCSID); + + return d; +} + + +char * +curl_pushheader_byname_ccsid(struct curl_pushheaders *h, const char *header, + unsigned int ccsidin, unsigned int ccsidout) +{ + char *d = (char *) NULL; + + if(header) { + header = dynconvert(ASCII_CCSID, header, -1, ccsidin); + + if(header) { + char *s = curl_pushheader_byname(h, header); + free((char *) header); + + if(s) + d = dynconvert(ccsidout, s, -1, ASCII_CCSID); + } + } + + return d; +} + +static CURLcode +mime_string_call(curl_mimepart *part, const char *string, unsigned int ccsid, + CURLcode (*mimefunc)(curl_mimepart *part, const char *string)) +{ + char *s = (char *) NULL; + CURLcode result; + + if(!string) + return mimefunc(part, string); + s = dynconvert(ASCII_CCSID, string, -1, ccsid); + if(!s) + return CURLE_OUT_OF_MEMORY; + + result = mimefunc(part, s); + free(s); + return result; +} + +CURLcode +curl_mime_name_ccsid(curl_mimepart *part, const char *name, unsigned int ccsid) +{ + return mime_string_call(part, name, ccsid, curl_mime_name); +} + +CURLcode +curl_mime_filename_ccsid(curl_mimepart *part, + const char *filename, unsigned int ccsid) +{ + return mime_string_call(part, filename, ccsid, curl_mime_filename); +} + +CURLcode +curl_mime_type_ccsid(curl_mimepart *part, + const char *mimetype, unsigned int ccsid) +{ + return mime_string_call(part, mimetype, ccsid, curl_mime_type); +} + +CURLcode +curl_mime_encoder_ccsid(curl_mimepart *part, + const char *encoding, unsigned int ccsid) +{ + return mime_string_call(part, encoding, ccsid, curl_mime_encoder); +} + +CURLcode +curl_mime_filedata_ccsid(curl_mimepart *part, + const char *filename, unsigned int ccsid) +{ + return mime_string_call(part, filename, ccsid, curl_mime_filedata); +} + +CURLcode +curl_mime_data_ccsid(curl_mimepart *part, + const char *data, size_t datasize, unsigned int ccsid) +{ + char *s = (char *) NULL; + CURLcode result; + + if(!data) + return curl_mime_data(part, data, datasize); + s = dynconvert(ASCII_CCSID, data, datasize, ccsid); + if(!s) + return CURLE_OUT_OF_MEMORY; + + result = curl_mime_data(part, s, datasize); + free(s); + return result; +} + +CURLUcode +curl_url_get_ccsid(CURLU *handle, CURLUPart what, char **part, + unsigned int flags, unsigned int ccsid) +{ + char *s = (char *)NULL; + CURLUcode result; + + if(!part) + return CURLUE_BAD_PARTPOINTER; + + *part = (char *)NULL; + result = curl_url_get(handle, what, &s, flags); + if(result == CURLUE_OK) { + if(s) { + *part = dynconvert(ccsid, s, -1, ASCII_CCSID); + if(!*part) + result = CURLUE_OUT_OF_MEMORY; + } + } + if(s) + free(s); + return result; +} + +CURLUcode +curl_url_set_ccsid(CURLU *handle, CURLUPart what, const char *part, + unsigned int flags, unsigned int ccsid) +{ + char *s = (char *)NULL; + CURLUcode result; + + if(part) { + s = dynconvert(ASCII_CCSID, part, -1, ccsid); + if(!s) + return CURLUE_OUT_OF_MEMORY; + } + result = curl_url_set(handle, what, s, flags); + if(s) + free(s); + return result; +} + +const struct curl_easyoption * +curl_easy_option_by_name_ccsid(const char *name, unsigned int ccsid) +{ + const struct curl_easyoption *option = NULL; + + if(name) { + char *s = dynconvert(ASCII_CCSID, name, -1, ccsid); + + if(s) { + option = curl_easy_option_by_name(s); + free(s); + } + } + + return option; +} + +/* Return option name in the given ccsid. */ +const char * +curl_easy_option_get_name_ccsid(const struct curl_easyoption *option, + unsigned int ccsid) +{ + char *name = NULL; + + if(option && option->name) + name = dynconvert(ccsid, option->name, -1, ASCII_CCSID); + + return (const char *) name; +} + +/* Header API CCSID support. */ +CURLHcode +curl_easy_header_ccsid(CURL *easy, const char *name, size_t index, + unsigned int origin, int request, + struct curl_header **hout, unsigned int ccsid) +{ + CURLHcode result = CURLHE_BAD_ARGUMENT; + + if(name) { + char *s = dynconvert(ASCII_CCSID, name, -1, ccsid); + + result = CURLHE_OUT_OF_MEMORY; + if(s) { + result = curl_easy_header(easy, s, index, origin, request, hout); + free(s); + } + } + + return result; +} diff --git a/packages/OS400/ccsidcurl.h b/packages/OS400/ccsidcurl.h new file mode 100644 index 0000000..ab01d32 --- /dev/null +++ b/packages/OS400/ccsidcurl.h @@ -0,0 +1,113 @@ +#ifndef CURLINC_CCSIDCURL_H +#define CURLINC_CCSIDCURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ +#include "curl.h" +#include "easy.h" +#include "multi.h" + + +CURL_EXTERN char *curl_version_ccsid(unsigned int ccsid); +CURL_EXTERN char *curl_easy_escape_ccsid(CURL *handle, + const char *string, int length, + unsigned int sccsid, + unsigned int dccsid); +CURL_EXTERN char *curl_easy_unescape_ccsid(CURL *handle, const char *string, + int length, int *outlength, + unsigned int sccsid, + unsigned int dccsid); +CURL_EXTERN struct curl_slist *curl_slist_append_ccsid(struct curl_slist *l, + const char *data, + unsigned int ccsid); +CURL_EXTERN time_t curl_getdate_ccsid(const char *p, const time_t *unused, + unsigned int ccsid); +CURL_EXTERN curl_version_info_data *curl_version_info_ccsid(CURLversion stamp, + unsigned int cid); +CURL_EXTERN const char *curl_easy_strerror_ccsid(CURLcode error, + unsigned int ccsid); +CURL_EXTERN const char *curl_share_strerror_ccsid(CURLSHcode error, + unsigned int ccsid); +CURL_EXTERN const char *curl_multi_strerror_ccsid(CURLMcode error, + unsigned int ccsid); +CURL_EXTERN CURLcode curl_easy_getinfo_ccsid(CURL *curl, CURLINFO info, ...); +CURL_EXTERN CURLFORMcode curl_formadd_ccsid(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); +CURL_EXTERN char *curl_form_long_value(long value); +CURL_EXTERN int curl_formget_ccsid(struct curl_httppost *form, void *arg, + curl_formget_callback append, + unsigned int ccsid); +CURL_EXTERN CURLcode curl_easy_setopt_ccsid(CURL *curl, CURLoption tag, ...); +CURL_EXTERN void curl_certinfo_free_all(struct curl_certinfo *info); +CURL_EXTERN char *curl_pushheader_bynum_cssid(struct curl_pushheaders *h, + size_t num, unsigned int ccsid); +CURL_EXTERN char *curl_pushheader_byname_ccsid(struct curl_pushheaders *h, + const char *header, + unsigned int ccsidin, + unsigned int ccsidout); +CURL_EXTERN CURLcode curl_mime_name_ccsid(curl_mimepart *part, + const char *name, + unsigned int ccsid); +CURL_EXTERN CURLcode curl_mime_filename_ccsid(curl_mimepart *part, + const char *filename, + unsigned int ccsid); +CURL_EXTERN CURLcode curl_mime_type_ccsid(curl_mimepart *part, + const char *mimetype, + unsigned int ccsid); +CURL_EXTERN CURLcode curl_mime_encoder_ccsid(curl_mimepart *part, + const char *encoding, + unsigned int ccsid); +CURL_EXTERN CURLcode curl_mime_filedata_ccsid(curl_mimepart *part, + const char *filename, + unsigned int ccsid); +CURL_EXTERN CURLcode curl_mime_data_ccsid(curl_mimepart *part, + const char *data, size_t datasize, + unsigned int ccsid); +CURL_EXTERN CURLUcode curl_url_get_ccsid(CURLU *handle, CURLUPart what, + char **part, unsigned int flags, + unsigned int ccsid); +CURL_EXTERN CURLUcode curl_url_set_ccsid(CURLU *handle, CURLUPart what, + const char *part, unsigned int flags, + unsigned int ccsid); +CURL_EXTERN const struct curl_easyoption *curl_easy_option_by_name_ccsid( + const char *name, unsigned int ccsid); +CURL_EXTERN const char *curl_easy_option_get_name_ccsid( + const struct curl_easyoption *option, + unsigned int ccsid); +CURL_EXTERN const char *curl_url_strerror_ccsid(CURLUcode error, + unsigned int ccsid); +CURL_EXTERN CURLHcode curl_easy_header_ccsid(CURL *easy, const char *name, + size_t index, unsigned int origin, + int request, + struct curl_header **hout, + unsigned int ccsid); +CURL_EXTERN const char *curl_from_ccsid(const char *s, unsigned int ccsid); +CURL_EXTERN const char *curl_to_ccsid(const char *s, unsigned int ccsid); +CURL_EXTERN CURLcode curl_easy_setopt_RPGnum_(CURL *easy, + CURLoption tag, curl_off_t arg); +CURL_EXTERN CURLcode curl_multi_setopt_RPGnum_(CURLM *multi, CURLMoption tag, + curl_off_t arg); + +#endif diff --git a/packages/OS400/config400.default b/packages/OS400/config400.default new file mode 100644 index 0000000..91a8277 --- /dev/null +++ b/packages/OS400/config400.default @@ -0,0 +1,55 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# Tunable configuration parameters. + +setenv TARGETLIB 'CURL' # Target OS/400 program library. +setenv STATBNDDIR 'CURL_A' # Static binding directory. +setenv DYNBNDDIR 'CURL' # Dynamic binding directory. +setenv SRVPGM "CURL.${SONAME}" # Service program. +setenv CURLPGM 'CURL' # CLI tool bound program. +setenv CURLCMD 'CURL' # CL command name. +setenv CURLCLI 'CURLCL' # CL interface program. +setenv TGTCCSID '500' # Target CCSID of objects. +setenv DEBUG '*ALL' # Debug level. +setenv OPTIMIZE '10' # Optimization level +setenv OUTPUT '*NONE' # Compilation output option. +setenv TGTRLS '*CURRENT' # Target OS release. +setenv IFSDIR '/curl' # Installation IFS directory. +setenv QADRTDIR '/QIBM/ProdData/qadrt' # QADRT IFS directory. + +# Define ZLIB availability and locations. + +setenv WITH_ZLIB 0 # Define to 1 to enable. +setenv ZLIB_INCLUDE '/zlib/include' # ZLIB include IFS directory. +setenv ZLIB_LIB 'ZLIB' # ZLIB library. +setenv ZLIB_BNDDIR 'ZLIB_A' # ZLIB binding directory. + +# Define LIBSSH2 availability and locations. + +setenv WITH_LIBSSH2 0 # Define to 1 to enable. +setenv LIBSSH2_INCLUDE '/libssh2/include' # LIBSSH2 include IFS directory. +setenv LIBSSH2_LIB 'LIBSSH2' # LIBSSH2 library. +setenv LIBSSH2_BNDDIR 'LIBSSH2_A' # LIBSSH2 binding directory. diff --git a/packages/OS400/curl.cmd b/packages/OS400/curl.cmd new file mode 100644 index 0000000..ae7a788 --- /dev/null +++ b/packages/OS400/curl.cmd @@ -0,0 +1,32 @@ +/*****************************************************************************/ +/* _ _ ____ _ */ +/* Project ___| | | | _ \| | */ +/* / __| | | | |_) | | */ +/* | (__| |_| | _ <| |___ */ +/* \___|\___/|_| \_\_____| */ +/* */ +/* Copyright (C) Daniel Stenberg, , et al. */ +/* */ +/* This software is licensed as described in the file COPYING, which */ +/* you should have received as part of this distribution. The terms */ +/* are also available at https://curl.se/docs/copyright.html. */ +/* */ +/* You may opt to use, copy, modify, merge, publish, distribute and/or sell */ +/* copies of the Software, and permit persons to whom the Software is */ +/* furnished to do so, under the terms of the COPYING file. */ +/* */ +/* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY */ +/* KIND, either express or implied. */ +/* */ +/* SPDX-License-Identifier: curl */ +/* */ +/* */ +/*****************************************************************************/ + +/* Use program CURLCL as interface to the curl command line tool */ + + CMD PROMPT('File transfer utility') + + PARM KWD(CMDARGS) TYPE(*CHAR) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) MIN(1) + + PROMPT('Curl command arguments') diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in new file mode 100644 index 0000000..b3a4e9e --- /dev/null +++ b/packages/OS400/curl.inc.in @@ -0,0 +1,3425 @@ + ************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * + ************************************************************************** + * + /if not defined(CURL_CURL_INC_) + /define CURL_CURL_INC_ + * + * WARNING: this file should be kept in sync with C include files. + * + ************************************************************************** + * Constants + ************************************************************************** + * + d LIBCURL_VERSION... + d c '@LIBCURL_VERSION@' + d LIBCURL_VERSION_MAJOR... + d c @LIBCURL_VERSION_MAJOR@ + d LIBCURL_VERSION_MINOR... + d c @LIBCURL_VERSION_MINOR@ + d LIBCURL_VERSION_PATCH... + d c @LIBCURL_VERSION_PATCH@ + d LIBCURL_VERSION_NUM... + d c X'00@LIBCURL_VERSION_NUM@' + d LIBCURL_TIMESTAMP... + d c '@LIBCURL_TIMESTAMP@' + * + d CURL_SOCKET_BAD... + d c -1 + d CURL_SOCKET_TIMEOUT... + d c -1 + * + /if not defined(CURL_MAX_WRITE_SIZE) + /define CURL_MAX_WRITE_SIZE + d CURL_MAX_WRITE_SIZE... + d c 16384 + /endif + * + /if not defined(CURL_MAX_HTTP_HEADER) + /define CURL_MAX_HTTP_HEADER + d CURL_MAX_HTTP_HEADER... + d c 102400 + /endif + * + d CURLINFO_STRING... + d c X'00100000' + d CURLINFO_LONG c X'00200000' + d CURLINFO_DOUBLE... + d c X'00300000' + d CURLINFO_SLIST c X'00400000' + d CURLINFO_PTR c X'00400000' + d CURLINFO_SOCKET... + d c X'00500000' + d CURLINFO_OFF_T... + d c X'00600000' + d CURLINFO_MASK c X'000FFFFF' + d CURLINFO_TYPEMASK... + d c X'00F00000' + * + d CURL_GLOBAL_SSL... + d c X'00000001' + d CURL_GLOBAL_WIN32... + d c X'00000002' + d CURL_GLOBAL_ALL... + d c X'00000003' + d CURL_GLOBAL_NOTHING... + d c X'00000000' + d CURL_GLOBAL_DEFAULT... + d c X'00000003' + d CURL_GLOBAL_ACK_EINTR... + d c X'00000004' + * + d CURL_VERSION_IPV6... + d c X'00000001' + d CURL_VERSION_KERBEROS4... + d c X'00000002' + d CURL_VERSION_SSL... + d c X'00000004' + d CURL_VERSION_LIBZ... + d c X'00000008' + d CURL_VERSION_NTLM... + d c X'00000010' + d CURL_VERSION_GSSNEGOTIATE... + d c X'00000020' Deprecated + d CURL_VERSION_DEBUG... + d c X'00000040' + d CURL_VERSION_ASYNCHDNS... + d c X'00000080' + d CURL_VERSION_SPNEGO... + d c X'00000100' + d CURL_VERSION_LARGEFILE... + d c X'00000200' + d CURL_VERSION_IDN... + d c X'00000400' + d CURL_VERSION_SSPI... + d c X'00000800' + d CURL_VERSION_CONV... + d c X'00001000' + d CURL_VERSION_CURLDEBUG... + d c X'00002000' + d CURL_VERSION_TLSAUTH_SRP... + d c X'00004000' + d CURL_VERSION_NTLM_WB... + d c X'00008000' + d CURL_VERSION_HTTP2... + d c X'00010000' + d CURL_VERSION_GSSAPI... + d c X'00020000' + d CURL_VERSION_KERBEROS5... + d c X'00040000' + d CURL_VERSION_UNIX_SOCKETS... + d c X'00080000' + d CURL_VERSION_PSL... + d c X'00100000' + d CURL_VERSION_HTTPS_PROXY... + d c X'00200000' + d CURL_VERSION_MULTI_SSL... + d c X'00400000' + d CURL_VERSION_BROTLI... + d c X'00800000' + d CURL_VERSION_ALTSVC... + d c X'01000000' + d CURL_VERSION_HTTP3... + d c X'02000000' + d CURL_VERSION_ZSTD... + d c X'04000000' + d CURL_VERSION_UNICODE... + d c X'08000000' + d CURL_VERSION_HSTS... + d c X'10000000' + d CURL_VERSION_GSASL... + d c X'20000000' + d CURL_VERSION_THREADSAFE... + d c X'40000000' + * + d CURL_HTTPPOST_FILENAME... + d c X'00000001' + d CURL_HTTPPOST_READFILE... + d c X'00000002' + d CURL_HTTPPOST_PTRNAME... + d c X'00000004' + d CURL_HTTPPOST_PTRCONTENTS... + d c X'00000008' + d CURL_HTTPPOST_BUFFER... + d c X'00000010' + d CURL_HTTPPOST_PTRBUFFER... + d c X'00000020' + d CURL_HTTPPOST_CALLBACK... + d c X'00000040' + d CURL_HTTPPOST_LARGE... + d c X'00000080' + * + d CURL_SEEKFUNC_OK... + d c 0 + d CURL_SEEKFUNC_FAIL... + d c 1 + d CURL_SEEKFUNC_CANTSEEK... + d c 2 + * + d CURL_READFUNC_ABORT... + d c X'10000000' + d CURL_READFUNC_PAUSE... + d c X'10000001' + * + d CURL_WRITEFUNC_PAUSE... + d c X'10000001' + d CURL_WRITEFUNC_ERROR... + d c X'FFFFFFFF' + * + d CURL_TRAILERFUNC_OK... + d c 0 + d CURL_TRAILERFUNC_ABORT... + d c 1 + * + d CURL_PREREQFUNC_OK... + d c 0 + d CURL_PREREQFUNC_ABORT... + d c 1 + * + d CURLAUTH_NONE c X'00000000' + d CURLAUTH_BASIC c X'00000001' + d CURLAUTH_DIGEST... + d c X'00000002' + d CURLAUTH_NEGOTIATE... + d c X'00000004' + d CURLAUTH_NTLM c X'00000008' + d CURLAUTH_DIGEST_IE... + d c X'00000010' + d CURLAUTH_NTLM_WB... + d c X'00000020' + d CURLAUTH_BEARER... + d c X'00000040' + d CURLAUTH_AWS_SIGV4... + d c X'00000080' + d CURLAUTH_ONLY... + d c X'80000000' + d CURLAUTH_ANY c X'7FFFFFEF' + d CURLAUTH_ANYSAFE... + d c X'7FFFFFEE' + * + d CURLSSH_AUTH_ANY... + d c X'7FFFFFFF' + d CURLSSH_AUTH_NONE... + d c X'00000000' + d CURLSSH_AUTH_PUBLICKEY... + d c X'00000001' + d CURLSSH_AUTH_PASSWORD... + d c X'00000002' + d CURLSSH_AUTH_HOST... + d c X'00000004' + d CURLSSH_AUTH_KEYBOARD... + d c X'00000008' + d CURLSSH_AUTH_AGENT... + d c X'00000010' + d CURLSSH_AUTH_DEFAULT... + d c X'7FFFFFFF' CURLSSH_AUTH_ANY + * + d CURLGSSAPI_DELEGATION_NONE... + d c 0 + d CURLGSSAPI_DELEGATION_POLICY_FLAG... + d c X'00000001' + d CURLGSSAPI_DELEGATION_FLAG... + d c X'00000002' + * + d CURL_ERROR_SIZE... + d c 256 + * + d CURLOPTTYPE_LONG... + d c 0 + d CURLOPTTYPE_VALUES... + d c 0 + d CURLOPTTYPE_OBJECTPOINT... + d c 10000 + d CURLOPTTYPE_STRINGPOINT... + d c 10000 + d CURLOPTTYPE_SLISTPOINT... + d c 10000 + d CURLOPTTYPE_CBPOINT... + d c 10000 + d CURLOPTTYPE_FUNCTIONPOINT... + d c 20000 + d CURLOPTTYPE_OFF_T... + d c 30000 + d CURLOPTTYPE_BLOB... + d c 40000 + * + d CURL_IPRESOLVE_WHATEVER... + d c 0 + d CURL_IPRESOLVE_V4... + d c 1 + d CURL_IPRESOLVE_V6... + d c 2 + * + d CURL_HTTP_VERSION_NONE... + d c 0 + d CURL_HTTP_VERSION_1_0... + d c 1 + d CURL_HTTP_VERSION_1_1... + d c 2 + d CURL_HTTP_VERSION_2_0... + d c 3 + d CURL_HTTP_VERSION_2... + d c 3 + d CURL_HTTP_VERSION_2TLS... + d c 4 + d CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE... + d c 5 + d CURL_HTTP_VERSION_3... + d c 30 + d CURL_HTTP_VERSION_3ONLY... + d c 31 + * + d CURL_NETRC_IGNORED... + d c 0 + d CURL_NETRC_OPTIONAL... + d c 1 + d CURL_NETRC_REQUIRED... + d c 2 + * + d CURL_SSLVERSION_DEFAULT... + d c 0 + d CURL_SSLVERSION_TLSv1... + d c 1 + d CURL_SSLVERSION_SSLv2... + d c 2 + d CURL_SSLVERSION_SSLv3... + d c 3 + d CURL_SSLVERSION_TLSv1_0... + d c 4 + d CURL_SSLVERSION_TLSv1_1... + d c 5 + d CURL_SSLVERSION_TLSv1_2... + d c 6 + d CURL_SSLVERSION_TLSv1_3... + d c 7 + d CURL_SSLVERSION_MAX_DEFAULT... + d c X'00010000' + d CURL_SSLVERSION_MAX_TLSv1_0... + d c X'00040000' + d CURL_SSLVERSION_MAX_TLSv1_1... + d c X'00050000' + d CURL_SSLVERSION_MAX_TLSv1_2... + d c X'00060000' + d CURL_SSLVERSION_MAX_TLSv1_3... + d c X'00070000' + * + d CURL_TLSAUTH_NONE... + d c 0 + d CURL_TLSAUTH_SRP... + d c 1 + * + d CURL_REDIR_GET_ALL... + d c 0 + d CURL_REDIR_POST_301... + d c 1 + d CURL_REDIR_POST_302... + d c 2 + d CURL_REDIR_POST_303... + d c 4 + d CURL_REDIR_POST_ALL... + d c 7 + * + d CURL_ZERO_TERMINATED... + d c X'FFFFFFFF' + * + d CURL_POLL_NONE c 0 + d CURL_POLL_IN c 1 + d CURL_POLL_OUT c 2 + d CURL_POLL_INOUT... + d c 3 + d CURL_POLL_REMOVE... + d c 4 + * + d CURL_BLOB_NOCOPY... + d c 0 + d CURL_BLOB_COPY c 1 + * + d CURL_CSELECT_IN... + d c X'00000001' + d CURL_CSELECT_OUT... + d c X'00000002' + d CURL_CSELECT_ERR... + d c X'00000004' + * + d CURL_PUSH_OK c 0 + d CURL_PUSH_DENY c 1 + * + d CURLPAUSE_RECV c X'00000001' + d CURLPAUSE_RECV_CONT... + d c X'00000000' + d CURLPAUSE_SEND c X'00000004' + d CURLPAUSE_SEND_CONT... + d c X'00000000' + d CURLPAUSE_ALL c X'00000005' + d CURLPAUSE_CONT c X'00000000' + * + d CURLINFOFLAG_KNOWN_FILENAME... + d c X'00000001' + d CURLINFOFLAG_KNOWN_FILETYPE... + d c X'00000002' + d CURLINFOFLAG_KNOWN_TIME... + d c X'00000004' + d CURLINFOFLAG_KNOWN_PERM... + d c X'00000008' + d CURLINFOFLAG_KNOWN_UID... + d c X'00000010' + d CURLINFOFLAG_KNOWN_GID... + d c X'00000020' + d CURLINFOFLAG_KNOWN_SIZE... + d c X'00000040' + d CURLINFOFLAG_KNOWN_HLINKCOUNT... + d c X'00000080' + * + d CURL_CHUNK_BGN_FUNC_OK... + d c 0 + d CURL_CHUNK_BGN_FUNC_FAIL... + d c 1 + d CURL_CHUNK_BGN_FUNC_SKIP... + d c 2 + * + d CURL_CHUNK_END_FUNC_OK... + d c 0 + d CURL_CHUNK_END_FUNC_FAIL... + d c 1 + * + d CURL_FNMATCHFUNC_MATCH... + d c 0 + d CURL_FNMATCHFUNC_NOMATCH... + d c 1 + d CURL_FNMATCHFUNC_FAIL... + d c 2 + * + d CURL_WAIT_POLLIN... + d c X'0001' + d CURL_WAIT_POLLPRI... + d c X'0002' + d CURL_WAIT_POLLOUT... + d c X'0004' + * + d CURLU_DEFAULT_PORT... + d c X'00000001' + d CURLU_NO_DEFAULT_PORT... + d c X'00000002' + d CURLU_DEFAULT_SCHEME... + d c X'00000004' + d CURLU_NON_SUPPORT_SCHEME... + d c X'00000008' + d CURLU_PATH_AS_IS... + d c X'00000010' + d CURLU_DISALLOW_USER... + d c X'00000020' + d CURLU_URLDECODE... + d c X'00000040' + d CURLU_URLENCODE... + d c X'00000080' + d CURLU_APPENDQUERY... + d c X'00000100' + d CURLU_GUESS_SCHEME... + d c X'00000200' + d CURLU_NO_AUTHORITY... + d c X'00000400' + d CURLU_ALLOW_SPACE... + d c X'00000800' + d CURLU_PUNYCODE... + d c X'00001000' + * + d CURLOT_FLAG_ALIAS... + d c X'00000001' + * + d CURLH_HEADER c X'00000001' + d CURLH_TRAILER c X'00000002' + d CURLH_CONNECT c X'00000004' + d CURLH_1XX c X'00000008' + d CURLH_PSEUDO c X'00000010' + * + d CURLWS_TEXT c X'00000001' + d CURLWS_BINARY c X'00000002' + d CURLWS_CONT c X'00000004' + d CURLWS_CLOSE c X'00000008' + d CURLWS_PING c X'00000010' + d CURLWS_OFFSET c X'00000020' + d CURLWS_PONG c X'00000040' + * + d CURLWS_RAW_MODE... + d c X'00000001' + * + ************************************************************************** + * Types + ************************************************************************** + * + d curl_socket_t s 10i 0 based(######ptr######) + * + d curl_off_t s 20i 0 based(######ptr######) + * + d CURLcode s 10i 0 based(######ptr######) Enum + d CURLE_OK c 0 + d CURLE_UNSUPPORTED_PROTOCOL... + d c 1 + d CURLE_FAILED_INIT... + d c 2 + d CURLE_URL_MALFORMAT... + d c 3 + d CURLE_NOT_BUILT_IN... + d c 4 + d CURLE_COULDNT_RESOLVE_PROXY... + d c 5 + d CURLE_COULDNT_RESOLVE_HOST... + d c 6 + d CURLE_COULDNT_CONNECT... + d c 7 + d CURLE_WEIRD_SERVER_REPLY... + d c 8 + d CURLE_REMOTE_ACCESS_DENIED... + d c 9 + d CURLE_FTP_ACCEPT_FAILED... + d c 10 + d CURLE_FTP_WEIRD_PASS_REPLY... + d c 11 + d CURLE_FTP_ACCEPT_TIMEOUT... + d c 12 + d CURLE_FTP_WEIRD_PASV_REPLY... + d c 13 + d CURLE_FTP_WEIRD_227_FORMAT... + d c 14 + d CURLE_FTP_CANT_GET_HOST... + d c 15 + d CURLE_HTTP2 c 16 + d CURLE_FTP_COULDNT_SET_TYPE... + d c 17 + d CURLE_PARTIAL_FILE... + d c 18 + d CURLE_FTP_COULDNT_RETR_FILE... + d c 19 + d CURLE_OBSOLETE20... + d c 20 + d CURLE_QUOTE_ERROR... + d c 21 + d CURLE_HTTP_RETURNED_ERROR... + d c 22 + d CURLE_WRITE_ERROR... + d c 23 + d CURLE_OBSOLETE24... + d c 24 + d CURLE_UPLOAD_FAILED... + d c 25 + d CURLE_READ_ERROR... + d c 26 + d CURLE_OUT_OF_MEMORY... + d c 27 + d CURLE_OPERATION_TIMEDOUT... + d c 28 + d CURLE_OBSOLETE29... + d c 29 + d CURLE_FTP_PORT_FAILED... + d c 30 + d CURLE_FTP_COULDNT_USE_REST... + d c 31 + d CURLE_OBSOLETE32... + d c 32 + d CURLE_RANGE_ERROR... + d c 33 + d CURLE_HTTP_POST_ERROR... + d c 34 + d CURLE_SSL_CONNECT_ERROR... + d c 35 + d CURLE_BAD_DOWNLOAD_RESUME... + d c 36 + d CURLE_FILE_COULDNT_READ_FILE... + d c 37 + d CURLE_LDAP_CANNOT_BIND... + d c 38 + d CURLE_LDAP_SEARCH_FAILED... + d c 39 + d CURLE_OBSOLETE40... + d c 40 + d CURLE_FUNCTION_NOT_FOUND... + d c 41 + d CURLE_ABORTED_BY_CALLBACK... + d c 42 + d CURLE_BAD_FUNCTION_ARGUMENT... + d c 43 + d CURLE_OBSOLETE44... + d c 44 + d CURLE_INTERFACE_FAILED... + d c 45 + d CURLE_OBSOLETE46... + d c 46 + d CURLE_TOO_MANY_REDIRECTS... + d c 47 + d CURLE_UNKNOWN_OPTION... + d c 48 + d CURLE_SETOPT_OPTION_SYNTAX... + d c 49 + d CURLE_OBSOLETE50... + d c 50 + d CURLE_OBSOLETE51... + d c 51 + d CURLE_GOT_NOTHING... + d c 52 + d CURLE_SSL_ENGINE_NOTFOUND... + d c 53 + d CURLE_SSL_ENGINE_SETFAILED... + d c 54 + d CURLE_SEND_ERROR... + d c 55 + d CURLE_RECV_ERROR... + d c 56 + d CURLE_OBSOLETE57... + d c 57 + d CURLE_SSL_CERTPROBLEM... + d c 58 + d CURLE_SSL_CIPHER... + d c 59 + d CURLE_PEER_FAILED_VERIFICATION... + d c 60 + d CURLE_BAD_CONTENT_ENCODING... + d c 61 + d CURLE_OBSOLETE62... + d c 62 + d CURLE_FILESIZE_EXCEEDED... + d c 63 + d CURLE_USE_SSL_FAILED... + d c 64 + d CURLE_SEND_FAIL_REWIND... + d c 65 + d CURLE_SSL_ENGINE_INITFAILED... + d c 66 + d CURLE_LOGIN_DENIED... + d c 67 + d CURLE_TFTP_NOTFOUND... + d c 68 + d CURLE_TFTP_PERM... + d c 69 + d CURLE_REMOTE_DISK_FULL... + d c 70 + d CURLE_TFTP_ILLEGAL... + d c 71 + d CURLE_TFTP_UNKNOWNID... + d c 72 + d CURLE_REMOTE_FILE_EXISTS... + d c 73 + d CURLE_TFTP_NOSUCHUSER... + d c 74 + d CURLE_OBSOLETE75... + d c 75 + d CURLE_OBSOLETE76... + d c 76 + d CURLE_SSL_CACERT_BADFILE... + d c 77 + d CURLE_REMOTE_FILE_NOT_FOUND... + d c 78 + d CURLE_SSH c 79 + d CURLE_SSL_SHUTDOWN_FAILED... + d c 80 + d CURLE_AGAIN c 81 + d CURLE_SSL_CRL_BADFILE... + d c 82 + d CURLE_SSL_ISSUER_ERROR... + d c 83 + d CURLE_FTP_PRET_FAILED... + d c 84 + d CURLE_RTSP_CSEQ_ERROR... + d c 85 + d CURLE_RTSP_SESSION_ERROR... + d c 86 + d CURLE_FTP_BAD_FILE_LIST... + d c 87 + d CURLE_CHUNK_FAILED... + d c 88 + d CURLE_NO_CONNECTION_AVAILABLE... + d c 89 + d CURLE_SSL_PINNEDPUBKEYNOTMATCH... + d c 90 + d CURLE_SSL_INVALIDCERTSTATUS... + d c 91 + d CURLE_HTTP2_STREAM... + d c 92 + d CURLE_RECURSIVE_API_CALL... + d c 93 + d CURLE_AUTH_ERROR... + d c 94 + d CURLE_HTTP3 c 95 + d CURLE_QUIC_CONNECT_ERROR... + d c 96 + d CURLE_PROXY c 97 + d CURLE_SSL_CLIENTCERT... + d c 98 + d CURLE_UNRECOVERABLE_POLL... + d c 99 + d CURLE_TOO_LARGE... + d c 100 + * + /if not defined(CURL_NO_OLDIES) + d CURLE_URL_MALFORMAT_USER... + d c 4 + d CURLE_FTP_WEIRD_SERVER_REPLY... + d c 8 + d CURLE_FTP_ACCESS_DENIED... + d c 9 + d CURLE_FTP_USER_PASSWORD_INCORRECT... + d c 10 + d CURLE_FTP_WEIRD_USER_REPLY... + d c 12 + d CURLE_FTP_CANT_RECONNECT... + d c 16 + d CURLE_FTP_COULDNT_SET_BINARY... + d c 17 + d CURLE_FTP_PARTIAL_FILE... + d c 18 + d CURLE_FTP_WRITE_ERROR... + d c 20 + d CURLE_FTP_QUOTE_ERROR... + d c 21 + d CURLE_HTTP_NOT_FOUND... + d c 22 + d CURLE_MALFORMAT_USER... + d c 24 + d CURLE_FTP_COULDNT_STOR_FILE... + d c 25 + d CURLE_OPERATION_TIMEOUTED... + d c 28 + d CURLE_FTP_COULDNT_SET_ASCII... + d c 29 + d CURLE_FTP_COULDNT_GET_SIZE... + d c 32 + d CURLE_HTTP_RANGE_ERROR... + d c 33 + d CURLE_FTP_BAD_DOWNLOAD_RESUME... + d c 36 + d CURLE_LIBRARY_NOT_FOUND... + d c 40 + d CURLE_BAD_CALLING_ORDER... + d c 44 + d CURLE_HTTP_PORT_FAILED... + d c 45 + d CURLE_BAD_PASSWORD_ENTERED... + d c 46 + d CURLE_UNKNOWN_TELNET_OPTION... + d c 48 + d CURLE_TELNET_OPTION_SYNTAX... + d c 49 + d CURLE_OBSOLETE... + d c 50 + d CURLE_SHARE_IN_USE... + d c 57 + d CURLE_SSL_CACERT... + d c 60 + d CURLE_SSL_PEER_CERTIFICATE... + d c 60 + d CURLE_LDAP_INVALID_URL... + d c 62 + d CURLE_FTP_SSL_FAILED... + d c 64 + d CURLE_TFTP_DISKFULL... + d c 70 + d CURLE_TFTP_EXISTS... + d c 73 + d CURLE_CONV_FAILED... + d c 75 + d CURLE_CONV_REQD... + d c 76 + d CURLE_ALREADY_COMPLETE... + d c 99999 + /endif + * + d CURLproxycode s 10i 0 based(######ptr######) Enum + d CURLPX_OK c 0 + d CURLPX_BAD_ADDRESS_TYPE... + d c 1 + d CURLPX_BAD_VERSION... + d c 2 + d CURLPX_CLOSED... + d c 3 + d CURLPX_GSSAPI... + d c 4 + d CURLPX_GSSAPI_PERMSG... + d c 5 + d CURLPX_GSSAPI_PROTECTION... + d c 6 + d CURLPX_IDENTD... + d c 7 + d CURLPX_IDENTD_DIFFER... + d c 8 + d CURLPX_LONG_HOSTNAME... + d c 9 + d CURLPX_LONG_PASSWD... + d c 10 + d CURLPX_LONG_USER... + d c 11 + d CURLPX_NO_AUTH... + d c 12 + d CURLPX_RECV_ADDRESS... + d c 13 + d CURLPX_RECV_AUTH... + d c 14 + d CURLPX_RECV_CONNECT... + d c 15 + d CURLPX_RECV_REQACK... + d c 16 + d CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED... + d c 17 + d CURLPX_REPLY_COMMAND_NOT_SUPPORTED... + d c 18 + d CURLPX_REPLY_CONNECTION_REFUSED... + d c 10 + d CURLPX_REPLY_GENERAL_SERVER_FAILURE... + d c 20 + d CURLPX_REPLY_HOST_UNREACHABLE... + d c 21 + d CURLPX_REPLY_NETWORK_UNREACHABLE... + d c 22 + d CURLPX_REPLY_NOT_ALLOWED... + d c 23 + d CURLPX_REPLY_TTL_EXPIRED... + d c 24 + d CURLPX_REPLY_UNASSIGNED... + d c 25 + d CURLPX_REQUEST_FAILED... + d c 26 + d CURLPX_RESOLVE_HOST... + d c 27 + d CURLPX_SEND_AUTH... + d c 28 + d CURLPX_SEND_CONNECT... + d c 29 + d CURLPX_SEND_REQUEST... + d c 30 + d CURLPX_UNKNOWN_FAIL... + d c 31 + d CURLPX_UNKNOWN_MODE... + d c 32 + d CURLPX_USER_REJECTED... + d c 33 + * + d curlioerr s 10i 0 based(######ptr######) Enum + d CURLIOE_OK c 0 + d CURLIOE_UNKNOWNCMD... + d c 1 + d CURLIOE_FAILRESTART... + d c 2 + * + d curlfiletype s 10i 0 based(######ptr######) Enum + d CURLFILETYPE_FILE... + d c 0 + d CURLFILETYPE_DIRECTORY... + d c 1 + d CURLFILETYPE_SYMLINK... + d c 2 + d CURLFILETYPE_DEVICE_BLOCK... + d c 3 + d CURLFILETYPE_DEVICE_CHAR... + d c 4 + d CURLFILETYPE_NAMEDPIPE... + d c 5 + d CURLFILETYPE_SOCKET... + d c 6 + d CURLFILETYPE_DOOR... + d c 7 + * + d curliocmd s 10i 0 based(######ptr######) Enum + d CURLIOCMD_NOP c 0 + d CURLIOCMD_RESTARTREAD... + d c 1 + * + d curl_infotype s 10i 0 based(######ptr######) Enum + d CURLINFO_TEXT... + d c 0 + d CURLINFO_HEADER_IN... + d c 1 + d CURLINFO_HEADER_OUT... + d c 2 + d CURLINFO_DATA_IN... + d c 3 + d CURLINFO_DATA_OUT... + d c 4 + d CURLINFO_SSL_DATA_IN... + d c 5 + d CURLINFO_SSL_DATA_OUT... + d c 6 + d CURLINFO_END... + d c 7 + * + d curl_proxytype s 10i 0 based(######ptr######) Enum + d CURLPROXY_HTTP... + d c 0 + d CURLPROXY_HTTP_1_0... + d c 1 + d CURLPROXY_HTTPS... + d c 2 + d CURLPROXY_HTTPS2... + d c 3 + d CURLPROXY_SOCKS4... + d c 4 + d CURLPROXY_SOCKS5... + d c 5 + d CURLPROXY_SOCKS4A... + d c 6 + d CURLPROXY_SOCKS5_HOSTNAME... + d c 7 + * + d curl_khstat s 10i 0 based(######ptr######) Enum + d CURLKHSTAT_FINE_ADD_TO_FILE... + d c 0 + d CURLKHSTAT_FINE... + d c 1 + d CURLKHSTAT_REJECT... + d c 2 + d CURLKHSTAT_DEFER... + d c 3 + d CURLKHSTAT_FINE_REPLACE... + d c 4 + d CURLKHSTAT_LAST... + d c 5 + * + d curl_khmatch s 10i 0 based(######ptr######) Enum + d CURLKHMATCH_OK... + d c 0 + d CURLKHMATCH_MISMATCH... + d c 1 + d CURLKHMATCH_MISSING... + d c 2 + d CURLKHMATCH_LAST... + d c 3 + * + d curl_usessl s 10i 0 based(######ptr######) Enum + d CURLUSESSL_NONE... + d c 0 + d CURLUSESSL_TRY... + d c 1 + d CURLUSESSL_CONTROL... + d c 2 + d CURLUSESSL_ALL... + d c 3 + * + d CURLSSLOPT_ALLOW_BEAST... + d c X'0001' + d CURLSSLOPT_NO_REVOKE... + d c X'0002' + d CURLSSLOPT_NO_PARTIALCHAIN... + d c X'0004' + d CURLSSLOPT_REVOKE_BEST_EFFORT... + d c X'0008' + d CURLSSLOPT_NATIVE_CA... + d c X'0010' + d CURLSSLOPT_AUTO_CLIENT_CERT... + d c X'0020' + * + d CURL_HET_DEFAULT... + d c 200 + * + d CURL_UPKEEP_INTERVAL_DEFAULT... + d c 60000 + * + /if not defined(CURL_NO_OLDIES) + d curl_ftpssl s like(curl_usessl) + d based(######ptr######) + d CURLFTPSSL_NONE... + d c 0 + d CURLFTPSSL_TRY... + d c 1 + d CURLFTPSSL_CONTROL... + d c 2 + d CURLFTPSSL_ALL... + d c 3 + /endif + * + d curl_ftpccc s 10i 0 based(######ptr######) Enum + d CURLFTPSSL_CCC_NONE... + d c 0 + d CURLFTPSSL_CCC_PASSIVE... + d c 1 + d CURLFTPSSL_CCC_ACTIVE... + d c 2 + * + d curl_ftpauth s 10i 0 based(######ptr######) Enum + d CURLFTPAUTH_DEFAULT... + d c 0 + d CURLFTPAUTH_SSL... + d c 1 + d CURLFTPAUTH_TLS... + d c 2 + * + d curl_ftpcreatedir... + d s 10i 0 based(######ptr######) Enum + d CURLFTP_CREATE_DIR_NONE... + d c 0 + d CURLFTP_CREATE_DIR... + d c 1 + d CURLFTP_CREATE_DIR_RETRY... + d c 2 + * + d curl_ftpmethod s 10i 0 based(######ptr######) Enum + d CURLFTPMETHOD_DEFAULT... + d c 0 + d CURLFTPMETHOD_MULTICWD... + d c 1 + d CURLFTPMETHOD_NOCWD... + d c 2 + d CURLFTPMETHOD_SINGLECWD... + d c 3 + * + d CURLHEADER_UNIFIED... + d c X'00000000' + d CURLHEADER_SEPARATE... + d c X'00000001' + * + d CURLALTSVC_READONLYFILE... + d c X'00000004' + d CURLALTSVC_H1... + d c X'00000008' + d CURLALTSVC_H2... + d c X'00000010' + d CURLALTSVC_H3... + d c X'00000020' + * + d CURLHSTS_ENABLE... + d c X'00000001' + d CURLHSTS_READONLYFILE... + d c X'00000002' + * + d CURLPROTO_HTTP... + d c X'00000001' + d CURLPROTO_HTTPS... + d c X'00000002' + d CURLPROTO_FTP... + d c X'00000004' + d CURLPROTO_FTPS... + d c X'00000008' + d CURLPROTO_SCP... + d c X'00000010' + d CURLPROTO_SFTP... + d c X'00000020' + d CURLPROTO_TELNET... + d c X'00000040' + d CURLPROTO_LDAP... + d c X'00000080' + d CURLPROTO_LDAPS... + d c X'00000100' + d CURLPROTO_DICT... + d c X'00000200' + d CURLPROTO_FILE... + d c X'00000400' + d CURLPROTO_TFTP... + d c X'00000800' + d CURLPROTO_IMAP... + d c X'00001000' + d CURLPROTO_IMAPS... + d c X'00002000' + d CURLPROTO_POP3... + d c X'00004000' + d CURLPROTO_POP3S... + d c X'00008000' + d CURLPROTO_SMTP... + d c X'00010000' + d CURLPROTO_SMTPS... + d c X'00020000' + d CURLPROTO_RTSP... + d c X'00040000' + d CURLPROTO_RTMP... + d c X'00080000' + d CURLPROTO_RTMPT... + d c X'00100000' + d CURLPROTO_RTMPTE... + d c X'00200000' + d CURLPROTO_RTMPE... + d c X'00400000' + d CURLPROTO_RTMPS... + d c X'00800000' + d CURLPROTO_RTMPTS... + d c X'01000000' + d CURLPROTO_GOPHER... + d c X'02000000' + d CURLPROTO_SMB... + d c X'04000000' + d CURLPROTO_SMBS... + d c X'08000000' + d CURLPROTO_MQTT... + d c X'10000000' + d CURLPROTO_GOPHERS... + d c X'20000000' + * + d CURLoption s 10i 0 based(######ptr######) Enum + d CURLOPT_WRITEDATA... + d c 10001 + d CURLOPT_URL c 10002 + d CURLOPT_PORT c 00003 + d CURLOPT_PROXY c 10004 + d CURLOPT_USERPWD... + d c 10005 + d CURLOPT_PROXYUSERPWD... + d c 10006 + d CURLOPT_RANGE c 10007 + d CURLOPT_READDATA... + d c 10009 + d CURLOPT_ERRORBUFFER... + d c 10010 + d CURLOPT_WRITEFUNCTION... + d c 20011 + d CURLOPT_READFUNCTION... + d c 20012 + d CURLOPT_TIMEOUT... + d c 00013 + d CURLOPT_INFILESIZE... + d c 00014 + d CURLOPT_POSTFIELDS... + d c 10015 + d CURLOPT_REFERER... + d c 10016 + d CURLOPT_FTPPORT... + d c 10017 + d CURLOPT_USERAGENT... + d c 10018 + d CURLOPT_LOW_SPEED_LIMIT... + d c 00019 + d CURLOPT_LOW_SPEED_TIME... + d c 00020 + d CURLOPT_RESUME_FROM... + d c 00021 + d CURLOPT_COOKIE... + d c 10022 + d CURLOPT_HTTPHEADER... + d c 10023 + d CURLOPT_RTSPHEADER... + d c 10023 + d CURLOPT_HTTPPOST... + d c 10024 + d CURLOPT_SSLCERT... + d c 10025 + d CURLOPT_KEYPASSWD... + d c 10026 + d CURLOPT_CRLF c 00027 + d CURLOPT_QUOTE c 10028 + d CURLOPT_HEADERDATA... + d c 10029 + d CURLOPT_COOKIEFILE... + d c 10031 + d CURLOPT_SSLVERSION... + d c 00032 + d CURLOPT_TIMECONDITION... + d c 00033 + d CURLOPT_TIMEVALUE... + d c 00034 + d CURLOPT_CUSTOMREQUEST... + d c 10036 + d CURLOPT_STDERR... + d c 10037 + d CURLOPT_POSTQUOTE... + d c 10039 + d CURLOPT_VERBOSE... + d c 00041 + d CURLOPT_HEADER... + d c 00042 + d CURLOPT_NOPROGRESS... + d c 00043 + d CURLOPT_NOBODY... + d c 00044 + d CURLOPT_FAILONERROR... + d c 00045 + d CURLOPT_UPLOAD... + d c 00046 + d CURLOPT_POST c 00047 + d CURLOPT_DIRLISTONLY... + d c 00048 + d CURLOPT_APPEND... + d c 00050 + d CURLOPT_NETRC c 00051 + d CURLOPT_FOLLOWLOCATION... + d c 00052 + d CURLOPT_TRANSFERTEXT... + d c 00053 + d CURLOPT_PUT c 00054 + d CURLOPT_PROGRESSFUNCTION... + d c 20056 + d CURLOPT_PROGRESSDATA... + d c 10057 + d CURLOPT_XFERINFODATA... + d c 10057 PROGRESSDATA alias + d CURLOPT_AUTOREFERER... + d c 00058 + d CURLOPT_PROXYPORT... + d c 00059 + d CURLOPT_POSTFIELDSIZE... + d c 00060 + d CURLOPT_HTTPPROXYTUNNEL... + d c 00061 + d CURLOPT_INTERFACE... + d c 10062 + d CURLOPT_KRBLEVEL... + d c 10063 + d CURLOPT_SSL_VERIFYPEER... + d c 00064 + d CURLOPT_CAINFO... + d c 10065 + d CURLOPT_MAXREDIRS... + d c 00068 + d CURLOPT_FILETIME... + d c 00069 + d CURLOPT_TELNETOPTIONS... + d c 10070 + d CURLOPT_MAXCONNECTS... + d c 00071 + d CURLOPT_FRESH_CONNECT... + d c 00074 + d CURLOPT_FORBID_REUSE... + d c 00075 + d CURLOPT_RANDOM_FILE... + d c 10076 + d CURLOPT_EGDSOCKET... + d c 10077 + d CURLOPT_CONNECTTIMEOUT... + d c 00078 + d CURLOPT_HEADERFUNCTION... + d c 20079 + d CURLOPT_HTTPGET... + d c 00080 + d CURLOPT_SSL_VERIFYHOST... + d c 00081 + d CURLOPT_COOKIEJAR... + d c 10082 + d CURLOPT_SSL_CIPHER_LIST... + d c 10083 + d CURLOPT_HTTP_VERSION... + d c 00084 + d CURLOPT_FTP_USE_EPSV... + d c 00085 + d CURLOPT_SSLCERTTYPE... + d c 10086 + d CURLOPT_SSLKEY... + d c 10087 + d CURLOPT_SSLKEYTYPE... + d c 10088 + d CURLOPT_SSLENGINE... + d c 10089 + d CURLOPT_SSLENGINE_DEFAULT... + d c 00090 + d CURLOPT_DNS_USE_GLOBAL_CACHE... + d c 00091 + d CURLOPT_DNS_CACHE_TIMEOUT... + d c 00092 + d CURLOPT_PREQUOTE... + d c 10093 + d CURLOPT_DEBUGFUNCTION... + d c 20094 + d CURLOPT_DEBUGDATA... + d c 10095 + d CURLOPT_COOKIESESSION... + d c 00096 + d CURLOPT_CAPATH... + d c 10097 + d CURLOPT_BUFFERSIZE... + d c 00098 + d CURLOPT_NOSIGNAL... + d c 00099 + d CURLOPT_SHARE c 10100 + d CURLOPT_PROXYTYPE... + d c 00101 + d CURLOPT_ACCEPT_ENCODING... + d c 10102 + d CURLOPT_PRIVATE... + d c 10103 + d CURLOPT_HTTP200ALIASES... + d c 10104 + d CURLOPT_UNRESTRICTED_AUTH... + d c 00105 + d CURLOPT_FTP_USE_EPRT... + d c 00106 + d CURLOPT_HTTPAUTH... + d c 00107 + d CURLOPT_SSL_CTX_FUNCTION... + d c 20108 + d CURLOPT_SSL_CTX_DATA... + d c 10109 + d CURLOPT_FTP_CREATE_MISSING_DIRS... + d c 00110 + d CURLOPT_PROXYAUTH... + d c 00111 + d CURLOPT_SERVER_RESPONSE_TIMEOUT... + d c 00112 + d CURLOPT_IPRESOLVE... + d c 00113 + d CURLOPT_MAXFILESIZE... + d c 00114 + d CURLOPT_INFILESIZE_LARGE... + d c 30115 + d CURLOPT_RESUME_FROM_LARGE... + d c 30116 + d CURLOPT_MAXFILESIZE_LARGE... + d c 30117 + d CURLOPT_NETRC_FILE... + d c 10118 + d CURLOPT_USE_SSL... + d c 00119 + d CURLOPT_POSTFIELDSIZE_LARGE... + d c 30120 + d CURLOPT_TCP_NODELAY... + d c 00121 + d CURLOPT_FTPSSLAUTH... + d c 00129 + d CURLOPT_IOCTLFUNCTION... + d c 20130 + d CURLOPT_IOCTLDATA... + d c 10131 + d CURLOPT_FTP_ACCOUNT... + d c 10134 + d CURLOPT_COOKIELIST... + d c 10135 + d CURLOPT_IGNORE_CONTENT_LENGTH... + d c 00136 + d CURLOPT_FTP_SKIP_PASV_IP... + d c 00137 + d CURLOPT_FTP_FILEMETHOD... + d c 00138 + d CURLOPT_LOCALPORT... + d c 00139 + d CURLOPT_LOCALPORTRANGE... + d c 00140 + d CURLOPT_CONNECT_ONLY... + d c 00141 + d CURLOPT_CONV_FROM_NETWORK_FUNCTION... + d c 20142 + d CURLOPT_CONV_TO_NETWORK_FUNCTION... + d c 20143 + d CURLOPT_CONV_FROM_UTF8_FUNCTION... + d c 20144 + d CURLOPT_MAX_SEND_SPEED_LARGE... + d c 30145 + d CURLOPT_MAX_RECV_SPEED_LARGE... + d c 30146 + d CURLOPT_FTP_ALTERNATIVE_TO_USER... + d c 10147 + d CURLOPT_SOCKOPTFUNCTION... + d c 20148 + d CURLOPT_SOCKOPTDATA... + d c 10149 + d CURLOPT_SSL_SESSIONID_CACHE... + d c 00150 + d CURLOPT_SSH_AUTH_TYPES... + d c 00151 + d CURLOPT_SSH_PUBLIC_KEYFILE... + d c 10152 + d CURLOPT_SSH_PRIVATE_KEYFILE... + d c 10153 + d CURLOPT_FTP_SSL_CCC... + d c 00154 + d CURLOPT_TIMEOUT_MS... + d c 00155 + d CURLOPT_CONNECTTIMEOUT_MS... + d c 00156 + d CURLOPT_HTTP_TRANSFER_DECODING... + d c 00157 + d CURLOPT_HTTP_CONTENT_DECODING... + d c 00158 + d CURLOPT_NEW_FILE_PERMS... + d c 00159 + d CURLOPT_NEW_DIRECTORY_PERMS... + d c 00160 + d CURLOPT_POSTREDIR... + d c 00161 + d CURLOPT_SSH_HOST_PUBLIC_KEY_MD5... + d c 10162 + d CURLOPT_OPENSOCKETFUNCTION... + d c 20163 + d CURLOPT_OPENSOCKETDATA... + d c 10164 + d CURLOPT_COPYPOSTFIELDS... + d c 10165 + d CURLOPT_PROXY_TRANSFER_MODE... + d c 00166 + d CURLOPT_SEEKFUNCTION... + d c 20167 + d CURLOPT_SEEKDATA... + d c 10168 + d CURLOPT_CRLFILE... + d c 10169 + d CURLOPT_ISSUERCERT... + d c 10170 + d CURLOPT_ADDRESS_SCOPE... + d c 00171 + d CURLOPT_CERTINFO... + d c 00172 + d CURLOPT_USERNAME... + d c 10173 + d CURLOPT_PASSWORD... + d c 10174 + d CURLOPT_PROXYUSERNAME... + d c 10175 + d CURLOPT_PROXYPASSWORD... + d c 10176 + d CURLOPT_NOPROXY... + d c 10177 + d CURLOPT_TFTP_BLKSIZE... + d c 00178 + d CURLOPT_SOCKS5_GSSAPI_SERVICE... + d c 10179 + d CURLOPT_SOCKS5_GSSAPI_NEC... + d c 00180 + d CURLOPT_PROTOCOLS... + d c 00181 + d CURLOPT_REDIR_PROTOCOLS... + d c 00182 + d CURLOPT_SSH_KNOWNHOSTS... + d c 10183 + d CURLOPT_SSH_KEYFUNCTION... + d c 20184 + d CURLOPT_SSH_KEYDATA... + d c 10185 + d CURLOPT_MAIL_FROM... + d c 10186 + d CURLOPT_MAIL_RCPT... + d c 10187 + d CURLOPT_FTP_USE_PRET... + d c 00188 + d CURLOPT_RTSP_REQUEST... + d c 00189 + d CURLOPT_RTSP_SESSION_ID... + d c 10190 + d CURLOPT_RTSP_STREAM_URI... + d c 10191 + d CURLOPT_RTSP_TRANSPORT... + d c 10192 + d CURLOPT_RTSP_CLIENT_CSEQ... + d c 00193 + d CURLOPT_RTSP_SERVER_CSEQ... + d c 00194 + d CURLOPT_INTERLEAVEDATA... + d c 10195 + d CURLOPT_INTERLEAVEFUNCTION... + d c 20196 + d CURLOPT_WILDCARDMATCH... + d c 00197 + d CURLOPT_CHUNK_BGN_FUNCTION... + d c 20198 + d CURLOPT_CHUNK_END_FUNCTION... + d c 20199 + d CURLOPT_FNMATCH_FUNCTION... + d c 20200 + d CURLOPT_CHUNK_DATA... + d c 10201 + d CURLOPT_FNMATCH_DATA... + d c 10202 + d CURLOPT_RESOLVE... + d c 10203 + d CURLOPT_TLSAUTH_USERNAME... + d c 10204 + d CURLOPT_TLSAUTH_PASSWORD... + d c 10205 + d CURLOPT_TLSAUTH_TYPE... + d c 10206 + d CURLOPT_TRANSFER_ENCODING... + d c 00207 + d CURLOPT_CLOSESOCKETFUNCTION... + d c 20208 + d CURLOPT_CLOSESOCKETDATA... + d c 10209 + d CURLOPT_GSSAPI_DELEGATION... + d c 00210 + d CURLOPT_DNS_SERVERS... + d c 10211 + d CURLOPT_ACCEPTTIMEOUT_MS... + d c 00212 + d CURLOPT_TCP_KEEPALIVE... + d c 00213 + d CURLOPT_TCP_KEEPIDLE... + d c 00214 + d CURLOPT_TCP_KEEPINTVL... + d c 00215 + d CURLOPT_SSL_OPTIONS... + d c 00216 + d CURLOPT_MAIL_AUTH... + d c 10217 + d CURLOPT_SASL_IR... + d c 00218 + d CURLOPT_XFERINFOFUNCTION... + d c 20219 + d CURLOPT_XOAUTH2_BEARER... + d c 10220 + d CURLOPT_DNS_INTERFACE... + d c 10221 + d CURLOPT_DNS_LOCAL_IP4... + d c 10222 + d CURLOPT_DNS_LOCAL_IP6... + d c 10223 + d CURLOPT_LOGIN_OPTIONS... + d c 10224 + d CURLOPT_SSL_ENABLE_NPN... + d c 00225 + d CURLOPT_SSL_ENABLE_ALPN... + d c 00226 + d CURLOPT_EXPECT_100_TIMEOUT_MS... + d c 00227 + d CURLOPT_PROXYHEADER... + d c 10228 + d CURLOPT_HEADEROPT... + d c 00229 + d CURLOPT_PINNEDPUBLICKEY... + d c 10230 + d CURLOPT_UNIX_SOCKET_PATH... + d c 10231 + d CURLOPT_SSL_VERIFYSTATUS... + d c 00232 + d CURLOPT_SSL_FALSESTART... + d c 00233 + d CURLOPT_PATH_AS_IS... + d c 00234 + d CURLOPT_PROXY_SERVICE_NAME... + d c 10235 + d CURLOPT_SERVICE_NAME... + d c 10236 + d CURLOPT_PIPEWAIT... + d c 00237 + d CURLOPT_DEFAULT_PROTOCOL... + d c 10238 + d CURLOPT_STREAM_WEIGHT... + d c 00239 + d CURLOPT_STREAM_DEPENDS... + d c 10240 + d CURLOPT_STREAM_DEPENDS_E... + d c 10241 + d CURLOPT_TFTP_NO_OPTIONS... + d c 00242 + d CURLOPT_CONNECT_TO... + d c 10243 + d CURLOPT_TCP_FASTOPEN... + d c 00244 + d CURLOPT_KEEP_SENDING_ON_ERROR... + d c 00245 + d CURLOPT_PROXY_CAINFO... + d c 10246 + d CURLOPT_PROXY_CAPATH... + d c 10247 + d CURLOPT_PROXY_SSL_VERIFYPEER... + d c 00248 + d CURLOPT_PROXY_SSL_VERIFYHOST... + d c 00249 + d CURLOPT_PROXY_SSLVERSION... + d c 00250 + d CURLOPT_PROXY_TLSAUTH_USERNAME... + d c 10251 + d CURLOPT_PROXY_TLSAUTH_PASSWORD... + d c 10252 + d CURLOPT_PROXY_TLSAUTH_TYPE... + d c 10253 + d CURLOPT_PROXY_SSLCERT... + d c 10254 + d CURLOPT_PROXY_SSLCERTTYPE... + d c 10255 + d CURLOPT_PROXY_SSLKEY... + d c 10256 + d CURLOPT_PROXY_SSLKEYTYPE... + d c 10257 + d CURLOPT_PROXY_KEYPASSWD... + d c 10258 + d CURLOPT_PROXY_SSL_CIPHER_LIST... + d c 10259 + d CURLOPT_PROXY_CRLFILE... + d c 10260 + d CURLOPT_PROXY_SSL_OPTIONS... + d c 00261 + d CURLOPT_PRE_PROXY... + d c 10262 + d CURLOPT_PROXY_PINNEDPUBLICKEY... + d c 10263 + d CURLOPT_ABSTRACT_UNIX_SOCKET... + d c 10264 + d CURLOPT_SUPPRESS_CONNECT_HEADERS... + d c 00265 + d CURLOPT_REQUEST_TARGET... + d c 10266 + d CURLOPT_SOCKS5_AUTH... + d c 00267 + d CURLOPT_SSH_COMPRESSION... + d c 00268 + d CURLOPT_MIMEPOST... + d c 10269 + d CURLOPT_TIMEVALUE_LARGE... + d c 30270 + d CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS... + d c 00271 + d CURLOPT_RESOLVER_START_FUNCTION... + d c 20272 + d CURLOPT_RESOLVER_START_DATA... + d c 10273 + d CURLOPT_HAPROXYPROTOCOL... + d c 00274 + d CURLOPT_DNS_SHUFFLE_ADDRESSES... + d c 00275 + d CURLOPT_TLS13_CIPHERS... + d c 10276 + d CURLOPT_PROXY_TLS13_CIPHERS... + d c 10277 + d CURLOPT_DISALLOW_USERNAME_IN_URL... + d c 00278 + d CURLOPT_DOH_URL... + d c 10279 + d CURLOPT_UPLOAD_BUFFERSIZE... + d c 00280 + d CURLOPT_UPKEEP_INTERVAL_MS... + d c 00281 + d CURLOPT_CURLU c 10282 + d CURLOPT_TRAILERFUNCTION... + d c 20283 + d CURLOPT_TRAILERDATA... + d c 10284 + d CURLOPT_HTTP09_ALLOWED... + d c 00285 + d CURLOPT_ALTSVC_CTRL... + d c 00286 + d CURLOPT_ALTSVC... + d c 10287 + d CURLOPT_MAXAGE_CONN... + d c 00288 + d CURLOPT_SASL_AUTHZID... + d c 10289 + d CURLOPT_MAIL_RCPT_ALLOWFAILS... + d c 00290 + d CURLOPT_SSLCERT_BLOB... + d c 40291 + d CURLOPT_SSLKEY_BLOB... + d c 40292 + d CURLOPT_PROXY_SSLCERT_BLOB... + d c 40293 + d CURLOPT_PROXY_SSLKEY_BLOB... + d c 40294 + d CURLOPT_ISSUERCERT_BLOB... + d c 40295 + d CURLOPT_PROXY_ISSUERCERT... + d c 10296 + d CURLOPT_PROXY_ISSUERCERT_BLOB... + d c 40297 + d CURLOPT_SSL_EC_CURVES... + d c 10298 + d CURLOPT_HSTS_CTRL... + d c 00299 + d CURLOPT_HSTS... + d c 10300 + d CURLOPT_HSTSREADFUNCTION... + d c 20301 + d CURLOPT_HSTSREADDATA... + d c 10302 + d CURLOPT_HSTSWRITEFUNCTION... + d c 20303 + d CURLOPT_HSTSWRITEDATA... + d c 10304 + d CURLOPT_AWS_SIG4... + d c 10305 + d CURLOPT_DOH_SSL_VERIFYPEER... + d c 00306 + d CURLOPT_DOH_SSL_VERIFYHOST... + d c 00307 + d CURLOPT_DOH_SSL_VERIFYSTATUS... + d c 00308 + d CURLOPT_CAINFO_BLOB... + d c 40309 + d CURLOPT_PROXY_CAINFO_BLOB... + d c 40310 + d CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256... + d c 10311 + d CURLOPT_PREREQFUNCTION... + d c 20312 + d CURLOPT_PREREQDATA... + d c 10313 + d CURLOPT_MAXLIFETIME_CONN... + d c 00314 + d CURLOPT_MIME_OPTIONS... + d c 00315 + d CURLOPT_SSH_HOSTKEYFUNCTION... + d c 20316 + d CURLOPT_SSH_HOSTKEYDATA... + d c 10317 + d CURLOPT_PROTOCOLS_STR... + d c 10318 + d CURLOPT_REDIR_PROTOCOLS_STR... + d c 10319 + d CURLOPT_WS_OPTIONS... + d c 00320 + d CURLOPT_CA_CACHE_TIMEOUT... + d c 00321 + d CURLOPT_QUICK_EXIT... + d c 00322 + d CURLOPT_HAPROXY_CLIENT_IP... + d c 10323 + d CURLOPT_SERVER_RESPONSE_TIMEOUT_MS... + d c 00324 + * + /if not defined(CURL_NO_OLDIES) + d CURLOPT_FILE c 10001 + d CURLOPT_INFILE... + d c 10009 + d CURLOPT_SSLKEYPASSWD... + d c 10026 + d CURLOPT_SSLCERTPASSWD... + d c 10026 + d CURLOPT_WRITEHEADER... + d c 10029 + d CURLOPT_WRITEINFO... + d c 10040 + d CURLOPT_FTPLISTONLY... + d c 00048 + d CURLOPT_FTPAPPEND... + d c 00050 + d CURLOPT_CLOSEPOLICY... + d c 00072 + d CURLOPT_KRB4LEVEL... + d c 10063 + d CURLOPT_ENCODING... + d c 10102 + d CURLOPT_FTP_SSL... + d c 00119 + d CURLOPT_POST301... + d c 00161 + d CURLOPT_FTP_RESPONSE_TIMEOUT... + d c 00112 + /endif + * + d CURLFORMcode s 10i 0 based(######ptr######) Enum + d CURL_FORMADD_OK... + d c 0 + d CURL_FORMADD_MEMORY... + d c 1 + d CURL_FORMADD_OPTION_TWICE... + d c 2 + d CURL_FORMADD_NULL... + d c 3 + d CURL_FORMADD_UNKNOWN_OPTION... + d c 4 + d CURL_FORMADD_INCOMPLETE... + d c 5 + d CURL_FORMADD_ILLEGAL_ARRAY... + d c 6 + d CURL_FORMADD_DISABLED... + d c 7 + * + d CURLformoption s 10i 0 based(######ptr######) Enum + d CURLFORM_NOTHING... + d c 0 + d CURLFORM_COPYNAME... + d c 1 + d CURLFORM_PTRNAME... + d c 2 + d CURLFORM_NAMELENGTH... + d c 3 + d CURLFORM_COPYCONTENTS... + d c 4 + d CURLFORM_PTRCONTENTS... + d c 5 + d CURLFORM_CONTENTSLENGTH... + d c 6 + d CURLFORM_FILECONTENT... + d c 7 + d CURLFORM_ARRAY... + d c 8 + d CURLFORM_OBSOLETE... + d c 9 + d CURLFORM_FILE... + d c 10 + d CURLFORM_BUFFER... + d c 11 + d CURLFORM_BUFFERPTR... + d c 12 + d CURLFORM_BUFFERLENGTH... + d c 13 + d CURLFORM_CONTENTTYPE... + d c 14 + d CURLFORM_CONTENTHEADER... + d c 15 + d CURLFORM_FILENAME... + d c 16 + d CURLFORM_END... + d c 17 + d CURLFORM_OBSOLETE2... + d c 18 + d CURLFORM_STREAM... + d c 19 + d CURLFORM_CONTENTLEN... + d c 20 + * + d CURLMIMEOPT_FORMESCAPE... + d c X'00000001' + * + d CURLINFO s 10i 0 based(######ptr######) Enum + d CURLINFO_EFFECTIVE_URL... CURLINFO_STRING + 1 + d c X'00100001' + d CURLINFO_RESPONSE_CODE... CURLINFO_LONG + 2 + d c X'00200002' + d CURLINFO_TOTAL_TIME... CURLINFO_DOUBLE + 3 + d c X'00300003' + d CURLINFO_NAMELOOKUP_TIME... CURLINFO_DOUBLE + 4 + d c X'00300004' + d CURLINFO_CONNECT_TIME... CURLINFO_DOUBLE + 5 + d c X'00300005' + d CURLINFO_PRETRANSFER_TIME... CURLINFO_DOUBLE + 6 + d c X'00300006' + d CURLINFO_SIZE_UPLOAD... CURLINFO_DOUBLE + 7 + d c X'00300007' + d CURLINFO_SIZE_UPLOAD_T... CURLINFO_OFF_T + 7 + d c X'00600007' + d CURLINFO_SIZE_DOWNLOAD... CURLINFO_DOUBLE + 8 + d c X'00300008' + d CURLINFO_SIZE_DOWNLOAD_T... CURLINFO_OFF_T + 8 + d c X'00600008' + d CURLINFO_SPEED_DOWNLOAD... CURLINFO_DOUBLE + 9 + d c X'00300009' + d CURLINFO_SPEED_DOWNLOAD_T... CURLINFO_OFF_T + 9 + d c X'00600009' + d CURLINFO_SPEED_UPLOAD... CURLINFO_DOUBLE + 10 + d c X'0030000A' + d CURLINFO_SPEED_UPLOAD_T... CURLINFO_OFF_T + 10 + d c X'0060000A' + d CURLINFO_HEADER_SIZE... CURLINFO_LONG + 11 + d c X'0020000B' + d CURLINFO_REQUEST_SIZE... CURLINFO_LONG + 12 + d c X'0020000C' + d CURLINFO_SSL_VERIFYRESULT... CURLINFO_LONG + 13 + d c X'0020000D' + d CURLINFO_FILETIME... CURLINFO_LONG + 14 + d c X'0020000E' + d CURLINFO_FILETIME_T... CURLINFO_OFF_T + 14 + d c X'0060000E' + d CURLINFO_CONTENT_LENGTH_DOWNLOAD... CURLINFO_DOUBLE + 15 + d c X'0030000F' + d CURLINFO_CONTENT_LENGTH_DOWNLOAD_T... CURLINFO_OFF_T + 15 + d c X'0060000F' + d CURLINFO_CONTENT_LENGTH_UPLOAD... CURLINFO_DOUBLE + 16 + d c X'00300010' + d CURLINFO_CONTENT_LENGTH_UPLOAD_T... CURLINFO_OFF_T + 16 + d c X'00600010' + d CURLINFO_STARTTRANSFER_TIME... CURLINFO_DOUBLE + 17 + d c X'00300011' + d CURLINFO_CONTENT_TYPE... CURLINFO_STRING + 18 + d c X'00100012' + d CURLINFO_REDIRECT_TIME... CURLINFO_DOUBLE + 19 + d c X'00300013' + d CURLINFO_REDIRECT_COUNT... CURLINFO_LONG + 20 + d c X'00200014' + d CURLINFO_PRIVATE... CURLINFO_STRING + 21 + d c X'00100015' + d CURLINFO_HTTP_CONNECTCODE... CURLINFO_LONG + 22 + d c X'00200016' + d CURLINFO_HTTPAUTH_AVAIL... CURLINFO_LONG + 23 + d c X'00200017' + d CURLINFO_PROXYAUTH_AVAIL... CURLINFO_LONG + 24 + d c X'00200018' + d CURLINFO_OS_ERRNO... CURLINFO_LONG + 25 + d c X'00200019' + d CURLINFO_NUM_CONNECTS... CURLINFO_LONG + 26 + d c X'0020001A' + d CURLINFO_SSL_ENGINES... CURLINFO_SLIST + 27 + d c X'0040001B' + d CURLINFO_COOKIELIST... CURLINFO_SLIST + 28 + d c X'0040001C' + d CURLINFO_LASTSOCKET... CURLINFO_LONG + 29 + d c X'0020001D' + d CURLINFO_FTP_ENTRY_PATH... CURLINFO_STRING + 30 + d c X'0010001E' + d CURLINFO_REDIRECT_URL... CURLINFO_STRING + 31 + d c X'0010001F' + d CURLINFO_PRIMARY_IP... CURLINFO_STRING + 32 + d c X'00100020' + d CURLINFO_APPCONNECT_TIME... CURLINFO_DOUBLE + 33 + d c X'00300021' + d CURLINFO_CERTINFO... CURLINFO_SLIST + 34 + d c X'00400022' + d CURLINFO_CONDITION_UNMET... CURLINFO_LONG + 35 + d c X'00200023' + d CURLINFO_RTSP_SESSION_ID... CURLINFO_STRING + 36 + d c X'00100024' + d CURLINFO_RTSP_CLIENT_CSEQ... CURLINFO_LONG + 37 + d c X'00200025' + d CURLINFO_RTSP_SERVER_CSEQ... CURLINFO_LONG + 38 + d c X'00200026' + d CURLINFO_RTSP_CSEQ_RECV... CURLINFO_LONG + 39 + d c X'00200027' + d CURLINFO_PRIMARY_PORT... CURLINFO_LONG + 40 + d c X'00200028' + d CURLINFO_LOCAL_IP... CURLINFO_STRING + 41 + d c X'00100029' + d CURLINFO_LOCAL_PORT... CURLINFO_LONG + 42 + d c X'0020002A' + d CURLINFO_TLS_SESSION... CURLINFO_SLIST + 43 + d c X'0040002B' + d CURLINFO_ACTIVESOCKET... CURLINFO_SOCKET + 44 + d c X'0050002C' + d CURLINFO_TLS_SSL_PTR... CURLINFO_SLIST + 45 + d c X'0040002D' + d CURLINFO_HTTP_VERSION... CURLINFO_LONG + 46 + d c X'0020002E' + d CURLINFO_PROXY_SSL_VERIFYRESULT... CURLINFO_LONG + 47 + d c X'0020002F' + d CURLINFO_PROTOCOL... CURLINFO_LONG + 48 + d c X'00200030' + d CURLINFO_SCHEME... CURLINFO_STRING + 49 + d c X'00100031' + d CURLINFO_TOTAL_TIME_T... CURLINFO_OFF_T + 50 + d c X'00600032' + d CURLINFO_NAMELOOKUP_TIME_T... CURLINFO_OFF_T + 51 + d c X'00600033' + d CURLINFO_CONNECT_TIME_T... CURLINFO_OFF_T + 52 + d c X'00600034' + d CURLINFO_PRETRANSFER_TIME_T... CURLINFO_OFF_T + 53 + d c X'00600035' + d CURLINFO_STARTTRANSFER_TIME_T... CURLINFO_OFF_T + 54 + d c X'00600036' + d CURLINFO_REDIRECT_TIME_T... CURLINFO_OFF_T + 55 + d c X'00600037' + d CURLINFO_APPCONNECT_TIME_T... CURLINFO_OFF_T + 56 + d c X'00600038' + d CURLINFO_RETRY_AFTER... CURLINFO_OFF_T + 57 + d c X'00600039' + d CURLINFO_EFFECTIVE_METHOD... CURLINFO_STRING + 58 + d c X'0010003A' + d CURLINFO_PROXY_ERROR... CURLINFO_LONG + 59 + d c X'0020003B' + d CURLINFO_REFERER... CURLINFO_STRING + 60 + d c X'0010003C' + d CURLINFO_CAINFO... CURLINFO_STRING + 61 + d c X'0010003D' + d CURLINFO_CAPATH... CURLINFO_STRING + 62 + d c X'0010003E' + d CURLINFO_XFER_ID... CURLINFO_OFF_T + 63 + d c X'0060003F' + d CURLINFO_CONN_ID... CURLINFO_OFF_T + 64 + d c X'00600040' + d CURLINFO_QUEUE_TIME_T... CURLINFO_OFF_T + 65 + d c X'00600041' + * + d CURLINFO_HTTP_CODE... Old ...RESPONSE_CODE + d c X'00200002' + * + d curl_sslbackend... + d s 10i 0 based(######ptr######) Enum + d CURLSSLBACKEND_NONE... + d c 0 + d CURLSSLBACKEND_OPENSSL... + d c 1 + d CURLSSLBACKEND_GNUTLS... + d c 2 + d CURLSSLBACKEND_NSS... + d c 3 + d CURLSSLBACKEND_OBSOLETE4... + d c 4 + d CURLSSLBACKEND_GSKIT... + d c 5 + d CURLSSLBACKEND_POLARSSL... + d c 6 + d CURLSSLBACKEND_CYASSL... + d c 7 + d CURLSSLBACKEND_SCHANNEL... + d c 8 + d CURLSSLBACKEND_DARWINSSL... + d c 9 + d CURLSSLBACKEND_AXTLS... + d c 10 + d CURLSSLBACKEND_MBEDTLS... + d c 11 + d CURLSSLBACKEND_MESALINK... + d c 12 + d CURLSSLBACKEND_BEARSSL... + d c 13 + d CURLSSLBACKEND_RUSTLS... + d c 14 + * Aliases for clones. + d CURLSSLBACKEND_AWSLC... + d c 1 + d CURLSSLBACKEND_BORINGSSL... + d c 1 + d CURLSSLBACKEND_LIBRESSL... + d c 1 + d CURLSSLBACKEND_WOLFSSL... + d c 6 + * + d curl_closepolicy... + d s 10i 0 based(######ptr######) Enum + d CURLCLOSEPOLICY_OLDEST... + d c 1 + d CURLCLOSEPOLICY_LEAST_RECENTLY_USED... + d c 2 + d CURLCLOSEPOLICY_LEAST_TRAFFIC... + d c 3 + d CURLCLOSEPOLICY_SLOWEST... + d c 4 + d CURLCLOSEPOLICY_CALLBACK... + d c 5 + * + d curl_lock_data... + d s 10i 0 based(######ptr######) Enum + d CURL_LOCK_DATA_NONE... + d c 0 + d CURL_LOCK_DATA_SHARE... + d c 1 + d CURL_LOCK_DATA_COOKIE... + d c 2 + d CURL_LOCK_DATA_DNS... + d c 3 + d CURL_LOCK_DATA_SSL_SESSION... + d c 4 + d CURL_LOCK_DATA_CONNECT... + d c 5 + d CURL_LOCK_DATA_PSL... + d c 6 + d CURL_LOCK_DATA_HSTS... + d c 7 + d CURL_LOCK_DATA_LAST... + d c 8 + * + d curl_lock_access... + d s 10i 0 based(######ptr######) Enum + d CURL_LOCK_ACCESS_NONE... + d c 0 + d CURL_LOCK_ACCESS_SHARED... + d c 1 + d CURL_LOCK_ACCESS_SINGLE... + d c 2 + * + d curl_TimeCond s 10i 0 based(######ptr######) Enum + d CURL_TIMECOND_NONE... + d c 0 + d CURL_TIMECOND_IFMODSINCE... + d c 1 + d CURL_TIMECOND_LASTMOD... + d c 2 + d CURL_TIMECOND_LAST... + d c 3 + * + d curl_easytype s 10i 0 based(######ptr######) Enum + d CURLOT_LONG c 0 + d CURLOT_VALUES... + d c 1 + d CURLOT_OFF_T c 2 + d CURLOT_OBJECT... + d c 3 + d CURLOT_STRING... + d c 4 + d CURLOT_SLIST c 5 + d CURLOT_CBPTR c 6 + d CURLOT_BLOB c 7 + d CURLOT_FUNCTION... + d c 8 + * + d CURLSHcode s 10i 0 based(######ptr######) Enum + d CURLSHE_OK c 0 + d CURLSHE_BAD_OPTION... + d c 1 + d CURLSHE_IN_USE... + d c 2 + d CURLSHE_INVALID... + d c 3 + d CURLSHE_NOMEM... + d c 4 + d CURLSHE_NOT_BUILT_IN... + d c 5 + * + d CURLSHoption... + d s 10i 0 based(######ptr######) Enum + d CURLSHOPT_SHARE... + d c 1 + d CURLSHOPT_UNSHARE... + d c 2 + d CURLSHOPT_LOCKFUNC... + d c 3 + d CURLSHOPT_UNLOCKFUNC... + d c 4 + d CURLSHOPT_USERDATA... + d c 5 + * + d CURLversion s 10i 0 based(######ptr######) Enum + d CURLVERSION_FIRST... + d c 0 + d CURLVERSION_SECOND... + d c 1 + d CURLVERSION_THIRD... + d c 2 + d CURLVERSION_FOURTH... + d c 3 + d CURLVERSION_FIFTH... + d c 4 + d CURLVERSION_SIXTH... + d c 5 + d CURLVERSION_SEVENTH... + d c 6 + d CURLVERSION_EIGHTH... + d c 7 + d CURLVERSION_NINTH... + d c 8 + d CURLVERSION_TENTH... + d c 9 + d CURLVERSION_ELEVENTH... + d c 10 + d CURLVERSION_NOW... + d c 10 CURLVERSION_ELEVENTH + * + d CURLHcode s 10i 0 based(######ptr######) Enum + d CURLHE_OK c 0 + d CURLHE_BADINDEX... + d c 1 + d CURLHE_MISSING... + d c 2 + d CURLHE_NOHEADERS... + d c 3 + d CURLHE_NOREQUEST... + d c 4 + d CURLHE_OUT_OF_MEMORY... + d c 5 + d CURLHE_BAD_ARGUMENT... + d c 6 + d CURLHE_NOT_BUILT_IN... + d c 7 + * + d curlsocktype s 10i 0 based(######ptr######) Enum + d CURLSOCKTYPE_IPCXN... + d c 0 + d CURLSOCKTYPE_ACCEPT... + d c 1 + * + d CURL_SOCKOPT_OK... + d c 0 + d CURL_SOCKOPT_ERROR... + d c 1 + d CURL_SOCKOPT_ALREADY_CONNECTED... + d c 2 + * + d CURLMcode s 10i 0 based(######ptr######) Enum + d CURLM_CALL_MULTI_PERFORM... + d c -1 + d CURLM_CALL_MULTI_SOCKET... + d c -1 + d CURLM_OK c 0 + d CURLM_BAD_HANDLE... + d c 1 + d CURLM_BAD_EASY_HANDLE... + d c 2 + d CURLM_OUT_OF_MEMORY... + d c 3 + d CURLM_INTERNAL_ERROR... + d c 4 + d CURLM_BAD_SOCKET... + d c 5 + d CURLM_UNKNOWN_OPTION... + d c 6 + d CURLM_ADDED_ALREADY... + d c 7 + d CURLM_RECURSIVE_API_CALL... + d c 8 + d CURLM_WAKEUP_FAILURE... + d c 9 + d CURLM_BAD_FUNCTION_ARGUMENT... + d c 10 + d CURLM_LAST c 11 + * + d CURLMSG s 10i 0 based(######ptr######) Enum + d CURLMSG_NONE c 0 + d CURLMSG_DONE c 1 + * + d CURLMoption s 10i 0 based(######ptr######) Enum + d CURLMOPT_SOCKETFUNCTION... + d c 20001 + d CURLMOPT_SOCKETDATA... + d c 10002 + d CURLMOPT_PIPELINING... + d c 00003 + d CURLMOPT_TIMERFUNCTION... + d c 20004 + d CURLMOPT_TIMERDATA... + d c 10005 + d CURLMOPT_MAXCONNECTS... + d c 00006 + d CURLMOPT_MAX_HOST_CONNECTIONS... + d c 00007 + d CURLMOPT_MAX_PIPELINE_LENGTH... + d c 00008 + d CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE... + d c 30009 + d CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE... + d c 30010 + d CURLMOPT_PIPELINING_SITE_BL... + d c 10011 + d CURLMOPT_PIPELINING_SERVER_BL... + d c 10012 + d CURLMOPT_MAX_TOTAL_CONNECTIONS... + d c 00013 + d CURLMOPT_PUSHFUNCTION... + d c 20014 + d CURLMOPT_PUSHDATA... + d c 10015 + d CURLMOPT_MAX_CONCURRENT_STREAMS... + d c 10016 + * + * Bitmask bits for CURLMOPT_PIPELING. + * + d CURLPIPE_NOTHING... + d c x'00000000' + d CURLPIPE_HTTP1 c x'00000001' + d CURLPIPE_MULTIPLEX... + d c x'00000002' + * + * Public API enums for RTSP requests. + * + d CURLRTSPREQ_NONE... + d c 0 + d CURL_RTSPREQ_OPTIONS... + d c 1 + d CURL_RTSPREQ_DESCRIBE... + d c 2 + d CURL_RTSPREQ_ANNOUNCE... + d c 3 + d CURL_RTSPREQ_SETUP... + d c 4 + d CURL_RTSPREQ_PLAY... + d c 5 + d CURL_RTSPREQ_PAUSE... + d c 6 + d CURL_RTSPREQ_TEARDOWN... + d c 7 + d CURL_RTSPREQ_GET_PARAMETER... + d c 8 + d CURL_RTSPREQ_SET_PARAMETER... + d c 9 + d CURL_RTSPREQ_RECORD... + d c 10 + d CURL_RTSPREQ_RECEIVE... + d c 12 + d CURL_RTSPREQ_LAST... + d c 13 + * + d CURLUcode s 10i 0 based(######ptr######) Enum + d CURLUE_OK c 0 + d CURLUE_BAD_HANDLE... + d c 1 + d CURLUE_BAD_PARTPOINTER... + d c 2 + d CURLUE_MALFORMED_INPUT... + d c 3 + d CURLUE_BAD_PORT_NUMBER... + d c 4 + d CURLUE_UNSUPPORTED_SCHEME... + d c 5 + d CURLUE_URLDECODE... + d c 6 + d CURLUE_OUT_OF_MEMORY... + d c 7 + d CURLUE_USER_NOT_ALLOWED... + d c 8 + d CURLUE_UNKNOWN_PART... + d c 9 + d CURLUE_NO_SCHEME... + d c 10 + d CURLUE_NO_USER... + d c 11 + d CURLUE_NO_PASSWORD... + d c 12 + d CURLUE_NO_OPTIONS... + d c 13 + d CURLUE_NO_HOST... + d c 14 + d CURLUE_NO_PORT... + d c 15 + d CURLUE_NO_QUERY... + d c 16 + d CURLUE_NO_FRAGMENT... + d c 17 + d CURLUE_NO_ZONEID... + d c 18 + d CURLUE_BAD_FILE_URL... + d c 19 + d CURLUE_BAD_FRAGMENT... + d c 20 + d CURLUE_BAD_HOSTNAME... + d c 21 + d CURLUE_BAD_IPV6... + d c 22 + d CURLUE_BAD_LOGIN... + d c 23 + d CURLUE_BAD_PASSWORD... + d c 24 + d CURLUE_BAD_PATH... + d c 25 + d CURLUE_BAD_QUERY... + d c 26 + d CURLUE_BAD_SCHEME... + d c 27 + d CURLUE_BAD_SLASHES... + d c 28 + d CURLUE_BAD_USER... + d c 29 + d CURLUE_LACKS_IDN... + d c 30 + d CURLUE_TOO_LARGE... + d c 31 + * + d CURLUPart s 10i 0 based(######ptr######) Enum + d CURLUPART_URL c 0 + d CURLUPART_SCHEME... + d c 1 + d CURLUPART_USER... + d c 2 + d CURLUPART_PASSWORD... + d c 3 + d CURLUPART_OPTIONS... + d c 4 + d CURLUPART_HOST... + d c 5 + d CURLUPART_PORT... + d c 6 + d CURLUPART_PATH... + d c 7 + d CURLUPART_QUERY... + d c 8 + d CURLUPART_FRAGMENT... + d c 9 + d CURLUPART_ZONEID... + d c 10 + * + * + d CURLSTScode s 10i 0 based(######ptr######) Enum + d CURLSTS_OK c 0 + d CURLSTS_DONE c 1 + d CURLSTS_FAIL c 2 + * + * Renaming CURLMsg to CURL_Msg to avoid case-insensitivity name clash. + * + d CURL_Msg ds based(######ptr######) + d qualified + d msg like(CURLMSG) + d easy_handle * CURL * + d data * + d whatever * overlay(data) void * + d result overlay(data) like(CURLcode) + * + d curl_waitfd... + d ds based(######ptr######) + d qualified + d fd like(curl_socket_t) + d events 5i 0 + d revents 5i 0 + * + d curl_http_post... + d ds based(######ptr######) + d qualified + d next * curl_httppost * + d name * char * + d namelength 10i 0 long + d contents * char * + d contentslength... + d 10i 0 long + d buffer * char * + d bufferlength... + d 10i 0 long + d contenttype * char * + d contentheader... + d * curl_slist * + d more * curl_httppost * + d flags 10i 0 long + d showfilename * char * + d userp * void * + * + d curl_sockaddr ds based(######ptr######) + d qualified + d family 10i 0 + d socktype 10i 0 + d protocol 10i 0 + d addrlen 10u 0 + d addr 16 struct sockaddr + * + d curl_khtype s 10i 0 based(######ptr######) enum + d CURLKHTYPE_UNKNOWN... + d c 0 + d CURLKHTYPE_RSA1... + d c 1 + d CURLKHTYPE_RSA... + d c 2 + d CURLKHTYPE_DSS... + d c 3 + * + d curl_khkey ds based(######ptr######) + d qualified + d key * const char * + d len 10u 0 + d keytype like(curl_khtype) + * + d curl_forms ds based(######ptr######) + d qualified + d option like(CURLformoption) + d value * const char * + d value_ptr * overlay(value) + d value_procptr... + d * overlay(value) procptr + d value_num overlay(value: 8) like(curl_off_t) + * + d curl_slist ds based(######ptr######) + d qualified + d data * char * + d next * struct curl_slist * + * + d curl_version_info_data... + d ds based(######ptr######) + d qualified + d age like(CURLversion) + d version * const char * + d version_num 10u 0 + d host * const char * + d features 10i 0 + d ssl_version * const char * + d ssl_version_num... + d 10i 0 long + d libz_version * const char * + d protocols * const char * const * + d ares * const char * + d ares_num 10i 0 + d libidn * const char * + d iconv_ver_num... + d 10i 0 + d libssh_version... + d * const char * + d brotli_ver_num... + d 10u 0 + d brotli_version... + d * const char * + d nghttp2_ver_num... + d 10u 0 + d nghttp2_version... + d * const char * + d quic_version... + d * const char * + d cainfo... + d * const char * + d capath... + d * const char * + d zstd_ver_num... + d 10u 0 + d zstd_version... + d * const char * + d hyper_version... + d * const char * + d gsasl_version... + d * const char * + d feature_names... + d * const char * + * + d curl_certinfo ds based(######ptr######) + d qualified + d num_of_certs 10i 0 + d certinfo * struct curl_slist ** + * + d curl_fistrgs ds based(######ptr######) + d qualified + d time * char * + d perm * char * + d user * char * + d group * char * + d target * char * + * + d curl_tlssessioninfo... + d ds based(######ptr######) + d qualified + d backend like(curl_sslbackend) + d internals * void * + * + d curl_fileinfo ds based(######ptr######) + d qualified + d filename * char * + d filetype like(curlfiletype) + d time 10i 0 time_t + d perm 10u 0 + d uid 10i 0 + d gid 10i 0 + d size like(curl_off_t) + d hardlinks 10i 0 + d strings likeds(curl_fistrgs) + d flags 10u 0 + d b_data * char * + d b_size 10u 0 size_t + d b_used 10u 0 size_t + * + d curl_easyoption... + d ds based(######ptr######) + d qualified + d name * const char * + d id like(CURLoption) + d type like(curl_easytype) + d flags 10u 0 + * + d curl_hstsentry... + d ds based(######ptr######) + d qualified + d name * char * + d namelen 10u 0 size_t + d includeSubDomain... + d 10u 0 Bit field: 1 + d expire 10 + * + d curl_index ds based(######ptr######) + d qualified + d index 10u 0 size_t + d total 10u 0 size_t + * + d curl_header ds based(######ptr######) + d qualified + d name * char * + d value * char * + d amount 10u 0 size_t + d index 10u 0 size_t + d origin 10u 0 + d anchor * void * + * + d curl_blob ds based(######ptr######) + d qualified + d data * void * + d len 10u 0 size_t + d flags 10u 0 + * + d curl_ws_frame ds based(######ptr######) + d qualified + d age 10i 0 + d flags 10i 0 + d offset like(curl_off_t) + d bytesleft like(curl_off_t) + d len 10u 0 size_t + * + d curl_formget_callback... + d s * based(######ptr######) procptr + * + d curl_malloc_callback... + d s * based(######ptr######) procptr + * + d curl_free_callback... + d s * based(######ptr######) procptr + * + d curl_realloc_callback... + d s * based(######ptr######) procptr + * + d curl_strdup_callback... + d s * based(######ptr######) procptr + * + d curl_calloc_callback... + d s * based(######ptr######) procptr + * + d curl_lock_function... + d s * based(######ptr######) procptr + * + d curl_unlock_function... + d s * based(######ptr######) procptr + * + d curl_progress_callback... + d s * based(######ptr######) procptr + * + d curl_xferinfo_callback... + d s * based(######ptr######) procptr + * + d curl_read_callback... + d s * based(######ptr######) procptr + * + d curl_trailer_callback... + d s * based(######ptr######) procptr + * + d curl_write_callback... + d s * based(######ptr######) procptr + * + d curl_seek_callback... + d s * based(######ptr######) procptr + * + d curl_sockopt_callback... + d s * based(######ptr######) procptr + * + d curl_ioctl_callback... + d s * based(######ptr######) procptr + * + d curl_debug_callback... + d s * based(######ptr######) procptr + * + d curl_conv_callback... + d s * based(######ptr######) procptr + * + d curl_ssl_ctx_callback... + d s * based(######ptr######) procptr + * + d curl_socket_callback... + d s * based(######ptr######) procptr + * + d curl_multi_timer_callback... + d s * based(######ptr######) procptr + * + d curl_push_callback... + d s * based(######ptr######) procptr + * + d curl_opensocket_callback... + d s * based(######ptr######) procptr + * + d curl_sshkeycallback... + d s * based(######ptr######) procptr + * + d curl_chunk_bgn_callback... + d s * based(######ptr######) procptr + * + d curl_chunk_end_callback... + d s * based(######ptr######) procptr + * + d curl_fnmatch_callback... + d s * based(######ptr######) procptr + * + d curl_closesocket_callback... + d s * based(######ptr######) procptr + * + d curl_resolver_start_callback... + d s * based(######ptr######) procptr + * + d curl_hstsread_callback... + d s * based(######ptr######) procptr + * + d curl_hstswrite_callback... + d s * based(######ptr######) procptr + * + d curl_prereq_callback... + d s * based(######ptr######) procptr + * + d curl_sshhostkeycallback... + d s * based(######ptr######) procptr + * + d curl_ws_write_callback... + d s * based(######ptr######) procptr + * + ************************************************************************** + * Prototypes + ************************************************************************** + * + d curl_mime_init pr * extproc('curl_mime_init') curl_mime * + d easy * value CURL * + * + d curl_mime_free pr extproc('curl_mime_free') + d mime * value curl_mime * + * + d curl_mime_addpart... + d pr * extproc('curl_mime_addpart') curl_mimepart * + d mime * value curl_mime * + * + d curl_mime_name pr extproc('curl_mime_name') + d like(CURLcode) + d part * value curl_mimepart * + d name * value options(*string) + * + d curl_mime_filename... + d pr extproc('curl_mime_filename') + d like(CURLcode) + d part * value curl_mimepart * + d filename * value options(*string) + * + d curl_mime_type pr extproc('curl_mime_type') + d like(CURLcode) + d part * value curl_mimepart * + d mimetype * value options(*string) + * + d curl_mime_encoder... + d pr extproc('curl_mime_encoder') + d like(CURLcode) + d part * value curl_mimepart * + d encoding * value options(*string) + * + d curl_mime_data pr extproc('curl_mime_data') + d like(CURLcode) + d part * value curl_mimepart * + d data * value options(*string) + d datasize 10u 0 value size_t + * + d curl_mime_filedata... + d pr extproc('curl_mime_filedata') + d like(CURLcode) + d part * value curl_mimepart * + d filename * value options(*string) + * + d curl_mime_data_cb... + d pr extproc('curl_mime_data_cb') + d like(CURLcode) + d part * value curl_mimepart * + d datasize value like(curl_off_t) + d readfunc value like(curl_read_callback) + d seekfunc value like(curl_seek_callback) + d freefunc value like(curl_free_callback) + d arg * value void * + * + d curl_mime_subparts... + d pr extproc('curl_mime_subparts') + d like(CURLcode) + d part * value curl_mimepart * + d subparts * value curl_mime * + * + d curl_mime_headers... + d pr extproc('curl_mime_headers') + d like(CURLcode) + d part * value curl_mimepart * + d headers * value curl_slist * + d take_ownership... + d 10i 0 value + * + * This procedure as a variable parameter list. + * This prototype allows use of an option array, or a single "object" + * option. Other argument lists may be implemented by alias procedure + * prototype definitions. + * + d curl_formadd pr extproc('curl_formadd') + d like(CURLFORMcode) + d httppost * curl_httppost * + d lastpost * curl_httppost * + d option1 value like(CURLFORMoption) CURLFORM_ARRAY + d options(*nopass) + d object1 * value options(*string: *nopass) + d option2 value like(CURLFORMoption) CURLFORM_END + d options(*nopass) + * + * + d curl_strequal pr 10i 0 extproc('curl_strequal') + d s1 * value options(*string) + d s2 * value options(*string) + * + d curl_strnequal pr 10i 0 extproc('curl_strnequal') + d s1 * value options(*string) + d s2 * value options(*string) + d n 10u 0 value + * + d curl_formget pr 10i 0 extproc('curl_formget') + d form * value curl_httppost * + d arg * value + d append value like(curl_formget_callback) + * + d curl_formfree pr extproc('curl_formfree') + d form * value curl_httppost * + * + d curl_getenv pr * extproc('curl_getenv') + d variable * value options(*string) + * + d curl_version pr * extproc('curl_version') + * + d curl_easy_escape... + d pr * extproc('curl_easy_escape') char * + d handle * value CURL * + d string * value options(*string) + d length 10i 0 value + * + d curl_escape pr * extproc('curl_escape') char * + d string * value options(*string) + d length 10i 0 value + * + d curl_easy_unescape... + d pr * extproc('curl_easy_unescape') char * + d handle * value CURL * + d string * value options(*string) + d length 10i 0 value + d outlength 10i 0 options(*omit) + * + d curl_unescape pr * extproc('curl_unescape') char * + d string * value options(*string) + d length 10i 0 value + * + d curl_free pr extproc('curl_free') + d p * value + * + d curl_global_init... + d pr extproc('curl_global_init') + d like(CURLcode) + d flags 10i 0 value + * + d curl_global_init_mem... + d pr extproc('curl_global_init_mem') + d like(CURLcode) + d m value like(curl_malloc_callback) + d f value like(curl_free_callback) + d r value like(curl_realloc_callback) + d s value like(curl_strdup_callback) + d c value like(curl_calloc_callback) + * + d curl_global_cleanup... + d pr extproc('curl_global_cleanup') + * + d curl_slist_append... + d pr * extproc('curl_slist_append') struct curl_slist * + d list * value struct curl_slist * + d data * value options(*string) const char * + * + d curl_slist_free_all... + d pr extproc('curl_slist_free_all') + d list * value struct curl_slist * + * + d curl_getdate pr 10i 0 extproc('curl_getdate') time_t + d p * value options(*string) const char * + d unused 10i 0 const options(*omit) time_t + * + d curl_share_init... + d pr * extproc('curl_share_init') CURLSH * (= void *) + * + * Variable argument type procedure. + * Multiply prototyped to support all possible types. + * + d curl_share_setopt_int... + d pr extproc('curl_share_setopt') + d like(CURLSHcode) + d share * value CURLSH * (= void *) + d option value like(CURLSHoption) + d intarg 10i 0 value options(*nopass) + * + d curl_share_setopt_ptr... + d pr extproc('curl_share_setopt') + d like(CURLSHcode) + d share * value CURLSH * (= void *) + d option value like(CURLSHoption) + d ptrarg * value options(*nopass) + * + d curl_share_setopt_proc... + d pr extproc('curl_share_setopt') + d like(CURLSHcode) + d share * value CURLSH * (= void *) + d option value like(CURLSHoption) + d procarg * value procptr options(*nopass) + * + d curl_share_cleanup... + d pr extproc('curl_share_cleanup') + d like(CURLSHcode) + d share * value CURLSH * (= void *) + * + d curl_version_info... + d pr * extproc('curl_version_info') c_i_version_data * + d version value like(CURLversion) + * + d curl_easy_strerror... + d pr * extproc('curl_easy_strerror') const char * + d code value like(CURLcode) + * + d curl_share_strerror... + d pr * extproc('curl_share_strerror') const char * + d code value like(CURLSHcode) + * + d curl_easy_init pr * extproc('curl_easy_init') CURL * + * + * Multiple prototypes for vararg procedure curl_easy_setopt. + * + d curl_easy_setopt_long... + d pr extproc('curl_easy_setopt') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d longarg 10i 0 value options(*nopass) + * + d curl_easy_setopt_object... + d pr extproc('curl_easy_setopt') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d objectarg * value options(*string: *nopass) + * + d curl_easy_setopt_function... + d pr extproc('curl_easy_setopt') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d functionarg * value procptr options(*nopass) + * + d curl_easy_setopt_offset... + d pr extproc('curl_easy_setopt') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d offsetarg value like(curl_off_t) + d options(*nopass) + * + d curl_easy_setopt_blob... + d pr extproc('curl_easy_setopt') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d blob const likeds(curl_blob) + d options(*nopass) + * + * + d curl_easy_perform... + d pr extproc('curl_easy_perform') + d like(CURLcode) + d curl * value CURL * + * + d curl_easy_cleanup... + d pr extproc('curl_easy_cleanup') + d curl * value CURL * + * + * Multiple prototypes for vararg procedure curl_easy_getinfo. + * + d curl_easy_getinfo_string... + d pr extproc('curl_easy_getinfo') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d stringarg * options(*nopass) char * + * + d curl_easy_getinfo_long... + d pr extproc('curl_easy_getinfo') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d longarg 10i 0 options(*nopass) + * + d curl_easy_getinfo_double... + d pr extproc('curl_easy_getinfo') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d doublearg 8f options(*nopass) + * + d curl_easy_getinfo_slist... + d pr extproc('curl_easy_getinfo') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d slistarg * options(*nopass) struct curl_slist * + * + d curl_easy_getinfo_ptr... + d pr extproc('curl_easy_getinfo') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d ptrarg * options(*nopass) void * + * + d curl_easy_getinfo_socket... + d pr extproc('curl_easy_getinfo') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d socketarg like(curl_socket_t) options(*nopass) + * + d curl_easy_getinfo_off_t... + d pr extproc('curl_easy_getinfo') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d offsetarg like(curl_off_t) options(*nopass) + * + * + d curl_easy_duphandle... + d pr * extproc('curl_easy_duphandle') CURL * + d curl * value CURL * + * + d curl_easy_reset... + d pr extproc('curl_easy_reset') + d curl * value CURL * + * + d curl_easy_recv... + d pr extproc('curl_easy_recv') + d like(CURLcode) + d curl * value CURL * + d buffer * value void * + d buflen 10u 0 value size_t + d n 10u 0 size_t * + * + d curl_easy_send... + d pr extproc('curl_easy_send') + d like(CURLcode) + d curl * value CURL * + d buffer * value const void * + d buflen 10u 0 value size_t + d n 10u 0 size_t * + * + d curl_easy_pause... + d pr extproc('curl_easy_pause') + d like(CURLcode) + d curl * value CURL * + d bitmask 10i 0 value + * + d curl_easy_upkeep... + d pr extproc('curl_easy_upkeep') + d like(CURLcode) + d curl * value CURL * + * + d curl_multi_init... + d pr * extproc('curl_multi_init') CURLM * + * + d curl_multi_add_handle... + d pr extproc('curl_multi_add_handle') + d like(CURLMcode) + d multi_handle * value CURLM * + d curl_handle * value CURL * + * + d curl_multi_remove_handle... + d pr extproc('curl_multi_remove_handle') + d like(CURLMcode) + d multi_handle * value CURLM * + d curl_handle * value CURL * + * + d curl_multi_fdset... + d pr extproc('curl_multi_fdset') + d like(CURLMcode) + d multi_handle * value CURLM * + d read_fd_set 65535 options(*varsize) fd_set + d write_fd_set 65535 options(*varsize) fd_set + d exc_fd_set 65535 options(*varsize) fd_set + d max_fd 10i 0 + * + d curl_multi_wait... + d pr extproc('curl_multi_wait') + d like(CURLMcode) + d multi_handle * value CURLM * + d extra_fds * value curl_waitfd * + d extra_nfds 10u 0 value + d timeout_ms 10i 0 value + d ret 10i 0 options(*omit) + * + d curl_multi_perform... + d pr extproc('curl_multi_perform') + d like(CURLMcode) + d multi_handle * value CURLM * + d running_handles... + d 10i 0 + * + d curl_multi_cleanup... + d pr extproc('curl_multi_cleanup') + d like(CURLMcode) + d multi_handle * value CURLM * + * + d curl_multi_info_read... + d pr * extproc('curl_multi_info_read') CURL_Msg * + d multi_handle * value CURLM * + d msgs_in_queue 10i 0 + * + d curl_multi_strerror... + d pr * extproc('curl_multi_strerror') char * + d code value like(CURLMcode) + * + d curl_pushheader_bynum... + d pr * extproc('curl_pushheader_bynum') char * + d h * value curl_pushheaders * + d num 10u 0 value + * + d curl_pushheader_byname... + d pr * extproc('curl_pushheader_byname') char * + d h * value curl_pushheaders * + d header * value options(*string) const char * + * + d curl_multi_socket... + d pr extproc('curl_multi_socket') + d like(CURLMcode) + d multi_handle * value CURLM * + d s value like(curl_socket_t) + d running_handles... + d 10i 0 + * + d curl_multi_socket_action... + d pr extproc('curl_multi_socket_action') + d like(CURLMcode) + d multi_handle * value CURLM * + d s value like(curl_socket_t) + d ev_bitmask 10i 0 value + d running_handles... + d 10i 0 + * + d curl_multi_socket_all... + d pr extproc('curl_multi_socket_all') + d like(CURLMcode) + d multi_handle * value CURLM * + d running_handles... + d 10i 0 + * + d curl_multi_timeout... + d pr extproc('curl_multi_timeout') + d like(CURLMcode) + d multi_handle * value CURLM * + d milliseconds 10i 0 + * + * Multiple prototypes for vararg procedure curl_multi_setopt. + * + d curl_multi_setopt_long... + d pr extproc('curl_multi_setopt') + d like(CURLMcode) + d multi_handle * value CURLM * + d option value like(CURLMoption) + d longarg 10i 0 value options(*nopass) + * + d curl_multi_setopt_object... + d pr extproc('curl_multi_setopt') + d like(CURLMcode) + d multi_handle * value CURLM * + d option value like(CURLMoption) + d objectarg * value options(*string: *nopass) + * + d curl_multi_setopt_function... + d pr extproc('curl_multi_setopt') + d like(CURLMcode) + d multi_handle * value CURLM * + d option value like(CURLMoption) + d functionarg * value procptr options(*nopass) + * + d curl_multi_setopt_offset... + d pr extproc('curl_multi_setopt') + d like(CURLMcode) + d multi_handle * value CURLM * + d option value like(CURLMoption) + d offsetarg value like(curl_off_t) + d options(*nopass) + * + * + d curl_multi_assign... + d pr extproc('curl_multi_assign') + d like(CURLMcode) + d multi_handle * value CURLM * + d sockfd value like(curl_socket_t) + d sockp * value void * + * + d curl_multi_get_handles... + d pr * extproc('curl_multi_get_handles') CURL ** + d multi_handle * value CURLM * + * + d curl_url pr * extproc('curl_url') CURLU * + * + d curl_url_cleanup... + d pr extproc('curl_url_cleanup') + d handle * value CURLU * + * + d curl_url_dup pr * extproc('curl_url_dup') CURLU * + d in * value CURLU * + * + d curl_url_get pr extproc('curl_url_get') + d like(CURLUcode) + d handle * value CURLU * + d what value like(CURLUPart) + d part * char ** + d flags 10u 0 value + * + d curl_url_set pr extproc('curl_url_set') + d like(CURLUcode) + d handle * value CURLU * + d what value like(CURLUPart) + d part * value options(*string) + d flags 10u 0 value + * + d curl_url_strerror... + d pr * extproc('curl_url_strerror') const char * + d code value like(CURLUcode) + * + d curl_easy_option_by_name... + d pr * extproc('curl_easy_option_by_name') curl_easyoption * + d name * value options(*string) + * + d curl_easy_option_by_id... + d pr * extproc('curl_easy_option_by_id') curl_easyoption * + d id value like(CURLoption) + * + d curl_easy_option_next... + d pr * extproc('curl_easy_next') curl_easyoption * + d prev * value curl_easyoption * + * + d curl_ws_recv pr extproc('curl_ws_recv') + d like(CURLcode) + d curl * value CURL * + d buffer * value void * + d buflen 10u 0 value size_t + d recv 10u 0 size_t * + d metap likeds(curl_ws_frame) + * + d curl_ws_send pr extproc('curl_ws_send') + d like(CURLcode) + d curl * value CURL * + d buffer * value const void * + d buflen 10u 0 value size_t + d sent 10u 0 size_t * + d framesize like(curl_off_t) + d sendflags 10u 0 value + * + d curl_ws_meta pr * extproc('curl_ws_meta') curl_ws_frame * + d curl * value CURL * + * + d curl_easy_header... + d pr extproc('curl_easy_header') curl_header * + d like(CURLHcode) + d curl * value CURL * + d name * value options(*string) const char * + d index 10u 0 value size_t + d origin 10u 0 value + d request 10i 0 value + d hout * curl_header ** + * + d curl_easy_nextheader... + d pr * extproc('curl_easy_nextheader') curl_header * + d curl * value CURL * + d origin 10u 0 value + d request 10i 0 value + d prev * value curl_header * + * + ************************************************************************** + * CCSID wrapper procedure prototypes + ************************************************************************** + * + d curl_version_ccsid... + d pr * extproc('curl_version_ccsid') + d ccsid 10u 0 value + * + d curl_easy_escape_ccsid... + d pr * extproc('curl_easy_escape_ccsid') char * + d handle * value CURL * + d string * value options(*string) + d length 10i 0 value + d ccsid 10u 0 value + * + d curl_easy_unescape_ccsid... + d pr * extproc('curl_easy_unescape_ccsid') char * + d handle * value CURL * + d string * value options(*string) + d length 10i 0 value + d outlength 10i 0 options(*omit) + d ccsid 10u 0 value + * + d curl_slist_append_ccsid... + d pr * extproc('curl_slist_append_ccsid') struct curl_slist * + d list * value struct curl_slist * + d data * value options(*string) const char * + d ccsid 10u 0 value + * + d curl_getdate_ccsid... + d pr 10i 0 extproc('curl_getdate_ccsid') time_t + d p * value options(*string) const char * + d unused 10i 0 const options(*omit) time_t + d ccsid 10u 0 value + * + d curl_version_info_ccsid... + d pr * extproc('curl_version_info_ccsid') c_i_version_data * + d version value like(CURLversion) + d ccsid 10u 0 value + * + d curl_easy_strerror_ccsid... + d pr * extproc('curl_easy_strerror_ccsid') const char * + d code value like(CURLcode) + d ccsid 10u 0 value + * + d curl_share_strerror_ccsid... + d pr * extproc('curl_share_strerror_ccsid') const char * + d code value like(CURLSHcode) + d ccsid 10u 0 value + * + d curl_multi_strerror_ccsid... + d pr * extproc('curl_multi_strerror_ccsid') char * + d code value like(CURLMcode) + d ccsid 10u 0 value + * + * May be used for strings and structures. + d curl_easy_getinfo_ccsid... + d pr extproc('curl_easy_getinfo_ccsid') + d like(CURLcode) + d curl * value CURL * + d info value like(CURLINFO) + d ptrarg * options(*nopass) char * + d ccsid 10u 0 value options(*nopass) + * + d curl_certinfo_free_all... + d pr extproc('curl_certinfo_free_all') + d info * value + * + d curl_formadd_ccsid... + d pr extproc('curl_formadd_ccsid') + d like(CURLFORMcode) + d httppost * curl_httppost * + d lastpost * curl_httppost * + d option1 value like(CURLFORMoption) CURLFORM_ARRAY + d options(*nopass) + d object1 * value options(*string: *nopass) + d option2 value like(CURLFORMoption) CURLFORM_END + d options(*nopass) + * + d curl_formget_ccsid... + d pr 10i 0 extproc('curl_formget_ccsid') + d form * value curl_httppost * + d arg * value + d append value like(curl_formget_callback) + d ccsid 10u 0 value + * + d curl_form_long_value... + d pr * extproc('curl_form_long_value') + d value 10i 0 value curl_httppost * + * + d curl_easy_setopt_ccsid... + d pr extproc('curl_easy_setopt_ccsid') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d objectarg * value options(*string: *nopass) + d ccsid 10u 0 value options(*nopass) + * + d curl_easy_setopt_blob_ccsid... + d pr extproc('curl_easy_setopt_ccsid') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d blob const likeds(curl_blob) + d options(*nopass) + d ccsid 10u 0 value options(*nopass) + * + d curl_pushheader_bynum_ccsid... + d pr * extproc( char * + d 'curl_pushheader_bynum_ccsid') + d h * value curl_pushheaders * + d num 10u 0 value + d ccsid 10u 0 value + * + d curl_pushheader_byname_ccsid... + d pr * extproc( char * + d 'curl_pushheader_byname_ccsid') + d h * value curl_pushheaders * + d header * value options(*string) const char * + d ccsidin 10u 0 value + d ccsidout 10u 0 value + * + d curl_mime_name_ccsid... + d pr extproc('curl_mime_name_ccsid') + d like(CURLcode) + d part * value curl_mimepart * + d name * value options(*string) + d ccsid 10u 0 value + * + d curl_mime_filename_ccsid... + d pr extproc('curl_mime_filename_ccsid') + d like(CURLcode) + d part * value curl_mimepart * + d filename * value options(*string) + d ccsid 10u 0 value + * + d curl_mime_type_ccsid... + d pr extproc('curl_mime_type_ccsid') + d like(CURLcode) + d part * value curl_mimepart * + d mimetype * value options(*string) + d ccsid 10u 0 value + * + d curl_mime_encoder_ccsid... + d pr extproc('curl_mime_encoder_ccsid') + d like(CURLcode) + d part * value curl_mimepart * + d encoding * value options(*string) + d ccsid 10u 0 value + * + d curl_mime_data_ccsid... + d pr extproc('curl_mime_data_ccsid') + d like(CURLcode) + d part * value curl_mimepart * + d data * value options(*string) + d datasize 10u 0 value size_t + d ccsid 10u 0 value + * + d curl_mime_filedata_ccsid... + d pr extproc('curl_mime_filedata_ccsid') + d like(CURLcode) + d part * value curl_mimepart * + d filename * value options(*string) + d ccsid 10u 0 value + * + d curl_url_get_ccsid... + d pr extproc('curl_url_get_ccsid') + d like(CURLUcode) + d handle * value CURLU * + d what value like(CURLUPart) + d part * char ** + d flags 10u 0 value + d ccsid 10u 0 value + * + d curl_url_set_ccsid... + d pr extproc('curl_url_set_ccsid') + d like(CURLUcode) + d handle * value CURLU * + d what value like(CURLUPart) + d part * value options(*string) + d flags 10u 0 value + d ccsid 10u 0 value + * + d curl_url_strerror_ccsid... + d pr * extproc('curl_url_strerror_ccsid') const char * + d code value like(CURLUcode) + d ccsid 10u 0 value + * + d curl_easy_option_by_name_ccsid... + d pr * extproc( curl_easyoption * + d 'curl_easy_option_by_name_ccsid') + d name * value options(*string) + d ccsid 10u 0 value + * + d curl_easy_option_get_name_ccsid... + d pr * extproc( const char * + d 'curl_easy_option_get_name_ccsid') + d option * value curl_easyoption * + d ccsid 10u 0 value + * + d curl_easy_header_ccsid... + d pr extproc('curl_easy_header_ccsid') curl_header * + d like(CURLHcode) + d curl * value CURL * + d name * value options(*string) const char * + d index 10u 0 value size_t + d origin 10u 0 value + d request 10i 0 value + d hout * curl_header ** + d ccsid 10u 0 value + * + d curl_from_ccsid... + d pr * extproc('curl_from_ccsid') const char * + d s * value options(*string) const char * + d ccsid 10u 0 value + * + d curl_to_ccsid... + d pr * extproc('curl_to_ccsid') const char * + d s * value options(*string) const char * + d ccsid 10u 0 value + * + ************************************************************************** + * Procedure overloading + ************************************************************************** + * + /if defined(*V7R4M0) + d curl_easy_setopt_RPGnum_... + d pr extproc('curl_easy_setopt_RPGnum_') + d like(CURLcode) + d curl * value CURL * + d option value like(CURLoption) + d numarg 20i 0 value + * + d curl_easy_setopt... + d pr like(CURLcode) + d overload(curl_easy_setopt_RPGnum_: + d curl_easy_setopt_object: + d curl_easy_setopt_function) + * + d curl_multi_setopt_RPGnum_... + d pr extproc('curl_multi_setopt_RPGnum_') + d like(CURLcode) + d curl * value CURLM * + d option value like(CURLMoption) + d numarg 20i 0 value + * + d curl_multi_setopt... + d pr like(CURLcode) + d overload(curl_multi_setopt_RPGnum_: + d curl_multi_setopt_object: + d curl_multi_setopt_function) + * + d curl_share_setopt... + d pr like(CURLcode) + d overload(curl_share_setopt_int: + d curl_share_setopt_ptr: + d curl_share_setopt_proc) + * + d curl_easy_getinfo... + d pr like(CURLcode) + d overload(curl_easy_getinfo_long: + d curl_easy_getinfo_off_t: + d curl_easy_getinfo_double: + d curl_easy_getinfo_ptr) + /endif + * + /endif diff --git a/packages/OS400/curlcl.c b/packages/OS400/curlcl.c new file mode 100644 index 0000000..02edcd6 --- /dev/null +++ b/packages/OS400/curlcl.c @@ -0,0 +1,177 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ + +/* CL interface program to curl cli tool. */ + +#include +#include + +#include +#include +#include + +#ifndef CURLPGM +#define CURLPGM "CURL" +#endif + +/* Variable-length string, with 16-bit length. */ +struct vary2 { + short len; + char string[5000]; +}; + +/* Arguments from CL command. */ +struct arguments { + char *pgm; /* Program name. */ + struct vary2 *cmdargs; /* Command line arguments. */ +}; + +static int +is_ifs(char c) +{ + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +static int +parse_command_line(const char *cmdargs, size_t len, + size_t *argc, char **argv, + size_t *argsize, char *argbuf) +{ + const char *endline = cmdargs + len; + char quote = '\0'; + int inarg = 0; + + *argc = 0; + *argsize = 0; + + while(cmdargs < endline) { + char c = *cmdargs++; + + if(!inarg) { + /* Skip argument separator. */ + if(is_ifs(c)) + continue; + + /* Start a new argument. */ + ++*argc; + if(argv) + *argv++ = argbuf; + inarg = 1; + } + + /* Check for quoting end. */ + if(quote && quote == c) { + quote = '\0'; + continue; + } + + /* Check for backslash-escaping. */ + if(quote != '\'' && c == '\\') { + if(cmdargs >= endline) { + fputs("Trailing backslash in command\n", stderr); + return -1; + } + c = *cmdargs++; + } + else if(!quote && is_ifs(c)) { /* Check for end of argument. */ + inarg = 0; + c = '\0'; /* Will store a string terminator. */ + } + + /* Store argument character and count it. */ + if(argbuf) + *argbuf++ = c; + ++*argsize; + } + + if(quote) { + fprintf(stderr, "Unterminated quote: %c\n", quote); + return -1; + } + + /* Terminate last argument. */ + if(inarg) { + if(argbuf) + *argbuf = '\0'; + ++*argsize; + } + + /* Terminate argument list. */ + if(argv) + *argv = NULL; + + return 0; +} + + +int +main(int argsc, struct arguments *args) +{ + size_t argc; + char **argv; + size_t argsize; + int i; + int exitcode; + char library[11]; + + /* Extract current program library name. */ + for(i = 0; i < 10; i++) { + char c = args->pgm[i]; + + if(!c || c == '/') + break; + + library[i] = c; + } + library[i] = '\0'; + + /* Measure arguments size. */ + exitcode = parse_command_line(args->cmdargs->string, args->cmdargs->len, + &argc, NULL, &argsize, NULL); + + if(!exitcode) { + /* Allocate space for parsed arguments. */ + argv = (char **) malloc((argc + 1) * sizeof(*argv) + argsize); + if(!argv) { + fputs("Memory allocation error\n", stderr); + exitcode = -2; + } + else { + _SYSPTR pgmptr = rslvsp(WLI_PGM, (char *) CURLPGM, library, _AUTH_NONE); + _LU_Work_Area_T *luwrka = (_LU_Work_Area_T *) _LUWRKA(); + + parse_command_line(args->cmdargs->string, args->cmdargs->len, + &argc, argv, &argsize, (char *) (argv + argc + 1)); + + /* Call program. */ + _CALLPGMV((void *) &pgmptr, argv, argc); + exitcode = luwrka->LU_RC; + + free(argv); + } + } + + return exitcode; +} diff --git a/packages/OS400/curlmain.c b/packages/OS400/curlmain.c new file mode 100644 index 0000000..1b030b7 --- /dev/null +++ b/packages/OS400/curlmain.c @@ -0,0 +1,121 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ + +/* + * QADRT/QADRTMAIN2 substitution program. + * This is needed because the IBM-provided QADRTMAIN2 does not + * properly translate arguments by default or if no locale is provided. + */ + +#include +#include +#include +#include +#include + +/* Do not use qadrt.h since it defines unneeded static procedures. */ +extern void QadrtInit(void); +extern int QadrtFreeConversionTable(void); +extern int QadrtFreeEnviron(void); +extern char * setlocale_a(int, const char *); + + +/* The ASCII main program. */ +extern int main_a(int argc, char * * argv); + +/* Global values of original EBCDIC arguments. */ +int ebcdic_argc; +char ** ebcdic_argv; + + +int main(int argc, char **argv) +{ + int i; + int j; + iconv_t cd; + size_t bytecount = 0; + char *inbuf; + char *outbuf; + size_t inbytesleft; + size_t outbytesleft; + char dummybuf[128]; + char tocode[32]; + char fromcode[32]; + + ebcdic_argc = argc; + ebcdic_argv = argv; + + /* Build the encoding converter. */ + strncpy(tocode, "IBMCCSID01208", sizeof(tocode)); /* Use UTF-8. */ + strncpy(fromcode, "IBMCCSID000000000010", sizeof(fromcode)); + cd = iconv_open(tocode, fromcode); + + /* Measure the arguments. */ + for(i = 0; i < argc; i++) { + inbuf = argv[i]; + do { + inbytesleft = 0; + outbuf = dummybuf; + outbytesleft = sizeof(dummybuf); + j = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + bytecount += outbuf - dummybuf; + } while(j == -1 && errno == E2BIG); + + /* Reset the shift state. */ + iconv(cd, NULL, &inbytesleft, &outbuf, &outbytesleft); + } + + /* Allocate memory for the ASCII arguments and vector. */ + argv = (char **) malloc((argc + 1) * sizeof(*argv) + bytecount); + + /* Build the vector and convert argument encoding. */ + outbuf = (char *) (argv + argc + 1); + outbytesleft = bytecount; + + for(i = 0; i < argc; i++) { + argv[i] = outbuf; + inbuf = ebcdic_argv[i]; + inbytesleft = 0; + iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + iconv(cd, NULL, &inbytesleft, &outbuf, &outbytesleft); + } + + iconv_close(cd); + argv[argc] = NULL; + + /* Try setting the locale regardless of QADRT_ENV_LOCALE. */ + setlocale_a(LC_ALL, ""); + + /* Call the program. */ + i = main_a(argc, argv); + + /* Clean-up allocated items. */ + free((char *) argv); + QadrtFreeConversionTable(); + QadrtFreeEnviron(); + + /* Terminate. */ + return i; +} diff --git a/packages/OS400/initscript.sh b/packages/OS400/initscript.sh new file mode 100755 index 0000000..b75055a --- /dev/null +++ b/packages/OS400/initscript.sh @@ -0,0 +1,287 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +CLcommand() +{ + /usr/bin/system "${@}" || exit 1 +} + +setenv() + +{ + # Define and export. + + eval ${1}="${2}" + export ${1} +} + + +case "${SCRIPTDIR}" in +/*) ;; +*) SCRIPTDIR="`pwd`/${SCRIPTDIR}" +esac + +while true +do case "${SCRIPTDIR}" in + */.) SCRIPTDIR="${SCRIPTDIR%/.}";; + *) break;; + esac +done + +# The script directory is supposed to be in $TOPDIR/packages/os400. + +TOPDIR=`dirname "${SCRIPTDIR}"` +TOPDIR=`dirname "${TOPDIR}"` +export SCRIPTDIR TOPDIR + +# Extract the SONAME from the library makefile. + +SONAME=`sed -e '/^VERSIONCHANGE=/!d;s/^.*=\([0-9]*\).*/\1/' \ + < "${TOPDIR}/lib/Makefile.soname"` +export SONAME + +# Get OS/400 configuration parameters. + +. "${SCRIPTDIR}/config400.default" +if [ -f "${SCRIPTDIR}/config400.override" ] +then . "${SCRIPTDIR}/config400.override" +fi + +# Need to get the version definitions. + +LIBCURL_VERSION=`grep '^#define *LIBCURL_VERSION ' \ + "${TOPDIR}/include/curl/curlver.h" | + sed 's/.*"\(.*\)".*/\1/'` +LIBCURL_VERSION_MAJOR=`grep '^#define *LIBCURL_VERSION_MAJOR ' \ + "${TOPDIR}/include/curl/curlver.h" | + sed 's/^#define *LIBCURL_VERSION_MAJOR *\([^ ]*\).*/\1/'` +LIBCURL_VERSION_MINOR=`grep '^#define *LIBCURL_VERSION_MINOR ' \ + "${TOPDIR}/include/curl/curlver.h" | + sed 's/^#define *LIBCURL_VERSION_MINOR *\([^ ]*\).*/\1/'` +LIBCURL_VERSION_PATCH=`grep '^#define *LIBCURL_VERSION_PATCH ' \ + "${TOPDIR}/include/curl/curlver.h" | + sed 's/^#define *LIBCURL_VERSION_PATCH *\([^ ]*\).*/\1/'` +LIBCURL_VERSION_NUM=`grep '^#define *LIBCURL_VERSION_NUM ' \ + "${TOPDIR}/include/curl/curlver.h" | + sed 's/^#define *LIBCURL_VERSION_NUM *0x\([^ ]*\).*/\1/'` +LIBCURL_TIMESTAMP=`grep '^#define *LIBCURL_TIMESTAMP ' \ + "${TOPDIR}/include/curl/curlver.h" | + sed 's/.*"\(.*\)".*/\1/'` +export LIBCURL_VERSION +export LIBCURL_VERSION_MAJOR LIBCURL_VERSION_MINOR LIBCURL_VERSION_PATCH +export LIBCURL_VERSION_NUM LIBCURL_TIMESTAMP + +################################################################################ +# +# OS/400 specific definitions. +# +################################################################################ + +LIBIFSNAME="/QSYS.LIB/${TARGETLIB}.LIB" + + +################################################################################ +# +# Procedures. +# +################################################################################ + +# action_needed dest [src] +# +# dest is an object to build +# if specified, src is an object on which dest depends. +# +# exit 0 (succeeds) if some action has to be taken, else 1. + +action_needed() + +{ + [ ! -e "${1}" ] && return 0 + [ "${2}" ] || return 1 + [ "${1}" -ot "${2}" ] && return 0 + return 1 +} + + +# canonicalize_path path +# +# Return canonicalized path as: +# - Absolute +# - No . or .. component. + +canonicalize_path() + +{ + if expr "${1}" : '^/' > /dev/null + then P="${1}" + else P="`pwd`/${1}" + fi + + R= + IFSSAVE="${IFS}" + IFS="/" + + for C in ${P} + do IFS="${IFSSAVE}" + case "${C}" in + .) ;; + ..) R=`expr "${R}" : '^\(.*/\)..*'` + ;; + ?*) R="${R}${C}/" + ;; + *) ;; + esac + done + + IFS="${IFSSAVE}" + echo "/`expr "${R}" : '^\(.*\)/'`" +} + + +# make_module module_name source_name [additional_definitions] +# +# Compile source name into ASCII module if needed. +# As side effect, append the module name to variable MODULES. +# Set LINK to "YES" if the module has been compiled. + +make_module() + +{ + MODULES="${MODULES} ${1}" + MODIFSNAME="${LIBIFSNAME}/${1}.MODULE" + action_needed "${MODIFSNAME}" "${2}" || return 0; + SRCDIR=`dirname \`canonicalize_path "${2}"\`` + + # #pragma convert has to be in the source file itself, i.e. + # putting it in an include file makes it only active + # for that include file. + # Thus we build a temporary file with the pragma prepended to + # the source file and we compile that temporary file. + + echo "#line 1 \"${2}\"" > __tmpsrcf.c + echo "#pragma convert(819)" >> __tmpsrcf.c + echo "#line 1" >> __tmpsrcf.c + cat "${2}" >> __tmpsrcf.c + CMD="CRTCMOD MODULE(${TARGETLIB}/${1}) SRCSTMF('__tmpsrcf.c')" + CMD="${CMD} SYSIFCOPT(*IFS64IO *ASYNCSIGNAL)" +# CMD="${CMD} OPTION(*INCDIRFIRST *SHOWINC *SHOWSYS)" + CMD="${CMD} OPTION(*INCDIRFIRST)" + CMD="${CMD} LOCALETYPE(*LOCALE) FLAG(10)" + CMD="${CMD} INCDIR('${QADRTDIR}/include'" + CMD="${CMD} '${TOPDIR}/include/curl' '${TOPDIR}/include' '${SRCDIR}'" + CMD="${CMD} '${TOPDIR}/packages/OS400'" + + if [ "${WITH_ZLIB}" != "0" ] + then CMD="${CMD} '${ZLIB_INCLUDE}'" + fi + + if [ "${WITH_LIBSSH2}" != "0" ] + then CMD="${CMD} '${LIBSSH2_INCLUDE}'" + fi + + CMD="${CMD} ${INCLUDES})" + CMD="${CMD} TGTCCSID(${TGTCCSID}) TGTRLS(${TGTRLS})" + CMD="${CMD} OUTPUT(${OUTPUT})" + CMD="${CMD} OPTIMIZE(${OPTIMIZE})" + CMD="${CMD} DBGVIEW(${DEBUG})" + + DEFINES="${3} 'qadrt_use_inline'" + + if [ "${WITH_ZLIB}" != "0" ] + then DEFINES="${DEFINES} HAVE_LIBZ" + fi + + if [ "${WITH_LIBSSH2}" != "0" ] + then DEFINES="${DEFINES} USE_LIBSSH2" + fi + + if [ "${DEFINES}" ] + then CMD="${CMD} DEFINE(${DEFINES})" + fi + + CLcommand "${CMD}" + rm -f __tmpsrcf.c + LINK=YES +} + + +# Determine DB2 object name from IFS name. + +db2_name() + +{ + if [ "${2}" = 'nomangle' ] + then basename "${1}" | + tr 'a-z-' 'A-Z_' | + sed -e 's/\..*//' \ + -e 's/^\(.\).*\(.........\)$/\1\2/' + else basename "${1}" | + tr 'a-z-' 'A-Z_' | + sed -e 's/\..*//' \ + -e 's/^CURL_*/C/' \ + -e 's/^TOOL_*/T/' \ + -e 's/^\(.\).*\(.........\)$/\1\2/' + fi +} + + +# Copy IFS file replacing version info. + +versioned_copy() + +{ + sed -e "s/@LIBCURL_VERSION@/${LIBCURL_VERSION}/g" \ + -e "s/@LIBCURL_VERSION_MAJOR@/${LIBCURL_VERSION_MAJOR}/g" \ + -e "s/@LIBCURL_VERSION_MINOR@/${LIBCURL_VERSION_MINOR}/g" \ + -e "s/@LIBCURL_VERSION_PATCH@/${LIBCURL_VERSION_PATCH}/g" \ + -e "s/@LIBCURL_VERSION_NUM@/${LIBCURL_VERSION_NUM}/g" \ + -e "s/@LIBCURL_TIMESTAMP@/${LIBCURL_TIMESTAMP}/g" \ + < "${1}" > "${2}" +} + + +# Get definitions from a make file. +# The `sed' statement works as follows: +# - Join \nl-separated lines. +# - Retain only lines that begins with "identifier =". +# - Replace @...@ substitutions by shell variable references. +# - Turn these lines into shell variable assignments. + +get_make_vars() + +{ + eval "`sed -e ': begin' \ + -e '/\\\\$/{' \ + -e 'N' \ + -e 's/\\\\\\n/ /' \ + -e 'b begin' \ + -e '}' \ + -e '/^[A-Za-z_][A-Za-z0-9_]*[[:space:]]*=/!d' \ + -e 's/@\\([A-Za-z0-9_]*\\)@/${\\1}/g' \ + -e 's/[[:space:]]*=[[:space:]]*/=/' \ + -e 's/=\\(.*[^[:space:]]\\)[[:space:]]*$/=\\"\\1\\"/' \ + -e 's/\\\$(\\([^)]*\\))/\${\\1}/g' \ + < \"${1}\"`" +} diff --git a/packages/OS400/make-include.sh b/packages/OS400/make-include.sh new file mode 100755 index 0000000..30235eb --- /dev/null +++ b/packages/OS400/make-include.sh @@ -0,0 +1,106 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# +# Installation of the header files in the OS/400 library. +# + +SCRIPTDIR=`dirname "${0}"` +. "${SCRIPTDIR}/initscript.sh" +cd "${TOPDIR}/include" + + +# Create the OS/400 source program file for the header files. + +SRCPF="${LIBIFSNAME}/H.FILE" + +if action_needed "${SRCPF}" +then CMD="CRTSRCPF FILE(${TARGETLIB}/H) RCDLEN(112)" + CMD="${CMD} CCSID(${TGTCCSID}) TEXT('curl: Header files')" + CLcommand "${CMD}" +fi + + +# Create the IFS directory for the header files. + +IFSINCLUDE="${IFSDIR}/include/curl" + +if action_needed "${IFSINCLUDE}" +then mkdir -p "${IFSINCLUDE}" +fi + + +# Enumeration values are used as va_arg tagfields, so they MUST be +# integers. + +copy_hfile() + +{ + destfile="${1}" + srcfile="${2}" + shift + shift + sed -e '1i\ +#pragma enum(int)\ +' "${@}" -e '$a\ +#pragma enum(pop)\ +' < "${srcfile}" > "${destfile}" +} + +# Copy the header files. + +for HFILE in curl/*.h ${SCRIPTDIR}/ccsidcurl.h +do case "`basename \"${HFILE}\" .h`" in + stdcheaders|typecheck-gcc) + continue;; + esac + + DEST="${SRCPF}/`db2_name \"${HFILE}\" nomangle`.MBR" + + if action_needed "${DEST}" "${HFILE}" + then copy_hfile "${DEST}" "${HFILE}" + IFSDEST="${IFSINCLUDE}/`basename \"${HFILE}\"`" + rm -f "${IFSDEST}" + ln -s "${DEST}" "${IFSDEST}" + fi +done + + +# Copy the ILE/RPG header file, setting-up version number. + +versioned_copy "${SCRIPTDIR}/curl.inc.in" "${SRCPF}/CURL.INC.MBR" +rm -f "${IFSINCLUDE}/curl.inc.rpgle" +ln -s "${SRCPF}/CURL.INC.MBR" "${IFSINCLUDE}/curl.inc.rpgle" + + +# Duplicate file H as CURL to support more include path forms. + +if action_needed "${LIBIFSNAME}/CURL.FILE" +then : +else CLcommand "DLTF FILE(${TARGETLIB}/CURL)" +fi + +CMD="CRTDUPOBJ OBJ(H) FROMLIB(${TARGETLIB}) OBJTYPE(*FILE) TOLIB(*FROMLIB)" +CMD="${CMD} NEWOBJ(CURL) DATA(*YES)" +CLcommand "${CMD}" diff --git a/packages/OS400/make-lib.sh b/packages/OS400/make-lib.sh new file mode 100755 index 0000000..860cb5d --- /dev/null +++ b/packages/OS400/make-lib.sh @@ -0,0 +1,183 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# +# libcurl compilation script for the OS/400. +# + +SCRIPTDIR=`dirname "${0}"` +. "${SCRIPTDIR}/initscript.sh" +cd "${TOPDIR}/lib" + +# Need to have IFS access to the mih/cipher header file. + +if action_needed cipher.mih '/QSYS.LIB/QSYSINC.LIB/MIH.FILE/CIPHER.MBR' +then rm -f cipher.mih + ln -s '/QSYS.LIB/QSYSINC.LIB/MIH.FILE/CIPHER.MBR' cipher.mih +fi + + +# Create and compile the identification source file. + +echo '#pragma comment(user, "libcurl version '"${LIBCURL_VERSION}"'")' > os400.c +echo '#pragma comment(user, __DATE__)' >> os400.c +echo '#pragma comment(user, __TIME__)' >> os400.c +echo '#pragma comment(copyright, "Copyright (C) Daniel Stenberg et al. OS/400 version by P. Monnerat")' >> os400.c +make_module OS400 os400.c BUILDING_LIBCURL +LINK= # No need to rebuild service program yet. +MODULES= + + +# Get source list (CSOURCES variable). + +get_make_vars Makefile.inc + + +# Compile the sources into modules. + +INCLUDES="'`pwd`'" + +make_module OS400SYS "${SCRIPTDIR}/os400sys.c" BUILDING_LIBCURL +make_module CCSIDCURL "${SCRIPTDIR}/ccsidcurl.c" BUILDING_LIBCURL + +for SRC in ${CSOURCES} +do MODULE=`db2_name "${SRC}"` + make_module "${MODULE}" "${SRC}" BUILDING_LIBCURL +done + + +# If needed, (re)create the static binding directory. + +if action_needed "${LIBIFSNAME}/${STATBNDDIR}.BNDDIR" +then LINK=YES +fi + +if [ "${LINK}" ] +then rm -rf "${LIBIFSNAME}/${STATBNDDIR}.BNDDIR" + CMD="CRTBNDDIR BNDDIR(${TARGETLIB}/${STATBNDDIR})" + CMD="${CMD} TEXT('LibCurl API static binding directory')" + CLcommand "${CMD}" + + for MODULE in ${MODULES} + do CMD="ADDBNDDIRE BNDDIR(${TARGETLIB}/${STATBNDDIR})" + CMD="${CMD} OBJ((${TARGETLIB}/${MODULE} *MODULE))" + CLcommand "${CMD}" + done +fi + + +# The exportation file for service program creation must be in a DB2 +# source file, so make sure it exists. + +if action_needed "${LIBIFSNAME}/TOOLS.FILE" +then CMD="CRTSRCPF FILE(${TARGETLIB}/TOOLS) RCDLEN(112)" + CMD="${CMD} TEXT('curl: build tools')" + CLcommand "${CMD}" +fi + + +# Gather the list of symbols to export. +# First use awk to pull all CURL_EXTERN function prototypes from +# the header files, pass through to sed to strip CURL_DEPRECATED(..) +# and CURL_TEMP_PRINTF(..) then back to awk to pull the string +# immediately to the left of a bracket stripping any spaces or *'s. + +EXPORTS=`awk '/^CURL_EXTERN/,/;/' \ + "${TOPDIR}"/include/curl/*.h \ + "${SCRIPTDIR}/ccsidcurl.h" | + sed 's/ CURL_DEPRECATED(.*)//g;s/ CURL_TEMP_PRINTF(.*)//g' | + awk '{br=index($0,"("); \ + if (br) { \ + for(c=br-1; ;c--) { \ + if (c==1) { \ + print substr($0,c,br-1); break \ + } else if (match(substr($0, c, br-c), "[ *]") != 0) { \ + print substr($0, c+1, br-c-1); break \ + } \ + } \ + } \ + }'` + +# Create the service program exportation file in DB2 member if needed. + +BSF="${LIBIFSNAME}/TOOLS.FILE/BNDSRC.MBR" + +if action_needed "${BSF}" Makefile.am +then LINK=YES +fi + +if [ "${LINK}" ] +then echo " STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('LIBCURL_${SONAME}')" \ + > "${BSF}" + for EXPORT in ${EXPORTS} + do echo ' EXPORT SYMBOL("'"${EXPORT}"'")' >> "${BSF}" + done + + echo ' ENDPGMEXP' >> "${BSF}" +fi + + +# Build the service program if needed. + +if action_needed "${LIBIFSNAME}/${SRVPGM}.SRVPGM" +then LINK=YES +fi + +if [ "${LINK}" ] +then CMD="CRTSRVPGM SRVPGM(${TARGETLIB}/${SRVPGM})" + CMD="${CMD} SRCFILE(${TARGETLIB}/TOOLS) SRCMBR(BNDSRC)" + CMD="${CMD} MODULE(${TARGETLIB}/OS400)" + CMD="${CMD} BNDDIR(${TARGETLIB}/${STATBNDDIR}" + if [ "${WITH_ZLIB}" != 0 ] + then CMD="${CMD} ${ZLIB_LIB}/${ZLIB_BNDDIR}" + liblist -a "${ZLIB_LIB}" + fi + if [ "${WITH_LIBSSH2}" != 0 ] + then CMD="${CMD} ${LIBSSH2_LIB}/${LIBSSH2_BNDDIR}" + liblist -a "${LIBSSH2_LIB}" + fi + CMD="${CMD})" + CMD="${CMD} BNDSRVPGM(QADRTTS QGLDCLNT QGLDBRDR)" + CMD="${CMD} TEXT('curl API library')" + CMD="${CMD} TGTRLS(${TGTRLS})" + CLcommand "${CMD}" + LINK=YES +fi + + +# If needed, (re)create the dynamic binding directory. + +if action_needed "${LIBIFSNAME}/${DYNBNDDIR}.BNDDIR" +then LINK=YES +fi + +if [ "${LINK}" ] +then rm -rf "${LIBIFSNAME}/${DYNBNDDIR}.BNDDIR" + CMD="CRTBNDDIR BNDDIR(${TARGETLIB}/${DYNBNDDIR})" + CMD="${CMD} TEXT('LibCurl API dynamic binding directory')" + CLcommand "${CMD}" + CMD="ADDBNDDIRE BNDDIR(${TARGETLIB}/${DYNBNDDIR})" + CMD="${CMD} OBJ((*LIBL/${SRVPGM} *SRVPGM))" + CLcommand "${CMD}" +fi diff --git a/packages/OS400/make-src.sh b/packages/OS400/make-src.sh new file mode 100755 index 0000000..931c1f3 --- /dev/null +++ b/packages/OS400/make-src.sh @@ -0,0 +1,99 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# +# Command line interface tool compilation script for the OS/400. + +SCRIPTDIR=`dirname "${0}"` +. "${SCRIPTDIR}/initscript.sh" +cd "${TOPDIR}/src" + + +# Get source lists. +# CURL_CFILES are in the current directory. +# CURLX_CFILES are in the lib directory and need to be recompiled because +# some function names change using macros. + +get_make_vars Makefile.inc + + +# Compile the sources into modules. + +LINK= +MODULES= +INCLUDES="'${TOPDIR}/lib'" + +for SRC in ${CURLX_CFILES} +do MODULE=`db2_name "${SRC}"` + MODULE=`db2_name "X${MODULE}"` + make_module "${MODULE}" "${SRC}" +done + +for SRC in ${CURL_CFILES} +do MODULE=`db2_name "${SRC}"` + make_module "${MODULE}" "${SRC}" +done + + +# Link modules into program. + +MODULES="`echo \"${MODULES}\" | sed \"s/[^ ][^ ]*/${TARGETLIB}\/&/g\"`" +CMD="CRTPGM PGM(${TARGETLIB}/${CURLPGM})" +CMD="${CMD} ENTMOD(${TARGETLIB}/CURLMAIN)" +CMD="${CMD} MODULE(${MODULES})" +CMD="${CMD} BNDSRVPGM(${TARGETLIB}/${SRVPGM} QADRTTS)" +CMD="${CMD} TGTRLS(${TGTRLS})" +CLcommand "${CMD}" + + +# Create the IFS command. + +IFSBIN="${IFSDIR}/bin" + +if action_needed "${IFSBIN}" +then mkdir -p "${IFSBIN}" +fi + +rm -f "${IFSBIN}/curl" +ln -s "/QSYS.LIB/${TARGETLIB}.LIB/${CURLPGM}.PGM" "${IFSBIN}/curl" + + +# Create the CL interface program. + +if action_needed "${LIBIFSNAME}/CURLCL.PGM" "${SCRIPTDIR}/curlcl.c" +then CMD="CRTBNDC PGM(${TARGETLIB}/${CURLCLI})" + CMD="${CMD} SRCSTMF('${SCRIPTDIR}/curlcl.c')" + CMD="${CMD} DEFINE('CURLPGM=\"${CURLPGM}\"')" + CMD="${CMD} TGTCCSID(${TGTCCSID})" + CLcommand "${CMD}" +fi + + +# Create the CL command. + +if action_needed "${LIBIFSNAME}/${CURLCMD}.CMD" "${SCRIPTDIR}/curl.cmd" +then CMD="CRTCMD CMD(${TARGETLIB}/${CURLCMD}) PGM(${TARGETLIB}/${CURLCLI})" + CMD="${CMD} SRCSTMF('${SCRIPTDIR}/curl.cmd')" + CLcommand "${CMD}" +fi diff --git a/packages/OS400/make-tests.sh b/packages/OS400/make-tests.sh new file mode 100755 index 0000000..ed47595 --- /dev/null +++ b/packages/OS400/make-tests.sh @@ -0,0 +1,145 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# +# tests compilation script for the OS/400. +# + + +SCRIPTDIR=`dirname "${0}"` +. "${SCRIPTDIR}/initscript.sh" +cd "${TOPDIR}/tests" + + +# Build programs in a directory. + +build_all_programs() + +{ + # Compile all programs. + # The list is found in variable "noinst_PROGRAMS" + + INCLUDES="'`pwd`' '${TOPDIR}/lib' '${TOPDIR}/src'" + MODS="${1}" + SRVPGMS="${2}" + + for PGM in ${noinst_PROGRAMS} + do DB2PGM=`db2_name "${PGM}"` + PGMIFSNAME="${LIBIFSNAME}/${DB2PGM}.PGM" + + # Extract preprocessor symbol definitions from + # compilation options for the program. + + PGMCFLAGS="`eval echo \"\\${${PGM}_CFLAGS}\"`" + PGMDFNS= + + for FLAG in ${PGMCFLAGS} + do case "${FLAG}" in + -D?*) DEFINE="`echo \"${FLAG}\" | sed 's/^..//'`" + PGMDFNS="${PGMDFNS} '${DEFINE}'" + ;; + esac + done + + # Compile all C sources for the program into modules. + + PGMSOURCES="`eval echo \"\\${${PGM}_SOURCES}\"`" + LINK= + MODULES= + + for SOURCE in ${PGMSOURCES} + do case "${SOURCE}" in + *.c) # Special processing for libxxx.c files: + # their module name is determined + # by the target PROGRAM name. + + case "${SOURCE}" in + lib*.c) MODULE="${DB2PGM}" + ;; + *) MODULE=`db2_name "${SOURCE}"` + ;; + esac + + # If source is in a sibling directory, + # prefix module name with 'X'. + + case "${SOURCE}" in + ../*) MODULE=`db2_name "X${MODULE}"` + ;; + esac + + make_module "${MODULE}" "${SOURCE}" "${PGMDFNS}" + if action_needed "${PGMIFSNAME}" "${MODIFSNAME}" + then LINK=yes + fi + ;; + esac + done + + # Link program if needed. + + if [ "${LINK}" ] + then PGMLDADD="`eval echo \"\\${${PGM}_LDADD}\"`" + for ARG in ${PGMLDADD} + do case "${ARG}" in + -*) ;; # Ignore non-module. + *) MODULES="${MODULES} "`db2_name "${ARG}"` + ;; + esac + done + MODULES="`echo \"${MODULES}\" | + sed \"s/[^ ][^ ]*/${TARGETLIB}\/&/g\"`" + CMD="CRTPGM PGM(${TARGETLIB}/${DB2PGM})" + CMD="${CMD} ENTMOD(${TARGETLIB}/CURLMAIN)" + CMD="${CMD} MODULE(${MODULES} ${MODS})" + CMD="${CMD} BNDSRVPGM(${SRVPGMS} QADRTTS)" + CMD="${CMD} TGTRLS(${TGTRLS})" + CLcommand "${CMD}" + fi + done +} + + +# Build programs in the server directory. + +( + cd server + get_make_vars Makefile.inc + build_all_programs "${TARGETLIB}/OS400SYS" +) + + +# Build all programs in the libtest subdirectory. + +( + cd libtest + get_make_vars Makefile.inc + + # Special case: redefine chkhostname compilation parameters. + + chkhostname_SOURCES=chkhostname.c + chkhostname_LDADD=curl_gethostname.o + + build_all_programs "" "${TARGETLIB}/${SRVPGM}" +) diff --git a/packages/OS400/makefile.sh b/packages/OS400/makefile.sh new file mode 100755 index 0000000..3d65964 --- /dev/null +++ b/packages/OS400/makefile.sh @@ -0,0 +1,123 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# +# curl compilation script for the OS/400. +# +# +# This is a shell script since make is not a standard component of OS/400. + +SCRIPTDIR=`dirname "${0}"` +. "${SCRIPTDIR}/initscript.sh" +cd "${TOPDIR}" + + +# Create the OS/400 library if it does not exist. + +if action_needed "${LIBIFSNAME}" +then CMD="CRTLIB LIB(${TARGETLIB}) TEXT('curl: multiprotocol support API')" + CLcommand "${CMD}" +fi + + +# Create the DOCS source file if it does not exist. + +if action_needed "${LIBIFSNAME}/DOCS.FILE" +then CMD="CRTSRCPF FILE(${TARGETLIB}/DOCS) RCDLEN(240)" + CMD="${CMD} CCSID(${TGTCCSID}) TEXT('Documentation texts')" + CLcommand "${CMD}" +fi + + +# Copy some documentation files if needed. + +for TEXT in "${TOPDIR}/COPYING" "${SCRIPTDIR}/README.OS400" \ + "${TOPDIR}/CHANGES" "${TOPDIR}/docs/THANKS" "${TOPDIR}/docs/FAQ" \ + "${TOPDIR}/docs/FEATURES" "${TOPDIR}/docs/SSLCERTS.md" \ + "${TOPDIR}/docs/RESOURCES" "${TOPDIR}/docs/VERSIONS.md" \ + "${TOPDIR}/docs/HISTORY.md" +do MEMBER="`basename \"${TEXT}\" .OS400`" + MEMBER="`basename \"${MEMBER}\" .md`" + MEMBER="${LIBIFSNAME}/DOCS.FILE/`db2_name \"${MEMBER}\"`.MBR" + + [ -e "${TEXT}" ] || continue + + if action_needed "${MEMBER}" "${TEXT}" + then CMD="CPY OBJ('${TEXT}') TOOBJ('${MEMBER}') TOCCSID(${TGTCCSID})" + CMD="${CMD} DTAFMT(*TEXT) REPLACE(*YES)" + CLcommand "${CMD}" + fi +done + + +# Create the RPGXAMPLES source file if it does not exist. + +if action_needed "${LIBIFSNAME}/RPGXAMPLES.FILE" +then CMD="CRTSRCPF FILE(${TARGETLIB}/RPGXAMPLES) RCDLEN(240)" + CMD="${CMD} CCSID(${TGTCCSID}) TEXT('ILE/RPG examples')" + CLcommand "${CMD}" +fi + + +# Copy RPG examples if needed. + +for EXAMPLE in "${SCRIPTDIR}/rpg-examples"/* +do MEMBER="`basename \"${EXAMPLE}\"`" + IFSMEMBER="${LIBIFSNAME}/RPGXAMPLES.FILE/`db2_name \"${MEMBER}\"`.MBR" + + [ -e "${EXAMPLE}" ] || continue + + if action_needed "${IFSMEMBER}" "${EXAMPLE}" + then CMD="CPY OBJ('${EXAMPLE}') TOOBJ('${IFSMEMBER}')" + CMD="${CMD} TOCCSID(${TGTCCSID}) DTAFMT(*TEXT) REPLACE(*YES)" + CLcommand "${CMD}" + MBRTEXT=`sed -e '1!d;/^ \*/!d;s/^ *\* *//' \ + -e 's/ *$//;s/'"'"'/&&/g' < "${EXAMPLE}"` + CMD="CHGPFM FILE(${TARGETLIB}/RPGXAMPLES) MBR(${MEMBER})" + CMD="${CMD} SRCTYPE(RPGLE) TEXT('${MBRTEXT}')" + CLcommand "${CMD}" + fi +done + + +# Compile the QADRTMAIN2 replacement module. + +if action_needed "${LIBIFSNAME}/CURLMAIN.MODULE" "${SCRIPTDIR}/curlmain.c" +then CMD="CRTCMOD MODULE(${TARGETLIB}/CURLMAIN)" + CMD="${CMD} SRCSTMF('${SCRIPTDIR}/curlmain.c')" + CMD="${CMD} SYSIFCOPT(*IFS64IO) LOCALETYPE(*LOCALE) FLAG(10)" + CMD="${CMD} TGTCCSID(${TGTCCSID}) TGTRLS(${TGTRLS})" + CMD="${CMD} OUTPUT(${OUTPUT})" + CMD="${CMD} OPTIMIZE(${OPTIMIZE})" + CMD="${CMD} DBGVIEW(${DEBUG})" + CLcommand "${CMD}" +fi + + +# Build in each directory. + +# for SUBDIR in include lib src tests +for SUBDIR in include lib src +do "${SCRIPTDIR}/make-${SUBDIR}.sh" +done diff --git a/packages/OS400/os400sys.c b/packages/OS400/os400sys.c new file mode 100644 index 0000000..510c1c4 --- /dev/null +++ b/packages/OS400/os400sys.c @@ -0,0 +1,1040 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ + +/* OS/400 additional support. */ + +#include +#include "config-os400.h" /* Not curl_setup.h: we only need some defines. */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBZ +#include +#endif + +#ifdef HAVE_GSSAPI +#include +#endif + +#ifndef CURL_DISABLE_LDAP +#include +#endif + +#include +#include + +#include "os400sys.h" + +/** +*** QADRT OS/400 ASCII runtime defines only the most used procedures, but a +*** lot of them are not supported. This module implements ASCII wrappers for +*** those that are used by libcurl, but not defined by QADRT. +**/ + +#pragma convert(0) /* Restore EBCDIC. */ + +#define MIN_BYTE_GAIN 1024 /* Minimum gain when shortening a buffer. */ + +struct buffer_t { + unsigned long size; /* Buffer size. */ + char *buf; /* Buffer address. */ +}; + + +static char *buffer_undef(localkey_t key, long size); +static char *buffer_threaded(localkey_t key, long size); +static char *buffer_unthreaded(localkey_t key, long size); + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t thdkey; +static struct buffer_t *locbufs; + +char *(*Curl_thread_buffer)(localkey_t key, long size) = buffer_undef; + +static void thdbufdestroy(void *private) +{ + if(private) { + struct buffer_t *p = (struct buffer_t *) private; + localkey_t i; + + for(i = (localkey_t) 0; i < LK_LAST; i++) { + free(p->buf); + p++; + } + + free(private); + } +} + + +static void +terminate(void) +{ + if(Curl_thread_buffer == buffer_threaded) { + locbufs = pthread_getspecific(thdkey); + pthread_setspecific(thdkey, (void *) NULL); + pthread_key_delete(thdkey); + } + + if(Curl_thread_buffer != buffer_undef) { + thdbufdestroy((void *) locbufs); + locbufs = (struct buffer_t *) NULL; + } + + Curl_thread_buffer = buffer_undef; +} + + +static char * +get_buffer(struct buffer_t *buf, long size) +{ + char *cp; + + /* If `size' >= 0, make sure buffer at `buf' is at least `size'-byte long. + Return the buffer address. */ + + if(size < 0) + return buf->buf; + + if(!buf->buf) { + buf->buf = malloc(size); + if(buf->buf) + buf->size = size; + + return buf->buf; + } + + if((unsigned long) size <= buf->size) { + /* Shorten the buffer only if it frees a significant byte count. This + avoids some realloc() overhead. */ + + if(buf->size - size < MIN_BYTE_GAIN) + return buf->buf; + } + + /* Resize the buffer. */ + + cp = realloc(buf->buf, size); + if(cp) { + buf->buf = cp; + buf->size = size; + } + else if(size <= buf->size) + cp = buf->buf; + + return cp; +} + + +static char * +buffer_unthreaded(localkey_t key, long size) +{ + return get_buffer(locbufs + key, size); +} + + +static char * +buffer_threaded(localkey_t key, long size) +{ + struct buffer_t *bufs; + + /* Get the buffer for the given local key in the current thread, and + make sure it is at least `size'-byte long. Set `size' to < 0 to get + its address only. */ + + bufs = (struct buffer_t *) pthread_getspecific(thdkey); + + if(!bufs) { + if(size < 0) + return (char *) NULL; /* No buffer yet. */ + + /* Allocate buffer descriptors for the current thread. */ + + bufs = calloc((size_t) LK_LAST, sizeof(*bufs)); + if(!bufs) + return (char *) NULL; + + if(pthread_setspecific(thdkey, (void *) bufs)) { + free(bufs); + return (char *) NULL; + } + } + + return get_buffer(bufs + key, size); +} + + +static char * +buffer_undef(localkey_t key, long size) +{ + /* Define the buffer system, get the buffer for the given local key in + the current thread, and make sure it is at least `size'-byte long. + Set `size' to < 0 to get its address only. */ + + pthread_mutex_lock(&mutex); + + /* Determine if we can use pthread-specific data. */ + + if(Curl_thread_buffer == buffer_undef) { /* If unchanged during lock. */ + if(!pthread_key_create(&thdkey, thdbufdestroy)) + Curl_thread_buffer = buffer_threaded; + else { + locbufs = calloc((size_t) LK_LAST, sizeof(*locbufs)); + if(!locbufs) { + pthread_mutex_unlock(&mutex); + return (char *) NULL; + } + else + Curl_thread_buffer = buffer_unthreaded; + } + + atexit(terminate); + } + + pthread_mutex_unlock(&mutex); + return Curl_thread_buffer(key, size); +} + + +static char * +set_thread_string(localkey_t key, const char *s) +{ + int i; + char *cp; + + if(!s) + return (char *) NULL; + + i = strlen(s) + 1; + cp = Curl_thread_buffer(key, MAX_CONV_EXPANSION * i + 1); + + if(cp) { + i = QadrtConvertE2A(cp, s, MAX_CONV_EXPANSION * i, i); + cp[i] = '\0'; + } + + return cp; +} + + +int +Curl_getnameinfo_a(const struct sockaddr *sa, socklen_t salen, + char *nodename, socklen_t nodenamelen, + char *servname, socklen_t servnamelen, + int flags) +{ + char *enodename = NULL; + char *eservname = NULL; + int status; + + if(nodename && nodenamelen) { + enodename = malloc(nodenamelen); + if(!enodename) + return EAI_MEMORY; + } + + if(servname && servnamelen) { + eservname = malloc(servnamelen); + if(!eservname) { + free(enodename); + return EAI_MEMORY; + } + } + + status = getnameinfo(sa, salen, enodename, nodenamelen, + eservname, servnamelen, flags); + + if(!status) { + int i; + if(enodename) { + i = QadrtConvertE2A(nodename, enodename, + nodenamelen - 1, strlen(enodename)); + nodename[i] = '\0'; + } + + if(eservname) { + i = QadrtConvertE2A(servname, eservname, + servnamelen - 1, strlen(eservname)); + servname[i] = '\0'; + } + } + + free(enodename); + free(eservname); + return status; +} + +int +Curl_getaddrinfo_a(const char *nodename, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res) +{ + char *enodename; + char *eservname; + int status; + int i; + + enodename = (char *) NULL; + eservname = (char *) NULL; + + if(nodename) { + i = strlen(nodename); + + enodename = malloc(i + 1); + if(!enodename) + return EAI_MEMORY; + + i = QadrtConvertA2E(enodename, nodename, i, i); + enodename[i] = '\0'; + } + + if(servname) { + i = strlen(servname); + + eservname = malloc(i + 1); + if(!eservname) { + free(enodename); + return EAI_MEMORY; + } + + QadrtConvertA2E(eservname, servname, i, i); + eservname[i] = '\0'; + } + + status = getaddrinfo(enodename, eservname, hints, res); + free(enodename); + free(eservname); + return status; +} + +#ifdef HAVE_GSSAPI + +/* ASCII wrappers for the GSSAPI procedures. */ + +static int +Curl_gss_convert_in_place(OM_uint32 *minor_status, gss_buffer_t buf) +{ + unsigned int i = buf->length; + + /* Convert `buf' in place, from EBCDIC to ASCII. + If error, release the buffer and return -1. Else return 0. */ + + if(i) { + char *t = malloc(i); + if(!t) { + gss_release_buffer(minor_status, buf); + + if(minor_status) + *minor_status = ENOMEM; + + return -1; + } + + QadrtConvertE2A(t, buf->value, i, i); + memcpy(buf->value, t, i); + free(t); + } + + return 0; +} + + +OM_uint32 +Curl_gss_import_name_a(OM_uint32 *minor_status, gss_buffer_t in_name, + gss_OID in_name_type, gss_name_t *out_name) +{ + OM_uint32 rc; + unsigned int i; + gss_buffer_desc in; + + if(!in_name || !in_name->value || !in_name->length) + return gss_import_name(minor_status, in_name, in_name_type, out_name); + + memcpy((char *) &in, (char *) in_name, sizeof(in)); + i = in.length; + + in.value = malloc(i + 1); + if(!in.value) { + if(minor_status) + *minor_status = ENOMEM; + + return GSS_S_FAILURE; + } + + QadrtConvertA2E(in.value, in_name->value, i, i); + ((char *) in.value)[i] = '\0'; + rc = gss_import_name(minor_status, &in, in_name_type, out_name); + free(in.value); + return rc; +} + +OM_uint32 +Curl_gss_display_status_a(OM_uint32 *minor_status, OM_uint32 status_value, + int status_type, gss_OID mech_type, + gss_msg_ctx_t *message_context, + gss_buffer_t status_string) +{ + int rc; + + rc = gss_display_status(minor_status, status_value, status_type, + mech_type, message_context, status_string); + + if(rc != GSS_S_COMPLETE || !status_string || + !status_string->length || !status_string->value) + return rc; + + /* No way to allocate a buffer here, because it will be released by + gss_release_buffer(). The solution is to overwrite the EBCDIC buffer + with ASCII to return it. */ + + if(Curl_gss_convert_in_place(minor_status, status_string)) + return GSS_S_FAILURE; + + return rc; +} + +OM_uint32 +Curl_gss_init_sec_context_a(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_ctx_id_t *context_handle, + gss_name_t target_name, gss_OID mech_type, + gss_flags_t req_flags, OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, gss_flags_t *ret_flags, + OM_uint32 *time_rec) +{ + int rc; + gss_buffer_desc in; + gss_buffer_t inp; + + in.value = NULL; + inp = input_token; + + if(inp) { + if(inp->length && inp->value) { + unsigned int i = inp->length; + + in.value = malloc(i + 1); + if(!in.value) { + if(minor_status) + *minor_status = ENOMEM; + + return GSS_S_FAILURE; + } + + QadrtConvertA2E(in.value, input_token->value, i, i); + ((char *) in.value)[i] = '\0'; + in.length = i; + inp = ∈ + } + } + + rc = gss_init_sec_context(minor_status, cred_handle, context_handle, + target_name, mech_type, req_flags, time_req, + input_chan_bindings, inp, actual_mech_type, + output_token, ret_flags, time_rec); + free(in.value); + + if(rc != GSS_S_COMPLETE || !output_token || + !output_token->length || !output_token->value) + return rc; + + /* No way to allocate a buffer here, because it will be released by + gss_release_buffer(). The solution is to overwrite the EBCDIC buffer + with ASCII to return it. */ + + if(Curl_gss_convert_in_place(minor_status, output_token)) + return GSS_S_FAILURE; + + return rc; +} + + +OM_uint32 +Curl_gss_delete_sec_context_a(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + OM_uint32 rc; + + rc = gss_delete_sec_context(minor_status, context_handle, output_token); + + if(rc != GSS_S_COMPLETE || !output_token || + !output_token->length || !output_token->value) + return rc; + + /* No way to allocate a buffer here, because it will be released by + gss_release_buffer(). The solution is to overwrite the EBCDIC buffer + with ASCII to return it. */ + + if(Curl_gss_convert_in_place(minor_status, output_token)) + return GSS_S_FAILURE; + + return rc; +} + +#endif /* HAVE_GSSAPI */ + +#ifndef CURL_DISABLE_LDAP + +/* ASCII wrappers for the LDAP procedures. */ + +void * +Curl_ldap_init_a(char *host, int port) +{ + size_t i; + char *ehost; + void *result; + + if(!host) + return (void *) ldap_init(host, port); + + i = strlen(host); + + ehost = malloc(i + 1); + if(!ehost) + return (void *) NULL; + + QadrtConvertA2E(ehost, host, i, i); + ehost[i] = '\0'; + result = (void *) ldap_init(ehost, port); + free(ehost); + return result; +} + +int +Curl_ldap_simple_bind_s_a(void *ld, char *dn, char *passwd) +{ + int i; + char *edn; + char *epasswd; + + edn = (char *) NULL; + epasswd = (char *) NULL; + + if(dn) { + i = strlen(dn); + + edn = malloc(i + 1); + if(!edn) + return LDAP_NO_MEMORY; + + QadrtConvertA2E(edn, dn, i, i); + edn[i] = '\0'; + } + + if(passwd) { + i = strlen(passwd); + + epasswd = malloc(i + 1); + if(!epasswd) { + free(edn); + return LDAP_NO_MEMORY; + } + + QadrtConvertA2E(epasswd, passwd, i, i); + epasswd[i] = '\0'; + } + + i = ldap_simple_bind_s(ld, edn, epasswd); + free(epasswd); + free(edn); + return i; +} + +int +Curl_ldap_search_s_a(void *ld, char *base, int scope, char *filter, + char **attrs, int attrsonly, LDAPMessage **res) +{ + int i; + int j; + char *ebase; + char *efilter; + char **eattrs; + int status; + + ebase = (char *) NULL; + efilter = (char *) NULL; + eattrs = (char **) NULL; + status = LDAP_SUCCESS; + + if(base) { + i = strlen(base); + + ebase = malloc(i + 1); + if(!ebase) + status = LDAP_NO_MEMORY; + else { + QadrtConvertA2E(ebase, base, i, i); + ebase[i] = '\0'; + } + } + + if(filter && status == LDAP_SUCCESS) { + i = strlen(filter); + + efilter = malloc(i + 1); + if(!efilter) + status = LDAP_NO_MEMORY; + else { + QadrtConvertA2E(efilter, filter, i, i); + efilter[i] = '\0'; + } + } + + if(attrs && status == LDAP_SUCCESS) { + for(i = 0; attrs[i++];) + ; + + eattrs = calloc(i, sizeof(*eattrs)); + if(!eattrs) + status = LDAP_NO_MEMORY; + else { + for(j = 0; attrs[j]; j++) { + i = strlen(attrs[j]); + + eattrs[j] = malloc(i + 1); + if(!eattrs[j]) { + status = LDAP_NO_MEMORY; + break; + } + + QadrtConvertA2E(eattrs[j], attrs[j], i, i); + eattrs[j][i] = '\0'; + } + } + } + + if(status == LDAP_SUCCESS) + status = ldap_search_s(ld, ebase? ebase: "", scope, + efilter? efilter: "(objectclass=*)", + eattrs, attrsonly, res); + + if(eattrs) { + for(j = 0; eattrs[j]; j++) + free(eattrs[j]); + + free(eattrs); + } + + free(efilter); + free(ebase); + return status; +} + + +struct berval ** +Curl_ldap_get_values_len_a(void *ld, LDAPMessage *entry, const char *attr) +{ + char *cp; + struct berval **result; + + cp = (char *) NULL; + + if(attr) { + int i = strlen(attr); + + cp = malloc(i + 1); + if(!cp) { + ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL, + ldap_err2string(LDAP_NO_MEMORY)); + return (struct berval **) NULL; + } + + QadrtConvertA2E(cp, attr, i, i); + cp[i] = '\0'; + } + + result = ldap_get_values_len(ld, entry, cp); + free(cp); + + /* Result data are binary in nature, so they haven't been + converted to EBCDIC. Therefore do not convert. */ + + return result; +} + +char * +Curl_ldap_err2string_a(int error) +{ + return set_thread_string(LK_LDAP_ERROR, ldap_err2string(error)); +} + +char * +Curl_ldap_get_dn_a(void *ld, LDAPMessage *entry) +{ + int i; + char *cp; + char *cp2; + + cp = ldap_get_dn(ld, entry); + + if(!cp) + return cp; + + i = strlen(cp); + + cp2 = malloc(i + 1); + if(!cp2) + return cp2; + + QadrtConvertE2A(cp2, cp, i, i); + cp2[i] = '\0'; + + /* No way to allocate a buffer here, because it will be released by + ldap_memfree() and ldap_memalloc() does not exist. The solution is to + overwrite the EBCDIC buffer with ASCII to return it. */ + + strcpy(cp, cp2); + free(cp2); + return cp; +} + +char * +Curl_ldap_first_attribute_a(void *ld, + LDAPMessage *entry, BerElement **berptr) +{ + int i; + char *cp; + char *cp2; + + cp = ldap_first_attribute(ld, entry, berptr); + + if(!cp) + return cp; + + i = strlen(cp); + + cp2 = malloc(i + 1); + if(!cp2) + return cp2; + + QadrtConvertE2A(cp2, cp, i, i); + cp2[i] = '\0'; + + /* No way to allocate a buffer here, because it will be released by + ldap_memfree() and ldap_memalloc() does not exist. The solution is to + overwrite the EBCDIC buffer with ASCII to return it. */ + + strcpy(cp, cp2); + free(cp2); + return cp; +} + +char * +Curl_ldap_next_attribute_a(void *ld, + LDAPMessage *entry, BerElement *berptr) +{ + int i; + char *cp; + char *cp2; + + cp = ldap_next_attribute(ld, entry, berptr); + + if(!cp) + return cp; + + i = strlen(cp); + + cp2 = malloc(i + 1); + if(!cp2) + return cp2; + + QadrtConvertE2A(cp2, cp, i, i); + cp2[i] = '\0'; + + /* No way to allocate a buffer here, because it will be released by + ldap_memfree() and ldap_memalloc() does not exist. The solution is to + overwrite the EBCDIC buffer with ASCII to return it. */ + + strcpy(cp, cp2); + free(cp2); + return cp; +} + +#endif /* CURL_DISABLE_LDAP */ + +static int +sockaddr2ebcdic(struct sockaddr_storage *dstaddr, + const struct sockaddr *srcaddr, int srclen) +{ + const struct sockaddr_un *srcu; + struct sockaddr_un *dstu; + unsigned int i; + unsigned int dstsize; + + /* Convert a socket address to job CCSID, if needed. */ + + if(!srcaddr || srclen < offsetof(struct sockaddr, sa_family) + + sizeof(srcaddr->sa_family) || srclen > sizeof(*dstaddr)) { + errno = EINVAL; + return -1; + } + + memcpy((char *) dstaddr, (char *) srcaddr, srclen); + + switch(srcaddr->sa_family) { + + case AF_UNIX: + srcu = (const struct sockaddr_un *) srcaddr; + dstu = (struct sockaddr_un *) dstaddr; + dstsize = sizeof(*dstaddr) - offsetof(struct sockaddr_un, sun_path); + srclen -= offsetof(struct sockaddr_un, sun_path); + i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen); + dstu->sun_path[i] = '\0'; + srclen = i + offsetof(struct sockaddr_un, sun_path); + } + + return srclen; +} + + +static int +sockaddr2ascii(struct sockaddr *dstaddr, int dstlen, + const struct sockaddr_storage *srcaddr, int srclen) +{ + const struct sockaddr_un *srcu; + struct sockaddr_un *dstu; + unsigned int dstsize; + + /* Convert a socket address to ASCII, if needed. */ + + if(!srclen) + return 0; + if(srclen > dstlen) + srclen = dstlen; + if(!srcaddr || srclen < 0) { + errno = EINVAL; + return -1; + } + + memcpy((char *) dstaddr, (char *) srcaddr, srclen); + + if(srclen >= offsetof(struct sockaddr_storage, ss_family) + + sizeof(srcaddr->ss_family)) { + switch(srcaddr->ss_family) { + + case AF_UNIX: + srcu = (const struct sockaddr_un *) srcaddr; + dstu = (struct sockaddr_un *) dstaddr; + dstsize = dstlen - offsetof(struct sockaddr_un, sun_path); + srclen -= offsetof(struct sockaddr_un, sun_path); + if(dstsize > 0 && srclen > 0) { + srclen = QadrtConvertE2A(dstu->sun_path, srcu->sun_path, + dstsize - 1, srclen); + dstu->sun_path[srclen] = '\0'; + } + srclen += offsetof(struct sockaddr_un, sun_path); + } + } + + return srclen; +} + +int +Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen) +{ + int i; + struct sockaddr_storage laddr; + + i = sockaddr2ebcdic(&laddr, destaddr, addrlen); + + if(i < 0) + return -1; + + return connect(sd, (struct sockaddr *) &laddr, i); +} + +int +Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen) +{ + int i; + struct sockaddr_storage laddr; + + i = sockaddr2ebcdic(&laddr, localaddr, addrlen); + + if(i < 0) + return -1; + + return bind(sd, (struct sockaddr *) &laddr, i); +} + +int +Curl_os400_sendto(int sd, char *buffer, int buflen, int flags, + const struct sockaddr *dstaddr, int addrlen) +{ + int i; + struct sockaddr_storage laddr; + + i = sockaddr2ebcdic(&laddr, dstaddr, addrlen); + + if(i < 0) + return -1; + + return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i); +} + +int +Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags, + struct sockaddr *fromaddr, int *addrlen) +{ + int rcvlen; + struct sockaddr_storage laddr; + int laddrlen = sizeof(laddr); + + if(!fromaddr || !addrlen || *addrlen <= 0) + return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen); + + laddr.ss_family = AF_UNSPEC; /* To detect if unused. */ + rcvlen = recvfrom(sd, buffer, buflen, flags, + (struct sockaddr *) &laddr, &laddrlen); + + if(rcvlen < 0) + return rcvlen; + + if(laddr.ss_family == AF_UNSPEC) + laddrlen = 0; + else { + laddrlen = sockaddr2ascii(fromaddr, *addrlen, &laddr, laddrlen); + if(laddrlen < 0) + return laddrlen; + } + *addrlen = laddrlen; + return rcvlen; +} + +int +Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen) +{ + struct sockaddr_storage laddr; + int laddrlen = sizeof(laddr); + int retcode = getpeername(sd, (struct sockaddr *) &laddr, &laddrlen); + + if(!retcode) { + laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen); + if(laddrlen < 0) + return laddrlen; + *addrlen = laddrlen; + } + + return retcode; +} + +int +Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen) +{ + struct sockaddr_storage laddr; + int laddrlen = sizeof(laddr); + int retcode = getsockname(sd, (struct sockaddr *) &laddr, &laddrlen); + + if(!retcode) { + laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen); + if(laddrlen < 0) + return laddrlen; + *addrlen = laddrlen; + } + + return retcode; +} + + +#ifdef HAVE_LIBZ +const char * +Curl_os400_zlibVersion(void) +{ + return set_thread_string(LK_ZLIB_VERSION, zlibVersion()); +} + + +int +Curl_os400_inflateInit_(z_streamp strm, const char *version, int stream_size) +{ + z_const char *msgb4 = strm->msg; + int ret; + + ret = inflateInit(strm); + + if(strm->msg != msgb4) + strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); + + return ret; +} + +int +Curl_os400_inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) +{ + z_const char *msgb4 = strm->msg; + int ret; + + ret = inflateInit2(strm, windowBits); + + if(strm->msg != msgb4) + strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); + + return ret; +} + +int +Curl_os400_inflate(z_streamp strm, int flush) +{ + z_const char *msgb4 = strm->msg; + int ret; + + ret = inflate(strm, flush); + + if(strm->msg != msgb4) + strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); + + return ret; +} + +int +Curl_os400_inflateEnd(z_streamp strm) +{ + z_const char *msgb4 = strm->msg; + int ret; + + ret = inflateEnd(strm); + + if(strm->msg != msgb4) + strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); + + return ret; +} + +#endif diff --git a/packages/OS400/os400sys.h b/packages/OS400/os400sys.h new file mode 100644 index 0000000..d5ff412 --- /dev/null +++ b/packages/OS400/os400sys.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ + +/* OS/400 additional definitions. */ + +#ifndef __OS400_SYS_ +#define __OS400_SYS_ + + +/* Per-thread item identifiers. */ + +typedef enum { + LK_GSK_ERROR, + LK_LDAP_ERROR, + LK_CURL_VERSION, + LK_VERSION_INFO, + LK_VERSION_INFO_DATA, + LK_EASY_STRERROR, + LK_SHARE_STRERROR, + LK_MULTI_STRERROR, + LK_URL_STRERROR, + LK_ZLIB_VERSION, + LK_ZLIB_MSG, + LK_LAST +} localkey_t; + + +extern char * (* Curl_thread_buffer)(localkey_t key, long size); + + +/* Maximum string expansion factor due to character code conversion. */ + +#define MAX_CONV_EXPANSION 4 /* Can deal with UTF-8. */ + +#endif diff --git a/packages/OS400/rpg-examples/HEADERAPI b/packages/OS400/rpg-examples/HEADERAPI new file mode 100644 index 0000000..2c2407e --- /dev/null +++ b/packages/OS400/rpg-examples/HEADERAPI @@ -0,0 +1,146 @@ + * Curl header API: extract headers post transfer + * + h DFTACTGRP(*NO) ACTGRP(*NEW) + h OPTION(*NOSHOWCPY) + h BNDDIR('CURL') + * + ************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ************************************************************************** + * + /include H,CURL.INC + * + * Extract headers post transfer with the header API. + * + d pi + d url 120 + * + d urllen s 10u 0 URL length + * + ************************************************************************** + + urllen = trimmed_length(url: %len(url)); + + // Do the curl stuff. + + curl_global_init(CURL_GLOBAL_ALL); + main(); + curl_global_cleanup(); + *inlr = *on; // Exit + * + ************************************************************************** + * Main procedure: do the curl job. + ************************************************************************** + * + p main b + d main pi + * + d h s * Easy handle + d result s like(CURLcode) Curl return code + d inz(CURLE_OUT_OF_MEMORY) + d header ds likeds(curl_header) based(hp) + d strp1 s * Work string pointer + d strp2 s * Work string pointer + d inout s 52 For error display + + // Create and fill curl handle. + + h = curl_easy_init(); + if h <> *NULL; + curl_easy_setopt_ccsid(h: CURLOPT_URL: %subst(url: 1: urllen): 0); + curl_easy_setopt(h: CURLOPT_FOLLOWLOCATION: 1); + curl_easy_setopt(h: CURLOPT_WRITEFUNCTION: %paddr(in_data_cb)); // Ignore input data + + // Perform the request. + + result = curl_easy_perform(h); + endif; + + // Check for error and report if some. + + if result <> CURLE_OK; + inout = %str(curl_easy_strerror_ccsid(result: 0)); + dsply '' '*EXT' inout; + else; + if curl_easy_header_ccsid(h: 'Content-Type': 0: CURLH_HEADER: -1: + hp: 0) = CURLHE_OK; + strp2 = curl_to_ccsid(header.value: 0); + inout = 'Content-Type: ' + %str(strp2); + dsply inout; + curl_free(strp2); + endif; + dsply ' All server headers:'; + hp = *NULL; + dow *on; + hp = curl_easy_nextheader(h: CURLH_HEADER: -1: hp); + if hp = *NULL; + leave; + endif; + strp1 = curl_to_ccsid(header.name: 0); + strp2 = curl_to_ccsid(header.value: 0); + inout = %str(strp1) + ': ' + %str(strp2) + + ' (' + %char(header.amount) + ')'; + curl_free(strp2); + curl_free(strp1); + dsply inout; + enddo; + inout = 'Done'; + dsply '' '*EXT' inout; + curl_easy_cleanup(h); // Release handle + endif; + p main e + * + ************************************************************************** + * Dummy data input callback procedure. + ************************************************************************** + * + p in_data_cb b + d in_data_cb pi 10u 0 + d ptr * value Input data pointer + d size 10u 0 value Data element size + d nmemb 10u 0 value Data element count + d userdata * value User data pointer + * + return size * nmemb; + p in_data_cb e + * + ************************************************************************** + * Get the length of right-trimmed string + ************************************************************************** + * + p trimmed_length b + d trimmed_length pi 10u 0 + d string 999999 const options(*varsize) + d length 10u 0 value + * + d len s 10u 0 + * + len = %scan(X'00': string: 1: length); // Limit to zero-terminated string + if len = 0; + len = length + 1; + endif; + if len <= 1; + return 0; + endif; + return %checkr(' ': string: len - 1); // Trim right + p trimmed_length e diff --git a/packages/OS400/rpg-examples/HTTPPOST b/packages/OS400/rpg-examples/HTTPPOST new file mode 100644 index 0000000..21202eb --- /dev/null +++ b/packages/OS400/rpg-examples/HTTPPOST @@ -0,0 +1,129 @@ + * Curl MIME post data and display response + * + h DFTACTGRP(*NO) ACTGRP(*NEW) + h OPTION(*NOSHOWCPY) + h BNDDIR('CURL') + * + ************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ************************************************************************** + * + /include H,CURL.INC + * + * Example to HTTP POST data using the MIME API. Displays the response. + * + d pi + d userinput 120 User data to post + * + d url c 'http://httpbin.org/anything' + * + * + d inputlen s 10u 0 User input length + ************************************************************************** + + inputlen = trimmed_length(userinput: %len(userinput)); + + // Do the curl stuff. + + curl_global_init(CURL_GLOBAL_ALL); + main(); + curl_global_cleanup(); + *inlr = *on; // Exit + * + ************************************************************************** + * Main procedure: do the curl job. + ************************************************************************** + * + p main b + d main pi + * + d h s * Easy handle + d result s like(CURLcode) Curl return code + d inz(CURLE_OUT_OF_MEMORY) + d errmsgp s * Error string pointer + d response s 52 For error display + d mime s * MIME handle + d mimepart s * MIME part handle + d parthdrs s * inz(*NULL) Part headers + + // Create and fill curl handle. + + h = curl_easy_init(); + if h <> *NULL; + curl_easy_setopt_ccsid(h: CURLOPT_URL: url: 0); + curl_easy_setopt(h: CURLOPT_FOLLOWLOCATION: 1); + mime = curl_mime_init(h); + mimepart = curl_mime_addpart(mime); + curl_mime_name_ccsid(mimepart: 'autofield': 0); + curl_mime_data_ccsid(mimepart: 'program-generated value': + CURL_ZERO_TERMINATED: 0); + mimepart = curl_mime_addpart(mime); + curl_mime_name_ccsid(mimepart: 'userfield': 0); + curl_mime_data_ccsid(mimepart: %subst(userinput: 1: inputlen): + CURL_ZERO_TERMINATED: 0); + mimepart = curl_mime_addpart(mime); + curl_mime_name_ccsid(mimepart: 'ebcdicfield': 0); + curl_mime_data(mimepart: %subst(userinput: 1: inputlen): inputlen); + curl_mime_encoder_ccsid(mimepart: 'base64': 0); + // Avoid server to convert base64 to text. + parthdrs = curl_slist_append_ccsid(parthdrs: + 'Content-Transfer-Encoding: bit': 0); + curl_mime_headers(mimepart: parthdrs: 1); + curl_easy_setopt(h: CURLOPT_MIMEPOST: mime); + + // Perform the request. + + result = curl_easy_perform(h); + curl_mime_free(mime); + curl_easy_cleanup(h); // Release handle + endif; + + // Check for error and report if some. + + if result <> CURLE_OK; + errmsgp = curl_easy_strerror_ccsid(result: 0); + response = %str(errmsgp); + dsply '' '*EXT' response; + endif; + p main e + * + ************************************************************************** + * Get the length of right-trimmed string + ************************************************************************** + * + p trimmed_length b + d trimmed_length pi 10u 0 + d string 999999 const options(*varsize) + d length 10u 0 value + * + d len s 10u 0 + * + len = %scan(X'00': string: 1: length); // Limit to zero-terminated string + if len = 0; + len = length + 1; + endif; + if len <= 1; + return 0; + endif; + return %checkr(' ': string: len - 1); // Trim right + p trimmed_length e diff --git a/packages/OS400/rpg-examples/INMEMORY b/packages/OS400/rpg-examples/INMEMORY new file mode 100644 index 0000000..e6f43ab --- /dev/null +++ b/packages/OS400/rpg-examples/INMEMORY @@ -0,0 +1,159 @@ + * Curl get in memory and count HTML tags + * + h DFTACTGRP(*NO) ACTGRP(*NEW) + h OPTION(*NOSHOWCPY) + h BNDDIR('CURL') + * + ************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ************************************************************************** + * + /include H,CURL.INC + * + * Example to request the URL given as command line parameter and count + * HTML tags in its response. + * + d pi + d url 120 + * + d countdata ds qualified based(###dummyptr) User data type + d tagcount 10u 0 Tag counter + d tagopen n Possible opening tag + * + d urllen s 10u 0 URL length + * + ************************************************************************** + + urllen = trimmed_length(url: %len(url)); + + // Do the curl stuff. + + curl_global_init(CURL_GLOBAL_ALL); + main(); + curl_global_cleanup(); + *inlr = *on; // Exit + * + ************************************************************************** + * Main procedure: do the curl job. + ************************************************************************** + * + p main b + d main pi + * + d h s * Easy handle + d result s like(CURLcode) Curl return code + d inz(CURLE_OUT_OF_MEMORY) + d errmsgp s * Error string pointer + d response s 52 For error display + d counter ds likeds(countdata) HTML tag counter + + counter.tagcount = 0; + counter.tagopen = *off; + + // Create and fill curl handle. + + h = curl_easy_init(); + if h <> *NULL; + curl_easy_setopt_ccsid(h: CURLOPT_URL: %subst(url: 1: urllen): 0); + curl_easy_setopt(h: CURLOPT_FOLLOWLOCATION: 1); + curl_easy_setopt(h: CURLOPT_WRITEFUNCTION: %paddr(in_data_cb)); + curl_easy_setopt(h: CURLOPT_WRITEDATA: %addr(counter)); + + // Perform the request. + + result = curl_easy_perform(h); + curl_easy_cleanup(h); // Release handle + endif; + + // Check for error and report if some. + + if result <> CURLE_OK; + errmsgp = curl_easy_strerror_ccsid(result: 0); + response = %str(errmsgp); + dsply '' '*EXT' response; + else; + // Display the tag count. + + response = 'Tag count: ' + %char(counter.tagcount); + dsply '' '*EXT' response; + endif; + p main e + * + ************************************************************************** + * Data input callback procedure. + ************************************************************************** + * + p in_data_cb b + d in_data_cb pi 10u 0 + d ptr * value Input data pointer + d size 10u 0 value Data element size + d nmemb 10u 0 value Data element count + d userdata * value User data pointer + * + d counter ds likeds(countdata) based(userdata) HTML tag counter + d ebcdata s * EBCDIC data pointer + d chars s 1 based(ebcdata) dim(1000000) + d i s 10u 0 Character position + * + size = size * nmemb; // The size in bytes. + ebcdata = curl_to_ccsid(%str(ptr: size): 0); // Convert to EBCDIC. + i = 1; + dow i <= size; + if counter.tagopen; // Did we see '<' ? + counter.tagopen = *off; + if chars(i) <> '/'; // Reject closing tag. + counter.tagcount = counter.tagcount + 1; // Count this tag. + endif; + else; + i = %scan('<': %str(ebcdata): i); // Search next possible tag. + if i = 0; + leave; + endif; + counter.tagopen = *on; // Found one: flag it. + endif; + i = i + 1; + enddo; + curl_free(ebcdata); + return size; + p in_data_cb e + * + ************************************************************************** + * Get the length of right-trimmed string + ************************************************************************** + * + p trimmed_length b + d trimmed_length pi 10u 0 + d string 999999 const options(*varsize) + d length 10u 0 value + * + d len s 10u 0 + * + len = %scan(X'00': string: 1: length); // Limit to zero-terminated string + if len = 0; + len = length + 1; + endif; + if len <= 1; + return 0; + endif; + return %checkr(' ': string: len - 1); // Trim right + p trimmed_length e diff --git a/packages/OS400/rpg-examples/SIMPLE1 b/packages/OS400/rpg-examples/SIMPLE1 new file mode 100644 index 0000000..52c0c93 --- /dev/null +++ b/packages/OS400/rpg-examples/SIMPLE1 @@ -0,0 +1,108 @@ + * Curl simple URL request + * + h DFTACTGRP(*NO) ACTGRP(*NEW) + h OPTION(*NOSHOWCPY) + h BNDDIR('CURL') + * + ************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ************************************************************************** + * + /include H,CURL.INC + * + * Simple example to request the URL given as command line parameter and + * output its response. + * + d pi + d url 120 + * + d urllen s 10u 0 URL length + * + ************************************************************************** + * + c eval urllen = trimmed_length(url: %len(url)) + * + * Do the curl stuff. + * + c callp curl_global_init(CURL_GLOBAL_ALL) + c callp main + c callp curl_global_cleanup() + c seton lr Exit + * + ************************************************************************** + * Main procedure: do the curl job. + ************************************************************************** + * + p main b + d main pi + * + d h s * Easy handle + d result s like(CURLcode) Curl return code + d inz(CURLE_OUT_OF_MEMORY) + d errmsgp s * Error string pointer + d response s 52 For error display + * + * Create and fill curl handle. + * + c eval h = curl_easy_init() + c if h <> *NULL + c callp curl_easy_setopt_ccsid(h: CURLOPT_URL: + c %subst(url: 1: urllen): 0) + c callp curl_easy_setopt_long(h: + c CURLOPT_FOLLOWLOCATION: 1) + * + * Perform the request. + * + c eval result = curl_easy_perform(h) + c callp curl_easy_cleanup(h) Release handle + c endif + * + * Check for error and report if some. + * + c if result <> CURLE_OK + c eval errmsgp = curl_easy_strerror_ccsid(result: 0) + c eval response = %str(errmsgp) + c dsply response + c endif + p main e + * + ************************************************************************** + * Get the length of right-trimmed string + ************************************************************************** + * + p trimmed_length b + d trimmed_length pi 10u 0 + d string 999999 const options(*varsize) + d length 10u 0 value + * + d len s 10u 0 + * + c eval len = %scan(X'00': string: 1: length) Limit 0-terminated + c if len = 0 + c eval len = length + 1 + c endif + c if len <= 1 + c return 0 + c endif + c return %checkr(' ': string: len - 1) Trim right + p trimmed_length e diff --git a/packages/OS400/rpg-examples/SIMPLE2 b/packages/OS400/rpg-examples/SIMPLE2 new file mode 100644 index 0000000..493c91e --- /dev/null +++ b/packages/OS400/rpg-examples/SIMPLE2 @@ -0,0 +1,108 @@ + * Curl simple URL request (free-format RPG) + * + ctl-opt dftactgrp(*NO) actgrp(*NEW) + option(*NOSHOWCPY) + bnddir('CURL'); + * + ************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ************************************************************************** + + /include H,CURL.INC + + * Simple free-format RPG program to request the URL given as command line + * parameter and output its response. + + dcl-pi *N; + url char(120); + end-pi; + + dcl-s urllen int(10); // URL length + + ************************************************************************** + + urllen = trimmed_length(url: %len(url)); + + // Do the curl stuff. + + curl_global_init(CURL_GLOBAL_ALL); + main(); + curl_global_cleanup(); + *inlr = *on; // Exit + + ************************************************************************** + * Main procedure: do the curl job. + ************************************************************************** + + dcl-proc main; + dcl-pi *N end-pi; + + dcl-s h pointer; // Easy handle + dcl-s result like(CURLcode) inz(CURLE_OUT_OF_MEMORY); // Curl return code + dcl-s errmsgp pointer; // Error string pointer + dcl-s response char(52); // For error display + + // Create and fill curl handle. + + h = curl_easy_init(); + if h <> *NULL; + curl_easy_setopt_ccsid(h: CURLOPT_URL: %subst(url: 1: urllen): + 0); + curl_easy_setopt(h: CURLOPT_FOLLOWLOCATION: 1); + + // Perform the request. + + result = curl_easy_perform(h); + curl_easy_cleanup(h); // Release handle + endif; + + // Check for error and report if some. + + if result <> CURLE_OK; + errmsgp = curl_easy_strerror_ccsid(result: 0); + response = %str(errmsgp); + dsply '' '*EXT' response; + endif; + end-proc; + * + ************************************************************************** + * Get the length of right-trimmed string + ************************************************************************** + * + dcl-proc trimmed_length; + dcl-pi *N uns(10); + string char(9999999) const options(*varsize); + length uns(10) value; + end-pi; + + dcl-s len uns(10); + + len = %scan(X'00': string: 1: length); // Limit to zero-terminated string + if len = 0; + len = length + 1; + endif; + if len <= 1; + return 0; + endif; + return %checkr(' ': string: len - 1); // Trim right + end-proc; diff --git a/packages/OS400/rpg-examples/SMTPSRCMBR b/packages/OS400/rpg-examples/SMTPSRCMBR new file mode 100644 index 0000000..88f4fd2 --- /dev/null +++ b/packages/OS400/rpg-examples/SMTPSRCMBR @@ -0,0 +1,239 @@ + * Curl SMTP send source member as attachment + * + h DFTACTGRP(*NO) ACTGRP(*NEW) + h OPTION(*NOSHOWCPY) + h BNDDIR('CURL') + * + ************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ************************************************************************** + * + /include H,CURL.INC + * + * Example to SMTP send source member as attachment via SMTP. + * + fRPGXAMPLESif e disk extmbr(program_name) + f rename(RPGXAMPLES: record) + d pi + d url 60 SMTP server URL + d recipient_mail 40 Recipient mail addr + * + d program_name c 'SMTPSRCMBR' Member name to send + d sender_name c 'Curl' Sender name + d sender_mail c 'curl@example.com' Sender e-mail + d recipient_name c 'WIMC' Recipient name + d crlf c X'0D25' + * + d urllen s 10u 0 URL length + d rcptmlen s 10u 0 Recipient mail len + * + ************************************************************************** + + urllen = trimmed_length(url: %len(url)); + rcptmlen = trimmed_length(recipient_mail: %len(recipient_mail)); + + // Do the curl stuff. + + curl_global_init(CURL_GLOBAL_ALL); + main(); + curl_global_cleanup(); + *inlr = *on; // Exit + * + ************************************************************************** + * Main procedure: do the curl job. + ************************************************************************** + * + p main b + d main pi + * + d h s * Easy handle + d result s like(CURLcode) Curl return code + d inz(CURLE_OUT_OF_MEMORY) + d errmsgp s * Error string pointer + d response s 52 For error display + d headers s * inz(*NULL) Mail headers + d rcpts s * inz(*NULL) List of recipients + d mime s * Mail MIME structure + d mimepart s * Mail part + + // Create and fill curl handle. + + h = curl_easy_init(); + if h <> *NULL; + rcpts = curl_slist_append_ccsid(rcpts: + %subst(recipient_mail: 1: rcptmlen): 0); + headers = curl_slist_append_ccsid(headers: 'From: ' + sender_name + + ' <' + sender_mail + '>': + 0); + headers = curl_slist_append_ccsid(headers: 'To: ' + recipient_name + + ' <' + %subst(recipient_mail: 1: rcptmlen) + '>': 0); + headers = curl_slist_append_ccsid(headers: 'Subject: An ILE/RPG ' + + 'source program': 0); + headers = curl_slist_append_ccsid(headers: 'Date: ' + mail_date(): + 0); + curl_easy_setopt_ccsid(h: CURLOPT_URL: %subst(url: 1: urllen): 0); + curl_easy_setopt_ccsid(h: CURLOPT_MAIL_FROM: sender_mail: 0); + curl_easy_setopt(h: CURLOPT_MAIL_RCPT: rcpts); + curl_easy_setopt(h: CURLOPT_HTTPHEADER: headers); + mime = curl_mime_init(h); + mimepart = curl_mime_addpart(mime); + curl_mime_data_ccsid(mimepart: 'Please find the ILE/RPG program ' + + program_name + ' source code in ' + + 'attachment.' + crlf: + CURL_ZERO_TERMINATED: 0); + mimepart = curl_mime_addpart(mime); + curl_mime_data_cb(mimepart: -1: %paddr(out_data_cb): *NULL: *NULL: + *NULL); + curl_mime_filename_ccsid(mimepart: program_name: 0); + curl_mime_encoder_ccsid(mimepart: 'quoted-printable': 0); + curl_easy_setopt(h: CURLOPT_MIMEPOST: mime); + + // Perform the request. + + setll *start RPGXAMPLES; + result = curl_easy_perform(h); + + // Cleanup. + + curl_mime_free(mime); + curl_slist_free_all(headers); + curl_slist_free_all(rcpts); + curl_easy_cleanup(h); // Release handle + endif; + + // Check for error and report if some. + + if result <> CURLE_OK; + errmsgp = curl_easy_strerror_ccsid(result: 0); + response = %str(errmsgp); + dsply '' '*EXT' response; + else; + response = 'Mail sent'; + dsply '' '*EXT' response; + endif; + p main e + * + ************************************************************************** + * Attachment data callback procedure. + ************************************************************************** + * + p out_data_cb b + d out_data_cb pi 10u 0 + d ptr * value Output data pointer + d size 10u 0 value Data element size + d nmemb 10u 0 value Data element count + d userdata * value User data pointer + * + d buffer s 9999999 based(ptr) Output buffer + d line s 9999999 based(lineptr) ASCII line pointer + d linelen s 10u 0 + d i s 10u 0 Buffer position + * + size = size * nmemb; // The size in bytes. + i = 0; + dow size - i >= %len(SRCDTA) + %len(crlf) and not %eof(RPGXAMPLES); + read record; + lineptr = curl_from_ccsid(%trimr(SRCDTA) + crlf: 0); + linelen = %scan(X'00': line) - 1; + %subst(buffer: i + 1: linelen) = %str(lineptr); + curl_free(lineptr); + i = i + linelen; + enddo; + return i; + p out_data_cb e + * + ************************************************************************** + * Mail-formatted date procedure. + ************************************************************************** + * + p mail_date b + d mail_date pi 50 varying + * + d sysval ds qualified To retrieve timezone + d numsysval 10u 0 + d offset 10u 0 + d 100 + * + d get_sysval pr extpgm('QWCRSVAL') + d outdata likeds(sysval) + d outsize 10u 0 const + d numsysval 10u 0 const + d name 10 const + d errcode 10000 options(*varsize) + * + d now ds qualified + d ts z + d year 4s 0 overlay(ts: 1) + d month 2s 0 overlay(ts: 6) + d day 2s 0 overlay(ts: 9) + d hour 2s 0 overlay(ts: 12) + d minute 2 overlay(ts: 15) + d second 2 overlay(ts: 18) + * + d sysvalinfo ds qualified based(sysvalinfoptr) + d name 10 + d type 1 + d status 1 + d length 10u 0 + d value 99999 + * + d qusec ds qualified + d 10u 0 inz(0) + * + d weekday s 10u 0 + * + now.ts = %timestamp(*SYS); + get_sysval(sysval: %len(sysval): 1: 'QUTCOFFSET': qusec); + sysvalinfoptr = %addr(sysval) + sysval.offset; + weekday = %rem(%diff(now.ts: %timestamp('2001-01-01-00.00.00.000000'): + *DAYS): 7); + return %subst('MonTueWedThuFriSatSun': 3 * weekday + 1: 3) + ', ' + + %char(now.day) + ' ' + + %subst('JanFebMarAprMayJunJulAugSepOctNovDec': + 3 * now.month - 2: 3) + ' ' + + %char(now.year) + ' ' + + %char(now.hour) + ':' + now.minute + ':' + now.second + ' ' + + %subst(sysvalinfo.value: 1: sysvalinfo.length); + p mail_date e + * + ************************************************************************** + * Get the length of right-trimmed string + ************************************************************************** + * + p trimmed_length b + d trimmed_length pi 10u 0 + d string 999999 const options(*varsize) + d length 10u 0 value + * + d addrdiff s 10i 0 + d len s 10u 0 + * + len = %scan(X'00': string: 1: length); // Limit to zero-terminated string + if len = 0; + len = length + 1; + endif; + if len <= 1; + return 0; + endif; + return %checkr(' ': string: len - 1); // Trim right + p trimmed_length e diff --git a/packages/README.md b/packages/README.md new file mode 100644 index 0000000..f52f8e4 --- /dev/null +++ b/packages/README.md @@ -0,0 +1,12 @@ + + +# Packages + + This directory and all its subdirectories are for special package +information, templates, scripts and docs. The files herein should be of use +for those of you who want to package curl in a binary or source format for +these platforms. diff --git a/packages/vms/Makefile.am b/packages/vms/Makefile.am new file mode 100644 index 0000000..e869a89 --- /dev/null +++ b/packages/vms/Makefile.am @@ -0,0 +1,59 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +EXTRA_DIST = \ + backup_gnv_curl_src.com \ + build_curl-config_script.com \ + build_gnv_curl.com \ + build_gnv_curl_pcsi_desc.com \ + build_gnv_curl_pcsi_text.com \ + build_gnv_curl_release_notes.com \ + build_libcurl_pc.com \ + build_vms.com \ + clean_gnv_curl.com \ + compare_curl_source.com \ + config_h.com \ + curl_crtl_init.c \ + curl_gnv_build_steps.txt \ + curl_release_note_start.txt \ + curl_startup.com \ + curlmsg.h \ + curlmsg.msg \ + curlmsg.sdl \ + curlmsg_vms.h \ + generate_config_vms_h_curl.com \ + generate_vax_transfer.com \ + gnv_conftest.c_first \ + gnv_curl_configure.sh \ + gnv_libcurl_symbols.opt \ + gnv_link_curl.com \ + macro32_exactcase.patch \ + make_gnv_curl_install.sh \ + make_pcsi_curl_kit_name.com \ + pcsi_gnv_curl_file_list.txt \ + pcsi_product_gnv_curl.com \ + readme \ + report_openssl_version.c \ + setup_gnv_curl_build.com \ + stage_curl_install.com \ + vms_eco_level.h diff --git a/packages/vms/Makefile.in b/packages/vms/Makefile.in new file mode 100644 index 0000000..fbba71d --- /dev/null +++ b/packages/vms/Makefile.in @@ -0,0 +1,629 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = packages/vms +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +EXTRA_DIST = \ + backup_gnv_curl_src.com \ + build_curl-config_script.com \ + build_gnv_curl.com \ + build_gnv_curl_pcsi_desc.com \ + build_gnv_curl_pcsi_text.com \ + build_gnv_curl_release_notes.com \ + build_libcurl_pc.com \ + build_vms.com \ + clean_gnv_curl.com \ + compare_curl_source.com \ + config_h.com \ + curl_crtl_init.c \ + curl_gnv_build_steps.txt \ + curl_release_note_start.txt \ + curl_startup.com \ + curlmsg.h \ + curlmsg.msg \ + curlmsg.sdl \ + curlmsg_vms.h \ + generate_config_vms_h_curl.com \ + generate_vax_transfer.com \ + gnv_conftest.c_first \ + gnv_curl_configure.sh \ + gnv_libcurl_symbols.opt \ + gnv_link_curl.com \ + macro32_exactcase.patch \ + make_gnv_curl_install.sh \ + make_pcsi_curl_kit_name.com \ + pcsi_gnv_curl_file_list.txt \ + pcsi_product_gnv_curl.com \ + readme \ + report_openssl_version.c \ + setup_gnv_curl_build.com \ + stage_curl_install.com \ + vms_eco_level.h + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign packages/vms/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign packages/vms/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/packages/vms/backup_gnv_curl_src.com b/packages/vms/backup_gnv_curl_src.com new file mode 100644 index 0000000..298f11f --- /dev/null +++ b/packages/vms/backup_gnv_curl_src.com @@ -0,0 +1,130 @@ +$! File: Backup_gnv_curl_src.com +$! +$! Procedure to create backup save sets for installing in a PCSI kit. +$! +$! To comply with most Open Source licenses, the source used for building +$! a kit will be packaged with the distribution kit for the binary. +$! +$! Backup save sets are the only storage format that I can expect a +$! VMS system to be able to extract ODS-5 filenames and directories. +$! +$! The make_pcsi_kit_name.com needs to be run before this procedure to +$! properly name the files that will be created. +$! +$! This file is created from a template file for the purpose of making it +$! easier to port Unix code, particularly open source code to VMS. +$! Therefore permission is freely granted for any use. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!=========================================================================== +$! +$! Save default +$ default_dir = f$environment("DEFAULT") +$! +$ arch_type = f$getsyi("ARCH_NAME") +$ arch_code = f$extract(0, 1, arch_type) +$! +$ if arch_code .nes. "V" +$ then +$ set proc/parse=extended +$ endif +$! +$ ss_abort = 44 +$ status = ss_abort +$! +$ kit_name = f$trnlnm("GNV_PCSI_KITNAME") +$ if kit_name .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$ producer = f$trnlnm("GNV_PCSI_PRODUCER") +$ if producer .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$ filename_base = f$trnlnm("GNV_PCSI_FILENAME_BASE") +$ if filename_base .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$! +$ node_swvers = f$getsyi("NODE_SWVERS") +$ node_swvers_type = f$extract(0, 1, node_swvers) +$ node_swvers_vers = f$extract(1, f$length(node_swvers), node_swvers) +$ swvers_maj = f$element(0, ".", node_swvers_vers) +$ node_swvers_min_update = f$element(1, ".", node_swvers_vers) +$ swvers_min = f$element(0, "-", node_swvers_min_update) +$ swvers_update = f$element(1, "-", node_swvers_min_update) +$! +$ if swvers_update .eqs. "-" then swvers_update = "" +$! +$ vms_vers = f$fao("!2ZB!2ZB!AS", 'swvers_maj', 'swvers_min', swvers_update) +$! +$! +$! +$! If available make an interchange save set +$!------------------------------------------- +$ interchange = "" +$ if arch_code .eqs. "V" +$ then +$ interchange = "/interchange" +$ endif +$ if (swvers_maj .ges. "8") .and. (swvers_min .ges. 4) +$ then +$ interchange = "/interchange/noconvert" +$ endif +$! +$! +$! Move to the base directories +$ set def [--] +$! +$! Put things back on error. +$ on warning then goto all_exit +$! +$ current_default = f$environment("DEFAULT") +$ my_dir = f$parse(current_default,,,"DIRECTORY") - "[" - "<" - ">" - "]" +$! +$ src_root = "src_root:" +$ if f$trnlnm("src_root1") .nes. "" then src_root = "src_root1:" +$ backup'interchange' 'src_root'[curl...]*.*;0 - + 'filename_base'_original_src.bck/sav +$ status = $status +$! +$! There may be a VMS specific source kit +$!----------------------------------------- +$ vms_root = "vms_root:" +$ if f$trnlnm("vms_root1") .nes. "" then vms_root = "vms_root1:" +$ files_found = 0 +$ define/user sys$error nl: +$ define/user sys$output nl: +$ directory 'vms_root'[...]*.*;*/exc=*.dir +$ if '$severity' .eq. 1 then files_found = 1 +$! +$ if files_found .eq. 1 +$ then +$ backup'interchange' 'vms_root'[curl...]*.*;0 - + 'filename_base'_vms_src.bck/sav +$ status = $status +$ endif +$! +$all_exit: +$ set def 'default_dir' +$ exit diff --git a/packages/vms/build_curl-config_script.com b/packages/vms/build_curl-config_script.com new file mode 100644 index 0000000..1667d07 --- /dev/null +++ b/packages/vms/build_curl-config_script.com @@ -0,0 +1,153 @@ +$! build_curl-config_script.com +$! +$! This generates the curl-config. script from the curl-config.in file. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!=========================================================================== +$! +$! Skip this if the curl-config. already exists. +$ if f$search("[--]curl-config.") .nes. "" then goto all_exit +$! +$ if (f$getsyi("HW_MODEL") .lt. 1024) +$ then +$ arch_name = "VAX" +$ else +$ arch_name = "" +$ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") +$ if (arch_name .eqs. "") then arch_name = "UNK" +$ endif +$! +$ x_prefix = "/usr" +$ x_exec_prefix = "/usr" +$ x_includedir = "${prefix}/include" +$ x_cppflag_curl_staticlib = "-DCURL_STATICLIB" +$ x_enabled_shared = "no" +$ x_curl_ca_bundle = "" +$ x_cc = "cc" +$ x_support_features = "SSL IPv6 libz NTLM" +$ x_support_protocols1 = "DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP" +$ x_support_protocols2 = " LDAPS POP3 POP3S RTSP SMTP SMTPS TELNET TFTP" +$ x_support_protocols = x_support_protocols1 + x_support_protocols2 +$ x_curlversion = "0.0.0.0" +$ x_versionnum = "" +$ x_libdir = "${prefix}/lib" +$ x_require_lib_deps = "" +$ x_enable_static = "" +$ x_ldflags = "" +$ part1 = "-L/usr/lib -L/SSL_LIB -lssl -lcrypto -lz" +$ if arch_name .eqs. "VAX" +$ then +$ x_libcurl_libs = part1 +$ else +$ x_libcurl_libs = part1 + " -lgssapi" +$ endif +$ x_libext = "a" +$! +$! Get the version number +$!----------------------- +$ i = 0 +$ open/read/error=version_loop_end vhf [--.include.curl]curlver.h +$ version_loop: +$ read/end=version_loop_end vhf line_in +$ if line_in .eqs. "" then goto version_loop +$ if f$locate("#define LIBCURL_VERSION ", line_in) .eq. 0 +$ then +$ x_curlversion = f$element(2," ", line_in) - """" - """" +$ i = i + 1 +$ endif +$ if f$locate("#define LIBCURL_VERSION_NUM ", line_in) .eq. 0 +$ then +$ x_versionnum = f$element(2," ", line_in) - """" - """" +$ i = i + 1 +$ endif +$ if i .lt 2 then goto version_loop +$ version_loop_end: +$ close vhf +$! +$ kit_type = "V" +$ if f$locate("-", x_curlversion) .lt. f$length(x_curlversion) +$ then +$ kit_type = "D" +$ x_prefix = "/beta" +$ x_exec_prefix = "/beta" +$ endif +$! +$ if kit_type .nes. "D" +$ then +$ part1 = " echo "" '--prefix=/usr' '--exec-prefix=/usr' " +$ else +$ part1 = " echo "" '--prefix=/beta' '--exec_prefix=/beta' " +$ endif +$ if arch_name .eqs. "VAX" +$ then +$ part3 = "" +$ else +$ part3 = "'--with-gssapi' " +$ endif +$ part2 = "'--disable-dependency-tracking' '--disable-libtool-lock' " +$ part4 = "'--disable-ntlm-wb' '--with-ca-path=gnv$curl_ca_path'""" +$! +$ x_configure_options = part1 + part2 + part3 + part4 +$! +$! +$ open/read/error=read_loop_end c_c_in sys$disk:[--]curl-config.in +$ create sys$disk:[--]curl-config. +$ open/append c_c_out sys$disk:[--]curl-config. +$read_loop: +$ read/end=read_loop_end c_c_in line_in +$ line_in_len = f$length(line_in) +$ if f$locate("@", line_in) .ge. line_in_len +$ then +$ write c_c_out line_in +$ goto read_loop +$ endif +$ i = 0 +$ line_out = "" +$sub_loop: +$ ! Replace between pairs of @ by alternating the elements. +$ ! If mis-matched pairs, do not substitute anything. +$ section1 = f$element(i, "@", line_in) +$ if section1 .eqs. "@" +$ then +$ goto sub_loop_end +$ endif +$ i = i + 1 +$ section2 = f$element(i, "@", line_in) +$ if section2 .eqs. "@" +$ then +$ goto sub_loop_end +$ endif +$ i = i + 1 +$ section3 = f$element(i, "@", line_in) +$ if section3 .eqs. "@" +$ then +$ if line_out .eqs. "" then line_out = line_in +$ goto sub_loop_end +$ endif +$ line_out = line_out + section1 +$ if f$type(x_'section2') .eqs. "STRING" +$ then +$ line_out = line_out + x_'section2' +$ endif +$ goto sub_loop +$sub_loop_end: +$ write c_c_out line_out +$ goto read_loop +$read_loop_end: +$ close c_c_in +$ close c_c_out diff --git a/packages/vms/build_gnv_curl.com b/packages/vms/build_gnv_curl.com new file mode 100644 index 0000000..36e7281 --- /dev/null +++ b/packages/vms/build_gnv_curl.com @@ -0,0 +1,36 @@ +$! File: build_gnv_curl.com +$! +$! All in one build procedure +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!----------------------------------------------------------------------- +$! +$ @setup_gnv_curl_build.com +$! +$ bash gnv_curl_configure.sh +$! +$ @clean_gnv_curl.com +$! +$ bash make_gnv_curl_install.sh +$! +$ @gnv_link_curl.com +$! +$ purge new_gnu:[*...]/log +$! +$! +$exit diff --git a/packages/vms/build_gnv_curl_pcsi_desc.com b/packages/vms/build_gnv_curl_pcsi_desc.com new file mode 100644 index 0000000..8567426 --- /dev/null +++ b/packages/vms/build_gnv_curl_pcsi_desc.com @@ -0,0 +1,489 @@ +$! File: Build_GNV_CURL_PCSI_DESC.COM +$! +$! Build the *.pcsi$text file in the following sections: +$! Required software dependencies. +$! install/upgrade/postinstall steps. +$! 1. Duplicate filenames need an alias procedure. (N/A for curl) +$! 2. ODS-5 filenames need an alias procedure. (N/A for curl) +$! 3. Special alias links for executables (curl. -> curl.exe) +$! if a lot, then an alias procedure is needed. +$! 4. Rename the files to lowercase. +$! Move Release Notes to destination +$! Source kit option +$! Create directory lines +$! Add file lines for curl. +$! Add Link alias procedure file (N/A for curl) +$! Add [.SYS$STARTUP]curl_startup file +$! Add Release notes file. +$! +$! The file PCSI_GNV_CURL_FILE_LIST.TXT is read in to get the files other +$! than the release notes file and the source backup file. +$! +$! The PCSI system can really only handle ODS-2 format filenames and +$! assumes that there is only one source directory. It also assumes that +$! all destination files with the same name come from the same source file. +$! Fortunately CURL does not trip most of these issues, so those steps +$! above are marked N/A. +$! +$! A rename action section is needed to make sure that the files are +$! created in the GNV$GNU: in the correct case, and to create the alias +$! link [usr.bin]curl. for [usr.bin]curl.exe. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!=========================================================================== +$! +$ kit_name = f$trnlnm("GNV_PCSI_KITNAME") +$ if kit_name .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$ producer = f$trnlnm("GNV_PCSI_PRODUCER") +$ if producer .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$ filename_base = f$trnlnm("GNV_PCSI_FILENAME_BASE") +$ if filename_base .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$! +$! +$! Parse the kit name into components. +$!--------------------------------------- +$ producer = f$element(0, "-", kit_name) +$ base = f$element(1, "-", kit_name) +$ product = f$element(2, "-", kit_name) +$ mmversion = f$element(3, "-", kit_name) +$ majorver = f$extract(0, 3, mmversion) +$ minorver = f$extract(3, 2, mmversion) +$ updatepatch = f$element(4, "-", kit_name) +$ if updatepatch .eqs. "-" then updatepatch = "" +$! +$! kit type of "D" means a daily build +$ kit_type = f$edit(f$extract(0, 1, majorver), "upcase") +$! +$! +$ product_line = "product ''producer' ''base' ''product'" +$ if updatepatch .eqs. "" +$ then +$ product_name = " ''majorver'.''minorver'" +$ else +$ product_name = " ''majorver'.''minorver'-''updatepatch'" +$ endif +$ product_line = product_line + " ''product_name' full;" +$!write sys$output product_line +$! +$! +$! +$! Create the file as a VMS text file. +$!---------------------------------------- +$ base_file = kit_name +$ create 'base_file'.pcsi$desc +$! +$! +$! Start building file. +$!---------------------- +$ open/append pdsc 'base_file'.pcsi$desc +$! +$ write pdsc product_line +$! +$! Required product dependencies. +$!---------------------------------- +$ vmsprd = "DEC" +$ if base .eqs. "I64VMS" then vmsprd = "HP" +$ vsiprd = "VSI" +$! +$ write pdsc " software ''vmsprd' ''base' VMS ;" +$ arch_type = f$getsyi("ARCH_NAME") +$ node_swvers = f$getsyi("node_swvers") +$ vernum = f$extract(1, f$length(node_swvers), node_swvers) +$ majver = f$element(0, ".", vernum) +$ minverdash = f$element(1, ".", vernum) +$ minver = f$element(0, "-", minverdash) +$ dashver = f$element(1, "-", minverdash) +$ if dashver .eqs. "-" then dashver = "" +$ vmstag = majver + minver + dashver +$ code = f$extract(0, 1, arch_type) +$ arch_code = f$extract(0, 1, arch_type) +$ line_out = - + " if ((not ) and" + - + " (not ));" +$ write pdsc line_out +$ write pdsc " error NEED_VMS''vmstag';" +$ write pdsc " end if;" +$! +$write pdsc " software VMSPORTS ''base' ZLIB ;" +$write pdsc - + " if (not ) ;" +$write pdsc " error NEED_ZLIB;" +$write pdsc " end if;" +$! +$! +$! +$! install/upgrade/postinstall steps. +$!----------------------------------- +$! 1. Duplicate filenames need an alias procedure. (N/A for curl) +$! 2. ODS-5 filenames need an alias procedure. (N/A for curl) +$! 3. Special alias links for executables (curl. -> curl.exe) +$! if a lot, then an alias procedure is needed. +$! 4. Rename the files to lowercase. +$! +$! +$! Alias links needed. +$!------------------------- +$ add_alias_lines = "" +$ rem_alias_lines = "" +$ line_out = "" +$! +$! Read through the file list to set up aliases and rename commands. +$!--------------------------------------------------------------------- +$ open/read flst pcsi_gnv_curl_file_list.txt +$! +$inst_alias_loop: +$ read/end=inst_alias_loop_end flst line_in +$ line_in = f$edit(line_in,"compress,trim,uncomment") +$ if line_in .eqs. "" then goto inst_alias_loop +$ pathname = f$element(0, " ", line_in) +$ linkflag = f$element(1, " ", line_in) + +$ if linkflag .nes. "->" then goto inst_alias_write +$! +$ linktarget = f$element(2, " ", line_in) +$ if kit_type .eqs. "D" +$ then +$ old_start = f$locate("[gnv.usr", pathname) +$ if old_start .lt. f$length(pathname) +$ then +$ pathname = "[gnv.beta" + pathname - "[gnv.usr" +$ linktarget = "[gnv.beta" + linktarget - "[gnv.usr" +$ endif +$ endif +$ nlink = "pcsi$destination:" + pathname +$ ntarg = "pcsi$destination:" + linktarget +$ new_add_alias_line = - + """if f$search(""""''nlink'"""") .eqs. """""""" then" + - + " set file/enter=''nlink' ''ntarg'""" +$ if add_alias_lines .nes. "" +$ then +$ add_alias_lines = add_alias_lines + "," + new_add_alias_line +$ else +$ add_alias_lines = new_add_alias_line +$ endif +$! +$ new_rem_alias_line = - + """if f$search(""""''nlink'"""") .nes. """""""" then" + - + " set file/remove ''nlink';""" +$ if rem_alias_lines .nes. "" +$ then +$ rem_alias_lines = rem_alias_lines + "," + new_rem_alias_line +$ else +$ rem_alias_lines = new_rem_alias_line +$ endif +$! +$ goto inst_alias_loop +$! +$inst_alias_write: +$! +$! execute install / remove +$ write pdsc " execute install (" +$! add aliases +$ i = 0 +$ex_ins_loop: +$ line = f$element(i, ",", add_alias_lines) +$ i = i + 1 +$ if line .eqs. "" then goto ex_ins_loop +$ if line .eqs. "," then goto ex_ins_loop_end +$ if line_out .nes. "" then write pdsc line_out,"," +$ line_out = line +$ goto ex_ins_loop +$ex_ins_loop_end: +$ write pdsc line_out +$ line_out = "" +$ write pdsc " )" +$ write pdsc " remove (" +$! remove aliases +$ i = 0 +$ex_rem_loop: +$ line = f$element(i, ",", rem_alias_lines) +$ i = i + 1 +$ if line .eqs. "" then goto ex_rem_loop +$ if line .eqs. "," then goto ex_rem_loop_end +$ if line_out .nes. "" then write pdsc line_out,"," +$ line_out = line +$ goto ex_rem_loop +$ex_rem_loop_end: +$ write pdsc line_out +$ line_out = "" +$ write pdsc " ) ;" +$! +$! execute upgrade +$ write pdsc " execute upgrade (" +$ i = 0 +$ex_upg_loop: +$ line = f$element(i, ",", rem_alias_lines) +$ i = i + 1 +$ if line .eqs. "" then goto ex_upg_loop +$ if line .eqs. "," then goto ex_upg_loop_end +$ if line_out .nes. "" then write pdsc line_out,"," +$ line_out = line +$ goto ex_upg_loop +$ex_upg_loop_end: +$ write pdsc line_out +$ line_out = "" +$! remove aliases +$ write pdsc " ) ;" +$! +$! execute postinstall +$ write pdsc " execute postinstall (" +$ if arch_code .nes. "V" +$ then +$ line_out = " ""set process/parse=extended""" +$ endif +$ i = 0 +$ex_pins_loop: +$ line = f$element(i, ",", add_alias_lines) +$ i = i + 1 +$ if line .eqs. "" then goto ex_pins_loop +$ if line .eqs. "," then goto ex_pins_loop_end +$ if line_out .nes. "" then write pdsc line_out,"," +$ line_out = line +$ goto ex_pins_loop +$ex_pins_loop_end: +$ if line_out .eqs. "" then line_out = " ""continue""" +$! write pdsc line_out +$! line_out = "" +$! add aliases and follow with renames. +$! +$goto inst_dir +$! +$inst_dir_loop: +$ read/end=inst_alias_loop_end flst line_in +$ line_in = f$edit(line_in,"compress,trim,uncomment") +$ if line_in .eqs. "" then goto inst_dir_loop +$inst_dir: +$ pathname = f$element(0, " ", line_in) +$ if kit_type .eqs. "D" +$ then +$ if pathname .eqs. "[gnv]usr.dir" +$ then +$ pathname = "[gnv]beta.dir" +$ else +$ old_start = f$locate("[gnv.usr", pathname) +$ if old_start .lt. f$length(pathname) +$ then +$ pathname = "[gnv.beta" + pathname - "[gnv.usr" +$ endif +$ endif +$ endif +$! +$! Ignore the directory entries for now. +$!----------------------------------------- +$ filedir = f$parse(pathname,,,"DIRECTORY") +$ if pathname .eqs. filedir then goto inst_dir_loop +$! +$! process .dir extensions for rename +$! If this is not a directory then start processing files. +$!------------------------- +$ filetype = f$parse(pathname,,,"TYPE") +$ filetype_u = f$edit(filetype, "upcase") +$ filename = f$parse(pathname,,,"NAME") +$ if filetype_u .nes. ".DIR" then goto inst_file +$! +$! process directory lines for rename. +$!-------------------------------------- +$ if line_out .nes. "" +$ then +$ write pdsc line_out,"," +$ line_out = "" +$ endif +$ if arch_code .nes. "V" +$ then +$ if line_out .nes. "" then write pdsc line_out,"," +$ line_out = " ""rename pcsi$destination:''pathname' ''filename'.DIR""" +$ else +$ if line_out .nes. "" then write pdsc line_out +$ line_out = "" +$ endif +$ goto inst_dir_loop +$! +$! +$! process file lines for rename +$!--------------------------------- +$inst_file_loop: +$ read/end=inst_alias_loop_end flst line_in +$ line_in = f$edit(line_in,"compress,trim,uncomment") +$ if line_in .eqs. "" then goto inst_dir_loop +$ pathname = f$element(0, " ", line_in) +$ if kit_type .eqs. "D" +$ then +$ if pathname .eqs. "[gnv]usr.dir" +$ then +$ pathname = "[gnv]beta.dir" +$ else +$ old_start = f$locate("[gnv.usr", pathname) +$ if old_start .lt. f$length(pathname) +$ then +$ pathname = "[gnv.beta" + pathname - "[gnv.usr" +$ endif +$ endif +$ endif +$! +$! Filenames with $ in them are VMS special and do not need to be lowercase. +$! -------------------------------------------------------------------------- +$ if f$locate("$", pathname) .lt. f$length(pathname) then goto inst_file_loop +$! +$ filetype = f$parse(pathname,,,"TYPE") +$ filename = f$parse(pathname,,,"NAME") + filetype +$inst_file: +$ if arch_code .nes. "V" +$ then +$ if line_out .nes. "" then write pdsc line_out,"," +$ filetype = f$parse(pathname,,,"TYPE") +$ filename = f$parse(pathname,,,"NAME") + filetype +$ line_out = " ""rename pcsi$destination:''pathname' ''filename'""" +$ else +$ if line_out .nes. "" then write pdsc line_out +$ line_out = "" +$ endif +$ goto inst_file_loop +$! +$inst_alias_loop_end: +$! +$write pdsc line_out +$write pdsc " ) ;" +$close flst +$! +$! Move Release Notes to destination +$!------------------------------------- +$write pdsc " information RELEASE_NOTES phase after ;" +$! +$! Source kit option +$!--------------------- +$write pdsc " option SOURCE default 0;" +$write pdsc " directory ""[gnv.common_src]"" PROTECTION PUBLIC ;" +$write pdsc - + " file ""[gnv.common_src]''filename_base'_original_src.bck""" +$write pdsc - + " source [common_src]''filename_base'_original_src.bck ;" +$if f$search("gnv$gnu:[vms_src]''filename_base'_vms_src.bck") .nes. "" +$then +$ write pdsc " directory ""[gnv.vms_src]"" PROTECTION PUBLIC ;" +$ write pdsc " file ""[gnv.vms_src]''filename_base'_vms_src.bck""" +$ write pdsc " source [vms_src]''filename_base'_vms_src.bck ;" +$endif +$write pdsc " end option;" +$! +$! +$! Read through the file list again. +$!---------------------------------- +$open/read flst pcsi_gnv_curl_file_list.txt +$! +$! +$! Create directory lines +$!------------------------- +$flst_dir_loop: +$ read/end=flst_loop_end flst line_in +$ line_in = f$edit(line_in,"compress,trim,uncomment") +$ if line_in .eqs. "" then goto flst_dir_loop +$! +$ filename = f$element(0, " ", line_in) +$ linkflag = f$element(1, " ", line_in) +$ if linkflag .eqs. "->" then goto flst_dir_loop +$! +$! Ignore .dir extensions +$!------------------------- +$ filetype = f$edit(f$parse(filename,,,"TYPE"), "upcase") +$ if filetype .eqs. ".DIR" then goto flst_dir_loop +$! +$ destname = filename +$ if kit_type .eqs. "D" +$ then +$ old_start = f$locate("[gnv.usr", destname) +$ if old_start .lt. f$length(destname) +$ then +$ destname = "[gnv.beta" + destname - "[gnv.usr" +$ endif +$ endif +$! +$! It should be just a directory then. +$!------------------------------------- +$ filedir = f$edit(f$parse(filename,,,"DIRECTORY"), "lowercase") +$! If this is not a directory then start processing files. +$!--------------------------------------------------------- +$ if filename .nes. filedir then goto flst_file +$! +$ write pdsc " directory ""''destname'"" PROTECTION PUBLIC ;" +$ goto flst_dir_loop +$! +$! +$! Add file lines for curl. +$!--------------------------- +$flst_file_loop: +$ read/end=flst_loop_end flst line_in +$ line_in = f$edit(line_in,"compress,trim,uncomment") +$ if line_in .eqs. "" then goto inst_file_loop +$ filename = f$element(0, " ", line_in) +$ destname = filename +$ if kit_type .eqs. "D" +$ then +$ old_start = f$locate("[gnv.usr", destname) +$ if old_start .lt. f$length(destname) +$ then +$ destname = "[gnv.beta" + destname - "[gnv.usr" +$ endif +$ endif +$flst_file: +$ srcfile = filename - "gnv." +$ write pdsc " file ""''destname'"" " +$ write pdsc " source ""''srcfile'"" ;" +$ goto flst_file_loop +$! +$flst_loop_end: +$ close flst +$! +$! Add Link alias procedure file (N/A for curl) +$!------------------------------------------------ +$! +$! Add [.SYS$STARTUP]curl_startup file +$!--------------------------------------- +$ if kit_type .eqs. "D" +$ then +$ write pdsc " file ""[sys$startup]curl_daily_startup.com""" +$ else +$ write pdsc " file ""[sys$startup]curl_startup.com""" +$ endif +$ write pdsc " source [usr.lib]curl_startup.com ;" +$! +$! Add Release notes file. +$!------------------------------ +$ write pdsc - + " file ""[SYSHLP]''filename_base'.release_notes"" release notes ;" +$! +$! Close the product file +$!------------------------ +$ write pdsc "end product;" +$! +$close pdsc +$! +$all_exit: +$ exit diff --git a/packages/vms/build_gnv_curl_pcsi_text.com b/packages/vms/build_gnv_curl_pcsi_text.com new file mode 100644 index 0000000..8f109c1 --- /dev/null +++ b/packages/vms/build_gnv_curl_pcsi_text.com @@ -0,0 +1,195 @@ +$! File: Build_GNV_curl_pcsi_text.com +$! +$! Build the *.pcsi$text file from the four components: +$! 1. Generated =product header section +$! 2. [--]readme. file from the Curl distribution, modified to fit +$! a pcsi$text file format. +$! 3. [--]copying file from the Curl distribution, modified to fit +$! a pcsi$text file format. +$! 4. Generated Producer section. +$! +$! Set the name of the release notes from the GNV_PCSI_FILENAME_BASE +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!=========================================================================== +$! +$ kit_name = f$trnlnm("GNV_PCSI_KITNAME") +$ if kit_name .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$ producer = f$trnlnm("GNV_PCSI_PRODUCER") +$ if producer .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$ producer_full_name = f$trnlnm("GNV_PCSI_PRODUCER_FULL_NAME") +$ if producer_full_name .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$! +$! +$! Parse the kit name into components. +$!--------------------------------------- +$ producer = f$element(0, "-", kit_name) +$ base = f$element(1, "-", kit_name) +$ product = f$element(2, "-", kit_name) +$ mmversion = f$element(3, "-", kit_name) +$ majorver = f$extract(0, 3, mmversion) +$ minorver = f$extract(3, 2, mmversion) +$ updatepatch = f$element(4, "-", kit_name) +$ if updatepatch .eqs. "-" then updatepatch = "" +$! +$! +$ product_line = "=product ''producer' ''base' ''product'" +$ if updatepatch .eqs. "" +$ then +$ product_name = " ''majorver'.''minorver'" +$ else +$ product_name = " ''majorver'.''minorver'-''updatepatch'" +$ endif +$ product_line = product_line + " ''product_name' full" +$! +$! +$! If this is VAX and the file is on NFS, the names may be mangled. +$!----------------------------------------------------------------- +$ readme_file = "" +$ if f$search("[--]readme.") .nes. "" +$ then +$ readme_file = "[--]readme." +$ else +$ if f$search("[--]$README.") .nes. "" +$ then +$ readme_file = "[--]$README." +$ else +$ write sys$output "Can not find readme file." +$ goto all_exit +$ endif +$ endif +$ copying_file = "" +$ if f$search("[--]copying.") .nes. "" +$ then +$ copying_file = "[--]copying." +$ else +$ if f$search("[--]$COPYING.") .nes. "" +$ then +$ copying_file = "[--]$COPYING." +$ else +$ write sys$output "Can not find copying file." +$ goto all_exit +$ endif +$ endif +$! +$! Create the file as a VMS text file. +$!---------------------------------------- +$ base_file = kit_name +$ create 'base_file'.pcsi$text +$! +$! +$! Start building file. +$!---------------------- +$ open/append ptxt 'base_file'.pcsi$text +$ write ptxt product_line +$! +$! +$! First insert the Readme file. +$! +$ open/read rf 'readme_file' +$! +$ write ptxt "1 'PRODUCT" +$ write ptxt "=prompt ''producter' ''product' for OpenVMS" +$! +$rf_loop: +$ read/end=rf_loop_end rf line_in +$ if line_in .nes. "" +$ then +$! PCSI files use the first character in for their purposes. +$!-------------------------------------------------------------- +$ first_char = f$extract(0, 1, line_in) +$ if first_char .nes. " " then line_in = " " + line_in +$ endif +$ write ptxt line_in +$ goto rf_loop +$rf_loop_end: +$ close rf +$! +$! +$! Now add in the copying file +$!-------------------------------- +$ write ptxt "" +$ write ptxt "1 'NOTICE" +$ write ptxt "" +$! +$ open/read cf 'copying_file' +$! +$cf_loop: +$ read/end=cf_loop_end cf line_in +$ if line_in .nes. "" +$ then +$! PCSI files use the first character in for their purposes. +$!-------------------------------------------------------------- +$ first_char = f$extract(0, 1, line_in) +$ if first_char .nes. " " then line_in = " " + line_in +$ endif +$ write ptxt line_in +$ goto cf_loop +$cf_loop_end: +$ close cf +$! +$! Now we need the rest of the boiler plate. +$!-------------------------------------------- +$ write ptxt "" +$ write ptxt "1 'PRODUCER" +$ write ptxt "=prompt ''producer_full_name'" +$ write ptxt - + "This software product is provided by ''producer_full_name' with no warranty." +$! +$ arch_type = f$getsyi("ARCH_NAME") +$ node_swvers = f$getsyi("node_swvers") +$ vernum = f$extract(1, f$length(node_swvers), node_swvers) +$ majver = f$element(0, ".", vernum) +$ minverdash = f$element(1, ".", vernum) +$ minver = f$element(0, "-", minverdash) +$ dashver = f$element(1, "-", minverdash) +$ if dashver .eqs. "-" then dashver = "" +$ vmstag = majver + minver + dashver +$ code = f$extract(0, 1, arch_type) +$! +$ write ptxt "1 NEED_VMS''vmstag'" +$ write ptxt - + "=prompt OpenVMS ''vernum' or later is not installed on your system." +$ write ptxt "This product requires OpenVMS ''vernum' or later to function." +$ write ptxt "1 NEED_ZLIB" +$ write ptxt "=prompt ZLIB 1.2-8 or later is not installed on your system." +$ write ptxt "This product requires ZLIB 1.2-8 or later to function." +$ write ptxt "1 SOURCE" +$ write ptxt "=prompt Source modules for ''product'" +$ write ptxt "The Source modules for ''product' will be installed." +$ write ptxt "1 RELEASE_NOTES" +$ write ptxt "=prompt Release notes are available in the [SYSHLP] directory." +$! +$ close ptxt +$! +$! +$! +$all_exit: +$ exit diff --git a/packages/vms/build_gnv_curl_release_notes.com b/packages/vms/build_gnv_curl_release_notes.com new file mode 100644 index 0000000..0da9445 --- /dev/null +++ b/packages/vms/build_gnv_curl_release_notes.com @@ -0,0 +1,100 @@ +$! File: Build_GNV_curl_release_notes.com +$! +$! Build the release note file from the four components: +$! 1. The curl_release_note_start.txt +$! 2. The hp_ssl_release_info.txt +$! 3. [--]readme. file from the Curl distribution. +$! 4. The Curl_gnv-build_steps.txt. +$! +$! Set the name of the release notes from the GNV_PCSI_FILENAME_BASE +$! logical name. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!=========================================================================== +$! +$ base_file = f$trnlnm("GNV_PCSI_FILENAME_BASE") +$ if base_file .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$! +$! +$ curl_readme = f$search("sys$disk:[--]readme.") +$ if curl_readme .eqs. "" +$ then +$ curl_readme = f$search("sys$disk:[--]$README.") +$ endif +$ if curl_readme .eqs. "" +$ then +$ write sys$output "Can not find Curl readme file." +$ goto all_exit +$ endif +$! +$ curl_copying = f$search("sys$disk:[--]copying.") +$ if curl_copying .eqs. "" +$ then +$ curl_copying = f$search("sys$disk:[--]$COPYING.") +$ endif +$ if curl_copying .eqs. "" +$ then +$ write sys$output "Can not find Curl copying file." +$ goto all_exit +$ endif +$! +$ vms_readme = f$search("sys$disk:[]readme.") +$ if vms_readme .eqs. "" +$ then +$ vms_readme = f$search("sys$disk:[]$README.") +$ endif +$ if vms_readme .eqs. "" +$ then +$ write sys$output "Can not find VMS specific Curl readme file." +$ goto all_exit +$ endif +$! +$ curl_release_notes = f$search("sys$disk:[--]release-notes.") +$ if curl_release_notes .eqs. "" +$ then +$ curl_release_notes = f$search("sys$disk:[--]$RELEASE-NOTES.") +$ endif +$ if curl_release_notes .eqs. "" +$ then +$ write sys$output "Can not find Curl release-notes file." +$ goto all_exit +$ endif +$! +$ if f$search("sys$disk:[]hp_ssl_release_info.txt") .eqs. "" +$ then +$ write sys$output "GNV_LINK_CURL.COM has not been run!" +$ goto all_exit +$ endif +$! +$ type/noheader 'curl_readme', 'vms_readme', - + 'curl_release_notes', - + sys$disk:[]curl_release_note_start.txt, - + sys$disk:[]hp_ssl_release_info.txt, - + 'curl_copying', - + sys$disk:[]curl_gnv_build_steps.txt - + /out='base_file'.release_notes +$! +$ purge 'base_file'.release_notes +$ rename 'base_file.release_notes ;1 +$! +$all_exit: +$ exit diff --git a/packages/vms/build_libcurl_pc.com b/packages/vms/build_libcurl_pc.com new file mode 100644 index 0000000..294ae08 --- /dev/null +++ b/packages/vms/build_libcurl_pc.com @@ -0,0 +1,202 @@ +$! File: build_libcurl_pc.com +$! +$! Build the libcurl.pc file from the libcurl.pc.in file +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!=========================================================================== +$! +$! Skip this if the libcurl.pc already exists. +$ if f$search("[--]libcurl.pc") .nes. "" then goto all_exit +$! +$! Need to know the kit type. +$ kit_name = f$trnlnm("GNV_PCSI_KITNAME") +$ if kit_name .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$! +$! +$! Parse the kit name into components. +$!--------------------------------------- +$ producer = f$element(0, "-", kit_name) +$ base = f$element(1, "-", kit_name) +$ product = f$element(2, "-", kit_name) +$ mmversion = f$element(3, "-", kit_name) +$ majorver = f$extract(0, 3, mmversion) +$ minorver = f$extract(3, 2, mmversion) +$ updatepatch = f$element(4, "-", kit_name) +$ if updatepatch .eqs. "-" then updatepatch = "" +$! +$! kit type of "D" means a daily build +$ kit_type = f$edit(f$extract(0, 1, majorver), "upcase") +$! +$ pc_file_in = "[--]libcurl^.pc.in" +$! +$ if f$search(pc_file_in) .eqs. "" +$ then +$ pc_file_in = "[--]libcurl.pc$5nin" +$ if f$search(pc_file_in) .eqs. "" +$ then +$ pc_file_in = "[--]libcurl.pc_in" +$ if f$search(pc_file_in) .eqs. "" +$ then +$ write sys$output "Can not find libcurl.pc.in." +$ goto all_exit +$ endif +$ endif +$ endif +$! +$ if (f$getsyi("HW_MODEL") .lt. 1024) +$ then +$ arch_name = "VAX" +$ else +$ arch_name = "" +$ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") +$ if (arch_name .eqs. "") then arch_name = "UNK" +$ endif +$! +$! +$ curl_version = "0.0.0" +$ open/read vf [--.src]tool_version.h +$version_loop: +$ read vf/end=version_loop_end line_in +$ if line_in .eqs. "" then goto version_loop +$ key = f$element(0, " ", line_in) +$ if key .nes. "#define" then goto version_loop +$ name = f$element(1, " ", line_in) +$ if name .eqs. "VERSION" +$ then +$ curl_version = f$element(2, " ", line_in) - """" - """" +$ else +$ goto version_loop +$ endif +$version_loop_end: +$ close vf +$! +$! +$ create [--]libcurl.pc +$ open/append pco [--]libcurl.pc +$ open/read pci 'pc_file_in' +$pc_file_loop: +$ read pci/end=pc_file_loop_end line_in +$! +$! blank lines +$ if line_in .eqs. "" +$ then +$ write pco "" +$ goto pc_file_loop +$ endif +$! +$! comment lines +$ key = f$extract(0, 1, line_in) +$ if key .eqs. "#" +$ then +$ write pco line_in +$ goto pc_file_loop +$ endif +$! +$! Special handling for libs. +$ if f$locate("Libs:", line_in) .eq. 0 +$ then +$ write pco "#",line_in +$ goto pc_file_loop +$ endif +$! No substitution line +$ line_in_len = f$length(line_in) +$ if f$locate("@", line_in) .ge. line_in_len +$ then +$ write pco line_in +$ goto pc_file_loop +$ endif +$! +$ if f$locate("@prefix@", line_in) .lt line_in_len +$ then +$ if kit_type .nes. "D" +$ then +$ write pco "prefix=/usr" +$ else +$ write pco "prefix=/beta" +$ endif +$ goto pc_file_loop +$ endif +$ if f$locate("@exec_prefix@", line_in) .lt line_in_len +$ then +$ if kit_type .nes. "D" +$ then +$ write pco "exec_prefix=/usr" +$ else +$ write pco "exec_prefix=/beta" +$ endif +$ goto pc_file_loop +$ endif +$ if f$locate("@libdir@", line_in) .lt line_in_len +$ then +$ write pco "libdir=$(exec_prefix}/lib" +$ goto pc_file_loop +$ endif +$ if f$locate("@includedir@", line_in) .lt line_in_len +$ then +$ write pco "includedir=$(prefix}/include" +$ goto pc_file_loop +$ endif +$ if f$locate("@SUPPORT_PROTOCOLS@", line_in) .lt line_in_len +$ then +$ proto1 = "DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS" +$ proto2 = " LDAP LDAPS POP3 POP3S RTSP SMTP SMTPS TELNET TFTP" +$ proto = proto1 + proto2 +$ write pco "supported_protocols=""" + proto + """" +$ goto pc_file_loop +$ endif +$ if f$locate("@SUPPORT_FEATURES@", line_in) .lt line_in_len +$ then +$ if arch_name .eqs. "VAX" +$ then +$ write pco "supported_features=""SSL libz NTLM""" +$ else +$ write pco "supported_features=""SSL IPv6 libz NTLM""" +$ endif +$ goto pc_file_loop +$ endif +$ if f$locate("@CURLVERSION@", line_in) .lt line_in_len +$ then +$ write pco "Version: ''curl_version'" +$ goto pc_file_loop +$ endif +$ if f$locate("@LIBCURL_LIBS@", line_in) .lt line_in_len +$ then +$ if arch_name .eqs. "VAX" +$ then +$ write pco "Libs.private: -lssl -lcrypto -lz" +$ else +$ write pco "Libs.private: -lssl -lcrypto -lgssapi -lz" +$ endif +$ goto pc_file_loop +$ endif +$ if f$locate("@CPPFLAG_CURL_STATICLIB@", line_in) .lt line_in_len +$ then +$ write pco "Cflags: -I${includedir} -DCURL_STATICLIB" +$ goto pc_file_loop +$ endif +$! +$pc_file_loop_end: +$ close pco +$ close pci +$! +$all_exit: +$ exit diff --git a/packages/vms/build_vms.com b/packages/vms/build_vms.com new file mode 100644 index 0000000..1b02364 --- /dev/null +++ b/packages/vms/build_vms.com @@ -0,0 +1,1038 @@ +$! BUILD_VMS.COM +$! +$! I've taken the original build_vms.com, supplied by Nico Baggus, if +$! memory serves me correctly, and made some modifications. +$! +$! SSL support is controlled by logical names. If SSL$INCLUDE is +$! defined, then it is assumed that HP's SSL product has been installed. +$! If OPENSSL is defined, but SSL$INCLUDE is not, then OpenSSL will be +$! used. If neither logical name is defined, then SSL support will not +$! be compiled/linked in. Command-line options NOHPSSL and NOSSL can be +$! specified to override the automatic SSL selection. +$! +$! Command-line Options: +$! +$! CLEAN Delete product files for this host architecture. (No +$! build done.) +$! CLEAN_ALL Delete product files for all host architectures. (No +$! build done.) +$! +$! 64 Compile with 64-bit pointers. +$! Note, you must match the pointer size that the OpenSSL +$! shared image expects. +$! Currently curl is not building properly with 64 bit pointers +$! on VMS because it is trying to cast pointers to 32 bit +$! integers and some OpenVMS library routines called by curl +$! do not yet support 64 bit pointers. +$! CCQUAL=x Add "x" to the C compiler qualifiers. +$! Default qualifiers are: +$! /standard=relaxed +$! /names=(as_is, shortened) +$! /repository=[.'arch'] +$! /nested_include_directory=none +$! /define=(_LARGEFILE=1,_USE_STD_STAT=1) (non-vax) +$! /float=ieee/ieee_mode=denorm_results (non-vax) +$! DEBUG Compile debug and nooptimize +$! Alpha/IA64 always compiles /debug. +$! Always link a debug image. +$! NOIEEE Do not use IEEE floating point. (Alpha/I64) +$! VAX must always use DFLOAT +$! NOLARGE Disable large-file support if large file support available. +$! (Non-VAX, VMS >= V7.2.) +$! NOLDAP Disable LDAP support if LDAP is available. +$! NOKERBEROS Disable Kerberos support if Kerberos is available. +$! LIST Create C compiler listings and linker maps. +$! /list/show=(expan,includ)/machine +$! FULLLIST Full detailed listing. +$! /list/show=(all, nomessages)/machine +$! NOHPSSL Don't use HP SSL, even if available. +$! Note, you must match the pointer size that the OpenSSL +$! shared image expects. This procedure will select the +$! correct HP OpenSSL image. +$! NOSSL Don't use any SSL, even if available. +$! OSSLOLB Use OpenSSL object libraries (.OLB), even if shared +$! images (.EXE) are available. +$! NOZLIB Don't use GNV$ZLIB shared image even if available. +$! REALCLEAN Delete product files for all host architectures. (No +$! build done.) Alias for CLEAN_ALL +$! +$! DCL Symbols: +$! +$! CURL_CCDEFS="c_macro_1=value1 [, c_macro_2=value2 [...]]" +$! Compile with these additional C macros defined. +$! +$! Revisions: +$! +$! 2-DEC-2003, MSK, the "original" version. +$! It works for me. Your mileage may vary. +$! 13-JAN-2004, MSK, moved this procedure to the [.packages.vms] directory +$! and updated it to do hardware dependent builds. +$! 29-JAN-2004, MSK, moved logical defines into defines.com +$! 6-FEB-2004, MSK, put in various SSL support bits +$! 9-MAR-2004, MSK, the config-vms.h* files are now copied to the lib and +$! src directories as curl_config.h. +$! 15-MAR-2004, MSK, All of the curlmsg*.* files have also been moved to +$! this build directory. They will be copied to the src +$! directory before build. The .msg file will be compiled +$! to get the .obj for messages, but the .h and .sdl files +$! are not automatically created since they partly rely on +$! the freeware SDL tool. +$! 8-FEB-2005, MSK, merged the two config-vms.h* files into one that uses +$! USE_SSLEAY to define if the target has SSL support built +$! in. Changed the cc/define parameter accordingly. +$! 11-FEB-2005, MSK, If [--.LIB]AMIGAOS.C and NWLIB.C are there, rename them +$! 23-MAR-2005, MSK, relocated cc_qual define so that DEBUG option would work +$! 25-APR-2007, STL, allow compilation in 64-bit mode. +$! 13-DEC-2009. SMS, Changed to skip unwanted source files without +$! renaming the original files. +$! Eliminated needless, persistent logical names. +$! Added CURL_CCDEFS DCL symbol for user-specified C +$! macro definitions. +$! Added CLEAN and CLEAN_ALL options. +$! Added CCQUAL option for user-specified C compiler +$! qualifiers. +$! Added IEEE option for IEEE floating point (Alpha). +$! Added LARGE option for large-file support. +$! Added OSSLOLB option, and support for OpenSSL +$! shared images. +$! Changed to put listing and map files into lisdir:. +$! Changed to avoid case confusion on ODS5 disks. +$! Added more default dev:[dir] save+restore. +$! Moved remaining "defines.com" code (back) into +$! here, eliminating the hard-coded OpenSSL nonsense. +$! Changed to use F$GETSYI("ARCH_NAME") (or +$! equivalent) to name architecture-specific product +$! file destination directory, and to create the +$! directory if needed (obviating inclusion of these +$! directories and dummy files in the distribution +$! kit). +$! Changed the "compile" subroutine to break the CC +$! command across multiple lines to avoid DCL +$! line-too-long problems. +$! Changed "vo_c" messages to show the CC qualifiers +$! once, not with every compile command. +$! 01-Jan-2013 J. Malmberg +$! VMS build procedures need to be able to work with +$! the default set to a search list, with created or +$! modified files only in the first member of the search +$! list. +$! Whitespace change to be more compatible with current +$! practices. +$! One pass option parsing instead of loop. +$! GNV ZLIB shared image support. +$! KERBEROS support where available. +$! LDAP default to on where available +$! LARGEFILE default to on where available +$! IEEE float default to on where available. +$! Generate the curl_config.h file from system inspection. +$! Linker finds ldap with out option file. +$! 13-Mar-2013, Tom Grace +$! Added missing slash in cc_full_list. +$! Removed unwanted extra quotes inside symbol tool_main +$! for non-VAX architectures that triggered link failure. +$! Replaced curl_sys_inc with sys_inc. +$! 19-Mar-2013, John Malmberg +$! symbol tool_main needs to be quoted when parse style is +$! set to extended in versions of VMS greater than 7.3-1. +$! Remove curlbuild.h generation as it should be pre-built +$! in the curl release or daily tarball. +$! 12-Jul-2013, John Malmberg +$! Adjust to find and use ZLIB from the Jean-Francois +$! Pieronne shared image and newer GNV ZLIB kit that +$! is upward compatible with Jean-Francois's kit. +$! Remove tabs from file. +$! Fixed DCL formatting as follows: +$! * Labels have no space after leading $. +$! * 1 space after $ for first level. +$! * 3 spaces after $ for second level. Line start + 4. +$! * 7 spaces after $ for third level. Line start + 8. +$! * Each level after that indents 4 characters. +$! * then/else/endif same indentation as if statement. +$! 17-Nov-2014, Michael Steve +$! Modified build to handle new location of the VTLS lib +$! source within zip archive. Not a pretty fix. +$! +$!=========================================================================== +$! +$! +$! Save the original default dev:[dir], and arrange for its restoration +$! at exit. +$!------------------------------------------------------------------------ +$ curl = "" +$ orig_def = f$environment("DEFAULT") +$ on error then goto Common_Exit +$ on control_y then goto Common_Exit +$! +$ ctrl_y = 1556 +$ proc = f$environment("PROCEDURE") +$ proc_fid = f$file_attributes(proc, "FID") +$ proc_dev = f$parse(proc, , , "DEVICE") +$ proc_dir = f$parse(proc, , , "DIRECTORY") +$ proc_name = f$parse(proc, , , "NAME") +$ proc_type = f$parse(proc, , , "TYPE") +$ proc_dev_dir = proc_dev + proc_dir +$! +$! Have to manually parse the device for a search list. +$! Can not use the f$parse() as it will return the first name +$! in the search list. +$! +$ orig_def_dev = f$element(0, ":", orig_def) + ":" +$ if orig_def_dev .eqs. "::" then orig_def_dev = "sys$disk:" +$ test_proc = orig_def_dev + proc_dir + proc_name + proc_type +$! +$! If we can find this file using the default directory +$! then we know that we should use the original device from the +$! default directory which could be a search list. +$! +$ test_proc_fid = f$file_attributes(test_proc, "FID") +$! +$ if (test_proc_fid .eq. proc_fid) +$ then +$ proc_dev_dir = orig_def_dev + proc_dir +$ endif +$! +$! +$! Verbose output message stuff. Define symbol to "write sys$output" or "!". +$! vo_c - verbose output for compile +$! vo_l - link +$! vo_o - object check +$! +$ vo_c := "write sys$output" +$ vo_l := "write sys$output" +$ vo_o := "!" +$! +$! Determine the main distribution directory ("[--]") in an +$! ODS5-tolerant (case-insensitive) way. (We do assume that the only +$! "]" or ">" is the one at the end.) +$! +$! Some non-US VMS installations report ">" for the directory delimiter +$! so do not assume that it is "]". +$! +$ orig_def_len = f$length(orig_def) +$ delim = f$extract(orig_def_len - 1, 1, orig_def) +$! +$ set default 'proc_dev_dir' +$ set default [--] +$ base_dev_dir = f$environment("default") +$ top_dev_dir = base_dev_dir - delim +$! +$! +$! +$! Define the architecture-specific product file destination directory +$! name(s). +$! +$ parse_style = "TRADITIONAL" +$ if (f$getsyi("HW_MODEL") .lt. 1024) +$ then +$ arch_name = "VAX" +$ else +$ arch_name = "" +$ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") +$ if (arch_name .eqs. "") then arch_name = "UNK" +$! +$! Extended parsing option starts with VMS 7.3-1. +$! There is no 7.4, so that simplifies the parse a bit. +$! +$ node_swvers = f$getsyi("node_swvers") +$ version_patch = f$extract(1, f$length(node_swvers), node_swvers) +$ maj_ver = f$element(0, ".", version_patch) +$ min_ver_patch = f$element(1, ".", version_patch) +$ min_ver = f$element(0, "-", min_ver_patch) +$ patch = f$element(1, "-", min_ver_patch) +$ if patch .eqs. "-" then patch = "" +$ parse_x = 0 +$ if maj_ver .ges. "8" +$ then +$ parse_x = 1 +$ else +$ if maj_ver .eqs. "7" .and. min_ver .ges. "3" .and. patch .nes. "" +$ then +$ parse_x = 1 +$ endif +$ endif +$ if parse_x +$ then +$ parse_style = f$getjpi("", "parse_style_perm") +$ endif +$ endif +$! +$ exedir = proc_dev_dir - delim + ".''arch_name'" + delim +$ lisdir = exedir +$ objdir = exedir +$! +$! When building on a search list, need to do a create to make sure that +$! the output directory exists, since the clean procedure tries to delete +$! it. +$ create/dir 'exedir'/prot=o:rwed +$! +$! Interpret command-line options. +$! +$ hpssl = 0 +$ ldap = 1 +$ list = 0 +$ full_list = 0 +$ nohpssl = 0 +$ nossl = 0 +$ openssl = 0 +$ osslolb = 0 +$ nozlib = 0 +$ nokerberos = 0 +$ cc_names = "/names=(shortened, as_is)/repository='exedir' +$ cc_defs = "HAVE_CONFIG_H=1" +$ cc_list = "/list='objdir'/show=(expan, includ)/machine +$ cc_full_list = "/list='objdir'/show=(all, nomessages)/machine +$ link_qual = "" +$ if arch_name .eqs. "VAX" +$ then +$ cc_debug = "/nodebug/optimize" +$ !cc_defs = cc_defs + "" +$ cc_float = "" +$ cc_large = "" +$ else +$ cc_debug = "/debug/optimize" +$ cc_defs = cc_defs + ",_USE_STD_STAT" +$ cc_float = "/float=ieee/ieee_mode=denorm_results" +$ cc_large = ",_LARGEFILE" +$ endif +$ cc_qual1 = "" +$ cc_qual2 = "" +$ if (f$type(CURL_CCDEFS) .nes. "") +$ then +$ CURL_CCDEFS = f$edit(CURL_CCDEFS, "TRIM") +$ cc_defs = cc_defs + ", " + CURL_CCDEFS +$ endif +$ msg_qual = "/object = ''objdir'" +$ ssl_opt = "" +$! +$! Allow arguments to be grouped together with comma or separated by spaces +$! Do no know if we will need more than 8. +$ args = "," + p1 + "," + p2 + "," + p3 + "," + p4 + "," +$ args = args + p5 + "," + p6 + "," + p7 + "," + p8 + "," +$! +$! Provide lower case version to simplify parsing. +$ args_lower = f$edit(args, "LOWERCASE,COLLAPSE") +$! +$ args_len = f$length(args) +$ args_lower_len = f$length(args_lower) +$! +$ clean = 0 +$ if f$locate(",clean,", args_lower) .lt. args_lower_len +$ then +$ clean = 1 +$ endif +$ clean_all = 0 +$ if f$locate(",clean_all,", args_lower) .lt. args_lower_len +$ then +$ clean = 1 +$ clean_all = 1 +$ endif +$ if f$locate(",realclean,", args_lower) .lt. args_lower_len +$ then +$ clean = 1 +$ clean_all = 1 +$ endif +$! +$ if clean .ne. 0 +$ then +$ prods = "''exedir'*.*;*" +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ prods = proc_dev_dir + arch_name + ".DIR;1" +$ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ file = "[]config_vms.h" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[]config.h" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[]curl-config." +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[]libcurl.pc" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[.lib.cxx_repository]cxx$demangler_db." +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[.src.cxx_repository]cxx$demangler_db." +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[.lib]config_vms.h" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]curl_crtl_init" +$ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* +$ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* +$ file = "[...]gnv$curlmsg" +$ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* +$ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* +$ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* +$ file = "[...]curlmsg" +$ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* +$ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* +$ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* +$ file = "[...]report_openssl_version" +$ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* +$ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* +$ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* +$ file = "[...]hp_ssl_release_info.txt" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]gnv_libcurl_xfer.mar_exact" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]gnv_libcurl_xfer" +$ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* +$ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* +$ if f$search("''file'.opt") .nes. "" then delete/log 'file'.opt;* +$ file = "[...]curl-*_original_src.bck" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]curl_d-*_original_src.bck" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]curl-*_vms_src.bck" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]curl_d-*_vms_src.bck" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]curl-*.release_notes" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]curl_d-*.release_notes" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]*curl*.pcsi$desc" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]*curl_d*.pcsi$desc" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]*curl*.pcsi$text" +$ if f$search(file) .nes. "" then delete/log 'file';* +$ file = "[...]*curl_d*.pcsi$text" +$ if f$search(file) .nes. "" then delete/log 'file';* +$! +$ if clean_all .eq. 0 then goto Common_Exit +$ endif +$! +$! +$ if clean_all .ne. 0 +$ then +$ file = "[...]gnv$libcurl" +$ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* +$ if f$search("''file'.map") .nes. "" then delete/log 'file'.map;* +$ if f$search("''file'.dsf") .nes. "" then delete/log 'file'.dsf;* +$ file = "[.src]curl" +$ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* +$ if f$search("''file'.map") .nes. "" then delete/log 'file'.map;* +$ if f$search("''file'.dsf") .nes. "" then delete/log 'file'.dsf;* +$ prods = proc_dev_dir - delim + ".ALPHA" + delim + "*.*;*" +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ prods = proc_dev_dir + "ALPHA" + ".DIR;1" +$ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ prods = proc_dev_dir - delim + ".IA64" + delim + "*.*;*" +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ prods = proc_dev_dir + "IA64" + ".DIR;1" +$ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ prods = proc_dev_dir - delim + ".VAX" + delim + "*.*;*" +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ prods = proc_dev_dir + "VAX"+ ".DIR;1" +$ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' +$ if (f$search(prods) .nes. "") then delete /log 'prods' +$ file = "[...]macro32_exactcase" +$ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* +$ if f$search("''file'.jnl") .nes. "" then delete/log 'file'.jnl;* +$ goto Common_Exit +$ endif +$! +$ build_64 = 0 +$ if f$locate(",64,", args_lower) .lt. args_lower_len +$ then +$ cc_qual1 = cc_qual1 + " /POINTER = 64" +$ build_64 = 1 +$ endif +$! +$ args_loc = f$locate(",ccqual=", args_lower) +$ if args_loc .lt. args_lower_len +$ then +$ arg = f$extract(args_loc + 1, args_lower_len, args_lower) +$ arg_val = f$element(0, ",", arg) +$ cc_qual2 = f$element(1, "=", arg_val); +$ endif +$! +$! On Alpha/IA64 no size penalty for compiling /debug/optimize +$! by default. +$ if f$locate(",debug,", args_lower) .lt. args_lower_len +$ then +$ cc_debug = "/debug/nooptimize" +$ endif +$! +$! We normally want IEEE float if it is available. Programs that are +$! calling libcurl will typically prefer IEEE behavior, unless on the +$! VAX where we have no choice. +$! +$ if f$locate(",noieee,", args_lower) .lt. args_lower_len +$ then +$ cc_float = "" +$ endif +$! +$! Normally we want large file if it is available. +$ if f$locate(",nolarge,", args_lower) .lt. args_lower_len +$ then +$ write sys$output "Handling of large files disabled." +$ cc_large = "" +$ endif +$ if cc_large .nes. "" +$ then +$ cc_defs = cc_defs + cc_large +$ endif +$! +$ if f$locate(",noldap,", args_lower) .lt. args_lower_len +$ then +$ ldap = 0 +$ endif +$! +$ if f$locate(",list,", args_lower) .lt. args_lower_len +$ then +$ list = 1 +$ endif +$ if f$locate(",fulllist,", args_lower) .lt. args_lower_len +$ then +$ list = 1 +$ full_list = 1 +$ endif +$! +$ if f$locate(",nohpssl,", args_lower) .lt. args_lower_len +$ then +$ nohpssl = 1 +$ endif +$! +$ if f$locate(",nossl,", args_lower) .lt. args_lower_len +$ then +$ nossl = 1 +$ endif +$! +$ if f$locate(",osslolb,", args_lower) .lt. args_lower_len +$ then +$ osslolb = 1 +$ endif +$! +$ if f$locate(",nozlib,", args_lower) .lt. args_lower_len +$ then +$ nozlib = 1 +$ endif +$! +$ if f$locate(",nokerberos,", args_lower) .lt. args_lower_len +$ then +$ nokerberos = 1 +$ endif +$! +$! +$! CC /LIST, LINK /MAP, and MESSAGE /LIST are defaults in batch mode, +$! so be explicit when they're not desired. +$! +$ +$ if list .eq. 0 +$ then +$ cc_qual1 = cc_qual1 + "/nolist" +$ msg_qual = msg_qual + "/nolist" +$ else +$ msg_qual = msg_qual + "/list='objdir'" +$ if (full_list .ne. 0) +$ then +$ cc_qual1 = cc_qual1 + cc_full_list +$ else +$ cc_qual1 = cc_qual1 + cc_list +$ endif +$ endif +$ cc_qual1 = cc_qual1 + cc_names + cc_float + cc_debug +$! +$! Create product directory, if needed. +$! +$ if (f$search(proc_dev_dir + arch_name + ".DIR;1") .eqs. "") +$ then +$ create /directory 'exedir' +$ endif +$! +$! Detect available (but not prohibited) SSL software. +$! +$ libsslshr_line = "" +$ libcryptoshr_line = "" +$ if (.not. nossl) +$ then +$ if (f$trnlnm("OPENSSL") .nes. "") +$ then +$! cc_defs = cc_defs + ", USE_OPENSSL=1" +$ if ((f$trnlnm("SSL$INCLUDE") .nes. "") .and. (.not. nohpssl)) +$ then +$! Use HP SSL. +$ hpssl = 1 +$! +$! Older SSL only has lib*_shr32 images +$!----------------------------------------------- +$ libsslshr = "sys$share:ssl$libssl_shr" +$ if (f$search("''libsslshr'.exe") .eqs. "") .or. (.not. build_64) +$ then +$ libsslshr = libsslshr + "32" +$ endif +$ libcryptoshr = "sys$share:ssl$libcrypto_shr" +$ if (f$search("''libcryptoshr'.exe") .eqs. "") .or. (.not. build_64) +$ then +$ libcryptoshr = libcryptoshr + "32" +$ endif +$ libsslshr_line = "''libsslshr'.exe/share" +$ libcryptoshr_line = "''libcryptoshr'.exe/share" +$ else +$! Use OpenSSL. Assume object libraries, unless shared images +$! are found (and not prohibited). +$! TODO: We do not know how to automatically choose based on the +$! pointer size. +$! +$ openssl = 1 +$ libsslshr_line = "ssllib:libssl.olb/lib" +$ libcryptoshr_line = "ssllib:libcrypto.olb/lib" +$ ssl_opt = ", ssllib:libssl.olb /library" + - + ", ssllib:libcrypto.olb /library" +$ if (osslolb .eq. 0) +$ then + if ((f$search("ssllib:ssl_libcrypto.exe") .nes. "") .and. - + (f$search("ssllib:ssl_libssl.exe") .nes. "")) +$ then +$! OpenSSL shared images with "SSL_xxx.EXE names. +$ openssl = 2 +$ libsslshr_line = "ssllib:ssl_libssl_shr.exe/share" +$ libcryptoshr_line = "ssllib:ssl_libcrypto_shr.exe/share" +$ else +$ if ((f$search("ssllib:libcrypto.exe") .nes. "") .and. - + (f$search("ssllib:libssl.exe") .nes. "")) +$ then +$! OpenSSL shared images with "xxx.EXE names. +$ openssl = 3 +$ libsslshr_line = "ssllib:libssl_shr.exe/share" +$ libcryptoshr_line = "ssllib:libcrypto_shr.exe/share" +$ endif +$ endif +$ endif +$ endif +$ endif +$ endif +$! +$! LDAP. +$! +$ if f$search("SYS$SHARE:LDAP$SHR.EXE") .eqs. "" +$ then +$ ldap = 0 +$ endif +$ if (ldap .eq. 0) +$ then +$! cc_defs = cc_defs + ", CURL_DISABLE_LDAP=1" +$ else +$ 'vo_c' "%CURL-I-BLDHPLDAP, building with HP LDAP support" +$ endif +$! +$! KERBEROS +$ gssrtlshr_line = "" +$ try_shr = "sys$share:gss$rtl" +$ if f$search("''try_shr'.exe") .eqs. "" +$ then +$ nokerberos = 1 +$ endif +$ curl_sys_krbinc = "" +$ if nokerberos .eq. 0 +$ then +$ 'vo_c' "%CURL-I-BLDHPKERBEROS, building with HP KERBEROS support" +$ curl_sys_krbinc = "sys$sysroot:[kerberos.include]" +$ gssrtlshr_line = "''try_shr'/share" +$ endif +$! +$! +$! LIBZ +$ libzshr_line = "" +$ try_shr = "gnv$libzshr" +$ if build_64 +$ then +$! First look for 64 bit +$ if f$search("''try_shr'64") .eqs. "" +$ then +$! Second look for the J.F. Pieronne 64 bit shared image +$ try_shr = "LIBZ_SHR64" +$ if f$search(try_shr) .eqs. "" then nozlib = 1 +$ endif +$ else +$! First look for 32 bit +$ if f$search("''try_shr'32") .eqs. "" +$ then +$! Second look for old 32 bit image +$ if f$search(try_shr) .eqs. "" +$ then +$! Third look for the J.F. Pieronne 32 bit shared image +$ try_shr = "LIBZ_SHR32" +$ if f$search(try_shr) .eqs. "" then nozlib = 1 +$ endif +$ endif +$ endif +$ if f$search(try_shr) .eqs. "" +$ then +$ nozlib = 1 +$ endif +$ curl_sys_zlibinc = "" +$ if nozlib .eq. 0 +$ then +$ libzshr_line = "''try_shr'/share" +$ if f$locate("LIBZ", try_shr) .eq. 0 +$ then +$ 'vo_c' "%CURL-I-BLDJFPLIBZ, building with JFP LIBZ support" +$ curl_sys_zlibinc = "LIBZ:" +$ else +$ 'vo_c' "%CURL-I-BLDGNVLIBZ, building with GNV LIBZ support" +$ curl_sys_zlibinc = "GNV$ZLIB_INCLUDE:" +$ endif +$ endif +$! +$! Form CC qualifiers. +$! +$ cc_defs = "/define = (''cc_defs')" +$ cc_qual2 = cc_qual2 + " /object = ''objdir'" +$ cc_qual2 = cc_qual2 + "/nested_include_directory=none" +$! +$ 'vo_c' "CC opts:", - + " ''cc_defs'", - + " ''cc_qual1'", - + " ''cc_qual2'" +$! +$! Inform the victim of our plans. +$! +$ if (hpssl) +$ then +$ 'vo_c' "%CURL-I-BLDHPSSL, building with HP SSL support" +$ else +$ if (openssl .ne. 0) +$ then +$ if (openssl .eq. 1) +$ then +$ 'vo_c' - + "%CURL-I-BLDOSSL_OLB, building with OpenSSL (object library) support" +$ else +$ 'vo_c' - + "%CURL-I-BLDOSSL_EXE, building with OpenSSL (shared image) support" +$ endif +$ else +$ 'vo_c' "%CURL-I-BLDNOSSL, building with NO SSL support" +$ endif +$ endif +$! +$! Announce destination and SSL directories. +$! +$ 'vo_c' " OBJDIR = ''objdir'" +$ 'vo_c' " EXEDIR = ''exedir'" +$! +$ if (openssl .ne. 0) +$ then +$ ssllib = f$trnlnm("ssllib") +$ if (ssllib .eqs. "") +$ then +$ ssllib = "(undefined)" +$ endif +$ 'vo_c' " SSLLIB = ''ssllib'" +$! +$! TODO: Why are we translating the logical name? +$! The logical aname used to find the shared image should just be used +$! as translating it could result in the wrong location at run time. +$ if (openssl .eq. 1) +$ then +$ ossl_lib1 = f$trnlnm("ssllib")+ "LIBSSL.OLB" +$ ossl_lib2 = f$trnlnm("ssllib")+ "LIBCRYPTO.OLB" +$ msg = "object libraries" +$ else +$ if (openssl .eq. 2) +$ then +$ ossl_lib1 = f$trnlnm("ssllib")+ "SSL_LIBSSL.EXE" +$ ossl_lib2 = f$trnlnm("ssllib")+ "SSL_LIBCRYPTO.EXE" +$ else +$ ossl_lib1 = f$trnlnm("ssllib")+ "LIBSSL.EXE" +$ ossl_lib2 = f$trnlnm("ssllib")+ "LIBCRYPTO.EXE" +$ endif +$ msg = "shared images" +$ endif +$ if ((f$search(ossl_lib1) .eqs. "") .or. - + (f$search(ossl_lib2) .eqs. "")) +$ then +$ write sys$output "Can't find OpenSSL ''msg':" +$ write sys$output " ''ossl_lib1'" +$ write sys$output " ''ossl_lib2'" +$ goto Common_Exit +$ endif +$ endif +$! +$! Define the "curl" (process) logical name for "#include ". +$! +$ curl = f$trnlnm("curl", "LNM$PROCESS") +$ if (curl .nes. "") +$ then +$ write sys$output "" +$ write sys$output - + "Process logical name ""curl"" is already defined, but this procedure" +$ write sys$output - + "would override that definition. Use a command like" +$ write sys$output - + " deassign /process curl" +$ write sys$output - + "to cancel that logical name definition, and then and re-run this procedure." +$ write sys$output "" +$ goto Common_Exit +$ endif +$ curl_logical = top_dev_dir + ".include.curl" + delim +$ curl_sys_inc2 = curl_logical +$ curl_sys_inc1 = top_dev_dir + ".include" + delim +$! define curl 'top_dev_dir'.include.curl'delim' +$! +$! Generate config file into the product directory. +$! +$! call MoveIfDiff [.lib]config-vms.h 'objdir'curl_config.h +$! +$ conf_params = "" +$ if nossl .ne. 0 then conf_params = conf_params + ",nossl" +$ if nohpssl .ne. 0 then conf_params = conf_params + ",nohpssl," +$ if ldap .eq. 0 then conf_params = conf_params + ",noldap," +$ if nozlib .ne. 0 then conf_params = conf_params + ",nozlib," +$ if nokerberos .ne. 0 then conf_params = conf_params + ",nokerberos" +$ conf_params = conf_params - "," +$! +$! +$ new_conf = f$search("''objdir'curl_config.h") +$ if new_conf .eqs. "" +$ then +$! set ver +$ write sys$output "Generating curl custom config_vms.h" +$ @'proc_dev_dir'generate_config_vms_h_curl.com ''conf_params' +$! +$ write sys$output "Generating curl_config.h" +$ conf_in = f$search("[.lib]curl_config*.*in") +$ if conf_in .eqs. "" +$ then +$ write sys$output "Can not find [.lib]curl_config*.*in file!" +$ goto common_exit +$ endif +$ @'proc_dev_dir'config_h.com 'conf_in' +$ copy config.h 'objdir'curl_config.h +$ delete config.h; +$! set nover +$ endif +$! +$! +$ on control_y then goto Common_Exit +$! +$ set default 'proc_dev_dir' +$ sys_inc = "''curl_sys_inc1', ''curl_sys_inc2', ''curl_logical'" +$ if curl_sys_krbinc .nes. "" +$ then +$ sys_inc = sys_inc + ",''curl_sys_krbinc'" +$ endif +$ if curl_sys_zlibinc .nes. "" +$ then +$ sys_inc = sys_inc + ",''curl_sys_zlibinc'" +$ endif +$! Build LIB +$ cc_include = "/include=([-.lib],[-.lib.vtls],[-.packages.vms]" +$ cc_include = cc_include + ",[-.packages.vms.''arch_name'])" +$ call build "[--.lib]" "*.c" "''objdir'CURLLIB.OLB" "amigaos, nwlib, nwos" +$ if ($status .eq. ctrl_y) then goto Common_Exit +$! Build VTLS +$ cc_include = "/include=([--.lib.vtls],[--.lib],[--.src]" +$ cc_include = cc_include + ",[--.packages.vms],[--.packages.vms.''arch_name'])" +$ call build "[--.lib.vtls]" "*.c" "''objdir'CURLLIB.OLB" "amigaos, nwlib, nwos" +$! Build SRC +$ cc_include = "/include=([-.src],[-.lib],[-.lib.vtls]" +$ cc_include = cc_include + ",[-.packages.vms],[-.packages.vms.''arch_name'])" +$ call build "[--.src]" "*.c" "''objdir'CURLSRC.OLB" +$ if ($status .eq. ctrl_y) then goto Common_Exit +$! Build MSG +$ call build "[]" "*.msg" "''objdir'CURLSRC.OLB" +$ if ($status .eq. ctrl_y) then goto Common_Exit +$! +$! +$ if (openssl .ne. 0) +$ then +$ if (openssl .eq. 1) +$ then +$ 'vo_l' "%CURL-I-LINK_OSSL, linking with OpenSSL (object library)" +$ else +$ 'vo_l' "%CURL-I-LINK_HPSSL, linking with OpenSSL (shared image)" +$ endif +$ else +$ if (hpssl) +$ then +$ 'vo_l' "%CURL-I-LINK_HPSSL, linking with HP SSL" +$ else +$ 'vo_l' "%CURL-I-LINK_NOSSL, linking with NO SSL support" +$ endif +$ endif +$! +$! +$! GNV helper files for building the test curl binary. +$!----------------------------------------------- +$ create 'exedir'gnv$curl.opt +$ open/append opt 'exedir'gnv$curl.opt +$ if libzshr_line .nes. "" then write opt libzshr_line +$ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line +$ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line +$ if libsslshr_line .nes. "" then write opt libsslshr_line +$ close opt +$! +$! +$! Create the libcurl +$!------------------------------------------------------ +$ create 'exedir'gnv_libcurl_linker.opt +$ open/append opt 'exedir'gnv_libcurl_linker.opt +$ if libzshr_line .nes. "" then write opt libzshr_line +$ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line +$ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line +$ if libsslshr_line .nes. "" then write opt libsslshr_line +$ close opt +$! +$! +$! If we are not on VAX, then we want the debug symbol table in +$! a separate file. +$! VAX needs the tool_main unquoted in uppercase, +$! Alpha and IA64 need tool_main quoted in exact case when parse style is +$! extended. +$ link_dsf1 = "" +$ link_dsf2 = "" +$ tool_main = "tool_main" +$ if arch_name .nes. "VAX" +$ then +$ if parse_style .eqs. "EXTENDED" +$ then +$ tool_main = """tool_main""" +$ endif +$ link_dsf1 = "/dsf=" + exedir + "CURL.DSF" +$ link_dsf2 = "/dsf=" + exedir + "CURL_DEBUG.DSF" +$ endif +$ if (list .eq. 0) +$ then +$ link_map1 = "/nomap" +$ link_map2 = "/nomap" +$ else +$ link_map1 = "/map=" + exedir + "CURL.MAP" +$ link_map2 = "/map=" + exedir + "CURL_DEBUG.MAP" +$ endif +$! +$! +$! Make a normal image. +$ set ver +$ link 'link_map1' 'link_dsf1' /executable = 'exedir'CURL.EXE - + 'objdir'curlsrc.olb /library /include = ('tool_main', curlmsg), - + 'objdir'curllib.olb /library, - + 'exedir'gnv$curl.opt/opt +$! +$! Also make a debug copy. +$ link/debug 'link_map2' 'link_dsf2' /executable = 'exedir'CURL_DEBUG.EXE - + 'objdir'curlsrc.olb /library /include = ('tool_main', curlmsg), - + 'objdir'curllib.olb /library, - + 'exedir'gnv$curl.opt/opt +$ set nover +$! +$ goto Common_Exit +$! +$! Subroutine to build everything with a filetype passed in via P2 in +$! the directory passed in via P1 and put it in the object library named +$! via P3. Exclude items in P4. +$! +$build: subroutine +$ build_def = f$environment("default") +$ on control_y then goto EndLoop ! SS$_CONTROLY +$ sts = 1 ! SS$_NORMAL. +$! set noon +$ set default 'p1' +$ search = "sys$disk:" + p2 +$ reset = f$search("reset") +$ if f$search( p3) .eqs. "" +$ then +$ librarian /create /object 'p3' +$ endif +$ reject_list__ = "," + f$edit(p4, "COLLAPSE, UPCASE") + "," +$ reject_list___len = f$length(reject_list__) +$ reset = f$search( "reset", 1) +$Loop: +$ file = f$search( search, 1) +$ if file .eqs. "" then goto EndLoop +$! Skip a name if it's in the P4 exclusion list. +$ if (p4 .nes. "") +$ then +$ name__ = "," + - + f$edit(f$parse(file, , , "NAME", "SYNTAX_ONLY"), "UPCASE") + - + "," +$ if (f$locate(name__, reject_list__) .lt. reject_list___len) +$ then +$ goto Loop +$ endif +$ endif +$ objfile = f$parse("''objdir'.OBJ;", file) +$ obj = f$search(objfile, 2) +$ if (obj .nes. "") +$ then +$ if (f$cvtime(f$file(file,"rdt")) .gts. f$cvtime(f$file(obj,"rdt"))) +$ then +$ call compile 'file' +$ sts = $status +$ if .not. sts +$ then +$ goto EndLoop +$ endif +$ librarian /object 'p3' 'objfile' +$ else +$ 'vo_o' "%CURL-I-OBJUTD, ", objfile, " is up to date" +$ endif +$ else +$ 'vo_o' "%CURL-I-OBJDNE, ", file, " does not exist" +$ call compile 'file' +$ sts = $status +$ if .not. sts +$ then +$ goto EndLoop +$ endif +$ librarian /object 'p3' 'objfile' +$ endif +$ goto Loop +$EndLoop: +$!!! purge +$ set default 'build_def' +$ exit 'sts' +$ endsubroutine ! Build +$! +$! Based on the file TYPE, do the right compile command. +$! Only C and MSG supported. +$! +$compile: subroutine +$ on control_y then return ctrl_y ! SS$_CONTROLY +$! set noon +$ file = p1 +$ qual = p2+ p3+ p4+ p5+ p6+ p7+ p8 +$ typ = f$edit(f$parse(file, , , "TYPE"), "UPCASE") - "." +$ if (typ .eqs. "C") +$ then +$ 'vo_c' "CC (opts) ", file +$ define/user curl 'curl_logical' +$ if curl_sys_krbinc .nes. "" then define/user gssapi 'curl_sys_krbinc' +$ define/user decc$system_include 'sys_inc' +$ CC 'cc_defs' - + 'cc_qual1' - + 'cc_qual2' - + 'cc_include' - + 'file' +$ else +$ cmd_msg = "MESSAGE " + msg_qual +$ x = cmd_'typ' +$ 'vo_c' x, " ", file +$ 'x' 'file' +$ endif +$ ENDSUBROUTINE ! Compile +$! +$! Do a diff of the file specified in P1 with that in P2. If different +$! copy P1 to P2. This also covers if P2 doesn't exist, but not if P2 +$! is an invalid filespec. +$! +$MoveIfDiff: subroutine +$ set NoOn +$ define /user_mode sys$error nl: +$ define /user_mode sys$output nl: +$ differences 'p1' 'p2' +$ status = $status +$ if (status .ne. %X006C8009) ! if status is not "no diff" +$ then +$ copy 'p1' 'p2' +$ purge /nolog 'p2' +$ endif +$ on control_y then return ctrl_y ! SS$_CONTROLY +$ ENDSUBROUTINE ! MoveIfDiff +$! +$Common_Exit: +$ set default 'orig_def' +$ exit diff --git a/packages/vms/clean_gnv_curl.com b/packages/vms/clean_gnv_curl.com new file mode 100644 index 0000000..198c0de --- /dev/null +++ b/packages/vms/clean_gnv_curl.com @@ -0,0 +1,242 @@ +$! File: clean_gnv_curl.COM +$! +$! The GNV environment leaves behind some during the configure and build +$! procedure that need to be cleaned up. +$! +$! The default is to remove all the left over stuff from running the +$! configure script and to remove all intermediate binary files. +$! +$! This should be run with no parameters after the gnv_curl_configure.sh +$! script is run. +$! +$! Parameter P1: REALCLEAN +$! This removes all build products and brings the environment back to +$! the point where the gnv_curl_configure.sh procedure needs to be run again. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!============================================================================ +$! +$! Save this so we can get back. +$ default_dir = f$environment("default") +$! +$! +$! Move to where the base directory is. +$ set def [--] +$! +$! +$ file = "sys$login:sh*." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "sys$login:make*." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]confdefs.h" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]conftest.dsf" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]conftest.lis" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]conftest.sym" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$! +$ file = "lcl_root:[.conf*...]*.*" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "lcl_root:[]conf*.dir +$ if f$search(file) .nes. "" then delete 'file';* +$! +$! +$ file = "lcl_root:[.lib]*.out" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "lcl_root:[.lib]*.o" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$! +$ file = "lcl_root:[.lib]*.lis" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.src]*.lis" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.src]cc_temp*." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.src]*.dsf" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.src]*.o" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.lib]ar*." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.lib]cc_temp*." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]*.lo" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]*.a" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]*.la" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]*.lai" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]curl-*_original_src.bck" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]curl_d-*_original_src.bck" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]curl-*_vms_src.bck" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]curl_d-*_vms_src.bck" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]curl-*.release_notes" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]curl_d-*.release_notes" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]*-curl-*.pcsi$desc" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]*-curl_d-*.pcsi$desc" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]*-curl-*.pcsi$text" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]*-curl_d-*.pcsi$text" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$!====================================================================== +$! +$ if p1 .nes. "REALCLEAN" then goto all_exit +$! +$ file = "lcl_root:[...]*.obj" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]Makefile." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]libtool." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]*.lis" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]POTFILES." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]libcurl.pc" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]curl-config." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]config.h" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.src]config.h" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.src]curl." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.tests]configurehelp.pm" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.lib]config.h" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.lib]curl_config.h" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.lib]libcurl.vers" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.lib]libcurl.plist" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]ca-bundle.h" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]config.log" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]config.status" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]conftest.dangle" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]CXX$DEMANGLER_DB." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[]stamp-h1." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]stamp-h1." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]stamp-h2." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]stamp-h3." +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.lib]*.a" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]*.spec" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]gnv$*.*" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[...]gnv*.opt" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]macro32_exactcase.exe" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]report_openssl_version.exe" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.packages.vms]hp_ssl_release_info.txt" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$ file = "lcl_root:[.src]curl.exe" +$ if f$search(file) .nes. "" then delete 'file';* +$! +$all_exit: +$! +$! Put the default back. +$!----------------------- +$ set def 'default_dir' +$! +$ exit diff --git a/packages/vms/compare_curl_source.com b/packages/vms/compare_curl_source.com new file mode 100644 index 0000000..3f7542d --- /dev/null +++ b/packages/vms/compare_curl_source.com @@ -0,0 +1,363 @@ +$! Compare_curl_source.com +$! +$! This procedure compares the files in two directories and reports the +$! differences. It is customized for the vmsports repository layout. +$! +$! It needs to be customized to the local site directories. +$! +$! This is used by me for these purposes: +$! 1. Compare the original source of a project with an existing +$! VMS port. +$! 2. Compare the checked out repository of a project with the +$! the local working copy to make sure they are in sync. +$! 3. Keep a copy directory up to date. The third is needed by +$! me because VMS Backup can create a saveset of files from a +$! NFS mounted volume. +$! +$! First the files in the original source directory which is assumed to be +$! under source code control are compared with the copy directory. +$! +$! Then the files are are only in the copy directory are listed. +$! +$! The result will five diagnostics about of files: +$! 1. Files that are not generation 1. +$! 2. Files missing in the copy directory. +$! 3. Files in the copy directory not in the source directory. +$! 4. Files different from the source directory. +$! 5. Files that VMS DIFF can not process. +$! +$! This needs to be run on an ODS-5 volume. +$! +$! If UPDATE is given as a second parameter, files missing or different in the +$! copy directory will be updated. +$! +$! By default: +$! The directory src_root:[project_name] will be translated to something like +$! DISK:[dir.dir.reference.project_name] and this will be used +$! to calculate DISK:[dir.dir.vms_source.project_name] for the VMS specific +$! source directory. +$! +$! The copy directory is vms_root:[project_name] +$! The UPDATE parameter is ignored. +$! +$! This setting is used to make sure that the working vms directory +$! and the repository checkout directory have the same contents. +$! +$! If P1 is "SRCBCK" then this +$! The source directory tree is: src_root:[project_name] +$! The copy directory is src_root1:[project_name] +$! +$! src_root1:[project_name] is used by me to work around that VMS backup will +$! not use NFS as a source directory so I need to make a copy. +$! +$! This is to make sure that the backup save set for the unmodified +$! source is up to date. +$! +$! If your repository checkout is not on an NFS mounted volume, you do not +$! need to use this option or have the logical name src_root1 defined. +$! +$! If P1 is "VMSBCK" then this changes the two directories: +$! The source directory is vms_root:[project_name] +$! The copy directory is vms_root1:[project_name] +$! +$! vms_root:[project_name] is where I do the VMS specific edits. +$! vms_root1:[project_name] is used by me to work around that VMS backup will +$! not use NFS as a source directory so I need to make a copy. +$! +$! This is to make sure that the backup save set for the unmodified +$! source is up to date. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!========================================================================== +$! +$! Update missing/changed files. +$ update_file = 0 +$ if (p2 .eqs. "UPDATE") +$ then +$ update_file = 1 +$ endif +$! +$ myproc = f$environment("PROCEDURE") +$ myprocdir = f$parse(myproc,,,"DIRECTORY") - "[" - "]" - "<" - ">" +$ myprocdir = f$edit(myprocdir, "LOWERCASE") +$ mydefault = f$environment("DEFAULT") +$ mydir = f$parse(mydefault,,,"DIRECTORY") +$ mydir = f$edit(mydir, "LOWERCASE") +$ odelim = f$extract(0, 1, mydir) +$ mydir = mydir - "[" - "]" - "<" - ">" +$ mydev = f$parse(mydefault,,,"DEVICE") +$! +$ ref = "" +$ if P1 .eqs. "" +$ then +$ ref_base_dir = myprocdir +$ wrk_base_dir = mydir +$ update_file = 0 +$ resultd = f$parse("src_root:",,,,"NO_CONCEAL") +$ resultd = f$edit(resultd, "LOWERCASE") +$ resultd = resultd - "][" - "><" - ".;" - ".." +$ resultd_len = f$length(resultd) - 1 +$ delim = f$extract(resultd_len, 1, resultd) +$ ref_root_base = mydir + delim +$ resultd = resultd - ref_root_base - "reference." + "vms_source." +$ ref = resultd + ref_base_dir +$ wrk = "VMS_ROOT:" + odelim + wrk_base_dir +$ resultd_len = f$length(resultd) - 1 +$ resultd = f$extract(0, resultd_len, resultd) + delim +$ ref_root_dir = f$parse(resultd,,,"DIRECTORY") +$ ref_root_dir = f$edit(ref_root_dir, "LOWERCASE") +$ ref_root_dir = ref_root_dir - "[" - "]" +$ ref_base_dir = ref_root_dir + "." + ref_base_dir +$ endif +$! +$ if p1 .eqs. "SRCBCK" +$ then +$ ref_base_dir = "curl" +$ wrk_base_dir = "curl" +$ ref = "src_root:[" + ref_base_dir +$ wrk = "src_root1:[" + wrk_base_dir +$ if update_file +$ then +$ if f$search("src_root1:[000000]curl.dir") .eqs. "" +$ then +$ create/dir/prot=o:rwed src_root1:[curl] +$ endif +$ endif +$ endif +$! +$! +$ if p1 .eqs. "VMSBCK" +$ then +$ ref_base_dir = "curl" +$ wrk_base_dir = "curl" +$ ref = "vms_root:[" + ref_base_dir +$ wrk = "vms_root1:[" + wrk_base_dir +$ if update_file +$ then +$ if f$search("vms_root1:[000000]curl.dir") .eqs. "" +$ then +$ create/dir/prot=o:rwed vms_root1:[curl] +$ endif +$ endif +$ endif +$! +$! +$ if ref .eqs. "" +$ then +$ write sys$output "Unknown compare type specified!" +$ exit 44 +$ endif +$! +$! +$! Future - check the device types involved for the +$! the syntax to check. +$ ODS2_SYNTAX = 0 +$ NFS_MANGLE = 0 +$ PWRK_MANGLE = 0 +$! +$ vax = f$getsyi("HW_MODEL") .lt. 1024 +$ if vax +$ then +$ ODS2_SYNTAX = 1 +$ endif +$! +$ report_missing = 1 +$! +$ if .not. ODS2_SYNTAX +$ then +$ set proc/parse=extended +$ endif +$! +$loop: +$ ref_spec = f$search("''ref'...]*.*;",1) +$ if ref_spec .eqs. "" then goto loop_end +$! +$ ref_dev = f$parse(ref_spec,,,"DEVICE") +$ ref_dir = f$parse(ref_spec,,,"DIRECTORY") +$ ref_dir = f$edit(ref_dir, "LOWERCASE") +$ ref_name = f$parse(ref_spec,,,"NAME") +$ ref_type = f$parse(ref_spec,,,"TYPE") +$! +$! +$ rel_path = ref_dir - "[" - ref_base_dir +$! rel_path_len = f$length(rel_path) - 1 +$! delim = f$extract(rel_path_len, 1, rel_path) +$! rel_path = rel_path - ".]" - ".>" - "]" - ">" +$! rel_path = rel_path + delim +$! +$ if ODS2_SYNTAX +$ then +$! if rel_path .eqs. ".examples.scripts^.noah]" +$! then +$! rel_path = ".examples.scripts_noah]" +$! endif +$! if rel_path .eqs. ".examples.scripts^.v2]" +$! then +$! rel_path = ".examples.scripts_v2]" +$! endif +$ endif +$! +$ wrk_path = wrk + rel_path +$! +$ ref_name_type = ref_name + ref_type +$! +$ if ODS2_SYNTAX +$ then +$ endif +$! +$ wrk_spec = wrk_path + ref_name_type +$! +$! +$ wrk_chk = f$search(wrk_spec, 0) +$ if wrk_chk .eqs. "" +$ then +$ if report_missing +$ then +$ write sys$output "''wrk_spec' is missing" +$ endif +$ if update_file +$ then +$ copy/log 'ref_spec' 'wrk_spec' +$ endif +$ goto loop +$ endif +$! +$ wrk_name = f$parse(wrk_spec,,,"NAME") +$ wrk_type = f$parse(wrk_spec,,,"TYPE") +$ wrk_fname = wrk_name + wrk_type" +$ ref_fname = ref_name + ref_type +$! +$ if ref_fname .nes. wrk_fname +$ then +$ write sys$output "''wrk_spc' wrong name, should be ""''ref_fname'""" +$ endif +$! +$ ref_type = f$edit(ref_type, "UPCASE") +$ if ref_type .eqs. ".DIR" then goto loop +$! +$ if ODS2_SYNTAX +$ then +$ ref_fname = f$edit(ref_fname, "LOWERCASE") +$ endif +$! +$! These files are in the wrong format for VMS diff, and we don't change them. +$ ref_skip = 0 +$ if ref_type .eqs. ".PDF" then ref_skip = 1 +$ if ref_type .eqs. ".HTML" then ref_skip = 1 +$ if ref_type .eqs. ".P12" then ref_skip = 1 +$ if ref_type .eqs. "." +$ then +$ if f$locate("test", ref_fname) .eq. 0 then ref_skip = 1 +$ if ref_fname .eqs. "configure." then ref_skip = 1 +$ endif +$! +$! +$ if ref_skip .ne. 0 +$ then +$ if report_missing +$ then +$ write sys$output "Skipping diff of ''ref_fname'" +$ endif +$ goto loop +$ endif +$! +$! +$ wrk_ver = f$parse(wrk_chk,,,"VERSION") +$ if wrk_ver .nes. ";1" +$ then +$ write sys$output "Version for ''wrk_spec' is not 1" +$ endif +$ set noon +$ diff/out=nl: 'wrk_spec' 'ref_spec' +$ if $severity .nes. "1" +$ then +$ write sys$output "''wrk_spec' is different from ''ref_spec'" +$ if update_file +$ then +$ delete 'wrk_spec';* +$ copy/log 'ref_spec' 'wrk_spec' +$ endif +$ endif +$ set on +$ +$! +$ goto loop +$loop_end: +$! +$! +$missing_loop: +$! For missing loop, check the latest generation. +$ ref_spec = f$search("''wrk'...]*.*;") +$ if ref_spec .eqs. "" then goto missing_loop_end +$! +$ ref_dev = f$parse(ref_spec,,,"DEVICE") +$ ref_dir = f$parse(ref_spec,,,"DIRECTORY") +$ ref_dir = f$edit(ref_dir, "LOWERCASE") +$ ref_name = f$parse(ref_spec,,,"NAME") +$ ref_type = f$parse(ref_spec,,,"TYPE") +$ ref_name_type = ref_name + ref_type +$! +$ rel_path = ref_dir - "[" - wrk_base_dir +$! +$! +$ wrk_path = ref + rel_path +$ wrk_spec = wrk_path + ref_name + ref_type +$ wrk_name = f$parse(wrk_spec,,,"NAME") +$ wrk_type = f$parse(wrk_spec,,,"TYPE") +$! +$ wrk_fname = wrk_name + wrk_type" +$ ref_fname = ref_name + ref_type +$! +$ wrk_skip = 0 +$ ref_utype = f$edit(ref_type,"UPCASE") +$ ref_ufname = f$edit(ref_fname,"UPCASE") +$! +$ if wrk_skip .eq. 0 +$ then +$ wrk_chk = f$search(wrk_spec, 0) +$ if wrk_chk .eqs. "" +$ then +$ if report_missing +$ then +$ write sys$output "''wrk_spec' is missing" +$ endif +$ goto missing_loop +$ endif +$ else +$ goto missing_loop +$ endif +$! +$ if ref_fname .nes. wrk_fname +$ then +$ write sys$output "''wrk_spc' wrong name, should be ""''ref_fname'""" +$ endif +$! +$ if ref_utype .eqs. ".DIR" then goto missing_loop +$! +$ wrk_ver = f$parse(wrk_chk,,,"VERSION") +$ if wrk_ver .nes. ";1" +$ then +$ write sys$output "Version for ''wrk_spec' is not 1" +$ endif +$! +$ goto missing_loop +$! +$! +$missing_loop_end: +$! +$exit diff --git a/packages/vms/config_h.com b/packages/vms/config_h.com new file mode 100644 index 0000000..6378802 --- /dev/null +++ b/packages/vms/config_h.com @@ -0,0 +1,1972 @@ +$! File: config_h.com +$! +$! This procedure attempts to figure out how to build a config.h file +$! for the current project. +$! +$! P1 specifies the config.h.in file or equivalent. If it is not specified +$! then this procedure will search for several common names of the file. +$! +$! The CONFIGURE shell script will be examined for hints and a few symbols +$! but most of the tests will not produce valid results on OpenVMS. Some +$! will produce false positives and some will produce false negatives. +$! +$! It is easier to just read the config.h_in file and make up tests based +$! on what is in it! +$! +$! This file will create an empty config_vms.h file if one does not exist. +$! The config_vms.h is intended for manual edits to handle things that +$! this procedure can not. +$! +$! The config_vms.h will be invoked by the resulting config.h file. +$! +$! This procedure knows about the DEC C RTL on the system it is on. +$! Future versions may be handle the GNV, the OpenVMS porting library, +$! and others. +$! +$! This procedure may not guess the options correctly for all architectures, +$! and is a work in progress. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!============================================================================ +$! +$ss_normal = 1 +$ss_abort = 44 +$ss_control_y = 1556 +$status = ss_normal +$on control_y then goto control_y +$on warning then goto general_error +$!on warning then set ver +$! +$! Some information for writing timestamps to created files +$!---------------------------------------------------------- +$my_proc = f$environment("PROCEDURE") +$my_proc_file = f$parse(my_proc,,,"NAME") + f$parse(my_proc,,,"TYPE") +$tab[0,8] = 9 +$datetime = f$element(0,".",f$cvtime(,"ABSOLUTE","DATETIME")) +$username = f$edit(f$getjpi("","USERNAME"),"TRIM") +$! +$pid = f$getjpi("","PID") +$tfile1 = "SYS$SCRATCH:config_h_temp1_''pid'.TEMP" +$dchfile = "SYS$SCRATCH:config_h_decc_''pid'.TEMP" +$starhfile = "SYS$SCRATCH:config_h_starlet_''pid'.TEMP" +$configure_script = "SYS$SCRATCH:configure_script_''pid'.TEMP" +$! +$! Get the system type +$!---------------------- +$arch_type = f$getsyi("arch_type") +$! +$! Does config_vms.h exist? +$!------------------------- +$update_config_vms = 0 +$file = f$search("sys$disk:[]config_vms.h") +$if file .nes. "" +$then +$ write sys$output "Found existing custom file ''file'." +$else +$ update_config_vms = 1 +$ write sys$output "Creating new sys$disk:[]config_vms.h for you." +$ gosub write_config_vms +$endif +$! +$! +$! On some platforms, DCL search has problems with searching a file +$! on a NFS mounted volume. So copy it to sys$scratch: +$! +$if f$search(configure_script) .nes. "" then delete 'configure_script';* +$copy sys$disk:[]configure 'configure_script' +$! +$ssl_header_dir = "OPENSSL:" +$if f$trnlnm("OPENSSL") .eqs. "" +$then +$ ssl_header_dir = "SSL$INCLUDE:" +$endif +$! +$! +$! Write out the header +$!---------------------- +$gosub write_config_h_header +$! +$! +$! +$! config.h.in could have at least five different names depending +$! on how it was transferred to OpenVMS +$!------------------------------------------------------------------ +$if p1 .nes. "" +$then +$ cfile = p1 +$else +$ cfile = f$search("sys$disk:[]config.h.in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("sys$disk:[]config.h_in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("sys$disk:[]configh.in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("sys$disk:[]config__2eh.in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("sys$disk:[]config.h__2ein") +$ endif +$ endif +$ endif +$ endif +$endif +$if f$trnlnm("PRJ_INCLUDE") .nes. "" +$then +$ cfile = f$search("PRJ_INCLUDE:config.h.in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("PRJ_INCLUDE:config.h_in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("PRJ_INCLUDE:config__2eh.in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("PRJ_INCLUDE:config__2eh.in") +$ if cfile .eqs. "" +$ then +$ cfile = f$search("PRJ_INCLUDE:config.h__2ein") +$ endif +$ endif +$ endif +$ endif +$endif +$if cfile .eqs. "" +$then +$ write sys$output "Can not find sys$disk:config.h.in" +$ line_out = "Looked for config.h.in, config.h_in, configh.in, " +$ line_out = line_out + "config__2eh.in, config.h__2ein" +$ write/symbol sys$output line_out +$ if f$trnlnm("PRJ_INCLUDE") .nes. "" +$ then +$ write sys$output "Also looked in PRJ_INCLUDE: for these files." +$ endif +$! +$ write tf "" +$ write tf - + " /* Could not find sys$disk:config.h.in */" +$ write tf - + " /* Looked also for config.h_in, configh.in, config__2eh.in, */" +$ write tf - + " /* config.h__2ein */" +$ if f$trnlnm("PRJ_INCLUDE") .nes. "" +$ then +$ write tf - + " /* Also looked in PRJ_INCLUDE: for these files. */" +$ endif +$ write tf - + "/*--------------------------------------------------------------*/ +$ write tf "" +$ goto write_tail +$endif +$! +$! +$! Locate the DECC libraries in use +$!----------------------------------- +$decc_rtldef = f$parse("decc$rtldef","sys$library:.tlb;0") +$decc_starletdef = f$parse("sys$starlet_c","sys$library:.tlb;0") +$decc_shr = f$parse("decc$shr","sys$share:.exe;0") +$! +$! Dump the DECC header names into a file +$!---------------------------------------- +$if f$search(dchfile) .nes. "" then delete 'dchfile';* +$if f$search(tfile1) .nes. "" then delete 'tfile1';* +$define/user sys$output 'tfile1' +$library/list 'decc_rtldef' +$open/read/error=rtldef_loop1_end tf1 'tfile1' +$open/write/error=rtldef_loop1_end tf2 'dchfile' +$rtldef_loop1: +$ read/end=rtldef_loop1_end tf1 line_in +$ line_in = f$edit(line_in,"TRIM,COMPRESS") +$ key1 = f$element(0," ",line_in) +$ key2 = f$element(1," ",line_in) +$ if key1 .eqs. " " .or. key1 .eqs. "" then goto rtldef_loop1 +$ if key2 .nes. " " .and. key2 .nes. "" then goto rtldef_loop1 +$ write tf2 "|",key1,"|" +$ goto rtldef_loop1 +$rtldef_loop1_end: +$if f$trnlnm("tf1","lnm$process",,"SUPERVISOR") .nes. "" then close tf1 +$if f$trnlnm("tf2","lnm$process",,"SUPERVISOR") .nes. "" then close tf2 +$if f$search(tfile1) .nes. "" then delete 'tfile1';* +$! +$! Dump the STARLET header names into a file +$!---------------------------------------- +$if f$search(starhfile) .nes. "" then delete 'starhfile';* +$if f$search(tfile1) .nes. "" then delete 'tfile1';* +$define/user sys$output 'tfile1' +$library/list 'decc_starletdef' +$open/read/error=stardef_loop1_end tf1 'tfile1' +$open/write/error=stardef_loop1_end tf2 'starhfile' +$stardef_loop1: +$ read/end=stardef_loop1_end tf1 line_in +$ line_in = f$edit(line_in,"TRIM,COMPRESS") +$ key1 = f$element(0," ",line_in) +$ key2 = f$element(1," ",line_in) +$ if key1 .eqs. " " .or. key1 .eqs. "" then goto stardef_loop1 +$ if key2 .nes. " " .and. key2 .nes. "" then goto stardef_loop1 +$ write tf2 "|",key1,"|" +$ goto stardef_loop1 +$stardef_loop1_end: +$if f$trnlnm("tf1","lnm$process",,"SUPERVISOR") .nes. "" then close tf1 +$if f$trnlnm("tf2","lnm$process",,"SUPERVISOR") .nes. "" then close tf2 +$if f$search(tfile1) .nes. "" then delete 'tfile1';* +$! +$! +$! Now calculate what should be in the file from reading +$! config.h.in and CONFIGURE. +$!--------------------------------------------------------------- +$open/read inf 'cfile' +$do_comment = 0 +$if_block = 0 +$cfgh_in_loop1: +$!set nover +$ read/end=cfgh_in_loop1_end inf line_in +$ xline = f$edit(line_in,"TRIM,COMPRESS") +$! +$! Blank line handling +$!--------------------- +$ if xline .eqs. "" +$ then +$ write tf "" +$ goto cfgh_in_loop1 +$ endif +$ xlen = f$length(xline) +$ key = f$extract(0,2,xline) +$! +$! deal with comments by copying exactly +$!----------------------------------------- +$ if (do_comment .eq. 1) .or. (key .eqs. "/*") +$ then +$ do_comment = 1 +$ write tf line_in +$ key = f$extract(xlen - 2, 2, xline) +$ if key .eqs. "*/" then do_comment = 0 +$ goto cfgh_in_loop1 +$ endif +$! +$! Some quick parsing +$!---------------------- +$ keyif = f$extract(0,3,xline) +$ key1 = f$element(0," ",xline) +$ key2 = f$element(1," ",xline) +$ key2a = f$element(0,"_",key2) +$ key2b = f$element(1,"_",key2) +$ key2_len = f$length(key2) +$ key2_h = f$extract(key2_len - 2, 2, key2) +$ key2_t = f$extract(key2_len - 5, 5, key2) +$ if key2_t .eqs. "_TYPE" then key2_h = "_T" +$ key64 = 0 +$ if f$locate("64", xline) .lt. xlen then key64 = 1 +$! +$!write sys$output "xline = ''xline'" +$! +$! Comment out this section of the ifblock +$!----------------------------------------- +$ if if_block .ge. 3 +$ then +$ write tf "/* ", xline, " */" +$ if keyif .eqs. "#en" then if_block = 0 +$ goto cfgh_in_loop1 +$ endif +$! +$! Handle the end of an ifblock +$!------------------------------- +$ if keyif .eqs. "#en" +$ then +$ write tf xline +$ if_block = 0 +$ goto cfgh_in_loop1 +$ endif +$! +$ if key1 .eqs. "#ifndef" +$ then +$! Manual check for _ALL_SOURCE on AIX error +$!----------------------------------------------- +$ if key2 .eqs. "_ALL_SOURCE" +$ then +$ write tf "/* ", xline, " */" +$! +$! Ignore the rest of the block +$!-------------------------------------- +$ if_block = 3 +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$! +$! Default action for an #if/#else/#endif +$!------------------------------------------ +$ if keyif .eqs. "#if" .or. keyif .eqs. "#el" +$ then +$ if_block = 1 +$ write tf xline +$ goto cfgh_in_loop1 +$ endif +$! +$! +$! Process "normal?" stuff +$!--------------------------- +$ if key1 .eqs. "#undef" +$ then +$ key2c = f$element(2, "_", key2) +$ if (key2c .eqs. "_") .or. (key2c .eqs. "H") then key2c = "" +$ key2d = f$element(3, "_", key2) +$ if (key2d .eqs. "_") .or. (key2d .eqs. "H") then key2d = "" +$ key2e = f$element(4, "_", key2) +$ if (key2e .eqs. "_") .or. (key2e .eqs. "H") then key2e = "" +$ if key2d .eqs. "T" +$ then +$ if key2e .eqs. "TYPE" +$ then +$ key2_h = "_T" +$ key2d = "" +$ endif +$ endif +$! +$ double_under = 0 +$! +$! Process FCNTL directives +$!------------------------------------- +$ if (key2b .eqs. "FCNTL") .and. (key2c .eqs. "O") .and. - + (key2d .eqs. "NONBLOCK") +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process GETADDRINFO directives +$!------------------------------------- +$ if key2 .eqs. "GETADDRINFO_THREADSAFE" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process IOCTL directives +$!------------------------------------- +$ if (key2b .eqs. "IOCTL") .and. (key2c .nes. "") +$ then +$ if (key2c .eqs. "FIONBIO") .or. (key2c .eqs. "SIOCGIFADDR") +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$! +$! Manual check for LL on +$!----------------------------------------------- +$ if key2 .eqs. "LL" +$ then +$ write tf "#ifndef __VAX +$ write tf "#define HAVE_''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "bool_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' short" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "bits16_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' short" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "u_bits16_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' unsigned short" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "bits32_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "u_bits32_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' unsigned int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "intmax_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#ifdef __VAX" +$ write tf "#define ''key2' long" +$ write tf "#else" +$ write tf "#define ''key2' long long" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "uintmax_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#ifdef __VAX" +$ write tf "#define ''key2' unsigned long" +$ write tf "#else" +$ write tf "#define ''key2' unsigned long long" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "socklen_t" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "GETGROUPS_T" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' gid_t" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_SYS_SIGLIST" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 0" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_SYS_ERRLIST" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_STRUCT_DIRENT_D_INO" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_STRUCT_TIMEVAL" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! ! The header files have this information, however +$! ! The ioctl() call only works on sockets. +$! if key2 .eqs. "FIONREAD_IN_SYS_IOCTL" +$! then +$! write tf "#ifndef ''key2'" +$! write tf "#define ''key2' 1" +$! write tf "#endif" +$! goto cfgh_in_loop1 +$! endif +$! +$! ! The header files have this information, however +$! ! The ioctl() call only works on sockets. +$! if key2 .eqs. "GWINSZ_IN_SYS_IOCTL" +$! then +$! write tf "#ifndef ''key2'" +$! write tf "#define ''key2' 1" +$! write tf "#endif" +$! goto cfgh_in_loop1 +$! endif +$! +$! ! The header files have this information, however +$! ! The ioctl() call only works on sockets. +$! if key2 .eqs. "STRUCT_WINSIZE_IN_SYS_IOCTL" +$! then +$! write tf "#ifndef ''key2'" +$! write tf "#define ''key2' 0" +$! write tf "#endif" +$! goto cfgh_in_loop1 +$! endif +$! +$ if key2 .eqs. "HAVE_STRUCT_TM_TM_ZONE" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_TM_ZONE" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_TIMEVAL" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "WEXITSTATUS_OFFSET" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 2" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_GETPW_DECLS" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_CONFSTR" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_PRINTF" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_SBRK" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_STRSIGNAL" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 0" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2a .eqs. "HAVE_DECL_STRTOLD" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 0" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_STRTOIMAX" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 0" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_STRTOL" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_STRTOLL" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_STRTOUL" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_STRTOULL" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_STRTOUMAX" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 0" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "GETPGRP_VOID" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "NAMED_PIPES_MISSING" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "OPENDIR_NOT_ROBUST" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "PGRP_PIPE" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "CAN_REDEFINE_GETENV" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_PRINTF_A_FORMAT" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "CTYPE_NON_ASCII" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_LANGINFO_CODESET" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 0" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! This wants execve() to do this automagically to pass. +$! if key2 .eqs. "HAVE_HASH_BANG_EXEC" +$! then +$! write tf "#ifndef ''key2'" +$! write tf "#define ''key2' 1" +$! write tf "#endif" +$! goto cfgh_in_loop1 +$! endif +$! +$ if key2 .eqs. "ICONV_CONST" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2'" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "VOID_SIGHANDLER" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_POSIX_SIGNALS" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "UNUSABLE_RT_SIGNALS" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2a .eqs. "HAVE_DECL_FPURGE" +$ then +$ write tf "#ifndef ''key2a'" +$ write tf "#define ''key2a' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_DECL_SETREGID" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "HAVE_POSIX_SIGSETJMP" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2b .eqs. "RAND" .and. key2c .nes. "" .and. key2d .eqs. "" +$ then +$ if (key2c .eqs. "EGD") .or. - + (key2c .eqs. "STATUS") .or. - + (key2c .eqs. "SCREEN") +$ then +$ if f$search("''ssl_header_dir'rand.h") .nes. "" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ else +$ write tf "/* #undef ''key2' */" +$ endif +$ endif +$ endif +$! +$ if key2 .eqs. "STRCOLL_BROKEN" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2 .eqs. "DUP_BROKEN" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! This is for a test that getcwd(0,0) works. +$! It does not on VMS. +$!-------------------------- +$ if key2 .eqs. "GETCWD_BROKEN" +$ then +$ write sys$output "" +$ write sys$output - + "%CONFIG_H-I-NONPORT, ''key2' being tested for!" +$ write sys$output - + "-CONFIG_H-I-GETCWD, GETCWD(0,0) does not work on VMS." +$ write sys$output - + "-CONFIG_H-I-GETCWD2, Work around hack probably required." +$ write sys$output - + "-CONFIG_H-I-REVIEW, Manual Code review required!" +$ if update_config_vms +$ then +$ open/append tfcv sys$disk:[]config_vms.h +$ write tfcv "" +$ write tfcv - + "/* Check config.h for use of ''key2' settings */" +$ write tfcv "" +$ close tfcv +$ endif +$ +$ goto cfgh_in_loop1 +$ endif +$! +$ if (key2a .eqs. "HAVE") .or. (key2a .eqs. "STAT") .or. - + (key2 .eqs. "ENABLE_IPV6") .or. (key2b .eqs. "LDAP") +$ then +$! +$! Process extra underscores +$!------------------------------------ +$ if f$locate("HAVE___", key2) .lt. key2_len +$ then +$ key2b = "__" + key2d +$ key2d = "" +$ double_under = 1 +$ else +$ if f$locate("HAVE__", key2) .lt. key2_len +$ then +$ key2b = "_" + key2c +$ key2c = "" +$ double_under = 1 +$ endif +$ endif +$! +$ if (key2_h .eqs. "_H") .or. (key2 .eqs. "ENABLE_IPV6") .or. - + (key2b .eqs. "LDAP") +$ then +$! +$! Looking for a header file +$!--------------------------------------- +$ headf = key2b +$ if key2c .nes. "" then headf = headf + "_" + key2c +$ if key2d .nes. "" then headf = headf + "_" + key2d +$! +$! (key2b .eqs. "READLINE") +$! +$! Some special parsing +$!------------------------------------------ +$ if (key2b .eqs. "SYS") .or. (key2b .eqs. "ARPA") .or. - + (key2b .eqs. "NET") .or. (key2b .eqs. "NETINET") +$ then +$ if key2c .nes. "" +$ then +$ headf = key2c +$ if key2d .nes. "" then headf = key2c + "_" + key2d +$ endif +$ endif +$! +$! And of course what's life with out some special cases +$!-------------------------------------------------------------------- +$ if key2 .eqs. "ENABLE_IPV6" +$ then +$ headf = "in6" +$ endif +$! +$ if key2b .eqs. "LDAP" +$ then +$ if (key2 .eqs. "HAVE_LDAP_SSL") .or. - + (key2 .eqs. "HAVE_LDAP_URL_PARSE") +$ then +$ headf = "ldap" +$ endif +$ endif +$! +$! +$ if key2b .eqs. "FILE" +$ then +$ write sys$output "" +$ write sys$output - + "%CONFIG_H-I-NONPORT, ''key2' being asked for!" +$ write sys$output - + "-CONFIG_H-I-FILE_OLD, file.h will not be configured as is obsolete!" +$ write sys$output - + "-CONFIG_H_I-FCNTL_NEW, "Expecting fcntl.h to be configured instead!" +$ write sys$output - + "-CONFIG_H_I-FCNTL_CHK, "Unable to verify at this time!" +$ write sys$output - + "-CONFIG_H-I-REVIEW, Manual Code review required!" +$! +$ if update_config_vms +$ then +$ open/append tfcv sys$disk:[]config_vms.h +$ write tfcv "" +$ write tfcv - + "/* Check config.h for use of fcntl.h instead of file.h */" +$ write tfcv "" +$ close tfcv +$ endif +$ endif +$! +$! Now look it up in the DEC C RTL +$!--------------------------------------------- +$ define/user sys$output nl: +$ define/user sys$error nl: +$ search/output=nl: 'dchfile' |'headf'|/exact +$ if '$severity' .eq. 1 +$ then +$ if key64 then write tf "#ifndef __VAX" +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$if p2 .nes. "" then write sys$output "''dchfile' - #define ''key2' 1" +$ write tf "#endif" +$ if key64 then write tf "#endif" +$set nover +$ goto cfgh_in_loop1 +$ endif +$! +$! +$! Now look it up in the DEC C STARLET_C +$!--------------------------------------------- +$ define/user sys$output nl: +$ define/user sys$error nl: +$ search/output=nl: 'starhfile' |'headf'|/exact +$ if '$severity' .eq. 1 +$ then +$ if key64 then write tf "#ifndef __VAX" +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$if p2 .nes. "" then write sys$output "''starfile' - #define ''key2' 1" +$ write tf "#endif" +$ if key64 then write tf "#endif" +$set nover +$ goto cfgh_in_loop1 +$ endif +$! +$! Now look for OPENSSL headers +$!--------------------------------------------------------- +$ if key2b .eqs. "OPENSSL" +$ then +$ headf = headf - "OPENSSL_" +$ header = f$search("''ssl_header_dir'''headf'.h") +$ if header .nes. "" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$set nover +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$! Now look for Kerberos +$!------------------------------------------------------------ +$ if key2b .eqs. "GSSAPI" +$ then +$ header_dir = "sys$sysroot:[kerberos.include]" +$ headf = headf - "GSSAPI_" +$ header = f$search("''header_dir'''headf'.h") +$ if header .nes. "" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$set nover +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$set nover +$ else +$! +$! Looking for a routine or a symbol +$!------------------------------------------------ +$ if key2c .eqs. "MACRO" +$ then +$ if (key2b .eqs. "FILE") .or. (key2b .eqs. "DATE") - + .or. (key2b .eqs. "LINE") .or. (key2b .eqs. "TIME") +$ then +$ write tf "#ifndef HAVE_''key2b'" +$ write tf "#define HAVE_''key2b' 1" +$ write tf "#endif" +$ endif +$ goto cfgh_in_loop1 +$ endif +$! +$! Special false tests +$!------------------------------------- +$ if double_under +$ then +$ if key2b .eqs. "_FCNTL" .or. key2b .eqs. "__FCNTL" +$ then +$ write tf "/* #undef HAVE_''key2b' */" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2b .eqs. "_STAT" .or. key2b .eqs. "__STAT" +$ then +$ write tf "/* #undef HAVE_''key2b' */" +$ goto cfgh_in_loop1 +$ endif +$! +$ if key2b .eqs. "_READ" .or. key2b .eqs. "__READ" +$ then +$ write tf "/* #undef HAVE_''key2b' */" +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$ keysym = key2b +$ if key2c .nes. "" then keysym = keysym + "_" + key2c +$ if key2d .nes. "" then keysym = keysym + "_" + key2d +$ if key2e .nes. "" then keysym = keysym + "_" + key2e +$! +$! +$! Stat structure members +$!------------------------------------- +$ if key2b .eqs. "STRUCT" +$ then +$ if key2c .eqs. "STAT" .and (key2d .nes. "") +$ then +$ key2b = key2b + "_" + key2c + "_" + key2d +$ key2c = key2e +$ key2d = "" +$ key2e = "" +$ endif +$ endif +$ if (key2b .eqs. "ST") .or. (key2b .eqs. "STRUCT_STAT_ST") +$ then +$ keysym = "ST" + "_" + key2c +$ keysym = f$edit(keysym,"LOWERCASE") +$ endif +$ if key2a .eqs. "STAT" +$ then +$ if (f$locate("STATVFS", key2b) .eq. 0) .and. key2c .eqs. "" +$ then +$ keysym = f$edit(key2b, "LOWERCASE") +$ endif +$!$ if (key2b .eqs. "STATVFS" .or. key2b .eqs. "STATFS2" - +$! .or. key2b .eqs. "STATFS3") .and. key2c .nes. "" +$! +$ if (key2b .eqs. "STATVFS") .and. key2c .nes. "" +$ then +$! Should really verify that the structure +$! named by key2b actually exists first. +$!------------------------------------------------------------ +$! +$! Statvfs structure members +$!------------------------------------------------- +$ keysym = "f_" + f$edit(key2c,"LOWERCASE") +$ endif +$ endif +$! +$! UTMPX structure members +$!-------------------------------------- +$ if key2b .eqs. "UT" .and. key2c .eqs. "UT" +$ then +$ keysym = "ut_" + f$edit(key2d,"LOWERCASE") +$ endif +$! +$ if f$locate("MMAP",key2) .lt. key2_len +$ then +$ write sys$output "" +$ write sys$output - + "%CONFIG_H-I-NONPORT, ''key2' being asked for!" +$ write sys$output - + "-CONFIG_H-I-MMAP, MMAP operations only work on STREAM and BINARY files!" +$ write sys$output - + "-CONFIG_H-I-REVIEW, Manual Code review required!" +$ if update_config_vms +$ then +$ open/append tfcv sys$disk:[]config_vms.h +$ write tfcv "" +$ write tfcv - + "/* Check config.h for use of ''key2' settings */" +$ write tfcv "" +$ close tfcv +$ endif +$ endif +$! +$! +$ if keysym .eqs. "CRYPT" +$ then +$ write sys$output "" +$ write sys$output - + "%CONFIG_H-I-NONPORT, ''key2' being asked for!" +$ write sys$output - + "-CONFIG_H-I-CRYPT, CRYPT operations on the VMS SYSUAF may not work!" +$ write sys$output - + "-CONFIG_H-I-REVIEW, Manual Code review required!" +$ if update_config_vms +$ then +$ open/append tfcv sys$disk:[]config_vms.h +$ write tfcv "" +$ write tfcv - + "/* Check config.h for use of ''keysym' */" +$ write tfcv "" +$ close tfcv +$ endif +$ endif +$! +$! +$ if keysym .eqs. "EXECL" +$ then +$ write sys$output "" +$ write sys$output - + "%CONFIG_H-I-NONPORT, ''key2' being asked for!" +$ write sys$output - + "-CONFIG_H-I-EXCEL, EXECL configured, Will probably not work." +$ write sys$output - + "-CONFIG_H-I-REVIEW, Manual Code review required!" +$ if update_config_vms +$ then +$ open/append tfcv sys$disk:[]config_vms.h +$ write tfcv "" +$ write tfcv - + "/* Check config.h for use of ''keysym' */" +$ write tfcv "" +$ close tfcv +$ endif +$ endif +$! +$! +$! Process if cpp supports ANSI-C stringizing '#' operator +$!----------------------------------------------------------------------- +$ if keysym .eqs. "STRINGIZE" +$ then +$ write tf "#ifndef HAVE_STRINGIZE" +$ write tf "#define HAVE_STRINGSIZE 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if keysym .eqs. "VOLATILE" +$ then +$ write tf "#ifndef HAVE_VOLATILE" +$ write tf "#define HAVE_VOLATILE 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if keysym .eqs. "ALLOCA" +$ then +$ write tf "#ifndef HAVE_ALLOCA" +$ write tf "#define HAVE_ALLOCA 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if keysym .eqs. "ERRNO_DECL" +$ then +$ write tf "#ifndef HAVE_ERRNO_DECL" +$ write tf "#define HAVE_ERRNO_DECL 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if keysym .eqs. "LONGLONG" +$ then +$ write tf "#ifndef __VAX" +$ write tf "#pragma message disable longlongtype" +$ write tf "#ifndef HAVE_LONGLONG" +$ write tf "#define HAVE_LONGLONG 1" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! May need to test compiler version +$!----------------------------------------------- +$ if keysym .eqs. "LONG_LONG" +$ then +$ write tf "#ifndef __VAX" +$ write tf "#pragma message disable longlongtype" +$ write tf "#ifndef HAVE_LONG_LONG" +$ write tf "#define HAVE_LONG_LONG 1" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! May need to test compiler version +$!----------------------------------------------- +$ if keysym .eqs. "UNSIGNED_LONG_LONG" +$ then +$ write tf "#ifndef __VAX" +$ write tf "#pragma message disable longlongtype" +$ write tf "#ifndef HAVE_UNSIGNED_LONG_LONG" +$ write tf "#define HAVE_UNSIGNED_LONG_LONG 1" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! May need to test compiler version +$!----------------------------------------------- +$ if keysym .eqs. "UNSIGNED_LONG_LONG_INT" +$ then +$ write tf "#ifndef __VAX" +$ write tf "#pragma message disable longlongtype" +$ write tf "#ifndef HAVE_UNSIGNED_LONG_LONG_INT" +$ write tf "#define HAVE_UNSIGNED_LONG_LONG_INT 1" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! May need to test compiler version +$!----------------------------------------------- +$ if keysym .eqs. "LONG_DOUBLE" +$ then +$ write tf "#ifndef __VAX" +$ write tf "#pragma message disable longlongtype" +$ write tf "#ifndef HAVE_LONG_DOUBLE" +$ write tf "#define HAVE_LONG_DOUBLE 1" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$ if keysym .eqs. "FCNTL_LOCK" +$ then +$ write sys$output - + "%CONFIG_H-I-NONPORT, ''key2' being asked for! +$ write sys$output - + "-CONFIG_H-I-REVIEW, Manual Code review required!" +$ goto cfgh_in_loop1 +$ endif +$! +$! +$! These libraries are provided by the DEC C RTL +$!------------------------------------------------------------- +$ if keysym .eqs. "LIBINET" .or. keysym .eqs. "LIBSOCKET" +$ then +$ write tf "#ifndef HAVE_''keysym'" +$ write tf "#define HAVE_''keysym' 1" +$if p2 .nes. "" then write sys$output "''decc_shr' #define ''keysym' 1" +$ write tf "#endif +$ goto cfgh_in_loop1 +$ endif +$! +$ if keysym .eqs. "HERRNO" then keysym = "h_errno" +$ if keysym .eqs. "UTIMBUF" then keysym = "utimbuf" +$ if key2c .eqs. "STRUCT" +$ then +$ keysym = f$edit(key2d,"LOWERCASE") +$ else +$ if key2_h .eqs. "_T" +$ then +$ if key2_t .eqs. "_TYPE" +$ then +$ keysym = f$extract(0, key2_len - 5, key2) - "HAVE_" +$ endif +$ keysym = f$edit(keysym,"LOWERCASE") +$ endif +$ endif +$! +$! Check the DEC C RTL shared image first +$!------------------------------------------------------ +$ if f$search(tfile1) .nes. "" then delete 'tfile1';* +$ define/user sys$output nl: +$ define/user sys$error nl: +$ search/format=nonull/out='tfile1' 'decc_shr' 'keysym' +$ if '$severity' .eq. 1 +$ then +$! +$! Not documented, but from observation +$!------------------------------------------------------ +$ define/user sys$output nl: +$ define/user sys$error nl: +$ if arch_type .eq. 3 +$ then +$ keyterm = "''keysym'" +$ else +$ if arch_type .eq. 2 +$ then +$ keyterm = "''keysym'" +$ else +$ keyterm = "''keysym'" +$ endif +$ endif +$ search/out=nl: 'tfile1' - + "$''keyterm'","$g''keyterm'","$__utc_''keyterm'",- + "$__utctz_''keyterm'","$__bsd44_''keyterm'","$bsd_''keyterm'",- + "$''keysym'decc$","$G''keysym'decc$","$GX''keyterm'" +$ severity = '$severity' +$! +$! +$! Of course the 64 bit stuff is different +$!--------------------------------------------------------- +$ if severity .ne. 1 .and. key64 +$ then +$ define/user sys$output nl: +$ define/user sys$error nl: +$ search/out=nl: 'tfile1' "$_''keyterm'" +$! search/out 'tfile1' "$_''keyterm'" +$ severity = '$severity' +$ endif +$! +$! Unix compatibility routines +$!--------------------------------------------- +$ if severity .ne. 1 +$ then +$ define/user sys$output nl: +$ define/user sys$error nl: +$ search/out=nl: 'tfile1' - + "$__unix_''keyterm'","$__vms_''keyterm'","$_posix_''keyterm'" +$ severity = '$severity' +$ endif +$! +$! Show the result of the search +$!------------------------------------------------ +$ if 'severity' .eq. 1 +$ then +$ if key64 then write tf "#ifndef __VAX" +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$if p2 .nes. "" then write sys$output "''decc_shr' #define ''key2' 1" +$ write tf "#endif" +$ if key64 then write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ endif +$ if f$search(tfile1) .nes. "" then delete 'tfile1';* +$! +$! Check the DECC Header files next +$!---------------------------------------------- +$ define/user sys$output nl: +$ define/user sys$error nl: +$ search/out=nl: 'decc_rtldef' - + "''keysym';", "''keysym'[", "struct ''keysym'"/exact +$ severity = '$severity' +$ if severity .eq. 1 +$ then +$ if key64 then write tf "#ifndef __VAX" +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$if p2 .nes. "" then write sys$output "''decc_rtldef' #define ''key2' 1" +$ write tf "#endif" +$ if key64 then write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Check kerberos +$!-------------------------------------------- +$ if f$search("SYS$SYSROOT:[kerberos]include.dir") .nes. "" +$ then +$ test_mit = "SYS$SYSROOT:[kerberos.include]gssapi_krb5.h" +$ if (key2 .eqs. "HAVE_GSSAPI") +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$ endif +$ write tf "/* ", xline, " */" +$ goto cfgh_in_loop1 +$ endif +$! +$! +$! Process SIZEOF directives found in SAMBA and others +$!---------------------------------------------------------- +$ if key2a .eqs. "SIZEOF" +$ then +$ if key2b .eqs. "INO" .and. key2_h .eqs. "_T" +$ then +$ write tf "#ifndef SIZEOF_INO_T" +$ write tf "#if !__USING_STD_STAT +$ write tf "#define SIZEOF_INO_T 6" +$ write tf "#else +$ write tf "#define SIZEOF_INO_T 8" +$ write tf "#endif +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "INTMAX" .and. key2_h .eqs. "_T" +$ then +$ write tf "#ifndef SIZEOF_INTMAX_T" +$ write tf "#ifdef __VAX" +$ write tf "#define SIZEOF_INTMAX_T 4" +$ write tf "#else" +$ write tf "#define SIZEOF_INTMAX_T 8" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "OFF" .and. key2_h .eqs. "_T" +$ then +$ write tf "#ifndef SIZEOF_OFF_T" +$ write tf "#if __USE_OFF64_T" +$ write tf "#define SIZEOF_OFF_T 8" +$ write tf "#else" +$ write tf "#define SIZEOF_OFF_T 4" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "CHAR" .and. key2_h .eqs. "_P" +$ then +$ write tf "#ifndef SIZEOF_CHAR_P" +$ write tf "#if __INITIAL_POINTER_SIZE == 64" +$ write tf "#define SIZEOF_CHAR_P 8" +$ write tf "#else" +$ write tf "#define SIZEOF_CHAR_P 4" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "VOIDP" +$ then +$ write tf "#ifndef SIZEOF_VOIDP" +$ write tf "#if __INITIAL_POINTER_SIZE == 64" +$ write tf "#define SIZEOF_VOIDP 8" +$ write tf "#else" +$ write tf "#define SIZEOF_VOIDP 4" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "INT" +$ then +$ write tf "#ifndef SIZEOF_INT" +$ write tf "#define SIZEOF_INT 4" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "SIZE" .and. key2_h .eqs. "_T" +$ then +$ write tf "#ifndef SIZEOF_SIZE_T" +$ write tf "#define SIZEOF_SIZE_T 4" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "TIME" .and. key2_h .eqs. "_T" +$ then +$ write tf "#ifndef SIZEOF_TIME_T" +$ write tf "#define SIZEOF_TIME_T 4" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "DOUBLE" +$ then +$ write tf "#ifndef SIZEOF_DOUBLE" +$ write tf "#define SIZEOF_DOUBLE 8" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2b .eqs. "LONG" +$ then +$ if key2c .eqs. "" +$ then +$ write tf "#ifndef SIZEOF_LONG" +$ write tf "#define SIZEOF_LONG 4" +$ write tf "#endif" +$ else +$ write tf "#ifndef SIZEOF_LONG_LONG" +$ write tf "#ifndef __VAX" +$ write tf "#define SIZEOF_LONG_LONG 8" +$ write tf "#endif" +$ write tf "#endif" +$ endif +$ goto cfgh_in_loop1 +$ endif +$ write tf "/* ", xline, " */" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process NEED directives +$!------------------------------- +$ if key2a .eqs. "NEED" +$ then +$ if key2b .eqs. "STRINGS" .and. key2_h .eqs. "_H" +$ then +$ write tf "#ifndef NEED_STRINGS_H" +$ write tf "#define NEED_STRINGS_H 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ write tf "/* ", xline, " */" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process GETHOSTNAME directives +$!------------------------------------- +$ if key2 .eqs. "GETHOSTNAME_TYPE_ARG2" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#ifdef _DECC_V4_SOURCE" +$ write tf "#define ''key2' int" +$ write tf "#else" +$ write tf "#define ''key2' size_t" +$ write tf "#endif" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process GETNAMEINFO directives +$!------------------------------------- +$ if key2a .eqs. "GETNAMEINFO" +$ then +$ if key2 .eqs. "GETNAMEINFO_QUAL_ARG1" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' const" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "GETNAMEINFO_TYPE_ARG1" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' struct sockaddr *" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "GETNAMEINFO_TYPE_ARG2" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' size_t" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "GETNAMEINFO_TYPE_ARG46" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' size_t" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "GETNAMEINFO_TYPE_ARG7" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$! Process RECV directives +$!------------------------------------- +$ if key2a .eqs. "RECV" +$ then +$ if key2 .eqs. "RECV_TYPE_ARG1" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "RECV_TYPE_ARG2" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' void *" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "RECV_TYPE_ARG3" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' size_t" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "RECV_TYPE_ARG4" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "RECV_TYPE_RETV" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$! Process SEND directives +$!------------------------------------- +$ if key2a .eqs. "SEND" +$ then +$ if key2 .eqs. "SEND_QUAL_ARG2" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' const" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "SEND_TYPE_ARG1" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "SEND_TYPE_ARG2" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' void *" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "SEND_TYPE_ARG3" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' size_t" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "SEND_TYPE_ARG4" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ if key2 .eqs. "SEND_TYPE_RETV" +$ then +$ write tf "#ifndef ''key2'" +$ write tf "#define ''key2' int" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$ endif +$! +$! +$! Process STATFS directives +$!------------------------------- +$! if key2a .eqs. "STATFS" +$! then +$! write tf "/* ", xline, " */" +$! goto cfgh_in_loop1 +$! endif +$! +$! Process inline directive +$!------------------------------ +$ if key2 .eqs. "inline" +$ then +$ write tf "#ifndef inline" +$ write tf "#define inline __inline" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process restrict directive +$!-------------------------------- +$ if key2 .eqs. "restrict" +$ then +$ write tf "#ifndef restrict" +$ write tf "#define restrict __restrict" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process STDC_HEADERS (SAMBA!) +$!--------------------------- +$ if key2 .eqs. "STDC_HEADERS" +$ then +$ write tf "#ifndef STDC_HEADERS" +$ write tf "#define STDC_HEADERS 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Process PROTOTYPES directive +$!------------------------------------- +$ if key2 .eqs. "PROTOTYPES" +$ then +$ write tf "#ifndef PROTOTYPES" +$ write tf "#define PROTOTYPES 1" +$ write tf "#endif" +$ goto cfgh_in_loop1 +$ endif +$! +$! Special for SEEKDIR_RETURNS_VOID +$!--------------------------------------- +$ if key2 .eqs. "SEEKDIR_RETURNS_VOID" +$ then +$ write tf "#ifndef SEEKDIR_RETURNS_VOID" +$ write tf "#define SEEKDIR_RETURNS_VOID 1" +$ write tf "#endif" +$ endif +$! +$! Unknown - See if CONFIGURE can give a clue for this +$!---------------------------------------------------------- +$ pflag = 0 +$ set_flag = 0 +$! gproj_name = proj_name - "_VMS" - "-VMS" +$ if f$search(tfile1) .nes. "" then delete 'tfile1';* +$ define/user sys$output nl: +$ define/user sys$error nl: +$! if f$locate("FILE", key2) .lt. key2_len then pflag = 1 +$! if f$locate("DIR", key2) .eq. key2_len - 3 then pflag = 1 +$! if f$locate("PATH", key2) .eq. key2_len - 4 then pflag = 1 +$! +$ search/out='tfile1' 'configure_script' "''key2'="/exact +$ search_sev = '$severity' +$ if 'search_sev' .eq. 1 +$ then +$ open/read/err=unknown_cf_rd_error sf 'tfile1' +$search_file_rd_loop: +$ read/end=unknown_cf_rd_err sf line_in +$ line_in = f$edit(line_in, "TRIM") +$ skey1 = f$element(0,"=",line_in) +$ if skey1 .eqs. key2 +$ then +$ skey2 = f$element(1,"=",line_in) +$ skey2a = f$extract(0,2,skey2) +$! +$! +$! We can not handle assignment to shell symbols. +$! For now skip them. +$!------------------------------------------------------------ +$ if f$locate("$", skey2) .lt. f$length(skey2) +$ then +$ write tf "/* ", xline, " */" +$ set_flag = 1 +$ goto found_in_configure +$ endif +$! +$! Keep these two cases separate to make it easier to add +$! more future intelligence to this routine +$!---------------------------------------------------------------------- +$ if skey2a .eqs. """`" +$ then +$! if pflag .eq. 1 +$! then +$! write tf "#ifndef ''key2'" +$! write tf "#define ",key2," """,gproj_name,"_",key2,"""" +$! write tf "#endif" +$! else +$! Ignore this for now +$!------------------------------------------ +$ write tf "/* ", xline, " */" +$! endif +$ set_flag = 1 +$ goto found_in_configure +$ endif +$ if skey2a .eqs. """$" +$ then +$! if pflag .eq. 1 +$! then +$! write tf "#ifndef ''key2'" +$! write tf "#define ",key2," """,gproj_name,"_",key2,"""" +$! write tf "#endif" +$! else +$! Ignore this for now +$!------------------------------------------- +$ write tf "/* ", xline, " */" +$! endif +$ set_flag = 1 +$ goto found_in_configure +$ endif +$! +$! Remove multiple layers of quotes if present +$!---------------------------------------------------------- +$ if f$extract(0, 1, skey2) .eqs. "'" +$ then +$ skey2 = skey2 - "'" - "'" - "'" - "'" +$ endif +$ if f$extract(0, 1, skey2) .eqs. """" +$ then +$ skey2 = skey2 - """" - """" - """" - """" +$ endif +$ write tf "#ifndef ''key2'" +$ if skey2 .eqs. "" +$ then +$ write tf "#define ",key2 +$ else +$! Only quote non-numbers +$!---------------------------------------- +$ if f$string(skey2+0) .eqs. skey2 +$ then +$ write tf "#define ",key2," ",skey2 +$ else +$ write tf "#define ",key2," """,skey2,"""" +$ endif +$ endif +$ write tf "#endif" +$ set_flag = 1 +$ else +$ goto search_file_rd_loop +$! if pflag .eq. 1 +$! then +$! write tf "#ifndef ''key2'" +$! write tf "#define ",key2," """,gproj_name,"_",key2,"""" +$! write tf "#endif" +$! set_flag = 1 +$! endif +$ endif +$found_in_configure: +$unknown_cf_rd_err: +$ if f$trnlnm("sf","lnm$process",,"SUPERVISOR") .nes. "" +$ then +$ close sf +$ endif +$ if f$search(tfile1) .nes. "" then delete 'tfile1';* +$ if set_flag .eq. 1 then goto cfgh_in_loop1 +$ endif +$ endif +$! +$! +$! +$! If it falls through everything else, comment it out +$!----------------------------------------------------- +$ write tf "/* ", xline, " */" +$ goto cfgh_in_loop1 +$cfgh_in_loop1_end: +$close inf +$! +$! +$! Write out the tail +$!-------------------- +$write_tail: +$gosub write_config_h_tail +$! +$! Exit and clean up +$!-------------------- +$general_error: +$status = '$status' +$all_exit: +$set noon +$if f$trnlnm("sf","lnm$process",,"SUPERVISOR") .nes. "" then close sf +$if f$trnlnm("tf","lnm$process",,"SUPERVISOR") .nes. "" then close tf +$if f$trnlnm("inf","lnm$process",,"SUPERVISOR") .nes. "" then close inf +$if f$trnlnm("tf1","lnm$process",,"SUPERVISOR") .nes. "" then close tf1 +$if f$trnlnm("tf2","lnm$process",,"SUPERVISOR") .nes. "" then close tf2 +$if f$trnlnm("tfcv","lnm$process",,"SUPERVISOR") .nes. "" then close tfcv +$if f$type(tfile1) .eqs. "STRING" +$then +$ if f$search(tfile1) .nes. "" then delete 'tfile1';* +$endif +$if f$type(dchfile) .eqs. "STRING" +$then +$ if f$search(dchfile) .nes. "" then delete 'dchfile';* +$endif +$if f$type(starhfile) .eqs. "STRING" +$then +$ if f$search(starhfile) .nes. "" then delete 'starhfile';* +$endif +$if f$type(configure_script) .eqs. "STRING" +$then +$ if f$search(configure_script) .nes. "" then delete 'configure_script';* +$endif +$exit 'status' +$! +$! +$control_y: +$ status = ss_control_y +$ goto all_exit +$! +$! +$! +$! Gosub to write a new config_vms.h +$!----------------------------------- +$write_config_vms: +$outfile = "sys$disk:[]config_vms.h" +$create 'outfile' +$open/append tf 'outfile' +$write tf "/* File: config_vms.h" +$write tf "**" +$write tf "** This file contains the manual edits needed for porting" +$!write tf "** the ''proj_name' package to OpenVMS. +$write tf "**" +$write tf "** Edit this file as needed. The procedure that automatically" +$write tf "** generated this header stub will not overwrite or make any" +$write tf "** changes to this file." +$write tf "**" +$write tf - + "** ", datetime, tab, username, tab, "Generated by ''my_proc_file'" +$write tf "**" +$write tf - + "**========================================================================*/" +$write tf "" +$close tf +$return +$! +$! gosub to write out a documentation header for config.h +$!---------------------------------------------------------------- +$write_config_h_header: +$outfile = "sys$disk:[]config.h" +$create 'outfile' +$open/append tf 'outfile' +$write tf "#ifndef CONFIG_H" +$write tf "#define CONFIG_H" +$write tf "/* File: config.h" +$write tf "**" +$write tf - + "** This file contains the options needed for porting " +$write tf "** the project on a VMS system." +$write tf "**" +$write tf "** Try not to make any edits to this file, as it is" +$write tf "** automagically generated." +$write tf "**" +$write tf "** Manual edits should be made to the config_vms.h file." +$write tf "**" +$write tf - + "** ", datetime, tab, username, tab, "Generated by ''my_proc_file'" +$write tf "**" +$write tf - + "**========================================================================*/" +$write tf "" +$write tf "#if (__CRTL_VER >= 70200000) && !defined (__VAX)" +$write tf "#define _LARGEFILE 1" +$write tf "#endif" +$write tf "" +$write tf "#ifndef __VAX" +$write tf "#ifdef __CRTL_VER" +$write tf "#if __CRTL_VER >= 80200000" +$write tf "#define _USE_STD_STAT 1" +$write tf "#endif" +$write tf "#endif" +$write tf "#endif" +$write tf "" +$! +$write tf " /* Allow compiler builtins */" +$write tf "/*-------------------------*/" +$write tf "#ifdef __DECC_VER" +$write tf "#include " +$write tf "#endif" +$! +$write tf "" +$return +$! +$! gosub to write out the tail for config.h and close it +$!--------------------------------------------------------- +$write_config_h_tail: +$write tf "" +$write tf " /* Include the hand customized settings */" +$write tf "/*--------------------------------------*/" +$write tf "#include ""config_vms.h""" +$write tf "" +$write tf "#endif /* CONFIG_H */" +$close tf +$return +$! diff --git a/packages/vms/curl_crtl_init.c b/packages/vms/curl_crtl_init.c new file mode 100644 index 0000000..6ae7e8c --- /dev/null +++ b/packages/vms/curl_crtl_init.c @@ -0,0 +1,333 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* File: curl_crtl_init.c + * + * This file makes sure that the DECC Unix settings are correct for + * the mode the program is run in. + * + * The CRTL has not been initialized at the time that these routines + * are called, so many routines can not be called. + * + * This is a module that provides a LIB$INITIALIZE routine that + * will turn on some CRTL features that are not enabled by default. + * + * The CRTL features can also be turned on via logical names, but that + * impacts all programs and some aren't ready, willing, or able to handle + * those settings. + * + * On VMS versions that are too old to use the feature setting API, this + * module falls back to using logical names. + * + * Copyright (C) John Malmberg + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Unix headers */ +#include +#include + +/* VMS specific headers */ +#include +#include +#include + +#pragma member_alignment save +#pragma nomember_alignment longword +#pragma message save +#pragma message disable misalgndmem +struct itmlst_3 { + unsigned short int buflen; + unsigned short int itmcode; + void *bufadr; + unsigned short int *retlen; +}; +#pragma message restore +#pragma member_alignment restore + +#ifdef __VAX +#define ENABLE "ENABLE" +#define DISABLE "DISABLE" +#else + +#define ENABLE TRUE +#define DISABLE 0 +int decc$feature_get_index (const char *name); +int decc$feature_set_value (int index, int mode, int value); +#endif + +int SYS$TRNLNM( + const unsigned long * attr, + const struct dsc$descriptor_s * table_dsc, + struct dsc$descriptor_s * name_dsc, + const unsigned char * acmode, + const struct itmlst_3 * item_list); +int SYS$CRELNM( + const unsigned long * attr, + const struct dsc$descriptor_s * table_dsc, + const struct dsc$descriptor_s * name_dsc, + const unsigned char * acmode, + const struct itmlst_3 * item_list); + + +/* Take all the fun out of simply looking up a logical name */ +static int sys_trnlnm + (const char * logname, + char * value, + int value_len) +{ + const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV"); + const unsigned long attr = LNM$M_CASE_BLIND; + struct dsc$descriptor_s name_dsc; + int status; + unsigned short result; + struct itmlst_3 itlst[2]; + + itlst[0].buflen = value_len; + itlst[0].itmcode = LNM$_STRING; + itlst[0].bufadr = value; + itlst[0].retlen = &result; + + itlst[1].buflen = 0; + itlst[1].itmcode = 0; + + name_dsc.dsc$w_length = strlen(logname); + name_dsc.dsc$a_pointer = (char *)logname; + name_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + name_dsc.dsc$b_class = DSC$K_CLASS_S; + + status = SYS$TRNLNM(&attr, &table_dsc, &name_dsc, 0, itlst); + + if($VMS_STATUS_SUCCESS(status)) { + + /* Null terminate and return the string */ + /*--------------------------------------*/ + value[result] = '\0'; + } + + return status; +} + +/* How to simply create a logical name */ +static int sys_crelnm + (const char * logname, + const char * value) +{ + int ret_val; + const char * proc_table = "LNM$PROCESS_TABLE"; + struct dsc$descriptor_s proc_table_dsc; + struct dsc$descriptor_s logname_dsc; + struct itmlst_3 item_list[2]; + + proc_table_dsc.dsc$a_pointer = (char *) proc_table; + proc_table_dsc.dsc$w_length = strlen(proc_table); + proc_table_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + proc_table_dsc.dsc$b_class = DSC$K_CLASS_S; + + logname_dsc.dsc$a_pointer = (char *) logname; + logname_dsc.dsc$w_length = strlen(logname); + logname_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + logname_dsc.dsc$b_class = DSC$K_CLASS_S; + + item_list[0].buflen = strlen(value); + item_list[0].itmcode = LNM$_STRING; + item_list[0].bufadr = (char *)value; + item_list[0].retlen = NULL; + + item_list[1].buflen = 0; + item_list[1].itmcode = 0; + + ret_val = SYS$CRELNM(NULL, &proc_table_dsc, &logname_dsc, NULL, item_list); + + return ret_val; +} + + + /* Start of DECC RTL Feature handling */ + +/* +** Sets default value for a feature +*/ +#ifdef __VAX +static void set_feature_default(const char *name, const char *value) +{ + sys_crelnm(name, value); +} +#else +static void set_feature_default(const char *name, int value) +{ + int index; + + index = decc$feature_get_index(name); + + if(index > 0) + decc$feature_set_value (index, 0, value); +} +#endif + +static void set_features(void) +{ + int status; + char unix_shell_name[255]; + int use_unix_settings = 1; + + status = sys_trnlnm("GNV$UNIX_SHELL", + unix_shell_name, sizeof unix_shell_name -1); + if(!$VMS_STATUS_SUCCESS(status)) { + use_unix_settings = 0; + } + + /* ACCESS should check ACLs or it is lying. */ + set_feature_default("DECC$ACL_ACCESS_CHECK", ENABLE); + + /* We always want the new parse style */ + set_feature_default ("DECC$ARGV_PARSE_STYLE" , ENABLE); + + + /* Unless we are in POSIX compliant mode, we want the old POSIX root + * enabled. + */ + set_feature_default("DECC$DISABLE_POSIX_ROOT", DISABLE); + + /* EFS charset, means UTF-8 support */ + /* VTF-7 support is controlled by a feature setting called UTF8 */ + set_feature_default ("DECC$EFS_CHARSET", ENABLE); + set_feature_default ("DECC$EFS_CASE_PRESERVE", ENABLE); + + /* Support timestamps when available */ + set_feature_default ("DECC$EFS_FILE_TIMESTAMPS", ENABLE); + + /* Cache environment variables - performance improvements */ + set_feature_default ("DECC$ENABLE_GETENV_CACHE", ENABLE); + + /* Start out with new file attribute inheritance */ +#ifdef __VAX + set_feature_default ("DECC$EXEC_FILEATTR_INHERITANCE", "2"); +#else + set_feature_default ("DECC$EXEC_FILEATTR_INHERITANCE", 2); +#endif + + /* Don't display trailing dot after files without type */ + set_feature_default ("DECC$READDIR_DROPDOTNOTYPE", ENABLE); + + /* For standard output channels buffer output until terminator */ + /* Gets rid of output logs with single character lines in them. */ + set_feature_default ("DECC$STDIO_CTX_EOL", ENABLE); + + /* Fix mv aa.bb aa */ + set_feature_default ("DECC$RENAME_NO_INHERIT", ENABLE); + + if(use_unix_settings) { + + /* POSIX requires that open files be able to be removed */ + set_feature_default ("DECC$ALLOW_REMOVE_OPEN_FILES", ENABLE); + + /* Default to outputting Unix filenames in VMS routines */ + set_feature_default ("DECC$FILENAME_UNIX_ONLY", ENABLE); + /* FILENAME_UNIX_ONLY Implicitly sets */ + /* decc$disable_to_vms_logname_translation */ + + set_feature_default ("DECC$FILE_PERMISSION_UNIX", ENABLE); + + set_feature_default ("DECC$FILE_SHARING", ENABLE); + + set_feature_default ("DECC$FILE_OWNER_UNIX", ENABLE); + set_feature_default ("DECC$POSIX_SEEK_STREAM_FILE", ENABLE); + + } else { + set_feature_default("DECC$FILENAME_UNIX_REPORT", ENABLE); + } + + /* When reporting Unix filenames, glob the same way */ + set_feature_default ("DECC$GLOB_UNIX_STYLE", ENABLE); + + /* The VMS version numbers on Unix filenames is incompatible with most */ + /* ported packages. */ + set_feature_default("DECC$FILENAME_UNIX_NO_VERSION", ENABLE); + + /* The VMS version numbers on Unix filenames is incompatible with most */ + /* ported packages. */ + set_feature_default("DECC$UNIX_PATH_BEFORE_LOGNAME", ENABLE); + + /* Set strtol to proper behavior */ + set_feature_default("DECC$STRTOL_ERANGE", ENABLE); + + /* Commented here to prevent future bugs: A program or user should */ + /* never ever enable DECC$POSIX_STYLE_UID. */ + /* It will probably break all code that accesses UIDs */ + /* do_not_set_default ("DECC$POSIX_STYLE_UID", TRUE); */ +} + + +/* Some boilerplate to force this to be a proper LIB$INITIALIZE section */ + +#pragma nostandard +#pragma extern_model save +#ifdef __VAX +#pragma extern_model strict_refdef "LIB$INITIALIZE" nowrt, long, nopic +#else +#pragma extern_model strict_refdef "LIB$INITIALIZE" nowrt, long +# if __INITIAL_POINTER_SIZE +# pragma __pointer_size __save +# pragma __pointer_size 32 +# else +# pragma __required_pointer_size __save +# pragma __required_pointer_size 32 +# endif +#endif +/* Set our contribution to the LIB$INITIALIZE array */ +void (* const iniarray[])(void) = {set_features, } ; +#ifndef __VAX +# if __INITIAL_POINTER_SIZE +# pragma __pointer_size __restore +# else +# pragma __required_pointer_size __restore +# endif +#endif + + +/* +** Force a reference to LIB$INITIALIZE to ensure it +** exists in the image. +*/ +int LIB$INITIALIZE(void); +#ifdef __DECC +#pragma extern_model strict_refdef +#endif + int lib_init_ref = (int) LIB$INITIALIZE; +#ifdef __DECC +#pragma extern_model restore +#pragma standard +#endif diff --git a/packages/vms/curl_gnv_build_steps.txt b/packages/vms/curl_gnv_build_steps.txt new file mode 100644 index 0000000..b7ea952 --- /dev/null +++ b/packages/vms/curl_gnv_build_steps.txt @@ -0,0 +1,290 @@ +From File: curl_gnv_build_steps.txt + + Copyright (C) John Malmberg + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + SPDX-License-Identifier: ISC + +Currently building Curl using GNV takes longer than building Curl via DCL. +The GNV procedure actually uses the same configure and makefiles that +Unix builds use. + +Building CURL on OpenVMS using GNV requires GNV V2.1-2 or the updated +images that are available via anonymous FTP at encompasserve.org in the gnv +directory. It also requires the GNV Bash 4.2.45 kit as an update from the +same location or from the sourceforge.net GNV project. + +The HP C 7.x compiler was used for building the GNV version. + +The source kits are provided in backup savesets inside of the PCSI install kit. + +Backup save sets are currently the only distribution medium that I can be +sure is installed on a target VMS system that will correctly unpack files +with extended character sets in them. You may need to adjust the ownership +of the restored files, since /Interchange/noconvert was not available at the +time that this document was written. + +[gnv.common_src]curl_*_original_src.bck is the original source of the curl kit +as provided by the curl project. [gnv.vms_src]curl-*_vms_src.bck, if present, +has the OpenVMS specific files that are used for building that are not yet in +the curl source kits for that release distributed https://curl.se + +These backup savesets should be restored to different directory trees on +an ODS-5 volume(s) which are referenced by concealed rooted logical names. + +SRC_ROOT: is for the source files common to all platforms. +VMS_ROOT: is for the source files that are specific to OpenVMS. + Note, you should create the VMS_ROOT: directory tree even if it is + initially empty. This is where you should put edits if you are + making changes. +LCL_ROOT: is manually created to have the same base and sub-directories as + SRC_ROOT: and VMS_ROOT: + +The logical name REF_ROOT: may be defined to be a search list for +VMS_ROOT:,SRC_ROOT: + +The logical name PRJ_ROOT: is defined to be a search list for +LCL_ROOT:,VMS_ROOT:,SRC_ROOT: + +For the make install process to work, it must have write access to the +directories referenced by the GNU: logical name. + +In future releases of GNV, and with GNV Bash 4.3.30 installed, this name +should be GNV$GNU: + +As directly updating those directories would probably be disruptive to other +users of the system and require elevated privilege, this can be handled by +creating a separate directory tree to install into which can be referenced +by the concealed rooted logical name new_gnu:. A concealed logical name of +OLD_GNU: can be set up to reference the real GNV directory tree. + +Then a local copy of the GNU/GNV$GNU logical names can be set up as a search +list such as NEW_GNU:,OLD_GNU: + +The directory NEW_GNU:[usr] should be created. The make install phase should +create all the other directories. + +The make install process may abort if curl is already because it can not +uninstall the older version of curl because it does not have permission. + +The file stage_curl_install.com is used set up a new_gnu: directory tree +for testing. The PCSI kitting procedure uses these files as input. + +These files do not create the directories in the VMS_ROOT and LCL_ROOT +directory trees. You can create them with commands similar to: + + $ create/dir lcl_root:[curl]/prot=w:re + $ copy src_root:[curl...]*.dir - + lcl_root:[curl...]/prot=(o:rwed,w:re) + $ create/dir vms_root:[curl]/prot=w:re + $ copy src_root:[curl...]*.dir - + vms_root:[curl...]/prot=(o:rwed,w:re) + +One of the ways with to protect the source from being modified is to have +the directories under src_root: owned by a user or resource where the build +username only has read access to it. + + +Note to builders: + +GNV currently has a bug where configure scripts take a long time to run. +Some of the configure steps take a while to complete, and on a 600 Mhz +DS10 with IDE disks, taking an hour to run the CURL configure is normal. + +The following messages can be ignored and may get fixed in a future version +of GNV. The GNV$*.OPT files are used to find the libraries as many have +different names on VMS than on Unix. The Bash environment variable +GNV_CC_QUALIFIERS can override all other settings for the C Compiler. + +? cc: No support for switch -warnprotos +? cc: Unrecognized file toomanyargs +? cc: Warning: library "ssl" not found +? cc: Warning: library "crypto" not found +? cc: Warning: library "gssapi" not found +? cc: Warning: library "z" not found +u unimplemented switch - ignored + + +With these search lists set up and the properly, curl can be built by +setting your default to PRJ_ROOT:[curl.packages.vms] and then issuing +either the command: + + $ @pcsi_product_gnv_curl.com + +or + + $ @build_gnv_curl.com. + +The GNV configure procedure takes considerably longer than the DCL build +procedure takes. It is of use for testing the GNV build environment, and +may not have been kept up to date. + +The pcsi_product_gnv_curl.com needs the following logical names which +are described in the section below: + + gnv_pcsi_producer + gnv_pcsi_producer_full_name + stage_root + vms_root1 (Optional if vms_root is on a NFS volume) + src_root1 (Optional if src_root is on a NFS volume) + +The pcsi_product_gnv_curl.com is described in more detail below. It does +the following steps. The build steps are only done if they are needed to +allow using either DCL or GNV based building procedures. + + $ @build_vms list + + $ @gnv_link_curl.com + + $ @build_gnv_curl_release_notes.com + + $ @backup_gnv_curl_src.com + + $ @build_gnv_curl_pcsi_desc.com + + $ @build_gnv_curl_pcsi_text.com + + $ @stage_curl_install remove + $ @stage_curl_install + + Then builds the kit. + +The build_gnv_curl.com command procedure does the following: + + $ @setup_gnv_curl_build.com + + $ bash gnv_curl_configure.sh + + $ @clean_gnv_curl.com + + $ bash make_gnv_curl_install.sh + + $ @gnv_link_curl.com + + $ @stage_curl_install.com + + $ purge new_gnu:[*...]/log + +To clean up after a GNV based build to start over, the following commands are +used: + + $ bash + bash$ cd ../.. + bash$ make clean + bash$ exit + +Then run the @clean_gnv_curl.com. Use the parameter "realclean" if you are +going to run the setup_gnv_curl_build.com and configure script again. + + $ @clean_gnv_curl.com realclean + +If new public symbols have been added, adjust the file gnv_libcurl_symbols.opt +to have the new symbols. If the symbols are longer than 32 characters, +then they will need to have the original be exact case CRC shortened and +an alias in upper case with CRC shortened, in addition to having an exact +case truncated alias and an uppercase truncated alias. + +The *.EXE files are not moved to the new_gnu: directory. + +After you are satisfied with the results of your build, you can move the +files from new_gnu: to old_gnu: at your convenience. + +Building a PCSI kit for an architecture takes the following steps after +making sure that you have a working build environment. + +Note that it requires manually creating two logical names as described +below. It is intentional that they be manually set. This is for +branding the PCSI kit based on who is making the kit. + + 1. Make sure that you have a staging directory that can be referenced + by the path STAGE_ROOT:[KIT] + + 2. Edit the file curl_release_note_start.txt or other text files to + reflect any changes. + + 3. Define the logical name GNV_PCSI_PRODUCER to indicate who is making + the distribution. For making updates to an existing open source + kit you may need to keep the producer the same. + + 4. Define the logical name GNV_PCSI_PRODUCER_FULL_NAME to be your full + name or full name of your company. + + 5. If you are producing an update kit, then update the file + vms_eco_level.h by changing the value for the VMS_ECO_LEVEL macro. + This file is currently only used in building the PCSI kit. + + 6. Edit the file PCSI_GNV_CURL_FILE_LIST.TXT if there are new files added + to the kit. These files should all be ODS-2 legal filenames and + directories. + + A limitation of the PCSI kitting procedure is that when selecting files, + it tends to ignore the directory structure and assumes that all files + with the same name are the same file, so every file placed in the kit + must have a unique name. Then a procedure needs to be added to the kit + to create an alias link on install and remove the link on remove. + + Since at this time curl does not need this alias procedure, the steps + to automatically build it are not included here. + + While newer versions of PCSI can support ODS-5 filenames, not all versions + of PCSI on systems that have ODS-5 filenames do. So as a post install + step, the PCSI kit built by these steps does a rename to the correct + case as a post install step. + + 7. Edit the build_curl_pcsi_desc.com and build_curl_pcsi_text.com if you + have changed the version of ZLIB that curl is built against. + + 8. Prepare to backup the files for building the kit. + + Note that if src_root: or vms_root: are NFS mounted disks, the + step of backing up the source files will probably hang or fail. + + You need to copy the source files to VMS mounted disks and create + logical names SRC_ROOT1 and VMS_ROOT1 to work around this to + reference local disks. Make sure src_root1:[000000] and + vms_root1:[000000] exist and can be written to. + + The command procedure compare_curl_source can be used to check + those directories and keep them up to date. + + @compare_curl_source.com SRCBCK UPDATE + + This compares the reference project source with the backup + staging directory for it and updates with any changes. + + @compare_curl_source.com VMSBCK UPDATE + + This compares the VMS specific source with the backup + staging directory for it and updates with any changes. + + Leave off "UPDATE" to just check without doing any changes. + + If you are not using NFS mounted disks and do not want to have a + separate directory for staging the sources for backup make sure + that src_root1: and vms_root1: do not exist. + + 9. Build the PCSI kit with @pcsi_product_gnv_curl.com + + The following message is normal: + %PCSI-I-CANNOTVAL, cannot validate + EAGLE$DQA0:[stage_root.][kit]VMSPORTS-AXPVMS-CURL-V0731-0-1.PCSI;1 + -PCSI-I-NOTSIGNED, product kit is not signed and therefore has + no manifest file + + This will result in an uncompressed kit for the target platform. + On Alpha and Integrity, the pcsi_product_gnv_curl.com can be used with + the "COMPRESSED" parameter to build both a compressed and uncompressed + kits. + +Good Luck. diff --git a/packages/vms/curl_release_note_start.txt b/packages/vms/curl_release_note_start.txt new file mode 100644 index 0000000..62b2836 --- /dev/null +++ b/packages/vms/curl_release_note_start.txt @@ -0,0 +1,77 @@ +From file: CURL_RELEASE_NOTE_START.TXT + +Note: These kits are produced by a hobbyist and are providing any support +or any commitment to supply bug fixes or future releases. This code is +as-is with no warranties. + +The testing of this build of curl was minimal and involved building some of +the sample and test programs, accessing a public HTTPS: website, doing a +form post of some VMS test files, and FTP upload of some text files. + +Due to the way that PCSI identifies packages, if you install a package from +one producer and then want to upgrade it from another producer, you will +probably need to uninstall the previous package first. + +OpenVMS specific building and kitting instructions are after the standard +curl readme file. + +This product may be available for your platform in a PCSI kit. The source kit +contains files for building CURL using GNV or with a DCL procedure. + +The GNV based build creates a libcurl share imaged which is supplied in the +PCSI kit. + +This version of CURL will return VMS compatible status codes when run from +DCL and Unix compatible exit codes and messages when run with the SHELL +environment variable set. + +This port of Curl uses the OpenSSL, Ldap, and Kerberos V5 that are bundled +with OpenVMS or supplied as updates by HP. Ldap and Kerberos are not available +on the VAX platform. See section below for a special note about HP OpenSSL +on Alpha and IA64. + +The supplied CURL_STARTUP.COM procedure that is installed in +[VMS$COMMON.SYS$STARTUP] can be put in your VMS startup procedure to install +the GNV$LIBCURL shared image and create logical names GNV$LIBCURL to reference +it. It will create the GNV$CURL_INCLUDE logical name for build procedures +to access the header files. + +Normally to use curl from DCL, just create a foreign command as: + curl :== $gnv$gnu:[usr.bin]gnv$curl.exe + +If you need to work around having the older HP SSL kit installed, then +for DCL create this command procedure: + + $ create/dir gnv$gnu:[vms_bin]/prot=w:re + $ create gnv$gnu:[vms_bin]curl.com + $ curl := $gnv$gnu:[usr.bin]gnv$curl.exe + $ define/user ssl$libcrypto_shr32 gnv$curl_ssl_libcryptoshr32 + $ curl "''p1'" "''p2'" "''p3'" "''p4'" "''p5'" "''p6'" "''p7'" "''p8'" + ^Z + +Then you can use: curl :== @gnv$gnu:[vms_bin]curl.com to run curl. + +For the HP SSL work around to work for GNV do the following: + $ create/dir gnv$gnu:[usr.local.bin]/prot=w:re + $ create gnv$gnu:[usr.local.bin]curl. + #! /bin/sh + dcl @gnv\$gnu:[vms_bin]curl.com $* + ^Z + +Similar workarounds will be needed for any program linked with GNV$LIBCURL +until the HP OpenSSL is upgraded to the current 1.4 version or later. + +If you are installing a "daily" build instead of a release build of Curl, some +things have been changed so that it can be installed at the same time as +a production build without conflicts. + + The CURL_DAILY_STARTUP.COM will be supplied instead of CURL_STARTUP.COM. + This file is actually not used with the daily package and is provided as + a preview of what the next CURL_STARTUP.COM will be for the next release. + Do not run it. + + The files that are normally installed in [VMS$COMMON.GNV.usr], for the + daily build are installed in [VMS$COMMON.GNV.beta] directory. + + To use the daily GNV$LIBCURL image, you will need to define the logical + name GNV$LIBCURL to the image. diff --git a/packages/vms/curl_startup.com b/packages/vms/curl_startup.com new file mode 100644 index 0000000..e90bbec --- /dev/null +++ b/packages/vms/curl_startup.com @@ -0,0 +1,98 @@ +$! File: curl_Startup.com +$! +$! Procedure to setup the CURL libraries for use by programs from the +$! VMS SYSTARTUP*.COM procedure. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!======================================================================== +$! +$! +$! GNV$GNU if needed. +$ if f$trnlnm("GNV$GNU") .eqs. "" +$ then +$ x = f$trnlnm("GNU","LNM$SYSTEM_TABLE") +$ if x .eqs. "" +$ then +$ write sys$output "GNV must be started up before this procedure. +$ exit 44 +$ endif +$ define/system/exec/trans=conc GNV$GNU 'x' +$ endif +$! +$! +$ myproc = f$environment("procedure") +$! +$! ZLIB needed. +$ if f$trnlnm("GNV$LIBZSHR32") .eqs. "" +$ then +$ zlib_startup = f$parse("gnv$zlib_startup.com;0", myproc,,,) +$ if f$search(zlib_startup) .nes. "" +$ then +$ @'zlib_startup +$ else +$ write sys$output "ZLIB package not found and is required." +$ exit 44 +$ endif +$ endif +$! +$! +$ curl_ssl_libcrypto32 = "" +$ curl_ssl_libssl32 = "" +$ gnv_ssl_libcrypto32 = "gnv$gnu:[lib]ssl$libcrypto_shr32.exe" +$ gnv_ssl_libssl32 = "gnv$gnu:[lib]ssl$libssl_shr32.exe" +$ if f$search(gnv_ssl_libcrypto32) .nes. "" +$ then +$ curl_ssl_libcrypto32 = gnv_ssl_libcrypto32 +$ curl_ssl_libssl32 = gnv_ssl_libssl32 +$ else +$ hp_ssl_libcrypto32 = "sys$share:ssl$libcrypto_shr32.exe" +$ hp_ssl_libssl32 = "sys$share:ssl$libssl_shr32.exe" +$ if f$search(hp_ssl_libcrypto32) .nes. "" +$ then +$ curl_ssl_libcrypto32 = hp_ssl_libcrypto32 +$ curl_ssl_libssl32 = hp_ssl_libssl32 +$ else +$ write sys$output "HP SSL package not found and is required." +$ endif +$ endif +$! +$ define/system/exec gnv$curl_ssl_libcryptoshr32 'curl_ssl_libcrypto32' +$ define/system/exec gnv$curl_ssl_libsslshr32 'curl_ssl_libssl32' +$! +$! +$! CURL setup +$ define/system/exec gnv$libcurl gnv$gnu:[usr.lib]GNV$LIBCURL.EXE +$ define/system/exec gnv$curl_include gnv$gnu:[usr.include.curl] +$ if .not. f$file_attributes("gnv$libcurl", "known") +$ then +$ install ADD gnv$libcurl/OPEN/SHARE/HEADER +$ else +$ install REPLACE gnv$libcurl/OPEN/SHARE/HEADER +$ endif +$! +$! +$ curl_exe = "gnv$gnu:[usr.bin]gnv$curl.exe" +$ if .not. f$file_attributes(curl_exe, "known") +$ then +$ install ADD 'curl_exe'/OPEN/SHARE/HEADER +$ else +$ install REPLACE 'curl_exe'/OPEN/SHARE/HEADER +$ endif +$! +$all_exit: +$ exit diff --git a/packages/vms/curlmsg.h b/packages/vms/curlmsg.h new file mode 100644 index 0000000..9b5c4c7 --- /dev/null +++ b/packages/vms/curlmsg.h @@ -0,0 +1,143 @@ +#ifndef HEADER_CURLMSG_H +#define HEADER_CURLMSG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#pragma __member_alignment __save +#pragma __nomember_alignment + +/* */ +/* CURLMSG.H */ +/* */ +/* SDL File Generated by VAX-11 Message V04-00 on 3-SEP-2008 13:33:54.09 */ +/* */ +/* THESE VMS ERROR CODES ARE GENERATED BY TAKING APART THE CURL.H */ +/* FILE AND PUTTING ALL THE CURLE_* ENUM STUFF INTO THIS FILE, */ +/* CURLMSG.MSG. AN .SDL FILE IS CREATED FROM THIS FILE WITH */ +/* MESSAGE/SDL. THE .H FILE IS CREATED USING THE FREEWARE SDL TOOL */ +/* AGAINST THE .SDL FILE WITH SDL/ALPHA/LANG=CC COMMAND. */ +/* */ +/* WITH THE EXCEPTION OF CURLE_OK, ALL OF THE MESSAGES ARE AT */ +/* THE ERROR SEVERITY LEVEL. WITH THE EXCEPTION OF */ +/* PEER_FAILED_VERIF, WHICH IS A SHORTENED FORM OF */ +/* PEER_FAILED_VERIFICATION, THESE ARE THE SAME NAMES AS THE */ +/* CURLE_ ONES IN INCLUDE/CURL.H. THE MESSAGE UTILITY MANUAL STATES */ +/* "THE COMBINED LENGTH OF THE PREFIX AND THE MESSAGE SYMBOL NAME CANNOT */ +/* EXCEED 31 CHARACTERS." WITH A PREFIX OF FIVE THAT LEAVES US WITH 26 */ +/* FOR THE MESSAGE NAME. */ +/* */ +/* IF YOU UPDATE THIS FILE, UPDATE CURLMSG_VMS.H SO THAT THEY ARE IN SYNC */ +/* */ + +#define CURL_FACILITY 3841 +#define CURL_OK 251756553 +#define CURL_UNSUPPORTED_PROTOCOL 251756562 +#define CURL_FAILED_INIT 251756570 +#define CURL_URL_MALFORMAT 251756578 +#define CURL_OBSOLETE4 251756586 +#define CURL_COULDNT_RESOLVE_PROXY 251756594 +#define CURL_COULDNT_RESOLVE_HOST 251756602 +#define CURL_COULDNT_CONNECT 251756610 +#define CURL_WEIRD_SERVER_REPLY 251756618 +#define CURL_FTP_WEIRD_SERVER_REPLY CURL_WEIRD_SERVER_REPLY +#define CURL_FTP_ACCESS_DENIED 251756626 +#define CURL_OBSOLETE10 251756634 +#define CURL_FTP_WEIRD_PASS_REPLY 251756642 +#define CURL_OBSOLETE12 251756650 +#define CURL_FTP_WEIRD_PASV_REPLY 251756658 +#define CURL_FTP_WEIRD_227_FORMAT 251756666 +#define CURL_FTP_CANT_GET_HOST 251756674 +#define CURL_OBSOLETE16 251756682 +#define CURL_FTP_COULDNT_SET_TYPE 251756690 +#define CURL_PARTIAL_FILE 251756698 +#define CURL_FTP_COULDNT_RETR_FILE 251756706 +#define CURL_OBSOLETE20 251756714 +#define CURL_QUOTE_ERROR 251756722 +#define CURL_HTTP_RETURNED_ERROR 251756730 +#define CURL_WRITE_ERROR 251756738 +#define CURL_OBSOLETE24 251756746 +#define CURL_UPLOAD_FAILED 251756754 +#define CURL_READ_ERROR 251756762 +#define CURL_OUT_OF_MEMORY 251756770 +#define CURL_OPERATION_TIMEOUTED 251756778 +#define CURL_OBSOLETE29 251756786 +#define CURL_FTP_PORT_FAILED 251756794 +#define CURL_FTP_COULDNT_USE_REST 251756802 +#define CURL_OBSOLETE32 251756810 +#define CURL_RANGE_ERROR 251756818 +#define CURL_HTTP_POST_ERROR 251756826 +#define CURL_SSL_CONNECT_ERROR 251756834 +#define CURL_BAD_DOWNLOAD_RESUME 251756842 +#define CURL_FILE_COULDNT_READ_FILE 251756850 +#define CURL_LDAP_CANNOT_BIND 251756858 +#define CURL_LDAP_SEARCH_FAILED 251756866 +#define CURL_OBSOLETE40 251756874 +#define CURL_FUNCTION_NOT_FOUND 251756882 +#define CURL_ABORTED_BY_CALLBACK 251756890 +#define CURL_BAD_FUNCTION_ARGUMENT 251756898 +#define CURL_OBSOLETE44 251756906 +#define CURL_INTERFACE_FAILED 251756914 +#define CURL_OBSOLETE46 251756922 +#define CURL_TOO_MANY_REDIRECTS 251756930 +#define CURL_UNKNOWN_TELNET_OPTION 251756938 +#define CURL_TELNET_OPTION_SYNTAX 251756946 +#define CURL_OBSOLETE50 251756954 +#define CURL_PEER_FAILED_VERIF 251756962 +#define CURL_GOT_NOTHING 251756970 +#define CURL_SSL_ENGINE_NOTFOUND 251756978 +#define CURL_SSL_ENGINE_SETFAILED 251756986 +#define CURL_SEND_ERROR 251756994 +#define CURL_RECV_ERROR 251757002 +#define CURL_OBSOLETE57 251757010 +#define CURL_SSL_CERTPROBLEM 251757018 +#define CURL_SSL_CIPHER 251757026 +#define CURL_SSL_CACERT 251757034 +#define CURL_BAD_CONTENT_ENCODING 251757042 +#define CURL_LDAP_INVALID_URL 251757050 +#define CURL_FILESIZE_EXCEEDED 251757058 +#define CURL_USE_SSL_FAILED 251757066 +#define CURL_SEND_FAIL_REWIND 251757074 +#define CURL_SSL_ENGINE_INITFAILED 251757082 +#define CURL_LOGIN_DENIED 251757090 +#define CURL_TFTP_NOTFOUND 251757098 +#define CURL_TFTP_PERM 251757106 +#define CURL_REMOTE_DISK_FULL 251757114 +#define CURL_TFTP_ILLEGAL 251757122 +#define CURL_TFTP_UNKNOWNID 251757130 +#define CURL_REMOTE_FILE_EXISTS 251757138 +#define CURL_TFTP_NOSUCHUSER 251757146 +#define CURL_CONV_FAILED 251757154 +#define CURL_CONV_REQD 251757162 +#define CURL_SSL_CACERT_BADFILE 251757170 +#define CURL_REMOTE_FILE_NOT_FOUND 251757178 +#define CURL_SSH 251757186 +#define CURL_SSL_SHUTDOWN_FAILED 251757194 +#define CURL_AGAIN 251757202 +#define CURL_SSL_CRL_BADFILE 251757210 +#define CURL_SSL_ISSUER_ERROR 251757218 +#define CURL_CURL_LAST 251757226 + +#pragma __member_alignment __restore + +#endif /* HEADER_CURLMSG_H */ diff --git a/packages/vms/curlmsg.msg b/packages/vms/curlmsg.msg new file mode 100644 index 0000000..ac2d508 --- /dev/null +++ b/packages/vms/curlmsg.msg @@ -0,0 +1,134 @@ +!*************************************************************************** +! _ _ ____ _ +! Project ___| | | | _ \| | +! / __| | | | |_) | | +! | (__| |_| | _ <| |___ +! \___|\___/|_| \_\_____| +! +! Copyright (C) Daniel Stenberg, , et al. +! +! This software is licensed as described in the file COPYING, which +! you should have received as part of this distribution. The terms +! are also available at https://curl.se/docs/copyright.html. +! +! You may opt to use, copy, modify, merge, publish, distribute and/or sell +! copies of the Software, and permit persons to whom the Software is +! furnished to do so, under the terms of the COPYING file. +! +! This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +! KIND, either express or implied. +! +! SPDX-License-Identifier: curl +! +!########################################################################## +! +! These VMS error codes are generated by taking apart the curl.h +! file and putting all the CURLE_* enum stuff into this file, +! CURLMSG.MSG. An .SDL file is created from this file with +! MESSAGE/SDL. The .H file is created using the freeware SDL tool +! against the .SDL file with SDL/ALPHA/LANG=CC command. +! +! With the exception of CURLE_OK, all of the messages are at +! the error severity level. With the exception of +! PEER_FAILED_VERIF, which is a shortened form of +! PEER_FAILED_VERIFICATION, these are the same names as the +! CURLE_ ones in include/curl.h. The Message Utility manual states +! "The combined length of the prefix and the message symbol name cannot +! exceed 31 characters." With a prefix of five that leaves us with 26 +! for the message name. +! +! If you update this file also update curlmsg_vms.h so that they are in sync +! +.TITLE CURLMSG Message files +.FACILITY CURL,1793 /PREFIX=CURL_ +.BASE 1 +.SEVERITY SUCCESS +OK + +.SEVERITY ERROR +UNSUPPORTED_PROTOCOL +FAILED_INIT +URL_MALFORMAT +OBSOLETE4 +COULDNT_RESOLVE_PROXY +COULDNT_RESOLVE_HOST +COULDNT_CONNECT +WEIRD_SERVER_REPLY +FTP_ACCESS_DENIED +OBSOLETE10 +FTP_WEIRD_PASS_REPLY +OBSOLETE12 +FTP_WEIRD_PASV_REPLY +FTP_WEIRD_227_FORMAT +FTP_CANT_GET_HOST +OBSOLETE16 +FTP_COULDNT_SET_TYPE +PARTIAL_FILE +FTP_COULDNT_RETR_FILE +OBSOLETE20 +QUOTE_ERROR +HTTP_RETURNED_ERROR +WRITE_ERROR +OBSOLETE24 +UPLOAD_FAILED +READ_ERROR +OUT_OF_MEMORY +OPERATION_TIMEOUTED +OBSOLETE29 +FTP_PORT_FAILED +FTP_COULDNT_USE_REST +OBSOLETE32 +RANGE_ERROR +HTTP_POST_ERROR +SSL_CONNECT_ERROR +BAD_DOWNLOAD_RESUME +FILE_COULDNT_READ_FILE +LDAP_CANNOT_BIND +LDAP_SEARCH_FAILED +OBSOLETE40 +FUNCTION_NOT_FOUND +ABORTED_BY_CALLBACK +BAD_FUNCTION_ARGUMENT +OBSOLETE44 +INTERFACE_FAILED +OBSOLETE46 +TOO_MANY_REDIRECTS +UNKNOWN_TELNET_OPTION +TELNET_OPTION_SYNTAX +OBSOLETE50 +PEER_FAILED_VERIF +GOT_NOTHING +SSL_ENGINE_NOTFOUND +SSL_ENGINE_SETFAILED +SEND_ERROR +RECV_ERROR +OBSOLETE57 +SSL_CERTPROBLEM +SSL_CIPHER +SSL_CACERT +BAD_CONTENT_ENCODING +LDAP_INVALID_URL +FILESIZE_EXCEEDED +USE_SSL_FAILED +SEND_FAIL_REWIND +SSL_ENGINE_INITFAILED +LOGIN_DENIED +TFTP_NOTFOUND +TFTP_PERM +REMOTE_DISK_FULL +TFTP_ILLEGAL +TFTP_UNKNOWNID +REMOTE_FILE_EXISTS +TFTP_NOSUCHUSER +CONV_FAILED +CONV_REQD +SSL_CACERT_BADFILE +REMOTE_FILE_NOT_FOUND +SSH +SSL_SHUTDOWN_FAILED +AGAIN +SSL_CRL_BADFILE +SSL_ISSUER_ERROR +CURL_LAST + +.END diff --git a/packages/vms/curlmsg.sdl b/packages/vms/curlmsg.sdl new file mode 100644 index 0000000..db5baad --- /dev/null +++ b/packages/vms/curlmsg.sdl @@ -0,0 +1,116 @@ + + + MODULE $CURDEF; + +/* +/* This SDL File Generated by VAX-11 Message V04-00 on 3-SEP-2008 13:33:54.09 +/* +/* $ID: CURLMSG.MSG,V 1.7 2008-05-30 23:51:09 CURLVMS EXP $ +/* +/* THESE VMS ERROR CODES ARE GENERATED BY TAKING APART THE CURL.H +/* FILE AND PUTTING ALL THE CURLE_* ENUM STUFF INTO THIS FILE, +/* CURLMSG.MSG. AN .SDL FILE IS CREATED FROM THIS FILE WITH +/* MESSAGE/SDL. THE .H FILE IS CREATED USING THE FREEWARE SDL TOOL +/* AGAINST THE .SDL FILE WITH SDL/ALPHA/LANG=CC COMMAND. +/* +/* WITH THE EXCEPTION OF CURLE_OK, ALL OF THE MESSAGES ARE AT +/* THE ERROR SEVERITY LEVEL. WITH THE EXCEPTION OF +/* PEER_FAILED_VERIF, WHICH IS A SHORTENED FORM OF +/* PEER_FAILED_VERIFICATION, THESE ARE THE SAME NAMES AS THE +/* CURLE_ ONES IN INCLUDE/CURL.H. THE MESSAGE UTILITY MANUAL STATES +/* "THE COMBINED LENGTH OF THE PREFIX AND THE MESSAGE SYMBOL NAME CANNOT +/* EXCEED 31 CHARACTERS." WITH A PREFIX OF FIVE THAT LEAVES US WITH 26 +/* FOR THE MESSAGE NAME. +/* +/* IF YOU UPDATE THIS FILE ALSO UPDATE CURLMSG_VMS.H SO THAT THEY ARE IN SYNC +/* + CONSTANT + "FACILITY" EQUALS 3841 PREFIX "CURL" TAG "" + ,"OK" EQUALS %X0F018009 PREFIX "CURL" TAG "" + ,"UNSUPPORTED_PROTOCOL" EQUALS %X0F018012 PREFIX "CURL" TAG "" + ,"FAILED_INIT" EQUALS %X0F01801A PREFIX "CURL" TAG "" + ,"URL_MALFORMAT" EQUALS %X0F018022 PREFIX "CURL" TAG "" + ,"OBSOLETE4" EQUALS %X0F01802A PREFIX "CURL" TAG "" + ,"COULDNT_RESOLVE_PROXY" EQUALS %X0F018032 PREFIX "CURL" TAG "" + ,"COULDNT_RESOLVE_HOST" EQUALS %X0F01803A PREFIX "CURL" TAG "" + ,"COULDNT_CONNECT" EQUALS %X0F018042 PREFIX "CURL" TAG "" + ,"WEIRD_SERVER_REPLY" EQUALS %X0F01804A PREFIX "CURL" TAG "" + ,"FTP_WEIRD_SERVER_REPLY" EQUALS %X0F01804A PREFIX "CURL" TAG "" + ,"FTP_ACCESS_DENIED" EQUALS %X0F018052 PREFIX "CURL" TAG "" + ,"OBSOLETE10" EQUALS %X0F01805A PREFIX "CURL" TAG "" + ,"FTP_WEIRD_PASS_REPLY" EQUALS %X0F018062 PREFIX "CURL" TAG "" + ,"OBSOLETE12" EQUALS %X0F01806A PREFIX "CURL" TAG "" + ,"FTP_WEIRD_PASV_REPLY" EQUALS %X0F018072 PREFIX "CURL" TAG "" + ,"FTP_WEIRD_227_FORMAT" EQUALS %X0F01807A PREFIX "CURL" TAG "" + ,"FTP_CANT_GET_HOST" EQUALS %X0F018082 PREFIX "CURL" TAG "" + ,"OBSOLETE16" EQUALS %X0F01808A PREFIX "CURL" TAG "" + ,"FTP_COULDNT_SET_TYPE" EQUALS %X0F018092 PREFIX "CURL" TAG "" + ,"PARTIAL_FILE" EQUALS %X0F01809A PREFIX "CURL" TAG "" + ,"FTP_COULDNT_RETR_FILE" EQUALS %X0F0180A2 PREFIX "CURL" TAG "" + ,"OBSOLETE20" EQUALS %X0F0180AA PREFIX "CURL" TAG "" + ,"QUOTE_ERROR" EQUALS %X0F0180B2 PREFIX "CURL" TAG "" + ,"HTTP_RETURNED_ERROR" EQUALS %X0F0180BA PREFIX "CURL" TAG "" + ,"WRITE_ERROR" EQUALS %X0F0180C2 PREFIX "CURL" TAG "" + ,"OBSOLETE24" EQUALS %X0F0180CA PREFIX "CURL" TAG "" + ,"UPLOAD_FAILED" EQUALS %X0F0180D2 PREFIX "CURL" TAG "" + ,"READ_ERROR" EQUALS %X0F0180DA PREFIX "CURL" TAG "" + ,"OUT_OF_MEMORY" EQUALS %X0F0180E2 PREFIX "CURL" TAG "" + ,"OPERATION_TIMEOUTED" EQUALS %X0F0180EA PREFIX "CURL" TAG "" + ,"OBSOLETE29" EQUALS %X0F0180F2 PREFIX "CURL" TAG "" + ,"FTP_PORT_FAILED" EQUALS %X0F0180FA PREFIX "CURL" TAG "" + ,"FTP_COULDNT_USE_REST" EQUALS %X0F018102 PREFIX "CURL" TAG "" + ,"OBSOLETE32" EQUALS %X0F01810A PREFIX "CURL" TAG "" + ,"RANGE_ERROR" EQUALS %X0F018112 PREFIX "CURL" TAG "" + ,"HTTP_POST_ERROR" EQUALS %X0F01811A PREFIX "CURL" TAG "" + ,"SSL_CONNECT_ERROR" EQUALS %X0F018122 PREFIX "CURL" TAG "" + ,"BAD_DOWNLOAD_RESUME" EQUALS %X0F01812A PREFIX "CURL" TAG "" + ,"FILE_COULDNT_READ_FILE" EQUALS %X0F018132 PREFIX "CURL" TAG "" + ,"LDAP_CANNOT_BIND" EQUALS %X0F01813A PREFIX "CURL" TAG "" + ,"LDAP_SEARCH_FAILED" EQUALS %X0F018142 PREFIX "CURL" TAG "" + ,"OBSOLETE40" EQUALS %X0F01814A PREFIX "CURL" TAG "" + ,"FUNCTION_NOT_FOUND" EQUALS %X0F018152 PREFIX "CURL" TAG "" + ,"ABORTED_BY_CALLBACK" EQUALS %X0F01815A PREFIX "CURL" TAG "" + ,"BAD_FUNCTION_ARGUMENT" EQUALS %X0F018162 PREFIX "CURL" TAG "" + ,"OBSOLETE44" EQUALS %X0F01816A PREFIX "CURL" TAG "" + ,"INTERFACE_FAILED" EQUALS %X0F018172 PREFIX "CURL" TAG "" + ,"OBSOLETE46" EQUALS %X0F01817A PREFIX "CURL" TAG "" + ,"TOO_MANY_REDIRECTS" EQUALS %X0F018182 PREFIX "CURL" TAG "" + ,"UNKNOWN_TELNET_OPTION" EQUALS %X0F01818A PREFIX "CURL" TAG "" + ,"TELNET_OPTION_SYNTAX" EQUALS %X0F018192 PREFIX "CURL" TAG "" + ,"OBSOLETE50" EQUALS %X0F01819A PREFIX "CURL" TAG "" + ,"PEER_FAILED_VERIF" EQUALS %X0F0181A2 PREFIX "CURL" TAG "" + ,"GOT_NOTHING" EQUALS %X0F0181AA PREFIX "CURL" TAG "" + ,"SSL_ENGINE_NOTFOUND" EQUALS %X0F0181B2 PREFIX "CURL" TAG "" + ,"SSL_ENGINE_SETFAILED" EQUALS %X0F0181BA PREFIX "CURL" TAG "" + ,"SEND_ERROR" EQUALS %X0F0181C2 PREFIX "CURL" TAG "" + ,"RECV_ERROR" EQUALS %X0F0181CA PREFIX "CURL" TAG "" + ,"OBSOLETE57" EQUALS %X0F0181D2 PREFIX "CURL" TAG "" + ,"SSL_CERTPROBLEM" EQUALS %X0F0181DA PREFIX "CURL" TAG "" + ,"SSL_CIPHER" EQUALS %X0F0181E2 PREFIX "CURL" TAG "" + ,"SSL_CACERT" EQUALS %X0F0181EA PREFIX "CURL" TAG "" + ,"BAD_CONTENT_ENCODING" EQUALS %X0F0181F2 PREFIX "CURL" TAG "" + ,"LDAP_INVALID_URL" EQUALS %X0F0181FA PREFIX "CURL" TAG "" + ,"FILESIZE_EXCEEDED" EQUALS %X0F018202 PREFIX "CURL" TAG "" + ,"USE_SSL_FAILED" EQUALS %X0F01820A PREFIX "CURL" TAG "" + ,"SEND_FAIL_REWIND" EQUALS %X0F018212 PREFIX "CURL" TAG "" + ,"SSL_ENGINE_INITFAILED" EQUALS %X0F01821A PREFIX "CURL" TAG "" + ,"LOGIN_DENIED" EQUALS %X0F018222 PREFIX "CURL" TAG "" + ,"TFTP_NOTFOUND" EQUALS %X0F01822A PREFIX "CURL" TAG "" + ,"TFTP_PERM" EQUALS %X0F018232 PREFIX "CURL" TAG "" + ,"REMOTE_DISK_FULL" EQUALS %X0F01823A PREFIX "CURL" TAG "" + ,"TFTP_ILLEGAL" EQUALS %X0F018242 PREFIX "CURL" TAG "" + ,"TFTP_UNKNOWNID" EQUALS %X0F01824A PREFIX "CURL" TAG "" + ,"REMOTE_FILE_EXISTS" EQUALS %X0F018252 PREFIX "CURL" TAG "" + ,"TFTP_NOSUCHUSER" EQUALS %X0F01825A PREFIX "CURL" TAG "" + ,"CONV_FAILED" EQUALS %X0F018262 PREFIX "CURL" TAG "" + ,"CONV_REQD" EQUALS %X0F01826A PREFIX "CURL" TAG "" + ,"SSL_CACERT_BADFILE" EQUALS %X0F018272 PREFIX "CURL" TAG "" + ,"REMOTE_FILE_NOT_FOUND" EQUALS %X0F01827A PREFIX "CURL" TAG "" + ,"SSH" EQUALS %X0F018282 PREFIX "CURL" TAG "" + ,"SSL_SHUTDOWN_FAILED" EQUALS %X0F01828A PREFIX "CURL" TAG "" + ,"AGAIN" EQUALS %X0F018292 PREFIX "CURL" TAG "" + ,"SSL_CRL_BADFILE" EQUALS %X0F01829A PREFIX "CURL" TAG "" + ,"SSL_ISSUER_ERROR" EQUALS %X0F0182A2 PREFIX "CURL" TAG "" + ,"CURL_LAST" EQUALS %X0F0182AA PREFIX "CURL" TAG "" + ; + END_MODULE; diff --git a/packages/vms/curlmsg_vms.h b/packages/vms/curlmsg_vms.h new file mode 100644 index 0000000..bb64702 --- /dev/null +++ b/packages/vms/curlmsg_vms.h @@ -0,0 +1,143 @@ +#ifndef HEADER_CURLMSG_VMS_H +#define HEADER_CURLMSG_VMS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* */ +/* CURLMSG_VMS.H */ +/* */ +/* This defines the necessary bits to change CURLE_* error codes to VMS */ +/* style error codes. CURLMSG.H is built from CURLMSG.SDL which is built */ +/* from CURLMSG.MSG. The vms_cond array is used to return VMS errors by */ +/* putting the VMS error codes into the array offset based on CURLE_* code. */ +/* */ +/* If you update CURLMSG.MSG make sure to update this file to match. */ +/* */ + +#include "curlmsg.h" + +/* +#define FAC_CURL 0xC01 +#define FAC_SYSTEM 0 +#define MSG_NORMAL 0 +*/ + +/* +#define SEV_WARNING 0 +#define SEV_SUCCESS 1 +#define SEV_ERROR 2 +#define SEV_INFO 3 +#define SEV_FATAL 4 +*/ + +static const long vms_cond[] = + { + CURL_OK, + CURL_UNSUPPORTED_PROTOCOL, + CURL_FAILED_INIT, + CURL_URL_MALFORMAT, + CURL_OBSOLETE4, + CURL_COULDNT_RESOLVE_PROXY, + CURL_COULDNT_RESOLVE_HOST, + CURL_COULDNT_CONNECT, + CURL_WEIRD_SERVER_REPLY, + CURL_FTP_ACCESS_DENIED, + CURL_OBSOLETE10, + CURL_FTP_WEIRD_PASS_REPLY, + CURL_OBSOLETE12, + CURL_FTP_WEIRD_PASV_REPLY, + CURL_FTP_WEIRD_227_FORMAT, + CURL_FTP_CANT_GET_HOST, + CURL_OBSOLETE16, + CURL_FTP_COULDNT_SET_TYPE, + CURL_PARTIAL_FILE, + CURL_FTP_COULDNT_RETR_FILE, + CURL_OBSOLETE20, + CURL_QUOTE_ERROR, + CURL_HTTP_RETURNED_ERROR, + CURL_WRITE_ERROR, + CURL_OBSOLETE24, + CURL_UPLOAD_FAILED, + CURL_READ_ERROR, + CURL_OUT_OF_MEMORY, + CURL_OPERATION_TIMEOUTED, + CURL_OBSOLETE29, + CURL_FTP_PORT_FAILED, + CURL_FTP_COULDNT_USE_REST, + CURL_OBSOLETE32, + CURL_RANGE_ERROR, + CURL_HTTP_POST_ERROR, + CURL_SSL_CONNECT_ERROR, + CURL_BAD_DOWNLOAD_RESUME, + CURL_FILE_COULDNT_READ_FILE, + CURL_LDAP_CANNOT_BIND, + CURL_LDAP_SEARCH_FAILED, + CURL_OBSOLETE40, + CURL_FUNCTION_NOT_FOUND, + CURL_ABORTED_BY_CALLBACK, + CURL_BAD_FUNCTION_ARGUMENT, + CURL_OBSOLETE44, + CURL_INTERFACE_FAILED, + CURL_OBSOLETE46, + CURL_TOO_MANY_REDIRECTS, + CURL_UNKNOWN_TELNET_OPTION, + CURL_TELNET_OPTION_SYNTAX, + CURL_OBSOLETE50, + CURL_PEER_FAILED_VERIF, + CURL_GOT_NOTHING, + CURL_SSL_ENGINE_NOTFOUND, + CURL_SSL_ENGINE_SETFAILED, + CURL_SEND_ERROR, + CURL_RECV_ERROR, + CURL_OBSOLETE57, + CURL_SSL_CERTPROBLEM, + CURL_SSL_CIPHER, + CURL_SSL_CACERT, + CURL_BAD_CONTENT_ENCODING, + CURL_LDAP_INVALID_URL, + CURL_FILESIZE_EXCEEDED, + CURL_USE_SSL_FAILED, + CURL_SEND_FAIL_REWIND, + CURL_SSL_ENGINE_INITFAILED, + CURL_LOGIN_DENIED, + CURL_TFTP_NOTFOUND, + CURL_TFTP_PERM, + CURL_REMOTE_DISK_FULL, + CURL_TFTP_ILLEGAL, + CURL_TFTP_UNKNOWNID, + CURL_REMOTE_FILE_EXISTS, + CURL_TFTP_NOSUCHUSER, + CURL_CONV_FAILED, + CURL_CONV_REQD, + CURL_SSL_CACERT_BADFILE, + CURL_REMOTE_FILE_NOT_FOUND, + CURL_SSH, + CURL_SSL_SHUTDOWN_FAILED, + CURL_AGAIN, + CURLE_SSL_CRL_BADFILE, + CURLE_SSL_ISSUER_ERROR, + CURL_CURL_LAST + }; + +#endif /* HEADER_CURLMSG_VMS_H */ diff --git a/packages/vms/generate_config_vms_h_curl.com b/packages/vms/generate_config_vms_h_curl.com new file mode 100644 index 0000000..99a39c8 --- /dev/null +++ b/packages/vms/generate_config_vms_h_curl.com @@ -0,0 +1,450 @@ +$! File: GENERATE_CONFIG_H_CURL.COM +$! +$! Curl like most open source products uses a variant of a config.h file. +$! Depending on the curl version, this could be config.h or curl_config.h. +$! +$! For GNV based builds, the configure script is run and that produces +$! a [curl_]config.h file. Configure scripts on VMS generally do not +$! know how to do everything, so there is also a [-.lib]config-vms.h file +$! that has VMS specific code that compensates for bugs in some of the +$! VMS shared images. +$! +$! This generates a [curl_]config.h file and also a config_vms.h file, +$! which is used to supplement that file. Note that the config_vms.h file +$! and the [.lib]config-vms.h file do two different tasks and that the +$! filenames are slightly different. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!========================================================================= +$! +$! Allow arguments to be grouped together with comma or separated by spaces +$! Do no know if we will need more than 8. +$args = "," + p1 + "," + p2 + "," + p3 + "," + p4 + "," +$args = args + p5 + "," + p6 + "," + p7 + "," + p8 + "," +$! +$! Provide lower case version to simplify parsing. +$args_lower = f$edit(args, "LOWERCASE") +$! +$args_len = f$length(args) +$! +$if (f$getsyi("HW_MODEL") .lt. 1024) +$then +$ arch_name = "VAX" +$else +$ arch_name = "" +$ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") +$ if (arch_name .eqs. "") then arch_name = "UNK" +$endif +$! +$! +$nossl = 0 +$nohpssl = 1 +$hpssl = 0 +$libidn = 0 +$libssh2 = 0 +$noldap = 0 +$nozlib = 0 +$nokerberos = 0 +$! +$! First check to see if SSL is disabled. +$!--------------------------------------- +$if f$locate(",nossl,", args_lower) .lt. args_len then nossl = 1 +$if .not. nossl +$then +$! +$! ssl$* logicals means HP ssl is present +$!---------------------------------------- +$ if f$trnlnm("ssl$root") .nes. "" +$ then +$ nohpssl = 0 +$ hpssl = 1 +$ endif +$! +$! HP defines OPENSSL as SSL$INCLUDE as a convenience for linking. +$! As it is a violation of VMS standards for this to be provided, +$! some sites may have removed it, but if present, assume that +$! it indicates which OpenSSL to use. +$!------------------------------------ +$ openssl_lnm = f$trnlnm("OPENSSL") +$ if (openssl_lnm .nes. "SYS$INCLUDE") +$ then +$! Non HP SSL is installed, default to use it. +$ nohpssl = 1 +$ hpssl = 0 +$ endif +$! +$! Now check to see if hpssl has been specifically disabled +$!---------------------------------------------------------- +$ if f$locate(",nohpssl,", args_lower) .lt. args_len +$ then +$ nohpssl = 1 +$ hpssl = 0 +$ endif +$! +$! Finally check to see if hp ssl has been specifically included. +$!---------------------------------------------------------------- +$ if f$locate(",nohpssl,", args_lower) .lt. args_len +$ then +$ nohpssl = 1 +$ hpssl = 0 +$ endif +$endif +$! +$! Did someone port LIBIDN in the GNV compatible way? +$!------------------------------------------------------ +$if f$trnlnm("GNV$LIBIDNSHR") .nes. "" +$then +$ write sys$output "NOTICE: A LIBIDN port has been detected." +$ write sys$output " This port of curl for VMS has not been tested with it." +$ if f$locate(",libidn,", args_lower) .lt. args_len +$ then +$ libidn = 1 +$ endif +$ if .not. libidn +$ then +$ write sys$output " LIBIDN support is not enabled." +$ write sys$output "Run with the ""libidn"" parameter to attempt to use." +$ else +$ write sys$output " Untested LIBIDN support requested." +$ endif +$endif +$! +$! Did someone port LIBSSH2 in the GNV compatible way? +$!------------------------------------------------------ +$if f$trnlnm("GNV$LIBSSH2SHR") .nes. "" +$then +$ write sys$output "NOTICE: A LIBSSH2 port has been detected." +$ write sys$output " This port of curl for VMS has not been tested with it." +$ if f$locate(",libssh2,", args_lower) .lt. args_len +$ then +$ libssh2 = 1 +$ endif +$ if .not. libssh2 +$ then +$ write sys$output " LIBSSH2 support is not enabled." +$ write sys$output "Run with the ""libssh2"" parameter to attempt to use." +$ else +$ write sys$output " Untested LIBSSH2 support requested." +$ endif +$endif +$! +$! LDAP suppressed? +$if f$locate(",noldap,", args_lower) .lt. args_len +$then +$ noldap = 1 +$endif +$if f$search("SYS$SHARE:LDAP$SHR.EXE") .eqs. "" +$then +$ noldap = 1 +$endif +$! +$if f$locate(",nokerberos,", args_lower) .lt. args_len then nokerberos = 1 +$if .not. nokerberos +$then +$! If kerberos is installed: sys$share:gss$rtl.exe exists. +$ if f$search("sys$shsare:gss$rtl.exe") .eqs. "" +$ then +$ nokerberos = 1 +$ endif +$endif +$! +$! +$! Is GNV compatible LIBZ present? +$!------------------------------------------------------ +$if f$trnlnm("GNV$LIBZSHR") .nes. "" +$then +$ if f$locate(",nozlib,", args_lower) .lt. args_len +$ then +$ nozlib = 1 +$ endif +$! if .not. nozlib +$! then +$! write sys$output " GNV$LIBZSHR support is enabled." +$! else +$! write sys$output " GNV$LIBZSHR support is disabled by nozlib." +$! endif +$else +$ nozlib = 1 +$endif +$! +$! +$! Start the configuration file. +$! Need to do a create and then an append to make the file have the +$! typical file attributes of a VMS text file. +$create sys$disk:[curl.lib]config_vms.h +$open/append cvh sys$disk:[curl.lib]config_vms.h +$! +$! Write the defines to prevent multiple includes. +$! These are probably not needed in this case, +$! but are best practice to put on all header files. +$write cvh "#ifndef __CONFIG_VMS_H__" +$write cvh "#define __CONFIG_VMS_H__" +$write cvh "" +$write cvh "/* Define cpu-machine-OS */" +$! +$! Curl uses an OS macro to set the build environment. +$!---------------------------------------------------- +$! Now the DCL builds usually say xxx-HP-VMS and configure scripts +$! may put DEC or COMPAQ or HP for the middle part. +$! +$write cvh "#if defined(__alpha)" +$write cvh "#define OS ""ALPHA-HP-VMS""" +$write cvh "#elif defined(__vax)" +$write cvh "#define OS ""VAX-HP-VMS""" +$write cvh "#elif defined(__ia64)" +$write cvh "#define OS ""IA64-HP-VMS"" +$write cvh "#else" +$write cvh "#define OS ""UNKNOWN-HP-VMS"" +$write cvh "#endif" +$write cvh "" +$! +$! We are now setting this on the GNV build, so also do this +$! for compatibility. +$write cvh "/* Location of default ca path */" +$write cvh "#define curl_ca_path ""gnv$curl_ca_path""" +$! +$! NTLM_WB_ENABLED requires fork() but configure does not know this +$! We have to disable this in the configure command line. +$! config_h.com finds that configure defaults to it being enabled so +$! reports it. So we need to turn it off here. +$! +$write cvh "#ifdef NTLM_WB_ENABLED" +$write cvh "#undef NTLM_WB_ENABLED" +$write cvh "#endif" +$! +$! The config_h.com finds a bunch of default disable commands in +$! configure and will incorrectly disable these options. The config_h.com +$! is a generic procedure and it would break more things to try to fix it +$! to special case it for curl. So we will fix it here. +$! +$! We do them all here, even the ones that config_h.com currently gets correct. +$! +$write cvh "#ifdef CURL_DISABLE_COOKIES" +$write cvh "#undef CURL_DISABLE_COOKIES" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_DICT" +$write cvh "#undef CURL_DISABLE_DICT" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_FILE" +$write cvh "#undef CURL_DISABLE_FILE" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_FTP" +$write cvh "#undef CURL_DISABLE_FTP" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_GOPHER" +$write cvh "#undef CURL_DISABLE_GOPHER" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_HTTP" +$write cvh "#undef CURL_DISABLE_HTTP" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_IMAP" +$write cvh "#undef CURL_DISABLE_IMAP" +$write cvh "#endif" +$if .not. noldap +$then +$ write cvh "#ifdef CURL_DISABLE_LDAP" +$ write cvh "#undef CURL_DISABLE_LDAP" +$ write cvh "#endif" +$ if .not. nossl +$ then +$ write cvh "#ifdef CURL_DISABLE_LDAPS" +$ write cvh "#undef CURL_DISABLE_LDAPS" +$ write cvh "#endif" +$ endif +$endif +$write cvh "#ifdef CURL_DISABLE_LIBCURL_OPTION" +$write cvh "#undef CURL_DISABLE_LIBCURL_OPTION" +$write cvh "#endif" +$write cvh "#ifndef __VAX" +$write cvh "#ifdef CURL_DISABLE_NTLM" +$write cvh "#undef CURL_DISABLE_NTLM" +$write cvh "#endif" +$write cvh "#else" +$! NTLM needs long long or int64 support, missing from DECC C. +$write cvh "#ifdef __DECC +$write cvh "#ifndef CURL_DISABLE_NTLM" +$write cvh "#define CURL_DISABLE_NTLM 1" +$write cvh "#endif" +$write cvh "#endif" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_POP3" +$write cvh "#undef CURL_DISABLE_POP3" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_PROXY" +$write cvh "#undef CURL_DISABLE_PROXY" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_RTSP" +$write cvh "#undef CURL_DISABLE_RTSP" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_SMTP" +$write cvh "#undef CURL_DISABLE_SMTP" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_TELNET" +$write cvh "#undef CURL_DISABLE_TELNET" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_TFTP" +$write cvh "#undef CURL_DISABLE_TFTP" +$write cvh "#endif" +$write cvh "#ifdef CURL_DISABLE_POP3" +$write cvh "#undef CURL_DISABLE_POP3" +$write cvh "#endif" +$if .not. nossl +$then +$ write cvh "#ifdef CURL_DISABLE_TLS_SRP" +$ write cvh "#undef CURL_DISABLE_TLS_SRP" +$ write cvh "#endif" +$! +$endif +$write cvh "#ifdef CURL_DISABLE_VERBOSE_STRINGS" +$write cvh "#undef CURL_DISABLE_VERBOSE_STRINGS" +$write cvh "#endif" +$! +$! configure defaults to USE_*, a real configure on VMS chooses different. +$write cvh "#ifdef USE_ARES" +$write cvh "#undef USE_ARES" +$write cvh "#endif" +$write cvh "#ifdef USE_WOLFSSL" +$write cvh "#undef USE_WOLFSSL" +$write cvh "#endif" +$write cvh "#ifdef USE_GNUTLS" +$write cvh "#undef USE_GNUTLS" +$write cvh "#endif" +$write cvh "#ifdef USE_LIBRTMP" +$write cvh "#undef USE_LIBRTMP" +$write cvh "#endif" +$write cvh "#ifdef USE_MANUAL" +$write cvh "#undef USE_MANUAL" +$write cvh "#endif" +$write cvh "#ifdef USE_NGHTTP2" +$write cvh "#undef USE_NGHTTP2" +$write cvh "#endif" +$write cvh "#ifdef USE_OPENLDAP" +$write cvh "#undef USE_OPENLDAP" +$write cvh "#endif" +$write cvh "#ifdef USE_THREADS_POSIX" +$write cvh "#undef USE_THREADS_POSIX" +$write cvh "#endif" +$write cvh "#ifdef USE_TLS_SRP" +$write cvh "#undef USE_TLS_SRP" +$write cvh "#endif" +$write cvh "#ifdef USE_UNIX_SOCKETS" +$write cvh "#undef USE_UNIX_SOCKETS" +$write cvh "#endif" +$! +$write cvh "#ifndef HAVE_OLD_GSSMIT" +$write cvh "#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE" +$write cvh "#endif" +$! +$! +$! Note: +$! The CURL_EXTERN_SYMBOL is used for platforms that need the compiler +$! to know about universal symbols. VMS does not need this support so +$! we do not set it here. +$! +$! +$! I can not figure out where the C compiler is finding the ALLOCA.H file +$! in the text libraries, so CONFIG_H.COM can not find it either. +$! Usually the header file name is the module name in the text library. +$! It does not appear to hurt anything to not find header file, so we +$! are not overriding it here. +$! +$! +$! Check to see if OpenSSL is present. +$!---------------------------------- +$ssl_include = f$trnlnm("OPENSSL") +$if ssl_include .eqs. "" +$then +$ ssl_include = f$trnlnm("ssl$include") +$endif +$if ssl_include .eqs. "" then nossl = 1 +$! +$if .not. nossl +$then +$! +$ write cvh "#ifndef USE_OPENSSL" +$ write cvh "#define USE_OPENSSL 1" +$ write cvh "#endif" +$ if arch_name .eqs. "VAX" +$ then +$ old_mes = f$environment("message") +$ set message/notext/nofaci/noseve/noident +$ search/output=nla0: ssl$include:*.h CONF_MFLAGS_IGNORE_MISSING_FILE +$ status = $severity +$ set message'old_mes' +$ if status .nes. "1" +$ then +$ write cvh "#define VMS_OLD_SSL 1" +$ endif +$ endif +$endif +$! +$! +$! LibIDN not ported to VMS at this time. +$! This is for international domain name support. +$! Allow explicit experimentation. +$if libidn +$then +$ write cvh "#define HAVE_IDNA_STRERROR 1" +$ write cvh "#define HAVE_IDNA_FREE 1" +$ write cvh "#define HAVE_IDNA_FREE_H 1" +$ write cvh "#define HAVE_LIBIDN 1" +$else +$ write cvh "#ifdef HAVE_LIBIDN" +$ write cvh "#undef HAVE_LIBIDN" +$ write cvh "#endif" +$endif +$! +$! +$! LibSSH2 not ported to VMS at this time. +$! Allow explicit experimentation. +$if libssh2 +$then +$ write cvh "#define HAVE_LIBSSH2_EXIT 1" +$ write cvh "#define HAVE_LIBSSH2_INIT 1" +$ write cvh "#define HAVE_LIBSSH2_SCP_SEND64 1" +$ write cvh "#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1" +$ write cvh "#define HAVE_LIBSSH2_VERSION 1 +$! +$ write cvh "#ifndef USE_LIBSSH2" +$ write cvh "#define USE_LIBSSH2 1" +$ write cvh "#endif" +$else +$ write cvh "#ifdef USE_LIBSSH2" +$ write cvh "#undef USE_LIBSSH2" +$ write cvh "#endif" +$endif +$! +$! +$! +$if .not. nozlib +$then +$ write cvh "#define HAVE_LIBZ 1" +$endif +$! +$! +$! Suppress a message in curl_gssapi.c compile. +$write cvh "#pragma message disable notconstqual" +$! +$! Close out the file +$! +$write cvh "" +$write cvh "#endif /* __CONFIG_VMS_H__ */" +$close cvh +$! +$all_exit: +$exit diff --git a/packages/vms/generate_vax_transfer.com b/packages/vms/generate_vax_transfer.com new file mode 100644 index 0000000..3ed49cb --- /dev/null +++ b/packages/vms/generate_vax_transfer.com @@ -0,0 +1,273 @@ +$! File: generate_vax_transfer.com +$! +$! File to generate and compile the VAX transfer vectors from reading in the +$! Alpha/Itanium gnv_libcurl_symbols.opt file. +$! +$! This procedure patches the VAX Macro32 assembler to be case sensitive +$! and then compiles the generated +$! +$! The output of this procedure is: +$! gnv_libcurl_xfer.mar_exact +$! gnv_libcurl_xfer.obj +$! gnv_libcurl_xfer.opt +$! macro32_exactcase.exe +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!============================================================================ +$! +$! Save this so we can get back. +$ default_dir = f$environment("default") +$! +$ on warning then goto all_exit +$! +$! Want hard tabs in the generated file. +$ tab[0,8] = 9 +$! +$! This procedure is used on VAX only +$ if (f$getsyi("HW_MODEL") .ge. 1024) +$ then +$ write sys$output "This procedure is only used on VAX." +$ goto all_exit +$ endif +$! +$! +$! Get the libcurl version to generate the ident string. +$! ident string is max of 31 characters. +$! +$ ident_string = "unknown" +$ open/read cver [-.-.include.curl]curlver.h +$cver_loop: +$ read/end=cver_loop_end cver line_in +$ line_in = f$edit(line_in, "COMPRESS,TRIM") +$ if line_in .eqs. "" then goto cver_loop +$ code = f$extract(0, 1, line_in) +$ if code .nes. "#" then goto cver_loop +$ directive = f$element(0, " ", line_in) +$ if directive .nes. "#define" then goto cver_loop +$ name = f$element(1, " ", line_in) +$ if name .nes. "LIBCURL_VERSION" then goto cver_loop +$ ident_string = f$element(2, " ", line_in) - "" - "" +$cver_loop_end: +$ close cver +$! +$ open/read aopt gnv_libcurl_symbols.opt +$! +$! Write out the header +$ gosub do_header +$! +$ open/append vopt gnv_libcurl_xfer.mar_exact +$ write vopt tab,".IDENT /", ident_string, "/" +$! +$ write vopt tab, ".PSECT LIBCURL_XFERVECTORS -" +$ write vopt tab,tab,tab, "PIC,USR,CON,REL,GBL,SHR,EXE,RD,NOWRT,QUAD" +$ write vopt "" +$ write vopt tab, "SPARE", tab, "; never delete this spare" +$ write vopt ";" +$ write vopt ";", tab, "Exact case and upper case transfer vectors" +$! +$ alias_count = 0 +$vector_loop: +$! +$! Read in symbol_vector +$! +$ read/end=vector_loop_end aopt line_in +$ line = f$edit(line_in, "UNCOMMENT,COMPRESS,TRIM") +$ if line .eqs. "" then goto vector_loop +$! +$ line_u = f$edit(line, "UPCASE") +$ key = f$element(0, "=", line_u) +$ if (key .eqs. "SYMBOL_VECTOR") +$ then +$ symbol_string = f$element(1, "=", line) - "(" +$ symbol_type = f$element(2, "=", line_u) - ")" +$ symbol_name = f$element(1, "/", symbol_string) +$ if symbol_type .nes. "PROCEDURE" +$ then +$ write sys$output "%CURLBUILD-W-NOTPROC, " + - +$ "This procedure can only handle procedure vectors" +$ write sys$output - +"Data vectors require manual construction for which this procedure or" +$ write sys$output - +"the shared library needs to be updated to resolve." +$ write sys$output - +"the preferred solution is to have a procedure return the address of the " +$ write sys$output - +"the variable instead of having a variable, as if the size of the variable " + write sys$output - +"changes, the symbol vector is no longer backwards compatible." +$ endif +$ if (symbol_name .eqs. "/") +$ then +$ symbol_name = symbol_string +$ write vopt tab, symbol_type, tab, symbol_name +$ else +$ alias_count = alias_count + 1 +$ symbol_alias = f$element(0, "/", symbol_string) +$ write vopt - + tab, "''symbol_type_U", tab, symbol_name, tab, symbol_alias +$ endif +$ endif +$ goto vector_loop +$vector_loop_end: +$! +$! End of pass one, second pass needed if aliases exist +$ close aopt +$! +$ if alias_count .eq. 0 then goto finish_file +$! +$! Start pass 2, write stub routine header +$! +$ open/read aopt gnv_libcurl_symbols.opt +$! +$alias_loop: +$! +$! Read in symbol_vector +$! +$ read/end=alias_loop_end aopt line_in +$ line = f$edit(line_in, "UNCOMMENT,COMPRESS,TRIM") +$ if line .eqs. "" then goto alias_loop +$! +$ line_u = f$edit(line, "UPCASE") +$ key = f$element(0, "=", line_u) +$ if (key .eqs. "SYMBOL_VECTOR") +$ then +$ symbol_string = f$element(1, "=", line) - "(" +$ symbol_type = f$element(2, "=", line_u) - ")" +$ symbol_name = f$element(1, "/", symbol_string) +$ if (symbol_name .eqs. "/") +$ then +$ symbol_name = symbol_string +$ else +$ alias_count = alias_count + 1 +$ symbol_alias = f$element(0, "/", symbol_string) +$ write vopt tab, ".ENTRY", tab, symbol_alias, ", ^M<>" +$ endif +$ endif +$ goto alias_loop +$! read in symbol_vector +$! if not alias, then loop +$! write out subroutine name +$! +$alias_loop_end: +$! +$ write vopt tab, "MOVL #1, R0" +$ write vopt tab, "RET" +$! +$finish_file: +$! +$ write vopt "" +$ write vopt tab, ".END" +$! +$ close aopt +$ close vopt +$! +$! Patch the Macro32 compiler +$!---------------------------- +$ patched_macro = "sys$disk:[]macro32_exactcase.exe" +$ if f$search(patched_macro) .eqs. "" +$ then +$ copy sys$system:macro32.exe 'patched_macro' +$ patch @macro32_exactcase.patch +$ endif +$ define/user macro32 'patched_macro' +$ macro/object=gnv_libcurl_xfer.obj gnv_libcurl_xfer.mar_exact +$! +$! Create the option file for linking the shared image. +$ create gnv_libcurl_xfer.opt +$ open/append lco gnv_libcurl_xfer.opt +$ write lco "gsmatch=lequal,1,1" +$ write lco "cluster=transfer_vector,,,''default_dir'gnv_libcurl_xfer" +$ write lco "collect=libcurl_global, libcurl_xfervectors" +$ close lco +$! +$! +$ goto all_exit +$! +$! Process the header +$do_header: +$! +$! Force the mode of the file to same as text editor generated. +$ create gnv_libcurl_xfer.mar_exact +$deck +; File: gnv_libcurl_xfer.mar_exact +; +; VAX transfer vectors +; +; This needs to be compiled with a specialized patch on Macro32 to make it +; preserve the case of symbols instead of converting it to uppercase. +; +; This patched Macro32 requires all directives to be in upper case. +; +; There are three sets of symbols for transfer vectors here. +; +; The first for upper case which matches the tradition method of generating +; VAX transfer vectors. +; +; The second is the exact case for compatibility with open source C programs +; that expect exact case symbols in images. These are separated because a +; previous kit had only upper case symbols. +; +; The third is the routine stub that is used to resolve part of the upper +; case transfer vectors, with exact case entry symbols. +; +; When you add routines, you need to add them after the second set of transfer +; vectors for both upper and exact case, and then additional entry points +; in upper case added to stub routines. +; +;************************************************************************* + + .TITLE libcurl_xfer - Transfer vector for libcurl + .DISABLE GLOBAL + +; +; Macro to generate a transfer vector entry +; + .MACRO PROCEDURE NAME + .EXTRN 'NAME + .ALIGN QUAD + .TRANSFER 'NAME + .MASK 'NAME + JMP 'NAME+2 + .ENDM + + .MACRO PROCEDUREU NAME NAMEU + .EXTRN 'NAME + .ALIGN QUAD + .TRANSFER 'NAMEU + .MASK 'NAME + JMP 'NAME+2 + + .ENDM +; +; +; Macro to reserve a spare entry. +; + .MACRO SPARE + .ALIGN QUAD + .ALIGN QUAD + .QUAD 0 + .ENDM + +$EOD +$! +$! +$ return +$! +$all_exit: +$set def 'default_dir' +$exit '$status' diff --git a/packages/vms/gnv_conftest.c_first b/packages/vms/gnv_conftest.c_first new file mode 100644 index 0000000..317b1ab --- /dev/null +++ b/packages/vms/gnv_conftest.c_first @@ -0,0 +1,58 @@ +/* File: GNV$CONFTEST.C_FIRST + * + * Copyright (C) John Malmberg + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: ISC + * + */ + +/* This is needed for Configure tests to get the correct exit status */ +void __posix_exit(int __status); +#define exit(__p1) __posix_exit(__p1) + +/* Fake pass the test to find a standard ldap routine that we know is */ +/* present on VMS, but with the wrong case for the symbol */ +char ldap_url_parse(void) {return 0;} + +/* These are to pass the test that does not use headers */ +/* Because configure does an #undef which keeps us from using #define */ +/* char CRYPTO_add_lock(void) {return 0;} */ +char SSL_connect(void) {return 0;} +char ENGINE_init(void) {return 0;} +char RAND_status(void) {return 0;} +/* char RAND_screen(void) {return 0;} In headers, but not present */ +char CRYPTO_cleanup_all_ex_data(void) {return 0;} +char SSL_get_shutdown(void) {return 0;} +char ENGINE_load_builtin_engines (void) {return 0;} + +/* And these are to pass the test that uses headers. */ +/* Because the HP OpenSSL transfer vectors are currently in Upper case only */ +#pragma message disable macroredef +#define CRYPTO_add_lock CRYPTO_ADD_LOCK +#define SSL_connect SSL_CONNECT +#define ENGINE_init ENGINE_INIT +#define RAND_status RAND_STATUS +/* #define RAND_screen RAND_SCREEN */ +#define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA +#define SSL_get_shutdown SSL_GET_SHUTDOWN +#define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES + +/* Can not use the #define macro to fix the case on CRYPTO_lock because */ +/* there is a macro CRYPTO_LOCK that is a number */ + +/* After all the work to get configure to pass the CRYPTO_LOCK tests, + * it turns out that VMS does not have the CRYPTO_LOCK symbol in the + * transfer vector, even though it is in the header file. + */ diff --git a/packages/vms/gnv_curl_configure.sh b/packages/vms/gnv_curl_configure.sh new file mode 100755 index 0000000..2155800 --- /dev/null +++ b/packages/vms/gnv_curl_configure.sh @@ -0,0 +1,44 @@ +# File: gnv_curl_configure.sh +# +# Set up and run the configure script for Curl so that it can find the +# proper options for VMS. +# +# Copyright (C) John Malmberg +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#========================================================================== +# +# POSIX exit mode is needed for Unix shells. +export GNV_CC_MAIN_POSIX_EXIT=1 +# +# Where to look for the helper files. +export GNV_OPT_DIR=. +# +# How to find the SSL library files. +export LIB_OPENSSL=/SSL_LIB +# +# Override configure adding -std1 which is too strict for what curl +# actually wants. +export GNV_CC_QUALIFIERS=/STANDARD=RELAXED +# +# Set the directory to where the Configure script actually is. +cd ../.. +# +# +./configure --prefix=/usr --exec-prefix=/usr --disable-dependency-tracking \ + --disable-libtool-lock --with-gssapi --disable-ntlm-wb \ + --with-ca-path=gnv\$curl_ca_path +# diff --git a/packages/vms/gnv_libcurl_symbols.opt b/packages/vms/gnv_libcurl_symbols.opt new file mode 100644 index 0000000..5bc2a85 --- /dev/null +++ b/packages/vms/gnv_libcurl_symbols.opt @@ -0,0 +1,181 @@ +! File GNV$LIBCURL_SYMBOLS.OPT +! +! This file must be manually maintained to allow upward compatibility +! The SYMBOL_VECTORs are set up so that applications can be compiled +! with either case sensitive symbol names or the default of uppercase. +! This is because many of the Open Source applications that would call +! the LIBCURL library need to be built with case sensitive names. +! +! Automatic generation is currently not practical because the order of +! the entries are important for upward compatibility. +! +! The GSMATCH is manually set to the major version of 1, with the minor +! version being the next two sections multiplied by a power of 10 to +! become the minor version. +! So LIBCURL 7.18.1 becomes 1,718010. +! And a future LIBCURL of 7.18.2 would be 1,718020 if new routines were added. +! +! This leaves some spare digits for minor patches. +! +! Note that the GSMATCH does not need to have any real relationship to the +! actual package version number. +! +! New SYMBOL_VECTORs must be added to the end of this list, and added +! in pairs for both exact and with an uppercase alias. +! If the public symbol is more than 31 characters long, then a special +! shortened symbol will be exported, and three aliases should be created, +! The aliases will be the special shortened uppercase alias, and both +! upper and lowercase versions of a truncated name (preferred) or a +! modified manually shortened name if a truncated name will not be +! unique. +! +! Routines can not be removed, the functionality must be maintained. +! If a new routine is supplied where the arguments are incompatible with +! the older version, both versions are needed to be maintained. +! The old version can be given a different name, but must be in the same +! SYMBOL_VECTOR positions in this file. +! +! Changing the number of parameters for an existing routine does not require +! maintaining multiple versions as long as the routine can be called with +! the old number of parameters. +! +! Copyright (C) John Malmberg +! +! Permission to use, copy, modify, and/or distribute this software for any +! purpose with or without fee is hereby granted, provided that the above +! copyright notice and this permission notice appear in all copies. +! +! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +! +! SPDX-License-Identifier: ISC +!============================================================================ +GSMATCH=LEQUAL,1,719050 +CASE_SENSITIVE=YES +SYMBOL_VECTOR=(curl_strequal=PROCEDURE) +SYMBOL_VECTOR=(CURL_STREQUAL/curl_strequal=PROCEDURE) +SYMBOL_VECTOR=(curl_strnequal=PROCEDURE) +SYMBOL_VECTOR=(CURL_STRNEQUAL/curl_strnequal=PROCEDURE) +SYMBOL_VECTOR=(curl_formadd=PROCEDURE) +SYMBOL_VECTOR=(CURL_FORMADD/curl_formadd=PROCEDURE) +SYMBOL_VECTOR=(curl_formget=PROCEDURE) +SYMBOL_VECTOR=(CURL_FORMGET/curl_formget=PROCEDURE) +SYMBOL_VECTOR=(curl_formfree=PROCEDURE) +SYMBOL_VECTOR=(CURL_FORMFREE/curl_formfree=PROCEDURE) +SYMBOL_VECTOR=(curl_getenv=PROCEDURE) +SYMBOL_VECTOR=(CURL_GETENV/curl_getenv=PROCEDURE) +SYMBOL_VECTOR=(curl_version=PROCEDURE) +SYMBOL_VECTOR=(CURL_VERSION/curl_version=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_escape=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_ESCAPE/curl_easy_escape=PROCEDURE) +SYMBOL_VECTOR=(curl_escape=PROCEDURE) +SYMBOL_VECTOR=(CURL_ESCAPE/curl_escape=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_unescape=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_UNESCAPE/curl_easy_unescape=PROCEDURE) +SYMBOL_VECTOR=(curl_unescape=PROCEDURE) +SYMBOL_VECTOR=(CURL_UNESCAPE/curl_unescape=PROCEDURE) +SYMBOL_VECTOR=(curl_free=PROCEDURE) +SYMBOL_VECTOR=(CURL_FREE/curl_free=PROCEDURE) +SYMBOL_VECTOR=(curl_global_init=PROCEDURE) +SYMBOL_VECTOR=(CURL_GLOBAL_INIT/curl_global_init=PROCEDURE) +SYMBOL_VECTOR=(curl_global_init_mem=PROCEDURE) +SYMBOL_VECTOR=(CURL_GLOBAL_INIT_MEM/curl_global_init_mem=PROCEDURE) +SYMBOL_VECTOR=(curl_global_cleanup=PROCEDURE) +SYMBOL_VECTOR=(CURL_GLOBAL_CLEANUP/curl_global_cleanup=PROCEDURE) +SYMBOL_VECTOR=(curl_slist_append=PROCEDURE) +SYMBOL_VECTOR=(CURL_SLIST_APPEND/curl_slist_append=PROCEDURE) +SYMBOL_VECTOR=(curl_slist_free_all=PROCEDURE) +SYMBOL_VECTOR=(CURL_SLIST_FREE_ALL/curl_slist_free_all=PROCEDURE) +SYMBOL_VECTOR=(curl_getdate=PROCEDURE) +SYMBOL_VECTOR=(CURL_GETDATE/curl_getdate=PROCEDURE) +SYMBOL_VECTOR=(curl_share_init=PROCEDURE) +SYMBOL_VECTOR=(CURL_SHARE_INIT/curl_share_init=PROCEDURE) +SYMBOL_VECTOR=(curl_share_setopt=PROCEDURE) +SYMBOL_VECTOR=(CURL_SHARE_SETOPT/curl_share_setopt=PROCEDURE) +SYMBOL_VECTOR=(curl_share_cleanup=PROCEDURE) +SYMBOL_VECTOR=(CURL_SHARE_CLEANUP/curl_share_cleanup=PROCEDURE) +SYMBOL_VECTOR=(curl_version_info=PROCEDURE) +SYMBOL_VECTOR=(CURL_VERSION_INFO/curl_version_info=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_strerror=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_STRERROR/curl_easy_strerror=PROCEDURE) +SYMBOL_VECTOR=(curl_share_strerror=PROCEDURE) +SYMBOL_VECTOR=(CURL_SHARE_STRERROR/curl_share_strerror=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_pause=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_PAUSE/curl_easy_pause=PROCEDURE) +! +! easy.h +SYMBOL_VECTOR=(curl_easy_init=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_INIT/curl_easy_init=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_setopt=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_SETOPT/curl_easy_setopt=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_perform=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_PERFORM/curl_easy_perform=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_cleanup=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_CLEANUP/curl_easy_cleanup=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_getinfo=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_GETINFO/curl_easy_getinfo=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_duphandle=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_DUPHANDLE/curl_easy_duphandle=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_reset=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_RESET/curl_easy_reset=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_recv=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_RECV/curl_easy_recv=PROCEDURE) +SYMBOL_VECTOR=(curl_easy_send=PROCEDURE) +SYMBOL_VECTOR=(CURL_EASY_SEND/curl_easy_send=PROCEDURE) +! +! multi.h +SYMBOL_VECTOR=(curl_multi_init=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_INIT/curl_multi_init=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_add_handle=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_ADD_HANDLE/curl_multi_add_handle=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_remove_handle=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_REMOVE_HANDLE/curl_multi_remove_handle=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_fdset=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_FDSET/curl_multi_fdset=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_perform=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_PERFORM/curl_multi_perform=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_cleanup=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_CLEANUP/curl_multi_cleanup=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_info_read=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_INFO_READ/curl_multi_info_read=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_strerror=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_STRERROR/curl_multi_strerror=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_socket=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_SOCKET/curl_multi_socket=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_socket_action=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_SOCKET_ACTION/curl_multi_socket_action=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_socket_all=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_SOCKET_ALL/curl_multi_socket_all=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_timeout=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_TIMEOUT/curl_multi_timeout=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_setopt=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_SETOPT/curl_multi_setopt=PROCEDURE) +SYMBOL_VECTOR=(curl_multi_assign=PROCEDURE) +SYMBOL_VECTOR=(CURL_MULTI_ASSIGN/curl_multi_assign=PROCEDURE) +! +! mprintf.h +SYMBOL_VECTOR=(curl_mprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MPRINTF/curl_mprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_mfprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MFPRINTF/curl_mfprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_msprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MSPRINTF/curl_msprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_msnprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MSNPRINTF/curl_msnprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_mvprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MVPRINTF/curl_mvprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_mvfprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MVFPRINTF/curl_mvfprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_mvsprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MVSPRINTF/curl_mvsprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_mvsnprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MVSNPRINTF/curl_mvsnprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_maprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MAPRINTF/curl_maprintf=PROCEDURE) +SYMBOL_VECTOR=(curl_mvaprintf=PROCEDURE) +SYMBOL_VECTOR=(CURL_MVAPRINTF/curl_mvaprintf=PROCEDURE) diff --git a/packages/vms/gnv_link_curl.com b/packages/vms/gnv_link_curl.com new file mode 100644 index 0000000..247987a --- /dev/null +++ b/packages/vms/gnv_link_curl.com @@ -0,0 +1,851 @@ +$! File: gnv_link_curl.com +$! +$! File to build images using gnv$libcurl.exe +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!============================================================================ +$! +$! Save this so we can get back. +$ default_dir = f$environment("default") +$ define/job gnv_packages_vms 'default_dir' +$! +$ on warning then goto all_exit +$! +$! On VAX, we need to generate a Macro transfer vector. +$ parse_style = "TRADITIONAL" +$ if (f$getsyi("HW_MODEL") .lt. 1024) +$ then +$ @generate_vax_transfer.com +$ arch_name = "VAX" +$ else +$ arch_name = "" +$ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") +$ if (arch_name .eqs. "") then arch_name = "UNK" +$! +$! Extended parsing option starts with VMS 7.3-1. +$! There is no 7.4, so that simplifies the parse a bit. +$! +$ node_swvers = f$getsyi("node_swvers") +$ version_patch = f$extract(1, f$length(node_swvers), node_swvers) +$ maj_ver = f$element(0, ".", version_patch) +$ min_ver_patch = f$element(1, ".", version_patch) +$ min_ver = f$element(0, "-", min_ver_patch) +$ patch = f$element(1, "-", min_ver_patch) +$ if patch .eqs. "-" then patch = "" +$ parse_x = 0 +$ if maj_ver .ges. "8" +$ then +$ parse_x = 1 +$ else +$ if maj_ver .eqs. "7" .and. min_ver .ges. "3" .and. patch .nes. "" +$ then +$ parse_x = 1 +$ endif +$ endif +$ if parse_x +$ then +$ parse_style = f$getjpi("", "parse_style_perm") +$ endif +$ endif +$! +$! +$! Move to where the base directories. +$ set def [--] +$! +$! +$! Build the Message file. +$!-------------------------- +$ if f$search("[.packages.vms]curlmsg.obj") .eqs. "" +$ then +$ message [.packages.vms]curlmsg.msg/object=[.packages.vms] +$ endif +$ if f$search("gnv$curlmsg.exe") .eqs. "" +$ then +$ link/share=gnv$curlmsg.exe [.packages.vms]curlmsg.obj +$ endif +$! +$! +$! Need to build the common init module. +$!------------------------------------------- +$ cflags = "/list/show=(expan,includ)" +$ init_obj = "[.packages.vms]curl_crtl_init.obj" +$ if f$search(init_obj) .eqs. "" +$ then +$ cc'cflags' 'default_dir'curl_crtl_init.c/obj='init_obj' +$ endif +$ purge 'init_obj' +$ rename 'init_obj' ;1 +$! +$! +$! Need to build the module to test the HP OpenSSL version +$!-------------------------------------------------------- +$ if arch_name .nes. "VAX" +$ then +$ rpt_obj = "[.packages.vms]report_openssl_version.obj +$ if f$search(rpt_obj) .eqs. "" +$ then +$ cc'cflags' 'default_dir'report_openssl_version.c/obj='rpt_obj' +$ endif +$ purge 'rpt_obj' +$ rename 'rpt_obj' ;1 +$! +$ link/exe='default_dir'report_openssl_version.exe 'rpt_obj' +$ report_openssl_version := $'default_dir'report_openssl_version.exe +$ endif +$! +$! +$ base_link_opt_file = "[.packages.vms.''arch_name']gnv_libcurl_linker.opt" +$ share_link_opt_file = "[.packages.vms.''arch_name']gnv_ssl_libcurl_linker.opt" +$ if f$search(base_link_opt_file) .eqs. "" +$ then +$ base_link_opt_file = "[.packages.vms]gnv_libcurl_linker.opt" +$ share_link_opt_file = "[.packages.vms]gnv_ssl_libcurl_linker.opt" +$ if f$search(base_link_opt_file) .eqs. "" +$ then +$ write sys$output "Can not find base library option file!" +$ goto all_exit +$ endif +$ endif +$! +$! Create the a new option file with special fixup for HP SSL +$! For a shared image, we always want ZLIB and 32 bit HPSSL +$! +$ if f$search("gnv$libzshr32") .eqs. "" +$ then +$ write sys$output "VMSPORTS/GNV LIBZ Shared image not found!" +$ goto all_exit +$ endif +$! +$! +$! Need to check the version of the HP SSL shared image. +$! +$! VAX platform can not be checked this way, it appears symbol lookup +$! was disabled. VAX has not been updated in a while. +$ if arch_name .eqs. "VAX" +$ then +$ hp_ssl_libcrypto32 = "sys$common:[syslib]ssl$libcrypto_shr32.exe" +$ hp_ssl_libssl32 = "sys$common:[syslib]ssl$libssl_shr32.exe" +$ if f$search(hp_ssl_libcrypto32) .nes. "" +$ then +$ use_hp_ssl = 1 +$ curl_ssl_libcrypto32 = hp_ssl_libcrypto32 +$ curl_ssl_libssl32 = hp_ssl_libssl32 +$ curl_ssl_version = "OpenSSL/0.9.6g" +$ else +$ write sys$output "HP OpenSSL Shared images not found!" +$ goto all_exit +$ endif +$ else +$! +$! Minimum HP version we can use reports: +$! "OpenSSL 0.9.8w 23 Apr 2012" +$! +$ use_hp_ssl = 0 +$ hp_ssl_libcrypto32 = "sys$share:ssl$libcrypto_shr32.exe" +$ hp_ssl_libssl32 = "sys$share:ssl$libssl_shr32.exe" +$ if f$search(hp_ssl_libcrypto32) .nes. "" +$ then +$ curl_ssl_libcrypto32 = hp_ssl_libcrypto32 +$ curl_ssl_libssl32 = hp_ssl_libssl32 +$ report_openssl_version 'hp_ssl_libcrypto32' hp_ssl_version +$ endif +$! +$ if f$type(hp_ssl_version) .eqs. "STRING" +$ then +$ curl_ssl_version = hp_ssl_version +$ full_version = f$element(1, " ", hp_ssl_version) +$ ver_maj = f$element(0, ".", full_version) +$ ver_min = f$element(1, ".", full_version) +$ ver_patch = f$element(2, ".", full_version) +$! ! ver_patch is typically both a number and some letters +$ ver_patch_len = f$length(ver_patch) +$ ver_patchltr = "" +$ver_patch_loop: +$ ver_patchltr_c = f$extract(ver_patch_len - 1, 1, ver_patch) +$ if ver_patchltr_c .les. "9" then goto ver_patch_loop_end +$ ver_patchltr = ver_patchltr_c + ver_patchltr +$ ver_patch_len = ver_patch_len - 1 +$ goto ver_patch_loop +$ver_patch_loop_end: +$ ver_patchnum = ver_patch - ver_patchltr +$ if 'ver_maj' .ge. 0 +$ then +$ if 'ver_min' .ge. 9 +$ then +$ if 'ver_patchnum' .ge. 8 +$ then +$ if ver_patchltr .ges. "w" then use_hp_ssl = 1 +$ endif +$ endif +$ endif +$set nover +$ if use_hp_ssl .eq. 0 +$ then +$ write sys$output - + " HP OpenSSL version of ""''hp_ssl_version'"" is too old for shared libcurl!" +$ endif +$ else +$ write sys$output "Unable to get version of HP OpenSSL" +$ endif +$! +$ gnv_ssl_libcrypto32 = "gnv$gnu:[lib]ssl$libcrypto_shr32.exe" +$ gnv_ssl_libssl32 = "gnv$gnu:[lib]ssl$libssl_shr32.exe" +$ if f$search(gnv_ssl_libcrypto32) .nes. "" +$ then +$ report_openssl_version 'gnv_ssl_libcrypto32' gnv_ssl_version +$ endif +$! +$ use_gnv_ssl = 0 +$ if f$type(gnv_ssl_version) .eqs. "STRING" +$ then +$ gnv_full_version = f$element(1, " ", gnv_ssl_version) +$ gnv_ver_maj = f$element(0, ".", gnv_full_version) +$ gnv_ver_min = f$element(1, ".", gnv_full_version) +$ gnv_ver_patch = f$element(2, ".", gnv_full_version) +$ gnv_ver_patch_len = f$length(gnv_ver_patch) +$ gnv_ver_patchnum = f$extract(0, gnv_ver_patch_len - 1, gnv_ver_patch) +$ gnv_ver_patchltr = f$extract(gnv_ver_patch_len - 1, 1, gnv_ver_patch) +$ if 'gnv_ver_maj' .ge. 0 +$ then +$ if 'gnv_ver_min' .ge. 9 +$ then +$ if 'gnv_ver_patchnum' .ge. 8 +$ then +$ if gnv_ver_patchltr .ges. "w" then use_gnv_ssl = 1 +$ endif +$ endif +$ endif +$ if use_gnv_ssl .eq. 0 +$ then +$ write sys$output - + "GNV OpenSSL version of ""''gnv_ssl_version'" is too old for shared libcurl!" +$ endif +$! +$! Prefer to break the tie with the lowest supported version +$! For simplicity, if the GNV image is present, it will be used. +$! Version tuple is not a simple compare. +$! +$ if use_gnv_ssl .eq. 1 then +$ curl_ssl_libcrypto32 = gnv_ssl_libcrypto32 +$ curl_ssl_libssl32 = gnv_ssl_libssl32 +$ curl_ssl_version = gnv_ssl_version +$ use_hp_ssl = 0 +$ endif +!$! +$ else +$ write sys$output "Unable to get version of GNV OpenSSL" +$ endif +$! +$! Need to write a release note section about HP OpenSSL +$! +$create 'default_dir'hp_ssl_release_info.txt +$deck +This package is built on with the OpenSSL version listed below and requires +the shared images from the HP OpenSSL product that is kitted with that +version or a compatible later version. + +For Alpha and IA64 platforms, see the url below to register to get the +download URL. The kit will be HP 1.4-467 or later. + https://h41379.www4.hpe.com/openvms/products/ssl/ssl.html + +For VAX, use the same registration, but remove the kit name from any of the +download URLs provided and put in CPQ-VAXVMS-SSL-V0101-B-1.PCSI-DCX_VAXEXE + +If your system can not be upgraded to a compatible version of OpenSSL, then +you can extract the two shared images from the kit and place them in the +[vms$common.gnv.lib]directory of the volume that you are installing GNV and +or GNV compatible components like Curl. + +If GNV is installed, you must run the GNV startup procedure before these steps +and before installing Curl. + + + 1. make sure that [vms$common.gnv.lib] exists by using the following + commands. We want the directory to be in lowercase except on VAX. + + $SET PROCESS/PARSE=extend !If not VAX. + $CREATE/DIR device:[vms$common.gnv.lib]/prot=w:re + + 2. Extract the ssl$crypto_shr32.exe and ssl$libssl_shr32.exe images. + + $PRODUCT EXTRACT FILE - + /select=(ssl$libcrypto_shr32.exe,ssl$libssl_shr32.exe)- + /source=device:[dir] - + /options=noconfirm - + /destination=device:[vms$common.gnv.lib] SSL + +The [vms$common.sys$startup}curl_startup.com procedure will then configure +libcurl to use these shared images instead of the system ones. + +When you upgrade SSL on VMS to the newer version of HP SSL, then these copies +should be deleted. + +$eod +$! +$ open/append sslr 'default_dir'hp_ssl_release_info.txt +$ write sslr "OpenSSL version used for building this kit: ",curl_ssl_version +$ write sslr "" +$ close sslr +$! +$! +$! LIBZ +$ libzshr_line = "" +$ try_shr = "gnv$libzshr32" +$ if f$search(try_shr) .nes. "" +$ then +$ libzshr_line = "''try_shr'/share" +$ else +$ write sys$output "''try_shr' image not found!" +$ goto all_exit +$ endif +$! +$! +$ gssrtlshr_line = "" +$ if arch_name .nes. "VAX" +$ then +$ try_shr = "sys$share:gss$rtl" +$ if f$search("''try_shr'.exe") .nes. "" +$ then +$ gssrtlshr_line = "''try_shr'/share" +$ else +$ write sys$output "''try_shr' image not found!" +$ goto all_exit +$ endif +$ endif +$! +$! +$! +$ if f$search(share_link_opt_file) .eqs. "" +$ then +$ create 'share_link_opt_file' +$ open/append slopt 'share_link_opt_file' +$ if libzshr_line .nes. "" then write slopt libzshr_line +$ if gssrtlshr_line .nes. "" then write slopt gssrtlshr_line +$ write slopt "gnv$curl_ssl_libcryptoshr32/share" +$ write slopt "gnv$curl_ssl_libsslshr32/share" +$ close slopt +$ endif +$! +$! DCL build puts curllib in architecture directory +$! GNV build uses the makefile. +$ libfile = "[.packages.vms.''arch_name']curllib.olb" +$ if f$search(libfile) .nes. "" +$ then +$ olb_file = libfile +$ else +$ ! GNV based build +$ libfile = "[.lib.^.libs]libcurl.a" +$ if f$search(libfile) .nes. "" +$ then +$ olb_file = libfile +$ else +$ write sys$output - + "Can not build shared image, libcurl object library not found!" +$ goto all_exit +$ endif +$ endif +$! +$gnv_libcurl_share = "''default_dir'gnv$libcurl.exe" +$! +$ if f$search(gnv_libcurl_share) .eqs. "" +$ then +$ if arch_name .nes. "VAX" +$ then +$ define/user gnv$curl_ssl_libcryptoshr32 'curl_ssl_libcrypto32' +$ define/user gnv$curl_ssl_libsslshr32 'curl_ssl_libssl32' +$ link/dsf='default_dir'gnv$libcurl.dsf/share='gnv_libcurl_share' - + /map='default_dir'gnv$libcurl.map - + gnv_packages_vms:gnv_libcurl_symbols.opt/opt,- + 'olb_file'/lib,- + 'share_link_opt_file'/opt +$ else +$! VAX will not allow the logical name hack for the +$! SSL libcryto library, it is pulling it in twice if I try it. +$ link/share='gnv_libcurl_share'/map='default_dir'gnv$libcurl.map - + gnv_packages_vms:gnv_libcurl_xfer.opt/opt,- + 'olb_file'/lib,- + 'base_link_opt_file'/opt +$ endif +$ endif +$! +$! +$ if f$search("[.src]curl-tool_main.o") .nes. "" +$ then +$! From src/makefile.inc: +$! # libcurl has sources that provide functions named curlx_* that aren't +$! # part of the official API, but we reuse the code here to avoid +$! # duplication. +$! +$! +$ if f$search("[.src]curl.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.src]curl.exe/dsf=[.src]curl.dsf - + [.src]curl-tool_main.o, [.src]curl-tool_binmode.o, - + [.src]curl-tool_bname.o, [.src]curl-tool_cb_dbg.o, - + [.src]curl-tool_cb_hdr.o, [.src]curl-tool_cb_prg.o, - + [.src]curl-tool_cb_rea.o, [.src]curl-tool_cb_see.o, - + [.src]curl-tool_cb_wrt.o, [.src]curl-tool_cfgable.o, - + [.src]curl-tool_convert.o, [.src]curl-tool_dirhie.o, - + [.src]curl-tool_doswin.o, [.src]curl-tool_easysrc.o, - + [.src]curl-tool_formparse.o, [.src]curl-tool_getparam.o, - + [.src]curl-tool_getpass.o, [.src]curl-tool_help.o, - + [.src]curl-tool_helpers.o, [.src]curl-tool_homedir.o, - + [.src]curl-tool_hugehelp.o, [.src]curl-tool_libinfo.o, - + [.src]curl-tool_mfiles.o, - + [.src]curl-tool_msgs.o, [.src]curl-tool_operate.o, - + [.src]curl-tool_operhlp.o, - + [.src]curl-tool_paramhlp.o, [.src]curl-tool_parsecfg.o, - + [.src]curl-tool_setopt.o, [.src]curl-tool_sleep.o, - + [.src]curl-tool_urlglob.o, [.src]curl-tool_util.o, - + [.src]curl-tool_vms.o, [.src]curl-tool_writeenv.o, - + [.src]curl-tool_writeout.o, [.src]curl-tool_xattr.o, - + [.src]curl-strtoofft.o, [.src]curl-strdup.o, [.src]curl-strcase.o, - + [.src]curl-nonblock.o, gnv_packages_vms:curlmsg.obj,- + sys$input:/opt +gnv$libcurl/share +gnv_packages_vms:curl_crtl_init.obj +$ endif +$ else +$ curl_exe = "[.src]curl.exe" +$ curl_dsf = "[.src]curl.dsf" +$ curl_main = "[.packages.vms.''arch_name']tool_main.obj" +$ curl_src = "[.packages.vms.''arch_name']curlsrc.olb" +$ curl_lib = "[.packages.vms.''arch_name']curllib.olb" +$ strcase = "strcase" +$ nonblock = "nonblock" +$ warnless = "warnless" +$! +$! Extended parse style requires special quoting +$! +$ if (arch_name .nes. "VAX") .and. (parse_style .eqs. "EXTENDED") +$ then +$ strcase = """strcase""" +$ nonblock = """nonblock""" +$ warnless = """warnless""" +$ endif +$ if f$search(curl_exe) .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe='curl_exe'/dsf='curl_dsf' - + 'curl_main','curl_src'/lib, - + 'curl_lib'/library/include=- + ('strcase','nonblock','warnless'),- + gnv_packages_vms:curlmsg.obj,- + sys$input:/opt +gnv$libcurl/share +gnv_packages_vms:curl_crtl_init.obj +$ endif +$ endif +$! +$! +$! +$! in6addr_missing so skip building: +$! [.server]sws.o +$! [.server]sockfilt.o +$! [.server]tftpd.o +$! +$! +$ target = "10-at-a-time" +$ if f$search("[.docs.examples]''target'.o") .eqs. "" +$ then +$ write sys$output "examples not built" +$ goto all_exit +$ endif +$ if f$search("[.docs.examples]''target'.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$ endif +$! +$! +$ target = "anyauthput" +$ if f$search("[.docs.examples]''target'.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$ endif +$! +$! +$ target = "certinfo" +$ if f$search("[.docs.examples]''target'.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$ endif +$! +$! +$ target = "cookie_interface" +$ if f$search("[.docs.examples]''target'.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$ endif +$! +$! +$ target = "debug" +$ if f$search("[.docs.examples]''target'.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$ endif +$! +$! +$ target = "fileupload" +$ if f$search("[.docs.examples]''target'.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$ endif +$! +$! +$ target = "fopen" +$ if f$search("[.docs.examples]''target'.exe") .eqs. "" +$ then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$ endif +$! +$! +$target = "ftpget" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "ftpgetresp" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "ftpupload" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "getinfo" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "getinmemory" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "http-post" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "httpcustomheader" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "httpput" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "https" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "multi-app" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "multi-debugcallback" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "multi-double" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "multi-post" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "multi-single" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "persistent" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "post-callback" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "postit2" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "sendrecv" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "sepheaders" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "simple" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "simplepost" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! +$target = "simplessl" +$if f$search("[.docs.examples]''target'.exe") .eqs. "" +$then +$ define/user gnv$libcurl 'gnv_libcurl_share' +$ link'ldebug'/exe=[.docs.examples]'target'.exe- + /dsf=[.docs.examples]'target'.dsf - + [.docs.examples]'target'.o,- + gnv$'target'.opt/opt,- + sys$input:/opt +gnv$libcurl/share +$endif +$! +$! =============== End of docs/examples ========================= +$! +$! +$all_exit: +$set def 'default_dir' +$exit '$status' +$! diff --git a/packages/vms/macro32_exactcase.patch b/packages/vms/macro32_exactcase.patch new file mode 100644 index 0000000..eda5cac --- /dev/null +++ b/packages/vms/macro32_exactcase.patch @@ -0,0 +1,11 @@ +macro32_exactcase.exe +SE EC +^X00000001 +RE /I +^X00012B1D +'BICB2 #^X00000020,R3' +EXIT +'BICB2 #^X00000000,R3' +EXI +U +EXI diff --git a/packages/vms/make_gnv_curl_install.sh b/packages/vms/make_gnv_curl_install.sh new file mode 100755 index 0000000..b85ef0c --- /dev/null +++ b/packages/vms/make_gnv_curl_install.sh @@ -0,0 +1,44 @@ +# File: make_gnv_curl_install.sh +# +# Set up and run the make script for Curl. +# +# This makes the library, the curl binary and attempts an install. +# A search list should be set up for GNU (GNV$GNU). +# +# Copyright (C) John Malmberg +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# SPDX-License-Identifier: ISC +# +#========================================================================== +# +# +# Needed VMS build setups for GNV. +export GNV_OPT_DIR=. +export GNV_CC_QUALIFIERS=/DEBUG/OPTIMIZE/STANDARD=RELAXED\ +/float=ieee_float/ieee_mode=denorm_results +export GNV_CXX_QUALIFIERS=/DEBUG/OPTIMIZE/float=ieee/ieee_mode=denorm_results +export GNV_CC_NO_INC_PRIMARY=1 +# +# +# POSIX exit mode is needed for Unix shells. +export GNV_CC_MAIN_POSIX_EXIT=1 +make +cd ../.. +# adjust the libcurl.pc file, GNV currently ignores the Lib: line. +# but is noisy about it, so we just remove it. +sed -e 's/^Libs:/#Libs:/g' libcurl.pc > libcurl.pc_new +rm libcurl.pc +mv libcurl.pc_new libcurl.pc +make install diff --git a/packages/vms/make_pcsi_curl_kit_name.com b/packages/vms/make_pcsi_curl_kit_name.com new file mode 100644 index 0000000..956f7c1 --- /dev/null +++ b/packages/vms/make_pcsi_curl_kit_name.com @@ -0,0 +1,188 @@ +$! File: MAKE_PCSI_CURL_KIT_NAME.COM +$! +$! Calculates the PCSI kit name for use in building an installation kit. +$! PCSI is HP's PolyCenter Software Installation Utility. +$! +$! The results are stored in as logical names so that other procedures +$! can use them. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!======================================================================== +$! +$! Save default +$ default_dir = f$environment("DEFAULT") +$! +$! Move to the base directories +$ set def [--] +$! +$! Put things back on error. +$ on warning then goto all_exit +$! +$! The producer is the name or common abbreviation for the entity that is +$! making the kit. It must be set as a logical name before running this +$! procedure. +$! +$! HP documents the producer as the legal owner of the software, but for +$! open source work, it should document who is creating the package for +$! distribution. +$! +$ producer = f$trnlnm("GNV_PCSI_PRODUCER") +$ if producer .eqs. "" +$ then +$ write sys$output "The logical name GNV_PCSI_PRODUCER needs to be defined." +$ write sys$output "This should be set to the common abbreviation or name of" +$ write sys$output "the entity creating this kit. If you are an individual" +$ write sys$output "then use your initials." +$ goto all_exit +$ endif +$ producer_full_name = f$trnlnm("GNV_PCSI_PRODUCER_FULL_NAME") +$ if producer_full_name .eqs. "" +$ then +$ write sys$output "The logical name GNV_PCSI_PRODUCER_FULL_NAME needs to" +$ write sys$output "be defined. This should be set to the full name of" +$ write sys$output "the entity creating this kit. If you are an individual" +$ write sys$output "then use your name." +$ write sys$output "EX: DEFINE GNV_PCSI_PRODUCER_FULL_NAME ""First M. Last""" +$ goto all_exit +$ endif +$! +$ write sys$output "*****" +$ write sys$output "***** Producer = ''producer'" +$ write sys$output "*****" +$! +$! +$! Base is one of 'VMS', 'AXPVMS', 'I64VMS', 'VAXVMS' and indicates what +$! binaries are in the kit. A kit with just 'VMS' can be installed on all +$! architectures. +$! +$ base = "VMS" +$ arch_type = f$getsyi("ARCH_NAME") +$ code = f$extract(0, 1, arch_type) +$ if (code .eqs. "I") then base = "I64VMS" +$ if (code .eqs. "V") then base = "VAXVMS" +$ if (code .eqs. "A") then base = "AXPVMS" +$! +$! +$ product = "curl" +$! +$! +$! We need to get the version from curlver_h. It will have a line like +$! #define LIBCURL_VERSION "7.31.0" +$! or +$! #define LIBCURL_VERSION "7.32.0-20130731". +$! +$! The dash indicates that this is a daily pre-release. +$! +$! +$ open/read/error=version_loop_end vhf [.include.curl]curlver.h +$ version_loop: +$ read vhf line_in +$ if line_in .eqs. "" then goto version_loop +$ if f$locate("#define LIBCURL_VERSION ", line_in) .ne. 0 +$ then +$ goto version_loop +$ endif +$ raw_version = f$element(2," ", line_in) - """" - """" +$ version_loop_end: +$ close vhf +$! +$! +$ eco_level = "" +$ if f$search("''default_dir'vms_eco_level.h") .nes. "" +$ then +$ open/read ef 'default_dir'vms_eco_level.h +$ecolevel_loop: +$ read/end=ecolevel_loop_end ef line_in +$ prefix = f$element(0, " ", line_in) +$ if prefix .nes. "#define" then goto ecolevel_loop +$ key = f$element(1, " ", line_in) +$ value = f$element(2, " ", line_in) - """" - """" +$ if key .eqs. "VMS_ECO_LEVEL" +$ then +$ eco_level = "''value'" +$ if eco_level .eqs. "0" +$ then +$ eco_level = "" +$ else +$ eco_level = "E" + eco_level +$ endif +$ goto ecolevel_loop_end +$ endif +$ goto ecolevel_loop +$ecolevel_loop_end: +$ close ef +$ endif +$! +$! +$! This translates to V0732-0 or D0732-0 +$! We encode the snapshot date into the version as an ECO since a daily +$! can never have an ECO. +$! +$! version_type = 'V' for a production release, and 'D' for a build from a +$! daiy snapshot of the curl source. +$ majorver = f$element(0, ".", raw_version) +$ minorver = f$element(1, ".", raw_version) +$ raw_update = f$element(2, ".", raw_version) +$ update = f$element(0, "-", raw_update) +$ if update .eqs. "0" then update = "" +$ daily_tag = f$element(1, "-", raw_update) +$ vtype = "V" +$ patch = "" +$ if daily_tag .nes. "-" +$ then +$ vtype = "D" +$ daily_tag_len = f$length(daily_tag) +$ daily_tag = f$extract(4, daily_tag_len - 4, daily_tag) +$ patch = vtype + daily_tag +$ product = product + "_d" +$ else +$ daily_tag = "" +$ if eco_level .nes. "" then patch = eco_level +$ endif +$! +$! +$ version_fao = "!2ZB!2ZB" +$ mmversion = f$fao(version_fao, 'majorver', 'minorver') +$ version = vtype + "''mmversion'" +$ if update .nes. "" .or. patch .nes. "" +$ then +$! The presence of a patch implies an update +$ if update .eqs. "" .and. patch .nes. "" then update = "0" +$ version = version + "-" + update + patch +$ fversion = version +$ else +$ fversion = version +$ version = version + "-" +$ endif +$! +$! Kit type 1 is complete kit, the only type that this procedure will make. +$ kittype = 1 +$! +$! Write out a logical name for the resulting base kit name. +$ name = "''producer'-''base'-''product'-''version'-''kittype'" +$ define GNV_PCSI_KITNAME "''name'" +$ fname = "''product'-''fversion'" +$ define GNV_PCSI_FILENAME_BASE "''fname'" +$ write sys$output "*****" +$ write sys$output "***** GNV_PCSI_KITNAME = ''name'." +$ write sys$output "***** GNV_PCSI_FILENAME_BASE = ''fname'." +$ write sys$output "*****" +$! +$all_exit: +$ set def 'default_dir' +$ exit '$status' diff --git a/packages/vms/pcsi_gnv_curl_file_list.txt b/packages/vms/pcsi_gnv_curl_file_list.txt new file mode 100644 index 0000000..586f7e7 --- /dev/null +++ b/packages/vms/pcsi_gnv_curl_file_list.txt @@ -0,0 +1,125 @@ +! File: PCSI_GNV_CURL_FILE_LIST.TXT +! +! File list for building a PCSI kit. +! Very simple format so that the parsing logic can be simple. +! links first, directory second, and files third. +! +! link -> file tells procedure to create/remove a link on install/uninstall +! If more than one link, consider using an alias file. +! +! [xxx.yyy]foo.dir is a directory file for the rename phase. +! [xxx.yyy.foo] is a directory file for the create phase. +! Each subdirectory needs to be on its own pair of lines. +! +! [xxx.yyy]file.ext is a file for the rename and add phases. +! +! Copyright (C) John Malmberg +! +! Permission to use, copy, modify, and/or distribute this software for any +! purpose with or without fee is hereby granted, provided that the above +! copyright notice and this permission notice appear in all copies. +! +! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +! +! SPDX-License-Identifier: ISC +! +!============================================================================ +[gnv.usr.bin]curl. -> [gnv.usr.bin]gnv$curl.exe +[gnv.usr.bin]curl.exe -> [gnv.usr.bin]gnv$curl.exe +[gnv] +[000000]gnv.dir +[gnv.usr] +[gnv]usr.dir +[gnv.usr]bin.dir +[gnv.usr.bin] +[gnv.usr]include.dir +[gnv.usr.include] +[gnv.usr.include]curl.dir +[gnv.usr.include.curl] +[gnv.usr]lib.dir +[gnv.usr.lib] +[gnv.usr.lib]pkgconfig.dir +[gnv.usr.lib.pkgconfig] +[gnv.usr]share.dir +[gnv.usr.share] +[gnv.usr.share]man.dir +[gnv.usr.share.man] +[gnv.usr.share.man]man1.dir +[gnv.usr.share.man.man1] +[gnv.usr.share.man]man3.dir +[gnv.usr.share.man.man3] +[gnv.usr.bin]curl-config. +[gnv.usr.bin]gnv$curl.exe +[gnv.usr.include.curl]curl.h +[gnv.usr.include.curl]system.h +[gnv.usr.include.curl]curlver.h +[gnv.usr.include.curl]easy.h +[gnv.usr.include.curl]mprintf.h +[gnv.usr.include.curl]multi.h +[gnv.usr.include.curl]stdcheaders.h +[gnv.usr.include.curl]typecheck-gcc.h +[gnv.usr.lib]gnv$libcurl.exe +[gnv.usr.lib]gnv$curlmsg.exe +[gnv.usr.lib.pkgconfig]libcurl.pc +[gnv.usr.share.man.man1]curl-config.1 +[gnv.usr.share.man.man1]curl.1 +[gnv.usr.share.man.man3]curl_easy_cleanup.3 +[gnv.usr.share.man.man3]curl_easy_duphandle.3 +[gnv.usr.share.man.man3]curl_easy_escape.3 +[gnv.usr.share.man.man3]curl_easy_getinfo.3 +[gnv.usr.share.man.man3]curl_easy_init.3 +[gnv.usr.share.man.man3]curl_easy_pause.3 +[gnv.usr.share.man.man3]curl_easy_perform.3 +[gnv.usr.share.man.man3]curl_easy_recv.3 +[gnv.usr.share.man.man3]curl_easy_reset.3 +[gnv.usr.share.man.man3]curl_easy_send.3 +[gnv.usr.share.man.man3]curl_easy_setopt.3 +[gnv.usr.share.man.man3]curl_easy_strerror.3 +[gnv.usr.share.man.man3]curl_easy_unescape.3 +[gnv.usr.share.man.man3]curl_escape.3 +[gnv.usr.share.man.man3]curl_formadd.3 +[gnv.usr.share.man.man3]curl_formfree.3 +[gnv.usr.share.man.man3]curl_formget.3 +[gnv.usr.share.man.man3]curl_free.3 +[gnv.usr.share.man.man3]curl_getdate.3 +[gnv.usr.share.man.man3]curl_getenv.3 +[gnv.usr.share.man.man3]curl_global_cleanup.3 +[gnv.usr.share.man.man3]curl_global_init.3 +[gnv.usr.share.man.man3]curl_global_init_mem.3 +[gnv.usr.share.man.man3]curl_mprintf.3 +[gnv.usr.share.man.man3]curl_multi_add_handle.3 +[gnv.usr.share.man.man3]curl_multi_assign.3 +[gnv.usr.share.man.man3]curl_multi_cleanup.3 +[gnv.usr.share.man.man3]curl_multi_fdset.3 +[gnv.usr.share.man.man3]curl_multi_info_read.3 +[gnv.usr.share.man.man3]curl_multi_init.3 +[gnv.usr.share.man.man3]curl_multi_perform.3 +[gnv.usr.share.man.man3]curl_multi_remove_handle.3 +[gnv.usr.share.man.man3]curl_multi_setopt.3 +[gnv.usr.share.man.man3]curl_multi_socket.3 +[gnv.usr.share.man.man3]curl_multi_socket_action.3 +[gnv.usr.share.man.man3]curl_multi_strerror.3 +[gnv.usr.share.man.man3]curl_multi_timeout.3 +[gnv.usr.share.man.man3]curl_multi_wait.3 +[gnv.usr.share.man.man3]curl_share_cleanup.3 +[gnv.usr.share.man.man3]curl_share_init.3 +[gnv.usr.share.man.man3]curl_share_setopt.3 +[gnv.usr.share.man.man3]curl_share_strerror.3 +[gnv.usr.share.man.man3]curl_slist_append.3 +[gnv.usr.share.man.man3]curl_slist_free_all.3 +[gnv.usr.share.man.man3]curl_strequal.3 +[gnv.usr.share.man.man3]curl_unescape.3 +[gnv.usr.share.man.man3]curl_version.3 +[gnv.usr.share.man.man3]curl_version_info.3 +[gnv.usr.share.man.man3]libcurl-easy.3 +[gnv.usr.share.man.man3]libcurl-errors.3 +[gnv.usr.share.man.man3]libcurl-multi.3 +[gnv.usr.share.man.man3]libcurl-share.3 +[gnv.usr.share.man.man3]libcurl-tutorial.3 +[gnv.usr.share.man.man3]libcurl.3 diff --git a/packages/vms/pcsi_product_gnv_curl.com b/packages/vms/pcsi_product_gnv_curl.com new file mode 100644 index 0000000..83d8fa3 --- /dev/null +++ b/packages/vms/pcsi_product_gnv_curl.com @@ -0,0 +1,197 @@ +$! File: PCSI_PRODUCT_GNV_CURL.COM +$! +$! This command file packages up the product CURL into a sequential +$! format kit +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!========================================================================= +$! +$! Save default +$ default_dir = f$environment("DEFAULT") +$! +$! Put things back on error. +$ on warning then goto all_exit +$! +$! +$ can_build = 1 +$ producer = f$trnlnm("GNV_PCSI_PRODUCER") +$ if producer .eqs. "" +$ then +$ write sys$output "GNV_PCSI_PRODUCER logical name has not been set." +$ can_build = 0 +$ endif +$ producer_full_name = f$trnlnm("GNV_PCSI_PRODUCER_FULL_NAME") +$ if producer_full_name .eqs. "" +$ then +$ write sys$output - + "GNV_PCSI_PRODUCER_FULL_NAME logical name has not been set." +$ can_build = 0 +$ endif +$ stage_root_name = f$trnlnm("STAGE_ROOT") +$ if stage_root_name .eqs. "" +$ then +$ write sys$output "STAGE_ROOT logical name has not been set." +$ can_build = 0 +$ endif +$! +$ if (can_build .eq. 0) +$ then +$ write sys$output "Not able to build a kit." +$ goto all_exit +$ endif +$! +$! Make sure that the kit name is up to date for this build +$!---------------------------------------------------------- +$ @MAKE_PCSI_CURL_KIT_NAME.COM +$! +$! +$! Make sure that the image is built +$!---------------------------------- +$ arch_name = f$edit(f$getsyi("arch_name"),"UPCASE") +$ if f$search("[--.src]curl.exe") .eqs. "" +$ then +$ build_it = 1 +$ libfile = "[.packages.vms.''arch_name']curllib.olb" +$ if f$search(libfile) .nes. "" +$ then +$ build_it = 0 +$ else +$ ! GNV based build +$ libfile = "[.lib.^.libs]libcurl.a" +$ if f$search(libfile) .nes. "" +$ then +$ build_it = 0; +$ endif +$ endif +$ if build_it .eq. 1 +$ then +$ @build_vms list +$ endif +$ @gnv_link_curl.com +$ endif +$! +$! Make sure that the release note file name is up to date +$!--------------------------------------------------------- +$ @BUILD_GNV_CURL_RELEASE_NOTES.COM +$! +$! +$! Make sure that the source has been backed up. +$!---------------------------------------------- +$ arch_type = f$getsyi("ARCH_NAME") +$ arch_code = f$extract(0, 1, arch_type) +$ @backup_gnv_curl_src.com +$! +$! Regenerate the PCSI description file. +$!-------------------------------------- +$ @BUILD_GNV_CURL_PCSI_DESC.COM +$! +$! Regenerate the PCSI Text file. +$!--------------------------------- +$ @BUILD_GNV_CURL_PCSI_TEXT.COM +$! +$! +$! Parse the kit name into components. +$!--------------------------------------- +$ kit_name = f$trnlnm("GNV_PCSI_KITNAME") +$ if kit_name .eqs. "" +$ then +$ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." +$ goto all_exit +$ endif +$ producer = f$element(0, "-", kit_name) +$ base = f$element(1, "-", kit_name) +$ product_name = f$element(2, "-", kit_name) +$ mmversion = f$element(3, "-", kit_name) +$ majorver = f$extract(0, 3, mmversion) +$ minorver = f$extract(3, 2, mmversion) +$ updatepatch = f$element(4, "-", kit_name) +$ if updatepatch .eqs. "" then updatepatch = "" +$! +$ version_fao = "!AS.!AS" +$ mmversion = f$fao(version_fao, "''majorver'", "''minorver'") +$ if updatepatch .nes. "" +$ then +$ version = "''mmversion'" + "-" + updatepatch +$ else +$ version = "''mmversion'" +$ endif +$! +$ @stage_curl_install remove +$ @stage_curl_install +$! +$! Move to the base directories +$ set def [--] +$ current_default = f$environment("DEFAULT") +$ my_dir = f$parse(current_default,,,"DIRECTORY") - "[" - "<" - ">" - "]" +$! +$! +$! +$ source = "''default_dir'" +$ src1 = "new_gnu:[usr.bin]," +$ src2 = "new_gnu:[usr.include.curl]," +$ src3 = "new_gnu:[usr.lib]," +$ src4 = "new_gnu:[usr.lib.pkgconfig]," +$ src5 = "new_gnu:[usr.share.man.man1]," +$ src6 = "new_gnu:[usr.share.man.man3]," +$ src7 = "new_gnu:[vms_src]," +$ src8 = "new_gnu:[common_src]," +$ src9 = "prj_root:[''my_dir'],prj_root:[''my_dir'.src]" +$ gnu_src = src1 + src2 + src3 + src4 + src5 + src6 + src7 + src8 + src9 +$! +$! +$ base = "" +$ if arch_name .eqs. "ALPHA" then base = "AXPVMS" +$ if arch_name .eqs. "IA64" then base = "I64VMS" +$ if arch_name .eqs. "VAX" then base = "VAXVMS" +$! +$ if base .eqs. "" then exit 44 +$! +$ pcsi_option = "/option=noconfirm" +$ if arch_code .eqs. "V" +$ then +$ pcsi_option = "" +$ endif +$! +$! +$product package 'product_name' - + /base='base' - + /producer='producer' - + /source='source' - + /destination=STAGE_ROOT:[KIT] - + /material=('gnu_src','source') - + /format=sequential 'pcsi_option' +$! +$! +$! VAX can not do a compressed kit. +$! ZIP -9 "-V" does a better job, so no reason to normally build a compressed +$! kit. +$!---------------------------------- +$if p1 .eqs. "COMPRESSED" +$then +$ if arch_code .nes. "V" +$ then +$ product copy /options=(novalidate, noconfirm) /format=compressed - + 'product_name' - + /source=stage_root:[kit]/dest=stage_root:[kit] - + /version='version'/base='base' +$ endif +$endif +$! +$all_exit: +$ set def 'default_dir' +$ exit diff --git a/packages/vms/readme b/packages/vms/readme new file mode 100644 index 0000000..0bb6166 --- /dev/null +++ b/packages/vms/readme @@ -0,0 +1,228 @@ + _ _ ____ _ + ___| | | | _ \| | + / __| | | | |_) | | + ( (__| |_| | _ <| |___ + \___|\___/|_| \_\_____| + for OpenVMS + +History: + + 9-MAR-2004, Created this readme. file. Marty Kuhrt (MSK). +15-MAR-2004, MSK, Updated to reflect the new files in this directory. +14-FEB-2005, MSK, removed config-vms.h_with* file comments +10-FEB-2010, SMS. General update. +14-Jul-2013, JEM, General Update, add GNV build information. + + +The release notes installed by the PCSI kit consist of this file and the +curl_gnv_build_steps.txt and other useful information. + +Prerequisites: + +OpenVMS V7.0 or later (any platform) +DECC V6.5 or later +OpenSSL or hp SSL, if you want SSL support + +What is Here: + +This directory contains the following files for a DCL based build. + +backup_gnv_curl_src.com This procedure backs up the source modules for + creating a PCSI kit. + +build_curl-config_script.com + Procedure to create the curl-config script. + +build_gnv_curl.com This procedure does a build of curl using the + GNV utilities and then uses DCL tools to build + the libcurl shared image. The setup_gnv_curl_build.com + procedure must be run first. + +build_gnv_curl_pcsi_desc.com + This procedure builds the pcsi$desc file for + creating a PCSI based package. + +build_gnv_curl_pcsi_text.com + This procedure builds the pcsi$text file for + creating a PCSI based package. + +build_gnv_curl_release_notes.com + This procedure creates the release notes for + a PCSI kit based on curl_release_note_start.txt, + this readme file, and the curl_gnv_build_steps.txt + +build_libcurl_pc.com Procedure to create a libcurl.pc file. + +build_vms.com DCL based build procedure. + +clean_gnv_curl.com This procedure cleans up the files generated by + a GNV based build. + +config_h.com DCL based procedure used by build_vms.com + to run generate the curl_config.h file. + This is a generic procedure that does most + of the work for generating config.h files. + +compare_curl_source.com Procedure to compare the working directory + with a repository directory or a backup staging + directory. + +curl_crtl_init.c A special pre-initialization routine to for + programs to behave more Unix like when run + under GNV. + +curl_gnv_build_steps.txt + Detailed instructions on how to built curl using + GNV and how to build the libcurl shared image and + PCSI kit. + +curl_release_note_start.txt + The first part of the curl release notes. + +curl_startup.com A procedure run at VMS startup to install the + libcurl shared image and to set up the needed + logical names. + +curlmsg.h C header defining curl status code macros. + +curlmsg.msg Error message source for curlmsg.h and curlmsg.sdl. + +curlmsg.sdl SDL source defining curl status code constants. + +curlmsg_vms.h Mapping of curl status codes to VMS-form codes. + +generate_config_vms_h_curl.com + DCL procedure to generate the curl specific + definitions for curl_config.h that config_h.com + can not properly generate. + +generate_vax_transfer.com + DCL procedure to read an Alpha/IA64 symbol vector + linker option file and generate the VAX transfer + vector modules. + +gnv_conftest.c_first A helper file for the configure script. + +gnv_curl_configure.sh A script to run the configure script with the + options needed for VMS. + +gnv_libcurl_symbols.opt The symbol vectors needed for Alpha and IA64 + libcurl shared image. + +gnv_link_curl.com Links the libcurl shared image and then links a curl + image to use the libcurl. + +macro32_exactcase.patch The patch file needed to modify VAX Macro32 to be + case sensitive and case preserving. + +Makefile.am curl kit file list for this directory. + +Makefile.in curl kit makefile source for this directory. + +make_gnv_curl_install.sh + Script to do a make install using GNV after running + the configure script. + +make_pcsi_curl_kit_name.com + This generates the name of the PCSI kit based on + the version of curl being built. + +pcsi_gnv_curl_file_list.txt + This is a text file describing what files should + be included in a PCSI kit. + +pcsi_product_gnv_curl.com + This generates the PCSI kit after the libcurl + shared image has been made. + +readme. This file. + +report_openssl_version.c + Program to check that the openssl version is new + enough for building a shared libcurl image. + +setup_gnv_curl_build.com + This procedure sets up symbols and logical names + for a GNV build environment and also copies some + helper files. + +stage_curl_install.com This procedure sets up new_gnu: directory tree to + for testing the install and building the PCSI kit. + It takes a "remove" option to remove all the staged + files. + +vms_eco_level.h This sets the ECO level for the PCSI kit name. + + +How to Build: + +The GNV based build and the DCL based build procedures are not compatible +and you must make sure that none of the build files are present before +running a different type of build. Use the "REALCLEAN" option for +BUILD_VMS.COM and the "REALCLEAN" option for clean_gnv_curl.com. + +The (brute-force) DCL based builder is [.packages.vms]build_vms.com. +Comments in this procedure describe various optional parameters which +enable or disable optional program features, or which control the build +in other ways. Product files (.EXE, .H, .LIS, .MAP, .OBJ, .OLB, ...) +should be produced in an architecture-specific subdirectory under this +directory ([.ALPHA], [.IA64], [.VAX]). + +The file curl_gnv_build_steps.txt contains information on building using +the GNV tool kit, building a shared libcurl, and producing a PCSI kit for +distribution. The curl_gnv_build_steps.text is included in the release +notes file of the PCSI kit. + +The building with 64 bit pointers does not currently work. + +The build procedure will detect if HP OpenSSL, LDAP, and Kerberos are +installed and default to building with them. + +The build procedure will also detect if a compatible ZLIB shared image +is installed from a PCSI kit and default to using it. + + Example build commands: + + @ [.packages.vms]build_vms.com CLEAN + @ [.packages.vms]build_vms.com LARGE LDAP + submit /noprint [.packages.vms]build_vms.com /param = (LARGE, LDAP) + +The build_vms.com procedure does not build the shared image file or the PCSI +kit. If you have built a curl with ZLIB and HPSSL support as well as if +LDAP and Kerberos installed, you can use the GNV_LINK_CURL.COM file. + +The GNV_LINK_CURL.COM contains information on how to link and run with a newer +version of HP SSL than what may be install on an Alpha or IA64 based system. + +To build the PCSI kit, follow the instructions in the file +curl_gnv_build_steps.txt. + +Other Notes: + +This release fixes known bugs #22, and #57 in the [curl.docs]known_bugs. +file. + +The libcurl formdata.c module and Curl tools post form now have some +understanding of VMS file types. Files will be posted in STREAM_LF format. + +The Curl tool now has some understanding of VMS file types and will upload the +files in STREAM_LF format. + +When CURL is uploading a VARIABLE format VMS file, it is less efficient as in +order to get the file size, it will first read the entire file once, and then +read the file again for the actual upload. + +The Curl tool will now always download files into STREAM_LF format. Even if a +file by that name with a different format already exists. This is needed to +allow interrupted downloads to be continued. + + +The libcurl file module still does not understand VMS file types and requires +the input files to be in STREAM_LF to work property. + +The test suites are not supported as of 7.11.0. + +The curlmsg.sdl and curlmsg.h files are generated from curlmsg.msg. +This is not done automatically, since the .MSG file is a hand edit +of the relevant stuff from the curl.h file. If you want to do this +yourself you'll need the SDL package from the freeware collection. diff --git a/packages/vms/report_openssl_version.c b/packages/vms/report_openssl_version.c new file mode 100644 index 0000000..64e1ee0 --- /dev/null +++ b/packages/vms/report_openssl_version.c @@ -0,0 +1,100 @@ +/* File: report_openssl_version.c + * + * This file dynamically loads the openssl shared image to report the + * version string. + * + * It will optionally place that version string in a DCL symbol. + * + * Usage: report_openssl_version [] + * + * Copyright (C) John Malmberg + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: ISC + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +unsigned long LIB$SET_SYMBOL( + const struct dsc$descriptor_s * symbol, + const struct dsc$descriptor_s * value, + const unsigned long * table_type); + +int main(int argc, char ** argv) { + + +void * libptr; +const char * (*ssl_version)(int t); +const char * version; + + if(argc < 1) { + puts("report_openssl_version filename"); + exit(1); + } + + libptr = dlopen(argv[1], 0); + + ssl_version = (const char * (*)(int))dlsym(libptr, "SSLeay_version"); + if(ssl_version == NULL) { + ssl_version = (const char * (*)(int))dlsym(libptr, "ssleay_version"); + if(ssl_version == NULL) { + ssl_version = (const char * (*)(int))dlsym(libptr, "SSLEAY_VERSION"); + } + } + + dlclose(libptr); + + if(ssl_version == NULL) { + puts("Unable to lookup version of OpenSSL"); + exit(1); + } + + version = ssl_version(SSLEAY_VERSION); + + puts(version); + + /* Was a symbol argument given? */ + if(argc > 1) { + int status; + struct dsc$descriptor_s symbol_dsc; + struct dsc$descriptor_s value_dsc; + const unsigned long table_type = LIB$K_CLI_LOCAL_SYM; + + symbol_dsc.dsc$a_pointer = argv[2]; + symbol_dsc.dsc$w_length = strlen(argv[2]); + symbol_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + symbol_dsc.dsc$b_class = DSC$K_CLASS_S; + + value_dsc.dsc$a_pointer = (char *)version; /* Cast ok */ + value_dsc.dsc$w_length = strlen(version); + value_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + value_dsc.dsc$b_class = DSC$K_CLASS_S; + + status = LIB$SET_SYMBOL(&symbol_dsc, &value_dsc, &table_type); + if(!$VMS_STATUS_SUCCESS(status)) { + exit(status); + } + } + + exit(0); +} diff --git a/packages/vms/setup_gnv_curl_build.com b/packages/vms/setup_gnv_curl_build.com new file mode 100644 index 0000000..8404ec3 --- /dev/null +++ b/packages/vms/setup_gnv_curl_build.com @@ -0,0 +1,286 @@ +$! File: setup_gnv_curl_build.com +$! +$! Set up build environment for building Curl under GNV on VMS. +$! +$! GNV needs some files moved into the other directories to help with +$! the configure script and the build. +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!======================================================================= +$! +$! Save this so we can get back. +$ default_dir = f$environment("default") +$! +$! Move to where the Configure script is. +$ set def [--] +$! +$! Get the path to where the Configure script is. +$ base_dir = f$environment("default") +$! +$! Allow arguments to be grouped together with comma or separated by spaces +$! Do no know if we will need more than 8. +$ args = "," + p1 + "," + p2 + "," + p3 + "," + p4 + "," +$ args = args + p5 + "," + p6 + "," + p7 + "," + p8 + "," +$! +$! Provide lower case version to simplify parsing. +$ args_lower = f$edit(args, "LOWERCASE,COLLAPSE") +$! +$ args_len = f$length(args) +$ args_lower_len = f$length(args_lower) +$! +$ tests = 0 +$ if f$locate(",test", args_lower) .lt. args_lower_len +$ then +$ tests = 1 +$ endif +$! +$ examples = 0 +$ if f$locate(",exam", args_lower) .lt. args_lower_len +$ then +$ examples = 1 +$ endif +$! +$! We want detailed build logs. +$ clist = "/list/show=(expan,includ)" +$! +$! We want full symbol names in exact case. Need a common +$! repository for all directories. +$ cnames = "/names=(shortened,as_is)/repository=''base_dir'" +$! +$! Set the compiler options for GNV CC wrapper to inherit. +$ cc :== cc'clist''cnames'/nested_include_directory=none +$ cxx :== cxx'clist''cnames'/nested_include_directory=none +$ pointer_size = "32" +$! Note 64 bit pointers requires all libraries to either have +$! 64 bit pointers or have #pragma directives. +$! Currently building curl on VMS with 64 bit pointers does not work. +$! +$! A logical name to make it easier to find some of the hacks. +$ define/job gnv_hacks 'base_dir' +$! +$! A logical name to find the [.packages.vms] directory where we started. +$ define/job gnv_packages_vms 'default_dir' +$! +$! Kerberos headers: +$ if f$trnlnm("gssapi") .eqs. "" +$ then +$ if f$search("sys$sysroot:[kerberos]include.dir") .nes. "" +$ then +$ define/job gssapi sys$sysroot:[kerberos.include] +$ endif +$ endif +$! +$! OpenSSL headers +$ if f$trnlnm("openssl") .eqs. "" +$ then +$ if f$trnlnm("ssl$include") .nes. "" +$ then +$ define/job openssl ssl$include: +$ endif +$ endif +$! +$! C compiler include path. +$ define/job decc$system_include prj_root:[.include.curl],- + [-.packages.vms],- + ssl$include:,gnv$gnu:[usr.include],- + gnv$gnu:[usr.include.libz],gnv$gnu:[include],- + gnv$zlib_include:,- + sys$sysroot:[kerberos.include] +$! +$! Set up a include list for the compiler to find all the header files +$! that they need. +$! +$ define/job decc$user_include src_root:[.include.curl] +$ define ssl_lib sys$library: +$! +$! Calculate what is needed in the option files +$ libzshr_line = "" +$ try_shr = "gnv$libzshr''pointer_size'" +$ if f$search(try_shr) .nes. "" then libzshr_line = "''try_shr'/share" +$ if (libzshr_line .eqs. "") +$ then +$ try_shr = "sys$share:" + try_shr +$ if f$search("''try_shr'.exe") .nes. "" +$ then +$ libzshr_line = "''try_shr'/share" +$ endif +$ endif +$! +$! Kerberos +$ gssrtlshr_line = "" +$ try_shr = "sys$share:gss$rtl" +$ if f$search("''try_shr'.exe") .nes. "" +$ then +$ gssrtlshr_line = "''try_shr'/share" +$ endif +$! +$! HP OpenSSL +$ libcryptoshr_line = "" +$ try_shr = "sys$share:ssl$libcrypto_shr''pointer_size'" +$ if f$search("''try_shr'.exe") .nes. "" +$ then +$ libcryptoshr_line = "''try_shr'/share" +$ endif +$! +$ libsslshr_line = "" +$ try_shr = "sys$share:ssl$libssl_shr''pointer_size'" +$ if f$search("''try_shr'.exe") .nes. "" +$ then +$ libsslshr_line = "''try_shr'/share" +$ endif +$! +$! +$! Copy over the gnv$conftest* files to base directory. +$!----------------------------------------------------- +$ copy 'default_dir'gnv_conftest.c_first 'base_dir'gnv$conftest.c_first +$ create 'base_dir'gnv$conftest.opt +$ open/append opt 'base_dir'gnv$conftest.opt +$ if libzshr_line .nes. "" then write opt libzshr_line +$ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line +$ if libsslshr_line .nes. "" then write opt libsslshr_line +$ close opt +$ purge 'base_dir'gnv$conftest.* +$ rename 'base_dir'gnv$conftest.* ;1 +$! +$! +$! +$! GNV helper files for building the test curl binary. +$!----------------------------------------------- +$ create [.src]gnv$curl.opt +$ open/append opt [.src]gnv$curl.opt +$ write opt "gnv_packages_vms:curlmsg.obj" +$ if libzshr_line .nes. "" then write opt libzshr_line +$ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line +$ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line +$ if libsslshr_line .nes. "" then write opt libsslshr_line +$ close opt +$ purge [.src]gnv$*.* +$ rename [.src]gnv$*.* ;1 +$! +$! +$! Create the libcurl +$!------------------------------------------------------ +$ create 'default_dir'gnv_libcurl_linker.opt +$ open/append opt 'default_dir'gnv_libcurl_linker.opt +$ if libzshr_line .nes. "" then write opt libzshr_line +$ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line +$ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line +$ if libsslshr_line .nes. "" then write opt libsslshr_line +$ close opt +$! +$! +$! Create the template linker file +$!--------------------------------- +$ create 'default_dir'gnv_template_linker.opt +$ open/append opt 'default_dir'gnv_template_linker.opt +$ write opt "gnv_vms_common:vms_curl_init_unix.obj" +$ if libzshr_line .nes. "" then write opt libzshr_line +$ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line +$ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line +$ if libsslshr_line .nes. "" then write opt libsslshr_line +$ close opt +$! +$! Copy over the gnv$*.opt files for [.docs.examples] +$!---------------------------------------------------- +$ if examples .ne. 0 +$ then +$ example_apps = "10-at-a-time,anyauthput,certinfo,cookie_interface,debug" +$ example_apps = example_apps + ",fileupload,fopen,ftpget,ftpgetresp" +$ example_apps = example_apps + ",ftpupload,getinfo,getinmemory" +$ example_apps = example_apps + ",http-post,httpcustomheader,httpput" +$ example_apps = example_apps + ",https,multi-app,multi-debugcallback" +$ example_apps = example_apps + ",multi-double,multi-post,multi-single" +$ example_apps = example_apps + ",persistent,post-callback,postit2" +$ example_apps = example_apps + ",sendrecv,sepheaders,simple,simplepost" +$ example_apps = example_apps + ",simplessl" +$! +$ i = 0 +$example_loop: +$ ap_name = f$element(i, ",", example_apps) +$ if ap_name .eqs. "," then goto example_loop_end +$ if ap_name .eqs. "" then goto example_loop_end +$ copy 'default_dir'gnv_template_linker.opt - + [.docs.examples]gnv$'ap_name'.opt +$ i = i + 1 +$ goto example_loop +$example_loop_end: +$! +$! clean up the copy. +$ purge [.docs.examples]gnv$*.opt +$ rename [.docs.examples]gnv$*.opt ;1 +$ endif +$! +$! +$ if tests .ne. 0 +$ then +$ libtest_apps = "lib500,lib501,lib502,lib503,lib504,lib505,lib506,lib507" +$ libtest_apps = libtest_apps + ",lib508,lib510,lib511,lib512,lib513,lib514" +$ libtest_apps = libtest_apps + ",lib515,lib516,lib517,lib518,lib519,lib520" +$ libtest_apps = libtest_apps + ",lib521,lib523,lib524,lib525,lib526,lib527" +$ libtest_apps = libtest_apps + ",lib529,lib530,lib532,lib533,lib536,lib537" +$ libtest_apps = libtest_apps + ",lib539,lib540,lib541,lib542,lib543,lib544" +$ libtest_apps = libtest_apps + ",lib545,lib547,lib548,lib549,lib552,lib553" +$ libtest_apps = libtest_apps + ",lib554,lib555,lib556,lib557,lib558,lib559" +$ libtest_apps = libtest_apps + ",lib560,lib562,lib564" +$ i = 0 +$libtest_loop: +$ ap_name = f$element(i, ",", libtest_apps) +$ if ap_name .eqs. "," then goto libtest_loop_end +$ if ap_name .eqs. "" then goto libtest_loop_end +$ copy 'default_dir'gnv_template_linker.opt - + [.tests.libtest]gnv$'ap_name'.opt +$ i = i + 1 +$ goto libtest_loop +$libtest_loop_end: +$! +$! clean up the copy. +$ purge [.tests.libtest]gnv$*.opt +$ rename [.tests.libtest]gnv$*.opt ;1 +$ endif +$! +$! +$! Build the Message file. +$!-------------------------- +$ if f$search("[.packages.vms]curlmsg.obj") .eqs. "" +$ then +$ message [.packages.vms]curlmsg.msg/object=[.packages.vms] +$ endif +$ if f$search("gnv$curlmsg.exe") .eqs. "" +$ then +$ link/share=gnv$curlmsg.exe [.packages.vms]curlmsg.obj +$ endif +$! +$! +$! +$! Need to build the common init module. +$!------------------------------------------- +$ init_obj = "[.packages.vms]curl_crtl_init.obj" +$ if f$search(init_obj) .eqs. "" +$ then +$ cc'cflags' 'default_dir'curl_crtl_init.c/obj='init_obj' +$ purge 'init_obj' +$ rename 'init_obj' ;1 +$ endif +$! +$all_exit: +$! +$ set def 'default_dir' +$! +$! Verify can break things in bash, especially in Configure scripts. +$ set nover +$ exit diff --git a/packages/vms/stage_curl_install.com b/packages/vms/stage_curl_install.com new file mode 100644 index 0000000..10ae17a --- /dev/null +++ b/packages/vms/stage_curl_install.com @@ -0,0 +1,170 @@ +$! File: stage_curl_install.com +$! +$! This updates or removes the GNV$CURL.EXE and related files for the +$! new_gnu:[*...] directory tree for running the self tests. +$! +$! The files installed/removed are: +$! [usr.bin]gnv$curl.exe +$! [usr.bin]curl-config. +$! [usr.lib]gnv$libcurl.exe +$! [usr.bin]curl. hard link for [usr.bin]gnv$curl.exe +$! [usr.include.curl]curl.h +$! [usr.include.curl]curlver.h +$! [usr.include.curl]easy.h +$! [usr.include.curl]mprintf.h +$! [usr.include.curl]multi.h +$! [usr.include.curl]stdcheaders.h +$! [usr.include.curl]typecheck-gcc.h +$! [usr.lib.pkgconfig]libcurl.pc +$! [usr.share.man.man1]curl-config.1 +$! [usr.share.man.man1]curl.1 +$! [usr.share.man.man3]curl*.3 +$! [usr.share.man.man3]libcurl*.3 +$! Future: A symbolic link to the release notes? +$! +$! Copyright (C) John Malmberg +$! +$! Permission to use, copy, modify, and/or distribute this software for any +$! purpose with or without fee is hereby granted, provided that the above +$! copyright notice and this permission notice appear in all copies. +$! +$! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +$! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +$! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +$! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +$! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +$! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +$! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +$! +$! SPDX-License-Identifier: ISC +$! +$!=========================================================================== +$! +$ arch_type = f$getsyi("ARCH_NAME") +$ arch_code = f$extract(0, 1, arch_type) +$! +$ if arch_code .nes. "V" +$ then +$ set proc/parse=extended +$ endif +$! +$! +$! If the first parameter begins with "r" or "R" then this is to +$! remove the files instead of installing them. +$ remove_filesq = f$edit(p1, "upcase,trim") +$ remove_filesq = f$extract(0, 1, remove_filesq) +$ remove_files = 0 +$ if remove_filesq .eqs. "R" then remove_files = 1 +$! +$! +$! If we are staging files, make sure that the libcurl.pc and curl-config +$! files are present. +$ if remove_files .eq. 0 +$ then +$ if f$search("[--]libcurl.pc") .eqs. "" +$ then +$ @build_libcurl_pc.com +$ endif +$ if f$search("[--]curl-config") .eqs. "" +$ then +$ @build_curl-config_script.com +$ endif +$ endif +$! +$! +$! Dest dirs +$!------------------ +$ dest_dirs1 = "[usr],[usr.bin],[usr.include],[usr.include.curl]" +$ dest_dirs2 = ",[usr.bin],[usr.lib.pkgconfig],[usr.share]" +$ dest_dirs3 = ",[usr.share.man],[usr.share.man.man1],[usr.share.man.man3]" +$ dest_dirs = dest_dirs1 + dest_dirs2 + dest_dirs3 +$! +$! +$! Alias links needed. +$!------------------------- +$ source_curl = "gnv$curl.exe" +$ dest_curl = "[bin]gnv$curl.exe" +$ curl_links = "[bin]curl." +$ new_gnu = "new_gnu:" +$! +$! +$! Create the directories if they do not exist +$!--------------------------------------------- +$ i = 0 +$curl_dir_loop: +$ this_dir = f$element(i, ",", dest_dirs) +$ i = i + 1 +$ if this_dir .eqs. "" then goto curl_dir_loop +$ if this_dir .eqs. "," then goto curl_dir_loop_end +$! Just create the directories, do not delete them. +$! -------------------------------------------------- +$ if remove_files .eq. 0 +$ then +$ create/dir 'new_gnu''this_dir'/prot=(o:rwed) +$ endif +$ goto curl_dir_loop +$curl_dir_loop_end: +$! +$! +$! Need to add in the executable file +$!----------------------------------- +$ if remove_files .eq. 0 +$ then +$ copy [--.src]curl.exe 'new_gnu'[usr.bin]gnv$curl.exe/prot=w:re +$ copy [--]curl-config. 'new_gnu'[usr.bin]curl-config./prot=w:re +$ copy sys$disk:[]gnv$libcurl.exe 'new_gnu'[usr.lib]gnv$libcurl.exe/prot=w:re +$ endif +$! +$ if remove_files .eq. 0 +$ then +$ set file/enter='new_gnu'[bin]curl. 'new_gnu'[usr.bin]gnv$curl.exe +$ else +$ file = "''new_gnu'[bin]curl." +$ if f$search(file) .nes. "" then set file/remove 'file';* +$ endif +$! +$! +$ if remove_files .eq. 0 +$ then +$ copy [--.include.curl]curl.h 'new_gnu'[usr.include.curl]curl.h +$ copy [--.include.curl]system.h - + 'new_gnu'[usr.include.curl]system.h +$ copy [--.include.curl]curlver.h - + 'new_gnu'[usr.include.curl]curlver.h +$ copy [--.include.curl]easy.h - + 'new_gnu'[usr.include.curl]easy.h +$ copy [--.include.curl]mprintf.h - + 'new_gnu'[usr.include.curl]mprintf.h +$ copy [--.include.curl]multi.h - + 'new_gnu'[usr.include.curl]multi.h +$ copy [--.include.curl]stdcheaders.h - + 'new_gnu'[usr.include.curl]stdcheaders.h +$ copy [--.include.curl]typecheck-gcc.h - + 'new_gnu'[usr.include.curl]typecheck-gcc.h +$ copy [--]libcurl.pc 'new_gnu'[usr.lib.pkgconfig]libcurl.pc +$! +$ copy [--.docs]curl-config.1 'new_gnu'[usr.share.man.man1]curl-config.1 +$ copy [--.docs]curl.1 'new_gnu'[usr.share.man.man1]curl.1 +$! +$ copy [--.docs.libcurl]*.3 - + 'new_gnu'[usr.share.man.man3]*.3 +$! +$ else +$ file = "''new_gnu'[usr.bin]curl-config." +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "''new_gnu'[usr.bin]gnv$curl.exe" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "''new_gnu'[usr.lib]gnv$libcurl.exe" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "''new_gnu'[usr.include.curl]*.h" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "''new_gnu'[usr.share.man.man1]curl-config.1" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "''new_gnu'[usr.share.man.man1]curl.1" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "''new_gnu'[usr.share.man.man3]curl*.3" +$ if f$search(file) .nes. "" then delete 'file';* +$ file = "''new_gnu'[usr.share.man.man3]libcurl*.3" +$ if f$search(file) .nes. "" then delete 'file';* +$ endif +$! diff --git a/packages/vms/vms_eco_level.h b/packages/vms/vms_eco_level.h new file mode 100644 index 0000000..89f1dfd --- /dev/null +++ b/packages/vms/vms_eco_level.h @@ -0,0 +1,30 @@ +/* File: vms_eco_level.h + * + * Copyright (C) John Malmberg + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: ISC + * + */ + +/* This file should be incremented for each ECO that is kit */ +/* for a specific curl x.y-z release. */ +/* When any part of x.y-z is incremented, the ECO should be set back to 0 */ + +#ifndef _VMS_ECO_LEVEL_H +#define _VMS_ECO_LEVEL_H + +#define VMS_ECO_LEVEL "0" + +#endif diff --git a/plan9/README b/plan9/README new file mode 100644 index 0000000..6df23d3 --- /dev/null +++ b/plan9/README @@ -0,0 +1,55 @@ +Prerequirement +============== +This document describes how to compile, build and install curl and libcurl +from sources using mk. To build it, you will require to install latest +9legacy patches into Plan 9. Also Plan 9 still have no configuration option so +both zlib and libopenssl are required too. + +The zlib that is available on Plan 9 can be downloaded from: + + https://github.com/madler/zlib/pull/398 + +LibreSSL Portable can be downloaded from: + + https://github.com/libressl-portable/portable/pull/510 + +Instruction +=========== +First, you should construct namespace as like described below: + +% bind -ac ../lib lib +% bind -ac ../src src +% bind -ac ../include include +% bind -ac .. . + +Then you will see as shown below (excerpt): + + curl.git/ + |_plan9 + | |_BUILD.PLAN9.txt + | |_CHANGES + | |_CMake + | | : + | |_mkfile + | |_mkfile.proto + | |_include + | | |_Makefile.am + | | | : + | | |_mkfile + | |_lib + | | |_CMakeLists.txt + | | | : + | | |_mkfile + | | |_mkfile.inc + | |_src + | | |_CMakeLists.txt + | | | : + | | |_mkfile + | | |_mkfile.inc + |_lib + |_src + +After constructing namespace, you can run mk on plan9 directory. + +% mk +% mk install diff --git a/plan9/include/mkfile b/plan9/include/mkfile new file mode 100644 index 0000000..a0970e9 --- /dev/null +++ b/plan9/include/mkfile @@ -0,0 +1,36 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +DIR=/sys/include/ape/curl +HFILES=`{ls curl/*.h} + +all:V: $HFILES + +install:V: all + mkdir -p $DIR + cp curl/*.h $DIR/ + +clean:V: $HFILES # do nothing + +nuke:V: clean diff --git a/plan9/lib/mkfile b/plan9/lib/mkfile new file mode 100644 index 0000000..04b54a8 --- /dev/null +++ b/plan9/lib/mkfile @@ -0,0 +1,41 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +<../mkfile.proto +<|mkfile.inc + +CFLAGS=$CFLAGS -I../include -I. -c + +OFILES=${CSOURCES:%.c=%.$O} +HFILES=$HHEADERS +LIB=/$objtype/lib/ape/libcurl.a + +CLEANFILES=\ + ${LIB_VAUTH_CFILES:%.c=%.$O}\ + ${LIB_VTLS_CFILES:%.c=%.$O}\ + +, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# rename $(VAR) -> $VAR +sed 's/\$\(([A-Z_]+)\)/$\1/g' Makefile.inc diff --git a/plan9/mkfile b/plan9/mkfile new file mode 100644 index 0000000..2133a49 --- /dev/null +++ b/plan9/mkfile @@ -0,0 +1,38 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +<../mkfile.proto +<|mkfile.inc + +CFLAGS=$CFLAGS -I../include -I../lib -c + +OFILES=${CURL_CFILES:%.c=%.$O} +HFILES=$CURL_HFILES + +LIB=\ + /$objtype/lib/ape/libcurl.a\ + /$objtype/lib/ape/libssl.a\ + /$objtype/lib/ape/libcrypto.a\ + /$objtype/lib/ape/libz.a\ + +BIN=/$objtype/bin +TARG=curl + +CLEANFILES=tool_hugehelp.c + +$target diff --git a/plan9/src/mkfile.inc b/plan9/src/mkfile.inc new file mode 100755 index 0000000..5c2cc12 --- /dev/null +++ b/plan9/src/mkfile.inc @@ -0,0 +1,27 @@ +#!/bin/rc +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# rename $(VAR) -> $VAR +sed 's/\$\(([A-Z_]+)\)/$\1/g' Makefile.inc diff --git a/projects/README.md b/projects/README.md new file mode 100644 index 0000000..9b18ccd --- /dev/null +++ b/projects/README.md @@ -0,0 +1,160 @@ + + +Building via IDE Project Files +============================== + +This document describes how to compile, build and install curl and libcurl +from sources using an IDE based development tool such as Visual Studio. + +Project files are available for several different Visual C++ versions. The +following directory structure has been used to cater for this: + + somedirectory\ + |_curl + |_projects + |_ + |_ + |_lib + |_src + +This structure allows for side-by-side compilation of curl on the same machine +using different versions of a given compiler (for example VC10 and VC12) and +allows for your own application or product to be compiled against those +variants of libcurl for example. + +Note: Typically this side-by-side compilation is generally only required when +a library is being compiled against dynamic runtime libraries. + +## Dependencies + +The projects files also support build configurations that require third party +dependencies such as OpenSSL, wolfSSL and libssh2. If you wish to support +these, you will also need to download and compile those libraries as well. + +To support compilation of these libraries using different versions of +compilers, the following directory structure has been used for both the output +of curl and libcurl as well as these dependencies. + + somedirectory\ + |_curl + | |_ build + | |_ + | |_ + | |_ + | |_lib + | |_src + | + |_openssl + | |_ build + | |_ + | |_VC + | |_ + | + |_libssh2 + |_ build + |_ + |_VC + |_ + +As OpenSSL and wolfSSL don't support side-by-side compilation when using +different versions of Visual Studio, build helper batch files have been +provided to assist with this. Please run `build-openssl -help` and/or +`build-wolfssl -help` for usage details. + +## Building with Visual C++ + +To build with VC++, you will of course have to first install VC++ which is +part of Visual Studio. + +Once you have VC++ installed you should launch the application and open one of +the solution or workspace files. The VC directory names are based on the +version of Visual C++ that you will be using. Each version of Visual Studio +has a default version of Visual C++. We offer these versions: + + - VC10 (Visual Studio 2010 Version 10.0) + - VC11 (Visual Studio 2012 Version 11.0) + - VC12 (Visual Studio 2013 Version 12.0) + - VC14 (Visual Studio 2015 Version 14.0) + - VC14.10 (Visual Studio 2017 Version 15.0) + - VC14.30 (Visual Studio 2022 Version 17.0) + +Separate solutions are provided for both libcurl and the curl command line +tool as well as a solution that includes both projects. libcurl.sln, curl.sln +and curl-all.sln, respectively. We recommend using curl-all.sln to build both +projects. + +For example, if you are using Visual Studio 2022 then you should be able to +use `VC14.30\curl-all.sln` to build curl and libcurl. + +## Running DLL based configurations + +If you are a developer and plan to run the curl tool from Visual Studio with +any third-party libraries (such as OpenSSL, wolfSSL or LibSSH2) then you will +need to add the search path of these DLLs to the configuration's PATH +environment. To do that: + + 1. Open the 'curl-all.sln' or 'curl.sln' solutions + 2. Right-click on the 'curl' project and select Properties + 3. Navigate to 'Configuration Properties > Debugging > Environment' + 4. Add `PATH='Path to DLL';C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem` + +... where 'Path to DLL` is the configuration specific path. For example the +following configurations in Visual Studio 2010 might be: + +DLL Debug - DLL OpenSSL (Win32): + + PATH=..\..\..\..\..\openssl\build\Win32\VC10\DLL Debug;C:\Windows\system32; + C:\Windows;C:\Windows\System32\Wbem + +DLL Debug - DLL OpenSSL (x64): + + PATH=..\..\..\..\..\openssl\build\Win64\VC10\DLL Debug;C:\Windows\system32; + C:\Windows;C:\Windows\System32\Wbem + +DLL Debug - DLL wolfSSL (Win32): + + PATH=..\..\..\..\..\wolfssl\build\Win32\VC10\DLL Debug;C:\Windows\system32; + C:\Windows;C:\Windows\System32\Wbem + +DLL Debug - DLL wolfSSL (x64): + + PATH=..\..\..\..\..\wolfssl\build\Win64\VC10\DLL Debug;C:\Windows\system32; + C:\Windows;C:\Windows\System32\Wbem + +If you are using a configuration that uses multiple third-party library DLLs +(such as DLL Debug - DLL OpenSSL - DLL LibSSH2) then 'Path to DLL' will need +to contain the path to both of these. + +## Notes + +The following keywords have been used in the directory hierarchy: + + - `` - The platform (For example: Windows) + - `` - The IDE (For example: VC10) + - `` - The platform architecture (For example: Win32, Win64) + - `` - The target configuration (For example: DLL Debug, LIB + Release - LIB OpenSSL) + +If you are using the source code from the git repository, rather than a +release archive or nightly build, you will need to generate the project +files. Please run "generate -help" for usage details. + +Should you wish to help out with some of the items on the TODO list, or find +bugs in the project files that need correcting, and would like to submit +updated files back then please note that, whilst the solution files can be +edited directly, the templates for the project files (which are stored in the +git repository) will need to be modified rather than the generated project +files that Visual Studio uses. + +## Legacy Windows and SSL + +Some of the project configurations allow the use of Schannel, the native SSL +library in Windows which forms part of Windows SSPI. However, Schannel in +Windows <= XP is unable to connect to servers that no longer support the +legacy handshakes and algorithms used by those versions. If you will be using +curl in one of those earlier versions of Windows you should choose another SSL +backend such as OpenSSL. diff --git a/projects/Windows/VC14.10/curl-all.sln b/projects/Windows/VC14.10/curl-all.sln new file mode 100644 index 0000000..d4576a1 --- /dev/null +++ b/projects/Windows/VC14.10/curl-all.sln @@ -0,0 +1,298 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "src\curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" + ProjectSection(ProjectDependencies) = postProject + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "lib\libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.10/lib/libcurl.sln b/projects/Windows/VC14.10/lib/libcurl.sln new file mode 100644 index 0000000..4de796c --- /dev/null +++ b/projects/Windows/VC14.10/lib/libcurl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.10/lib/libcurl.vcxproj b/projects/Windows/VC14.10/lib/libcurl.vcxproj new file mode 100644 index 0000000..ff6678d --- /dev/null +++ b/projects/Windows/VC14.10/lib/libcurl.vcxproj @@ -0,0 +1,2696 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + libcurl + + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + StaticLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + DynamicLibrary + false + Unicode + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)lib\ + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.10\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.10\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14.10/lib/libcurl.vcxproj.filters b/projects/Windows/VC14.10/lib/libcurl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14.10/lib/libcurl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/Windows/VC14.10/src/curl.sln b/projects/Windows/VC14.10/src/curl.sln new file mode 100644 index 0000000..16d2296 --- /dev/null +++ b/projects/Windows/VC14.10/src/curl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.10/src/curl.vcxproj b/projects/Windows/VC14.10/src/curl.vcxproj new file mode 100644 index 0000000..3aff41b --- /dev/null +++ b/projects/Windows/VC14.10/src/curl.vcxproj @@ -0,0 +1,2771 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {5228E9CE-A216-422F-A5E6-58E95E2DD71D} + curl + + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.10\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14.10\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14.10\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14.10\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14.10\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\LIB Debug;..\..\..\..\..\libssh2\build\Win32\VC14.10\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\LIB Debug;..\..\..\..\..\libssh2\build\Win64\VC14.10\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\LIB Release;..\..\..\..\..\libssh2\build\Win32\VC14.10\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\LIB Release;..\..\..\..\..\libssh2\build\Win64\VC14.10\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14.10\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.10\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libssh2.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.10\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14.10\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.10\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14.10/src/curl.vcxproj.filters b/projects/Windows/VC14.10/src/curl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14.10/src/curl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/Windows/VC14.20/curl-all.sln b/projects/Windows/VC14.20/curl-all.sln new file mode 100644 index 0000000..3df7e1c --- /dev/null +++ b/projects/Windows/VC14.20/curl-all.sln @@ -0,0 +1,298 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 16 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "src\curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" + ProjectSection(ProjectDependencies) = postProject + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "lib\libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.20/lib/libcurl.sln b/projects/Windows/VC14.20/lib/libcurl.sln new file mode 100644 index 0000000..171bb83 --- /dev/null +++ b/projects/Windows/VC14.20/lib/libcurl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 17 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.20/lib/libcurl.vcxproj b/projects/Windows/VC14.20/lib/libcurl.vcxproj new file mode 100644 index 0000000..8bd0abe --- /dev/null +++ b/projects/Windows/VC14.20/lib/libcurl.vcxproj @@ -0,0 +1,2696 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + libcurl + + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + StaticLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)lib\ + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.20\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.20\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14.20/lib/libcurl.vcxproj.filters b/projects/Windows/VC14.20/lib/libcurl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14.20/lib/libcurl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/Windows/VC14.20/src/curl.sln b/projects/Windows/VC14.20/src/curl.sln new file mode 100644 index 0000000..94c2fb7 --- /dev/null +++ b/projects/Windows/VC14.20/src/curl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 16 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.20/src/curl.vcxproj b/projects/Windows/VC14.20/src/curl.vcxproj new file mode 100644 index 0000000..4a84059 --- /dev/null +++ b/projects/Windows/VC14.20/src/curl.vcxproj @@ -0,0 +1,2771 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {5228E9CE-A216-422F-A5E6-58E95E2DD71D} + curl + + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.20\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14.20\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14.20\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14.20\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14.20\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\LIB Debug;..\..\..\..\..\libssh2\build\Win32\VC14.20\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\LIB Debug;..\..\..\..\..\libssh2\build\Win64\VC14.20\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\LIB Release;..\..\..\..\..\libssh2\build\Win32\VC14.20\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\LIB Release;..\..\..\..\..\libssh2\build\Win64\VC14.20\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14.20\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.20\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libssh2.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.20\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14.20\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.20\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14.20/src/curl.vcxproj.filters b/projects/Windows/VC14.20/src/curl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14.20/src/curl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/Windows/VC14.30/curl-all.sln b/projects/Windows/VC14.30/curl-all.sln new file mode 100644 index 0000000..88bf032 --- /dev/null +++ b/projects/Windows/VC14.30/curl-all.sln @@ -0,0 +1,298 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 17 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "src\curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" + ProjectSection(ProjectDependencies) = postProject + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "lib\libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.30/lib/libcurl.sln b/projects/Windows/VC14.30/lib/libcurl.sln new file mode 100644 index 0000000..171bb83 --- /dev/null +++ b/projects/Windows/VC14.30/lib/libcurl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 17 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.30/lib/libcurl.vcxproj b/projects/Windows/VC14.30/lib/libcurl.vcxproj new file mode 100644 index 0000000..254da43 --- /dev/null +++ b/projects/Windows/VC14.30/lib/libcurl.vcxproj @@ -0,0 +1,2696 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + libcurl + + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + StaticLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)lib\ + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14.30\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14.30\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14.30/lib/libcurl.vcxproj.filters b/projects/Windows/VC14.30/lib/libcurl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14.30/lib/libcurl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/Windows/VC14.30/src/curl.sln b/projects/Windows/VC14.30/src/curl.sln new file mode 100644 index 0000000..ce5aa2c --- /dev/null +++ b/projects/Windows/VC14.30/src/curl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 17 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14.30/src/curl.vcxproj b/projects/Windows/VC14.30/src/curl.vcxproj new file mode 100644 index 0000000..95477e4 --- /dev/null +++ b/projects/Windows/VC14.30/src/curl.vcxproj @@ -0,0 +1,2771 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {5228E9CE-A216-422F-A5E6-58E95E2DD71D} + curl + + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + Application + false + Unicode + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win32\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + ..\..\..\..\build\Win64\VC14.30\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14.30\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14.30\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14.30\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14.30\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\LIB Debug;..\..\..\..\..\libssh2\build\Win32\VC14.30\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\LIB Debug;..\..\..\..\..\libssh2\build\Win64\VC14.30\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\LIB Release;..\..\..\..\..\libssh2\build\Win32\VC14.30\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\LIB Release;..\..\..\..\..\libssh2\build\Win64\VC14.30\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14.30\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14.30\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libssh2.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14.30\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14.30\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14.30\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14.30/src/curl.vcxproj.filters b/projects/Windows/VC14.30/src/curl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14.30/src/curl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/Windows/VC14/curl-all.sln b/projects/Windows/VC14/curl-all.sln new file mode 100644 index 0000000..02bccc5 --- /dev/null +++ b/projects/Windows/VC14/curl-all.sln @@ -0,0 +1,298 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2015 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "src\curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" + ProjectSection(ProjectDependencies) = postProject + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "lib\libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14/lib/libcurl.sln b/projects/Windows/VC14/lib/libcurl.sln new file mode 100644 index 0000000..f768b6d --- /dev/null +++ b/projects/Windows/VC14/lib/libcurl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2015 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "libcurl.vcxproj", "{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14/lib/libcurl.vcxproj b/projects/Windows/VC14/lib/libcurl.vcxproj new file mode 100644 index 0000000..ae06fd7 --- /dev/null +++ b/projects/Windows/VC14/lib/libcurl.vcxproj @@ -0,0 +1,2724 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} + libcurl + + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + StaticLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + DynamicLibrary + false + Unicode + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)lib\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)lib\ + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win32\VC14\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WOLFSSL;USE_IPV6;WOLFSSL_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\wolfssl\build\Win64\VC14\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + 4214 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\wolfssl;..\..\..\..\..\wolfssl\wolfssl;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + 4214 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + %(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14\DLL Debug;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + Win32 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win32\VC14\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14\DLL Release;%(AdditionalLibraryDirectories) + $(IntDir)$(TargetFileName).intermediate.manifest + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + X64 + $(OutDir)$(ProjectName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\..\openssl\build\Win64\VC14\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14\DLL Release;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\LIB Debug\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\LIB Debug\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + _DEBUG;BUILDING_LIBCURL;DEBUGBUILD;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\DLL Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WINDOWS_SSPI;USE_SCHANNEL;USE_WIN32_IDN;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\LIB Release\include;..\..\..\..\..\openssl\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win32\VC14\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX86 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;..\..\..\..\..\openssl\include\..\build\Win64\VC14\LIB Release\include;..\..\..\..\..\openssl\include;..\..\..\..\..\libssh2\include;%(AdditionalIncludeDirectories) + NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_OPENSSL;USE_LIBSSH2;USE_IPV6;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14/lib/libcurl.vcxproj.filters b/projects/Windows/VC14/lib/libcurl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14/lib/libcurl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/Windows/VC14/src/curl.sln b/projects/Windows/VC14/src/curl.sln new file mode 100644 index 0000000..ca123ed --- /dev/null +++ b/projects/Windows/VC14/src/curl.sln @@ -0,0 +1,181 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2015 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "curl.vcxproj", "{5228E9CE-A216-422F-A5E6-58E95E2DD71D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + DLL Debug - DLL OpenSSL|Win32 = DLL Debug - DLL OpenSSL|Win32 + DLL Debug - DLL OpenSSL|x64 = DLL Debug - DLL OpenSSL|x64 + DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + DLL Debug - DLL Windows SSPI|Win32 = DLL Debug - DLL Windows SSPI|Win32 + DLL Debug - DLL Windows SSPI|x64 = DLL Debug - DLL Windows SSPI|x64 + DLL Debug - DLL wolfSSL|Win32 = DLL Debug - DLL wolfSSL|Win32 + DLL Debug - DLL wolfSSL|x64 = DLL Debug - DLL wolfSSL|x64 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Debug|x64 = DLL Debug|x64 + DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + DLL Release - DLL OpenSSL - DLL LibSSH2|x64 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + DLL Release - DLL OpenSSL|Win32 = DLL Release - DLL OpenSSL|Win32 + DLL Release - DLL OpenSSL|x64 = DLL Release - DLL OpenSSL|x64 + DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + DLL Release - DLL Windows SSPI - DLL WinIDN|x64 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + DLL Release - DLL Windows SSPI|Win32 = DLL Release - DLL Windows SSPI|Win32 + DLL Release - DLL Windows SSPI|x64 = DLL Release - DLL Windows SSPI|x64 + DLL Release - DLL wolfSSL|Win32 = DLL Release - DLL wolfSSL|Win32 + DLL Release - DLL wolfSSL|x64 = DLL Release - DLL wolfSSL|x64 + DLL Release|Win32 = DLL Release|Win32 + DLL Release|x64 = DLL Release|x64 + LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + LIB Debug - DLL OpenSSL|Win32 = LIB Debug - DLL OpenSSL|Win32 + LIB Debug - DLL OpenSSL|x64 = LIB Debug - DLL OpenSSL|x64 + LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + LIB Debug - DLL Windows SSPI|Win32 = LIB Debug - DLL Windows SSPI|Win32 + LIB Debug - DLL Windows SSPI|x64 = LIB Debug - DLL Windows SSPI|x64 + LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + LIB Debug - LIB OpenSSL|Win32 = LIB Debug - LIB OpenSSL|Win32 + LIB Debug - LIB OpenSSL|x64 = LIB Debug - LIB OpenSSL|x64 + LIB Debug - LIB wolfSSL|Win32 = LIB Debug - LIB wolfSSL|Win32 + LIB Debug - LIB wolfSSL|x64 = LIB Debug - LIB wolfSSL|x64 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Debug|x64 = LIB Debug|x64 + LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + LIB Release - DLL OpenSSL - DLL LibSSH2|x64 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + LIB Release - DLL OpenSSL|Win32 = LIB Release - DLL OpenSSL|Win32 + LIB Release - DLL OpenSSL|x64 = LIB Release - DLL OpenSSL|x64 + LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + LIB Release - DLL Windows SSPI - DLL WinIDN|x64 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + LIB Release - DLL Windows SSPI|Win32 = LIB Release - DLL Windows SSPI|Win32 + LIB Release - DLL Windows SSPI|x64 = LIB Release - DLL Windows SSPI|x64 + LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + LIB Release - LIB OpenSSL - LIB LibSSH2|x64 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + LIB Release - LIB OpenSSL|Win32 = LIB Release - LIB OpenSSL|Win32 + LIB Release - LIB OpenSSL|x64 = LIB Release - LIB OpenSSL|x64 + LIB Release - LIB wolfSSL|Win32 = LIB Release - LIB wolfSSL|Win32 + LIB Release - LIB wolfSSL|x64 = LIB Release - LIB wolfSSL|x64 + LIB Release|Win32 = LIB Release|Win32 + LIB Release|x64 = LIB Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.ActiveCfg = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|Win32.Build.0 = DLL Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.ActiveCfg = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL OpenSSL|x64.Build.0 = DLL Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.ActiveCfg = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|Win32.Build.0 = DLL Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.ActiveCfg = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL Windows SSPI|x64.Build.0 = DLL Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.ActiveCfg = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|Win32.Build.0 = DLL Debug - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.ActiveCfg = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug - DLL wolfSSL|x64.Build.0 = DLL Debug - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Debug|x64.Build.0 = DLL Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = DLL Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.ActiveCfg = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|Win32.Build.0 = DLL Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.ActiveCfg = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL OpenSSL|x64.Build.0 = DLL Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = DLL Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.ActiveCfg = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|Win32.Build.0 = DLL Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.ActiveCfg = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL Windows SSPI|x64.Build.0 = DLL Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.ActiveCfg = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|Win32.Build.0 = DLL Release - DLL wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.ActiveCfg = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release - DLL wolfSSL|x64.Build.0 = DLL Release - DLL wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.ActiveCfg = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.DLL Release|x64.Build.0 = DLL Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Debug - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.ActiveCfg = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|Win32.Build.0 = LIB Debug - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.ActiveCfg = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL OpenSSL|x64.Build.0 = LIB Debug - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Debug - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.ActiveCfg = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|Win32.Build.0 = LIB Debug - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.ActiveCfg = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - DLL Windows SSPI|x64.Build.0 = LIB Debug - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Debug - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.ActiveCfg = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|Win32.Build.0 = LIB Debug - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.ActiveCfg = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB OpenSSL|x64.Build.0 = LIB Debug - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.ActiveCfg = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|Win32.Build.0 = LIB Debug - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.ActiveCfg = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug - LIB wolfSSL|x64.Build.0 = LIB Debug - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.ActiveCfg = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Debug|x64.Build.0 = LIB Debug|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|Win32.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.ActiveCfg = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL - DLL LibSSH2|x64.Build.0 = LIB Release - DLL OpenSSL - DLL LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.ActiveCfg = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|Win32.Build.0 = LIB Release - DLL OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.ActiveCfg = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL OpenSSL|x64.Build.0 = LIB Release - DLL OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|Win32.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.ActiveCfg = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI - DLL WinIDN|x64.Build.0 = LIB Release - DLL Windows SSPI - DLL WinIDN|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.ActiveCfg = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|Win32.Build.0 = LIB Release - DLL Windows SSPI|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.ActiveCfg = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - DLL Windows SSPI|x64.Build.0 = LIB Release - DLL Windows SSPI|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|Win32.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.ActiveCfg = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL - LIB LibSSH2|x64.Build.0 = LIB Release - LIB OpenSSL - LIB LibSSH2|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.ActiveCfg = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|Win32.Build.0 = LIB Release - LIB OpenSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.ActiveCfg = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB OpenSSL|x64.Build.0 = LIB Release - LIB OpenSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.ActiveCfg = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|Win32.Build.0 = LIB Release - LIB wolfSSL|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.ActiveCfg = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release - LIB wolfSSL|x64.Build.0 = LIB Release - LIB wolfSSL|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.ActiveCfg = LIB Release|x64 + {5228E9CE-A216-422F-A5E6-58E95E2DD71D}.LIB Release|x64.Build.0 = LIB Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/Windows/VC14/src/curl.vcxproj b/projects/Windows/VC14/src/curl.vcxproj new file mode 100644 index 0000000..4fecad1 --- /dev/null +++ b/projects/Windows/VC14/src/curl.vcxproj @@ -0,0 +1,2799 @@ + + + + + DLL Debug - DLL wolfSSL + Win32 + + + DLL Debug - DLL wolfSSL + x64 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Debug - DLL OpenSSL + Win32 + + + DLL Debug - DLL OpenSSL + x64 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Debug - DLL Windows SSPI + Win32 + + + DLL Debug - DLL Windows SSPI + x64 + + + DLL Debug + Win32 + + + DLL Debug + x64 + + + DLL Release - DLL wolfSSL + Win32 + + + DLL Release - DLL wolfSSL + x64 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + DLL Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + DLL Release - DLL OpenSSL + Win32 + + + DLL Release - DLL OpenSSL + x64 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + DLL Release - DLL Windows SSPI - DLL WinIDN + x64 + + + DLL Release - DLL Windows SSPI + Win32 + + + DLL Release - DLL Windows SSPI + x64 + + + DLL Release + Win32 + + + DLL Release + x64 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Debug - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Debug - DLL OpenSSL + Win32 + + + LIB Debug - DLL OpenSSL + x64 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Debug - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Debug - DLL Windows SSPI + Win32 + + + LIB Debug - DLL Windows SSPI + x64 + + + LIB Debug - LIB wolfSSL + Win32 + + + LIB Debug - LIB wolfSSL + x64 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Debug - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Debug - LIB OpenSSL + Win32 + + + LIB Debug - LIB OpenSSL + x64 + + + LIB Debug + Win32 + + + LIB Debug + x64 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + Win32 + + + LIB Release - DLL OpenSSL - DLL LibSSH2 + x64 + + + LIB Release - DLL OpenSSL + Win32 + + + LIB Release - DLL OpenSSL + x64 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + Win32 + + + LIB Release - DLL Windows SSPI - DLL WinIDN + x64 + + + LIB Release - DLL Windows SSPI + Win32 + + + LIB Release - DLL Windows SSPI + x64 + + + LIB Release - LIB wolfSSL + Win32 + + + LIB Release - LIB wolfSSL + x64 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + Win32 + + + LIB Release - LIB OpenSSL - LIB LibSSH2 + x64 + + + LIB Release - LIB OpenSSL + Win32 + + + LIB Release - LIB OpenSSL + x64 + + + LIB Release + Win32 + + + LIB Release + x64 + + + + {5228E9CE-A216-422F-A5E6-58E95E2DD71D} + curl + + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + ..\..\..\..\build\Win32\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + ..\..\..\..\build\Win64\VC14\$(Configuration)\ + $(OutDir)src\ + $(OutDir)src\ + false + false + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + $(ProjectName) + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + true + $(TargetDir)$(TargetName).pdb + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + true + $(TargetDir)$(TargetName).pdb + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\wolfssl\build\Win32\VC14\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;wolfssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\wolfssl\build\Win64\VC14\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\LIB Debug;..\..\..\..\..\libssh2\build\Win32\VC14\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\LIB Debug;..\..\..\..\..\libssh2\build\Win64\VC14\LIB Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\LIB Release;..\..\..\..\..\libssh2\build\Win32\VC14\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\LIB Release;..\..\..\..\..\libssh2\build\Win64\VC14\LIB Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\DLL Debug;..\..\..\..\..\libssh2\build\Win32\VC14\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurld.lib;libcrypto.lib;libssl.lib;libssh2d.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\DLL Debug;..\..\..\..\..\libssh2\build\Win64\VC14\DLL Debug;%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libcrypto.lib;libssl.lib;libssh2.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win32\VC14\DLL Release;..\..\..\..\..\libssh2\build\Win32\VC14\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;ws2_32.lib;wldap32.lib;libcurl.lib;libssh2.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);..\..\..\..\..\openssl\build\Win64\VC14\DLL Release;..\..\..\..\..\libssh2\build\Win64\VC14\DLL Release;%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + Disabled + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;DEBUGBUILD;CURL_STATICLIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurld.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win32\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + X64 + $(TargetDir)$(TargetName).tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\..\..\include;..\..\..\..\lib;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;CURL_STATICLIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level4 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib;libcurl.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + ..\..\..\..\build\Win64\VC14\$(Configuration);%(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Windows/VC14/src/curl.vcxproj.filters b/projects/Windows/VC14/src/curl.vcxproj.filters new file mode 100644 index 0000000..4d6341d --- /dev/null +++ b/projects/Windows/VC14/src/curl.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/projects/build-openssl.bat b/projects/build-openssl.bat new file mode 100644 index 0000000..0ded764 --- /dev/null +++ b/projects/build-openssl.bat @@ -0,0 +1,739 @@ +@echo off +rem *************************************************************************** +rem * _ _ ____ _ +rem * Project ___| | | | _ \| | +rem * / __| | | | |_) | | +rem * | (__| |_| | _ <| |___ +rem * \___|\___/|_| \_\_____| +rem * +rem * Copyright (C) Steve Holme, . +rem * +rem * This software is licensed as described in the file COPYING, which +rem * you should have received as part of this distribution. The terms +rem * are also available at https://curl.se/docs/copyright.html. +rem * +rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell +rem * copies of the Software, and permit persons to whom the Software is +rem * furnished to do so, under the terms of the COPYING file. +rem * +rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +rem * KIND, either express or implied. +rem * +rem * SPDX-License-Identifier: curl +rem * +rem *************************************************************************** + +:begin + rem Check we are running on a Windows NT derived OS + if not "%OS%" == "Windows_NT" goto nodos + + rem Set our variables + setlocal ENABLEDELAYEDEXPANSION + set BUILD_CONFIG= + set BUILD_PLATFORM= + set SAVED_PATH= + set SOURCE_PATH= + set TMP_BUILD_PATH= + set TMP_INSTALL_PATH= + set VC_VER= + + rem Ensure we have the required arguments + if /i "%~1" == "" goto syntax + + rem Calculate the program files directory + if defined PROGRAMFILES ( + set "PF=%PROGRAMFILES%" + set OS_PLATFORM=x86 + ) + if defined PROGRAMFILES(x86) ( + rem Visual Studio was x86-only prior to 14.3 + if /i "%~1" == "vc14.3" ( + set "PF=%PROGRAMFILES%" + ) else ( + set "PF=%PROGRAMFILES(x86)%" + ) + set OS_PLATFORM=x64 + ) + +:parseArgs + if not "%~1" == "" ( + if /i "%~1" == "vc10" ( + set VC_VER=10.0 + set VC_DESC=VC10 + set "VC_PATH=Microsoft Visual Studio 10.0\VC" + ) else if /i "%~1" == "vc11" ( + set VC_VER=11.0 + set VC_DESC=VC11 + set "VC_PATH=Microsoft Visual Studio 11.0\VC" + ) else if /i "%~1" == "vc12" ( + set VC_VER=12.0 + set VC_DESC=VC12 + set "VC_PATH=Microsoft Visual Studio 12.0\VC" + ) else if /i "%~1" == "vc14" ( + set VC_VER=14.0 + set VC_DESC=VC14 + set "VC_PATH=Microsoft Visual Studio 14.0\VC" + ) else if /i "%~1" == "vc14.1" ( + set VC_VER=14.1 + set VC_DESC=VC14.10 + + rem Determine the VC14.1 path based on the installed edition in descending + rem order (Enterprise, then Professional and finally Community) + if exist "%PF%\Microsoft Visual Studio\2017\Enterprise\VC" ( + set "VC_PATH=Microsoft Visual Studio\2017\Enterprise\VC" + ) else if exist "%PF%\Microsoft Visual Studio\2017\Professional\VC" ( + set "VC_PATH=Microsoft Visual Studio\2017\Professional\VC" + ) else ( + set "VC_PATH=Microsoft Visual Studio\2017\Community\VC" + ) + ) else if /i "%~1" == "vc14.2" ( + set VC_VER=14.2 + set VC_DESC=VC14.20 + + rem Determine the VC14.2 path based on the installed edition in descending + rem order (Enterprise, then Professional and finally Community) + if exist "%PF%\Microsoft Visual Studio\2019\Enterprise\VC" ( + set "VC_PATH=Microsoft Visual Studio\2019\Enterprise\VC" + ) else if exist "%PF%\Microsoft Visual Studio\2019\Professional\VC" ( + set "VC_PATH=Microsoft Visual Studio\2019\Professional\VC" + ) else ( + set "VC_PATH=Microsoft Visual Studio\2019\Community\VC" + ) + ) else if /i "%~1" == "vc14.3" ( + set VC_VER=14.3 + set VC_DESC=VC14.30 + + rem Determine the VC14.3 path based on the installed edition in descending + rem order (Enterprise, then Professional and finally Community) + if exist "%PF%\Microsoft Visual Studio\2022\Enterprise\VC" ( + set "VC_PATH=Microsoft Visual Studio\2022\Enterprise\VC" + ) else if exist "%PF%\Microsoft Visual Studio\2022\Professional\VC" ( + set "VC_PATH=Microsoft Visual Studio\2022\Professional\VC" + ) else ( + set "VC_PATH=Microsoft Visual Studio\2022\Community\VC" + ) + ) else if /i "%~1%" == "x86" ( + set BUILD_PLATFORM=x86 + ) else if /i "%~1%" == "x64" ( + set BUILD_PLATFORM=x64 + ) else if /i "%~1%" == "debug" ( + set BUILD_CONFIG=debug + ) else if /i "%~1%" == "release" ( + set BUILD_CONFIG=release + ) else if /i "%~1" == "-?" ( + goto syntax + ) else if /i "%~1" == "-h" ( + goto syntax + ) else if /i "%~1" == "-help" ( + goto syntax + ) else if /i "%~1" == "-VSpath" ( + if "%~2" == "" ( + echo. + echo Error. Please provide VS Path. + goto error + ) else ( + set "ABS_VC_PATH=%~2\VC" + shift + ) + ) else if /i "%~1" == "-perlpath" ( + if "%~2" == "" ( + echo. + echo Error. Please provide Perl root Path. + goto error + ) else ( + set "PERL_PATH=%~2" + shift + ) + ) else ( + if not defined START_DIR ( + set "START_DIR=%~1%" + ) else ( + goto unknown + ) + ) + + shift & goto parseArgs + ) + +:prerequisites + rem Compiler is a required parameter + if not defined VC_VER goto syntax + + rem Default the start directory if one isn't specified + if not defined START_DIR set START_DIR=..\..\openssl + + if not defined ABS_VC_PATH ( + rem Check we have a program files directory + if not defined PF goto nopf + set "ABS_VC_PATH=%PF%\%VC_PATH%" + ) + + rem Check we have Visual Studio installed + if not exist "%ABS_VC_PATH%" goto novc + + if not defined PERL_PATH ( + rem Check we have Perl in our path + perl --version NUL 2>&1 + if errorlevel 1 ( + rem It isn't so check we have it installed and set the path if it is + if exist "%SystemDrive%\Perl" ( + set "PATH=%SystemDrive%\Perl\bin;%PATH%" + ) else ( + if exist "%SystemDrive%\Perl64" ( + set "PATH=%SystemDrive%\Perl64\bin;%PATH%" + ) else ( + goto noperl + ) + ) + ) + ) else ( + set "PATH=%PERL_PATH%\Perl\bin;%PATH%" + ) + + rem Check the start directory exists + if not exist "%START_DIR%" goto noopenssl + +:setup + if "%BUILD_PLATFORM%" == "" ( + if "%VC_VER%" == "6.0" ( + set BUILD_PLATFORM=x86 + ) else if "%VC_VER%" == "7.0" ( + set BUILD_PLATFORM=x86 + ) else if "%VC_VER%" == "7.1" ( + set BUILD_PLATFORM=x86 + ) else ( + set BUILD_PLATFORM=%OS_PLATFORM% + ) + ) + + if "%BUILD_PLATFORM%" == "x86" ( + set VCVARS_PLATFORM=x86 + ) else if "%BUILD_PLATFORM%" == "x64" ( + if "%VC_VER%" == "10.0" set VCVARS_PLATFORM=%BUILD_PLATFORM% + if "%VC_VER%" == "11.0" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "12.0" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.0" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.1" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.2" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.3" set VCVARS_PLATFORM=amd64 + ) + + if exist "%START_DIR%\ms\do_ms.bat" ( + set LEGACY_BUILD=TRUE + ) else ( + set LEGACY_BUILD=FALSE + ) + +:start + echo. + set "SAVED_PATH=%CD%" + + if "%VC_VER%" == "14.1" ( + call "%ABS_VC_PATH%\Auxiliary\Build\vcvarsall" %VCVARS_PLATFORM% + ) else if "%VC_VER%" == "14.2" ( + call "%ABS_VC_PATH%\Auxiliary\Build\vcvarsall" %VCVARS_PLATFORM% + ) else if "%VC_VER%" == "14.3" ( + call "%ABS_VC_PATH%\Auxiliary\Build\vcvarsall" %VCVARS_PLATFORM% + ) else ( + call "%ABS_VC_PATH%\vcvarsall" %VCVARS_PLATFORM% + ) + + echo. + + cd /d "%START_DIR%" || (echo Error: Failed cd start & exit /B 1) + rem Save the full path of the openssl source dir + set "SOURCE_PATH=%CD%" + + rem Set temporary paths for building and installing OpenSSL. If a temporary + rem path is not the same as the source path then it is *removed* after the + rem installation is completed. + rem + rem For legacy OpenSSL the temporary build path must be the source path. + rem + rem For OpenSSL 1.1.x the temporary paths must be separate not a descendant + rem of the other, otherwise pdb files will be lost between builds. + rem https://github.com/openssl/openssl/issues/10005 + rem + if "%LEGACY_BUILD%" == "TRUE" ( + set "TMP_BUILD_PATH=%SOURCE_PATH%" + set "TMP_INSTALL_PATH=%SOURCE_PATH%" + ) else ( + set "TMP_BUILD_PATH=%SOURCE_PATH%\build\tmp_build" + set "TMP_INSTALL_PATH=%SOURCE_PATH%\build\tmp_install" + ) + + goto %BUILD_PLATFORM% + +:x64 + rem Calculate our output directory + set OUTDIR=build\Win64\%VC_DESC% + if not exist %OUTDIR% md %OUTDIR% + + if not "%BUILD_CONFIG%" == "release" ( + rem Configuring 64-bit Static Library Debug Build + call :configure x64 debug static %LEGACY_BUILD% + + rem Perform the build + call :build x64 static %LEGACY_BUILD% + + rem Perform the install + call :install debug static %LEGACY_BUILD% + + rem Configuring 64-bit Shared Library Debug Build + call :configure x64 debug shared %LEGACY_BUILD% + + rem Perform the build + call :build x64 shared %LEGACY_BUILD% + + rem Perform the install + call :install debug shared %LEGACY_BUILD% + ) + + if not "%BUILD_CONFIG%" == "debug" ( + rem Configuring 64-bit Static Library Release Build + call :configure x64 release static %LEGACY_BUILD% + + rem Perform the build + call :build x64 static %LEGACY_BUILD% + + rem Perform the install + call :install release static %LEGACY_BUILD% + + rem Configuring 64-bit Shared Library Release Build + call :configure x64 release shared %LEGACY_BUILD% + + rem Perform the build + call :build x64 shared %LEGACY_BUILD% + + rem Perform the install + call :install release shared %LEGACY_BUILD% + ) + + goto success + +:x86 + rem Calculate our output directory + set OUTDIR=build\Win32\%VC_DESC% + if not exist %OUTDIR% md %OUTDIR% + + if not "%BUILD_CONFIG%" == "release" ( + rem Configuring 32-bit Static Library Debug Build + call :configure x86 debug static %LEGACY_BUILD% + + rem Perform the build + call :build x86 static %LEGACY_BUILD% + + rem Perform the install + call :install debug static %LEGACY_BUILD% + + rem Configuring 32-bit Shared Library Debug Build + call :configure x86 debug shared %LEGACY_BUILD% + + rem Perform the build + call :build x86 shared %LEGACY_BUILD% + + rem Perform the install + call :install debug shared %LEGACY_BUILD% + ) + + if not "%BUILD_CONFIG%" == "debug" ( + rem Configuring 32-bit Static Library Release Build + call :configure x86 release static %LEGACY_BUILD% + + rem Perform the build + call :build x86 static %LEGACY_BUILD% + + rem Perform the install + call :install release static %LEGACY_BUILD% + + rem Configuring 32-bit Shared Library Release Build + call :configure x86 release shared %LEGACY_BUILD% + + rem Perform the build + call :build x86 shared %LEGACY_BUILD% + + rem Perform the install + call :install release shared %LEGACY_BUILD% + ) + + goto success + +rem Function to configure the build. +rem +rem %1 - Platform (x86 or x64) +rem %2 - Configuration (release or debug) +rem %3 - Build Type (static or shared) +rem %4 - Build type (TRUE for legacy aka pre v1.1.0; otherwise FALSE) +rem +:configure + setlocal + + if "%1" == "" exit /B 1 + if "%2" == "" exit /B 1 + if "%3" == "" exit /B 1 + if "%4" == "" exit /B 1 + + if not exist "%TMP_BUILD_PATH%" mkdir "%TMP_BUILD_PATH%" + cd /d "%TMP_BUILD_PATH%" || (echo Error: Failed cd build & exit /B 1) + + if "%4" == "TRUE" ( + rem Calculate the configure options + if "%1" == "x86" ( + if "%2" == "debug" ( + set options=debug-VC-WIN32 + ) else if "%2" == "release" ( + set options=VC-WIN32 + ) else ( + exit /B 1 + ) + + set options=!options! no-asm + ) else if "%1" == "x64" ( + if "%2" == "debug" ( + set options=debug-VC-WIN64A + ) else if "%2" == "release" ( + set options=VC-WIN64A + ) else ( + exit /B 1 + ) + ) else ( + exit /B 1 + ) + ) else if "%4" == "FALSE" ( + rem Has configure already been ran? + if exist makefile ( + rem Clean up the previous build + nmake clean + + rem Remove the old makefile + del makefile 1>nul + ) + + rem Calculate the configure options + if "%1" == "x86" ( + set options=VC-WIN32 + ) else if "%1" == "x64" ( + set options=VC-WIN64A + ) else ( + exit /B 1 + ) + + if "%2" == "debug" ( + set options=!options! --debug + ) else if "%2" == "release" ( + set options=!options! --release + ) else ( + exit /B 1 + ) + + if "%3" == "static" ( + set options=!options! no-shared + ) else if not "%3" == "shared" ( + exit /B 1 + ) + + set options=!options! no-asm + ) else ( + exit /B 1 + ) + + rem Run the configure + perl "%SOURCE_PATH%\Configure" %options% "--prefix=%TMP_INSTALL_PATH%" + + exit /B %ERRORLEVEL% + +rem Main build function. +rem +rem %1 - Platform (x86 or x64) +rem %2 - Build Type (static or shared) +rem %3 - Build type (TRUE for legacy aka pre v1.1.0; otherwise FALSE) +rem +:build + setlocal + + if "%1" == "" exit /B 1 + if "%2" == "" exit /B 1 + if "%3" == "" exit /B 1 + + cd /d "%TMP_BUILD_PATH%" || (echo Error: Failed cd build & exit /B 1) + + if "%3" == "TRUE" ( + if "%1" == "x86" ( + call ms\do_ms.bat + ) else if "%1" == "x64" ( + call ms\do_win64a.bat + ) else ( + exit /B 1 + ) + + if "%2" == "static" ( + nmake -f ms\nt.mak + ) else if "%2" == "shared" ( + nmake -f ms\ntdll.mak + ) else ( + exit /B 1 + ) + ) else if "%3" == "FALSE" ( + nmake + ) else ( + exit /B 1 + ) + + exit /B 0 + +rem Main installation function. +rem +rem %1 - Configuration (release or debug) +rem %2 - Build Type (static or shared) +rem %3 - Build type (TRUE for legacy aka pre v1.1.0; otherwise FALSE) +rem +:install + setlocal + + if "%1" == "" exit /B 1 + if "%2" == "" exit /B 1 + if "%3" == "" exit /B 1 + + rem Copy the generated files to our directory structure + if "%3" == "TRUE" ( + rem There's no actual installation for legacy OpenSSL, the files are copied + rem from the build dir (for legacy this is same as source dir) to the final + rem location. + cd /d "%SOURCE_PATH%" || (echo Error: Failed cd source & exit /B 1) + if "%1" == "debug" ( + if "%2" == "static" ( + rem Move the output directories + if exist "%OUTDIR%\LIB Debug" ( + copy /y out32.dbg\* "%OUTDIR%\LIB Debug" 1>nul + rd out32.dbg /s /q + ) else ( + move out32.dbg "%OUTDIR%\LIB Debug" 1>nul + ) + + rem Move the PDB files + move tmp32.dbg\lib.pdb "%OUTDIR%\LIB Debug" 1>nul + + rem Remove the intermediate directories + rd tmp32.dbg /s /q + ) else if "%2" == "shared" ( + if exist "%OUTDIR%\DLL Debug" ( + copy /y out32dll.dbg\* "%OUTDIR%\DLL Debug" 1>nul + rd out32dll.dbg /s /q + ) else ( + move out32dll.dbg "%OUTDIR%\DLL Debug" 1>nul + ) + + rem Move the PDB files + move tmp32dll.dbg\lib.pdb "%OUTDIR%\DLL Debug" 1>nul + + rem Remove the intermediate directories + rd tmp32dll.dbg /s /q + ) else ( + exit /B 1 + ) + ) else if "%1" == "release" ( + if "%2" == "static" ( + rem Move the output directories + if exist "%OUTDIR%\LIB Release" ( + copy /y out32\* "%OUTDIR%\LIB Release" 1>nul + rd out32 /s /q + ) else ( + move out32 "%OUTDIR%\LIB Release" 1>nul + ) + + rem Move the PDB files + move tmp32\lib.pdb "%OUTDIR%\LIB Release" 1>nul + + rem Remove the intermediate directories + rd tmp32 /s /q + ) else if "%2" == "shared" ( + if exist "%OUTDIR%\DLL Release" ( + copy /y out32dll\* "%OUTDIR%\DLL Release" 1>nul + rd out32dll /s /q + ) else ( + move out32dll "%OUTDIR%\DLL Release" 1>nul + ) + + rem Move the PDB files + move tmp32dll\lib.pdb "%OUTDIR%\DLL Release" 1>nul + + rem Remove the intermediate directories + rd tmp32dll /s /q + ) else ( + exit /B 1 + ) + ) + ) else if "%3" == "FALSE" ( + cd /d "%TMP_BUILD_PATH%" || (echo Error: Failed cd build & exit /B 1) + + rem Perform the installation + nmake install_sw + + cd /d "%SOURCE_PATH%" || (echo Error: Failed cd source & exit /B 1) + + rem Move the output directories + if "%1" == "debug" ( + if "%2" == "static" ( + if not exist "%OUTDIR%\LIB Debug" ( + mkdir "%OUTDIR%\LIB Debug" 1>nul + ) + + move "%TMP_INSTALL_PATH%\lib\*.lib" "%OUTDIR%\LIB Debug" 1>nul + move "%TMP_INSTALL_PATH%\lib\*.pdb" "%OUTDIR%\LIB Debug" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.exe" "%OUTDIR%\LIB Debug" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.pdb" "%OUTDIR%\LIB Debug" 1>nul + xcopy /E /I /Y "%TMP_INSTALL_PATH%\include" "%OUTDIR%\LIB Debug\include" 1>nul + ) else if "%2" == "shared" ( + if not exist "%OUTDIR%\DLL Debug" ( + mkdir "%OUTDIR%\DLL Debug" 1>nul + ) + + move "%TMP_INSTALL_PATH%\lib\*.lib" "%OUTDIR%\DLL Debug" 1>nul + if exist "%TMP_INSTALL_PATH%\lib\engines-3" ( + move "%TMP_INSTALL_PATH%\lib\engines-3\*.dll" "%OUTDIR%\DLL Debug" 1>nul + move "%TMP_INSTALL_PATH%\lib\engines-3\*.pdb" "%OUTDIR%\DLL Debug" 1>nul + ) else if exist "%TMP_INSTALL_PATH%\lib\engines-1_1" ( + move "%TMP_INSTALL_PATH%\lib\engines-1_1\*.dll" "%OUTDIR%\DLL Debug" 1>nul + move "%TMP_INSTALL_PATH%\lib\engines-1_1\*.pdb" "%OUTDIR%\DLL Debug" 1>nul + ) + move "%TMP_INSTALL_PATH%\bin\*.dll" "%OUTDIR%\DLL Debug" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.exe" "%OUTDIR%\DLL Debug" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.pdb" "%OUTDIR%\DLL Debug" 1>nul + xcopy /E /I /Y "%TMP_INSTALL_PATH%\include" "%OUTDIR%\DLL Debug\include" 1>nul + ) else ( + exit /B 1 + ) + ) else if "%1" == "release" ( + if "%2" == "static" ( + if not exist "%OUTDIR%\LIB Release" ( + mkdir "%OUTDIR%\LIB Release" 1>nul + ) + + move "%TMP_INSTALL_PATH%\lib\*.lib" "%OUTDIR%\LIB Release" 1>nul + move "%TMP_INSTALL_PATH%\lib\*.pdb" "%OUTDIR%\LIB Release" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.exe" "%OUTDIR%\LIB Release" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.pdb" "%OUTDIR%\LIB Release" 1>nul + xcopy /E /I /Y "%TMP_INSTALL_PATH%\include" "%OUTDIR%\LIB Release\include" 1>nul + ) else if "%2" == "shared" ( + if not exist "%OUTDIR%\DLL Release" ( + mkdir "%OUTDIR%\DLL Release" 1>nul + ) + + move "%TMP_INSTALL_PATH%\lib\*.lib" "%OUTDIR%\DLL Release" 1>nul + if exist "%TMP_INSTALL_PATH%\lib\engines-3" ( + move "%TMP_INSTALL_PATH%\lib\engines-3\*.dll" "%OUTDIR%\DLL Release" 1>nul + move "%TMP_INSTALL_PATH%\lib\engines-3\*.pdb" "%OUTDIR%\DLL Release" 1>nul + ) else if exist "%TMP_INSTALL_PATH%\lib\engines-1_1" ( + move "%TMP_INSTALL_PATH%\lib\engines-1_1\*.dll" "%OUTDIR%\DLL Release" 1>nul + move "%TMP_INSTALL_PATH%\lib\engines-1_1\*.pdb" "%OUTDIR%\DLL Release" 1>nul + ) + move "%TMP_INSTALL_PATH%\bin\*.dll" "%OUTDIR%\DLL Release" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.exe" "%OUTDIR%\DLL Release" 1>nul + move "%TMP_INSTALL_PATH%\bin\*.pdb" "%OUTDIR%\DLL Release" 1>nul + xcopy /E /I /Y "%TMP_INSTALL_PATH%\include" "%OUTDIR%\DLL Release\include" 1>nul + ) else ( + exit /B 1 + ) + ) else ( + exit /B 1 + ) + + rem Remove the output directories + if not "%SOURCE_PATH%" == "%TMP_BUILD_PATH%" ( + rd "%TMP_BUILD_PATH%" /s /q + ) + if not "%SOURCE_PATH%" == "%TMP_INSTALL_PATH%" ( + rd "%TMP_INSTALL_PATH%" /s /q + ) + ) else ( + exit /B 1 + ) + + exit /B 0 + +:syntax + rem Display the help + echo. + echo Usage: build-openssl ^ [platform] [configuration] [directory] [-VSpath] ["VSpath"] [-perlpath] ["perlpath"] + echo. + echo Compiler: + echo. + echo vc10 - Use Visual Studio 2010 + echo vc11 - Use Visual Studio 2012 + echo vc12 - Use Visual Studio 2013 + echo vc14 - Use Visual Studio 2015 + echo vc14.1 - Use Visual Studio 2017 + echo vc14.2 - Use Visual Studio 2019 + echo vc14.3 - Use Visual Studio 2022 + echo. + echo Platform: + echo. + echo x86 - Perform a 32-bit build + echo x64 - Perform a 64-bit build + echo. + echo Configuration: + echo. + echo debug - Perform a debug build + echo release - Perform a release build + echo. + echo Other: + echo. + echo directory - Specifies the OpenSSL source directory + echo. + echo -VSpath - Specify the custom VS path if Visual Studio is not located at + echo "C:\\Microsoft Visual Studio " + echo For e.g. -VSpath "C:\apps\MVS14" + echo. + echo -perlpath - Specify the custom perl root path if perl is not located at + echo "C:\Perl" and it is a portable copy of perl and not + echo installed on the win system. + echo For e.g. -perlpath "D:\strawberry-perl-5.24.3.1-64bit-portable" + goto error + +:unknown + echo. + echo Error: Unknown argument '%1' + goto error + +:nodos + echo. + echo Error: Only a Windows NT based Operating System is supported + goto error + +:nopf + echo. + echo Error: Cannot obtain the directory for Program Files + goto error + +:novc + echo. + echo Error: %VC_DESC% is not installed + echo Error: Please check whether Visual compiler is installed at the path "%ABS_VC_PATH%" + echo Error: Please provide proper VS Path by using -VSpath + goto error + +:noperl + echo. + echo Error: Perl is not installed + echo Error: Please check whether Perl is installed or it is at location "C:\Perl" + echo Error: If Perl is portable please provide perl root path by using -perlpath + goto error + +:nox64 + echo. + echo Error: %VC_DESC% does not support 64-bit builds + goto error + +:noopenssl + echo. + echo Error: Cannot locate OpenSSL source directory + goto error + +:error + if "%OS%" == "Windows_NT" endlocal + exit /B 1 + +:success + cd /d "%SAVED_PATH%" + endlocal + exit /B 0 diff --git a/projects/build-wolfssl.bat b/projects/build-wolfssl.bat new file mode 100644 index 0000000..1ceaa62 --- /dev/null +++ b/projects/build-wolfssl.bat @@ -0,0 +1,429 @@ +@echo off +rem *************************************************************************** +rem * _ _ ____ _ +rem * Project ___| | | | _ \| | +rem * / __| | | | |_) | | +rem * | (__| |_| | _ <| |___ +rem * \___|\___/|_| \_\_____| +rem * +rem * Copyright (C) Steve Holme, . +rem * Copyright (C) Jay Satiro, . +rem * +rem * This software is licensed as described in the file COPYING, which +rem * you should have received as part of this distribution. The terms +rem * are also available at https://curl.se/docs/copyright.html. +rem * +rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell +rem * copies of the Software, and permit persons to whom the Software is +rem * furnished to do so, under the terms of the COPYING file. +rem * +rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +rem * KIND, either express or implied. +rem * +rem * SPDX-License-Identifier: curl +rem * +rem *************************************************************************** + +:begin + rem Check we are running on a Windows NT derived OS + if not "%OS%" == "Windows_NT" goto nodos + + rem Set our variables + setlocal + set SUCCESSFUL_BUILDS= + set VC_VER= + set BUILD_PLATFORM= + set DEFAULT_START_DIR=..\..\wolfssl + + rem Calculate the program files directory + if defined PROGRAMFILES ( + set "PF=%PROGRAMFILES%" + set OS_PLATFORM=x86 + ) + if defined PROGRAMFILES(x86) ( + rem Visual Studio was x86-only prior to 14.3 + if /i "%~1" == "vc14.3" ( + set "PF=%PROGRAMFILES%" + ) else ( + set "PF=%PROGRAMFILES(x86)%" + ) + set OS_PLATFORM=x64 + ) + + rem Ensure we have the required arguments + if /i "%~1" == "" goto syntax + +:parseArgs + if "%~1" == "" goto prerequisites + + if /i "%~1" == "vc10" ( + set VC_VER=10.0 + set VC_DESC=VC10 + set VC_TOOLSET=v100 + set "VC_PATH=Microsoft Visual Studio 10.0\VC" + ) else if /i "%~1" == "vc11" ( + set VC_VER=11.0 + set VC_DESC=VC11 + set VC_TOOLSET=v110 + set "VC_PATH=Microsoft Visual Studio 11.0\VC" + ) else if /i "%~1" == "vc12" ( + set VC_VER=12.0 + set VC_DESC=VC12 + set VC_TOOLSET=v120 + set "VC_PATH=Microsoft Visual Studio 12.0\VC" + ) else if /i "%~1" == "vc14" ( + set VC_VER=14.0 + set VC_DESC=VC14 + set VC_TOOLSET=v140 + set "VC_PATH=Microsoft Visual Studio 14.0\VC" + ) else if /i "%~1" == "vc14.1" ( + set VC_VER=14.1 + set VC_DESC=VC14.10 + set VC_TOOLSET=v141 + + rem Determine the VC14.1 path based on the installed edition in descending + rem order (Enterprise, then Professional and finally Community) + if exist "%PF%\Microsoft Visual Studio\2017\Enterprise\VC" ( + set "VC_PATH=Microsoft Visual Studio\2017\Enterprise\VC" + ) else if exist "%PF%\Microsoft Visual Studio\2017\Professional\VC" ( + set "VC_PATH=Microsoft Visual Studio\2017\Professional\VC" + ) else ( + set "VC_PATH=Microsoft Visual Studio\2017\Community\VC" + ) + ) else if /i "%~1" == "vc14.2" ( + set VC_VER=14.2 + set VC_DESC=VC14.20 + set VC_TOOLSET=v142 + + rem Determine the VC14.2 path based on the installed edition in descending + rem order (Enterprise, then Professional and finally Community) + if exist "%PF%\Microsoft Visual Studio\2019\Enterprise\VC" ( + set "VC_PATH=Microsoft Visual Studio\2019\Enterprise\VC" + ) else if exist "%PF%\Microsoft Visual Studio\2019\Professional\VC" ( + set "VC_PATH=Microsoft Visual Studio\2019\Professional\VC" + ) else ( + set "VC_PATH=Microsoft Visual Studio\2019\Community\VC" + ) + ) else if /i "%~1" == "vc14.3" ( + set VC_VER=14.3 + set VC_DESC=VC14.30 + set VC_TOOLSET=v143 + + rem Determine the VC14.3 path based on the installed edition in descending + rem order (Enterprise, then Professional and finally Community) + if exist "%PF%\Microsoft Visual Studio\2022\Enterprise\VC" ( + set "VC_PATH=Microsoft Visual Studio\2022\Enterprise\VC" + ) else if exist "%PF%\Microsoft Visual Studio\2022\Professional\VC" ( + set "VC_PATH=Microsoft Visual Studio\2022\Professional\VC" + ) else ( + set "VC_PATH=Microsoft Visual Studio\2022\Community\VC" + ) + ) else if /i "%~1" == "x86" ( + set BUILD_PLATFORM=x86 + ) else if /i "%~1" == "x64" ( + set BUILD_PLATFORM=x64 + ) else if /i "%~1" == "debug" ( + set BUILD_CONFIG=debug + ) else if /i "%~1" == "release" ( + set BUILD_CONFIG=release + ) else if /i "%~1" == "-?" ( + goto syntax + ) else if /i "%~1" == "-h" ( + goto syntax + ) else if /i "%~1" == "-help" ( + goto syntax + ) else ( + if not defined START_DIR ( + set START_DIR=%~1 + ) else ( + goto unknown + ) + ) + + shift & goto parseArgs + +:prerequisites + rem Compiler is a required parameter + if not defined VC_VER goto syntax + + rem Default the start directory if one isn't specified + if not defined START_DIR set "START_DIR=%DEFAULT_START_DIR%" + + rem Check we have a program files directory + if not defined PF goto nopf + + rem Check we have Visual Studio installed + if not exist "%PF%\%VC_PATH%" goto novc + + rem Check the start directory exists + if not exist "%START_DIR%" goto nowolfssl + +:configure + if "%BUILD_PLATFORM%" == "" set BUILD_PLATFORM=%OS_PLATFORM% + + if "%BUILD_PLATFORM%" == "x86" ( + set VCVARS_PLATFORM=x86 + ) else if "%BUILD_PLATFORM%" == "x64" ( + if "%VC_VER%" == "10.0" set VCVARS_PLATFORM=%BUILD_PLATFORM% + if "%VC_VER%" == "11.0" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "12.0" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.0" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.1" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.2" set VCVARS_PLATFORM=amd64 + if "%VC_VER%" == "14.3" set VCVARS_PLATFORM=amd64 + ) + +:start + echo. + set SAVED_PATH=%CD% + + if "%VC_VER%" == "14.1" ( + call "%PF%\%VC_PATH%\Auxiliary\Build\vcvarsall" %VCVARS_PLATFORM% + ) else if "%VC_VER%" == "14.2" ( + call "%PF%\%VC_PATH%\Auxiliary\Build\vcvarsall" %VCVARS_PLATFORM% + ) else if "%VC_VER%" == "14.3" ( + call "%PF%\%VC_PATH%\Auxiliary\Build\vcvarsall" %VCVARS_PLATFORM% + ) else ( + call "%PF%\%VC_PATH%\vcvarsall" %VCVARS_PLATFORM% + ) + + echo. + cd /d %SAVED_PATH% + if defined START_DIR cd /d %START_DIR% + goto %BUILD_PLATFORM% + +:x64 + rem Calculate our output directory + set OUTDIR=build\Win64\%VC_DESC% + if not exist %OUTDIR% md %OUTDIR% + + if "%BUILD_CONFIG%" == "release" goto x64release + +:x64debug + rem Perform 64-bit Debug Build + + call :build Debug x64 + if errorlevel 1 goto error + + call :build "DLL Debug" x64 + if errorlevel 1 goto error + + if "%BUILD_CONFIG%" == "debug" goto success + +:x64release + rem Perform 64-bit Release Build + + call :build Release x64 + if errorlevel 1 goto error + + call :build "DLL Release" x64 + if errorlevel 1 goto error + + goto success + +:x86 + rem Calculate our output directory + set OUTDIR=build\Win32\%VC_DESC% + if not exist %OUTDIR% md %OUTDIR% + + if "%BUILD_CONFIG%" == "release" goto x86release + +:x86debug + rem Perform 32-bit Debug Build + + call :build Debug Win32 + if errorlevel 1 goto error + + call :build "DLL Debug" Win32 + if errorlevel 1 goto error + + if "%BUILD_CONFIG%" == "debug" goto success + +:x86release + rem Perform 32-bit Release Build + + call :build Release Win32 + if errorlevel 1 goto error + + call :build "DLL Release" Win32 + if errorlevel 1 goto error + + goto success + +:build + rem This function builds wolfSSL. + rem Usage: CALL :build + rem The current directory must be the wolfSSL directory. + rem VS Configuration: Debug, Release, DLL Debug or DLL Release. + rem VS Platform: Win32 or x64. + rem Returns: 1 on fail, 0 on success. + rem An informational message should be shown before any return. + setlocal + set MSBUILD_CONFIG=%~1 + set MSBUILD_PLATFORM=%~2 + + if not exist wolfssl64.sln ( + echo. + echo Error: build: wolfssl64.sln not found in "%CD%" + exit /b 1 + ) + + rem OUTDIR isn't a full path, only relative. MSBUILD_OUTDIR must be full and + rem not have trailing backslashes, which are handled later. + if "%MSBUILD_CONFIG%" == "Debug" ( + set "MSBUILD_OUTDIR=%CD%\%OUTDIR%\LIB Debug" + ) else if "%MSBUILD_CONFIG%" == "Release" ( + set "MSBUILD_OUTDIR=%CD%\%OUTDIR%\LIB Release" + ) else if "%MSBUILD_CONFIG%" == "DLL Debug" ( + set "MSBUILD_OUTDIR=%CD%\%OUTDIR%\DLL Debug" + ) else if "%MSBUILD_CONFIG%" == "DLL Release" ( + set "MSBUILD_OUTDIR=%CD%\%OUTDIR%\DLL Release" + ) else ( + echo. + echo Error: build: Configuration not recognized. + exit /b 1 + ) + + if not "%MSBUILD_PLATFORM%" == "Win32" if not "%MSBUILD_PLATFORM%" == "x64" ( + echo. + echo Error: build: Platform not recognized. + exit /b 1 + ) + + copy /v /y "%~dp0\wolfssl_options.h" .\cyassl\options.h + if %ERRORLEVEL% neq 0 ( + echo. + echo Error: build: Couldn't replace .\cyassl\options.h + exit /b 1 + ) + + copy /v /y "%~dp0\wolfssl_options.h" .\wolfssl\options.h + if %ERRORLEVEL% neq 0 ( + echo. + echo Error: build: Couldn't replace .\wolfssl\options.h + exit /b 1 + ) + + rem Extra trailing \ in Dirs because otherwise it thinks a quote is escaped + msbuild wolfssl64.sln ^ + -p:CustomAfterMicrosoftCommonTargets="%~dp0\wolfssl_override.props" ^ + -p:Configuration="%MSBUILD_CONFIG%" ^ + -p:Platform="%MSBUILD_PLATFORM%" ^ + -p:PlatformToolset="%VC_TOOLSET%" ^ + -p:OutDir="%MSBUILD_OUTDIR%\\" ^ + -p:IntDir="%MSBUILD_OUTDIR%\obj\\" + + if %ERRORLEVEL% neq 0 ( + echo. + echo Error: Failed building wolfSSL %MSBUILD_CONFIG%^|%MSBUILD_PLATFORM%. + exit /b 1 + ) + + rem For tests to run properly the wolfSSL directory must remain the current. + set "PATH=%MSBUILD_OUTDIR%;%PATH%" + "%MSBUILD_OUTDIR%\testsuite.exe" + + if %ERRORLEVEL% neq 0 ( + echo. + echo Error: Failed testing wolfSSL %MSBUILD_CONFIG%^|%MSBUILD_PLATFORM%. + exit /b 1 + ) + + echo. + echo Success: Built and tested wolfSSL %MSBUILD_CONFIG%^|%MSBUILD_PLATFORM%. + echo. + echo. + rem This is necessary to export our local variables back to the caller. + endlocal & set SUCCESSFUL_BUILDS="%MSBUILD_CONFIG%|%MSBUILD_PLATFORM%" ^ + %SUCCESSFUL_BUILDS% + exit /b 0 + +:syntax + rem Display the help + echo. + echo Usage: build-wolfssl ^ [platform] [configuration] [directory] + echo. + echo. + echo Compiler: + echo. + echo vc10 - Use Visual Studio 2010 + echo vc11 - Use Visual Studio 2012 + echo vc12 - Use Visual Studio 2013 + echo vc14 - Use Visual Studio 2015 + echo vc14.1 - Use Visual Studio 2017 + echo vc14.2 - Use Visual Studio 2019 + echo vc14.3 - Use Visual Studio 2022 + echo. + echo. + echo Platform: + echo. + echo x86 - Perform a 32-bit build + echo x64 - Perform a 64-bit build + echo. + echo If this parameter is unset the OS platform is used ^(%OS_PLATFORM%^). + echo. + echo. + echo Configuration: + echo. + echo debug - Perform a debug build + echo release - Perform a release build + echo. + echo If this parameter is unset both configurations are built. + echo. + echo. + echo Other: + echo. + echo directory - Specifies the wolfSSL source directory + echo. + echo If this parameter is unset the directory used is "%DEFAULT_START_DIR%". + echo. + goto error + +:unknown + echo. + echo Error: Unknown argument '%1' + goto error + +:nodos + echo. + echo Error: Only a Windows NT based Operating System is supported + goto error + +:nopf + echo. + echo Error: Cannot obtain the directory for Program Files + goto error + +:novc + echo. + echo Error: %VC_DESC% is not installed + goto error + +:nox64 + echo. + echo Error: %VC_DESC% does not support 64-bit builds + goto error + +:nowolfssl + echo. + echo Error: Cannot locate wolfSSL source directory, expected "%START_DIR%" + goto error + +:error + if "%OS%" == "Windows_NT" endlocal + exit /B 1 + +:success + if defined SUCCESSFUL_BUILDS ( + echo. + echo. + echo Build complete. + echo. + echo The following configurations were built and tested successfully: + echo. + echo %SUCCESSFUL_BUILDS% + echo. + ) + cd /d %SAVED_PATH% + endlocal + exit /B 0 diff --git a/projects/checksrc.bat b/projects/checksrc.bat new file mode 100644 index 0000000..af0ff1e --- /dev/null +++ b/projects/checksrc.bat @@ -0,0 +1,225 @@ +@echo off +rem *************************************************************************** +rem * _ _ ____ _ +rem * Project ___| | | | _ \| | +rem * / __| | | | |_) | | +rem * | (__| |_| | _ <| |___ +rem * \___|\___/|_| \_\_____| +rem * +rem * Copyright (C) Steve Holme, . +rem * +rem * This software is licensed as described in the file COPYING, which +rem * you should have received as part of this distribution. The terms +rem * are also available at https://curl.se/docs/copyright.html. +rem * +rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell +rem * copies of the Software, and permit persons to whom the Software is +rem * furnished to do so, under the terms of the COPYING file. +rem * +rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +rem * KIND, either express or implied. +rem * +rem * SPDX-License-Identifier: curl +rem * +rem *************************************************************************** + +:begin + rem Check we are running on a Windows NT derived OS + if not "%OS%" == "Windows_NT" goto nodos + + rem Set our variables + setlocal + set CHECK_LIB=TRUE + set CHECK_SRC=TRUE + set CHECK_TESTS=TRUE + set CHECK_EXAMPLES=TRUE + set SRC_DIR= + set CUR_DIR=%cd% + set ARG0_DIR=%~dp0 + +:parseArgs + if "%~1" == "" goto prerequisites + + if /i "%~1" == "-?" ( + goto syntax + ) else if /i "%~1" == "-h" ( + goto syntax + ) else if /i "%~1" == "-help" ( + goto syntax + ) else if /i "%~1" == "lib" ( + set CHECK_LIB=TRUE + set CHECK_SRC=FALSE + set CHECK_TESTS=FALSE + set CHECK_EXAMPLES=FALSE + ) else if /i "%~1" == "src" ( + set CHECK_LIB=FALSE + set CHECK_SRC=TRUE + set CHECK_TESTS=FALSE + set CHECK_EXAMPLES=FALSE + ) else if /i "%~1" == "tests" ( + set CHECK_LIB=FALSE + set CHECK_SRC=FALSE + set CHECK_TESTS=TRUE + set CHECK_EXAMPLES=FALSE + ) else if /i "%~1" == "examples" ( + set CHECK_LIB=FALSE + set CHECK_SRC=FALSE + set CHECK_TESTS=FALSE + set CHECK_EXAMPLES=TRUE + ) else ( + if not defined SRC_DIR ( + set SRC_DIR=%~1% + ) else ( + goto unknown + ) + ) + + shift & goto parseArgs + +:prerequisites + rem Check we have Perl in our path + perl --version NUL 2>&1 + if errorlevel 1 ( + rem It isn't so check we have it installed and set the path if it is + if exist "%SystemDrive%\Perl" ( + set "PATH=%SystemDrive%\Perl\bin;%PATH%" + ) else ( + if exist "%SystemDrive%\Perl64" ( + set "PATH=%SystemDrive%\Perl64\bin;%PATH%" + ) else ( + goto noperl + ) + ) + ) + +:configure + if "%SRC_DIR%" == "" ( + rem Are we being executed from the "projects" or main directory? + if "%CUR_DIR%\" == "%ARG0_DIR%" ( + set SRC_DIR=.. + ) else if exist projects ( + if exist docs ( + if exist lib ( + if exist src ( + if exist tests ( + set SRC_DIR=. + ) + ) + ) + ) + ) + ) + if not exist "%SRC_DIR%" goto nosrc + +:start + if "%CHECK_SRC%" == "TRUE" ( + rem Check the src directory + if exist %SRC_DIR%\src ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\src\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\src" -Wtool_hugehelp.c "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\src\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\src" "%%i" + ) + ) + + if "%CHECK_LIB%" == "TRUE" ( + rem Check the lib directory + if exist %SRC_DIR%\lib ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib" -Wcurl_config.h.cmake -Wcurl_config.h.in -Wcurl_config.h "%%i" + ) + + rem Check the lib\vauth directory + if exist %SRC_DIR%\lib\vauth ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vauth\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vauth" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vauth\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vauth" "%%i" + ) + + rem Check the lib\vquic directory + if exist %SRC_DIR%\lib\vquic ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vquic\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vquic" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vquic\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vquic" "%%i" + ) + + rem Check the lib\vssh directory + if exist %SRC_DIR%\lib\vssh ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vssh\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vssh" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vssh\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vssh" "%%i" + ) + + rem Check the lib\vtls directory + if exist %SRC_DIR%\lib\vtls ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vtls\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vtls" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\lib\vtls\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\lib\vtls" "%%i" + ) + ) + + if "%CHECK_TESTS%" == "TRUE" ( + rem Check the tests\libtest directory + if exist %SRC_DIR%\tests\libtest ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\tests\libtest\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\tests\libtest" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\tests\libtest\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\tests\libtest" "%%i" + ) + + rem Check the tests\unit directory + if exist %SRC_DIR%\tests\unit ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\tests\unit\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\tests\unit" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\tests\unit\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\tests\unit" "%%i" + ) + + rem Check the tests\server directory + if exist %SRC_DIR%\tests\server ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\tests\server\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\tests\server" "%%i" + for /f "delims=" %%i in ('dir "%SRC_DIR%\tests\server\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\tests\server" "%%i" + ) + ) + + if "%CHECK_EXAMPLES%" == "TRUE" ( + rem Check the docs\examples directory + if exist %SRC_DIR%\docs\examples ( + for /f "delims=" %%i in ('dir "%SRC_DIR%\docs\examples\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\docs\examples" -ASNPRINTF "%%i" + ) + ) + + goto success + +:syntax + rem Display the help + echo. + echo Usage: checksrc [what] [directory] + echo. + echo What to scan: + echo. + echo lib - Scan the libcurl source + echo src - Scan the command-line tool source + echo tests - Scan the library tests and unit tests + echo examples - Scan the examples + echo. + echo directory - Specifies the curl source directory + goto success + +:unknown + echo. + echo Error: Unknown argument '%1' + goto error + +:nodos + echo. + echo Error: Only a Windows NT based Operating System is supported + goto error + +:noperl + echo. + echo Error: Perl is not installed + goto error + +:nosrc + echo. + echo Error: "%SRC_DIR%" does not exist + goto error + +:error + if "%OS%" == "Windows_NT" endlocal + exit /B 1 + +:success + endlocal + exit /B 0 diff --git a/projects/generate.bat b/projects/generate.bat new file mode 100644 index 0000000..83e6387 --- /dev/null +++ b/projects/generate.bat @@ -0,0 +1,424 @@ +@echo off +rem *************************************************************************** +rem * _ _ ____ _ +rem * Project ___| | | | _ \| | +rem * / __| | | | |_) | | +rem * | (__| |_| | _ <| |___ +rem * \___|\___/|_| \_\_____| +rem * +rem * Copyright (C) Steve Holme, . +rem * +rem * This software is licensed as described in the file COPYING, which +rem * you should have received as part of this distribution. The terms +rem * are also available at https://curl.se/docs/copyright.html. +rem * +rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell +rem * copies of the Software, and permit persons to whom the Software is +rem * furnished to do so, under the terms of the COPYING file. +rem * +rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +rem * KIND, either express or implied. +rem * +rem * SPDX-License-Identifier: curl +rem * +rem *************************************************************************** + +:begin + rem Check we are running on a Windows NT derived OS + if not "%OS%" == "Windows_NT" goto nodos + + rem Set our variables + setlocal ENABLEEXTENSIONS + set VERSION=ALL + set MODE=GENERATE + + rem Check we are not running on a network drive + if "%~d0."=="\\." goto nonetdrv + + rem Switch to this batch file's directory + cd /d "%~0\.." 1>NUL 2>&1 + + rem Check we are running from a curl git repository + if not exist ..\GIT-INFO goto norepo + +:parseArgs + if "%~1" == "" goto start + + if /i "%~1" == "pre" ( + set VERSION=PRE + ) else if /i "%~1" == "vc10" ( + set VERSION=VC10 + ) else if /i "%~1" == "vc11" ( + set VERSION=VC11 + ) else if /i "%~1" == "vc12" ( + set VERSION=VC12 + ) else if /i "%~1" == "vc14" ( + set VERSION=VC14 + ) else if /i "%~1" == "vc14.10" ( + set VERSION=VC14.10 + ) else if /i "%~1" == "vc14.20" ( + set VERSION=VC14.20 + ) else if /i "%~1" == "vc14.30" ( + set VERSION=VC14.30 + ) else if /i "%~1" == "-clean" ( + set MODE=CLEAN + ) else if /i "%~1" == "-?" ( + goto syntax + ) else if /i "%~1" == "-h" ( + goto syntax + ) else if /i "%~1" == "-help" ( + goto syntax + ) else ( + goto unknown + ) + + shift & goto parseArgs + +:start + if exist ..\buildconf.bat ( + if "%MODE%" == "GENERATE" ( + call ..\buildconf + ) else if "%VERSION%" == "PRE" ( + call ..\buildconf -clean + ) else if "%VERSION%" == "ALL" ( + call ..\buildconf -clean + ) + ) + if "%VERSION%" == "PRE" goto success + if "%VERSION%" == "VC10" goto vc10 + if "%VERSION%" == "VC11" goto vc11 + if "%VERSION%" == "VC12" goto vc12 + if "%VERSION%" == "VC14" goto vc14 + if "%VERSION%" == "VC14.10" goto vc14.10 + if "%VERSION%" == "VC14.20" goto vc14.20 + if "%VERSION%" == "VC14.30" goto vc14.30 + +:vc10 + echo. + + if "%MODE%" == "GENERATE" ( + echo Generating VC10 project files + call :generate vcxproj Windows\VC10\src\curl.tmpl Windows\VC10\src\curl.vcxproj + call :generate vcxproj Windows\VC10\lib\libcurl.tmpl Windows\VC10\lib\libcurl.vcxproj + ) else ( + echo Removing VC10 project files + call :clean Windows\VC10\src\curl.vcxproj + call :clean Windows\VC10\lib\libcurl.vcxproj + ) + + if not "%VERSION%" == "ALL" goto success + +:vc11 + echo. + + if "%MODE%" == "GENERATE" ( + echo Generating VC11 project files + call :generate vcxproj Windows\VC11\src\curl.tmpl Windows\VC11\src\curl.vcxproj + call :generate vcxproj Windows\VC11\lib\libcurl.tmpl Windows\VC11\lib\libcurl.vcxproj + ) else ( + echo Removing VC11 project files + call :clean Windows\VC11\src\curl.vcxproj + call :clean Windows\VC11\lib\libcurl.vcxproj + ) + + if not "%VERSION%" == "ALL" goto success + +:vc12 + echo. + + if "%MODE%" == "GENERATE" ( + echo Generating VC12 project files + call :generate vcxproj Windows\VC12\src\curl.tmpl Windows\VC12\src\curl.vcxproj + call :generate vcxproj Windows\VC12\lib\libcurl.tmpl Windows\VC12\lib\libcurl.vcxproj + ) else ( + echo Removing VC12 project files + call :clean Windows\VC12\src\curl.vcxproj + call :clean Windows\VC12\lib\libcurl.vcxproj + ) + + if not "%VERSION%" == "ALL" goto success + +:vc14 + echo. + + if "%MODE%" == "GENERATE" ( + echo Generating VC14 project files + call :generate vcxproj Windows\VC14\src\curl.tmpl Windows\VC14\src\curl.vcxproj + call :generate vcxproj Windows\VC14\lib\libcurl.tmpl Windows\VC14\lib\libcurl.vcxproj + ) else ( + echo Removing VC14 project files + call :clean Windows\VC14\src\curl.vcxproj + call :clean Windows\VC14\lib\libcurl.vcxproj + ) + + if not "%VERSION%" == "ALL" goto success + +:vc14.10 + echo. + + if "%MODE%" == "GENERATE" ( + echo Generating VC14.10 project files + call :generate vcxproj Windows\VC14.10\src\curl.tmpl Windows\VC14.10\src\curl.vcxproj + call :generate vcxproj Windows\VC14.10\lib\libcurl.tmpl Windows\VC14.10\lib\libcurl.vcxproj + ) else ( + echo Removing VC14.10 project files + call :clean Windows\VC14.10\src\curl.vcxproj + call :clean Windows\VC14.10\lib\libcurl.vcxproj + ) + + if not "%VERSION%" == "ALL" goto success + +:vc14.20 + echo. + + if "%MODE%" == "GENERATE" ( + echo Generating VC14.20 project files + call :generate vcxproj Windows\VC14.20\src\curl.tmpl Windows\VC14.20\src\curl.vcxproj + call :generate vcxproj Windows\VC14.20\lib\libcurl.tmpl Windows\VC14.20\lib\libcurl.vcxproj + ) else ( + echo Removing VC14.20 project files + call :clean Windows\VC14.20\src\curl.vcxproj + call :clean Windows\VC14.20\lib\libcurl.vcxproj + ) + + if not "%VERSION%" == "ALL" goto success + +:vc14.30 + echo. + + if "%MODE%" == "GENERATE" ( + echo Generating VC14.30 project files + call :generate vcxproj Windows\VC14.30\src\curl.tmpl Windows\VC14.30\src\curl.vcxproj + call :generate vcxproj Windows\VC14.30\lib\libcurl.tmpl Windows\VC14.30\lib\libcurl.vcxproj + ) else ( + echo Removing VC14.30 project files + call :clean Windows\VC14.30\src\curl.vcxproj + call :clean Windows\VC14.30\lib\libcurl.vcxproj + ) + + goto success + +rem Main generate function. +rem +rem %1 - Project Type (vcxproj for VC10, VC11, VC12, VC14, VC14.10, VC14.20 and VC14.30) +rem %2 - Input template file +rem %3 - Output project file +rem +:generate + if not exist %2 ( + echo. + echo Error: Cannot open %2 + exit /B + ) + + if exist %3 ( + del %3 + ) + + echo * %CD%\%3 + for /f "usebackq delims=" %%i in (`"findstr /n ^^ %2"`) do ( + set "var=%%i" + setlocal enabledelayedexpansion + set "var=!var:*:=!" + + if "!var!" == "CURL_SRC_C_FILES" ( + for /f "delims=" %%c in ('dir /b ..\src\*.c') do call :element %1 src "%%c" %3 + ) else if "!var!" == "CURL_SRC_H_FILES" ( + for /f "delims=" %%h in ('dir /b ..\src\*.h') do call :element %1 src "%%h" %3 + ) else if "!var!" == "CURL_SRC_RC_FILES" ( + for /f "delims=" %%r in ('dir /b ..\src\*.rc') do call :element %1 src "%%r" %3 + ) else if "!var!" == "CURL_SRC_X_C_FILES" ( + call :element %1 lib "strtoofft.c" %3 + call :element %1 lib "timediff.c" %3 + call :element %1 lib "nonblock.c" %3 + call :element %1 lib "warnless.c" %3 + call :element %1 lib "curl_multibyte.c" %3 + call :element %1 lib "version_win32.c" %3 + call :element %1 lib "dynbuf.c" %3 + call :element %1 lib "base64.c" %3 + ) else if "!var!" == "CURL_SRC_X_H_FILES" ( + call :element %1 lib "config-win32.h" %3 + call :element %1 lib "curl_setup.h" %3 + call :element %1 lib "strtoofft.h" %3 + call :element %1 lib "timediff.h" %3 + call :element %1 lib "nonblock.h" %3 + call :element %1 lib "warnless.h" %3 + call :element %1 lib "curl_ctype.h" %3 + call :element %1 lib "curl_multibyte.h" %3 + call :element %1 lib "version_win32.h" %3 + call :element %1 lib "dynbuf.h" %3 + call :element %1 lib "curl_base64.h" %3 + ) else if "!var!" == "CURL_LIB_C_FILES" ( + for /f "delims=" %%c in ('dir /b ..\lib\*.c') do call :element %1 lib "%%c" %3 + ) else if "!var!" == "CURL_LIB_H_FILES" ( + for /f "delims=" %%h in ('dir /b ..\include\curl\*.h') do call :element %1 include\curl "%%h" %3 + for /f "delims=" %%h in ('dir /b ..\lib\*.h') do call :element %1 lib "%%h" %3 + ) else if "!var!" == "CURL_LIB_RC_FILES" ( + for /f "delims=" %%r in ('dir /b ..\lib\*.rc') do call :element %1 lib "%%r" %3 + ) else if "!var!" == "CURL_LIB_VAUTH_C_FILES" ( + for /f "delims=" %%c in ('dir /b ..\lib\vauth\*.c') do call :element %1 lib\vauth "%%c" %3 + ) else if "!var!" == "CURL_LIB_VAUTH_H_FILES" ( + for /f "delims=" %%h in ('dir /b ..\lib\vauth\*.h') do call :element %1 lib\vauth "%%h" %3 + ) else if "!var!" == "CURL_LIB_VQUIC_C_FILES" ( + for /f "delims=" %%c in ('dir /b ..\lib\vquic\*.c') do call :element %1 lib\vquic "%%c" %3 + ) else if "!var!" == "CURL_LIB_VQUIC_H_FILES" ( + for /f "delims=" %%h in ('dir /b ..\lib\vquic\*.h') do call :element %1 lib\vquic "%%h" %3 + ) else if "!var!" == "CURL_LIB_VSSH_C_FILES" ( + for /f "delims=" %%c in ('dir /b ..\lib\vssh\*.c') do call :element %1 lib\vssh "%%c" %3 + ) else if "!var!" == "CURL_LIB_VSSH_H_FILES" ( + for /f "delims=" %%h in ('dir /b ..\lib\vssh\*.h') do call :element %1 lib\vssh "%%h" %3 + ) else if "!var!" == "CURL_LIB_VTLS_C_FILES" ( + for /f "delims=" %%c in ('dir /b ..\lib\vtls\*.c') do call :element %1 lib\vtls "%%c" %3 + ) else if "!var!" == "CURL_LIB_VTLS_H_FILES" ( + for /f "delims=" %%h in ('dir /b ..\lib\vtls\*.h') do call :element %1 lib\vtls "%%h" %3 + ) else ( + echo.!var!>> %3 + ) + + endlocal + ) + exit /B + +rem Generates a single file xml element. +rem +rem %1 - Project Type (vcxproj for VC10, VC11, VC12, VC14, VC14.10, VC14.20 and VC14.30) +rem %2 - Directory (src, lib, lib\vauth, lib\vquic, lib\vssh, lib\vtls) +rem %3 - Source filename +rem %4 - Output project file +rem +:element + set "SPACES= " + if "%2" == "lib\vauth" ( + set "TABS= " + ) else if "%2" == "lib\vquic" ( + set "TABS= " + ) else if "%2" == "lib\vssh" ( + set "TABS= " + ) else if "%2" == "lib\vtls" ( + set "TABS= " + ) else ( + set "TABS= " + ) + + call :extension %3 ext + + if "%1" == "dsp" ( + echo # Begin Source File>> %4 + echo.>> %4 + echo SOURCE=..\..\..\..\%2\%~3>> %4 + echo # End Source File>> %4 + ) else if "%1" == "vcproj1" ( + echo %TABS%^> %4 + echo %TABS% RelativePath="..\..\..\..\%2\%~3"^>>> %4 + echo %TABS%^>> %4 + ) else if "%1" == "vcproj2" ( + echo %TABS%^> %4 + echo %TABS% RelativePath="..\..\..\..\%2\%~3">> %4 + echo %TABS%^>>> %4 + echo %TABS%^>> %4 + ) else if "%1" == "vcxproj" ( + if "%ext%" == "c" ( + echo %SPACES%^>> %4 + ) else if "%ext%" == "h" ( + echo %SPACES%^>> %4 + ) else if "%ext%" == "rc" ( + echo %SPACES%^>> %4 + ) + ) + + exit /B + +rem Returns the extension for a given filename. +rem +rem %1 - The filename +rem %2 - The return value +rem +:extension + set fname=%~1 + set ename= +:loop1 + if "%fname%"=="" ( + set %2= + exit /B + ) + + if not "%fname:~-1%"=="." ( + set ename=%fname:~-1%%ename% + set fname=%fname:~0,-1% + goto loop1 + ) + + set %2=%ename% + exit /B + +rem Removes the given project file. +rem +rem %1 - The filename +rem +:clean + echo * %CD%\%1 + + if exist %1 ( + del %1 + ) + + exit /B + +:syntax + rem Display the help + echo. + echo Usage: generate [what] [-clean] + echo. + echo What to generate: + echo. + echo pre - Prerequisites only + echo vc10 - Use Visual Studio 2010 + echo vc11 - Use Visual Studio 2012 + echo vc12 - Use Visual Studio 2013 + echo vc14 - Use Visual Studio 2015 + echo vc14.10 - Use Visual Studio 2017 + echo vc14.20 - Use Visual Studio 2019 + echo vc14.30 - Use Visual Studio 2022 + echo. + echo -clean - Removes the project files + goto error + +:unknown + echo. + echo Error: Unknown argument '%1' + goto error + +:nodos + echo. + echo Error: Only a Windows NT based Operating System is supported + goto error + +:nonetdrv + echo. + echo Error: This batch file cannot run from a network drive + goto error + +:norepo + echo. + echo Error: This batch file should only be used from a curl git repository + goto error + +:seterr + rem Set the caller's errorlevel. + rem %1[opt]: Errorlevel as integer. + rem If %1 is empty the errorlevel will be set to 0. + rem If %1 is not empty and not an integer the errorlevel will be set to 1. + setlocal + set EXITCODE=%~1 + if not defined EXITCODE set EXITCODE=0 + echo %EXITCODE%|findstr /r "[^0-9\-]" 1>NUL 2>&1 + if %ERRORLEVEL% EQU 0 set EXITCODE=1 + exit /b %EXITCODE% + +:error + if "%OS%" == "Windows_NT" endlocal + exit /B 1 + +:success + endlocal + exit /B 0 diff --git a/projects/wolfssl_options.h b/projects/wolfssl_options.h new file mode 100644 index 0000000..3ef23fb --- /dev/null +++ b/projects/wolfssl_options.h @@ -0,0 +1,308 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +/* +By default wolfSSL has a very conservative configuration that can result in +connections to servers failing due to certificate or algorithm problems. +To remedy this issue for libcurl I've generated this options file that +build-wolfssl will copy to the wolfSSL include directories and will result in +maximum compatibility. + +These are the configure options that were used to build wolfSSL v5.1.1 in +mingw and generate the options in this file: + +C_EXTRA_FLAGS="\ + -Wno-attributes \ + -Wno-unused-but-set-variable \ + -DFP_MAX_BITS=16384 \ + -DHAVE_SECRET_CALLBACK \ + -DTFM_TIMING_RESISTANT \ + -DUSE_WOLF_STRTOK \ + -DWOLFSSL_DES_ECB \ + -DWOLFSSL_STATIC_DH \ + -DWOLFSSL_STATIC_RSA \ + " \ +./configure --prefix=/usr/local \ + --disable-jobserver \ + --enable-aesgcm \ + --enable-alpn \ + --enable-altcertchains \ + --enable-certgen \ + --enable-des3 \ + --enable-dh \ + --enable-dsa \ + --enable-ecc \ + --enable-eccshamir \ + --enable-fastmath \ + --enable-opensslextra \ + --enable-ripemd \ + --enable-sessioncerts \ + --enable-sha512 \ + --enable-sni \ + --enable-tlsv10 \ + --enable-supportedcurves \ + --enable-tls13 \ + --enable-testcert \ + > config.out 2>&1 + +Two generated options HAVE_THREAD_LS and _POSIX_THREADS were removed since they +are inapplicable for our Visual Studio build. Currently thread local storage is +only used by the Fixed Point cache ECC which we're not enabling. However even +if we later may decide to enable the cache it will fallback on mutexes when +thread local storage is not available. wolfSSL is using __declspec(thread) to +create the thread local storage and that could be a problem for LoadLibrary. + +Regarding the options that were added via C_EXTRA_FLAGS: + +FP_MAX_BITS=16384 +https://www.yassl.com/forums/topic423-cacertorgs-ca-cert-verify-failed-but-withdisablefastmath-it-works.html +"Since root.crt uses a 4096-bit RSA key, you'll need to increase the fastmath +buffer size. You can do this using the define: +FP_MAX_BITS and setting it to 8192." + +HAVE_SECRET_CALLBACK +Build wolfSSL with wolfSSL_set_tls13_secret_cb which allows saving TLS 1.3 +secrets to SSLKEYLOGFILE. + +TFM_TIMING_RESISTANT +https://wolfssl.com/wolfSSL/Docs-wolfssl-manual-2-building-wolfssl.html +From section 2.4.5 Increasing Performance, USE_FAST_MATH: +"Because the stack memory usage can be larger when using fastmath, we recommend +defining TFM_TIMING_RESISTANT as well when using this option." + +USE_WOLF_STRTOK +Build wolfSSL to always use its internal strtok instead of C runtime strtok. + +WOLFSSL_DES_ECB +Build wolfSSL with wolfSSL_DES_ecb_encrypt which is needed by libcurl for NTLM. + +WOLFSSL_STATIC_DH: Allow TLS_ECDH_ ciphers +WOLFSSL_STATIC_RSA: Allow TLS_RSA_ ciphers +https://github.com/wolfSSL/wolfssl/blob/v3.6.6/README.md#note-1 +Static key cipher suites are deprecated and disabled by default since v3.6.6. +*/ + +/* wolfssl options.h + * generated from configure options + * + * Copyright (C) 2006-2022 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + */ + +#ifndef WOLFSSL_OPTIONS_H +#define WOLFSSL_OPTIONS_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#undef FP_MAX_BITS +#define FP_MAX_BITS 16384 + +#undef HAVE_SECRET_CALLBACK +#define HAVE_SECRET_CALLBACK + +#undef TFM_TIMING_RESISTANT +#define TFM_TIMING_RESISTANT + +#undef USE_WOLF_STRTOK +#define USE_WOLF_STRTOK + +#undef WOLFSSL_DES_ECB +#define WOLFSSL_DES_ECB + +#undef WOLFSSL_STATIC_DH +#define WOLFSSL_STATIC_DH + +#undef WOLFSSL_STATIC_RSA +#define WOLFSSL_STATIC_RSA + +#undef TFM_TIMING_RESISTANT +#define TFM_TIMING_RESISTANT + +#undef ECC_TIMING_RESISTANT +#define ECC_TIMING_RESISTANT + +#undef WC_RSA_BLINDING +#define WC_RSA_BLINDING + +#undef WOLFSSL_USE_ALIGN +#define WOLFSSL_USE_ALIGN + +#undef WOLFSSL_RIPEMD +#define WOLFSSL_RIPEMD + +#undef WOLFSSL_SHA512 +#define WOLFSSL_SHA512 + +#undef WOLFSSL_SHA384 +#define WOLFSSL_SHA384 + +#undef SESSION_CERTS +#define SESSION_CERTS + +#undef HAVE_HKDF +#define HAVE_HKDF + +#undef HAVE_ECC +#define HAVE_ECC + +#undef TFM_ECC256 +#define TFM_ECC256 + +#undef ECC_SHAMIR +#define ECC_SHAMIR + +#undef WOLFSSL_ALLOW_TLSV10 +#define WOLFSSL_ALLOW_TLSV10 + +#undef WC_RSA_PSS +#define WC_RSA_PSS + +#undef NO_HC128 +#define NO_HC128 + +#undef NO_RABBIT +#define NO_RABBIT + +#undef HAVE_POLY1305 +#define HAVE_POLY1305 + +#undef HAVE_ONE_TIME_AUTH +#define HAVE_ONE_TIME_AUTH + +#undef HAVE_CHACHA +#define HAVE_CHACHA + +#undef HAVE_HASHDRBG +#define HAVE_HASHDRBG + +#undef HAVE_TLS_EXTENSIONS +#define HAVE_TLS_EXTENSIONS + +#undef HAVE_SNI +#define HAVE_SNI + +#undef HAVE_TLS_EXTENSIONS +#define HAVE_TLS_EXTENSIONS + +#undef HAVE_ALPN +#define HAVE_ALPN + +#undef HAVE_TLS_EXTENSIONS +#define HAVE_TLS_EXTENSIONS + +#undef HAVE_SUPPORTED_CURVES +#define HAVE_SUPPORTED_CURVES + +#undef HAVE_FFDHE_2048 +#define HAVE_FFDHE_2048 + +#undef HAVE_SUPPORTED_CURVES +#define HAVE_SUPPORTED_CURVES + +#undef WOLFSSL_TLS13 +#define WOLFSSL_TLS13 + +#undef HAVE_TLS_EXTENSIONS +#define HAVE_TLS_EXTENSIONS + +#undef HAVE_EXTENDED_MASTER +#define HAVE_EXTENDED_MASTER + +#undef WOLFSSL_ALT_CERT_CHAINS +#define WOLFSSL_ALT_CERT_CHAINS + +#undef WOLFSSL_TEST_CERT +#define WOLFSSL_TEST_CERT + +#undef NO_RC4 +#define NO_RC4 + +#undef HAVE_ENCRYPT_THEN_MAC +#define HAVE_ENCRYPT_THEN_MAC + +#undef NO_PSK +#define NO_PSK + +#undef NO_MD4 +#define NO_MD4 + +#undef WOLFSSL_ENCRYPTED_KEYS +#define WOLFSSL_ENCRYPTED_KEYS + +#undef USE_FAST_MATH +#define USE_FAST_MATH + +#undef WC_NO_ASYNC_THREADING +#define WC_NO_ASYNC_THREADING + +#undef HAVE_DH_DEFAULT_PARAMS +#define HAVE_DH_DEFAULT_PARAMS + +#undef WOLFSSL_CERT_GEN +#define WOLFSSL_CERT_GEN + +#undef OPENSSL_EXTRA +#define OPENSSL_EXTRA + +#undef WOLFSSL_ALWAYS_VERIFY_CB +#define WOLFSSL_ALWAYS_VERIFY_CB + +#undef WOLFSSL_VERIFY_CB_ALL_CERTS +#define WOLFSSL_VERIFY_CB_ALL_CERTS + +#undef WOLFSSL_EXTRA_ALERTS +#define WOLFSSL_EXTRA_ALERTS + +#undef HAVE_EXT_CACHE +#define HAVE_EXT_CACHE + +#undef WOLFSSL_FORCE_CACHE_ON_TICKET +#define WOLFSSL_FORCE_CACHE_ON_TICKET + +#undef WOLFSSL_AKID_NAME +#define WOLFSSL_AKID_NAME + +#undef HAVE_CTS +#define HAVE_CTS + +#undef GCM_TABLE_4BIT +#define GCM_TABLE_4BIT + +#undef HAVE_AESGCM +#define HAVE_AESGCM + +#undef HAVE_WC_INTROSPECTION +#define HAVE_WC_INTROSPECTION + + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + + +#endif /* WOLFSSL_OPTIONS_H */ diff --git a/projects/wolfssl_override.props b/projects/wolfssl_override.props new file mode 100644 index 0000000..fab60f3 --- /dev/null +++ b/projects/wolfssl_override.props @@ -0,0 +1,40 @@ + + + + + + %(PreprocessorDefinitions); + + $(SolutionDir)\wolfssl\options.h;%(ForcedIncludeFiles); + + _UNICODE;UNICODE;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;%(UndefinePreprocessorDefinitions); + + + _UNICODE;UNICODE;%(UndefinePreprocessorDefinitions); + + + + + + + + + + diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 0000000..ae95e85 --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,63 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +EXTRA_DIST = coverage.sh completion.pl firefox-db2pem.sh checksrc.pl \ + mk-ca-bundle.pl schemetable.c cd2nroff nroff2cd cdall cd2cd + +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +PERL = @PERL@ + +ZSH_COMPLETION_FUNCTION_FILENAME = _curl +FISH_COMPLETION_FUNCTION_FILENAME = curl.fish + +CLEANFILES = $(ZSH_COMPLETION_FUNCTION_FILENAME) $(FISH_COMPLETION_FUNCTION_FILENAME) + +all-local: $(ZSH_COMPLETION_FUNCTION_FILENAME) $(FISH_COMPLETION_FUNCTION_FILENAME) + +$(ZSH_COMPLETION_FUNCTION_FILENAME): completion.pl +if CROSSCOMPILING + @echo "NOTICE: we can't generate zsh completion when cross-compiling!" +else # if not cross-compiling: + @if ! test -x "$(PERL)"; then echo "No perl: can't install completion.pl"; exit 0; fi + $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell zsh > $@ +endif + +$(FISH_COMPLETION_FUNCTION_FILENAME): completion.pl +if CROSSCOMPILING + @echo "NOTICE: we can't generate fish completion when cross-compiling!" +else # if not cross-compiling: + @if ! test -x "$(PERL)"; then echo "No perl: can't install completion.pl"; exit 0; fi + $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell fish > $@ +endif + +install-data-local: +if CROSSCOMPILING + @echo "NOTICE: we can't install zsh completion when cross-compiling!" +else # if not cross-compiling: + $(MKDIR_P) $(DESTDIR)$(ZSH_FUNCTIONS_DIR) + $(MKDIR_P) $(DESTDIR)$(FISH_FUNCTIONS_DIR) + $(INSTALL_DATA) $(ZSH_COMPLETION_FUNCTION_FILENAME) $(DESTDIR)$(ZSH_FUNCTIONS_DIR)/$(ZSH_COMPLETION_FUNCTION_FILENAME) + $(INSTALL_DATA) $(FISH_COMPLETION_FUNCTION_FILENAME) $(DESTDIR)$(FISH_FUNCTIONS_DIR)/$(FISH_COMPLETION_FUNCTION_FILENAME) +endif diff --git a/scripts/Makefile.in b/scripts/Makefile.in new file mode 100644 index 0000000..adc8775 --- /dev/null +++ b/scripts/Makefile.in @@ -0,0 +1,619 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = scripts +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NROFF = @NROFF@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = coverage.sh completion.pl firefox-db2pem.sh checksrc.pl \ + mk-ca-bundle.pl schemetable.c cd2nroff nroff2cd cdall cd2cd + +ZSH_COMPLETION_FUNCTION_FILENAME = _curl +FISH_COMPLETION_FUNCTION_FILENAME = curl.fish +CLEANFILES = $(ZSH_COMPLETION_FUNCTION_FILENAME) $(FISH_COMPLETION_FUNCTION_FILENAME) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign scripts/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign scripts/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-data-local install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +all-local: $(ZSH_COMPLETION_FUNCTION_FILENAME) $(FISH_COMPLETION_FUNCTION_FILENAME) + +$(ZSH_COMPLETION_FUNCTION_FILENAME): completion.pl +@CROSSCOMPILING_TRUE@ @echo "NOTICE: we can't generate zsh completion when cross-compiling!" +@CROSSCOMPILING_FALSE@ @if ! test -x "$(PERL)"; then echo "No perl: can't install completion.pl"; exit 0; fi +@CROSSCOMPILING_FALSE@ $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell zsh > $@ + +$(FISH_COMPLETION_FUNCTION_FILENAME): completion.pl +@CROSSCOMPILING_TRUE@ @echo "NOTICE: we can't generate fish completion when cross-compiling!" +@CROSSCOMPILING_FALSE@ @if ! test -x "$(PERL)"; then echo "No perl: can't install completion.pl"; exit 0; fi +@CROSSCOMPILING_FALSE@ $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell fish > $@ + +install-data-local: +@CROSSCOMPILING_TRUE@ @echo "NOTICE: we can't install zsh completion when cross-compiling!" +@CROSSCOMPILING_FALSE@ $(MKDIR_P) $(DESTDIR)$(ZSH_FUNCTIONS_DIR) +@CROSSCOMPILING_FALSE@ $(MKDIR_P) $(DESTDIR)$(FISH_FUNCTIONS_DIR) +@CROSSCOMPILING_FALSE@ $(INSTALL_DATA) $(ZSH_COMPLETION_FUNCTION_FILENAME) $(DESTDIR)$(ZSH_FUNCTIONS_DIR)/$(ZSH_COMPLETION_FUNCTION_FILENAME) +@CROSSCOMPILING_FALSE@ $(INSTALL_DATA) $(FISH_COMPLETION_FUNCTION_FILENAME) $(DESTDIR)$(FISH_FUNCTIONS_DIR)/$(FISH_COMPLETION_FUNCTION_FILENAME) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/scripts/cd2cd b/scripts/cd2cd new file mode 100755 index 0000000..a4de2f8 --- /dev/null +++ b/scripts/cd2cd @@ -0,0 +1,226 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +=begin comment + +This script updates a curldown file to current/better curldown. + +Example: cd2cd [--in-place] > + +--in-place: if used, it replaces the original file with the cleaned up + version. When this is used, cd2cd accepts multiple files to work + on and it ignores errors on single files. + +=end comment +=cut + +my $cd2cd = "0.1"; # to keep check +my $dir; +my $extension; +my $inplace = 0; + +while(1) { + if($ARGV[0] eq "--in-place") { + shift @ARGV; + $inplace = 1; + } + else { + last; + } +} + + +use POSIX qw(strftime); +my @ts; +if (defined($ENV{SOURCE_DATE_EPOCH})) { + @ts = localtime($ENV{SOURCE_DATE_EPOCH}); +} else { + @ts = localtime; +} +my $date = strftime "%B %d %Y", @ts; + +sub outseealso { + my (@sa) = @_; + my $comma = 0; + my @o; + push @o, ".SH SEE ALSO\n"; + for my $s (sort @sa) { + push @o, sprintf "%s.BR $s", $comma ? ",\n": ""; + $comma = 1; + } + push @o, "\n"; + return @o; +} + +sub single { + my @head; + my @seealso; + my ($f)=@_; + my $title; + my $section; + my $source; + my $start = 0; + my $d; + my $line = 0; + open(F, "<:crlf", "$f") || + return 1; + while() { + $line++; + $d = $_; + if(!$start) { + if(/^---/) { + # header starts here + $start = 1; + push @head, $d; + } + next; + } + if(/^Title: *(.*)/i) { + $title=$1; + } + elsif(/^Section: *(.*)/i) { + $section=$1; + } + elsif(/^Source: *(.*)/i) { + $source=$1; + } + elsif(/^See-also: +(.*)/i) { + $salist = 0; + push @seealso, $1; + } + elsif(/^See-also: */i) { + if($seealso[0]) { + print STDERR "$f:$line:1:ERROR: bad See-Also, needs list\n"; + return 2; + } + $salist = 1; + } + elsif(/^ +- (.*)/i) { + # the only list we support is the see-also + if($salist) { + push @seealso, $1; + } + } + # REUSE-IgnoreStart + elsif(/^C: (.*)/i) { + $copyright=$1; + } + elsif(/^SPDX-License-Identifier: (.*)/i) { + $spdx=$1; + } + # REUSE-IgnoreEnd + elsif(/^---/) { + # end of the header section + if(!$title) { + print STDERR "ERROR: no 'Title:' in $f\n"; + return 1; + } + if(!$section) { + print STDERR "ERROR: no 'Section:' in $f\n"; + return 2; + } + if(!$seealso[0]) { + print STDERR "$f:$line:1:ERROR: no 'See-also:' present\n"; + return 2; + } + if(!$copyright) { + print STDERR "$f:$line:1:ERROR: no 'C:' field present\n"; + return 2; + } + if(!$spdx) { + print STDERR "$f:$line:1:ERROR: no 'SPDX-License-Identifier:' field present\n"; + return 2; + } + last; + } + else { + chomp; + print STDERR "WARN: unrecognized line in $f, ignoring:\n:'$_';" + } + } + + if(!$start) { + print STDERR "$f:$line:1:ERROR: no header present\n"; + return 2; + } + + my @desc; + + push @desc, sprintf <, et al. +SPDX-License-Identifier: curl +Title: $title +Section: $section +Source: $source +HEAD + ; + push @desc, "See-also:\n"; + for my $s (sort @seealso) { + push @desc, " - $s\n" if($s); + } + push @desc, "---\n"; + + my $blankline = 0; + while() { + $d = $_; + $line++; + if($d =~ /^[ \t]*\n/) { + $blankline++; + } + else { + $blankline = 0; + } + # *italics* for curl symbol links get the asterisks removed + $d =~ s/\*((lib|)curl[^ ]*\(3\))\*/$1/gi; + + if(length($d) > 90) { + print STDERR "$f:$line:1:WARN: excessive line length\n"; + } + + push @desc, $d if($blankline < 2); + } + close(F); + + if($inplace) { + open(O, ">$f") || return 1; + print O @desc; + close(O); + } + else { + print @desc; + } + return 0; +} + +if($inplace) { + for my $a (@ARGV) { + # this ignores errors + single($a); + } +} +else { + exit single($ARGV[0]); +} diff --git a/scripts/cd2nroff b/scripts/cd2nroff new file mode 100755 index 0000000..17a83b4 --- /dev/null +++ b/scripts/cd2nroff @@ -0,0 +1,373 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +=begin comment + +Converts a curldown file to nroff (man page). + +=end comment +=cut + +use strict; +use warnings; + +my $cd2nroff = "0.1"; # to keep check +my $dir; +my $extension; +my $keepfilename; + +while(@ARGV) { + if($ARGV[0] eq "-d") { + shift @ARGV; + $dir = shift @ARGV; + } + elsif($ARGV[0] eq "-e") { + shift @ARGV; + $extension = shift @ARGV; + } + elsif($ARGV[0] eq "-k") { + shift @ARGV; + $keepfilename = 1; + } + elsif($ARGV[0] eq "-h") { + print < Write the output to the file name from the meta-data in the + specified directory, instead of writing to stdout +-e If -d is used, this option can provide an added "extension", arbitrary + text really, to append to the file name. +-h This help text, +-v Show version then exit +HELP + ; + exit 0; + } + elsif($ARGV[0] eq "-v") { + print "cd2nroff version $cd2nroff\n"; + exit 0; + } + else { + last; + } +} + +use POSIX qw(strftime); +my @ts; +if (defined($ENV{SOURCE_DATE_EPOCH})) { + @ts = localtime($ENV{SOURCE_DATE_EPOCH}); +} else { + @ts = localtime; +} +my $date = strftime "%B %d %Y", @ts; + +sub outseealso { + my (@sa) = @_; + my $comma = 0; + my @o; + push @o, ".SH SEE ALSO\n"; + for my $s (sort @sa) { + push @o, sprintf "%s.BR $s", $comma ? ",\n": ""; + $comma = 1; + } + push @o, "\n"; + return @o; +} + +sub single { + my @seealso; + my $d; + my ($f)=@_; + my $copyright; + my $errors = 0; + my $fh; + my $line; + my $salist; + my $section; + my $source; + my $spdx; + my $start = 0; + my $title; + + if(defined($f)) { + if(!open($fh, "<:crlf", "$f")) { + print STDERR "Failed to open $f : $!\n"; + return 1; + } + } + else { + $f = "STDIN"; + $fh = \*STDIN; + binmode($fh, ":crlf"); + } + while(<$fh>) { + $line++; + if(!$start) { + if(/^---/) { + # header starts here + $start = 1; + } + next; + } + if(/^Title: *(.*)/i) { + $title=$1; + } + elsif(/^Section: *(.*)/i) { + $section=$1; + } + elsif(/^Source: *(.*)/i) { + $source=$1; + } + elsif(/^See-also: +(.*)/i) { + $salist = 0; + push @seealso, $1; + } + elsif(/^See-also: */i) { + if($seealso[0]) { + print STDERR "$f:$line:1:ERROR: bad See-Also, needs list\n"; + return 2; + } + $salist = 1; + } + elsif(/^ +- (.*)/i) { + # the only list we support is the see-also + if($salist) { + push @seealso, $1; + } + } + # REUSE-IgnoreStart + elsif(/^C: (.*)/i) { + $copyright=$1; + } + elsif(/^SPDX-License-Identifier: (.*)/i) { + $spdx=$1; + } + # REUSE-IgnoreEnd + elsif(/^---/) { + # end of the header section + if(!$title) { + print STDERR "ERROR: no 'Title:' in $f\n"; + return 1; + } + if(!$section) { + print STDERR "ERROR: no 'Section:' in $f\n"; + return 2; + } + if(!$seealso[0]) { + print STDERR "$f:$line:1:ERROR: no 'See-also:' present\n"; + return 2; + } + if(!$copyright) { + print STDERR "$f:$line:1:ERROR: no 'C:' field present\n"; + return 2; + } + if(!$spdx) { + print STDERR "$f:$line:1:ERROR: no 'SPDX-License-Identifier:' field present\n"; + return 2; + } + last; + } + else { + chomp; + print STDERR "WARN: unrecognized line in $f, ignoring:\n:'$_';" + } + } + + if(!$start) { + print STDERR "$f:$line:1:ERROR: no header present\n"; + return 2; + } + + my @desc; + my $quote = 0; + my $blankline = 0; + my $header = 0; + + # cut off the leading path from the file name, if any + $f =~ s/^(.*[\\\/])//; + + push @desc, ".\\\" generated by cd2nroff $cd2nroff from $f\n"; + push @desc, ".TH $title $section \"$date\" $source\n"; + while(<$fh>) { + $line++; + + $d = $_; + + if($quote) { + if($quote == 4) { + # remove the indentation + if($d =~ /^ (.*)/) { + push @desc, "$1\n"; + next; + } + else { + # end of quote + $quote = 0; + push @desc, ".fi\n"; + next; + } + } + if(/^~~~/) { + # end of quote + $quote = 0; + push @desc, ".fi\n"; + next; + } + # convert single backslahes to doubles + $d =~ s/\\/\\\\/g; + # lines starting with a period needs it escaped + $d =~ s/^\./\\&./; + push @desc, $d; + next; + } + + # **bold** + $d =~ s/\*\*(\S.*?)\*\*/\\fB$1\\fP/g; + # *italics* + $d =~ s/\*(\S.*?)\*/\\fI$1\\fP/g; + + # mentions of curl symbols with man pages use italics by default + $d =~ s/((lib|)curl([^ ]*\(3\)))/\\fI$1\\fP/gi; + + # backticked becomes italics + $d =~ s/\`(.*?)\`/\\fI$1\\fP/g; + + if(/^## (.*)/) { + my $word = $1; + # if there are enclosing quotes, remove them first + $word =~ s/[\"\'](.*)[\"\']\z/$1/; + + # enclose in double quotes if there is a space present + if($word =~ / /) { + push @desc, ".IP \"$word\"\n"; + } + else { + push @desc, ".IP $word\n"; + } + $header = 1; + } + elsif(/^# (.*)/) { + my $word = $1; + # if there are enclosing quotes, remove them first + $word =~ s/[\"\'](.*)[\"\']\z/$1/; + push @desc, ".SH $word\n"; + $header = 1; + } + elsif(/^~~~c/) { + # start of a code section, not indented + $quote = 1; + push @desc, "\n" if($blankline && !$header); + $header = 0; + push @desc, ".nf\n"; + } + elsif(/^~~~/) { + # start of a quote section; not code, not indented + $quote = 1; + push @desc, "\n" if($blankline && !$header); + $header = 0; + push @desc, ".nf\n"; + } + elsif(/^ (.*)/) { + # quoted, indented by 4 space + $quote = 4; + push @desc, "\n" if($blankline && !$header); + $header = 0; + push @desc, ".nf\n$1\n"; + } + elsif(/^[ \t]*\n/) { + # count and ignore blank lines + $blankline++; + } + else { + # don't output newlines if this is the first content after a + # header + push @desc, "\n" if($blankline && !$header); + $blankline = 0; + $header = 0; + + # remove single line HTML comments + $d =~ s///g; + + # quote minuses in the output + $d =~ s/([^\\])-/$1\\-/g; + # replace single quotes + $d =~ s/\'/\\(aq/g; + # handle double quotes first on the line + $d =~ s/^(\s*)\"/$1\\&\"/; + + # lines starting with a period needs it escaped + $d =~ s/^\./\\&./; + + if($d =~ /^(.*) /) { + printf STDERR "$f:$line:%d:ERROR: 2 spaces detected\n", + length($1); + $errors++; + } + if($d =~ /^[ \t]*\n/) { + # replaced away all contents + $blankline= 1; + } + else { + push @desc, $d; + } + } + } + if($fh != \*STDIN) { + close($fh); + } + push @desc, outseealso(@seealso); + if($dir) { + if($keepfilename) { + $title = $f; + $title =~ s/\.[^.]*$//; + } + my $outfile = "$dir/$title.$section"; + if(defined($extension)) { + $outfile .= $extension; + } + if(!open(O, ">", $outfile)) { + print STDERR "Failed to open $outfile : $!\n"; + return 1; + } + print O @desc; + close(O); + } + else { + print @desc; + } + return $errors; +} + +if(@ARGV) { + for my $f (@ARGV) { + my $r = single($f); + if($r) { + exit $r; + } + } +} +else { + exit single(); +} diff --git a/scripts/cdall b/scripts/cdall new file mode 100755 index 0000000..507ccc6 --- /dev/null +++ b/scripts/cdall @@ -0,0 +1,44 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# provide all dir names to scan on the cmdline + +sub convert { + my ($dir)=@_; + opendir(my $dh, $dir) || die "could not open $dir"; + my @cd = grep { /\.md\z/ && -f "$dir/$_" } readdir($dh); + closedir $dh; + + for my $cd (@cd) { + my $nroff = "$cd"; + $nroff =~ s/\.md\z/.3/; + print "$dir/$cd = $dir/$nroff\n"; + system("./scripts/cd2nroff -d $dir $dir/$cd"); + } +} + +for my $d (sort @ARGV) { + convert($d); +} diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl new file mode 100755 index 0000000..76f4660 --- /dev/null +++ b/scripts/checksrc.pl @@ -0,0 +1,988 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +use strict; +use warnings; + +my $max_column = 79; +my $indent = 2; + +my $warnings = 0; +my $swarnings = 0; +my $errors = 0; +my $serrors = 0; +my $suppressed; # skipped problems +my $file; +my $dir="."; +my $wlist=""; +my @alist; +my $windows_os = $^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys'; +my $verbose; +my %skiplist; + +my %ignore; +my %ignore_set; +my %ignore_used; +my @ignore_line; + +my %warnings_extended = ( + 'COPYRIGHTYEAR' => 'copyright year incorrect', + 'STRERROR', => 'strerror() detected', + 'STDERR', => 'stderr detected', + ); + +my %warnings = ( + 'ASSIGNWITHINCONDITION' => 'assignment within conditional expression', + 'ASTERISKNOSPACE' => 'pointer declared without space before asterisk', + 'ASTERISKSPACE' => 'pointer declared with space after asterisk', + 'BADCOMMAND' => 'bad !checksrc! instruction', + 'BANNEDFUNC' => 'a banned function was used', + 'BANNEDPREPROC' => 'a banned symbol was used on a preprocessor line', + 'BRACEELSE' => '} else on the same line', + 'BRACEPOS' => 'wrong position for an open brace', + 'BRACEWHILE' => 'A single space between open brace and while', + 'COMMANOSPACE' => 'comma without following space', + 'COMMENTNOSPACEEND' => 'no space before */', + 'COMMENTNOSPACESTART' => 'no space following /*', + 'COPYRIGHT' => 'file missing a copyright statement', + 'CPPCOMMENTS' => '// comment detected', + 'DOBRACE' => 'A single space between do and open brace', + 'EMPTYLINEBRACE' => 'Empty line before the open brace', + 'EQUALSNOSPACE' => 'equals sign without following space', + 'EQUALSNULL' => 'if/while comparison with == NULL', + 'EXCLAMATIONSPACE' => 'Whitespace after exclamation mark in expression', + 'FOPENMODE' => 'fopen needs a macro for the mode string', + 'INCLUDEDUP', => 'same file is included again', + 'INDENTATION' => 'wrong start column for code', + 'LONGLINE' => "Line longer than $max_column", + 'SPACEBEFORELABEL' => 'labels not at the start of the line', + 'MULTISPACE' => 'multiple spaces used when not suitable', + 'NOSPACEEQUALS' => 'equals sign without preceding space', + 'NOTEQUALSZERO', => 'if/while comparison with != 0', + 'ONELINECONDITION' => 'conditional block on the same line as the if()', + 'OPENCOMMENT' => 'file ended with a /* comment still "open"', + 'PARENBRACE' => '){ without sufficient space', + 'RETURNNOSPACE' => 'return without space', + 'SEMINOSPACE' => 'semicolon without following space', + 'SIZEOFNOPAREN' => 'use of sizeof without parentheses', + 'SNPRINTF' => 'use of snprintf', + 'SPACEAFTERPAREN' => 'space after open parenthesis', + 'SPACEBEFORECLOSE' => 'space before a close parenthesis', + 'SPACEBEFORECOMMA' => 'space before a comma', + 'SPACEBEFOREPAREN' => 'space before an open parenthesis', + 'SPACESEMICOLON' => 'space before semicolon', + 'SPACESWITCHCOLON' => 'space before colon of switch label', + 'TABS' => 'TAB characters not allowed', + 'TRAILINGSPACE' => 'Trailing whitespace on the line', + 'TYPEDEFSTRUCT' => 'typedefed struct', + 'UNUSEDIGNORE' => 'a warning ignore was not used', + ); + +sub readskiplist { + open(my $W, '<', "$dir/checksrc.skip") or return; + my @all=<$W>; + for(@all) { + $windows_os ? $_ =~ s/\r?\n$// : chomp; + $skiplist{$_}=1; + } + close($W); +} + +# Reads the .checksrc in $dir for any extended warnings to enable locally. +# Currently there is no support for disabling warnings from the standard set, +# and since that's already handled via !checksrc! commands there is probably +# little use to add it. +sub readlocalfile { + my $i = 0; + + open(my $rcfile, "<", "$dir/.checksrc") or return; + + while(<$rcfile>) { + $i++; + + # Lines starting with '#' are considered comments + if (/^\s*(#.*)/) { + next; + } + elsif (/^\s*enable ([A-Z]+)$/) { + if(!defined($warnings_extended{$1})) { + print STDERR "invalid warning specified in .checksrc: \"$1\"\n"; + next; + } + $warnings{$1} = $warnings_extended{$1}; + } + elsif (/^\s*disable ([A-Z]+)$/) { + if(!defined($warnings{$1})) { + print STDERR "invalid warning specified in .checksrc: \"$1\"\n"; + next; + } + # Accept-list + push @alist, $1; + } + else { + die "Invalid format in $dir/.checksrc on line $i\n"; + } + } + close($rcfile); +} + +sub checkwarn { + my ($name, $num, $col, $file, $line, $msg, $error) = @_; + + my $w=$error?"error":"warning"; + my $nowarn=0; + + #if(!$warnings{$name}) { + # print STDERR "Dev! there's no description for $name!\n"; + #} + + # checksrc.skip + if($skiplist{$line}) { + $nowarn = 1; + } + # !checksrc! controlled + elsif($ignore{$name}) { + $ignore{$name}--; + $ignore_used{$name}++; + $nowarn = 1; + if(!$ignore{$name}) { + # reached zero, enable again + enable_warn($name, $num, $file, $line); + } + } + + if($nowarn) { + $suppressed++; + if($w) { + $swarnings++; + } + else { + $serrors++; + } + return; + } + + if($w) { + $warnings++; + } + else { + $errors++; + } + + $col++; + print "$file:$num:$col: $w: $msg ($name)\n"; + print " $line\n"; + + if($col < 80) { + my $pref = (' ' x $col); + print "${pref}^\n"; + } +} + +$file = shift @ARGV; + +while(defined $file) { + + if($file =~ /-D(.*)/) { + $dir = $1; + $file = shift @ARGV; + next; + } + elsif($file =~ /-W(.*)/) { + $wlist .= " $1 "; + $file = shift @ARGV; + next; + } + elsif($file =~ /-A(.+)/) { + push @alist, $1; + $file = shift @ARGV; + next; + } + elsif($file =~ /-i([1-9])/) { + $indent = $1 + 0; + $file = shift @ARGV; + next; + } + elsif($file =~ /-m([0-9]+)/) { + $max_column = $1 + 0; + $file = shift @ARGV; + next; + } + elsif($file =~ /^(-h|--help)/) { + undef $file; + last; + } + + last; +} + +if(!$file) { + print "checksrc.pl [option] [file2] ...\n"; + print " Options:\n"; + print " -A[rule] Accept this violation, can be used multiple times\n"; + print " -D[DIR] Directory to prepend file names\n"; + print " -h Show help output\n"; + print " -W[file] Skip the given file - ignore all its flaws\n"; + print " -i Indent spaces. Default: 2\n"; + print " -m Maximum line length. Default: 79\n"; + print "\nDetects and warns for these problems:\n"; + my @allw = keys %warnings; + push @allw, keys %warnings_extended; + for my $w (sort @allw) { + if($warnings{$w}) { + printf (" %-18s: %s\n", $w, $warnings{$w}); + } + else { + printf (" %-18s: %s[*]\n", $w, $warnings_extended{$w}); + } + } + print " [*] = disabled by default\n"; + exit; +} + +readskiplist(); +readlocalfile(); + +do { + if("$wlist" !~ / $file /) { + my $fullname = $file; + $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/'); + scanfile($fullname); + } + $file = shift @ARGV; + +} while($file); + +sub accept_violations { + for my $r (@alist) { + if(!$warnings{$r}) { + print "'$r' is not a warning to accept!\n"; + exit; + } + $ignore{$r}=999999; + $ignore_used{$r}=0; + } +} + +sub checksrc_clear { + undef %ignore; + undef %ignore_set; + undef @ignore_line; +} + +sub checksrc_endoffile { + my ($file) = @_; + for(keys %ignore_set) { + if($ignore_set{$_} && !$ignore_used{$_}) { + checkwarn("UNUSEDIGNORE", $ignore_set{$_}, + length($_)+11, $file, + $ignore_line[$ignore_set{$_}], + "Unused ignore: $_"); + } + } +} + +sub enable_warn { + my ($what, $line, $file, $l) = @_; + + # switch it back on, but warn if not triggered! + if(!$ignore_used{$what}) { + checkwarn("UNUSEDIGNORE", + $line, length($what) + 11, $file, $l, + "No warning was inhibited!"); + } + $ignore_set{$what}=0; + $ignore_used{$what}=0; + $ignore{$what}=0; +} +sub checksrc { + my ($cmd, $line, $file, $l) = @_; + if($cmd =~ / *([^ ]*) *(.*)/) { + my ($enable, $what) = ($1, $2); + $what =~ s: *\*/$::; # cut off end of C comment + # print "ENABLE $enable WHAT $what\n"; + if($enable eq "disable") { + my ($warn, $scope)=($1, $2); + if($what =~ /([^ ]*) +(.*)/) { + ($warn, $scope)=($1, $2); + } + else { + $warn = $what; + $scope = 1; + } + # print "IGNORE $warn for SCOPE $scope\n"; + if($scope eq "all") { + $scope=999999; + } + + # Comparing for a literal zero rather than the scalar value zero + # covers the case where $scope contains the ending '*' from the + # comment. If we use a scalar comparison (==) we induce warnings + # on non-scalar contents. + if($scope eq "0") { + checkwarn("BADCOMMAND", + $line, 0, $file, $l, + "Disable zero not supported, did you mean to enable?"); + } + elsif($ignore_set{$warn}) { + checkwarn("BADCOMMAND", + $line, 0, $file, $l, + "$warn already disabled from line $ignore_set{$warn}"); + } + else { + $ignore{$warn}=$scope; + $ignore_set{$warn}=$line; + $ignore_line[$line]=$l; + } + } + elsif($enable eq "enable") { + enable_warn($what, $line, $file, $l); + } + else { + checkwarn("BADCOMMAND", + $line, 0, $file, $l, + "Illegal !checksrc! command"); + } + } +} + +sub nostrings { + my ($str) = @_; + $str =~ s/\".*\"//g; + return $str; +} + +sub scanfile { + my ($file) = @_; + + my $line = 1; + my $prevl=""; + my $prevpl=""; + my $l = ""; + my $prep = 0; + my $prevp = 0; + open(my $R, '<', $file) || die "failed to open $file"; + + my $incomment=0; + my @copyright=(); + my %includes; + checksrc_clear(); # for file based ignores + accept_violations(); + + while(<$R>) { + $windows_os ? $_ =~ s/\r?\n$// : chomp; + my $l = $_; + my $ol = $l; # keep the unmodified line for error reporting + my $column = 0; + + # check for !checksrc! commands + if($l =~ /\!checksrc\! (.*)/) { + my $cmd = $1; + checksrc($cmd, $line, $file, $l) + } + + if($l =~ /^#line (\d+) \"([^\"]*)\"/) { + # a #line instruction + $file = $2; + $line = $1; + next; + } + + # check for a copyright statement and save the years + if($l =~ /\* +copyright .* (\d\d\d\d|)/i) { + my $count = 0; + while($l =~ /([\d]{4})/g) { + push @copyright, { + year => $1, + line => $line, + col => index($l, $1), + code => $l + }; + $count++; + } + if(!$count) { + # year-less + push @copyright, { + year => -1, + line => $line, + col => index($l, $1), + code => $l + }; + } + } + + # detect long lines + if(length($l) > $max_column) { + checkwarn("LONGLINE", $line, length($l), $file, $l, + "Longer than $max_column columns"); + } + # detect TAB characters + if($l =~ /^(.*)\t/) { + checkwarn("TABS", + $line, length($1), $file, $l, "Contains TAB character", 1); + } + # detect trailing whitespace + if($l =~ /^(.*)[ \t]+\z/) { + checkwarn("TRAILINGSPACE", + $line, length($1), $file, $l, "Trailing whitespace"); + } + + # no space after comment start + if($l =~ /^(.*)\/\*\w/) { + checkwarn("COMMENTNOSPACESTART", + $line, length($1) + 2, $file, $l, + "Missing space after comment start"); + } + # no space at comment end + if($l =~ /^(.*)\w\*\//) { + checkwarn("COMMENTNOSPACEEND", + $line, length($1) + 1, $file, $l, + "Missing space end comment end"); + } + # ------------------------------------------------------------ + # Above this marker, the checks were done on lines *including* + # comments + # ------------------------------------------------------------ + + # strip off C89 comments + + comment: + if(!$incomment) { + if($l =~ s/\/\*.*\*\// /g) { + # full /* comments */ were removed! + } + if($l =~ s/\/\*.*//) { + # start of /* comment was removed + $incomment = 1; + } + } + else { + if($l =~ s/.*\*\///) { + # end of comment */ was removed + $incomment = 0; + goto comment; + } + else { + # still within a comment + $l=""; + } + } + + # ------------------------------------------------------------ + # Below this marker, the checks were done on lines *without* + # comments + # ------------------------------------------------------------ + + # prev line was a preprocessor **and** ended with a backslash + if($prep && ($prevpl =~ /\\ *\z/)) { + # this is still a preprocessor line + $prep = 1; + goto preproc; + } + $prep = 0; + + # crude attempt to detect // comments without too many false + # positives + if($l =~ /^(([^"\*]*)[^:"]|)\/\//) { + checkwarn("CPPCOMMENTS", + $line, length($1), $file, $l, "\/\/ comment"); + } + + if($l =~ /^(\#\s*include\s+)([\">].*[>}"])/) { + my ($pre, $path) = ($1, $2); + if($includes{$path}) { + checkwarn("INCLUDEDUP", + $line, length($1), $file, $l, "duplicated include"); + } + $includes{$path} = $l; + } + + # detect and strip preprocessor directives + if($l =~ /^[ \t]*\#/) { + # preprocessor line + $prep = 1; + goto preproc; + } + + my $nostr = nostrings($l); + # check spaces after for/if/while/function call + if($nostr =~ /^(.*)(for|if|while|switch| ([a-zA-Z0-9_]+)) \((.)/) { + my ($leading, $word, $extra, $first)=($1,$2,$3,$4); + if($1 =~ / *\#/) { + # this is a #if, treat it differently + } + elsif(defined $3 && $3 eq "return") { + # return must have a space + } + elsif(defined $3 && $3 eq "case") { + # case must have a space + } + elsif(($first eq "*") && ($word !~ /(for|if|while|switch)/)) { + # A "(*" beginning makes the space OK because it wants to + # allow function pointer declared + } + elsif($1 =~ / *typedef/) { + # typedefs can use space-paren + } + else { + checkwarn("SPACEBEFOREPAREN", $line, length($leading)+length($word), $file, $l, + "$word with space"); + } + } + # check for '== NULL' in if/while conditions but not if the thing on + # the left of it is a function call + if($nostr =~ /^(.*)(if|while)(\(.*?)([!=]= NULL|NULL [!=]=)/) { + checkwarn("EQUALSNULL", $line, + length($1) + length($2) + length($3), + $file, $l, "we prefer !variable instead of \"== NULL\" comparisons"); + } + + # check for '!= 0' in if/while conditions but not if the thing on + # the left of it is a function call + if($nostr =~ /^(.*)(if|while)(\(.*[^)]) != 0[^x]/) { + checkwarn("NOTEQUALSZERO", $line, + length($1) + length($2) + length($3), + $file, $l, "we prefer if(rc) instead of \"rc != 0\" comparisons"); + } + + # check spaces in 'do {' + if($nostr =~ /^( *)do( *)\{/ && length($2) != 1) { + checkwarn("DOBRACE", $line, length($1) + 2, $file, $l, "one space after do before brace"); + } + # check spaces in 'do {' + elsif($nostr =~ /^( *)\}( *)while/ && length($2) != 1) { + checkwarn("BRACEWHILE", $line, length($1) + 2, $file, $l, "one space between brace and while"); + } + if($nostr =~ /^((.*\s)(if) *\()(.*)\)(.*)/) { + my $pos = length($1); + my $postparen = $5; + my $cond = $4; + if($cond =~ / = /) { + checkwarn("ASSIGNWITHINCONDITION", + $line, $pos+1, $file, $l, + "assignment within conditional expression"); + } + my $temp = $cond; + $temp =~ s/\(//g; # remove open parens + my $openc = length($cond) - length($temp); + + $temp = $cond; + $temp =~ s/\)//g; # remove close parens + my $closec = length($cond) - length($temp); + my $even = $openc == $closec; + + if($l =~ / *\#/) { + # this is a #if, treat it differently + } + elsif($even && $postparen && + ($postparen !~ /^ *$/) && ($postparen !~ /^ *[,{&|\\]+/)) { + checkwarn("ONELINECONDITION", + $line, length($l)-length($postparen), $file, $l, + "conditional block on the same line"); + } + } + # check spaces after open parentheses + if($l =~ /^(.*[a-z])\( /i) { + checkwarn("SPACEAFTERPAREN", + $line, length($1)+1, $file, $l, + "space after open parenthesis"); + } + + # check spaces before close parentheses, unless it was a space or a + # close parenthesis! + if($l =~ /(.*[^\) ]) \)/) { + checkwarn("SPACEBEFORECLOSE", + $line, length($1)+1, $file, $l, + "space before close parenthesis"); + } + + # check spaces before comma! + if($l =~ /(.*[^ ]) ,/) { + checkwarn("SPACEBEFORECOMMA", + $line, length($1)+1, $file, $l, + "space before comma"); + } + + # check for "return(" without space + if($l =~ /^(.*)return\(/) { + if($1 =~ / *\#/) { + # this is a #if, treat it differently + } + else { + checkwarn("RETURNNOSPACE", $line, length($1)+6, $file, $l, + "return without space before paren"); + } + } + + # check for "sizeof" without parenthesis + if(($l =~ /^(.*)sizeof *([ (])/) && ($2 ne "(")) { + if($1 =~ / *\#/) { + # this is a #if, treat it differently + } + else { + checkwarn("SIZEOFNOPAREN", $line, length($1)+6, $file, $l, + "sizeof without parenthesis"); + } + } + + # check for comma without space + if($l =~ /^(.*),[^ \n]/) { + my $pref=$1; + my $ign=0; + if($pref =~ / *\#/) { + # this is a #if, treat it differently + $ign=1; + } + elsif($pref =~ /\/\*/) { + # this is a comment + $ign=1; + } + elsif($pref =~ /[\"\']/) { + $ign = 1; + # There is a quote here, figure out whether the comma is + # within a string or '' or not. + if($pref =~ /\"/) { + # within a string + } + elsif($pref =~ /\'$/) { + # a single letter + } + else { + $ign = 0; + } + } + if(!$ign) { + checkwarn("COMMANOSPACE", $line, length($pref)+1, $file, $l, + "comma without following space"); + } + } + + # check for "} else" + if($l =~ /^(.*)\} *else/) { + checkwarn("BRACEELSE", + $line, length($1), $file, $l, "else after closing brace on same line"); + } + # check for "){" + if($l =~ /^(.*)\)\{/) { + checkwarn("PARENBRACE", + $line, length($1)+1, $file, $l, "missing space after close paren"); + } + # check for "^{" with an empty line before it + if(($l =~ /^\{/) && ($prevl =~ /^[ \t]*\z/)) { + checkwarn("EMPTYLINEBRACE", + $line, 0, $file, $l, "empty line before open brace"); + } + + # check for space before the semicolon last in a line + if($l =~ /^(.*[^ ].*) ;$/) { + checkwarn("SPACESEMICOLON", + $line, length($1), $file, $ol, "no space before semicolon"); + } + + # check for space before the colon in a switch label + if($l =~ /^( *(case .+|default)) :/) { + checkwarn("SPACESWITCHCOLON", + $line, length($1), $file, $ol, "no space before colon of switch label"); + } + + if($prevl !~ /\?\z/ && $l =~ /^ +([A-Za-z_][A-Za-z0-9_]*):$/ && $1 ne 'default') { + checkwarn("SPACEBEFORELABEL", + $line, length($1), $file, $ol, "no space before label"); + } + + # scan for use of banned functions + if($l =~ /^(.*\W) + (gmtime|localtime| + gets| + strtok| + v?sprintf| + (str|_mbs|_tcs|_wcs)n?cat| + LoadLibrary(Ex)?(A|W)?) + \s*\( + /x) { + checkwarn("BANNEDFUNC", + $line, length($1), $file, $ol, + "use of $2 is banned"); + } + if($warnings{"STRERROR"}) { + # scan for use of banned strerror. This is not a BANNEDFUNC to + # allow for individual enable/disable of this warning. + if($l =~ /^(.*\W)(strerror)\s*\(/x) { + if($1 !~ /^ *\#/) { + # skip preprocessor lines + checkwarn("STRERROR", + $line, length($1), $file, $ol, + "use of $2 is banned"); + } + } + } + if($warnings{"STDERR"}) { + # scan for use of banned stderr. This is not a BANNEDFUNC to + # allow for individual enable/disable of this warning. + if($l =~ /^([^\"-]*\W)(stderr)[^\"_]/x) { + if($1 !~ /^ *\#/) { + # skip preprocessor lines + checkwarn("STDERR", + $line, length($1), $file, $ol, + "use of $2 is banned (use tool_stderr instead)"); + } + } + } + # scan for use of snprintf for curl-internals reasons + if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) { + checkwarn("SNPRINTF", + $line, length($1), $file, $ol, + "use of $2 is banned"); + } + + # scan for use of non-binary fopen without the macro + if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) { + my $mode = $2; + if($mode !~ /b/) { + checkwarn("FOPENMODE", + $line, length($1), $file, $ol, + "use of non-binary fopen without FOPEN_* macro: $mode"); + } + } + + # check for open brace first on line but not first column only alert + # if previous line ended with a close paren and it wasn't a cpp line + if(($prevl =~ /\)\z/) && ($l =~ /^( +)\{/) && !$prevp) { + checkwarn("BRACEPOS", + $line, length($1), $file, $ol, "badly placed open brace"); + } + + # if the previous line starts with if/while/for AND ends with an open + # brace, or an else statement, check that this line is indented $indent + # more steps, if not a cpp line + if(!$prevp && ($prevl =~ /^( *)((if|while|for)\(.*\{|else)\z/)) { + my $first = length($1); + # this line has some character besides spaces + if($l =~ /^( *)[^ ]/) { + my $second = length($1); + my $expect = $first+$indent; + if($expect != $second) { + my $diff = $second - $first; + checkwarn("INDENTATION", $line, length($1), $file, $ol, + "not indented $indent steps (uses $diff)"); + + } + } + } + + # if the previous line starts with if/while/for AND ends with a closed + # parenthesis and there's an equal number of open and closed + # parentheses, check that this line is indented $indent more steps, if + # not a cpp line + elsif(!$prevp && ($prevl =~ /^( *)(if|while|for)(\(.*\))\z/)) { + my $first = length($1); + my $op = $3; + my $cl = $3; + + $op =~ s/[^(]//g; + $cl =~ s/[^)]//g; + + if(length($op) == length($cl)) { + # this line has some character besides spaces + if($l =~ /^( *)[^ ]/) { + my $second = length($1); + my $expect = $first+$indent; + if($expect != $second) { + my $diff = $second - $first; + checkwarn("INDENTATION", $line, length($1), $file, $ol, + "not indented $indent steps (uses $diff)"); + } + } + } + } + + # check for 'char * name' + if(($l =~ /(^.*(char|int|long|void|CURL|CURLM|CURLMsg|[cC]url_[A-Za-z_]+|struct [a-zA-Z_]+) *(\*+)) (\w+)/) && ($4 !~ /^(const|volatile)$/)) { + checkwarn("ASTERISKSPACE", + $line, length($1), $file, $ol, + "space after declarative asterisk"); + } + # check for 'char*' + if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost|sockaddr_in|FILE)\*)/)) { + checkwarn("ASTERISKNOSPACE", + $line, length($1)-1, $file, $ol, + "no space before asterisk"); + } + + # check for 'void func() {', but avoid false positives by requiring + # both an open and closed parentheses before the open brace + if($l =~ /^((\w).*)\{\z/) { + my $k = $1; + $k =~ s/const *//; + $k =~ s/static *//; + if($k =~ /\(.*\)/) { + checkwarn("BRACEPOS", + $line, length($l)-1, $file, $ol, + "wrongly placed open brace"); + } + } + + # check for equals sign without spaces next to it + if($nostr =~ /(.*)\=[a-z0-9]/i) { + checkwarn("EQUALSNOSPACE", + $line, length($1)+1, $file, $ol, + "no space after equals sign"); + } + # check for equals sign without spaces before it + elsif($nostr =~ /(.*)[a-z0-9]\=/i) { + checkwarn("NOSPACEEQUALS", + $line, length($1)+1, $file, $ol, + "no space before equals sign"); + } + + # check for plus signs without spaces next to it + if($nostr =~ /(.*)[^+]\+[a-z0-9]/i) { + checkwarn("PLUSNOSPACE", + $line, length($1)+1, $file, $ol, + "no space after plus sign"); + } + # check for plus sign without spaces before it + elsif($nostr =~ /(.*)[a-z0-9]\+[^+]/i) { + checkwarn("NOSPACEPLUS", + $line, length($1)+1, $file, $ol, + "no space before plus sign"); + } + + # check for semicolons without space next to it + if($nostr =~ /(.*)\;[a-z0-9]/i) { + checkwarn("SEMINOSPACE", + $line, length($1)+1, $file, $ol, + "no space after semicolon"); + } + + # typedef struct ... { + if($nostr =~ /^(.*)typedef struct.*{/) { + checkwarn("TYPEDEFSTRUCT", + $line, length($1)+1, $file, $ol, + "typedef'ed struct"); + } + + if($nostr =~ /(.*)! +(\w|\()/) { + checkwarn("EXCLAMATIONSPACE", + $line, length($1)+1, $file, $ol, + "space after exclamation mark"); + } + + # check for more than one consecutive space before open brace or + # question mark. Skip lines containing strings since they make it hard + # due to artificially getting multiple spaces + if(($l eq $nostr) && + $nostr =~ /^(.*(\S)) + [{?]/i) { + checkwarn("MULTISPACE", + $line, length($1)+1, $file, $ol, + "multiple spaces"); + } + preproc: + if($prep) { + # scan for use of banned symbols on a preprocessor line + if($l =~ /^(^|.*\W) + (WIN32) + (\W|$) + /x) { + checkwarn("BANNEDPREPROC", + $line, length($1), $file, $ol, + "use of $2 is banned from preprocessor lines" . + (($2 eq "WIN32") ? ", use _WIN32 instead" : "")); + } + } + $line++; + $prevp = $prep; + $prevl = $ol if(!$prep); + $prevpl = $ol if($prep); + } + + if(!scalar(@copyright)) { + checkwarn("COPYRIGHT", 1, 0, $file, "", "Missing copyright statement", 1); + } + + # COPYRIGHTYEAR is a extended warning so we must first see if it has been + # enabled in .checksrc + if(defined($warnings{"COPYRIGHTYEAR"})) { + # The check for updated copyrightyear is overly complicated in order to + # not punish current hacking for past sins. The copyright years are + # right now a bit behind, so enforcing copyright year checking on all + # files would cause hundreds of errors. Instead we only look at files + # which are tracked in the Git repo and edited in the workdir, or + # committed locally on the branch without being in upstream master. + # + # The simple and naive test is to simply check for the current year, + # but updating the year even without an edit is against project policy + # (and it would fail every file on January 1st). + # + # A rather more interesting, and correct, check would be to not test + # only locally committed files but inspect all files wrt the year of + # their last commit. Removing the `git rev-list origin/master..HEAD` + # condition below will enforce copyright year checks against the year + # the file was last committed (and thus edited to some degree). + my $commityear = undef; + @copyright = sort {$$b{year} cmp $$a{year}} @copyright; + + # if the file is modified, assume commit year this year + if(`git status -s -- "$file"` =~ /^ [MARCU]/) { + $commityear = (localtime(time))[5] + 1900; + } + else { + # min-parents=1 to ignore wrong initial commit in truncated repos + my $grl = `git rev-list --max-count=1 --min-parents=1 --timestamp HEAD -- "$file"`; + if($grl) { + chomp $grl; + $commityear = (localtime((split(/ /, $grl))[0]))[5] + 1900; + } + } + + if(defined($commityear) && scalar(@copyright) && + $copyright[0]{year} != $commityear) { + checkwarn("COPYRIGHTYEAR", $copyright[0]{line}, $copyright[0]{col}, + $file, $copyright[0]{code}, + "Copyright year out of date, should be $commityear, " . + "is $copyright[0]{year}", 1); + } + } + + if($incomment) { + checkwarn("OPENCOMMENT", 1, 0, $file, "", "Missing closing comment", 1); + } + + checksrc_endoffile($file); + + close($R); + +} + + +if($errors || $warnings || $verbose) { + printf "checksrc: %d errors and %d warnings\n", $errors, $warnings; + if($suppressed) { + printf "checksrc: %d errors and %d warnings suppressed\n", + $serrors, + $swarnings; + } + exit 5; # return failure +} diff --git a/scripts/completion.pl b/scripts/completion.pl new file mode 100755 index 0000000..00c7368 --- /dev/null +++ b/scripts/completion.pl @@ -0,0 +1,166 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +use strict; +use warnings; +use Getopt::Long(); +use Pod::Usage(); + +my $curl = 'curl'; +my $shell = 'zsh'; +my $help = 0; +Getopt::Long::GetOptions( + 'curl=s' => \$curl, + 'shell=s' => \$shell, + 'help' => \$help, +) or Pod::Usage::pod2usage(); +Pod::Usage::pod2usage() if $help; + +my $regex = '\s+(?:(-[^\s]+),\s)?(--[^\s]+)\s*(\<.+?\>)?\s+(.*)'; +my @opts = parse_main_opts('--help all', $regex); + +if ($shell eq 'fish') { + print "# curl fish completion\n\n"; + print qq{$_ \n} foreach (@opts); +} elsif ($shell eq 'zsh') { + my $opts_str; + + $opts_str .= qq{ $_ \\\n} foreach (@opts); + chomp $opts_str; + +my $tmpl = <<"EOS"; +#compdef curl + +# curl zsh completion + +local curcontext="\$curcontext" state state_descr line +typeset -A opt_args + +local rc=1 + +_arguments -C -S \\ +$opts_str + '*:URL:_urls' && rc=0 + +return rc +EOS + + print $tmpl; +} else { + die("Unsupported shell: $shell"); +} + +sub parse_main_opts { + my ($cmd, $regex) = @_; + + my @list; + my @lines = call_curl($cmd); + + foreach my $line (@lines) { + my ($short, $long, $arg, $desc) = ($line =~ /^$regex/) or next; + + my $option = ''; + + $arg =~ s/\:/\\\:/g if defined $arg; + + $desc =~ s/'/'\\''/g if defined $desc; + $desc =~ s/\[/\\\[/g if defined $desc; + $desc =~ s/\]/\\\]/g if defined $desc; + $desc =~ s/\:/\\\:/g if defined $desc; + + if ($shell eq 'fish') { + $option .= "complete --command curl"; + $option .= " --short-option '" . strip_dash(trim($short)) . "'" + if defined $short; + $option .= " --long-option '" . strip_dash(trim($long)) . "'" + if defined $long; + $option .= " --description '" . strip_dash(trim($desc)) . "'" + if defined $desc; + } elsif ($shell eq 'zsh') { + $option .= '{' . trim($short) . ',' if defined $short; + $option .= trim($long) if defined $long; + $option .= '}' if defined $short; + $option .= '\'[' . trim($desc) . ']\'' if defined $desc; + + if (defined $arg) { + $option .= ":'$arg'"; + if ($arg =~ /|/) { + $option .= ':_files'; + } elsif ($arg =~ //) { + $option .= ":'_path_files -/'"; + } elsif ($arg =~ //i) { + $option .= ':_urls'; + } elsif ($long =~ /ftp/ && $arg =~ //) { + $option .= ":'(multicwd nocwd singlecwd)'"; + } elsif ($arg =~ //) { + $option .= ":'(DELETE GET HEAD POST PUT)'"; + } + } + } + + push @list, $option; + } + + # Sort longest first, because zsh won't complete an option listed + # after one that's a prefix of it. + @list = sort { + $a =~ /([^=]*)/; my $ma = $1; + $b =~ /([^=]*)/; my $mb = $1; + + length($mb) <=> length($ma) + } @list if $shell eq 'zsh'; + + return @list; +} + +sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s }; +sub strip_dash { my $s = shift; $s =~ s/^-+//g; return $s }; + +sub call_curl { + my ($cmd) = @_; + my $output = `"$curl" $cmd`; + if ($? == -1) { + die "Could not run curl: $!"; + } elsif ((my $exit_code = $? >> 8) != 0) { + die "curl returned $exit_code with output:\n$output"; + } + return split /\n/, $output; +} + +__END__ + +=head1 NAME + +completion.pl - Generates tab-completion files for various shells + +=head1 SYNOPSIS + +completion.pl [options...] + + --curl path to curl executable + --shell zsh/fish + --help prints this help + +=cut diff --git a/scripts/coverage.sh b/scripts/coverage.sh new file mode 100755 index 0000000..0a7c782 --- /dev/null +++ b/scripts/coverage.sh @@ -0,0 +1,39 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +autoreconf -fi +mkdir -p cvr +cd cvr +../configure --disable-shared --enable-debug --enable-maintainer-mode --enable-code-coverage +make -sj +# the regular test run +make TFLAGS=-n test-nonflaky +# make all allocs/file operations fail +#make TFLAGS=-n test-torture +# do everything event-based +make TFLAGS=-n test-event +lcov -d . -c -o cov.lcov +genhtml cov.lcov --output-directory coverage --title "curl code coverage" +tar -cjf curl-coverage.tar.bz2 coverage diff --git a/scripts/firefox-db2pem.sh b/scripts/firefox-db2pem.sh new file mode 100755 index 0000000..f78f415 --- /dev/null +++ b/scripts/firefox-db2pem.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# *************************************************************************** +# * _ _ ____ _ +# * Project ___| | | | _ \| | +# * / __| | | | |_) | | +# * | (__| |_| | _ <| |___ +# * \___|\___/|_| \_\_____| +# * +# * Copyright (C) Daniel Stenberg, , et al. +# * +# * This software is licensed as described in the file COPYING, which +# * you should have received as part of this distribution. The terms +# * are also available at https://curl.se/docs/copyright.html. +# * +# * You may opt to use, copy, modify, merge, publish, distribute and/or sell +# * copies of the Software, and permit persons to whom the Software is +# * furnished to do so, under the terms of the COPYING file. +# * +# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# * KIND, either express or implied. +# * +# * SPDX-License-Identifier: curl +# * +# *************************************************************************** +# This shell script creates a fresh ca-bundle.crt file for use with libcurl. +# It extracts all ca certs it finds in the local Firefox database and converts +# them all into PEM format. +# +db=$(ls -1d $HOME/.mozilla/firefox/*default*) +out=$1 + +if test -z "$out"; then + out="ca-bundle.crt" # use a sensible default +fi + +currentdate=$(date) + +cat >$out <> $out diff --git a/scripts/mk-ca-bundle.pl b/scripts/mk-ca-bundle.pl new file mode 100755 index 0000000..83027a4 --- /dev/null +++ b/scripts/mk-ca-bundle.pl @@ -0,0 +1,713 @@ +#!/usr/bin/env perl +# *************************************************************************** +# * _ _ ____ _ +# * Project ___| | | | _ \| | +# * / __| | | | |_) | | +# * | (__| |_| | _ <| |___ +# * \___|\___/|_| \_\_____| +# * +# * Copyright (C) Daniel Stenberg, , et al. +# * +# * This software is licensed as described in the file COPYING, which +# * you should have received as part of this distribution. The terms +# * are also available at https://curl.se/docs/copyright.html. +# * +# * You may opt to use, copy, modify, merge, publish, distribute and/or sell +# * copies of the Software, and permit persons to whom the Software is +# * furnished to do so, under the terms of the COPYING file. +# * +# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# * KIND, either express or implied. +# * +# * SPDX-License-Identifier: curl +# * +# *************************************************************************** +# This Perl script creates a fresh ca-bundle.crt file for use with libcurl. +# It downloads certdata.txt from Mozilla's source tree (see URL below), +# then parses certdata.txt and extracts CA Root Certificates into PEM format. +# These are then processed with the OpenSSL commandline tool to produce the +# final ca-bundle.crt file. +# The script is based on the parse-certs script written by Roland Krikava. +# This Perl script works on almost any platform since its only external +# dependency is the OpenSSL commandline tool for optional text listing. +# Hacked by Guenter Knauf. +# +use Encode; +use Getopt::Std; +use MIME::Base64; +use strict; +use warnings; +use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); +use List::Util; +use Text::Wrap; +use Time::Local; +my $MOD_SHA = "Digest::SHA"; +eval "require $MOD_SHA"; +if ($@) { + $MOD_SHA = "Digest::SHA::PurePerl"; + eval "require $MOD_SHA"; +} +eval "require LWP::UserAgent"; + +my %urls = ( + 'nss' => + 'https://hg.mozilla.org/projects/nss/raw-file/default/lib/ckfw/builtins/certdata.txt', + 'central' => + 'https://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'beta' => + 'https://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'release' => + 'https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', +); + +$opt_d = 'release'; + +# If the OpenSSL commandline is not in search path you can configure it here! +my $openssl = 'openssl'; + +my $version = '1.29'; + +$opt_w = 76; # default base64 encoded lines length + +# default cert types to include in the output (default is to include CAs which +# may issue SSL server certs) +my $default_mozilla_trust_purposes = "SERVER_AUTH"; +my $default_mozilla_trust_levels = "TRUSTED_DELEGATOR"; +$opt_p = $default_mozilla_trust_purposes . ":" . $default_mozilla_trust_levels; + +my @valid_mozilla_trust_purposes = ( + "DIGITAL_SIGNATURE", + "NON_REPUDIATION", + "KEY_ENCIPHERMENT", + "DATA_ENCIPHERMENT", + "KEY_AGREEMENT", + "KEY_CERT_SIGN", + "CRL_SIGN", + "SERVER_AUTH", + "CLIENT_AUTH", + "CODE_SIGNING", + "EMAIL_PROTECTION", + "IPSEC_END_SYSTEM", + "IPSEC_TUNNEL", + "IPSEC_USER", + "TIME_STAMPING", + "STEP_UP_APPROVED" +); + +my @valid_mozilla_trust_levels = ( + "TRUSTED_DELEGATOR", # CAs + "NOT_TRUSTED", # Don't trust these certs. + "MUST_VERIFY_TRUST", # This explicitly tells us that it ISN'T a CA but is + # otherwise ok. In other words, this should tell the + # app to ignore any other sources that claim this is + # a CA. + "TRUSTED" # This cert is trusted, but only for itself and not + # for delegates (i.e. it is not a CA). +); + +my $default_signature_algorithms = $opt_s = "MD5"; + +my @valid_signature_algorithms = ( + "MD5", + "SHA1", + "SHA256", + "SHA384", + "SHA512" +); + +$0 =~ s@.*(/|\\)@@; +$Getopt::Std::STANDARD_HELP_VERSION = 1; +getopts('bd:fhiklmnp:qs:tuvw:'); + +if(!defined($opt_d)) { + # to make plain "-d" use not cause warnings, and actually still work + $opt_d = 'release'; +} + +# Use predefined URL or else custom URL specified on command line. +my $url; +if(defined($urls{$opt_d})) { + $url = $urls{$opt_d}; + if(!$opt_k && $url !~ /^https:\/\//i) { + die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n"; + } +} +else { + $url = $opt_d; +} + +my $curl = `curl -V`; + +if ($opt_i) { + print ("=" x 78 . "\n"); + print "Script Version : $version\n"; + print "Perl Version : $]\n"; + print "Operating System Name : $^O\n"; + print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; + print "Encode::Encoding.pm Version : ${Encode::Encoding::VERSION}\n"; + print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; + print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n" if($LWP::UserAgent::VERSION); + print "LWP.pm Version : ${LWP::VERSION}\n" if($LWP::VERSION); + print "Digest::SHA.pm Version : ${Digest::SHA::VERSION}\n" if ($Digest::SHA::VERSION); + print "Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION}\n" if ($Digest::SHA::PurePerl::VERSION); + print ("=" x 78 . "\n"); +} + +sub warning_message() { + if ( $opt_d =~ m/^risk$/i ) { # Long Form Warning and Exit + print "Warning: Use of this script may pose some risk:\n"; + print "\n"; + print " 1) If you use HTTP URLs they are subject to a man in the middle attack\n"; + print " 2) Default to 'release', but more recent updates may be found in other trees\n"; + print " 3) certdata.txt file format may change, lag time to update this script\n"; + print " 4) Generally unwise to blindly trust CAs without manual review & verification\n"; + print " 5) Mozilla apps use additional security checks aren't represented in certdata\n"; + print " 6) Use of this script will make a security engineer grind his teeth and\n"; + print " swear at you. ;)\n"; + exit; + } else { # Short Form Warning + print "Warning: Use of this script may pose some risk, -d risk for more details.\n"; + } +} + +sub HELP_MESSAGE() { + print "Usage:\t${0} [-b] [-d] [-f] [-i] [-k] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; + print "\t-b\tbackup an existing version of ca-bundle.crt\n"; + print "\t-d\tspecify Mozilla tree to pull certdata.txt or custom URL\n"; + print "\t\t Valid names are:\n"; + print "\t\t ", join( ", ", map { ( $_ =~ m/$opt_d/ ) ? "$_ (default)" : "$_" } sort keys %urls ), "\n"; + print "\t-f\tforce rebuild even if certdata.txt is current\n"; + print "\t-i\tprint version info about used modules\n"; + print "\t-k\tallow URLs other than HTTPS, enable HTTP fallback (insecure)\n"; + print "\t-l\tprint license info about certdata.txt\n"; + print "\t-m\tinclude meta data in output\n"; + print "\t-n\tno download of certdata.txt (to use existing)\n"; + print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; + print "\t\t Valid purposes are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_purposes ) ), "\n"; + print "\t\t Valid levels are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_levels ) ), "\n"; + print "\t-q\tbe really quiet (no progress output at all)\n"; + print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); + print "\t\t Valid signature algorithms are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_signature_algorithms ) ), "\n"; + print "\t-t\tinclude plain text listing of certificates\n"; + print "\t-u\tunlink (remove) certdata.txt after processing\n"; + print "\t-v\tbe verbose and print out processed CAs\n"; + print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; + exit; +} + +sub VERSION_MESSAGE() { + print "${0} version ${version} running Perl ${]} on ${^O}\n"; +} + +warning_message() unless ($opt_q || $url =~ m/^(ht|f)tps:/i ); +HELP_MESSAGE() if ($opt_h); + +sub report($@) { + my $output = shift; + + print STDERR $output . "\n" unless $opt_q; +} + +sub is_in_list($@) { + my $target = shift; + + return defined(List::Util::first { $target eq $_ } @_); +} + +# Parses $param_string as a case insensitive comma separated list with optional +# whitespace validates that only allowed parameters are supplied +sub parse_csv_param($$@) { + my $description = shift; + my $param_string = shift; + my @valid_values = @_; + + my @values = map { + s/^\s+//; # strip leading spaces + s/\s+$//; # strip trailing spaces + uc $_ # return the modified string as upper case + } split( ',', $param_string ); + + # Find all values which are not in the list of valid values or "ALL" + my @invalid = grep { !is_in_list($_,"ALL",@valid_values) } @values; + + if ( scalar(@invalid) > 0 ) { + # Tell the user which parameters were invalid and print the standard help + # message which will exit + print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join( ", ", map { "\"$_\"" } @invalid ), "\n"; + HELP_MESSAGE(); + } + + @values = @valid_values if ( is_in_list("ALL",@values) ); + + return @values; +} + +sub sha256 { + my $result; + if ($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION) { + open(FILE, $_[0]) or die "Can't open '$_[0]': $!"; + binmode(FILE); + $result = $MOD_SHA->new(256)->addfile(*FILE)->hexdigest; + close(FILE); + } else { + # Use OpenSSL command if Perl Digest::SHA modules not available + $result = `"$openssl" dgst -r -sha256 "$_[0]"`; + $result =~ s/^([0-9a-f]{64}) .+/$1/is; + } + return $result; +} + + +sub oldhash { + my $hash = ""; + open(C, "<$_[0]") || return 0; + while() { + chomp; + if($_ =~ /^\#\# SHA256: (.*)/) { + $hash = $1; + last; + } + } + close(C); + return $hash; +} + +if ( $opt_p !~ m/:/ ) { + print "Error: Mozilla trust identifier list must include both purposes and levels\n"; + HELP_MESSAGE(); +} + +(my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split( ':', $opt_p ); +my @included_mozilla_trust_purposes = parse_csv_param( "trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes ); +my @included_mozilla_trust_levels = parse_csv_param( "trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels ); + +my @included_signature_algorithms = parse_csv_param( "signature algorithm", $opt_s, @valid_signature_algorithms ); + +sub should_output_cert(%) { + my %trust_purposes_by_level = @_; + + foreach my $level (@included_mozilla_trust_levels) { + # for each level we want to output, see if any of our desired purposes are + # included + return 1 if ( defined( List::Util::first { is_in_list( $_, @included_mozilla_trust_purposes ) } @{$trust_purposes_by_level{$level}} ) ); + } + + return 0; +} + +my $crt = $ARGV[0] || 'ca-bundle.crt'; +(my $txt = $url) =~ s@(.*/|\?.*)@@g; + +my $stdout = $crt eq '-'; +my $resp; +my $fetched; + +my $oldhash = oldhash($crt); + +report "SHA256 of old file: $oldhash"; + +if(!$opt_n) { + report "Downloading $txt ..."; + + # If we have an HTTPS URL then use curl + if($url =~ /^https:\/\//i) { + if($curl) { + if($curl =~ /^Protocols:.* https( |$)/m) { + report "Get certdata with curl!"; + my $proto = !$opt_k ? "--proto =https" : ""; + my $quiet = $opt_q ? "-s" : ""; + my @out = `curl -w %{response_code} $proto $quiet -o "$txt" "$url"`; + if(!$? && @out && $out[0] == 200) { + $fetched = 1; + report "Downloaded $txt"; + } + else { + report "Failed downloading via HTTPS with curl"; + if(-e $txt && !unlink($txt)) { + report "Failed to remove '$txt': $!"; + } + } + } + else { + report "curl lacks https support"; + } + } + else { + report "curl not found"; + } + } + + # If nothing was fetched then use LWP + if(!$fetched) { + if($url =~ /^https:\/\//i) { + report "Falling back to HTTP"; + $url =~ s/^https:\/\//http:\/\//i; + } + if(!$opt_k) { + report "URLs other than HTTPS are disabled by default, to enable use -k"; + exit 1; + } + report "Get certdata with LWP!"; + if(!defined(${LWP::UserAgent::VERSION})) { + report "LWP is not available (LWP::UserAgent not found)"; + exit 1; + } + my $ua = new LWP::UserAgent(agent => "$0/$version"); + $ua->env_proxy(); + $resp = $ua->mirror($url, $txt); + if($resp && $resp->code eq '304') { + report "Not modified"; + exit 0 if -e $crt && !$opt_f; + } + else { + $fetched = 1; + report "Downloaded $txt"; + } + if(!$resp || $resp->code !~ /^(?:200|304)$/) { + report "Unable to download latest data: " + . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed"); + exit 1 if -e $crt || ! -r $txt; + } + } +} + +my $filedate = $resp ? $resp->last_modified : (stat($txt))[9]; +my $datesrc = "as of"; +if(!$filedate) { + # mxr.mozilla.org gave us a time, hg.mozilla.org does not! + $filedate = time(); + $datesrc="downloaded on"; +} + +# get the hash from the download file +my $newhash= sha256($txt); + +if(!$opt_f && $oldhash eq $newhash) { + report "Downloaded file identical to previous run\'s source file. Exiting"; + if($opt_u && -e $txt && !unlink($txt)) { + report "Failed to remove $txt: $!\n"; + } + exit; +} + +report "SHA256 of new file: $newhash"; + +my $currentdate = scalar gmtime($filedate); + +my $format = $opt_t ? "plain text and " : ""; +if( $stdout ) { + open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; +} else { + open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; +} +print CRT <) { + if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { + print CRT; + print if ($opt_l); + while () { + print CRT; + print if ($opt_l); + last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); + } + next; + } + # The input file format consists of blocks of Mozilla objects. + # The blocks are separated by blank lines but may be related. + elsif(/^\s*$/) { + $main_block = 0; + $trust_block = 0; + next; + } + # Each certificate has a main block. + elsif(/^# Certificate "(.*)"/) { + (!$main_block && !$trust_block) or die "Unexpected certificate block"; + $main_block = 1; + $main_block_name = $1; + # Reset all other certificate variables. + $trust_block = 0; + $trust_block_name = ""; + $valid = 0; + $start_of_cert = 0; + $caname = ""; + $cka_value = ""; + undef @precert; + next; + } + # Each certificate's main block is followed by a trust block. + elsif(/^# Trust for (?:Certificate )?"(.*)"/) { + (!$main_block && !$trust_block) or die "Unexpected trust block"; + $trust_block = 1; + $trust_block_name = $1; + if($main_block_name ne $trust_block_name) { + die "cert name \"$main_block_name\" != trust name \"$trust_block_name\""; + } + next; + } + # Ignore other blocks. + # + # There is a documentation comment block, a BEGINDATA block, and a bunch of + # blocks starting with "# Explicitly Distrust ". + # + # The latter is for certificates that have already been removed and are not + # included. Not all explicitly distrusted certificates are ignored at this + # point, just those without an actual certificate. + elsif(!$main_block && !$trust_block) { + next; + } + elsif(/^#/) { + # The commented lines in a main block are plaintext metadata that describes + # the certificate. Issuer, Subject, Fingerprint, etc. + if($main_block) { + push @precert, $_ if not /^#$/; + if(/^# Not Valid After : (.*)/) { + my $stamp = $1; + use Time::Piece; + # Not Valid After : Thu Sep 30 14:01:15 2021 + my $t = Time::Piece->strptime($stamp, "%a %b %d %H:%M:%S %Y"); + my $delta = ($t->epoch - time()); # negative means no longer valid + if($delta < 0) { + $skipnum++; + report "Skipping: $main_block_name is not valid anymore" if ($opt_v); + $valid = 0; + } + else { + $valid = 1; + } + } + } + next; + } + elsif(!$valid) { + next; + } + + chomp; + + if($main_block) { + if(/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { + !$start_of_cert or die "Duplicate CKO_CERTIFICATE object"; + $start_of_cert = 1; + next; + } + elsif(!$start_of_cert) { + next; + } + elsif(/^CKA_LABEL UTF8 \"(.*)\"/) { + ($caname eq "") or die "Duplicate CKA_LABEL attribute"; + $caname = $1; + if($caname ne $main_block_name) { + die "caname \"$caname\" != cert name \"$main_block_name\""; + } + next; + } + elsif(/^CKA_VALUE MULTILINE_OCTAL/) { + ($cka_value eq "") or die "Duplicate CKA_VALUE attribute"; + while () { + last if (/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for (@octets) { + $cka_value .= chr(oct); + } + } + next; + } + elsif (/^CKA_NSS_SERVER_DISTRUST_AFTER (CK_BBOOL CK_FALSE|MULTILINE_OCTAL)/) { + # Example: + # CKA_NSS_SERVER_DISTRUST_AFTER MULTILINE_OCTAL + # \062\060\060\066\061\067\060\060\060\060\060\060\132 + # END + if($1 eq "MULTILINE_OCTAL") { + my @timestamp; + while () { + last if (/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for (@octets) { + push @timestamp, chr(oct); + } + } + scalar(@timestamp) == 13 or die "Failed parsing timestamp"; + # A trailing Z in the timestamp signifies UTC + if($timestamp[12] ne "Z") { + report "distrust date stamp is not using UTC"; + } + # Example date: 200617000000Z + # Means 2020-06-17 00:00:00 UTC + my $distrustat = + timegm($timestamp[10] . $timestamp[11], # second + $timestamp[8] . $timestamp[9], # minute + $timestamp[6] . $timestamp[7], # hour + $timestamp[4] . $timestamp[5], # day + ($timestamp[2] . $timestamp[3]) - 1, # month + "20" . $timestamp[0] . $timestamp[1]); # year + if(time >= $distrustat) { + # not trusted anymore + $skipnum++; + report "Skipping: $main_block_name is not trusted anymore" if ($opt_v); + $valid = 0; + } + else { + # still trusted + } + } + next; + } + else { + next; + } + } + + if(!$trust_block || !$start_of_cert || $caname eq "" || $cka_value eq "") { + die "Certificate extraction failed"; + } + + my %trust_purposes_by_level; + + if(/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/) { + # now scan the trust part to determine how we should trust this cert + while () { + if(/^\s*$/) { + $trust_block = 0; + last; + } + if (/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { + if ( !is_in_list($1,@valid_mozilla_trust_purposes) ) { + report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } elsif ( !is_in_list($2,@valid_mozilla_trust_levels) ) { + report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } else { + push @{$trust_purposes_by_level{$2}}, $1; + } + } + } + + # Sanity check that an explicitly distrusted certificate only has trust + # purposes with a trust level of NOT_TRUSTED. + # + # Certificate objects that are explicitly distrusted are in a certificate + # block that starts # Certificate "Explicitly Distrust(ed) ", + # where "Explicitly Distrust(ed) " was prepended to the original cert name. + if($caname =~ /distrust/i || + $main_block_name =~ /distrust/i || + $trust_block_name =~ /distrust/i) { + my @levels = keys %trust_purposes_by_level; + if(scalar(@levels) != 1 || $levels[0] ne "NOT_TRUSTED") { + die "\"$caname\" must have all trust purposes at level NOT_TRUSTED."; + } + } + + if ( !should_output_cert(%trust_purposes_by_level) ) { + $skipnum ++; + report "Skipping: $caname lacks acceptable trust level" if ($opt_v); + } else { + my $encoded = MIME::Base64::encode_base64($cka_value, ''); + $encoded =~ s/(.{1,${opt_w}})/$1\n/g; + my $pem = "-----BEGIN CERTIFICATE-----\n" + . $encoded + . "-----END CERTIFICATE-----\n"; + print CRT "\n$caname\n"; + my $maxStringLength = length(decode('UTF-8', $caname, Encode::FB_CROAK | Encode::LEAVE_SRC)); + print CRT ("=" x $maxStringLength . "\n"); + if ($opt_t) { + foreach my $key (sort keys %trust_purposes_by_level) { + my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); + print CRT $string . "\n"; + } + } + if($opt_m) { + print CRT for @precert; + } + if (!$opt_t) { + print CRT $pem; + } else { + my $pipe = ""; + foreach my $hash (@included_signature_algorithms) { + $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + $pipe = "|$openssl x509 -text -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + report "Processed: $caname" if ($opt_v); + $certnum ++; + } + } +} +close(TXT) or die "Couldn't close $txt: $!\n"; +close(CRT) or die "Couldn't close $crt.~: $!\n"; +unless( $stdout ) { + if ($opt_b && -e $crt) { + my $bk = 1; + while (-e "$crt.~${bk}~") { + $bk++; + } + rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; + } elsif( -e $crt ) { + unlink( $crt ) or die "Failed to remove $crt: $!\n"; + } + rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; +} +if($opt_u && -e $txt && !unlink($txt)) { + report "Failed to remove $txt: $!\n"; +} +report "Done ($certnum CA certs processed, $skipnum skipped)."; diff --git a/scripts/nroff2cd b/scripts/nroff2cd new file mode 100755 index 0000000..500367f --- /dev/null +++ b/scripts/nroff2cd @@ -0,0 +1,193 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +=begin comment + +This script converts an nroff file to curldown + +Example: cd2nroff [options] > + +Note: when converting .nf sections, this tool does not know if the +section is code or just regular quotes. It then assumes and uses ~~~c +for code. + +=end comment +=cut + +my $nroff2cd = "0.1"; # to keep check + +sub single { + my ($f)=@_; + open(F, "<:crlf", "$f") || + return 1; + my $line; + my $title; + my $section; + my $source; + my @seealso; + my @desc; + my $header; # non-zero when TH is passed + my $quote = 0; # quote state + while() { + $line++; + my $d = $_; + if($_ =~ /^.\\\"/) { + # a comment we can ignore + next; + } + if(!$header) { + if($d =~ /.so (.*)/) { + # this is basically an include, so do that + my $f = $1; + # remove leading directory + $f =~ s/(.*?\/)//; + close(F); + open(F, "<:crlf", "$f") || return 1; + } + if($d =~ /^\.TH ([^ ]*) (\d) \"(.*?)\" ([^ \n]*)/) { + # header, this needs to be the first thing after leading comments + $title = $1; + $section = $2; + # date is $3 + $source = $4; + # if there are enclosing quotes around source, remove them + $source =~ s/[\"\'](.*)[\"\']\z/$1/; + $header = 1; + + print <, et al. +SPDX-License-Identifier: curl +Title: $title +Section: $section +Source: $source +HEAD + ; + } + next; + } + + if($quote) { + if($d =~ /^\.SH/) { + #end of quote without an .fi + $quote = 0; + push @desc, "~~~\n"; + } + elsif($d =~ /^\.fi/) { + #end of quote + $quote = 0; + push @desc, "~~~\n"; + next; + } + else { + # double-backslashes converted to single ones + $d =~ s/\\\\/\\/g; + push @desc, $d; + next; + } + } + if($d =~ /^\.SH (.*)/) { + my $word = $1; + # if there are enclosing quotes, remove them first + $word =~ s/[\"\'](.*)[\"\']\z/$1/; + if($word eq "SEE ALSO") { + # we just slurp up this section + next; + } + push @desc, "\n# $word\n\n"; + } + elsif($d =~ /^\.(RS|RE)/) { + # ignore these + } + elsif($d =~ /^\.IP (.*)/) { + my $word = $1; + # if there are enclosing quotes, remove them first + $word =~ s/[\"\'](.*)[\"\']\z/$1/; + push @desc, "\n## $word\n\n"; + } + elsif($d =~ /^\.IP/) { + # .IP with no text we just skip + } + elsif($d =~ /^\.BR (.*)/) { + # only used for SEE ALSO + my $word = $1; + # remove trailing comma + $word =~ s/,\z//; + + for my $s (split(/,/, $word)) { + # remove all double quotes + $s =~ s/\"//g; + # tream leading whitespace + $s =~ s/^ +//g; + push @seealso, $s; + } + } + elsif($d =~ /^\.I (.*)/) { + push @desc, "*$1*\n"; + } + elsif($d =~ /^\.B (.*)/) { + push @desc, "**$1**\n"; + } + elsif($d =~ /^\.nf/) { + push @desc, "~~~c\n"; + $quote = 1; + } + else { + # embolden + $d =~ s/\\fB(.*?)\\fP/**$1**/g; + # links to "curl.*()" are left bare since cd2nroff handles them + # specially + $d =~ s/\\fI(curl.*?\(3\))\\fP/$1/ig; + # emphasize + $d =~ s/\\fI(.*?)\\fP/*$1*/g; + # emphasize on a split line + $d =~ s/\\fI/*/g; + # bold on a split line + $d =~ s/\\fB/**/g; + # remove backslash amp + $d =~ s/\\&//g; + # remove backslashes + $d =~ s/\\//g; + # fix single quotes + $d =~ s/\(aq/'/g; + # fix double quotes + $d =~ s/\(dq/\"/g; + push @desc, $d; + } + } + close(F); + + print "See-also:\n"; + for my $s (sort @seealso) { + print " - $s\n" if($s); + } + print "---\n"; + print @desc; + + return !$header; +} + +exit single($ARGV[0]); + diff --git a/scripts/schemetable.c b/scripts/schemetable.c new file mode 100644 index 0000000..ae79eaa --- /dev/null +++ b/scripts/schemetable.c @@ -0,0 +1,207 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include +#include + +/* + * Use this tool to generate an updated table for the Curl_getn_scheme_handler + * function in url.c. + */ + +struct detail { + const char *n; + const char *ifdef; +}; + +static const struct detail scheme[] = { + {"dict", "#ifndef CURL_DISABLE_DICT" }, + {"file", "#ifndef CURL_DISABLE_FILE" }, + {"ftp", "#ifndef CURL_DISABLE_FTP" }, + {"ftps", "#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)" }, + {"gopher", "#ifndef CURL_DISABLE_GOPHER" }, + {"gophers", "#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)" }, + {"http", "#ifndef CURL_DISABLE_HTTP" }, + {"https", "#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)" }, + {"imap", "#ifndef CURL_DISABLE_IMAP" }, + {"imaps", "#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)" }, + {"ldap", "#ifndef CURL_DISABLE_LDAP" }, + {"ldaps", "#if !defined(CURL_DISABLE_LDAP) && \\\n" + " !defined(CURL_DISABLE_LDAPS) && \\\n" + " ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \\\n" + " (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))" }, + {"mqtt", "#ifndef CURL_DISABLE_MQTT" }, + {"pop3", "#ifndef CURL_DISABLE_POP3" }, + {"pop3s", "#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)" }, + {"rtmp", "#ifdef USE_LIBRTMP" }, + {"rtmpt", "#ifdef USE_LIBRTMP" }, + {"rtmpe", "#ifdef USE_LIBRTMP" }, + {"rtmpte", "#ifdef USE_LIBRTMP" }, + {"rtmps", "#ifdef USE_LIBRTMP" }, + {"rtmpts", "#ifdef USE_LIBRTMP" }, + {"rtsp", "#ifndef CURL_DISABLE_RTSP" }, + {"scp", "#if defined(USE_SSH) && !defined(USE_WOLFSSH)" }, + {"sftp", "#if defined(USE_SSH)" }, + {"smb", "#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \\\n" + " (SIZEOF_CURL_OFF_T > 4)" }, + {"smbs", "#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \\\n" + " defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)" }, + {"smtp", "#ifndef CURL_DISABLE_SMTP" }, + {"smtps", "#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)" }, + {"telnet", "#ifndef CURL_DISABLE_TELNET" }, + {"tftp", "#ifndef CURL_DISABLE_TFTP" }, + {"ws", "#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)" }, + {"wss", "#if defined(USE_WEBSOCKETS) && \\\n" + " defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)" }, + { NULL, NULL } +}; + +unsigned int calc(const char *s, int add, int shift) +{ + const char *so = s; + unsigned int c = add; + while(*s) { + c <<= shift; + c += *s; + s++; + } + return c; +} + +unsigned int num[100]; +unsigned int ix[100]; + +static void showtable(int try, int init, int shift) +{ + int nulls = 0; + int i; + for(i = 0; scheme[i].n; ++i) + num[i] = calc(scheme[i].n, init, shift); + for(i = 0; scheme[i].n; ++i) + ix[i] = num[i] % try; + printf("/*\n" + " unsigned int c = %d\n" + " while(l) {\n" + " c <<= %d;\n" + " c += Curl_raw_tolower(*s);\n" + " s++;\n" + " l--;\n" + " }\n" + "*/\n", init, shift); + + printf(" static const struct Curl_handler * const protocols[%d] = {", try); + + /* generate table */ + for(i=0; i < try; i++) { + int match = 0; + int j; + for(j=0; scheme[j].n; j++) { + if(ix[j] == i) { + printf("\n"); + printf("%s\n", scheme[j].ifdef); + printf(" &Curl_handler_%s,\n", scheme[j].n); + printf("#else\n NULL,\n"); + printf("#endif"); + match = 1; + nulls = 0; + break; + } + } + if(!match) { + if(!nulls || (nulls>10)) { + printf("\n "); + nulls = 0; + } + printf(" NULL,", nulls); + nulls++; + } + } + printf("\n };\n"); +} + +int main(void) +{ + int i; + int try; + int besttry = 9999; + int bestadd = 0; + int bestshift = 0; + int add; + int shift; + for(shift = 0; shift < 8; shift++) { + for(add = 0; add < 999; add++) { + for(i = 0; scheme[i].n; ++i) { + unsigned int v = calc(scheme[i].n, add, shift); + int j; + int badcombo = 0; + for(j=0; j < i; j++) { + + if(num[j] == v) { + /* + printf("NOPE: %u is a dupe (%s and %s)\n", + v, scheme[i], scheme[j]); + */ + badcombo = 1; + break; + } + } + if(badcombo) + break; + num[i] = v; + } +#if 0 + for(i = 0; scheme[i].n; ++i) { + printf("%u - %s\n", num[i], scheme[i].n); + } +#endif + /* try different remainders to find smallest possible table */ + for(try = 28; try < 199; try++) { + int good = 1; + for(i = 0; scheme[i].n; ++i) { + ix[i] = num[i] % try; + } + /* check for dupes */ + for(i = 0; scheme[i].n && good; ++i) { + int j; + for(j=0; j < i; j++) { + if(ix[j] == ix[i]) { + /* printf("NOPE, try %u causes dupes (%d and %d)\n", try, j, i); */ + good = 0; + break; + } + } + } + if(good) { + if(try < besttry) { + besttry = try; + bestadd = add; + bestshift = shift; + } + break; + } + } + } + } + + showtable(besttry, bestadd, bestshift); +} diff --git a/src/.checksrc b/src/.checksrc new file mode 100644 index 0000000..946367c --- /dev/null +++ b/src/.checksrc @@ -0,0 +1 @@ +enable STDERR diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..5695670 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,134 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +set(EXE_NAME curl) +add_definitions(-DBUILDING_CURL) + +if(ENABLE_CURL_MANUAL AND HAVE_MANUAL_TOOLS) + add_definitions("-DUSE_MANUAL") + # Use the C locale to ensure that only ASCII characters appear in the + # embedded text. NROFF and MANOPT are set in the parent CMakeLists.txt + add_custom_command( + OUTPUT tool_hugehelp.c + COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_setup.h\"" > tool_hugehelp.c + COMMAND ${CMAKE_COMMAND} -E echo "#ifndef HAVE_LIBZ" >> tool_hugehelp.c + COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT} + "${CURL_BINARY_DIR}/docs/curl.1" | + "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" >> tool_hugehelp.c + COMMAND ${CMAKE_COMMAND} -E echo "#else" >> tool_hugehelp.c + COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT} + "${CURL_BINARY_DIR}/docs/curl.1" | + "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" -c >> tool_hugehelp.c + COMMAND ${CMAKE_COMMAND} -E echo "#endif /* HAVE_LIBZ */" >> tool_hugehelp.c + DEPENDS + generate-curl.1 + "${CURL_BINARY_DIR}/docs/curl.1" + "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" + "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h" + VERBATIM) +else() + add_custom_command( + OUTPUT tool_hugehelp.c + COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_hugehelp.h\"" > tool_hugehelp.c + DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h" + VERBATIM) + +endif() + +transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) + +if(WIN32) + list(APPEND CURL_CFILES curl.rc) +endif() + +# CURL_CFILES, CURLX_CFILES, CURL_HFILES, CURLTOOL_LIBCURL_CFILES +# come from Makefile.inc +if(BUILD_STATIC_CURL) + set(CURLX_CFILES ${CURLTOOL_LIBCURL_CFILES}) +endif() + +if(ENABLE_CURLDEBUG) + # We must compile this source separately to avoid memdebug.h redefinitions + # applying to them. + set_source_files_properties(../lib/curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) +endif() + +add_executable( + ${EXE_NAME} + ${CURL_CFILES} ${CURLX_CFILES} ${CURL_HFILES} + ) + +add_executable( + ${PROJECT_NAME}::${EXE_NAME} + ALIAS ${EXE_NAME} + ) + +add_library( + curltool # special libcurltool library just for unittests + STATIC + EXCLUDE_FROM_ALL + ${CURL_CFILES} ${CURLTOOL_LIBCURL_CFILES} ${CURL_HFILES} +) +target_compile_definitions(curltool PUBLIC UNITTESTS CURL_STATICLIB) +target_link_libraries(curltool PRIVATE ${CURL_LIBS}) + +if(CURL_HAS_LTO) + set_target_properties(${EXE_NAME} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) +endif() + +if(ENABLE_UNICODE AND MINGW) + target_link_libraries(${EXE_NAME} -municode) +endif() + +source_group("curlX source files" FILES ${CURLX_CFILES}) +source_group("curl source files" FILES ${CURL_CFILES}) +source_group("curl header files" FILES ${CURL_HFILES}) + +include_directories( + ${CURL_SOURCE_DIR}/lib # To be able to reach "curl_setup_once.h" + ${CURL_BINARY_DIR}/lib # To be able to reach "curl_config.h" + ${CURL_BINARY_DIR}/include # To be able to reach "curl/curl.h" + # This is needed as tool_hugehelp.c is generated in the binary dir + ${CURL_SOURCE_DIR}/src # To be able to reach "tool_hugehelp.h" + ) + +#Build curl executable +target_link_libraries(${EXE_NAME} ${LIB_SELECTED_FOR_EXE} ${CURL_LIBS}) + +################################################################################ + +#SET_TARGET_PROPERTIES(${EXE_NAME} ARCHIVE_OUTPUT_DIRECTORY "blah blah blah") +#SET_TARGET_PROPERTIES(${EXE_NAME} RUNTIME_OUTPUT_DIRECTORY "blah blah blah") +#SET_TARGET_PROPERTIES(${EXE_NAME} LIBRARY_OUTPUT_DIRECTORY "blah blah blah") + +#INCLUDE(ModuleInstall OPTIONAL) + +install(TARGETS ${EXE_NAME} EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) +export(TARGETS ${EXE_NAME} + FILE ${PROJECT_BINARY_DIR}/curl-target.cmake + NAMESPACE ${PROJECT_NAME}:: +) diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..7a99c25 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,165 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +AUTOMAKE_OPTIONS = foreign nostdinc + +# remove targets if the command fails +.DELETE_ON_ERROR: + +# Specify our include paths here, and do it relative to $(top_srcdir) and +# $(top_builddir), to ensure that these paths which belong to the library +# being currently built and tested are searched before the library which +# might possibly already be installed in the system. +# +# $(top_srcdir)/include is for libcurl's external include files +# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file +# $(top_builddir)/src is for curl's generated src/curl_config.h file +# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files +# $(top_srcdir)/src is for curl's src/tool_setup.h and "curl-private" files + +AM_CPPFLAGS = -I$(top_srcdir)/include \ + -I$(top_builddir)/lib \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src + +bin_PROGRAMS = curl + +SUBDIRS = ../docs + +if USE_CPPFLAG_CURL_STATICLIB +AM_CPPFLAGS += -DCURL_STATICLIB +endif +AM_CPPFLAGS += -DBUILDING_CURL + +include Makefile.inc + +# CURL_FILES comes from Makefile.inc +curl_SOURCES = $(CURL_FILES) +if HAVE_WINDRES +curl_SOURCES += $(CURL_RCFILES) +$(CURL_RCFILES): tool_version.h +endif + +curl_LDFLAGS = $(AM_LDFLAGS) $(CURL_LDFLAGS_BIN) + +# This might hold -Werror +CFLAGS += @CURL_CFLAG_EXTRAS@ + +# Prevent LIBS from being used for all link targets +LIBS = $(BLANK_AT_MAKETIME) + +if USE_EXPLICIT_LIB_DEPS +curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ +else +curl_LDADD = $(top_builddir)/lib/libcurl.la @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ +endif + +# if unit tests are enabled, build a static library to link them with +if BUILD_UNITTESTS +noinst_LTLIBRARIES = libcurltool.la +libcurltool_la_CPPFLAGS = $(AM_CPPFLAGS) \ + -DCURL_STATICLIB -DUNITTESTS +libcurltool_la_CFLAGS = +libcurltool_la_LDFLAGS = -static $(LINKFLAGS) +libcurltool_la_SOURCES = $(CURL_FILES) +endif + +CLEANFILES = tool_hugehelp.c +# Use the C locale to ensure that only ASCII characters appear in the +# embedded text. +NROFF=env LC_ALL=C @NROFF@ @MANOPT@ 2>/dev/null # figured out by the configure script + +EXTRA_DIST = mkhelp.pl \ + Makefile.mk curl.rc Makefile.inc CMakeLists.txt .checksrc + +# Use absolute directory to disable VPATH +MANPAGE=$(abs_top_builddir)/docs/curl.1 +MKHELP=$(top_srcdir)/src/mkhelp.pl +HUGE=tool_hugehelp.c + +HUGECMD = $(HUGEIT_$(V)) +HUGEIT_0 = @echo " HUGE " $@; +HUGEIT_1 = +HUGEIT_ = $(HUGEIT_0) + +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) + +if USE_MANUAL +# Here are the stuff to create a built-in manual + +$(MANPAGE): + cd $(top_builddir)/docs && $(MAKE) + +if HAVE_LIBZ +# This generates the tool_hugehelp.c file in both uncompressed and +# compressed formats. +$(HUGE): $(MANPAGE) $(MKHELP) + $(HUGECMD) (echo '#include "tool_setup.h"' > $(HUGE); \ + echo '#ifndef HAVE_LIBZ' >> $(HUGE); \ + $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE); \ + echo '#else' >> $(HUGE); \ + $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) -c >> $(HUGE); \ + echo '#endif /* HAVE_LIBZ */' >> $(HUGE) ) +else # HAVE_LIBZ +# This generates the tool_hugehelp.c file uncompressed only +$(HUGE): $(MANPAGE) $(MKHELP) + $(HUGECMD)(echo '#include "tool_setup.h"' > $(HUGE); \ + $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE) ) +endif + +else # USE_MANUAL +# built-in manual has been disabled, make a blank file +$(HUGE): + echo '#include "tool_hugehelp.h"' >> $(HUGE) +endif + +# ignore tool_hugehelp.c since it is generated source code and it plays +# by slightly different rules! +checksrc: + $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \ + -W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch]) + +if CURLDEBUG +# for debug builds, we scan the sources on all regular make invokes +all-local: checksrc +endif + +# disable the tests that are mostly causing false positives +TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference + +TIDY:=clang-tidy + +tidy: + $(TIDY) $(CURL_CFILES) $(TIDYFLAGS) -- $(curl_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H + +listhelp: + (cd $(top_srcdir)/docs/cmdline-opts && make listhelp) + +if HAVE_WINDRES +.rc.o: + $(RC) -I$(top_srcdir)/include -DCURL_EMBED_MANIFEST $(RCFLAGS) -i $< -o $@ +endif diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..bf2ef68 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,2081 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# ./src/Makefile.inc +# Using the backslash as line continuation character might be problematic with +# some make flavours. If we ever want to change this in a portable manner then +# we should consider this idea : +# CSRC1 = file1.c file2.c file3.c +# CSRC2 = file4.c file5.c file6.c +# CSOURCES = $(CSRC1) $(CSRC2) + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = curl$(EXEEXT) +@USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_1 = -DCURL_STATICLIB +@HAVE_WINDRES_TRUE@am__append_2 = $(CURL_RCFILES) +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \ + $(top_srcdir)/m4/curl-bearssl.m4 \ + $(top_srcdir)/m4/curl-compilers.m4 \ + $(top_srcdir)/m4/curl-confopts.m4 \ + $(top_srcdir)/m4/curl-functions.m4 \ + $(top_srcdir)/m4/curl-gnutls.m4 \ + $(top_srcdir)/m4/curl-mbedtls.m4 \ + $(top_srcdir)/m4/curl-openssl.m4 \ + $(top_srcdir)/m4/curl-override.m4 \ + $(top_srcdir)/m4/curl-reentrant.m4 \ + $(top_srcdir)/m4/curl-rustls.m4 \ + $(top_srcdir)/m4/curl-schannel.m4 \ + $(top_srcdir)/m4/curl-sectransp.m4 \ + $(top_srcdir)/m4/curl-sysconfig.m4 \ + $(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/xc-am-iface.m4 \ + $(top_srcdir)/m4/xc-cc-check.m4 \ + $(top_srcdir)/m4/xc-lt-iface.m4 \ + $(top_srcdir)/m4/xc-translit.m4 \ + $(top_srcdir)/m4/xc-val-flgs.m4 \ + $(top_srcdir)/m4/zz40-xc-ovr.m4 \ + $(top_srcdir)/m4/zz50-xc-ovr.m4 \ + $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/curl_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +LTLIBRARIES = $(noinst_LTLIBRARIES) +libcurltool_la_LIBADD = +am__libcurltool_la_SOURCES_DIST = slist_wc.c tool_binmode.c \ + tool_bname.c tool_cb_dbg.c tool_cb_hdr.c tool_cb_prg.c \ + tool_cb_rea.c tool_cb_see.c tool_cb_wrt.c tool_cfgable.c \ + tool_dirhie.c tool_doswin.c tool_easysrc.c tool_filetime.c \ + tool_findfile.c tool_formparse.c tool_getparam.c \ + tool_getpass.c tool_help.c tool_helpers.c tool_hugehelp.c \ + tool_ipfs.c tool_libinfo.c tool_listhelp.c tool_main.c \ + tool_msgs.c tool_operate.c tool_operhlp.c tool_paramhlp.c \ + tool_parsecfg.c tool_progress.c tool_setopt.c tool_sleep.c \ + tool_stderr.c tool_strdup.c tool_urlglob.c tool_util.c \ + tool_vms.c tool_writeout.c tool_writeout_json.c tool_xattr.c \ + var.c ../lib/base64.c ../lib/curl_multibyte.c ../lib/dynbuf.c \ + ../lib/nonblock.c ../lib/strtoofft.c ../lib/timediff.c \ + ../lib/version_win32.c ../lib/warnless.c slist_wc.h \ + tool_binmode.h tool_bname.h tool_cb_dbg.h tool_cb_hdr.h \ + tool_cb_prg.h tool_cb_rea.h tool_cb_see.h tool_cb_wrt.h \ + tool_cfgable.h tool_dirhie.h tool_doswin.h tool_easysrc.h \ + tool_filetime.h tool_findfile.h tool_formparse.h \ + tool_getparam.h tool_getpass.h tool_help.h tool_helpers.h \ + tool_hugehelp.h tool_ipfs.h tool_libinfo.h tool_main.h \ + tool_msgs.h tool_operate.h tool_operhlp.h tool_paramhlp.h \ + tool_parsecfg.h tool_progress.h tool_sdecls.h tool_setopt.h \ + tool_setup.h tool_sleep.h tool_stderr.h tool_strdup.h \ + tool_urlglob.h tool_util.h tool_version.h tool_vms.h \ + tool_writeout.h tool_writeout_json.h tool_xattr.h var.h +am__objects_1 = libcurltool_la-slist_wc.lo \ + libcurltool_la-tool_binmode.lo libcurltool_la-tool_bname.lo \ + libcurltool_la-tool_cb_dbg.lo libcurltool_la-tool_cb_hdr.lo \ + libcurltool_la-tool_cb_prg.lo libcurltool_la-tool_cb_rea.lo \ + libcurltool_la-tool_cb_see.lo libcurltool_la-tool_cb_wrt.lo \ + libcurltool_la-tool_cfgable.lo libcurltool_la-tool_dirhie.lo \ + libcurltool_la-tool_doswin.lo libcurltool_la-tool_easysrc.lo \ + libcurltool_la-tool_filetime.lo \ + libcurltool_la-tool_findfile.lo \ + libcurltool_la-tool_formparse.lo \ + libcurltool_la-tool_getparam.lo libcurltool_la-tool_getpass.lo \ + libcurltool_la-tool_help.lo libcurltool_la-tool_helpers.lo \ + libcurltool_la-tool_hugehelp.lo libcurltool_la-tool_ipfs.lo \ + libcurltool_la-tool_libinfo.lo libcurltool_la-tool_listhelp.lo \ + libcurltool_la-tool_main.lo libcurltool_la-tool_msgs.lo \ + libcurltool_la-tool_operate.lo libcurltool_la-tool_operhlp.lo \ + libcurltool_la-tool_paramhlp.lo \ + libcurltool_la-tool_parsecfg.lo \ + libcurltool_la-tool_progress.lo libcurltool_la-tool_setopt.lo \ + libcurltool_la-tool_sleep.lo libcurltool_la-tool_stderr.lo \ + libcurltool_la-tool_strdup.lo libcurltool_la-tool_urlglob.lo \ + libcurltool_la-tool_util.lo libcurltool_la-tool_vms.lo \ + libcurltool_la-tool_writeout.lo \ + libcurltool_la-tool_writeout_json.lo \ + libcurltool_la-tool_xattr.lo libcurltool_la-var.lo +am__dirstamp = $(am__leading_dot)dirstamp +am__objects_2 = ../lib/libcurltool_la-base64.lo \ + ../lib/libcurltool_la-curl_multibyte.lo \ + ../lib/libcurltool_la-dynbuf.lo \ + ../lib/libcurltool_la-nonblock.lo \ + ../lib/libcurltool_la-strtoofft.lo \ + ../lib/libcurltool_la-timediff.lo \ + ../lib/libcurltool_la-version_win32.lo \ + ../lib/libcurltool_la-warnless.lo +am__objects_3 = +am__objects_4 = $(am__objects_1) $(am__objects_2) $(am__objects_3) +@BUILD_UNITTESTS_TRUE@am_libcurltool_la_OBJECTS = $(am__objects_4) +libcurltool_la_OBJECTS = $(am_libcurltool_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libcurltool_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libcurltool_la_CFLAGS) $(CFLAGS) $(libcurltool_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@BUILD_UNITTESTS_TRUE@am_libcurltool_la_rpath = +am__curl_SOURCES_DIST = slist_wc.c tool_binmode.c tool_bname.c \ + tool_cb_dbg.c tool_cb_hdr.c tool_cb_prg.c tool_cb_rea.c \ + tool_cb_see.c tool_cb_wrt.c tool_cfgable.c tool_dirhie.c \ + tool_doswin.c tool_easysrc.c tool_filetime.c tool_findfile.c \ + tool_formparse.c tool_getparam.c tool_getpass.c tool_help.c \ + tool_helpers.c tool_hugehelp.c tool_ipfs.c tool_libinfo.c \ + tool_listhelp.c tool_main.c tool_msgs.c tool_operate.c \ + tool_operhlp.c tool_paramhlp.c tool_parsecfg.c tool_progress.c \ + tool_setopt.c tool_sleep.c tool_stderr.c tool_strdup.c \ + tool_urlglob.c tool_util.c tool_vms.c tool_writeout.c \ + tool_writeout_json.c tool_xattr.c var.c ../lib/base64.c \ + ../lib/curl_multibyte.c ../lib/dynbuf.c ../lib/nonblock.c \ + ../lib/strtoofft.c ../lib/timediff.c ../lib/version_win32.c \ + ../lib/warnless.c slist_wc.h tool_binmode.h tool_bname.h \ + tool_cb_dbg.h tool_cb_hdr.h tool_cb_prg.h tool_cb_rea.h \ + tool_cb_see.h tool_cb_wrt.h tool_cfgable.h tool_dirhie.h \ + tool_doswin.h tool_easysrc.h tool_filetime.h tool_findfile.h \ + tool_formparse.h tool_getparam.h tool_getpass.h tool_help.h \ + tool_helpers.h tool_hugehelp.h tool_ipfs.h tool_libinfo.h \ + tool_main.h tool_msgs.h tool_operate.h tool_operhlp.h \ + tool_paramhlp.h tool_parsecfg.h tool_progress.h tool_sdecls.h \ + tool_setopt.h tool_setup.h tool_sleep.h tool_stderr.h \ + tool_strdup.h tool_urlglob.h tool_util.h tool_version.h \ + tool_vms.h tool_writeout.h tool_writeout_json.h tool_xattr.h \ + var.h curl.rc +am__objects_5 = slist_wc.$(OBJEXT) tool_binmode.$(OBJEXT) \ + tool_bname.$(OBJEXT) tool_cb_dbg.$(OBJEXT) \ + tool_cb_hdr.$(OBJEXT) tool_cb_prg.$(OBJEXT) \ + tool_cb_rea.$(OBJEXT) tool_cb_see.$(OBJEXT) \ + tool_cb_wrt.$(OBJEXT) tool_cfgable.$(OBJEXT) \ + tool_dirhie.$(OBJEXT) tool_doswin.$(OBJEXT) \ + tool_easysrc.$(OBJEXT) tool_filetime.$(OBJEXT) \ + tool_findfile.$(OBJEXT) tool_formparse.$(OBJEXT) \ + tool_getparam.$(OBJEXT) tool_getpass.$(OBJEXT) \ + tool_help.$(OBJEXT) tool_helpers.$(OBJEXT) \ + tool_hugehelp.$(OBJEXT) tool_ipfs.$(OBJEXT) \ + tool_libinfo.$(OBJEXT) tool_listhelp.$(OBJEXT) \ + tool_main.$(OBJEXT) tool_msgs.$(OBJEXT) tool_operate.$(OBJEXT) \ + tool_operhlp.$(OBJEXT) tool_paramhlp.$(OBJEXT) \ + tool_parsecfg.$(OBJEXT) tool_progress.$(OBJEXT) \ + tool_setopt.$(OBJEXT) tool_sleep.$(OBJEXT) \ + tool_stderr.$(OBJEXT) tool_strdup.$(OBJEXT) \ + tool_urlglob.$(OBJEXT) tool_util.$(OBJEXT) tool_vms.$(OBJEXT) \ + tool_writeout.$(OBJEXT) tool_writeout_json.$(OBJEXT) \ + tool_xattr.$(OBJEXT) var.$(OBJEXT) +am__objects_6 = ../lib/base64.$(OBJEXT) \ + ../lib/curl_multibyte.$(OBJEXT) ../lib/dynbuf.$(OBJEXT) \ + ../lib/nonblock.$(OBJEXT) ../lib/strtoofft.$(OBJEXT) \ + ../lib/timediff.$(OBJEXT) ../lib/version_win32.$(OBJEXT) \ + ../lib/warnless.$(OBJEXT) +am__objects_7 = $(am__objects_5) $(am__objects_6) $(am__objects_3) +am__objects_8 = curl.$(OBJEXT) +@HAVE_WINDRES_TRUE@am__objects_9 = $(am__objects_8) +am_curl_OBJECTS = $(am__objects_7) $(am__objects_9) +curl_OBJECTS = $(am_curl_OBJECTS) +@USE_EXPLICIT_LIB_DEPS_FALSE@curl_DEPENDENCIES = \ +@USE_EXPLICIT_LIB_DEPS_FALSE@ $(top_builddir)/lib/libcurl.la +@USE_EXPLICIT_LIB_DEPS_TRUE@curl_DEPENDENCIES = \ +@USE_EXPLICIT_LIB_DEPS_TRUE@ $(top_builddir)/lib/libcurl.la +curl_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(curl_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ../lib/$(DEPDIR)/base64.Po \ + ../lib/$(DEPDIR)/curl_multibyte.Po ../lib/$(DEPDIR)/dynbuf.Po \ + ../lib/$(DEPDIR)/libcurltool_la-base64.Plo \ + ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo \ + ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo \ + ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo \ + ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo \ + ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo \ + ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo \ + ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo \ + ../lib/$(DEPDIR)/nonblock.Po ../lib/$(DEPDIR)/strtoofft.Po \ + ../lib/$(DEPDIR)/timediff.Po ../lib/$(DEPDIR)/version_win32.Po \ + ../lib/$(DEPDIR)/warnless.Po \ + ./$(DEPDIR)/libcurltool_la-slist_wc.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_binmode.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_bname.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_doswin.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_filetime.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_findfile.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_formparse.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_getparam.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_getpass.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_help.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_helpers.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_hugehelp.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_ipfs.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_libinfo.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_listhelp.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_main.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_msgs.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_operate.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_operhlp.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_paramhlp.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_parsecfg.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_progress.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_setopt.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_sleep.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_stderr.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_strdup.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_urlglob.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_util.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_vms.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_writeout.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo \ + ./$(DEPDIR)/libcurltool_la-tool_xattr.Plo \ + ./$(DEPDIR)/libcurltool_la-var.Plo ./$(DEPDIR)/slist_wc.Po \ + ./$(DEPDIR)/tool_binmode.Po ./$(DEPDIR)/tool_bname.Po \ + ./$(DEPDIR)/tool_cb_dbg.Po ./$(DEPDIR)/tool_cb_hdr.Po \ + ./$(DEPDIR)/tool_cb_prg.Po ./$(DEPDIR)/tool_cb_rea.Po \ + ./$(DEPDIR)/tool_cb_see.Po ./$(DEPDIR)/tool_cb_wrt.Po \ + ./$(DEPDIR)/tool_cfgable.Po ./$(DEPDIR)/tool_dirhie.Po \ + ./$(DEPDIR)/tool_doswin.Po ./$(DEPDIR)/tool_easysrc.Po \ + ./$(DEPDIR)/tool_filetime.Po ./$(DEPDIR)/tool_findfile.Po \ + ./$(DEPDIR)/tool_formparse.Po ./$(DEPDIR)/tool_getparam.Po \ + ./$(DEPDIR)/tool_getpass.Po ./$(DEPDIR)/tool_help.Po \ + ./$(DEPDIR)/tool_helpers.Po ./$(DEPDIR)/tool_hugehelp.Po \ + ./$(DEPDIR)/tool_ipfs.Po ./$(DEPDIR)/tool_libinfo.Po \ + ./$(DEPDIR)/tool_listhelp.Po ./$(DEPDIR)/tool_main.Po \ + ./$(DEPDIR)/tool_msgs.Po ./$(DEPDIR)/tool_operate.Po \ + ./$(DEPDIR)/tool_operhlp.Po ./$(DEPDIR)/tool_paramhlp.Po \ + ./$(DEPDIR)/tool_parsecfg.Po ./$(DEPDIR)/tool_progress.Po \ + ./$(DEPDIR)/tool_setopt.Po ./$(DEPDIR)/tool_sleep.Po \ + ./$(DEPDIR)/tool_stderr.Po ./$(DEPDIR)/tool_strdup.Po \ + ./$(DEPDIR)/tool_urlglob.Po ./$(DEPDIR)/tool_util.Po \ + ./$(DEPDIR)/tool_vms.Po ./$(DEPDIR)/tool_writeout.Po \ + ./$(DEPDIR)/tool_writeout_json.Po ./$(DEPDIR)/tool_xattr.Po \ + ./$(DEPDIR)/var.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libcurltool_la_SOURCES) $(curl_SOURCES) +DIST_SOURCES = $(am__libcurltool_la_SOURCES_DIST) \ + $(am__curl_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc \ + $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APACHECTL = @APACHECTL@ +APXS = @APXS@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@ +CADDY = @CADDY@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ + +# This might hold -Werror +CFLAGS = @CFLAGS@ @CURL_CFLAG_EXTRAS@ +CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ +CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURLVERSION = @CURLVERSION@ +CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ +CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ +CURL_DISABLE_DICT = @CURL_DISABLE_DICT@ +CURL_DISABLE_FILE = @CURL_DISABLE_FILE@ +CURL_DISABLE_FTP = @CURL_DISABLE_FTP@ +CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@ +CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@ +CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@ +CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@ +CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@ +CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@ +CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@ +CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@ +CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@ +CURL_DISABLE_SMB = @CURL_DISABLE_SMB@ +CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@ +CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@ +CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@ +CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@ +CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ +CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@ +CURL_PLIST_VERSION = @CURL_PLIST_VERSION@ +CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_SHARED = @ENABLE_SHARED@ +ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ +GCOV = @GCOV@ +GREP = @GREP@ +HAVE_BROTLI = @HAVE_BROTLI@ +HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ +HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ +HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ +HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ +HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ +HAVE_ZSTD = @HAVE_ZSTD@ +HTTPD = @HTTPD@ +HTTPD_NGHTTPX = @HTTPD_NGHTTPX@ +IDN_ENABLED = @IDN_ENABLED@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPV6_ENABLED = @IPV6_ENABLED@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@ +LIBOBJS = @LIBOBJS@ + +# Prevent LIBS from being used for all link targets +LIBS = $(BLANK_AT_MAKETIME) +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANOPT = @MANOPT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +# Use the C locale to ensure that only ASCII characters appear in the +# embedded text. +NROFF = env LC_ALL=C @NROFF@ @MANOPT@ 2>/dev/null # figured out by the configure script +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGADD_NAME = @PKGADD_NAME@ +PKGADD_PKG = @PKGADD_PKG@ +PKGADD_VENDOR = @PKGADD_VENDOR@ +PKGCONFIG = @PKGCONFIG@ +RANDOM_FILE = @RANDOM_FILE@ +RANLIB = @RANLIB@ +RC = @RC@ +REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSL_BACKENDS = @SSL_BACKENDS@ +SSL_ENABLED = @SSL_ENABLED@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUPPORT_FEATURES = @SUPPORT_FEATURES@ +SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ +TEST_NGHTTPX = @TEST_NGHTTPX@ +USE_ARES = @USE_ARES@ +USE_BEARSSL = @USE_BEARSSL@ +USE_GNUTLS = @USE_GNUTLS@ +USE_HYPER = @USE_HYPER@ +USE_LIBRTMP = @USE_LIBRTMP@ +USE_LIBSSH = @USE_LIBSSH@ +USE_LIBSSH2 = @USE_LIBSSH2@ +USE_MBEDTLS = @USE_MBEDTLS@ +USE_MSH3 = @USE_MSH3@ +USE_NGHTTP2 = @USE_NGHTTP2@ +USE_NGHTTP3 = @USE_NGHTTP3@ +USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ +USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ +USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ +USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ +USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ +USE_QUICHE = @USE_QUICHE@ +USE_RUSTLS = @USE_RUSTLS@ +USE_SCHANNEL = @USE_SCHANNEL@ +USE_SECTRANSP = @USE_SECTRANSP@ +USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ +USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@ +USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@ +USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@ +USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ +USE_WOLFSSL = @USE_WOLFSSL@ +VERSION = @VERSION@ +VERSIONNUM = @VERSIONNUM@ +ZLIB_LIBS = @ZLIB_LIBS@ +ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libext = @libext@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +AUTOMAKE_OPTIONS = foreign nostdinc + +# Specify our include paths here, and do it relative to $(top_srcdir) and +# $(top_builddir), to ensure that these paths which belong to the library +# being currently built and tested are searched before the library which +# might possibly already be installed in the system. +# +# $(top_srcdir)/include is for libcurl's external include files +# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file +# $(top_builddir)/src is for curl's generated src/curl_config.h file +# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files +# $(top_srcdir)/src is for curl's src/tool_setup.h and "curl-private" files +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/lib \ + -I$(top_builddir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/src \ + $(am__append_1) -DBUILDING_CURL +SUBDIRS = ../docs + +# libcurl sources to include in curltool lib we use for test binaries +CURLTOOL_LIBCURL_CFILES = \ + ../lib/base64.c \ + ../lib/dynbuf.c + + +# libcurl has sources that provide functions named curlx_* that aren't part of +# the official API, but we reuse the code here to avoid duplication. +CURLX_CFILES = \ + ../lib/base64.c \ + ../lib/curl_multibyte.c \ + ../lib/dynbuf.c \ + ../lib/nonblock.c \ + ../lib/strtoofft.c \ + ../lib/timediff.c \ + ../lib/version_win32.c \ + ../lib/warnless.c + +CURLX_HFILES = \ + ../lib/curl_ctype.h \ + ../lib/curl_multibyte.h \ + ../lib/curl_setup.h \ + ../lib/dynbuf.h \ + ../lib/nonblock.h \ + ../lib/strtoofft.h \ + ../lib/timediff.h \ + ../lib/version_win32.h \ + ../lib/warnless.h + +CURL_CFILES = \ + slist_wc.c \ + tool_binmode.c \ + tool_bname.c \ + tool_cb_dbg.c \ + tool_cb_hdr.c \ + tool_cb_prg.c \ + tool_cb_rea.c \ + tool_cb_see.c \ + tool_cb_wrt.c \ + tool_cfgable.c \ + tool_dirhie.c \ + tool_doswin.c \ + tool_easysrc.c \ + tool_filetime.c \ + tool_findfile.c \ + tool_formparse.c \ + tool_getparam.c \ + tool_getpass.c \ + tool_help.c \ + tool_helpers.c \ + tool_hugehelp.c \ + tool_ipfs.c \ + tool_libinfo.c \ + tool_listhelp.c \ + tool_main.c \ + tool_msgs.c \ + tool_operate.c \ + tool_operhlp.c \ + tool_paramhlp.c \ + tool_parsecfg.c \ + tool_progress.c \ + tool_setopt.c \ + tool_sleep.c \ + tool_stderr.c \ + tool_strdup.c \ + tool_urlglob.c \ + tool_util.c \ + tool_vms.c \ + tool_writeout.c \ + tool_writeout_json.c \ + tool_xattr.c \ + var.c + +CURL_HFILES = \ + slist_wc.h \ + tool_binmode.h \ + tool_bname.h \ + tool_cb_dbg.h \ + tool_cb_hdr.h \ + tool_cb_prg.h \ + tool_cb_rea.h \ + tool_cb_see.h \ + tool_cb_wrt.h \ + tool_cfgable.h \ + tool_dirhie.h \ + tool_doswin.h \ + tool_easysrc.h \ + tool_filetime.h \ + tool_findfile.h \ + tool_formparse.h \ + tool_getparam.h \ + tool_getpass.h \ + tool_help.h \ + tool_helpers.h \ + tool_hugehelp.h \ + tool_ipfs.h \ + tool_libinfo.h \ + tool_main.h \ + tool_msgs.h \ + tool_operate.h \ + tool_operhlp.h \ + tool_paramhlp.h \ + tool_parsecfg.h \ + tool_progress.h \ + tool_sdecls.h \ + tool_setopt.h \ + tool_setup.h \ + tool_sleep.h \ + tool_stderr.h \ + tool_strdup.h \ + tool_urlglob.h \ + tool_util.h \ + tool_version.h \ + tool_vms.h \ + tool_writeout.h \ + tool_writeout_json.h \ + tool_xattr.h \ + var.h + +CURL_RCFILES = curl.rc + +# curl_SOURCES is special and gets assigned in src/Makefile.am +CURL_FILES = $(CURL_CFILES) $(CURLX_CFILES) $(CURL_HFILES) + +# CURL_FILES comes from Makefile.inc +curl_SOURCES = $(CURL_FILES) $(am__append_2) +curl_LDFLAGS = $(AM_LDFLAGS) $(CURL_LDFLAGS_BIN) +@USE_EXPLICIT_LIB_DEPS_FALSE@curl_LDADD = $(top_builddir)/lib/libcurl.la @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ +@USE_EXPLICIT_LIB_DEPS_TRUE@curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ + +# if unit tests are enabled, build a static library to link them with +@BUILD_UNITTESTS_TRUE@noinst_LTLIBRARIES = libcurltool.la +@BUILD_UNITTESTS_TRUE@libcurltool_la_CPPFLAGS = $(AM_CPPFLAGS) \ +@BUILD_UNITTESTS_TRUE@ -DCURL_STATICLIB -DUNITTESTS + +@BUILD_UNITTESTS_TRUE@libcurltool_la_CFLAGS = +@BUILD_UNITTESTS_TRUE@libcurltool_la_LDFLAGS = -static $(LINKFLAGS) +@BUILD_UNITTESTS_TRUE@libcurltool_la_SOURCES = $(CURL_FILES) +CLEANFILES = tool_hugehelp.c +EXTRA_DIST = mkhelp.pl \ + Makefile.mk curl.rc Makefile.inc CMakeLists.txt .checksrc + + +# Use absolute directory to disable VPATH +MANPAGE = $(abs_top_builddir)/docs/curl.1 +MKHELP = $(top_srcdir)/src/mkhelp.pl +HUGE = tool_hugehelp.c +HUGECMD = $(HUGEIT_$(V)) +HUGEIT_0 = @echo " HUGE " $@; +HUGEIT_1 = +HUGEIT_ = $(HUGEIT_0) +CHECKSRC = $(CS_$(V)) +CS_0 = @echo " RUN " $@; +CS_1 = +CS_ = $(CS_0) + +# disable the tests that are mostly causing false positives +TIDYFLAGS = -checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference +TIDY := clang-tidy +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj .rc +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.inc $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/Makefile.inc $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +../lib/$(am__dirstamp): + @$(MKDIR_P) ../lib + @: > ../lib/$(am__dirstamp) +../lib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) ../lib/$(DEPDIR) + @: > ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-base64.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-curl_multibyte.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-dynbuf.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-nonblock.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-strtoofft.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-timediff.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-version_win32.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/libcurltool_la-warnless.lo: ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) + +libcurltool.la: $(libcurltool_la_OBJECTS) $(libcurltool_la_DEPENDENCIES) $(EXTRA_libcurltool_la_DEPENDENCIES) + $(AM_V_CCLD)$(libcurltool_la_LINK) $(am_libcurltool_la_rpath) $(libcurltool_la_OBJECTS) $(libcurltool_la_LIBADD) $(LIBS) +../lib/base64.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/curl_multibyte.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/dynbuf.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/nonblock.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/strtoofft.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/timediff.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/version_win32.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) +../lib/warnless.$(OBJEXT): ../lib/$(am__dirstamp) \ + ../lib/$(DEPDIR)/$(am__dirstamp) + +curl$(EXEEXT): $(curl_OBJECTS) $(curl_DEPENDENCIES) $(EXTRA_curl_DEPENDENCIES) + @rm -f curl$(EXEEXT) + $(AM_V_CCLD)$(curl_LINK) $(curl_OBJECTS) $(curl_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f ../lib/*.$(OBJEXT) + -rm -f ../lib/*.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/base64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/curl_multibyte.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/dynbuf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-base64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-timediff.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-warnless.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/nonblock.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/strtoofft.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/timediff.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/version_win32.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-slist_wc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_binmode.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_bname.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_doswin.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_filetime.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_findfile.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_formparse.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_getparam.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_getpass.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_help.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_helpers.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_hugehelp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_ipfs.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_libinfo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_listhelp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_main.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_msgs.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_operate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_operhlp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_paramhlp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_parsecfg.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_progress.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_setopt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_sleep.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_stderr.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_strdup.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_urlglob.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_vms.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_writeout.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_xattr.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-var.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slist_wc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_binmode.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_bname.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_dbg.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_hdr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_prg.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_rea.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_see.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_wrt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cfgable.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_dirhie.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_doswin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_easysrc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_filetime.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_findfile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_formparse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_getparam.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_getpass.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_help.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_helpers.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_hugehelp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_ipfs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_libinfo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_listhelp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_msgs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_operate.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_operhlp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_paramhlp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_parsecfg.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_progress.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_setopt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_sleep.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_stderr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_strdup.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_urlglob.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_vms.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_writeout.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_writeout_json.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_xattr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/var.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libcurltool_la-slist_wc.lo: slist_wc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-slist_wc.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-slist_wc.Tpo -c -o libcurltool_la-slist_wc.lo `test -f 'slist_wc.c' || echo '$(srcdir)/'`slist_wc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-slist_wc.Tpo $(DEPDIR)/libcurltool_la-slist_wc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slist_wc.c' object='libcurltool_la-slist_wc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-slist_wc.lo `test -f 'slist_wc.c' || echo '$(srcdir)/'`slist_wc.c + +libcurltool_la-tool_binmode.lo: tool_binmode.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_binmode.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_binmode.Tpo -c -o libcurltool_la-tool_binmode.lo `test -f 'tool_binmode.c' || echo '$(srcdir)/'`tool_binmode.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_binmode.Tpo $(DEPDIR)/libcurltool_la-tool_binmode.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_binmode.c' object='libcurltool_la-tool_binmode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_binmode.lo `test -f 'tool_binmode.c' || echo '$(srcdir)/'`tool_binmode.c + +libcurltool_la-tool_bname.lo: tool_bname.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_bname.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_bname.Tpo -c -o libcurltool_la-tool_bname.lo `test -f 'tool_bname.c' || echo '$(srcdir)/'`tool_bname.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_bname.Tpo $(DEPDIR)/libcurltool_la-tool_bname.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_bname.c' object='libcurltool_la-tool_bname.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_bname.lo `test -f 'tool_bname.c' || echo '$(srcdir)/'`tool_bname.c + +libcurltool_la-tool_cb_dbg.lo: tool_cb_dbg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_dbg.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_dbg.Tpo -c -o libcurltool_la-tool_cb_dbg.lo `test -f 'tool_cb_dbg.c' || echo '$(srcdir)/'`tool_cb_dbg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_dbg.Tpo $(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_cb_dbg.c' object='libcurltool_la-tool_cb_dbg.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_dbg.lo `test -f 'tool_cb_dbg.c' || echo '$(srcdir)/'`tool_cb_dbg.c + +libcurltool_la-tool_cb_hdr.lo: tool_cb_hdr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_hdr.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_hdr.Tpo -c -o libcurltool_la-tool_cb_hdr.lo `test -f 'tool_cb_hdr.c' || echo '$(srcdir)/'`tool_cb_hdr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_hdr.Tpo $(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_cb_hdr.c' object='libcurltool_la-tool_cb_hdr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_hdr.lo `test -f 'tool_cb_hdr.c' || echo '$(srcdir)/'`tool_cb_hdr.c + +libcurltool_la-tool_cb_prg.lo: tool_cb_prg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_prg.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_prg.Tpo -c -o libcurltool_la-tool_cb_prg.lo `test -f 'tool_cb_prg.c' || echo '$(srcdir)/'`tool_cb_prg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_prg.Tpo $(DEPDIR)/libcurltool_la-tool_cb_prg.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_cb_prg.c' object='libcurltool_la-tool_cb_prg.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_prg.lo `test -f 'tool_cb_prg.c' || echo '$(srcdir)/'`tool_cb_prg.c + +libcurltool_la-tool_cb_rea.lo: tool_cb_rea.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_rea.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_rea.Tpo -c -o libcurltool_la-tool_cb_rea.lo `test -f 'tool_cb_rea.c' || echo '$(srcdir)/'`tool_cb_rea.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_rea.Tpo $(DEPDIR)/libcurltool_la-tool_cb_rea.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_cb_rea.c' object='libcurltool_la-tool_cb_rea.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_rea.lo `test -f 'tool_cb_rea.c' || echo '$(srcdir)/'`tool_cb_rea.c + +libcurltool_la-tool_cb_see.lo: tool_cb_see.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_see.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_see.Tpo -c -o libcurltool_la-tool_cb_see.lo `test -f 'tool_cb_see.c' || echo '$(srcdir)/'`tool_cb_see.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_see.Tpo $(DEPDIR)/libcurltool_la-tool_cb_see.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_cb_see.c' object='libcurltool_la-tool_cb_see.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_see.lo `test -f 'tool_cb_see.c' || echo '$(srcdir)/'`tool_cb_see.c + +libcurltool_la-tool_cb_wrt.lo: tool_cb_wrt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_wrt.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_wrt.Tpo -c -o libcurltool_la-tool_cb_wrt.lo `test -f 'tool_cb_wrt.c' || echo '$(srcdir)/'`tool_cb_wrt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_wrt.Tpo $(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_cb_wrt.c' object='libcurltool_la-tool_cb_wrt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_wrt.lo `test -f 'tool_cb_wrt.c' || echo '$(srcdir)/'`tool_cb_wrt.c + +libcurltool_la-tool_cfgable.lo: tool_cfgable.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cfgable.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cfgable.Tpo -c -o libcurltool_la-tool_cfgable.lo `test -f 'tool_cfgable.c' || echo '$(srcdir)/'`tool_cfgable.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cfgable.Tpo $(DEPDIR)/libcurltool_la-tool_cfgable.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_cfgable.c' object='libcurltool_la-tool_cfgable.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cfgable.lo `test -f 'tool_cfgable.c' || echo '$(srcdir)/'`tool_cfgable.c + +libcurltool_la-tool_dirhie.lo: tool_dirhie.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_dirhie.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_dirhie.Tpo -c -o libcurltool_la-tool_dirhie.lo `test -f 'tool_dirhie.c' || echo '$(srcdir)/'`tool_dirhie.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_dirhie.Tpo $(DEPDIR)/libcurltool_la-tool_dirhie.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_dirhie.c' object='libcurltool_la-tool_dirhie.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_dirhie.lo `test -f 'tool_dirhie.c' || echo '$(srcdir)/'`tool_dirhie.c + +libcurltool_la-tool_doswin.lo: tool_doswin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_doswin.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_doswin.Tpo -c -o libcurltool_la-tool_doswin.lo `test -f 'tool_doswin.c' || echo '$(srcdir)/'`tool_doswin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_doswin.Tpo $(DEPDIR)/libcurltool_la-tool_doswin.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_doswin.c' object='libcurltool_la-tool_doswin.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_doswin.lo `test -f 'tool_doswin.c' || echo '$(srcdir)/'`tool_doswin.c + +libcurltool_la-tool_easysrc.lo: tool_easysrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_easysrc.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_easysrc.Tpo -c -o libcurltool_la-tool_easysrc.lo `test -f 'tool_easysrc.c' || echo '$(srcdir)/'`tool_easysrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_easysrc.Tpo $(DEPDIR)/libcurltool_la-tool_easysrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_easysrc.c' object='libcurltool_la-tool_easysrc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_easysrc.lo `test -f 'tool_easysrc.c' || echo '$(srcdir)/'`tool_easysrc.c + +libcurltool_la-tool_filetime.lo: tool_filetime.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_filetime.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_filetime.Tpo -c -o libcurltool_la-tool_filetime.lo `test -f 'tool_filetime.c' || echo '$(srcdir)/'`tool_filetime.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_filetime.Tpo $(DEPDIR)/libcurltool_la-tool_filetime.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_filetime.c' object='libcurltool_la-tool_filetime.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_filetime.lo `test -f 'tool_filetime.c' || echo '$(srcdir)/'`tool_filetime.c + +libcurltool_la-tool_findfile.lo: tool_findfile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_findfile.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_findfile.Tpo -c -o libcurltool_la-tool_findfile.lo `test -f 'tool_findfile.c' || echo '$(srcdir)/'`tool_findfile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_findfile.Tpo $(DEPDIR)/libcurltool_la-tool_findfile.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_findfile.c' object='libcurltool_la-tool_findfile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_findfile.lo `test -f 'tool_findfile.c' || echo '$(srcdir)/'`tool_findfile.c + +libcurltool_la-tool_formparse.lo: tool_formparse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_formparse.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_formparse.Tpo -c -o libcurltool_la-tool_formparse.lo `test -f 'tool_formparse.c' || echo '$(srcdir)/'`tool_formparse.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_formparse.Tpo $(DEPDIR)/libcurltool_la-tool_formparse.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_formparse.c' object='libcurltool_la-tool_formparse.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_formparse.lo `test -f 'tool_formparse.c' || echo '$(srcdir)/'`tool_formparse.c + +libcurltool_la-tool_getparam.lo: tool_getparam.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_getparam.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_getparam.Tpo -c -o libcurltool_la-tool_getparam.lo `test -f 'tool_getparam.c' || echo '$(srcdir)/'`tool_getparam.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_getparam.Tpo $(DEPDIR)/libcurltool_la-tool_getparam.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_getparam.c' object='libcurltool_la-tool_getparam.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_getparam.lo `test -f 'tool_getparam.c' || echo '$(srcdir)/'`tool_getparam.c + +libcurltool_la-tool_getpass.lo: tool_getpass.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_getpass.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_getpass.Tpo -c -o libcurltool_la-tool_getpass.lo `test -f 'tool_getpass.c' || echo '$(srcdir)/'`tool_getpass.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_getpass.Tpo $(DEPDIR)/libcurltool_la-tool_getpass.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_getpass.c' object='libcurltool_la-tool_getpass.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_getpass.lo `test -f 'tool_getpass.c' || echo '$(srcdir)/'`tool_getpass.c + +libcurltool_la-tool_help.lo: tool_help.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_help.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_help.Tpo -c -o libcurltool_la-tool_help.lo `test -f 'tool_help.c' || echo '$(srcdir)/'`tool_help.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_help.Tpo $(DEPDIR)/libcurltool_la-tool_help.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_help.c' object='libcurltool_la-tool_help.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_help.lo `test -f 'tool_help.c' || echo '$(srcdir)/'`tool_help.c + +libcurltool_la-tool_helpers.lo: tool_helpers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_helpers.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_helpers.Tpo -c -o libcurltool_la-tool_helpers.lo `test -f 'tool_helpers.c' || echo '$(srcdir)/'`tool_helpers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_helpers.Tpo $(DEPDIR)/libcurltool_la-tool_helpers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_helpers.c' object='libcurltool_la-tool_helpers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_helpers.lo `test -f 'tool_helpers.c' || echo '$(srcdir)/'`tool_helpers.c + +libcurltool_la-tool_hugehelp.lo: tool_hugehelp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_hugehelp.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_hugehelp.Tpo -c -o libcurltool_la-tool_hugehelp.lo `test -f 'tool_hugehelp.c' || echo '$(srcdir)/'`tool_hugehelp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_hugehelp.Tpo $(DEPDIR)/libcurltool_la-tool_hugehelp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_hugehelp.c' object='libcurltool_la-tool_hugehelp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_hugehelp.lo `test -f 'tool_hugehelp.c' || echo '$(srcdir)/'`tool_hugehelp.c + +libcurltool_la-tool_ipfs.lo: tool_ipfs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_ipfs.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_ipfs.Tpo -c -o libcurltool_la-tool_ipfs.lo `test -f 'tool_ipfs.c' || echo '$(srcdir)/'`tool_ipfs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_ipfs.Tpo $(DEPDIR)/libcurltool_la-tool_ipfs.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_ipfs.c' object='libcurltool_la-tool_ipfs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_ipfs.lo `test -f 'tool_ipfs.c' || echo '$(srcdir)/'`tool_ipfs.c + +libcurltool_la-tool_libinfo.lo: tool_libinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_libinfo.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_libinfo.Tpo -c -o libcurltool_la-tool_libinfo.lo `test -f 'tool_libinfo.c' || echo '$(srcdir)/'`tool_libinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_libinfo.Tpo $(DEPDIR)/libcurltool_la-tool_libinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_libinfo.c' object='libcurltool_la-tool_libinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_libinfo.lo `test -f 'tool_libinfo.c' || echo '$(srcdir)/'`tool_libinfo.c + +libcurltool_la-tool_listhelp.lo: tool_listhelp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_listhelp.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_listhelp.Tpo -c -o libcurltool_la-tool_listhelp.lo `test -f 'tool_listhelp.c' || echo '$(srcdir)/'`tool_listhelp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_listhelp.Tpo $(DEPDIR)/libcurltool_la-tool_listhelp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_listhelp.c' object='libcurltool_la-tool_listhelp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_listhelp.lo `test -f 'tool_listhelp.c' || echo '$(srcdir)/'`tool_listhelp.c + +libcurltool_la-tool_main.lo: tool_main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_main.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_main.Tpo -c -o libcurltool_la-tool_main.lo `test -f 'tool_main.c' || echo '$(srcdir)/'`tool_main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_main.Tpo $(DEPDIR)/libcurltool_la-tool_main.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_main.c' object='libcurltool_la-tool_main.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_main.lo `test -f 'tool_main.c' || echo '$(srcdir)/'`tool_main.c + +libcurltool_la-tool_msgs.lo: tool_msgs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_msgs.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_msgs.Tpo -c -o libcurltool_la-tool_msgs.lo `test -f 'tool_msgs.c' || echo '$(srcdir)/'`tool_msgs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_msgs.Tpo $(DEPDIR)/libcurltool_la-tool_msgs.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_msgs.c' object='libcurltool_la-tool_msgs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_msgs.lo `test -f 'tool_msgs.c' || echo '$(srcdir)/'`tool_msgs.c + +libcurltool_la-tool_operate.lo: tool_operate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_operate.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_operate.Tpo -c -o libcurltool_la-tool_operate.lo `test -f 'tool_operate.c' || echo '$(srcdir)/'`tool_operate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_operate.Tpo $(DEPDIR)/libcurltool_la-tool_operate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_operate.c' object='libcurltool_la-tool_operate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_operate.lo `test -f 'tool_operate.c' || echo '$(srcdir)/'`tool_operate.c + +libcurltool_la-tool_operhlp.lo: tool_operhlp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_operhlp.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_operhlp.Tpo -c -o libcurltool_la-tool_operhlp.lo `test -f 'tool_operhlp.c' || echo '$(srcdir)/'`tool_operhlp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_operhlp.Tpo $(DEPDIR)/libcurltool_la-tool_operhlp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_operhlp.c' object='libcurltool_la-tool_operhlp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_operhlp.lo `test -f 'tool_operhlp.c' || echo '$(srcdir)/'`tool_operhlp.c + +libcurltool_la-tool_paramhlp.lo: tool_paramhlp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_paramhlp.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_paramhlp.Tpo -c -o libcurltool_la-tool_paramhlp.lo `test -f 'tool_paramhlp.c' || echo '$(srcdir)/'`tool_paramhlp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_paramhlp.Tpo $(DEPDIR)/libcurltool_la-tool_paramhlp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_paramhlp.c' object='libcurltool_la-tool_paramhlp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_paramhlp.lo `test -f 'tool_paramhlp.c' || echo '$(srcdir)/'`tool_paramhlp.c + +libcurltool_la-tool_parsecfg.lo: tool_parsecfg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_parsecfg.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_parsecfg.Tpo -c -o libcurltool_la-tool_parsecfg.lo `test -f 'tool_parsecfg.c' || echo '$(srcdir)/'`tool_parsecfg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_parsecfg.Tpo $(DEPDIR)/libcurltool_la-tool_parsecfg.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_parsecfg.c' object='libcurltool_la-tool_parsecfg.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_parsecfg.lo `test -f 'tool_parsecfg.c' || echo '$(srcdir)/'`tool_parsecfg.c + +libcurltool_la-tool_progress.lo: tool_progress.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_progress.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_progress.Tpo -c -o libcurltool_la-tool_progress.lo `test -f 'tool_progress.c' || echo '$(srcdir)/'`tool_progress.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_progress.Tpo $(DEPDIR)/libcurltool_la-tool_progress.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_progress.c' object='libcurltool_la-tool_progress.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_progress.lo `test -f 'tool_progress.c' || echo '$(srcdir)/'`tool_progress.c + +libcurltool_la-tool_setopt.lo: tool_setopt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_setopt.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_setopt.Tpo -c -o libcurltool_la-tool_setopt.lo `test -f 'tool_setopt.c' || echo '$(srcdir)/'`tool_setopt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_setopt.Tpo $(DEPDIR)/libcurltool_la-tool_setopt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_setopt.c' object='libcurltool_la-tool_setopt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_setopt.lo `test -f 'tool_setopt.c' || echo '$(srcdir)/'`tool_setopt.c + +libcurltool_la-tool_sleep.lo: tool_sleep.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_sleep.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_sleep.Tpo -c -o libcurltool_la-tool_sleep.lo `test -f 'tool_sleep.c' || echo '$(srcdir)/'`tool_sleep.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_sleep.Tpo $(DEPDIR)/libcurltool_la-tool_sleep.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_sleep.c' object='libcurltool_la-tool_sleep.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_sleep.lo `test -f 'tool_sleep.c' || echo '$(srcdir)/'`tool_sleep.c + +libcurltool_la-tool_stderr.lo: tool_stderr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_stderr.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_stderr.Tpo -c -o libcurltool_la-tool_stderr.lo `test -f 'tool_stderr.c' || echo '$(srcdir)/'`tool_stderr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_stderr.Tpo $(DEPDIR)/libcurltool_la-tool_stderr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_stderr.c' object='libcurltool_la-tool_stderr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_stderr.lo `test -f 'tool_stderr.c' || echo '$(srcdir)/'`tool_stderr.c + +libcurltool_la-tool_strdup.lo: tool_strdup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_strdup.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_strdup.Tpo -c -o libcurltool_la-tool_strdup.lo `test -f 'tool_strdup.c' || echo '$(srcdir)/'`tool_strdup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_strdup.Tpo $(DEPDIR)/libcurltool_la-tool_strdup.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_strdup.c' object='libcurltool_la-tool_strdup.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_strdup.lo `test -f 'tool_strdup.c' || echo '$(srcdir)/'`tool_strdup.c + +libcurltool_la-tool_urlglob.lo: tool_urlglob.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_urlglob.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_urlglob.Tpo -c -o libcurltool_la-tool_urlglob.lo `test -f 'tool_urlglob.c' || echo '$(srcdir)/'`tool_urlglob.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_urlglob.Tpo $(DEPDIR)/libcurltool_la-tool_urlglob.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_urlglob.c' object='libcurltool_la-tool_urlglob.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_urlglob.lo `test -f 'tool_urlglob.c' || echo '$(srcdir)/'`tool_urlglob.c + +libcurltool_la-tool_util.lo: tool_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_util.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_util.Tpo -c -o libcurltool_la-tool_util.lo `test -f 'tool_util.c' || echo '$(srcdir)/'`tool_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_util.Tpo $(DEPDIR)/libcurltool_la-tool_util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_util.c' object='libcurltool_la-tool_util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_util.lo `test -f 'tool_util.c' || echo '$(srcdir)/'`tool_util.c + +libcurltool_la-tool_vms.lo: tool_vms.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_vms.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_vms.Tpo -c -o libcurltool_la-tool_vms.lo `test -f 'tool_vms.c' || echo '$(srcdir)/'`tool_vms.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_vms.Tpo $(DEPDIR)/libcurltool_la-tool_vms.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_vms.c' object='libcurltool_la-tool_vms.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_vms.lo `test -f 'tool_vms.c' || echo '$(srcdir)/'`tool_vms.c + +libcurltool_la-tool_writeout.lo: tool_writeout.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_writeout.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_writeout.Tpo -c -o libcurltool_la-tool_writeout.lo `test -f 'tool_writeout.c' || echo '$(srcdir)/'`tool_writeout.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_writeout.Tpo $(DEPDIR)/libcurltool_la-tool_writeout.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_writeout.c' object='libcurltool_la-tool_writeout.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_writeout.lo `test -f 'tool_writeout.c' || echo '$(srcdir)/'`tool_writeout.c + +libcurltool_la-tool_writeout_json.lo: tool_writeout_json.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_writeout_json.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_writeout_json.Tpo -c -o libcurltool_la-tool_writeout_json.lo `test -f 'tool_writeout_json.c' || echo '$(srcdir)/'`tool_writeout_json.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_writeout_json.Tpo $(DEPDIR)/libcurltool_la-tool_writeout_json.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_writeout_json.c' object='libcurltool_la-tool_writeout_json.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_writeout_json.lo `test -f 'tool_writeout_json.c' || echo '$(srcdir)/'`tool_writeout_json.c + +libcurltool_la-tool_xattr.lo: tool_xattr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_xattr.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_xattr.Tpo -c -o libcurltool_la-tool_xattr.lo `test -f 'tool_xattr.c' || echo '$(srcdir)/'`tool_xattr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_xattr.Tpo $(DEPDIR)/libcurltool_la-tool_xattr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool_xattr.c' object='libcurltool_la-tool_xattr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_xattr.lo `test -f 'tool_xattr.c' || echo '$(srcdir)/'`tool_xattr.c + +libcurltool_la-var.lo: var.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-var.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-var.Tpo -c -o libcurltool_la-var.lo `test -f 'var.c' || echo '$(srcdir)/'`var.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-var.Tpo $(DEPDIR)/libcurltool_la-var.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='var.c' object='libcurltool_la-var.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-var.lo `test -f 'var.c' || echo '$(srcdir)/'`var.c + +../lib/libcurltool_la-base64.lo: ../lib/base64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-base64.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-base64.Tpo -c -o ../lib/libcurltool_la-base64.lo `test -f '../lib/base64.c' || echo '$(srcdir)/'`../lib/base64.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-base64.Tpo ../lib/$(DEPDIR)/libcurltool_la-base64.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/base64.c' object='../lib/libcurltool_la-base64.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-base64.lo `test -f '../lib/base64.c' || echo '$(srcdir)/'`../lib/base64.c + +../lib/libcurltool_la-curl_multibyte.lo: ../lib/curl_multibyte.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-curl_multibyte.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Tpo -c -o ../lib/libcurltool_la-curl_multibyte.lo `test -f '../lib/curl_multibyte.c' || echo '$(srcdir)/'`../lib/curl_multibyte.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Tpo ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/curl_multibyte.c' object='../lib/libcurltool_la-curl_multibyte.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-curl_multibyte.lo `test -f '../lib/curl_multibyte.c' || echo '$(srcdir)/'`../lib/curl_multibyte.c + +../lib/libcurltool_la-dynbuf.lo: ../lib/dynbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-dynbuf.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Tpo -c -o ../lib/libcurltool_la-dynbuf.lo `test -f '../lib/dynbuf.c' || echo '$(srcdir)/'`../lib/dynbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Tpo ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/dynbuf.c' object='../lib/libcurltool_la-dynbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-dynbuf.lo `test -f '../lib/dynbuf.c' || echo '$(srcdir)/'`../lib/dynbuf.c + +../lib/libcurltool_la-nonblock.lo: ../lib/nonblock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-nonblock.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-nonblock.Tpo -c -o ../lib/libcurltool_la-nonblock.lo `test -f '../lib/nonblock.c' || echo '$(srcdir)/'`../lib/nonblock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-nonblock.Tpo ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/nonblock.c' object='../lib/libcurltool_la-nonblock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-nonblock.lo `test -f '../lib/nonblock.c' || echo '$(srcdir)/'`../lib/nonblock.c + +../lib/libcurltool_la-strtoofft.lo: ../lib/strtoofft.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-strtoofft.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Tpo -c -o ../lib/libcurltool_la-strtoofft.lo `test -f '../lib/strtoofft.c' || echo '$(srcdir)/'`../lib/strtoofft.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Tpo ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/strtoofft.c' object='../lib/libcurltool_la-strtoofft.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-strtoofft.lo `test -f '../lib/strtoofft.c' || echo '$(srcdir)/'`../lib/strtoofft.c + +../lib/libcurltool_la-timediff.lo: ../lib/timediff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-timediff.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-timediff.Tpo -c -o ../lib/libcurltool_la-timediff.lo `test -f '../lib/timediff.c' || echo '$(srcdir)/'`../lib/timediff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-timediff.Tpo ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/timediff.c' object='../lib/libcurltool_la-timediff.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-timediff.lo `test -f '../lib/timediff.c' || echo '$(srcdir)/'`../lib/timediff.c + +../lib/libcurltool_la-version_win32.lo: ../lib/version_win32.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-version_win32.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-version_win32.Tpo -c -o ../lib/libcurltool_la-version_win32.lo `test -f '../lib/version_win32.c' || echo '$(srcdir)/'`../lib/version_win32.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-version_win32.Tpo ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/version_win32.c' object='../lib/libcurltool_la-version_win32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-version_win32.lo `test -f '../lib/version_win32.c' || echo '$(srcdir)/'`../lib/version_win32.c + +../lib/libcurltool_la-warnless.lo: ../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT ../lib/libcurltool_la-warnless.lo -MD -MP -MF ../lib/$(DEPDIR)/libcurltool_la-warnless.Tpo -c -o ../lib/libcurltool_la-warnless.lo `test -f '../lib/warnless.c' || echo '$(srcdir)/'`../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/libcurltool_la-warnless.Tpo ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/warnless.c' object='../lib/libcurltool_la-warnless.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o ../lib/libcurltool_la-warnless.lo `test -f '../lib/warnless.c' || echo '$(srcdir)/'`../lib/warnless.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../lib/.libs ../lib/_libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +@CURLDEBUG_FALSE@all-local: +all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) all-local +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../lib/$(DEPDIR)/$(am__dirstamp) + -rm -f ../lib/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-recursive + -rm -f ../lib/$(DEPDIR)/base64.Po + -rm -f ../lib/$(DEPDIR)/curl_multibyte.Po + -rm -f ../lib/$(DEPDIR)/dynbuf.Po + -rm -f ../lib/$(DEPDIR)/libcurltool_la-base64.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo + -rm -f ../lib/$(DEPDIR)/nonblock.Po + -rm -f ../lib/$(DEPDIR)/strtoofft.Po + -rm -f ../lib/$(DEPDIR)/timediff.Po + -rm -f ../lib/$(DEPDIR)/version_win32.Po + -rm -f ../lib/$(DEPDIR)/warnless.Po + -rm -f ./$(DEPDIR)/libcurltool_la-slist_wc.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_binmode.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_bname.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_doswin.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_filetime.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_findfile.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_formparse.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_getparam.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_getpass.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_help.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_helpers.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_hugehelp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_ipfs.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_libinfo.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_listhelp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_main.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_msgs.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_operate.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_operhlp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_paramhlp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_parsecfg.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_progress.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_setopt.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_sleep.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_stderr.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_strdup.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_urlglob.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_util.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_vms.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_xattr.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-var.Plo + -rm -f ./$(DEPDIR)/slist_wc.Po + -rm -f ./$(DEPDIR)/tool_binmode.Po + -rm -f ./$(DEPDIR)/tool_bname.Po + -rm -f ./$(DEPDIR)/tool_cb_dbg.Po + -rm -f ./$(DEPDIR)/tool_cb_hdr.Po + -rm -f ./$(DEPDIR)/tool_cb_prg.Po + -rm -f ./$(DEPDIR)/tool_cb_rea.Po + -rm -f ./$(DEPDIR)/tool_cb_see.Po + -rm -f ./$(DEPDIR)/tool_cb_wrt.Po + -rm -f ./$(DEPDIR)/tool_cfgable.Po + -rm -f ./$(DEPDIR)/tool_dirhie.Po + -rm -f ./$(DEPDIR)/tool_doswin.Po + -rm -f ./$(DEPDIR)/tool_easysrc.Po + -rm -f ./$(DEPDIR)/tool_filetime.Po + -rm -f ./$(DEPDIR)/tool_findfile.Po + -rm -f ./$(DEPDIR)/tool_formparse.Po + -rm -f ./$(DEPDIR)/tool_getparam.Po + -rm -f ./$(DEPDIR)/tool_getpass.Po + -rm -f ./$(DEPDIR)/tool_help.Po + -rm -f ./$(DEPDIR)/tool_helpers.Po + -rm -f ./$(DEPDIR)/tool_hugehelp.Po + -rm -f ./$(DEPDIR)/tool_ipfs.Po + -rm -f ./$(DEPDIR)/tool_libinfo.Po + -rm -f ./$(DEPDIR)/tool_listhelp.Po + -rm -f ./$(DEPDIR)/tool_main.Po + -rm -f ./$(DEPDIR)/tool_msgs.Po + -rm -f ./$(DEPDIR)/tool_operate.Po + -rm -f ./$(DEPDIR)/tool_operhlp.Po + -rm -f ./$(DEPDIR)/tool_paramhlp.Po + -rm -f ./$(DEPDIR)/tool_parsecfg.Po + -rm -f ./$(DEPDIR)/tool_progress.Po + -rm -f ./$(DEPDIR)/tool_setopt.Po + -rm -f ./$(DEPDIR)/tool_sleep.Po + -rm -f ./$(DEPDIR)/tool_stderr.Po + -rm -f ./$(DEPDIR)/tool_strdup.Po + -rm -f ./$(DEPDIR)/tool_urlglob.Po + -rm -f ./$(DEPDIR)/tool_util.Po + -rm -f ./$(DEPDIR)/tool_vms.Po + -rm -f ./$(DEPDIR)/tool_writeout.Po + -rm -f ./$(DEPDIR)/tool_writeout_json.Po + -rm -f ./$(DEPDIR)/tool_xattr.Po + -rm -f ./$(DEPDIR)/var.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ../lib/$(DEPDIR)/base64.Po + -rm -f ../lib/$(DEPDIR)/curl_multibyte.Po + -rm -f ../lib/$(DEPDIR)/dynbuf.Po + -rm -f ../lib/$(DEPDIR)/libcurltool_la-base64.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo + -rm -f ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo + -rm -f ../lib/$(DEPDIR)/nonblock.Po + -rm -f ../lib/$(DEPDIR)/strtoofft.Po + -rm -f ../lib/$(DEPDIR)/timediff.Po + -rm -f ../lib/$(DEPDIR)/version_win32.Po + -rm -f ../lib/$(DEPDIR)/warnless.Po + -rm -f ./$(DEPDIR)/libcurltool_la-slist_wc.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_binmode.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_bname.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_doswin.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_filetime.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_findfile.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_formparse.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_getparam.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_getpass.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_help.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_helpers.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_hugehelp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_ipfs.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_libinfo.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_listhelp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_main.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_msgs.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_operate.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_operhlp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_paramhlp.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_parsecfg.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_progress.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_setopt.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_sleep.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_stderr.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_strdup.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_urlglob.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_util.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_vms.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-tool_xattr.Plo + -rm -f ./$(DEPDIR)/libcurltool_la-var.Plo + -rm -f ./$(DEPDIR)/slist_wc.Po + -rm -f ./$(DEPDIR)/tool_binmode.Po + -rm -f ./$(DEPDIR)/tool_bname.Po + -rm -f ./$(DEPDIR)/tool_cb_dbg.Po + -rm -f ./$(DEPDIR)/tool_cb_hdr.Po + -rm -f ./$(DEPDIR)/tool_cb_prg.Po + -rm -f ./$(DEPDIR)/tool_cb_rea.Po + -rm -f ./$(DEPDIR)/tool_cb_see.Po + -rm -f ./$(DEPDIR)/tool_cb_wrt.Po + -rm -f ./$(DEPDIR)/tool_cfgable.Po + -rm -f ./$(DEPDIR)/tool_dirhie.Po + -rm -f ./$(DEPDIR)/tool_doswin.Po + -rm -f ./$(DEPDIR)/tool_easysrc.Po + -rm -f ./$(DEPDIR)/tool_filetime.Po + -rm -f ./$(DEPDIR)/tool_findfile.Po + -rm -f ./$(DEPDIR)/tool_formparse.Po + -rm -f ./$(DEPDIR)/tool_getparam.Po + -rm -f ./$(DEPDIR)/tool_getpass.Po + -rm -f ./$(DEPDIR)/tool_help.Po + -rm -f ./$(DEPDIR)/tool_helpers.Po + -rm -f ./$(DEPDIR)/tool_hugehelp.Po + -rm -f ./$(DEPDIR)/tool_ipfs.Po + -rm -f ./$(DEPDIR)/tool_libinfo.Po + -rm -f ./$(DEPDIR)/tool_listhelp.Po + -rm -f ./$(DEPDIR)/tool_main.Po + -rm -f ./$(DEPDIR)/tool_msgs.Po + -rm -f ./$(DEPDIR)/tool_operate.Po + -rm -f ./$(DEPDIR)/tool_operhlp.Po + -rm -f ./$(DEPDIR)/tool_paramhlp.Po + -rm -f ./$(DEPDIR)/tool_parsecfg.Po + -rm -f ./$(DEPDIR)/tool_progress.Po + -rm -f ./$(DEPDIR)/tool_setopt.Po + -rm -f ./$(DEPDIR)/tool_sleep.Po + -rm -f ./$(DEPDIR)/tool_stderr.Po + -rm -f ./$(DEPDIR)/tool_strdup.Po + -rm -f ./$(DEPDIR)/tool_urlglob.Po + -rm -f ./$(DEPDIR)/tool_util.Po + -rm -f ./$(DEPDIR)/tool_vms.Po + -rm -f ./$(DEPDIR)/tool_writeout.Po + -rm -f ./$(DEPDIR)/tool_writeout_json.Po + -rm -f ./$(DEPDIR)/tool_xattr.Po + -rm -f ./$(DEPDIR)/var.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ + am--depfiles check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-binPROGRAMS + +.PRECIOUS: Makefile + + +# remove targets if the command fails +.DELETE_ON_ERROR: +@HAVE_WINDRES_TRUE@$(CURL_RCFILES): tool_version.h + +# Here are the stuff to create a built-in manual + +@USE_MANUAL_TRUE@$(MANPAGE): +@USE_MANUAL_TRUE@ cd $(top_builddir)/docs && $(MAKE) + +# This generates the tool_hugehelp.c file in both uncompressed and +# compressed formats. +@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@$(HUGE): $(MANPAGE) $(MKHELP) +@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@ $(HUGECMD) (echo '#include "tool_setup.h"' > $(HUGE); \ +@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@ echo '#ifndef HAVE_LIBZ' >> $(HUGE); \ +@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE); \ +@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@ echo '#else' >> $(HUGE); \ +@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) -c >> $(HUGE); \ +@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@ echo '#endif /* HAVE_LIBZ */' >> $(HUGE) ) +# This generates the tool_hugehelp.c file uncompressed only +@HAVE_LIBZ_FALSE@@USE_MANUAL_TRUE@$(HUGE): $(MANPAGE) $(MKHELP) +@HAVE_LIBZ_FALSE@@USE_MANUAL_TRUE@ $(HUGECMD)(echo '#include "tool_setup.h"' > $(HUGE); \ +@HAVE_LIBZ_FALSE@@USE_MANUAL_TRUE@ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE) ) + +# built-in manual has been disabled, make a blank file +@USE_MANUAL_FALSE@$(HUGE): +@USE_MANUAL_FALSE@ echo '#include "tool_hugehelp.h"' >> $(HUGE) + +# ignore tool_hugehelp.c since it is generated source code and it plays +# by slightly different rules! +checksrc: + $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \ + -W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch]) + +# for debug builds, we scan the sources on all regular make invokes +@CURLDEBUG_TRUE@all-local: checksrc + +tidy: + $(TIDY) $(CURL_CFILES) $(TIDYFLAGS) -- $(curl_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H + +listhelp: + (cd $(top_srcdir)/docs/cmdline-opts && make listhelp) + +@HAVE_WINDRES_TRUE@.rc.o: +@HAVE_WINDRES_TRUE@ $(RC) -I$(top_srcdir)/include -DCURL_EMBED_MANIFEST $(RCFLAGS) -i $< -o $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/Makefile.inc b/src/Makefile.inc new file mode 100644 index 0000000..c1d202a --- /dev/null +++ b/src/Makefile.inc @@ -0,0 +1,153 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### +# ./src/Makefile.inc +# Using the backslash as line continuation character might be problematic with +# some make flavours. If we ever want to change this in a portable manner then +# we should consider this idea : +# CSRC1 = file1.c file2.c file3.c +# CSRC2 = file4.c file5.c file6.c +# CSOURCES = $(CSRC1) $(CSRC2) + +# libcurl sources to include in curltool lib we use for test binaries +CURLTOOL_LIBCURL_CFILES = \ + ../lib/base64.c \ + ../lib/dynbuf.c + +# libcurl has sources that provide functions named curlx_* that aren't part of +# the official API, but we reuse the code here to avoid duplication. +CURLX_CFILES = \ + ../lib/base64.c \ + ../lib/curl_multibyte.c \ + ../lib/dynbuf.c \ + ../lib/nonblock.c \ + ../lib/strtoofft.c \ + ../lib/timediff.c \ + ../lib/version_win32.c \ + ../lib/warnless.c + +CURLX_HFILES = \ + ../lib/curl_ctype.h \ + ../lib/curl_multibyte.h \ + ../lib/curl_setup.h \ + ../lib/dynbuf.h \ + ../lib/nonblock.h \ + ../lib/strtoofft.h \ + ../lib/timediff.h \ + ../lib/version_win32.h \ + ../lib/warnless.h + +CURL_CFILES = \ + slist_wc.c \ + tool_binmode.c \ + tool_bname.c \ + tool_cb_dbg.c \ + tool_cb_hdr.c \ + tool_cb_prg.c \ + tool_cb_rea.c \ + tool_cb_see.c \ + tool_cb_wrt.c \ + tool_cfgable.c \ + tool_dirhie.c \ + tool_doswin.c \ + tool_easysrc.c \ + tool_filetime.c \ + tool_findfile.c \ + tool_formparse.c \ + tool_getparam.c \ + tool_getpass.c \ + tool_help.c \ + tool_helpers.c \ + tool_hugehelp.c \ + tool_ipfs.c \ + tool_libinfo.c \ + tool_listhelp.c \ + tool_main.c \ + tool_msgs.c \ + tool_operate.c \ + tool_operhlp.c \ + tool_paramhlp.c \ + tool_parsecfg.c \ + tool_progress.c \ + tool_setopt.c \ + tool_sleep.c \ + tool_stderr.c \ + tool_strdup.c \ + tool_urlglob.c \ + tool_util.c \ + tool_vms.c \ + tool_writeout.c \ + tool_writeout_json.c \ + tool_xattr.c \ + var.c + +CURL_HFILES = \ + slist_wc.h \ + tool_binmode.h \ + tool_bname.h \ + tool_cb_dbg.h \ + tool_cb_hdr.h \ + tool_cb_prg.h \ + tool_cb_rea.h \ + tool_cb_see.h \ + tool_cb_wrt.h \ + tool_cfgable.h \ + tool_dirhie.h \ + tool_doswin.h \ + tool_easysrc.h \ + tool_filetime.h \ + tool_findfile.h \ + tool_formparse.h \ + tool_getparam.h \ + tool_getpass.h \ + tool_help.h \ + tool_helpers.h \ + tool_hugehelp.h \ + tool_ipfs.h \ + tool_libinfo.h \ + tool_main.h \ + tool_msgs.h \ + tool_operate.h \ + tool_operhlp.h \ + tool_paramhlp.h \ + tool_parsecfg.h \ + tool_progress.h \ + tool_sdecls.h \ + tool_setopt.h \ + tool_setup.h \ + tool_sleep.h \ + tool_stderr.h \ + tool_strdup.h \ + tool_urlglob.h \ + tool_util.h \ + tool_version.h \ + tool_vms.h \ + tool_writeout.h \ + tool_writeout_json.h \ + tool_xattr.h \ + var.h + +CURL_RCFILES = curl.rc + +# curl_SOURCES is special and gets assigned in src/Makefile.am +CURL_FILES = $(CURL_CFILES) $(CURLX_CFILES) $(CURL_HFILES) diff --git a/src/Makefile.mk b/src/Makefile.mk new file mode 100644 index 0000000..83dd65d --- /dev/null +++ b/src/Makefile.mk @@ -0,0 +1,90 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +#*************************************************************************** + +# See usage in lib/Makefile.mk + +PROOT := .. + +### Common + +include $(PROOT)/lib/Makefile.mk + +### Local + +CPPFLAGS += -I$(PROOT)/lib +LDFLAGS += -L$(PROOT)/lib +LIBS := -lcurl $(LIBS) + +### Sources and targets + +# Provides CURL_CFILES, CURLX_CFILES +include Makefile.inc + +TARGETS := curl$(BIN_EXT) + +CURL_CFILES += $(notdir $(CURLX_CFILES)) + +curl_OBJECTS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(strip $(CURL_CFILES))) +ifdef MAP +CURL_MAP := curl.map +LDFLAGS += -Wl,-Map,$(CURL_MAP) +TOVCLEAN := $(CURL_MAP) +endif +vpath %.c $(PROOT)/lib + +TOCLEAN := $(curl_OBJECTS) + +### Rules + +ifneq ($(wildcard tool_hugehelp.c.cvs),) +PERL ?= perl +NROFF ?= groff + +TOCLEAN += tool_hugehelp.c + +ifneq ($(shell $(call WHICH, $(NROFF))),) +$(PROOT)/docs/curl.1: $(wildcard $(PROOT)/docs/cmdline-opts/*.d) + cd $(PROOT)/docs/cmdline-opts && \ + $(PERL) gen.pl mainpage $(notdir $^) > ../curl.1 + +# Necessary for the generated tools_hugehelp.c +CPPFLAGS += -DUSE_MANUAL + +ifdef ZLIB +_MKHELPOPT += -c +endif +tool_hugehelp.c: $(PROOT)/docs/curl.1 mkhelp.pl + $(NROFF) -man -Tascii $(MANOPT) $< | \ + $(PERL) mkhelp.pl $(_MKHELPOPT) $< > $@ +else +tool_hugehelp.c: + @echo Creating $@ + @$(call COPY, $@.cvs, $@) +endif +endif + +$(TARGETS): $(curl_OBJECTS) $(PROOT)/lib/libcurl.a + $(CC) $(LDFLAGS) -o $@ $(curl_OBJECTS) $(LIBS) + +all: $(OBJ_DIR) $(TARGETS) diff --git a/src/curl.rc b/src/curl.rc new file mode 100644 index 0000000..6fcaf35 --- /dev/null +++ b/src/curl.rc @@ -0,0 +1,113 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include +#include "tool_version.h" + +LANGUAGE 0, 0 + +#define RC_VERSION CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RC_VERSION + PRODUCTVERSION RC_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#if defined(DEBUGBUILD) || defined(_DEBUG) + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0L + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "curl, https://curl.se/\0" + VALUE "FileDescription", "The curl executable\0" + VALUE "FileVersion", CURL_VERSION "\0" + VALUE "InternalName", "curl\0" + VALUE "OriginalFilename", "curl.exe\0" + VALUE "ProductName", "The curl executable\0" + VALUE "ProductVersion", CURL_VERSION "\0" + VALUE "LegalCopyright", "Copyright (C) " CURL_COPYRIGHT "\0" + VALUE "License", "https://curl.se/docs/copyright.html\0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +/* Manifest */ + +#if defined(CURL_EMBED_MANIFEST) + +/* String escaping rules: + https://msdn.microsoft.com/library/aa381050 + Application Manifest doc, including the list of 'supportedOS Id's: + https://msdn.microsoft.com/library/aa374191 */ + +#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID +#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 +#endif +#ifndef RT_MANIFEST +#define RT_MANIFEST 24 +#endif + +#define _STR(macro) _STR_(macro) +#define _STR_(macro) #macro + +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST +BEGIN + "" + "" + "" + "" + "" + "" /* Vista / Server 2008 */ + "" /* 7 / Server 2008 R2 */ + "" /* 8 / Server 2012 */ + "" /* 8.1 / Server 2012 R2 */ + "" /* 10 / Server 2016 */ + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" +END + +#endif diff --git a/src/mkhelp.pl b/src/mkhelp.pl new file mode 100755 index 0000000..91551cf --- /dev/null +++ b/src/mkhelp.pl @@ -0,0 +1,234 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# SPDX-License-Identifier: curl +# +########################################################################### + +# Yeah, I know, probably 1000 other persons already wrote a script like +# this, but I'll tell ya: + +# THEY DON'T FIT ME :-) + +# Get readme file as parameter: + +if($ARGV[0] eq "-c") { + $c=1; + shift @ARGV; +} + +push @out, " _ _ ____ _\n"; +push @out, " Project ___| | | | _ \\| |\n"; +push @out, " / __| | | | |_) | |\n"; +push @out, " | (__| |_| | _ <| |___\n"; +push @out, " \\___|\\___/|_| \\_\\_____|\n"; + +my $olen=0; +while () { + my $line = $_; + + # this should be removed: + $line =~ s/(.|_)//g; + + # remove trailing CR from line. msysgit checks out files as line+CRLF + $line =~ s/\r$//; + + $line =~ s/\x1b\x5b[0-9]+m//g; # escape sequence + if($line =~ /^([ \t]*\n|curl)/i) { + # cut off headers and empty lines + $wline++; # count number of cut off lines + next; + } + + my $text = $line; + $text =~ s/^\s+//g; # cut off preceding... + $text =~ s/\s+$//g; # and trailing whitespaces + + $tlen = length($text); + + if($wline && ($olen == $tlen)) { + # if the previous line with contents was exactly as long as + # this line, then we ignore the newlines! + + # We do this magic because a header may abort a paragraph at + # any line, but we don't want that to be noticed in the output + # here + $wline=0; + } + $olen = $tlen; + + if($wline) { + # we only make one empty line max + $wline = 0; + push @out, "\n"; + } + push @out, $line; +} +push @out, "\n"; # just an extra newline + +print <import(); + 1; + }; + print STDERR "Warning: compression requested but Gzip is not available\n" if (!$c) +} + +if($c) +{ + my $content = join("", @out); + my $gzippedContent; + IO::Compress::Gzip::gzip( + \$content, \$gzippedContent, Level => 9, TextFlag => 1, Time=>0) or die "gzip failed:"; + $gzip = length($content); + $gzipped = length($gzippedContent); + + print < +#include "memdebug.h" /* keep this as LAST include */ +static const unsigned char hugehelpgz[] = { + /* This mumbo-jumbo is the huge help text compressed with gzip. + Thanks to this operation, the size of this data shrank from $gzip + to $gzipped bytes. You can disable the use of compressed help + texts by NOT passing -c to the mkhelp.pl tool. */ +HEAD +; + + my $c=0; + print " "; + for(split(//, $gzippedContent)) { + my $num=ord($_); + printf(" 0x%02x,", 0+$num); + if(!(++$c % 12)) { + print "\n "; + } + } + print "\n};\n"; + + print < 500) { + # terminate and make another fputs() call here + print ", stdout);\n fputs(\n"; + $outsize=length($new)+1; + } + printf("\"%s\\n\"\n", $new); + +} + +print ", stdout) ;\n}\n"; + +foot(); + +sub foot { + print <, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "tool_setup.h" + +#ifndef CURL_DISABLE_LIBCURL_OPTION + +#include "slist_wc.h" + +/* The last #include files should be: */ +#include "memdebug.h" + +/* + * slist_wc_append() appends a string to the linked list. This function can be + * used as an initialization function as well as an append function. + */ +struct slist_wc *slist_wc_append(struct slist_wc *list, + const char *data) +{ + struct curl_slist *new_item = curl_slist_append(NULL, data); + + if(!new_item) + return NULL; + + if(!list) { + list = malloc(sizeof(struct slist_wc)); + + if(!list) { + curl_slist_free_all(new_item); + return NULL; + } + + list->first = new_item; + list->last = new_item; + return list; + } + + list->last->next = new_item; + list->last = list->last->next; + return list; +} + +/* be nice and clean up resources */ +void slist_wc_free_all(struct slist_wc *list) +{ + if(!list) + return; + + curl_slist_free_all(list->first); + free(list); +} + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/src/slist_wc.h b/src/slist_wc.h new file mode 100644 index 0000000..dd7b8c1 --- /dev/null +++ b/src/slist_wc.h @@ -0,0 +1,57 @@ +#ifndef HEADER_CURL_SLIST_WC_H +#define HEADER_CURL_SLIST_WC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "tool_setup.h" +#ifndef CURL_DISABLE_LIBCURL_OPTION + +/* linked-list structure with last node cache for easysrc */ +struct slist_wc { + struct curl_slist *first; + struct curl_slist *last; +}; + +/* + * NAME curl_slist_wc_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +struct slist_wc *slist_wc_append(struct slist_wc *, const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist_wc. + */ +void slist_wc_free_all(struct slist_wc *); + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ + +#endif /* HEADER_CURL_SLIST_WC_H */ diff --git a/src/tool_binmode.c b/src/tool_binmode.c new file mode 100644 index 0000000..e27ce96 --- /dev/null +++ b/src/tool_binmode.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SETMODE + +#ifdef HAVE_IO_H +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#include "tool_binmode.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void set_binmode(FILE *stream) +{ +#ifdef O_BINARY +# ifdef __HIGHC__ + _setmode(stream, O_BINARY); +# else + (void)setmode(fileno(stream), O_BINARY); +# endif +#else + (void)stream; +#endif +} + +#endif /* HAVE_SETMODE */ diff --git a/src/tool_binmode.h b/src/tool_binmode.h new file mode 100644 index 0000000..bee837b --- /dev/null +++ b/src/tool_binmode.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_TOOL_BINMODE_H +#define HEADER_CURL_TOOL_BINMODE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SETMODE + +void set_binmode(FILE *stream); + +#else + +#define set_binmode(x) Curl_nop_stmt + +#endif /* HAVE_SETMODE */ + +#endif /* HEADER_CURL_TOOL_BINMODE_H */ diff --git a/src/tool_bname.c b/src/tool_bname.c new file mode 100644 index 0000000..4ba1a3b --- /dev/null +++ b/src/tool_bname.c @@ -0,0 +1,51 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "tool_bname.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifndef HAVE_BASENAME + +char *tool_basename(char *path) +{ + char *s1; + char *s2; + + s1 = strrchr(path, '/'); + s2 = strrchr(path, '\\'); + + if(s1 && s2) { + path = (s1 > s2) ? s1 + 1 : s2 + 1; + } + else if(s1) + path = s1 + 1; + else if(s2) + path = s2 + 1; + + return path; +} + +#endif /* HAVE_BASENAME */ diff --git a/src/tool_bname.h b/src/tool_bname.h new file mode 100644 index 0000000..d091c22 --- /dev/null +++ b/src/tool_bname.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_BNAME_H +#define HEADER_CURL_TOOL_BNAME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifndef HAVE_BASENAME + +char *tool_basename(char *path); + +#define basename(x) tool_basename((x)) + +#endif /* HAVE_BASENAME */ + +#endif /* HEADER_CURL_TOOL_BNAME_H */ diff --git a/src/tool_cb_dbg.c b/src/tool_cb_dbg.c new file mode 100644 index 0000000..cbf57f0 --- /dev/null +++ b/src/tool_cb_dbg.c @@ -0,0 +1,300 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_cb_dbg.h" +#include "tool_util.h" + +#include "memdebug.h" /* keep this as LAST include */ + +static void dump(const char *timebuf, const char *idsbuf, const char *text, + FILE *stream, const unsigned char *ptr, size_t size, + trace tracetype, curl_infotype infotype); + +/* + * Return the formatted HH:MM:SS for the tv_sec given. + * NOT thread safe. + */ +static const char *hms_for_sec(time_t tv_sec) +{ + static time_t cached_tv_sec; + static char hms_buf[12]; + static time_t epoch_offset; + static int known_epoch; + + if(tv_sec != cached_tv_sec) { + struct tm *now; + time_t secs; + /* recalculate */ + if(!known_epoch) { + epoch_offset = time(NULL) - tv_sec; + known_epoch = 1; + } + secs = epoch_offset + tv_sec; + /* !checksrc! disable BANNEDFUNC 1 */ + now = localtime(&secs); /* not thread safe but we don't care */ + msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d", + now->tm_hour, now->tm_min, now->tm_sec); + cached_tv_sec = tv_sec; + } + return hms_buf; +} + +static void log_line_start(FILE *log, const char *timebuf, + const char *idsbuf, curl_infotype type) +{ + /* + * This is the trace look that is similar to what libcurl makes on its + * own. + */ + static const char * const s_infotype[] = { + "* ", "< ", "> ", "{ ", "} ", "{ ", "} " + }; + if((timebuf && *timebuf) || (idsbuf && *idsbuf)) + fprintf(log, "%s%s%s", timebuf, idsbuf, s_infotype[type]); + else + fputs(s_infotype[type], log); +} + +#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] " +#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \ + CURL_FORMAT_CURL_OFF_T "] " +/* +** callback for CURLOPT_DEBUGFUNCTION +*/ +int tool_debug_cb(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userdata) +{ + struct OperationConfig *operation = userdata; + struct GlobalConfig *config = operation->global; + FILE *output = tool_stderr; + const char *text; + struct timeval tv; + char timebuf[20]; + /* largest signed 64bit is: 9,223,372,036,854,775,807 + * max length in decimal: 1 + (6*3) = 19 + * formatted via TRC_IDS_FORMAT_IDS_2 this becomes 2 + 19 + 1 + 19 + 2 = 43 + * negative xfer-id are not printed, negative conn-ids use TRC_IDS_FORMAT_1 + */ + char idsbuf[60]; + curl_off_t xfer_id, conn_id; + + (void)handle; /* not used */ + + if(config->tracetime) { + tv = tvnow(); + msnprintf(timebuf, sizeof(timebuf), "%s.%06ld ", + hms_for_sec(tv.tv_sec), (long)tv.tv_usec); + } + else + timebuf[0] = 0; + + if(handle && config->traceids && + !curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { + if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && + conn_id >= 0) { + msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, + xfer_id, conn_id); + } + else { + msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); + } + } + else + idsbuf[0] = 0; + + if(!config->trace_stream) { + /* open for append */ + if(!strcmp("-", config->trace_dump)) + config->trace_stream = stdout; + else if(!strcmp("%", config->trace_dump)) + /* Ok, this is somewhat hackish but we do it undocumented for now */ + config->trace_stream = tool_stderr; + else { + config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT); + config->trace_fopened = TRUE; + } + } + + if(config->trace_stream) + output = config->trace_stream; + + if(!output) { + warnf(config, "Failed to create/open output"); + return 0; + } + + if(config->tracetype == TRACE_PLAIN) { + static bool newl = FALSE; + static bool traced_data = FALSE; + + switch(type) { + case CURLINFO_HEADER_OUT: + if(size > 0) { + size_t st = 0; + size_t i; + for(i = 0; i < size - 1; i++) { + if(data[i] == '\n') { /* LF */ + if(!newl) { + log_line_start(output, timebuf, idsbuf, type); + } + (void)fwrite(data + st, i - st + 1, 1, output); + st = i + 1; + newl = FALSE; + } + } + if(!newl) + log_line_start(output, timebuf, idsbuf, type); + (void)fwrite(data + st, i - st + 1, 1, output); + } + newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; + traced_data = FALSE; + break; + case CURLINFO_TEXT: + case CURLINFO_HEADER_IN: + if(!newl) + log_line_start(output, timebuf, idsbuf, type); + (void)fwrite(data, size, 1, output); + newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; + traced_data = FALSE; + break; + case CURLINFO_DATA_OUT: + case CURLINFO_DATA_IN: + case CURLINFO_SSL_DATA_IN: + case CURLINFO_SSL_DATA_OUT: + if(!traced_data) { + /* if the data is output to a tty and we're sending this debug trace + to stderr or stdout, we don't display the alert about the data not + being shown as the data _is_ shown then just not via this + function */ + if(!config->isatty || + ((output != tool_stderr) && (output != stdout))) { + if(!newl) + log_line_start(output, timebuf, idsbuf, type); + fprintf(output, "[%zu bytes data]\n", size); + newl = FALSE; + traced_data = TRUE; + } + } + break; + default: /* nada */ + newl = FALSE; + traced_data = FALSE; + break; + } + + return 0; + } + + switch(type) { + case CURLINFO_TEXT: + fprintf(output, "%s%s== Info: %.*s", timebuf, idsbuf, (int)size, data); + FALLTHROUGH(); + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + } + + dump(timebuf, idsbuf, text, output, (unsigned char *) data, size, + config->tracetype, type); + return 0; +} + +static void dump(const char *timebuf, const char *idsbuf, const char *text, + FILE *stream, const unsigned char *ptr, size_t size, + trace tracetype, curl_infotype infotype) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(tracetype == TRACE_ASCII) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf, + text, size, size); + + for(i = 0; i < size; i += width) { + + fprintf(stream, "%04zx: ", i); + + if(tracetype == TRACE_BIN) { + /* hex not disabled, show it */ + for(c = 0; c < width; c++) + if(i + c < size) + fprintf(stream, "%02x ", ptr[i + c]); + else + fputs(" ", stream); + } + + for(c = 0; (c < width) && (i + c < size); c++) { + /* check for 0D0A; if found, skip past and start a new line of output */ + if((tracetype == TRACE_ASCII) && + (i + c + 1 < size) && (ptr[i + c] == 0x0D) && + (ptr[i + c + 1] == 0x0A)) { + i += (c + 2 - width); + break; + } + (void)infotype; + fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ? + ptr[i + c] : UNPRINTABLE_CHAR); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if((tracetype == TRACE_ASCII) && + (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) && + (ptr[i + c + 2] == 0x0A)) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} diff --git a/src/tool_cb_dbg.h b/src/tool_cb_dbg.h new file mode 100644 index 0000000..d78afb3 --- /dev/null +++ b/src/tool_cb_dbg.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_CB_DBG_H +#define HEADER_CURL_TOOL_CB_DBG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* +** callback for CURLOPT_DEBUGFUNCTION +*/ + +int tool_debug_cb(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userdata); + +#endif /* HEADER_CURL_TOOL_CB_DBG_H */ diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c new file mode 100644 index 0000000..30ee3b0 --- /dev/null +++ b/src/tool_cb_hdr.c @@ -0,0 +1,442 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_doswin.h" +#include "tool_msgs.h" +#include "tool_cb_hdr.h" +#include "tool_cb_wrt.h" +#include "tool_operate.h" +#include "tool_libinfo.h" + +#include "memdebug.h" /* keep this as LAST include */ + +static char *parse_filename(const char *ptr, size_t len); + +#ifdef _WIN32 +#define BOLD "\x1b[1m" +#define BOLDOFF "\x1b[22m" +#else +#define BOLD "\x1b[1m" +/* Switch off bold by setting "all attributes off" since the explicit + bold-off code (21) isn't supported everywhere - like in the mac + Terminal. */ +#define BOLDOFF "\x1b[0m" +/* OSC 8 hyperlink escape sequence */ +#define LINK "\x1b]8;;" +#define LINKST "\x1b\\" +#define LINKOFF LINK LINKST +#endif + +#ifdef LINK +static void write_linked_location(CURL *curl, const char *location, + size_t loclen, FILE *stream); +#endif + +/* +** callback for CURLOPT_HEADERFUNCTION +*/ + +size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + struct per_transfer *per = userdata; + struct HdrCbData *hdrcbdata = &per->hdrcbdata; + struct OutStruct *outs = &per->outs; + struct OutStruct *heads = &per->heads; + struct OutStruct *etag_save = &per->etag_save; + const char *str = ptr; + const size_t cb = size * nmemb; + const char *end = (char *)ptr + cb; + const char *scheme = NULL; + + if(!per->config) + return CURL_WRITEFUNC_ERROR; + +#ifdef DEBUGBUILD + if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { + warnf(per->config->global, "Header data exceeds single call write limit"); + return CURL_WRITEFUNC_ERROR; + } +#endif + +#ifdef _WIN32 + /* Discard incomplete UTF-8 sequence buffered from body */ + if(outs->utf8seq[0]) + memset(outs->utf8seq, 0, sizeof(outs->utf8seq)); +#endif + + /* + * Write header data when curl option --dump-header (-D) is given. + */ + + if(per->config->headerfile && heads->stream) { + size_t rc = fwrite(ptr, size, nmemb, heads->stream); + if(rc != cb) + return rc; + /* flush the stream to send off what we got earlier */ + (void)fflush(heads->stream); + } + + /* + * Write etag to file when --etag-save option is given. + */ + if(per->config->etag_save_file && etag_save->stream) { + /* match only header that start with etag (case insensitive) */ + if(curl_strnequal(str, "etag:", 5)) { + const char *etag_h = &str[5]; + const char *eot = end - 1; + if(*eot == '\n') { + while(ISBLANK(*etag_h) && (etag_h < eot)) + etag_h++; + while(ISSPACE(*eot)) + eot--; + + if(eot >= etag_h) { + size_t etag_length = eot - etag_h + 1; + fwrite(etag_h, size, etag_length, etag_save->stream); + /* terminate with newline */ + fputc('\n', etag_save->stream); + (void)fflush(etag_save->stream); + } + } + } + } + + /* + * This callback sets the filename where output shall be written when + * curl options --remote-name (-O) and --remote-header-name (-J) have + * been simultaneously given and additionally server returns an HTTP + * Content-Disposition header specifying a filename property. + */ + + curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme); + scheme = proto_token(scheme); + if(hdrcbdata->honor_cd_filename && + (cb > 20) && checkprefix("Content-disposition:", str) && + (scheme == proto_http || scheme == proto_https)) { + const char *p = str + 20; + + /* look for the 'filename=' parameter + (encoded filenames (*=) are not supported) */ + for(;;) { + char *filename; + size_t len; + + while((p < end) && *p && !ISALPHA(*p)) + p++; + if(p > end - 9) + break; + + if(memcmp(p, "filename=", 9)) { + /* no match, find next parameter */ + while((p < end) && *p && (*p != ';')) + p++; + if((p < end) && *p) + continue; + else + break; + } + p += 9; + + /* this expression below typecasts 'cb' only to avoid + warning: signed and unsigned type in conditional expression + */ + len = (ssize_t)cb - (p - str); + filename = parse_filename(p, len); + if(filename) { + if(outs->stream) { + /* indication of problem, get out! */ + free(filename); + return CURL_WRITEFUNC_ERROR; + } + + if(per->config->output_dir) { + outs->filename = aprintf("%s/%s", per->config->output_dir, filename); + free(filename); + if(!outs->filename) + return CURL_WRITEFUNC_ERROR; + } + else + outs->filename = filename; + + outs->is_cd_filename = TRUE; + outs->s_isreg = TRUE; + outs->fopened = FALSE; + outs->alloc_filename = TRUE; + hdrcbdata->honor_cd_filename = FALSE; /* done now! */ + if(!tool_create_output_file(outs, per->config)) + return CURL_WRITEFUNC_ERROR; + } + break; + } + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return CURL_WRITEFUNC_ERROR; + } + if(hdrcbdata->config->writeout) { + char *value = memchr(ptr, ':', cb); + if(value) { + if(per->was_last_header_empty) + per->num_headers = 0; + per->was_last_header_empty = FALSE; + per->num_headers++; + } + else if(ptr[0] == '\r' || ptr[0] == '\n') + per->was_last_header_empty = TRUE; + } + if(hdrcbdata->config->show_headers && + (scheme == proto_http || scheme == proto_https || + scheme == proto_rtsp || scheme == proto_file)) { + /* bold headers only for selected protocols */ + char *value = NULL; + + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return CURL_WRITEFUNC_ERROR; + + if(hdrcbdata->global->isatty && +#ifdef _WIN32 + tool_term_has_bold && +#endif + hdrcbdata->global->styled_output) + value = memchr(ptr, ':', cb); + if(value) { + size_t namelen = value - ptr; + fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", (int)namelen, ptr); +#ifndef LINK + fwrite(&value[1], cb - namelen - 1, 1, outs->stream); +#else + if(curl_strnequal("Location", ptr, namelen)) { + write_linked_location(per->curl, &value[1], cb - namelen - 1, + outs->stream); + } + else + fwrite(&value[1], cb - namelen - 1, 1, outs->stream); +#endif + } + else + /* not "handled", just show it */ + fwrite(ptr, cb, 1, outs->stream); + } + return cb; +} + +/* + * Copies a file name part and returns an ALLOCATED data buffer. + */ +static char *parse_filename(const char *ptr, size_t len) +{ + char *copy; + char *p; + char *q; + char stop = '\0'; + + /* simple implementation of strndup() */ + copy = malloc(len + 1); + if(!copy) + return NULL; + memcpy(copy, ptr, len); + copy[len] = '\0'; + + p = copy; + if(*p == '\'' || *p == '"') { + /* store the starting quote */ + stop = *p; + p++; + } + else + stop = ';'; + + /* scan for the end letter and stop there */ + q = strchr(p, stop); + if(q) + *q = '\0'; + + /* if the filename contains a path, only use filename portion */ + q = strrchr(p, '/'); + if(q) { + p = q + 1; + if(!*p) { + Curl_safefree(copy); + return NULL; + } + } + + /* If the filename contains a backslash, only use filename portion. The idea + is that even systems that don't handle backslashes as path separators + probably want the path removed for convenience. */ + q = strrchr(p, '\\'); + if(q) { + p = q + 1; + if(!*p) { + Curl_safefree(copy); + return NULL; + } + } + + /* make sure the file name doesn't end in \r or \n */ + q = strchr(p, '\r'); + if(q) + *q = '\0'; + + q = strchr(p, '\n'); + if(q) + *q = '\0'; + + if(copy != p) + memmove(copy, p, strlen(p) + 1); + +#if defined(_WIN32) || defined(MSDOS) + { + char *sanitized; + SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0); + Curl_safefree(copy); + if(sc) + return NULL; + copy = sanitized; + } +#endif /* _WIN32 || MSDOS */ + + /* in case we built debug enabled, we allow an environment variable + * named CURL_TESTDIR to prefix the given file name to put it into a + * specific directory + */ +#ifdef DEBUGBUILD + { + char *tdir = curlx_getenv("CURL_TESTDIR"); + if(tdir) { + char buffer[512]; /* suitably large */ + msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy); + Curl_safefree(copy); + copy = strdup(buffer); /* clone the buffer, we don't use the libcurl + aprintf() or similar since we want to use the + same memory code as the "real" parse_filename + function */ + curl_free(tdir); + } + } +#endif + + return copy; +} + +#ifdef LINK +/* + * Treat the Location: header specially, by writing a special escape + * sequence that adds a hyperlink to the displayed text. This makes + * the absolute URL of the redirect clickable in supported terminals, + * which couldn't happen otherwise for relative URLs. The Location: + * header is supposed to always be absolute so this theoretically + * shouldn't be needed but the real world returns plenty of relative + * URLs here. + */ +static +void write_linked_location(CURL *curl, const char *location, size_t loclen, + FILE *stream) { + /* This would so simple if CURLINFO_REDIRECT_URL were available here */ + CURLU *u = NULL; + char *copyloc = NULL, *locurl = NULL, *scheme = NULL, *finalurl = NULL; + const char *loc = location; + size_t llen = loclen; + int space_skipped = 0; + char *vver = getenv("VTE_VERSION"); + + if(vver) { + long vvn = strtol(vver, NULL, 10); + /* Skip formatting for old versions of VTE <= 0.48.1 (Mar 2017) since some + of those versions have formatting bugs. (#10428) */ + if(0 < vvn && vvn <= 4801) + goto locout; + } + + /* Strip leading whitespace of the redirect URL */ + while(llen && (*loc == ' ' || *loc == '\t')) { + ++loc; + --llen; + ++space_skipped; + } + + /* Strip the trailing end-of-line characters, normally "\r\n" */ + while(llen && (loc[llen-1] == '\n' || loc[llen-1] == '\r')) + --llen; + + /* CURLU makes it easy to handle the relative URL case */ + u = curl_url(); + if(!u) + goto locout; + + /* Create a NUL-terminated and whitespace-stripped copy of Location: */ + copyloc = malloc(llen + 1); + if(!copyloc) + goto locout; + memcpy(copyloc, loc, llen); + copyloc[llen] = 0; + + /* The original URL to use as a base for a relative redirect URL */ + if(curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &locurl)) + goto locout; + if(curl_url_set(u, CURLUPART_URL, locurl, 0)) + goto locout; + + /* Redirected location. This can be either absolute or relative. */ + if(curl_url_set(u, CURLUPART_URL, copyloc, 0)) + goto locout; + + if(curl_url_get(u, CURLUPART_URL, &finalurl, CURLU_NO_DEFAULT_PORT)) + goto locout; + + if(curl_url_get(u, CURLUPART_SCHEME, &scheme, 0)) + goto locout; + + if(!strcmp("http", scheme) || + !strcmp("https", scheme) || + !strcmp("ftp", scheme) || + !strcmp("ftps", scheme)) { + fprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF, + space_skipped, location, + finalurl, + (int)loclen - space_skipped, loc); + goto locdone; + } + + /* Not a "safe" URL: don't linkify it */ + +locout: + /* Write the normal output in case of error or unsafe */ + fwrite(location, loclen, 1, stream); + +locdone: + if(u) { + curl_free(finalurl); + curl_free(scheme); + curl_url_cleanup(u); + free(copyloc); + } +} +#endif diff --git a/src/tool_cb_hdr.h b/src/tool_cb_hdr.h new file mode 100644 index 0000000..a855052 --- /dev/null +++ b/src/tool_cb_hdr.h @@ -0,0 +1,58 @@ +#ifndef HEADER_CURL_TOOL_CB_HDR_H +#define HEADER_CURL_TOOL_CB_HDR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* + * curl operates using a single HdrCbData struct variable, a + * pointer to this is passed as userdata pointer to tool_header_cb. + * + * 'outs' member is a pointer to the OutStruct variable used to keep + * track of information relative to curl's output writing. + * + * 'heads' member is a pointer to the OutStruct variable used to keep + * track of information relative to header response writing. + * + * 'honor_cd_filename' member is TRUE when tool_header_cb is allowed + * to honor Content-Disposition filename property and accordingly + * set 'outs' filename, otherwise FALSE; + */ + +struct HdrCbData { + struct GlobalConfig *global; + struct OperationConfig *config; + struct OutStruct *outs; + struct OutStruct *heads; + struct OutStruct *etag_save; + bool honor_cd_filename; +}; + +/* +** callback for CURLOPT_HEADERFUNCTION +*/ + +size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata); + +#endif /* HEADER_CURL_TOOL_CB_HDR_H */ diff --git a/src/tool_cb_prg.c b/src/tool_cb_prg.c new file mode 100644 index 0000000..86b6fa6 --- /dev/null +++ b/src/tool_cb_prg.c @@ -0,0 +1,292 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_cb_prg.h" +#include "tool_util.h" +#include "tool_operate.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#define MAX_BARLENGTH 256 + +#ifdef HAVE_TERMIOS_H +# include +#elif defined(HAVE_TERMIO_H) +# include +#endif + +/* 200 values generated by this perl code: + + my $pi = 3.1415; + foreach my $i (1 .. 200) { + printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000; + } +*/ +static const unsigned int sinus[] = { + 515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491, + 654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906, + 781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047, + 885248, 895069, 904500, 913532, 922156, 930363, 938145, 945495, 952406, + 958870, 964881, 970434, 975522, 980141, 984286, 987954, 991139, 993840, + 996054, 997778, 999011, 999752, 999999, 999754, 999014, 997783, 996060, + 993848, 991148, 987964, 984298, 980154, 975536, 970449, 964898, 958888, + 952426, 945516, 938168, 930386, 922180, 913558, 904527, 895097, 885277, + 875077, 864507, 853577, 842299, 830682, 818739, 806482, 793922, 781072, + 767945, 754553, 740910, 727030, 712925, 698610, 684100, 669407, 654548, + 639536, 624386, 609113, 593733, 578260, 562710, 547098, 531440, 515751, + 500046, 484341, 468651, 452993, 437381, 421830, 406357, 390976, 375703, + 360552, 345539, 330679, 315985, 301474, 287158, 273052, 259170, 245525, + 232132, 219003, 206152, 193590, 181331, 169386, 157768, 146487, 135555, + 124983, 114781, 104959, 95526, 86493, 77868, 69660, 61876, 54525, 47613, + 41147, 35135, 29581, 24491, 19871, 15724, 12056, 8868, 6166, 3951, 2225, + 990, 248, 0, 244, 982, 2212, 3933, 6144, 8842, 12025, 15690, 19832, 24448, + 29534, 35084, 41092, 47554, 54462, 61809, 69589, 77794, 86415, 95445, + 104873, 114692, 124891, 135460, 146389, 157667, 169282, 181224, 193480, + 206039, 218888, 232015, 245406, 259048, 272928, 287032, 301346, 315856, + 330548, 345407, 360419, 375568, 390841, 406221, 421693, 437243, 452854, + 468513, 484202, 499907 +}; + +static void fly(struct ProgressData *bar, bool moved) +{ + char buf[MAX_BARLENGTH + 2]; + int pos; + int check = bar->width - 2; + + /* bar->width is range checked when assigned */ + DEBUGASSERT(bar->width <= MAX_BARLENGTH); + memset(buf, ' ', bar->width); + buf[bar->width] = '\r'; + buf[bar->width + 1] = '\0'; + + memcpy(&buf[bar->bar], "-=O=-", 5); + + pos = sinus[bar->tick%200] / (1000000 / check); + buf[pos] = '#'; + pos = sinus[(bar->tick + 5)%200] / (1000000 / check); + buf[pos] = '#'; + pos = sinus[(bar->tick + 10)%200] / (1000000 / check); + buf[pos] = '#'; + pos = sinus[(bar->tick + 15)%200] / (1000000 / check); + buf[pos] = '#'; + + fputs(buf, bar->out); + bar->tick += 2; + if(bar->tick >= 200) + bar->tick -= 200; + + bar->bar += (moved?bar->barmove:0); + if(bar->bar >= (bar->width - 6)) { + bar->barmove = -1; + bar->bar = bar->width - 6; + } + else if(bar->bar < 0) { + bar->barmove = 1; + bar->bar = 0; + } +} + +/* +** callback for CURLOPT_XFERINFOFUNCTION +*/ + +#if (SIZEOF_CURL_OFF_T < 8) +#error "too small curl_off_t" +#else + /* assume SIZEOF_CURL_OFF_T == 8 */ +# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) +#endif + +int tool_progress_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + struct timeval now = tvnow(); + struct per_transfer *per = clientp; + struct OperationConfig *config = per->config; + struct ProgressData *bar = &per->progressbar; + curl_off_t total; + curl_off_t point; + + /* Calculate expected transfer size. initial_size can be less than zero when + indicating that we are expecting to get the filesize from the remote */ + if(bar->initial_size < 0) { + if(dltotal || ultotal) + total = dltotal + ultotal; + else + total = CURL_OFF_T_MAX; + } + else if((CURL_OFF_T_MAX - bar->initial_size) < (dltotal + ultotal)) + total = CURL_OFF_T_MAX; + else + total = dltotal + ultotal + bar->initial_size; + + /* Calculate the current progress. initial_size can be less than zero when + indicating that we are expecting to get the filesize from the remote */ + if(bar->initial_size < 0) { + if(dltotal || ultotal) + point = dlnow + ulnow; + else + point = CURL_OFF_T_MAX; + } + else if((CURL_OFF_T_MAX - bar->initial_size) < (dlnow + ulnow)) + point = CURL_OFF_T_MAX; + else + point = dlnow + ulnow + bar->initial_size; + + if(bar->calls) { + /* after first call... */ + if(total) { + /* we know the total data to get... */ + if(bar->prev == point) + /* progress didn't change since last invoke */ + return 0; + else if((tvdiff(now, bar->prevtime) < 100L) && point < total) + /* limit progress-bar updating to 10 Hz except when we're at 100% */ + return 0; + } + else { + /* total is unknown */ + if(tvdiff(now, bar->prevtime) < 100L) + /* limit progress-bar updating to 10 Hz */ + return 0; + fly(bar, point != bar->prev); + } + } + + /* simply count invokes */ + bar->calls++; + + if((total > 0) && (point != bar->prev)) { + char line[MAX_BARLENGTH + 1]; + char format[40]; + double frac; + double percent; + int barwidth; + int num; + if(point > total) + /* we have got more than the expected total! */ + total = point; + + frac = (double)point / (double)total; + percent = frac * 100.0; + barwidth = bar->width - 7; + num = (int) (((double)barwidth) * frac); + if(num > MAX_BARLENGTH) + num = MAX_BARLENGTH; + memset(line, '#', num); + line[num] = '\0'; + msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + fprintf(bar->out, format, line, percent); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + fflush(bar->out); + bar->prev = point; + bar->prevtime = now; + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + + return 0; +} + +void progressbarinit(struct ProgressData *bar, + struct OperationConfig *config) +{ + char *colp; + memset(bar, 0, sizeof(struct ProgressData)); + + /* pass the resume from value through to the progress function so it can + * display progress towards total file not just the part that's left. */ + if(config->use_resume) + bar->initial_size = config->resume_from; + + colp = curlx_getenv("COLUMNS"); + if(colp) { + char *endptr; + long num = strtol(colp, &endptr, 10); + if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) && + (num < 10000)) + bar->width = (int)num; + curl_free(colp); + } + + if(!bar->width) { + int cols = 0; + +#ifdef TIOCGSIZE + struct ttysize ts; + if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts)) + cols = ts.ts_cols; +#elif defined(TIOCGWINSZ) + struct winsize ts; + if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts)) + cols = ts.ws_col; +#elif defined(_WIN32) + { + HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO console_info; + + if((stderr_hnd != INVALID_HANDLE_VALUE) && + GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) { + /* + * Do not use +1 to get the true screen-width since writing a + * character at the right edge will cause a line wrap. + */ + cols = (int) + (console_info.srWindow.Right - console_info.srWindow.Left); + } + } +#endif /* TIOCGSIZE */ + if(cols > 20) + bar->width = cols; + } + + if(!bar->width) + bar->width = 79; + else if(bar->width > MAX_BARLENGTH) + bar->width = MAX_BARLENGTH; + + bar->out = tool_stderr; + bar->tick = 150; + bar->barmove = 1; +} diff --git a/src/tool_cb_prg.h b/src/tool_cb_prg.h new file mode 100644 index 0000000..565ad56 --- /dev/null +++ b/src/tool_cb_prg.h @@ -0,0 +1,54 @@ +#ifndef HEADER_CURL_TOOL_CB_PRG_H +#define HEADER_CURL_TOOL_CB_PRG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define CURL_PROGRESS_STATS 0 /* default progress display */ +#define CURL_PROGRESS_BAR 1 + +struct ProgressData { + int calls; + curl_off_t prev; + struct timeval prevtime; + int width; + FILE *out; /* where to write everything to */ + curl_off_t initial_size; + unsigned int tick; + int bar; + int barmove; +}; + +void progressbarinit(struct ProgressData *bar, + struct OperationConfig *config); + +/* +** callback for CURLOPT_PROGRESSFUNCTION +*/ + +int tool_progress_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow); + +#endif /* HEADER_CURL_TOOL_CB_PRG_H */ diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c new file mode 100644 index 0000000..8cb5bbe --- /dev/null +++ b/src/tool_cb_rea.c @@ -0,0 +1,132 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_cb_rea.h" +#include "tool_operate.h" +#include "tool_util.h" +#include "tool_msgs.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* +** callback for CURLOPT_READFUNCTION +*/ + +size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) +{ + ssize_t rc = 0; + struct per_transfer *per = userdata; + struct OperationConfig *config = per->config; + + if((per->uploadfilesize != -1) && + (per->uploadedsofar == per->uploadfilesize)) { + /* done */ + return 0; + } + + if(config->timeout_ms) { + struct timeval now = tvnow(); + long msdelta = tvdiff(now, per->start); + + if(msdelta > config->timeout_ms) + /* timeout */ + return 0; +#ifndef _WIN32 + /* this logic waits on read activity on a file descriptor that is not a + socket which makes it not work with select() on Windows */ + else { + fd_set bits; + struct timeval timeout; + long wait = config->timeout_ms - msdelta; + + /* wait this long at the most */ + timeout.tv_sec = wait/1000; + timeout.tv_usec = (int)((wait%1000)*1000); + + FD_ZERO(&bits); + FD_SET(per->infd, &bits); + if(!select(per->infd + 1, &bits, NULL, NULL, &timeout)) + return 0; /* timeout */ + } +#endif + } + + rc = read(per->infd, buffer, sz*nmemb); + if(rc < 0) { + if(errno == EAGAIN) { + errno = 0; + config->readbusy = TRUE; + return CURL_READFUNC_PAUSE; + } + /* since size_t is unsigned we can't return negative values fine */ + rc = 0; + } + if((per->uploadfilesize != -1) && + (per->uploadedsofar + rc > per->uploadfilesize)) { + /* do not allow uploading more than originally set out to do */ + curl_off_t delta = per->uploadedsofar + rc - per->uploadfilesize; + warnf(per->config->global, "File size larger in the end than when " + "started. Dropping at least %" CURL_FORMAT_CURL_OFF_T " bytes", + delta); + rc = (ssize_t)(per->uploadfilesize - per->uploadedsofar); + } + config->readbusy = FALSE; + + /* when select() returned zero here, it timed out */ + return (size_t)rc; +} + +/* +** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads +*/ + +int tool_readbusy_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + struct per_transfer *per = clientp; + struct OperationConfig *config = per->config; + + (void)dltotal; /* unused */ + (void)dlnow; /* unused */ + (void)ultotal; /* unused */ + (void)ulnow; /* unused */ + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + + return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE; +} diff --git a/src/tool_cb_rea.h b/src/tool_cb_rea.h new file mode 100644 index 0000000..06899d3 --- /dev/null +++ b/src/tool_cb_rea.h @@ -0,0 +1,42 @@ +#ifndef HEADER_CURL_TOOL_CB_REA_H +#define HEADER_CURL_TOOL_CB_REA_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* +** callback for CURLOPT_READFUNCTION +*/ + +size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata); + +/* +** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads +*/ + +int tool_readbusy_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow); + +#endif /* HEADER_CURL_TOOL_CB_REA_H */ diff --git a/src/tool_cb_see.c b/src/tool_cb_see.c new file mode 100644 index 0000000..bce57bb --- /dev/null +++ b/src/tool_cb_see.c @@ -0,0 +1,121 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_operate.h" +#include "tool_cb_see.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* OUR_MAX_SEEK_L has 'long' data type, OUR_MAX_SEEK_O has 'curl_off_t, + both represent the same value. Maximum offset used here when we lseek + using a 'long' data type offset */ + +#define OUR_MAX_SEEK_L 2147483647L - 1L +#define OUR_MAX_SEEK_O CURL_OFF_T_C(0x7FFFFFFF) - CURL_OFF_T_C(0x1) + +/* +** callback for CURLOPT_SEEKFUNCTION +** +** Notice that this is not supposed to return the resulting offset. This +** shall only return CURL_SEEKFUNC_* return codes. +*/ + +int tool_seek_cb(void *userdata, curl_off_t offset, int whence) +{ + struct per_transfer *per = userdata; + +#if(SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES) + + /* The offset check following here is only interesting if curl_off_t is + larger than off_t and we are not using the WIN32 large file support + macros that provide the support to do 64bit seeks correctly */ + + if(offset > OUR_MAX_SEEK_O) { + /* Some precaution code to work around problems with different data sizes + to allow seeking >32bit even if off_t is 32bit. Should be very rare and + is really valid on weirdo-systems. */ + curl_off_t left = offset; + + if(whence != SEEK_SET) + /* this code path doesn't support other types */ + return CURL_SEEKFUNC_FAIL; + + if(LSEEK_ERROR == lseek(per->infd, 0, SEEK_SET)) + /* couldn't rewind to beginning */ + return CURL_SEEKFUNC_FAIL; + + while(left) { + long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left; + if(LSEEK_ERROR == lseek(per->infd, step, SEEK_CUR)) + /* couldn't seek forwards the desired amount */ + return CURL_SEEKFUNC_FAIL; + left -= step; + } + return CURL_SEEKFUNC_OK; + } +#endif + + if(LSEEK_ERROR == lseek(per->infd, offset, whence)) + /* couldn't rewind, the reason is in errno but errno is just not portable + enough and we don't actually care that much why we failed. We'll let + libcurl know that it may try other means if it wants to. */ + return CURL_SEEKFUNC_CANTSEEK; + + return CURL_SEEKFUNC_OK; +} + +#ifdef USE_TOOL_FTRUNCATE + +#ifdef _WIN32_WCE +/* 64-bit lseek-like function unavailable */ +# undef _lseeki64 +# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) +# undef _get_osfhandle +# define _get_osfhandle(fd) (fd) +#endif + +/* + * Truncate a file handle at a 64-bit position 'where'. + */ + +int tool_ftruncate64(int fd, curl_off_t where) +{ + intptr_t handle = _get_osfhandle(fd); + + if(_lseeki64(fd, where, SEEK_SET) < 0) + return -1; + + if(!SetEndOfFile((HANDLE)handle)) + return -1; + + return 0; +} + +#endif /* USE_TOOL_FTRUNCATE */ diff --git a/src/tool_cb_see.h b/src/tool_cb_see.h new file mode 100644 index 0000000..b5d7bf9 --- /dev/null +++ b/src/tool_cb_see.h @@ -0,0 +1,46 @@ +#ifndef HEADER_CURL_TOOL_CB_SEE_H +#define HEADER_CURL_TOOL_CB_SEE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(_WIN32) && !defined(HAVE_FTRUNCATE) + +int tool_ftruncate64(int fd, curl_off_t where); + +#undef ftruncate +#define ftruncate(fd,where) tool_ftruncate64(fd,where) + +#define HAVE_FTRUNCATE 1 +#define USE_TOOL_FTRUNCATE 1 + +#endif /* _WIN32 && ! HAVE_FTRUNCATE */ + +/* +** callback for CURLOPT_SEEKFUNCTION +*/ + +int tool_seek_cb(void *userdata, curl_off_t offset, int whence); + +#endif /* HEADER_CURL_TOOL_CB_SEE_H */ diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c new file mode 100644 index 0000000..143cba2 --- /dev/null +++ b/src/tool_cb_wrt.c @@ -0,0 +1,371 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_FCNTL_H +/* for open() */ +#include +#endif + +#include + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_cb_wrt.h" +#include "tool_operate.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifdef _WIN32 +#define OPENMODE S_IREAD | S_IWRITE +#else +#define OPENMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH +#endif + +/* create/open a local file for writing, return TRUE on success */ +bool tool_create_output_file(struct OutStruct *outs, + struct OperationConfig *config) +{ + struct GlobalConfig *global; + FILE *file = NULL; + char *fname = outs->filename; + DEBUGASSERT(outs); + DEBUGASSERT(config); + global = config->global; + if(!fname || !*fname) { + warnf(global, "Remote filename has no length"); + return FALSE; + } + + if(config->file_clobber_mode == CLOBBER_ALWAYS || + (config->file_clobber_mode == CLOBBER_DEFAULT && + !outs->is_cd_filename)) { + /* open file for writing */ + file = fopen(fname, "wb"); + } + else { + int fd; + do { + fd = open(fname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE); + /* Keep retrying in the hope that it isn't interrupted sometime */ + } while(fd == -1 && errno == EINTR); + if(config->file_clobber_mode == CLOBBER_NEVER && fd == -1) { + int next_num = 1; + size_t len = strlen(fname); + size_t newlen = len + 13; /* nul + 1-11 digits + dot */ + char *newname; + /* Guard against wraparound in new filename */ + if(newlen < len) { + errorf(global, "overflow in filename generation"); + return FALSE; + } + newname = malloc(newlen); + if(!newname) { + errorf(global, "out of memory"); + return FALSE; + } + memcpy(newname, fname, len); + newname[len] = '.'; + while(fd == -1 && /* haven't successfully opened a file */ + (errno == EEXIST || errno == EISDIR) && + /* because we keep having files that already exist */ + next_num < 100 /* and we haven't reached the retry limit */ ) { + curlx_msnprintf(newname + len + 1, 12, "%d", next_num); + next_num++; + do { + fd = open(newname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE); + /* Keep retrying in the hope that it isn't interrupted sometime */ + } while(fd == -1 && errno == EINTR); + } + outs->filename = newname; /* remember the new one */ + outs->alloc_filename = TRUE; + } + /* An else statement to not overwrite existing files and not retry with + new numbered names (which would cover + config->file_clobber_mode == CLOBBER_DEFAULT && outs->is_cd_filename) + is not needed because we would have failed earlier, in the while loop + and `fd` would now be -1 */ + if(fd != -1) { + file = fdopen(fd, "wb"); + if(!file) + close(fd); + } + } + + if(!file) { + warnf(global, "Failed to open the file %s: %s", fname, + strerror(errno)); + return FALSE; + } + outs->s_isreg = TRUE; + outs->fopened = TRUE; + outs->stream = file; + outs->bytes = 0; + outs->init = 0; + return TRUE; +} + +/* +** callback for CURLOPT_WRITEFUNCTION +*/ + +size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) +{ + size_t rc; + struct per_transfer *per = userdata; + struct OutStruct *outs = &per->outs; + struct OperationConfig *config = per->config; + size_t bytes = sz * nmemb; + bool is_tty = config->global->isatty; +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO console_info; + intptr_t fhnd; +#endif + +#ifdef DEBUGBUILD + { + char *tty = curlx_getenv("CURL_ISATTY"); + if(tty) { + is_tty = TRUE; + curl_free(tty); + } + } + + if(config->show_headers) { + if(bytes > (size_t)CURL_MAX_HTTP_HEADER) { + warnf(config->global, "Header data size exceeds single call write " + "limit"); + return CURL_WRITEFUNC_ERROR; + } + } + else { + if(bytes > (size_t)CURL_MAX_WRITE_SIZE) { + warnf(config->global, "Data size exceeds single call write limit"); + return CURL_WRITEFUNC_ERROR; + } + } + + { + /* Some internal congruency checks on received OutStruct */ + bool check_fails = FALSE; + if(outs->filename) { + /* regular file */ + if(!*outs->filename) + check_fails = TRUE; + if(!outs->s_isreg) + check_fails = TRUE; + if(outs->fopened && !outs->stream) + check_fails = TRUE; + if(!outs->fopened && outs->stream) + check_fails = TRUE; + if(!outs->fopened && outs->bytes) + check_fails = TRUE; + } + else { + /* standard stream */ + if(!outs->stream || outs->s_isreg || outs->fopened) + check_fails = TRUE; + if(outs->alloc_filename || outs->is_cd_filename || outs->init) + check_fails = TRUE; + } + if(check_fails) { + warnf(config->global, "Invalid output struct data for write callback"); + return CURL_WRITEFUNC_ERROR; + } + } +#endif + + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return CURL_WRITEFUNC_ERROR; + + if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { + /* binary output to terminal? */ + if(memchr(buffer, 0, bytes)) { + warnf(config->global, "Binary output can mess up your terminal. " + "Use \"--output -\" to tell curl to output it to your terminal " + "anyway, or consider \"--output \" to save to a file."); + config->synthetic_error = TRUE; + return CURL_WRITEFUNC_ERROR; + } + } + +#ifdef _WIN32 + fhnd = _get_osfhandle(fileno(outs->stream)); + /* if windows console then UTF-8 must be converted to UTF-16 */ + if(isatty(fileno(outs->stream)) && + GetConsoleScreenBufferInfo((HANDLE)fhnd, &console_info)) { + wchar_t *wc_buf; + DWORD wc_len, chars_written; + unsigned char *rbuf = (unsigned char *)buffer; + DWORD rlen = (DWORD)bytes; + +#define IS_TRAILING_BYTE(x) (0x80 <= (x) && (x) < 0xC0) + + /* attempt to complete an incomplete UTF-8 sequence from previous call. + the sequence does not have to be well-formed. */ + if(outs->utf8seq[0] && rlen) { + bool complete = false; + /* two byte sequence (lead byte 110yyyyy) */ + if(0xC0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xE0) { + outs->utf8seq[1] = *rbuf++; + --rlen; + complete = true; + } + /* three byte sequence (lead byte 1110zzzz) */ + else if(0xE0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF0) { + if(!outs->utf8seq[1]) { + outs->utf8seq[1] = *rbuf++; + --rlen; + } + if(rlen && !outs->utf8seq[2]) { + outs->utf8seq[2] = *rbuf++; + --rlen; + complete = true; + } + } + /* four byte sequence (lead byte 11110uuu) */ + else if(0xF0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF8) { + if(!outs->utf8seq[1]) { + outs->utf8seq[1] = *rbuf++; + --rlen; + } + if(rlen && !outs->utf8seq[2]) { + outs->utf8seq[2] = *rbuf++; + --rlen; + } + if(rlen && !outs->utf8seq[3]) { + outs->utf8seq[3] = *rbuf++; + --rlen; + complete = true; + } + } + + if(complete) { + WCHAR prefix[3] = {0}; /* UTF-16 (1-2 WCHARs) + NUL */ + + if(MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)outs->utf8seq, -1, + prefix, sizeof(prefix)/sizeof(prefix[0]))) { + DEBUGASSERT(prefix[2] == L'\0'); + if(!WriteConsoleW( + (HANDLE) fhnd, + prefix, + prefix[1] ? 2 : 1, + &chars_written, + NULL)) { + return CURL_WRITEFUNC_ERROR; + } + } + /* else: UTF-8 input was not well formed and OS is pre-Vista which + drops invalid characters instead of writing U+FFFD to output. */ + + memset(outs->utf8seq, 0, sizeof(outs->utf8seq)); + } + } + + /* suppress an incomplete utf-8 sequence at end of rbuf */ + if(!outs->utf8seq[0] && rlen && (rbuf[rlen - 1] & 0x80)) { + /* check for lead byte from a two, three or four byte sequence */ + if(0xC0 <= rbuf[rlen - 1] && rbuf[rlen - 1] < 0xF8) { + outs->utf8seq[0] = rbuf[rlen - 1]; + rlen -= 1; + } + else if(rlen >= 2 && IS_TRAILING_BYTE(rbuf[rlen - 1])) { + /* check for lead byte from a three or four byte sequence */ + if(0xE0 <= rbuf[rlen - 2] && rbuf[rlen - 2] < 0xF8) { + outs->utf8seq[0] = rbuf[rlen - 2]; + outs->utf8seq[1] = rbuf[rlen - 1]; + rlen -= 2; + } + else if(rlen >= 3 && IS_TRAILING_BYTE(rbuf[rlen - 2])) { + /* check for lead byte from a four byte sequence */ + if(0xF0 <= rbuf[rlen - 3] && rbuf[rlen - 3] < 0xF8) { + outs->utf8seq[0] = rbuf[rlen - 3]; + outs->utf8seq[1] = rbuf[rlen - 2]; + outs->utf8seq[2] = rbuf[rlen - 1]; + rlen -= 3; + } + } + } + } + + if(rlen) { + /* calculate buffer size for wide characters */ + wc_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, rlen, NULL, 0); + if(!wc_len) + return CURL_WRITEFUNC_ERROR; + + wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t)); + if(!wc_buf) + return CURL_WRITEFUNC_ERROR; + + wc_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, rlen, wc_buf, + wc_len); + if(!wc_len) { + free(wc_buf); + return CURL_WRITEFUNC_ERROR; + } + + if(!WriteConsoleW( + (HANDLE) fhnd, + wc_buf, + wc_len, + &chars_written, + NULL)) { + free(wc_buf); + return CURL_WRITEFUNC_ERROR; + } + free(wc_buf); + } + + rc = bytes; + } + else +#endif + rc = fwrite(buffer, sz, nmemb, outs->stream); + + if(bytes == rc) + /* we added this amount of data to the output */ + outs->bytes += bytes; + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + + if(config->nobuffer) { + /* output buffering disabled */ + int res = fflush(outs->stream); + if(res) + return CURL_WRITEFUNC_ERROR; + } + + return rc; +} diff --git a/src/tool_cb_wrt.h b/src/tool_cb_wrt.h new file mode 100644 index 0000000..55502f4 --- /dev/null +++ b/src/tool_cb_wrt.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_TOOL_CB_WRT_H +#define HEADER_CURL_TOOL_CB_WRT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* +** callback for CURLOPT_WRITEFUNCTION +*/ + +size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata); + +/* create a local file for writing, return TRUE on success */ +bool tool_create_output_file(struct OutStruct *outs, + struct OperationConfig *config); + +#endif /* HEADER_CURL_TOOL_CB_WRT_H */ diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c new file mode 100644 index 0000000..3259bc7 --- /dev/null +++ b/src/tool_cfgable.c @@ -0,0 +1,194 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "tool_cfgable.h" +#include "tool_formparse.h" +#include "tool_paramhlp.h" +#include "tool_main.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void config_init(struct OperationConfig *config) +{ + memset(config, 0, sizeof(struct OperationConfig)); + + config->use_httpget = FALSE; + config->create_dirs = FALSE; + config->maxredirs = DEFAULT_MAXREDIRS; + config->proto_present = FALSE; + config->proto_redir_present = FALSE; + config->proto_default = NULL; + config->tcp_nodelay = TRUE; /* enabled by default */ + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; + config->http09_allowed = FALSE; + config->ftp_skip_ip = TRUE; + config->file_clobber_mode = CLOBBER_DEFAULT; + curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY); +} + +static void free_config_fields(struct OperationConfig *config) +{ + struct getout *urlnode; + + Curl_safefree(config->useragent); + Curl_safefree(config->altsvc); + Curl_safefree(config->hsts); + Curl_safefree(config->haproxy_clientip); + curl_slist_free_all(config->cookies); + Curl_safefree(config->cookiejar); + curl_slist_free_all(config->cookiefiles); + + Curl_dyn_free(&config->postdata); + Curl_safefree(config->query); + Curl_safefree(config->referer); + + Curl_safefree(config->headerfile); + Curl_safefree(config->ftpport); + Curl_safefree(config->iface); + + Curl_safefree(config->range); + + Curl_safefree(config->userpwd); + Curl_safefree(config->tls_username); + Curl_safefree(config->tls_password); + Curl_safefree(config->tls_authtype); + Curl_safefree(config->proxy_tls_username); + Curl_safefree(config->proxy_tls_password); + Curl_safefree(config->proxy_tls_authtype); + Curl_safefree(config->proxyuserpwd); + Curl_safefree(config->proxy); + + Curl_safefree(config->dns_ipv6_addr); + Curl_safefree(config->dns_ipv4_addr); + Curl_safefree(config->dns_interface); + Curl_safefree(config->dns_servers); + + Curl_safefree(config->noproxy); + + Curl_safefree(config->mail_from); + curl_slist_free_all(config->mail_rcpt); + Curl_safefree(config->mail_auth); + + Curl_safefree(config->netrc_file); + Curl_safefree(config->output_dir); + Curl_safefree(config->proto_str); + Curl_safefree(config->proto_redir_str); + + urlnode = config->url_list; + while(urlnode) { + struct getout *next = urlnode->next; + Curl_safefree(urlnode->url); + Curl_safefree(urlnode->outfile); + Curl_safefree(urlnode->infile); + Curl_safefree(urlnode); + urlnode = next; + } + config->url_list = NULL; + config->url_last = NULL; + config->url_get = NULL; + config->url_out = NULL; + + Curl_safefree(config->ipfs_gateway); + Curl_safefree(config->doh_url); + Curl_safefree(config->cipher_list); + Curl_safefree(config->proxy_cipher_list); + Curl_safefree(config->cert); + Curl_safefree(config->proxy_cert); + Curl_safefree(config->cert_type); + Curl_safefree(config->proxy_cert_type); + Curl_safefree(config->cacert); + Curl_safefree(config->login_options); + Curl_safefree(config->proxy_cacert); + Curl_safefree(config->capath); + Curl_safefree(config->proxy_capath); + Curl_safefree(config->crlfile); + Curl_safefree(config->pinnedpubkey); + Curl_safefree(config->proxy_pinnedpubkey); + Curl_safefree(config->proxy_crlfile); + Curl_safefree(config->key); + Curl_safefree(config->proxy_key); + Curl_safefree(config->key_type); + Curl_safefree(config->proxy_key_type); + Curl_safefree(config->key_passwd); + Curl_safefree(config->proxy_key_passwd); + Curl_safefree(config->pubkey); + Curl_safefree(config->hostpubmd5); + Curl_safefree(config->hostpubsha256); + Curl_safefree(config->engine); + Curl_safefree(config->etag_save_file); + Curl_safefree(config->etag_compare_file); + Curl_safefree(config->ssl_ec_curves); + Curl_safefree(config->request_target); + Curl_safefree(config->customrequest); + Curl_safefree(config->krblevel); + Curl_safefree(config->oauth_bearer); + Curl_safefree(config->sasl_authzid); + Curl_safefree(config->unix_socket_path); + Curl_safefree(config->writeout); + Curl_safefree(config->proto_default); + + curl_slist_free_all(config->quote); + curl_slist_free_all(config->postquote); + curl_slist_free_all(config->prequote); + + curl_slist_free_all(config->headers); + curl_slist_free_all(config->proxyheaders); + + curl_mime_free(config->mimepost); + config->mimepost = NULL; + tool_mime_free(config->mimeroot); + config->mimeroot = NULL; + config->mimecurrent = NULL; + + curl_slist_free_all(config->telnet_options); + curl_slist_free_all(config->resolve); + curl_slist_free_all(config->connect_to); + + Curl_safefree(config->preproxy); + Curl_safefree(config->proxy_service_name); + Curl_safefree(config->service_name); + + Curl_safefree(config->ftp_account); + Curl_safefree(config->ftp_alternative_to_user); + + Curl_safefree(config->aws_sigv4); + Curl_safefree(config->proto_str); + Curl_safefree(config->proto_redir_str); +} + +void config_free(struct OperationConfig *config) +{ + struct OperationConfig *last = config; + + /* Free each of the structures in reverse order */ + while(last) { + struct OperationConfig *prev = last->prev; + + free_config_fields(last); + free(last); + + last = prev; + } +} diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h new file mode 100644 index 0000000..dfa74d8 --- /dev/null +++ b/src/tool_cfgable.h @@ -0,0 +1,336 @@ +#ifndef HEADER_CURL_TOOL_CFGABLE_H +#define HEADER_CURL_TOOL_CFGABLE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_sdecls.h" +#include "tool_urlglob.h" +#include "var.h" + +struct GlobalConfig; + +struct State { + struct getout *urlnode; + struct URLGlob *inglob; + struct URLGlob *urls; + char *outfiles; + char *httpgetfields; + char *uploadfile; + curl_off_t infilenum; /* number of files to upload */ + curl_off_t up; /* upload file counter within a single upload glob */ + curl_off_t urlnum; /* how many iterations this single URL has with ranges + etc */ + curl_off_t li; +}; + +struct OperationConfig { + bool remote_time; + char *useragent; + struct curl_slist *cookies; /* cookies to serialize into a single line */ + char *cookiejar; /* write to this file */ + struct curl_slist *cookiefiles; /* file(s) to load cookies from */ + char *altsvc; /* alt-svc cache file name */ + char *hsts; /* HSTS cache file name */ + bool cookiesession; /* new session? */ + bool encoding; /* Accept-Encoding please */ + bool tr_encoding; /* Transfer-Encoding please */ + unsigned long authtype; /* auth bitmask */ + bool use_resume; + bool resume_from_current; + bool disable_epsv; + bool disable_eprt; + bool ftp_pret; + char *proto_str; + bool proto_present; + char *proto_redir_str; + bool proto_redir_present; + char *proto_default; + curl_off_t resume_from; + char *postfields; + struct curlx_dynbuf postdata; + char *referer; + char *query; + long timeout_ms; + long connecttimeout_ms; + long maxredirs; + curl_off_t max_filesize; + char *output_dir; + char *headerfile; + char *ftpport; + char *iface; + long localport; + long localportrange; + unsigned short porttouse; + char *range; + long low_speed_limit; + long low_speed_time; + char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */ + char *dns_interface; /* interface name */ + char *dns_ipv4_addr; /* dot notation */ + char *dns_ipv6_addr; /* dot notation */ + char *userpwd; + char *login_options; + char *tls_username; + char *tls_password; + char *tls_authtype; + char *proxy_tls_username; + char *proxy_tls_password; + char *proxy_tls_authtype; + char *proxyuserpwd; + char *proxy; + int proxyver; /* set to CURLPROXY_HTTP* define */ + char *noproxy; + char *mail_from; + struct curl_slist *mail_rcpt; + char *mail_auth; + bool mail_rcpt_allowfails; /* --mail-rcpt-allowfails */ + char *sasl_authzid; /* Authorization identity (identity to use) */ + bool sasl_ir; /* Enable/disable SASL initial response */ + bool proxytunnel; + bool ftp_append; /* APPE on ftp */ + bool use_ascii; /* select ascii or text transfer */ + bool autoreferer; /* automatically set referer */ + bool failonerror; /* fail on (HTTP) errors */ + bool failwithbody; /* fail on (HTTP) errors but still store body */ + bool show_headers; /* show headers to data output */ + bool no_body; /* don't get the body */ + bool dirlistonly; /* only get the FTP dir list */ + bool followlocation; /* follow http redirects */ + bool unrestricted_auth; /* Continue to send authentication (user+password) + when following redirects, even when hostname + changed */ + bool netrc_opt; + bool netrc; + char *netrc_file; + struct getout *url_list; /* point to the first node */ + struct getout *url_last; /* point to the last/current node */ + struct getout *url_get; /* point to the node to fill in URL */ + struct getout *url_out; /* point to the node to fill in outfile */ + struct getout *url_ul; /* point to the node to fill in upload */ + char *ipfs_gateway; + char *doh_url; + char *cipher_list; + char *proxy_cipher_list; + char *cipher13_list; + char *proxy_cipher13_list; + char *cert; + char *proxy_cert; + char *cert_type; + char *proxy_cert_type; + char *cacert; + char *proxy_cacert; + char *capath; + char *proxy_capath; + char *crlfile; + char *proxy_crlfile; + char *pinnedpubkey; + char *proxy_pinnedpubkey; + char *key; + char *proxy_key; + char *key_type; + char *proxy_key_type; + char *key_passwd; + char *proxy_key_passwd; + char *pubkey; + char *hostpubmd5; + char *hostpubsha256; + char *engine; + char *etag_save_file; + char *etag_compare_file; + bool crlf; + char *customrequest; + char *ssl_ec_curves; + char *krblevel; + char *request_target; + long httpversion; + bool http09_allowed; + bool nobuffer; + bool readbusy; /* set when reading input returns EAGAIN */ + bool globoff; + bool use_httpget; + bool insecure_ok; /* set TRUE to allow insecure SSL connects */ + bool doh_insecure_ok; /* set TRUE to allow insecure SSL connects + for DoH */ + bool proxy_insecure_ok; /* set TRUE to allow insecure SSL connects + for proxy */ + bool terminal_binary_ok; + bool verifystatus; + bool doh_verifystatus; + bool create_dirs; + bool ftp_create_dirs; + bool ftp_skip_ip; + bool proxynegotiate; + bool proxyntlm; + bool proxydigest; + bool proxybasic; + bool proxyanyauth; + bool jsoned; /* added json content-type */ + char *writeout; /* %-styled format string to output */ + struct curl_slist *quote; + struct curl_slist *postquote; + struct curl_slist *prequote; + long ssl_version; + long ssl_version_max; + long proxy_ssl_version; + long ip_version; + long create_file_mode; /* CURLOPT_NEW_FILE_PERMS */ + curl_TimeCond timecond; + curl_off_t condtime; + struct curl_slist *headers; + struct curl_slist *proxyheaders; + struct tool_mime *mimeroot; + struct tool_mime *mimecurrent; + curl_mime *mimepost; + struct curl_slist *telnet_options; + struct curl_slist *resolve; + struct curl_slist *connect_to; + HttpReq httpreq; + + /* for bandwidth limiting features: */ + curl_off_t sendpersecond; /* send to peer */ + curl_off_t recvpersecond; /* receive from peer */ + + bool ftp_ssl; + bool ftp_ssl_reqd; + bool ftp_ssl_control; + bool ftp_ssl_ccc; + int ftp_ssl_ccc_mode; + char *preproxy; + bool socks5_gssapi_nec; /* The NEC reference server does not protect the + encryption type exchange */ + unsigned long socks5_auth;/* auth bitmask for socks5 proxies */ + char *proxy_service_name; /* set authentication service name for HTTP and + SOCKS5 proxies */ + char *service_name; /* set authentication service name for DIGEST-MD5, + Kerberos 5 and SPNEGO */ + + bool tcp_nodelay; + bool tcp_fastopen; + long req_retry; /* number of retries */ + bool retry_all_errors; /* retry on any error */ + bool retry_connrefused; /* set connection refused as a transient error */ + long retry_delay; /* delay between retries (in seconds) */ + long retry_maxtime; /* maximum time to keep retrying */ + + char *ftp_account; /* for ACCT */ + char *ftp_alternative_to_user; /* send command if USER/PASS fails */ + int ftp_filemethod; + long mime_options; /* Mime option flags. */ + long tftp_blksize; /* TFTP BLKSIZE option */ + bool tftp_no_options; /* do not send TFTP options requests */ + bool ignorecl; /* --ignore-content-length */ + bool disable_sessionid; + + bool raw; + bool post301; + bool post302; + bool post303; + bool nokeepalive; /* for keepalive needs */ + long alivetime; + bool content_disposition; /* use Content-disposition filename */ + + int default_node_flags; /* default flags to search for each 'node', which + is basically each given URL to transfer */ + + bool xattr; /* store metadata in extended attributes */ + long gssapi_delegation; + bool ssl_allow_beast; /* allow this SSL vulnerability */ + bool proxy_ssl_allow_beast; /* allow this SSL vulnerability for proxy */ + bool ssl_no_revoke; /* disable SSL certificate revocation checks */ + bool ssl_revoke_best_effort; /* ignore SSL revocation offline/missing + revocation list errors */ + + bool native_ca_store; /* use the native OS CA store */ + bool proxy_native_ca_store; /* use the native OS CA store for proxy */ + bool ssl_auto_client_cert; /* automatically locate and use a client + certificate for authentication (Schannel) */ + bool proxy_ssl_auto_client_cert; /* proxy version of ssl_auto_client_cert */ + char *oauth_bearer; /* OAuth 2.0 bearer token */ + bool noalpn; /* enable/disable TLS ALPN extension */ + char *unix_socket_path; /* path to Unix domain socket */ + bool abstract_unix_socket; /* path to an abstract Unix domain socket */ + bool falsestart; + bool path_as_is; + long expect100timeout_ms; + bool suppress_connect_headers; /* suppress proxy CONNECT response headers + from user callbacks */ + bool synthetic_error; /* if TRUE, this is tool-internal error */ + bool ssh_compression; /* enable/disable SSH compression */ + long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds. + 0 is valid. default: CURL_HET_DEFAULT. */ + bool haproxy_protocol; /* whether to send HAProxy protocol v1 */ + char *haproxy_clientip; /* client IP for HAProxy protocol */ + bool disallow_username_in_url; /* disallow usernames in URLs */ + char *aws_sigv4; + enum { + CLOBBER_DEFAULT, /* Provides compatibility with previous versions of curl, + by using the default behavior for -o, -O, and -J. + If those options would have overwritten files, like + -o and -O would, then overwrite them. In the case of + -J, this will not overwrite any files. */ + CLOBBER_NEVER, /* If the file exists, always fail */ + CLOBBER_ALWAYS /* If the file exists, always overwrite it */ + } file_clobber_mode; + struct GlobalConfig *global; + struct OperationConfig *prev; + struct OperationConfig *next; /* Always last in the struct */ + struct State state; /* for create_transfer() */ + bool rm_partial; /* on error, remove partially written output + files */ +}; + +struct GlobalConfig { + bool showerror; /* show errors when silent */ + bool silent; /* don't show messages, --silent given */ + bool noprogress; /* don't show progress bar */ + bool isatty; /* Updated internally if output is a tty */ + char *trace_dump; /* file to dump the network trace to */ + FILE *trace_stream; + bool trace_fopened; + trace tracetype; + bool tracetime; /* include timestamp? */ + bool traceids; /* include xfer-/conn-id? */ + int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */ + char *libcurl; /* Output libcurl code to this file name */ + bool fail_early; /* exit on first transfer error */ + bool styled_output; /* enable fancy output style detection */ + long ms_per_transfer; /* start next transfer after (at least) this + many milliseconds */ +#ifdef CURLDEBUG + bool test_event_based; +#endif + bool parallel; + unsigned short parallel_max; /* MAX_PARALLEL is the maximum */ + bool parallel_connect; + char *help_category; /* The help category, if set */ + struct var *variables; + struct OperationConfig *first; + struct OperationConfig *current; + struct OperationConfig *last; /* Always last in the struct */ +}; + +void config_init(struct OperationConfig *config); +void config_free(struct OperationConfig *config); + +#endif /* HEADER_CURL_TOOL_CFGABLE_H */ diff --git a/src/tool_dirhie.c b/src/tool_dirhie.c new file mode 100644 index 0000000..1cadbd0 --- /dev/null +++ b/src/tool_dirhie.c @@ -0,0 +1,167 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include + +#ifdef _WIN32 +# include +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_dirhie.h" +#include "tool_msgs.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#if defined(_WIN32) || (defined(MSDOS) && !defined(__DJGPP__)) +# define mkdir(x,y) (mkdir)((x)) +# ifndef F_OK +# define F_OK 0 +# endif +#endif + +static void show_dir_errno(struct GlobalConfig *global, const char *name) +{ + switch(errno) { +#ifdef EACCES + case EACCES: + errorf(global, "You don't have permission to create %s", name); + break; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: + errorf(global, "The directory name %s is too long", name); + break; +#endif +#ifdef EROFS + case EROFS: + errorf(global, "%s resides on a read-only file system", name); + break; +#endif +#ifdef ENOSPC + case ENOSPC: + errorf(global, "No space left on the file system that will " + "contain the directory %s", name); + break; +#endif +#ifdef EDQUOT + case EDQUOT: + errorf(global, "Cannot create directory %s because you " + "exceeded your quota", name); + break; +#endif + default: + errorf(global, "Error creating directory %s", name); + break; + } +} + +/* + * Create the needed directory hierarchy recursively in order to save + * multi-GETs in file output, ie: + * curl "http://example.org/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt" + * should create all the dir* automagically + */ + +#if defined(_WIN32) || defined(__DJGPP__) +/* systems that may use either or when specifying a path */ +#define PATH_DELIMITERS "\\/" +#else +#define PATH_DELIMITERS DIR_CHAR +#endif + + +CURLcode create_dir_hierarchy(const char *outfile, struct GlobalConfig *global) +{ + char *tempdir; + char *tempdir2; + char *outdup; + char *dirbuildup; + CURLcode result = CURLE_OK; + size_t outlen; + + outlen = strlen(outfile); + outdup = strdup(outfile); + if(!outdup) + return CURLE_OUT_OF_MEMORY; + + dirbuildup = malloc(outlen + 1); + if(!dirbuildup) { + Curl_safefree(outdup); + return CURLE_OUT_OF_MEMORY; + } + dirbuildup[0] = '\0'; + + /* Allow strtok() here since this isn't used threaded */ + /* !checksrc! disable BANNEDFUNC 2 */ + tempdir = strtok(outdup, PATH_DELIMITERS); + + while(tempdir) { + bool skip = false; + tempdir2 = strtok(NULL, PATH_DELIMITERS); + /* since strtok returns a token for the last word even + if not ending with DIR_CHAR, we need to prune it */ + if(tempdir2) { + size_t dlen = strlen(dirbuildup); + if(dlen) + msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir); + else { + if(outdup == tempdir) { +#if defined(_WIN32) || defined(MSDOS) + /* Skip creating a drive's current directory. + It may seem as though that would harmlessly fail but it could be + a corner case if X: did not exist, since we would be creating it + erroneously. + eg if outfile is X:\foo\bar\filename then don't mkdir X: + This logic takes into account unsupported drives !:, 1:, etc. */ + char *p = strchr(tempdir, ':'); + if(p && !p[1]) + skip = true; +#endif + /* the output string doesn't start with a separator */ + strcpy(dirbuildup, tempdir); + } + else + msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir); + } + /* Create directory. Ignore access denied error to allow traversal. */ + if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) && + (errno != EACCES) && (errno != EEXIST)) { + show_dir_errno(global, dirbuildup); + result = CURLE_WRITE_ERROR; + break; /* get out of loop */ + } + } + tempdir = tempdir2; + } + + Curl_safefree(dirbuildup); + Curl_safefree(outdup); + + return result; +} diff --git a/src/tool_dirhie.h b/src/tool_dirhie.h new file mode 100644 index 0000000..0ee407f --- /dev/null +++ b/src/tool_dirhie.h @@ -0,0 +1,32 @@ +#ifndef HEADER_CURL_TOOL_DIRHIE_H +#define HEADER_CURL_TOOL_DIRHIE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_cfgable.h" + +CURLcode create_dir_hierarchy(const char *outfile, + struct GlobalConfig *global); + +#endif /* HEADER_CURL_TOOL_DIRHIE_H */ diff --git a/src/tool_doswin.c b/src/tool_doswin.c new file mode 100644 index 0000000..db2b8b7 --- /dev/null +++ b/src/tool_doswin.c @@ -0,0 +1,796 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(_WIN32) || defined(MSDOS) + +#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) +# include +#endif + +#ifdef _WIN32 +# include +# include +# include "tool_cfgable.h" +# include "tool_libinfo.h" +#endif + +#include "tool_bname.h" +#include "tool_doswin.h" + +#include "curlx.h" +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef _WIN32 +# undef PATH_MAX +# define PATH_MAX MAX_PATH +#endif + +#ifndef S_ISCHR +# ifdef S_IFCHR +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# else +# define S_ISCHR(m) (0) /* cannot tell if file is a device */ +# endif +#endif + +#ifdef _WIN32 +# define _use_lfn(f) (1) /* long file names always available */ +#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */ +# define _use_lfn(f) (0) /* long file names never available */ +#elif defined(__DJGPP__) +# include /* _use_lfn(f) prototype */ +#endif + +#ifndef UNITTESTS +static SANITIZEcode truncate_dryrun(const char *path, + const size_t truncate_pos); +#ifdef MSDOS +static SANITIZEcode msdosify(char **const sanitized, const char *file_name, + int flags); +#endif +static SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, + const char *file_name, + int flags); +#endif /* !UNITTESTS (static declarations used if no unit tests) */ + + +/* +Sanitize a file or path name. + +All banned characters are replaced by underscores, for example: +f?*foo => f__foo +f:foo::$DATA => f_foo__$DATA +f:\foo:bar => f__foo_bar +f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH) + +This function was implemented according to the guidelines in 'Naming Files, +Paths, and Namespaces' section 'Naming Conventions'. +https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx + +Flags +----- +SANITIZE_ALLOW_COLONS: Allow colons. +Without this flag colons are sanitized. + +SANITIZE_ALLOW_PATH: Allow path separators and colons. +Without this flag path separators and colons are sanitized. + +SANITIZE_ALLOW_RESERVED: Allow reserved device names. +Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's +in a UNC prefixed path. + +SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename. +Without this flag if the sanitized filename or path will be too long an error +occurs. With this flag the filename --and not any other parts of the path-- may +be truncated to at least a single character. A filename followed by an +alternate data stream (ADS) cannot be truncated in any case. + +Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. +Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. +*/ +SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, + int flags) +{ + char *p, *target; + size_t len; + SANITIZEcode sc; + size_t max_sanitized_len; + + if(!sanitized) + return SANITIZE_ERR_BAD_ARGUMENT; + + *sanitized = NULL; + + if(!file_name) + return SANITIZE_ERR_BAD_ARGUMENT; + + if((flags & SANITIZE_ALLOW_PATH)) { +#ifndef MSDOS + if(file_name[0] == '\\' && file_name[1] == '\\') + /* UNC prefixed path \\ (eg \\?\C:\foo) */ + max_sanitized_len = 32767-1; + else +#endif + max_sanitized_len = PATH_MAX-1; + } + else + /* The maximum length of a filename. + FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and + does not discount the path information therefore we shouldn't use it. */ + max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1; + + len = strlen(file_name); + if(len > max_sanitized_len) { + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || + truncate_dryrun(file_name, max_sanitized_len)) + return SANITIZE_ERR_INVALID_PATH; + + len = max_sanitized_len; + } + + target = malloc(len + 1); + if(!target) + return SANITIZE_ERR_OUT_OF_MEMORY; + + strncpy(target, file_name, len); + target[len] = '\0'; + +#ifndef MSDOS + if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4)) + /* Skip the literal path prefix \\?\ */ + p = target + 4; + else +#endif + p = target; + + /* replace control characters and other banned characters */ + for(; *p; ++p) { + const char *banned; + + if((1 <= *p && *p <= 31) || + (!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *p == ':') || + (!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) { + *p = '_'; + continue; + } + + for(banned = "|<>\"?*"; *banned; ++banned) { + if(*p == *banned) { + *p = '_'; + break; + } + } + } + + /* remove trailing spaces and periods if not allowing paths */ + if(!(flags & SANITIZE_ALLOW_PATH) && len) { + char *clip = NULL; + + p = &target[len]; + do { + --p; + if(*p != ' ' && *p != '.') + break; + clip = p; + } while(p != target); + + if(clip) { + *clip = '\0'; + len = clip - target; + } + } + +#ifdef MSDOS + sc = msdosify(&p, target, flags); + free(target); + if(sc) + return sc; + target = p; + len = strlen(target); + + if(len > max_sanitized_len) { + free(target); + return SANITIZE_ERR_INVALID_PATH; + } +#endif + + if(!(flags & SANITIZE_ALLOW_RESERVED)) { + sc = rename_if_reserved_dos_device_name(&p, target, flags); + free(target); + if(sc) + return sc; + target = p; + len = strlen(target); + + if(len > max_sanitized_len) { + free(target); + return SANITIZE_ERR_INVALID_PATH; + } + } + + *sanitized = target; + return SANITIZE_ERR_OK; +} + + +/* +Test if truncating a path to a file will leave at least a single character in +the filename. Filenames suffixed by an alternate data stream can't be +truncated. This performs a dry run, nothing is modified. + +Good truncate_pos 9: C:\foo\bar => C:\foo\ba +Good truncate_pos 6: C:\foo => C:\foo +Good truncate_pos 5: C:\foo => C:\fo +Bad* truncate_pos 5: C:foo => C:foo +Bad truncate_pos 5: C:\foo:ads => C:\fo +Bad truncate_pos 9: C:\foo:ads => C:\foo:ad +Bad truncate_pos 5: C:\foo\bar => C:\fo +Bad truncate_pos 5: C:\foo\ => C:\fo +Bad truncate_pos 7: C:\foo\ => C:\foo\ +Error truncate_pos 7: C:\foo => (pos out of range) +Bad truncate_pos 1: C:\foo\ => C + +* C:foo is ambiguous, C could end up being a drive or file therefore something + like C:superlongfilename can't be truncated. + +Returns +SANITIZE_ERR_OK: Good -- 'path' can be truncated +SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated +!= SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error +*/ +SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos) +{ + size_t len; + + if(!path) + return SANITIZE_ERR_BAD_ARGUMENT; + + len = strlen(path); + + if(truncate_pos > len) + return SANITIZE_ERR_BAD_ARGUMENT; + + if(!len || !truncate_pos) + return SANITIZE_ERR_INVALID_PATH; + + if(strpbrk(&path[truncate_pos - 1], "\\/:")) + return SANITIZE_ERR_INVALID_PATH; + + /* C:\foo can be truncated but C:\foo:ads can't */ + if(truncate_pos > 1) { + const char *p = &path[truncate_pos - 1]; + do { + --p; + if(*p == ':') + return SANITIZE_ERR_INVALID_PATH; + } while(p != path && *p != '\\' && *p != '/'); + } + + return SANITIZE_ERR_OK; +} + +/* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function + * were taken with modification from the DJGPP port of tar 1.12. They use + * algorithms originally from DJTAR. + */ + +/* +Extra sanitization MSDOS for file_name. + +This is a supporting function for sanitize_file_name. + +Warning: This is an MSDOS legacy function and was purposely written in a way +that some path information may pass through. For example drive letter names +(C:, D:, etc) are allowed to pass through. For sanitizing a filename use +sanitize_file_name. + +Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. +Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. +*/ +#if defined(MSDOS) || defined(UNITTESTS) +SANITIZEcode msdosify(char **const sanitized, const char *file_name, + int flags) +{ + char dos_name[PATH_MAX]; + static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */ + "|<>/\\\":?*"; /* illegal in DOS & W95 */ + static const char *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 *illegal_aliens = illegal_chars_dos; + size_t len = sizeof(illegal_chars_dos) - 1; + + if(!sanitized) + return SANITIZE_ERR_BAD_ARGUMENT; + + *sanitized = NULL; + + if(!file_name) + return SANITIZE_ERR_BAD_ARGUMENT; + + if(strlen(file_name) > PATH_MAX-1 && + (!(flags & SANITIZE_ALLOW_TRUNCATE) || + truncate_dryrun(file_name, PATH_MAX-1))) + return SANITIZE_ERR_INVALID_PATH; + + /* Support for Windows 9X VFAT systems, when available. */ + if(_use_lfn(file_name)) { + illegal_aliens = illegal_chars_w95; + len -= (illegal_chars_w95 - illegal_chars_dos); + } + + /* Get past the drive letter, if any. */ + if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') { + *d++ = *s++; + *d = ((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) ? ':' : '_'; + ++d; ++s; + } + + for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) { + if(memchr(illegal_aliens, *s, len)) { + + if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':') + *d = ':'; + else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\')) + *d = *s; + /* Dots are special: DOS doesn't allow them as the leading character, + and a file name cannot have more than a single dot. We leave the + first non-leading dot alone, unless it comes too close to the + beginning of the name: we want sh.lex.c to become sh_lex.c, not + sh.lex-c. */ + else if(*s == '.') { + if((flags & SANITIZE_ALLOW_PATH) && idx == 0 && + (s[1] == '/' || s[1] == '\\' || + (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) { + /* Copy "./" and "../" verbatim. */ + *d++ = *s++; + if(d == dlimit) + break; + if(*s == '.') { + *d++ = *s++; + if(d == dlimit) + break; + } + *d = *s; + } + else if(idx == 0) + *d = '_'; + else if(dot_idx >= 0) { + if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */ + d[dot_idx - idx] = '_'; /* replace previous dot */ + *d = '.'; + } + else + *d = '-'; + } + else + *d = '.'; + + if(*s == '.') + dot_idx = idx; + } + else if(*s == '+' && s[1] == '+') { + if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */ + *d++ = 'x'; + if(d == dlimit) + break; + *d = 'x'; + } + else { + /* libg++ etc. */ + if(dlimit - d < 4) { + *d++ = 'x'; + if(d == dlimit) + break; + *d = 'x'; + } + else { + memcpy(d, "plus", 4); + d += 3; + } + } + s++; + idx++; + } + else + *d = '_'; + } + else + *d = *s; + if(*s == '/' || *s == '\\') { + idx = 0; + dot_idx = -1; + } + else + idx++; + } + *d = '\0'; + + if(*s) { + /* dos_name is truncated, check that truncation requirements are met, + specifically truncating a filename suffixed by an alternate data stream + or truncating the entire filename is not allowed. */ + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || strpbrk(s, "\\/:") || + truncate_dryrun(dos_name, d - dos_name)) + return SANITIZE_ERR_INVALID_PATH; + } + + *sanitized = strdup(dos_name); + return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); +} +#endif /* MSDOS || UNITTESTS */ + +/* +Rename file_name if it's a reserved dos device name. + +This is a supporting function for sanitize_file_name. + +Warning: This is an MSDOS legacy function and was purposely written in a way +that some path information may pass through. For example drive letter names +(C:, D:, etc) are allowed to pass through. For sanitizing a filename use +sanitize_file_name. + +Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. +Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. +*/ +SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, + const char *file_name, + int flags) +{ + /* We could have a file whose name is a device on MS-DOS. Trying to + * retrieve such a file would fail at best and wedge us at worst. We need + * to rename such files. */ + char *p, *base; + char fname[PATH_MAX]; +#ifdef MSDOS + struct_stat st_buf; +#endif + + if(!sanitized) + return SANITIZE_ERR_BAD_ARGUMENT; + + *sanitized = NULL; + + if(!file_name) + return SANITIZE_ERR_BAD_ARGUMENT; + + /* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */ +#ifndef MSDOS + if((flags & SANITIZE_ALLOW_PATH) && + file_name[0] == '\\' && file_name[1] == '\\') { + size_t len = strlen(file_name); + *sanitized = malloc(len + 1); + if(!*sanitized) + return SANITIZE_ERR_OUT_OF_MEMORY; + strncpy(*sanitized, file_name, len + 1); + return SANITIZE_ERR_OK; + } +#endif + + if(strlen(file_name) > PATH_MAX-1 && + (!(flags & SANITIZE_ALLOW_TRUNCATE) || + truncate_dryrun(file_name, PATH_MAX-1))) + return SANITIZE_ERR_INVALID_PATH; + + strncpy(fname, file_name, PATH_MAX-1); + fname[PATH_MAX-1] = '\0'; + base = basename(fname); + + /* Rename reserved device names that are known to be accessible without \\.\ + Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS + https://support.microsoft.com/en-us/kb/74496 + https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx + */ + for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) { + size_t p_len; + int x = (curl_strnequal(p, "CON", 3) || + curl_strnequal(p, "PRN", 3) || + curl_strnequal(p, "AUX", 3) || + curl_strnequal(p, "NUL", 3)) ? 3 : + (curl_strnequal(p, "CLOCK$", 6)) ? 6 : + (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ? + (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0; + + if(!x) + continue; + + /* the devices may be accessible with an extension or ADS, for + example CON.AIR and 'CON . AIR' and CON:AIR access console */ + + for(; p[x] == ' '; ++x) + ; + + if(p[x] == '.') { + p[x] = '_'; + continue; + } + else if(p[x] == ':') { + if(!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) { + p[x] = '_'; + continue; + } + ++x; + } + else if(p[x]) /* no match */ + continue; + + /* p points to 'CON' or 'CON ' or 'CON:', etc */ + p_len = strlen(p); + + /* Prepend a '_' */ + if(strlen(fname) == PATH_MAX-1) { + --p_len; + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(p, p_len)) + return SANITIZE_ERR_INVALID_PATH; + p[p_len] = '\0'; + } + memmove(p + 1, p, p_len + 1); + p[0] = '_'; + ++p_len; + + /* if fname was just modified then the basename pointer must be updated */ + if(p == fname) + base = basename(fname); + } + + /* This is the legacy portion from rename_if_dos_device_name that checks for + reserved device names. It only works on MSDOS. On Windows XP the stat + check errors with EINVAL if the device name is reserved. On Windows + Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN + stat doc the latter behavior is correct, but that doesn't help us identify + whether it's a reserved device name and not a regular file name. */ +#ifdef MSDOS + if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { + /* Prepend a '_' */ + size_t blen = strlen(base); + if(blen) { + if(strlen(fname) == PATH_MAX-1) { + --blen; + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(base, blen)) + return SANITIZE_ERR_INVALID_PATH; + base[blen] = '\0'; + } + memmove(base + 1, base, blen + 1); + base[0] = '_'; + } + } +#endif + + *sanitized = strdup(fname); + return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); +} + +#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) + +/* + * Disable program default argument globbing. We do it on our own. + */ +char **__crt0_glob_function(char *arg) +{ + (void)arg; + return (char **)0; +} + +#endif /* MSDOS && (__DJGPP__ || __GO32__) */ + +#ifdef _WIN32 + +/* + * Function to find CACert bundle on a Win32 platform using SearchPath. + * (SearchPath is already declared via inclusions done in setup header file) + * (Use the ASCII version instead of the unicode one!) + * The order of the directories it searches is: + * 1. application's directory + * 2. current working directory + * 3. Windows System directory (e.g. C:\windows\system32) + * 4. Windows Directory (e.g. C:\windows) + * 5. all directories along %PATH% + * + * For WinXP and later search order actually depends on registry value: + * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode + */ + +CURLcode FindWin32CACert(struct OperationConfig *config, + curl_sslbackend backend, + const TCHAR *bundle_file) +{ + CURLcode result = CURLE_OK; + + /* Search and set cert file only if libcurl supports SSL. + * + * If Schannel is the selected SSL backend then these locations are + * ignored. We allow setting CA location for schannel only when explicitly + * specified by the user via CURLOPT_CAINFO / --cacert. + */ + if(feature_ssl && backend != CURLSSLBACKEND_SCHANNEL) { + + DWORD res_len; + TCHAR buf[PATH_MAX]; + TCHAR *ptr = NULL; + + buf[0] = TEXT('\0'); + + res_len = SearchPath(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr); + if(res_len > 0) { + char *mstr = curlx_convert_tchar_to_UTF8(buf); + Curl_safefree(config->cacert); + if(mstr) + config->cacert = strdup(mstr); + curlx_unicodefree(mstr); + if(!config->cacert) + result = CURLE_OUT_OF_MEMORY; + } + } + + return result; +} + + +/* Get a list of all loaded modules with full paths. + * Returns slist on success or NULL on error. + */ +struct curl_slist *GetLoadedModulePaths(void) +{ + HANDLE hnd = INVALID_HANDLE_VALUE; + MODULEENTRY32 mod = {0}; + struct curl_slist *slist = NULL; + + mod.dwSize = sizeof(MODULEENTRY32); + + do { + hnd = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); + } while(hnd == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH); + + if(hnd == INVALID_HANDLE_VALUE) + goto error; + + if(!Module32First(hnd, &mod)) + goto error; + + do { + char *path; /* points to stack allocated buffer */ + struct curl_slist *temp; + +#ifdef UNICODE + /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total + bytes of multibyte chars won't be more than twice that. */ + char buffer[sizeof(mod.szExePath) * 2]; + if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1, + buffer, sizeof(buffer), NULL, NULL)) + goto error; + path = buffer; +#else + path = mod.szExePath; +#endif + temp = curl_slist_append(slist, path); + if(!temp) + goto error; + slist = temp; + } while(Module32Next(hnd, &mod)); + + goto cleanup; + +error: + curl_slist_free_all(slist); + slist = NULL; +cleanup: + if(hnd != INVALID_HANDLE_VALUE) + CloseHandle(hnd); + return slist; +} + +/* The terminal settings to restore on exit */ +static struct TerminalSettings { + HANDLE hStdOut; + DWORD dwOutputMode; + LONG valid; +} TerminalSettings; + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +bool tool_term_has_bold; + +static void restore_terminal(void) +{ + if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE)) + SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode); +} + +/* This is the console signal handler. + * The system calls it in a separate thread. + */ +static BOOL WINAPI signal_handler(DWORD type) +{ + if(type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT) + restore_terminal(); + return FALSE; +} + +static void init_terminal(void) +{ + TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + + /* + * Enable VT (Virtual Terminal) output. + * Note: VT mode flag can be set on any version of Windows, but VT + * processing only performed on Win10 >= version 1709 (OS build 16299) + * Creator's Update. Also, ANSI bold on/off supported since then. + */ + if(TerminalSettings.hStdOut == INVALID_HANDLE_VALUE || + !GetConsoleMode(TerminalSettings.hStdOut, + &TerminalSettings.dwOutputMode) || + !curlx_verify_windows_version(10, 0, 16299, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) + return; + + if((TerminalSettings.dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) + tool_term_has_bold = true; + else { + /* The signal handler is set before attempting to change the console mode + because otherwise a signal would not be caught after the change but + before the handler was installed. */ + (void)InterlockedExchange(&TerminalSettings.valid, (LONG)TRUE); + if(SetConsoleCtrlHandler(signal_handler, TRUE)) { + if(SetConsoleMode(TerminalSettings.hStdOut, + (TerminalSettings.dwOutputMode | + ENABLE_VIRTUAL_TERMINAL_PROCESSING))) { + tool_term_has_bold = true; + atexit(restore_terminal); + } + else { + SetConsoleCtrlHandler(signal_handler, FALSE); + (void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE); + } + } + } +} + +LARGE_INTEGER tool_freq; +bool tool_isVistaOrGreater; + +CURLcode win32_init(void) +{ + /* curlx_verify_windows_version must be called during init at least once + because it has its own initialization routine. */ + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) + tool_isVistaOrGreater = true; + else + tool_isVistaOrGreater = false; + + QueryPerformanceFrequency(&tool_freq); + + init_terminal(); + + return CURLE_OK; +} + +#endif /* _WIN32 */ + +#endif /* _WIN32 || MSDOS */ diff --git a/src/tool_doswin.h b/src/tool_doswin.h new file mode 100644 index 0000000..e07d89d --- /dev/null +++ b/src/tool_doswin.h @@ -0,0 +1,72 @@ +#ifndef HEADER_CURL_TOOL_DOSWIN_H +#define HEADER_CURL_TOOL_DOSWIN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(_WIN32) || defined(MSDOS) + +#define SANITIZE_ALLOW_COLONS (1<<0) /* Allow colons */ +#define SANITIZE_ALLOW_PATH (1<<1) /* Allow path separators and colons */ +#define SANITIZE_ALLOW_RESERVED (1<<2) /* Allow reserved device names */ +#define SANITIZE_ALLOW_TRUNCATE (1<<3) /* Allow truncating a long filename */ + +typedef enum { + SANITIZE_ERR_OK = 0, /* 0 - OK */ + SANITIZE_ERR_INVALID_PATH, /* 1 - the path is invalid */ + SANITIZE_ERR_BAD_ARGUMENT, /* 2 - bad function parameter */ + SANITIZE_ERR_OUT_OF_MEMORY, /* 3 - out of memory */ + SANITIZE_ERR_LAST /* never use! */ +} SANITIZEcode; + +SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, + int flags); +#ifdef UNITTESTS +SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos); +SANITIZEcode msdosify(char **const sanitized, const char *file_name, + int flags); +SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, + const char *file_name, + int flags); +#endif /* UNITTESTS */ + +#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) + +char **__crt0_glob_function(char *arg); + +#endif /* MSDOS && (__DJGPP__ || __GO32__) */ + +#ifdef _WIN32 + +CURLcode FindWin32CACert(struct OperationConfig *config, + curl_sslbackend backend, + const TCHAR *bundle_file); +struct curl_slist *GetLoadedModulePaths(void); +CURLcode win32_init(void); + +#endif /* _WIN32 */ + +#endif /* _WIN32 || MSDOS */ + +#endif /* HEADER_CURL_TOOL_DOSWIN_H */ diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c new file mode 100644 index 0000000..6ef2be7 --- /dev/null +++ b/src/tool_easysrc.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "slist_wc.h" + +#ifndef CURL_DISABLE_LIBCURL_OPTION + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_easysrc.h" +#include "tool_msgs.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* global variable definitions, for easy-interface source code generation */ + +struct slist_wc *easysrc_decl = NULL; /* Variable declarations */ +struct slist_wc *easysrc_data = NULL; /* Build slists, forms etc. */ +struct slist_wc *easysrc_code = NULL; /* Setopt calls */ +struct slist_wc *easysrc_toohard = NULL; /* Unconvertible setopt */ +struct slist_wc *easysrc_clean = NULL; /* Clean up allocated data */ +int easysrc_mime_count = 0; +int easysrc_slist_count = 0; + +static const char *const srchead[]={ + "/********* Sample code generated by the curl command line tool **********", + " * All curl_easy_setopt() options are documented at:", + " * https://curl.se/libcurl/c/curl_easy_setopt.html", + " ************************************************************************/", + "#include ", + "", + "int main(int argc, char *argv[])", + "{", + " CURLcode ret;", + " CURL *hnd;", + NULL +}; +/* easysrc_decl declarations come here */ +/* easysrc_data initialization come here */ +/* easysrc_code statements come here */ +static const char *const srchard[]={ + "/* Here is a list of options the curl code used that cannot get generated", + " as source easily. You may choose to either not use them or implement", + " them yourself.", + "", + NULL +}; +static const char *const srcend[]={ + "", + " return (int)ret;", + "}", + "/**** End of sample code ****/", + NULL +}; + +/* Clean up all source code if we run out of memory */ +static void easysrc_free(void) +{ + slist_wc_free_all(easysrc_decl); + easysrc_decl = NULL; + slist_wc_free_all(easysrc_data); + easysrc_data = NULL; + slist_wc_free_all(easysrc_code); + easysrc_code = NULL; + slist_wc_free_all(easysrc_toohard); + easysrc_toohard = NULL; + slist_wc_free_all(easysrc_clean); + easysrc_clean = NULL; +} + +/* Add a source line to the main code or remarks */ +CURLcode easysrc_add(struct slist_wc **plist, const char *line) +{ + CURLcode ret = CURLE_OK; + struct slist_wc *list = slist_wc_append(*plist, line); + if(!list) { + easysrc_free(); + ret = CURLE_OUT_OF_MEMORY; + } + else + *plist = list; + return ret; +} + +CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...) +{ + CURLcode ret; + char *bufp; + va_list ap; + va_start(ap, fmt); + bufp = curlx_mvaprintf(fmt, ap); + va_end(ap); + if(!bufp) { + ret = CURLE_OUT_OF_MEMORY; + } + else { + ret = easysrc_add(plist, bufp); + curl_free(bufp); + } + return ret; +} + +#define CHKRET(v) do {CURLcode ret = (v); if(ret) return ret;} while(0) + +CURLcode easysrc_init(void) +{ + CHKRET(easysrc_add(&easysrc_code, + "hnd = curl_easy_init();")); + return CURLE_OK; +} + +CURLcode easysrc_perform(void) +{ + /* Note any setopt calls which we could not convert */ + if(easysrc_toohard) { + int i; + struct curl_slist *ptr; + const char *c; + CHKRET(easysrc_add(&easysrc_code, "")); + /* Preamble comment */ + for(i = 0; ((c = srchard[i]) != NULL); i++) + CHKRET(easysrc_add(&easysrc_code, c)); + /* Each unconverted option */ + if(easysrc_toohard) { + for(ptr = easysrc_toohard->first; ptr; ptr = ptr->next) + CHKRET(easysrc_add(&easysrc_code, ptr->data)); + } + CHKRET(easysrc_add(&easysrc_code, "")); + CHKRET(easysrc_add(&easysrc_code, "*/")); + + slist_wc_free_all(easysrc_toohard); + easysrc_toohard = NULL; + } + + CHKRET(easysrc_add(&easysrc_code, "")); + CHKRET(easysrc_add(&easysrc_code, "ret = curl_easy_perform(hnd);")); + CHKRET(easysrc_add(&easysrc_code, "")); + + return CURLE_OK; +} + +CURLcode easysrc_cleanup(void) +{ + CHKRET(easysrc_add(&easysrc_code, "curl_easy_cleanup(hnd);")); + CHKRET(easysrc_add(&easysrc_code, "hnd = NULL;")); + + return CURLE_OK; +} + +void dumpeasysrc(struct GlobalConfig *config) +{ + struct curl_slist *ptr; + char *o = config->libcurl; + + FILE *out; + bool fopened = FALSE; + if(strcmp(o, "-")) { + out = fopen(o, FOPEN_WRITETEXT); + fopened = TRUE; + } + else + out = stdout; + if(!out) + warnf(config, "Failed to open %s to write libcurl code", o); + else { + int i; + const char *c; + + for(i = 0; ((c = srchead[i]) != NULL); i++) + fprintf(out, "%s\n", c); + + /* Declare variables used for complex setopt values */ + if(easysrc_decl) { + for(ptr = easysrc_decl->first; ptr; ptr = ptr->next) + fprintf(out, " %s\n", ptr->data); + } + + /* Set up complex values for setopt calls */ + if(easysrc_data) { + fprintf(out, "\n"); + + for(ptr = easysrc_data->first; ptr; ptr = ptr->next) + fprintf(out, " %s\n", ptr->data); + } + + fprintf(out, "\n"); + if(easysrc_code) { + for(ptr = easysrc_code->first; ptr; ptr = ptr->next) { + if(ptr->data[0]) { + fprintf(out, " %s\n", ptr->data); + } + else { + fprintf(out, "\n"); + } + } + } + + if(easysrc_clean) { + for(ptr = easysrc_clean->first; ptr; ptr = ptr->next) + fprintf(out, " %s\n", ptr->data); + } + + for(i = 0; ((c = srcend[i]) != NULL); i++) + fprintf(out, "%s\n", c); + + if(fopened) + fclose(out); + } + + easysrc_free(); +} + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/src/tool_easysrc.h b/src/tool_easysrc.h new file mode 100644 index 0000000..f698c8f --- /dev/null +++ b/src/tool_easysrc.h @@ -0,0 +1,58 @@ +#ifndef HEADER_CURL_TOOL_EASYSRC_H +#define HEADER_CURL_TOOL_EASYSRC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#ifndef CURL_DISABLE_LIBCURL_OPTION + +/* global variable declarations, for easy-interface source code generation */ + +extern struct slist_wc *easysrc_decl; /* Variable declarations */ +extern struct slist_wc *easysrc_data; /* Build slists, forms etc. */ +extern struct slist_wc *easysrc_code; /* Setopt calls etc. */ +extern struct slist_wc *easysrc_toohard; /* Unconvertible setopt */ +extern struct slist_wc *easysrc_clean; /* Clean up (reverse order) */ + +extern int easysrc_mime_count; /* Number of curl_mime variables */ +extern int easysrc_slist_count; /* Number of curl_slist variables */ + +extern CURLcode easysrc_init(void); +extern CURLcode easysrc_add(struct slist_wc **plist, const char *bupf); +extern CURLcode easysrc_addf(struct slist_wc **plist, + const char *fmt, ...) CURL_PRINTF(2, 3); +extern CURLcode easysrc_perform(void); +extern CURLcode easysrc_cleanup(void); + +void dumpeasysrc(struct GlobalConfig *config); + +#else /* CURL_DISABLE_LIBCURL_OPTION is defined */ + +#define easysrc_init() CURLE_OK +#define easysrc_cleanup() +#define dumpeasysrc(x) +#define easysrc_perform() CURLE_OK + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ + +#endif /* HEADER_CURL_TOOL_EASYSRC_H */ diff --git a/src/tool_filetime.c b/src/tool_filetime.c new file mode 100644 index 0000000..1311388 --- /dev/null +++ b/src/tool_filetime.c @@ -0,0 +1,156 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_filetime.h" +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "curlx.h" + +#ifdef HAVE_UTIME_H +# include +#elif defined(HAVE_SYS_UTIME_H) +# include +#endif + +/* Returns 0 on success, non-zero on file problems */ +int getfiletime(const char *filename, struct GlobalConfig *global, + curl_off_t *stamp) +{ + int rc = 1; + +/* Windows stat() may attempt to adjust the unix GMT file time by a daylight + saving time offset and since it's GMT that is bad behavior. When we have + access to a 64-bit type we can bypass stat and get the times directly. */ +#if defined(_WIN32) + HANDLE hfile; + TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename); + + hfile = CreateFile(tchar_filename, FILE_READ_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE), + NULL, OPEN_EXISTING, 0, NULL); + curlx_unicodefree(tchar_filename); + if(hfile != INVALID_HANDLE_VALUE) { + FILETIME ft; + if(GetFileTime(hfile, NULL, NULL, &ft)) { + curl_off_t converted = (curl_off_t)ft.dwLowDateTime + | ((curl_off_t)ft.dwHighDateTime) << 32; + + if(converted < CURL_OFF_T_C(116444736000000000)) + warnf(global, "Failed to get filetime: underflow"); + else { + *stamp = (converted - CURL_OFF_T_C(116444736000000000)) / 10000000; + rc = 0; + } + } + else { + warnf(global, "Failed to get filetime: " + "GetFileTime failed: GetLastError %u", + (unsigned int)GetLastError()); + } + CloseHandle(hfile); + } + else if(GetLastError() != ERROR_FILE_NOT_FOUND) { + warnf(global, "Failed to get filetime: " + "CreateFile failed: GetLastError %u", + (unsigned int)GetLastError()); + } +#else + struct_stat statbuf; + if(-1 != stat(filename, &statbuf)) { + *stamp = (curl_off_t)statbuf.st_mtime; + rc = 0; + } + else + warnf(global, "Failed to get filetime: %s", strerror(errno)); +#endif + return rc; +} + +#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || defined(_WIN32) +void setfiletime(curl_off_t filetime, const char *filename, + struct GlobalConfig *global) +{ + if(filetime >= 0) { +/* Windows utime() may attempt to adjust the unix GMT file time by a daylight + saving time offset and since it's GMT that is bad behavior. When we have + access to a 64-bit type we can bypass utime and set the times directly. */ +#if defined(_WIN32) + HANDLE hfile; + TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename); + + /* 910670515199 is the maximum unix filetime that can be used as a + Windows FILETIME without overflow: 30827-12-31T23:59:59. */ + if(filetime > CURL_OFF_T_C(910670515199)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on outfile: overflow", filetime); + curlx_unicodefree(tchar_filename); + return; + } + + hfile = CreateFile(tchar_filename, FILE_WRITE_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE), + NULL, OPEN_EXISTING, 0, NULL); + curlx_unicodefree(tchar_filename); + if(hfile != INVALID_HANDLE_VALUE) { + curl_off_t converted = ((curl_off_t)filetime * 10000000) + + CURL_OFF_T_C(116444736000000000); + FILETIME ft; + ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF); + ft.dwHighDateTime = (DWORD)(converted >> 32); + if(!SetFileTime(hfile, NULL, &ft, &ft)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on outfile: SetFileTime failed: GetLastError %u", + filetime, (unsigned int)GetLastError()); + } + CloseHandle(hfile); + } + else { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on outfile: CreateFile failed: GetLastError %u", + filetime, (unsigned int)GetLastError()); + } + +#elif defined(HAVE_UTIMES) + struct timeval times[2]; + times[0].tv_sec = times[1].tv_sec = (time_t)filetime; + times[0].tv_usec = times[1].tv_usec = 0; + if(utimes(filename, times)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on '%s': %s", filetime, filename, strerror(errno)); + } + +#elif defined(HAVE_UTIME) + struct utimbuf times; + times.actime = (time_t)filetime; + times.modtime = (time_t)filetime; + if(utime(filename, ×)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on '%s': %s", filetime, filename, strerror(errno)); + } +#endif + } +} +#endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ + defined(_WIN32) */ diff --git a/src/tool_filetime.h b/src/tool_filetime.h new file mode 100644 index 0000000..205e5ce --- /dev/null +++ b/src/tool_filetime.h @@ -0,0 +1,42 @@ +#ifndef HEADER_CURL_TOOL_FILETIME_H +#define HEADER_CURL_TOOL_FILETIME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +struct GlobalConfig; + +int getfiletime(const char *filename, struct GlobalConfig *global, + curl_off_t *stamp); + +#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ + (defined(_WIN32) && (SIZEOF_CURL_OFF_T >= 8)) +void setfiletime(curl_off_t filetime, const char *filename, + struct GlobalConfig *global); +#else +#define setfiletime(a,b,c) Curl_nop_stmt +#endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ + (defined(_WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */ + +#endif /* HEADER_CURL_TOOL_FILETIME_H */ diff --git a/src/tool_findfile.c b/src/tool_findfile.c new file mode 100644 index 0000000..a1544a5 --- /dev/null +++ b/src/tool_findfile.c @@ -0,0 +1,157 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_PWD_H +# undef __NO_NET_API /* required for building for AmigaOS */ +# include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +#include + +#include "tool_findfile.h" + +#include "memdebug.h" /* keep this as LAST include */ + +struct finder { + const char *env; + const char *append; + bool withoutdot; +}; + +/* The order of the variables below is important, as the index number is used + in the findfile() function */ +static const struct finder conf_list[] = { + { "CURL_HOME", NULL, FALSE }, + { "XDG_CONFIG_HOME", NULL, FALSE }, /* index == 1, used in the code */ + { "HOME", NULL, FALSE }, +#ifdef _WIN32 + { "USERPROFILE", NULL, FALSE }, + { "APPDATA", NULL, FALSE }, + { "USERPROFILE", "\\Application Data", FALSE}, +#endif + /* these are for .curlrc if XDG_CONFIG_HOME is not defined */ + { "CURL_HOME", "/.config", TRUE }, + { "HOME", "/.config", TRUE }, + + { NULL, NULL, FALSE } +}; + +static char *checkhome(const char *home, const char *fname, bool dotscore) +{ + const char pref[2] = { '.', '_' }; + int i; + for(i = 0; i < (dotscore ? 2 : 1); i++) { + char *c; + if(dotscore) + c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]); + else + c = curl_maprintf("%s" DIR_CHAR "%s", home, fname); + if(c) { + int fd = open(c, O_RDONLY); + if(fd >= 0) { + char *path = strdup(c); + close(fd); + curl_free(c); + return path; + } + curl_free(c); + } + } + return NULL; +} + +/* + * findfile() - return the full path name of the file. + * + * If 'dotscore' is TRUE, then check for the file first with a leading dot + * and then with a leading underscore. + * + * 1. Iterate over the environment variables in order, and if set, check for + * the given file to be accessed there, then it is a match. + * 2. Non-windows: try getpwuid + */ +char *findfile(const char *fname, int dotscore) +{ + int i; + bool xdg = FALSE; + DEBUGASSERT(fname && fname[0]); + DEBUGASSERT((dotscore != 1) || (fname[0] == '.')); + + if(!fname[0]) + return NULL; + + for(i = 0; conf_list[i].env; i++) { + char *home = curl_getenv(conf_list[i].env); + if(home) { + char *path; + const char *filename = fname; + if(i == 1 /* XDG_CONFIG_HOME */) + xdg = TRUE; + if(!home[0]) { + curl_free(home); + continue; + } + if(conf_list[i].append) { + char *c = curl_maprintf("%s%s", home, conf_list[i].append); + curl_free(home); + if(!c) + return NULL; + home = c; + } + if(conf_list[i].withoutdot) { + if(!dotscore || xdg) { + /* this is not looking for .curlrc, or the XDG_CONFIG_HOME was + defined so we skip the extended check */ + curl_free(home); + continue; + } + filename++; /* move past the leading dot */ + dotscore = 0; /* disable it for this check */ + } + path = checkhome(home, filename, dotscore ? dotscore - 1 : 0); + curl_free(home); + if(path) + return path; + } + } +#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) + { + struct passwd *pw = getpwuid(geteuid()); + if(pw) { + char *home = pw->pw_dir; + if(home && home[0]) + return checkhome(home, fname, FALSE); + } + } +#endif /* PWD-stuff */ + return NULL; +} diff --git a/src/tool_findfile.h b/src/tool_findfile.h new file mode 100644 index 0000000..63d2519 --- /dev/null +++ b/src/tool_findfile.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_HOMEDIR_H +#define HEADER_CURL_TOOL_HOMEDIR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef _WIN32 +#define CURLRC_DOTSCORE 2 /* look for underscore-prefixed name too */ +#else +#define CURLRC_DOTSCORE 1 /* regular .curlrc check */ +#endif + +char *findfile(const char *fname, int dotscore); + +#endif /* HEADER_CURL_TOOL_HOMEDIR_H */ diff --git a/src/tool_formparse.c b/src/tool_formparse.c new file mode 100644 index 0000000..875ce78 --- /dev/null +++ b/src/tool_formparse.c @@ -0,0 +1,907 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_binmode.h" +#include "tool_getparam.h" +#include "tool_paramhlp.h" +#include "tool_formparse.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* tool_mime functions. */ +static struct tool_mime *tool_mime_new(struct tool_mime *parent, + toolmimekind kind) +{ + struct tool_mime *m = (struct tool_mime *) calloc(1, sizeof(*m)); + + if(m) { + m->kind = kind; + m->parent = parent; + if(parent) { + m->prev = parent->subparts; + parent->subparts = m; + } + } + return m; +} + +static struct tool_mime *tool_mime_new_parts(struct tool_mime *parent) +{ + return tool_mime_new(parent, TOOLMIME_PARTS); +} + +static struct tool_mime *tool_mime_new_data(struct tool_mime *parent, + char *mime_data) +{ + char *mime_data_copy; + struct tool_mime *m = NULL; + + mime_data_copy = strdup(mime_data); + if(mime_data_copy) { + m = tool_mime_new(parent, TOOLMIME_DATA); + if(!m) + free(mime_data_copy); + else + m->data = mime_data_copy; + } + return m; +} + +static struct tool_mime *tool_mime_new_filedata(struct tool_mime *parent, + const char *filename, + bool isremotefile, + CURLcode *errcode) +{ + CURLcode result = CURLE_OK; + struct tool_mime *m = NULL; + + *errcode = CURLE_OUT_OF_MEMORY; + if(strcmp(filename, "-")) { + /* This is a normal file. */ + char *filedup = strdup(filename); + if(filedup) { + m = tool_mime_new(parent, TOOLMIME_FILE); + if(!m) + free(filedup); + else { + m->data = filedup; + if(!isremotefile) + m->kind = TOOLMIME_FILEDATA; + *errcode = CURLE_OK; + } + } + } + else { /* Standard input. */ + int fd = fileno(stdin); + char *data = NULL; + curl_off_t size; + curl_off_t origin; + struct_stat sbuf; + + set_binmode(stdin); + origin = ftell(stdin); + /* If stdin is a regular file, do not buffer data but read it + when needed. */ + if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) && +#ifdef __VMS + sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC && +#endif + S_ISREG(sbuf.st_mode)) { + size = sbuf.st_size - origin; + if(size < 0) + size = 0; + } + else { /* Not suitable for direct use, buffer stdin data. */ + size_t stdinsize = 0; + + switch(file2memory(&data, &stdinsize, stdin)) { + case PARAM_NO_MEM: + return m; + case PARAM_READ_ERROR: + result = CURLE_READ_ERROR; + break; + default: + if(!stdinsize) { + /* Zero-length data has been freed. Re-create it. */ + data = strdup(""); + if(!data) + return m; + } + break; + } + size = curlx_uztoso(stdinsize); + origin = 0; + } + m = tool_mime_new(parent, TOOLMIME_STDIN); + if(!m) + Curl_safefree(data); + else { + m->data = data; + m->origin = origin; + m->size = size; + m->curpos = 0; + if(!isremotefile) + m->kind = TOOLMIME_STDINDATA; + *errcode = result; + } + } + return m; +} + +void tool_mime_free(struct tool_mime *mime) +{ + if(mime) { + if(mime->subparts) + tool_mime_free(mime->subparts); + if(mime->prev) + tool_mime_free(mime->prev); + Curl_safefree(mime->name); + Curl_safefree(mime->filename); + Curl_safefree(mime->type); + Curl_safefree(mime->encoder); + Curl_safefree(mime->data); + curl_slist_free_all(mime->headers); + free(mime); + } +} + + +/* Mime part callbacks for stdin. */ +size_t tool_mime_stdin_read(char *buffer, + size_t size, size_t nitems, void *arg) +{ + struct tool_mime *sip = (struct tool_mime *) arg; + curl_off_t bytesleft; + (void) size; /* Always 1: ignored. */ + + if(sip->size >= 0) { + if(sip->curpos >= sip->size) + return 0; /* At eof. */ + bytesleft = sip->size - sip->curpos; + if(curlx_uztoso(nitems) > bytesleft) + nitems = curlx_sotouz(bytesleft); + } + if(nitems) { + if(sip->data) { + /* Return data from memory. */ + memcpy(buffer, sip->data + curlx_sotouz(sip->curpos), nitems); + } + else { + /* Read from stdin. */ + nitems = fread(buffer, 1, nitems, stdin); + if(ferror(stdin)) { + /* Show error only once. */ + if(sip->config) { + warnf(sip->config, "stdin: %s", strerror(errno)); + sip->config = NULL; + } + return CURL_READFUNC_ABORT; + } + } + sip->curpos += curlx_uztoso(nitems); + } + return nitems; +} + +int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence) +{ + struct tool_mime *sip = (struct tool_mime *) instream; + + switch(whence) { + case SEEK_CUR: + offset += sip->curpos; + break; + case SEEK_END: + offset += sip->size; + break; + } + if(offset < 0) + return CURL_SEEKFUNC_CANTSEEK; + if(!sip->data) { + if(fseek(stdin, (long) (offset + sip->origin), SEEK_SET)) + return CURL_SEEKFUNC_CANTSEEK; + } + sip->curpos = offset; + return CURL_SEEKFUNC_OK; +} + +/* Translate an internal mime tree into a libcurl mime tree. */ + +static CURLcode tool2curlparts(CURL *curl, struct tool_mime *m, + curl_mime *mime) +{ + CURLcode ret = CURLE_OK; + curl_mimepart *part = NULL; + curl_mime *submime = NULL; + const char *filename = NULL; + + if(m) { + ret = tool2curlparts(curl, m->prev, mime); + if(!ret) { + part = curl_mime_addpart(mime); + if(!part) + ret = CURLE_OUT_OF_MEMORY; + } + if(!ret) { + filename = m->filename; + switch(m->kind) { + case TOOLMIME_PARTS: + ret = tool2curlmime(curl, m, &submime); + if(!ret) { + ret = curl_mime_subparts(part, submime); + if(ret) + curl_mime_free(submime); + } + break; + + case TOOLMIME_DATA: + ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED); + break; + + case TOOLMIME_FILE: + case TOOLMIME_FILEDATA: + ret = curl_mime_filedata(part, m->data); + if(!ret && m->kind == TOOLMIME_FILEDATA && !filename) + ret = curl_mime_filename(part, NULL); + break; + + case TOOLMIME_STDIN: + if(!filename) + filename = "-"; + FALLTHROUGH(); + case TOOLMIME_STDINDATA: + ret = curl_mime_data_cb(part, m->size, + (curl_read_callback) tool_mime_stdin_read, + (curl_seek_callback) tool_mime_stdin_seek, + NULL, m); + break; + + default: + /* Other cases not possible in this context. */ + break; + } + } + if(!ret && filename) + ret = curl_mime_filename(part, filename); + if(!ret) + ret = curl_mime_type(part, m->type); + if(!ret) + ret = curl_mime_headers(part, m->headers, 0); + if(!ret) + ret = curl_mime_encoder(part, m->encoder); + if(!ret) + ret = curl_mime_name(part, m->name); + } + return ret; +} + +CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime) +{ + CURLcode ret = CURLE_OK; + + *mime = curl_mime_init(curl); + if(!*mime) + ret = CURLE_OUT_OF_MEMORY; + else + ret = tool2curlparts(curl, m->subparts, *mime); + if(ret) { + curl_mime_free(*mime); + *mime = NULL; + } + return ret; +} + +/* + * helper function to get a word from form param + * after call get_parm_word, str either point to string end + * or point to any of end chars. + */ +static char *get_param_word(struct OperationConfig *config, char **str, + char **end_pos, char endchar) +{ + char *ptr = *str; + /* the first non-space char is here */ + char *word_begin = ptr; + char *ptr2; + char *escape = NULL; + + if(*ptr == '"') { + ++ptr; + while(*ptr) { + if(*ptr == '\\') { + if(ptr[1] == '\\' || ptr[1] == '"') { + /* remember the first escape position */ + if(!escape) + escape = ptr; + /* skip escape of back-slash or double-quote */ + ptr += 2; + continue; + } + } + if(*ptr == '"') { + bool trailing_data = FALSE; + *end_pos = ptr; + if(escape) { + /* has escape, we restore the unescaped string here */ + ptr = ptr2 = escape; + do { + if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"')) + ++ptr; + *ptr2++ = *ptr++; + } + while(ptr < *end_pos); + *end_pos = ptr2; + } + ++ptr; + while(*ptr && *ptr != ';' && *ptr != endchar) { + if(!ISSPACE(*ptr)) + trailing_data = TRUE; + ++ptr; + } + if(trailing_data) + warnf(config->global, "Trailing data after quoted form parameter"); + *str = ptr; + return word_begin + 1; + } + ++ptr; + } + /* end quote is missing, treat it as non-quoted. */ + ptr = word_begin; + } + + while(*ptr && *ptr != ';' && *ptr != endchar) + ++ptr; + *str = *end_pos = ptr; + return word_begin; +} + +/* Append slist item and return -1 if failed. */ +static int slist_append(struct curl_slist **plist, const char *data) +{ + struct curl_slist *s = curl_slist_append(*plist, data); + + if(!s) + return -1; + + *plist = s; + return 0; +} + +/* Read headers from a file and append to list. */ +static int read_field_headers(struct OperationConfig *config, + const char *filename, FILE *fp, + struct curl_slist **pheaders) +{ + size_t hdrlen = 0; + size_t pos = 0; + bool incomment = FALSE; + int lineno = 1; + char hdrbuf[999] = ""; /* Max. header length + 1. */ + + for(;;) { + int c = getc(fp); + if(c == EOF || (!pos && !ISSPACE(c))) { + /* Strip and flush the current header. */ + while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1])) + hdrlen--; + if(hdrlen) { + hdrbuf[hdrlen] = '\0'; + if(slist_append(pheaders, hdrbuf)) { + errorf(config->global, "Out of memory for field headers"); + return -1; + } + hdrlen = 0; + } + } + + switch(c) { + case EOF: + if(ferror(fp)) { + errorf(config->global, "Header file %s read error: %s", filename, + strerror(errno)); + return -1; + } + return 0; /* Done. */ + case '\r': + continue; /* Ignore. */ + case '\n': + pos = 0; + incomment = FALSE; + lineno++; + continue; + case '#': + if(!pos) + incomment = TRUE; + break; + } + + pos++; + if(!incomment) { + if(hdrlen == sizeof(hdrbuf) - 1) { + warnf(config->global, "File %s line %d: header too long (truncated)", + filename, lineno); + c = ' '; + } + if(hdrlen <= sizeof(hdrbuf) - 1) + hdrbuf[hdrlen++] = (char) c; + } + } + /* NOTREACHED */ +} + +static int get_param_part(struct OperationConfig *config, char endchar, + char **str, char **pdata, char **ptype, + char **pfilename, char **pencoder, + struct curl_slist **pheaders) +{ + char *p = *str; + char *type = NULL; + char *filename = NULL; + char *encoder = NULL; + char *endpos; + char *tp; + char sep; + char type_major[128] = ""; + char type_minor[128] = ""; + char *endct = NULL; + struct curl_slist *headers = NULL; + + if(ptype) + *ptype = NULL; + if(pfilename) + *pfilename = NULL; + if(pheaders) + *pheaders = NULL; + if(pencoder) + *pencoder = NULL; + while(ISSPACE(*p)) + p++; + tp = p; + *pdata = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(*pdata == tp) + while(endpos > *pdata && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + while(sep == ';') { + while(p++ && ISSPACE(*p)) + ; + + if(!endct && checkprefix("type=", p)) { + for(p += 5; ISSPACE(*p); p++) + ; + /* set type pointer */ + type = p; + + /* verify that this is a fine type specifier */ + if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) { + warnf(config->global, "Illegally formatted content-type field"); + curl_slist_free_all(headers); + return -1; /* illegal content-type syntax! */ + } + + /* now point beyond the content-type specifier */ + p = type + strlen(type_major) + strlen(type_minor) + 1; + for(endct = p; *p && *p != ';' && *p != endchar; p++) + if(!ISSPACE(*p)) + endct = p + 1; + sep = *p; + } + else if(checkprefix("filename=", p)) { + if(endct) { + *endct = '\0'; + endct = NULL; + } + for(p += 9; ISSPACE(*p); p++) + ; + tp = p; + filename = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(filename == tp) + while(endpos > filename && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + } + else if(checkprefix("headers=", p)) { + if(endct) { + *endct = '\0'; + endct = NULL; + } + p += 8; + if(*p == '@' || *p == '<') { + char *hdrfile; + FILE *fp; + /* Read headers from a file. */ + + do { + p++; + } while(ISSPACE(*p)); + tp = p; + hdrfile = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(hdrfile == tp) + while(endpos > hdrfile && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + fp = fopen(hdrfile, FOPEN_READTEXT); + if(!fp) + warnf(config->global, "Cannot read from %s: %s", hdrfile, + strerror(errno)); + else { + int i = read_field_headers(config, hdrfile, fp, &headers); + + fclose(fp); + if(i) { + curl_slist_free_all(headers); + return -1; + } + } + } + else { + char *hdr; + + while(ISSPACE(*p)) + p++; + tp = p; + hdr = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(hdr == tp) + while(endpos > hdr && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + if(slist_append(&headers, hdr)) { + errorf(config->global, "Out of memory for field header"); + curl_slist_free_all(headers); + return -1; + } + } + } + else if(checkprefix("encoder=", p)) { + if(endct) { + *endct = '\0'; + endct = NULL; + } + for(p += 8; ISSPACE(*p); p++) + ; + tp = p; + encoder = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(encoder == tp) + while(endpos > encoder && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + } + else if(endct) { + /* This is part of content type. */ + for(endct = p; *p && *p != ';' && *p != endchar; p++) + if(!ISSPACE(*p)) + endct = p + 1; + sep = *p; + } + else { + /* unknown prefix, skip to next block */ + char *unknown = get_param_word(config, &p, &endpos, endchar); + + sep = *p; + *endpos = '\0'; + if(*unknown) + warnf(config->global, "skip unknown form field: %s", unknown); + } + } + + /* Terminate content type. */ + if(endct) + *endct = '\0'; + + if(ptype) + *ptype = type; + else if(type) + warnf(config->global, "Field content type not allowed here: %s", type); + + if(pfilename) + *pfilename = filename; + else if(filename) + warnf(config->global, + "Field file name not allowed here: %s", filename); + + if(pencoder) + *pencoder = encoder; + else if(encoder) + warnf(config->global, + "Field encoder not allowed here: %s", encoder); + + if(pheaders) + *pheaders = headers; + else if(headers) { + warnf(config->global, + "Field headers not allowed here: %s", headers->data); + curl_slist_free_all(headers); + } + + *str = p; + return sep & 0xFF; +} + + +/*************************************************************************** + * + * formparse() + * + * Reads a 'name=value' parameter and builds the appropriate linked list. + * + * If the value is of the form ''. + * + * If literal_value is set, any initial '@' or '<' in the value string + * loses its special meaning, as does any embedded ';type='. + * + * You may specify more than one file for a single name (field). Specify + * multiple files by writing it like: + * + * 'name=@filename,filename2,filename3' + * + * or use double-quotes quote the filename: + * + * 'name=@"filename","filename2","filename3"' + * + * If you want content-types specified for each too, write them like: + * + * 'name=@filename;type=image/gif,filename2,filename3' + * + * If you want custom headers added for a single part, write them in a separate + * file and do like this: + * + * 'name=foo;headers=@headerfile' or why not + * 'name=@filemame;headers=@headerfile' + * + * To upload a file, but to fake the file name that will be included in the + * formpost, do like this: + * + * 'name=@filename;filename=/dev/null' or quote the faked filename like: + * 'name=@filename;filename="play, play, and play.txt"' + * + * If filename/path contains ',' or ';', it must be quoted by double-quotes, + * else curl will fail to figure out the correct filename. if the filename + * tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash. + * + ***************************************************************************/ + +#define SET_TOOL_MIME_PTR(m, field) \ + do { \ + if(field) { \ + (m)->field = strdup(field); \ + if(!(m)->field) \ + goto fail; \ + } \ + } while(0) + +int formparse(struct OperationConfig *config, + const char *input, + struct tool_mime **mimeroot, + struct tool_mime **mimecurrent, + bool literal_value) +{ + /* input MUST be a string in the format 'name=contents' and we'll + build a linked list with the info */ + char *name = NULL; + char *contents = NULL; + char *contp; + char *data; + char *type = NULL; + char *filename = NULL; + char *encoder = NULL; + struct curl_slist *headers = NULL; + struct tool_mime *part = NULL; + CURLcode res; + int err = 1; + + /* Allocate the main mime structure if needed. */ + if(!*mimecurrent) { + *mimeroot = tool_mime_new_parts(NULL); + if(!*mimeroot) + goto fail; + *mimecurrent = *mimeroot; + } + + /* Make a copy we can overwrite. */ + contents = strdup(input); + if(!contents) + goto fail; + + /* Scan for the end of the name. */ + contp = strchr(contents, '='); + if(contp) { + int sep = '\0'; + if(contp > contents) + name = contents; + *contp++ = '\0'; + + if(*contp == '(' && !literal_value) { + /* Starting a multipart. */ + sep = get_param_part(config, '\0', + &contp, &data, &type, NULL, NULL, &headers); + if(sep < 0) + goto fail; + part = tool_mime_new_parts(*mimecurrent); + if(!part) + goto fail; + *mimecurrent = part; + part->headers = headers; + headers = NULL; + SET_TOOL_MIME_PTR(part, type); + } + else if(!name && !strcmp(contp, ")") && !literal_value) { + /* Ending a multipart. */ + if(*mimecurrent == *mimeroot) { + warnf(config->global, "no multipart to terminate"); + goto fail; + } + *mimecurrent = (*mimecurrent)->parent; + } + else if('@' == contp[0] && !literal_value) { + + /* we use the @-letter to indicate file name(s) */ + + struct tool_mime *subparts = NULL; + + do { + /* since this was a file, it may have a content-type specifier + at the end too, or a filename. Or both. */ + ++contp; + sep = get_param_part(config, ',', &contp, + &data, &type, &filename, &encoder, &headers); + if(sep < 0) { + goto fail; + } + + /* now contp point to comma or string end. + If more files to come, make sure we have multiparts. */ + if(!subparts) { + if(sep != ',') /* If there is a single file. */ + subparts = *mimecurrent; + else { + subparts = tool_mime_new_parts(*mimecurrent); + if(!subparts) + goto fail; + } + } + + /* Store that file in a part. */ + part = tool_mime_new_filedata(subparts, data, TRUE, &res); + if(!part) + goto fail; + part->headers = headers; + headers = NULL; + part->config = config->global; + if(res == CURLE_READ_ERROR) { + /* An error occurred while reading stdin: if read has started, + issue the error now. Else, delay it until processed by + libcurl. */ + if(part->size > 0) { + warnf(config->global, + "error while reading standard input"); + goto fail; + } + Curl_safefree(part->data); + part->data = NULL; + part->size = -1; + res = CURLE_OK; + } + SET_TOOL_MIME_PTR(part, filename); + SET_TOOL_MIME_PTR(part, type); + SET_TOOL_MIME_PTR(part, encoder); + + /* *contp could be '\0', so we just check with the delimiter */ + } while(sep); /* loop if there's another file name */ + part = (*mimecurrent)->subparts; /* Set name on group. */ + } + else { + if(*contp == '<' && !literal_value) { + ++contp; + sep = get_param_part(config, '\0', &contp, + &data, &type, NULL, &encoder, &headers); + if(sep < 0) + goto fail; + + part = tool_mime_new_filedata(*mimecurrent, data, FALSE, + &res); + if(!part) + goto fail; + part->headers = headers; + headers = NULL; + part->config = config->global; + if(res == CURLE_READ_ERROR) { + /* An error occurred while reading stdin: if read has started, + issue the error now. Else, delay it until processed by + libcurl. */ + if(part->size > 0) { + warnf(config->global, + "error while reading standard input"); + goto fail; + } + Curl_safefree(part->data); + part->data = NULL; + part->size = -1; + res = CURLE_OK; + } + } + else { + if(literal_value) + data = contp; + else { + sep = get_param_part(config, '\0', &contp, + &data, &type, &filename, &encoder, &headers); + if(sep < 0) + goto fail; + } + + part = tool_mime_new_data(*mimecurrent, data); + if(!part) + goto fail; + part->headers = headers; + headers = NULL; + } + + SET_TOOL_MIME_PTR(part, filename); + SET_TOOL_MIME_PTR(part, type); + SET_TOOL_MIME_PTR(part, encoder); + + if(sep) { + *contp = (char) sep; + warnf(config->global, + "garbage at end of field specification: %s", contp); + } + } + + /* Set part name. */ + SET_TOOL_MIME_PTR(part, name); + } + else { + warnf(config->global, "Illegally formatted input field"); + goto fail; + } + err = 0; +fail: + Curl_safefree(contents); + curl_slist_free_all(headers); + return err; +} diff --git a/src/tool_formparse.h b/src/tool_formparse.h new file mode 100644 index 0000000..35d5c95 --- /dev/null +++ b/src/tool_formparse.h @@ -0,0 +1,73 @@ +#ifndef HEADER_CURL_TOOL_FORMPARSE_H +#define HEADER_CURL_TOOL_FORMPARSE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* Private structure for mime/parts. */ + +typedef enum { + TOOLMIME_NONE = 0, + TOOLMIME_PARTS, + TOOLMIME_DATA, + TOOLMIME_FILE, + TOOLMIME_FILEDATA, + TOOLMIME_STDIN, + TOOLMIME_STDINDATA +} toolmimekind; + +struct tool_mime { + /* Structural fields. */ + toolmimekind kind; /* Part kind. */ + struct tool_mime *parent; /* Parent item. */ + struct tool_mime *prev; /* Previous sibling (reverse order link). */ + /* Common fields. */ + char *data; /* Actual data or data filename. */ + char *name; /* Part name. */ + char *filename; /* Part's filename. */ + char *type; /* Part's mime type. */ + char *encoder; /* Part's requested encoding. */ + struct curl_slist *headers; /* User-defined headers. */ + /* TOOLMIME_PARTS fields. */ + struct tool_mime *subparts; /* Part's subparts. */ + /* TOOLMIME_STDIN/TOOLMIME_STDINDATA fields. */ + curl_off_t origin; /* Stdin read origin offset. */ + curl_off_t size; /* Stdin data size. */ + curl_off_t curpos; /* Stdin current read position. */ + struct GlobalConfig *config; /* For access from callback. */ +}; + +size_t tool_mime_stdin_read(char *buffer, + size_t size, size_t nitems, void *arg); +int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence); + +int formparse(struct OperationConfig *config, + const char *input, + struct tool_mime **mimeroot, + struct tool_mime **mimecurrent, + bool literal_value); +CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime); +void tool_mime_free(struct tool_mime *mime); + +#endif /* HEADER_CURL_TOOL_FORMPARSE_H */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c new file mode 100644 index 0000000..4c910fd --- /dev/null +++ b/src/tool_getparam.c @@ -0,0 +1,2858 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_binmode.h" +#include "tool_cfgable.h" +#include "tool_cb_prg.h" +#include "tool_filetime.h" +#include "tool_formparse.h" +#include "tool_getparam.h" +#include "tool_helpers.h" +#include "tool_libinfo.h" +#include "tool_msgs.h" +#include "tool_paramhlp.h" +#include "tool_parsecfg.h" +#include "tool_main.h" +#include "dynbuf.h" +#include "tool_stderr.h" +#include "var.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef MSDOS +# define USE_WATT32 +#endif + +#define ALLOW_BLANK TRUE +#define DENY_BLANK FALSE + +static ParameterError getstr(char **str, const char *val, bool allowblank) +{ + if(*str) { + free(*str); + *str = NULL; + } + if(val) { + if(!allowblank && !val[0]) + return PARAM_BLANK_STRING; + + *str = strdup(val); + if(!*str) + return PARAM_NO_MEM; + } + return PARAM_OK; +} + +/* one enum for every command line option. The name is the verbatim long + option name, but in uppercase with periods and minuses replaced with + underscores using a "C_" prefix. */ +typedef enum { + C_ABSTRACT_UNIX_SOCKET, + C_ALPN, + C_ALT_SVC, + C_ANYAUTH, + C_APPEND, + C_AWS_SIGV4, + C_BASIC, + C_BUFFER, + C_CA_NATIVE, + C_CACERT, + C_CAPATH, + C_CERT, + C_CERT_STATUS, + C_CERT_TYPE, + C_CIPHERS, + C_CLOBBER, + C_COMPRESSED, + C_COMPRESSED_SSH, + C_CONFIG, + C_CONNECT_TIMEOUT, + C_CONNECT_TO, + C_CONTINUE_AT, + C_COOKIE, + C_COOKIE_JAR, + C_CREATE_DIRS, + C_CREATE_FILE_MODE, + C_CRLF, + C_CRLFILE, + C_CURVES, + C_DATA, + C_DATA_ASCII, + C_DATA_BINARY, + C_DATA_RAW, + C_DATA_URLENCODE, + C_DELEGATION, + C_DIGEST, + C_DISABLE, + C_DISABLE_EPRT, + C_DISABLE_EPSV, + C_DISALLOW_USERNAME_IN_URL, + C_DNS_INTERFACE, + C_DNS_IPV4_ADDR, + C_DNS_IPV6_ADDR, + C_DNS_SERVERS, + C_DOH_CERT_STATUS, + C_DOH_INSECURE, + C_DOH_URL, + C_DUMP_HEADER, + C_EGD_FILE, + C_ENGINE, + C_EPRT, + C_EPSV, + C_ETAG_COMPARE, + C_ETAG_SAVE, + C_EXPECT100_TIMEOUT, + C_FAIL, + C_FAIL_EARLY, + C_FAIL_WITH_BODY, + C_FALSE_START, + C_FORM, + C_FORM_ESCAPE, + C_FORM_STRING, + C_FTP_ACCOUNT, + C_FTP_ALTERNATIVE_TO_USER, + C_FTP_CREATE_DIRS, + C_FTP_METHOD, + C_FTP_PASV, + C_FTP_PORT, + C_FTP_PRET, + C_FTP_SKIP_PASV_IP, + C_FTP_SSL, + C_FTP_SSL_CCC, + C_FTP_SSL_CCC_MODE, + C_FTP_SSL_CONTROL, + C_FTP_SSL_REQD, + C_GET, + C_GLOBOFF, + C_HAPPY_EYEBALLS_TIMEOUT_MS, + C_HAPROXY_CLIENTIP, + C_HAPROXY_PROTOCOL, + C_HEAD, + C_HEADER, + C_HELP, + C_HOSTPUBMD5, + C_HOSTPUBSHA256, + C_HSTS, + C_HTTP0_9, + C_HTTP1_0, + C_HTTP1_1, + C_HTTP2, + C_HTTP2_PRIOR_KNOWLEDGE, + C_HTTP3, + C_HTTP3_ONLY, + C_IGNORE_CONTENT_LENGTH, + C_INCLUDE, + C_INSECURE, + C_INTERFACE, + C_IPFS_GATEWAY, + C_IPV4, + C_IPV6, + C_JSON, + C_JUNK_SESSION_COOKIES, + C_KEEPALIVE, + C_KEEPALIVE_TIME, + C_KEY, + C_KEY_TYPE, + C_KRB, + C_KRB4, + C_LIBCURL, + C_LIMIT_RATE, + C_LIST_ONLY, + C_LOCAL_PORT, + C_LOCATION, + C_LOCATION_TRUSTED, + C_LOGIN_OPTIONS, + C_MAIL_AUTH, + C_MAIL_FROM, + C_MAIL_RCPT, + C_MAIL_RCPT_ALLOWFAILS, + C_MANUAL, + C_MAX_FILESIZE, + C_MAX_REDIRS, + C_MAX_TIME, + C_METALINK, + C_NEGOTIATE, + C_NETRC, + C_NETRC_FILE, + C_NETRC_OPTIONAL, + C_NEXT, + C_NOPROXY, + C_NPN, + C_NTLM, + C_NTLM_WB, + C_OAUTH2_BEARER, + C_OUTPUT, + C_OUTPUT_DIR, + C_PARALLEL, + C_PARALLEL_IMMEDIATE, + C_PARALLEL_MAX, + C_PASS, + C_PATH_AS_IS, + C_PINNEDPUBKEY, + C_POST301, + C_POST302, + C_POST303, + C_PREPROXY, + C_PROGRESS_BAR, + C_PROGRESS_METER, + C_PROTO, + C_PROTO_DEFAULT, + C_PROTO_REDIR, + C_PROXY, + C_PROXY_ANYAUTH, + C_PROXY_BASIC, + C_PROXY_CA_NATIVE, + C_PROXY_CACERT, + C_PROXY_CAPATH, + C_PROXY_CERT, + C_PROXY_CERT_TYPE, + C_PROXY_CIPHERS, + C_PROXY_CRLFILE, + C_PROXY_DIGEST, + C_PROXY_HEADER, + C_PROXY_HTTP2, + C_PROXY_INSECURE, + C_PROXY_KEY, + C_PROXY_KEY_TYPE, + C_PROXY_NEGOTIATE, + C_PROXY_NTLM, + C_PROXY_PASS, + C_PROXY_PINNEDPUBKEY, + C_PROXY_SERVICE_NAME, + C_PROXY_SSL_ALLOW_BEAST, + C_PROXY_SSL_AUTO_CLIENT_CERT, + C_PROXY_TLS13_CIPHERS, + C_PROXY_TLSAUTHTYPE, + C_PROXY_TLSPASSWORD, + C_PROXY_TLSUSER, + C_PROXY_TLSV1, + C_PROXY_USER, + C_PROXY1_0, + C_PROXYTUNNEL, + C_PUBKEY, + C_QUOTE, + C_RANDOM_FILE, + C_RANGE, + C_RATE, + C_RAW, + C_REFERER, + C_REMOTE_HEADER_NAME, + C_REMOTE_NAME, + C_REMOTE_NAME_ALL, + C_REMOTE_TIME, + C_REMOVE_ON_ERROR, + C_REQUEST, + C_REQUEST_TARGET, + C_RESOLVE, + C_RETRY, + C_RETRY_ALL_ERRORS, + C_RETRY_CONNREFUSED, + C_RETRY_DELAY, + C_RETRY_MAX_TIME, + C_SASL_AUTHZID, + C_SASL_IR, + C_SERVICE_NAME, + C_SESSIONID, + C_SHOW_ERROR, + C_SILENT, + C_SOCKS4, + C_SOCKS4A, + C_SOCKS5, + C_SOCKS5_BASIC, + C_SOCKS5_GSSAPI, + C_SOCKS5_GSSAPI_NEC, + C_SOCKS5_GSSAPI_SERVICE, + C_SOCKS5_HOSTNAME, + C_SPEED_LIMIT, + C_SPEED_TIME, + C_SSL, + C_SSL_ALLOW_BEAST, + C_SSL_AUTO_CLIENT_CERT, + C_SSL_NO_REVOKE, + C_SSL_REQD, + C_SSL_REVOKE_BEST_EFFORT, + C_SSLV2, + C_SSLV3, + C_STDERR, + C_STYLED_OUTPUT, + C_SUPPRESS_CONNECT_HEADERS, + C_TCP_FASTOPEN, + C_TCP_NODELAY, + C_TELNET_OPTION, + C_TEST_EVENT, + C_TFTP_BLKSIZE, + C_TFTP_NO_OPTIONS, + C_TIME_COND, + C_TLS_MAX, + C_TLS13_CIPHERS, + C_TLSAUTHTYPE, + C_TLSPASSWORD, + C_TLSUSER, + C_TLSV1, + C_TLSV1_0, + C_TLSV1_1, + C_TLSV1_2, + C_TLSV1_3, + C_TR_ENCODING, + C_TRACE, + C_TRACE_ASCII, + C_TRACE_CONFIG, + C_TRACE_IDS, + C_TRACE_TIME, + C_UNIX_SOCKET, + C_UPLOAD_FILE, + C_URL, + C_URL_QUERY, + C_USE_ASCII, + C_USER, + C_USER_AGENT, + C_VARIABLE, + C_VERBOSE, + C_VERSION, + C_WDEBUG, + C_WRITE_OUT, + C_XATTR +} cmdline_t; + +struct LongShort { + const char *lname; /* long name option */ + enum { + ARG_NONE, /* stand-alone but not a boolean */ + ARG_BOOL, /* accepts a --no-[name] prefix */ + ARG_STRG, /* requires an argument */ + ARG_FILE /* requires an argument, usually a file name */ + } desc; + char letter; /* short name option or ' ' */ + cmdline_t cmd; +}; + +/* this array MUST be alphasorted based on the 'lname' */ +static const struct LongShort aliases[]= { + {"abstract-unix-socket", ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET}, + {"alpn", ARG_BOOL, ' ', C_ALPN}, + {"alt-svc", ARG_STRG, ' ', C_ALT_SVC}, + {"anyauth", ARG_BOOL, ' ', C_ANYAUTH}, + {"append", ARG_BOOL, 'a', C_APPEND}, + {"aws-sigv4", ARG_STRG, ' ', C_AWS_SIGV4}, + {"basic", ARG_BOOL, ' ', C_BASIC}, + {"buffer", ARG_BOOL, 'N', C_BUFFER}, + {"ca-native", ARG_BOOL, ' ', C_CA_NATIVE}, + {"cacert", ARG_FILE, ' ', C_CACERT}, + {"capath", ARG_FILE, ' ', C_CAPATH}, + {"cert", ARG_FILE, 'E', C_CERT}, + {"cert-status", ARG_BOOL, ' ', C_CERT_STATUS}, + {"cert-type", ARG_STRG, ' ', C_CERT_TYPE}, + {"ciphers", ARG_STRG, ' ', C_CIPHERS}, + {"clobber", ARG_BOOL, ' ', C_CLOBBER}, + {"compressed", ARG_BOOL, ' ', C_COMPRESSED}, + {"compressed-ssh", ARG_BOOL, ' ', C_COMPRESSED_SSH}, + {"config", ARG_FILE, 'K', C_CONFIG}, + {"connect-timeout", ARG_STRG, ' ', C_CONNECT_TIMEOUT}, + {"connect-to", ARG_STRG, ' ', C_CONNECT_TO}, + {"continue-at", ARG_STRG, 'C', C_CONTINUE_AT}, + {"cookie", ARG_STRG, 'b', C_COOKIE}, + {"cookie-jar", ARG_STRG, 'c', C_COOKIE_JAR}, + {"create-dirs", ARG_BOOL, ' ', C_CREATE_DIRS}, + {"create-file-mode", ARG_STRG, ' ', C_CREATE_FILE_MODE}, + {"crlf", ARG_BOOL, ' ', C_CRLF}, + {"crlfile", ARG_FILE, ' ', C_CRLFILE}, + {"curves", ARG_STRG, ' ', C_CURVES}, + {"data", ARG_STRG, 'd', C_DATA}, + {"data-ascii", ARG_STRG, ' ', C_DATA_ASCII}, + {"data-binary", ARG_STRG, ' ', C_DATA_BINARY}, + {"data-raw", ARG_STRG, ' ', C_DATA_RAW}, + {"data-urlencode", ARG_STRG, ' ', C_DATA_URLENCODE}, + {"delegation", ARG_STRG, ' ', C_DELEGATION}, + {"digest", ARG_BOOL, ' ', C_DIGEST}, + {"disable", ARG_BOOL, 'q', C_DISABLE}, + {"disable-eprt", ARG_BOOL, ' ', C_DISABLE_EPRT}, + {"disable-epsv", ARG_BOOL, ' ', C_DISABLE_EPSV}, + {"disallow-username-in-url", ARG_BOOL, ' ', C_DISALLOW_USERNAME_IN_URL}, + {"dns-interface", ARG_STRG, ' ', C_DNS_INTERFACE}, + {"dns-ipv4-addr", ARG_STRG, ' ', C_DNS_IPV4_ADDR}, + {"dns-ipv6-addr", ARG_STRG, ' ', C_DNS_IPV6_ADDR}, + {"dns-servers", ARG_STRG, ' ', C_DNS_SERVERS}, + {"doh-cert-status", ARG_BOOL, ' ', C_DOH_CERT_STATUS}, + {"doh-insecure", ARG_BOOL, ' ', C_DOH_INSECURE}, + {"doh-url" , ARG_STRG, ' ', C_DOH_URL}, + {"dump-header", ARG_FILE, 'D', C_DUMP_HEADER}, + {"egd-file", ARG_STRG, ' ', C_EGD_FILE}, + {"engine", ARG_STRG, ' ', C_ENGINE}, + {"eprt", ARG_BOOL, ' ', C_EPRT}, + {"epsv", ARG_BOOL, ' ', C_EPSV}, + {"etag-compare", ARG_FILE, ' ', C_ETAG_COMPARE}, + {"etag-save", ARG_FILE, ' ', C_ETAG_SAVE}, + {"expect100-timeout", ARG_STRG, ' ', C_EXPECT100_TIMEOUT}, + {"fail", ARG_BOOL, 'f', C_FAIL}, + {"fail-early", ARG_BOOL, ' ', C_FAIL_EARLY}, + {"fail-with-body", ARG_BOOL, ' ', C_FAIL_WITH_BODY}, + {"false-start", ARG_BOOL, ' ', C_FALSE_START}, + {"form", ARG_STRG, 'F', C_FORM}, + {"form-escape", ARG_BOOL, ' ', C_FORM_ESCAPE}, + {"form-string", ARG_STRG, ' ', C_FORM_STRING}, + {"ftp-account", ARG_STRG, ' ', C_FTP_ACCOUNT}, + {"ftp-alternative-to-user", ARG_STRG, ' ', C_FTP_ALTERNATIVE_TO_USER}, + {"ftp-create-dirs", ARG_BOOL, ' ', C_FTP_CREATE_DIRS}, + {"ftp-method", ARG_STRG, ' ', C_FTP_METHOD}, + {"ftp-pasv", ARG_BOOL, ' ', C_FTP_PASV}, + {"ftp-port", ARG_STRG, 'P', C_FTP_PORT}, + {"ftp-pret", ARG_BOOL, ' ', C_FTP_PRET}, + {"ftp-skip-pasv-ip", ARG_BOOL, ' ', C_FTP_SKIP_PASV_IP}, + {"ftp-ssl", ARG_BOOL, ' ', C_FTP_SSL}, + {"ftp-ssl-ccc", ARG_BOOL, ' ', C_FTP_SSL_CCC}, + {"ftp-ssl-ccc-mode", ARG_STRG, ' ', C_FTP_SSL_CCC_MODE}, + {"ftp-ssl-control", ARG_BOOL, ' ', C_FTP_SSL_CONTROL}, + {"ftp-ssl-reqd", ARG_BOOL, ' ', C_FTP_SSL_REQD}, + {"get", ARG_BOOL, 'G', C_GET}, + {"globoff", ARG_BOOL, 'g', C_GLOBOFF}, + {"happy-eyeballs-timeout-ms", ARG_STRG, ' ', C_HAPPY_EYEBALLS_TIMEOUT_MS}, + {"haproxy-clientip", ARG_STRG, ' ', C_HAPROXY_CLIENTIP}, + {"haproxy-protocol", ARG_BOOL, ' ', C_HAPROXY_PROTOCOL}, + {"head", ARG_BOOL, 'I', C_HEAD}, + {"header", ARG_STRG, 'H', C_HEADER}, + {"help", ARG_BOOL, 'h', C_HELP}, + {"hostpubmd5", ARG_STRG, ' ', C_HOSTPUBMD5}, + {"hostpubsha256", ARG_STRG, ' ', C_HOSTPUBSHA256}, + {"hsts", ARG_STRG, ' ', C_HSTS}, + {"http0.9", ARG_BOOL, ' ', C_HTTP0_9}, + {"http1.0", ARG_NONE, '0', C_HTTP1_0}, + {"http1.1", ARG_NONE, ' ', C_HTTP1_1}, + {"http2", ARG_NONE, ' ', C_HTTP2}, + {"http2-prior-knowledge", ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE}, + {"http3", ARG_NONE, ' ', C_HTTP3}, + {"http3-only", ARG_NONE, ' ', C_HTTP3_ONLY}, + {"ignore-content-length", ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH}, + {"include", ARG_BOOL, 'i', C_INCLUDE}, + {"insecure", ARG_BOOL, 'k', C_INSECURE}, + {"interface", ARG_STRG, ' ', C_INTERFACE}, + {"ipfs-gateway", ARG_STRG, ' ', C_IPFS_GATEWAY}, + {"ipv4", ARG_NONE, '4', C_IPV4}, + {"ipv6", ARG_NONE, '6', C_IPV6}, + {"json", ARG_STRG, ' ', C_JSON}, + {"junk-session-cookies", ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES}, + {"keepalive", ARG_BOOL, ' ', C_KEEPALIVE}, + {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME}, + {"key", ARG_FILE, ' ', C_KEY}, + {"key-type", ARG_STRG, ' ', C_KEY_TYPE}, + {"krb", ARG_STRG, ' ', C_KRB}, + {"krb4", ARG_STRG, ' ', C_KRB4}, + {"libcurl", ARG_STRG, ' ', C_LIBCURL}, + {"limit-rate", ARG_STRG, ' ', C_LIMIT_RATE}, + {"list-only", ARG_BOOL, 'l', C_LIST_ONLY}, + {"local-port", ARG_STRG, ' ', C_LOCAL_PORT}, + {"location", ARG_BOOL, 'L', C_LOCATION}, + {"location-trusted", ARG_BOOL, ' ', C_LOCATION_TRUSTED}, + {"login-options", ARG_STRG, ' ', C_LOGIN_OPTIONS}, + {"mail-auth", ARG_STRG, ' ', C_MAIL_AUTH}, + {"mail-from", ARG_STRG, ' ', C_MAIL_FROM}, + {"mail-rcpt", ARG_STRG, ' ', C_MAIL_RCPT}, + {"mail-rcpt-allowfails", ARG_BOOL, ' ', C_MAIL_RCPT_ALLOWFAILS}, + {"manual", ARG_BOOL, 'M', C_MANUAL}, + {"max-filesize", ARG_STRG, ' ', C_MAX_FILESIZE}, + {"max-redirs", ARG_STRG, ' ', C_MAX_REDIRS}, + {"max-time", ARG_STRG, 'm', C_MAX_TIME}, + {"metalink", ARG_BOOL, ' ', C_METALINK}, + {"negotiate", ARG_BOOL, ' ', C_NEGOTIATE}, + {"netrc", ARG_BOOL, 'n', C_NETRC}, + {"netrc-file", ARG_FILE, ' ', C_NETRC_FILE}, + {"netrc-optional", ARG_BOOL, ' ', C_NETRC_OPTIONAL}, + {"next", ARG_NONE, ':', C_NEXT}, + {"noproxy", ARG_STRG, ' ', C_NOPROXY}, + {"npn", ARG_BOOL, ' ', C_NPN}, + {"ntlm", ARG_BOOL, ' ', C_NTLM}, + {"ntlm-wb", ARG_BOOL, ' ', C_NTLM_WB}, + {"oauth2-bearer", ARG_STRG, ' ', C_OAUTH2_BEARER}, + {"output", ARG_FILE, 'o', C_OUTPUT}, + {"output-dir", ARG_STRG, ' ', C_OUTPUT_DIR}, + {"parallel", ARG_BOOL, 'Z', C_PARALLEL}, + {"parallel-immediate", ARG_BOOL, ' ', C_PARALLEL_IMMEDIATE}, + {"parallel-max", ARG_STRG, ' ', C_PARALLEL_MAX}, + {"pass", ARG_STRG, ' ', C_PASS}, + {"path-as-is", ARG_BOOL, ' ', C_PATH_AS_IS}, + {"pinnedpubkey", ARG_STRG, ' ', C_PINNEDPUBKEY}, + {"post301", ARG_BOOL, ' ', C_POST301}, + {"post302", ARG_BOOL, ' ', C_POST302}, + {"post303", ARG_BOOL, ' ', C_POST303}, + {"preproxy", ARG_STRG, ' ', C_PREPROXY}, + {"progress-bar", ARG_BOOL, '#', C_PROGRESS_BAR}, + {"progress-meter", ARG_BOOL, ' ', C_PROGRESS_METER}, + {"proto", ARG_STRG, ' ', C_PROTO}, + {"proto-default", ARG_STRG, ' ', C_PROTO_DEFAULT}, + {"proto-redir", ARG_STRG, ' ', C_PROTO_REDIR}, + {"proxy", ARG_STRG, 'x', C_PROXY}, + {"proxy-anyauth", ARG_BOOL, ' ', C_PROXY_ANYAUTH}, + {"proxy-basic", ARG_BOOL, ' ', C_PROXY_BASIC}, + {"proxy-ca-native", ARG_BOOL, ' ', C_PROXY_CA_NATIVE}, + {"proxy-cacert", ARG_FILE, ' ', C_PROXY_CACERT}, + {"proxy-capath", ARG_FILE, ' ', C_PROXY_CAPATH}, + {"proxy-cert", ARG_FILE, ' ', C_PROXY_CERT}, + {"proxy-cert-type", ARG_STRG, ' ', C_PROXY_CERT_TYPE}, + {"proxy-ciphers", ARG_STRG, ' ', C_PROXY_CIPHERS}, + {"proxy-crlfile", ARG_FILE, ' ', C_PROXY_CRLFILE}, + {"proxy-digest", ARG_BOOL, ' ', C_PROXY_DIGEST}, + {"proxy-header", ARG_STRG, ' ', C_PROXY_HEADER}, + {"proxy-http2", ARG_BOOL, ' ', C_PROXY_HTTP2}, + {"proxy-insecure", ARG_BOOL, ' ', C_PROXY_INSECURE}, + {"proxy-key", ARG_FILE, ' ', C_PROXY_KEY}, + {"proxy-key-type", ARG_STRG, ' ', C_PROXY_KEY_TYPE}, + {"proxy-negotiate", ARG_BOOL, ' ', C_PROXY_NEGOTIATE}, + {"proxy-ntlm", ARG_BOOL, ' ', C_PROXY_NTLM}, + {"proxy-pass", ARG_STRG, ' ', C_PROXY_PASS}, + {"proxy-pinnedpubkey", ARG_STRG, ' ', C_PROXY_PINNEDPUBKEY}, + {"proxy-service-name", ARG_STRG, ' ', C_PROXY_SERVICE_NAME}, + {"proxy-ssl-allow-beast", ARG_BOOL, ' ', C_PROXY_SSL_ALLOW_BEAST}, + {"proxy-ssl-auto-client-cert", ARG_BOOL, ' ', C_PROXY_SSL_AUTO_CLIENT_CERT}, + {"proxy-tls13-ciphers", ARG_STRG, ' ', C_PROXY_TLS13_CIPHERS}, + {"proxy-tlsauthtype", ARG_STRG, ' ', C_PROXY_TLSAUTHTYPE}, + {"proxy-tlspassword", ARG_STRG, ' ', C_PROXY_TLSPASSWORD}, + {"proxy-tlsuser", ARG_STRG, ' ', C_PROXY_TLSUSER}, + {"proxy-tlsv1", ARG_NONE, ' ', C_PROXY_TLSV1}, + {"proxy-user", ARG_STRG, 'U', C_PROXY_USER}, + {"proxy1.0", ARG_STRG, ' ', C_PROXY1_0}, + {"proxytunnel", ARG_BOOL, 'p', C_PROXYTUNNEL}, + {"pubkey", ARG_STRG, ' ', C_PUBKEY}, + {"quote", ARG_STRG, 'Q', C_QUOTE}, + {"random-file", ARG_FILE, ' ', C_RANDOM_FILE}, + {"range", ARG_STRG, 'r', C_RANGE}, + {"rate", ARG_STRG, ' ', C_RATE}, + {"raw", ARG_BOOL, ' ', C_RAW}, + {"referer", ARG_STRG, 'e', C_REFERER}, + {"remote-header-name", ARG_BOOL, 'J', C_REMOTE_HEADER_NAME}, + {"remote-name", ARG_BOOL, 'O', C_REMOTE_NAME}, + {"remote-name-all", ARG_BOOL, ' ', C_REMOTE_NAME_ALL}, + {"remote-time", ARG_BOOL, 'R', C_REMOTE_TIME}, + {"remove-on-error", ARG_BOOL, ' ', C_REMOVE_ON_ERROR}, + {"request", ARG_STRG, 'X', C_REQUEST}, + {"request-target", ARG_STRG, ' ', C_REQUEST_TARGET}, + {"resolve", ARG_STRG, ' ', C_RESOLVE}, + {"retry", ARG_STRG, ' ', C_RETRY}, + {"retry-all-errors", ARG_BOOL, ' ', C_RETRY_ALL_ERRORS}, + {"retry-connrefused", ARG_BOOL, ' ', C_RETRY_CONNREFUSED}, + {"retry-delay", ARG_STRG, ' ', C_RETRY_DELAY}, + {"retry-max-time", ARG_STRG, ' ', C_RETRY_MAX_TIME}, + {"sasl-authzid", ARG_STRG, ' ', C_SASL_AUTHZID}, + {"sasl-ir", ARG_BOOL, ' ', C_SASL_IR}, + {"service-name", ARG_STRG, ' ', C_SERVICE_NAME}, + {"sessionid", ARG_BOOL, ' ', C_SESSIONID}, + {"show-error", ARG_BOOL, 'S', C_SHOW_ERROR}, + {"silent", ARG_BOOL, 's', C_SILENT}, + {"socks4", ARG_STRG, ' ', C_SOCKS4}, + {"socks4a", ARG_STRG, ' ', C_SOCKS4A}, + {"socks5", ARG_STRG, ' ', C_SOCKS5}, + {"socks5-basic", ARG_BOOL, ' ', C_SOCKS5_BASIC}, + {"socks5-gssapi", ARG_BOOL, ' ', C_SOCKS5_GSSAPI}, + {"socks5-gssapi-nec", ARG_BOOL, ' ', C_SOCKS5_GSSAPI_NEC}, + {"socks5-gssapi-service", ARG_STRG, ' ', C_SOCKS5_GSSAPI_SERVICE}, + {"socks5-hostname", ARG_STRG, ' ', C_SOCKS5_HOSTNAME}, + {"speed-limit", ARG_STRG, 'Y', C_SPEED_LIMIT}, + {"speed-time", ARG_STRG, 'y', C_SPEED_TIME}, + {"ssl", ARG_BOOL, ' ', C_SSL}, + {"ssl-allow-beast", ARG_BOOL, ' ', C_SSL_ALLOW_BEAST}, + {"ssl-auto-client-cert", ARG_BOOL, ' ', C_SSL_AUTO_CLIENT_CERT}, + {"ssl-no-revoke", ARG_BOOL, ' ', C_SSL_NO_REVOKE}, + {"ssl-reqd", ARG_BOOL, ' ', C_SSL_REQD}, + {"ssl-revoke-best-effort", ARG_BOOL, ' ', C_SSL_REVOKE_BEST_EFFORT}, + {"sslv2", ARG_NONE, '2', C_SSLV2}, + {"sslv3", ARG_NONE, '3', C_SSLV3}, + {"stderr", ARG_FILE, ' ', C_STDERR}, + {"styled-output", ARG_BOOL, ' ', C_STYLED_OUTPUT}, + {"suppress-connect-headers", ARG_BOOL, ' ', C_SUPPRESS_CONNECT_HEADERS}, + {"tcp-fastopen", ARG_BOOL, ' ', C_TCP_FASTOPEN}, + {"tcp-nodelay", ARG_BOOL, ' ', C_TCP_NODELAY}, + {"telnet-option", ARG_STRG, 't', C_TELNET_OPTION}, + {"test-event", ARG_BOOL, ' ', C_TEST_EVENT}, + {"tftp-blksize", ARG_STRG, ' ', C_TFTP_BLKSIZE}, + {"tftp-no-options", ARG_BOOL, ' ', C_TFTP_NO_OPTIONS}, + {"time-cond", ARG_STRG, 'z', C_TIME_COND}, + {"tls-max", ARG_STRG, ' ', C_TLS_MAX}, + {"tls13-ciphers", ARG_STRG, ' ', C_TLS13_CIPHERS}, + {"tlsauthtype", ARG_STRG, ' ', C_TLSAUTHTYPE}, + {"tlspassword", ARG_STRG, ' ', C_TLSPASSWORD}, + {"tlsuser", ARG_STRG, ' ', C_TLSUSER}, + {"tlsv1", ARG_NONE, '1', C_TLSV1}, + {"tlsv1.0", ARG_NONE, ' ', C_TLSV1_0}, + {"tlsv1.1", ARG_NONE, ' ', C_TLSV1_1}, + {"tlsv1.2", ARG_NONE, ' ', C_TLSV1_2}, + {"tlsv1.3", ARG_NONE, ' ', C_TLSV1_3}, + {"tr-encoding", ARG_BOOL, ' ', C_TR_ENCODING}, + {"trace", ARG_FILE, ' ', C_TRACE}, + {"trace-ascii", ARG_FILE, ' ', C_TRACE_ASCII}, + {"trace-config", ARG_STRG, ' ', C_TRACE_CONFIG}, + {"trace-ids", ARG_BOOL, ' ', C_TRACE_IDS}, + {"trace-time", ARG_BOOL, ' ', C_TRACE_TIME}, + {"unix-socket", ARG_FILE, ' ', C_UNIX_SOCKET}, + {"upload-file", ARG_FILE, 'T', C_UPLOAD_FILE}, + {"url", ARG_STRG, ' ', C_URL}, + {"url-query", ARG_STRG, ' ', C_URL_QUERY}, + {"use-ascii", ARG_BOOL, 'B', C_USE_ASCII}, + {"user", ARG_STRG, 'u', C_USER}, + {"user-agent", ARG_STRG, 'A', C_USER_AGENT}, + {"variable", ARG_STRG, ' ', C_VARIABLE}, + {"verbose", ARG_BOOL, 'v', C_VERBOSE}, + {"version", ARG_BOOL, 'V', C_VERSION}, +#ifdef USE_WATT32 + {"wdebug", ARG_BOOL, ' ', C_WDEBUG}, +#endif + {"write-out", ARG_STRG, 'w', C_WRITE_OUT}, + {"xattr", ARG_BOOL, ' ', C_XATTR}, +}; + +/* Split the argument of -E to 'certname' and 'passphrase' separated by colon. + * We allow ':' and '\' to be escaped by '\' so that we can use certificate + * nicknames containing ':'. See + * for details. */ +#ifndef UNITTESTS +static +#endif +void parse_cert_parameter(const char *cert_parameter, + char **certname, + char **passphrase) +{ + size_t param_length = strlen(cert_parameter); + size_t span; + const char *param_place = NULL; + char *certname_place = NULL; + *certname = NULL; + *passphrase = NULL; + + /* most trivial assumption: cert_parameter is empty */ + if(param_length == 0) + return; + + /* next less trivial: cert_parameter starts 'pkcs11:' and thus + * looks like a RFC7512 PKCS#11 URI which can be used as-is. + * Also if cert_parameter contains no colon nor backslash, this + * means no passphrase was given and no characters escaped */ + if(curl_strnequal(cert_parameter, "pkcs11:", 7) || + !strpbrk(cert_parameter, ":\\")) { + *certname = strdup(cert_parameter); + return; + } + /* deal with escaped chars; find unescaped colon if it exists */ + certname_place = malloc(param_length + 1); + if(!certname_place) + return; + + *certname = certname_place; + param_place = cert_parameter; + while(*param_place) { + span = strcspn(param_place, ":\\"); + strncpy(certname_place, param_place, span); + param_place += span; + certname_place += span; + /* we just ate all the non-special chars. now we're on either a special + * char or the end of the string. */ + switch(*param_place) { + case '\0': + break; + case '\\': + param_place++; + switch(*param_place) { + case '\0': + *certname_place++ = '\\'; + break; + case '\\': + *certname_place++ = '\\'; + param_place++; + break; + case ':': + *certname_place++ = ':'; + param_place++; + break; + default: + *certname_place++ = '\\'; + *certname_place++ = *param_place; + param_place++; + break; + } + break; + case ':': + /* Since we live in a world of weirdness and confusion, the win32 + dudes can use : when using drive letters and thus c:\file:password + needs to work. In order not to break compatibility, we still use : as + separator, but we try to detect when it is used for a file name! On + windows. */ +#ifdef _WIN32 + if((param_place == &cert_parameter[1]) && + (cert_parameter[2] == '\\' || cert_parameter[2] == '/') && + (ISALPHA(cert_parameter[0])) ) { + /* colon in the second column, followed by a backslash, and the + first character is an alphabetic letter: + + this is a drive letter colon */ + *certname_place++ = ':'; + param_place++; + break; + } +#endif + /* escaped colons and Windows drive letter colons were handled + * above; if we're still here, this is a separating colon */ + param_place++; + if(*param_place) { + *passphrase = strdup(param_place); + } + goto done; + } + } +done: + *certname_place = '\0'; +} + +/* Replace (in-place) '%20' by '+' according to RFC1866 */ +static size_t replace_url_encoded_space_by_plus(char *url) +{ + size_t orig_len = strlen(url); + size_t orig_index = 0; + size_t new_index = 0; + + while(orig_index < orig_len) { + if((url[orig_index] == '%') && + (url[orig_index + 1] == '2') && + (url[orig_index + 2] == '0')) { + url[new_index] = '+'; + orig_index += 3; + } + else{ + if(new_index != orig_index) { + url[new_index] = url[orig_index]; + } + orig_index++; + } + new_index++; + } + + url[new_index] = 0; /* terminate string */ + + return new_index; /* new size */ +} + +static void +GetFileAndPassword(char *nextarg, char **file, char **password) +{ + char *certname, *passphrase; + if(nextarg) { + parse_cert_parameter(nextarg, &certname, &passphrase); + Curl_safefree(*file); + *file = certname; + if(passphrase) { + Curl_safefree(*password); + *password = passphrase; + } + } +} + +/* Get a size parameter for '--limit-rate' or '--max-filesize'. + * We support a 'G', 'M' or 'K' suffix too. + */ +static ParameterError GetSizeParameter(struct GlobalConfig *global, + const char *arg, + const char *which, + curl_off_t *value_out) +{ + char *unit; + curl_off_t value; + + if(curlx_strtoofft(arg, &unit, 10, &value)) { + warnf(global, "invalid number specified for %s", which); + return PARAM_BAD_USE; + } + + if(!*unit) + unit = (char *)"b"; + else if(strlen(unit) > 1) + unit = (char *)"w"; /* unsupported */ + + switch(*unit) { + case 'G': + case 'g': + if(value > (CURL_OFF_T_MAX / (1024*1024*1024))) + return PARAM_NUMBER_TOO_LARGE; + value *= 1024*1024*1024; + break; + case 'M': + case 'm': + if(value > (CURL_OFF_T_MAX / (1024*1024))) + return PARAM_NUMBER_TOO_LARGE; + value *= 1024*1024; + break; + case 'K': + case 'k': + if(value > (CURL_OFF_T_MAX / 1024)) + return PARAM_NUMBER_TOO_LARGE; + value *= 1024; + break; + case 'b': + case 'B': + /* for plain bytes, leave as-is */ + break; + default: + warnf(global, "unsupported %s unit. Use G, M, K or B", which); + return PARAM_BAD_USE; + } + *value_out = value; + return PARAM_OK; +} + +#ifdef HAVE_WRITABLE_ARGV +static void cleanarg(argv_item_t str) +{ + /* now that getstr has copied the contents of nextarg, wipe the next + * argument out so that the username:password isn't displayed in the + * system process list */ + if(str) { + size_t len = strlen(str); + memset(str, ' ', len); + } +} +#else +#define cleanarg(x) +#endif + +/* --data-urlencode */ +static ParameterError data_urlencode(struct GlobalConfig *global, + char *nextarg, + char **postp, + size_t *lenp) +{ + /* [name]=[content], we encode the content part only + * [name]@[file name] + * + * Case 2: we first load the file using that name and then encode + * the content. + */ + ParameterError err; + const char *p = strchr(nextarg, '='); + size_t nlen; + char is_file; + char *postdata = NULL; + size_t size = 0; + if(!p) + /* there was no '=' letter, check for a '@' instead */ + p = strchr(nextarg, '@'); + if(p) { + nlen = p - nextarg; /* length of the name part */ + is_file = *p++; /* pass the separator */ + } + else { + /* neither @ nor =, so no name and it isn't a file */ + nlen = is_file = 0; + p = nextarg; + } + if('@' == is_file) { + FILE *file; + /* a '@' letter, it means that a file name or - (stdin) follows */ + if(!strcmp("-", p)) { + file = stdin; + set_binmode(stdin); + } + else { + file = fopen(p, "rb"); + if(!file) { + errorf(global, "Failed to open %s", p); + return PARAM_READ_ERROR; + } + } + + err = file2memory(&postdata, &size, file); + + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + } + else { + err = getstr(&postdata, p, ALLOW_BLANK); + if(err) + goto error; + if(postdata) + size = strlen(postdata); + } + + if(!postdata) { + /* no data from the file, point to a zero byte string to make this + get sent as a POST anyway */ + postdata = strdup(""); + if(!postdata) + return PARAM_NO_MEM; + size = 0; + } + else { + char *enc = curl_easy_escape(NULL, postdata, (int)size); + Curl_safefree(postdata); /* no matter if it worked or not */ + if(enc) { + char *n; + replace_url_encoded_space_by_plus(enc); + if(nlen > 0) { /* only append '=' if we have a name */ + n = aprintf("%.*s=%s", (int)nlen, nextarg, enc); + curl_free(enc); + if(!n) + return PARAM_NO_MEM; + } + else + n = enc; + + size = strlen(n); + postdata = n; + } + else + return PARAM_NO_MEM; + } + *postp = postdata; + *lenp = size; + return PARAM_OK; +error: + return err; +} + +static void sethttpver(struct GlobalConfig *global, + struct OperationConfig *config, + long httpversion) +{ + if(config->httpversion && + (config->httpversion != httpversion)) + warnf(global, "Overrides previous HTTP version option"); + + config->httpversion = httpversion; +} + +static CURLcode set_trace_config(struct GlobalConfig *global, + const char *config) +{ + CURLcode result = CURLE_OK; + char *token, *tmp, *name; + bool toggle; + + tmp = strdup(config); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + /* Allow strtok() here since this isn't used threaded */ + /* !checksrc! disable BANNEDFUNC 2 */ + token = strtok(tmp, ", "); + while(token) { + switch(*token) { + case '-': + toggle = FALSE; + name = token + 1; + break; + case '+': + toggle = TRUE; + name = token + 1; + break; + default: + toggle = TRUE; + name = token; + break; + } + + if(strcasecompare(name, "all")) { + global->traceids = toggle; + global->tracetime = toggle; + result = curl_global_trace(token); + if(result) + goto out; + } + else if(strcasecompare(name, "ids")) { + global->traceids = toggle; + } + else if(strcasecompare(name, "time")) { + global->tracetime = toggle; + } + else { + result = curl_global_trace(token); + if(result) + goto out; + } + token = strtok(NULL, ", "); + } +out: + free(tmp); + return result; +} + +static int findarg(const void *a, const void *b) +{ + const struct LongShort *aa = a; + const struct LongShort *bb = b; + return strcmp(aa->lname, bb->lname); +} + +static const struct LongShort *single(char letter) +{ + static const struct LongShort *singles[128 - ' ']; /* ASCII => pointer */ + static bool singles_done = FALSE; + DEBUGASSERT((letter < 127) && (letter > ' ')); + + if(!singles_done) { + unsigned int j; + for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { + if(aliases[j].letter != ' ') { + unsigned char l = aliases[j].letter; + singles[l - ' '] = &aliases[j]; + } + } + singles_done = TRUE; + } + return singles[letter - ' ']; +} + +#define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */ +static ParameterError url_query(char *nextarg, + struct GlobalConfig *global, + struct OperationConfig *config) +{ + size_t size = 0; + ParameterError err = PARAM_OK; + char *query; + struct curlx_dynbuf dyn; + curlx_dyn_init(&dyn, MAX_QUERY_LEN); + + if(*nextarg == '+') { + /* use without encoding */ + query = strdup(&nextarg[1]); + if(!query) + err = PARAM_NO_MEM; + } + else + err = data_urlencode(global, nextarg, &query, &size); + + if(!err) { + if(config->query) { + CURLcode result = curlx_dyn_addf(&dyn, "%s&%s", config->query, query); + free(query); + if(result) + err = PARAM_NO_MEM; + else { + free(config->query); + config->query = curlx_dyn_ptr(&dyn); + } + } + else + config->query = query; + } + return err; +} + +static ParameterError set_data(cmdline_t cmd, + char *nextarg, + struct GlobalConfig *global, + struct OperationConfig *config) +{ + char *postdata = NULL; + FILE *file; + size_t size = 0; + ParameterError err = PARAM_OK; + + if(cmd == C_DATA_URLENCODE) { /* --data-urlencode */ + err = data_urlencode(global, nextarg, &postdata, &size); + if(err) + return err; + } + else if('@' == *nextarg && (cmd != C_DATA_RAW)) { + /* the data begins with a '@' letter, it means that a file name + or - (stdin) follows */ + nextarg++; /* pass the @ */ + + if(!strcmp("-", nextarg)) { + file = stdin; + if(cmd == C_DATA_BINARY) /* forced data-binary */ + set_binmode(stdin); + } + else { + file = fopen(nextarg, "rb"); + if(!file) { + errorf(global, "Failed to open %s", nextarg); + return PARAM_READ_ERROR; + } + } + + if((cmd == C_DATA_BINARY) || /* --data-binary */ + (cmd == C_JSON) /* --json */) + /* forced binary */ + err = file2memory(&postdata, &size, file); + else { + err = file2string(&postdata, file); + if(postdata) + size = strlen(postdata); + } + + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + + if(!postdata) { + /* no data from the file, point to a zero byte string to make this + get sent as a POST anyway */ + postdata = strdup(""); + if(!postdata) + return PARAM_NO_MEM; + } + } + else { + err = getstr(&postdata, nextarg, ALLOW_BLANK); + if(err) + return err; + if(postdata) + size = strlen(postdata); + } + if(cmd == C_JSON) + config->jsoned = TRUE; + + if(curlx_dyn_len(&config->postdata)) { + /* skip separator append for --json */ + if(!err && (cmd != C_JSON) && + curlx_dyn_addn(&config->postdata, "&", 1)) + err = PARAM_NO_MEM; + } + + if(!err && curlx_dyn_addn(&config->postdata, postdata, size)) + err = PARAM_NO_MEM; + + Curl_safefree(postdata); + + config->postfields = curlx_dyn_ptr(&config->postdata); + return err; +} + +static ParameterError set_rate(struct GlobalConfig *global, + char *nextarg) +{ + /* --rate */ + /* support a few different suffixes, extract the suffix first, then + get the number and convert to per hour. + /s == per second + /m == per minute + /h == per hour (default) + /d == per day (24 hours) + */ + ParameterError err = PARAM_OK; + char *div = strchr(nextarg, '/'); + char number[26]; + long denominator; + long numerator = 60*60*1000; /* default per hour */ + size_t numlen = div ? (size_t)(div - nextarg) : strlen(nextarg); + if(numlen > sizeof(number) -1) + return PARAM_NUMBER_TOO_LARGE; + + strncpy(number, nextarg, numlen); + number[numlen] = 0; + err = str2unum(&denominator, number); + if(err) + return err; + + if(denominator < 1) + return PARAM_BAD_USE; + + if(div) { + char unit = div[1]; + switch(unit) { + case 's': /* per second */ + numerator = 1000; + break; + case 'm': /* per minute */ + numerator = 60*1000; + break; + case 'h': /* per hour */ + break; + case 'd': /* per day */ + numerator = 24*60*60*1000; + break; + default: + errorf(global, "unsupported --rate unit"); + err = PARAM_BAD_USE; + break; + } + } + + if(err) + ; + else if(denominator > numerator) + err = PARAM_NUMBER_TOO_LARGE; + else + global->ms_per_transfer = numerator/denominator; + + return err; +} + + +ParameterError getparameter(const char *flag, /* f or -long-flag */ + char *nextarg, /* NULL if unset */ + argv_item_t cleararg, + bool *usedarg, /* set to TRUE if the arg + has been used */ + struct GlobalConfig *global, + struct OperationConfig *config) +{ + int rc; + const char *parse = NULL; + time_t now; + bool longopt = FALSE; + bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ + ParameterError err = PARAM_OK; + bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled + by using --OPTION or --no-OPTION */ + bool nextalloc = FALSE; /* if nextarg is allocated */ + struct getout *url; + static const char *redir_protos[] = { + "http", + "https", + "ftp", + "ftps", + NULL + }; + const struct LongShort *a = NULL; + curl_off_t value; +#ifdef HAVE_WRITABLE_ARGV + argv_item_t clearthis = NULL; +#else + (void)cleararg; +#endif + + *usedarg = FALSE; /* default is that we don't use the arg */ + + if(('-' != flag[0]) || ('-' == flag[1])) { + /* this should be a long name */ + const char *word = ('-' == flag[0]) ? flag + 2 : flag; + bool noflagged = FALSE; + bool expand = FALSE; + struct LongShort key; + + if(!strncmp(word, "no-", 3)) { + /* disable this option but ignore the "no-" part when looking for it */ + word += 3; + toggle = FALSE; + noflagged = TRUE; + } + else if(!strncmp(word, "expand-", 7)) { + /* variable expansions is to be done on the argument */ + word += 7; + expand = TRUE; + } + key.lname = word; + + a = bsearch(&key, aliases, sizeof(aliases)/sizeof(aliases[0]), + sizeof(aliases[0]), findarg); + if(a) { + longopt = TRUE; + } + else { + err = PARAM_OPTION_UNKNOWN; + goto error; + } + if(noflagged && (a->desc != ARG_BOOL)) { + /* --no- prefixed an option that isn't boolean! */ + err = PARAM_NO_NOT_BOOLEAN; + goto error; + } + else if(expand && nextarg) { + struct curlx_dynbuf nbuf; + bool replaced; + + if((a->desc != ARG_STRG) && + (a->desc != ARG_FILE)) { + /* --expand on an option that isn't a string or a filename */ + err = PARAM_EXPAND_ERROR; + goto error; + } + err = varexpand(global, nextarg, &nbuf, &replaced); + if(err) { + curlx_dyn_free(&nbuf); + goto error; + } + if(replaced) { + nextarg = curlx_dyn_ptr(&nbuf); + nextalloc = TRUE; + } + } + } + else { + flag++; /* prefixed with one dash, pass it */ + parse = flag; + } + + do { + /* we can loop here if we have multiple single-letters */ + char letter; + cmdline_t cmd; + + if(!longopt && !a) { + a = single(*parse); + if(!a) { + err = PARAM_OPTION_UNKNOWN; + break; + } + } + letter = a->letter; + cmd = a->cmd; + if(a->desc >= ARG_STRG) { + /* this option requires an extra parameter */ + if(!longopt && parse[1]) { + nextarg = (char *)&parse[1]; /* this is the actual extra parameter */ + singleopt = TRUE; /* don't loop anymore after this */ + } + else if(!nextarg) { + err = PARAM_REQUIRES_PARAMETER; + break; + } + else { +#ifdef HAVE_WRITABLE_ARGV + clearthis = cleararg; +#endif + *usedarg = TRUE; /* mark it as used */ + } + + if((a->desc == ARG_FILE) && + (nextarg[0] == '-') && nextarg[1]) { + /* if the file name looks like a command line option */ + warnf(global, "The file name argument '%s' looks like a flag.", + nextarg); + } + } + else if((a->desc == ARG_NONE) && !toggle) { + err = PARAM_NO_PREFIX; + break; + } + + if(!nextarg) + /* this is a precaution mostly to please scan-build, as all arguments + that use nextarg should be marked as such and they will check that + nextarg is set before continuing, but code analyzers are not always + that aware of that state */ + nextarg = (char *)""; + + switch(cmd) { + case C_DNS_IPV4_ADDR: /* --dns-ipv4-addr */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + /* addr in dot notation */ + err = getstr(&config->dns_ipv4_addr, nextarg, DENY_BLANK); + break; + case C_DNS_IPV6_ADDR: /* --dns-ipv6-addr */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + /* addr in dot notation */ + err = getstr(&config->dns_ipv6_addr, nextarg, DENY_BLANK); + break; + case C_RANDOM_FILE: /* --random-file */ + break; + case C_EGD_FILE: /* --egd-file */ + break; + case C_OAUTH2_BEARER: /* --oauth2-bearer */ + err = getstr(&config->oauth_bearer, nextarg, DENY_BLANK); + if(!err) { + cleanarg(clearthis); + config->authtype |= CURLAUTH_BEARER; + } + break; + case C_CONNECT_TIMEOUT: /* --connect-timeout */ + err = secs2ms(&config->connecttimeout_ms, nextarg); + break; + case C_DOH_URL: /* --doh-url */ + err = getstr(&config->doh_url, nextarg, ALLOW_BLANK); + if(!err && config->doh_url && !config->doh_url[0]) + /* if given a blank string, make it NULL again */ + Curl_safefree(config->doh_url); + break; + case C_CIPHERS: /* -- ciphers */ + err = getstr(&config->cipher_list, nextarg, DENY_BLANK); + break; + case C_DNS_INTERFACE: /* --dns-interface */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + /* interface name */ + err = getstr(&config->dns_interface, nextarg, DENY_BLANK); + break; + case C_DISABLE_EPSV: /* --disable-epsv */ + config->disable_epsv = toggle; + break; + case C_DISALLOW_USERNAME_IN_URL: /* --disallow-username-in-url */ + config->disallow_username_in_url = toggle; + break; + case C_EPSV: /* --epsv */ + config->disable_epsv = (!toggle)?TRUE:FALSE; + break; + case C_DNS_SERVERS: /* --dns-servers */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + /* IP addrs of DNS servers */ + err = getstr(&config->dns_servers, nextarg, DENY_BLANK); + break; + case C_TRACE: /* --trace */ + err = getstr(&global->trace_dump, nextarg, DENY_BLANK); + if(!err) { + if(global->tracetype && (global->tracetype != TRACE_BIN)) + warnf(global, "--trace overrides an earlier trace/verbose option"); + global->tracetype = TRACE_BIN; + } + break; + case C_NPN: /* --npn */ + warnf(global, "--npn is no longer supported"); + break; + case C_TRACE_ASCII: /* --trace-ascii */ + err = getstr(&global->trace_dump, nextarg, DENY_BLANK); + if(!err) { + if(global->tracetype && (global->tracetype != TRACE_ASCII)) + warnf(global, + "--trace-ascii overrides an earlier trace/verbose option"); + global->tracetype = TRACE_ASCII; + } + break; + case C_ALPN: /* --alpn */ + config->noalpn = (!toggle)?TRUE:FALSE; + break; + case C_LIMIT_RATE: /* --limit-rate */ + err = GetSizeParameter(global, nextarg, "rate", &value); + if(!err) { + config->recvpersecond = value; + config->sendpersecond = value; + } + break; + case C_RATE: + err = set_rate(global, nextarg); + break; + case C_COMPRESSED: /* --compressed */ + if(toggle && !(feature_libz || feature_brotli || feature_zstd)) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + config->encoding = toggle; + break; + case C_TR_ENCODING: /* --tr-encoding */ + config->tr_encoding = toggle; + break; + case C_DIGEST: /* --digest */ + if(toggle) + config->authtype |= CURLAUTH_DIGEST; + else + config->authtype &= ~CURLAUTH_DIGEST; + break; + case C_NEGOTIATE: /* --negotiate */ + if(!toggle) + config->authtype &= ~CURLAUTH_NEGOTIATE; + else if(feature_spnego) + config->authtype |= CURLAUTH_NEGOTIATE; + else + err = PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case C_NTLM: /* --ntlm */ + if(!toggle) + config->authtype &= ~CURLAUTH_NTLM; + else if(feature_ntlm) + config->authtype |= CURLAUTH_NTLM; + else + err = PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case C_NTLM_WB: /* --ntlm-wb */ + if(!toggle) + config->authtype &= ~CURLAUTH_NTLM_WB; + else if(feature_ntlm_wb) + config->authtype |= CURLAUTH_NTLM_WB; + else + err = PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case C_BASIC: /* --basic */ + if(toggle) + config->authtype |= CURLAUTH_BASIC; + else + config->authtype &= ~CURLAUTH_BASIC; + break; + case C_ANYAUTH: /* --anyauth */ + if(toggle) + config->authtype = CURLAUTH_ANY; + /* --no-anyauth simply doesn't touch it */ + break; +#ifdef USE_WATT32 + case C_WDEBUG: /* --wdebug */ + dbug_init(); + break; +#endif + case C_FTP_CREATE_DIRS: /* --ftp-create-dirs */ + config->ftp_create_dirs = toggle; + break; + case C_CREATE_DIRS: /* --create-dirs */ + config->create_dirs = toggle; + break; + case C_CREATE_FILE_MODE: /* --create-file-mode */ + err = oct2nummax(&config->create_file_mode, nextarg, 0777); + break; + case C_MAX_REDIRS: /* --max-redirs */ + /* specified max no of redirects (http(s)), this accepts -1 as a + special condition */ + err = str2num(&config->maxredirs, nextarg); + if(!err && (config->maxredirs < -1)) + err = PARAM_BAD_NUMERIC; + break; + case C_IPFS_GATEWAY: /* --ipfs-gateway */ + err = getstr(&config->ipfs_gateway, nextarg, DENY_BLANK); + break; + case C_PROXY_NTLM: /* --proxy-ntlm */ + if(!feature_ntlm) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + config->proxyntlm = toggle; + break; + case C_CRLF: /* --crlf */ + /* LF -> CRLF conversion? */ + config->crlf = toggle; + break; + case C_AWS_SIGV4: /* --aws-sigv4 */ + config->authtype |= CURLAUTH_AWS_SIGV4; + err = getstr(&config->aws_sigv4, nextarg, DENY_BLANK); + break; + case C_STDERR: /* --stderr */ + tool_set_stderr_file(global, nextarg); + break; + case C_INTERFACE: /* --interface */ + /* interface */ + err = getstr(&config->iface, nextarg, DENY_BLANK); + break; + case C_KRB: /* --krb */ + /* kerberos level string */ + if(!feature_spnego) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + err = getstr(&config->krblevel, nextarg, DENY_BLANK); + break; + case C_HAPROXY_PROTOCOL: /* --haproxy-protocol */ + config->haproxy_protocol = toggle; + break; + case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */ + err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK); + break; + case C_MAX_FILESIZE: /* --max-filesize */ + err = GetSizeParameter(global, nextarg, "max-filesize", &value); + if(!err) + config->max_filesize = value; + break; + case C_DISABLE_EPRT: /* --disable-eprt */ + config->disable_eprt = toggle; + break; + case C_EPRT: /* --eprt */ + config->disable_eprt = (!toggle)?TRUE:FALSE; + break; + case C_XATTR: /* --xattr */ + config->xattr = toggle; + break; + case C_URL: /* --url */ + if(!config->url_get) + config->url_get = config->url_list; + + if(config->url_get) { + /* there's a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_get && (config->url_get->flags & GETOUT_URL)) + config->url_get = config->url_get->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_get) + /* existing node */ + url = config->url_get; + else + /* there was no free node, create one! */ + config->url_get = url = new_getout(config); + + if(!url) + err = PARAM_NO_MEM; + else { + /* fill in the URL */ + err = getstr(&url->url, nextarg, DENY_BLANK); + url->flags |= GETOUT_URL; + } + break; + case C_SSL: /* --ssl */ + if(toggle && !feature_ssl) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else { + config->ftp_ssl = toggle; + if(config->ftp_ssl) + warnf(global, + "--ssl is an insecure option, consider --ssl-reqd instead"); + } + break; + case C_FTP_PASV: /* --ftp-pasv */ + Curl_safefree(config->ftpport); + break; + case C_SOCKS5: /* --socks5 */ + /* socks5 proxy to use, and resolves the name locally and passes on the + resolved address */ + err = getstr(&config->proxy, nextarg, DENY_BLANK); + config->proxyver = CURLPROXY_SOCKS5; + break; + case C_SOCKS4: /* --socks4 */ + err = getstr(&config->proxy, nextarg, DENY_BLANK); + config->proxyver = CURLPROXY_SOCKS4; + break; + case C_SOCKS4A: /* --socks4a */ + err = getstr(&config->proxy, nextarg, DENY_BLANK); + config->proxyver = CURLPROXY_SOCKS4A; + break; + case C_SOCKS5_HOSTNAME: /* --socks5-hostname */ + err = getstr(&config->proxy, nextarg, DENY_BLANK); + config->proxyver = CURLPROXY_SOCKS5_HOSTNAME; + break; + case C_TCP_NODELAY: /* --tcp-nodelay */ + config->tcp_nodelay = toggle; + break; + case C_PROXY_DIGEST: /* --proxy-digest */ + config->proxydigest = toggle; + break; + case C_PROXY_BASIC: /* --proxy-basic */ + config->proxybasic = toggle; + break; + case C_RETRY: /* --retry */ + err = str2unum(&config->req_retry, nextarg); + break; + case C_RETRY_CONNREFUSED: /* --retry-connrefused */ + config->retry_connrefused = toggle; + break; + case C_RETRY_DELAY: /* --retry-delay */ + err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000); + break; + case C_RETRY_MAX_TIME: /* --retry-max-time */ + err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000); + break; + case C_RETRY_ALL_ERRORS: /* --retry-all-errors */ + config->retry_all_errors = toggle; + break; + case C_PROXY_NEGOTIATE: /* --proxy-negotiate */ + if(!feature_spnego) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + config->proxynegotiate = toggle; + break; + case C_FORM_ESCAPE: /* --form-escape */ + config->mime_options &= ~CURLMIMEOPT_FORMESCAPE; + if(toggle) + config->mime_options |= CURLMIMEOPT_FORMESCAPE; + break; + case C_FTP_ACCOUNT: /* --ftp-account */ + err = getstr(&config->ftp_account, nextarg, DENY_BLANK); + break; + case C_PROXY_ANYAUTH: /* --proxy-anyauth */ + config->proxyanyauth = toggle; + break; + case C_TRACE_TIME: /* --trace-time */ + global->tracetime = toggle; + break; + case C_IGNORE_CONTENT_LENGTH: /* --ignore-content-length */ + config->ignorecl = toggle; + break; + case C_FTP_SKIP_PASV_IP: /* --ftp-skip-pasv-ip */ + config->ftp_skip_ip = toggle; + break; + case C_FTP_METHOD: /* --ftp-method */ + config->ftp_filemethod = ftpfilemethod(config, nextarg); + break; + case C_LOCAL_PORT: { /* --local-port */ + /* 16bit base 10 is 5 digits, but we allow 6 so that this catches + overflows, not just truncates */ + char lrange[7]=""; + char *p = nextarg; + while(ISDIGIT(*p)) + p++; + if(*p) { + /* if there's anything more than a plain decimal number */ + rc = sscanf(p, " - %6s", lrange); + *p = 0; /* null-terminate to make str2unum() work below */ + } + else + rc = 0; + + err = str2unum(&config->localport, nextarg); + if(err || (config->localport > 65535)) { + err = PARAM_BAD_USE; + break; + } + if(!rc) + config->localportrange = 1; /* default number of ports to try */ + else { + err = str2unum(&config->localportrange, lrange); + if(err || (config->localportrange > 65535)) + err = PARAM_BAD_USE; + else { + config->localportrange -= (config->localport-1); + if(config->localportrange < 1) + err = PARAM_BAD_USE; + } + } + break; + } + case C_FTP_ALTERNATIVE_TO_USER: /* --ftp-alternative-to-user */ + err = getstr(&config->ftp_alternative_to_user, nextarg, DENY_BLANK); + break; + case C_FTP_SSL_REQD: /* --ftp-ssl-reqd */ + case C_SSL_REQD: /* --ssl-reqd */ + if(toggle && !feature_ssl) { + err = PARAM_LIBCURL_DOESNT_SUPPORT; + break; + } + config->ftp_ssl_reqd = toggle; + break; + case C_SESSIONID: /* --sessionid */ + config->disable_sessionid = (!toggle)?TRUE:FALSE; + break; + case C_FTP_SSL_CONTROL: /* --ftp-ssl-control */ + if(toggle && !feature_ssl) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + config->ftp_ssl_control = toggle; + break; + case C_FTP_SSL_CCC: /* --ftp-ssl-ccc */ + config->ftp_ssl_ccc = toggle; + if(!config->ftp_ssl_ccc_mode) + config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; + break; + case C_FTP_SSL_CCC_MODE: /* --ftp-ssl-ccc-mode */ + config->ftp_ssl_ccc = TRUE; + config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); + break; + case C_LIBCURL: /* --libcurl */ +#ifdef CURL_DISABLE_LIBCURL_OPTION + warnf(global, + "--libcurl option was disabled at build-time"); + err = PARAM_OPTION_UNKNOWN; +#else + err = getstr(&global->libcurl, nextarg, DENY_BLANK); +#endif + break; + case C_RAW: /* --raw */ + config->raw = toggle; + break; + case C_KEEPALIVE: /* --keepalive */ + config->nokeepalive = (!toggle)?TRUE:FALSE; + break; + case C_KEEPALIVE_TIME: /* --keepalive-time */ + err = str2unum(&config->alivetime, nextarg); + break; + case C_POST301: /* --post301 */ + config->post301 = toggle; + break; + case C_POST302: /* --post302 */ + config->post302 = toggle; + break; + case C_POST303: /* --post303 */ + config->post303 = toggle; + break; + case C_NOPROXY: /* --noproxy */ + /* This specifies the noproxy list */ + err = getstr(&config->noproxy, nextarg, ALLOW_BLANK); + break; + case C_SOCKS5_GSSAPI_NEC: /* --socks5-gssapi-nec */ + config->socks5_gssapi_nec = toggle; + break; + case C_PROXY1_0: /* --proxy1.0 */ + /* http 1.0 proxy */ + err = getstr(&config->proxy, nextarg, DENY_BLANK); + config->proxyver = CURLPROXY_HTTP_1_0; + break; + case C_TFTP_BLKSIZE: /* --tftp-blksize */ + err = str2unum(&config->tftp_blksize, nextarg); + break; + case C_MAIL_FROM: /* --mail-from */ + err = getstr(&config->mail_from, nextarg, DENY_BLANK); + break; + case C_MAIL_RCPT: /* --mail-rcpt */ + /* append receiver to a list */ + err = add2list(&config->mail_rcpt, nextarg); + break; + case C_FTP_PRET: /* --ftp-pret */ + config->ftp_pret = toggle; + break; + case C_PROTO: /* --proto */ + config->proto_present = TRUE; + err = proto2num(config, built_in_protos, &config->proto_str, nextarg); + break; + case C_PROTO_REDIR: /* --proto-redir */ + config->proto_redir_present = TRUE; + if(proto2num(config, redir_protos, &config->proto_redir_str, + nextarg)) + err = PARAM_BAD_USE; + break; + case C_RESOLVE: /* --resolve */ + err = add2list(&config->resolve, nextarg); + break; + case C_DELEGATION: /* --delegation */ + config->gssapi_delegation = delegation(config, nextarg); + break; + case C_MAIL_AUTH: /* --mail-auth */ + err = getstr(&config->mail_auth, nextarg, DENY_BLANK); + break; + case C_METALINK: /* --metalink */ + errorf(global, "--metalink is disabled"); + err = PARAM_BAD_USE; + break; + case C_SASL_AUTHZID: /* --sasl-authzid */ + err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK); + break; + case C_SASL_IR: /* --sasl-ir */ + config->sasl_ir = toggle; + break; + case C_TEST_EVENT: /* --test-event */ +#ifdef CURLDEBUG + global->test_event_based = toggle; +#else + warnf(global, "--test-event is ignored unless a debug build"); +#endif + break; + case C_UNIX_SOCKET: /* --unix-socket */ + config->abstract_unix_socket = FALSE; + err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); + break; + case C_PATH_AS_IS: /* --path-as-is */ + config->path_as_is = toggle; + break; + case C_PROXY_SERVICE_NAME: /* --proxy-service-name */ + err = getstr(&config->proxy_service_name, nextarg, DENY_BLANK); + break; + case C_SERVICE_NAME: /* --service-name */ + err = getstr(&config->service_name, nextarg, DENY_BLANK); + break; + case C_PROTO_DEFAULT: /* --proto-default */ + err = getstr(&config->proto_default, nextarg, DENY_BLANK); + if(!err) + err = check_protocol(config->proto_default); + break; + case C_EXPECT100_TIMEOUT: /* --expect100-timeout */ + err = secs2ms(&config->expect100timeout_ms, nextarg); + break; + case C_TFTP_NO_OPTIONS: /* --tftp-no-options */ + config->tftp_no_options = toggle; + break; + case C_CONNECT_TO: /* --connect-to */ + err = add2list(&config->connect_to, nextarg); + break; + case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */ + config->abstract_unix_socket = TRUE; + err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); + break; + case C_TLS_MAX: /* --tls-max */ + err = str2tls_max(&config->ssl_version_max, nextarg); + break; + case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */ + config->suppress_connect_headers = toggle; + break; + case C_COMPRESSED_SSH: /* --compressed-ssh */ + config->ssh_compression = toggle; + break; + case C_HAPPY_EYEBALLS_TIMEOUT_MS: /* --happy-eyeballs-timeout-ms */ + err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg); + /* 0 is a valid value for this timeout */ + break; + case C_TRACE_IDS: /* --trace-ids */ + global->traceids = toggle; + break; + case C_TRACE_CONFIG: /* --trace-config */ + if(set_trace_config(global, nextarg)) + err = PARAM_NO_MEM; + break; + case C_PROGRESS_METER: /* --progress-meter */ + global->noprogress = !toggle; + break; + case C_PROGRESS_BAR: /* --progress-bar */ + global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS; + break; + case C_VARIABLE: /* --Variable */ + err = setvariable(global, nextarg); + break; + case C_NEXT: /* --next */ + err = PARAM_NEXT_OPERATION; + break; + case C_HTTP1_0: /* --http1.0 */ + /* HTTP version 1.0 */ + sethttpver(global, config, CURL_HTTP_VERSION_1_0); + break; + case C_HTTP1_1: /* --http1.1 */ + /* HTTP version 1.1 */ + sethttpver(global, config, CURL_HTTP_VERSION_1_1); + break; + case C_HTTP2: /* --http2 */ + /* HTTP version 2.0 */ + if(!feature_http2) + return PARAM_LIBCURL_DOESNT_SUPPORT; + sethttpver(global, config, CURL_HTTP_VERSION_2_0); + break; + case C_HTTP2_PRIOR_KNOWLEDGE: /* --http2-prior-knowledge */ + /* HTTP version 2.0 over clean TCP */ + if(!feature_http2) + return PARAM_LIBCURL_DOESNT_SUPPORT; + sethttpver(global, config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); + break; + case C_HTTP3: /* --http3: */ + /* Try HTTP/3, allow fallback */ + if(!feature_http3) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + sethttpver(global, config, CURL_HTTP_VERSION_3); + break; + case C_HTTP3_ONLY: /* --http3-only */ + /* Try HTTP/3 without fallback */ + if(!feature_http3) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + sethttpver(global, config, CURL_HTTP_VERSION_3ONLY); + break; + case C_HTTP0_9: /* --http0.9 */ + /* Allow HTTP/0.9 responses! */ + config->http09_allowed = toggle; + break; + case C_PROXY_HTTP2: /* --proxy-http2 */ + if(!feature_httpsproxy || !feature_http2) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + config->proxyver = CURLPROXY_HTTPS2; + break; + case C_TLSV1: /* --tlsv1 */ + config->ssl_version = CURL_SSLVERSION_TLSv1; + break; + case C_TLSV1_0: /* --tlsv1.0 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_0; + break; + case C_TLSV1_1: /* --tlsv1.1 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_1; + break; + case C_TLSV1_2: /* --tlsv1.2 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_2; + break; + case C_TLSV1_3: /* --tlsv1.3 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_3; + break; + case C_TLS13_CIPHERS: /* --tls13-ciphers */ + err = getstr(&config->cipher13_list, nextarg, DENY_BLANK); + break; + case C_PROXY_TLS13_CIPHERS: /* --proxy-tls13-ciphers */ + err = getstr(&config->proxy_cipher13_list, nextarg, DENY_BLANK); + break; + case C_SSLV2: /* --sslv2 */ + warnf(global, "Ignores instruction to use SSLv2"); + break; + case C_SSLV3: /* --sslv3 */ + warnf(global, "Ignores instruction to use SSLv3"); + break; + case C_IPV4: /* --ipv4 */ + config->ip_version = CURL_IPRESOLVE_V4; + break; + case C_IPV6: /* --ipv6 */ + config->ip_version = CURL_IPRESOLVE_V6; + break; + case C_APPEND: /* --append */ + /* This makes the FTP sessions use APPE instead of STOR */ + config->ftp_append = toggle; + break; + case C_USER_AGENT: /* --user-agent */ + err = getstr(&config->useragent, nextarg, ALLOW_BLANK); + break; + case C_ALT_SVC: /* --alt-svc */ + if(!feature_altsvc) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + err = getstr(&config->altsvc, nextarg, ALLOW_BLANK); + break; + case C_HSTS: /* --hsts */ + if(!feature_hsts) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + err = getstr(&config->hsts, nextarg, ALLOW_BLANK); + break; + case C_COOKIE: /* --cookie */ + if(strchr(nextarg, '=')) { + /* A cookie string must have a =-letter */ + err = add2list(&config->cookies, nextarg); + break; + } + else { + /* We have a cookie file to read from! */ + err = add2list(&config->cookiefiles, nextarg); + } + break; + case C_USE_ASCII: /* --use-ascii */ + config->use_ascii = toggle; + break; + case C_COOKIE_JAR: /* --cookie-jar */ + err = getstr(&config->cookiejar, nextarg, DENY_BLANK); + break; + case C_CONTINUE_AT: /* --continue-at */ + /* This makes us continue an ftp transfer at given position */ + if(strcmp(nextarg, "-")) { + err = str2offset(&config->resume_from, nextarg); + config->resume_from_current = FALSE; + } + else { + config->resume_from_current = TRUE; + config->resume_from = 0; + } + config->use_resume = TRUE; + break; + case C_DATA: /* --data */ + case C_DATA_ASCII: /* --data-ascii */ + case C_DATA_BINARY: /* --data-binary */ + case C_DATA_URLENCODE: /* --data-urlencode */ + case C_JSON: /* --json */ + case C_DATA_RAW: /* --data-raw */ + err = set_data(cmd, nextarg, global, config); + break; + case C_URL_QUERY: /* --url-query */ + err = url_query(nextarg, global, config); + break; + case C_DUMP_HEADER: /* --dump-header */ + err = getstr(&config->headerfile, nextarg, DENY_BLANK); + break; + case C_REFERER: { /* --referer */ + char *ptr = strstr(nextarg, ";auto"); + if(ptr) { + /* Automatic referer requested, this may be combined with a + set initial one */ + config->autoreferer = TRUE; + *ptr = 0; /* null-terminate here */ + } + else + config->autoreferer = FALSE; + ptr = *nextarg ? nextarg : NULL; + err = getstr(&config->referer, ptr, ALLOW_BLANK); + } + break; + case C_CERT: /* --cert */ + cleanarg(clearthis); + GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); + break; + case C_CACERT: /* --cacert */ + err = getstr(&config->cacert, nextarg, DENY_BLANK); + break; + case C_CA_NATIVE: /* --ca-native */ + config->native_ca_store = toggle; + break; + case C_PROXY_CA_NATIVE: /* --proxy-ca-native */ + config->proxy_native_ca_store = toggle; + break; + case C_CERT_TYPE: /* --cert-type */ + err = getstr(&config->cert_type, nextarg, DENY_BLANK); + break; + case C_KEY: /* --key */ + err = getstr(&config->key, nextarg, DENY_BLANK); + break; + case C_KEY_TYPE: /* --key-type */ + err = getstr(&config->key_type, nextarg, DENY_BLANK); + break; + case C_PASS: /* --pass */ + err = getstr(&config->key_passwd, nextarg, DENY_BLANK); + cleanarg(clearthis); + break; + case C_ENGINE: /* --engine */ + err = getstr(&config->engine, nextarg, DENY_BLANK); + if(!err && + config->engine && !strcmp(config->engine, "list")) { + err = PARAM_ENGINES_REQUESTED; + } + break; + case C_CAPATH: /* --capath */ + err = getstr(&config->capath, nextarg, DENY_BLANK); + break; + case C_PUBKEY: /* --pubkey */ + err = getstr(&config->pubkey, nextarg, DENY_BLANK); + break; + case C_HOSTPUBMD5: /* --hostpubmd5 */ + err = getstr(&config->hostpubmd5, nextarg, DENY_BLANK); + if(!err) { + if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) + err = PARAM_BAD_USE; + } + break; + case C_HOSTPUBSHA256: /* --hostpubsha256 */ + err = getstr(&config->hostpubsha256, nextarg, DENY_BLANK); + break; + case C_CRLFILE: /* --crlfile */ + err = getstr(&config->crlfile, nextarg, DENY_BLANK); + break; + case C_TLSUSER: /* --tlsuser */ + if(!feature_tls_srp) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + err = getstr(&config->tls_username, nextarg, DENY_BLANK); + cleanarg(clearthis); + break; + case C_TLSPASSWORD: /* --tlspassword */ + if(!feature_tls_srp) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + err = getstr(&config->tls_password, nextarg, ALLOW_BLANK); + cleanarg(clearthis); + break; + case C_TLSAUTHTYPE: /* --tlsauthtype */ + if(!feature_tls_srp) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else { + err = getstr(&config->tls_authtype, nextarg, DENY_BLANK); + if(!err && strcmp(config->tls_authtype, "SRP")) + err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ + } + break; + case C_SSL_ALLOW_BEAST: /* --ssl-allow-beast */ + if(feature_ssl) + config->ssl_allow_beast = toggle; + break; + case C_SSL_AUTO_CLIENT_CERT: /* --ssl-auto-client-cert */ + if(feature_ssl) + config->ssl_auto_client_cert = toggle; + break; + case C_PROXY_SSL_AUTO_CLIENT_CERT: /* --proxy-ssl-auto-client-cert */ + if(feature_ssl) + config->proxy_ssl_auto_client_cert = toggle; + break; + case C_PINNEDPUBKEY: /* --pinnedpubkey */ + err = getstr(&config->pinnedpubkey, nextarg, DENY_BLANK); + break; + case C_PROXY_PINNEDPUBKEY: /* --proxy-pinnedpubkey */ + err = getstr(&config->proxy_pinnedpubkey, nextarg, DENY_BLANK); + break; + case C_CERT_STATUS: /* --cert-status */ + config->verifystatus = TRUE; + break; + case C_DOH_CERT_STATUS: /* --doh-cert-status */ + config->doh_verifystatus = TRUE; + break; + case C_FALSE_START: /* --false-start */ + config->falsestart = TRUE; + break; + case C_SSL_NO_REVOKE: /* --ssl-no-revoke */ + if(feature_ssl) + config->ssl_no_revoke = TRUE; + break; + case C_SSL_REVOKE_BEST_EFFORT: /* --ssl-revoke-best-effort */ + if(feature_ssl) + config->ssl_revoke_best_effort = TRUE; + break; + case C_TCP_FASTOPEN: /* --tcp-fastopen */ + config->tcp_fastopen = TRUE; + break; + case C_PROXY_TLSUSER: /* --proxy-tlsuser */ + cleanarg(clearthis); + if(!feature_tls_srp) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + err = getstr(&config->proxy_tls_username, nextarg, ALLOW_BLANK); + break; + case C_PROXY_TLSPASSWORD: /* --proxy-tlspassword */ + cleanarg(clearthis); + if(!feature_tls_srp) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else + err = getstr(&config->proxy_tls_password, nextarg, DENY_BLANK); + break; + case C_PROXY_TLSAUTHTYPE: /* --proxy-tlsauthtype */ + if(!feature_tls_srp) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else { + err = getstr(&config->proxy_tls_authtype, nextarg, DENY_BLANK); + if(!err && strcmp(config->proxy_tls_authtype, "SRP")) + err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ + } + break; + case C_PROXY_CERT: /* --proxy-cert */ + cleanarg(clearthis); + GetFileAndPassword(nextarg, &config->proxy_cert, + &config->proxy_key_passwd); + break; + case C_PROXY_CERT_TYPE: /* --proxy-cert-type */ + err = getstr(&config->proxy_cert_type, nextarg, DENY_BLANK); + break; + case C_PROXY_KEY: /* --proxy-key */ + err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK); + break; + case C_PROXY_KEY_TYPE: /* --proxy-key-type */ + err = getstr(&config->proxy_key_type, nextarg, DENY_BLANK); + break; + case C_PROXY_PASS: /* --proxy-pass */ + err = getstr(&config->proxy_key_passwd, nextarg, ALLOW_BLANK); + cleanarg(clearthis); + break; + case C_PROXY_CIPHERS: /* --proxy-ciphers */ + err = getstr(&config->proxy_cipher_list, nextarg, DENY_BLANK); + break; + case C_PROXY_CRLFILE: /* --proxy-crlfile */ + err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK); + break; + case C_PROXY_SSL_ALLOW_BEAST: /* --proxy-ssl-allow-beast */ + if(feature_ssl) + config->proxy_ssl_allow_beast = toggle; + break; + case C_LOGIN_OPTIONS: /* --login-options */ + err = getstr(&config->login_options, nextarg, ALLOW_BLANK); + break; + case C_PROXY_CACERT: /* --proxy-cacert */ + err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK); + break; + case C_PROXY_CAPATH: /* --proxy-capath */ + err = getstr(&config->proxy_capath, nextarg, DENY_BLANK); + break; + case C_PROXY_INSECURE: /* --proxy-insecure */ + config->proxy_insecure_ok = toggle; + break; + case C_PROXY_TLSV1: /* --proxy-tlsv1 */ + /* TLS version 1 for proxy */ + config->proxy_ssl_version = CURL_SSLVERSION_TLSv1; + break; + case C_SOCKS5_BASIC: /* --socks5-basic */ + if(toggle) + config->socks5_auth |= CURLAUTH_BASIC; + else + config->socks5_auth &= ~CURLAUTH_BASIC; + break; + case C_SOCKS5_GSSAPI: /* --socks5-gssapi */ + if(toggle) + config->socks5_auth |= CURLAUTH_GSSAPI; + else + config->socks5_auth &= ~CURLAUTH_GSSAPI; + break; + case C_ETAG_SAVE: /* --etag-save */ + err = getstr(&config->etag_save_file, nextarg, DENY_BLANK); + break; + case C_ETAG_COMPARE: /* --etag-compare */ + err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK); + break; + case C_CURVES: /* --curves */ + err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK); + break; + case C_FAIL_EARLY: /* --fail-early */ + global->fail_early = toggle; + break; + case C_STYLED_OUTPUT: /* --styled-output */ + global->styled_output = toggle; + break; + case C_MAIL_RCPT_ALLOWFAILS: /* --mail-rcpt-allowfails */ + config->mail_rcpt_allowfails = toggle; + break; + case C_FAIL_WITH_BODY: /* --fail-with-body */ + config->failwithbody = toggle; + if(config->failonerror && config->failwithbody) { + errorf(config->global, "You must select either --fail or " + "--fail-with-body, not both."); + err = PARAM_BAD_USE; + } + break; + case C_REMOVE_ON_ERROR: /* --remove-on-error */ + config->rm_partial = toggle; + break; + case C_FAIL: /* --fail */ + config->failonerror = toggle; + if(config->failonerror && config->failwithbody) { + errorf(config->global, "You must select either --fail or " + "--fail-with-body, not both."); + err = PARAM_BAD_USE; + } + break; + case C_FORM: /* --form */ + case C_FORM_STRING: /* --form-string */ + /* "form data" simulation, this is a little advanced so lets do our best + to sort this out slowly and carefully */ + if(formparse(config, + nextarg, + &config->mimeroot, + &config->mimecurrent, + (cmd == C_FORM_STRING)?TRUE:FALSE)) /* literal string */ + err = PARAM_BAD_USE; + else if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq)) + err = PARAM_BAD_USE; + break; + case C_GLOBOFF: /* --globoff */ + config->globoff = toggle; + break; + case C_GET: /* --get */ + config->use_httpget = toggle; + break; + case C_REQUEST_TARGET: /* --request-target */ + err = getstr(&config->request_target, nextarg, DENY_BLANK); + break; + case C_HELP: /* --help */ + if(toggle) { + if(*nextarg) { + global->help_category = strdup(nextarg); + if(!global->help_category) { + err = PARAM_NO_MEM; + break; + } + } + err = PARAM_HELP_REQUESTED; + } + /* we now actually support --no-help too! */ + break; + case C_HEADER: /* --header */ + case C_PROXY_HEADER: /* --proxy-header */ + /* A custom header to append to a list */ + if(nextarg[0] == '@') { + /* read many headers from a file or stdin */ + char *string; + size_t len; + bool use_stdin = !strcmp(&nextarg[1], "-"); + FILE *file = use_stdin?stdin:fopen(&nextarg[1], FOPEN_READTEXT); + if(!file) { + errorf(global, "Failed to open %s", &nextarg[1]); + err = PARAM_READ_ERROR; + } + else { + err = file2memory(&string, &len, file); + if(!err && string) { + /* Allow strtok() here since this isn't used threaded */ + /* !checksrc! disable BANNEDFUNC 2 */ + char *h = strtok(string, "\r\n"); + while(h) { + if(cmd == C_PROXY_HEADER) /* --proxy-header */ + err = add2list(&config->proxyheaders, h); + else + err = add2list(&config->headers, h); + if(err) + break; + h = strtok(NULL, "\r\n"); + } + free(string); + } + if(!use_stdin) + fclose(file); + } + } + else { + if(cmd == C_PROXY_HEADER) /* --proxy-header */ + err = add2list(&config->proxyheaders, nextarg); + else + err = add2list(&config->headers, nextarg); + } + break; + case C_INCLUDE: /* --include */ + config->show_headers = toggle; /* show the headers as well in the + general output stream */ + break; + case C_JUNK_SESSION_COOKIES: /* --junk-session-cookies */ + config->cookiesession = toggle; + break; + case C_HEAD: /* --head */ + config->no_body = toggle; + config->show_headers = toggle; + if(SetHTTPrequest(config, + (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET, + &config->httpreq)) + err = PARAM_BAD_USE; + break; + case C_REMOTE_HEADER_NAME: /* --remote-header-name */ + config->content_disposition = toggle; + break; + case C_INSECURE: /* --insecure */ + config->insecure_ok = toggle; + break; + case C_DOH_INSECURE: /* --doh-insecure */ + config->doh_insecure_ok = toggle; + break; + case C_CONFIG: /* --config */ + if(parseconfig(nextarg, global)) { + errorf(global, "cannot read config from '%s'", nextarg); + err = PARAM_READ_ERROR; + } + break; + case C_LIST_ONLY: /* --list-only */ + config->dirlistonly = toggle; /* only list the names of the FTP dir */ + break; + case C_LOCATION_TRUSTED: /* --location-trusted */ + /* Continue to send authentication (user+password) when following + * locations, even when hostname changed */ + config->unrestricted_auth = toggle; + FALLTHROUGH(); + case C_LOCATION: /* --location */ + config->followlocation = toggle; /* Follow Location: HTTP headers */ + break; + case C_MAX_TIME: /* --max-time */ + /* specified max time */ + err = secs2ms(&config->timeout_ms, nextarg); + break; + case C_MANUAL: /* --manual */ + if(toggle) { /* --no-manual shows no manual... */ +#ifndef USE_MANUAL + warnf(global, + "built-in manual was disabled at build-time"); +#endif + err = PARAM_MANUAL_REQUESTED; + } + break; + case C_NETRC_OPTIONAL: /* --netrc-optional */ + config->netrc_opt = toggle; + break; + case C_NETRC_FILE: /* --netrc-file */ + err = getstr(&config->netrc_file, nextarg, DENY_BLANK); + break; + case C_NETRC: /* --netrc */ + /* pick info from .netrc, if this is used for http, curl will + automatically enforce user+password with the request */ + config->netrc = toggle; + break; + case C_BUFFER: /* --buffer */ + /* disable the output I/O buffering. note that the option is called + --buffer but is mostly used in the negative form: --no-buffer */ + config->nobuffer = longopt ? !toggle : TRUE; + break; + case C_REMOTE_NAME_ALL: /* --remote-name-all */ + config->default_node_flags = toggle?GETOUT_USEREMOTE:0; + break; + case C_OUTPUT_DIR: /* --output-dir */ + err = getstr(&config->output_dir, nextarg, DENY_BLANK); + break; + case C_CLOBBER: /* --clobber */ + config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER; + break; + case C_OUTPUT: /* --output */ + case C_REMOTE_NAME: /* --remote-name */ + /* output file */ + if(!config->url_out) + config->url_out = config->url_list; + if(config->url_out) { + /* there's a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) + config->url_out = config->url_out->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_out) + /* existing node */ + url = config->url_out; + else { + if(!toggle && !config->default_node_flags) + break; + /* there was no free node, create one! */ + config->url_out = url = new_getout(config); + } + + if(!url) { + err = PARAM_NO_MEM; + break; + } + + /* fill in the outfile */ + if('o' == letter) { + err = getstr(&url->outfile, nextarg, DENY_BLANK); + url->flags &= ~GETOUT_USEREMOTE; /* switch off */ + } + else { + url->outfile = NULL; /* leave it */ + if(toggle) + url->flags |= GETOUT_USEREMOTE; /* switch on */ + else + url->flags &= ~GETOUT_USEREMOTE; /* switch off */ + } + url->flags |= GETOUT_OUTFILE; + break; + case C_FTP_PORT: /* --ftp-port */ + /* This makes the FTP sessions use PORT instead of PASV */ + /* use or <192.168.10.10> style addresses. Anything except + this will make us try to get the "default" address. + NOTE: this is a changed behavior since the released 4.1! + */ + err = getstr(&config->ftpport, nextarg, DENY_BLANK); + break; + case C_PROXYTUNNEL: /* --proxytunnel */ + /* proxy tunnel for non-http protocols */ + config->proxytunnel = toggle; + break; + + case C_DISABLE: /* --disable */ + /* if used first, already taken care of, we do it like this so we don't + cause an error! */ + break; + case C_QUOTE: /* --quote */ + /* QUOTE command to send to FTP server */ + switch(nextarg[0]) { + case '-': + /* prefixed with a dash makes it a POST TRANSFER one */ + nextarg++; + err = add2list(&config->postquote, nextarg); + break; + case '+': + /* prefixed with a plus makes it a just-before-transfer one */ + nextarg++; + err = add2list(&config->prequote, nextarg); + break; + default: + err = add2list(&config->quote, nextarg); + break; + } + break; + case C_RANGE: /* --range */ + /* Specifying a range WITHOUT A DASH will create an illegal HTTP range + (and won't actually be range by definition). The man page previously + claimed that to be a good way, why this code is added to work-around + it. */ + if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) { + char buffer[32]; + if(curlx_strtoofft(nextarg, NULL, 10, &value)) { + warnf(global, "unsupported range point"); + err = PARAM_BAD_USE; + } + else { + warnf(global, + "A specified range MUST include at least one dash (-). " + "Appending one for you"); + msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", + value); + Curl_safefree(config->range); + config->range = strdup(buffer); + if(!config->range) + err = PARAM_NO_MEM; + } + } + else { + /* byte range requested */ + const char *tmp_range = nextarg; + while(*tmp_range) { + if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { + warnf(global, "Invalid character is found in given range. " + "A specified range MUST have only digits in " + "\'start\'-\'stop\'. The server's response to this " + "request is uncertain."); + break; + } + tmp_range++; + } + err = getstr(&config->range, nextarg, DENY_BLANK); + } + break; + case C_REMOTE_TIME: /* --remote-time */ + /* use remote file's time */ + config->remote_time = toggle; + break; + case C_SILENT: /* --silent */ + global->silent = toggle; + break; + case C_SHOW_ERROR: /* --show-error */ + global->showerror = toggle; + break; + case C_TELNET_OPTION: /* --telnet-option */ + /* Telnet options */ + err = add2list(&config->telnet_options, nextarg); + break; + case C_UPLOAD_FILE: /* --upload-file */ + /* we are uploading */ + if(!config->url_ul) + config->url_ul = config->url_list; + if(config->url_ul) { + /* there's a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD)) + config->url_ul = config->url_ul->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_ul) + /* existing node */ + url = config->url_ul; + else + /* there was no free node, create one! */ + config->url_ul = url = new_getout(config); + + if(!url) { + err = PARAM_NO_MEM; + break; + } + + url->flags |= GETOUT_UPLOAD; /* mark -T used */ + if(!*nextarg) + url->flags |= GETOUT_NOUPLOAD; + else { + /* "-" equals stdin, but keep the string around for now */ + err = getstr(&url->infile, nextarg, DENY_BLANK); + } + break; + case C_USER: /* --user */ + /* user:password */ + err = getstr(&config->userpwd, nextarg, ALLOW_BLANK); + cleanarg(clearthis); + break; + case C_PROXY_USER: /* --proxy-user */ + /* Proxy user:password */ + err = getstr(&config->proxyuserpwd, nextarg, ALLOW_BLANK); + cleanarg(clearthis); + break; + case C_VERBOSE: /* --verbose */ + if(toggle) { + /* the '%' thing here will cause the trace get sent to stderr */ + Curl_safefree(global->trace_dump); + global->trace_dump = strdup("%"); + if(!global->trace_dump) + err = PARAM_NO_MEM; + else { + if(global->tracetype && (global->tracetype != TRACE_PLAIN)) + warnf(global, + "-v, --verbose overrides an earlier trace/verbose option"); + global->tracetype = TRACE_PLAIN; + } + } + else + /* verbose is disabled here */ + global->tracetype = TRACE_NONE; + break; + case C_VERSION: /* --version */ + if(toggle) /* --no-version yields no output! */ + err = PARAM_VERSION_INFO_REQUESTED; + break; + case C_WRITE_OUT: /* --write-out */ + /* get the output string */ + if('@' == *nextarg) { + /* the data begins with a '@' letter, it means that a file name + or - (stdin) follows */ + FILE *file; + const char *fname; + nextarg++; /* pass the @ */ + if(!strcmp("-", nextarg)) { + fname = ""; + file = stdin; + } + else { + fname = nextarg; + file = fopen(fname, FOPEN_READTEXT); + if(!file) { + errorf(global, "Failed to open %s", fname); + err = PARAM_READ_ERROR; + break; + } + } + Curl_safefree(config->writeout); + err = file2string(&config->writeout, file); + if(file && (file != stdin)) + fclose(file); + if(err) + break; + if(!config->writeout) + warnf(global, "Failed to read %s", fname); + } + else + err = getstr(&config->writeout, nextarg, DENY_BLANK); + break; + case C_PREPROXY: /* --preproxy */ + err = getstr(&config->preproxy, nextarg, DENY_BLANK); + break; + case C_PROXY: /* --proxy */ + /* --proxy */ + err = getstr(&config->proxy, nextarg, ALLOW_BLANK); + if(config->proxyver != CURLPROXY_HTTPS2) + config->proxyver = CURLPROXY_HTTP; + break; + case C_REQUEST: /* --request */ + /* set custom request */ + err = getstr(&config->customrequest, nextarg, DENY_BLANK); + break; + case C_SPEED_TIME: /* --speed-time */ + /* low speed time */ + err = str2unum(&config->low_speed_time, nextarg); + if(!err && !config->low_speed_limit) + config->low_speed_limit = 1; + break; + case C_SPEED_LIMIT: /* --speed-limit */ + /* low speed limit */ + err = str2unum(&config->low_speed_limit, nextarg); + if(!err && !config->low_speed_time) + config->low_speed_time = 30; + break; + case C_PARALLEL: /* --parallel */ + global->parallel = toggle; + break; + case C_PARALLEL_MAX: { /* --parallel-max */ + long val; + err = str2unum(&val, nextarg); + if(err) + break; + if(val > MAX_PARALLEL) + global->parallel_max = MAX_PARALLEL; + else if(val < 1) + global->parallel_max = PARALLEL_DEFAULT; + else + global->parallel_max = (unsigned short)val; + break; + } + case C_PARALLEL_IMMEDIATE: /* --parallel-immediate */ + global->parallel_connect = toggle; + break; + case C_TIME_COND: /* --time-cond */ + switch(*nextarg) { + case '+': + nextarg++; + FALLTHROUGH(); + default: + /* If-Modified-Since: (section 14.28 in RFC2068) */ + config->timecond = CURL_TIMECOND_IFMODSINCE; + break; + case '-': + /* If-Unmodified-Since: (section 14.24 in RFC2068) */ + config->timecond = CURL_TIMECOND_IFUNMODSINCE; + nextarg++; + break; + case '=': + /* Last-Modified: (section 14.29 in RFC2068) */ + config->timecond = CURL_TIMECOND_LASTMOD; + nextarg++; + break; + } + now = time(NULL); + config->condtime = (curl_off_t)curl_getdate(nextarg, &now); + if(-1 == config->condtime) { + /* now let's see if it is a file name to get the time from instead! */ + rc = getfiletime(nextarg, global, &value); + if(!rc) + /* pull the time out from the file */ + config->condtime = value; + else { + /* failed, remove time condition */ + config->timecond = CURL_TIMECOND_NONE; + warnf(global, + "Illegal date format for -z, --time-cond (and not " + "a file name). Disabling time condition. " + "See curl_getdate(3) for valid date syntax."); + } + } + break; + default: /* unknown flag */ + err = PARAM_OPTION_UNKNOWN; + break; + } + a = NULL; + + } while(!longopt && !singleopt && *++parse && !*usedarg && !err); + +error: + if(nextalloc) + free(nextarg); + return err; +} + +ParameterError parse_args(struct GlobalConfig *global, int argc, + argv_item_t argv[]) +{ + int i; + bool stillflags; + char *orig_opt = NULL; + ParameterError result = PARAM_OK; + struct OperationConfig *config = global->first; + + for(i = 1, stillflags = TRUE; i < argc && !result; i++) { + orig_opt = curlx_convert_tchar_to_UTF8(argv[i]); + if(!orig_opt) + return PARAM_NO_MEM; + + if(stillflags && ('-' == orig_opt[0])) { + bool passarg; + + if(!strcmp("--", orig_opt)) + /* This indicates the end of the flags and thus enables the + following (URL) argument to start with -. */ + stillflags = FALSE; + else { + char *nextarg = NULL; + if(i < (argc - 1)) { + nextarg = curlx_convert_tchar_to_UTF8(argv[i + 1]); + if(!nextarg) { + curlx_unicodefree(orig_opt); + return PARAM_NO_MEM; + } + } + + result = getparameter(orig_opt, nextarg, argv[i + 1], &passarg, + global, config); + + curlx_unicodefree(nextarg); + config = global->last; + if(result == PARAM_NEXT_OPERATION) { + /* Reset result as PARAM_NEXT_OPERATION is only used here and not + returned from this function */ + result = PARAM_OK; + + if(config->url_list && config->url_list->url) { + /* Allocate the next config */ + config->next = malloc(sizeof(struct OperationConfig)); + if(config->next) { + /* Initialise the newly created config */ + config_init(config->next); + + /* Set the global config pointer */ + config->next->global = global; + + /* Update the last config pointer */ + global->last = config->next; + + /* Move onto the new config */ + config->next->prev = config; + config = config->next; + } + else + result = PARAM_NO_MEM; + } + else { + errorf(global, "missing URL before --next"); + result = PARAM_BAD_USE; + } + } + else if(!result && passarg) + i++; /* we're supposed to skip this */ + } + } + else { + bool used; + + /* Just add the URL please */ + result = getparameter("--url", orig_opt, argv[i], &used, global, config); + } + + if(!result) + curlx_unicodefree(orig_opt); + } + + if(!result && config->content_disposition) { + if(config->show_headers) + result = PARAM_CONTDISP_SHOW_HEADER; + else if(config->resume_from_current) + result = PARAM_CONTDISP_RESUME_FROM; + } + + if(result && result != PARAM_HELP_REQUESTED && + result != PARAM_MANUAL_REQUESTED && + result != PARAM_VERSION_INFO_REQUESTED && + result != PARAM_ENGINES_REQUESTED) { + const char *reason = param2text(result); + + if(orig_opt && strcmp(":", orig_opt)) + helpf(tool_stderr, "option %s: %s", orig_opt, reason); + else + helpf(tool_stderr, "%s", reason); + } + + curlx_unicodefree(orig_opt); + return result; +} diff --git a/src/tool_getparam.h b/src/tool_getparam.h new file mode 100644 index 0000000..12a971d --- /dev/null +++ b/src/tool_getparam.h @@ -0,0 +1,74 @@ +#ifndef HEADER_CURL_TOOL_GETPARAM_H +#define HEADER_CURL_TOOL_GETPARAM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +typedef enum { + PARAM_OK = 0, + PARAM_OPTION_AMBIGUOUS, + PARAM_OPTION_UNKNOWN, + PARAM_REQUIRES_PARAMETER, + PARAM_BAD_USE, + PARAM_HELP_REQUESTED, + PARAM_MANUAL_REQUESTED, + PARAM_VERSION_INFO_REQUESTED, + PARAM_ENGINES_REQUESTED, + PARAM_GOT_EXTRA_PARAMETER, + PARAM_BAD_NUMERIC, + PARAM_NEGATIVE_NUMERIC, + PARAM_LIBCURL_DOESNT_SUPPORT, + PARAM_LIBCURL_UNSUPPORTED_PROTOCOL, + PARAM_NO_MEM, + PARAM_NEXT_OPERATION, + PARAM_NO_PREFIX, + PARAM_NUMBER_TOO_LARGE, + PARAM_NO_NOT_BOOLEAN, + PARAM_CONTDISP_SHOW_HEADER, /* --include and --remote-header-name */ + PARAM_CONTDISP_RESUME_FROM, /* --continue-at and --remote-header-name */ + PARAM_READ_ERROR, + PARAM_EXPAND_ERROR, /* --expand problem */ + PARAM_BLANK_STRING, + PARAM_LAST +} ParameterError; + +struct GlobalConfig; +struct OperationConfig; + +ParameterError getparameter(const char *flag, char *nextarg, + argv_item_t cleararg, + bool *usedarg, + struct GlobalConfig *global, + struct OperationConfig *operation); + +#ifdef UNITTESTS +void parse_cert_parameter(const char *cert_parameter, + char **certname, + char **passphrase); +#endif + +ParameterError parse_args(struct GlobalConfig *config, int argc, + argv_item_t argv[]); + +#endif /* HEADER_CURL_TOOL_GETPARAM_H */ diff --git a/src/tool_getpass.c b/src/tool_getpass.c new file mode 100644 index 0000000..8ccccdf --- /dev/null +++ b/src/tool_getpass.c @@ -0,0 +1,207 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(__AMIGA__) && !defined(__amigaos4__) +# undef HAVE_TERMIOS_H +#endif + +#ifndef HAVE_GETPASS_R +/* this file is only for systems without getpass_r() */ + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_TERMIOS_H +# include +#elif defined(HAVE_TERMIO_H) +# include +#endif + +#ifdef __VMS +# include descrip +# include starlet +# include iodef +#endif + +#ifdef _WIN32 +# include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#include "tool_getpass.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef __VMS +/* VMS implementation */ +char *getpass_r(const char *prompt, char *buffer, size_t buflen) +{ + long sts; + short chan; + + /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */ + /* distribution so I created this. May revert back later to */ + /* struct _iosb iosb; */ + struct _iosb + { + short int iosb$w_status; /* status */ + short int iosb$w_bcnt; /* byte count */ + int unused; /* unused */ + } iosb; + + $DESCRIPTOR(ttdesc, "TT"); + + buffer[0] = '\0'; + sts = sys$assign(&ttdesc, &chan, 0, 0); + if(sts & 1) { + sts = sys$qiow(0, chan, + IO$_READPROMPT | IO$M_NOECHO, + &iosb, 0, 0, buffer, buflen, 0, 0, + prompt, strlen(prompt)); + + if((sts & 1) && (iosb.iosb$w_status & 1)) + buffer[iosb.iosb$w_bcnt] = '\0'; + + sys$dassgn(chan); + } + return buffer; /* we always return success */ +} +#define DONE +#endif /* __VMS */ + +#if defined(_WIN32) + +char *getpass_r(const char *prompt, char *buffer, size_t buflen) +{ + size_t i; + fputs(prompt, tool_stderr); + + for(i = 0; i < buflen; i++) { + buffer[i] = (char)getch(); + if(buffer[i] == '\r' || buffer[i] == '\n') { + buffer[i] = '\0'; + break; + } + else + if(buffer[i] == '\b') + /* remove this letter and if this is not the first key, remove the + previous one as well */ + i = i - (i >= 1 ? 2 : 1); + } + /* since echo is disabled, print a newline */ + fputs("\n", tool_stderr); + /* if user didn't hit ENTER, terminate buffer */ + if(i == buflen) + buffer[buflen-1] = '\0'; + + return buffer; /* we always return success */ +} +#define DONE +#endif /* _WIN32 */ + +#ifndef DONE /* not previously provided */ + +#ifdef HAVE_TERMIOS_H +# define struct_term struct termios +#elif defined(HAVE_TERMIO_H) +# define struct_term struct termio +#else +# undef struct_term +#endif + +static bool ttyecho(bool enable, int fd) +{ +#ifdef struct_term + static struct_term withecho; + static struct_term noecho; +#endif + if(!enable) { + /* disable echo by extracting the current 'withecho' mode and remove the + ECHO bit and set back the struct */ +#ifdef HAVE_TERMIOS_H + tcgetattr(fd, &withecho); + noecho = withecho; + noecho.c_lflag &= ~ECHO; + tcsetattr(fd, TCSANOW, &noecho); +#elif defined(HAVE_TERMIO_H) + ioctl(fd, TCGETA, &withecho); + noecho = withecho; + noecho.c_lflag &= ~ECHO; + ioctl(fd, TCSETA, &noecho); +#else + /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ + (void)fd; + return FALSE; /* not disabled */ +#endif + return TRUE; /* disabled */ + } + /* re-enable echo, assumes we disabled it before (and set the structs we + now use to reset the terminal status) */ +#ifdef HAVE_TERMIOS_H + tcsetattr(fd, TCSAFLUSH, &withecho); +#elif defined(HAVE_TERMIO_H) + ioctl(fd, TCSETA, &withecho); +#else + return FALSE; /* not enabled */ +#endif + return TRUE; /* enabled */ +} + +char *getpass_r(const char *prompt, /* prompt to display */ + char *password, /* buffer to store password in */ + size_t buflen) /* size of buffer to store password in */ +{ + ssize_t nread; + bool disabled; + int fd = open("/dev/tty", O_RDONLY); + if(-1 == fd) + fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */ + + disabled = ttyecho(FALSE, fd); /* disable terminal echo */ + + fputs(prompt, tool_stderr); + nread = read(fd, password, buflen); + if(nread > 0) + password[--nread] = '\0'; /* null-terminate where enter is stored */ + else + password[0] = '\0'; /* got nothing */ + + if(disabled) { + /* if echo actually was disabled, add a newline */ + fputs("\n", tool_stderr); + (void)ttyecho(TRUE, fd); /* enable echo */ + } + + if(STDIN_FILENO != fd) + close(fd); + + return password; /* return pointer to buffer */ +} + +#endif /* DONE */ +#endif /* HAVE_GETPASS_R */ diff --git a/src/tool_getpass.h b/src/tool_getpass.h new file mode 100644 index 0000000..b93585d --- /dev/null +++ b/src/tool_getpass.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_TOOL_GETPASS_H +#define HEADER_CURL_TOOL_GETPASS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifndef HAVE_GETPASS_R +/* If there's a system-provided function named like this, we trust it is + also found in one of the standard headers. */ + +/* + * Returning NULL will abort the continued operation! + */ +char *getpass_r(const char *prompt, char *buffer, size_t buflen); +#endif + +#endif /* HEADER_CURL_TOOL_GETPASS_H */ diff --git a/src/tool_help.c b/src/tool_help.c new file mode 100644 index 0000000..04ac245 --- /dev/null +++ b/src/tool_help.c @@ -0,0 +1,235 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_help.h" +#include "tool_libinfo.h" +#include "tool_util.h" +#include "tool_version.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef MSDOS +# define USE_WATT32 +#endif + +struct category_descriptors { + const char *opt; + const char *desc; + curlhelp_t category; +}; + +static const struct category_descriptors categories[] = { + {"auth", "Different types of authentication methods", CURLHELP_AUTH}, + {"connection", "Low level networking operations", + CURLHELP_CONNECTION}, + {"curl", "The command line tool itself", CURLHELP_CURL}, + {"dns", "General DNS options", CURLHELP_DNS}, + {"file", "FILE protocol options", CURLHELP_FILE}, + {"ftp", "FTP protocol options", CURLHELP_FTP}, + {"http", "HTTP and HTTPS protocol options", CURLHELP_HTTP}, + {"imap", "IMAP protocol options", CURLHELP_IMAP}, + /* important is left out because it is the default help page */ + {"misc", "Options that don't fit into any other category", CURLHELP_MISC}, + {"output", "Filesystem output", CURLHELP_OUTPUT}, + {"pop3", "POP3 protocol options", CURLHELP_POP3}, + {"post", "HTTP Post specific options", CURLHELP_POST}, + {"proxy", "All options related to proxies", CURLHELP_PROXY}, + {"scp", "SCP protocol options", CURLHELP_SCP}, + {"sftp", "SFTP protocol options", CURLHELP_SFTP}, + {"smtp", "SMTP protocol options", CURLHELP_SMTP}, + {"ssh", "SSH protocol options", CURLHELP_SSH}, + {"telnet", "TELNET protocol options", CURLHELP_TELNET}, + {"tftp", "TFTP protocol options", CURLHELP_TFTP}, + {"tls", "All TLS/SSL related options", CURLHELP_TLS}, + {"upload", "All options for uploads", + CURLHELP_UPLOAD}, + {"verbose", "Options related to any kind of command line output of curl", + CURLHELP_VERBOSE}, + {NULL, NULL, CURLHELP_HIDDEN} +}; + + +static void print_category(curlhelp_t category) +{ + unsigned int i; + size_t longopt = 5; + size_t longdesc = 5; + + for(i = 0; helptext[i].opt; ++i) { + size_t len; + if(!(helptext[i].categories & category)) + continue; + len = strlen(helptext[i].opt); + if(len > longopt) + longopt = len; + len = strlen(helptext[i].desc); + if(len > longdesc) + longdesc = len; + } + if(longopt + longdesc > 80) + longopt = 80 - longdesc; + + for(i = 0; helptext[i].opt; ++i) + if(helptext[i].categories & category) { + printf(" %-*s %s\n", (int)longopt, helptext[i].opt, helptext[i].desc); + } +} + +/* Prints category if found. If not, it returns 1 */ +static int get_category_content(const char *category) +{ + unsigned int i; + for(i = 0; categories[i].opt; ++i) + if(curl_strequal(categories[i].opt, category)) { + printf("%s: %s\n", categories[i].opt, categories[i].desc); + print_category(categories[i].category); + return 0; + } + return 1; +} + +/* Prints all categories and their description */ +static void get_categories(void) +{ + unsigned int i; + for(i = 0; categories[i].opt; ++i) + printf(" %-11s %s\n", categories[i].opt, categories[i].desc); +} + + +void tool_help(char *category) +{ + puts("Usage: curl [options...] "); + /* If no category was provided */ + if(!category) { + const char *category_note = "\nThis is not the full help, this " + "menu is stripped into categories.\nUse \"--help category\" to get " + "an overview of all categories.\nFor all options use the manual" + " or \"--help all\"."; + print_category(CURLHELP_IMPORTANT); + puts(category_note); + } + /* Lets print everything if "all" was provided */ + else if(curl_strequal(category, "all")) + /* Print everything except hidden */ + print_category(~(CURLHELP_HIDDEN)); + /* Lets handle the string "category" differently to not print an errormsg */ + else if(curl_strequal(category, "category")) + get_categories(); + /* Otherwise print category and handle the case if the cat was not found */ + else if(get_category_content(category)) { + puts("Invalid category provided, here is a list of all categories:\n"); + get_categories(); + } + free(category); +} + +static bool is_debug(void) +{ + const char *const *builtin; + for(builtin = feature_names; *builtin; ++builtin) + if(curl_strequal("debug", *builtin)) + return TRUE; + return FALSE; +} + +void tool_version_info(void) +{ + const char *const *builtin; + if(is_debug()) + fprintf(tool_stderr, "WARNING: this libcurl is Debug-enabled, " + "do not use in production\n\n"); + + printf(CURL_ID "%s\n", curl_version()); +#ifdef CURL_PATCHSTAMP + printf("Release-Date: %s, security patched: %s\n", + LIBCURL_TIMESTAMP, CURL_PATCHSTAMP); +#else + printf("Release-Date: %s\n", LIBCURL_TIMESTAMP); +#endif + if(built_in_protos[0]) { + const char *insert = NULL; + /* we have ipfs and ipns support if libcurl has http support */ + for(builtin = built_in_protos; *builtin; ++builtin) { + if(insert) { + /* update insertion so ipfs will be printed in alphabetical order */ + if(strcmp(*builtin, "ipfs") < 0) + insert = *builtin; + else + break; + } + else if(!strcmp(*builtin, "http")) { + insert = *builtin; + } + } + printf("Protocols:"); + for(builtin = built_in_protos; *builtin; ++builtin) { + /* Special case: do not list rtmp?* protocols. + They may only appear together with "rtmp" */ + if(!curl_strnequal(*builtin, "rtmp", 4) || !builtin[0][4]) + printf(" %s", *builtin); + if(insert && insert == *builtin) { + printf(" ipfs ipns"); + insert = NULL; + } + } + puts(""); /* newline */ + } + if(feature_names[0]) { + printf("Features:"); + for(builtin = feature_names; *builtin; ++builtin) + printf(" %s", *builtin); + puts(""); /* newline */ + } + if(strcmp(CURL_VERSION, curlinfo->version)) { + printf("WARNING: curl and libcurl versions do not match. " + "Functionality may be affected.\n"); + } +} + +void tool_list_engines(void) +{ + CURL *curl = curl_easy_init(); + struct curl_slist *engines = NULL; + + /* Get the list of engines */ + curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines); + + puts("Build-time engines:"); + if(engines) { + for(; engines; engines = engines->next) + printf(" %s\n", engines->data); + } + else { + puts(" "); + } + + /* Cleanup the list of engines */ + curl_slist_free_all(engines); + curl_easy_cleanup(curl); +} diff --git a/src/tool_help.h b/src/tool_help.h new file mode 100644 index 0000000..a790626 --- /dev/null +++ b/src/tool_help.h @@ -0,0 +1,75 @@ +#ifndef HEADER_CURL_TOOL_HELP_H +#define HEADER_CURL_TOOL_HELP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +void tool_help(char *category); +void tool_list_engines(void); +void tool_version_info(void); + +typedef unsigned int curlhelp_t; + +struct helptxt { + const char *opt; + const char *desc; + curlhelp_t categories; +}; + +/* + * The bitmask output is generated with the following command + ------------------------------------------------------------ + cd $srcroot/docs/cmdline-opts + ./gen.pl listcats *.d + */ + +#define CURLHELP_HIDDEN 1u << 0u +#define CURLHELP_AUTH 1u << 1u +#define CURLHELP_CONNECTION 1u << 2u +#define CURLHELP_CURL 1u << 3u +#define CURLHELP_DNS 1u << 4u +#define CURLHELP_FILE 1u << 5u +#define CURLHELP_FTP 1u << 6u +#define CURLHELP_HTTP 1u << 7u +#define CURLHELP_IMAP 1u << 8u +#define CURLHELP_IMPORTANT 1u << 9u +#define CURLHELP_IPFS 1u << 10u +#define CURLHELP_MISC 1u << 11u +#define CURLHELP_OUTPUT 1u << 12u +#define CURLHELP_POP3 1u << 13u +#define CURLHELP_POST 1u << 14u +#define CURLHELP_PROXY 1u << 15u +#define CURLHELP_SCP 1u << 16u +#define CURLHELP_SFTP 1u << 17u +#define CURLHELP_SMTP 1u << 18u +#define CURLHELP_SSH 1u << 19u +#define CURLHELP_TELNET 1u << 20u +#define CURLHELP_TFTP 1u << 21u +#define CURLHELP_TLS 1u << 22u +#define CURLHELP_UPLOAD 1u << 23u +#define CURLHELP_VERBOSE 1u << 24u + +extern const struct helptxt helptext[]; + +#endif /* HEADER_CURL_TOOL_HELP_H */ diff --git a/src/tool_helpers.c b/src/tool_helpers.c new file mode 100644 index 0000000..67924a2 --- /dev/null +++ b/src/tool_helpers.c @@ -0,0 +1,136 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_getparam.h" +#include "tool_helpers.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* +** Helper functions that are used from more than one source file. +*/ + +const char *param2text(int res) +{ + ParameterError error = (ParameterError)res; + switch(error) { + case PARAM_GOT_EXTRA_PARAMETER: + return "had unsupported trailing garbage"; + case PARAM_OPTION_UNKNOWN: + return "is unknown"; + case PARAM_OPTION_AMBIGUOUS: + return "is ambiguous"; + case PARAM_REQUIRES_PARAMETER: + return "requires parameter"; + case PARAM_BAD_USE: + return "is badly used here"; + case PARAM_BAD_NUMERIC: + return "expected a proper numerical parameter"; + case PARAM_NEGATIVE_NUMERIC: + return "expected a positive numerical parameter"; + case PARAM_LIBCURL_DOESNT_SUPPORT: + return "the installed libcurl version doesn't support this"; + case PARAM_LIBCURL_UNSUPPORTED_PROTOCOL: + return "a specified protocol is unsupported by libcurl"; + case PARAM_NO_MEM: + return "out of memory"; + case PARAM_NO_PREFIX: + return "the given option can't be reversed with a --no- prefix"; + case PARAM_NUMBER_TOO_LARGE: + return "too large number"; + case PARAM_NO_NOT_BOOLEAN: + return "used '--no-' for option that isn't a boolean"; + case PARAM_CONTDISP_SHOW_HEADER: + return "showing headers and --remote-header-name cannot be combined"; + case PARAM_CONTDISP_RESUME_FROM: + return "--continue-at and --remote-header-name cannot be combined"; + case PARAM_READ_ERROR: + return "error encountered when reading a file"; + case PARAM_EXPAND_ERROR: + return "variable expansion failure"; + case PARAM_BLANK_STRING: + return "blank argument where content is expected"; + default: + return "unknown error"; + } +} + +int SetHTTPrequest(struct OperationConfig *config, HttpReq req, HttpReq *store) +{ + /* this mirrors the HttpReq enum in tool_sdecls.h */ + const char *reqname[]= { + "", /* unspec */ + "GET (-G, --get)", + "HEAD (-I, --head)", + "multipart formpost (-F, --form)", + "POST (-d, --data)", + "PUT (-T, --upload-file)" + }; + + if((*store == HTTPREQ_UNSPEC) || + (*store == req)) { + *store = req; + return 0; + } + warnf(config->global, "You can only select one HTTP request method! " + "You asked for both %s and %s.", + reqname[req], reqname[*store]); + + return 1; +} + +void customrequest_helper(struct OperationConfig *config, HttpReq req, + char *method) +{ + /* this mirrors the HttpReq enum in tool_sdecls.h */ + const char *dflt[]= { + "GET", + "GET", + "HEAD", + "POST", + "POST", + "PUT" + }; + + if(!method) + ; + else if(curl_strequal(method, dflt[req])) { + notef(config->global, "Unnecessary use of -X or --request, %s is already " + "inferred.", dflt[req]); + } + else if(curl_strequal(method, "head")) { + warnf(config->global, + "Setting custom HTTP method to HEAD with -X/--request may not work " + "the way you want. Consider using -I/--head instead."); + } +} diff --git a/src/tool_helpers.h b/src/tool_helpers.h new file mode 100644 index 0000000..2cfbad2 --- /dev/null +++ b/src/tool_helpers.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_HELPERS_H +#define HEADER_CURL_TOOL_HELPERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +const char *param2text(int res); + +int SetHTTPrequest(struct OperationConfig *config, HttpReq req, + HttpReq *store); + +void customrequest_helper(struct OperationConfig *config, HttpReq req, + char *method); + +#endif /* HEADER_CURL_TOOL_HELPERS_H */ diff --git a/src/tool_hugehelp.c b/src/tool_hugehelp.c new file mode 100644 index 0000000..43dd6d3 --- /dev/null +++ b/src/tool_hugehelp.c @@ -0,0 +1,13502 @@ +#include "tool_setup.h" +#ifndef HAVE_LIBZ +/* + * NEVER EVER edit this manually, fix the mkhelp.pl script instead! + */ +#ifdef USE_MANUAL +#include "tool_hugehelp.h" +void hugehelp(void) +{ + fputs( +" _ _ ____ _\n" +" Project ___| | | | _ \\| |\n" +" / __| | | | |_) | |\n" +" | (__| |_| | _ <| |___\n" +" \\___|\\___/|_| \\_\\_____|\n" +"\n" +"NAME\n" +" curl - transfer a URL\n" +"\n" +"SYNOPSIS\n" +" curl [options / URLs]\n" +"\n" +"DESCRIPTION\n" +" curl is a tool for transferring data from or to a server using URLs. It\n" +" supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP,\n" +, stdout); + fputs( +" HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP,\n" +" SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.\n" +"\n" +" curl is powered by libcurl for all transfer-related features. See\n" +" libcurl(3) for details.\n" +"\n" +"URL\n" +" The URL syntax is protocol-dependent. You find a detailed description\n" +" in RFC 3986.\n" +"\n" +" If you provide a URL without a leading protocol:// scheme, curl guesses\n" +, stdout); + fputs( +" what protocol you want. It then defaults to HTTP but assumes others\n" +" based on often-used host name prefixes. For example, for host names\n" +" starting with \"ftp.\" curl assumes you want FTP.\n" +"\n" +" You can specify any amount of URLs on the command line. They are\n" +" fetched in a sequential manner in the specified order unless you use\n" +" -Z, --parallel. You can specify command line options and URLs mixed and\n" +" in any order on the command line.\n" +"\n" +, stdout); + fputs( +" curl attempts to reuse connections when doing multiple transfers, so\n" +" that getting many files from the same server do not use multiple con-\n" +" nects and setup handshakes. This improves speed. Connection reuse can\n" +" only be done for URLs specified for a single command line invocation\n" +" and cannot be performed between separate curl runs.\n" +"\n" +" Provide an IPv6 zone id in the URL with an escaped percentage sign.\n" +" Like in\n" +"\n" +, stdout); + fputs( +" \"http://[fe80::3%25eth0]/\"\n" +"\n" +" Everything provided on the command line that is not a command line op-\n" +" tion or its argument, curl assumes is a URL and treats it as such.\n" +"\n" +"GLOBBING\n" +" You can specify multiple URLs or parts of URLs by writing lists within\n" +" braces or ranges within brackets. We call this \"globbing\".\n" +"\n" +" Provide a list with three different names like this:\n" +"\n" +" \"http://site.{one,two,three}.com\"\n" +"\n" +, stdout); + fputs( +" Do sequences of alphanumeric series by using [] as in:\n" +"\n" +" \"ftp://ftp.example.com/file[1-100].txt\"\n" +"\n" +" With leading zeroes:\n" +"\n" +" \"ftp://ftp.example.com/file[001-100].txt\"\n" +"\n" +" With letters through the alphabet:\n" +"\n" +" \"ftp://ftp.example.com/file[a-z].txt\"\n" +"\n" +" Nested sequences are not supported, but you can use several ones next\n" +" to each other:\n" +"\n" +" \"http://example.com/archive[1996-1999]/vol[1-4]/part{a,b,c}.html\"\n" +"\n" +, stdout); + fputs( +" You can specify a step counter for the ranges to get every Nth number\n" +" or letter:\n" +"\n" +" \"http://example.com/file[1-100:10].txt\"\n" +"\n" +" \"http://example.com/file[a-z:2].txt\"\n" +"\n" +" When using [] or {} sequences when invoked from a command line prompt,\n" +" you probably have to put the full URL within double quotes to avoid the\n" +" shell from interfering with it. This also goes for other characters\n" +" treated special, like for example '&', '?' and '*'.\n" +"\n" +, stdout); + fputs( +" Switch off globbing with -g, --globoff.\n" +"\n" +"VARIABLES\n" +" curl supports command line variables (added in 8.3.0). Set variables\n" +" with --variable name=content or --variable name@file (where \"file\" can\n" +" be stdin if set to a single dash (-)).\n" +"\n" +" Variable contents can be expanded in option parameters using \"{{name}}\"\n" +" (without the quotes) if the option name is prefixed with \"--expand-\".\n" +" This gets the contents of the variable \"name\" inserted, or a blank if\n" +, stdout); + fputs( +" the name does not exist as a variable. Insert \"{{\" verbatim in the\n" +" string by prefixing it with a backslash, like \"\\{{\".\n" +"\n" +" You an access and expand environment variables by first importing them.\n" +" You can select to either require the environment variable to be set or\n" +" you can provide a default value in case it is not already set. Plain\n" +" --variable %name imports the variable called 'name' but exits with an\n" +, stdout); + fputs( +" error if that environment variable is not already set. To provide a de-\n" +" fault value if it is not set, use --variable %name=content or --vari-\n" +" able %name@content.\n" +"\n" +" Example. Get the USER environment variable into the URL, fail if USER\n" +" is not set:\n" +"\n" +" --variable '%USER'\n" +" --expand-url = \"https://example.com/api/{{USER}}/method\"\n" +"\n" +" When expanding variables, curl supports a set of functions that can\n" +, stdout); + fputs( +" make the variable contents more convenient to use. It can trim leading\n" +" and trailing white space with trim, it can output the contents as a\n" +" JSON quoted string with json, URL encode the string with url or base64\n" +" encode it with b64. You apply function to a variable expansion, add\n" +" them colon separated to the right side of the variable. Variable con-\n" +" tent holding null bytes that are not encoded when expanded cause error.\n" +, stdout); + fputs( +" Example: get the contents of a file called $HOME/.secret into a vari-\n" +" able called \"fix\". Make sure that the content is trimmed and per-\n" +" cent-encoded sent as POST data:\n" +"\n" +" --variable %HOME\n" +" --expand-variable fix@{{HOME}}/.secret\n" +" --expand-data \"{{fix:trim:url}}\"\n" +" https://example.com/\n" +"\n" +" Command line variables and expansions were added in in 8.3.0.\n" +"\n" +"OUTPUT\n" +" If not told otherwise, curl writes the received data to stdout. It can\n" +, stdout); + fputs( +" be instructed to instead save that data into a local file, using the\n" +" -o, --output or -O, --remote-name options. If curl is given multiple\n" +" URLs to transfer on the command line, it similarly needs multiple op-\n" +" tions for where to save them.\n" +"\n" +" curl does not parse or otherwise \"understand\" the content it gets or\n" +" writes as output. It does no encoding or decoding, unless explicitly\n" +" asked to with dedicated command line options.\n" +"\n" +"PROTOCOLS\n" +, stdout); + fputs( +" curl supports numerous protocols, or put in URL terms: schemes. Your\n" +" particular build may not support them all.\n" +"\n" +" DICT Lets you lookup words using online dictionaries.\n" +"\n" +" FILE Read or write local files. curl does not support accessing\n" +" file:// URL remotely, but when running on Microsoft Windows us-\n" +" ing the native UNC approach works.\n" +"\n" +" FTP(S) curl supports the File Transfer Protocol with a lot of tweaks\n" +, stdout); + fputs( +" and levers. With or without using TLS.\n" +"\n" +" GOPHER(S)\n" +" Retrieve files.\n" +"\n" +" HTTP(S)\n" +" curl supports HTTP with numerous options and variations. It can\n" +" speak HTTP version 0.9, 1.0, 1.1, 2 and 3 depending on build op-\n" +" tions and the correct command line options.\n" +"\n" +" IMAP(S)\n" +" Using the mail reading protocol, curl can \"download\" emails for\n" +" you. With or without using TLS.\n" +"\n" +" LDAP(S)\n" +, stdout); + fputs( +" curl can do directory lookups for you, with or without TLS.\n" +"\n" +" MQTT curl supports MQTT version 3. Downloading over MQTT equals \"sub-\n" +" scribe\" to a topic while uploading/posting equals \"publish\" on a\n" +" topic. MQTT over TLS is not supported (yet).\n" +"\n" +" POP3(S)\n" +" Downloading from a pop3 server means getting a mail. With or\n" +" without using TLS.\n" +"\n" +" RTMP(S)\n" +, stdout); + fputs( +" The Realtime Messaging Protocol is primarily used to serve\n" +" streaming media and curl can download it.\n" +"\n" +" RTSP curl supports RTSP 1.0 downloads.\n" +"\n" +" SCP curl supports SSH version 2 scp transfers.\n" +"\n" +" SFTP curl supports SFTP (draft 5) done over SSH version 2.\n" +"\n" +" SMB(S) curl supports SMB version 1 for upload and download.\n" +"\n" +" SMTP(S)\n" +" Uploading contents to an SMTP server means sending an email.\n" +, stdout); + fputs( +" With or without TLS.\n" +"\n" +" TELNET Telling curl to fetch a telnet URL starts an interactive session\n" +" where it sends what it reads on stdin and outputs what the\n" +" server sends it.\n" +"\n" +" TFTP curl can do TFTP downloads and uploads.\n" +"\n" +"PROGRESS METER\n" +" curl normally displays a progress meter during operations, indicating\n" +" the amount of transferred data, transfer speeds and estimated time\n" +, stdout); + fputs( +" left, etc. The progress meter displays the transfer rate in bytes per\n" +" second. The suffixes (k, M, G, T, P) are 1024 based. For example 1k is\n" +" 1024 bytes. 1M is 1048576 bytes.\n" +"\n" +" curl displays this data to the terminal by default, so if you invoke\n" +" curl to do an operation and it is about to write data to the terminal,\n" +" it disables the progress meter as otherwise it would mess up the output\n" +" mixing progress meter and response data.\n" +"\n" +, stdout); + fputs( +" If you want a progress meter for HTTP POST or PUT requests, you need to\n" +" redirect the response output to a file, using shell redirect (>), -o,\n" +" --output or similar.\n" +"\n" +" This does not apply to FTP upload as that operation does not spit out\n" +" any response data to the terminal.\n" +"\n" +" If you prefer a progress \"bar\" instead of the regular meter, -#,\n" +" --progress-bar is your friend. You can also disable the progress meter\n" +, stdout); + fputs( +" completely with the -s, --silent option.\n" +"\n" +"VERSION\n" +" This man page describes curl %VERSION. If you use a later version,\n" +" chances are this man page does not fully document it. If you use an\n" +" earlier version, this document tries to include version information\n" +" about which specific version that introduced changes.\n" +"\n" +" You can always learn which the latest curl version is by running\n" +"\n" +" curl https://curl.se/info\n" +"\n" +, stdout); + fputs( +" The online version of this man page is always showing the latest incar-\n" +" nation: https://curl.se/docs/manpage.html\n" +"\n" +"OPTIONS\n" +" Options start with one or two dashes. Many of the options require an\n" +" additional value next to them. If provided text does not start with a\n" +" dash, it is presumed to be and treated as a URL.\n" +"\n" +" The short \"single-dash\" form of the options, -d for example, may be\n" +, stdout); + fputs( +" used with or without a space between it and its value, although a space\n" +" is a recommended separator. The long \"double-dash\" form, -d, --data for\n" +" example, requires a space between it and its value.\n" +"\n" +" Short version options that do not need any additional values can be\n" +" used immediately next to each other, like for example you can specify\n" +" all the options -O, -L and -v at once as -OLv.\n" +"\n" +, stdout); + fputs( +" In general, all boolean options are enabled with --option and yet again\n" +" disabled with --no-option. That is, you use the same option name but\n" +" prefix it with \"no-\". However, in this list we mostly only list and\n" +" show the --option version of them.\n" +"\n" +" When -:, --next is used, it resets the parser state and you start again\n" +" with a clean option state, except for the options that are \"global\".\n" +, stdout); + fputs( +" Global options retain their values and meaning even after -:, --next.\n" +"\n" +" The following options are global: --fail-early, --libcurl, --paral-\n" +" lel-immediate, -Z, --parallel, -#, --progress-bar, --rate, -S,\n" +" --show-error, --stderr, --styled-output, --trace-ascii, --trace-config,\n" +" --trace-ids, --trace-time, --trace and -v, --verbose.\n" +"\n" +" --abstract-unix-socket \n" +" (HTTP) Connect through an abstract Unix domain socket, instead\n" +, stdout); + fputs( +" of using the network. Note: netstat shows the path of an ab-\n" +" stract socket prefixed with '@', however the argument\n" +" should not have this leading character.\n" +"\n" +" If --abstract-unix-socket is provided several times, the last\n" +" set value is used.\n" +"\n" +" Example:\n" +" curl --abstract-unix-socket socketpath https://example.com\n" +"\n" +" See also --unix-socket. Added in 7.53.0.\n" +"\n" +, stdout); + fputs( +" --alt-svc \n" +" (HTTPS) This option enables the alt-svc parser in curl. If the\n" +" file name points to an existing alt-svc cache file, that gets\n" +" used. After a completed transfer, the cache is saved to the file\n" +" name again if it has been modified.\n" +"\n" +" Specify a \"\" file name (zero length) to avoid loading/saving and\n" +" make curl just handle the cache in memory.\n" +"\n" +, stdout); + fputs( +" If this option is used several times, curl loads contents from\n" +" all the files but the last one is used for saving.\n" +"\n" +" --alt-svc can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --alt-svc svc.txt https://example.com\n" +"\n" +" See also --resolve and --connect-to. Added in 7.64.1.\n" +"\n" +" --anyauth\n" +" (HTTP) Tells curl to figure out authentication method by itself,\n" +, stdout); + fputs( +" and use the most secure one the remote site claims to support.\n" +" This is done by first doing a request and checking the re-\n" +" sponse-headers, thus possibly inducing an extra network\n" +" round-trip. This is used instead of setting a specific authenti-\n" +" cation method, which you can do with --basic, --digest, --ntlm,\n" +" and --negotiate.\n" +"\n" +, stdout); + fputs( +" Using --anyauth is not recommended if you do uploads from stdin,\n" +" since it may require data to be sent twice and then the client\n" +" must be able to rewind. If the need should arise when uploading\n" +" from stdin, the upload operation fails.\n" +"\n" +" Used together with -u, --user.\n" +"\n" +" Providing --anyauth multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --anyauth --user me:pwd https://example.com\n" +"\n" +, stdout); + fputs( +" See also --proxy-anyauth, --basic and --digest.\n" +"\n" +" -a, --append\n" +" (FTP SFTP) When used in an upload, this option makes curl append\n" +" to the target file instead of overwriting it. If the remote file\n" +" does not exist, it is created. Note that this flag is ignored by\n" +" some SFTP servers (including OpenSSH).\n" +"\n" +" Providing --append multiple times has no extra effect. Disable\n" +" it again with --no-append.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --upload-file local --append ftp://example.com/\n" +"\n" +" See also -r, --range and -C, --continue-at.\n" +"\n" +" --aws-sigv4 \n" +" (HTTP) Use AWS V4 signature authentication in the transfer.\n" +"\n" +" The provider argument is a string that is used by the algorithm\n" +" when creating outgoing authentication headers.\n" +"\n" +, stdout); + fputs( +" The region argument is a string that points to a geographic area\n" +" of a resources collection (region-code) when the region name is\n" +" omitted from the endpoint.\n" +"\n" +" The service argument is a string that points to a function pro-\n" +" vided by a cloud (service-code) when the service name is omitted\n" +" from the endpoint.\n" +"\n" +" If --aws-sigv4 is provided several times, the last set value is\n" +" used.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --aws-sigv4 \"aws:amz:us-east-2:es\" --user \"key:secret\" https://example.com\n" +"\n" +" See also --basic and -u, --user. Added in 7.75.0.\n" +"\n" +" --basic\n" +" (HTTP) Tells curl to use HTTP Basic authentication with the re-\n" +" mote host. This is the default and this option is usually point-\n" +" less, unless you use it to override a previously set option that\n" +, stdout); + fputs( +" sets a different authentication method (such as --ntlm, --di-\n" +" gest, or --negotiate).\n" +"\n" +" Used together with -u, --user.\n" +"\n" +" Providing --basic multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl -u name:password --basic https://example.com\n" +"\n" +" See also --proxy-basic.\n" +"\n" +" --ca-native\n" +" (TLS) Tells curl to use the CA store from the native operating\n" +, stdout); + fputs( +" system to verify the peer. By default, curl otherwise uses a CA\n" +" store provided in a single file or directory, but when using\n" +" this option it interfaces the operating system's own vault.\n" +"\n" +" This option works for curl on Windows when built to use OpenSSL,\n" +" wolfSSL (added in 8.3.0) or GnuTLS (added in 8.5.0). When curl\n" +" on Windows is built to use Schannel, this feature is implied and\n" +, stdout); + fputs( +" curl then only uses the native CA store.\n" +"\n" +" Providing --ca-native multiple times has no extra effect. Dis-\n" +" able it again with --no-ca-native.\n" +"\n" +" Example:\n" +" curl --ca-native https://example.com\n" +"\n" +" See also --cacert, --capath and -k, --insecure. Added in 8.2.0.\n" +"\n" +" --cacert \n" +" (TLS) Tells curl to use the specified certificate file to verify\n" +, stdout); + fputs( +" the peer. The file may contain multiple CA certificates. The\n" +" certificate(s) must be in PEM format. Normally curl is built to\n" +" use a default file for this, so this option is typically used to\n" +" alter that default file.\n" +"\n" +" curl recognizes the environment variable named 'CURL_CA_BUNDLE'\n" +" if it is set and the TLS backend is not Schannel, and uses the\n" +, stdout); + fputs( +" given path as a path to a CA cert bundle. This option overrides\n" +" that variable.\n" +"\n" +" The windows version of curl automatically looks for a CA certs\n" +" file named 'curl-ca-bundle.crt', either in the same directory as\n" +" curl.exe, or in the Current Working Directory, or in any folder\n" +" along your PATH.\n" +"\n" +" (iOS and macOS only) If curl is built against Secure Transport,\n" +, stdout); + fputs( +" then this option is supported for backward compatibility with\n" +" other SSL engines, but it should not be set. If the option is\n" +" not set, then curl uses the certificates in the system and user\n" +" Keychain to verify the peer, which is the preferred method of\n" +" verifying the peer's certificate chain.\n" +"\n" +" (Schannel only) This option is supported for Schannel in Windows\n" +, stdout); + fputs( +" 7 or later (added in 7.60.0). This option is supported for back-\n" +" ward compatibility with other SSL engines; instead it is recom-\n" +" mended to use Windows' store of root certificates (the default\n" +" for Schannel).\n" +"\n" +" If --cacert is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --cacert CA-file.txt https://example.com\n" +"\n" +, stdout); + fputs( +" See also --capath and -k, --insecure.\n" +"\n" +" --capath \n" +" (TLS) Tells curl to use the specified certificate directory to\n" +" verify the peer. Multiple paths can be provided by separating\n" +" them with \":\" (e.g. \"path1:path2:path3\"). The certificates must\n" +" be in PEM format, and if curl is built against OpenSSL, the di-\n" +" rectory must have been processed using the c_rehash utility sup-\n" +, stdout); + fputs( +" plied with OpenSSL. Using --capath can allow OpenSSL-powered\n" +" curl to make SSL-connections much more efficiently than using\n" +" --cacert if the --cacert file contains many CA certificates.\n" +"\n" +" If this option is set, the default capath value is ignored.\n" +"\n" +" If --capath is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --capath /local/directory https://example.com\n" +"\n" +, stdout); + fputs( +" See also --cacert and -k, --insecure.\n" +"\n" +" --cert-status\n" +" (TLS) Tells curl to verify the status of the server certificate\n" +" by using the Certificate Status Request (aka. OCSP stapling) TLS\n" +" extension.\n" +"\n" +" If this option is enabled and the server sends an invalid (e.g.\n" +" expired) response, if the response suggests that the server cer-\n" +" tificate has been revoked, or no response at all is received,\n" +, stdout); + fputs( +" the verification fails.\n" +"\n" +" This is currently only implemented in the OpenSSL and GnuTLS\n" +" backends.\n" +"\n" +" Providing --cert-status multiple times has no extra effect.\n" +" Disable it again with --no-cert-status.\n" +"\n" +" Example:\n" +" curl --cert-status https://example.com\n" +"\n" +" See also --pinnedpubkey.\n" +"\n" +" --cert-type \n" +" (TLS) Tells curl what type the provided client certificate is\n" +, stdout); + fputs( +" using. PEM, DER, ENG and P12 are recognized types.\n" +"\n" +" The default type depends on the TLS backend and is usually PEM,\n" +" however for Secure Transport and Schannel it is P12. If -E,\n" +" --cert is a pkcs11: URI then ENG is the default type.\n" +"\n" +" If --cert-type is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --cert-type PEM --cert file https://example.com\n" +"\n" +, stdout); + fputs( +" See also -E, --cert, --key and --key-type.\n" +"\n" +" -E, --cert \n" +" (TLS) Tells curl to use the specified client certificate file\n" +" when getting a file with HTTPS, FTPS or another SSL-based proto-\n" +" col. The certificate must be in PKCS#12 format if using Secure\n" +" Transport, or PEM format if using any other engine. If the op-\n" +" tional password is not specified, it is queried for on the ter-\n" +, stdout); + fputs( +" minal. Note that this option assumes a certificate file that is\n" +" the private key and the client certificate concatenated. See -E,\n" +" --cert and --key to specify them independently.\n" +"\n" +" In the portion of the argument, you must escape\n" +" the character \":\" as \"\\:\" so that it is not recognized as the\n" +" password delimiter. Similarly, you must escape the double quote\n" +, stdout); + fputs( +" character as \\\" so that it is not recognized as an escape char-\n" +" acter.\n" +"\n" +" If curl is built against OpenSSL library, and the engine pkcs11\n" +" is available, then a PKCS#11 URI (RFC 7512) can be used to spec-\n" +" ify a certificate located in a PKCS#11 device. A string begin-\n" +" ning with \"pkcs11:\" is interpreted as a PKCS#11 URI. If a\n" +" PKCS#11 URI is provided, then the --engine option is set as\n" +, stdout); + fputs( +" \"pkcs11\" if none was provided and the --cert-type option is set\n" +" as \"ENG\" if none was provided.\n" +"\n" +" (iOS and macOS only) If curl is built against Secure Transport,\n" +" then the certificate string can either be the name of a certifi-\n" +" cate/private key in the system or user keychain, or the path to\n" +" a PKCS#12-encoded certificate and private key. If you want to\n" +, stdout); + fputs( +" use a file from the current directory, please precede it with\n" +" \"./\" prefix, in order to avoid confusion with a nickname.\n" +"\n" +" (Schannel only) Client certificates must be specified by a path\n" +" expression to a certificate store. (Loading PFX is not sup-\n" +" ported; you can import it to a store first). You can use \"\\\\\" to refer to a certificate\n" +, stdout); + fputs( +" in the system certificates store, for example, \"Curren-\n" +" tUser\\MY\\934a7ac6f8a5d579285a74fa61e19f23ddfe8d7a\". Thumbprint\n" +" is usually a SHA-1 hex string which you can see in certificate\n" +" details. Following store locations are supported: CurrentUser,\n" +" LocalMachine, CurrentService, Services, CurrentUserGroupPolicy,\n" +" LocalMachineGroupPolicy and LocalMachineEnterprise.\n" +"\n" +, stdout); + fputs( +" If --cert is provided several times, the last set value is used.\n" +"\n" +" Example:\n" +" curl --cert certfile --key keyfile https://example.com\n" +"\n" +" See also --cert-type, --key and --key-type.\n" +"\n" +" --ciphers \n" +" (TLS) Specifies which ciphers to use in the connection. The list\n" +" of ciphers must specify valid ciphers. Read up on SSL cipher\n" +" list details on this URL:\n" +"\n" +, stdout); + fputs( +" https://curl.se/docs/ssl-ciphers.html\n" +"\n" +" If --ciphers is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --ciphers ECDHE-ECDSA-AES256-CCM8 https://example.com\n" +"\n" +" See also --tlsv1.3, --tls13-ciphers and --proxy-ciphers.\n" +"\n" +" --compressed-ssh\n" +" (SCP SFTP) Enables built-in SSH compression. This is a request,\n" +" not an order; the server may or may not do it.\n" +"\n" +, stdout); + fputs( +" Providing --compressed-ssh multiple times has no extra effect.\n" +" Disable it again with --no-compressed-ssh.\n" +"\n" +" Example:\n" +" curl --compressed-ssh sftp://example.com/\n" +"\n" +" See also --compressed. Added in 7.56.0.\n" +"\n" +" --compressed\n" +" (HTTP) Request a compressed response using one of the algorithms\n" +" curl supports, and automatically decompress the content.\n" +"\n" +, stdout); + fputs( +" Response headers are not modified when saved, so if they are\n" +" \"interpreted\" separately again at a later point they might ap-\n" +" pear to be saying that the content is (still) compressed; while\n" +" in fact it has already been decompressed.\n" +"\n" +" If this option is used and the server sends an unsupported en-\n" +" coding, curl reports an error. This is a request, not an order;\n" +, stdout); + fputs( +" the server may or may not deliver data compressed.\n" +"\n" +" Providing --compressed multiple times has no extra effect. Dis-\n" +" able it again with --no-compressed.\n" +"\n" +" Example:\n" +" curl --compressed https://example.com\n" +"\n" +" See also --compressed-ssh.\n" +"\n" +" -K, --config \n" +" Specify a text file to read curl arguments from. The command\n" +" line arguments found in the text file are used as if they were\n" +, stdout); + fputs( +" provided on the command line.\n" +"\n" +" Options and their parameters must be specified on the same line\n" +" in the file, separated by whitespace, colon, or the equals sign.\n" +" Long option names can optionally be given in the config file\n" +" without the initial double dashes and if so, the colon or equals\n" +" characters can be used as separators. If the option is specified\n" +, stdout); + fputs( +" with one or two dashes, there can be no colon or equals charac-\n" +" ter between the option and its parameter.\n" +"\n" +" If the parameter contains whitespace or starts with a colon (:)\n" +" or equals sign (=), it must be specified enclosed within double\n" +" quotes (\"). Within double quotes the following escape sequences\n" +" are available: \\\\, \\\", \\t, \\n, \\r and \\v. A backslash preceding\n" +" any other letter is ignored.\n" +"\n" +, stdout); + fputs( +" If the first non-blank column of a config line is a '#' charac-\n" +" ter, that line is treated as a comment.\n" +"\n" +" Only write one option per physical line in the config file. A\n" +" single line is required to be no more than 10 megabytes (since\n" +" 8.2.0).\n" +"\n" +" Specify the filename to -K, --config as '-' to make curl read\n" +" the file from stdin.\n" +"\n" +, stdout); + fputs( +" Note that to be able to specify a URL in the config file, you\n" +" need to specify it using the --url option, and not by simply\n" +" writing the URL on its own line. So, it could look similar to\n" +" this:\n" +"\n" +" url = \"https://curl.se/docs/\"\n" +"\n" +" # --- Example file ---\n" +" # this is a comment\n" +" url = \"example.com\"\n" +" output = \"curlhere.html\"\n" +" user-agent = \"superagent/1.0\"\n" +"\n" +, stdout); + fputs( +" # and fetch another URL too\n" +" url = \"example.com/docs/manpage.html\"\n" +" -O\n" +" referer = \"http://nowhereatall.example.com/\"\n" +" # --- End of example file ---\n" +"\n" +" When curl is invoked, it (unless -q, --disable is used) checks\n" +" for a default config file and uses it if found, even when -K,\n" +" --config is used. The default config file is checked for in the\n" +" following places in this order:\n" +"\n" +, stdout); + fputs( +" 1) \"$CURL_HOME/.curlrc\"\n" +"\n" +" 2) \"$XDG_CONFIG_HOME/curlrc\" (Added in 7.73.0)\n" +"\n" +" 3) \"$HOME/.curlrc\"\n" +"\n" +" 4) Windows: \"%USERPROFILE%\\.curlrc\"\n" +"\n" +" 5) Windows: \"%APPDATA%\\.curlrc\"\n" +"\n" +" 6) Windows: \"%USERPROFILE%\\Application Data\\.curlrc\"\n" +"\n" +" 7) Non-Windows: use getpwuid to find the home directory\n" +"\n" +" 8) On Windows, if it finds no .curlrc file in the sequence de-\n" +, stdout); + fputs( +" scribed above, it checks for one in the same dir the curl exe-\n" +" cutable is placed.\n" +"\n" +" On Windows two filenames are checked per location: .curlrc and\n" +" _curlrc, preferring the former. Older versions on Windows\n" +" checked for _curlrc only.\n" +"\n" +" --config can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --config file.txt https://example.com\n" +"\n" +" See also -q, --disable.\n" +, stdout); + fputs( +"\n" +" --connect-timeout \n" +" Maximum time in seconds that you allow curl's connection to\n" +" take. This only limits the connection phase, so if curl connects\n" +" within the given period it continues - if not it exits.\n" +"\n" +" This option accepts decimal values. The decimal value needs to\n" +" be provided using a dot (.) as decimal separator - not the local\n" +, stdout); + fputs( +" version even if it might be using another separator.\n" +"\n" +" The connection phase is considered complete when the DNS lookup\n" +" and requested TCP, TLS or QUIC handshakes are done.\n" +"\n" +" If --connect-timeout is provided several times, the last set\n" +" value is used.\n" +"\n" +" Examples:\n" +" curl --connect-timeout 20 https://example.com\n" +" curl --connect-timeout 3.14 https://example.com\n" +"\n" +, stdout); + fputs( +" See also -m, --max-time.\n" +"\n" +" --connect-to \n" +" For a request to the given \"HOST1:PORT1\" pair, connect to\n" +" \"HOST2:PORT2\" instead. This option is suitable to direct re-\n" +" quests at a specific server, e.g. at a specific cluster node in\n" +" a cluster of servers. This option is only used to establish the\n" +" network connection. It does NOT affect the hostname/port that is\n" +, stdout); + fputs( +" used for TLS/SSL (e.g. SNI, certificate verification) or for the\n" +" application protocols. \"HOST1\" and \"PORT1\" may be the empty\n" +" string, meaning \"any host/port\". \"HOST2\" and \"PORT2\" may also be\n" +" the empty string, meaning \"use the request's original\n" +" host/port\".\n" +"\n" +" A hostname specified to this option is compared as a string, so\n" +, stdout); + fputs( +" it needs to match the name used in request URL. It can be either\n" +" numerical such as \"127.0.0.1\" or the full host name such as \"ex-\n" +" ample.org\".\n" +"\n" +" --connect-to can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --connect-to example.com:443:example.net:8443 https://example.com\n" +"\n" +" See also --resolve and -H, --header.\n" +"\n" +" -C, --continue-at \n" +, stdout); + fputs( +" Continue/Resume a previous file transfer at the given offset.\n" +" The given offset is the exact number of bytes that are skipped,\n" +" counting from the beginning of the source file before it is\n" +" transferred to the destination. If used with uploads, the FTP\n" +" server command SIZE is not used by curl.\n" +"\n" +" Use \"-C -\" to tell curl to automatically find out where/how to\n" +, stdout); + fputs( +" resume the transfer. It then uses the given output/input files\n" +" to figure that out.\n" +"\n" +" If --continue-at is provided several times, the last set value\n" +" is used.\n" +"\n" +" Examples:\n" +" curl -C - https://example.com\n" +" curl -C 400 https://example.com\n" +"\n" +" See also -r, --range.\n" +"\n" +" -c, --cookie-jar \n" +" (HTTP) Specify to which file you want curl to write all cookies\n" +, stdout); + fputs( +" after a completed operation. Curl writes all cookies from its\n" +" in-memory cookie storage to the given file at the end of opera-\n" +" tions. If no cookies are known, no data is written. The file is\n" +" created using the Netscape cookie file format. If you set the\n" +" file name to a single dash, \"-\", the cookies are written to std-\n" +" out.\n" +"\n" +" The file specified with -c, --cookie-jar is only used for out-\n" +, stdout); + fputs( +" put. No cookies are read from the file. To read cookies, use the\n" +" -b, --cookie option. Both options can specify the same file.\n" +"\n" +" This command line option activates the cookie engine that makes\n" +" curl record and use cookies. The -b, --cookie option also acti-\n" +" vates it.\n" +"\n" +" If the cookie jar cannot be created or written to, the whole\n" +" curl operation does not fail or even report an error clearly.\n" +, stdout); + fputs( +" Using -v, --verbose gets a warning displayed, but that is the\n" +" only visible feedback you get about this possibly lethal situa-\n" +" tion.\n" +"\n" +" If --cookie-jar is provided several times, the last set value is\n" +" used.\n" +"\n" +" Examples:\n" +" curl -c store-here.txt https://example.com\n" +" curl -c store-here.txt -b read-these https://example.com\n" +"\n" +" See also -b, --cookie.\n" +"\n" +, stdout); + fputs( +" -b, --cookie \n" +" (HTTP) Pass the data to the HTTP server in the Cookie header. It\n" +" is supposedly the data previously received from the server in a\n" +" \"Set-Cookie:\" line. The data should be in the format\n" +" \"NAME1=VALUE1; NAME2=VALUE2\". This makes curl use the cookie\n" +" header with this content explicitly in all outgoing request(s).\n" +, stdout); + fputs( +" If multiple requests are done due to authentication, followed\n" +" redirects or similar, they all get this cookie passed on.\n" +"\n" +" If no '=' symbol is used in the argument, it is instead treated\n" +" as a filename to read previously stored cookie from. This option\n" +" also activates the cookie engine which makes curl record incom-\n" +" ing cookies, which may be handy if you are using this in combi-\n" +, stdout); + fputs( +" nation with the -L, --location option or do multiple URL trans-\n" +" fers on the same invoke.\n" +"\n" +" If the file name is exactly a minus (\"-\"), curl instead reads\n" +" the contents from stdin. If the file name is an empty string\n" +" (\"\") and is the only cookie input, curl will activate the cookie\n" +" engine without any cookies.\n" +"\n" +" The file format of the file to read cookies from should be plain\n" +, stdout); + fputs( +" HTTP headers (Set-Cookie style) or the Netscape/Mozilla cookie\n" +" file format.\n" +"\n" +" The file specified with -b, --cookie is only used as input. No\n" +" cookies are written to the file. To store cookies, use the -c,\n" +" --cookie-jar option.\n" +"\n" +" If you use the Set-Cookie file format and do not specify a do-\n" +" main then the cookie is not sent since the domain never matches.\n" +, stdout); + fputs( +" To address this, set a domain in Set-Cookie line (doing that in-\n" +" cludes subdomains) or preferably: use the Netscape format.\n" +"\n" +" Users often want to both read cookies from a file and write up-\n" +" dated cookies back to a file, so using both -b, --cookie and -c,\n" +" --cookie-jar in the same command line is common.\n" +"\n" +" If curl is built with PSL (Public Suffix List) support, it de-\n" +, stdout); + fputs( +" tects and discards cookies that are specified for such suffix\n" +" domains that should not be allowed to have cookies. If curl is\n" +" not built with PSL support, it has no ability to stop super\n" +" cookies.\n" +"\n" +" --cookie can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl -b \"\" https://example.com\n" +" curl -b cookiefile https://example.com\n" +, stdout); + fputs( +" curl -b cookiefile -c cookiefile https://example.com\n" +"\n" +" See also -c, --cookie-jar and -j, --junk-session-cookies.\n" +"\n" +" --create-dirs\n" +" When used in conjunction with the -o, --output option, curl cre-\n" +" ates the necessary local directory hierarchy as needed. This op-\n" +" tion creates the directories mentioned with the -o, --output op-\n" +" tion combined with the path possibly set with --output-dir. If\n" +, stdout); + fputs( +" the combined output file name uses no directory, or if the di-\n" +" rectories it mentions already exist, no directories are created.\n" +" Created directories are made with mode 0750 on unix style file\n" +" systems.\n" +"\n" +" To create remote directories when using FTP or SFTP, try\n" +" --ftp-create-dirs.\n" +"\n" +" Providing --create-dirs multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-create-dirs.\n" +"\n" +" Example:\n" +" curl --create-dirs --output local/dir/file https://example.com\n" +"\n" +" See also --ftp-create-dirs and --output-dir.\n" +"\n" +" --create-file-mode \n" +" (SFTP SCP FILE) When curl is used to create files remotely using\n" +" one of the supported protocols, this option allows the user to\n" +" set which 'mode' to set on the file at creation time, instead of\n" +, stdout); + fputs( +" the default 0644.\n" +"\n" +" This option takes an octal number as argument.\n" +"\n" +" If --create-file-mode is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --create-file-mode 0777 -T localfile sftp://example.com/new\n" +"\n" +" See also --ftp-create-dirs. Added in 7.75.0.\n" +"\n" +" --crlf (FTP SMTP) Convert line feeds to carriage return plus line feeds\n" +" in upload. Useful for MVS (OS/390).\n" +"\n" +, stdout); + fputs( +" (SMTP added in 7.40.0)\n" +"\n" +" Providing --crlf multiple times has no extra effect. Disable it\n" +" again with --no-crlf.\n" +"\n" +" Example:\n" +" curl --crlf -T file ftp://example.com/\n" +"\n" +" See also -B, --use-ascii.\n" +"\n" +" --crlfile \n" +" (TLS) Provide a file using PEM format with a Certificate Revoca-\n" +" tion List that may specify peer certificates that are to be con-\n" +" sidered revoked.\n" +"\n" +, stdout); + fputs( +" If --crlfile is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --crlfile rejects.txt https://example.com\n" +"\n" +" See also --cacert and --capath.\n" +"\n" +" --curves \n" +" (TLS) Tells curl to request specific curves to use during SSL\n" +" session establishment according to RFC 8422, 5.1. Multiple algo-\n" +, stdout); + fputs( +" rithms can be provided by separating them with \":\" (e.g.\n" +" \"X25519:P-521\"). The parameter is available identically in the\n" +" OpenSSL \"s_client\" and \"s_server\" utilities.\n" +"\n" +" --curves allows a OpenSSL powered curl to make SSL-connections\n" +" with exactly the (EC) curve requested by the client, avoiding\n" +" nontransparent client/server negotiations.\n" +"\n" +, stdout); + fputs( +" If this option is set, the default curves list built into\n" +" OpenSSL are ignored.\n" +"\n" +" If --curves is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --curves X25519 https://example.com\n" +"\n" +" See also --ciphers. Added in 7.73.0.\n" +"\n" +" --data-ascii \n" +" (HTTP) This is just an alias for -d, --data.\n" +"\n" +, stdout); + fputs( +" --data-ascii can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --data-ascii @file https://example.com\n" +"\n" +" See also --data-binary, --data-raw and --data-urlencode.\n" +"\n" +" --data-binary \n" +" (HTTP) This posts data exactly as specified with no extra pro-\n" +" cessing whatsoever.\n" +"\n" +" If you start the data with the letter @, the rest should be a\n" +, stdout); + fputs( +" filename. Data is posted in a similar manner as -d, --data does,\n" +" except that newlines and carriage returns are preserved and con-\n" +" versions are never done.\n" +"\n" +" Like -d, --data the default content-type sent to the server is\n" +" application/x-www-form-urlencoded. If you want the data to be\n" +" treated as arbitrary binary data by the server then set the con-\n" +, stdout); + fputs( +" tent-type to octet-stream: -H \"Content-Type: applica-\n" +" tion/octet-stream\".\n" +"\n" +" If this option is used several times, the ones following the\n" +" first append data as described in -d, --data.\n" +"\n" +" --data-binary can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --data-binary @filename https://example.com\n" +"\n" +" See also --data-ascii.\n" +"\n" +" --data-raw \n" +, stdout); + fputs( +" (HTTP) This posts data similarly to -d, --data but without the\n" +" special interpretation of the @ character.\n" +"\n" +" --data-raw can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl --data-raw \"hello\" https://example.com\n" +" curl --data-raw \"@at@at@\" https://example.com\n" +"\n" +" See also -d, --data.\n" +"\n" +" --data-urlencode \n" +" (HTTP) This posts data, similar to the other -d, --data options\n" +, stdout); + fputs( +" with the exception that this performs URL-encoding.\n" +"\n" +" To be CGI-compliant, the part should begin with a name\n" +" followed by a separator and a content specification. The \n" +" part can be passed to curl using one of the following syntaxes:\n" +"\n" +" content\n" +" This makes curl URL-encode the content and pass that on.\n" +" Just be careful so that the content does not contain any\n" +, stdout); + fputs( +" = or @ symbols, as that makes the syntax match one of the\n" +" other cases below!\n" +"\n" +" =content\n" +" This makes curl URL-encode the content and pass that on.\n" +" The preceding = symbol is not included in the data.\n" +"\n" +" name=content\n" +" This makes curl URL-encode the content part and pass that\n" +" on. Note that the name part is expected to be URL-encoded\n" +, stdout); + fputs( +" already.\n" +"\n" +" @filename\n" +" This makes curl load data from the given file (including\n" +" any newlines), URL-encode that data and pass it on in the\n" +" POST.\n" +"\n" +" name@filename\n" +" This makes curl load data from the given file (including\n" +" any newlines), URL-encode that data and pass it on in the\n" +, stdout); + fputs( +" POST. The name part gets an equal sign appended, result-\n" +" ing in name=urlencoded-file-content. Note that the name\n" +" is expected to be URL-encoded already.\n" +"\n" +" --data-urlencode can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl --data-urlencode name=val https://example.com\n" +" curl --data-urlencode =encodethis https://example.com\n" +, stdout); + fputs( +" curl --data-urlencode name@file https://example.com\n" +" curl --data-urlencode @fileonly https://example.com\n" +"\n" +" See also -d, --data and --data-raw.\n" +"\n" +" -d, --data \n" +" (HTTP MQTT) Sends the specified data in a POST request to the\n" +" HTTP server, in the same way that a browser does when a user has\n" +" filled in an HTML form and presses the submit button. This makes\n" +, stdout); + fputs( +" curl pass the data to the server using the content-type applica-\n" +" tion/x-www-form-urlencoded. Compare to -F, --form.\n" +"\n" +" --data-raw is almost the same but does not have a special inter-\n" +" pretation of the @ character. To post data purely binary, you\n" +" should instead use the --data-binary option. To URL-encode the\n" +" value of a form field you may use --data-urlencode.\n" +"\n" +, stdout); + fputs( +" If any of these options is used more than once on the same com-\n" +" mand line, the data pieces specified are merged with a separat-\n" +" ing &-symbol. Thus, using '-d name=daniel -d skill=lousy' would\n" +" generate a post chunk that looks like 'name=daniel&skill=lousy'.\n" +" If you start the data with the letter @, the rest should be a\n" +" file name to read the data from, or - if you want curl to read\n" +, stdout); + fputs( +" the data from stdin. Posting data from a file named 'foobar'\n" +" would thus be done with -d, --data @foobar. When -d, --data is\n" +" told to read from a file like that, carriage returns and new-\n" +" lines are stripped out. If you do not want the @ character to\n" +" have a special interpretation use --data-raw instead.\n" +"\n" +" The data for this option is passed on to the server exactly as\n" +, stdout); + fputs( +" provided on the command line. curl does not convert, change or\n" +" improve it. It is up to the user to provide the data in the cor-\n" +" rect form.\n" +"\n" +" --data can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl -d \"name=curl\" https://example.com\n" +" curl -d \"name=curl\" -d \"tool=cmdline\" https://example.com\n" +" curl -d @filename https://example.com\n" +"\n" +, stdout); + fputs( +" See also --data-binary, --data-urlencode and --data-raw. This\n" +" option is mutually exclusive to -F, --form and -I, --head and\n" +" -T, --upload-file.\n" +"\n" +" --delegation \n" +" (GSS/kerberos) Set LEVEL to tell the server what it is allowed\n" +" to delegate when it comes to user credentials.\n" +"\n" +" none Do not allow any delegation.\n" +"\n" +" policy Delegates if and only if the OK-AS-DELEGATE flag is set\n" +, stdout); + fputs( +" in the Kerberos service ticket, which is a matter of\n" +" realm policy.\n" +"\n" +" always Unconditionally allow the server to delegate.\n" +"\n" +" If --delegation is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --delegation \"none\" https://example.com\n" +"\n" +" See also -k, --insecure and --ssl.\n" +"\n" +" --digest\n" +, stdout); + fputs( +" (HTTP) Enables HTTP Digest authentication. This is an authenti-\n" +" cation scheme that prevents the password from being sent over\n" +" the wire in clear text. Use this in combination with the normal\n" +" -u, --user option to set user name and password.\n" +"\n" +" Providing --digest multiple times has no extra effect. Disable\n" +" it again with --no-digest.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl -u name:password --digest https://example.com\n" +"\n" +" See also -u, --user, --proxy-digest and --anyauth. This option\n" +" is mutually exclusive to --basic and --ntlm and --negotiate.\n" +"\n" +" --disable-eprt\n" +" (FTP) Tell curl to disable the use of the EPRT and LPRT commands\n" +" when doing active FTP transfers. Curl normally first attempts to\n" +" use EPRT before using PORT, but with this option, it uses PORT\n" +, stdout); + fputs( +" right away. EPRT is an extension to the original FTP protocol,\n" +" and does not work on all servers, but enables more functionality\n" +" in a better way than the traditional PORT command.\n" +"\n" +" --eprt can be used to explicitly enable EPRT again and --no-eprt\n" +" is an alias for --disable-eprt.\n" +"\n" +" If the server is accessed using IPv6, this option has no effect\n" +" as EPRT is necessary then.\n" +"\n" +, stdout); + fputs( +" Disabling EPRT only changes the active behavior. If you want to\n" +" switch to passive mode you need to not use -P, --ftp-port or\n" +" force it with --ftp-pasv.\n" +"\n" +" Providing --disable-eprt multiple times has no extra effect.\n" +" Disable it again with --no-disable-eprt.\n" +"\n" +" Example:\n" +" curl --disable-eprt ftp://example.com/\n" +"\n" +" See also --disable-epsv and -P, --ftp-port.\n" +"\n" +" --disable-epsv\n" +, stdout); + fputs( +" (FTP) Tell curl to disable the use of the EPSV command when do-\n" +" ing passive FTP transfers. Curl normally first attempts to use\n" +" EPSV before PASV, but with this option, it does not try EPSV.\n" +"\n" +" --epsv can be used to explicitly enable EPSV again and --no-epsv\n" +" is an alias for --disable-epsv.\n" +"\n" +" If the server is an IPv6 host, this option has no effect as EPSV\n" +" is necessary then.\n" +"\n" +, stdout); + fputs( +" Disabling EPSV only changes the passive behavior. If you want to\n" +" switch to active mode you need to use -P, --ftp-port.\n" +"\n" +" Providing --disable-epsv multiple times has no extra effect.\n" +" Disable it again with --no-disable-epsv.\n" +"\n" +" Example:\n" +" curl --disable-epsv ftp://example.com/\n" +"\n" +" See also --disable-eprt and -P, --ftp-port.\n" +"\n" +" -q, --disable\n" +, stdout); + fputs( +" If used as the first parameter on the command line, the curlrc\n" +" config file is not read or used. See the -K, --config for de-\n" +" tails on the default config file search path.\n" +"\n" +" Prior to 7.50.0 curl supported the short option name q but not\n" +" the long option name disable.\n" +"\n" +" Providing --disable multiple times has no extra effect. Disable\n" +" it again with --no-disable.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl -q https://example.com\n" +"\n" +" See also -K, --config.\n" +"\n" +" --disallow-username-in-url\n" +" This tells curl to exit if passed a URL containing a username.\n" +" This is probably most useful when the URL is being provided at\n" +" runtime or similar.\n" +"\n" +" Providing --disallow-username-in-url multiple times has no extra\n" +" effect. Disable it again with --no-disallow-username-in-url.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --disallow-username-in-url https://example.com\n" +"\n" +" See also --proto. Added in 7.61.0.\n" +"\n" +" --dns-interface \n" +" (DNS) Tell curl to send outgoing DNS requests through . This option is a counterpart to --interface (which does\n" +" not affect DNS). The supplied string must be an interface name\n" +" (not an address).\n" +"\n" +, stdout); + fputs( +" If --dns-interface is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --dns-interface eth0 https://example.com\n" +"\n" +" See also --dns-ipv4-addr and --dns-ipv6-addr. --dns-interface\n" +" requires that the underlying libcurl was built to support c-\n" +" ares.\n" +"\n" +" --dns-ipv4-addr
\n" +" (DNS) Tell curl to bind to a specific IP address when making\n" +, stdout); + fputs( +" IPv4 DNS requests, so that the DNS requests originate from this\n" +" address. The argument should be a single IPv4 address.\n" +"\n" +" If --dns-ipv4-addr is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --dns-ipv4-addr 10.1.2.3 https://example.com\n" +"\n" +" See also --dns-interface and --dns-ipv6-addr. --dns-ipv4-addr\n" +" requires that the underlying libcurl was built to support c-\n" +, stdout); + fputs( +" ares.\n" +"\n" +" --dns-ipv6-addr
\n" +" (DNS) Tell curl to bind to a specific IP address when making\n" +" IPv6 DNS requests, so that the DNS requests originate from this\n" +" address. The argument should be a single IPv6 address.\n" +"\n" +" If --dns-ipv6-addr is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --dns-ipv6-addr 2a04:4e42::561 https://example.com\n" +"\n" +, stdout); + fputs( +" See also --dns-interface and --dns-ipv4-addr. --dns-ipv6-addr\n" +" requires that the underlying libcurl was built to support c-\n" +" ares.\n" +"\n" +" --dns-servers \n" +" (DNS) Set the list of DNS servers to be used instead of the sys-\n" +" tem default. The list of IP addresses should be separated with\n" +" commas. Port numbers may also optionally be given as : after each IP address.\n" +"\n" +, stdout); + fputs( +" If --dns-servers is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --dns-servers 192.168.0.1,192.168.0.2 https://example.com\n" +"\n" +" See also --dns-interface and --dns-ipv4-addr. --dns-servers re-\n" +" quires that the underlying libcurl was built to support c-ares.\n" +"\n" +" --doh-cert-status\n" +" Same as --cert-status but used for DoH (DNS-over-HTTPS).\n" +"\n" +, stdout); + fputs( +" Providing --doh-cert-status multiple times has no extra effect.\n" +" Disable it again with --no-doh-cert-status.\n" +"\n" +" Example:\n" +" curl --doh-cert-status --doh-url https://doh.example https://example.com\n" +"\n" +" See also --doh-insecure. Added in 7.76.0.\n" +"\n" +" --doh-insecure\n" +" Same as -k, --insecure but used for DoH (DNS-over-HTTPS).\n" +"\n" +" Providing --doh-insecure multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-doh-insecure.\n" +"\n" +" Example:\n" +" curl --doh-insecure --doh-url https://doh.example https://example.com\n" +"\n" +" See also --doh-url. Added in 7.76.0.\n" +"\n" +" --doh-url \n" +" Specifies which DNS-over-HTTPS (DoH) server to use to resolve\n" +" hostnames, instead of using the default name resolver mechanism.\n" +" The URL must be HTTPS.\n" +"\n" +, stdout); + fputs( +" Some SSL options that you set for your transfer also applies to\n" +" DoH since the name lookups take place over SSL. However, the\n" +" certificate verification settings are not inherited but are con-\n" +" trolled separately via --doh-insecure and --doh-cert-status.\n" +"\n" +" This option is unset if an empty string \"\" is used as the URL.\n" +" (Added in 7.85.0)\n" +"\n" +, stdout); + fputs( +" If --doh-url is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --doh-url https://doh.example https://example.com\n" +"\n" +" See also --doh-insecure. Added in 7.62.0.\n" +"\n" +" -D, --dump-header \n" +" (HTTP FTP) Write the received protocol headers to the specified\n" +" file. If no headers are received, the use of this option creates\n" +" an empty file.\n" +"\n" +, stdout); + fputs( +" When used in FTP, the FTP server response lines are considered\n" +" being \"headers\" and thus are saved there.\n" +"\n" +" Having multiple transfers in one set of operations (i.e. the\n" +" URLs in one -:, --next clause), appends them to the same file,\n" +" separated by a blank line.\n" +"\n" +" If --dump-header is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +, stdout); + fputs( +" curl --dump-header store.txt https://example.com\n" +"\n" +" See also -o, --output.\n" +"\n" +" --egd-file \n" +" (TLS) Deprecated option (added in 7.84.0). Prior to that it only\n" +" had an effect on curl if built to use old versions of OpenSSL.\n" +"\n" +" Specify the path name to the Entropy Gathering Daemon socket.\n" +" The socket is used to seed the random engine for SSL connec-\n" +" tions.\n" +"\n" +, stdout); + fputs( +" If --egd-file is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --egd-file /random/here https://example.com\n" +"\n" +" See also --random-file.\n" +"\n" +" --engine \n" +" (TLS) Select the OpenSSL crypto engine to use for cipher opera-\n" +" tions. Use --engine list to print a list of build-time supported\n" +" engines. Note that not all (and possibly none) of the engines\n" +, stdout); + fputs( +" may be available at runtime.\n" +"\n" +" If --engine is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --engine flavor https://example.com\n" +"\n" +" See also --ciphers and --curves.\n" +"\n" +" --etag-compare \n" +" (HTTP) This option makes a conditional HTTP request for the spe-\n" +" cific ETag read from the given file by sending a custom\n" +, stdout); + fputs( +" If-None-Match header using the stored ETag.\n" +"\n" +" For correct results, make sure that the specified file contains\n" +" only a single line with the desired ETag. An empty file is\n" +" parsed as an empty ETag.\n" +"\n" +" Use the option --etag-save to first save the ETag from a re-\n" +" sponse, and then use this option to compare against the saved\n" +" ETag in a subsequent request.\n" +"\n" +, stdout); + fputs( +" If --etag-compare is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --etag-compare etag.txt https://example.com\n" +"\n" +" See also --etag-save and -z, --time-cond. Added in 7.68.0.\n" +"\n" +" --etag-save \n" +" (HTTP) This option saves an HTTP ETag to the specified file. An\n" +" ETag is a caching related header, usually returned in a re-\n" +" sponse.\n" +"\n" +, stdout); + fputs( +" If no ETag is sent by the server, an empty file is created.\n" +"\n" +" If --etag-save is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --etag-save storetag.txt https://example.com\n" +"\n" +" See also --etag-compare. Added in 7.68.0.\n" +"\n" +" --expect100-timeout \n" +" (HTTP) Maximum time in seconds that you allow curl to wait for a\n" +, stdout); + fputs( +" 100-continue response when curl emits an Expects: 100-continue\n" +" header in its request. By default curl waits one second. This\n" +" option accepts decimal values! When curl stops waiting, it con-\n" +" tinues as if the response has been received.\n" +"\n" +" The decimal value needs to provided using a dot (.) as decimal\n" +" separator - not the local version even if it might be using an-\n" +" other separator.\n" +"\n" +, stdout); + fputs( +" If --expect100-timeout is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --expect100-timeout 2.5 -T file https://example.com\n" +"\n" +" See also --connect-timeout.\n" +"\n" +" --fail-early\n" +" Fail and exit on the first detected transfer error.\n" +"\n" +" When curl is used to do multiple transfers on the command line,\n" +" it attempts to operate on each given URL, one by one. By de-\n" +, stdout); + fputs( +" fault, it ignores errors if there are more URLs given and the\n" +" last URL's success determines the error code curl returns. So\n" +" early failures are \"hidden\" by subsequent successful transfers.\n" +"\n" +" Using this option, curl instead returns an error on the first\n" +" transfer that fails, independent of the amount of URLs that are\n" +" given on the command line. This way, no transfer failures go un-\n" +, stdout); + fputs( +" detected by scripts and similar.\n" +"\n" +" This option does not imply -f, --fail, which causes transfers to\n" +" fail due to the server's HTTP status code. You can combine the\n" +" two options, however note -f, --fail is not global and is there-\n" +" fore contained by -:, --next.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +, stdout); + fputs( +" Providing --fail-early multiple times has no extra effect. Dis-\n" +" able it again with --no-fail-early.\n" +"\n" +" Example:\n" +" curl --fail-early https://example.com https://two.example\n" +"\n" +" See also -f, --fail and --fail-with-body. Added in 7.52.0.\n" +"\n" +" --fail-with-body\n" +" (HTTP) Return an error on server errors where the HTTP response\n" +" code is 400 or greater). In normal cases when an HTTP server\n" +, stdout); + fputs( +" fails to deliver a document, it returns an HTML document stating\n" +" so (which often also describes why and more). This flag allows\n" +" curl to output and save that content but also to return error\n" +" 22.\n" +"\n" +" This is an alternative option to -f, --fail which makes curl\n" +" fail for the same circumstances but without saving the content.\n" +"\n" +" Providing --fail-with-body multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-fail-with-body.\n" +"\n" +" Example:\n" +" curl --fail-with-body https://example.com\n" +"\n" +" See also -f, --fail and --fail-early. This option is mutually\n" +" exclusive to -f, --fail. Added in 7.76.0.\n" +"\n" +" -f, --fail\n" +" (HTTP) Fail fast with no output at all on server errors. This is\n" +" useful to enable scripts and users to better deal with failed\n" +, stdout); + fputs( +" attempts. In normal cases when an HTTP server fails to deliver a\n" +" document, it returns an HTML document stating so (which often\n" +" also describes why and more). This flag prevents curl from out-\n" +" putting that and return error 22.\n" +"\n" +" This method is not fail-safe and there are occasions where\n" +" non-successful response codes slip through, especially when au-\n" +, stdout); + fputs( +" thentication is involved (response codes 401 and 407).\n" +"\n" +" Providing --fail multiple times has no extra effect. Disable it\n" +" again with --no-fail.\n" +"\n" +" Example:\n" +" curl --fail https://example.com\n" +"\n" +" See also --fail-with-body and --fail-early. This option is mutu-\n" +" ally exclusive to --fail-with-body.\n" +"\n" +" --false-start\n" +" (TLS) Tells curl to use false start during the TLS handshake.\n" +, stdout); + fputs( +" False start is a mode where a TLS client starts sending applica-\n" +" tion data before verifying the server's Finished message, thus\n" +" saving a round trip when performing a full handshake.\n" +"\n" +" This is currently only implemented in the Secure Transport (on\n" +" iOS 7.0 or later, or OS X 10.9 or later) backend.\n" +"\n" +" Providing --false-start multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-false-start.\n" +"\n" +" Example:\n" +" curl --false-start https://example.com\n" +"\n" +" See also --tcp-fastopen.\n" +"\n" +" --form-escape\n" +" (HTTP) Tells curl to pass on names of multipart form fields and\n" +" files using backslash-escaping instead of percent-encoding.\n" +"\n" +" If --form-escape is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +, stdout); + fputs( +" curl --form-escape -F 'field\\name=curl' -F 'file=@load\"this' https://example.com\n" +"\n" +" See also -F, --form. Added in 7.81.0.\n" +"\n" +" --form-string \n" +" (HTTP SMTP IMAP) Similar to -F, --form except that the value\n" +" string for the named parameter is used literally. Leading '@'\n" +" and '<' characters, and the ';type=' string in the value have no\n" +, stdout); + fputs( +" special meaning. Use this in preference to -F, --form if there\n" +" is any possibility that the string value may accidentally trig-\n" +" ger the '@' or '<' features of -F, --form.\n" +"\n" +" --form-string can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --form-string \"data\" https://example.com\n" +"\n" +" See also -F, --form.\n" +"\n" +" -F, --form \n" +, stdout); + fputs( +" (HTTP SMTP IMAP) For HTTP protocol family, this lets curl emu-\n" +" late a filled-in form in which a user has pressed the submit\n" +" button. This causes curl to POST data using the Content-Type\n" +" multipart/form-data according to RFC 2388.\n" +"\n" +" For SMTP and IMAP protocols, this is the means to compose a mul-\n" +" tipart mail message to transmit.\n" +"\n" +, stdout); + fputs( +" This enables uploading of binary files etc. To force the 'con-\n" +" tent' part to be a file, prefix the file name with an @ sign. To\n" +" just get the content part from a file, prefix the file name with\n" +" the symbol <. The difference between @ and < is then that @\n" +" makes a file get attached in the post as a file upload, while\n" +" the < makes a text field and just get the contents for that text\n" +, stdout); + fputs( +" field from a file.\n" +"\n" +" Tell curl to read content from stdin instead of a file by using\n" +" - as filename. This goes for both @ and < constructs. When stdin\n" +" is used, the contents is buffered in memory first by curl to de-\n" +" termine its size and allow a possible resend. Defining a part's\n" +" data from a named non-regular file (such as a named pipe or sim-\n" +, stdout); + fputs( +" ilar) is not subject to buffering and is instead read at trans-\n" +" mission time; since the full size is unknown before the transfer\n" +" starts, such data is sent as chunks by HTTP and rejected by\n" +" IMAP.\n" +"\n" +" Example: send an image to an HTTP server, where 'profile' is the\n" +" name of the form-field to which the file portrait.jpg is the in-\n" +" put:\n" +"\n" +, stdout); + fputs( +" curl -F profile=@portrait.jpg https://example.com/upload.cgi\n" +"\n" +" Example: send your name and shoe size in two text fields to the\n" +" server:\n" +"\n" +" curl -F name=John -F shoesize=11 https://example.com/\n" +"\n" +" Example: send your essay in a text field to the server. Send it\n" +" as a plain text field, but get the contents for it from a local\n" +" file:\n" +"\n" +" curl -F \"story=HTML message;type=text/html' \\\n" +" -F '=)' -F '=@textfile.txt' ... smtp://example.com\n" +"\n" +" Data can be encoded for transfer using encoder=. Available en-\n" +" codings are binary and 8bit that do nothing else than adding the\n" +" corresponding Content-Transfer-Encoding header, 7bit that only\n" +, stdout); + fputs( +" rejects 8-bit characters with a transfer error, quoted-printable\n" +" and base64 that encodes data according to the corresponding\n" +" schemes, limiting lines length to 76 characters.\n" +"\n" +" Example: send multipart mail with a quoted-printable text mes-\n" +" sage and a base64 attached file:\n" +"\n" +" curl -F '=text message;encoder=quoted-printable' \\\n" +" -F '=@localfile;encoder=base64' ... smtp://example.com\n" +"\n" +, stdout); + fputs( +" See further examples and details in the MANUAL.\n" +"\n" +" --form can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --form \"name=curl\" --form \"file=@loadthis\" https://example.com\n" +"\n" +" See also -d, --data, --form-string and --form-escape. This op-\n" +" tion is mutually exclusive to -d, --data and -I, --head and -T,\n" +" --upload-file.\n" +"\n" +" --ftp-account \n" +, stdout); + fputs( +" (FTP) When an FTP server asks for \"account data\" after user name\n" +" and password has been provided, this data is sent off using the\n" +" ACCT command.\n" +"\n" +" If --ftp-account is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --ftp-account \"mr.robot\" ftp://example.com/\n" +"\n" +" See also -u, --user.\n" +"\n" +" --ftp-alternative-to-user \n" +, stdout); + fputs( +" (FTP) If authenticating with the USER and PASS commands fails,\n" +" send this command. When connecting to Tumbleweed's Secure\n" +" Transport server over FTPS using a client certificate, using\n" +" \"SITE AUTH\" tells the server to retrieve the username from the\n" +" certificate.\n" +"\n" +" If --ftp-alternative-to-user is provided several times, the last\n" +" set value is used.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --ftp-alternative-to-user \"U53r\" ftp://example.com\n" +"\n" +" See also --ftp-account and -u, --user.\n" +"\n" +" --ftp-create-dirs\n" +" (FTP SFTP) When an FTP or SFTP URL/operation uses a path that\n" +" does not currently exist on the server, the standard behavior of\n" +" curl is to fail. Using this option, curl instead attempts to\n" +" create missing directories.\n" +"\n" +, stdout); + fputs( +" Providing --ftp-create-dirs multiple times has no extra effect.\n" +" Disable it again with --no-ftp-create-dirs.\n" +"\n" +" Example:\n" +" curl --ftp-create-dirs -T file ftp://example.com/remote/path/file\n" +"\n" +" See also --create-dirs.\n" +"\n" +" --ftp-method \n" +" (FTP) Control what method curl should use to reach a file on an\n" +" FTP(S) server. The method argument should be one of the follow-\n" +, stdout); + fputs( +" ing alternatives:\n" +"\n" +" multicwd\n" +" curl does a single CWD operation for each path part in\n" +" the given URL. For deep hierarchies this means many com-\n" +" mands. This is how RFC 1738 says it should be done. This\n" +" is the default but the slowest behavior.\n" +"\n" +" nocwd curl does no CWD at all. curl does SIZE, RETR, STOR etc\n" +, stdout); + fputs( +" and give a full path to the server for all these com-\n" +" mands. This is the fastest behavior.\n" +"\n" +" singlecwd\n" +" curl does one CWD with the full target directory and then\n" +" operates on the file \"normally\" (like in the multicwd\n" +" case). This is somewhat more standards compliant than\n" +" 'nocwd' but without the full penalty of 'multicwd'.\n" +"\n" +, stdout); + fputs( +" If --ftp-method is provided several times, the last set value is\n" +" used.\n" +"\n" +" Examples:\n" +" curl --ftp-method multicwd ftp://example.com/dir1/dir2/file\n" +" curl --ftp-method nocwd ftp://example.com/dir1/dir2/file\n" +" curl --ftp-method singlecwd ftp://example.com/dir1/dir2/file\n" +"\n" +" See also -l, --list-only.\n" +"\n" +" --ftp-pasv\n" +" (FTP) Use passive mode for the data connection. Passive is the\n" +, stdout); + fputs( +" internal default behavior, but using this option can be used to\n" +" override a previous -P, --ftp-port option.\n" +"\n" +" Reversing an enforced passive really is not doable but you must\n" +" then instead enforce the correct -P, --ftp-port again.\n" +"\n" +" Passive mode means that curl tries the EPSV command first and\n" +" then PASV, unless --disable-epsv is used.\n" +"\n" +, stdout); + fputs( +" Providing --ftp-pasv multiple times has no extra effect. Dis-\n" +" able it again with --no-ftp-pasv.\n" +"\n" +" Example:\n" +" curl --ftp-pasv ftp://example.com/\n" +"\n" +" See also --disable-epsv.\n" +" -P, --ftp-port
\n" +" (FTP) Reverses the default initiator/listener roles when con-\n" +" necting with FTP. This option makes curl use active mode. curl\n" +, stdout); + fputs( +" then tells the server to connect back to the client's specified\n" +" address and port, while passive mode asks the server to setup an\n" +" IP address and port for it to connect to.
should be\n" +" one of:\n" +"\n" +" interface\n" +" e.g. eth0 to specify which interface's IP address you\n" +" want to use (Unix only)\n" +"\n" +" IP address\n" +, stdout); + fputs( +" e.g. 192.168.10.1 to specify the exact IP address\n" +"\n" +" host name\n" +" e.g. my.host.domain to specify the machine\n" +"\n" +" - make curl pick the same IP address that is already used\n" +" for the control connection. This is the recommended\n" +" choice.\n" +"\n" +" Disable the use of PORT with --ftp-pasv. Disable the attempt to\n" +, stdout); + fputs( +" use the EPRT command instead of PORT by using --disable-eprt.\n" +" EPRT is really PORT++.\n" +"\n" +" You can also append \":[start]-[end]\" to the right of the ad-\n" +" dress, to tell curl what TCP port range to use. That means you\n" +" specify a port range, from a lower to a higher number. A single\n" +" number works as well, but do note that it increases the risk of\n" +" failure since the port may not be available.\n" +"\n" +, stdout); + fputs( +" If --ftp-port is provided several times, the last set value is\n" +" used.\n" +"\n" +" Examples:\n" +" curl -P - ftp:/example.com\n" +" curl -P eth0 ftp:/example.com\n" +" curl -P 192.168.0.2 ftp:/example.com\n" +"\n" +" See also --ftp-pasv and --disable-eprt.\n" +"\n" +" --ftp-pret\n" +" (FTP) Tell curl to send a PRET command before PASV (and EPSV).\n" +" Certain FTP servers, mainly drftpd, require this non-standard\n" +, stdout); + fputs( +" command for directory listings as well as up and downloads in\n" +" PASV mode.\n" +"\n" +" Providing --ftp-pret multiple times has no extra effect. Dis-\n" +" able it again with --no-ftp-pret.\n" +"\n" +" Example:\n" +" curl --ftp-pret ftp://example.com/\n" +"\n" +" See also -P, --ftp-port and --ftp-pasv.\n" +"\n" +" --ftp-skip-pasv-ip\n" +" (FTP) Tell curl to not use the IP address the server suggests in\n" +, stdout); + fputs( +" its response to curl's PASV command when curl connects the data\n" +" connection. Instead curl reuses the same IP address it already\n" +" uses for the control connection.\n" +"\n" +" This option is enabled by default (added in 7.74.0).\n" +"\n" +" This option has no effect if PORT, EPRT or EPSV is used instead\n" +" of PASV.\n" +"\n" +" Providing --ftp-skip-pasv-ip multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-ftp-skip-pasv-ip.\n" +"\n" +" Example:\n" +" curl --ftp-skip-pasv-ip ftp://example.com/\n" +"\n" +" See also --ftp-pasv.\n" +"\n" +" --ftp-ssl-ccc-mode \n" +" (FTP) Sets the CCC mode. The passive mode does not initiate the\n" +" shutdown, but instead waits for the server to do it, and does\n" +" not reply to the shutdown from the server. The active mode ini-\n" +, stdout); + fputs( +" tiates the shutdown and waits for a reply from the server.\n" +"\n" +" Providing --ftp-ssl-ccc-mode multiple times has no extra effect.\n" +" Disable it again with --no-ftp-ssl-ccc-mode.\n" +"\n" +" Example:\n" +" curl --ftp-ssl-ccc-mode active --ftp-ssl-ccc ftps://example.com/\n" +"\n" +" See also --ftp-ssl-ccc.\n" +"\n" +" --ftp-ssl-ccc\n" +" (FTP) Use CCC (Clear Command Channel) Shuts down the SSL/TLS\n" +, stdout); + fputs( +" layer after authenticating. The rest of the control channel com-\n" +" munication is be unencrypted. This allows NAT routers to follow\n" +" the FTP transaction. The default mode is passive.\n" +"\n" +" Providing --ftp-ssl-ccc multiple times has no extra effect.\n" +" Disable it again with --no-ftp-ssl-ccc.\n" +"\n" +" Example:\n" +" curl --ftp-ssl-ccc ftps://example.com/\n" +" See also --ssl and --ftp-ssl-ccc-mode.\n" +"\n" +, stdout); + fputs( +" --ftp-ssl-control\n" +" (FTP) Require SSL/TLS for the FTP login, clear for transfer. Al-\n" +" lows secure authentication, but non-encrypted data transfers for\n" +" efficiency. Fails the transfer if the server does not support\n" +" SSL/TLS.\n" +"\n" +" Providing --ftp-ssl-control multiple times has no extra effect.\n" +" Disable it again with --no-ftp-ssl-control.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --ftp-ssl-control ftp://example.com\n" +"\n" +" See also --ssl.\n" +"\n" +" -G, --get\n" +" (HTTP) When used, this option makes all data specified with -d,\n" +" --data, --data-binary or --data-urlencode to be used in an HTTP\n" +" GET request instead of the POST request that otherwise would be\n" +" used. The data is appended to the URL with a '?' separator.\n" +"\n" +" If used in combination with -I, --head, the POST data is instead\n" +, stdout); + fputs( +" appended to the URL with a HEAD request.\n" +"\n" +" Providing --get multiple times has no extra effect. Disable it\n" +" again with --no-get.\n" +"\n" +" Examples:\n" +" curl --get https://example.com\n" +" curl --get -d \"tool=curl\" -d \"age=old\" https://example.com\n" +" curl --get -I -d \"tool=curl\" https://example.com\n" +"\n" +" See also -d, --data and -X, --request.\n" +"\n" +" -g, --globoff\n" +, stdout); + fputs( +" This option switches off the \"URL globbing parser\". When you set\n" +" this option, you can specify URLs that contain the letters {}[]\n" +" without having curl itself interpret them. Note that these let-\n" +" ters are not normal legal URL contents but they should be en-\n" +" coded according to the URI standard.\n" +"\n" +" Providing --globoff multiple times has no extra effect. Disable\n" +" it again with --no-globoff.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl -g \"https://example.com/{[]}}}}\"\n" +"\n" +" See also -K, --config and -q, --disable.\n" +"\n" +" --happy-eyeballs-timeout-ms \n" +" Happy Eyeballs is an algorithm that attempts to connect to both\n" +" IPv4 and IPv6 addresses for dual-stack hosts, giving IPv6 a\n" +" head-start of the specified number of milliseconds. If the IPv6\n" +" address cannot be connected to within that time, then a connec-\n" +, stdout); + fputs( +" tion attempt is made to the IPv4 address in parallel. The first\n" +" connection to be established is the one that is used.\n" +"\n" +" The range of suggested useful values is limited. Happy Eyeballs\n" +" RFC 6555 says \"It is RECOMMENDED that connection attempts be\n" +" paced 150-250 ms apart to balance human factors against network\n" +" load.\" libcurl currently defaults to 200 ms. Firefox and Chrome\n" +, stdout); + fputs( +" currently default to 300 ms.\n" +"\n" +" If --happy-eyeballs-timeout-ms is provided several times, the\n" +" last set value is used.\n" +"\n" +" Example:\n" +" curl --happy-eyeballs-timeout-ms 500 https://example.com\n" +"\n" +" See also -m, --max-time and --connect-timeout. Added in 7.59.0.\n" +"\n" +" --haproxy-clientip \n" +" (HTTP) Sets a client IP in HAProxy PROXY protocol v1 header at\n" +, stdout); + fputs( +" the beginning of the connection.\n" +"\n" +" For valid requests, IPv4 addresses must be indicated as a series\n" +" of exactly 4 integers in the range [0..255] inclusive written in\n" +" decimal representation separated by exactly one dot between each\n" +" other. Heading zeroes are not permitted in front of numbers in\n" +" order to avoid any possible confusion with octal numbers. IPv6\n" +, stdout); + fputs( +" addresses must be indicated as series of 4 hexadecimal digits\n" +" (upper or lower case) delimited by colons between each other,\n" +" with the acceptance of one double colon sequence to replace the\n" +" largest acceptable range of consecutive zeroes. The total number\n" +" of decoded bits must exactly be 128.\n" +"\n" +" Otherwise, any string can be accepted for the client IP and get\n" +" sent.\n" +"\n" +, stdout); + fputs( +" It replaces --haproxy-protocol if used, it is not necessary to\n" +" specify both flags.\n" +"\n" +" If --haproxy-clientip is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --haproxy-clientip $IP\n" +"\n" +" See also -x, --proxy. Added in 8.2.0.\n" +"\n" +" --haproxy-protocol\n" +" (HTTP) Send a HAProxy PROXY protocol v1 header at the beginning\n" +, stdout); + fputs( +" of the connection. This is used by some load balancers and re-\n" +" verse proxies to indicate the client's true IP address and port.\n" +" This option is primarily useful when sending test requests to a\n" +" service that expects this header.\n" +"\n" +" Providing --haproxy-protocol multiple times has no extra effect.\n" +" Disable it again with --no-haproxy-protocol.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --haproxy-protocol https://example.com\n" +"\n" +" See also -x, --proxy. Added in 7.60.0.\n" +"\n" +" -I, --head\n" +" (HTTP FTP FILE) Fetch the headers only! HTTP-servers feature the\n" +" command HEAD which this uses to get nothing but the header of a\n" +" document. When used on an FTP or FILE file, curl displays the\n" +" file size and last modification time only.\n" +"\n" +, stdout); + fputs( +" Providing --head multiple times has no extra effect. Disable it\n" +" again with --no-head.\n" +"\n" +" Example:\n" +" curl -I https://example.com\n" +"\n" +" See also -G, --get, -v, --verbose and --trace-ascii.\n" +"\n" +" -H, --header
\n" +" (HTTP IMAP SMTP) Extra header to include in information sent.\n" +" When used within an HTTP request, it is added to the regular re-\n" +" quest headers.\n" +"\n" +, stdout); + fputs( +" For an IMAP or SMTP MIME uploaded mail built with -F, --form op-\n" +" tions, it is prepended to the resulting MIME document, effec-\n" +" tively including it at the mail global level. It does not affect\n" +" raw uploaded mails (Added in 7.56.0).\n" +"\n" +" You may specify any number of extra headers. Note that if you\n" +" should add a custom header that has the same name as one of the\n" +, stdout); + fputs( +" internal ones curl would use, your externally set header is used\n" +" instead of the internal one. This allows you to make even trick-\n" +" ier stuff than curl would normally do. You should not replace\n" +" internally set headers without knowing perfectly well what you\n" +" are doing. Remove an internal header by giving a replacement\n" +" without content on the right side of the colon, as in: -H\n" +, stdout); + fputs( +" \"Host:\". If you send the custom header with no-value then its\n" +" header must be terminated with a semicolon, such as \\-H \"X-Cus-\n" +" tom-Header;\" to send \"X-Custom-Header:\".\n" +"\n" +" curl makes sure that each header you add/replace is sent with\n" +" the proper end-of-line marker, you should thus not add that as a\n" +" part of the header content: do not add newlines or carriage re-\n" +, stdout); + fputs( +" turns, they only mess things up for you. curl passes on the ver-\n" +" batim string you give it without any filter or other safe\n" +" guards. That includes white space and control characters.\n" +"\n" +" This option can take an argument in @filename style, which then\n" +" adds a header for each line in the input file. Using @- makes\n" +" curl read the header file from stdin. Added in 7.55.0.\n" +"\n" +, stdout); + fputs( +" Please note that most anti-spam utilities check the presence and\n" +" value of several MIME mail headers: these are \"From:\", \"To:\",\n" +" \"Date:\" and \"Subject:\" among others and should be added with\n" +" this option.\n" +"\n" +" You need --proxy-header to send custom headers intended for an\n" +" HTTP proxy. Added in 7.37.0.\n" +"\n" +" Passing on a \"Transfer-Encoding: chunked\" header when doing an\n" +, stdout); + fputs( +" HTTP request with a request body, makes curl send the data using\n" +" chunked encoding.\n" +"\n" +" WARNING: headers set with this option are set in all HTTP re-\n" +" quests - even after redirects are followed, like when told with\n" +" -L, --location. This can lead to the header being sent to other\n" +" hosts than the original host, so sensitive headers should be\n" +" used with caution combined with following redirects.\n" +, stdout); + fputs( +" --header can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl -H \"X-First-Name: Joe\" https://example.com\n" +" curl -H \"User-Agent: yes-please/2000\" https://example.com\n" +" curl -H \"Host:\" https://example.com\n" +" curl -H @headers.txt https://example.com\n" +"\n" +" See also -A, --user-agent and -e, --referer.\n" +"\n" +" -h, --help \n" +, stdout); + fputs( +" Usage help. This lists all curl command line options within the\n" +" given category.\n" +"\n" +" If no argument is provided, curl displays only the most impor-\n" +" tant command line arguments.\n" +"\n" +" For category all, curl displays help for all options.\n" +"\n" +" If category is specified, curl displays all available help cate-\n" +" gories.\n" +"\n" +" Example:\n" +" curl --help all\n" +"\n" +" See also -v, --verbose.\n" +"\n" +, stdout); + fputs( +" --hostpubmd5 \n" +" (SFTP SCP) Pass a string containing 32 hexadecimal digits. The\n" +" string should be the 128 bit MD5 checksum of the remote host's\n" +" public key, curl refuses the connection with the host unless the\n" +" checksums match.\n" +"\n" +" If --hostpubmd5 is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --hostpubmd5 e5c1c49020640a5ab0f2034854c321a8 sftp://example.com/\n" +"\n" +" See also --hostpubsha256.\n" +"\n" +" --hostpubsha256 \n" +" (SFTP SCP) Pass a string containing a Base64-encoded SHA256 hash\n" +" of the remote host's public key. Curl refuses the connection\n" +" with the host unless the hashes match.\n" +"\n" +" This feature requires libcurl to be built with libssh2 and does\n" +" not work with other SSH backends.\n" +"\n" +, stdout); + fputs( +" If --hostpubsha256 is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --hostpubsha256 NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ= sftp://example.com/\n" +"\n" +" See also --hostpubmd5. Added in 7.80.0.\n" +"\n" +" --hsts \n" +" (HTTPS) This option enables HSTS for the transfer. If the file\n" +" name points to an existing HSTS cache file, that is used. After\n" +, stdout); + fputs( +" a completed transfer, the cache is saved to the file name again\n" +" if it has been modified.\n" +"\n" +" If curl is told to use HTTP:// for a transfer involving a host\n" +" name that exists in the HSTS cache, it upgrades the transfer to\n" +" use HTTPS. Each HSTS cache entry has an individual life time af-\n" +" ter which the upgrade is no longer performed.\n" +"\n" +" Specify a \"\" file name (zero length) to avoid loading/saving and\n" +, stdout); + fputs( +" make curl just handle HSTS in memory.\n" +"\n" +" If this option is used several times, curl loads contents from\n" +" all the files but the last one is used for saving.\n" +" --hsts can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --hsts cache.txt https://example.com\n" +"\n" +" See also --proto. Added in 7.74.0.\n" +"\n" +" --http0.9\n" +" (HTTP) Tells curl to be fine with HTTP version 0.9 response.\n" +"\n" +, stdout); + fputs( +" HTTP/0.9 is a response without headers and therefore you can\n" +" also connect with this to non-HTTP servers and still get a re-\n" +" sponse since curl simply transparently downgrades - if allowed.\n" +"\n" +" HTTP/0.9 is disabled by default (added in 7.66.0)\n" +"\n" +" Providing --http0.9 multiple times has no extra effect. Disable\n" +" it again with --no-http0.9.\n" +"\n" +" Example:\n" +" curl --http0.9 https://example.com\n" +"\n" +, stdout); + fputs( +" See also --http1.1, --http2 and --http3. Added in 7.64.0.\n" +"\n" +" -0, --http1.0\n" +" (HTTP) Tells curl to use HTTP version 1.0 instead of using its\n" +" internally preferred HTTP version.\n" +"\n" +" Providing --http1.0 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --http1.0 https://example.com\n" +"\n" +" See also --http0.9 and --http1.1. This option is mutually exclu-\n" +, stdout); + fputs( +" sive to --http1.1 and --http2 and --http2-prior-knowledge and\n" +" --http3.\n" +"\n" +" --http1.1\n" +" (HTTP) Tells curl to use HTTP version 1.1.\n" +"\n" +" Providing --http1.1 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --http1.1 https://example.com\n" +"\n" +" See also -0, --http1.0 and --http0.9. This option is mutually\n" +" exclusive to -0, --http1.0 and --http2 and --http2-prior-knowl-\n" +, stdout); + fputs( +" edge and --http3.\n" +"\n" +" --http2-prior-knowledge\n" +" (HTTP) Tells curl to issue its non-TLS HTTP requests using\n" +" HTTP/2 without HTTP/1.1 Upgrade. It requires prior knowledge\n" +" that the server supports HTTP/2 straight away. HTTPS requests\n" +" still do HTTP/2 the standard way with negotiated protocol ver-\n" +" sion in the TLS handshake.\n" +"\n" +, stdout); + fputs( +" Providing --http2-prior-knowledge multiple times has no extra\n" +" effect. Disable it again with --no-http2-prior-knowledge.\n" +"\n" +" Example:\n" +" curl --http2-prior-knowledge https://example.com\n" +"\n" +" See also --http2 and --http3. --http2-prior-knowledge requires\n" +" that the underlying libcurl was built to support HTTP/2. This\n" +" option is mutually exclusive to --http1.1 and -0, --http1.0 and\n" +, stdout); + fputs( +" --http2 and --http3.\n" +"\n" +" --http2\n" +" (HTTP) Tells curl to use HTTP version 2.\n" +"\n" +" For HTTPS, this means curl negotiates HTTP/2 in the TLS hand-\n" +" shake. curl does this by default.\n" +"\n" +" For HTTP, this means curl attempts to upgrade the request to\n" +" HTTP/2 using the Upgrade: request header.\n" +"\n" +" When curl uses HTTP/2 over HTTPS, it does not itself insist on\n" +, stdout); + fputs( +" TLS 1.2 or higher even though that is required by the specifica-\n" +" tion. A user can add this version requirement with --tlsv1.2.\n" +"\n" +" Providing --http2 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --http2 https://example.com\n" +"\n" +" See also --http1.1, --http3 and --no-alpn. --http2 requires that\n" +" the underlying libcurl was built to support HTTP/2. This option\n" +, stdout); + fputs( +" is mutually exclusive to --http1.1 and -0, --http1.0 and\n" +" --http2-prior-knowledge and --http3.\n" +"\n" +" --http3-only\n" +" (HTTP) Instructs curl to use HTTP/3 to the host in the URL, with\n" +" no fallback to earlier HTTP versions. HTTP/3 can only be used\n" +" for HTTPS and not for HTTP URLs. For HTTP, this option triggers\n" +" an error.\n" +"\n" +" This option allows a user to avoid using the Alt-Svc method of\n" +, stdout); + fputs( +" upgrading to HTTP/3 when you know that the target speaks HTTP/3\n" +" on the given host and port.\n" +"\n" +" This option makes curl fail if a QUIC connection cannot be es-\n" +" tablished, it does not attempt any other HTTP versions on its\n" +" own. Use --http3 for similar functionality with a fallback.\n" +"\n" +" Providing --http3-only multiple times has no extra effect.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --http3-only https://example.com\n" +"\n" +" See also --http1.1, --http2 and --http3. --http3-only requires\n" +" that the underlying libcurl was built to support HTTP/3. This\n" +" option is mutually exclusive to --http1.1 and -0, --http1.0 and\n" +" --http2 and --http2-prior-knowledge and --http3. Added in\n" +" 7.88.0.\n" +" --http3\n" +" (HTTP) Tells curl to try HTTP/3 to the host in the URL, but\n" +, stdout); + fputs( +" fallback to earlier HTTP versions if the HTTP/3 connection es-\n" +" tablishment fails. HTTP/3 is only available for HTTPS and not\n" +" for HTTP URLs.\n" +"\n" +" This option allows a user to avoid using the Alt-Svc method of\n" +" upgrading to HTTP/3 when you know that the target speaks HTTP/3\n" +" on the given host and port.\n" +"\n" +" When asked to use HTTP/3, curl issues a separate attempt to use\n" +, stdout); + fputs( +" older HTTP versions with a slight delay, so if the HTTP/3 trans-\n" +" fer fails or is slow, curl still tries to proceed with an older\n" +" HTTP version.\n" +"\n" +" Use --http3-only for similar functionality without a fallback.\n" +"\n" +" Providing --http3 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --http3 https://example.com\n" +"\n" +" See also --http1.1 and --http2. --http3 requires that the under-\n" +, stdout); + fputs( +" lying libcurl was built to support HTTP/3. This option is mutu-\n" +" ally exclusive to --http1.1 and -0, --http1.0 and --http2 and\n" +" --http2-prior-knowledge and --http3-only. Added in 7.66.0.\n" +"\n" +" --ignore-content-length\n" +" (FTP HTTP) For HTTP, Ignore the Content-Length header. This is\n" +" particularly useful for servers running Apache 1.x, which re-\n" +" ports incorrect Content-Length for files larger than 2 giga-\n" +, stdout); + fputs( +" bytes.\n" +"\n" +" For FTP, this makes curl skip the SIZE command to figure out the\n" +" size before downloading a file.\n" +"\n" +" This option does not work for HTTP if libcurl was built to use\n" +" hyper.\n" +"\n" +" Providing --ignore-content-length multiple times has no extra\n" +" effect. Disable it again with --no-ignore-content-length.\n" +"\n" +" Example:\n" +" curl --ignore-content-length https://example.com\n" +"\n" +, stdout); + fputs( +" See also --ftp-skip-pasv-ip.\n" +"\n" +" -i, --include\n" +" (HTTP FTP) Include response headers in the output. HTTP response\n" +" headers can include things like server name, cookies, date of\n" +" the document, HTTP version and more... With non-HTTP protocols,\n" +" the \"headers\" are other server communication.\n" +"\n" +" To view the request headers, consider the -v, --verbose option.\n" +"\n" +, stdout); + fputs( +" Prior to 7.75.0 curl did not print the headers if -f, --fail was\n" +" used in combination with this option and there was error re-\n" +" ported by server.\n" +"\n" +" Providing --include multiple times has no extra effect. Disable\n" +" it again with --no-include.\n" +"\n" +" Example:\n" +" curl -i https://example.com\n" +"\n" +" See also -v, --verbose.\n" +"\n" +" -k, --insecure\n" +, stdout); + fputs( +" (TLS SFTP SCP) By default, every secure connection curl makes is\n" +" verified to be secure before the transfer takes place. This op-\n" +" tion makes curl skip the verification step and proceed without\n" +" checking.\n" +"\n" +" When this option is not used for protocols using TLS, curl veri-\n" +" fies the server's TLS certificate before it continues: that the\n" +" certificate contains the right name which matches the host name\n" +, stdout); + fputs( +" used in the URL and that the certificate has been signed by a CA\n" +" certificate present in the cert store. See this online resource\n" +" for further details: https://curl.se/docs/sslcerts.html\n" +"\n" +" For SFTP and SCP, this option makes curl skip the known_hosts\n" +" verification. known_hosts is a file normally stored in the\n" +" user's home directory in the \".ssh\" subdirectory, which contains\n" +, stdout); + fputs( +" host names and their public keys.\n" +"\n" +" WARNING: using this option makes the transfer insecure.\n" +"\n" +" When curl uses secure protocols it trusts responses and allows\n" +" for example HSTS and Alt-Svc information to be stored and used\n" +" subsequently. Using -k, --insecure can make curl trust and use\n" +" such information from malicious servers.\n" +"\n" +" Providing --insecure multiple times has no extra effect. Dis-\n" +, stdout); + fputs( +" able it again with --no-insecure.\n" +"\n" +" Example:\n" +" curl --insecure https://example.com\n" +"\n" +" See also --proxy-insecure, --cacert and --capath.\n" +"\n" +" --interface \n" +" Perform an operation using a specified interface. You can enter\n" +" interface name, IP address or host name. An example could look\n" +" like:\n" +"\n" +" curl --interface eth0:1 https://www.example.com/\n" +"\n" +, stdout); + fputs( +" On Linux it can be used to specify a VRF, but the binary needs\n" +" to either have CAP_NET_RAW or to be run as root. More informa-\n" +" tion about Linux VRF: https://www.kernel.org/doc/Documenta-\n" +" tion/networking/vrf.txt\n" +"\n" +" If --interface is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --interface eth0 https://example.com\n" +"\n" +" See also --dns-interface.\n" +"\n" +, stdout); + fputs( +" --ipfs-gateway \n" +" (IPFS) Specify which gateway to use for IPFS and IPNS URLs. Not\n" +" specifying this will instead make curl check if the IPFS_GATEWAY\n" +" environment variable is set, or if a \"~/.ipfs/gateway\" file\n" +" holding the gateway URL exists.\n" +"\n" +" If you run a local IPFS node, this gateway is by default avail-\n" +" able under \"http://localhost:8080\". A full example URL would\n" +" look like:\n" +"\n" +, stdout); + fputs( +" curl --ipfs-gateway http://localhost:8080 ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi\n" +"\n" +" There are many public IPFS gateways. See for example:\n" +" https://ipfs.github.io/public-gateway-checker/\n" +"\n" +" WARNING: If you opt to go for a remote gateway you should be\n" +" aware that you completely trust the gateway. This is fine in lo-\n" +, stdout); + fputs( +" cal gateways as you host it yourself. With remote gateways there\n" +" could potentially be a malicious actor returning you data that\n" +" does not match the request you made, inspect or even interfere\n" +" with the request. You will not notice this when using curl. A\n" +" mitigation could be to go for a \"trustless\" gateway. This means\n" +" you locally verify that the data. Consult the docs page on\n" +, stdout); + fputs( +" trusted vs trustless: https://docs.ipfs.tech/refer-\n" +" ence/http/gateway/#trusted-vs-trustless\n" +"\n" +" If --ipfs-gateway is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --ipfs-gateway https://example.com ipfs://\n" +"\n" +" See also -h, --help and -M, --manual. Added in 8.4.0.\n" +"\n" +" -4, --ipv4\n" +" This option tells curl to use IPv4 addresses only when resolving\n" +, stdout); + fputs( +" host names, and not for example try IPv6.\n" +"\n" +" Providing --ipv4 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --ipv4 https://example.com\n" +"\n" +" See also --http1.1 and --http2. This option is mutually exclu-\n" +" sive to -6, --ipv6.\n" +"\n" +" -6, --ipv6\n" +" This option tells curl to use IPv6 addresses only when resolving\n" +" host names, and not for example try IPv4.\n" +"\n" +, stdout); + fputs( +" Providing --ipv6 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --ipv6 https://example.com\n" +"\n" +" See also --http1.1 and --http2. This option is mutually exclu-\n" +" sive to -4, --ipv4.\n" +"\n" +" --json \n" +" (HTTP) Sends the specified JSON data in a POST request to the\n" +" HTTP server. --json works as a shortcut for passing on these\n" +" three options:\n" +"\n" +" --data [arg]\n" +, stdout); + fputs( +" --header \"Content-Type: application/json\"\n" +" --header \"Accept: application/json\"\n" +"\n" +" There is no verification that the passed in data is actual JSON\n" +" or that the syntax is correct.\n" +"\n" +" If you start the data with the letter @, the rest should be a\n" +" file name to read the data from, or a single dash (-) if you\n" +" want curl to read the data from stdin. Posting data from a file\n" +, stdout); + fputs( +" named 'foobar' would thus be done with --json @foobar and to in-\n" +" stead read the data from stdin, use --json @-.\n" +"\n" +" If this option is used more than once on the same command line,\n" +" the additional data pieces are concatenated to the previous be-\n" +" fore sending.\n" +"\n" +" The headers this option sets can be overridden with -H, --header\n" +" as usual.\n" +"\n" +" --json can be used several times in a command line\n" +"\n" +, stdout); + fputs( +" Examples:\n" +" curl --json '{ \"drink\": \"coffe\" }' https://example.com\n" +" curl --json '{ \"drink\":' --json ' \"coffe\" }' https://example.com\n" +" curl --json @prepared https://example.com\n" +" curl --json @- https://example.com < json.txt\n" +"\n" +" See also --data-binary and --data-raw. This option is mutually\n" +" exclusive to -F, --form and -I, --head and -T, --upload-file.\n" +" Added in 7.82.0.\n" +"\n" +, stdout); + fputs( +" -j, --junk-session-cookies\n" +" (HTTP) When curl is told to read cookies from a given file, this\n" +" option makes it discard all \"session cookies\". This has the same\n" +" effect as if a new session is started. Typical browsers discard\n" +" session cookies when they are closed down.\n" +"\n" +" Providing --junk-session-cookies multiple times has no extra ef-\n" +" fect. Disable it again with --no-junk-session-cookies.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --junk-session-cookies -b cookies.txt https://example.com\n" +"\n" +" See also -b, --cookie and -c, --cookie-jar.\n" +"\n" +" --keepalive-time \n" +" This option sets the time a connection needs to remain idle be-\n" +" fore sending keepalive probes and the time between individual\n" +" keepalive probes. It is currently effective on operating systems\n" +, stdout); + fputs( +" offering the \"TCP_KEEPIDLE\" and \"TCP_KEEPINTVL\" socket options\n" +" (meaning Linux, recent AIX, HP-UX and more). Keepalive is used\n" +" by the TCP stack to detect broken networks on idle connections.\n" +" The number of missed keepalive probes before declaring the con-\n" +" nection down is OS dependent and is commonly 9 or 10. This op-\n" +" tion has no effect if --no-keepalive is used.\n" +"\n" +, stdout); + fputs( +" If unspecified, the option defaults to 60 seconds.\n" +"\n" +" If --keepalive-time is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --keepalive-time 20 https://example.com\n" +"\n" +" See also --no-keepalive and -m, --max-time.\n" +"\n" +" --key-type \n" +" (TLS) Private key file type. Specify which type your --key pro-\n" +, stdout); + fputs( +" vided private key is. DER, PEM, and ENG are supported. If not\n" +" specified, PEM is assumed.\n" +"\n" +" If --key-type is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --key-type DER --key here https://example.com\n" +"\n" +" See also --key.\n" +"\n" +" --key \n" +" (TLS SSH) Private key file name. Allows you to provide your pri-\n" +, stdout); + fputs( +" vate key in this separate file. For SSH, if not specified, curl\n" +" tries the following candidates in order: \"~/.ssh/id_rsa\",\n" +" \"~/.ssh/id_dsa\", \"./id_rsa\", \"./id_dsa\".\n" +"\n" +" If curl is built against OpenSSL library, and the engine pkcs11\n" +" is available, then a PKCS#11 URI (RFC 7512) can be used to spec-\n" +" ify a private key located in a PKCS#11 device. A string begin-\n" +, stdout); + fputs( +" ning with \"pkcs11:\" is interpreted as a PKCS#11 URI. If a\n" +" PKCS#11 URI is provided, then the --engine option is set as\n" +" \"pkcs11\" if none was provided and the --key-type option is set\n" +" as \"ENG\" if none was provided.\n" +"\n" +" If curl is built against Secure Transport or Schannel then this\n" +" option is ignored for TLS protocols (HTTPS, etc). Those backends\n" +, stdout); + fputs( +" expect the private key to be already present in the keychain or\n" +" PKCS#12 file containing the certificate.\n" +"\n" +" If --key is provided several times, the last set value is used.\n" +"\n" +" Example:\n" +" curl --cert certificate --key here https://example.com\n" +"\n" +" See also --key-type and -E, --cert.\n" +"\n" +" --krb \n" +" (FTP) Enable Kerberos authentication and use. The level must be\n" +, stdout); + fputs( +" entered and should be one of 'clear', 'safe', 'confidential', or\n" +" 'private'. Should you use a level that is not one of these,\n" +" 'private' is used.\n" +"\n" +" If --krb is provided several times, the last set value is used.\n" +"\n" +" Example:\n" +" curl --krb clear ftp://example.com/\n" +"\n" +" See also --delegation and --ssl. --krb requires that the under-\n" +" lying libcurl was built to support Kerberos.\n" +"\n" +, stdout); + fputs( +" --libcurl \n" +" Append this option to any ordinary curl command line, and you\n" +" get libcurl-using C source code written to the file that does\n" +" the equivalent of what your command-line operation does!\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +" If --libcurl is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --libcurl client.c https://example.com\n" +"\n" +" See also -v, --verbose.\n" +"\n" +" --limit-rate \n" +" Specify the maximum transfer rate you want curl to use - for\n" +" both downloads and uploads. This feature is useful if you have a\n" +" limited pipe and you would like your transfer not to use your\n" +" entire bandwidth. To make it slower than it otherwise would be.\n" +"\n" +, stdout); + fputs( +" The given speed is measured in bytes/second, unless a suffix is\n" +" appended. Appending 'k' or 'K' counts the number as kilobytes,\n" +" 'm' or 'M' makes it megabytes, while 'g' or 'G' makes it giga-\n" +" bytes. The suffixes (k, M, G, T, P) are 1024 based. For example\n" +" 1k is 1024. Examples: 200K, 3m and 1G.\n" +"\n" +" The rate limiting logic works on averaging the transfer speed to\n" +, stdout); + fputs( +" no more than the set threshold over a period of multiple sec-\n" +" onds.\n" +"\n" +" If you also use the -Y, --speed-limit option, that option takes\n" +" precedence and might cripple the rate-limiting slightly, to help\n" +" keeping the speed-limit logic working.\n" +"\n" +" If --limit-rate is provided several times, the last set value is\n" +" used.\n" +"\n" +" Examples:\n" +" curl --limit-rate 100K https://example.com\n" +, stdout); + fputs( +" curl --limit-rate 1000 https://example.com\n" +" curl --limit-rate 10M https://example.com\n" +"\n" +" See also --rate, -Y, --speed-limit and -y, --speed-time.\n" +"\n" +" -l, --list-only\n" +" (FTP POP3 SFTP) (FTP) When listing an FTP directory, this switch\n" +" forces a name-only view. This is especially useful if the user\n" +" wants to machine-parse the contents of an FTP directory since\n" +, stdout); + fputs( +" the normal directory view does not use a standard look or for-\n" +" mat. When used like this, the option causes an NLST command to\n" +" be sent to the server instead of LIST.\n" +"\n" +" Note: Some FTP servers list only files in their response to\n" +" NLST; they do not include sub-directories and symbolic links.\n" +"\n" +" (SFTP) When listing an SFTP directory, this switch forces a\n" +, stdout); + fputs( +" name-only view, one per line. This is especially useful if the\n" +" user wants to machine-parse the contents of an SFTP directory\n" +" since the normal directory view provides more information than\n" +" just file names.\n" +"\n" +" (POP3) When retrieving a specific email from POP3, this switch\n" +" forces a LIST command to be performed instead of RETR. This is\n" +, stdout); + fputs( +" particularly useful if the user wants to see if a specific mes-\n" +" sage-id exists on the server and what size it is.\n" +"\n" +" Note: When combined with -X, --request, this option can be used\n" +" to send a UIDL command instead, so the user may use the email's\n" +" unique identifier rather than its message-id to make the re-\n" +" quest.\n" +"\n" +" Providing --list-only multiple times has no extra effect. Dis-\n" +, stdout); + fputs( +" able it again with --no-list-only.\n" +"\n" +" Example:\n" +" curl --list-only ftp://example.com/dir/\n" +" See also -Q, --quote and -X, --request.\n" +"\n" +" --local-port \n" +" Set a preferred single number or range (FROM-TO) of local port\n" +" numbers to use for the connection(s). Note that port numbers by\n" +" nature are a scarce resource so setting this range to something\n" +, stdout); + fputs( +" too narrow might cause unnecessary connection setup failures.\n" +"\n" +" If --local-port is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --local-port 1000-3000 https://example.com\n" +"\n" +" See also -g, --globoff.\n" +"\n" +" --location-trusted\n" +" (HTTP) Like -L, --location, but allows sending the name + pass-\n" +" word to all hosts that the site may redirect to. This may or may\n" +, stdout); + fputs( +" not introduce a security breach if the site redirects you to a\n" +" site to which you send your authentication info (which is\n" +" clear-text in the case of HTTP Basic authentication).\n" +"\n" +" Providing --location-trusted multiple times has no extra effect.\n" +" Disable it again with --no-location-trusted.\n" +"\n" +" Example:\n" +" curl --location-trusted -u user:password https://example.com\n" +"\n" +, stdout); + fputs( +" See also -u, --user.\n" +"\n" +" -L, --location\n" +" (HTTP) If the server reports that the requested page has moved\n" +" to a different location (indicated with a Location: header and a\n" +" 3XX response code), this option makes curl redo the request on\n" +" the new place. If used together with -i, --include or -I,\n" +" --head, headers from all requested pages are shown.\n" +"\n" +, stdout); + fputs( +" When authentication is used, curl only sends its credentials to\n" +" the initial host. If a redirect takes curl to a different host,\n" +" it does not get the user+password pass on. See also --loca-\n" +" tion-trusted on how to change this.\n" +"\n" +" Limit the amount of redirects to follow by using the\n" +" --max-redirs option.\n" +"\n" +" When curl follows a redirect and if the request is a POST, it\n" +, stdout); + fputs( +" sends the following request with a GET if the HTTP response was\n" +" 301, 302, or 303. If the response code was any other 3xx code,\n" +" curl resends the following request using the same unmodified\n" +" method.\n" +"\n" +" You can tell curl to not change POST requests to GET after a 30x\n" +" response by using the dedicated options for that: --post301,\n" +" --post302 and --post303.\n" +"\n" +, stdout); + fputs( +" The method set with -X, --request overrides the method curl\n" +" would otherwise select to use.\n" +"\n" +" Providing --location multiple times has no extra effect. Dis-\n" +" able it again with --no-location.\n" +"\n" +" Example:\n" +" curl -L https://example.com\n" +"\n" +" See also --resolve and --alt-svc.\n" +"\n" +" --login-options \n" +" (IMAP LDAP POP3 SMTP) Specify the login options to use during\n" +, stdout); + fputs( +" server authentication.\n" +"\n" +" You can use login options to specify protocol specific options\n" +" that may be used during authentication. At present only IMAP,\n" +" POP3 and SMTP support login options. For more information about\n" +" login options please see RFC 2384, RFC 5092 and the IETF draft\n" +" https://datatracker.ietf.org/doc/html/draft-earhart-url-smtp-00\n" +"\n" +, stdout); + fputs( +" Since 8.2.0, IMAP supports the login option \"AUTH=+LOGIN\". With\n" +" this option, curl uses the plain (not SASL) \"LOGIN IMAP\" command\n" +" even if the server advertises SASL authentication. Care should\n" +" be taken in using this option, as it sends your password over\n" +" the network in plain text. This does not work if the IMAP server\n" +" disables the plain \"LOGIN\" (e.g. to prevent password snooping).\n" +"\n" +, stdout); + fputs( +" If --login-options is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --login-options 'AUTH=*' imap://example.com\n" +"\n" +" See also -u, --user.\n" +"\n" +" --mail-auth
\n" +" (SMTP) Specify a single address. This is used to specify the au-\n" +" thentication address (identity) of a submitted message that is\n" +" being relayed to another server.\n" +"\n" +, stdout); + fputs( +" If --mail-auth is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --mail-auth user@example.come -T mail smtp://example.com/\n" +"\n" +" See also --mail-rcpt and --mail-from.\n" +"\n" +" --mail-from
\n" +" (SMTP) Specify a single address that the given mail should get\n" +" sent from.\n" +"\n" +" If --mail-from is provided several times, the last set value is\n" +" used.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --mail-from user@example.com -T mail smtp://example.com/\n" +"\n" +" See also --mail-rcpt and --mail-auth.\n" +"\n" +" --mail-rcpt-allowfails\n" +" (SMTP) When sending data to multiple recipients, by default curl\n" +" aborts SMTP conversation if at least one of the recipients\n" +" causes RCPT TO command to return an error.\n" +"\n" +" The default behavior can be changed by passing --mail-rcpt-al-\n" +, stdout); + fputs( +" lowfails command-line option which makes curl ignore errors and\n" +" proceed with the remaining valid recipients.\n" +"\n" +" If all recipients trigger RCPT TO failures and this flag is\n" +" specified, curl still aborts the SMTP conversation and returns\n" +" the error received from to the last RCPT TO command.\n" +"\n" +" Providing --mail-rcpt-allowfails multiple times has no extra ef-\n" +, stdout); + fputs( +" fect. Disable it again with --no-mail-rcpt-allowfails.\n" +"\n" +" Example:\n" +" curl --mail-rcpt-allowfails --mail-rcpt dest@example.com smtp://example.com\n" +"\n" +" See also --mail-rcpt. Added in 7.69.0.\n" +"\n" +" --mail-rcpt
\n" +" (SMTP) Specify a single email address, user name or mailing list\n" +" name. Repeat this option several times to send to multiple re-\n" +" cipients.\n" +"\n" +, stdout); + fputs( +" When performing an address verification (VRFY command), the re-\n" +" cipient should be specified as the user name or user name and\n" +" domain (as per Section 3.5 of RFC 5321).\n" +"\n" +" When performing a mailing list expand (EXPN command), the recip-\n" +" ient should be specified using the mailing list name, such as\n" +" \"Friends\" or \"London-Office\".\n" +"\n" +" --mail-rcpt can be used several times in a command line\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --mail-rcpt user@example.net smtp://example.com\n" +"\n" +" See also --mail-rcpt-allowfails.\n" +"\n" +" -M, --manual\n" +" Manual. Display the huge help text.\n" +"\n" +" Example:\n" +" curl --manual\n" +"\n" +" See also -v, --verbose, --libcurl and --trace.\n" +"\n" +" --max-filesize \n" +" (FTP HTTP MQTT) Specify the maximum size (in bytes) of a file to\n" +, stdout); + fputs( +" download. If the file requested is larger than this value, the\n" +" transfer does not start and curl returns with exit code 63.\n" +"\n" +" A size modifier may be used. For example, Appending 'k' or 'K'\n" +" counts the number as kilobytes, 'm' or 'M' makes it megabytes,\n" +" while 'g' or 'G' makes it gigabytes. Examples: 200K, 3m and 1G.\n" +" (Added in 7.58.0)\n" +"\n" +, stdout); + fputs( +" NOTE: before curl 8.4.0, when the file size is not known prior\n" +" to download, for such files this option has no effect even if\n" +" the file transfer ends up being larger than this given limit.\n" +"\n" +" Starting with curl 8.4.0, this option aborts the transfer if it\n" +" reaches the threshold during transfer.\n" +"\n" +" If --max-filesize is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +, stdout); + fputs( +" curl --max-filesize 100K https://example.com\n" +"\n" +" See also --limit-rate.\n" +"\n" +" --max-redirs \n" +" (HTTP) Set maximum number of redirections to follow. When -L,\n" +" --location is used, to prevent curl from following too many\n" +" redirects, by default, the limit is set to 50 redirects. Set\n" +" this option to -1 to make it unlimited.\n" +"\n" +" If --max-redirs is provided several times, the last set value is\n" +, stdout); + fputs( +" used.\n" +"\n" +" Example:\n" +" curl --max-redirs 3 --location https://example.com\n" +"\n" +" See also -L, --location.\n" +"\n" +" -m, --max-time \n" +" Maximum time in seconds that you allow each transfer to take.\n" +" This is useful for preventing your batch jobs from hanging for\n" +" hours due to slow networks or links going down. This option ac-\n" +" cepts decimal values.\n" +"\n" +, stdout); + fputs( +" If you enable retrying the transfer (--retry) then the maximum\n" +" time counter is reset each time the transfer is retried. You can\n" +" use --retry-max-time to limit the retry time.\n" +"\n" +" The decimal value needs to provided using a dot (.) as decimal\n" +" separator - not the local version even if it might be using an-\n" +" other separator.\n" +"\n" +" If --max-time is provided several times, the last set value is\n" +, stdout); + fputs( +" used.\n" +"\n" +" Examples:\n" +" curl --max-time 10 https://example.com\n" +" curl --max-time 2.92 https://example.com\n" +"\n" +" See also --connect-timeout and --retry-max-time.\n" +"\n" +" --metalink\n" +" This option was previously used to specify a Metalink resource.\n" +" Metalink support is disabled in curl for security reasons (added\n" +" in 7.78.0).\n" +"\n" +, stdout); + fputs( +" If --metalink is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --metalink file https://example.com\n" +"\n" +" See also -Z, --parallel.\n" +"\n" +" --negotiate\n" +" (HTTP) Enables Negotiate (SPNEGO) authentication.\n" +"\n" +" This option requires a library built with GSS-API or SSPI sup-\n" +" port. Use -V, --version to see if your curl supports\n" +" GSS-API/SSPI or SPNEGO.\n" +, stdout); + fputs( +"\n" +" When using this option, you must also provide a fake -u, --user\n" +" option to activate the authentication code properly. Sending a\n" +" '-u :' is enough as the user name and password from the -u,\n" +" --user option are not actually used.\n" +"\n" +" Providing --negotiate multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --negotiate -u : https://example.com\n" +"\n" +, stdout); + fputs( +" See also --basic, --ntlm, --anyauth and --proxy-negotiate.\n" +"\n" +" --netrc-file \n" +" This option is similar to -n, --netrc, except that you provide\n" +" the path (absolute or relative) to the netrc file that curl\n" +" should use. You can only specify one netrc file per invocation.\n" +"\n" +" It abides by --netrc-optional if specified.\n" +"\n" +" If --netrc-file is provided several times, the last set value is\n" +" used.\n" +, stdout); + fputs( +"\n" +" Example:\n" +" curl --netrc-file netrc https://example.com\n" +"\n" +" See also -n, --netrc, -u, --user and -K, --config. This option\n" +" is mutually exclusive to -n, --netrc.\n" +"\n" +" --netrc-optional\n" +" Similar to -n, --netrc, but this option makes the .netrc usage\n" +" optional and not mandatory as the -n, --netrc option does.\n" +"\n" +" Providing --netrc-optional multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-netrc-optional.\n" +"\n" +" Example:\n" +" curl --netrc-optional https://example.com\n" +"\n" +" See also --netrc-file. This option is mutually exclusive to -n,\n" +" --netrc.\n" +"\n" +" -n, --netrc\n" +" Makes curl scan the .netrc file in the user's home directory for\n" +" login name and password. This is typically used for FTP on Unix.\n" +" If used with HTTP, curl enables user authentication. See\n" +, stdout); + fputs( +" netrc(5) and ftp(1) for details on the file format. Curl does\n" +" not complain if that file does not have the right permissions\n" +" (it should be neither world- nor group-readable). The environ-\n" +" ment variable \"HOME\" is used to find the home directory.\n" +"\n" +" On Windows two filenames in the home directory are checked:\n" +" .netrc and _netrc, preferring the former. Older versions on Win-\n" +, stdout); + fputs( +" dows checked for _netrc only.\n" +"\n" +" A quick and simple example of how to setup a .netrc to allow\n" +" curl to FTP to the machine host.domain.com with user name 'my-\n" +" self' and password 'secret' could look similar to:\n" +"\n" +" machine host.domain.com\n" +" login myself\n" +" password secret\n" +"\n" +" Providing --netrc multiple times has no extra effect.\n" +" Disable it again with --no-netrc.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --netrc https://example.com\n" +"\n" +" See also --netrc-file, -K, --config and -u, --user. This option\n" +" is mutually exclusive to --netrc-file and --netrc-optional.\n" +"\n" +" -:, --next\n" +" Tells curl to use a separate operation for the following URL and\n" +" associated options. This allows you to send several URL re-\n" +" quests, each with their own specific options, for example, such\n" +, stdout); + fputs( +" as different user names or custom requests for each.\n" +"\n" +" -:, --next resets all local options and only global ones have\n" +" their values survive over to the operation following the -:,\n" +" --next instruction. Global options include -v, --verbose,\n" +" --trace, --trace-ascii and --fail-early.\n" +"\n" +" For example, you can do both a GET and a POST in a single com-\n" +" mand line:\n" +"\n" +, stdout); + fputs( +" curl www1.example.com --next -d postthis www2.example.com\n" +"\n" +" --next can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl https://example.com --next -d postthis www2.example.com\n" +" curl -I https://example.com --next https://example.net/\n" +"\n" +" See also -Z, --parallel and -K, --config.\n" +"\n" +" --no-alpn\n" +" (HTTPS) Disable the ALPN TLS extension. ALPN is enabled by de-\n" +, stdout); + fputs( +" fault if libcurl was built with an SSL library that supports\n" +" ALPN. ALPN is used by a libcurl that supports HTTP/2 to negoti-\n" +" ate HTTP/2 support with the server during https sessions.\n" +"\n" +" Note that this is the negated option name documented. You can\n" +" use --alpn to enable ALPN.\n" +"\n" +" Providing --no-alpn multiple times has no extra effect. Disable\n" +" it again with --alpn.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --no-alpn https://example.com\n" +"\n" +" See also --no-npn and --http2. --no-alpn requires that the un-\n" +" derlying libcurl was built to support TLS.\n" +"\n" +" -N, --no-buffer\n" +" Disables the buffering of the output stream. In normal work sit-\n" +" uations, curl uses a standard buffered output stream that has\n" +" the effect that it outputs the data in chunks, not necessarily\n" +, stdout); + fputs( +" exactly when the data arrives. Using this option disables that\n" +" buffering.\n" +"\n" +" Note that this is the negated option name documented. You can\n" +" use --buffer to enable buffering again.\n" +"\n" +" Providing --no-buffer multiple times has no extra effect. Dis-\n" +" able it again with --buffer.\n" +"\n" +" Example:\n" +" curl --no-buffer https://example.com\n" +"\n" +" See also -#, --progress-bar.\n" +"\n" +, stdout); + fputs( +" --no-clobber\n" +" When used in conjunction with the -o, --output, -J, --re-\n" +" mote-header-name, -O, --remote-name, or --remote-name-all op-\n" +" tions, curl avoids overwriting files that already exist. In-\n" +" stead, a dot and a number gets appended to the name of the file\n" +" that would be created, up to filename.100 after which it does\n" +" not create any file.\n" +"\n" +, stdout); + fputs( +" Note that this is the negated option name documented. You can\n" +" thus use --clobber to enforce the clobbering, even if -J, --re-\n" +" mote-header-name is specified.\n" +"\n" +" Providing --no-clobber multiple times has no extra effect. Dis-\n" +" able it again with --clobber.\n" +"\n" +" Example:\n" +" curl --no-clobber --output local/dir/file https://example.com\n" +, stdout); + fputs( +" See also -o, --output and -O, --remote-name. Added in 7.83.0.\n" +"\n" +" --no-keepalive\n" +" Disables the use of keepalive messages on the TCP connection.\n" +" curl otherwise enables them by default.\n" +"\n" +" Note that this is the negated option name documented. You can\n" +" thus use --keepalive to enforce keepalive.\n" +"\n" +" Providing --no-keepalive multiple times has no extra effect.\n" +" Disable it again with --keepalive.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --no-keepalive https://example.com\n" +"\n" +" See also --keepalive-time.\n" +"\n" +" --no-npn\n" +" (HTTPS) curl never uses NPN, this option has no effect (added in\n" +" 7.86.0).\n" +"\n" +" Disable the NPN TLS extension. NPN is enabled by default if\n" +" libcurl was built with an SSL library that supports NPN. NPN is\n" +" used by a libcurl that supports HTTP/2 to negotiate HTTP/2 sup-\n" +, stdout); + fputs( +" port with the server during https sessions.\n" +"\n" +" Providing --no-npn multiple times has no extra effect. Disable\n" +" it again with --npn.\n" +"\n" +" Example:\n" +" curl --no-npn https://example.com\n" +"\n" +" See also --no-alpn and --http2. --no-npn requires that the un-\n" +" derlying libcurl was built to support TLS.\n" +"\n" +" --no-progress-meter\n" +" Option to switch off the progress meter output without muting or\n" +, stdout); + fputs( +" otherwise affecting warning and informational messages like -s,\n" +" --silent does.\n" +"\n" +" Note that this is the negated option name documented. You can\n" +" thus use --progress-meter to enable the progress meter again.\n" +"\n" +" Providing --no-progress-meter multiple times has no extra ef-\n" +" fect. Disable it again with --progress-meter.\n" +"\n" +" Example:\n" +" curl --no-progress-meter -o store https://example.com\n" +"\n" +, stdout); + fputs( +" See also -v, --verbose and -s, --silent. Added in 7.67.0.\n" +"\n" +" --no-sessionid\n" +" (TLS) Disable curl's use of SSL session-ID caching. By default\n" +" all transfers are done using the cache. Note that while nothing\n" +" should ever get hurt by attempting to reuse SSL session-IDs,\n" +" there seem to be broken SSL implementations in the wild that may\n" +" require you to disable this in order for you to succeed.\n" +"\n" +, stdout); + fputs( +" Note that this is the negated option name documented. You can\n" +" thus use --sessionid to enforce session-ID caching.\n" +"\n" +" Providing --no-sessionid multiple times has no extra effect.\n" +" Disable it again with --sessionid.\n" +"\n" +" Example:\n" +" curl --no-sessionid https://example.com\n" +"\n" +" See also -k, --insecure.\n" +"\n" +" --noproxy \n" +, stdout); + fputs( +" Comma-separated list of hosts for which not to use a proxy, if\n" +" one is specified. The only wildcard is a single \"*\" character,\n" +" which matches all hosts, and effectively disables the proxy.\n" +" Each name in this list is matched as either a domain which con-\n" +" tains the hostname, or the hostname itself. For example, \"lo-\n" +" cal.com\" would match \"local.com\", \"local.com:80\", and \"www.lo-\n" +, stdout); + fputs( +" cal.com\", but not \"www.notlocal.com\".\n" +"\n" +" This option overrides the environment variables that disable the\n" +" proxy (\"no_proxy\" and \"NO_PROXY\") (added in 7.53.0). If there is\n" +" an environment variable disabling a proxy, you can set the no\n" +" proxy list to \"\" to override it.\n" +"\n" +" IP addresses specified to this option can be provided using CIDR\n" +" notation (added in 7.86.0): an appended slash and number speci-\n" +, stdout); + fputs( +" fies the number of network bits out of the address to use in the\n" +" comparison. For example \"192.168.0.0/16\" would match all ad-\n" +" dresses starting with \"192.168\".\n" +"\n" +" If --noproxy is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --noproxy \"www.example\" https://example.com\n" +"\n" +" See also -x, --proxy.\n" +"\n" +" --ntlm-wb\n" +, stdout); + fputs( +" (HTTP) Enables NTLM much in the style --ntlm does, but hand over\n" +" the authentication to the separate binary \"ntlmauth\" application\n" +" that is executed when needed.\n" +"\n" +" Providing --ntlm-wb multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --ntlm-wb -u user:password https://example.com\n" +"\n" +" See also --ntlm and --proxy-ntlm.\n" +"\n" +" --ntlm (HTTP) Enables NTLM authentication. The NTLM authentication\n" +, stdout); + fputs( +" method was designed by Microsoft and is used by IIS web servers.\n" +" It is a proprietary protocol, reverse-engineered by clever peo-\n" +" ple and implemented in curl based on their efforts. This kind of\n" +" behavior should not be endorsed, you should encourage everyone\n" +" who uses NTLM to switch to a public and documented authentica-\n" +" tion method instead, such as Digest.\n" +"\n" +, stdout); + fputs( +" If you want to enable NTLM for your proxy authentication, then\n" +" use --proxy-ntlm.\n" +"\n" +" Providing --ntlm multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --ntlm -u user:password https://example.com\n" +"\n" +" See also --proxy-ntlm. --ntlm requires that the underlying\n" +" libcurl was built to support TLS. This option is mutually exclu-\n" +" sive to --basic and --negotiate and --digest and --anyauth.\n" +, stdout); + fputs( +"\n" +" --oauth2-bearer \n" +" (IMAP LDAP POP3 SMTP HTTP) Specify the Bearer Token for OAUTH\n" +" 2.0 server authentication. The Bearer Token is used in conjunc-\n" +" tion with the user name which can be specified as part of the\n" +" --url or -u, --user options.\n" +"\n" +" The Bearer Token and user name are formatted according to RFC\n" +" 6750.\n" +"\n" +" If --oauth2-bearer is provided several times, the last set value\n" +, stdout); + fputs( +" is used.\n" +" Example:\n" +" curl --oauth2-bearer \"mF_9.B5f-4.1JqM\" https://example.com\n" +"\n" +" See also --basic, --ntlm and --digest.\n" +"\n" +" --output-dir \n" +" This option specifies the directory in which files should be\n" +" stored, when -O, --remote-name or -o, --output are used.\n" +"\n" +" The given output directory is used for all URLs and output op-\n" +, stdout); + fputs( +" tions on the command line, up until the first -:, --next.\n" +"\n" +" If the specified target directory does not exist, the operation\n" +" fails unless --create-dirs is also used.\n" +"\n" +" If --output-dir is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --output-dir \"tmp\" -O https://example.com\n" +"\n" +" See also -O, --remote-name and -J, --remote-header-name. Added\n" +" in 7.73.0.\n" +"\n" +, stdout); + fputs( +" -o, --output \n" +" Write output to instead of stdout. If you are using {} or\n" +" [] to fetch multiple documents, you should quote the URL and you\n" +" can use '#' followed by a number in the specifier. That\n" +" variable is replaced with the current string for the URL being\n" +" fetched. Like in:\n" +"\n" +" curl \"http://{one,two}.example.com\" -o \"file_#1.txt\"\n" +"\n" +" or use several variables like:\n" +"\n" +, stdout); + fputs( +" curl \"http://{site,host}.host[1-5].example\" -o \"#1_#2\"\n" +"\n" +" You may use this option as many times as the number of URLs you\n" +" have. For example, if you specify two URLs on the same command\n" +" line, you can use it like this:\n" +"\n" +" curl -o aa example.com -o bb example.net\n" +"\n" +" and the order of the -o options and the URLs does not matter,\n" +" just that the first -o is for the first URL and so on, so the\n" +, stdout); + fputs( +" above command line can also be written as\n" +"\n" +" curl example.com example.net -o aa -o bb\n" +"\n" +" See also the --create-dirs option to create the local directo-\n" +" ries dynamically. Specifying the output as '-' (a single dash)\n" +" passes the output to stdout.\n" +"\n" +" To suppress response bodies, you can redirect output to\n" +" /dev/null:\n" +"\n" +" curl example.com -o /dev/null\n" +"\n" +" Or for Windows:\n" +"\n" +, stdout); + fputs( +" curl example.com -o nul\n" +"\n" +" --output can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl -o file https://example.com\n" +" curl \"http://{one,two}.example.com\" -o \"file_#1.txt\"\n" +" curl \"http://{site,host}.host[1-5].example\" -o \"#1_#2\"\n" +" curl -o file https://example.com -o file2 https://example.net\n" +"\n" +" See also -O, --remote-name, --remote-name-all and -J, --re-\n" +, stdout); + fputs( +" mote-header-name.\n" +"\n" +" --parallel-immediate\n" +" When doing parallel transfers, this option instructs curl that\n" +" it should rather prefer opening up more connections in parallel\n" +" at once rather than waiting to see if new transfers can be added\n" +" as multiplexed streams on another connection.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +, stdout); + fputs( +" Providing --parallel-immediate multiple times has no extra ef-\n" +" fect. Disable it again with --no-parallel-immediate.\n" +"\n" +" Example:\n" +" curl --parallel-immediate -Z https://example.com -o file1 https://example.com -o file2\n" +"\n" +" See also -Z, --parallel and --parallel-max. Added in 7.68.0.\n" +"\n" +" --parallel-max \n" +" When asked to do parallel transfers, using -Z, --parallel, this\n" +, stdout); + fputs( +" option controls the maximum amount of transfers to do simultane-\n" +" ously.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of -:, --next.\n" +" The default is 50.\n" +"\n" +" If --parallel-max is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --parallel-max 100 -Z https://example.com ftp://example.com/\n" +"\n" +, stdout); + fputs( +" See also -Z, --parallel. Added in 7.66.0.\n" +"\n" +" -Z, --parallel\n" +" Makes curl perform its transfers in parallel as compared to the\n" +" regular serial manner.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +" Providing --parallel multiple times has no extra effect. Dis-\n" +" able it again with --no-parallel.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --parallel https://example.com -o file1 https://example.com -o file2\n" +"\n" +" See also -:, --next and -v, --verbose. Added in 7.66.0.\n" +"\n" +" --pass \n" +" (SSH TLS) Passphrase for the private key.\n" +"\n" +" If --pass is provided several times, the last set value is used.\n" +"\n" +" Example:\n" +" curl --pass secret --key file https://example.com\n" +"\n" +" See also --key and -u, --user.\n" +"\n" +" --path-as-is\n" +, stdout); + fputs( +" Tell curl to not handle sequences of /../ or /./ in the given\n" +" URL path. Normally curl squashes or merges them according to\n" +" standards but with this option set you tell it not to do that.\n" +"\n" +" Providing --path-as-is multiple times has no extra effect. Dis-\n" +" able it again with --no-path-as-is.\n" +"\n" +" Example:\n" +" curl --path-as-is https://example.com/../../etc/passwd\n" +"\n" +, stdout); + fputs( +" See also --request-target.\n" +"\n" +" --pinnedpubkey \n" +" (TLS) Tells curl to use the specified public key file (or\n" +" hashes) to verify the peer. This can be a path to a file which\n" +" contains a single public key in PEM or DER format, or any number\n" +" of base64 encoded sha256 hashes preceded by 'sha256//' and sepa-\n" +" rated by ';'.\n" +"\n" +" When negotiating a TLS or SSL connection, the server sends a\n" +, stdout); + fputs( +" certificate indicating its identity. A public key is extracted\n" +" from this certificate and if it does not exactly match the pub-\n" +" lic key provided to this option, curl aborts the connection be-\n" +" fore sending or receiving any data.\n" +"\n" +" This option is independent of option -k, --insecure. If you use\n" +" both options together then the peer is still verified by public\n" +" key.\n" +"\n" +" PEM/DER support:\n" +"\n" +, stdout); + fputs( +" OpenSSL and GnuTLS, wolfSSL (added in 7.43.0), mbedTLS , Secure\n" +" Transport macOS 10.7+/iOS 10+ (7.54.1), Schannel (7.58.1)\n" +"\n" +" sha256 support:\n" +"\n" +" OpenSSL, GnuTLS and wolfSSL, mbedTLS (added in 7.47.0), Secure\n" +" Transport macOS 10.7+/iOS 10+ (7.54.1), Schannel (7.58.1)\n" +"\n" +" Other SSL backends not supported.\n" +"\n" +" If --pinnedpubkey is provided several times, the last set value\n" +" is used.\n" +"\n" +, stdout); + fputs( +" Examples:\n" +" curl --pinnedpubkey keyfile https://example.com\n" +" curl --pinnedpubkey 'sha256//ce118b51897f4452dc' https://example.com\n" +"\n" +" See also --hostpubsha256.\n" +"\n" +" --post301\n" +" (HTTP) Tells curl to respect RFC 7231/6.4.2 and not convert POST\n" +" requests into GET requests when following a 301 redirection. The\n" +" non-RFC behavior is ubiquitous in web browsers, so curl does the\n" +, stdout); + fputs( +" conversion by default to maintain consistency. However, a server\n" +" may require a POST to remain a POST after such a redirection.\n" +" This option is meaningful only when using -L, --location.\n" +"\n" +" Providing --post301 multiple times has no extra effect. Disable\n" +" it again with --no-post301.\n" +"\n" +" Example:\n" +" curl --post301 --location -d \"data\" https://example.com\n" +"\n" +, stdout); + fputs( +" See also --post302, --post303 and -L, --location.\n" +"\n" +" --post302\n" +" (HTTP) Tells curl to respect RFC 7231/6.4.3 and not convert POST\n" +" requests into GET requests when following a 302 redirection. The\n" +" non-RFC behavior is ubiquitous in web browsers, so curl does the\n" +" conversion by default to maintain consistency. However, a server\n" +" may require a POST to remain a POST after such a redirection.\n" +, stdout); + fputs( +" This option is meaningful only when using -L, --location.\n" +"\n" +" Providing --post302 multiple times has no extra effect. Disable\n" +" it again with --no-post302.\n" +"\n" +" Example:\n" +" curl --post302 --location -d \"data\" https://example.com\n" +"\n" +" See also --post301, --post303 and -L, --location.\n" +"\n" +" --post303\n" +" (HTTP) Tells curl to violate RFC 7231/6.4.4 and not convert POST\n" +, stdout); + fputs( +" requests into GET requests when following 303 redirections. A\n" +" server may require a POST to remain a POST after a 303 redirec-\n" +" tion. This option is meaningful only when using -L, --location.\n" +"\n" +" Providing --post303 multiple times has no extra effect. Disable\n" +" it again with --no-post303.\n" +"\n" +" Example:\n" +" curl --post303 --location -d \"data\" https://example.com\n" +"\n" +, stdout); + fputs( +" See also --post302, --post301 and -L, --location.\n" +"\n" +" --preproxy [protocol://]host[:port]\n" +" Use the specified SOCKS proxy before connecting to an HTTP or\n" +" HTTPS -x, --proxy. In such a case curl first connects to the\n" +" SOCKS proxy and then connects (through SOCKS) to the HTTP or\n" +" HTTPS proxy. Hence pre proxy.\n" +"\n" +" The pre proxy string should be specified with a protocol:// pre-\n" +, stdout); + fputs( +" fix to specify alternative proxy protocols. Use socks4://,\n" +" socks4a://, socks5:// or socks5h:// to request the specific\n" +" SOCKS version to be used. No protocol specified makes curl de-\n" +" fault to SOCKS4.\n" +"\n" +" If the port number is not specified in the proxy string, it is\n" +" assumed to be 1080.\n" +"\n" +" User and password that might be provided in the proxy string are\n" +, stdout); + fputs( +" URL decoded by curl. This allows you to pass in special charac-\n" +" ters such as @ by using %40 or pass in a colon with %3a.\n" +"\n" +" If --preproxy is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --preproxy socks5://proxy.example -x http://http.example https://example.com\n" +"\n" +" See also -x, --proxy and --socks5. Added in 7.52.0.\n" +"\n" +" -#, --progress-bar\n" +, stdout); + fputs( +" Make curl display transfer progress as a simple progress bar in-\n" +" stead of the standard, more informational, meter.\n" +"\n" +" This progress bar draws a single line of '#' characters across\n" +" the screen and shows a percentage if the transfer size is known.\n" +" For transfers without a known size, there is a space ship\n" +" (-=o=-) that moves back and forth but only while data is being\n" +, stdout); + fputs( +" transferred, with a set of flying hash sign symbols on top.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +" Providing --progress-bar multiple times has no extra effect.\n" +" Disable it again with --no-progress-bar.\n" +"\n" +" Example:\n" +" curl -# -O https://example.com\n" +"\n" +" See also --styled-output.\n" +"\n" +" --proto-default \n" +, stdout); + fputs( +" Tells curl to use protocol for any URL missing a scheme name.\n" +"\n" +" An unknown or unsupported protocol causes error CURLE_UNSUP-\n" +" PORTED_PROTOCOL (1).\n" +"\n" +" This option does not change the default proxy protocol (http).\n" +"\n" +" Without this option set, curl guesses protocol based on the host\n" +" name, see --url for details.\n" +"\n" +" If --proto-default is provided several times, the last set value\n" +" is used.\n" +, stdout); + fputs( +" Example:\n" +" curl --proto-default https ftp.example.com\n" +"\n" +" See also --proto and --proto-redir.\n" +"\n" +" --proto-redir \n" +" Tells curl to limit what protocols it may use on redirect. Pro-\n" +" tocols denied by --proto are not overridden by this option. See\n" +" --proto for how protocols are represented.\n" +"\n" +" Example, allow only HTTP and HTTPS on redirect:\n" +"\n" +, stdout); + fputs( +" curl --proto-redir -all,http,https http://example.com\n" +"\n" +" By default curl only allows HTTP, HTTPS, FTP and FTPS on redi-\n" +" rects (added in 7.65.2). Specifying all or +all enables all pro-\n" +" tocols on redirects, which is not good for security.\n" +"\n" +" If --proto-redir is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --proto-redir =http,https https://example.com\n" +"\n" +, stdout); + fputs( +" See also --proto.\n" +"\n" +" --proto \n" +" Tells curl to limit what protocols it may use for transfers.\n" +" Protocols are evaluated left to right, are comma separated, and\n" +" are each a protocol name or 'all', optionally prefixed by zero\n" +" or more modifiers. Available modifiers are:\n" +"\n" +" + Permit this protocol in addition to protocols already\n" +, stdout); + fputs( +" permitted (this is the default if no modifier is used).\n" +"\n" +" - Deny this protocol, removing it from the list of proto-\n" +" cols already permitted.\n" +"\n" +" = Permit only this protocol (ignoring the list already per-\n" +" mitted), though subject to later modification by subse-\n" +" quent entries in the comma separated list.\n" +"\n" +, stdout); + fputs( +" For example: --proto -ftps uses the default protocols, but dis-\n" +" ables ftps\n" +"\n" +" --proto -all,https,+http only enables http and https\n" +" --proto =http,https also only enables http and https\n" +"\n" +" Unknown and disabled protocols produce a warning. This allows\n" +" scripts to safely rely on being able to disable potentially dan-\n" +" gerous protocols, without relying upon support for that protocol\n" +, stdout); + fputs( +" being built into curl to avoid an error.\n" +"\n" +" This option can be used multiple times, in which case the effect\n" +" is the same as concatenating the protocols into one instance of\n" +" the option.\n" +"\n" +" If --proto is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --proto =http,https,sftp https://example.com\n" +"\n" +" See also --proto-redir and --proto-default.\n" +"\n" +, stdout); + fputs( +" --proxy-anyauth\n" +" Tells curl to pick a suitable authentication method when commu-\n" +" nicating with the given HTTP proxy. This might cause an extra\n" +" request/response round-trip.\n" +"\n" +" Providing --proxy-anyauth multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --proxy-anyauth --proxy-user user:passwd -x proxy https://example.com\n" +"\n" +" See also -x, --proxy, --proxy-basic and --proxy-digest.\n" +"\n" +, stdout); + fputs( +" --proxy-basic\n" +" Tells curl to use HTTP Basic authentication when communicating\n" +" with the given proxy. Use --basic for enabling HTTP Basic with a\n" +" remote host. Basic is the default authentication method curl\n" +" uses with proxies.\n" +"\n" +" Providing --proxy-basic multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --proxy-basic --proxy-user user:passwd -x proxy https://example.com\n" +"\n" +, stdout); + fputs( +" See also -x, --proxy, --proxy-anyauth and --proxy-digest.\n" +"\n" +" --proxy-ca-native\n" +" (TLS) Tells curl to use the CA store from the native operating\n" +" system to verify the HTTPS proxy. By default, curl uses a CA\n" +" store provided in a single file or directory, but when using\n" +" this option it interfaces the operating system's own vault.\n" +"\n" +" This option works for curl on Windows when built to use OpenSSL,\n" +, stdout); + fputs( +" wolfSSL (added in 8.3.0) or GnuTLS (added in 8.5.0). When curl\n" +" on Windows is built to use Schannel, this feature is implied and\n" +" curl then only uses the native CA store.\n" +"\n" +" Providing --proxy-ca-native multiple times has no extra effect.\n" +" Disable it again with --no-proxy-ca-native.\n" +"\n" +" Example:\n" +" curl --ca-native https://example.com\n" +"\n" +, stdout); + fputs( +" See also --cacert, --capath and -k, --insecure. Added in 8.2.0.\n" +"\n" +" --proxy-cacert \n" +" Same as --cacert but used in HTTPS proxy context.\n" +"\n" +" If --proxy-cacert is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --proxy-cacert CA-file.txt -x https://proxy https://example.com\n" +"\n" +" See also --proxy-capath, --cacert, --capath and -x, --proxy.\n" +" Added in 7.52.0.\n" +"\n" +, stdout); + fputs( +" --proxy-capath \n" +" Same as --capath but used in HTTPS proxy context.\n" +"\n" +" If --proxy-capath is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --proxy-capath /local/directory -x https://proxy https://example.com\n" +"\n" +" See also --proxy-cacert, -x, --proxy and --capath. Added in\n" +" 7.52.0.\n" +"\n" +" --proxy-cert-type \n" +, stdout); + fputs( +" Same as --cert-type but used in HTTPS proxy context.\n" +"\n" +" If --proxy-cert-type is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --proxy-cert-type PEM --proxy-cert file -x https://proxy https://example.com\n" +"\n" +" See also --proxy-cert. Added in 7.52.0.\n" +"\n" +" --proxy-cert \n" +" Same as -E, --cert but used in HTTPS proxy context.\n" +"\n" +, stdout); + fputs( +" If --proxy-cert is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --proxy-cert file -x https://proxy https://example.com\n" +"\n" +" See also --proxy-cert-type. Added in 7.52.0.\n" +"\n" +" --proxy-ciphers \n" +" Same as --ciphers but used in HTTPS proxy context.\n" +"\n" +" Specifies which ciphers to use in the connection to the HTTPS\n" +, stdout); + fputs( +" proxy. The list of ciphers must specify valid ciphers. Read up\n" +" on SSL cipher list details on this URL:\n" +"\n" +" https://curl.se/docs/ssl-ciphers.html\n" +"\n" +" If --proxy-ciphers is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --proxy-ciphers ECDHE-ECDSA-AES256-CCM8 -x https://proxy https://example.com\n" +"\n" +" See also --ciphers, --curves and -x, --proxy. Added in 7.52.0.\n" +"\n" +, stdout); + fputs( +" --proxy-crlfile \n" +" Same as --crlfile but used in HTTPS proxy context.\n" +"\n" +" If --proxy-crlfile is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --proxy-crlfile rejects.txt -x https://proxy https://example.com\n" +"\n" +" See also --crlfile and -x, --proxy. Added in 7.52.0.\n" +"\n" +" --proxy-digest\n" +" Tells curl to use HTTP Digest authentication when communicating\n" +, stdout); + fputs( +" with the given proxy. Use --digest for enabling HTTP Digest with\n" +" a remote host.\n" +"\n" +" Providing --proxy-digest multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --proxy-digest --proxy-user user:passwd -x proxy https://example.com\n" +"\n" +" See also -x, --proxy, --proxy-anyauth and --proxy-basic.\n" +"\n" +" --proxy-header
\n" +" (HTTP) Extra header to include in the request when sending HTTP\n" +, stdout); + fputs( +" to a proxy. You may specify any number of extra headers. This is\n" +" the equivalent option to -H, --header but is for proxy communi-\n" +" cation only like in CONNECT requests when you want a separate\n" +" header sent to the proxy to what is sent to the actual remote\n" +" host.\n" +"\n" +" curl makes sure that each header you add/replace is sent with\n" +" the proper end-of-line marker, you should thus not add that as a\n" +, stdout); + fputs( +" part of the header content: do not add newlines or carriage re-\n" +" turns, they only mess things up for you.\n" +"\n" +" Headers specified with this option are not included in requests\n" +" that curl knows are not be sent to a proxy.\n" +"\n" +" This option can take an argument in @filename style, which then\n" +" adds a header for each line in the input file (added in 7.55.0).\n" +" Using @- makes curl read the headers from stdin.\n" +"\n" +, stdout); + fputs( +" This option can be used multiple times to add/replace/remove\n" +" multiple headers.\n" +"\n" +" --proxy-header can be used several times in a command line\n" +"\n" +" Examples:\n" +" curl --proxy-header \"X-First-Name: Joe\" -x http://proxy https://example.com\n" +" curl --proxy-header \"User-Agent: surprise\" -x http://proxy https://example.com\n" +" curl --proxy-header \"Host:\" -x http://proxy https://example.com\n" +"\n" +, stdout); + fputs( +" See also -x, --proxy.\n" +"\n" +" --proxy-http2\n" +" (HTTP) Tells curl to try negotiate HTTP version 2 with an HTTPS\n" +" proxy. The proxy might still only offer HTTP/1 and then curl\n" +" sticks to using that version.\n" +"\n" +" This has no effect for any other kinds of proxies.\n" +"\n" +" Providing --proxy-http2 multiple times has no extra effect.\n" +" Disable it again with --no-proxy-http2.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --proxy-http2 -x proxy https://example.com\n" +"\n" +" See also -x, --proxy. --proxy-http2 requires that the underlying\n" +" libcurl was built to support HTTP/2. Added in 8.1.0.\n" +"\n" +" --proxy-insecure\n" +" Same as -k, --insecure but used in HTTPS proxy context.\n" +"\n" +" Providing --proxy-insecure multiple times has no extra effect.\n" +" Disable it again with --no-proxy-insecure.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --proxy-insecure -x https://proxy https://example.com\n" +"\n" +" See also -x, --proxy and -k, --insecure. Added in 7.52.0.\n" +"\n" +" --proxy-key-type \n" +" Same as --key-type but used in HTTPS proxy context.\n" +"\n" +" If --proxy-key-type is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --proxy-key-type DER --proxy-key here -x https://proxy https://example.com\n" +"\n" +, stdout); + fputs( +" See also --proxy-key and -x, --proxy. Added in 7.52.0.\n" +"\n" +" --proxy-key \n" +" Same as --key but used in HTTPS proxy context.\n" +"\n" +" If --proxy-key is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --proxy-key here -x https://proxy https://example.com\n" +"\n" +" See also --proxy-key-type and -x, --proxy. Added in 7.52.0.\n" +"\n" +" --proxy-negotiate\n" +, stdout); + fputs( +" Tells curl to use HTTP Negotiate (SPNEGO) authentication when\n" +" communicating with the given proxy. Use --negotiate for enabling\n" +" HTTP Negotiate (SPNEGO) with a remote host.\n" +"\n" +" Providing --proxy-negotiate multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --proxy-negotiate --proxy-user user:passwd -x proxy https://example.com\n" +"\n" +" See also --proxy-anyauth and --proxy-basic.\n" +"\n" +" --proxy-ntlm\n" +, stdout); + fputs( +" Tells curl to use HTTP NTLM authentication when communicating\n" +" with the given proxy. Use --ntlm for enabling NTLM with a remote\n" +" host.\n" +"\n" +" Providing --proxy-ntlm multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --proxy-ntlm --proxy-user user:passwd -x http://proxy https://example.com\n" +"\n" +" See also --proxy-negotiate and --proxy-anyauth.\n" +"\n" +" --proxy-pass \n" +, stdout); + fputs( +" Same as --pass but used in HTTPS proxy context.\n" +"\n" +" If --proxy-pass is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --proxy-pass secret --proxy-key here -x https://proxy https://example.com\n" +"\n" +" See also -x, --proxy and --proxy-key. Added in 7.52.0.\n" +"\n" +" --proxy-pinnedpubkey \n" +" (TLS) Tells curl to use the specified public key file (or\n" +, stdout); + fputs( +" hashes) to verify the proxy. This can be a path to a file which\n" +" contains a single public key in PEM or DER format, or any number\n" +" of base64 encoded sha256 hashes preceded by 'sha256//' and sepa-\n" +" rated by ';'.\n" +"\n" +" When negotiating a TLS or SSL connection, the server sends a\n" +" certificate indicating its identity. A public key is extracted\n" +, stdout); + fputs( +" from this certificate and if it does not exactly match the pub-\n" +" lic key provided to this option, curl aborts the connection be-\n" +" fore sending or receiving any data.\n" +"\n" +" If --proxy-pinnedpubkey is provided several times, the last set\n" +" value is used.\n" +"\n" +" Examples:\n" +" curl --proxy-pinnedpubkey keyfile https://example.com\n" +, stdout); + fputs( +" curl --proxy-pinnedpubkey 'sha256//ce118b51897f4452dc' https://example.com\n" +"\n" +" See also --pinnedpubkey and -x, --proxy. Added in 7.59.0.\n" +"\n" +" --proxy-service-name \n" +" This option allows you to change the service name for proxy ne-\n" +" gotiation.\n" +"\n" +" If --proxy-service-name is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --proxy-service-name \"shrubbery\" -x proxy https://example.com\n" +"\n" +" See also --service-name and -x, --proxy.\n" +"\n" +" --proxy-ssl-allow-beast\n" +" Same as --ssl-allow-beast but used in HTTPS proxy context.\n" +"\n" +" Providing --proxy-ssl-allow-beast multiple times has no extra\n" +" effect. Disable it again with --no-proxy-ssl-allow-beast.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --proxy-ssl-allow-beast -x https://proxy https://example.com\n" +"\n" +" See also --ssl-allow-beast and -x, --proxy. Added in 7.52.0.\n" +"\n" +" --proxy-ssl-auto-client-cert\n" +" Same as --ssl-auto-client-cert but used in HTTPS proxy context.\n" +"\n" +" Providing --proxy-ssl-auto-client-cert multiple times has no ex-\n" +" tra effect. Disable it again with --no-proxy-ssl-auto-client-\n" +" cert.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --proxy-ssl-auto-client-cert -x https://proxy https://example.com\n" +"\n" +" See also --ssl-auto-client-cert and -x, --proxy. Added in\n" +" 7.77.0.\n" +"\n" +" --proxy-tls13-ciphers \n" +" (TLS) Specifies which cipher suites to use in the connection to\n" +" your HTTPS proxy when it negotiates TLS 1.3. The list of ciphers\n" +" suites must specify valid ciphers. Read up on TLS 1.3 cipher\n" +, stdout); + fputs( +" suite details on this URL:\n" +"\n" +" https://curl.se/docs/ssl-ciphers.html\n" +"\n" +" This option is currently used only when curl is built to use\n" +" OpenSSL 1.1.1 or later. If you are using a different SSL backend\n" +" you can try setting TLS 1.3 cipher suites by using the\n" +" --proxy-ciphers option.\n" +"\n" +" If --proxy-tls13-ciphers is provided several times, the last set\n" +" value is used.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --proxy-tls13-ciphers TLS_AES_128_GCM_SHA256 -x proxy https://example.com\n" +"\n" +" See also --tls13-ciphers, --curves and --proxy-ciphers. Added in\n" +" 7.61.0.\n" +"\n" +" --proxy-tlsauthtype \n" +" Same as --tlsauthtype but used in HTTPS proxy context.\n" +"\n" +" If --proxy-tlsauthtype is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --proxy-tlsauthtype SRP -x https://proxy https://example.com\n" +"\n" +" See also -x, --proxy and --proxy-tlsuser. Added in 7.52.0.\n" +"\n" +" --proxy-tlspassword \n" +" Same as --tlspassword but used in HTTPS proxy context.\n" +"\n" +" If --proxy-tlspassword is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --proxy-tlspassword passwd -x https://proxy https://example.com\n" +"\n" +, stdout); + fputs( +" See also -x, --proxy and --proxy-tlsuser. Added in 7.52.0.\n" +"\n" +" --proxy-tlsuser \n" +" Same as --tlsuser but used in HTTPS proxy context.\n" +"\n" +" If --proxy-tlsuser is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --proxy-tlsuser smith -x https://proxy https://example.com\n" +"\n" +" See also -x, --proxy and --proxy-tlspassword. Added in 7.52.0.\n" +"\n" +" --proxy-tlsv1\n" +, stdout); + fputs( +" Same as -1, --tlsv1 but used in HTTPS proxy context.\n" +"\n" +" Providing --proxy-tlsv1 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --proxy-tlsv1 -x https://proxy https://example.com\n" +"\n" +" See also -x, --proxy. Added in 7.52.0.\n" +"\n" +" -U, --proxy-user \n" +" Specify the user name and password to use for proxy authentica-\n" +" tion.\n" +"\n" +, stdout); + fputs( +" If you use a Windows SSPI-enabled curl binary and do either Ne-\n" +" gotiate or NTLM authentication then you can tell curl to select\n" +" the user name and password from your environment by specifying a\n" +" single colon with this option: \"-U :\".\n" +"\n" +" On systems where it works, curl hides the given option argument\n" +" from process listings. This is not enough to protect credentials\n" +, stdout); + fputs( +" from possibly getting seen by other users on the same system as\n" +" they still are visible for a moment before cleared. Such sensi-\n" +" tive data should be retrieved from a file instead or similar and\n" +" never used in clear text in a command line.\n" +"\n" +" If --proxy-user is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --proxy-user name:pwd -x proxy https://example.com\n" +"\n" +, stdout); + fputs( +" See also --proxy-pass.\n" +"\n" +" -x, --proxy [protocol://]host[:port]\n" +" Use the specified proxy.\n" +"\n" +" The proxy string can be specified with a protocol:// prefix. No\n" +" protocol specified or http:// it is treated as an HTTP proxy.\n" +" Use socks4://, socks4a://, socks5:// or socks5h:// to request a\n" +" specific SOCKS version to be used.\n" +"\n" +" Unix domain sockets are supported for socks proxy. Set localhost\n" +, stdout); + fputs( +" for the host part. e.g. socks5h://localhost/path/to/socket.sock\n" +"\n" +" HTTPS proxy support works set with the https:// protocol prefix\n" +" for OpenSSL and GnuTLS (added in 7.52.0). It also works for\n" +" BearSSL, mbedTLS, rustls, Schannel, Secure Transport and wolfSSL\n" +" (added in 7.87.0).\n" +"\n" +" Unrecognized and unsupported proxy protocols cause an error\n" +, stdout); + fputs( +" (added in 7.52.0). Ancient curl versions ignored unknown\n" +" schemes and used http:// instead.\n" +"\n" +" If the port number is not specified in the proxy string, it is\n" +" assumed to be 1080.\n" +"\n" +" This option overrides existing environment variables that set\n" +" the proxy to use. If there is an environment variable setting a\n" +" proxy, you can set proxy to \"\" to override it.\n" +"\n" +, stdout); + fputs( +" All operations that are performed over an HTTP proxy are trans-\n" +" parently converted to HTTP. It means that certain protocol spe-\n" +" cific operations might not be available. This is not the case if\n" +" you can tunnel through the proxy, as one with the -p, --proxy-\n" +" tunnel option.\n" +"\n" +" User and password that might be provided in the proxy string are\n" +, stdout); + fputs( +" URL decoded by curl. This allows you to pass in special charac-\n" +" ters such as @ by using %40 or pass in a colon with %3a.\n" +"\n" +" The proxy host can be specified the same way as the proxy envi-\n" +" ronment variables, including the protocol prefix (http://) and\n" +" the embedded user + password.\n" +"\n" +" When a proxy is used, the active FTP mode as set with -P,\n" +" --ftp-port, cannot be used.\n" +"\n" +, stdout); + fputs( +" If --proxy is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --proxy http://proxy.example https://example.com\n" +"\n" +" See also --socks5 and --proxy-basic.\n" +"\n" +" --proxy1.0 \n" +" Use the specified HTTP 1.0 proxy. If the port number is not\n" +" specified, it is assumed at port 1080.\n" +"\n" +" The only difference between this and the HTTP proxy option -x,\n" +, stdout); + fputs( +" --proxy, is that attempts to use CONNECT through the proxy spec-\n" +" ifies an HTTP 1.0 protocol instead of the default HTTP 1.1.\n" +"\n" +" Providing --proxy1.0 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --proxy1.0 -x http://proxy https://example.com\n" +"\n" +" See also -x, --proxy, --socks5 and --preproxy.\n" +"\n" +" -p, --proxytunnel\n" +" When an HTTP proxy is used -x, --proxy, this option makes curl\n" +, stdout); + fputs( +" tunnel the traffic through the proxy. The tunnel approach is\n" +" made with the HTTP proxy CONNECT request and requires that the\n" +" proxy allows direct connect to the remote port number curl wants\n" +" to tunnel through to.\n" +"\n" +" To suppress proxy CONNECT response headers when curl is set to\n" +" output headers use --suppress-connect-headers.\n" +"\n" +" Providing --proxytunnel multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-proxytunnel.\n" +"\n" +" Example:\n" +" curl --proxytunnel -x http://proxy https://example.com\n" +"\n" +" See also -x, --proxy.\n" +"\n" +" --pubkey \n" +" (SFTP SCP) Public key file name. Allows you to provide your pub-\n" +" lic key in this separate file.\n" +"\n" +" curl attempts to automatically extract the public key from the\n" +" private key file, so passing this option is generally not re-\n" +, stdout); + fputs( +" quired. Note that this public key extraction requires libcurl to\n" +" be linked against a copy of libssh2 1.2.8 or higher that is it-\n" +" self linked against OpenSSL.\n" +"\n" +" If --pubkey is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --pubkey file.pub sftp://example.com/\n" +"\n" +" See also --pass.\n" +"\n" +" -Q, --quote \n" +, stdout); + fputs( +" (FTP SFTP) Send an arbitrary command to the remote FTP or SFTP\n" +" server. Quote commands are sent BEFORE the transfer takes place\n" +" (just after the initial PWD command in an FTP transfer, to be\n" +" exact). To make commands take place after a successful transfer,\n" +" prefix them with a dash '-'.\n" +"\n" +" (FTP only) To make commands be sent after curl has changed the\n" +, stdout); + fputs( +" working directory, just before the file transfer command(s),\n" +" prefix the command with a '+'. This is not performed when a di-\n" +" rectory listing is performed.\n" +"\n" +" You may specify any number of commands.\n" +"\n" +" By default curl stops at first failure. To make curl continue\n" +" even if the command fails, prefix the command with an asterisk\n" +" (*). Otherwise, if the server returns failure for one of the\n" +, stdout); + fputs( +" commands, the entire operation is aborted.\n" +"\n" +" You must send syntactically correct FTP commands as RFC 959 de-\n" +" fines to FTP servers, or one of the commands listed below to\n" +" SFTP servers.\n" +"\n" +" SFTP is a binary protocol. Unlike for FTP, curl interprets SFTP\n" +" quote commands itself before sending them to the server. File\n" +" names may be quoted shell-style to embed spaces or special char-\n" +, stdout); + fputs( +" acters. Following is the list of all supported SFTP quote com-\n" +" mands:\n" +"\n" +" atime date file\n" +" The atime command sets the last access time of the file\n" +" named by the file operand. The can be\n" +" all sorts of date strings, see the curl_getdate(3) man\n" +" page for date expression details. (Added in 7.73.0)\n" +"\n" +" chgrp group file\n" +, stdout); + fputs( +" The chgrp command sets the group ID of the file named by\n" +" the file operand to the group ID specified by the group\n" +" operand. The group operand is a decimal integer group ID.\n" +"\n" +" chmod mode file\n" +" The chmod command modifies the file mode bits of the\n" +" specified file. The mode operand is an octal integer mode\n" +" number.\n" +"\n" +" chown user file\n" +, stdout); + fputs( +" The chown command sets the owner of the file named by the\n" +" file operand to the user ID specified by the user\n" +" operand. The user operand is a decimal integer user ID.\n" +"\n" +" ln source_file target_file\n" +" The ln and symlink commands create a symbolic link at the\n" +" target_file location pointing to the source_file loca-\n" +" tion.\n" +"\n" +" mkdir directory_name\n" +, stdout); + fputs( +" The mkdir command creates the directory named by the di-\n" +" rectory_name operand.\n" +"\n" +" mtime date file\n" +" The mtime command sets the last modification time of the\n" +" file named by the file operand. The can\n" +" be all sorts of date strings, see the curl_getdate(3) man\n" +" page for date expression details. (Added in 7.73.0)\n" +"\n" +, stdout); + fputs( +" pwd The pwd command returns the absolute path name of the\n" +" current working directory.\n" +"\n" +" rename source target\n" +" The rename command renames the file or directory named by\n" +" the source operand to the destination path named by the\n" +" target operand.\n" +"\n" +" rm file\n" +" The rm command removes the file specified by the file\n" +" operand.\n" +"\n" +, stdout); + fputs( +" rmdir directory\n" +" The rmdir command removes the directory entry specified\n" +" by the directory operand, provided it is empty.\n" +"\n" +" symlink source_file target_file\n" +" See ln.\n" +"\n" +" --quote can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --quote \"DELE file\" ftp://example.com/foo\n" +"\n" +" See also -X, --request.\n" +"\n" +" --random-file \n" +, stdout); + fputs( +" Deprecated option. This option is ignored (added in 7.84.0).\n" +" Prior to that it only had an effect on curl if built to use old\n" +" versions of OpenSSL.\n" +"\n" +" Specify the path name to file containing random data. The data\n" +" may be used to seed the random engine for SSL connections.\n" +"\n" +" If --random-file is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +, stdout); + fputs( +" curl --random-file rubbish https://example.com\n" +"\n" +" See also --egd-file.\n" +"\n" +" -r, --range \n" +" (HTTP FTP SFTP FILE) Retrieve a byte range (i.e. a partial docu-\n" +" ment) from an HTTP/1.1, FTP or SFTP server or a local FILE.\n" +" Ranges can be specified in a number of ways.\n" +"\n" +" 0-499 specifies the first 500 bytes\n" +"\n" +" 500-999\n" +" specifies the second 500 bytes\n" +"\n" +, stdout); + fputs( +" -500 specifies the last 500 bytes\n" +"\n" +" 9500- specifies the bytes from offset 9500 and forward\n" +"\n" +" 0-0,-1 specifies the first and last byte only(*)(HTTP)\n" +"\n" +" 100-199,500-599\n" +" specifies two separate 100-byte ranges(*) (HTTP)\n" +"\n" +" (*) = NOTE that these make the server reply with a multipart re-\n" +" sponse, which is returned as-is by curl! Parsing or otherwise\n" +, stdout); + fputs( +" transforming this response is the responsibility of the caller.\n" +"\n" +" Only digit characters (0-9) are valid in the 'start' and 'stop'\n" +" fields of the 'start-stop' range syntax. If a non-digit charac-\n" +" ter is given in the range, the server's response is unspecified,\n" +" depending on the server's configuration.\n" +"\n" +" Many HTTP/1.1 servers do not have this feature enabled, so that\n" +, stdout); + fputs( +" when you attempt to get a range, curl instead gets the whole\n" +" document.\n" +"\n" +" FTP and SFTP range downloads only support the simple\n" +" 'start-stop' syntax (optionally with one of the numbers omit-\n" +" ted). FTP use depends on the extended FTP command SIZE.\n" +"\n" +" If --range is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --range 22-44 https://example.com\n" +"\n" +" See also -C, --continue-at and -a, --append.\n" +"\n" +" --rate \n" +" Specify the maximum transfer frequency you allow curl to use -\n" +" in number of transfer starts per time unit (sometimes called re-\n" +" quest rate). Without this option, curl starts the next transfer\n" +" as fast as possible.\n" +"\n" +" If given several URLs and a transfer completes faster than the\n" +, stdout); + fputs( +" allowed rate, curl waits until the next transfer is started to\n" +" maintain the requested rate. This option has no effect when -Z,\n" +" --parallel is used.\n" +"\n" +" The request rate is provided as \"N/U\" where N is an integer num-\n" +" ber and U is a time unit. Supported units are 's' (second), 'm'\n" +" (minute), 'h' (hour) and 'd' /(day, as in a 24 hour unit). The\n" +, stdout); + fputs( +" default time unit, if no \"/U\" is provided, is number of trans-\n" +" fers per hour.\n" +"\n" +" If curl is told to allow 10 requests per minute, it does not\n" +" start the next request until 6 seconds have elapsed since the\n" +" previous transfer was started.\n" +"\n" +" This function uses millisecond resolution. If the allowed fre-\n" +" quency is set more than 1000 per second, it instead runs unre-\n" +" stricted.\n" +"\n" +, stdout); + fputs( +" When retrying transfers, enabled with --retry, the separate\n" +" retry delay logic is used and not this setting.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +" If --rate is provided several times, the last set value is used.\n" +"\n" +" Examples:\n" +" curl --rate 2/s https://example.com ...\n" +" curl --rate 3/h https://example.com ...\n" +, stdout); + fputs( +" curl --rate 14/m https://example.com ...\n" +"\n" +" See also --limit-rate and --retry-delay. Added in 7.84.0.\n" +"\n" +" --raw (HTTP) When used, it disables all internal HTTP decoding of con-\n" +" tent or transfer encodings and instead makes them passed on un-\n" +" altered, raw.\n" +"\n" +" Providing --raw multiple times has no extra effect. Disable it\n" +" again with --no-raw.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --raw https://example.com\n" +"\n" +" See also --tr-encoding.\n" +"\n" +" -e, --referer \n" +" (HTTP) Sends the \"Referrer Page\" information to the HTTP server.\n" +" This can also be set with the -H, --header flag of course. When\n" +" used with -L, --location you can append \";auto\" to the -e,\n" +" --referer URL to make curl automatically set the previous URL\n" +, stdout); + fputs( +" when it follows a Location: header. The \";auto\" string can be\n" +" used alone, even if you do not set an initial -e, --referer.\n" +"\n" +" If --referer is provided several times, the last set value is\n" +" used.\n" +"\n" +" Examples:\n" +" curl --referer \"https://fake.example\" https://example.com\n" +" curl --referer \"https://fake.example;auto\" -L https://example.com\n" +" curl --referer \";auto\" -L https://example.com\n" +"\n" +, stdout); + fputs( +" See also -A, --user-agent and -H, --header.\n" +"\n" +" -J, --remote-header-name\n" +" (HTTP) This option tells the -O, --remote-name option to use the\n" +" server-specified Content-Disposition filename instead of ex-\n" +" tracting a filename from the URL. If the server-provided file\n" +" name contains a path, that is stripped off before the file name\n" +" is used.\n" +"\n" +, stdout); + fputs( +" The file is saved in the current directory, or in the directory\n" +" specified with --output-dir.\n" +"\n" +" If the server specifies a file name and a file with that name\n" +" already exists in the destination directory, it is not overwrit-\n" +" ten and an error occurs - unless you allow it by using the\n" +" --clobber option. If the server does not specify a file name\n" +" then this option has no effect.\n" +"\n" +, stdout); + fputs( +" There is no attempt to decode %-sequences (yet) in the provided\n" +" file name, so this option may provide you with rather unexpected\n" +" file names.\n" +"\n" +" This feature uses the name from the \"filename\" field, it does\n" +" not yet support the \"filename*\" field (filenames with explicit\n" +" character sets).\n" +"\n" +" WARNING: Exercise judicious use of this option, especially on\n" +, stdout); + fputs( +" Windows. A rogue server could send you the name of a DLL or\n" +" other file that could be loaded automatically by Windows or some\n" +" third party software.\n" +"\n" +" Providing --remote-header-name multiple times has no extra ef-\n" +" fect. Disable it again with --no-remote-header-name.\n" +"\n" +" Example:\n" +" curl -OJ https://example.com/file\n" +"\n" +" See also -O, --remote-name.\n" +"\n" +" --remote-name-all\n" +, stdout); + fputs( +" This option changes the default action for all given URLs to be\n" +" dealt with as if -O, --remote-name were used for each one. So if\n" +" you want to disable that for a specific URL after --re-\n" +" mote-name-all has been used, you must use \"-o -\" or --no-re-\n" +" mote-name.\n" +"\n" +" Providing --remote-name-all multiple times has no extra effect.\n" +" Disable it again with --no-remote-name-all.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --remote-name-all ftp://example.com/file1 ftp://example.com/file2\n" +"\n" +" See also -O, --remote-name.\n" +"\n" +" -O, --remote-name\n" +" Write output to a local file named like the remote file we get.\n" +" (Only the file part of the remote file is used, the path is cut\n" +" off.)\n" +"\n" +" The file is saved in the current working directory. If you want\n" +, stdout); + fputs( +" the file saved in a different directory, make sure you change\n" +" the current working directory before invoking curl with this op-\n" +" tion or use --output-dir.\n" +"\n" +" The remote file name to use for saving is extracted from the\n" +" given URL, nothing else, and if it already exists it is over-\n" +" written. If you want the server to be able to choose the file\n" +, stdout); + fputs( +" name refer to -J, --remote-header-name which can be used in ad-\n" +" dition to this option. If the server chooses a file name and\n" +" that name already exists it is not overwritten.\n" +"\n" +" There is no URL decoding done on the file name. If it has %20 or\n" +" other URL encoded parts of the name, they end up as-is as file\n" +" name.\n" +"\n" +" You may use this option as many times as the number of URLs you\n" +" have.\n" +"\n" +, stdout); + fputs( +" --remote-name can be used several times in a command line\n" +"\n" +" Example:\n" +" curl -O https://example.com/filename\n" +"\n" +" See also --remote-name-all, --output-dir and -J, --re-\n" +" mote-header-name.\n" +" -R, --remote-time\n" +" Makes curl attempt to figure out the timestamp of the remote\n" +" file that is getting downloaded, and if that is available make\n" +" the local file get that same timestamp.\n" +"\n" +, stdout); + fputs( +" Providing --remote-time multiple times has no extra effect.\n" +" Disable it again with --no-remote-time.\n" +"\n" +" Example:\n" +" curl --remote-time -o foo https://example.com\n" +"\n" +" See also -O, --remote-name and -z, --time-cond.\n" +"\n" +" --remove-on-error\n" +" When curl returns an error when told to save output in a local\n" +" file, this option removes that saved file before exiting. This\n" +, stdout); + fputs( +" prevents curl from leaving a partial file in the case of an er-\n" +" ror during transfer.\n" +"\n" +" If the output is not a regular file, this option has no effect.\n" +"\n" +" Providing --remove-on-error multiple times has no extra effect.\n" +" Disable it again with --no-remove-on-error.\n" +"\n" +" Example:\n" +" curl --remove-on-error -o output https://example.com\n" +"\n" +" See also -f, --fail. Added in 7.83.0.\n" +"\n" +, stdout); + fputs( +" --request-target \n" +" (HTTP) Tells curl to use an alternative \"target\" (path) instead\n" +" of using the path as provided in the URL. Particularly useful\n" +" when wanting to issue HTTP requests without leading slash or\n" +" other data that does not follow the regular URL pattern, like\n" +" \"OPTIONS *\".\n" +"\n" +" curl passes on the verbatim string you give it its the request\n" +, stdout); + fputs( +" without any filter or other safe guards. That includes white\n" +" space and control characters.\n" +"\n" +" If --request-target is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --request-target \"*\" -X OPTIONS https://example.com\n" +"\n" +" See also -X, --request. Added in 7.55.0.\n" +"\n" +" -X, --request \n" +" Change the method to use when starting the transfer.\n" +"\n" +, stdout); + fputs( +" curl passes on the verbatim string you give it its the request\n" +" without any filter or other safe guards. That includes white\n" +" space and control characters.\n" +"\n" +" HTTP Specifies a custom request method to use when communicat-\n" +" ing with the HTTP server. The specified request method is\n" +" used instead of the method otherwise used (which defaults\n" +, stdout); + fputs( +" to GET). Read the HTTP 1.1 specification for details and\n" +" explanations. Common additional HTTP requests include PUT\n" +" and DELETE, while related technologies like WebDAV offers\n" +" PROPFIND, COPY, MOVE and more.\n" +"\n" +" Normally you do not need this option. All sorts of GET,\n" +" HEAD, POST and PUT requests are rather invoked by using\n" +, stdout); + fputs( +" dedicated command line options.\n" +"\n" +" This option only changes the actual word used in the HTTP\n" +" request, it does not alter the way curl behaves. So for\n" +" example if you want to make a proper HEAD request, using\n" +" -X HEAD does not suffice. You need to use the -I, --head\n" +" option.\n" +"\n" +" The method string you set with -X, --request is used for\n" +, stdout); + fputs( +" all requests, which if you for example use -L, --location\n" +" may cause unintended side-effects when curl does not\n" +" change request method according to the HTTP 30x response\n" +" codes - and similar.\n" +"\n" +" FTP Specifies a custom FTP command to use instead of LIST\n" +" when doing file lists with FTP.\n" +"\n" +" POP3 Specifies a custom POP3 command to use instead of LIST or\n" +, stdout); + fputs( +" RETR.\n" +"\n" +" IMAP Specifies a custom IMAP command to use instead of LIST.\n" +"\n" +" SMTP Specifies a custom SMTP command to use instead of HELP or\n" +" VRFY.\n" +"\n" +" If --request is provided several times, the last set value is\n" +" used.\n" +"\n" +" Examples:\n" +" curl -X \"DELETE\" https://example.com\n" +" curl -X NLST ftp://example.com/\n" +"\n" +" See also --request-target.\n" +"\n" +, stdout); + fputs( +" --resolve <[+]host:port:addr[,addr]...>\n" +" Provide a custom address for a specific host and port pair. Us-\n" +" ing this, you can make the curl requests(s) use a specified ad-\n" +" dress and prevent the otherwise normally resolved address to be\n" +" used. Consider it a sort of /etc/hosts alternative provided on\n" +" the command line. The port number should be the number used for\n" +, stdout); + fputs( +" the specific protocol the host is used for. It means you need\n" +" several entries if you want to provide address for the same host\n" +" but different ports.\n" +"\n" +" By specifying '*' as host you can tell curl to resolve any host\n" +" and specific port pair to the specified address. Wildcard is re-\n" +" solved last so any --resolve with a specific host and port is\n" +" used first.\n" +"\n" +, stdout); + fputs( +" The provided address set by this option is used even if -4,\n" +" --ipv4 or -6, --ipv6 is set to make curl use another IP version.\n" +" By prefixing the host with a '+' you can make the entry time out\n" +" after curl's default timeout (1 minute). Note that this only\n" +" makes sense for long running parallel transfers with a lot of\n" +" files. In such cases, if this option is used curl tries to re-\n" +, stdout); + fputs( +" solve the host as it normally would once the timeout has ex-\n" +" pired.\n" +"\n" +" Support for providing the IP address within [brackets] was added\n" +" in 7.57.0.\n" +"\n" +" Support for providing multiple IP addresses per entry was added\n" +" in 7.59.0.\n" +"\n" +" Support for resolving with wildcard was added in 7.64.0.\n" +"\n" +" Support for the '+' prefix was was added in 7.75.0.\n" +"\n" +, stdout); + fputs( +" --resolve can be used several times in a command line\n" +"\n" +" Example:\n" +" curl --resolve example.com:443:127.0.0.1 https://example.com\n" +"\n" +" See also --connect-to and --alt-svc.\n" +"\n" +" --retry-all-errors\n" +" Retry on any error. This option is used together with --retry.\n" +"\n" +" This option is the \"sledgehammer\" of retrying. Do not use this\n" +" option by default (for example in your curlrc), there may be un-\n" +, stdout); + fputs( +" intended consequences such as sending or receiving duplicate\n" +" data. Do not use with redirected input or output. You'd be much\n" +" better off handling your unique problems in shell script. Please\n" +" read the example below.\n" +"\n" +" WARNING: For server compatibility curl attempts to retry failed\n" +" flaky transfers as close as possible to how they were started,\n" +, stdout); + fputs( +" but this is not possible with redirected input or output. For\n" +" example, before retrying it removes output data from a failed\n" +" partial transfer that was written to an output file. However\n" +" this is not true of data redirected to a | pipe or > file, which\n" +" are not reset. We strongly suggest you do not parse or record\n" +" output via redirect in combination with this option, since you\n" +, stdout); + fputs( +" may receive duplicate data.\n" +"\n" +" By default curl does not return error for transfers with an HTTP\n" +" response code that indicates an HTTP error, if the transfer was\n" +" successful. For example, if a server replies 404 Not Found and\n" +" the reply is fully received then that is not an error. When\n" +" --retry is used then curl retries on some HTTP response codes\n" +, stdout); + fputs( +" that indicate transient HTTP errors, but that does not include\n" +" most 4xx response codes such as 404. If you want to retry on all\n" +" response codes that indicate HTTP errors (4xx and 5xx) then com-\n" +" bine with -f, --fail.\n" +"\n" +" Providing --retry-all-errors multiple times has no extra effect.\n" +" Disable it again with --no-retry-all-errors.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --retry 5 --retry-all-errors https://example.com\n" +"\n" +" See also --retry. Added in 7.71.0.\n" +"\n" +" --retry-connrefused\n" +" In addition to the other conditions, consider ECONNREFUSED as a\n" +" transient error too for --retry. This option is used together\n" +" with --retry.\n" +"\n" +" Providing --retry-connrefused multiple times has no extra ef-\n" +" fect. Disable it again with --no-retry-connrefused.\n" +"\n" +, stdout); + fputs( +" Example:\n" +" curl --retry-connrefused --retry 7 https://example.com\n" +"\n" +" See also --retry and --retry-all-errors. Added in 7.52.0.\n" +"\n" +" --retry-delay \n" +" Make curl sleep this amount of time before each retry when a\n" +" transfer has failed with a transient error (it changes the de-\n" +" fault backoff time algorithm between retries). This option is\n" +, stdout); + fputs( +" only interesting if --retry is also used. Setting this delay to\n" +" zero makes curl use the default backoff time.\n" +"\n" +" If --retry-delay is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --retry-delay 5 --retry 7 https://example.com\n" +"\n" +" See also --retry.\n" +"\n" +" --retry-max-time \n" +" The retry timer is reset before the first transfer attempt. Re-\n" +, stdout); + fputs( +" tries are done as usual (see --retry) as long as the timer has\n" +" not reached this given limit. Notice that if the timer has not\n" +" reached the limit, the request is made and while performing, it\n" +" may take longer than this given time period. To limit a single\n" +" request's maximum time, use -m, --max-time. Set this option to\n" +" zero to not timeout retries.\n" +"\n" +, stdout); + fputs( +" If --retry-max-time is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --retry-max-time 30 --retry 10 https://example.com\n" +"\n" +" See also --retry.\n" +"\n" +" --retry \n" +" If a transient error is returned when curl tries to perform a\n" +" transfer, it retries this number of times before giving up. Set-\n" +" ting the number to 0 makes curl do no retries (which is the de-\n" +, stdout); + fputs( +" fault). Transient error means either: a timeout, an FTP 4xx re-\n" +" sponse code or an HTTP 408, 429, 500, 502, 503 or 504 response\n" +" code.\n" +"\n" +" When curl is about to retry a transfer, it first waits one sec-\n" +" ond and then for all forthcoming retries it doubles the waiting\n" +" time until it reaches 10 minutes which then remains delay be-\n" +" tween the rest of the retries. By using --retry-delay you dis-\n" +, stdout); + fputs( +" able this exponential backoff algorithm. See also\n" +" --retry-max-time to limit the total time allowed for retries.\n" +"\n" +" curl complies with the Retry-After: response header if one was\n" +" present to know when to issue the next retry (added in 7.66.0).\n" +"\n" +" If --retry is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --retry 7 https://example.com\n" +"\n" +, stdout); + fputs( +" See also --retry-max-time.\n" +"\n" +" --sasl-authzid \n" +" Use this authorization identity (authzid), during SASL PLAIN au-\n" +" thentication, in addition to the authentication identity (auth-\n" +" cid) as specified by -u, --user.\n" +"\n" +" If the option is not specified, the server derives the authzid\n" +" from the authcid, but if specified, and depending on the server\n" +, stdout); + fputs( +" implementation, it may be used to access another user's inbox,\n" +" that the user has been granted access to, or a shared mailbox\n" +" for example.\n" +"\n" +" If --sasl-authzid is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --sasl-authzid zid imap://example.com/\n" +"\n" +" See also --login-options. Added in 7.66.0.\n" +"\n" +" --sasl-ir\n" +, stdout); + fputs( +" Enable initial response in SASL authentication.\n" +"\n" +" Providing --sasl-ir multiple times has no extra effect. Disable\n" +" it again with --no-sasl-ir.\n" +"\n" +" Example:\n" +" curl --sasl-ir imap://example.com/\n" +"\n" +" See also --sasl-authzid.\n" +"\n" +" --service-name \n" +" This option allows you to change the service name for SPNEGO.\n" +"\n" +" If --service-name is provided several times, the last set value\n" +, stdout); + fputs( +" is used.\n" +" Example:\n" +" curl --service-name sockd/server https://example.com\n" +"\n" +" See also --negotiate and --proxy-service-name.\n" +"\n" +" -S, --show-error\n" +" When used with -s, --silent, it makes curl show an error message\n" +" if it fails.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +" Providing --show-error multiple times has no extra effect. Dis-\n" +, stdout); + fputs( +" able it again with --no-show-error.\n" +"\n" +" Example:\n" +" curl --show-error --silent https://example.com\n" +"\n" +" See also --no-progress-meter.\n" +"\n" +" -s, --silent\n" +" Silent or quiet mode. Do not show progress meter or error mes-\n" +" sages. Makes Curl mute. It still outputs the data you ask for,\n" +" potentially even to the terminal/stdout unless you redirect it.\n" +"\n" +, stdout); + fputs( +" Use -S, --show-error in addition to this option to disable\n" +" progress meter but still show error messages.\n" +"\n" +" Providing --silent multiple times has no extra effect. Disable\n" +" it again with --no-silent.\n" +"\n" +" Example:\n" +" curl -s https://example.com\n" +"\n" +" See also -v, --verbose, --stderr and --no-progress-meter.\n" +"\n" +" --socks4 \n" +, stdout); + fputs( +" Use the specified SOCKS4 proxy. If the port number is not speci-\n" +" fied, it is assumed at port 1080. Using this socket type make\n" +" curl resolve the host name and passing the address on to the\n" +" proxy.\n" +"\n" +" To specify proxy on a unix domain socket, use localhost for\n" +" host, e.g. \"socks4://localhost/path/to/socket.sock\"\n" +"\n" +" This option overrides any previous use of -x, --proxy, as they\n" +, stdout); + fputs( +" are mutually exclusive.\n" +"\n" +" This option is superfluous since you can specify a socks4 proxy\n" +" with -x, --proxy using a socks4:// protocol prefix.\n" +"\n" +" --preproxy can be used to specify a SOCKS proxy at the same time\n" +" proxy is used with an HTTP/HTTPS proxy (added in 7.52.0). In\n" +" such a case, curl first connects to the SOCKS proxy and then\n" +" connects (through SOCKS) to the HTTP or HTTPS proxy.\n" +"\n" +, stdout); + fputs( +" If --socks4 is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --socks4 hostname:4096 https://example.com\n" +"\n" +" See also --socks4a, --socks5 and --socks5-hostname.\n" +"\n" +" --socks4a \n" +" Use the specified SOCKS4a proxy. If the port number is not spec-\n" +" ified, it is assumed at port 1080. This asks the proxy to re-\n" +" solve the host name.\n" +"\n" +, stdout); + fputs( +" To specify proxy on a unix domain socket, use localhost for\n" +" host, e.g. \"socks4a://localhost/path/to/socket.sock\"\n" +"\n" +" This option overrides any previous use of -x, --proxy, as they\n" +" are mutually exclusive.\n" +"\n" +" This option is superfluous since you can specify a socks4a proxy\n" +" with -x, --proxy using a socks4a:// protocol prefix.\n" +"\n" +" --preproxy can be used to specify a SOCKS proxy at the same time\n" +, stdout); + fputs( +" -x, --proxy is used with an HTTP/HTTPS proxy (added in 7.52.0).\n" +" In such a case, curl first connects to the SOCKS proxy and then\n" +" connects (through SOCKS) to the HTTP or HTTPS proxy.\n" +"\n" +" If --socks4a is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --socks4a hostname:4096 https://example.com\n" +"\n" +" See also --socks4, --socks5 and --socks5-hostname.\n" +"\n" +, stdout); + fputs( +" --socks5-basic\n" +" Tells curl to use username/password authentication when connect-\n" +" ing to a SOCKS5 proxy. The username/password authentication is\n" +" enabled by default. Use --socks5-gssapi to force GSS-API authen-\n" +" tication to SOCKS5 proxies.\n" +"\n" +" Providing --socks5-basic multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --socks5-basic --socks5 hostname:4096 https://example.com\n" +"\n" +, stdout); + fputs( +" See also --socks5. Added in 7.55.0.\n" +"\n" +" --socks5-gssapi-nec\n" +" As part of the GSS-API negotiation a protection mode is negoti-\n" +" ated. RFC 1961 says in section 4.3/4.4 it should be protected,\n" +" but the NEC reference implementation does not. The option\n" +" --socks5-gssapi-nec allows the unprotected exchange of the pro-\n" +" tection mode negotiation.\n" +"\n" +, stdout); + fputs( +" Providing --socks5-gssapi-nec multiple times has no extra ef-\n" +" fect. Disable it again with --no-socks5-gssapi-nec.\n" +"\n" +" Example:\n" +" curl --socks5-gssapi-nec --socks5 hostname:4096 https://example.com\n" +"\n" +" See also --socks5.\n" +"\n" +" --socks5-gssapi-service \n" +" The default service name for a socks server is rcmd/server-fqdn.\n" +" This option allows you to change it.\n" +"\n" +, stdout); + fputs( +" If --socks5-gssapi-service is provided several times, the last\n" +" set value is used.\n" +"\n" +" Example:\n" +" curl --socks5-gssapi-service sockd --socks5 hostname:4096 https://example.com\n" +"\n" +" See also --socks5.\n" +"\n" +" --socks5-gssapi\n" +" Tells curl to use GSS-API authentication when connecting to a\n" +" SOCKS5 proxy. The GSS-API authentication is enabled by default\n" +, stdout); + fputs( +" (if curl is compiled with GSS-API support). Use --socks5-basic\n" +" to force username/password authentication to SOCKS5 proxies.\n" +"\n" +" Providing --socks5-gssapi multiple times has no extra effect.\n" +" Disable it again with --no-socks5-gssapi.\n" +"\n" +" Example:\n" +" curl --socks5-gssapi --socks5 hostname:4096 https://example.com\n" +"\n" +" See also --socks5. Added in 7.55.0.\n" +"\n" +" --socks5-hostname \n" +, stdout); + fputs( +" Use the specified SOCKS5 proxy (and let the proxy resolve the\n" +" host name). If the port number is not specified, it is assumed\n" +" at port 1080.\n" +"\n" +" To specify proxy on a unix domain socket, use localhost for\n" +" host, e.g. \"socks5h://localhost/path/to/socket.sock\"\n" +"\n" +" This option overrides any previous use of -x, --proxy, as they\n" +" are mutually exclusive.\n" +"\n" +, stdout); + fputs( +" This option is superfluous since you can specify a socks5 host-\n" +" name proxy with -x, --proxy using a socks5h:// protocol prefix.\n" +"\n" +" --preproxy can be used to specify a SOCKS proxy at the same time\n" +" -x, --proxy is used with an HTTP/HTTPS proxy (added in 7.52.0).\n" +" In such a case, curl first connects to the SOCKS proxy and then\n" +" connects (through SOCKS) to the HTTP or HTTPS proxy.\n" +"\n" +, stdout); + fputs( +" If --socks5-hostname is provided several times, the last set\n" +" value is used.\n" +"\n" +" Example:\n" +" curl --socks5-hostname proxy.example:7000 https://example.com\n" +"\n" +" See also --socks5 and --socks4a.\n" +"\n" +" --socks5 \n" +" Use the specified SOCKS5 proxy - but resolve the host name lo-\n" +" cally. If the port number is not specified, it is assumed at\n" +" port 1080.\n" +"\n" +, stdout); + fputs( +" To specify proxy on a unix domain socket, use localhost for\n" +" host, e.g. \"socks5://localhost/path/to/socket.sock\"\n" +"\n" +" This option overrides any previous use of -x, --proxy, as they\n" +" are mutually exclusive.\n" +"\n" +" This option is superfluous since you can specify a socks5 proxy\n" +" with -x, --proxy using a socks5:// protocol prefix.\n" +"\n" +" --preproxy can be used to specify a SOCKS proxy at the same time\n" +, stdout); + fputs( +" -x, --proxy is used with an HTTP/HTTPS proxy (added in 7.52.0).\n" +" In such a case, curl first connects to the SOCKS proxy and then\n" +" connects (through SOCKS) to the HTTP or HTTPS proxy.\n" +"\n" +" This option (as well as --socks4) does not work with IPV6, FTPS\n" +" or LDAP.\n" +"\n" +" If --socks5 is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --socks5 proxy.example:7000 https://example.com\n" +"\n" +" See also --socks5-hostname and --socks4a.\n" +"\n" +" -Y, --speed-limit \n" +" If a transfer is slower than this set speed (in bytes per sec-\n" +" ond) for a given number of seconds, it gets aborted. The time\n" +" period is set with -y, --speed-time and is 30 seconds by de-\n" +" fault.\n" +"\n" +" If --speed-limit is provided several times, the last set value\n" +, stdout); + fputs( +" is used.\n" +" Example:\n" +" curl --speed-limit 300 --speed-time 10 https://example.com\n" +"\n" +" See also -y, --speed-time, --limit-rate and -m, --max-time.\n" +"\n" +" -y, --speed-time \n" +" If a transfer runs slower than speed-limit bytes per second dur-\n" +" ing a speed-time period, the transfer is aborted. If speed-time\n" +" is used, the default speed-limit is 1 unless set with -Y,\n" +" --speed-limit.\n" +"\n" +, stdout); + fputs( +" This option controls transfers (in both directions) but does not\n" +" affect slow connects etc. If this is a concern for you, try the\n" +" --connect-timeout option.\n" +"\n" +" If --speed-time is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --speed-limit 300 --speed-time 10 https://example.com\n" +"\n" +" See also -Y, --speed-limit and --limit-rate.\n" +"\n" +" --ssl-allow-beast\n" +, stdout); + fputs( +" (TLS) This option tells curl to not work around a security flaw\n" +" in the SSL3 and TLS1.0 protocols known as BEAST. If this option\n" +" is not used, the SSL layer may use workarounds known to cause\n" +" interoperability problems with some older SSL implementations.\n" +"\n" +" WARNING: this option loosens the SSL security, and by using this\n" +" flag you ask for exactly that.\n" +"\n" +, stdout); + fputs( +" Providing --ssl-allow-beast multiple times has no extra effect.\n" +" Disable it again with --no-ssl-allow-beast.\n" +"\n" +" Example:\n" +" curl --ssl-allow-beast https://example.com\n" +"\n" +" See also --proxy-ssl-allow-beast and -k, --insecure.\n" +"\n" +" --ssl-auto-client-cert\n" +" (TLS) (Schannel) Tell libcurl to automatically locate and use a\n" +" client certificate for authentication, when requested by the\n" +, stdout); + fputs( +" server. Since the server can request any certificate that sup-\n" +" ports client authentication in the OS certificate store it could\n" +" be a privacy violation and unexpected.\n" +"\n" +" Providing --ssl-auto-client-cert multiple times has no extra ef-\n" +" fect. Disable it again with --no-ssl-auto-client-cert.\n" +"\n" +" Example:\n" +" curl --ssl-auto-client-cert https://example.com\n" +"\n" +, stdout); + fputs( +" See also --proxy-ssl-auto-client-cert. Added in 7.77.0.\n" +"\n" +" --ssl-no-revoke\n" +" (TLS) (Schannel) This option tells curl to disable certificate\n" +" revocation checks. WARNING: this option loosens the SSL secu-\n" +" rity, and by using this flag you ask for exactly that.\n" +"\n" +" Providing --ssl-no-revoke multiple times has no extra effect.\n" +" Disable it again with --no-ssl-no-revoke.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --ssl-no-revoke https://example.com\n" +"\n" +" See also --crlfile.\n" +"\n" +" --ssl-reqd\n" +" (FTP IMAP POP3 SMTP LDAP) Require SSL/TLS for the connection.\n" +" Terminates the connection if the transfer cannot be upgraded to\n" +" use SSL/TLS.\n" +"\n" +" This option is handled in LDAP (added in 7.81.0). It is fully\n" +" supported by the OpenLDAP backend and rejected by the generic\n" +, stdout); + fputs( +" ldap backend if explicit TLS is required.\n" +"\n" +" This option is unnecessary if you use a URL scheme that in it-\n" +" self implies immediate and implicit use of TLS, like for FTPS,\n" +" IMAPS, POP3S, SMTPS and LDAPS. Such a transfer always fails if\n" +" the TLS handshake does not work.\n" +"\n" +" This option was formerly known as --ftp-ssl-reqd.\n" +"\n" +" Providing --ssl-reqd multiple times has no extra effect. Dis-\n" +, stdout); + fputs( +" able it again with --no-ssl-reqd.\n" +"\n" +" Example:\n" +" curl --ssl-reqd ftp://example.com\n" +"\n" +" See also --ssl and -k, --insecure.\n" +"\n" +" --ssl-revoke-best-effort\n" +" (TLS) (Schannel) This option tells curl to ignore certificate\n" +" revocation checks when they failed due to missing/offline dis-\n" +" tribution points for the revocation check lists.\n" +"\n" +, stdout); + fputs( +" Providing --ssl-revoke-best-effort multiple times has no extra\n" +" effect. Disable it again with --no-ssl-revoke-best-effort.\n" +"\n" +" Example:\n" +" curl --ssl-revoke-best-effort https://example.com\n" +"\n" +" See also --crlfile and -k, --insecure. Added in 7.70.0.\n" +"\n" +" --ssl (FTP IMAP POP3 SMTP LDAP) Warning: this is considered an inse-\n" +" cure option. Consider using --ssl-reqd instead to be sure curl\n" +, stdout); + fputs( +" upgrades to a secure connection.\n" +"\n" +" Try to use SSL/TLS for the connection. Reverts to a non-secure\n" +" connection if the server does not support SSL/TLS. See also\n" +" --ftp-ssl-control and --ssl-reqd for different levels of encryp-\n" +" tion required.\n" +"\n" +" This option is handled in LDAP (added in 7.81.0). It is fully\n" +" supported by the OpenLDAP backend and ignored by the generic\n" +, stdout); + fputs( +" ldap backend.\n" +"\n" +" Please note that a server may close the connection if the nego-\n" +" tiation does not succeed.\n" +"\n" +" This option was formerly known as --ftp-ssl. That option name\n" +" can still be used but might be removed in a future version.\n" +"\n" +" Providing --ssl multiple times has no extra effect. Disable it\n" +" again with --no-ssl.\n" +"\n" +" Example:\n" +" curl --ssl pop3://example.com/\n" +"\n" +, stdout); + fputs( +" See also --ssl-reqd, -k, --insecure and --ciphers.\n" +"\n" +" -2, --sslv2\n" +" (SSL) This option previously asked curl to use SSLv2, but is now\n" +" ignored (added in 7.77.0). SSLv2 is widely considered insecure\n" +" (see RFC 6176).\n" +"\n" +" Providing --sslv2 multiple times has no extra effect.\n" +"\n" +" Example:\n" +" curl --sslv2 https://example.com\n" +"\n" +" See also --http1.1 and --http2. -2, --sslv2 requires that the\n" +, stdout); + fputs( +" underlying libcurl was built to support TLS. This option is mu-\n" +" tually exclusive to -3, --sslv3 and -1, --tlsv1 and --tlsv1.1\n" +" and --tlsv1.2.\n" +"\n" +" -3, --sslv3\n" +" (SSL) This option previously asked curl to use SSLv3, but is now\n" +" ignored (added in 7.77.0). SSLv3 is widely considered insecure\n" +" (see RFC 7568).\n" +"\n" +" Providing --sslv3 multiple times has no extra effect.\n" +"\n" +" Example:\n" +, stdout); + fputs( +" curl --sslv3 https://example.com\n" +"\n" +" See also --http1.1 and --http2. -3, --sslv3 requires that the\n" +" underlying libcurl was built to support TLS. This option is mu-\n" +" tually exclusive to -2, --sslv2 and -1, --tlsv1 and --tlsv1.1\n" +" and --tlsv1.2.\n" +"\n" +" --stderr \n" +" Redirect all writes to stderr to the specified file instead. If\n" +" the file name is a plain '-', it is instead written to stdout.\n" +"\n" +, stdout); + fputs( +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +" If --stderr is provided several times, the last set value is\n" +" used.\n" +"\n" +" Example:\n" +" curl --stderr output.txt https://example.com\n" +"\n" +" See also -v, --verbose and -s, --silent.\n" +"\n" +" --styled-output\n" +" Enables the automatic use of bold font styles when writing HTTP\n" +, stdout); + fputs( +" headers to the terminal. Use --no-styled-output to switch them\n" +" off.\n" +"\n" +" Styled output requires a terminal that supports bold fonts. This\n" +" feature is not present on curl for Windows due to lack of this\n" +" capability.\n" +"\n" +" This option is global and does not need to be specified for each\n" +" use of --next.\n" +"\n" +" Providing --styled-output multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-styled-output.\n" +"\n" +" Example:\n" +" curl --styled-output -I https://example.com\n" +"\n" +" See also -I, --head and -v, --verbose. Added in 7.61.0.\n" +"\n" +" --suppress-connect-headers\n" +" When -p, --proxytunnel is used and a CONNECT request is made do\n" +" not output proxy CONNECT response headers. This option is meant\n" +" to be used with -D, --dump-header or -i, --include which are\n" +, stdout); + fputs( +" used to show protocol headers in the output. It has no effect on\n" +" debug options such as -v, --verbose or --trace, or any statis-\n" +" tics.\n" +"\n" +" Providing --suppress-connect-headers multiple times has no extra\n" +" effect. Disable it again with --no-suppress-connect-headers.\n" +"\n" +" Example:\n" +" curl --suppress-connect-headers --include -x proxy https://example.com\n" +"\n" +, stdout); + fputs( +" See also -D, --dump-header, -i, --include and -p, --proxytunnel.\n" +" Added in 7.54.0.\n" +"\n" +" --tcp-fastopen\n" +" Enable use of TCP Fast Open (RFC 7413). TCP Fast Open is a TCP\n" +" extension that allows data to get sent earlier over the connec-\n" +" tion (before the final handshake ACK) if the client and server\n" +" have been connected previously.\n" +"\n" +" Providing --tcp-fastopen multiple times has no extra effect.\n" +, stdout); + fputs( +" Disable it again with --no-tcp-fastopen.\n" +"\n" +" Example:\n" +" curl --tcp-fastopen https://example.com\n" +"\n" +" See also --false-start.\n" +"\n" +" --tcp-nodelay\n" +" Turn on the TCP_NODELAY option. See the curl_easy_setopt(3) man\n" +" page for details about this option.\n" +"\n" +" curl sets this option by default and you need to explicitly\n" +" switch it off if you do not want it on (added in 7.50.2).\n" +"\n" +, stdout); + fputs( +" Providing --tcp-nodelay multiple times has no extra effect.\n" +" Disable it again with --no-tcp-nodelay.\n" +"\n" +" Example:\n" +" curl --tcp-nodelay https://example.com\n" +"\n" +" See also -N, --no-buffer.\n" +"\n" +" -t, --telnet-option \n" +" Pass options to the telnet protocol. Supported options are:\n" +"\n" +" `TTYPE=`\n" +" Sets the terminal type.\n" +"\n" +" `XDISPLOC=`\n" +, stdout); + fputs( +" Sets the X display location.\n" +"\n" +" `NEW_ENV=`\n" +" Sets an environment variable.\n" +"\n" +" --telnet-option can be used several times in a command line\n" +"\n" +" Example:\n" +" curl -t TTYPE=vt100 telnet://example.com/\n" +"\n" +" See also -K, --config.\n" +" --tftp-blksize \n" +" (TFTP) Set the TFTP BLKSIZE option (must be >512). This is the\n" +, stdout); + fputs( +" block size that curl tries to use when transferring data to or\n" +" from a TFTP server. By default 512 bytes are used.\n" +"\n" +" If --tftp-blksize is provided several times, the last set value\n" +" is used.\n" +" Example:\n" +" curl --tftp-blksize 1024 tftp://example.com/file\n" +"\n" +" See also --tftp-no-options.\n" +"\n" +" --tftp-no-options\n" +" (TFTP) Tells curl not to send TFTP options requests.\n" +"\n" +, stdout); + fputs( +" This option improves interop with some legacy servers that do\n" +" not acknowledge or properly implement TFTP options. When this\n" +" option is used --tftp-blksize is ignored.\n" +"\n" +" Providing --tftp-no-options multiple times has no extra effect.\n" +" Disable it again with --no-tftp-no-options.\n" +"\n" +" Example:\n" +" curl --tftp-no-options tftp://192.168.0.1/\n" +"\n" +" See also --tftp-blksize.\n" +"\n" +, stdout); + fputs( +" -z, --time-cond